mirror of
https://github.com/prometheus/prometheus.git
synced 2025-01-12 06:17:27 -08:00
labels: improve Get method for stringlabels build (#12485)
Inline one call to `decodeString`, and skip decoding the value string until we find a match for the name. Do a quick check on the first character in each string, and exit early if we've gone past - labels are sorted in order. Also improve tests and benchmark: * labels: test Get with varying lengths - it's not typical for Prometheus labels to all be the same length. * extend benchmark with label not found --------- Signed-off-by: Bryan Boreham <bjboreham@gmail.com>
This commit is contained in:
parent
446dff01ea
commit
e1115ae58d
|
@ -273,13 +273,27 @@ func (ls Labels) Copy() Labels {
|
||||||
// Get returns the value for the label with the given name.
|
// Get returns the value for the label with the given name.
|
||||||
// Returns an empty string if the label doesn't exist.
|
// Returns an empty string if the label doesn't exist.
|
||||||
func (ls Labels) Get(name string) string {
|
func (ls Labels) Get(name string) string {
|
||||||
|
if name == "" { // Avoid crash in loop if someone asks for "".
|
||||||
|
return "" // Prometheus does not store blank label names.
|
||||||
|
}
|
||||||
for i := 0; i < len(ls.data); {
|
for i := 0; i < len(ls.data); {
|
||||||
var lName, lValue string
|
var size int
|
||||||
lName, i = decodeString(ls.data, i)
|
size, i = decodeSize(ls.data, i)
|
||||||
lValue, i = decodeString(ls.data, i)
|
if ls.data[i] == name[0] {
|
||||||
if lName == name {
|
lName := ls.data[i : i+size]
|
||||||
return lValue
|
i += size
|
||||||
|
if lName == name {
|
||||||
|
lValue, _ := decodeString(ls.data, i)
|
||||||
|
return lValue
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if ls.data[i] > name[0] { // Stop looking if we've gone past.
|
||||||
|
break
|
||||||
|
}
|
||||||
|
i += size
|
||||||
}
|
}
|
||||||
|
size, i = decodeSize(ls.data, i)
|
||||||
|
i += size
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
|
@ -443,7 +443,8 @@ func TestLabels_Has(t *testing.T) {
|
||||||
|
|
||||||
func TestLabels_Get(t *testing.T) {
|
func TestLabels_Get(t *testing.T) {
|
||||||
require.Equal(t, "", FromStrings("aaa", "111", "bbb", "222").Get("foo"))
|
require.Equal(t, "", FromStrings("aaa", "111", "bbb", "222").Get("foo"))
|
||||||
require.Equal(t, "111", FromStrings("aaa", "111", "bbb", "222").Get("aaa"))
|
require.Equal(t, "111", FromStrings("aaaa", "111", "bbb", "222").Get("aaaa"))
|
||||||
|
require.Equal(t, "222", FromStrings("aaaa", "111", "bbb", "222").Get("bbb"))
|
||||||
}
|
}
|
||||||
|
|
||||||
// BenchmarkLabels_Get was written to check whether a binary search can improve the performance vs the linear search implementation
|
// BenchmarkLabels_Get was written to check whether a binary search can improve the performance vs the linear search implementation
|
||||||
|
@ -463,7 +464,7 @@ func BenchmarkLabels_Get(b *testing.B) {
|
||||||
maxLabels := 30
|
maxLabels := 30
|
||||||
allLabels := make([]Label, maxLabels)
|
allLabels := make([]Label, maxLabels)
|
||||||
for i := 0; i < maxLabels; i++ {
|
for i := 0; i < maxLabels; i++ {
|
||||||
allLabels[i] = Label{Name: strings.Repeat(string('a'+byte(i)), 5)}
|
allLabels[i] = Label{Name: strings.Repeat(string('a'+byte(i)), 5+(i%5))}
|
||||||
}
|
}
|
||||||
for _, size := range []int{5, 10, maxLabels} {
|
for _, size := range []int{5, 10, maxLabels} {
|
||||||
b.Run(fmt.Sprintf("with %d labels", size), func(b *testing.B) {
|
b.Run(fmt.Sprintf("with %d labels", size), func(b *testing.B) {
|
||||||
|
@ -474,6 +475,7 @@ func BenchmarkLabels_Get(b *testing.B) {
|
||||||
{"get first label", allLabels[0].Name},
|
{"get first label", allLabels[0].Name},
|
||||||
{"get middle label", allLabels[size/2].Name},
|
{"get middle label", allLabels[size/2].Name},
|
||||||
{"get last label", allLabels[size-1].Name},
|
{"get last label", allLabels[size-1].Name},
|
||||||
|
{"get not-found label", "benchmark"},
|
||||||
} {
|
} {
|
||||||
b.Run(scenario.desc, func(b *testing.B) {
|
b.Run(scenario.desc, func(b *testing.B) {
|
||||||
b.ResetTimer()
|
b.ResetTimer()
|
||||||
|
|
Loading…
Reference in a new issue