mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2025-03-11 15:34:56 +00:00
app/vmselect: make sorting for query result similar to Prometheus (#1647)
* app/vmselect: make sorting for query result similar to Prometheus Updated sorting allows to get the order of series in result similar or equal to what Prometheus returns. The change is needed for compatibility reasons. * Update app/vmselect/promql/exec_test.go Co-authored-by: Aliaksandr Valialkin <valyala@victoriametrics.com>
This commit is contained in:
parent
e564411a62
commit
57b3320478
3 changed files with 67 additions and 2 deletions
|
@ -94,7 +94,7 @@ func timeseriesToResult(tss []*timeseries, maySort bool) ([]netstorage.Result, e
|
|||
m := make(map[string]struct{}, len(tss))
|
||||
bb := bbPool.Get()
|
||||
for i, ts := range tss {
|
||||
bb.B = marshalMetricNameSorted(bb.B[:0], &ts.MetricName)
|
||||
bb.B = metricNameToBytes(bb.B[:0], &ts.MetricName)
|
||||
if _, ok := m[string(bb.B)]; ok {
|
||||
return nil, fmt.Errorf(`duplicate output timeseries: %s`, stringMetricName(&ts.MetricName))
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package promql
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
@ -6954,7 +6955,8 @@ func TestExecSuccess(t *testing.T) {
|
|||
Value: []byte("10"),
|
||||
},
|
||||
}
|
||||
resultExpected := []netstorage.Result{r1, r2, r3, r4}
|
||||
// expected sorted output for strings 1, 10, 2, 3
|
||||
resultExpected := []netstorage.Result{r1, r4, r2, r3}
|
||||
f(q, resultExpected)
|
||||
})
|
||||
t.Run(`count_values without (baz)`, func(t *testing.T) {
|
||||
|
@ -7008,6 +7010,44 @@ func TestExecSuccess(t *testing.T) {
|
|||
resultExpected := []netstorage.Result{r1, r2, r3}
|
||||
f(q, resultExpected)
|
||||
})
|
||||
t.Run(`result sorting`, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
q := `label_set(1, "instance", "localhost:1001", "type", "free")
|
||||
or label_set(1, "instance", "localhost:1001", "type", "buffers")
|
||||
or label_set(1, "instance", "localhost:1000", "type", "buffers")
|
||||
or label_set(1, "instance", "localhost:1000", "type", "free")
|
||||
`
|
||||
r1 := netstorage.Result{
|
||||
MetricName: metricNameExpected,
|
||||
Values: []float64{1, 1, 1, 1, 1, 1},
|
||||
Timestamps: timestampsExpected,
|
||||
}
|
||||
testAddLabels(t, &r1.MetricName,
|
||||
"instance", "localhost:1000", "type", "buffers")
|
||||
r2 := netstorage.Result{
|
||||
MetricName: metricNameExpected,
|
||||
Values: []float64{1, 1, 1, 1, 1, 1},
|
||||
Timestamps: timestampsExpected,
|
||||
}
|
||||
testAddLabels(t, &r2.MetricName,
|
||||
"instance", "localhost:1000", "type", "free")
|
||||
r3 := netstorage.Result{
|
||||
MetricName: metricNameExpected,
|
||||
Values: []float64{1, 1, 1, 1, 1, 1},
|
||||
Timestamps: timestampsExpected,
|
||||
}
|
||||
testAddLabels(t, &r3.MetricName,
|
||||
"instance", "localhost:1001", "type", "buffers")
|
||||
r4 := netstorage.Result{
|
||||
MetricName: metricNameExpected,
|
||||
Values: []float64{1, 1, 1, 1, 1, 1},
|
||||
Timestamps: timestampsExpected,
|
||||
}
|
||||
testAddLabels(t, &r4.MetricName,
|
||||
"instance", "localhost:1001", "type", "free")
|
||||
resultExpected := []netstorage.Result{r1, r2, r3, r4}
|
||||
f(q, resultExpected)
|
||||
})
|
||||
}
|
||||
|
||||
func TestExecError(t *testing.T) {
|
||||
|
@ -7285,3 +7325,16 @@ func testMetricNamesEqual(t *testing.T, mn, mnExpected *storage.MetricName, pos
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func testAddLabels(t *testing.T, mn *storage.MetricName, labels ...string) {
|
||||
t.Helper()
|
||||
if len(labels)%2 > 0 {
|
||||
t.Fatalf("uneven number of labels passed: %v", labels)
|
||||
}
|
||||
for i := 0; i < len(labels); i += 2 {
|
||||
mn.Tags = append(mn.Tags, storage.Tag{
|
||||
Key: []byte(labels[i]),
|
||||
Value: []byte(labels[i+1]),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -318,6 +318,18 @@ func marshalMetricTagsFast(dst []byte, tags []storage.Tag) []byte {
|
|||
return dst
|
||||
}
|
||||
|
||||
func metricNameToBytes(dst []byte, mn *storage.MetricName) []byte {
|
||||
dst = marshalBytesFast(dst, mn.MetricGroup)
|
||||
sortMetricTags(mn.Tags)
|
||||
for i := range mn.Tags {
|
||||
tag := &mn.Tags[i]
|
||||
dst = append(dst, tag.Key...)
|
||||
dst = append(dst, tag.Value...)
|
||||
dst = append(dst, ","...)
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
func marshalMetricNameSorted(dst []byte, mn *storage.MetricName) []byte {
|
||||
dst = marshalBytesFast(dst, mn.MetricGroup)
|
||||
sortMetricTags(mn.Tags)
|
||||
|
|
Loading…
Reference in a new issue