diff --git a/app/vmselect/promql/exec_test.go b/app/vmselect/promql/exec_test.go index a5951fc5b3..9ec2ac2b96 100644 --- a/app/vmselect/promql/exec_test.go +++ b/app/vmselect/promql/exec_test.go @@ -160,7 +160,7 @@ func TestExecSuccess(t *testing.T) { resultExpected := []netstorage.Result{r} f(q, resultExpected) }) - t.Run("time() offset 100s", func(t *testing.T) { + t.Run("time() offset 1m40s0ms", func(t *testing.T) { t.Parallel() q := `time() offset 100s` r := netstorage.Result{ diff --git a/go.mod b/go.mod index db5b3882fe..8ca84d1d63 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( // like https://github.com/valyala/fasthttp/commit/996610f021ff45fdc98c2ce7884d5fa4e7f9199b github.com/VictoriaMetrics/fasthttp v1.0.5 github.com/VictoriaMetrics/metrics v1.12.3 - github.com/VictoriaMetrics/metricsql v0.5.1 + github.com/VictoriaMetrics/metricsql v0.6.0 github.com/aws/aws-sdk-go v1.34.20 github.com/cespare/xxhash/v2 v2.1.1 github.com/golang/snappy v0.0.1 diff --git a/go.sum b/go.sum index 9685b4b01c..5808329946 100644 --- a/go.sum +++ b/go.sum @@ -58,8 +58,8 @@ github.com/VictoriaMetrics/metrics v1.12.2 h1:SG8iAmqavDNuh7GIdHPoGHUhDL23KeKfvS github.com/VictoriaMetrics/metrics v1.12.2/go.mod h1:Z1tSfPfngDn12bTfZSCqArT3OPY3u88J12hSoOhuiRE= github.com/VictoriaMetrics/metrics v1.12.3 h1:Fe6JHC6MSEKa+BtLhPN8WIvS+HKPzMc2evEpNeCGy7I= github.com/VictoriaMetrics/metrics v1.12.3/go.mod h1:Z1tSfPfngDn12bTfZSCqArT3OPY3u88J12hSoOhuiRE= -github.com/VictoriaMetrics/metricsql v0.5.1 h1:hG6Nck7R2/amLgHECobSTXsjZ2z9JP5J3W1sYlBoqfU= -github.com/VictoriaMetrics/metricsql v0.5.1/go.mod h1:ylO7YITho/Iw6P71oEaGyHbO94bGoGtzWfLGqFhMIg8= +github.com/VictoriaMetrics/metricsql v0.6.0 h1:JnHUmifuA3fdy1GQrmkZJFO+CwFrhLxKwzMv89wNgJ4= +github.com/VictoriaMetrics/metricsql v0.6.0/go.mod h1:ylO7YITho/Iw6P71oEaGyHbO94bGoGtzWfLGqFhMIg8= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156 h1:eMwmnE/GDgah4HI848JfFxHt+iPb26b4zyfspmqY0/8= github.com/allegro/bigcache v1.2.1-0.20190218064605-e24eb225f156/go.mod h1:Cb/ax3seSYIx7SuZdm2G2xzfwmv3TPSk2ucNfQESPXM= github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= diff --git a/vendor/github.com/VictoriaMetrics/metricsql/lexer.go b/vendor/github.com/VictoriaMetrics/metricsql/lexer.go index 44bef959f5..7d82db2c42 100644 --- a/vendor/github.com/VictoriaMetrics/metricsql/lexer.go +++ b/vendor/github.com/VictoriaMetrics/metricsql/lexer.go @@ -103,7 +103,7 @@ again: token = s[:n] goto tokenFoundLabel } - if n := scanDuration(s, false); n > 0 { + if n := scanDuration(s); n > 0 { token = s[:n] goto tokenFoundLabel } @@ -393,7 +393,7 @@ func scanSpecialIntegerPrefix(s string) int { } func isPositiveDuration(s string) bool { - n := scanDuration(s, false) + n := scanDuration(s) return n == len(s) } @@ -413,33 +413,57 @@ func PositiveDurationValue(s string, step int64) (int64, error) { // DurationValue returns the duration in milliseconds for the given s // and the given step. // +// Duration in s may be combined, i.e. 2h5m or 2h-5m. +// // The returned duration value can be negative. func DurationValue(s string, step int64) (int64, error) { - n := scanDuration(s, true) - if n != len(s) { - return 0, fmt.Errorf("cannot parse duration %q", s) + if len(s) == 0 { + return 0, fmt.Errorf("duration cannot be empty") } + var d int64 + for len(s) > 0 { + n := scanSingleDuration(s, true) + if n <= 0 { + return 0, fmt.Errorf("cannot parse duration %q", s) + } + ds := s[:n] + s = s[n:] + dLocal, err := parseSingleDuration(ds, step) + if err != nil { + return 0, err + } + d += dLocal + } + return d, nil +} - f, err := strconv.ParseFloat(s[:len(s)-1], 64) +func parseSingleDuration(s string, step int64) (int64, error) { + numPart := s[:len(s)-1] + if strings.HasSuffix(numPart, "m") { + // Duration in ms + numPart = numPart[:len(numPart)-1] + } + f, err := strconv.ParseFloat(numPart, 64) if err != nil { return 0, fmt.Errorf("cannot parse duration %q: %s", s, err) } - var mp float64 - switch s[len(s)-1] { - case 's': + switch s[len(numPart):] { + case "ms": + mp = 1e-3 + case "s": mp = 1 - case 'm': + case "m": mp = 60 - case 'h': + case "h": mp = 60 * 60 - case 'd': + case "d": mp = 24 * 60 * 60 - case 'w': + case "w": mp = 7 * 24 * 60 * 60 - case 'y': + case "y": mp = 365 * 24 * 60 * 60 - case 'i': + case "i": mp = float64(step) / 1e3 default: return 0, fmt.Errorf("invalid duration suffix in %q", s) @@ -447,7 +471,29 @@ func DurationValue(s string, step int64) (int64, error) { return int64(mp * f * 1e3), nil } -func scanDuration(s string, canBeNegative bool) int { +// scanDuration scans duration, which must start with positive num. +// +// I.e. 123h, 3h5m or 3.4d-35.66s +func scanDuration(s string) int { + // The first part must be non-negative + n := scanSingleDuration(s, false) + if n <= 0 { + return -1 + } + s = s[n:] + i := n + for { + // Other parts may be negative + n := scanSingleDuration(s, true) + if n <= 0 { + return i + } + s = s[n:] + i += n + } +} + +func scanSingleDuration(s string, canBeNegative bool) int { if len(s) == 0 { return -1 } @@ -472,7 +518,14 @@ func scanDuration(s string, canBeNegative bool) int { } } switch s[i] { - case 's', 'm', 'h', 'd', 'w', 'y', 'i': + case 'm': + if i+1 < len(s) && s[i+1] == 's' { + // duration in ms + return i + 2 + } + // duration in minutes + return i + 1 + case 's', 'h', 'd', 'w', 'y', 'i': return i + 1 default: return -1 diff --git a/vendor/modules.txt b/vendor/modules.txt index ed3599cb00..60f0396aab 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -16,7 +16,7 @@ github.com/VictoriaMetrics/fasthttp/fasthttputil github.com/VictoriaMetrics/fasthttp/stackless # github.com/VictoriaMetrics/metrics v1.12.3 github.com/VictoriaMetrics/metrics -# github.com/VictoriaMetrics/metricsql v0.5.1 +# github.com/VictoriaMetrics/metricsql v0.6.0 github.com/VictoriaMetrics/metricsql github.com/VictoriaMetrics/metricsql/binaryop # github.com/aws/aws-sdk-go v1.34.20