mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2026-07-14 04:41:15 +03:00
Compare commits
17 Commits
disable-gl
...
docs-artic
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
66523b9bfc | ||
|
|
c1e39b2cef | ||
|
|
0634599809 | ||
|
|
fccd724cd7 | ||
|
|
dedf4563d2 | ||
|
|
a0c60b4027 | ||
|
|
096bb8fdeb | ||
|
|
eaa39f8194 | ||
|
|
180a59119b | ||
|
|
414aa7b3ab | ||
|
|
6155e06ad4 | ||
|
|
fb26016beb | ||
|
|
66ac4114ed | ||
|
|
945dc5e42c | ||
|
|
2c9af81fbb | ||
|
|
431c315bff | ||
|
|
3b68e7fe1a |
@@ -63,6 +63,7 @@ func insertRows(at *auth.Token, tss []prompb.TimeSeries, mms []prompb.MetricMeta
|
||||
|
||||
rowsTotal := 0
|
||||
tssDst := ctx.WriteRequest.Timeseries[:0]
|
||||
mmsDst := ctx.WriteRequest.Metadata[:0]
|
||||
labels := ctx.Labels[:0]
|
||||
samples := ctx.Samples[:0]
|
||||
for i := range tss {
|
||||
@@ -82,7 +83,19 @@ func insertRows(at *auth.Token, tss []prompb.TimeSeries, mms []prompb.MetricMeta
|
||||
|
||||
var metadataTotal int
|
||||
if prommetadata.IsEnabled() {
|
||||
ctx.WriteRequest.Metadata = mms
|
||||
for i := range mms {
|
||||
mm := &mms[i]
|
||||
mmsDst = append(mmsDst, prompb.MetricMetadata{
|
||||
MetricFamilyName: mm.MetricFamilyName,
|
||||
Help: mm.Help,
|
||||
Type: mm.Type,
|
||||
Unit: mm.Unit,
|
||||
|
||||
AccountID: mm.AccountID,
|
||||
ProjectID: mm.ProjectID,
|
||||
})
|
||||
}
|
||||
ctx.WriteRequest.Metadata = mmsDst
|
||||
metadataTotal = len(mms)
|
||||
}
|
||||
|
||||
|
||||
@@ -172,7 +172,13 @@ func newBinaryOpFunc(bf func(left, right float64, isBool bool) float64) binaryOp
|
||||
left = removeEmptySeries(left)
|
||||
right = removeEmptySeries(right)
|
||||
}
|
||||
if len(left) == 0 || len(right) == 0 {
|
||||
if len(left) == 0 && len(right) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
if len(left) == 0 && bfa.be.FillLeft == nil {
|
||||
return nil, nil
|
||||
}
|
||||
if len(right) == 0 && bfa.be.FillRight == nil {
|
||||
return nil, nil
|
||||
}
|
||||
left, right, dst, err := adjustBinaryOpTags(bfa.be, left, right)
|
||||
@@ -183,6 +189,8 @@ func newBinaryOpFunc(bf func(left, right float64, isBool bool) float64) binaryOp
|
||||
logger.Panicf("BUG: len(left) must match len(right) and len(dst); got %d vs %d vs %d", len(left), len(right), len(dst))
|
||||
}
|
||||
isBool := bfa.be.Bool
|
||||
fillLeft := bfa.be.FillLeft
|
||||
fillRight := bfa.be.FillRight
|
||||
for i, tsLeft := range left {
|
||||
leftValues := tsLeft.Values
|
||||
rightValues := right[i].Values
|
||||
@@ -193,6 +201,19 @@ func newBinaryOpFunc(bf func(left, right float64, isBool bool) float64) binaryOp
|
||||
}
|
||||
for j, a := range leftValues {
|
||||
b := rightValues[j]
|
||||
leftIsNaN := math.IsNaN(a)
|
||||
rightIsNaN := math.IsNaN(b)
|
||||
// apply the fill value when either the left or right side is NaN, but not both.
|
||||
if leftIsNaN && rightIsNaN {
|
||||
dstValues[j] = bf(a, b, isBool)
|
||||
continue
|
||||
}
|
||||
if leftIsNaN && fillLeft != nil {
|
||||
a = fillLeft.N
|
||||
}
|
||||
if rightIsNaN && fillRight != nil {
|
||||
b = fillRight.N
|
||||
}
|
||||
dstValues[j] = bf(a, b, isBool)
|
||||
}
|
||||
}
|
||||
@@ -226,7 +247,7 @@ func adjustBinaryOpTags(be *metricsql.BinaryOpExpr, left, right []*timeseries) (
|
||||
}
|
||||
}
|
||||
|
||||
// Slow path: `vector op vector` or `a op {on|ignoring} {group_left|group_right} b`
|
||||
// Slow path: `vector op vector` or `a op {on|ignoring} {group_left|group_right} {fill|fill_left|fill_right} b`
|
||||
var rvsLeft, rvsRight []*timeseries
|
||||
mLeft, mRight := createTimeseriesMapByTagSet(be, left, right)
|
||||
joinOp := strings.ToLower(be.JoinModifier.Op)
|
||||
@@ -239,10 +260,27 @@ func adjustBinaryOpTags(be *metricsql.BinaryOpExpr, left, right []*timeseries) (
|
||||
// Add __name__ to groupTags if metric name must be preserved.
|
||||
groupTags = append(groupTags[:len(groupTags):len(groupTags)], "__name__")
|
||||
}
|
||||
// Add missing keys from mRight to mLeft when fill_left()/fill() modifier is used
|
||||
if be.FillLeft != nil {
|
||||
for k := range mRight {
|
||||
if _, ok := mLeft[k]; !ok {
|
||||
mLeft[k] = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
for k, tssLeft := range mLeft {
|
||||
tssRight := mRight[k]
|
||||
if len(tssLeft) == 0 {
|
||||
if be.FillLeft == nil {
|
||||
logger.Panicf("BUG: unexpected empty tssLeft for key %q when FillLeft is nil", k)
|
||||
}
|
||||
tssLeft = []*timeseries{newFillTimeseries(be, tssRight[0])}
|
||||
}
|
||||
if len(tssRight) == 0 {
|
||||
continue
|
||||
if be.FillRight == nil {
|
||||
continue
|
||||
}
|
||||
tssRight = []*timeseries{newFillTimeseries(be, tssLeft[0])}
|
||||
}
|
||||
switch joinOp {
|
||||
case "group_left":
|
||||
@@ -287,6 +325,28 @@ func adjustBinaryOpTags(be *metricsql.BinaryOpExpr, left, right []*timeseries) (
|
||||
return rvsLeft, rvsRight, dst, nil
|
||||
}
|
||||
|
||||
// newFillTimeseries returns a time series filled with NaN values for the fill_left()/fill_right()/fill() modifiers.
|
||||
// These NaN values will be replaced later with the fill value if needed.
|
||||
func newFillTimeseries(be *metricsql.BinaryOpExpr, src *timeseries) *timeseries {
|
||||
var ts timeseries
|
||||
ts.CopyFromShallowTimestamps(src)
|
||||
if !be.KeepMetricNames {
|
||||
ts.MetricName.ResetMetricGroup()
|
||||
}
|
||||
groupTags := be.GroupModifier.Args
|
||||
switch strings.ToLower(be.GroupModifier.Op) {
|
||||
case "on":
|
||||
ts.MetricName.RemoveTagsOn(groupTags)
|
||||
default:
|
||||
ts.MetricName.RemoveTagsIgnoring(groupTags)
|
||||
}
|
||||
values := ts.Values
|
||||
for i := range values {
|
||||
values[i] = math.NaN()
|
||||
}
|
||||
return &ts
|
||||
}
|
||||
|
||||
func ensureSingleTimeseries(side string, be *metricsql.BinaryOpExpr, tss []*timeseries) error {
|
||||
if len(tss) == 0 {
|
||||
logger.Panicf("BUG: tss must contain at least one value")
|
||||
|
||||
@@ -424,18 +424,7 @@ func evalBinaryOp(qt *querytracer.Tracer, ec *EvalConfig, be *metricsql.BinaryOp
|
||||
if bf == nil {
|
||||
return nil, fmt.Errorf(`unknown binary op %q`, be.Op)
|
||||
}
|
||||
var err error
|
||||
var tssLeft, tssRight []*timeseries
|
||||
switch strings.ToLower(be.Op) {
|
||||
case "and", "if":
|
||||
// Fetch right-side series at first, since it usually contains
|
||||
// lower number of time series for `and` and `if` operator.
|
||||
// This should produce more specific label filters for the left side of the query.
|
||||
// This, in turn, should reduce the time to select series for the left side of the query.
|
||||
tssRight, tssLeft, err = execBinaryOpArgs(qt, ec, be.Right, be.Left, be)
|
||||
default:
|
||||
tssLeft, tssRight, err = execBinaryOpArgs(qt, ec, be.Left, be.Right, be)
|
||||
}
|
||||
tssLeft, tssRight, err := execBinaryOpArgs(qt, ec, be)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot execute %q: %w", be.AppendString(nil), err)
|
||||
}
|
||||
@@ -451,6 +440,29 @@ func evalBinaryOp(qt *querytracer.Tracer, ec *EvalConfig, be *metricsql.BinaryOp
|
||||
return rv, nil
|
||||
}
|
||||
|
||||
// binaryOpEvalOrder might change the order of evaluation of the left and right sides of a binary operation,
|
||||
// when there is chance to push down common label filters from exprFirst to exprSecond in the following executions.
|
||||
func binaryOpEvalOrder(be *metricsql.BinaryOpExpr) (exprFirst, exprSecond metricsql.Expr) {
|
||||
exprFirst, exprSecond = be.Left, be.Right
|
||||
switch strings.ToLower(be.Op) {
|
||||
case "and", "if":
|
||||
// For `and` and `if`, fetch the right-side series first, since it usually contains
|
||||
// fewer time series and yields more specific filters for the left side.
|
||||
exprFirst, exprSecond = be.Right, be.Left
|
||||
}
|
||||
if be.FillLeft != nil && be.FillRight == nil {
|
||||
// For `fill_left(<value>)`, the unmatched series can only come from the right side, so evaluate it first.
|
||||
exprFirst, exprSecond = be.Right, be.Left
|
||||
}
|
||||
return exprFirst, exprSecond
|
||||
}
|
||||
|
||||
// canPushdownCommonFilters decides if common label filters can be pushed down from one side of a binary operation to the other.
|
||||
//
|
||||
// Common filters cannot be pushed down when:
|
||||
// - the operator is `or` or `default`;
|
||||
// - either side is an aggregation function without explicit grouping;
|
||||
// - fill(<value>) modifier is used.
|
||||
func canPushdownCommonFilters(be *metricsql.BinaryOpExpr) bool {
|
||||
switch strings.ToLower(be.Op) {
|
||||
case "or", "default":
|
||||
@@ -459,6 +471,10 @@ func canPushdownCommonFilters(be *metricsql.BinaryOpExpr) bool {
|
||||
if isAggrFuncWithoutGrouping(be.Left) || isAggrFuncWithoutGrouping(be.Right) {
|
||||
return false
|
||||
}
|
||||
// Filters cannot be propagated when fill(<value>) modifier is used.
|
||||
if be.FillLeft != nil && be.FillRight != nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -470,7 +486,15 @@ func isAggrFuncWithoutGrouping(e metricsql.Expr) bool {
|
||||
return len(afe.Modifier.Args) == 0
|
||||
}
|
||||
|
||||
func execBinaryOpArgs(qt *querytracer.Tracer, ec *EvalConfig, exprFirst, exprSecond metricsql.Expr, be *metricsql.BinaryOpExpr) ([]*timeseries, []*timeseries, error) {
|
||||
func execBinaryOpArgs(qt *querytracer.Tracer, ec *EvalConfig, be *metricsql.BinaryOpExpr) ([]*timeseries, []*timeseries, error) {
|
||||
exprFirst, exprSecond := binaryOpEvalOrder(be)
|
||||
firstIsLeft := exprFirst == be.Left
|
||||
sortResult := func(tssFirst, tssSecond []*timeseries) ([]*timeseries, []*timeseries, error) {
|
||||
if firstIsLeft {
|
||||
return tssFirst, tssSecond, nil
|
||||
}
|
||||
return tssSecond, tssFirst, nil
|
||||
}
|
||||
if canPushdownCommonFilters(be) {
|
||||
// Execute binary operation in the following way:
|
||||
//
|
||||
@@ -512,7 +536,7 @@ func execBinaryOpArgs(qt *querytracer.Tracer, ec *EvalConfig, exprFirst, exprSec
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return tssFirst, tssSecond, nil
|
||||
return sortResult(tssFirst, tssSecond)
|
||||
}
|
||||
|
||||
// Execute exprFirst and exprSecond sequentially if there are cacheable repeated subexpressions
|
||||
@@ -568,7 +592,7 @@ func execBinaryOpArgs(qt *querytracer.Tracer, ec *EvalConfig, exprFirst, exprSec
|
||||
if errSecond != nil {
|
||||
return nil, nil, errSecond
|
||||
}
|
||||
return tssFirst, tssSecond, nil
|
||||
return sortResult(tssFirst, tssSecond)
|
||||
}
|
||||
|
||||
func shouldOptimizeRepeatedBinaryOpSubexprs(ec *EvalConfig, exprFirst, exprSecond metricsql.Expr) bool {
|
||||
|
||||
@@ -4006,6 +4006,275 @@ func TestExecSuccess(t *testing.T) {
|
||||
resultExpected := []netstorage.Result{r1, r2}
|
||||
f(q, resultExpected)
|
||||
})
|
||||
t.Run(`vector + vector fill()`, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
q := `sort_by_label((
|
||||
label_set(1, "foo", "common")
|
||||
or label_set(2, "foo", "left_only")
|
||||
) + fill(0) (
|
||||
label_set(3, "foo", "common")
|
||||
or label_set(4, "foo", "right_only")
|
||||
), "foo")`
|
||||
r1 := netstorage.Result{
|
||||
MetricName: metricNameExpected,
|
||||
Values: []float64{4, 4, 4, 4, 4, 4},
|
||||
Timestamps: timestampsExpected,
|
||||
}
|
||||
r1.MetricName.Tags = []storage.Tag{{
|
||||
Key: []byte("foo"),
|
||||
Value: []byte("common"),
|
||||
}}
|
||||
r2 := netstorage.Result{
|
||||
MetricName: metricNameExpected,
|
||||
Values: []float64{2, 2, 2, 2, 2, 2},
|
||||
Timestamps: timestampsExpected,
|
||||
}
|
||||
r2.MetricName.Tags = []storage.Tag{{
|
||||
Key: []byte("foo"),
|
||||
Value: []byte("left_only"),
|
||||
}}
|
||||
r3 := netstorage.Result{
|
||||
MetricName: metricNameExpected,
|
||||
Values: []float64{4, 4, 4, 4, 4, 4},
|
||||
Timestamps: timestampsExpected,
|
||||
}
|
||||
r3.MetricName.Tags = []storage.Tag{{
|
||||
Key: []byte("foo"),
|
||||
Value: []byte("right_only"),
|
||||
}}
|
||||
resultExpected := []netstorage.Result{r1, r2, r3}
|
||||
f(q, resultExpected)
|
||||
})
|
||||
t.Run(`vector + vector fill() both sides NaN case`, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
q := `(
|
||||
label_set(time() <= 1200, "foo", "common")
|
||||
) + fill(10) (
|
||||
label_set(time() >= 1600, "foo", "common")
|
||||
)`
|
||||
r := netstorage.Result{
|
||||
MetricName: metricNameExpected,
|
||||
Values: []float64{1010, 1210, nan, 1610, 1810, 2010},
|
||||
Timestamps: timestampsExpected,
|
||||
}
|
||||
r.MetricName.Tags = []storage.Tag{{
|
||||
Key: []byte("foo"),
|
||||
Value: []byte("common"),
|
||||
}}
|
||||
resultExpected := []netstorage.Result{r}
|
||||
f(q, resultExpected)
|
||||
})
|
||||
t.Run(`vector + vector fill_left() fill_right()`, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
q := `sort_by_label((
|
||||
label_set(1, "foo", "common")
|
||||
or label_set(2, "foo", "left_only")
|
||||
) + fill_left(10) fill_right(20) (
|
||||
label_set(3, "foo", "common")
|
||||
or label_set(4, "foo", "right_only")
|
||||
), "foo")`
|
||||
r1 := netstorage.Result{
|
||||
MetricName: metricNameExpected,
|
||||
Values: []float64{4, 4, 4, 4, 4, 4},
|
||||
Timestamps: timestampsExpected,
|
||||
}
|
||||
r1.MetricName.Tags = []storage.Tag{{
|
||||
Key: []byte("foo"),
|
||||
Value: []byte("common"),
|
||||
}}
|
||||
r2 := netstorage.Result{
|
||||
MetricName: metricNameExpected,
|
||||
Values: []float64{22, 22, 22, 22, 22, 22},
|
||||
Timestamps: timestampsExpected,
|
||||
}
|
||||
r2.MetricName.Tags = []storage.Tag{{
|
||||
Key: []byte("foo"),
|
||||
Value: []byte("left_only"),
|
||||
}}
|
||||
r3 := netstorage.Result{
|
||||
MetricName: metricNameExpected,
|
||||
Values: []float64{14, 14, 14, 14, 14, 14},
|
||||
Timestamps: timestampsExpected,
|
||||
}
|
||||
r3.MetricName.Tags = []storage.Tag{{
|
||||
Key: []byte("foo"),
|
||||
Value: []byte("right_only"),
|
||||
}}
|
||||
resultExpected := []netstorage.Result{r1, r2, r3}
|
||||
f(q, resultExpected)
|
||||
})
|
||||
t.Run(`vector + vector fill_right() only`, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
q := `sort_by_label((
|
||||
label_set(1, "foo", "common")
|
||||
or label_set(2, "foo", "left_only")
|
||||
) + fill_right(20) (
|
||||
label_set(3, "foo", "common")
|
||||
or label_set(4, "foo", "right_only")
|
||||
), "foo")`
|
||||
r1 := netstorage.Result{
|
||||
MetricName: metricNameExpected,
|
||||
Values: []float64{4, 4, 4, 4, 4, 4},
|
||||
Timestamps: timestampsExpected,
|
||||
}
|
||||
r1.MetricName.Tags = []storage.Tag{{
|
||||
Key: []byte("foo"),
|
||||
Value: []byte("common"),
|
||||
}}
|
||||
r2 := netstorage.Result{
|
||||
MetricName: metricNameExpected,
|
||||
Values: []float64{22, 22, 22, 22, 22, 22},
|
||||
Timestamps: timestampsExpected,
|
||||
}
|
||||
r2.MetricName.Tags = []storage.Tag{{
|
||||
Key: []byte("foo"),
|
||||
Value: []byte("left_only"),
|
||||
}}
|
||||
resultExpected := []netstorage.Result{r1, r2}
|
||||
f(q, resultExpected)
|
||||
})
|
||||
t.Run(`vector + vector on() fill()`, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
q := `sort_by_label((
|
||||
label_set(1, "foo", "common", "extra", "l")
|
||||
or label_set(2, "foo", "left_only", "extra", "l")
|
||||
) + on(foo) fill(0) (
|
||||
label_set(3, "foo", "common", "extra", "r")
|
||||
or label_set(4, "foo", "right_only", "extra", "r")
|
||||
), "foo")`
|
||||
r1 := netstorage.Result{
|
||||
MetricName: metricNameExpected,
|
||||
Values: []float64{4, 4, 4, 4, 4, 4},
|
||||
Timestamps: timestampsExpected,
|
||||
}
|
||||
r1.MetricName.Tags = []storage.Tag{{
|
||||
Key: []byte("foo"),
|
||||
Value: []byte("common"),
|
||||
}}
|
||||
r2 := netstorage.Result{
|
||||
MetricName: metricNameExpected,
|
||||
Values: []float64{2, 2, 2, 2, 2, 2},
|
||||
Timestamps: timestampsExpected,
|
||||
}
|
||||
r2.MetricName.Tags = []storage.Tag{{
|
||||
Key: []byte("foo"),
|
||||
Value: []byte("left_only"),
|
||||
}}
|
||||
r3 := netstorage.Result{
|
||||
MetricName: metricNameExpected,
|
||||
Values: []float64{4, 4, 4, 4, 4, 4},
|
||||
Timestamps: timestampsExpected,
|
||||
}
|
||||
r3.MetricName.Tags = []storage.Tag{{
|
||||
Key: []byte("foo"),
|
||||
Value: []byte("right_only"),
|
||||
}}
|
||||
resultExpected := []netstorage.Result{r1, r2, r3}
|
||||
f(q, resultExpected)
|
||||
})
|
||||
t.Run(`vector + vector on() group_left() fill_right()`, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
q := `sort_by_label((
|
||||
label_set(1, "method", "get", "code", "500")
|
||||
or label_set(2, "method", "get", "code", "404")
|
||||
or label_set(3, "method", "put", "code", "501")
|
||||
) + on(method) group_left() fill_right(0) (
|
||||
label_set(10, "method", "get")
|
||||
), "method", "code")`
|
||||
r1 := netstorage.Result{
|
||||
MetricName: metricNameExpected,
|
||||
Values: []float64{12, 12, 12, 12, 12, 12},
|
||||
Timestamps: timestampsExpected,
|
||||
}
|
||||
r1.MetricName.Tags = []storage.Tag{
|
||||
{
|
||||
Key: []byte("code"),
|
||||
Value: []byte("404"),
|
||||
},
|
||||
{
|
||||
Key: []byte("method"),
|
||||
Value: []byte("get"),
|
||||
},
|
||||
}
|
||||
r2 := netstorage.Result{
|
||||
MetricName: metricNameExpected,
|
||||
Values: []float64{11, 11, 11, 11, 11, 11},
|
||||
Timestamps: timestampsExpected,
|
||||
}
|
||||
r2.MetricName.Tags = []storage.Tag{
|
||||
{
|
||||
Key: []byte("code"),
|
||||
Value: []byte("500"),
|
||||
},
|
||||
{
|
||||
Key: []byte("method"),
|
||||
Value: []byte("get"),
|
||||
},
|
||||
}
|
||||
r3 := netstorage.Result{
|
||||
MetricName: metricNameExpected,
|
||||
Values: []float64{3, 3, 3, 3, 3, 3},
|
||||
Timestamps: timestampsExpected,
|
||||
}
|
||||
r3.MetricName.Tags = []storage.Tag{
|
||||
{
|
||||
Key: []byte("code"),
|
||||
Value: []byte("501"),
|
||||
},
|
||||
{
|
||||
Key: []byte("method"),
|
||||
Value: []byte("put"),
|
||||
},
|
||||
}
|
||||
resultExpected := []netstorage.Result{r1, r2, r3}
|
||||
f(q, resultExpected)
|
||||
})
|
||||
t.Run(`vector / vector ignoring() fill()`, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
q := `sort_by_label((
|
||||
label_set(6, "method", "get", "code", "500")
|
||||
or label_set(1, "method", "put", "code", "500")
|
||||
) / ignoring(code) fill(0) (
|
||||
label_set(12, "method", "get")
|
||||
or label_set(5, "method", "post")
|
||||
or label_set(10, "method", "put")
|
||||
), "method")`
|
||||
r1 := netstorage.Result{
|
||||
MetricName: metricNameExpected,
|
||||
Values: []float64{0.5, 0.5, 0.5, 0.5, 0.5, 0.5},
|
||||
Timestamps: timestampsExpected,
|
||||
}
|
||||
r1.MetricName.Tags = []storage.Tag{
|
||||
{
|
||||
Key: []byte("method"),
|
||||
Value: []byte("get"),
|
||||
},
|
||||
}
|
||||
r2 := netstorage.Result{
|
||||
MetricName: metricNameExpected,
|
||||
Values: []float64{0, 0, 0, 0, 0, 0},
|
||||
Timestamps: timestampsExpected,
|
||||
}
|
||||
r2.MetricName.Tags = []storage.Tag{
|
||||
{
|
||||
Key: []byte("method"),
|
||||
Value: []byte("post"),
|
||||
},
|
||||
}
|
||||
r3 := netstorage.Result{
|
||||
MetricName: metricNameExpected,
|
||||
Values: []float64{0.1, 0.1, 0.1, 0.1, 0.1, 0.1},
|
||||
Timestamps: timestampsExpected,
|
||||
}
|
||||
r3.MetricName.Tags = []storage.Tag{
|
||||
{
|
||||
Key: []byte("method"),
|
||||
Value: []byte("put"),
|
||||
},
|
||||
}
|
||||
resultExpected := []netstorage.Result{r1, r2, r3}
|
||||
f(q, resultExpected)
|
||||
})
|
||||
t.Run(`histogram_quantile(scalar)`, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
q := `histogram_quantile(0.6, time())`
|
||||
|
||||
@@ -30,6 +30,11 @@ var (
|
||||
"See https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/#retention. See also -retentionFilter")
|
||||
futureRetention = flagutil.NewRetentionDuration("futureRetention", "2d", "Data with timestamps bigger than now+futureRetention is automatically deleted. "+
|
||||
"The minimum futureRetention is 2 days. See https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/#retention")
|
||||
maxBackfillAge = flagutil.NewRetentionDuration("maxBackfillAge", "0", "The maximum allowed age for the ingested samples with historical timestamps. "+
|
||||
"Samples with timestamps older than now-maxBackfillAge are rejected during data ingestion. "+
|
||||
"By default, or when set to 0, -maxBackfillAge equals to -retentionPeriod, e.g. it is unlimited within the configured retention. "+
|
||||
"This can be useful for limiting ingestion of historical samples, for example, when older data has been moved to another storage tier. "+
|
||||
"See https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/#retention")
|
||||
vmselectAddr = flag.String("vmselectAddr", "", "TCP address to accept connections from vmselect services")
|
||||
vmselectDisableRPCCompression = flag.Bool("rpc.disableCompression", false, "Whether to disable compression of the data sent from vmstorage to vmselect. "+
|
||||
"This reduces CPU usage at the cost of higher network bandwidth usage")
|
||||
@@ -146,6 +151,7 @@ func Init(vmselectMaxConcurrentRequests int, vmselectMaxQueueDuration time.Durat
|
||||
opts := storage.OpenOptions{
|
||||
Retention: retentionPeriod.Duration(),
|
||||
FutureRetention: futureRetention.Duration(),
|
||||
MaxBackfillAge: maxBackfillAge.Duration(),
|
||||
DenyQueriesOutsideRetention: *denyQueriesOutsideRetention,
|
||||
MaxHourlySeries: getMaxHourlySeries(),
|
||||
MaxDailySeries: getMaxDailySeries(),
|
||||
@@ -467,8 +473,10 @@ func (vms *VMStorage) writeStorageMetrics(w io.Writer) {
|
||||
metrics.WriteGaugeUint64(w, `vm_data_size_bytes{type="storage/inmemory"}`, tm.InmemorySizeBytes)
|
||||
metrics.WriteGaugeUint64(w, `vm_data_size_bytes{type="storage/small"}`, tm.SmallSizeBytes)
|
||||
metrics.WriteGaugeUint64(w, `vm_data_size_bytes{type="storage/big"}`, tm.BigSizeBytes)
|
||||
metrics.WriteGaugeUint64(w, `vm_data_size_bytes{type="storage/metaindex"}`, tm.MetaindexSizeBytes)
|
||||
metrics.WriteGaugeUint64(w, `vm_data_size_bytes{type="indexdb/inmemory"}`, idbm.InmemorySizeBytes)
|
||||
metrics.WriteGaugeUint64(w, `vm_data_size_bytes{type="indexdb/file"}`, idbm.FileSizeBytes)
|
||||
metrics.WriteGaugeUint64(w, `vm_data_size_bytes{type="indexdb/metaindex"}`, idbm.MetaindexSizeBytes)
|
||||
|
||||
metrics.WriteCounterUint64(w, `vm_rows_received_by_storage_total`, m.RowsReceivedTotal)
|
||||
metrics.WriteCounterUint64(w, `vm_rows_added_to_storage_total`, m.RowsAddedTotal)
|
||||
|
||||
@@ -17,10 +17,12 @@ interface HeaderNavProps {
|
||||
const HeaderNav: FC<HeaderNavProps> = ({ color, background, direction }) => {
|
||||
const { pathname } = useLocation();
|
||||
const [activeMenu, setActiveMenu] = useState(pathname);
|
||||
const [openMenu, setOpenMenu] = useState<string | null>(null);
|
||||
const menu = useNavigationMenu();
|
||||
|
||||
useEffect(() => {
|
||||
setActiveMenu(pathname);
|
||||
setOpenMenu(null);
|
||||
}, [pathname]);
|
||||
|
||||
return (
|
||||
@@ -41,6 +43,8 @@ const HeaderNav: FC<HeaderNavProps> = ({ color, background, direction }) => {
|
||||
color={color}
|
||||
background={background}
|
||||
direction={direction}
|
||||
openMenu={openMenu}
|
||||
setOpenMenu={setOpenMenu}
|
||||
/>
|
||||
)
|
||||
: (
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
import { FC, useRef, useState } from "preact/compat";
|
||||
import { useLocation } from "react-router-dom";
|
||||
import { FC, useRef, useState, Dispatch, SetStateAction } from "preact/compat";
|
||||
import classNames from "classnames";
|
||||
import { ArrowDropDownIcon } from "../../../components/Main/Icons";
|
||||
import Popper from "../../../components/Main/Popper/Popper";
|
||||
import NavItem from "./NavItem";
|
||||
import { useEffect } from "react";
|
||||
import useBoolean from "../../../hooks/useBoolean";
|
||||
import { NavigationItem, NavigationItemType } from "../../../router/navigation";
|
||||
|
||||
interface NavItemProps {
|
||||
@@ -15,6 +12,8 @@ interface NavItemProps {
|
||||
color?: string
|
||||
background?: string
|
||||
direction?: "row" | "column"
|
||||
openMenu: string | null,
|
||||
setOpenMenu: Dispatch<SetStateAction<string | null>>,
|
||||
}
|
||||
|
||||
const NavSubItem: FC<NavItemProps> = ({
|
||||
@@ -23,21 +22,18 @@ const NavSubItem: FC<NavItemProps> = ({
|
||||
color,
|
||||
background,
|
||||
submenu,
|
||||
direction = "row"
|
||||
direction = "row",
|
||||
openMenu,
|
||||
setOpenMenu,
|
||||
}) => {
|
||||
const { pathname } = useLocation();
|
||||
|
||||
const [menuTimeout, setMenuTimeout] = useState<NodeJS.Timeout | null>(null);
|
||||
const buttonRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const {
|
||||
value: openSubmenu,
|
||||
setFalse: handleCloseSubmenu,
|
||||
setTrue: setOpenSubmenu,
|
||||
} = useBoolean(false);
|
||||
const openSubmenu = openMenu === label;
|
||||
const handleCloseSubmenu = () => setOpenMenu(prev => (prev === label ? null : prev));
|
||||
|
||||
const handleOpenSubmenu = () => {
|
||||
if (direction === "row" || !openSubmenu) setOpenSubmenu();
|
||||
if (direction === "row" || !openSubmenu) setOpenMenu(label);
|
||||
if (direction === "column" && openSubmenu) handleCloseSubmenu();
|
||||
if (direction === "row" && menuTimeout) clearTimeout(menuTimeout);
|
||||
};
|
||||
@@ -52,10 +48,6 @@ const NavSubItem: FC<NavItemProps> = ({
|
||||
if (menuTimeout) clearTimeout(menuTimeout);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
handleCloseSubmenu();
|
||||
}, [pathname]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classNames({
|
||||
|
||||
222
apptest/tests/max_backfill_age_test.go
Normal file
222
apptest/tests/max_backfill_age_test.go
Normal file
@@ -0,0 +1,222 @@
|
||||
package tests
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/apptest"
|
||||
)
|
||||
|
||||
func TestSingleMaxBackfillAge(t *testing.T) {
|
||||
tc := apptest.NewTestCase(t)
|
||||
defer tc.Stop()
|
||||
|
||||
opts := maxBackfillAgeOpts{
|
||||
start: func(retentionPeriod, maxBackfillAge string) apptest.PrometheusWriteQuerier {
|
||||
return tc.MustStartVmsingle("vmsingle", []string{
|
||||
"-storageDataPath=" + filepath.Join(tc.Dir(), "vmsingle"),
|
||||
"-retentionPeriod=" + retentionPeriod,
|
||||
"-maxBackfillAge=" + maxBackfillAge,
|
||||
})
|
||||
},
|
||||
stop: func() {
|
||||
tc.StopApp("vmsingle")
|
||||
},
|
||||
}
|
||||
|
||||
testMaxBackfillAge(tc, opts)
|
||||
}
|
||||
|
||||
func TestClusterMaxBackfillAge(t *testing.T) {
|
||||
tc := apptest.NewTestCase(t)
|
||||
defer tc.Stop()
|
||||
|
||||
opts := maxBackfillAgeOpts{
|
||||
start: func(retentionPeriod, maxBackfillAge string) apptest.PrometheusWriteQuerier {
|
||||
return tc.MustStartCluster(&apptest.ClusterOptions{
|
||||
Vmstorage1Instance: "vmstorage1",
|
||||
Vmstorage1Flags: []string{
|
||||
"-storageDataPath=" + filepath.Join(tc.Dir(), "vmstorage1"),
|
||||
"-retentionPeriod=" + retentionPeriod,
|
||||
"-maxBackfillAge=" + maxBackfillAge,
|
||||
},
|
||||
Vmstorage2Instance: "vmstorage2",
|
||||
Vmstorage2Flags: []string{
|
||||
"-storageDataPath=" + filepath.Join(tc.Dir(), "vmstorage2"),
|
||||
"-retentionPeriod=" + retentionPeriod,
|
||||
"-maxBackfillAge=" + maxBackfillAge,
|
||||
},
|
||||
VminsertInstance: "vminsert",
|
||||
VminsertFlags: []string{},
|
||||
VmselectInstance: "vmselect",
|
||||
VmselectFlags: []string{},
|
||||
})
|
||||
},
|
||||
stop: func() {
|
||||
tc.StopApp("vminsert")
|
||||
tc.StopApp("vmselect")
|
||||
tc.StopApp("vmstorage1")
|
||||
tc.StopApp("vmstorage2")
|
||||
},
|
||||
}
|
||||
|
||||
testMaxBackfillAge(tc, opts)
|
||||
}
|
||||
|
||||
type maxBackfillAgeOpts struct {
|
||||
start func(retentionPeriod, maxBackfillAge string) apptest.PrometheusWriteQuerier
|
||||
stop func()
|
||||
}
|
||||
|
||||
func testMaxBackfillAge(tc *apptest.TestCase, opts maxBackfillAgeOpts) {
|
||||
t := tc.T()
|
||||
|
||||
assertSeries := func(app apptest.PrometheusQuerier, prefix string, start, end int64, want []map[string]string) {
|
||||
t.Helper()
|
||||
|
||||
query := fmt.Sprintf(`{__name__=~"metric_%s.*"}`, prefix)
|
||||
tc.Assert(&apptest.AssertOptions{
|
||||
Msg: "unexpected /api/v1/series response",
|
||||
Got: func() any {
|
||||
return app.PrometheusAPIV1Series(t, query, apptest.QueryOpts{
|
||||
Start: fmt.Sprintf("%d", start),
|
||||
End: fmt.Sprintf("%d", end),
|
||||
}).Sort()
|
||||
},
|
||||
Want: &apptest.PrometheusAPIV1SeriesResponse{
|
||||
Status: "success",
|
||||
Data: want,
|
||||
},
|
||||
FailNow: true,
|
||||
})
|
||||
}
|
||||
|
||||
assertQueryResults := func(app apptest.PrometheusQuerier, prefix string, start, end, step int64, want []*apptest.QueryResult) {
|
||||
t.Helper()
|
||||
|
||||
query := fmt.Sprintf(`{__name__=~"metric_%s.*"}`, prefix)
|
||||
tc.Assert(&apptest.AssertOptions{
|
||||
Msg: "unexpected /api/v1/query_range response",
|
||||
Got: func() any {
|
||||
return app.PrometheusAPIV1QueryRange(t, query, apptest.QueryOpts{
|
||||
Start: fmt.Sprintf("%d", start),
|
||||
End: fmt.Sprintf("%d", end),
|
||||
Step: fmt.Sprintf("%dms", step),
|
||||
MaxLookback: fmt.Sprintf("%dms", step-1),
|
||||
NoCache: "1",
|
||||
})
|
||||
},
|
||||
Want: &apptest.PrometheusAPIV1QueryResponse{
|
||||
Status: "success",
|
||||
Data: &apptest.QueryData{
|
||||
ResultType: "matrix",
|
||||
Result: want,
|
||||
},
|
||||
},
|
||||
FailNow: true,
|
||||
})
|
||||
}
|
||||
|
||||
const numMetrics = 1000
|
||||
now := time.Now().UTC()
|
||||
var start, end, step int64
|
||||
emptySeries := []map[string]string{}
|
||||
emptyQueryResults := []*apptest.QueryResult{}
|
||||
|
||||
// Start sut with the same -retentionPeriod and -maxBackfillAge.
|
||||
sut := opts.start("1y", "1y")
|
||||
|
||||
// Verify that samples older than the retention period are rejected.
|
||||
start = now.Add(-365 * 24 * time.Hour).Add(-time.Hour).UnixMilli()
|
||||
end = now.Add(-365 * 24 * time.Hour).UnixMilli()
|
||||
step = (end - start) / numMetrics
|
||||
outsideRetention := genMaxBackfillAgeData("outside_retention", numMetrics, start, step)
|
||||
sut.PrometheusAPIV1ImportPrometheus(t, outsideRetention.samples, apptest.QueryOpts{})
|
||||
sut.ForceFlush(t)
|
||||
assertSeries(sut, "outside_retention", start, end, emptySeries)
|
||||
assertQueryResults(sut, "outside_retention", start, end, step, emptyQueryResults)
|
||||
|
||||
// Verify that samples within the retention period are accepted and
|
||||
// searcheable.
|
||||
start = now.Add(-365 * 24 * time.Hour).Add(time.Hour).UnixMilli()
|
||||
end = now.Add(-365 * 24 * time.Hour).Add(2 * time.Hour).UnixMilli()
|
||||
step = (end - start) / numMetrics
|
||||
insideRetention := genMaxBackfillAgeData("inside_retention", numMetrics, start, step)
|
||||
sut.PrometheusAPIV1ImportPrometheus(t, insideRetention.samples, apptest.QueryOpts{})
|
||||
sut.ForceFlush(t)
|
||||
assertSeries(sut, "inside_retention", start, end, insideRetention.wantSeries)
|
||||
assertQueryResults(sut, "inside_retention", start, end, step, insideRetention.wantQueryResults)
|
||||
|
||||
// Restart sut with -maxBackfillAge shorter than the -retentionPeriod.
|
||||
opts.stop()
|
||||
sut = opts.start("1y", "6M")
|
||||
|
||||
// Verify that new samples older than max backfill age but still within the
|
||||
// retention period are rejected but existing samples are still searcheable.
|
||||
start = now.Add(-365 * 24 * time.Hour).Add(time.Hour).UnixMilli()
|
||||
end = now.Add(-365 * 24 * time.Hour).Add(2 * time.Hour).UnixMilli()
|
||||
step = (end - start) / numMetrics
|
||||
insideRetention2 := genMaxBackfillAgeData("inside_retention2", numMetrics, start, step)
|
||||
sut.PrometheusAPIV1ImportPrometheus(t, insideRetention2.samples, apptest.QueryOpts{})
|
||||
sut.ForceFlush(t)
|
||||
assertSeries(sut, "inside_retention2", start, end, emptySeries)
|
||||
assertQueryResults(sut, "inside_retention2", start, end, step, emptyQueryResults)
|
||||
assertSeries(sut, "inside_retention", start, end, insideRetention.wantSeries)
|
||||
assertQueryResults(sut, "inside_retention", start, end, step, insideRetention.wantQueryResults)
|
||||
|
||||
// Verify that the metrics that are outside the backfill window can still
|
||||
// be deleted.
|
||||
sut.PrometheusAPIV1AdminTSDBDeleteSeries(t, `{__name__=~".*inside_retention.*"}`, apptest.QueryOpts{})
|
||||
sut.ForceFlush(t)
|
||||
assertSeries(sut, "inside_retention", start, end, emptySeries)
|
||||
assertQueryResults(sut, "inside_retention", start, end, step, emptyQueryResults)
|
||||
|
||||
// Verify that the samples that are within the backfill window are accepted
|
||||
// and searchable.
|
||||
start = now.Add(-180 * 24 * time.Hour).UnixMilli()
|
||||
end = now.Add(-180 * 24 * time.Hour).Add(1 * time.Hour).UnixMilli()
|
||||
step = (end - start) / numMetrics
|
||||
insideMaxBackfillAge := genMaxBackfillAgeData("inside_max_backfill_age", numMetrics, start, step)
|
||||
sut.PrometheusAPIV1ImportPrometheus(t, insideMaxBackfillAge.samples, apptest.QueryOpts{})
|
||||
sut.ForceFlush(t)
|
||||
assertSeries(sut, "inside_max_backfill_age", start, end, insideMaxBackfillAge.wantSeries)
|
||||
assertQueryResults(sut, "inside_max_backfill_age", start, end, step, insideMaxBackfillAge.wantQueryResults)
|
||||
|
||||
opts.stop()
|
||||
}
|
||||
|
||||
type maxBackfillAgeData struct {
|
||||
samples []string
|
||||
wantSeries []map[string]string
|
||||
wantQueryResults []*apptest.QueryResult
|
||||
}
|
||||
|
||||
func genMaxBackfillAgeData(prefix string, numMetrics, start, step int64) maxBackfillAgeData {
|
||||
samples := make([]string, numMetrics)
|
||||
wantSeries := make([]map[string]string, numMetrics)
|
||||
wantQueryResults := make([]*apptest.QueryResult, numMetrics)
|
||||
for i := range numMetrics {
|
||||
metricName := fmt.Sprintf("metric_%s_%04d", prefix, i)
|
||||
labelName := fmt.Sprintf("label_%s_%04d", prefix, i)
|
||||
labelValue := fmt.Sprintf("value_%s_%04d", prefix, i)
|
||||
value := i
|
||||
timestamp := start + i*step
|
||||
samples[i] = fmt.Sprintf(`%s{%s="value", label="%s"} %d %d`, metricName, labelName, labelValue, value, timestamp)
|
||||
wantSeries[i] = map[string]string{
|
||||
"__name__": metricName,
|
||||
labelName: "value",
|
||||
"label": labelValue,
|
||||
}
|
||||
wantQueryResults[i] = &apptest.QueryResult{
|
||||
Metric: map[string]string{
|
||||
"__name__": metricName,
|
||||
labelName: "value",
|
||||
"label": labelValue,
|
||||
},
|
||||
Samples: []*apptest.Sample{{Timestamp: timestamp, Value: float64(value)}},
|
||||
}
|
||||
}
|
||||
return maxBackfillAgeData{samples, wantSeries, wantQueryResults}
|
||||
}
|
||||
@@ -114,6 +114,7 @@ See also [case studies](https://docs.victoriametrics.com/victoriametrics/casestu
|
||||
* [QCon London 2026: Wrangling Telemetry at Scale, a Guide to Self-Hosted Observability](https://www.infoq.com/news/2026/03/self-hosted-observability/)
|
||||
* [How We Made Telemetry Queries 10x Faster: Chunk-Split Caching for Metrics, Logs, and Traces](https://mirastacklabs.ai/blog/chunk-split-caching/)
|
||||
* [Claude Code: creating Kubernetes debugging AI Agent for VictoriaMetrics](https://rtfm.co.ua/en/claude-code-creating-kubernetes-debugging-ai-agent-for-victoriametrics/)
|
||||
* [OpenTelemetry: OTel Collectors in Kubernetes and VictoriaMetrics Stack integration](https://itnext.io/opentelemetry-otel-collectors-in-kubernetes-and-victoriametrics-stack-integration-d907ed0a15a0)
|
||||
|
||||
## Third-party articles and slides about VictoriaLogs
|
||||
|
||||
|
||||
@@ -403,6 +403,9 @@ Resources:
|
||||
* [Cardinality explorer blog post](https://victoriametrics.com/blog/cardinality-explorer/).
|
||||
* [skills/victoriametrics-cardinality-analysis](https://github.com/VictoriaMetrics/skills/blob/main/plugins/diagnostics/skills/victoriametrics-cardinality-analysis/SKILL.md) for [agent-assisted](https://docs.victoriametrics.com/ai-tools/#agent-skills) analysis.
|
||||
|
||||
For monitoring or alerting on cardinality, use [vmestimator](https://docs.victoriametrics.com/victoriametrics/vmestimator/).
|
||||
vmestimator measures metrics cardinality across [arbitrary label dimensions](https://docs.victoriametrics.com/victoriametrics/vmestimator/#basic) in real time and exposes the [results as metrics](https://docs.victoriametrics.com/victoriametrics/vmestimator/#cardinality-metrics).
|
||||
|
||||
### Cardinality explorer statistic inaccuracy
|
||||
|
||||
In [cluster version of VictoriaMetrics](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/) each vmstorage tracks the stored time series individually.
|
||||
@@ -1548,6 +1551,18 @@ For example, the following command starts VictoriaMetrics, which accepts samples
|
||||
/path/to/victoria-metrics -futureRetention=1y
|
||||
```
|
||||
|
||||
By default, VictoriaMetrics accepts samples with timestamps as old as the configured `-retentionPeriod` allows, e.g. it accepts backfilled
|
||||
historical data as long as it fits into the retention. If you need rejecting samples with historical timestamps older than the specified
|
||||
duration, then specify the desired duration via the `-maxBackfillAge` command-line flag. This can be useful for limiting ingestion of
|
||||
historical samples, for example, when older data has been moved to another storage tier (nvme/hdd, hot/cold).
|
||||
`-maxBackfillAge` cannot exceed the configured `-retentionPeriod` - bigger values are automatically clamped to `-retentionPeriod`.
|
||||
|
||||
For example, the following command starts VictoriaMetrics, which rejects ingested samples with timestamps older than 2 days:
|
||||
|
||||
```sh
|
||||
/path/to/victoria-metrics -maxBackfillAge=2d
|
||||
```
|
||||
|
||||
### Multiple retentions
|
||||
|
||||
Distinct retentions for distinct time series can be configured via [retention filters](#retention-filters)
|
||||
|
||||
@@ -25,8 +25,18 @@ The sandbox cluster installation runs under the constant load generated by
|
||||
See also [LTS releases](https://docs.victoriametrics.com/victoriametrics/lts-releases/).
|
||||
|
||||
## tip
|
||||
* BUGFIX: [vmagent](https://docs.victoriametrics.com/victoriametrics/vmagent/): flush pending persistent queue data to chunk file before updating the metadata. This prevents the metadata writer offset from getting ahead of the chunk file size and avoids losing the persistent queue after an unclean shutdown. See [#11192](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/11192).
|
||||
|
||||
* FEATURE: [MetricsQL](https://docs.victoriametrics.com/victoriametrics/metricsql/): support `fill` modifiers to allow missing series on either side of a binary operation to be filled with a provided default value. See [#10598](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/10598).
|
||||
* FEATURE: [vmagent](https://docs.victoriametrics.com/victoriametrics/vmagent/) and [vmsingle](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/): Improve background discovery performance for [http_sd](https://docs.victoriametrics.com/victoriametrics/sd_configs/#http_sd_configs) discovery. See [#8838](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/8838).
|
||||
* FEATURE: [vmagent](https://docs.victoriametrics.com/victoriametrics/vmagent/) and [vmsingle](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/): allow overriding `max_scrape_size` on a per-target basis via the `__max_scrape_size__` label during target relabeling. See [#11188](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/11188).
|
||||
* FEATURE: [vmstorage](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/) and [vmsingle](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/): add `-maxBackfillAge` command-line flag for limiting ingestion of samples with historical timestamps, for example, when older data has been moved between storage tiers (nvme/hdd, hot/cold). See [#11199](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/11199). Thanks to @AshwinRamaniPsg for contribution.
|
||||
|
||||
* BUGFIX: `vminsert` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/): Now drops metadata blocks when communicating with vmstorage nodes over the legacy RPC protocol. To avoid this limitation, upgrade `vmstorage` to a version that supports the new RPC protocol (>= [v1.137.0](https://github.com/VictoriaMetrics/VictoriaMetrics/blob/master/docs/victoriametrics/changelog/CHANGELOG.md#v11370)). See [#11146](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/11146).
|
||||
* BUGFIX: [vmbackup](https://docs.victoriametrics.com/victoriametrics/vmbackup/) and [vmbackupmanager](https://docs.victoriametrics.com/victoriametrics/vmbackupmanager/): retry S3 requests failing with `HTTP 429` status code or `TooManyRequests` error code. Previously such requests were not retried, so a short burst of rate limiting would fail the whole backup. See [#11218](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/11218). Thanks to @gautamrizwani for contribution.
|
||||
* BUGFIX: `vmselect` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/): properly apply limit to metrics metadata response. See [#11139](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/11139).
|
||||
* BUGFIX: [vmui](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/#vmui): keep only one header navigation dropdown (`Explore`, `Tools`) open at a time. Previously, hovering across two dropdowns could briefly leave both open due to the close delay. See [#11224](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/11224). Thanks to @antedotee for contribution.
|
||||
* BUGFIX: [vmagent](https://docs.victoriametrics.com/victoriametrics/vmagent/): fix a possible data race when processing OpenTelemetry metadata. See [#11238](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/11238). Thanks to @nevgeny for contribution.
|
||||
|
||||
## [v1.147.0](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.147.0)
|
||||
|
||||
@@ -38,6 +48,7 @@ Released at 2026-07-06
|
||||
* FEATURE: [vmagent](https://docs.victoriametrics.com/victoriametrics/vmagent/): reduces CPU usage by 10% at [sharding among remote storages](https://docs.victoriametrics.com/victoriametrics/vmagent/#sharding-among-remote-storages). See [#11113](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/11113). Thanks to @bennf for contribution.
|
||||
* FEATURE: [vmagent](https://docs.victoriametrics.com/victoriametrics/vmagent/), `vminsert` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/) and [vmsingle](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/): introduce `64KiB` size limit for `metric metadata` fields - `Unit`, `Help` and `MetricFamilyName`. See [#11128](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/11128).
|
||||
* FEATURE: [vmagent](https://docs.victoriametrics.com/victoriametrics/vmagent/) and [vmsingle](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/): reduce CPU usage for storing scrape target labels. See [#10919](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/10919).
|
||||
* FEATURE: [vmsingle](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/) and `vmstorage` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/): expose `vm_data_size_bytes{type="storage/metaindex"}` and `vm_data_size_bytes{type="indexdb/metaindex"}` metrics for tracking memory occupied by metaindex data. See [#11204](https://github.com/VictoriaMetrics/VictoriaMetrics/pull/11204). Thanks to @SamarthBagga for contribution.
|
||||
* FEATURE: [vmsingle](https://docs.victoriametrics.com/victoriametrics/single-server-victoriametrics/) and `vmselect` in [VictoriaMetrics cluster](https://docs.victoriametrics.com/victoriametrics/cluster-victoriametrics/): add `optimize_repeated_binary_op_subexprs=1` query arg to [/api/v1/query_range](https://docs.victoriametrics.com/victoriametrics/keyconcepts/#range-query) for executing binary operator sides sequentially when they share the same optimized aggregate rollup result expression. This allows the second side to reuse rollup result cache populated by the first side. See [#10575](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/10575). Thanks to @xhebox for the contribution.
|
||||
* FEATURE: [vmauth](https://docs.victoriametrics.com/victoriametrics/vmauth/): prevent possible password brute-force attacks with an artificial 2-3 second delay as recommended by [OWASP](https://owasp.org/Top10/2025/A07_2025-Authentication_Failures). See [#11180](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/11180).
|
||||
* FEATURE: [alerts](https://github.com/VictoriaMetrics/VictoriaMetrics/blob/master/deployment/docker/rules): add `InvalidAuthTokenRequestErrors` alerting rule to [vmauth alerts](https://github.com/VictoriaMetrics/VictoriaMetrics/blob/master/deployment/docker/rules/alerts-vmauth.yml). The new rule notifies when vmauth receives requests with invalid or missing auth tokens, which may indicate a client misconfiguration, expired token use, or brute-force attack. See [#11180](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/11180).
|
||||
|
||||
@@ -1923,6 +1923,9 @@ scrape_configs:
|
||||
# Example values:
|
||||
# - "10MiB" - 10 * 1024 * 1024 bytes
|
||||
# - "100MB" - 100 * 1000 * 1000 bytes
|
||||
# The max_scrape_size can be set on a per-target basis by specifying `__max_scrape_size__`
|
||||
# label during target relabeling phase.
|
||||
# See https://docs.victoriametrics.com/victoriametrics/relabeling/
|
||||
#
|
||||
# max_scrape_size: <size>
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
4
go.mod
4
go.mod
@@ -11,7 +11,7 @@ require (
|
||||
github.com/VictoriaMetrics/easyproto v1.2.0
|
||||
github.com/VictoriaMetrics/fastcache v1.13.3
|
||||
github.com/VictoriaMetrics/metrics v1.44.0
|
||||
github.com/VictoriaMetrics/metricsql v0.87.2
|
||||
github.com/VictoriaMetrics/metricsql v0.87.3
|
||||
github.com/aws/aws-sdk-go-v2 v1.42.0
|
||||
github.com/aws/aws-sdk-go-v2/config v1.32.25
|
||||
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.22.27
|
||||
@@ -36,7 +36,7 @@ require (
|
||||
github.com/valyala/quicktemplate v1.8.0
|
||||
golang.org/x/net v0.56.0
|
||||
golang.org/x/oauth2 v0.36.0
|
||||
golang.org/x/sys v0.46.0
|
||||
golang.org/x/sys v0.47.0
|
||||
google.golang.org/api v0.284.0
|
||||
gopkg.in/yaml.v2 v2.4.0
|
||||
)
|
||||
|
||||
4
go.sum
4
go.sum
@@ -62,6 +62,8 @@ github.com/VictoriaMetrics/metrics v1.44.0 h1:Fr8yqQSV+ZfYaDD/anqk1E8e9YPgfleSle
|
||||
github.com/VictoriaMetrics/metrics v1.44.0/go.mod h1:xDM82ULLYCYdFRgQ2JBxi8Uf1+8En1So9YUwlGTOqTc=
|
||||
github.com/VictoriaMetrics/metricsql v0.87.2 h1:7OsrcDBWREWKqqpnFyIUEOM4FNv2qHvCoww2GYz3Tc0=
|
||||
github.com/VictoriaMetrics/metricsql v0.87.2/go.mod h1:d4EisFO6ONP/HIGDYTAtwrejJBBeKGQYiRl095bS4QQ=
|
||||
github.com/VictoriaMetrics/metricsql v0.87.3 h1:JU4JnVKSC5Vp3b4AvogXyOAjkz1iFF9n1KBMphS4WO8=
|
||||
github.com/VictoriaMetrics/metricsql v0.87.3/go.mod h1:d4EisFO6ONP/HIGDYTAtwrejJBBeKGQYiRl095bS4QQ=
|
||||
github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow=
|
||||
github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4=
|
||||
github.com/alecthomas/units v0.0.0-20240927000941-0f3dac36c52b h1:mimo19zliBX/vSQ6PWWSL9lK8qwHozUj03+zLoEB8O0=
|
||||
@@ -544,6 +546,8 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw=
|
||||
golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs=
|
||||
golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
|
||||
golang.org/x/term v0.44.0 h1:0rLvDRCtNj0gZkyIXhCyOb2OAzEhLVqc4B+hrsBhrmc=
|
||||
golang.org/x/term v0.44.0/go.mod h1:7ze4MdzUzLXpSAoFP1H0bOI9aXDqveSvatT5vKcFh2Y=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
||||
@@ -164,6 +164,14 @@ func (fs *FS) Init(ctx context.Context) error {
|
||||
// when using EKS Pod Identity or similar.
|
||||
// See: https://github.com/VictoriaMetrics/VictoriaMetrics/issues/9280
|
||||
"ExpiredToken": {},
|
||||
// S3-compatible stores may return TooManyRequests instead of TooManyRequestsException.
|
||||
// See: https://github.com/VictoriaMetrics/VictoriaMetrics/issues/11218
|
||||
"TooManyRequests": {},
|
||||
},
|
||||
}, retry.RetryableHTTPStatusCode{
|
||||
Codes: map[int]struct{}{
|
||||
// S3-compatible stores may return HTTP 429 for rate limiting instead of HTTP 503.
|
||||
429: {},
|
||||
},
|
||||
}, retry.IsErrorRetryableFunc(func(err error) aws.Ternary {
|
||||
if errors.Is(err, io.ErrUnexpectedEOF) {
|
||||
|
||||
@@ -78,7 +78,8 @@ type part struct {
|
||||
|
||||
size uint64
|
||||
|
||||
mrs []metaindexRow
|
||||
mrs []metaindexRow
|
||||
metaindexSizeBytes uint64
|
||||
|
||||
indexFile fs.MustReadAtCloser
|
||||
itemsFile fs.MustReadAtCloser
|
||||
@@ -131,6 +132,7 @@ func newPart(ph *partHeader, path string, size uint64, metaindexReader filestrea
|
||||
p.path = path
|
||||
p.size = size
|
||||
p.mrs = mrs
|
||||
p.metaindexSizeBytes = metaindexSizeBytes(mrs)
|
||||
|
||||
p.indexFile = indexFile
|
||||
p.itemsFile = itemsFile
|
||||
@@ -155,6 +157,14 @@ func (p *part) MustClose() {
|
||||
ibSparseCache.RemoveBlocksForPart(p)
|
||||
}
|
||||
|
||||
func metaindexSizeBytes(mrs []metaindexRow) uint64 {
|
||||
n := uint64(cap(mrs)) * uint64(unsafe.Sizeof(metaindexRow{}))
|
||||
for i := range mrs {
|
||||
n += uint64(cap(mrs[i].firstItem))
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
type indexBlock struct {
|
||||
bhs []blockHeader
|
||||
|
||||
|
||||
@@ -584,6 +584,8 @@ type TableMetrics struct {
|
||||
PartsRefCount uint64
|
||||
|
||||
TooLongItemsDroppedTotal uint64
|
||||
|
||||
MetaindexSizeBytes uint64
|
||||
}
|
||||
|
||||
// TotalItemsCount returns the total number of items in the table.
|
||||
@@ -617,6 +619,7 @@ func (tb *Table) UpdateMetrics(m *TableMetrics) {
|
||||
m.InmemoryBlocksCount += p.ph.blocksCount
|
||||
m.InmemoryItemsCount += p.ph.itemsCount
|
||||
m.InmemorySizeBytes += p.size
|
||||
m.MetaindexSizeBytes += p.metaindexSizeBytes
|
||||
m.PartsRefCount += uint64(pw.refCount.Load())
|
||||
}
|
||||
|
||||
@@ -626,6 +629,7 @@ func (tb *Table) UpdateMetrics(m *TableMetrics) {
|
||||
m.FileBlocksCount += p.ph.blocksCount
|
||||
m.FileItemsCount += p.ph.itemsCount
|
||||
m.FileSizeBytes += p.size
|
||||
m.MetaindexSizeBytes += p.metaindexSizeBytes
|
||||
m.PartsRefCount += uint64(pw.refCount.Load())
|
||||
}
|
||||
tb.partsLock.Unlock()
|
||||
|
||||
@@ -52,6 +52,7 @@ type queue struct {
|
||||
writerFlushedOffset uint64
|
||||
|
||||
lastMetainfoFlushTime uint64
|
||||
hasDataToFlush bool
|
||||
|
||||
blocksDropped *metrics.Counter
|
||||
bytesDropped *metrics.Counter
|
||||
@@ -84,6 +85,7 @@ func (q *queue) mustResetFiles() {
|
||||
}
|
||||
q.reader.MustClose()
|
||||
q.writer.MustClose()
|
||||
q.hasDataToFlush = false
|
||||
fs.MustRemovePath(q.readerPath)
|
||||
|
||||
q.writerOffset = 0
|
||||
@@ -318,6 +320,7 @@ func tryOpeningQueue(path, name string, chunkFileSize, maxBlockSize, maxPendingB
|
||||
func (q *queue) MustClose() {
|
||||
// Close writer.
|
||||
q.writer.MustClose()
|
||||
q.hasDataToFlush = false
|
||||
q.writer = nil
|
||||
|
||||
// Close reader.
|
||||
@@ -414,7 +417,7 @@ func (q *queue) writeBlock(block []byte) error {
|
||||
}
|
||||
q.blocksWritten.Inc()
|
||||
q.bytesWritten.Add(len(block))
|
||||
return q.flushWriterMetainfoIfNeeded()
|
||||
return q.flushBufAndMetainfoIfNeeded()
|
||||
}
|
||||
|
||||
var writeDurationSeconds = metrics.NewFloatCounter(`vm_persistentqueue_write_duration_seconds_total`)
|
||||
@@ -422,6 +425,7 @@ var writeDurationSeconds = metrics.NewFloatCounter(`vm_persistentqueue_write_dur
|
||||
func (q *queue) nextChunkFileForWrite() error {
|
||||
// Finalize the current chunk and start new one.
|
||||
q.writer.MustClose()
|
||||
q.hasDataToFlush = false
|
||||
// There is no need to do fs.MustSyncPath(q.writerPath) here,
|
||||
// since MustClose already does this.
|
||||
if n := q.writerOffset % q.chunkFileSize; n > 0 {
|
||||
@@ -513,7 +517,7 @@ again:
|
||||
}
|
||||
q.blocksRead.Inc()
|
||||
q.bytesRead.Add(int(blockLen))
|
||||
if err := q.flushReaderMetainfoIfNeeded(); err != nil {
|
||||
if err := q.flushBufAndMetainfoIfNeeded(); err != nil {
|
||||
return dst, err
|
||||
}
|
||||
return dst, nil
|
||||
@@ -566,6 +570,7 @@ func (q *queue) write(buf []byte) error {
|
||||
}
|
||||
q.writerLocalOffset += bufLen
|
||||
q.writerOffset += bufLen
|
||||
q.hasDataToFlush = true
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -595,24 +600,16 @@ func (q *queue) checkReaderWriterOffsets() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (q *queue) flushReaderMetainfoIfNeeded() error {
|
||||
func (q *queue) flushBufAndMetainfoIfNeeded() error {
|
||||
t := fasttime.UnixTimestamp()
|
||||
if t == q.lastMetainfoFlushTime {
|
||||
return nil
|
||||
}
|
||||
if err := q.flushMetainfo(); err != nil {
|
||||
return fmt.Errorf("cannot flush metainfo: %w", err)
|
||||
if q.hasDataToFlush {
|
||||
q.writer.MustFlush(true)
|
||||
q.writerFlushedOffset = q.writerOffset
|
||||
q.hasDataToFlush = false
|
||||
}
|
||||
q.lastMetainfoFlushTime = t
|
||||
return nil
|
||||
}
|
||||
|
||||
func (q *queue) flushWriterMetainfoIfNeeded() error {
|
||||
t := fasttime.UnixTimestamp()
|
||||
if t == q.lastMetainfoFlushTime {
|
||||
return nil
|
||||
}
|
||||
q.writer.MustFlush(true)
|
||||
if err := q.flushMetainfo(); err != nil {
|
||||
return fmt.Errorf("cannot flush metainfo: %w", err)
|
||||
}
|
||||
|
||||
60
lib/persistentqueue/persistentqueue_synctest_test.go
Normal file
60
lib/persistentqueue/persistentqueue_synctest_test.go
Normal file
@@ -0,0 +1,60 @@
|
||||
//go:build synctest
|
||||
|
||||
package persistentqueue
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"testing/synctest"
|
||||
"time"
|
||||
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/encoding"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/fs"
|
||||
)
|
||||
|
||||
func TestFlushReaderMetainfoFlushesPendingWriterData(t *testing.T) {
|
||||
synctest.Test(t, func(t *testing.T) {
|
||||
path := "queue-flush-reader-metainfo"
|
||||
fs.MustRemoveDir(path)
|
||||
q := mustOpen(path, "foobar", 0)
|
||||
defer func() {
|
||||
q.MustClose()
|
||||
fs.MustRemoveDir(path)
|
||||
}()
|
||||
|
||||
block := []byte("foobar")
|
||||
data := encoding.MarshalUint64(nil, uint64(len(block)))
|
||||
data = append(data, block...)
|
||||
// it will call `flushBufAndMetainfoIfNeeded` internally to flush the data and metadata.
|
||||
err := q.writeBlock(data)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error when writing data to queue: %s", err)
|
||||
}
|
||||
// the second call will update the writeOffset in memory without flushing the data and metadata,
|
||||
// because the last flush was performed less than 1 second ago.
|
||||
err = q.writeBlock(data)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error when writing data to queue: %s", err)
|
||||
}
|
||||
time.Sleep(2 * time.Second)
|
||||
|
||||
// it will call `flushBufAndMetainfoIfNeeded` internally to flush the data and metadata.
|
||||
if _, err = q.readBlock(nil); err != nil {
|
||||
t.Fatalf("unexpected error when flushing reader metainfo: %s", err)
|
||||
}
|
||||
|
||||
if fileSize := fs.MustFileSize(q.writerPath); fileSize != q.writerOffset {
|
||||
t.Fatalf("unexpected writer file size after flushing reader metainfo; got %d bytes; want %d bytes", fileSize, q.writerOffset)
|
||||
}
|
||||
var mi metainfo
|
||||
if err := mi.ReadFromFile(q.metainfoPath()); err != nil {
|
||||
t.Fatalf("cannot read metainfo: %s", err)
|
||||
}
|
||||
if mi.ReaderOffset != q.readerOffset {
|
||||
t.Fatalf("unexpected ReaderOffset in metainfo; got %d; want %d", mi.ReaderOffset, q.readerOffset)
|
||||
}
|
||||
if mi.WriterOffset != q.writerOffset {
|
||||
t.Fatalf("unexpected WriterOffset in metainfo; got %d; want %d", mi.WriterOffset, q.writerOffset)
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
@@ -367,6 +367,9 @@ func (sc *ScrapeConfig) mustStart(baseDir string) {
|
||||
for i := range sc.KubernetesSDConfigs {
|
||||
sc.KubernetesSDConfigs[i].MustStart(baseDir, swosFunc)
|
||||
}
|
||||
for i := range sc.HTTPSDConfigs {
|
||||
sc.HTTPSDConfigs[i].MustStart(baseDir)
|
||||
}
|
||||
}
|
||||
|
||||
func (sc *ScrapeConfig) mustStop() {
|
||||
@@ -1271,6 +1274,17 @@ func (swc *scrapeWorkConfig) getScrapeWork(target string, extraLabels, metaLabel
|
||||
}
|
||||
scrapeTimeout = d
|
||||
}
|
||||
// Read max_scrape_size option from __max_scrape_size__ label.
|
||||
targetMaxScrapeSize := swc.maxScrapeSize
|
||||
if s := labels.Get("__max_scrape_size__"); len(s) > 0 {
|
||||
n, err := flagutil.ParseBytes(s)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot parse __max_scrape_size__=%q: %w", s, err)
|
||||
}
|
||||
if n > 0 {
|
||||
targetMaxScrapeSize = n
|
||||
}
|
||||
}
|
||||
// Read series_limit option from __series_limit__ label.
|
||||
// See https://docs.victoriametrics.com/victoriametrics/vmagent/#cardinality-limiter
|
||||
seriesLimit := swc.seriesLimit
|
||||
@@ -1333,7 +1347,7 @@ func (swc *scrapeWorkConfig) getScrapeWork(target string, extraLabels, metaLabel
|
||||
ScrapeURL: scrapeURL,
|
||||
ScrapeInterval: scrapeInterval,
|
||||
ScrapeTimeout: scrapeTimeout,
|
||||
MaxScrapeSize: swc.maxScrapeSize,
|
||||
MaxScrapeSize: targetMaxScrapeSize,
|
||||
HonorLabels: swc.honorLabels,
|
||||
HonorTimestamps: swc.honorTimestamps,
|
||||
DenyRedirects: swc.denyRedirects,
|
||||
|
||||
@@ -1153,6 +1153,57 @@ scrape_configs:
|
||||
})
|
||||
f(`
|
||||
scrape_configs:
|
||||
- job_name: foo
|
||||
max_scrape_size: 8MiB
|
||||
relabel_configs:
|
||||
- source_labels: [__address__]
|
||||
regex: foo1:.*
|
||||
target_label: __max_scrape_size__
|
||||
replacement: 2.5MiB
|
||||
- source_labels: [__address__]
|
||||
regex: foo2:.*
|
||||
target_label: __max_scrape_size__
|
||||
replacement: -1
|
||||
static_configs:
|
||||
- targets: ["foo1:1234", "foo2:1234", "foo3:1234"]
|
||||
`, []*ScrapeWork{
|
||||
{
|
||||
ScrapeURL: "http://foo1:1234/metrics",
|
||||
ScrapeInterval: defaultScrapeInterval,
|
||||
ScrapeTimeout: defaultScrapeTimeout,
|
||||
MaxScrapeSize: 2.5 * 1024 * 1024,
|
||||
Labels: promutil.NewLabelsFromMap(map[string]string{
|
||||
"instance": "foo1:1234",
|
||||
"job": "foo",
|
||||
}),
|
||||
jobNameOriginal: "foo",
|
||||
},
|
||||
// invalid __max_scrape_size__ will be ignored
|
||||
{
|
||||
ScrapeURL: "http://foo2:1234/metrics",
|
||||
ScrapeInterval: defaultScrapeInterval,
|
||||
ScrapeTimeout: defaultScrapeTimeout,
|
||||
MaxScrapeSize: 8 * 1024 * 1024,
|
||||
Labels: promutil.NewLabelsFromMap(map[string]string{
|
||||
"instance": "foo2:1234",
|
||||
"job": "foo",
|
||||
}),
|
||||
jobNameOriginal: "foo",
|
||||
},
|
||||
{
|
||||
ScrapeURL: "http://foo3:1234/metrics",
|
||||
ScrapeInterval: defaultScrapeInterval,
|
||||
ScrapeTimeout: defaultScrapeTimeout,
|
||||
MaxScrapeSize: 8 * 1024 * 1024,
|
||||
Labels: promutil.NewLabelsFromMap(map[string]string{
|
||||
"instance": "foo3:1234",
|
||||
"job": "foo",
|
||||
}),
|
||||
jobNameOriginal: "foo",
|
||||
},
|
||||
})
|
||||
f(`
|
||||
scrape_configs:
|
||||
- job_name: foo
|
||||
static_configs:
|
||||
- targets: ["foo.bar:1234"]
|
||||
|
||||
@@ -1,25 +1,41 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strconv"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/VictoriaMetrics/metrics"
|
||||
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutil"
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promutil"
|
||||
"github.com/VictoriaMetrics/metrics"
|
||||
)
|
||||
|
||||
var configMap = discoveryutil.NewConfigMap()
|
||||
|
||||
type apiConfig struct {
|
||||
client *discoveryutil.Client
|
||||
path string
|
||||
client *discoveryutil.Client
|
||||
path string
|
||||
sourceURL string
|
||||
checkInterval time.Duration
|
||||
|
||||
fetchErrors *metrics.Counter
|
||||
parseErrors *metrics.Counter
|
||||
|
||||
initOnce sync.Once
|
||||
prevAPIResponse atomic.Pointer[[]byte]
|
||||
targetLabels atomic.Pointer[targetLabelsResult]
|
||||
|
||||
wg sync.WaitGroup
|
||||
}
|
||||
|
||||
type targetLabelsResult struct {
|
||||
labels []*promutil.Labels
|
||||
err error
|
||||
}
|
||||
|
||||
// httpGroupTarget represent prometheus GroupTarget
|
||||
@@ -49,37 +65,89 @@ func newAPIConfig(sdc *SDConfig, baseDir string) (*apiConfig, error) {
|
||||
return nil, fmt.Errorf("cannot create HTTP client for %q: %w", apiServer, err)
|
||||
}
|
||||
cfg := &apiConfig{
|
||||
client: client,
|
||||
path: parsedURL.RequestURI(),
|
||||
fetchErrors: metrics.GetOrCreateCounter(fmt.Sprintf(`promscrape_discovery_http_errors_total{type="fetch",url=%q}`, sdc.URL)),
|
||||
parseErrors: metrics.GetOrCreateCounter(fmt.Sprintf(`promscrape_discovery_http_errors_total{type="parse",url=%q}`, sdc.URL)),
|
||||
client: client,
|
||||
path: parsedURL.RequestURI(),
|
||||
sourceURL: sdc.URL,
|
||||
checkInterval: max(*SDCheckInterval/2, time.Second),
|
||||
fetchErrors: metrics.GetOrCreateCounter(fmt.Sprintf(`promscrape_discovery_http_errors_total{type="fetch",url=%q}`, sdc.URL)),
|
||||
parseErrors: metrics.GetOrCreateCounter(fmt.Sprintf(`promscrape_discovery_http_errors_total{type="parse",url=%q}`, sdc.URL)),
|
||||
}
|
||||
cfg.wg.Go(func() {
|
||||
cfg.run()
|
||||
})
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
func getAPIConfig(sdc *SDConfig, baseDir string) (*apiConfig, error) {
|
||||
v, err := configMap.Get(sdc, func() (any, error) { return newAPIConfig(sdc, baseDir) })
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return v.(*apiConfig), nil
|
||||
func (cfg *apiConfig) init() {
|
||||
cfg.initOnce.Do(func() {
|
||||
cfg.refreshTargetsIfNeeded()
|
||||
})
|
||||
}
|
||||
|
||||
func getHTTPTargets(cfg *apiConfig) ([]httpGroupTarget, error) {
|
||||
func (cfg *apiConfig) run() {
|
||||
cfg.init()
|
||||
|
||||
ticker := time.NewTicker(cfg.checkInterval)
|
||||
defer ticker.Stop()
|
||||
stopCh := cfg.client.Context().Done()
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
cfg.refreshTargetsIfNeeded()
|
||||
case <-stopCh:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (cfg *apiConfig) refreshTargetsIfNeeded() {
|
||||
apiResponse, err := cfg.getAPIResponseData()
|
||||
if err != nil {
|
||||
cfg.targetLabels.Store(&targetLabelsResult{err: err})
|
||||
cfg.prevAPIResponse.Store(nil)
|
||||
return
|
||||
}
|
||||
prevAPIResponse := cfg.prevAPIResponse.Load()
|
||||
if prevAPIResponse != nil && bytes.Equal(apiResponse, *prevAPIResponse) {
|
||||
return
|
||||
}
|
||||
hts, err := parseAPIResponse(apiResponse, cfg.path)
|
||||
if err != nil {
|
||||
cfg.prevAPIResponse.Store(nil)
|
||||
cfg.parseErrors.Inc()
|
||||
cfg.targetLabels.Store(&targetLabelsResult{err: err})
|
||||
return
|
||||
}
|
||||
newTargets := addHTTPTargetLabels(hts, cfg.sourceURL)
|
||||
cfg.targetLabels.Store(&targetLabelsResult{labels: newTargets})
|
||||
cfg.prevAPIResponse.Store(&apiResponse)
|
||||
}
|
||||
|
||||
func (cfg *apiConfig) getAPIResponseData() ([]byte, error) {
|
||||
data, err := cfg.client.GetAPIResponseWithReqParams(cfg.path, func(request *http.Request) {
|
||||
request.Header.Set("X-Prometheus-Refresh-Interval-Seconds", strconv.FormatFloat(SDCheckInterval.Seconds(), 'f', 0, 64))
|
||||
request.Header.Set("X-Prometheus-Refresh-Interval-Seconds", strconv.FormatFloat(cfg.checkInterval.Seconds(), 'f', 0, 64))
|
||||
request.Header.Set("Accept", "application/json")
|
||||
})
|
||||
if err != nil {
|
||||
cfg.fetchErrors.Inc()
|
||||
return nil, fmt.Errorf("cannot read http_sd api response: %w", err)
|
||||
}
|
||||
tg, err := parseAPIResponse(data, cfg.path)
|
||||
if err != nil {
|
||||
cfg.parseErrors.Inc()
|
||||
return nil, err
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (cfg *apiConfig) getLabels() ([]*promutil.Labels, error) {
|
||||
cfg.init()
|
||||
|
||||
tlr := cfg.targetLabels.Load()
|
||||
if tlr.err != nil {
|
||||
return nil, tlr.err
|
||||
}
|
||||
return tg, nil
|
||||
return tlr.labels, nil
|
||||
}
|
||||
|
||||
func (cfg *apiConfig) mustStop() {
|
||||
cfg.client.Stop()
|
||||
cfg.wg.Wait()
|
||||
}
|
||||
|
||||
func parseAPIResponse(data []byte, path string) ([]httpGroupTarget, error) {
|
||||
|
||||
@@ -23,19 +23,35 @@ type SDConfig struct {
|
||||
HTTPClientConfig promauth.HTTPClientConfig `yaml:",inline"`
|
||||
ProxyURL *proxy.URL `yaml:"proxy_url,omitempty"`
|
||||
ProxyClientConfig promauth.ProxyClientConfig `yaml:",inline"`
|
||||
|
||||
cfg *apiConfig
|
||||
startErr error
|
||||
}
|
||||
|
||||
// MustStart initializes sdc before its usage.
|
||||
func (sdc *SDConfig) MustStart(baseDir string) {
|
||||
cfg, err := newAPIConfig(sdc, baseDir)
|
||||
if err != nil {
|
||||
sdc.startErr = fmt.Errorf("cannot create API config for http_sd: %w", err)
|
||||
return
|
||||
}
|
||||
sdc.cfg = cfg
|
||||
}
|
||||
|
||||
// GetLabels returns http service discovery labels according to sdc.
|
||||
func (sdc *SDConfig) GetLabels(baseDir string) ([]*promutil.Labels, error) {
|
||||
cfg, err := getAPIConfig(sdc, baseDir)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("cannot get API config: %w", err)
|
||||
if sdc.cfg == nil {
|
||||
return nil, sdc.startErr
|
||||
}
|
||||
hts, err := getHTTPTargets(cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return sdc.cfg.getLabels()
|
||||
}
|
||||
|
||||
// MustStop stops further usage for sdc.
|
||||
func (sdc *SDConfig) MustStop() {
|
||||
if sdc.cfg == nil {
|
||||
return
|
||||
}
|
||||
return addHTTPTargetLabels(hts, sdc.URL), nil
|
||||
sdc.cfg.mustStop()
|
||||
}
|
||||
|
||||
func addHTTPTargetLabels(src []httpGroupTarget, sourceURL string) []*promutil.Labels {
|
||||
@@ -54,12 +70,3 @@ func addHTTPTargetLabels(src []httpGroupTarget, sourceURL string) []*promutil.La
|
||||
}
|
||||
return ms
|
||||
}
|
||||
|
||||
// MustStop stops further usage for sdc.
|
||||
func (sdc *SDConfig) MustStop() {
|
||||
v := configMap.Delete(sdc)
|
||||
if v != nil {
|
||||
cfg := v.(*apiConfig)
|
||||
cfg.client.Stop()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
|
||||
"github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutil"
|
||||
@@ -38,3 +41,121 @@ func TestAddHTTPTargetLabels(t *testing.T) {
|
||||
}
|
||||
f(src, labelssExpected)
|
||||
}
|
||||
|
||||
func TestSDConfigGetLabels(t *testing.T) {
|
||||
|
||||
type apiResponse struct {
|
||||
statusCode int
|
||||
body string
|
||||
}
|
||||
var currentResponse atomic.Pointer[apiResponse]
|
||||
|
||||
// add initial non-empty response
|
||||
currentResponse.Store(&apiResponse{
|
||||
body: `[{"targets":["10.0.0.2:9100"],"labels":{"job":"node"}}]`,
|
||||
statusCode: http.StatusOK,
|
||||
})
|
||||
|
||||
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
||||
resp := currentResponse.Load()
|
||||
w.WriteHeader(resp.statusCode)
|
||||
_, _ = w.Write([]byte(resp.body))
|
||||
}))
|
||||
defer srv.Close()
|
||||
|
||||
sdc := &SDConfig{
|
||||
URL: srv.URL,
|
||||
}
|
||||
sdc.MustStart(".")
|
||||
defer sdc.MustStop()
|
||||
|
||||
assertLabelss := func(expectedLabelss []*promutil.Labels) {
|
||||
t.Helper()
|
||||
got, err := sdc.GetLabels(".")
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected GetLabels error: %s", err)
|
||||
}
|
||||
if len(got) == 0 && len(expectedLabelss) == 0 {
|
||||
return
|
||||
}
|
||||
discoveryutil.TestEqualLabelss(t, got, expectedLabelss)
|
||||
}
|
||||
|
||||
// check initial state, it must be non-empty
|
||||
// it also inits apiConfig below
|
||||
assertLabelss([]*promutil.Labels{
|
||||
promutil.NewLabelsFromMap(map[string]string{
|
||||
"__address__": "10.0.0.2:9100",
|
||||
"job": "node",
|
||||
"__meta_url": srv.URL,
|
||||
}),
|
||||
})
|
||||
|
||||
updateAPIResponse := func(response apiResponse) {
|
||||
currentResponse.Store(&response)
|
||||
sdc.cfg.refreshTargetsIfNeeded()
|
||||
|
||||
}
|
||||
|
||||
// change response to empty
|
||||
updateAPIResponse(apiResponse{
|
||||
statusCode: http.StatusOK,
|
||||
body: `[]`,
|
||||
})
|
||||
assertLabelss([]*promutil.Labels{})
|
||||
|
||||
// change response to non-empty
|
||||
updateAPIResponse(apiResponse{
|
||||
statusCode: http.StatusOK,
|
||||
body: `[{"targets":["10.0.0.1:9100"],"labels":{"job":"node"}},{"targets":["10.0.0.5:8429"],"labels":{"job":"vmagent"}}]`,
|
||||
})
|
||||
assertLabelss([]*promutil.Labels{
|
||||
promutil.NewLabelsFromMap(map[string]string{
|
||||
"__address__": "10.0.0.1:9100",
|
||||
"job": "node",
|
||||
"__meta_url": srv.URL,
|
||||
}),
|
||||
promutil.NewLabelsFromMap(map[string]string{
|
||||
"__address__": "10.0.0.5:8429",
|
||||
"job": "vmagent",
|
||||
"__meta_url": srv.URL,
|
||||
}),
|
||||
})
|
||||
|
||||
// change response to error
|
||||
updateAPIResponse(apiResponse{
|
||||
statusCode: http.StatusServiceUnavailable,
|
||||
body: `Internal Server Error`,
|
||||
})
|
||||
_, err := sdc.GetLabels(".")
|
||||
if err == nil {
|
||||
t.Fatalf("unexpected empty error")
|
||||
}
|
||||
|
||||
// transit back to correct api response
|
||||
updateAPIResponse(apiResponse{
|
||||
statusCode: http.StatusOK,
|
||||
body: `[{"targets":["10.0.0.1:9100"],"labels":{"job":"node"}},{"targets":["10.0.0.5:8429"],"labels":{"job":"vmagent"}}]`,
|
||||
})
|
||||
assertLabelss([]*promutil.Labels{
|
||||
promutil.NewLabelsFromMap(map[string]string{
|
||||
"__address__": "10.0.0.1:9100",
|
||||
"job": "node",
|
||||
"__meta_url": srv.URL,
|
||||
}),
|
||||
promutil.NewLabelsFromMap(map[string]string{
|
||||
"__address__": "10.0.0.5:8429",
|
||||
"job": "vmagent",
|
||||
"__meta_url": srv.URL,
|
||||
}),
|
||||
})
|
||||
|
||||
// make sure that api response is properly cached
|
||||
before := sdc.cfg.targetLabels.Load()
|
||||
updateAPIResponse(apiResponse{statusCode: http.StatusOK,
|
||||
body: `[{"targets":["10.0.0.1:9100"],"labels":{"job":"node"}},{"targets":["10.0.0.5:8429"],"labels":{"job":"vmagent"}}]`})
|
||||
|
||||
if sdc.cfg.targetLabels.Load() != before {
|
||||
t.Fatalf("expected identical response to be deduplicated")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1242,12 +1242,9 @@ func (db *indexDB) GetSeriesCount(deadline uint64) (uint64, error) {
|
||||
func (is *indexSearch) getSeriesCount() (uint64, error) {
|
||||
ts := &is.ts
|
||||
kb := &is.kb
|
||||
mp := &is.mp
|
||||
loopsPaceLimiter := 0
|
||||
var metricIDsLen uint64
|
||||
// Extract the number of series from ((__name__=value): metricIDs) rows
|
||||
kb.B = is.marshalCommonPrefix(kb.B[:0], nsPrefixTagToMetricIDs)
|
||||
kb.B = marshalTagValue(kb.B, nil)
|
||||
kb.B = is.marshalCommonPrefix(kb.B[:0], nsPrefixMetricIDToTSID)
|
||||
ts.Seek(kb.B)
|
||||
for ts.NextItem() {
|
||||
if loopsPaceLimiter&paceLimiterFastIterationsMask == 0 {
|
||||
@@ -1260,19 +1257,10 @@ func (is *indexSearch) getSeriesCount() (uint64, error) {
|
||||
if !bytes.HasPrefix(item, kb.B) {
|
||||
break
|
||||
}
|
||||
tail := item[len(kb.B):]
|
||||
n := bytes.IndexByte(tail, tagSeparatorChar)
|
||||
if n < 0 {
|
||||
return 0, fmt.Errorf("invalid tag->metricIDs line %q: cannot find tagSeparatorChar %d", item, tagSeparatorChar)
|
||||
}
|
||||
tail = tail[n+1:]
|
||||
if err := mp.InitOnlyTail(item, tail); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
// Take into account deleted timeseries too.
|
||||
// It is OK if series can be counted multiple times in rare cases -
|
||||
// the returned number is an estimation.
|
||||
metricIDsLen += uint64(mp.MetricIDsLen())
|
||||
metricIDsLen++
|
||||
}
|
||||
if err := ts.Error(); err != nil {
|
||||
return 0, fmt.Errorf("error when counting unique timeseries: %w", err)
|
||||
|
||||
@@ -1949,10 +1949,11 @@ func newTestStorage() *Storage {
|
||||
s := &Storage{
|
||||
cachePath: "test-storage-cache",
|
||||
|
||||
metricIDCache: workingsetcache.New(1234),
|
||||
metricNameCache: workingsetcache.New(1234),
|
||||
tsidCache: workingsetcache.New(1234),
|
||||
retentionMsecs: retentionMax.Milliseconds(),
|
||||
metricIDCache: workingsetcache.New(1234),
|
||||
metricNameCache: workingsetcache.New(1234),
|
||||
tsidCache: workingsetcache.New(1234),
|
||||
retentionMsecs: retentionMax.Milliseconds(),
|
||||
maxBackfillAgeMsecs: retentionMax.Milliseconds(),
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
@@ -42,7 +42,8 @@ type part struct {
|
||||
valuesFile fs.MustReadAtCloser
|
||||
indexFile fs.MustReadAtCloser
|
||||
|
||||
metaindex []metaindexRow
|
||||
metaindex []metaindexRow
|
||||
metaindexSizeBytes uint64
|
||||
}
|
||||
|
||||
// mustOpenFilePart opens file-based part from the given path.
|
||||
@@ -102,6 +103,7 @@ func newPart(ph *partHeader, path string, size uint64, metaindexReader filestrea
|
||||
p.valuesFile = valuesFile
|
||||
p.indexFile = indexFile
|
||||
p.metaindex = metaindex
|
||||
p.metaindexSizeBytes = metaindexSizeBytes(metaindex)
|
||||
|
||||
return &p
|
||||
}
|
||||
@@ -128,6 +130,10 @@ func (p *part) MustClose() {
|
||||
ibCache.RemoveBlocksForPart(p)
|
||||
}
|
||||
|
||||
func metaindexSizeBytes(metaindex []metaindexRow) uint64 {
|
||||
return uint64(cap(metaindex)) * uint64(unsafe.Sizeof(metaindexRow{}))
|
||||
}
|
||||
|
||||
type indexBlock struct {
|
||||
bhs []blockHeader
|
||||
}
|
||||
|
||||
@@ -334,9 +334,10 @@ type partitionMetrics struct {
|
||||
IndexBlocksCacheRequests uint64
|
||||
IndexBlocksCacheMisses uint64
|
||||
|
||||
InmemorySizeBytes uint64
|
||||
SmallSizeBytes uint64
|
||||
BigSizeBytes uint64
|
||||
InmemorySizeBytes uint64
|
||||
SmallSizeBytes uint64
|
||||
BigSizeBytes uint64
|
||||
MetaindexSizeBytes uint64
|
||||
|
||||
InmemoryRowsCount uint64
|
||||
SmallRowsCount uint64
|
||||
@@ -397,6 +398,7 @@ func (pt *partition) UpdateMetrics(m *partitionMetrics) {
|
||||
m.InmemoryRowsCount += p.ph.RowsCount
|
||||
m.InmemoryBlocksCount += p.ph.BlocksCount
|
||||
m.InmemorySizeBytes += p.size
|
||||
m.MetaindexSizeBytes += p.metaindexSizeBytes
|
||||
m.InmemoryPartsRefCount += uint64(pw.refCount.Load())
|
||||
if isDedupScheduled {
|
||||
m.ScheduledDownsamplingPartitionsSize += p.size
|
||||
@@ -407,6 +409,7 @@ func (pt *partition) UpdateMetrics(m *partitionMetrics) {
|
||||
m.SmallRowsCount += p.ph.RowsCount
|
||||
m.SmallBlocksCount += p.ph.BlocksCount
|
||||
m.SmallSizeBytes += p.size
|
||||
m.MetaindexSizeBytes += p.metaindexSizeBytes
|
||||
m.SmallPartsRefCount += uint64(pw.refCount.Load())
|
||||
if isDedupScheduled {
|
||||
m.ScheduledDownsamplingPartitionsSize += p.size
|
||||
@@ -417,6 +420,7 @@ func (pt *partition) UpdateMetrics(m *partitionMetrics) {
|
||||
m.BigRowsCount += p.ph.RowsCount
|
||||
m.BigBlocksCount += p.ph.BlocksCount
|
||||
m.BigSizeBytes += p.size
|
||||
m.MetaindexSizeBytes += p.metaindexSizeBytes
|
||||
m.BigPartsRefCount += uint64(pw.refCount.Load())
|
||||
if isDedupScheduled {
|
||||
m.ScheduledDownsamplingPartitionsSize += p.size
|
||||
|
||||
@@ -65,6 +65,7 @@ type Storage struct {
|
||||
cachePath string
|
||||
retentionMsecs int64
|
||||
futureRetentionMsecs int64
|
||||
maxBackfillAgeMsecs int64
|
||||
denyQueriesOutsideRetention bool
|
||||
|
||||
// lock file for exclusive access to the storage on the given path.
|
||||
@@ -164,6 +165,7 @@ type Storage struct {
|
||||
type OpenOptions struct {
|
||||
Retention time.Duration
|
||||
FutureRetention time.Duration
|
||||
MaxBackfillAge time.Duration
|
||||
DenyQueriesOutsideRetention bool
|
||||
MaxHourlySeries int
|
||||
MaxDailySeries int
|
||||
@@ -187,6 +189,10 @@ func MustOpenStorage(path string, opts OpenOptions) *Storage {
|
||||
retention = retentionMax
|
||||
}
|
||||
futureRetention := max(opts.FutureRetention, retention2Days)
|
||||
maxBackfillAge := opts.MaxBackfillAge
|
||||
if maxBackfillAge <= 0 || maxBackfillAge > retention {
|
||||
maxBackfillAge = retention
|
||||
}
|
||||
idbPrefillStart := opts.IDBPrefillStart
|
||||
if idbPrefillStart <= 0 {
|
||||
idbPrefillStart = time.Hour
|
||||
@@ -196,6 +202,7 @@ func MustOpenStorage(path string, opts OpenOptions) *Storage {
|
||||
cachePath: filepath.Join(path, cacheDirname),
|
||||
retentionMsecs: retention.Milliseconds(),
|
||||
futureRetentionMsecs: futureRetention.Milliseconds(),
|
||||
maxBackfillAgeMsecs: maxBackfillAge.Milliseconds(),
|
||||
denyQueriesOutsideRetention: opts.DenyQueriesOutsideRetention,
|
||||
stopCh: make(chan struct{}),
|
||||
idbPrefillStartSeconds: idbPrefillStart.Milliseconds() / 1000,
|
||||
@@ -1236,7 +1243,7 @@ func (s *Storage) checkTimeRange(tr TimeRange) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
minTimestamp, maxTimestamp := s.tb.getMinMaxTimestamps()
|
||||
minTimestamp, maxTimestamp := s.tb.getMinMaxRetentionTimestamps()
|
||||
if minTimestamp <= tr.MinTimestamp && tr.MaxTimestamp <= maxTimestamp {
|
||||
return nil
|
||||
}
|
||||
@@ -1896,7 +1903,7 @@ func (s *Storage) add(rows []rawRow, dstMrs []*MetricRow, mrs []MetricRow, preci
|
||||
var newSeriesCount uint64
|
||||
var seriesRepopulated uint64
|
||||
|
||||
minTimestamp, maxTimestamp := s.tb.getMinMaxTimestamps()
|
||||
minTimestamp, maxTimestamp := s.tb.getMinMaxIngestionTimestamps()
|
||||
|
||||
var lTSID legacyTSID
|
||||
var ptw *partitionWrapper
|
||||
@@ -1918,11 +1925,11 @@ func (s *Storage) add(rows []rawRow, dstMrs []*MetricRow, mrs []MetricRow, preci
|
||||
}
|
||||
}
|
||||
if mr.Timestamp < minTimestamp {
|
||||
// Skip rows with too small timestamps outside the retention.
|
||||
// Skip rows with too small timestamps outside the retention or -maxBackfillAge.
|
||||
if firstWarn == nil {
|
||||
metricName := getUserReadableMetricName(mr.MetricNameRaw)
|
||||
firstWarn = fmt.Errorf("cannot insert row with too small timestamp %d outside the retention; minimum allowed timestamp is %d; "+
|
||||
"probably you need updating -retentionPeriod command-line flag; metricName: %s",
|
||||
firstWarn = fmt.Errorf("cannot insert row with too small timestamp %d; minimum allowed timestamp is %d; "+
|
||||
"probably you need updating -retentionPeriod or -maxBackfillAge command-line flags; metricName: %s",
|
||||
mr.Timestamp, minTimestamp, metricName)
|
||||
}
|
||||
s.tooSmallTimestampRows.Add(1)
|
||||
|
||||
@@ -1410,3 +1410,80 @@ func TestStorage_denyQueriesOutsideRetention(t *testing.T) {
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
func TestStorageAddRows_MaxBackfillAge(t *testing.T) {
|
||||
defer testRemoveAll(t)
|
||||
|
||||
mn := MetricName{
|
||||
MetricGroup: []byte("metric"),
|
||||
}
|
||||
mr := MetricRow{
|
||||
MetricNameRaw: mn.marshalRaw(nil),
|
||||
Value: 123,
|
||||
}
|
||||
|
||||
f := func(s *Storage, age time.Duration, want uint64) {
|
||||
t.Helper()
|
||||
|
||||
mr.Timestamp = time.Now().UTC().Add(-age).UnixMilli()
|
||||
s.AddRows([]MetricRow{mr}, defaultPrecisionBits)
|
||||
s.DebugFlush()
|
||||
if got := s.tooSmallTimestampRows.Load(); got != want {
|
||||
t.Fatalf("unexpected number of tooSmallTimestampRows: got %d, want %d", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
synctest.Test(t, func(t *testing.T) {
|
||||
// synctest time begins at 2000-01-01T00:00:00Z.
|
||||
|
||||
retention1y := 365 * 24 * time.Hour
|
||||
var s *Storage
|
||||
|
||||
s = MustOpenStorage(t.Name(), OpenOptions{
|
||||
Retention: retention1y,
|
||||
// By default MaxBackfillAge must be the same as Retention
|
||||
})
|
||||
// Verify that the sample with timestamp 1ms older than retention is
|
||||
// rejected.
|
||||
f(s, retention1y+time.Millisecond, 1)
|
||||
// Verify that the sample with timestamp which is exactly at retention
|
||||
// boundary is accepted.
|
||||
f(s, retention1y, 1)
|
||||
|
||||
// Restart storage with negative MaxBackfillAge. In this case,
|
||||
// MaxBackfillAge must be the same as Retention.
|
||||
// Also advance time a bit so that the storage will not use the same
|
||||
// nanosecond for creating a new part for storing the samples.
|
||||
s.MustClose()
|
||||
time.Sleep(time.Nanosecond)
|
||||
s = MustOpenStorage(t.Name(), OpenOptions{
|
||||
Retention: retention1y,
|
||||
MaxBackfillAge: -1,
|
||||
})
|
||||
f(s, retention1y+time.Millisecond, 1)
|
||||
f(s, retention1y, 1)
|
||||
|
||||
// Restart storage with MaxBackfillAge bigger than Retention. In this
|
||||
// case, MaxBackfillAge must be the same as Retention.
|
||||
s.MustClose()
|
||||
time.Sleep(time.Nanosecond)
|
||||
s = MustOpenStorage(t.Name(), OpenOptions{
|
||||
Retention: retention1y,
|
||||
MaxBackfillAge: retention1y + time.Millisecond,
|
||||
})
|
||||
f(s, retention1y+time.Millisecond, 1)
|
||||
f(s, retention1y, 1)
|
||||
|
||||
// Restart storage with MaxBackfillAge smaller than Retention.
|
||||
s.MustClose()
|
||||
time.Sleep(time.Nanosecond)
|
||||
s = MustOpenStorage(t.Name(), OpenOptions{
|
||||
Retention: retention1y,
|
||||
MaxBackfillAge: retention1y - time.Millisecond,
|
||||
})
|
||||
f(s, retention1y, 1)
|
||||
f(s, retention1y-time.Millisecond, 1)
|
||||
|
||||
s.MustClose()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1807,18 +1807,19 @@ func TestStorageRowsNotAdded(t *testing.T) {
|
||||
defer testRemoveAll(t)
|
||||
|
||||
type options struct {
|
||||
name string
|
||||
retention time.Duration
|
||||
mrs []MetricRow
|
||||
tr TimeRange
|
||||
wantMetrics *Metrics
|
||||
name string
|
||||
retention time.Duration
|
||||
maxBackfillAge time.Duration
|
||||
mrs []MetricRow
|
||||
tr TimeRange
|
||||
wantMetrics *Metrics
|
||||
}
|
||||
f := func(opts *options) {
|
||||
t.Helper()
|
||||
|
||||
var gotMetrics Metrics
|
||||
path := fmt.Sprintf("%s/%s", t.Name(), opts.name)
|
||||
s := MustOpenStorage(path, OpenOptions{Retention: opts.retention})
|
||||
s := MustOpenStorage(path, OpenOptions{Retention: opts.retention, MaxBackfillAge: opts.maxBackfillAge})
|
||||
defer s.MustClose()
|
||||
s.AddRows(opts.mrs, defaultPrecisionBits)
|
||||
s.DebugFlush()
|
||||
@@ -1890,6 +1891,22 @@ func TestStorageRowsNotAdded(t *testing.T) {
|
||||
},
|
||||
})
|
||||
|
||||
retention = retentionMax
|
||||
maxBackfillAge := 48 * time.Hour
|
||||
minTimestamp = time.Now().Add(-maxBackfillAge - time.Hour).UnixMilli()
|
||||
maxTimestamp = minTimestamp + 1000
|
||||
f(&options{
|
||||
name: "TooSmallTimestampsForMaxBackfillAge",
|
||||
retention: retention,
|
||||
maxBackfillAge: maxBackfillAge,
|
||||
mrs: testGenerateMetricRows(rng, numRows, minTimestamp, maxTimestamp),
|
||||
tr: TimeRange{minTimestamp, maxTimestamp},
|
||||
wantMetrics: &Metrics{
|
||||
RowsReceivedTotal: numRows,
|
||||
TooSmallTimestampRows: numRows,
|
||||
},
|
||||
})
|
||||
|
||||
minTimestamp = time.Now().UnixMilli()
|
||||
maxTimestamp = minTimestamp + 1000
|
||||
mrs = testGenerateMetricRows(rng, numRows, minTimestamp, maxTimestamp)
|
||||
|
||||
@@ -368,7 +368,7 @@ func (tb *table) MustAddRows(rows []rawRow) {
|
||||
// The slowest path - there are rows that don't fit any existing partition.
|
||||
// Create new partitions for these rows.
|
||||
// Do this under tb.ptwsLock.
|
||||
minTimestamp, maxTimestamp := tb.getMinMaxTimestamps()
|
||||
minTimestamp, maxTimestamp := tb.getMinMaxIngestionTimestamps()
|
||||
tb.ptwsLock.Lock()
|
||||
for i := range missingRows {
|
||||
r := &missingRows[i]
|
||||
@@ -407,9 +407,28 @@ func (tb *table) MustGetIndexDBIDByHour(hour uint64) uint64 {
|
||||
return ptw.pt.idb.id
|
||||
}
|
||||
|
||||
func (tb *table) getMinMaxTimestamps() (int64, int64) {
|
||||
// getMinMaxRetentionTimestamps returns the minimum and maximum timestamps
|
||||
// allowed by the configured -retentionPeriod and -futureRetention.
|
||||
//
|
||||
// It is used for checking whether the given time range is fully covered
|
||||
// by the retention, e.g. for -denyQueriesOutsideRetention.
|
||||
func (tb *table) getMinMaxRetentionTimestamps() (int64, int64) {
|
||||
return tb.getMinMaxTimestampsForAge(tb.s.retentionMsecs)
|
||||
}
|
||||
|
||||
// getMinMaxIngestionTimestamps returns the minimum and maximum timestamps
|
||||
// allowed for newly ingested rows.
|
||||
//
|
||||
// The minimum timestamp is bound by -maxBackfillAge instead of -retentionPeriod,
|
||||
// since -maxBackfillAge can be configured to reject backfilled rows with historical
|
||||
// timestamps stricter than the full -retentionPeriod window.
|
||||
func (tb *table) getMinMaxIngestionTimestamps() (int64, int64) {
|
||||
return tb.getMinMaxTimestampsForAge(tb.s.maxBackfillAgeMsecs)
|
||||
}
|
||||
|
||||
func (tb *table) getMinMaxTimestampsForAge(minAgeMsecs int64) (int64, int64) {
|
||||
now := int64(fasttime.UnixTimestamp() * 1000)
|
||||
minTimestamp := now - tb.s.retentionMsecs
|
||||
minTimestamp := now - minAgeMsecs
|
||||
if minTimestamp < 0 {
|
||||
// Negative timestamps aren't supported by the storage.
|
||||
minTimestamp = 0
|
||||
|
||||
20
vendor/github.com/VictoriaMetrics/metricsql/binary_op.go
generated
vendored
20
vendor/github.com/VictoriaMetrics/metricsql/binary_op.go
generated
vendored
@@ -73,6 +73,16 @@ func isBinaryOp(op string) bool {
|
||||
return binaryOps[op]
|
||||
}
|
||||
|
||||
func isSetOperator(op string) bool {
|
||||
op = strings.ToLower(op)
|
||||
switch op {
|
||||
case "and", "or", "unless", "if", "ifnot", "default":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func binaryOpPriority(op string) int {
|
||||
op = strings.ToLower(op)
|
||||
return binaryOpPriorities[op]
|
||||
@@ -123,6 +133,16 @@ func isBinaryOpBoolModifier(s string) bool {
|
||||
return s == "bool"
|
||||
}
|
||||
|
||||
func isBinaryOpFillModifier(s string) bool {
|
||||
s = strings.ToLower(s)
|
||||
switch s {
|
||||
case "fill", "fill_left", "fill_right":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// IsBinaryOpCmp returns true if op is comparison operator such as '==', '!=', etc.
|
||||
func IsBinaryOpCmp(op string) bool {
|
||||
switch op {
|
||||
|
||||
22
vendor/github.com/VictoriaMetrics/metricsql/optimizer.go
generated
vendored
22
vendor/github.com/VictoriaMetrics/metricsql/optimizer.go
generated
vendored
@@ -39,6 +39,9 @@ func canOptimize(e Expr) bool {
|
||||
}
|
||||
}
|
||||
case *BinaryOpExpr:
|
||||
if t.FillLeft != nil && t.FillRight != nil {
|
||||
return canOptimize(t.Left) || canOptimize(t.Right)
|
||||
}
|
||||
return true
|
||||
}
|
||||
return false
|
||||
@@ -66,8 +69,23 @@ func optimizeInplace(e Expr) {
|
||||
case *BinaryOpExpr:
|
||||
optimizeInplace(t.Left)
|
||||
optimizeInplace(t.Right)
|
||||
lfs := getCommonLabelFilters(t)
|
||||
pushdownBinaryOpFiltersInplace(lfs, t)
|
||||
switch {
|
||||
case t.FillLeft != nil && t.FillRight != nil:
|
||||
// for two-sided fill, no cross-side pushdown.
|
||||
case t.FillLeft != nil:
|
||||
// for fill_left(), only propagate filters from right to left.
|
||||
lfs := getCommonLabelFilters(t.Right)
|
||||
lfs = TrimFiltersByGroupModifier(lfs, t)
|
||||
pushdownBinaryOpFiltersInplace(lfs, t.Left)
|
||||
case t.FillRight != nil:
|
||||
// for fill_right(), only propagate filters from left to right.
|
||||
lfs := getCommonLabelFilters(t.Left)
|
||||
lfs = TrimFiltersByGroupModifier(lfs, t)
|
||||
pushdownBinaryOpFiltersInplace(lfs, t.Right)
|
||||
default:
|
||||
lfs := getCommonLabelFilters(t)
|
||||
pushdownBinaryOpFiltersInplace(lfs, t)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
92
vendor/github.com/VictoriaMetrics/metricsql/parser.go
generated
vendored
92
vendor/github.com/VictoriaMetrics/metricsql/parser.go
generated
vendored
@@ -402,6 +402,15 @@ func (p *parser) parseExpr() (Expr, error) {
|
||||
}
|
||||
}
|
||||
}
|
||||
for {
|
||||
ok, err := p.parseFillModifier(&be)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
}
|
||||
e2, err := p.parseSingleExpr()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -506,6 +515,65 @@ func (p *parser) parseSingleExprWithoutRollupSuffix() (Expr, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func (p *parser) parseFillModifier(be *BinaryOpExpr) (bool, error) {
|
||||
if !isBinaryOpFillModifier(p.lex.Token) {
|
||||
return false, nil
|
||||
}
|
||||
if isSetOperator(be.Op) {
|
||||
return false, fmt.Errorf(`fill modifier cannot be applied to %q`, be.Op)
|
||||
}
|
||||
op := strings.ToLower(p.lex.Token)
|
||||
if err := p.lex.Next(); err != nil {
|
||||
return false, err
|
||||
}
|
||||
if p.lex.Token != "(" {
|
||||
p.lex.Prev()
|
||||
return false, nil
|
||||
}
|
||||
if err := p.lex.Next(); err != nil {
|
||||
return false, err
|
||||
}
|
||||
ne, err := p.parseFillValue()
|
||||
if err != nil {
|
||||
return false, fmt.Errorf("cannot parse %s fill value: %w", op, err)
|
||||
}
|
||||
if p.lex.Token != ")" {
|
||||
return false, fmt.Errorf(`%s: unexpected token %q; want ")"`, op, p.lex.Token)
|
||||
}
|
||||
if err := p.lex.Next(); err != nil {
|
||||
return false, err
|
||||
}
|
||||
switch op {
|
||||
case "fill":
|
||||
be.FillLeft = ne
|
||||
be.FillRight = ne
|
||||
case "fill_left":
|
||||
be.FillLeft = ne
|
||||
case "fill_right":
|
||||
be.FillRight = ne
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func (p *parser) parseFillValue() (*NumberExpr, error) {
|
||||
neg := false
|
||||
if p.lex.Token == "-" {
|
||||
neg = true
|
||||
if err := p.lex.Next(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
ne, err := p.parsePositiveNumberExpr()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if neg {
|
||||
ne.N = -ne.N
|
||||
ne.s = "-" + ne.s
|
||||
}
|
||||
return ne, nil
|
||||
}
|
||||
|
||||
func (p *parser) parsePositiveNumberExpr() (*NumberExpr, error) {
|
||||
if !isPositiveNumberPrefix(p.lex.Token) && !isInfOrNaN(p.lex.Token) {
|
||||
return nil, fmt.Errorf(`positiveNumberExpr: unexpected token %q; want "number"`, p.lex.Token)
|
||||
@@ -1896,6 +1964,12 @@ type BinaryOpExpr struct {
|
||||
// If KeepMetricNames is set to true, then the operation should keep metric names.
|
||||
KeepMetricNames bool
|
||||
|
||||
// FillLeft contains the fill value for fill_left() or fill() modifier.
|
||||
FillLeft *NumberExpr
|
||||
|
||||
// FillRight contains the fill value for fill_right() or fill() modifier.
|
||||
FillRight *NumberExpr
|
||||
|
||||
// Left contains left arg for the `left op right` expression.
|
||||
Left Expr
|
||||
|
||||
@@ -1971,6 +2045,22 @@ func (be *BinaryOpExpr) appendModifiers(dst []byte) []byte {
|
||||
dst = prefix.AppendString(dst)
|
||||
}
|
||||
}
|
||||
if be.FillLeft != nil && be.FillLeft == be.FillRight {
|
||||
dst = append(dst, " fill("...)
|
||||
dst = be.FillLeft.AppendString(dst)
|
||||
dst = append(dst, ')')
|
||||
} else {
|
||||
if be.FillLeft != nil {
|
||||
dst = append(dst, " fill_left("...)
|
||||
dst = be.FillLeft.AppendString(dst)
|
||||
dst = append(dst, ')')
|
||||
}
|
||||
if be.FillRight != nil {
|
||||
dst = append(dst, " fill_right("...)
|
||||
dst = be.FillRight.AppendString(dst)
|
||||
dst = append(dst, ')')
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
@@ -1989,7 +2079,7 @@ func needBinaryOpArgParens(arg Expr) bool {
|
||||
}
|
||||
|
||||
func isReservedBinaryOpIdent(s string) bool {
|
||||
return isBinaryOpGroupModifier(s) || isBinaryOpJoinModifier(s) || isBinaryOpBoolModifier(s) || isPrefixModifier(s)
|
||||
return isBinaryOpGroupModifier(s) || isBinaryOpJoinModifier(s) || isBinaryOpBoolModifier(s) || isPrefixModifier(s) || isBinaryOpFillModifier(s)
|
||||
}
|
||||
|
||||
func isPrefixModifier(s string) bool {
|
||||
|
||||
62
vendor/golang.org/x/sys/cpu/parse.go
generated
vendored
62
vendor/golang.org/x/sys/cpu/parse.go
generated
vendored
@@ -6,38 +6,50 @@ package cpu
|
||||
|
||||
import "strconv"
|
||||
|
||||
// parseRelease parses a dot-separated version number. It follows the semver
|
||||
// syntax, but allows the minor and patch versions to be elided.
|
||||
// parseRelease parses a dot-separated version number from the prefix
|
||||
// of rel. It returns ok=true only if at least the major and minor
|
||||
// components were successfully parsed; the patch component is
|
||||
// best-effort. Trailing vendor or build suffixes such as
|
||||
// "-generic", "+", "_hi3535", or "-rc1" are ignored.
|
||||
//
|
||||
// This is a copy of the Go runtime's parseRelease from
|
||||
// https://golang.org/cl/209597.
|
||||
// https://golang.org/cl/209597, updated in https://golang.org/cl/781800.
|
||||
func parseRelease(rel string) (major, minor, patch int, ok bool) {
|
||||
// Strip anything after a dash or plus.
|
||||
for i := range len(rel) {
|
||||
if rel[i] == '-' || rel[i] == '+' {
|
||||
rel = rel[:i]
|
||||
break
|
||||
// next consumes a run of decimal digits from the front of rel,
|
||||
// returning the parsed value. If the digits are followed by a
|
||||
// '.', it is consumed and more is set so the caller knows to
|
||||
// parse another component; otherwise scanning terminates and
|
||||
// the rest of rel is discarded.
|
||||
next := func() (n int, more, ok bool) {
|
||||
i := 0
|
||||
for i < len(rel) && rel[i] >= '0' && rel[i] <= '9' {
|
||||
i++
|
||||
}
|
||||
if i == 0 {
|
||||
return 0, false, false
|
||||
}
|
||||
n, err := strconv.Atoi(rel[:i])
|
||||
if err != nil {
|
||||
return 0, false, false
|
||||
}
|
||||
if i < len(rel) && rel[i] == '.' {
|
||||
rel = rel[i+1:]
|
||||
return n, true, true
|
||||
}
|
||||
rel = ""
|
||||
return n, false, true
|
||||
}
|
||||
|
||||
next := func() (int, bool) {
|
||||
for i := range len(rel) {
|
||||
if rel[i] == '.' {
|
||||
ver, err := strconv.Atoi(rel[:i])
|
||||
rel = rel[i+1:]
|
||||
return ver, err == nil
|
||||
}
|
||||
}
|
||||
ver, err := strconv.Atoi(rel)
|
||||
rel = ""
|
||||
return ver, err == nil
|
||||
var more bool
|
||||
if major, more, ok = next(); !ok || !more {
|
||||
return 0, 0, 0, false
|
||||
}
|
||||
if major, ok = next(); !ok || rel == "" {
|
||||
return
|
||||
if minor, more, ok = next(); !ok {
|
||||
return 0, 0, 0, false
|
||||
}
|
||||
if minor, ok = next(); !ok || rel == "" {
|
||||
return
|
||||
if !more {
|
||||
return major, minor, 0, true
|
||||
}
|
||||
patch, ok = next()
|
||||
return
|
||||
patch, _, _ = next()
|
||||
return major, minor, patch, true
|
||||
}
|
||||
|
||||
1
vendor/golang.org/x/sys/unix/syscall_linux.go
generated
vendored
1
vendor/golang.org/x/sys/unix/syscall_linux.go
generated
vendored
@@ -1874,6 +1874,7 @@ func Dup2(oldfd, newfd int) error {
|
||||
//sys Dup3(oldfd int, newfd int, flags int) (err error)
|
||||
//sysnb EpollCreate1(flag int) (fd int, err error)
|
||||
//sysnb EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error)
|
||||
//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) = SYS_EPOLL_PWAIT
|
||||
//sys Eventfd(initval uint, flags int) (fd int, err error) = SYS_EVENTFD2
|
||||
//sys Exit(code int) = SYS_EXIT_GROUP
|
||||
//sys Fallocate(fd int, mode uint32, off int64, len int64) (err error)
|
||||
|
||||
1
vendor/golang.org/x/sys/unix/syscall_linux_386.go
generated
vendored
1
vendor/golang.org/x/sys/unix/syscall_linux_386.go
generated
vendored
@@ -20,7 +20,6 @@ func setTimeval(sec, usec int64) Timeval {
|
||||
|
||||
// 64-bit file system and 32-bit uid calls
|
||||
// (386 default is 32-bit file system and 16-bit uid).
|
||||
//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
|
||||
//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64_64
|
||||
//sys Fchown(fd int, uid int, gid int) (err error) = SYS_FCHOWN32
|
||||
//sys Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64
|
||||
|
||||
1
vendor/golang.org/x/sys/unix/syscall_linux_amd64.go
generated
vendored
1
vendor/golang.org/x/sys/unix/syscall_linux_amd64.go
generated
vendored
@@ -6,7 +6,6 @@
|
||||
|
||||
package unix
|
||||
|
||||
//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
|
||||
//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64
|
||||
//sys Fchown(fd int, uid int, gid int) (err error)
|
||||
//sys Fstat(fd int, stat *Stat_t) (err error)
|
||||
|
||||
1
vendor/golang.org/x/sys/unix/syscall_linux_arm.go
generated
vendored
1
vendor/golang.org/x/sys/unix/syscall_linux_arm.go
generated
vendored
@@ -44,7 +44,6 @@ func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
|
||||
|
||||
// 64-bit file system and 32-bit uid calls
|
||||
// (16-bit uid calls are not always supported in newer kernels)
|
||||
//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
|
||||
//sys Fchown(fd int, uid int, gid int) (err error) = SYS_FCHOWN32
|
||||
//sys Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64
|
||||
//sys Fstatat(dirfd int, path string, stat *Stat_t, flags int) (err error) = SYS_FSTATAT64
|
||||
|
||||
1
vendor/golang.org/x/sys/unix/syscall_linux_arm64.go
generated
vendored
1
vendor/golang.org/x/sys/unix/syscall_linux_arm64.go
generated
vendored
@@ -8,7 +8,6 @@ package unix
|
||||
|
||||
import "unsafe"
|
||||
|
||||
//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) = SYS_EPOLL_PWAIT
|
||||
//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64
|
||||
//sys Fchown(fd int, uid int, gid int) (err error)
|
||||
//sys Fstat(fd int, stat *Stat_t) (err error)
|
||||
|
||||
1
vendor/golang.org/x/sys/unix/syscall_linux_loong64.go
generated
vendored
1
vendor/golang.org/x/sys/unix/syscall_linux_loong64.go
generated
vendored
@@ -8,7 +8,6 @@ package unix
|
||||
|
||||
import "unsafe"
|
||||
|
||||
//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) = SYS_EPOLL_PWAIT
|
||||
//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64
|
||||
//sys Fchown(fd int, uid int, gid int) (err error)
|
||||
//sys Fstatfs(fd int, buf *Statfs_t) (err error)
|
||||
|
||||
1
vendor/golang.org/x/sys/unix/syscall_linux_mips64x.go
generated
vendored
1
vendor/golang.org/x/sys/unix/syscall_linux_mips64x.go
generated
vendored
@@ -6,7 +6,6 @@
|
||||
|
||||
package unix
|
||||
|
||||
//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
|
||||
//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64
|
||||
//sys Fchown(fd int, uid int, gid int) (err error)
|
||||
//sys Fstatfs(fd int, buf *Statfs_t) (err error)
|
||||
|
||||
1
vendor/golang.org/x/sys/unix/syscall_linux_mipsx.go
generated
vendored
1
vendor/golang.org/x/sys/unix/syscall_linux_mipsx.go
generated
vendored
@@ -13,7 +13,6 @@ import (
|
||||
|
||||
func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err syscall.Errno)
|
||||
|
||||
//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
|
||||
//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64
|
||||
//sys Fchown(fd int, uid int, gid int) (err error)
|
||||
//sys Ftruncate(fd int, length int64) (err error) = SYS_FTRUNCATE64
|
||||
|
||||
1
vendor/golang.org/x/sys/unix/syscall_linux_ppc.go
generated
vendored
1
vendor/golang.org/x/sys/unix/syscall_linux_ppc.go
generated
vendored
@@ -11,7 +11,6 @@ import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
|
||||
//sys Fchown(fd int, uid int, gid int) (err error)
|
||||
//sys Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64
|
||||
//sys Fstatat(dirfd int, path string, stat *Stat_t, flags int) (err error) = SYS_FSTATAT64
|
||||
|
||||
1
vendor/golang.org/x/sys/unix/syscall_linux_ppc64x.go
generated
vendored
1
vendor/golang.org/x/sys/unix/syscall_linux_ppc64x.go
generated
vendored
@@ -6,7 +6,6 @@
|
||||
|
||||
package unix
|
||||
|
||||
//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
|
||||
//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64
|
||||
//sys Fchown(fd int, uid int, gid int) (err error)
|
||||
//sys Fstat(fd int, stat *Stat_t) (err error)
|
||||
|
||||
1
vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go
generated
vendored
1
vendor/golang.org/x/sys/unix/syscall_linux_riscv64.go
generated
vendored
@@ -8,7 +8,6 @@ package unix
|
||||
|
||||
import "unsafe"
|
||||
|
||||
//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) = SYS_EPOLL_PWAIT
|
||||
//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64
|
||||
//sys Fchown(fd int, uid int, gid int) (err error)
|
||||
//sys Fstat(fd int, stat *Stat_t) (err error)
|
||||
|
||||
1
vendor/golang.org/x/sys/unix/syscall_linux_s390x.go
generated
vendored
1
vendor/golang.org/x/sys/unix/syscall_linux_s390x.go
generated
vendored
@@ -10,7 +10,6 @@ import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
|
||||
//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64
|
||||
//sys Fchown(fd int, uid int, gid int) (err error)
|
||||
//sys Fstat(fd int, stat *Stat_t) (err error)
|
||||
|
||||
1
vendor/golang.org/x/sys/unix/syscall_linux_sparc64.go
generated
vendored
1
vendor/golang.org/x/sys/unix/syscall_linux_sparc64.go
generated
vendored
@@ -6,7 +6,6 @@
|
||||
|
||||
package unix
|
||||
|
||||
//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error)
|
||||
//sys Fadvise(fd int, offset int64, length int64, advice int) (err error) = SYS_FADVISE64
|
||||
//sys Fchown(fd int, uid int, gid int) (err error)
|
||||
//sys Fstat(fd int, stat *Stat_t) (err error)
|
||||
|
||||
8
vendor/golang.org/x/sys/unix/zerrors_linux.go
generated
vendored
8
vendor/golang.org/x/sys/unix/zerrors_linux.go
generated
vendored
@@ -1359,6 +1359,7 @@ const (
|
||||
FAN_UNLIMITED_MARKS = 0x20
|
||||
FAN_UNLIMITED_QUEUE = 0x10
|
||||
FD_CLOEXEC = 0x1
|
||||
FD_PIDFS_ROOT = -0x2712
|
||||
FD_SETSIZE = 0x400
|
||||
FF0 = 0x0
|
||||
FIB_RULE_DEV_DETACHED = 0x8
|
||||
@@ -1970,6 +1971,8 @@ const (
|
||||
MADV_DONTNEED = 0x4
|
||||
MADV_DONTNEED_LOCKED = 0x18
|
||||
MADV_FREE = 0x8
|
||||
MADV_GUARD_INSTALL = 0x66
|
||||
MADV_GUARD_REMOVE = 0x67
|
||||
MADV_HUGEPAGE = 0xe
|
||||
MADV_HWPOISON = 0x64
|
||||
MADV_KEEPONFORK = 0x13
|
||||
@@ -2114,7 +2117,7 @@ const (
|
||||
MS_NOSEC = 0x10000000
|
||||
MS_NOSUID = 0x2
|
||||
MS_NOSYMFOLLOW = 0x100
|
||||
MS_NOUSER = -0x80000000
|
||||
MS_NOUSER = 0x80000000
|
||||
MS_POSIXACL = 0x10000
|
||||
MS_PRIVATE = 0x40000
|
||||
MS_RDONLY = 0x1
|
||||
@@ -3786,6 +3789,9 @@ const (
|
||||
TCPOPT_TIMESTAMP = 0x8
|
||||
TCPOPT_TSTAMP_HDR = 0x101080a
|
||||
TCPOPT_WINDOW = 0x3
|
||||
TCP_AO_KEYF_EXCLUDE_OPT = 0x2
|
||||
TCP_AO_KEYF_IFINDEX = 0x1
|
||||
TCP_AO_MAXKEYLEN = 0x50
|
||||
TCP_CC_INFO = 0x1a
|
||||
TCP_CM_INQ = 0x24
|
||||
TCP_CONGESTION = 0xd
|
||||
|
||||
17
vendor/golang.org/x/sys/unix/zsyscall_linux.go
generated
vendored
17
vendor/golang.org/x/sys/unix/zsyscall_linux.go
generated
vendored
@@ -700,6 +700,23 @@ func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) {
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
|
||||
var _p0 unsafe.Pointer
|
||||
if len(events) > 0 {
|
||||
_p0 = unsafe.Pointer(&events[0])
|
||||
} else {
|
||||
_p0 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall6(SYS_EPOLL_PWAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
|
||||
n = int(r0)
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Eventfd(initval uint, flags int) (fd int, err error) {
|
||||
r0, _, e1 := Syscall(SYS_EVENTFD2, uintptr(initval), uintptr(flags), 0)
|
||||
fd = int(r0)
|
||||
|
||||
17
vendor/golang.org/x/sys/unix/zsyscall_linux_386.go
generated
vendored
17
vendor/golang.org/x/sys/unix/zsyscall_linux_386.go
generated
vendored
@@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
|
||||
var _p0 unsafe.Pointer
|
||||
if len(events) > 0 {
|
||||
_p0 = unsafe.Pointer(&events[0])
|
||||
} else {
|
||||
_p0 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
|
||||
n = int(r0)
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Fadvise(fd int, offset int64, length int64, advice int) (err error) {
|
||||
_, _, e1 := Syscall6(SYS_FADVISE64_64, uintptr(fd), uintptr(offset), uintptr(offset>>32), uintptr(length), uintptr(length>>32), uintptr(advice))
|
||||
if e1 != 0 {
|
||||
|
||||
17
vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go
generated
vendored
17
vendor/golang.org/x/sys/unix/zsyscall_linux_amd64.go
generated
vendored
@@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
|
||||
var _p0 unsafe.Pointer
|
||||
if len(events) > 0 {
|
||||
_p0 = unsafe.Pointer(&events[0])
|
||||
} else {
|
||||
_p0 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
|
||||
n = int(r0)
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Fadvise(fd int, offset int64, length int64, advice int) (err error) {
|
||||
_, _, e1 := Syscall6(SYS_FADVISE64, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0)
|
||||
if e1 != 0 {
|
||||
|
||||
17
vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go
generated
vendored
17
vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go
generated
vendored
@@ -213,23 +213,6 @@ func sendmsg(s int, msg *Msghdr, flags int) (n int, err error) {
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
|
||||
var _p0 unsafe.Pointer
|
||||
if len(events) > 0 {
|
||||
_p0 = unsafe.Pointer(&events[0])
|
||||
} else {
|
||||
_p0 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
|
||||
n = int(r0)
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Fchown(fd int, uid int, gid int) (err error) {
|
||||
_, _, e1 := Syscall(SYS_FCHOWN32, uintptr(fd), uintptr(uid), uintptr(gid))
|
||||
if e1 != 0 {
|
||||
|
||||
17
vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go
generated
vendored
17
vendor/golang.org/x/sys/unix/zsyscall_linux_arm64.go
generated
vendored
@@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
|
||||
var _p0 unsafe.Pointer
|
||||
if len(events) > 0 {
|
||||
_p0 = unsafe.Pointer(&events[0])
|
||||
} else {
|
||||
_p0 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall6(SYS_EPOLL_PWAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
|
||||
n = int(r0)
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Fadvise(fd int, offset int64, length int64, advice int) (err error) {
|
||||
_, _, e1 := Syscall6(SYS_FADVISE64, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0)
|
||||
if e1 != 0 {
|
||||
|
||||
17
vendor/golang.org/x/sys/unix/zsyscall_linux_loong64.go
generated
vendored
17
vendor/golang.org/x/sys/unix/zsyscall_linux_loong64.go
generated
vendored
@@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
|
||||
var _p0 unsafe.Pointer
|
||||
if len(events) > 0 {
|
||||
_p0 = unsafe.Pointer(&events[0])
|
||||
} else {
|
||||
_p0 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall6(SYS_EPOLL_PWAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
|
||||
n = int(r0)
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Fadvise(fd int, offset int64, length int64, advice int) (err error) {
|
||||
_, _, e1 := Syscall6(SYS_FADVISE64, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0)
|
||||
if e1 != 0 {
|
||||
|
||||
17
vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go
generated
vendored
17
vendor/golang.org/x/sys/unix/zsyscall_linux_mips.go
generated
vendored
@@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
|
||||
var _p0 unsafe.Pointer
|
||||
if len(events) > 0 {
|
||||
_p0 = unsafe.Pointer(&events[0])
|
||||
} else {
|
||||
_p0 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
|
||||
n = int(r0)
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Fadvise(fd int, offset int64, length int64, advice int) (err error) {
|
||||
_, _, e1 := Syscall9(SYS_FADVISE64, uintptr(fd), 0, uintptr(offset>>32), uintptr(offset), uintptr(length>>32), uintptr(length), uintptr(advice), 0, 0)
|
||||
if e1 != 0 {
|
||||
|
||||
17
vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go
generated
vendored
17
vendor/golang.org/x/sys/unix/zsyscall_linux_mips64.go
generated
vendored
@@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
|
||||
var _p0 unsafe.Pointer
|
||||
if len(events) > 0 {
|
||||
_p0 = unsafe.Pointer(&events[0])
|
||||
} else {
|
||||
_p0 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
|
||||
n = int(r0)
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Fadvise(fd int, offset int64, length int64, advice int) (err error) {
|
||||
_, _, e1 := Syscall6(SYS_FADVISE64, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0)
|
||||
if e1 != 0 {
|
||||
|
||||
17
vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go
generated
vendored
17
vendor/golang.org/x/sys/unix/zsyscall_linux_mips64le.go
generated
vendored
@@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
|
||||
var _p0 unsafe.Pointer
|
||||
if len(events) > 0 {
|
||||
_p0 = unsafe.Pointer(&events[0])
|
||||
} else {
|
||||
_p0 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
|
||||
n = int(r0)
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Fadvise(fd int, offset int64, length int64, advice int) (err error) {
|
||||
_, _, e1 := Syscall6(SYS_FADVISE64, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0)
|
||||
if e1 != 0 {
|
||||
|
||||
17
vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go
generated
vendored
17
vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go
generated
vendored
@@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
|
||||
var _p0 unsafe.Pointer
|
||||
if len(events) > 0 {
|
||||
_p0 = unsafe.Pointer(&events[0])
|
||||
} else {
|
||||
_p0 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
|
||||
n = int(r0)
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Fadvise(fd int, offset int64, length int64, advice int) (err error) {
|
||||
_, _, e1 := Syscall9(SYS_FADVISE64, uintptr(fd), 0, uintptr(offset), uintptr(offset>>32), uintptr(length), uintptr(length>>32), uintptr(advice), 0, 0)
|
||||
if e1 != 0 {
|
||||
|
||||
17
vendor/golang.org/x/sys/unix/zsyscall_linux_ppc.go
generated
vendored
17
vendor/golang.org/x/sys/unix/zsyscall_linux_ppc.go
generated
vendored
@@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
|
||||
var _p0 unsafe.Pointer
|
||||
if len(events) > 0 {
|
||||
_p0 = unsafe.Pointer(&events[0])
|
||||
} else {
|
||||
_p0 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
|
||||
n = int(r0)
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Fchown(fd int, uid int, gid int) (err error) {
|
||||
_, _, e1 := Syscall(SYS_FCHOWN, uintptr(fd), uintptr(uid), uintptr(gid))
|
||||
if e1 != 0 {
|
||||
|
||||
17
vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go
generated
vendored
17
vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64.go
generated
vendored
@@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
|
||||
var _p0 unsafe.Pointer
|
||||
if len(events) > 0 {
|
||||
_p0 = unsafe.Pointer(&events[0])
|
||||
} else {
|
||||
_p0 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
|
||||
n = int(r0)
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Fadvise(fd int, offset int64, length int64, advice int) (err error) {
|
||||
_, _, e1 := Syscall6(SYS_FADVISE64, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0)
|
||||
if e1 != 0 {
|
||||
|
||||
17
vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go
generated
vendored
17
vendor/golang.org/x/sys/unix/zsyscall_linux_ppc64le.go
generated
vendored
@@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
|
||||
var _p0 unsafe.Pointer
|
||||
if len(events) > 0 {
|
||||
_p0 = unsafe.Pointer(&events[0])
|
||||
} else {
|
||||
_p0 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
|
||||
n = int(r0)
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Fadvise(fd int, offset int64, length int64, advice int) (err error) {
|
||||
_, _, e1 := Syscall6(SYS_FADVISE64, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0)
|
||||
if e1 != 0 {
|
||||
|
||||
17
vendor/golang.org/x/sys/unix/zsyscall_linux_riscv64.go
generated
vendored
17
vendor/golang.org/x/sys/unix/zsyscall_linux_riscv64.go
generated
vendored
@@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
|
||||
var _p0 unsafe.Pointer
|
||||
if len(events) > 0 {
|
||||
_p0 = unsafe.Pointer(&events[0])
|
||||
} else {
|
||||
_p0 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall6(SYS_EPOLL_PWAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
|
||||
n = int(r0)
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Fadvise(fd int, offset int64, length int64, advice int) (err error) {
|
||||
_, _, e1 := Syscall6(SYS_FADVISE64, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0)
|
||||
if e1 != 0 {
|
||||
|
||||
17
vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go
generated
vendored
17
vendor/golang.org/x/sys/unix/zsyscall_linux_s390x.go
generated
vendored
@@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
|
||||
var _p0 unsafe.Pointer
|
||||
if len(events) > 0 {
|
||||
_p0 = unsafe.Pointer(&events[0])
|
||||
} else {
|
||||
_p0 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
|
||||
n = int(r0)
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Fadvise(fd int, offset int64, length int64, advice int) (err error) {
|
||||
_, _, e1 := Syscall6(SYS_FADVISE64, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0)
|
||||
if e1 != 0 {
|
||||
|
||||
17
vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go
generated
vendored
17
vendor/golang.org/x/sys/unix/zsyscall_linux_sparc64.go
generated
vendored
@@ -45,23 +45,6 @@ func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
|
||||
var _p0 unsafe.Pointer
|
||||
if len(events) > 0 {
|
||||
_p0 = unsafe.Pointer(&events[0])
|
||||
} else {
|
||||
_p0 = unsafe.Pointer(&_zero)
|
||||
}
|
||||
r0, _, e1 := Syscall6(SYS_EPOLL_WAIT, uintptr(epfd), uintptr(_p0), uintptr(len(events)), uintptr(msec), 0, 0)
|
||||
n = int(r0)
|
||||
if e1 != 0 {
|
||||
err = errnoErr(e1)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Fadvise(fd int, offset int64, length int64, advice int) (err error) {
|
||||
_, _, e1 := Syscall6(SYS_FADVISE64, uintptr(fd), uintptr(offset), uintptr(length), uintptr(advice), 0, 0)
|
||||
if e1 != 0 {
|
||||
|
||||
36
vendor/golang.org/x/sys/windows/security_windows.go
generated
vendored
36
vendor/golang.org/x/sys/windows/security_windows.go
generated
vendored
@@ -1109,17 +1109,53 @@ const (
|
||||
)
|
||||
|
||||
// This type is the union inside of TRUSTEE and must be created using one of the TrusteeValueFrom* functions.
|
||||
//
|
||||
// Go pointers stored in a TrusteeValue must be pinned using [runtime.Pinner]
|
||||
// for the lifetime of the TrusteeValue.
|
||||
type TrusteeValue uintptr
|
||||
|
||||
// TrusteeValueFromString is unsafe and should not be used.
|
||||
//
|
||||
// It returns a uintptr containing a reference to newly-allocated memory
|
||||
// which will be freed by the garbage collector.
|
||||
// There is no way for the caller to safely reference this memory.
|
||||
//
|
||||
// To create a [TrusteeValue] from a string, use:
|
||||
//
|
||||
// p, err := windows.UTF16PtrFromString(s)
|
||||
// if err != nil {
|
||||
// // handle error
|
||||
// }
|
||||
//
|
||||
// // Pin the string for as long as it is used.
|
||||
// var pinner runtime.Pinner
|
||||
// pinner.Pin(p)
|
||||
// defer pinner.Unpin()
|
||||
//
|
||||
// tv := TrusteeValue(unsafe.Pointer(p))
|
||||
//
|
||||
// Deprecated: TrusteeValueFromString is unsafe and should not be used.
|
||||
func TrusteeValueFromString(str string) TrusteeValue {
|
||||
return TrusteeValue(unsafe.Pointer(StringToUTF16Ptr(str)))
|
||||
}
|
||||
|
||||
// TrusteeValueFromSID returns a [TrusteeValue] referencing sid.
|
||||
//
|
||||
// The caller must pin sid using a [runtime.Pinner] for the lifetime of the TrusteeValue.
|
||||
func TrusteeValueFromSID(sid *SID) TrusteeValue {
|
||||
return TrusteeValue(unsafe.Pointer(sid))
|
||||
}
|
||||
|
||||
// TrusteeValueFromObjectsAndSid returns a [TrusteeValue] referencing objectsAndSid.
|
||||
//
|
||||
// The caller must pin objectsAndSid using a [runtime.Pinner] for the lifetime of the TrusteeValue.
|
||||
func TrusteeValueFromObjectsAndSid(objectsAndSid *OBJECTS_AND_SID) TrusteeValue {
|
||||
return TrusteeValue(unsafe.Pointer(objectsAndSid))
|
||||
}
|
||||
|
||||
// TrusteeValueFromObjectsAndName returns a [TrusteeValue] referencing objectsAndName.
|
||||
//
|
||||
// The caller must pin objectsAndName using a [runtime.Pinner] for the lifetime of the TrusteeValue.
|
||||
func TrusteeValueFromObjectsAndName(objectsAndName *OBJECTS_AND_NAME) TrusteeValue {
|
||||
return TrusteeValue(unsafe.Pointer(objectsAndName))
|
||||
}
|
||||
|
||||
8
vendor/golang.org/x/sys/windows/syscall_windows.go
generated
vendored
8
vendor/golang.org/x/sys/windows/syscall_windows.go
generated
vendored
@@ -1728,11 +1728,15 @@ func (s *NTUnicodeString) String() string {
|
||||
// the more common *uint16 string type.
|
||||
func NewNTString(s string) (*NTString, error) {
|
||||
var nts NTString
|
||||
s8, err := BytePtrFromString(s)
|
||||
s8, err := ByteSliceFromString(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
RtlInitString(&nts, s8)
|
||||
// The source string plus its terminating NUL must fit within MAX_USHORT.
|
||||
if len(s8) > MAX_USHORT {
|
||||
return nil, syscall.EINVAL
|
||||
}
|
||||
RtlInitString(&nts, &s8[0])
|
||||
return &nts, nil
|
||||
}
|
||||
|
||||
|
||||
1
vendor/golang.org/x/sys/windows/types_windows.go
generated
vendored
1
vendor/golang.org/x/sys/windows/types_windows.go
generated
vendored
@@ -169,6 +169,7 @@ const (
|
||||
FORMAT_MESSAGE_ARGUMENT_ARRAY = 8192
|
||||
FORMAT_MESSAGE_MAX_WIDTH_MASK = 255
|
||||
|
||||
MAX_USHORT = 0xffff
|
||||
MAX_PATH = 260
|
||||
MAX_LONG_PATH = 32768
|
||||
|
||||
|
||||
4
vendor/modules.txt
vendored
4
vendor/modules.txt
vendored
@@ -146,7 +146,7 @@ github.com/VictoriaMetrics/fastcache
|
||||
# github.com/VictoriaMetrics/metrics v1.44.0
|
||||
## explicit; go 1.24.0
|
||||
github.com/VictoriaMetrics/metrics
|
||||
# github.com/VictoriaMetrics/metricsql v0.87.2
|
||||
# github.com/VictoriaMetrics/metricsql v0.87.3
|
||||
## explicit; go 1.24.2
|
||||
github.com/VictoriaMetrics/metricsql
|
||||
github.com/VictoriaMetrics/metricsql/binaryop
|
||||
@@ -902,7 +902,7 @@ golang.org/x/oauth2/jwt
|
||||
## explicit; go 1.25.0
|
||||
golang.org/x/sync/errgroup
|
||||
golang.org/x/sync/semaphore
|
||||
# golang.org/x/sys v0.46.0
|
||||
# golang.org/x/sys v0.47.0
|
||||
## explicit; go 1.25.0
|
||||
golang.org/x/sys/cpu
|
||||
golang.org/x/sys/plan9
|
||||
|
||||
Reference in New Issue
Block a user