@@ -45,10 +45,13 @@ var separatorByteSlice = []byte{model.SeparatorByte} // For convenient use with
45
45
type CachedTGatherer struct {
46
46
metricFamiliesByName map [string ]* family
47
47
mMu sync.RWMutex
48
+
49
+ desiredTouchState bool
48
50
}
49
51
50
52
func NewCachedTGatherer () * CachedTGatherer {
51
53
return & CachedTGatherer {
54
+ desiredTouchState : true ,
52
55
metricFamiliesByName : map [string ]* family {},
53
56
}
54
57
}
@@ -57,30 +60,19 @@ type family struct {
57
60
* dto.MetricFamily
58
61
59
62
metricsByHash map [uint64 ]* metric
60
- touched bool
63
+ touchState bool
64
+ needsRebuild bool
61
65
}
62
66
63
67
type metric struct {
64
68
* dto.Metric
65
- touched bool
69
+ touchState bool
66
70
}
67
71
68
72
// normalizeMetricFamilies returns a MetricFamily slice with empty
69
73
// MetricFamilies pruned and the remaining MetricFamilies sorted by name within
70
74
// the slice, with the contained Metrics sorted within each MetricFamily.
71
75
func normalizeMetricFamilies (metricFamiliesByName map [string ]* family ) []* dto.MetricFamily {
72
- // TODO(bwplotka): We could optimize this further by bookkeeping this slice in place.
73
- for _ , mf := range metricFamiliesByName {
74
- if cap (mf .Metric ) < len (mf .metricsByHash ) {
75
- mf .Metric = make ([]* dto.Metric , 0 , len (mf .metricsByHash ))
76
- }
77
- mf .Metric = mf .Metric [:0 ]
78
- for _ , m := range mf .metricsByHash {
79
- mf .Metric = append (mf .Metric , m .Metric )
80
- }
81
- sort .Sort (internal .MetricSorter (mf .Metric ))
82
- }
83
-
84
76
names := make ([]string , 0 , len (metricFamiliesByName ))
85
77
for name , mf := range metricFamiliesByName {
86
78
if len (mf .Metric ) > 0 {
@@ -98,9 +90,6 @@ func normalizeMetricFamilies(metricFamiliesByName map[string]*family) []*dto.Met
98
90
// Gather implements TransactionalGatherer interface.
99
91
func (c * CachedTGatherer ) Gather () (_ []* dto.MetricFamily , done func (), err error ) {
100
92
c .mMu .RLock ()
101
-
102
- // BenchmarkCachedTGatherer_Update shows, even for 1 million metrics among 1000 families
103
- // this is efficient enough (~400ms and ~50 kB per op), no need to cache it for now.
104
93
return normalizeMetricFamilies (c .metricFamiliesByName ), c .mMu .RUnlock , nil
105
94
}
106
95
@@ -180,7 +169,10 @@ func (c *CachedTGatherer) Update(reset bool, inserts []Insert, deletions []Key)
180
169
}
181
170
mf .Name = & inserts [i ].FQName
182
171
}
183
- mf .touched = true
172
+ if reset {
173
+ mf .touchState = c .desiredTouchState
174
+ }
175
+
184
176
mf .Type = inserts [i ].ValueType .ToDTO ()
185
177
mf .Help = & inserts [i ].Help
186
178
@@ -200,8 +192,11 @@ func (c *CachedTGatherer) Update(reset bool, inserts []Insert, deletions []Key)
200
192
})
201
193
}
202
194
sort .Sort (internal .LabelPairSorter (m .Label ))
195
+ mf .needsRebuild = true
196
+ }
197
+ if reset {
198
+ m .touchState = c .desiredTouchState
203
199
}
204
- m .touched = true
205
200
206
201
switch inserts [i ].ValueType {
207
202
case prometheus .CounterValue :
@@ -263,18 +258,19 @@ func (c *CachedTGatherer) Update(reset bool, inserts []Insert, deletions []Key)
263
258
continue
264
259
}
265
260
261
+ mf .needsRebuild = true
266
262
delete (mf .metricsByHash , hSum )
267
263
}
268
264
269
265
if reset {
270
266
// Trading off-time instead of memory allocated for otherwise needed replacement map.
271
267
for name , mf := range c .metricFamiliesByName {
272
- if ! mf .touched {
268
+ if mf .touchState != c . desiredTouchState {
273
269
delete (c .metricFamiliesByName , name )
274
270
continue
275
271
}
276
272
for hash , m := range mf .metricsByHash {
277
- if ! m . touched {
273
+ if m . touchState != c . desiredTouchState {
278
274
delete (mf .metricsByHash , hash )
279
275
continue
280
276
}
@@ -283,15 +279,23 @@ func (c *CachedTGatherer) Update(reset bool, inserts []Insert, deletions []Key)
283
279
delete (c .metricFamiliesByName , name )
284
280
}
285
281
}
282
+
283
+ // Avoid resetting state by flipping what we will expect in the next update.
284
+ c .desiredTouchState = ! c .desiredTouchState
286
285
}
287
286
288
- // TODO(bwplotka): Potentially move this only for reset, but then code would assume
289
- // you either only update or only reset update. For now we can live with small overhead.
290
287
for _ , mf := range c .metricFamiliesByName {
291
- mf .touched = false
288
+ if ! mf .needsRebuild {
289
+ continue
290
+ }
291
+
292
+ mf .Metric = mf .Metric [:0 ]
292
293
for _ , m := range mf .metricsByHash {
293
- m . touched = false
294
+ mf . Metric = append ( mf . Metric , m . Metric )
294
295
}
296
+ sort .Sort (internal .MetricSorter (mf .Metric ))
297
+
298
+ mf .needsRebuild = false
295
299
}
296
300
297
301
return errs .MaybeUnwrap ()
0 commit comments