mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2025-03-11 15:34:56 +00:00
lib/storage: properly handle queries containing a filter on metric name plus any number of negative filters and zero non-negative filters
Example: `node_cpu_seconds_total{mode!="idle"}`
This commit is contained in:
parent
ae1238fe5c
commit
a537c4f602
4 changed files with 100 additions and 12 deletions
16
app/victoria-metrics/testdata/graphite/name-plus-negative-filter.json
vendored
Normal file
16
app/victoria-metrics/testdata/graphite/name-plus-negative-filter.json
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"name": "name-plus-negative-filter",
|
||||
"issue": "",
|
||||
"data": [
|
||||
"name-plus-negative-filter;foo=123 1 {TIME_S-1m}",
|
||||
"name-plus-negative-filter;bar=123 2 {TIME_S-1m}",
|
||||
"name-plus-negative-filter;foo=qwe 3 {TIME_S-1m}"
|
||||
],
|
||||
"query": ["/api/v1/query?query={__name__='name-plus-negative-filter',foo!='123'}&time={TIME_S-1m}"],
|
||||
"result_query": {
|
||||
"status":"success",
|
||||
"data":{"resultType":"vector","result":[
|
||||
{"metric":{"__name__":"name-plus-negative-filter","foo":"qwe"},"value":["{TIME_S-1m}","3"]}
|
||||
]}
|
||||
}
|
||||
}
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
# tip
|
||||
|
||||
* BUGFIX: properly handle queries containing a filter on metric name plus any number of negative filters and zero non-negative filters. For example, `node_cpu_seconds_total{mode!="idle"}`. The bug was introduced in [v1.54.0](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.54.0).
|
||||
|
||||
|
||||
# [v1.54.0](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.54.0)
|
||||
|
||||
|
|
|
@ -35,13 +35,16 @@ func convertToCompositeTagFilters(tfs *TagFilters) *TagFilters {
|
|||
}
|
||||
}
|
||||
if len(name) == 0 {
|
||||
// There is no metric name filter, so composite filters cannot be created.
|
||||
// Composite filters cannot be created in the following cases:
|
||||
// - if there is no filter on metric name
|
||||
// - if there is no at least a single positive filter.
|
||||
atomic.AddUint64(&compositeFilterMissingConversions, 1)
|
||||
return tfs
|
||||
}
|
||||
tfsNew := make([]tagFilter, 0, len(tfs.tfs))
|
||||
var compositeKey []byte
|
||||
compositeFilters := 0
|
||||
hasPositiveFilter := false
|
||||
for _, tf := range tfs.tfs {
|
||||
if len(tf.key) == 0 {
|
||||
if tf.isNegative || tf.isRegexp || string(tf.value) != string(name) {
|
||||
|
@ -58,10 +61,13 @@ func convertToCompositeTagFilters(tfs *TagFilters) *TagFilters {
|
|||
if err := tfNew.Init(tfs.commonPrefix, compositeKey, tf.value, tf.isNegative, tf.isRegexp); err != nil {
|
||||
logger.Panicf("BUG: unexpected error when creating composite tag filter for name=%q and key=%q: %s", name, tf.key, err)
|
||||
}
|
||||
if !tfNew.isNegative {
|
||||
hasPositiveFilter = true
|
||||
}
|
||||
tfsNew = append(tfsNew, tfNew)
|
||||
compositeFilters++
|
||||
}
|
||||
if compositeFilters == 0 {
|
||||
if compositeFilters == 0 || !hasPositiveFilter {
|
||||
atomic.AddUint64(&compositeFilterMissingConversions, 1)
|
||||
return tfs
|
||||
}
|
||||
|
|
|
@ -148,6 +148,70 @@ func TestConvertToCompositeTagFilters(t *testing.T) {
|
|||
},
|
||||
})
|
||||
|
||||
// A name filter with a single negative filter
|
||||
f([]TagFilter{
|
||||
{
|
||||
Key: nil,
|
||||
Value: []byte("bar"),
|
||||
IsNegative: false,
|
||||
IsRegexp: false,
|
||||
},
|
||||
{
|
||||
Key: []byte("foo"),
|
||||
Value: []byte("abc"),
|
||||
IsNegative: true,
|
||||
IsRegexp: false,
|
||||
},
|
||||
}, []TagFilter{
|
||||
{
|
||||
Key: nil,
|
||||
Value: []byte("bar"),
|
||||
IsNegative: false,
|
||||
IsRegexp: false,
|
||||
},
|
||||
{
|
||||
Key: []byte("foo"),
|
||||
Value: []byte("abc"),
|
||||
IsNegative: true,
|
||||
IsRegexp: false,
|
||||
},
|
||||
})
|
||||
|
||||
// A name filter with a negative and a positive filter
|
||||
f([]TagFilter{
|
||||
{
|
||||
Key: nil,
|
||||
Value: []byte("bar"),
|
||||
IsNegative: false,
|
||||
IsRegexp: false,
|
||||
},
|
||||
{
|
||||
Key: []byte("foo"),
|
||||
Value: []byte("abc"),
|
||||
IsNegative: true,
|
||||
IsRegexp: false,
|
||||
},
|
||||
{
|
||||
Key: []byte("a"),
|
||||
Value: []byte("b.+"),
|
||||
IsNegative: false,
|
||||
IsRegexp: true,
|
||||
},
|
||||
}, []TagFilter{
|
||||
{
|
||||
Key: []byte("\xfe\x03barfoo"),
|
||||
Value: []byte("abc"),
|
||||
IsNegative: true,
|
||||
IsRegexp: false,
|
||||
},
|
||||
{
|
||||
Key: []byte("\xfe\x03bara"),
|
||||
Value: []byte("b.+"),
|
||||
IsNegative: false,
|
||||
IsRegexp: true,
|
||||
},
|
||||
})
|
||||
|
||||
// Two name filters with non-name filter.
|
||||
f([]TagFilter{
|
||||
{
|
||||
|
@ -183,7 +247,7 @@ func TestConvertToCompositeTagFilters(t *testing.T) {
|
|||
},
|
||||
})
|
||||
|
||||
// A name filter with negative regexp non-name filter, which can be converted to non-regexp.
|
||||
// A name filter with regexp non-name filter, which can be converted to non-regexp.
|
||||
f([]TagFilter{
|
||||
{
|
||||
Key: nil,
|
||||
|
@ -194,19 +258,19 @@ func TestConvertToCompositeTagFilters(t *testing.T) {
|
|||
{
|
||||
Key: []byte("foo"),
|
||||
Value: []byte("abc"),
|
||||
IsNegative: true,
|
||||
IsNegative: false,
|
||||
IsRegexp: true,
|
||||
},
|
||||
}, []TagFilter{
|
||||
{
|
||||
Key: []byte("\xfe\x03barfoo"),
|
||||
Value: []byte("abc"),
|
||||
IsNegative: true,
|
||||
IsNegative: false,
|
||||
IsRegexp: false,
|
||||
},
|
||||
})
|
||||
|
||||
// A name filter with negative regexp non-name filter.
|
||||
// A name filter with regexp non-name filter.
|
||||
f([]TagFilter{
|
||||
{
|
||||
Key: nil,
|
||||
|
@ -217,14 +281,14 @@ func TestConvertToCompositeTagFilters(t *testing.T) {
|
|||
{
|
||||
Key: []byte("foo"),
|
||||
Value: []byte("abc.+"),
|
||||
IsNegative: true,
|
||||
IsNegative: false,
|
||||
IsRegexp: true,
|
||||
},
|
||||
}, []TagFilter{
|
||||
{
|
||||
Key: []byte("\xfe\x03barfoo"),
|
||||
Value: []byte("abc.+"),
|
||||
IsNegative: true,
|
||||
IsNegative: false,
|
||||
IsRegexp: true,
|
||||
},
|
||||
})
|
||||
|
@ -269,7 +333,7 @@ func TestConvertToCompositeTagFilters(t *testing.T) {
|
|||
{
|
||||
Key: []byte("foo"),
|
||||
Value: []byte("abc"),
|
||||
IsNegative: true,
|
||||
IsNegative: false,
|
||||
IsRegexp: true,
|
||||
},
|
||||
{
|
||||
|
@ -282,7 +346,7 @@ func TestConvertToCompositeTagFilters(t *testing.T) {
|
|||
{
|
||||
Key: []byte("\xfe\x03barfoo"),
|
||||
Value: []byte("abc"),
|
||||
IsNegative: true,
|
||||
IsNegative: false,
|
||||
IsRegexp: false,
|
||||
},
|
||||
{
|
||||
|
@ -304,14 +368,14 @@ func TestConvertToCompositeTagFilters(t *testing.T) {
|
|||
{
|
||||
Key: []byte("foo"),
|
||||
Value: []byte("abc"),
|
||||
IsNegative: true,
|
||||
IsNegative: false,
|
||||
IsRegexp: false,
|
||||
},
|
||||
}, []TagFilter{
|
||||
{
|
||||
Key: []byte("\xfe\x03barfoo"),
|
||||
Value: []byte("abc"),
|
||||
IsNegative: true,
|
||||
IsNegative: false,
|
||||
IsRegexp: false,
|
||||
},
|
||||
})
|
||||
|
|
Loading…
Reference in a new issue