Efficient iteration and search in HashForLabels and HashWithoutLabels (#5707)
* Efficient iteration and search in Labels.HashForLabels Signed-off-by: Ganesh Vernekar <cs15btech11018@iith.ac.in> * Better names for variables Signed-off-by: Ganesh Vernekar <cs15btech11018@iith.ac.in> * HashWithoutLabels optimizations Signed-off-by: Ganesh Vernekar <cs15btech11018@iith.ac.in> * Refactor HashForLabels and HashWithoutLabels to take sorted names Signed-off-by: Ganesh Vernekar <cs15btech11018@iith.ac.in> * Fix review comments Signed-off-by: Ganesh Vernekar <cs15btech11018@iith.ac.in>
This commit is contained in:
parent
06bdaf076f
commit
588eb20018
|
@ -131,44 +131,46 @@ func (ls Labels) Hash() uint64 {
|
||||||
}
|
}
|
||||||
|
|
||||||
// HashForLabels returns a hash value for the labels matching the provided names.
|
// HashForLabels returns a hash value for the labels matching the provided names.
|
||||||
func (ls Labels) HashForLabels(names ...string) uint64 {
|
// 'names' have to be sorted in ascending order.
|
||||||
b := make([]byte, 0, 1024)
|
func (ls Labels) HashForLabels(b []byte, names ...string) (uint64, []byte) {
|
||||||
|
b = b[:0]
|
||||||
for _, v := range ls {
|
i, j := 0, 0
|
||||||
for _, n := range names {
|
for i < len(ls) && j < len(names) {
|
||||||
if v.Name == n {
|
if names[j] < ls[i].Name {
|
||||||
b = append(b, v.Name...)
|
j++
|
||||||
b = append(b, sep)
|
} else if ls[i].Name < names[j] {
|
||||||
b = append(b, v.Value...)
|
i++
|
||||||
b = append(b, sep)
|
} else {
|
||||||
break
|
b = append(b, ls[i].Name...)
|
||||||
}
|
b = append(b, sep)
|
||||||
|
b = append(b, ls[i].Value...)
|
||||||
|
b = append(b, sep)
|
||||||
|
i++
|
||||||
|
j++
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return xxhash.Sum64(b)
|
return xxhash.Sum64(b), b
|
||||||
}
|
}
|
||||||
|
|
||||||
// HashWithoutLabels returns a hash value for all labels except those matching
|
// HashWithoutLabels returns a hash value for all labels except those matching
|
||||||
// the provided names.
|
// the provided names.
|
||||||
func (ls Labels) HashWithoutLabels(names ...string) uint64 {
|
// 'names' have to be sorted in ascending order.
|
||||||
b := make([]byte, 0, 1024)
|
func (ls Labels) HashWithoutLabels(b []byte, names ...string) (uint64, []byte) {
|
||||||
|
b = b[:0]
|
||||||
Outer:
|
j := 0
|
||||||
for _, v := range ls {
|
for i := range ls {
|
||||||
if v.Name == MetricName {
|
for j < len(names) && names[j] < ls[i].Name {
|
||||||
|
j++
|
||||||
|
}
|
||||||
|
if ls[i].Name == MetricName || (j < len(names) && ls[i].Name == names[j]) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
for _, n := range names {
|
b = append(b, ls[i].Name...)
|
||||||
if v.Name == n {
|
|
||||||
continue Outer
|
|
||||||
}
|
|
||||||
}
|
|
||||||
b = append(b, v.Name...)
|
|
||||||
b = append(b, sep)
|
b = append(b, sep)
|
||||||
b = append(b, v.Value...)
|
b = append(b, ls[i].Value...)
|
||||||
b = append(b, sep)
|
b = append(b, sep)
|
||||||
}
|
}
|
||||||
return xxhash.Sum64(b)
|
return xxhash.Sum64(b), b
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy returns a copy of the labels.
|
// Copy returns a copy of the labels.
|
||||||
|
|
|
@ -1523,13 +1523,17 @@ func (ev *evaluator) VectorBinop(op ItemType, lhs, rhs Vector, matching *VectorM
|
||||||
// signatureFunc returns a function that calculates the signature for a metric
|
// signatureFunc returns a function that calculates the signature for a metric
|
||||||
// ignoring the provided labels. If on, then the given labels are only used instead.
|
// ignoring the provided labels. If on, then the given labels are only used instead.
|
||||||
func signatureFunc(on bool, names ...string) func(labels.Labels) uint64 {
|
func signatureFunc(on bool, names ...string) func(labels.Labels) uint64 {
|
||||||
// TODO(fabxc): ensure names are sorted and then use that and sortedness
|
sort.Strings(names)
|
||||||
// of labels by names to speed up the operations below.
|
|
||||||
// Alternatively, inline the hashing and don't build new label sets.
|
|
||||||
if on {
|
if on {
|
||||||
return func(lset labels.Labels) uint64 { return lset.HashForLabels(names...) }
|
return func(lset labels.Labels) uint64 {
|
||||||
|
h, _ := lset.HashForLabels(make([]byte, 0, 1024), names...)
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return func(lset labels.Labels) uint64 {
|
||||||
|
h, _ := lset.HashWithoutLabels(make([]byte, 0, 1024), names...)
|
||||||
|
return h
|
||||||
}
|
}
|
||||||
return func(lset labels.Labels) uint64 { return lset.HashWithoutLabels(names...) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// resultMetric returns the metric for the given sample(s) based on the Vector
|
// resultMetric returns the metric for the given sample(s) based on the Vector
|
||||||
|
@ -1722,8 +1726,9 @@ func (ev *evaluator) aggregation(op ItemType, grouping []string, without bool, p
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sort.Strings(grouping)
|
||||||
lb := labels.NewBuilder(nil)
|
lb := labels.NewBuilder(nil)
|
||||||
|
buf := make([]byte, 0, 1024)
|
||||||
for _, s := range vec {
|
for _, s := range vec {
|
||||||
metric := s.Metric
|
metric := s.Metric
|
||||||
|
|
||||||
|
@ -1737,9 +1742,9 @@ func (ev *evaluator) aggregation(op ItemType, grouping []string, without bool, p
|
||||||
groupingKey uint64
|
groupingKey uint64
|
||||||
)
|
)
|
||||||
if without {
|
if without {
|
||||||
groupingKey = metric.HashWithoutLabels(grouping...)
|
groupingKey, buf = metric.HashWithoutLabels(buf, grouping...)
|
||||||
} else {
|
} else {
|
||||||
groupingKey = metric.HashForLabels(grouping...)
|
groupingKey, buf = metric.HashForLabels(buf, grouping...)
|
||||||
}
|
}
|
||||||
|
|
||||||
group, ok := result[groupingKey]
|
group, ok := result[groupingKey]
|
||||||
|
|
Loading…
Reference in New Issue