1
1
package index
2
2
3
3
import (
4
+ "math"
4
5
"sort"
5
6
"sync"
6
7
"unsafe"
@@ -88,12 +89,68 @@ func (ii *InvertedIndex) Delete(labels labels.Labels, fp model.Fingerprint) {
88
89
// NB slice entries are sorted in fp order.
89
90
type indexEntry struct {
90
91
name string
91
- fps map [string ]indexValueEntry
92
+ fps map [string ]* indexValueEntry
92
93
}
93
94
94
95
type indexValueEntry struct {
95
96
value string
96
- fps []model.Fingerprint
97
+ shards [][]model.Fingerprint
98
+ }
99
+
100
+
101
+ const indexValueShards = 200
102
+
103
+ func newIndexValueEntry (value string ) * indexValueEntry {
104
+ shards := make ([][]model.Fingerprint , indexValueShards )
105
+ return & indexValueEntry {
106
+ value : value ,
107
+ shards : shards ,
108
+ }
109
+ }
110
+
111
+ func (c * indexValueEntry ) fps () []model.Fingerprint {
112
+ var fps []model.Fingerprint
113
+ for _ , shard := range c .shards {
114
+ fps = append (fps , shard ... )
115
+ }
116
+ return fps
117
+ }
118
+
119
+ func (c * indexValueEntry ) delete (fp model.Fingerprint ){
120
+ num := c .shard (fp )
121
+ fps := c .shards [num ]
122
+ j := sort .Search (len (fps ), func (i int ) bool {
123
+ return fps [i ] >= fp
124
+ })
125
+ c .shards [num ] = fps [:j + copy (fps [j :], fps [j + 1 :])]
126
+ if len (c .shards [num ]) == 0 {
127
+ c .shards [num ] = []model.Fingerprint {}
128
+ }
129
+ }
130
+
131
+ func (c * indexValueEntry ) length () int {
132
+ var i int
133
+ for _ , shard := range c .shards {
134
+ i += len (shard )
135
+ }
136
+ return i
137
+ }
138
+
139
+ func (c * indexValueEntry ) shard (fp model.Fingerprint ) int {
140
+ return int (math .Floor (float64 (len (c .shards )) * float64 (fp ) / math .MaxUint64 ))
141
+ }
142
+
143
+ func (c * indexValueEntry ) add (fp model.Fingerprint ){
144
+ num := c .shard (fp )
145
+ fps := c .shards [num ]
146
+ // Insert into the right position to keep fingerprints sorted
147
+ j := sort .Search (len (fps ), func (i int ) bool {
148
+ return fps [i ] >= fp
149
+ })
150
+ fps = append (fps , 0 )
151
+ copy (fps [j + 1 :], fps [j :])
152
+ fps [j ] = fp
153
+ c .shards [num ] = fps
97
154
}
98
155
99
156
type unlockIndex map [string ]indexEntry
@@ -126,23 +183,15 @@ func (shard *indexShard) add(metric []client.LabelAdapter, fp model.Fingerprint)
126
183
if ! ok {
127
184
values = indexEntry {
128
185
name : copyString (pair .Name ),
129
- fps : map [string ]indexValueEntry {},
186
+ fps : map [string ]* indexValueEntry {},
130
187
}
131
188
shard .idx [values .name ] = values
132
189
}
133
190
fingerprints , ok := values .fps [pair .Value ]
134
191
if ! ok {
135
- fingerprints = indexValueEntry {
136
- value : copyString (pair .Value ),
137
- }
192
+ fingerprints = newIndexValueEntry (copyString (pair .Value ))
138
193
}
139
- // Insert into the right position to keep fingerprints sorted
140
- j := sort .Search (len (fingerprints .fps ), func (i int ) bool {
141
- return fingerprints .fps [i ] >= fp
142
- })
143
- fingerprints .fps = append (fingerprints .fps , 0 )
144
- copy (fingerprints .fps [j + 1 :], fingerprints .fps [j :])
145
- fingerprints .fps [j ] = fp
194
+ fingerprints .add (fp )
146
195
values .fps [fingerprints .value ] = fingerprints
147
196
internedLabels [i ] = labels.Label {Name : values .name , Value : fingerprints .value }
148
197
}
@@ -167,21 +216,26 @@ func (shard *indexShard) lookup(matchers []*labels.Matcher) []model.Fingerprint
167
216
}
168
217
var toIntersect model.Fingerprints
169
218
if matcher .Type == labels .MatchEqual {
170
- fps := values .fps [matcher .Value ]
171
- toIntersect = append (toIntersect , fps .fps ... ) // deliberate copy
219
+ fps , ok := values .fps [matcher .Value ]
220
+ if ok {
221
+ toIntersect = append (toIntersect , fps .fps ()... ) // deliberate copy
222
+ }
172
223
} else if matcher .Type == labels .MatchRegexp && len (chunk .FindSetMatches (matcher .Value )) > 0 {
173
224
// The lookup is of the form `=~"a|b|c|d"`
174
225
set := chunk .FindSetMatches (matcher .Value )
175
226
for _ , value := range set {
176
- toIntersect = append (toIntersect , values .fps [value ].fps ... )
227
+ fps , ok := values .fps [value ]
228
+ if ok {
229
+ toIntersect = append (toIntersect , fps .fps ()... )
230
+ }
177
231
}
178
232
sort .Sort (toIntersect )
179
233
} else {
180
234
// accumulate the matching fingerprints (which are all distinct)
181
235
// then sort to maintain the invariant
182
236
for value , fps := range values .fps {
183
237
if matcher .Matches (value ) {
184
- toIntersect = append (toIntersect , fps .fps ... )
238
+ toIntersect = append (toIntersect , fps .fps () ... )
185
239
}
186
240
}
187
241
sort .Sort (toIntersect )
@@ -240,13 +294,9 @@ func (shard *indexShard) delete(labels labels.Labels, fp model.Fingerprint) {
240
294
if ! ok {
241
295
continue
242
296
}
297
+ fingerprints .delete (fp )
243
298
244
- j := sort .Search (len (fingerprints .fps ), func (i int ) bool {
245
- return fingerprints .fps [i ] >= fp
246
- })
247
- fingerprints .fps = fingerprints .fps [:j + copy (fingerprints .fps [j :], fingerprints .fps [j + 1 :])]
248
-
249
- if len (fingerprints .fps ) == 0 {
299
+ if fingerprints .length () == 0 {
250
300
delete (values .fps , value )
251
301
} else {
252
302
values .fps [value ] = fingerprints
0 commit comments