11package collectors
22
33import (
4- "sort"
5- "strconv"
64 "time"
75
86 "github.com/prometheus-community/stackdriver_exporter/hash"
@@ -30,7 +28,7 @@ func (d *MetricDeduplicator) CheckAndMark(fqName string, labelKeys, labelValues
3028 return true // Duplicate detected
3129 }
3230 d .sentSignatures [signature ] = struct {}{} // Mark as seen
33- return false // Not a duplicate
31+ return false // Not a duplicate
3432}
3533
3634// hashLabelsTimestamp calculates a hash based on FQName, sorted labels, and timestamp.
@@ -39,37 +37,44 @@ func (d *MetricDeduplicator) hashLabelsTimestamp(fqName string, labelKeys, label
3937 dh = hash .Add (dh , fqName )
4038 dh = hash .AddByte (dh , hash .SeparatorByte )
4139
42- // Create label pairs for stable sorting
43- pairs := make ([]struct {
44- Key string
45- Value string
46- }, len (labelKeys ))
47- for i , key := range labelKeys {
48- // Ensure we don't go out of bounds if labelValues is shorter (shouldn't happen in normal flow)
49- val := ""
50- if i < len (labelValues ) {
51- val = labelValues [i ]
52- }
53- pairs [i ] = struct {
54- Key string
55- Value string
56- }{Key : key , Value : val }
40+ // Create indices for stable sorting
41+ indices := make ([]int , len (labelKeys ))
42+ for i := range indices {
43+ indices [i ] = i
5744 }
5845
59- // Sort pairs by key
60- sort .Slice (pairs , func (i , j int ) bool {
61- return pairs [i ].Key < pairs [j ].Key
62- })
46+ // Sort indices by key using a simple insertion sort
47+ // This is faster for small slices than sort.Slice
48+ for i := 0 ; i < len (indices ); i ++ {
49+ for j := i + 1 ; j < len (indices ); j ++ {
50+ if labelKeys [indices [i ]] > labelKeys [indices [j ]] {
51+ indices [i ], indices [j ] = indices [j ], indices [i ]
52+ }
53+ }
54+ }
6355
6456 // Add sorted key-value pairs to hash
65- for _ , pair := range pairs {
66- dh = hash .Add (dh , pair . Key )
57+ for _ , idx := range indices {
58+ dh = hash .Add (dh , labelKeys [ idx ] )
6759 dh = hash .AddByte (dh , hash .SeparatorByte )
68- dh = hash .Add (dh , pair .Value )
60+
61+ // Ensure we don't go out of bounds if labelValues is shorter
62+ if idx < len (labelValues ) {
63+ dh = hash .Add (dh , labelValues [idx ])
64+ }
6965 dh = hash .AddByte (dh , hash .SeparatorByte )
7066 }
7167
72- // Add timestamp (converted to string)
73- dh = hash .Add (dh , strconv .FormatInt (ts .UnixNano (), 10 ))
68+ // Add timestamp using binary operations instead of string conversion
69+ tsNano := ts .UnixNano ()
70+
71+ // Mix in the timestamp bytes directly using the FNV-1a algorithm
72+ dh = hash .AddUint64 (dh , uint64 (tsNano ))
73+
74+ // Mix in the high bits if they exist (for timestamps far in the future)
75+ if tsNano > 0xFFFFFFFF {
76+ dh = hash .AddUint64 (dh , uint64 (tsNano >> 32 ))
77+ }
78+
7479 return dh
7580}
0 commit comments