@@ -5,17 +5,16 @@ import (
55 "encoding/binary"
66 "encoding/hex"
77 "fmt"
8+ "slices"
89 "sort"
910 "strconv"
1011 "strings"
1112
1213 "github.com/cespare/xxhash/v2"
1314 pmodel "github.com/prometheus/common/model"
1415 "github.com/prometheus/prometheus/model/labels"
15- "github.com/prometheus/prometheus/promql/parser"
1616
1717 typesv1 "github.com/grafana/pyroscope/api/gen/proto/go/types/v1"
18- "github.com/grafana/pyroscope/pkg/slices"
1918 "github.com/grafana/pyroscope/pkg/util"
2019)
2120
@@ -102,52 +101,25 @@ func (ls Labels) Hash() uint64 {
102101 return xxhash .Sum64 (b )
103102}
104103
105- // HashForLabels returns a hash value for the labels matching the provided names.
106- // 'names' have to be sorted in ascending order.
107- func (ls Labels ) HashForLabels (b []byte , names ... string ) (uint64 , []byte ) {
108- b = b [:0 ]
109- i , j := 0 , 0
110- for i < len (ls ) && j < len (names ) {
111- if names [j ] < ls [i ].Name {
112- j ++
113- } else if ls [i ].Name < names [j ] {
114- i ++
115- } else {
116- b = append (b , ls [i ].Name ... )
117- b = append (b , seps [0 ])
118- b = append (b , ls [i ].Value ... )
119- b = append (b , seps [0 ])
120- i ++
121- j ++
122- }
123- }
124- return xxhash .Sum64 (b ), b
125- }
126-
127104// BytesWithLabels is just as Bytes(), but only for labels matching names.
128- // 'names' have to be sorted in ascending order.
129105// It uses an byte invalid character as a separator and so should not be used for printing.
130106func (ls Labels ) BytesWithLabels (buf []byte , names ... string ) []byte {
131- b := bytes .NewBuffer (buf [:0 ])
132- b .WriteByte (labelSep )
133- i , j := 0 , 0
134- for i < len (ls ) && j < len (names ) {
135- if names [j ] < ls [i ].Name {
136- j ++
137- } else if ls [i ].Name < names [j ] {
138- i ++
139- } else {
140- if b .Len () > 1 {
141- b .WriteByte (seps [0 ])
107+ buf = buf [:0 ]
108+ buf = append (buf , labelSep )
109+ for _ , name := range names {
110+ for _ , l := range ls {
111+ if l .Name == name {
112+ if len (buf ) > 1 {
113+ buf = append (buf , seps [0 ])
114+ }
115+ buf = append (buf , l .Name ... )
116+ buf = append (buf , seps [0 ])
117+ buf = append (buf , l .Value ... )
118+ break
142119 }
143- b .WriteString (ls [i ].Name )
144- b .WriteByte (seps [0 ])
145- b .WriteString (ls [i ].Value )
146- i ++
147- j ++
148120 }
149121 }
150- return b . Bytes ()
122+ return buf
151123}
152124
153125func (ls Labels ) ToPrometheusLabels () labels.Labels {
@@ -180,22 +152,18 @@ func IsLabelAllowedForIngestion(name string) bool {
180152 return allowed
181153}
182154
183- // WithLabels returns a subset of Labels that matches match with the provided label names.
155+ // WithLabels returns a subset of Labels that match with the provided label names.
184156func (ls Labels ) WithLabels (names ... string ) Labels {
185- matchedLabels := Labels {}
186-
187- nameSet := make (map [string ]struct {}, len (names ))
188- for _ , n := range names {
189- nameSet [n ] = struct {}{}
190- }
191-
192- for _ , v := range ls {
193- if _ , ok := nameSet [v .Name ]; ok {
194- matchedLabels = append (matchedLabels , v )
157+ matched := make (Labels , 0 , len (names ))
158+ for _ , name := range names {
159+ for _ , l := range ls {
160+ if l .Name == name {
161+ matched = append (matched , l )
162+ break
163+ }
195164 }
196165 }
197-
198- return matchedLabels
166+ return matched
199167}
200168
201169// Get returns the value for the label with the given name.
@@ -221,37 +189,42 @@ func (ls Labels) GetLabel(name string) (*typesv1.LabelPair, bool) {
221189
222190// Delete removes the first label encountered with the name given in place.
223191func (ls Labels ) Delete (name string ) Labels {
224- return slices .RemoveInPlace (ls , func (pair * typesv1.LabelPair , i int ) bool {
225- return pair .Name == name
226- })
192+ for i , l := range ls {
193+ if l .Name == name {
194+ return slices .Delete (ls , i , i + 1 )
195+ }
196+ }
197+ return ls
227198}
228199
229- // Insert adds the given label to the set of labels.
230- // It assumes the labels are ordered
231- func (ls * Labels ) Insert (name , value string ) {
232- // Find the index where the new label should be inserted
200+ // InsertSorted adds the given label to the set of labels.
201+ // It assumes the labels are sorted lexicographically.
202+ func (ls Labels ) InsertSorted (name , value string ) Labels {
203+ // Find the index where the new label should be inserted.
204+ // TODO: Use binary search on large label sets.
233205 index := - 1
234- for i , label := range * ls {
206+ for i , label := range ls {
235207 if label .Name > name {
236208 index = i
237209 break
238210 }
239211 if label .Name == name {
240212 label .Value = value
241- return
213+ return ls
242214 }
243215 }
244- // Insert the new label at the found index
216+ // Insert the new label at the found index.
245217 l := & typesv1.LabelPair {
246218 Name : name ,
247219 Value : value ,
248220 }
249- * ls = append (* ls , l )
221+ c : = append (ls , l )
250222 if index == - 1 {
251- return
223+ return c
252224 }
253- copy ((* ls )[index + 1 :], (* ls )[index :])
254- (* ls )[index ] = l
225+ copy ((c )[index + 1 :], (c )[index :])
226+ (c )[index ] = l
227+ return c
255228}
256229
257230func (ls Labels ) Clone () Labels {
@@ -301,22 +274,6 @@ func LabelPairsString(lbs []*typesv1.LabelPair) string {
301274 return b .String ()
302275}
303276
304- // StringToLabelsPairs converts a string representation of label pairs to a slice of label pairs.
305- func StringToLabelsPairs (s string ) ([]* typesv1.LabelPair , error ) {
306- matchers , err := parser .ParseMetricSelector (s )
307- if err != nil {
308- return nil , err
309- }
310- result := make ([]* typesv1.LabelPair , len (matchers ))
311- for i := range matchers {
312- result [i ] = & typesv1.LabelPair {
313- Name : matchers [i ].Name ,
314- Value : matchers [i ].Value ,
315- }
316- }
317- return result , nil
318- }
319-
320277// LabelsFromStrings creates new labels from pairs of strings.
321278func LabelsFromStrings (ss ... string ) Labels {
322279 if len (ss )% 2 != 0 {
@@ -454,33 +411,6 @@ Outer:
454411 return append (res , b .add ... )
455412}
456413
457- // StableHash is a labels hashing implementation which is guaranteed to not change over time.
458- // This function should be used whenever labels hashing backward compatibility must be guaranteed.
459- func StableHash (ls labels.Labels ) uint64 {
460- // Use xxhash.Sum64(b) for fast path as it's faster.
461- b := make ([]byte , 0 , 1024 )
462- for i , v := range ls {
463- if len (b )+ len (v .Name )+ len (v .Value )+ 2 >= cap (b ) {
464- // If labels entry is 1KB+ do not allocate whole entry.
465- h := xxhash .New ()
466- _ , _ = h .Write (b )
467- for _ , v := range ls [i :] {
468- _ , _ = h .WriteString (v .Name )
469- _ , _ = h .Write (seps )
470- _ , _ = h .WriteString (v .Value )
471- _ , _ = h .Write (seps )
472- }
473- return h .Sum64 ()
474- }
475-
476- b = append (b , v .Name ... )
477- b = append (b , seps [0 ])
478- b = append (b , v .Value ... )
479- b = append (b , seps [0 ])
480- }
481- return xxhash .Sum64 (b )
482- }
483-
484414type SessionID uint64
485415
486416func (s SessionID ) String () string {
0 commit comments