@@ -45,11 +45,11 @@ func NewAggregateSeries(functions, col string, buckets int, interval, rollupTime
45
45
46
46
split := strings .Split (functions , "," )
47
47
var aggrMask AggrType
48
- aggrList := []AggrType {}
48
+ var aggrList []AggrType
49
49
for _ , s := range split {
50
50
aggr , ok := aggrTypeString [s ]
51
51
if ! ok {
52
- return nil , fmt .Errorf ("Invalid aggragator type %s" , s )
52
+ return nil , fmt .Errorf ("invalid aggragator type %s" , s )
53
53
}
54
54
aggrMask = aggrMask | aggr
55
55
aggrList = append (aggrList , aggr )
@@ -87,7 +87,7 @@ func (as *AggregateSeries) toAttrName(aggr AggrType) string {
87
87
}
88
88
89
89
func (as * AggregateSeries ) GetAttrNames () []string {
90
- names := []string {}
90
+ var names []string
91
91
92
92
for _ , aggr := range rawAggregators {
93
93
if aggr & as .aggrMask != 0 {
@@ -115,7 +115,7 @@ func (as *AggregateSeries) NewSetFromAttrs(
115
115
if aggr & as .aggrMask != 0 {
116
116
attrBlob , ok := (* attrs )[as .toAttrName (aggr )]
117
117
if ! ok {
118
- return nil , fmt .Errorf ("Aggregation Attribute %s was not found" , as .toAttrName (aggr ))
118
+ return nil , fmt .Errorf ("aggregation attribute %s was not found" , as .toAttrName (aggr ))
119
119
}
120
120
aggrArrays [aggr ] = utils .AsInt64Array (attrBlob .([]byte ))
121
121
dataArrays [aggr ] = make ([]float64 , length , length )
@@ -124,7 +124,6 @@ func (as *AggregateSeries) NewSetFromAttrs(
124
124
125
125
aggrSet := AggregateSet {length : length , interval : as .interval , overlapWin : as .overlapWindows }
126
126
aggrSet .dataArrays = dataArrays
127
- aggrSet .validCells = make ([]bool , length , length )
128
127
129
128
arrayIndex := start
130
129
i := 0
@@ -138,7 +137,6 @@ func (as *AggregateSeries) NewSetFromAttrs(
138
137
for aggr , array := range aggrArrays {
139
138
aggrSet .mergeArrayCell (aggr , cellIndex , array [arrayIndex ])
140
139
}
141
- aggrSet .setValid (i )
142
140
} else {
143
141
144
142
// overlapping time windows (last 1hr, 6hr, ..)
@@ -149,7 +147,6 @@ func (as *AggregateSeries) NewSetFromAttrs(
149
147
for aggr , array := range aggrArrays {
150
148
aggrSet .mergeArrayCell (aggr , i , array [arrayIndex ])
151
149
}
152
- aggrSet .setValid (i )
153
150
}
154
151
}
155
152
}
@@ -180,13 +177,11 @@ func (as *AggregateSeries) NewSetFromChunks(length int) *AggregateSet {
180
177
}
181
178
182
179
newAggregateSet .dataArrays = dataArrays
183
- newAggregateSet .validCells = make ([]bool , length , length )
184
180
return & newAggregateSet
185
181
}
186
182
187
183
type AggregateSet struct {
188
184
dataArrays map [AggrType ][]float64
189
- validCells []bool
190
185
length int
191
186
maxCell int
192
187
baseTime int64
@@ -198,27 +193,20 @@ func (as *AggregateSet) GetMaxCell() int {
198
193
return as .maxCell
199
194
}
200
195
201
- func (as * AggregateSet ) setValid (cell int ) {
202
- if cell < as .length {
203
- as .validCells [cell ] = true
204
- }
205
- }
206
-
207
196
// append the value to a cell in all relevant aggregation arrays
208
197
func (as * AggregateSet ) AppendAllCells (cell int , val float64 ) {
209
198
210
- if cell >= as . length {
199
+ if ! isValidCell ( cell , as ) {
211
200
return
212
201
}
213
202
214
203
if cell > as .maxCell {
215
204
as .maxCell = cell
216
205
}
217
206
218
- for aggr , _ := range as .dataArrays {
207
+ for aggr := range as .dataArrays {
219
208
as .updateCell (aggr , cell , val )
220
209
}
221
- as .validCells [cell ] = true
222
210
}
223
211
224
212
// append/merge (v3io) aggregation values into aggregation per requested interval/step
@@ -241,9 +229,22 @@ func (as *AggregateSet) mergeArrayCell(aggr AggrType, cell int, val uint64) {
241
229
}
242
230
}
243
231
232
+ func isValidValue (v float64 ) bool {
233
+ return ! (math .IsNaN (v ) || math .IsInf (v , 1 ) || math .IsInf (v , - 1 ))
234
+ }
235
+
236
+ func isValidCell (cellIndex int , aSet * AggregateSet ) bool {
237
+ return cellIndex >= 0 &&
238
+ cellIndex < aSet .length
239
+ }
240
+
244
241
// function specific aggregation
245
242
func (as * AggregateSet ) updateCell (aggr AggrType , cell int , val float64 ) {
246
243
244
+ if ! isValidCell (cell , as ) {
245
+ return
246
+ }
247
+
247
248
switch aggr {
248
249
case aggrTypeCount :
249
250
as.dataArrays [aggr ][cell ] += 1
@@ -252,11 +253,11 @@ func (as *AggregateSet) updateCell(aggr AggrType, cell int, val float64) {
252
253
case aggrTypeSqr :
253
254
as.dataArrays [aggr ][cell ] += val * val
254
255
case aggrTypeMin :
255
- if val < as.dataArrays [aggr ][cell ] || ! as . validCells [ cell ] {
256
+ if val < as.dataArrays [aggr ][cell ] {
256
257
as.dataArrays [aggr ][cell ] = val
257
258
}
258
259
case aggrTypeMax :
259
- if val > as.dataArrays [aggr ][cell ] || ! as . validCells [ cell ] {
260
+ if val > as.dataArrays [aggr ][cell ] {
260
261
as.dataArrays [aggr ][cell ] = val
261
262
}
262
263
case aggrTypeLast :
@@ -267,13 +268,24 @@ func (as *AggregateSet) updateCell(aggr AggrType, cell int, val float64) {
267
268
// return the value per aggregate or complex function
268
269
func (as * AggregateSet ) GetCellValue (aggr AggrType , cell int ) (float64 , bool ) {
269
270
270
- if cell > as .maxCell || cell >= as .length || ! as .validCells [cell ] { // TODO: should >Len return NaN or Zero ?
271
+ if ! isValidCell (cell , as ) {
272
+ return math .NaN (), false
273
+ }
274
+
275
+ dependsOnSumAndCount := aggr == aggrTypeStddev || aggr == aggrTypeStdvar || aggr == aggrTypeAvg
276
+ dependsOnSqr := aggr == aggrTypeStddev || aggr == aggrTypeStdvar
277
+ dependsOnLast := aggr == aggrTypeLast || aggr == aggrTypeRate
278
+
279
+ // return undefined result one dependant fields is missing
280
+ if (dependsOnSumAndCount && ! (isValidValue (as.dataArrays [aggrTypeSum ][cell ]) && isValidValue (as.dataArrays [aggrTypeCount ][cell ]))) ||
281
+ (dependsOnSqr && ! isValidValue (as.dataArrays [aggrTypeSqr ][cell ])) ||
282
+ (dependsOnLast && ! isValidValue (as.dataArrays [aggrTypeLast ][cell ])) {
271
283
return math .NaN (), false
272
284
}
273
285
274
286
// if no samples in this bucket the result is undefined
275
287
var cnt float64
276
- if aggr == aggrTypeAvg || aggr == aggrTypeStddev || aggr == aggrTypeStdvar {
288
+ if dependsOnSumAndCount {
277
289
cnt = as.dataArrays [aggrTypeCount ][cell ]
278
290
if cnt == 0 {
279
291
return math .NaN (), false
@@ -295,13 +307,13 @@ func (as *AggregateSet) GetCellValue(aggr AggrType, cell int) (float64, bool) {
295
307
if cell == 0 {
296
308
return math .NaN (), false
297
309
}
310
+ // TODO: need to clarify the meaning of this type of aggregation. IMHO, rate has meaning for monotonic counters only
298
311
last := as .dataArrays [aggrTypeLast ][cell - 1 ]
299
312
this := as.dataArrays [aggrTypeLast ][cell ]
300
- return (this - last ) / float64 (as .interval / 1000 ), true // clac rate per sec
313
+ return (this - last ) / float64 (as .interval / 1000 ), true // rate per sec
301
314
default :
302
315
return as.dataArrays [aggr ][cell ], true
303
316
}
304
-
305
317
}
306
318
307
319
// get the time per aggregate cell
@@ -317,7 +329,7 @@ func (as *AggregateSet) GetCellTime(base int64, index int) int64 {
317
329
318
330
func (as * AggregateSet ) Clear () {
319
331
as .maxCell = 0
320
- for aggr , _ := range as .dataArrays {
332
+ for aggr := range as .dataArrays {
321
333
as .dataArrays [aggr ] = as .dataArrays [aggr ][:0 ]
322
334
}
323
335
}
0 commit comments