master
go 196 lines 4.13 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 package metrix
4
5 import (
6 "sort"
7 "strings"
8 )
9
10 type compiledLabelSet struct {
11 owner meterBackend // owning backend; used to reject foreign handles
12 items []Label // canonical sorted labels
13 key string // canonical packed key for fast identity joins
14 }
15
16 type labelView struct {
17 items []Label
18 }
19
20 func (v labelView) Len() int { return len(v.items) }
21
22 func (v labelView) Get(key string) (string, bool) {
23 for _, l := range v.items {
24 if l.Key == key {
25 return l.Value, true
26 }
27 }
28 return "", false
29 }
30
31 func (v labelView) Range(fn func(key, value string) bool) {
32 for _, l := range v.items {
33 if !fn(l.Key, l.Value) {
34 return
35 }
36 }
37 }
38
39 func (v labelView) CloneMap() map[string]string {
40 m := make(map[string]string, len(v.items))
41 for _, l := range v.items {
42 m[l.Key] = l.Value
43 }
44 return m
45 }
46
47 func canonicalizeLabels(input map[string]string) ([]Label, string, error) {
48 if len(input) == 0 {
49 return nil, "", nil
50 }
51
52 keys := make([]string, 0, len(input))
53 for k := range input {
54 keys = append(keys, k)
55 }
56 sort.Strings(keys)
57
58 labels := make([]Label, 0, len(keys))
59 var b strings.Builder
60 for _, k := range keys {
61 if k == "" {
62 return nil, "", errInvalidLabelKey
63 }
64 v := input[k]
65 labels = append(labels, Label{Key: k, Value: v})
66 b.WriteString(k)
67 b.WriteByte('\xff')
68 b.WriteString(v)
69 b.WriteByte('\xff')
70 }
71 return labels, b.String(), nil
72 }
73
74 // labelsFromSet merges precompiled label sets and validates ownership/duplicates.
75 func labelsFromSet(sets []LabelSet, owner meterBackend) ([]Label, string, error) {
76 if len(sets) == 0 {
77 return nil, "", nil
78 }
79
80 if len(sets) == 1 {
81 set, err := validatedLabelSet(sets[0], owner)
82 if err != nil {
83 return nil, "", err
84 }
85 // Reuse immutable precompiled labels directly on the single-set path.
86 return set.items, set.key, nil
87 }
88
89 if len(sets) == 2 {
90 left, err := validatedLabelSet(sets[0], owner)
91 if err != nil {
92 return nil, "", err
93 }
94 right, err := validatedLabelSet(sets[1], owner)
95 if err != nil {
96 return nil, "", err
97 }
98 return mergeTwoCompiledLabelSets(left, right)
99 }
100
101 merged := make(map[string]string)
102 for _, ls := range sets {
103 set, err := validatedLabelSet(ls, owner)
104 if err != nil {
105 return nil, "", err
106 }
107 for _, l := range set.items {
108 if _, ok := merged[l.Key]; ok {
109 return nil, "", errDuplicateLabelKey
110 }
111 merged[l.Key] = l.Value
112 }
113 }
114
115 return canonicalizeLabels(merged)
116 }
117
118 func validatedLabelSet(ls LabelSet, owner meterBackend) (*compiledLabelSet, error) {
119 if ls.set == nil {
120 return nil, errInvalidLabelSet
121 }
122 if ls.set.owner != owner {
123 return nil, errForeignLabelSet
124 }
125 return ls.set, nil
126 }
127
128 func mergeTwoCompiledLabelSets(left, right *compiledLabelSet) ([]Label, string, error) {
129 if len(left.items) == 0 {
130 // Reuse immutable precompiled labels directly.
131 return right.items, right.key, nil
132 }
133 if len(right.items) == 0 {
134 // Reuse immutable precompiled labels directly.
135 return left.items, left.key, nil
136 }
137
138 out := make([]Label, 0, len(left.items)+len(right.items))
139 var b strings.Builder
140
141 i := 0
142 j := 0
143 for i < len(left.items) && j < len(right.items) {
144 li := left.items[i]
145 rj := right.items[j]
146 if li.Key == rj.Key {
147 return nil, "", errDuplicateLabelKey
148 }
149 if li.Key < rj.Key {
150 out = append(out, li)
151 b.WriteString(li.Key)
152 b.WriteByte('\xff')
153 b.WriteString(li.Value)
154 b.WriteByte('\xff')
155 i++
156 continue
157 }
158 out = append(out, rj)
159 b.WriteString(rj.Key)
160 b.WriteByte('\xff')
161 b.WriteString(rj.Value)
162 b.WriteByte('\xff')
163 j++
164 }
165
166 for ; i < len(left.items); i++ {
167 li := left.items[i]
168 out = append(out, li)
169 b.WriteString(li.Key)
170 b.WriteByte('\xff')
171 b.WriteString(li.Value)
172 b.WriteByte('\xff')
173 }
174 for ; j < len(right.items); j++ {
175 rj := right.items[j]
176 out = append(out, rj)
177 b.WriteString(rj.Key)
178 b.WriteByte('\xff')
179 b.WriteString(rj.Value)
180 b.WriteByte('\xff')
181 }
182 return out, b.String(), nil
183 }
184
185 func appendLabelSets(base []LabelSet, extra []LabelSet) []LabelSet {
186 if len(extra) == 0 {
187 return base
188 }
189 if len(base) == 0 {
190 return extra
191 }
192 out := make([]LabelSet, 0, len(base)+len(extra))
193 out = append(out, base...)
194 out = append(out, extra...)
195 return out
196 }