@@ -78,10 +78,17 @@ func (mc *CCacheMetric) AddRange(prev uint32, itergens []chunk.IterGen) {
78
78
return
79
79
}
80
80
81
+ if len (itergens ) == 1 {
82
+ mc .Add (prev , itergens [0 ])
83
+ return
84
+ }
85
+
81
86
mc .Lock ()
82
87
defer mc .Unlock ()
83
88
84
- ts := itergens [0 ].Ts
89
+ // handle the first one
90
+ itergen := itergens [0 ]
91
+ ts := itergen .Ts
85
92
86
93
// if previous chunk has not been passed we try to be smart and figure it out.
87
94
// this is common in a scenario where a metric continuously gets queried
@@ -93,46 +100,74 @@ func (mc *CCacheMetric) AddRange(prev uint32, itergens []chunk.IterGen) {
93
100
}
94
101
}
95
102
96
- for _ , itergen := range itergens {
97
- ts = itergen .Ts
98
-
99
- if _ , ok := mc .chunks [ts ]; ok {
100
- // chunk is already present. no need to error on that, just ignore it
101
- continue
102
- }
103
+ // if the previous chunk is cached, link it
104
+ if _ , ok := mc .chunks [prev ]; ok {
105
+ mc .chunks [prev ].Next = ts
106
+ } else {
107
+ prev = 0
108
+ }
103
109
110
+ // add chunk if we don't have it yet (most likely)
111
+ if _ , ok := mc .chunks [ts ]; ! ok {
104
112
mc .chunks [ts ] = & CCacheChunk {
105
113
Ts : ts ,
106
- Prev : 0 ,
107
- Next : 0 ,
114
+ Prev : prev ,
115
+ Next : itergens [ 1 ]. Ts ,
108
116
Itgen : itergen ,
109
117
}
118
+ }
110
119
111
- // if the previous chunk is cached, link in both directions
112
- if _ , ok := mc .chunks [prev ]; ok {
113
- mc .chunks [prev ].Next = ts
114
- mc .chunks [ts ].Prev = prev
120
+ prev = ts
121
+
122
+ // handle the 2nd until the last-but-one
123
+ for i := 1 ; i < len (itergens )- 1 ; i ++ {
124
+ itergen := itergens [i ]
125
+ ts := itergen .Ts
126
+ // add chunk if we don't have it yet (most likely)
127
+ if _ , ok := mc .chunks [ts ]; ! ok {
128
+ mc .chunks [ts ] = & CCacheChunk {
129
+ Ts : ts ,
130
+ Prev : prev ,
131
+ Next : itergens [i + 1 ].Ts ,
132
+ Itgen : itergen ,
133
+ }
115
134
}
116
135
prev = ts
117
136
}
118
137
119
- nextTs := mc .nextTs (ts )
138
+ // handle the last one
139
+ itergen = itergens [len (itergens )- 1 ]
140
+ ts = itergen .Ts
120
141
121
142
// if nextTs() can't figure out the end date it returns ts
122
- if nextTs > ts {
143
+ next := mc .nextTsCore (itergen , ts , prev , 0 )
144
+ if next == ts {
145
+ next = 0
146
+ } else {
123
147
// if the next chunk is cached, link in both directions
124
- if _ , ok := mc .chunks [nextTs ]; ok {
125
- mc .chunks [nextTs ].Prev = ts
126
- mc .chunks [ts ].Next = nextTs
148
+ if _ , ok := mc .chunks [next ]; ok {
149
+ mc .chunks [next ].Prev = ts
150
+ } else {
151
+ next = 0
127
152
}
128
153
}
129
154
155
+ // add chunk if we don't have it yet (most likely)
156
+ if _ , ok := mc .chunks [ts ]; ! ok {
157
+ mc .chunks [ts ] = & CCacheChunk {
158
+ Ts : ts ,
159
+ Prev : prev ,
160
+ Next : next ,
161
+ Itgen : itergen ,
162
+ }
163
+ }
130
164
// regenerate the list of sorted keys after adding a chunk
131
165
mc .generateKeys ()
132
166
133
167
return
134
168
}
135
169
170
+ // Add adds a chunk to the cache
136
171
func (mc * CCacheMetric ) Add (prev uint32 , itergen chunk.IterGen ) {
137
172
ts := itergen .Ts
138
173
@@ -201,24 +236,29 @@ func (mc *CCacheMetric) generateKeys() {
201
236
// assumes we already have at least a read lock
202
237
func (mc * CCacheMetric ) nextTs (ts uint32 ) uint32 {
203
238
chunk := mc .chunks [ts ]
204
- span := chunk .Itgen .Span
239
+ return mc .nextTsCore (chunk .Itgen , chunk .Ts , chunk .Prev , chunk .Next )
240
+ }
241
+
242
+ // nextTsCore returns the ts of the next chunk, given a chunks key properties
243
+ // (to the extent we know them). It guesses if necessary.
244
+ // assumes we already have at least a read lock
245
+ func (mc * CCacheMetric ) nextTsCore (itgen chunk.IterGen , ts , prev , next uint32 ) uint32 {
246
+ span := itgen .Span
205
247
if span > 0 {
206
248
// if the chunk is span-aware we don't need anything else
207
- return chunk . Ts + span
249
+ return ts + span
208
250
}
209
251
210
- if chunk .Next == 0 {
211
- if chunk .Prev == 0 {
212
- // if a chunk has no next and no previous chunk we have to assume it's length is 0
213
- return chunk .Ts
214
- } else {
215
- // if chunk has no next chunk, but has a previous one, we assume the length of this one is same as the previous one
216
- return chunk .Ts + (chunk .Ts - chunk .Prev )
217
- }
218
- } else {
219
- // if chunk has a next chunk, then that's the ts we need
220
- return chunk .Next
252
+ // if chunk has a next chunk, then that's the ts we need
253
+ if next != 0 {
254
+ return next
255
+ }
256
+ // if chunk has no next chunk, but has a previous one, we assume the length of this one is same as the previous one
257
+ if prev != 0 {
258
+ return ts + (ts - prev )
221
259
}
260
+ // if a chunk has no next and no previous chunk we have to assume it's length is 0
261
+ return ts
222
262
}
223
263
224
264
// lastTs returns the last Ts of this metric cache
0 commit comments