25
const char *name;
26
uint32_t hash;
27
RRDR_TIME_GROUPING value;
28
+ RRDR_TIME_GROUPING add_flush;
29
30
// One time initialization for the module.
31
// This is called once, when netdata starts.
60
{.name = "average",
61
.hash = 0,
62
.value = RRDR_GROUPING_AVERAGE,
63
+ .add_flush = RRDR_GROUPING_AVERAGE,
64
.init = NULL,
63
- .create= grouping_create_average,
64
- .reset = grouping_reset_average,
65
- .free = grouping_free_average,
66
- .add = grouping_add_average,
67
- .flush = grouping_flush_average,
65
+ .create= tg_average_create,
66
+ .reset = tg_average_reset,
67
+ .free = tg_average_free,
68
+ .add = tg_average_add,
69
+ .flush = tg_average_flush,
70
.tier_query_fetch = TIER_QUERY_FETCH_AVERAGE
71
},
72
{.name = "avg", // alias on 'average'
73
.hash = 0,
74
.value = RRDR_GROUPING_AVERAGE,
75
+ .add_flush = RRDR_GROUPING_AVERAGE,
76
.init = NULL,
74
- .create= grouping_create_average,
75
- .reset = grouping_reset_average,
76
- .free = grouping_free_average,
77
- .add = grouping_add_average,
78
- .flush = grouping_flush_average,
77
+ .create= tg_average_create,
78
+ .reset = tg_average_reset,
79
+ .free = tg_average_free,
80
+ .add = tg_average_add,
81
+ .flush = tg_average_flush,
82
.tier_query_fetch = TIER_QUERY_FETCH_AVERAGE
83
},
84
{.name = "mean", // alias on 'average'
85
.hash = 0,
86
.value = RRDR_GROUPING_AVERAGE,
87
+ .add_flush = RRDR_GROUPING_AVERAGE,
88
.init = NULL,
85
- .create= grouping_create_average,
86
- .reset = grouping_reset_average,
87
- .free = grouping_free_average,
88
- .add = grouping_add_average,
89
- .flush = grouping_flush_average,
89
+ .create= tg_average_create,
90
+ .reset = tg_average_reset,
91
+ .free = tg_average_free,
92
+ .add = tg_average_add,
93
+ .flush = tg_average_flush,
94
.tier_query_fetch = TIER_QUERY_FETCH_AVERAGE
95
},
96
{.name = "trimmed-mean1",
97
.hash = 0,
98
.value = RRDR_GROUPING_TRIMMED_MEAN1,
99
+ .add_flush = RRDR_GROUPING_TRIMMED_MEAN,
100
.init = NULL,
96
- .create= grouping_create_trimmed_mean1,
97
- .reset = grouping_reset_trimmed_mean,
98
- .free = grouping_free_trimmed_mean,
99
- .add = grouping_add_trimmed_mean,
100
- .flush = grouping_flush_trimmed_mean,
101
+ .create= tg_trimmed_mean_create_1,
102
+ .reset = tg_trimmed_mean_reset,
103
+ .free = tg_trimmed_mean_free,
104
+ .add = tg_trimmed_mean_add,
105
+ .flush = tg_trimmed_mean_flush,
106
.tier_query_fetch = TIER_QUERY_FETCH_AVERAGE
107
},
108
{.name = "trimmed-mean2",
109
.hash = 0,
110
.value = RRDR_GROUPING_TRIMMED_MEAN2,
111
+ .add_flush = RRDR_GROUPING_TRIMMED_MEAN,
112
.init = NULL,
107
- .create= grouping_create_trimmed_mean2,
108
- .reset = grouping_reset_trimmed_mean,
109
- .free = grouping_free_trimmed_mean,
110
- .add = grouping_add_trimmed_mean,
111
- .flush = grouping_flush_trimmed_mean,
113
+ .create= tg_trimmed_mean_create_2,
114
+ .reset = tg_trimmed_mean_reset,
115
+ .free = tg_trimmed_mean_free,
116
+ .add = tg_trimmed_mean_add,
117
+ .flush = tg_trimmed_mean_flush,
118
.tier_query_fetch = TIER_QUERY_FETCH_AVERAGE
119
},
120
{.name = "trimmed-mean3",
121
.hash = 0,
122
.value = RRDR_GROUPING_TRIMMED_MEAN3,
123
+ .add_flush = RRDR_GROUPING_TRIMMED_MEAN,
124
.init = NULL,
118
- .create= grouping_create_trimmed_mean3,
119
- .reset = grouping_reset_trimmed_mean,
120
- .free = grouping_free_trimmed_mean,
121
- .add = grouping_add_trimmed_mean,
122
- .flush = grouping_flush_trimmed_mean,
125
+ .create= tg_trimmed_mean_create_3,
126
+ .reset = tg_trimmed_mean_reset,
127
+ .free = tg_trimmed_mean_free,
128
+ .add = tg_trimmed_mean_add,
129
+ .flush = tg_trimmed_mean_flush,
130
.tier_query_fetch = TIER_QUERY_FETCH_AVERAGE
131
},
132
{.name = "trimmed-mean5",
133
.hash = 0,
127
- .value = RRDR_GROUPING_TRIMMED_MEAN5,
134
+ .value = RRDR_GROUPING_TRIMMED_MEAN,
135
+ .add_flush = RRDR_GROUPING_TRIMMED_MEAN,
136
.init = NULL,
129
- .create= grouping_create_trimmed_mean5,
130
- .reset = grouping_reset_trimmed_mean,
131
- .free = grouping_free_trimmed_mean,
132
- .add = grouping_add_trimmed_mean,
133
- .flush = grouping_flush_trimmed_mean,
137
+ .create= tg_trimmed_mean_create_5,
138
+ .reset = tg_trimmed_mean_reset,
139
+ .free = tg_trimmed_mean_free,
140
+ .add = tg_trimmed_mean_add,
141
+ .flush = tg_trimmed_mean_flush,
142
.tier_query_fetch = TIER_QUERY_FETCH_AVERAGE
143
},
144
{.name = "trimmed-mean10",
145
.hash = 0,
146
.value = RRDR_GROUPING_TRIMMED_MEAN10,
147
+ .add_flush = RRDR_GROUPING_TRIMMED_MEAN,
148
.init = NULL,
140
- .create= grouping_create_trimmed_mean10,
141
- .reset = grouping_reset_trimmed_mean,
142
- .free = grouping_free_trimmed_mean,
143
- .add = grouping_add_trimmed_mean,
144
- .flush = grouping_flush_trimmed_mean,
149
+ .create= tg_trimmed_mean_create_10,
150
+ .reset = tg_trimmed_mean_reset,
151
+ .free = tg_trimmed_mean_free,
152
+ .add = tg_trimmed_mean_add,
153
+ .flush = tg_trimmed_mean_flush,
154
.tier_query_fetch = TIER_QUERY_FETCH_AVERAGE
155
},
156
{.name = "trimmed-mean15",
157
.hash = 0,
158
.value = RRDR_GROUPING_TRIMMED_MEAN15,
159
+ .add_flush = RRDR_GROUPING_TRIMMED_MEAN,
160
.init = NULL,
151
- .create= grouping_create_trimmed_mean15,
152
- .reset = grouping_reset_trimmed_mean,
153
- .free = grouping_free_trimmed_mean,
154
- .add = grouping_add_trimmed_mean,
155
- .flush = grouping_flush_trimmed_mean,
161
+ .create= tg_trimmed_mean_create_15,
162
+ .reset = tg_trimmed_mean_reset,
163
+ .free = tg_trimmed_mean_free,
164
+ .add = tg_trimmed_mean_add,
165
+ .flush = tg_trimmed_mean_flush,
166
.tier_query_fetch = TIER_QUERY_FETCH_AVERAGE
167
},
168
{.name = "trimmed-mean20",
169
.hash = 0,
170
.value = RRDR_GROUPING_TRIMMED_MEAN20,
171
+ .add_flush = RRDR_GROUPING_TRIMMED_MEAN,
172
.init = NULL,
162
- .create= grouping_create_trimmed_mean20,
163
- .reset = grouping_reset_trimmed_mean,
164
- .free = grouping_free_trimmed_mean,
165
- .add = grouping_add_trimmed_mean,
166
- .flush = grouping_flush_trimmed_mean,
173
+ .create= tg_trimmed_mean_create_20,
174
+ .reset = tg_trimmed_mean_reset,
175
+ .free = tg_trimmed_mean_free,
176
+ .add = tg_trimmed_mean_add,
177
+ .flush = tg_trimmed_mean_flush,
178
.tier_query_fetch = TIER_QUERY_FETCH_AVERAGE
179
},
180
{.name = "trimmed-mean25",
181
.hash = 0,
182
.value = RRDR_GROUPING_TRIMMED_MEAN25,
183
+ .add_flush = RRDR_GROUPING_TRIMMED_MEAN,
184
.init = NULL,
173
- .create= grouping_create_trimmed_mean25,
174
- .reset = grouping_reset_trimmed_mean,
175
- .free = grouping_free_trimmed_mean,
176
- .add = grouping_add_trimmed_mean,
177
- .flush = grouping_flush_trimmed_mean,
185
+ .create= tg_trimmed_mean_create_25,
186
+ .reset = tg_trimmed_mean_reset,
187
+ .free = tg_trimmed_mean_free,
188
+ .add = tg_trimmed_mean_add,
189
+ .flush = tg_trimmed_mean_flush,
190
.tier_query_fetch = TIER_QUERY_FETCH_AVERAGE
191
},
192
{.name = "trimmed-mean",
193
.hash = 0,
182
- .value = RRDR_GROUPING_TRIMMED_MEAN5,
194
+ .value = RRDR_GROUPING_TRIMMED_MEAN,
195
+ .add_flush = RRDR_GROUPING_TRIMMED_MEAN,
196
.init = NULL,
184
- .create= grouping_create_trimmed_mean5,
185
- .reset = grouping_reset_trimmed_mean,
186
- .free = grouping_free_trimmed_mean,
187
- .add = grouping_add_trimmed_mean,
188
- .flush = grouping_flush_trimmed_mean,
197
+ .create= tg_trimmed_mean_create_5,
198
+ .reset = tg_trimmed_mean_reset,
199
+ .free = tg_trimmed_mean_free,
200
+ .add = tg_trimmed_mean_add,
201
+ .flush = tg_trimmed_mean_flush,
202
.tier_query_fetch = TIER_QUERY_FETCH_AVERAGE
203
},
204
{.name = "incremental_sum",
205
.hash = 0,
206
.value = RRDR_GROUPING_INCREMENTAL_SUM,
207
+ .add_flush = RRDR_GROUPING_INCREMENTAL_SUM,
208
.init = NULL,
195
- .create= grouping_create_incremental_sum,
196
- .reset = grouping_reset_incremental_sum,
197
- .free = grouping_free_incremental_sum,
198
- .add = grouping_add_incremental_sum,
199
- .flush = grouping_flush_incremental_sum,
209
+ .create= tg_incremental_sum_create,
210
+ .reset = tg_incremental_sum_reset,
211
+ .free = tg_incremental_sum_free,
212
+ .add = tg_incremental_sum_add,
213
+ .flush = tg_incremental_sum_flush,
214
.tier_query_fetch = TIER_QUERY_FETCH_AVERAGE
215
},
216
{.name = "incremental-sum",
217
.hash = 0,
218
.value = RRDR_GROUPING_INCREMENTAL_SUM,
219
+ .add_flush = RRDR_GROUPING_INCREMENTAL_SUM,
220
.init = NULL,
206
- .create= grouping_create_incremental_sum,
207
- .reset = grouping_reset_incremental_sum,
208
- .free = grouping_free_incremental_sum,
209
- .add = grouping_add_incremental_sum,
210
- .flush = grouping_flush_incremental_sum,
221
+ .create= tg_incremental_sum_create,
222
+ .reset = tg_incremental_sum_reset,
223
+ .free = tg_incremental_sum_free,
224
+ .add = tg_incremental_sum_add,
225
+ .flush = tg_incremental_sum_flush,
226
.tier_query_fetch = TIER_QUERY_FETCH_AVERAGE
227
},
228
{.name = "median",
229
.hash = 0,
230
.value = RRDR_GROUPING_MEDIAN,
231
+ .add_flush = RRDR_GROUPING_MEDIAN,
232
.init = NULL,
217
- .create= grouping_create_median,
218
- .reset = grouping_reset_median,
219
- .free = grouping_free_median,
220
- .add = grouping_add_median,
221
- .flush = grouping_flush_median,
233
+ .create= tg_median_create,
234
+ .reset = tg_median_reset,
235
+ .free = tg_median_free,
236
+ .add = tg_median_add,
237
+ .flush = tg_median_flush,
238
.tier_query_fetch = TIER_QUERY_FETCH_AVERAGE
239
},
240
{.name = "trimmed-median1",
241
.hash = 0,
242
.value = RRDR_GROUPING_TRIMMED_MEDIAN1,
243
+ .add_flush = RRDR_GROUPING_MEDIAN,
244
.init = NULL,
228
- .create= grouping_create_trimmed_median1,
229
- .reset = grouping_reset_median,
230
- .free = grouping_free_median,
231
- .add = grouping_add_median,
232
- .flush = grouping_flush_median,
245
+ .create= tg_median_create_trimmed_1,
246
+ .reset = tg_median_reset,
247
+ .free = tg_median_free,
248
+ .add = tg_median_add,
249
+ .flush = tg_median_flush,
250
.tier_query_fetch = TIER_QUERY_FETCH_AVERAGE
251
},
252
{.name = "trimmed-median2",
253
.hash = 0,
254
.value = RRDR_GROUPING_TRIMMED_MEDIAN2,
255
+ .add_flush = RRDR_GROUPING_MEDIAN,
256
.init = NULL,
239
- .create= grouping_create_trimmed_median2,
240
- .reset = grouping_reset_median,
241
- .free = grouping_free_median,
242
- .add = grouping_add_median,
243
- .flush = grouping_flush_median,
257
+ .create= tg_median_create_trimmed_2,
258
+ .reset = tg_median_reset,
259
+ .free = tg_median_free,
260
+ .add = tg_median_add,
261
+ .flush = tg_median_flush,
262
.tier_query_fetch = TIER_QUERY_FETCH_AVERAGE
263
},
264
{.name = "trimmed-median3",
265
.hash = 0,
266
.value = RRDR_GROUPING_TRIMMED_MEDIAN3,
267
+ .add_flush = RRDR_GROUPING_MEDIAN,
268
.init = NULL,
250
- .create= grouping_create_trimmed_median3,
251
- .reset = grouping_reset_median,
252
- .free = grouping_free_median,
253
- .add = grouping_add_median,
254
- .flush = grouping_flush_median,
269
+ .create= tg_median_create_trimmed_3,
270
+ .reset = tg_median_reset,
271
+ .free = tg_median_free,
272
+ .add = tg_median_add,
273
+ .flush = tg_median_flush,
274
.tier_query_fetch = TIER_QUERY_FETCH_AVERAGE
275
},
276
{.name = "trimmed-median5",
277
.hash = 0,
278
.value = RRDR_GROUPING_TRIMMED_MEDIAN5,
279
+ .add_flush = RRDR_GROUPING_MEDIAN,
280
.init = NULL,
261
- .create= grouping_create_trimmed_median5,
262
- .reset = grouping_reset_median,
263
- .free = grouping_free_median,
264
- .add = grouping_add_median,
265
- .flush = grouping_flush_median,
281
+ .create= tg_median_create_trimmed_5,
282
+ .reset = tg_median_reset,
283
+ .free = tg_median_free,
284
+ .add = tg_median_add,
285
+ .flush = tg_median_flush,
286
.tier_query_fetch = TIER_QUERY_FETCH_AVERAGE
287
},
288
{.name = "trimmed-median10",
289
.hash = 0,
290
.value = RRDR_GROUPING_TRIMMED_MEDIAN10,
291
+ .add_flush = RRDR_GROUPING_MEDIAN,
292
.init = NULL,
272
- .create= grouping_create_trimmed_median10,
273
- .reset = grouping_reset_median,
274
- .free = grouping_free_median,
275
- .add = grouping_add_median,
276
- .flush = grouping_flush_median,
293
+ .create= tg_median_create_trimmed_10,
294
+ .reset = tg_median_reset,
295
+ .free = tg_median_free,
296
+ .add = tg_median_add,
297
+ .flush = tg_median_flush,
298
.tier_query_fetch = TIER_QUERY_FETCH_AVERAGE
299
},
300
{.name = "trimmed-median15",
301
.hash = 0,
302
.value = RRDR_GROUPING_TRIMMED_MEDIAN15,
303
+ .add_flush = RRDR_GROUPING_MEDIAN,
304
.init = NULL,
283
- .create= grouping_create_trimmed_median15,
284
- .reset = grouping_reset_median,
285
- .free = grouping_free_median,
286
- .add = grouping_add_median,
287
- .flush = grouping_flush_median,
305
+ .create= tg_median_create_trimmed_15,
306
+ .reset = tg_median_reset,
307
+ .free = tg_median_free,
308
+ .add = tg_median_add,
309
+ .flush = tg_median_flush,
310
.tier_query_fetch = TIER_QUERY_FETCH_AVERAGE
311
},
312
{.name = "trimmed-median20",
313
.hash = 0,
314
.value = RRDR_GROUPING_TRIMMED_MEDIAN20,
315
+ .add_flush = RRDR_GROUPING_MEDIAN,
316
.init = NULL,
294
- .create= grouping_create_trimmed_median20,
295
- .reset = grouping_reset_median,
296
- .free = grouping_free_median,
297
- .add = grouping_add_median,
298
- .flush = grouping_flush_median,
317
+ .create= tg_median_create_trimmed_20,
318
+ .reset = tg_median_reset,
319
+ .free = tg_median_free,
320
+ .add = tg_median_add,
321
+ .flush = tg_median_flush,
322
.tier_query_fetch = TIER_QUERY_FETCH_AVERAGE
323
},
324
{.name = "trimmed-median25",
325
.hash = 0,
326
.value = RRDR_GROUPING_TRIMMED_MEDIAN25,
327
+ .add_flush = RRDR_GROUPING_MEDIAN,
328
.init = NULL,
305
- .create= grouping_create_trimmed_median25,
306
- .reset = grouping_reset_median,
307
- .free = grouping_free_median,
308
- .add = grouping_add_median,
309
- .flush = grouping_flush_median,
329
+ .create= tg_median_create_trimmed_25,
330
+ .reset = tg_median_reset,
331
+ .free = tg_median_free,
332
+ .add = tg_median_add,
333
+ .flush = tg_median_flush,
334
.tier_query_fetch = TIER_QUERY_FETCH_AVERAGE
335
},
336
{.name = "trimmed-median",
337
.hash = 0,
338
.value = RRDR_GROUPING_TRIMMED_MEDIAN5,
339
+ .add_flush = RRDR_GROUPING_MEDIAN,
340
.init = NULL,
316
- .create= grouping_create_trimmed_median5,
317
- .reset = grouping_reset_median,
318
- .free = grouping_free_median,
319
- .add = grouping_add_median,
320
- .flush = grouping_flush_median,
341
+ .create= tg_median_create_trimmed_5,
342
+ .reset = tg_median_reset,
343
+ .free = tg_median_free,
344
+ .add = tg_median_add,
345
+ .flush = tg_median_flush,
346
.tier_query_fetch = TIER_QUERY_FETCH_AVERAGE
347
},
348
{.name = "percentile25",
349
.hash = 0,
350
.value = RRDR_GROUPING_PERCENTILE25,
351
+ .add_flush = RRDR_GROUPING_PERCENTILE,
352
.init = NULL,
327
- .create= grouping_create_percentile25,
328
- .reset = grouping_reset_percentile,
329
- .free = grouping_free_percentile,
330
- .add = grouping_add_percentile,
331
- .flush = grouping_flush_percentile,
353
+ .create= tg_percentile_create_25,
354
+ .reset = tg_percentile_reset,
355
+ .free = tg_percentile_free,
356
+ .add = tg_percentile_add,
357
+ .flush = tg_percentile_flush,
358
.tier_query_fetch = TIER_QUERY_FETCH_AVERAGE
359
},
360
{.name = "percentile50",
361
.hash = 0,
362
.value = RRDR_GROUPING_PERCENTILE50,
363
+ .add_flush = RRDR_GROUPING_PERCENTILE,
364
.init = NULL,
338
- .create= grouping_create_percentile50,
339
- .reset = grouping_reset_percentile,
340
- .free = grouping_free_percentile,
341
- .add = grouping_add_percentile,
342
- .flush = grouping_flush_percentile,
365
+ .create= tg_percentile_create_50,
366
+ .reset = tg_percentile_reset,
367
+ .free = tg_percentile_free,
368
+ .add = tg_percentile_add,
369
+ .flush = tg_percentile_flush,
370
.tier_query_fetch = TIER_QUERY_FETCH_AVERAGE
371
},
372
{.name = "percentile75",
373
.hash = 0,
374
.value = RRDR_GROUPING_PERCENTILE75,
375
+ .add_flush = RRDR_GROUPING_PERCENTILE,
376
.init = NULL,
349
- .create= grouping_create_percentile75,
350
- .reset = grouping_reset_percentile,
351
- .free = grouping_free_percentile,
352
- .add = grouping_add_percentile,
353
- .flush = grouping_flush_percentile,
377
+ .create= tg_percentile_create_75,
378
+ .reset = tg_percentile_reset,
379
+ .free = tg_percentile_free,
380
+ .add = tg_percentile_add,
381
+ .flush = tg_percentile_flush,
382
.tier_query_fetch = TIER_QUERY_FETCH_AVERAGE
383
},
384
{.name = "percentile80",
385
.hash = 0,
386
.value = RRDR_GROUPING_PERCENTILE80,
387
+ .add_flush = RRDR_GROUPING_PERCENTILE,
388
.init = NULL,
360
- .create= grouping_create_percentile80,
361
- .reset = grouping_reset_percentile,
362
- .free = grouping_free_percentile,
363
- .add = grouping_add_percentile,
364
- .flush = grouping_flush_percentile,
389
+ .create= tg_percentile_create_80,
390
+ .reset = tg_percentile_reset,
391
+ .free = tg_percentile_free,
392
+ .add = tg_percentile_add,
393
+ .flush = tg_percentile_flush,
394
.tier_query_fetch = TIER_QUERY_FETCH_AVERAGE
395
},
396
{.name = "percentile90",
397
.hash = 0,
398
.value = RRDR_GROUPING_PERCENTILE90,
399
+ .add_flush = RRDR_GROUPING_PERCENTILE,
400
.init = NULL,
371
- .create= grouping_create_percentile90,
372
- .reset = grouping_reset_percentile,
373
- .free = grouping_free_percentile,
374
- .add = grouping_add_percentile,
375
- .flush = grouping_flush_percentile,
401
+ .create= tg_percentile_create_90,
402
+ .reset = tg_percentile_reset,
403
+ .free = tg_percentile_free,
404
+ .add = tg_percentile_add,
405
+ .flush = tg_percentile_flush,
406
.tier_query_fetch = TIER_QUERY_FETCH_AVERAGE
407
},
408
{.name = "percentile95",
409
.hash = 0,
380
- .value = RRDR_GROUPING_PERCENTILE95,
410
+ .value = RRDR_GROUPING_PERCENTILE,
411
+ .add_flush = RRDR_GROUPING_PERCENTILE,
412
.init = NULL,
382
- .create= grouping_create_percentile95,
383
- .reset = grouping_reset_percentile,
384
- .free = grouping_free_percentile,
385
- .add = grouping_add_percentile,
386
- .flush = grouping_flush_percentile,
413
+ .create= tg_percentile_create_95,
414
+ .reset = tg_percentile_reset,
415
+ .free = tg_percentile_free,
416
+ .add = tg_percentile_add,
417
+ .flush = tg_percentile_flush,
418
.tier_query_fetch = TIER_QUERY_FETCH_AVERAGE
419
},
420
{.name = "percentile97",
421
.hash = 0,
422
.value = RRDR_GROUPING_PERCENTILE97,
423
+ .add_flush = RRDR_GROUPING_PERCENTILE,
424
.init = NULL,
393
- .create= grouping_create_percentile97,
394
- .reset = grouping_reset_percentile,
395
- .free = grouping_free_percentile,
396
- .add = grouping_add_percentile,
397
- .flush = grouping_flush_percentile,
425
+ .create= tg_percentile_create_97,
426
+ .reset = tg_percentile_reset,
427
+ .free = tg_percentile_free,
428
+ .add = tg_percentile_add,
429
+ .flush = tg_percentile_flush,
430
.tier_query_fetch = TIER_QUERY_FETCH_AVERAGE
431
},
432
{.name = "percentile98",
433
.hash = 0,
434
.value = RRDR_GROUPING_PERCENTILE98,
435
+ .add_flush = RRDR_GROUPING_PERCENTILE,
436
.init = NULL,
404
- .create= grouping_create_percentile98,
405
- .reset = grouping_reset_percentile,
406
- .free = grouping_free_percentile,
407
- .add = grouping_add_percentile,
408
- .flush = grouping_flush_percentile,
437
+ .create= tg_percentile_create_98,
438
+ .reset = tg_percentile_reset,
439
+ .free = tg_percentile_free,
440
+ .add = tg_percentile_add,
441
+ .flush = tg_percentile_flush,
442
.tier_query_fetch = TIER_QUERY_FETCH_AVERAGE
443
},
444
{.name = "percentile99",
445
.hash = 0,
446
.value = RRDR_GROUPING_PERCENTILE99,
447
+ .add_flush = RRDR_GROUPING_PERCENTILE,
448
.init = NULL,
415
- .create= grouping_create_percentile99,
416
- .reset = grouping_reset_percentile,
417
- .free = grouping_free_percentile,
418
- .add = grouping_add_percentile,
419
- .flush = grouping_flush_percentile,
449
+ .create= tg_percentile_create_99,
450
+ .reset = tg_percentile_reset,
451
+ .free = tg_percentile_free,
452
+ .add = tg_percentile_add,
453
+ .flush = tg_percentile_flush,
454
.tier_query_fetch = TIER_QUERY_FETCH_AVERAGE
455
},
456
{.name = "percentile",
457
.hash = 0,
424
- .value = RRDR_GROUPING_PERCENTILE95,
458
+ .value = RRDR_GROUPING_PERCENTILE,
459
+ .add_flush = RRDR_GROUPING_PERCENTILE,
460
.init = NULL,
426
- .create= grouping_create_percentile95,
427
- .reset = grouping_reset_percentile,
428
- .free = grouping_free_percentile,
429
- .add = grouping_add_percentile,
430
- .flush = grouping_flush_percentile,
461
+ .create= tg_percentile_create_95,
462
+ .reset = tg_percentile_reset,
463
+ .free = tg_percentile_free,
464
+ .add = tg_percentile_add,
465
+ .flush = tg_percentile_flush,
466
.tier_query_fetch = TIER_QUERY_FETCH_AVERAGE
467
},
468
{.name = "min",
469
.hash = 0,
470
.value = RRDR_GROUPING_MIN,
471
+ .add_flush = RRDR_GROUPING_MIN,
472
.init = NULL,
437
- .create= grouping_create_min,
438
- .reset = grouping_reset_min,
439
- .free = grouping_free_min,
440
- .add = grouping_add_min,
441
- .flush = grouping_flush_min,
473
+ .create= tg_min_create,
474
+ .reset = tg_min_reset,
475
+ .free = tg_min_free,
476
+ .add = tg_min_add,
477
+ .flush = tg_min_flush,
478
.tier_query_fetch = TIER_QUERY_FETCH_MIN
479
},
480
{.name = "max",
481
.hash = 0,
482
.value = RRDR_GROUPING_MAX,
483
+ .add_flush = RRDR_GROUPING_MAX,
484
.init = NULL,
448
- .create= grouping_create_max,
449
- .reset = grouping_reset_max,
450
- .free = grouping_free_max,
451
- .add = grouping_add_max,
452
- .flush = grouping_flush_max,
485
+ .create= tg_max_create,
486
+ .reset = tg_max_reset,
487
+ .free = tg_max_free,
488
+ .add = tg_max_add,
489
+ .flush = tg_max_flush,
490
.tier_query_fetch = TIER_QUERY_FETCH_MAX
491
},
492
{.name = "sum",
493
.hash = 0,
494
.value = RRDR_GROUPING_SUM,
495
+ .add_flush = RRDR_GROUPING_SUM,
496
.init = NULL,
459
- .create= grouping_create_sum,
460
- .reset = grouping_reset_sum,
461
- .free = grouping_free_sum,
462
- .add = grouping_add_sum,
463
- .flush = grouping_flush_sum,
497
+ .create= tg_sum_create,
498
+ .reset = tg_sum_reset,
499
+ .free = tg_sum_free,
500
+ .add = tg_sum_add,
501
+ .flush = tg_sum_flush,
502
.tier_query_fetch = TIER_QUERY_FETCH_SUM
503
},
504
506
{.name = "stddev",
507
.hash = 0,
508
.value = RRDR_GROUPING_STDDEV,
509
+ .add_flush = RRDR_GROUPING_STDDEV,
510
.init = NULL,
472
- .create= grouping_create_stddev,
473
- .reset = grouping_reset_stddev,
474
- .free = grouping_free_stddev,
475
- .add = grouping_add_stddev,
476
- .flush = grouping_flush_stddev,
511
+ .create= tg_stddev_create,
512
+ .reset = tg_stddev_reset,
513
+ .free = tg_stddev_free,
514
+ .add = tg_stddev_add,
515
+ .flush = tg_stddev_flush,
516
.tier_query_fetch = TIER_QUERY_FETCH_AVERAGE
517
},
518
{.name = "cv", // coefficient variation is calculated by stddev
519
.hash = 0,
520
.value = RRDR_GROUPING_CV,
521
+ .add_flush = RRDR_GROUPING_CV,
522
.init = NULL,
483
- .create= grouping_create_stddev, // not an error, stddev calculates this too
484
- .reset = grouping_reset_stddev, // not an error, stddev calculates this too
485
- .free = grouping_free_stddev, // not an error, stddev calculates this too
486
- .add = grouping_add_stddev, // not an error, stddev calculates this too
487
- .flush = grouping_flush_coefficient_of_variation,
523
+ .create= tg_stddev_create, // not an error, stddev calculates this too
524
+ .reset = tg_stddev_reset, // not an error, stddev calculates this too
525
+ .free = tg_stddev_free, // not an error, stddev calculates this too
526
+ .add = tg_stddev_add, // not an error, stddev calculates this too
527
+ .flush = tg_stddev_coefficient_of_variation_flush,
528
.tier_query_fetch = TIER_QUERY_FETCH_AVERAGE
529
},
530
{.name = "rsd", // alias of 'cv'
531
.hash = 0,
532
.value = RRDR_GROUPING_CV,
533
+ .add_flush = RRDR_GROUPING_CV,
534
.init = NULL,
494
- .create= grouping_create_stddev, // not an error, stddev calculates this too
495
- .reset = grouping_reset_stddev, // not an error, stddev calculates this too
496
- .free = grouping_free_stddev, // not an error, stddev calculates this too
497
- .add = grouping_add_stddev, // not an error, stddev calculates this too
498
- .flush = grouping_flush_coefficient_of_variation,
535
+ .create= tg_stddev_create, // not an error, stddev calculates this too
536
+ .reset = tg_stddev_reset, // not an error, stddev calculates this too
537
+ .free = tg_stddev_free, // not an error, stddev calculates this too
538
+ .add = tg_stddev_add, // not an error, stddev calculates this too
539
+ .flush = tg_stddev_coefficient_of_variation_flush,
540
.tier_query_fetch = TIER_QUERY_FETCH_AVERAGE
541
},
542
502
- /*
503
- {.name = "mean", // same as average, no need to define it again
504
- .hash = 0,
505
- .value = RRDR_GROUPING_MEAN,
506
- .setup = NULL,
507
- .create= grouping_create_stddev,
508
- .reset = grouping_reset_stddev,
509
- .free = grouping_free_stddev,
510
- .add = grouping_add_stddev,
511
- .flush = grouping_flush_mean,
512
- .tier_query_fetch = TIER_QUERY_FETCH_AVERAGE
513
- },
514
- */
515
-
516
- /*
517
- {.name = "variance", // meaningless to offer
518
- .hash = 0,
519
- .value = RRDR_GROUPING_VARIANCE,
520
- .setup = NULL,
521
- .create= grouping_create_stddev,
522
- .reset = grouping_reset_stddev,
523
- .free = grouping_free_stddev,
524
- .add = grouping_add_stddev,
525
- .flush = grouping_flush_variance,
526
- .tier_query_fetch = TIER_QUERY_FETCH_AVERAGE
527
- },
528
- */
529
-
543
// single exponential smoothing
544
{.name = "ses",
545
.hash = 0,
546
.value = RRDR_GROUPING_SES,
534
- .init = grouping_init_ses,
535
- .create= grouping_create_ses,
536
- .reset = grouping_reset_ses,
537
- .free = grouping_free_ses,
538
- .add = grouping_add_ses,
539
- .flush = grouping_flush_ses,
547
+ .add_flush = RRDR_GROUPING_SES,
548
+ .init = tg_ses_init,
549
+ .create= tg_ses_create,
550
+ .reset = tg_ses_reset,
551
+ .free = tg_ses_free,
552
+ .add = tg_ses_add,
553
+ .flush = tg_ses_flush,
554
.tier_query_fetch = TIER_QUERY_FETCH_AVERAGE
555
},
556
{.name = "ema", // alias for 'ses'
557
.hash = 0,
558
.value = RRDR_GROUPING_SES,
559
+ .add_flush = RRDR_GROUPING_SES,
560
.init = NULL,
546
- .create= grouping_create_ses,
547
- .reset = grouping_reset_ses,
548
- .free = grouping_free_ses,
549
- .add = grouping_add_ses,
550
- .flush = grouping_flush_ses,
561
+ .create= tg_ses_create,
562
+ .reset = tg_ses_reset,
563
+ .free = tg_ses_free,
564
+ .add = tg_ses_add,
565
+ .flush = tg_ses_flush,
566
.tier_query_fetch = TIER_QUERY_FETCH_AVERAGE
567
},
568
{.name = "ewma", // alias for ses
569
.hash = 0,
570
.value = RRDR_GROUPING_SES,
571
+ .add_flush = RRDR_GROUPING_SES,
572
.init = NULL,
557
- .create= grouping_create_ses,
558
- .reset = grouping_reset_ses,
559
- .free = grouping_free_ses,
560
- .add = grouping_add_ses,
561
- .flush = grouping_flush_ses,
573
+ .create= tg_ses_create,
574
+ .reset = tg_ses_reset,
575
+ .free = tg_ses_free,
576
+ .add = tg_ses_add,
577
+ .flush = tg_ses_flush,
578
.tier_query_fetch = TIER_QUERY_FETCH_AVERAGE
579
},
580
582
{.name = "des",
583
.hash = 0,
584
.value = RRDR_GROUPING_DES,
569
- .init = grouping_init_des,
570
- .create= grouping_create_des,
571
- .reset = grouping_reset_des,
572
- .free = grouping_free_des,
573
- .add = grouping_add_des,
574
- .flush = grouping_flush_des,
585
+ .add_flush = RRDR_GROUPING_DES,
586
+ .init = tg_des_init,
587
+ .create= tg_des_create,
588
+ .reset = tg_des_reset,
589
+ .free = tg_des_free,
590
+ .add = tg_des_add,
591
+ .flush = tg_des_flush,
592
.tier_query_fetch = TIER_QUERY_FETCH_AVERAGE
593
},
594
595
{.name = "countif",
596
.hash = 0,
597
.value = RRDR_GROUPING_COUNTIF,
598
+ .add_flush = RRDR_GROUPING_COUNTIF,
599
.init = NULL,
582
- .create= grouping_create_countif,
583
- .reset = grouping_reset_countif,
584
- .free = grouping_free_countif,
585
- .add = grouping_add_countif,
586
- .flush = grouping_flush_countif,
600
+ .create= tg_countif_create,
601
+ .reset = tg_countif_reset,
602
+ .free = tg_countif_free,
603
+ .add = tg_countif_add,
604
+ .flush = tg_countif_flush,
605
.tier_query_fetch = TIER_QUERY_FETCH_AVERAGE
606
},
607
609
{.name = NULL,
610
.hash = 0,
611
.value = RRDR_GROUPING_UNDEFINED,
612
+ .add_flush = RRDR_GROUPING_AVERAGE,
613
.init = NULL,
595
- .create= grouping_create_average,
596
- .reset = grouping_reset_average,
597
- .free = grouping_free_average,
598
- .add = grouping_add_average,
599
- .flush = grouping_flush_average,
614
+ .create= tg_average_create,
615
+ .reset = tg_average_reset,
616
+ .free = tg_average_free,
617
+ .add = tg_average_add,
618
+ .flush = tg_average_flush,
619
.tier_query_fetch = TIER_QUERY_FETCH_AVERAGE
620
}
621
};
674
r->time_grouping.add = api_v1_data_groups[i].add;
675
r->time_grouping.flush = api_v1_data_groups[i].flush;
676
r->time_grouping.tier_query_fetch = api_v1_data_groups[i].tier_query_fetch;
677
+ r->time_grouping.add_flush = api_v1_data_groups[i].add_flush;
678
found = 1;
679
}
680
}
681
if(!found) {
682
errno = 0;
683
internal_error(true, "QUERY: grouping method %u not found. Using 'average'", (unsigned int)group_method);
664
- r->time_grouping.create = grouping_create_average;
665
- r->time_grouping.reset = grouping_reset_average;
666
- r->time_grouping.free = grouping_free_average;
667
- r->time_grouping.add = grouping_add_average;
668
- r->time_grouping.flush = grouping_flush_average;
684
+ r->time_grouping.create = tg_average_create;
685
+ r->time_grouping.reset = tg_average_reset;
686
+ r->time_grouping.free = tg_average_free;
687
+ r->time_grouping.add = tg_average_add;
688
+ r->time_grouping.flush = tg_average_flush;
689
r->time_grouping.tier_query_fetch = TIER_QUERY_FETCH_AVERAGE;
690
+ r->time_grouping.add_flush = RRDR_GROUPING_AVERAGE;
691
+ }
692
+}
693
+
694
+static inline void time_grouping_add(RRDR *r, NETDATA_DOUBLE value, const RRDR_TIME_GROUPING add_flush) {
695
+ switch(add_flush) {
696
+ case RRDR_GROUPING_AVERAGE:
697
+ tg_average_add(r, value);
698
+ break;
699
+
700
+ case RRDR_GROUPING_MAX:
701
+ tg_max_add(r, value);
702
+ break;
703
+
704
+ case RRDR_GROUPING_MIN:
705
+ tg_min_add(r, value);
706
+ break;
707
+
708
+ case RRDR_GROUPING_MEDIAN:
709
+ tg_median_add(r, value);
710
+ break;
711
+
712
+ case RRDR_GROUPING_STDDEV:
713
+ case RRDR_GROUPING_CV:
714
+ tg_stddev_add(r, value);
715
+ break;
716
+
717
+ case RRDR_GROUPING_SUM:
718
+ tg_sum_add(r, value);
719
+ break;
720
+
721
+ case RRDR_GROUPING_COUNTIF:
722
+ tg_countif_add(r, value);
723
+ break;
724
+
725
+ case RRDR_GROUPING_TRIMMED_MEAN:
726
+ tg_trimmed_mean_add(r, value);
727
+ break;
728
+
729
+ case RRDR_GROUPING_PERCENTILE:
730
+ tg_percentile_add(r, value);
731
+ break;
732
+
733
+ case RRDR_GROUPING_SES:
734
+ tg_ses_add(r, value);
735
+ break;
736
+
737
+ case RRDR_GROUPING_DES:
738
+ tg_des_add(r, value);
739
+ break;
740
+
741
+ case RRDR_GROUPING_INCREMENTAL_SUM:
742
+ tg_incremental_sum_add(r, value);
743
+ break;
744
+
745
+ default:
746
+ r->time_grouping.add(r, value);
747
+ break;
748
+ }
749
+}
750
+
751
+static inline NETDATA_DOUBLE time_grouping_flush(RRDR *r, RRDR_VALUE_FLAGS *rrdr_value_options_ptr, const RRDR_TIME_GROUPING add_flush) {
752
+ switch(add_flush) {
753
+ case RRDR_GROUPING_AVERAGE:
754
+ return tg_average_flush(r, rrdr_value_options_ptr);
755
+
756
+ case RRDR_GROUPING_MAX:
757
+ return tg_max_flush(r, rrdr_value_options_ptr);
758
+
759
+ case RRDR_GROUPING_MIN:
760
+ return tg_min_flush(r, rrdr_value_options_ptr);
761
+
762
+ case RRDR_GROUPING_MEDIAN:
763
+ return tg_median_flush(r, rrdr_value_options_ptr);
764
+
765
+ case RRDR_GROUPING_STDDEV:
766
+ return tg_stddev_flush(r, rrdr_value_options_ptr);
767
+
768
+ case RRDR_GROUPING_CV:
769
+ return tg_stddev_coefficient_of_variation_flush(r, rrdr_value_options_ptr);
770
+
771
+ case RRDR_GROUPING_SUM:
772
+ return tg_sum_flush(r, rrdr_value_options_ptr);
773
+
774
+ case RRDR_GROUPING_COUNTIF:
775
+ return tg_countif_flush(r, rrdr_value_options_ptr);
776
+
777
+ case RRDR_GROUPING_TRIMMED_MEAN:
778
+ return tg_trimmed_mean_flush(r, rrdr_value_options_ptr);
779
+
780
+ case RRDR_GROUPING_PERCENTILE:
781
+ return tg_percentile_flush(r, rrdr_value_options_ptr);
782
+
783
+ case RRDR_GROUPING_SES:
784
+ return tg_ses_flush(r, rrdr_value_options_ptr);
785
+
786
+ case RRDR_GROUPING_DES:
787
+ return tg_des_flush(r, rrdr_value_options_ptr);
788
+
789
+ case RRDR_GROUPING_INCREMENTAL_SUM:
790
+ return tg_incremental_sum_flush(r, rrdr_value_options_ptr);
791
+
792
+ default:
793
+ return r->time_grouping.flush(r, rrdr_value_options_ptr);
794
}
795
}
796
810
if (strcmp(key, "instance") == 0)
811
group_by |= RRDR_GROUP_BY_INSTANCE;
812
813
+ if (strcmp(key, "percentage-of-instance") == 0)
814
+ group_by |= RRDR_GROUP_BY_PERCENTAGE_OF_INSTANCE;
815
+
816
if (strcmp(key, "label") == 0)
817
group_by |= RRDR_GROUP_BY_LABEL;
818
826
group_by |= RRDR_GROUP_BY_UNITS;
827
}
828
829
+ if((group_by & RRDR_GROUP_BY_SELECTED) && (group_by & ~RRDR_GROUP_BY_SELECTED)) {
830
+ internal_error(true, "group-by given by query has 'selected' together with more groupings");
831
+ group_by = RRDR_GROUP_BY_SELECTED; // remove all other groupings
832
+ }
833
+
834
+ if(group_by & RRDR_GROUP_BY_PERCENTAGE_OF_INSTANCE)
835
+ group_by = RRDR_GROUP_BY_PERCENTAGE_OF_INSTANCE; // remove all other groupings
836
+
837
return group_by;
838
}
839
840
void buffer_json_group_by_to_array(BUFFER *wb, RRDR_GROUP_BY group_by) {
706
- if(group_by & RRDR_GROUP_BY_SELECTED)
707
- buffer_json_add_array_item_string(wb, "selected");
841
+ if(group_by == RRDR_GROUP_BY_NONE)
842
+ buffer_json_add_array_item_string(wb, "none");
843
+ else {
844
+ if (group_by & RRDR_GROUP_BY_DIMENSION)
845
+ buffer_json_add_array_item_string(wb, "dimension");
846
+
847
+ if (group_by & RRDR_GROUP_BY_INSTANCE)
848
+ buffer_json_add_array_item_string(wb, "instance");
849
709
- if(group_by & RRDR_GROUP_BY_DIMENSION)
710
- buffer_json_add_array_item_string(wb, "dimension");
850
+ if (group_by & RRDR_GROUP_BY_PERCENTAGE_OF_INSTANCE)
851
+ buffer_json_add_array_item_string(wb, "percentage-of-instance");
852
712
- if(group_by & RRDR_GROUP_BY_INSTANCE)
713
- buffer_json_add_array_item_string(wb, "instance");
853
+ if (group_by & RRDR_GROUP_BY_LABEL)
854
+ buffer_json_add_array_item_string(wb, "label");
855
715
- if(group_by & RRDR_GROUP_BY_LABEL)
716
- buffer_json_add_array_item_string(wb, "label");
856
+ if (group_by & RRDR_GROUP_BY_NODE)
857
+ buffer_json_add_array_item_string(wb, "node");
858
718
- if(group_by & RRDR_GROUP_BY_NODE)
719
- buffer_json_add_array_item_string(wb, "node");
859
+ if (group_by & RRDR_GROUP_BY_CONTEXT)
860
+ buffer_json_add_array_item_string(wb, "context");
861
721
- if(group_by & RRDR_GROUP_BY_CONTEXT)
722
- buffer_json_add_array_item_string(wb, "context");
862
+ if (group_by & RRDR_GROUP_BY_UNITS)
863
+ buffer_json_add_array_item_string(wb, "units");
864
724
- if(group_by & RRDR_GROUP_BY_UNITS)
725
- buffer_json_add_array_item_string(wb, "units");
865
+ if (group_by & RRDR_GROUP_BY_SELECTED)
866
+ buffer_json_add_array_item_string(wb, "selected");
867
+ }
868
}
869
870
RRDR_GROUP_BY_FUNCTION group_by_aggregate_function_parse(const char *s) {
1166
size_t tier;
1167
struct query_metric_tier *tier_ptr;
1168
struct storage_engine_query_handle *handle;
1027
- STORAGE_POINT (*next_metric)(struct storage_engine_query_handle *handle);
1028
- int (*is_finished)(struct storage_engine_query_handle *handle);
1029
- void (*finalize)(struct storage_engine_query_handle *handle);
1169
1170
// aggregating points over time
1032
- void (*grouping_add)(struct rrdresult *r, NETDATA_DOUBLE value);
1033
- NETDATA_DOUBLE (*grouping_flush)(struct rrdresult *r, RRDR_VALUE_FLAGS *rrdr_value_options_ptr);
1171
size_t group_points_non_zero;
1172
size_t group_points_added;
1173
STORAGE_POINT group_point; // aggregates min, max, sum, count, anomaly count for each group point
1182
time_t expanded_after;
1183
time_t expanded_before;
1184
struct storage_engine_query_handle handle;
1048
- STORAGE_POINT (*next_metric)(struct storage_engine_query_handle *handle);
1049
- int (*is_finished)(struct storage_engine_query_handle *handle);
1050
- void (*finalize)(struct storage_engine_query_handle *handle);
1185
bool initialized;
1186
bool finalized;
1187
} plans[QUERY_PLANS_MAX];
1250
1251
struct query_metric_tier *tier_ptr = &qm->tiers[tier];
1252
STORAGE_ENGINE *eng = query_metric_storage_engine(ops->r->internal.qt, qm, tier);
1119
- eng->api.query_ops.init(
1120
- tier_ptr->db_metric_handle,
1121
- &ops->plans[p].handle,
1122
- after, before,
1123
- ops->r->internal.qt->request.priority);
1124
-
1125
- ops->plans[p].next_metric = eng->api.query_ops.next_metric;
1126
- ops->plans[p].is_finished = eng->api.query_ops.is_finished;
1127
- ops->plans[p].finalize = eng->api.query_ops.finalize;
1253
+ storage_engine_query_init(eng->backend, tier_ptr->db_metric_handle, &ops->plans[p].handle,
1254
+ after, before, ops->r->internal.qt->request.priority);
1255
+
1256
ops->plans[p].initialized = true;
1257
ops->plans[p].finalized = false;
1258
}
1262
// QUERY_METRIC *qm = ops->qm;
1263
1264
if(ops->plans[plan_id].initialized && !ops->plans[plan_id].finalized) {
1137
- ops->plans[plan_id].finalize(&ops->plans[plan_id].handle);
1265
+ storage_engine_query_finalize(&ops->plans[plan_id].handle);
1266
ops->plans[plan_id].initialized = false;
1267
ops->plans[plan_id].finalized = true;
1140
- ops->plans[plan_id].next_metric = NULL;
1141
- ops->plans[plan_id].is_finished = NULL;
1142
- ops->plans[plan_id].finalize = NULL;
1143
-
1144
- if(ops->current_plan == plan_id) {
1145
- ops->next_metric = NULL;
1146
- ops->is_finished = NULL;
1147
- ops->finalize = NULL;
1148
- }
1268
}
1269
}
1270
1287
ops->tier = qm->plan.array[plan_id].tier;
1288
ops->tier_ptr = &qm->tiers[ops->tier];
1289
ops->handle = &ops->plans[plan_id].handle;
1171
- ops->next_metric = ops->plans[plan_id].next_metric;
1172
- ops->is_finished = ops->plans[plan_id].is_finished;
1173
- ops->finalize = ops->plans[plan_id].finalize;
1290
ops->current_plan = plan_id;
1291
1292
if(plan_id + 1 < qm->plan.used && qm->plan.array[plan_id + 1].after < qm->plan.array[plan_id].before)
1481
} \
1482
} while(0)
1483
1368
-#define query_add_point_to_group(r, point, ops) do { \
1484
+#define query_add_point_to_group(r, point, ops, add_flush) do { \
1485
if(likely(netdata_double_isnumber((point).value))) { \
1486
if(likely(fpclassify((point).value) != FP_ZERO)) \
1487
(ops)->group_points_non_zero++; \
1489
if(unlikely((point).sp.flags & SN_FLAG_RESET)) \
1490
(ops)->group_value_flags |= RRDR_VALUE_RESET; \
1491
\
1376
- (ops)->grouping_add(r, (point).value); \
1492
+ time_grouping_add(r, (point).value, add_flush); \
1493
\
1494
storage_point_merge_to((ops)->group_point, (point).sp); \
1495
if(!(point).added) \
1538
*ops = (QUERY_ENGINE_OPS) {
1539
.r = r,
1540
.qm = query_metric(qt, query_metric_id),
1425
- .grouping_add = r->time_grouping.add,
1426
- .grouping_flush = r->time_grouping.flush,
1541
.tier_query_fetch = r->time_grouping.tier_query_fetch,
1542
.view_update_every = r->view.update_every,
1543
.query_granularity = (time_t)(r->view.update_every / r->view.group),
1556
QUERY_TARGET *qt = r->internal.qt;
1557
QUERY_METRIC *qm = ops->qm;
1558
1559
+ const RRDR_TIME_GROUPING add_flush = r->time_grouping.add_flush;
1560
+
1561
ops->group_point = STORAGE_POINT_UNSET;
1562
ops->query_point = STORAGE_POINT_UNSET;
1563
1610
last1_point = new_point;
1611
}
1612
1497
- if(unlikely(ops->is_finished(ops->handle))) {
1613
+ if(unlikely(storage_engine_query_is_finished(ops->handle))) {
1614
query_is_finished_counter++;
1615
1616
if(count_same_end_time != 0) {
1633
STORAGE_POINT sp;
1634
if(likely(storage_point_is_unset(next1_point))) {
1635
db_points_read_since_plan_switch++;
1520
- sp = ops->next_metric(ops->handle);
1636
+ sp = storage_engine_query_next_metric(ops->handle);
1637
ops->db_points_read_per_tier[ops->tier]++;
1638
ops->db_total_points_read++;
1639
1659
// A. the entire point of the previous plan is to the future of point from the next plan
1660
// B. part of the point of the previous plan overlaps with the point from the next plan
1661
1546
- STORAGE_POINT sp2 = ops->next_metric(ops->handle);
1662
+ STORAGE_POINT sp2 = storage_engine_query_next_metric(ops->handle);
1663
ops->db_points_read_per_tier[ops->tier]++;
1664
ops->db_total_points_read++;
1665
1753
if(likely(new_point.sp.end_time_s >= now_start_time)) { // likely to favor tier0
1754
// this db point ends after our now_start time
1755
1640
- query_add_point_to_group(r, new_point, ops);
1756
+ query_add_point_to_group(r, new_point, ops, add_flush);
1757
new_point.added = true;
1758
}
1759
else {
1861
current_point = QUERY_POINT_EMPTY;
1862
}
1863
1748
- query_add_point_to_group(r, current_point, ops);
1864
+ query_add_point_to_group(r, current_point, ops, add_flush);
1865
1866
rrdr_line = rrdr_line_init(r, now_end_time, rrdr_line);
1867
size_t rrdr_o_v_index = rrdr_line * r->d + dim_id_in_rrdr;
1877
*rrdr_value_options_ptr = ops->group_value_flags;
1878
1879
// store the group value
1764
- NETDATA_DOUBLE group_value = ops->grouping_flush(r, rrdr_value_options_ptr);
1880
+ NETDATA_DOUBLE group_value = time_grouping_flush(r, rrdr_value_options_ptr, add_flush);
1881
r->v[rrdr_o_v_index] = group_value;
1882
1883
r->ar[rrdr_o_v_index] = storage_point_anomaly_rate(ops->group_point);
1945
struct rrddim_tier *t = &rd->tiers[tier];
1946
if(unlikely(!t)) return;
1947
1832
- time_t latest_time_s = t->query_ops->latest_time_s(t->db_metric_handle);
1948
+ time_t latest_time_s = storage_engine_latest_time_s(t->backend, t->db_metric_handle);
1949
time_t granularity = (time_t)t->tier_grouping * (time_t)rd->update_every;
1950
time_t time_diff = now_s - latest_time_s;
1951
1959
1960
// for each lower tier
1961
for(int read_tier = (int)tier - 1; read_tier >= 0 ; read_tier--){
1846
- time_t smaller_tier_first_time = rd->tiers[read_tier].query_ops->oldest_time_s(rd->tiers[read_tier].db_metric_handle);
1847
- time_t smaller_tier_last_time = rd->tiers[read_tier].query_ops->latest_time_s(rd->tiers[read_tier].db_metric_handle);
1962
+ time_t smaller_tier_first_time = storage_engine_oldest_time_s(rd->tiers[read_tier].backend, rd->tiers[read_tier].db_metric_handle);
1963
+ time_t smaller_tier_last_time = storage_engine_latest_time_s(rd->tiers[read_tier].backend, rd->tiers[read_tier].db_metric_handle);
1964
if(smaller_tier_last_time <= latest_time_s) continue; // it is as bad as we are
1965
1966
long after_wanted = (latest_time_s < smaller_tier_first_time) ? smaller_tier_first_time : latest_time_s;
1967
long before_wanted = smaller_tier_last_time;
1968
1969
struct rrddim_tier *tmp = &rd->tiers[read_tier];
1854
- tmp->query_ops->init(tmp->db_metric_handle, &handle, after_wanted, before_wanted, STORAGE_PRIORITY_HIGH);
1970
+ storage_engine_query_init(tmp->backend, tmp->db_metric_handle, &handle, after_wanted, before_wanted, STORAGE_PRIORITY_HIGH);
1971
1972
size_t points_read = 0;
1973
1858
- while(!tmp->query_ops->is_finished(&handle)) {
1974
+ while(!storage_engine_query_is_finished(&handle)) {
1975
1860
- STORAGE_POINT sp = tmp->query_ops->next_metric(&handle);
1976
+ STORAGE_POINT sp = storage_engine_query_next_metric(&handle);
1977
points_read++;
1978
1979
if(sp.end_time_s > latest_time_s) {
1982
}
1983
}
1984
1869
- tmp->query_ops->finalize(&handle);
1985
+ storage_engine_query_finalize(&handle);
1986
store_metric_collection_completed();
1987
global_statistics_backfill_query_completed(points_read);
1988
2555
before_wanted, r->t[points_wanted - 1]);
2556
}
2557
2558
+static void query_group_by_make_dimension_key(BUFFER *key, RRDR_GROUP_BY group_by, size_t group_by_id, QUERY_TARGET *qt, QUERY_NODE *qn, QUERY_CONTEXT *qc, QUERY_INSTANCE *qi, QUERY_DIMENSION *qd __maybe_unused, QUERY_METRIC *qm, bool query_has_percentage_of_instance) {
2559
+ buffer_flush(key);
2560
+ if(unlikely(!query_has_percentage_of_instance && qm->status & RRDR_DIMENSION_HIDDEN)) {
2561
+ buffer_strcat(key, "__hidden_dimensions__");
2562
+ }
2563
+ else if(unlikely(group_by & RRDR_GROUP_BY_SELECTED)) {
2564
+ buffer_strcat(key, "selected");
2565
+ }
2566
+ else {
2567
+ if (group_by & RRDR_GROUP_BY_DIMENSION) {
2568
+ buffer_fast_strcat(key, "|", 1);
2569
+ buffer_strcat(key, query_metric_name(qt, qm));
2570
+ }
2571
+
2572
+ if (group_by & (RRDR_GROUP_BY_INSTANCE|RRDR_GROUP_BY_PERCENTAGE_OF_INSTANCE)) {
2573
+ buffer_fast_strcat(key, "|", 1);
2574
+ buffer_strcat(key, string2str(query_instance_id_fqdn(qi, qt->request.version)));
2575
+ }
2576
+
2577
+ if (group_by & RRDR_GROUP_BY_LABEL) {
2578
+ DICTIONARY *labels = rrdinstance_acquired_labels(qi->ria);
2579
+ for (size_t l = 0; l < qt->group_by[group_by_id].used; l++) {
2580
+ buffer_fast_strcat(key, "|", 1);
2581
+ rrdlabels_get_value_to_buffer_or_unset(labels, key, qt->group_by[group_by_id].label_keys[l], "[unset]");
2582
+ }
2583
+ }
2584
+
2585
+ if (group_by & RRDR_GROUP_BY_NODE) {
2586
+ buffer_fast_strcat(key, "|", 1);
2587
+ buffer_strcat(key, qn->rrdhost->machine_guid);
2588
+ }
2589
+
2590
+ if (group_by & RRDR_GROUP_BY_CONTEXT) {
2591
+ buffer_fast_strcat(key, "|", 1);
2592
+ buffer_strcat(key, rrdcontext_acquired_id(qc->rca));
2593
+ }
2594
+
2595
+ if (group_by & RRDR_GROUP_BY_UNITS) {
2596
+ buffer_fast_strcat(key, "|", 1);
2597
+ buffer_strcat(key, query_target_has_percentage_units(qt) ? "%" : rrdinstance_acquired_units(qi->ria));
2598
+ }
2599
+ }
2600
+}
2601
+
2602
+static void query_group_by_make_dimension_id(BUFFER *key, RRDR_GROUP_BY group_by, size_t group_by_id, QUERY_TARGET *qt, QUERY_NODE *qn, QUERY_CONTEXT *qc, QUERY_INSTANCE *qi, QUERY_DIMENSION *qd __maybe_unused, QUERY_METRIC *qm, bool query_has_percentage_of_instance) {
2603
+ buffer_flush(key);
2604
+ if(unlikely(!query_has_percentage_of_instance && qm->status & RRDR_DIMENSION_HIDDEN)) {
2605
+ buffer_strcat(key, "__hidden_dimensions__");
2606
+ }
2607
+ else if(unlikely(group_by & RRDR_GROUP_BY_SELECTED)) {
2608
+ buffer_strcat(key, "selected");
2609
+ }
2610
+ else {
2611
+ if (group_by & RRDR_GROUP_BY_DIMENSION) {
2612
+ buffer_strcat(key, query_metric_name(qt, qm));
2613
+ }
2614
+
2615
+ if (group_by & (RRDR_GROUP_BY_INSTANCE|RRDR_GROUP_BY_PERCENTAGE_OF_INSTANCE)) {
2616
+ if (buffer_strlen(key) != 0)
2617
+ buffer_fast_strcat(key, ",", 1);
2618
+
2619
+ if (group_by & RRDR_GROUP_BY_NODE)
2620
+ buffer_strcat(key, rrdinstance_acquired_id(qi->ria));
2621
+ else
2622
+ buffer_strcat(key, string2str(query_instance_id_fqdn(qi, qt->request.version)));
2623
+ }
2624
+
2625
+ if (group_by & RRDR_GROUP_BY_LABEL) {
2626
+ DICTIONARY *labels = rrdinstance_acquired_labels(qi->ria);
2627
+ for (size_t l = 0; l < qt->group_by[group_by_id].used; l++) {
2628
+ if (buffer_strlen(key) != 0)
2629
+ buffer_fast_strcat(key, ",", 1);
2630
+ rrdlabels_get_value_to_buffer_or_unset(labels, key, qt->group_by[group_by_id].label_keys[l], "[unset]");
2631
+ }
2632
+ }
2633
+
2634
+ if (group_by & RRDR_GROUP_BY_NODE) {
2635
+ if (buffer_strlen(key) != 0)
2636
+ buffer_fast_strcat(key, ",", 1);
2637
+
2638
+ buffer_strcat(key, qn->rrdhost->machine_guid);
2639
+ }
2640
+
2641
+ if (group_by & RRDR_GROUP_BY_CONTEXT) {
2642
+ if (buffer_strlen(key) != 0)
2643
+ buffer_fast_strcat(key, ",", 1);
2644
+
2645
+ buffer_strcat(key, rrdcontext_acquired_id(qc->rca));
2646
+ }
2647
+
2648
+ if (group_by & RRDR_GROUP_BY_UNITS) {
2649
+ if (buffer_strlen(key) != 0)
2650
+ buffer_fast_strcat(key, ",", 1);
2651
+
2652
+ buffer_strcat(key, query_target_has_percentage_units(qt) ? "%" : rrdinstance_acquired_units(qi->ria));
2653
+ }
2654
+ }
2655
+}
2656
+
2657
+static void query_group_by_make_dimension_name(BUFFER *key, RRDR_GROUP_BY group_by, size_t group_by_id, QUERY_TARGET *qt, QUERY_NODE *qn, QUERY_CONTEXT *qc, QUERY_INSTANCE *qi, QUERY_DIMENSION *qd __maybe_unused, QUERY_METRIC *qm, bool query_has_percentage_of_instance) {
2658
+ buffer_flush(key);
2659
+ if(unlikely(!query_has_percentage_of_instance && qm->status & RRDR_DIMENSION_HIDDEN)) {
2660
+ buffer_strcat(key, "__hidden_dimensions__");
2661
+ }
2662
+ else if(unlikely(group_by & RRDR_GROUP_BY_SELECTED)) {
2663
+ buffer_strcat(key, "selected");
2664
+ }
2665
+ else {
2666
+ if (group_by & RRDR_GROUP_BY_DIMENSION) {
2667
+ buffer_strcat(key, query_metric_name(qt, qm));
2668
+ }
2669
+
2670
+ if (group_by & (RRDR_GROUP_BY_INSTANCE|RRDR_GROUP_BY_PERCENTAGE_OF_INSTANCE)) {
2671
+ if (buffer_strlen(key) != 0)
2672
+ buffer_fast_strcat(key, ",", 1);
2673
+
2674
+ if (group_by & RRDR_GROUP_BY_NODE)
2675
+ buffer_strcat(key, rrdinstance_acquired_name(qi->ria));
2676
+ else
2677
+ buffer_strcat(key, string2str(query_instance_name_fqdn(qi, qt->request.version)));
2678
+ }
2679
+
2680
+ if (group_by & RRDR_GROUP_BY_LABEL) {
2681
+ DICTIONARY *labels = rrdinstance_acquired_labels(qi->ria);
2682
+ for (size_t l = 0; l < qt->group_by[group_by_id].used; l++) {
2683
+ if (buffer_strlen(key) != 0)
2684
+ buffer_fast_strcat(key, ",", 1);
2685
+ rrdlabels_get_value_to_buffer_or_unset(labels, key, qt->group_by[group_by_id].label_keys[l], "[unset]");
2686
+ }
2687
+ }
2688
+
2689
+ if (group_by & RRDR_GROUP_BY_NODE) {
2690
+ if (buffer_strlen(key) != 0)
2691
+ buffer_fast_strcat(key, ",", 1);
2692
+
2693
+ buffer_strcat(key, rrdhost_hostname(qn->rrdhost));
2694
+ }
2695
+
2696
+ if (group_by & RRDR_GROUP_BY_CONTEXT) {
2697
+ if (buffer_strlen(key) != 0)
2698
+ buffer_fast_strcat(key, ",", 1);
2699
+
2700
+ buffer_strcat(key, rrdcontext_acquired_id(qc->rca));
2701
+ }
2702
+
2703
+ if (group_by & RRDR_GROUP_BY_UNITS) {
2704
+ if (buffer_strlen(key) != 0)
2705
+ buffer_fast_strcat(key, ",", 1);
2706
+
2707
+ buffer_strcat(key, query_target_has_percentage_units(qt) ? "%" : rrdinstance_acquired_units(qi->ria));
2708
+ }
2709
+ }
2710
+}
2711
+
2712
+struct rrdr_group_by_entry {
2713
+ size_t priority;
2714
+ size_t count;
2715
+ STRING *id;
2716
+ STRING *name;
2717
+ STRING *units;
2718
+ RRDR_DIMENSION_FLAGS od;
2719
+ DICTIONARY *dl;
2720
+};
2721
+
2722
static RRDR *rrd2rrdr_group_by_initialize(ONEWAYALLOC *owa, QUERY_TARGET *qt) {
2723
RRDR_OPTIONS options = qt->window.options;
2724
2445
- if(qt->request.group_by == RRDR_GROUP_BY_NONE) {
2725
+ if(qt->request.version < 2) {
2726
+ // v1 query
2727
RRDR *r = rrdr_create(owa, qt, qt->query.used, qt->window.points);
2728
if(unlikely(!r)) {
2729
internal_error(true, "QUERY: cannot create RRDR for %s, after=%ld, before=%ld, dimensions=%u, points=%zu",
2730
qt->id, qt->window.after, qt->window.before, qt->query.used, qt->window.points);
2450
- query_target_release(qt);
2731
return NULL;
2732
}
2733
r->group_by.r = NULL;
2742
rrd2rrdr_set_timestamps(r);
2743
return r;
2744
}
2745
+ // v2 query
2746
2466
- struct rrdr_group_by_entry *entries = onewayalloc_callocz(owa, qt->query.used, sizeof(struct rrdr_group_by_entry));
2467
- DICTIONARY *groups = dictionary_create(DICT_OPTION_SINGLE_THREADED | DICT_OPTION_DONT_OVERWRITE_VALUE);
2468
-
2469
- if(qt->request.group_by & RRDR_GROUP_BY_LABEL && qt->request.group_by_label && *qt->request.group_by_label)
2470
- qt->group_by.used = quoted_strings_splitter(qt->request.group_by_label, qt->group_by.label_keys, GROUP_BY_MAX_LABEL_KEYS, group_by_label_is_space);
2471
-
2472
- if(!qt->group_by.used)
2473
- qt->request.group_by &= ~RRDR_GROUP_BY_LABEL;
2474
-
2475
- if(!(qt->request.group_by & (RRDR_GROUP_BY_SELECTED | RRDR_GROUP_BY_DIMENSION | RRDR_GROUP_BY_INSTANCE | RRDR_GROUP_BY_LABEL | RRDR_GROUP_BY_NODE | RRDR_GROUP_BY_CONTEXT)))
2476
- qt->request.group_by = RRDR_GROUP_BY_DIMENSION;
2477
-
2478
- DICTIONARY *label_keys = NULL;
2479
- if(options & RRDR_OPTION_GROUP_BY_LABELS)
2480
- label_keys = dictionary_create_advanced(DICT_OPTION_SINGLE_THREADED | DICT_OPTION_DONT_OVERWRITE_VALUE, NULL, 0);
2747
+ // parse all the group-by label keys
2748
+ for(size_t g = 0; g < MAX_QUERY_GROUP_BY_PASSES ;g++) {
2749
+ if (qt->request.group_by[g].group_by & RRDR_GROUP_BY_LABEL &&
2750
+ qt->request.group_by[g].group_by_label && *qt->request.group_by[g].group_by_label)
2751
+ qt->group_by[g].used = quoted_strings_splitter(
2752
+ qt->request.group_by[g].group_by_label, qt->group_by[g].label_keys,
2753
+ GROUP_BY_MAX_LABEL_KEYS, group_by_label_is_space);
2754
2482
- int added = 0;
2483
- BUFFER *key = buffer_create(0, NULL);
2484
- QUERY_INSTANCE *last_qi = NULL;
2485
- size_t priority = 0;
2486
- time_t update_every_max = 0;
2487
- for(size_t d = 0; d < qt->query.used ; d++) {
2488
- QUERY_METRIC *qm = query_metric(qt, d);
2489
- QUERY_INSTANCE *qi = query_instance(qt, qm->link.query_instance_id);
2490
- QUERY_CONTEXT *qc = query_context(qt, qm->link.query_context_id);
2491
- QUERY_NODE *qn = query_node(qt, qm->link.query_node_id);
2755
+ if (!qt->group_by[g].used)
2756
+ qt->request.group_by[g].group_by &= ~RRDR_GROUP_BY_LABEL;
2757
+ }
2758
2493
- if(qi != last_qi) {
2494
- priority = 0;
2495
- last_qi = qi;
2759
+ // make sure there are valid group-by methods
2760
+ bool query_has_percentage_of_instance = false;
2761
+ for(size_t g = 0; g < MAX_QUERY_GROUP_BY_PASSES - 1 ;g++) {
2762
+ if(!(qt->request.group_by[g].group_by & SUPPORTED_GROUP_BY_METHODS))
2763
+ qt->request.group_by[g].group_by = (g == 0) ? RRDR_GROUP_BY_DIMENSION : RRDR_GROUP_BY_NONE;
2764
2497
- time_t update_every = rrdinstance_acquired_update_every(qi->ria);
2498
- if(update_every > update_every_max)
2499
- update_every_max = update_every;
2500
- }
2501
- else
2502
- priority++;
2765
+ if(qt->request.group_by[g].group_by & RRDR_GROUP_BY_PERCENTAGE_OF_INSTANCE)
2766
+ query_has_percentage_of_instance = true;
2767
+ }
2768
2504
- // --------------------------------------------------------------------
2505
- // generate the group by key
2769
+ // merge all group-by options to upper levels
2770
+ for(size_t g = 0; g < MAX_QUERY_GROUP_BY_PASSES - 1 ;g++) {
2771
+ if(qt->request.group_by[g].group_by == RRDR_GROUP_BY_NONE)
2772
+ continue;
2773
2507
- buffer_flush(key);
2508
- if(unlikely(qm->status & RRDR_DIMENSION_HIDDEN)) {
2509
- buffer_strcat(key, "__hidden_dimensions__");
2510
- }
2511
- else if(unlikely(qt->request.group_by & RRDR_GROUP_BY_SELECTED)) {
2512
- buffer_strcat(key, "selected");
2774
+ if(qt->request.group_by[g].group_by == RRDR_GROUP_BY_SELECTED) {
2775
+ for (size_t r = g + 1; r < MAX_QUERY_GROUP_BY_PASSES; r++)
2776
+ qt->request.group_by[r].group_by = RRDR_GROUP_BY_NONE;
2777
}
2778
else {
2515
- if (qt->request.group_by & RRDR_GROUP_BY_DIMENSION) {
2516
- buffer_fast_strcat(key, "|", 1);
2517
- buffer_strcat(key, query_metric_name(qt, qm));
2518
- }
2779
+ for (size_t r = g + 1; r < MAX_QUERY_GROUP_BY_PASSES; r++) {
2780
+ if (qt->request.group_by[r].group_by == RRDR_GROUP_BY_NONE)
2781
+ continue;
2782
2520
- if (qt->request.group_by & RRDR_GROUP_BY_INSTANCE) {
2521
- buffer_fast_strcat(key, "|", 1);
2522
- buffer_strcat(key, string2str(query_instance_id_fqdn(qi, qt->request.version)));
2523
- }
2783
+ if (qt->request.group_by[r].group_by != RRDR_GROUP_BY_SELECTED) {
2784
+ if(qt->request.group_by[r].group_by & RRDR_GROUP_BY_PERCENTAGE_OF_INSTANCE)
2785
+ qt->request.group_by[g].group_by |= RRDR_GROUP_BY_INSTANCE;
2786
+ else
2787
+ qt->request.group_by[g].group_by |= qt->request.group_by[r].group_by;
2788
+
2789
+ if(qt->request.group_by[r].group_by & RRDR_GROUP_BY_LABEL) {
2790
+ for (size_t lr = 0; lr < qt->group_by[r].used; lr++) {
2791
+ bool found = false;
2792
+ for (size_t lg = 0; lg < qt->group_by[g].used; lg++) {
2793
+ if (strcmp(qt->group_by[g].label_keys[lg], qt->group_by[r].label_keys[lr]) == 0) {
2794
+ found = true;
2795
+ break;
2796
+ }
2797
+ }
2798
2525
- if (qt->request.group_by & RRDR_GROUP_BY_LABEL) {
2526
- DICTIONARY *labels = rrdinstance_acquired_labels(qi->ria);
2527
- for (size_t l = 0; l < qt->group_by.used; l++) {
2528
- buffer_fast_strcat(key, "|", 1);
2529
- rrdlabels_get_value_to_buffer_or_unset(labels, key, qt->group_by.label_keys[l], "[unset]");
2799
+ if (!found && qt->group_by[g].used < GROUP_BY_MAX_LABEL_KEYS * MAX_QUERY_GROUP_BY_PASSES)
2800
+ qt->group_by[g].label_keys[qt->group_by[g].used++] = qt->group_by[r].label_keys[lr];
2801
+ }
2802
+ }
2803
}
2804
}
2532
-
2533
- if (qt->request.group_by & RRDR_GROUP_BY_NODE) {
2534
- buffer_fast_strcat(key, "|", 1);
2535
- buffer_strcat(key, qn->rrdhost->machine_guid);
2536
- }
2537
-
2538
- if (qt->request.group_by & RRDR_GROUP_BY_CONTEXT) {
2539
- buffer_fast_strcat(key, "|", 1);
2540
- buffer_strcat(key, rrdcontext_acquired_id(qc->rca));
2541
- }
2542
-
2543
- if (qt->request.group_by & RRDR_GROUP_BY_UNITS) {
2544
- buffer_fast_strcat(key, "|", 1);
2545
- buffer_strcat(key, query_target_has_percentage_units(qt) ? "%" : rrdinstance_acquired_units(qi->ria));
2546
- }
2805
}
2806
+ }
2807
2549
- // lookup the key in the dictionary
2808
+ int added = 0;
2809
+ RRDR *first_r = NULL, *last_r = NULL;
2810
+ BUFFER *key = buffer_create(0, NULL);
2811
+ struct rrdr_group_by_entry *entries = onewayalloc_mallocz(owa, qt->query.used * sizeof(struct rrdr_group_by_entry));
2812
+ DICTIONARY *groups = dictionary_create(DICT_OPTION_SINGLE_THREADED | DICT_OPTION_DONT_OVERWRITE_VALUE);
2813
+ DICTIONARY *label_keys = NULL;
2814
2551
- int pos = -1;
2552
- int *set = dictionary_set(groups, buffer_tostring(key), &pos, sizeof(pos));
2553
- if(*set == -1) {
2554
- // the key just added to the dictionary
2815
+ for(size_t g = 0; g < MAX_QUERY_GROUP_BY_PASSES ;g++) {
2816
+ RRDR_GROUP_BY group_by = qt->request.group_by[g].group_by;
2817
2556
- *set = pos = added++;
2818
+ if(group_by == RRDR_GROUP_BY_NONE)
2819
+ break;
2820
2558
- // ----------------------------------------------------------------
2559
- // generate the dimension id
2821
+ memset(entries, 0, qt->query.used * sizeof(struct rrdr_group_by_entry));
2822
+ dictionary_flush(groups);
2823
+ added = 0;
2824
2561
- buffer_flush(key);
2562
- if(unlikely(qm->status & RRDR_DIMENSION_HIDDEN)) {
2563
- buffer_strcat(key, "__hidden_dimensions__");
2564
- }
2565
- else if(unlikely(qt->request.group_by & RRDR_GROUP_BY_SELECTED)) {
2566
- buffer_strcat(key, "selected");
2567
- }
2568
- else {
2569
- if (qt->request.group_by & RRDR_GROUP_BY_DIMENSION) {
2570
- buffer_strcat(key, query_metric_name(qt, qm));
2571
- }
2825
+ size_t hidden_dimensions = 0;
2826
+ bool final_grouping = (g == MAX_QUERY_GROUP_BY_PASSES - 1 || qt->request.group_by[g + 1].group_by == RRDR_GROUP_BY_NONE) ? true : false;
2827
2573
- if (qt->request.group_by & RRDR_GROUP_BY_INSTANCE) {
2574
- if (buffer_strlen(key) != 0)
2575
- buffer_fast_strcat(key, ",", 1);
2828
+ if (final_grouping && (options & RRDR_OPTION_GROUP_BY_LABELS))
2829
+ label_keys = dictionary_create_advanced(DICT_OPTION_SINGLE_THREADED | DICT_OPTION_DONT_OVERWRITE_VALUE, NULL, 0);
2830
2577
- if (qt->request.group_by & RRDR_GROUP_BY_NODE)
2578
- buffer_strcat(key, rrdinstance_acquired_id(qi->ria));
2579
- else
2580
- buffer_strcat(key, string2str(query_instance_id_fqdn(qi, qt->request.version)));
2581
- }
2831
+ QUERY_INSTANCE *last_qi = NULL;
2832
+ size_t priority = 0;
2833
+ time_t update_every_max = 0;
2834
+ for (size_t d = 0; d < qt->query.used; d++) {
2835
+ QUERY_METRIC *qm = query_metric(qt, d);
2836
+ QUERY_DIMENSION *qd = query_dimension(qt, qm->link.query_dimension_id);
2837
+ QUERY_INSTANCE *qi = query_instance(qt, qm->link.query_instance_id);
2838
+ QUERY_CONTEXT *qc = query_context(qt, qm->link.query_context_id);
2839
+ QUERY_NODE *qn = query_node(qt, qm->link.query_node_id);
2840
2583
- if (qt->request.group_by & RRDR_GROUP_BY_LABEL) {
2584
- DICTIONARY *labels = rrdinstance_acquired_labels(qi->ria);
2585
- for (size_t l = 0; l < qt->group_by.used; l++) {
2586
- if (buffer_strlen(key) != 0)
2587
- buffer_fast_strcat(key, ",", 1);
2588
- rrdlabels_get_value_to_buffer_or_unset(labels, key, qt->group_by.label_keys[l], "[unset]");
2589
- }
2590
- }
2841
+ if (qi != last_qi) {
2842
+ last_qi = qi;
2843
2592
- if (qt->request.group_by & RRDR_GROUP_BY_NODE) {
2593
- if (buffer_strlen(key) != 0)
2594
- buffer_fast_strcat(key, ",", 1);
2844
+ time_t update_every = rrdinstance_acquired_update_every(qi->ria);
2845
+ if (update_every > update_every_max)
2846
+ update_every_max = update_every;
2847
+ }
2848
2596
- buffer_strcat(key, qn->rrdhost->machine_guid);
2597
- }
2849
+ priority = qd->priority;
2850
2599
- if (qt->request.group_by & RRDR_GROUP_BY_CONTEXT) {
2600
- if (buffer_strlen(key) != 0)
2601
- buffer_fast_strcat(key, ",", 1);
2851
+ if(qm->status & RRDR_DIMENSION_HIDDEN)
2852
+ hidden_dimensions++;
2853
2603
- buffer_strcat(key, rrdcontext_acquired_id(qc->rca));
2604
- }
2854
+ // --------------------------------------------------------------------
2855
+ // generate the group by key
2856
2606
- if (qt->request.group_by & RRDR_GROUP_BY_UNITS) {
2607
- if (buffer_strlen(key) != 0)
2608
- buffer_fast_strcat(key, ",", 1);
2857
+ query_group_by_make_dimension_key(key, group_by, g, qt, qn, qc, qi, qd, qm, query_has_percentage_of_instance);
2858
2610
- buffer_strcat(key, query_target_has_percentage_units(qt) ? "%" : rrdinstance_acquired_units(qi->ria));
2611
- }
2612
- }
2859
+ // lookup the key in the dictionary
2860
2614
- entries[pos].id = string_strdupz(buffer_tostring(key));
2861
+ int pos = -1;
2862
+ int *set = dictionary_set(groups, buffer_tostring(key), &pos, sizeof(pos));
2863
+ if (*set == -1) {
2864
+ // the key just added to the dictionary
2865
2616
- // ----------------------------------------------------------------
2617
- // generate the dimension name
2866
+ *set = pos = added++;
2867
2619
- buffer_flush(key);
2620
- if(unlikely(qm->status & RRDR_DIMENSION_HIDDEN)) {
2621
- buffer_strcat(key, "__hidden_dimensions__");
2622
- }
2623
- else if(unlikely(qt->request.group_by & RRDR_GROUP_BY_SELECTED)) {
2624
- buffer_strcat(key, "selected");
2625
- }
2626
- else {
2627
- if (qt->request.group_by & RRDR_GROUP_BY_DIMENSION) {
2628
- buffer_strcat(key, query_metric_name(qt, qm));
2629
- }
2868
+ // ----------------------------------------------------------------
2869
+ // generate the dimension id
2870
2631
- if (qt->request.group_by & RRDR_GROUP_BY_INSTANCE) {
2632
- if (buffer_strlen(key) != 0)
2633
- buffer_fast_strcat(key, ",", 1);
2871
+ query_group_by_make_dimension_id(key, group_by, g, qt, qn, qc, qi, qd, qm, query_has_percentage_of_instance);
2872
+ entries[pos].id = string_strdupz(buffer_tostring(key));
2873
2635
- if (qt->request.group_by & RRDR_GROUP_BY_NODE)
2636
- buffer_strcat(key, rrdinstance_acquired_name(qi->ria));
2637
- else
2638
- buffer_strcat(key, string2str(query_instance_name_fqdn(qi, qt->request.version)));
2639
- }
2874
+ // ----------------------------------------------------------------
2875
+ // generate the dimension name
2876
2641
- if (qt->request.group_by & RRDR_GROUP_BY_LABEL) {
2642
- DICTIONARY *labels = rrdinstance_acquired_labels(qi->ria);
2643
- for (size_t l = 0; l < qt->group_by.used; l++) {
2644
- if (buffer_strlen(key) != 0)
2645
- buffer_fast_strcat(key, ",", 1);
2646
- rrdlabels_get_value_to_buffer_or_unset(labels, key, qt->group_by.label_keys[l], "[unset]");
2647
- }
2648
- }
2877
+ query_group_by_make_dimension_name(key, group_by, g, qt, qn, qc, qi, qd, qm, query_has_percentage_of_instance);
2878
+ entries[pos].name = string_strdupz(buffer_tostring(key));
2879
2650
- if (qt->request.group_by & RRDR_GROUP_BY_NODE) {
2651
- if (buffer_strlen(key) != 0)
2652
- buffer_fast_strcat(key, ",", 1);
2880
+ // add the rest of the info
2881
+ entries[pos].units = rrdinstance_acquired_units_dup(qi->ria);
2882
+ entries[pos].priority = priority;
2883
2654
- buffer_strcat(key, rrdhost_hostname(qn->rrdhost));
2884
+ if (label_keys) {
2885
+ entries[pos].dl = dictionary_create_advanced(
2886
+ DICT_OPTION_SINGLE_THREADED | DICT_OPTION_FIXED_SIZE | DICT_OPTION_DONT_OVERWRITE_VALUE,
2887
+ NULL, sizeof(struct group_by_label_key));
2888
+ dictionary_register_insert_callback(entries[pos].dl, group_by_label_key_insert_cb, label_keys);
2889
+ dictionary_register_delete_callback(entries[pos].dl, group_by_label_key_delete_cb, label_keys);
2890
}
2891
+ } else {
2892
+ // the key found in the dictionary
2893
+ pos = *set;
2894
+ }
2895
2657
- if (qt->request.group_by & RRDR_GROUP_BY_CONTEXT) {
2658
- if (buffer_strlen(key) != 0)
2659
- buffer_fast_strcat(key, ",", 1);
2896
+ entries[pos].count++;
2897
2661
- buffer_strcat(key, rrdcontext_acquired_id(qc->rca));
2662
- }
2898
+ if (unlikely(priority < entries[pos].priority))
2899
+ entries[pos].priority = priority;
2900
2664
- if (qt->request.group_by & RRDR_GROUP_BY_UNITS) {
2665
- if (buffer_strlen(key) != 0)
2666
- buffer_fast_strcat(key, ",", 1);
2901
+ if(g > 0)
2902
+ last_r->dgbs[qm->grouped_as.slot] = pos;
2903
+ else
2904
+ qm->grouped_as.first_slot = pos;
2905
+
2906
+ qm->grouped_as.slot = pos;
2907
+ qm->grouped_as.id = entries[pos].id;
2908
+ qm->grouped_as.name = entries[pos].name;
2909
+ qm->grouped_as.units = entries[pos].units;
2910
+
2911
+ // copy the dimension flags decided by the query target
2912
+ // we need this, because if a dimension is explicitly selected
2913
+ // the query target adds to it the non-zero flag
2914
+ qm->status |= RRDR_DIMENSION_GROUPED;
2915
+
2916
+ if(query_has_percentage_of_instance)
2917
+ // when the query has percentage of instance
2918
+ // there will be no hidden dimensions in the final query
2919
+ // so we have to remove the hidden flag from all dimensions
2920
+ entries[pos].od |= qm->status & ~RRDR_DIMENSION_HIDDEN;
2921
+ else
2922
+ entries[pos].od |= qm->status;
2923
2668
- buffer_strcat(key, query_target_has_percentage_units(qt) ? "%" : rrdinstance_acquired_units(qi->ria));
2669
- }
2670
- }
2924
+ if (entries[pos].dl)
2925
+ rrdlabels_walkthrough_read(rrdinstance_acquired_labels(qi->ria),
2926
+ rrdlabels_traversal_cb_to_group_by_label_key, entries[pos].dl);
2927
+ }
2928
2672
- entries[pos].name = string_strdupz(buffer_tostring(key));
2929
+ RRDR *r = rrdr_create(owa, qt, added, qt->window.points);
2930
+ if (!r) {
2931
+ internal_error(true,
2932
+ "QUERY: cannot create group by RRDR for %s, after=%ld, before=%ld, dimensions=%d, points=%zu",
2933
+ qt->id, qt->window.after, qt->window.before, added, qt->window.points);
2934
+ goto cleanup;
2935
+ }
2936
2674
- // add the rest of the info
2675
- entries[pos].units = rrdinstance_acquired_units_dup(qi->ria);
2676
- entries[pos].priority = priority;
2937
+ bool hidden_dimension_on_percentage_of_instance = hidden_dimensions && (group_by & RRDR_GROUP_BY_PERCENTAGE_OF_INSTANCE);
2938
2678
- if(options & RRDR_OPTION_GROUP_BY_LABELS) {
2679
- entries[pos].dl = dictionary_create_advanced(
2680
- DICT_OPTION_SINGLE_THREADED | DICT_OPTION_FIXED_SIZE | DICT_OPTION_DONT_OVERWRITE_VALUE,
2681
- NULL, sizeof(struct group_by_label_key));
2682
- dictionary_register_insert_callback(entries[pos].dl, group_by_label_key_insert_cb, label_keys);
2683
- dictionary_register_delete_callback(entries[pos].dl, group_by_label_key_delete_cb, label_keys);
2684
- }
2685
- }
2686
- else {
2687
- // the key found in the dictionary
2688
- pos = *set;
2689
- }
2939
+ // prevent double cleanup in case of error
2940
+ added = 0;
2941
2691
- entries[pos].count++;
2942
+ if(!last_r)
2943
+ first_r = last_r = r;
2944
+ else
2945
+ last_r->group_by.r = r;
2946
+
2947
+ last_r = r;
2948
+
2949
+ rrd2rrdr_set_timestamps(r);
2950
+ r->dp = onewayalloc_callocz(owa, r->d, sizeof(*r->dp));
2951
+ r->dview = onewayalloc_callocz(owa, r->d, sizeof(*r->dview));
2952
+ r->dgbc = onewayalloc_callocz(owa, r->d, sizeof(*r->dgbc));
2953
+ r->gbc = onewayalloc_callocz(owa, r->n * r->d, sizeof(*r->gbc));
2954
+ r->dqp = onewayalloc_callocz(owa, r->d, sizeof(STORAGE_POINT));
2955
+
2956
+ if(hidden_dimension_on_percentage_of_instance)
2957
+ // this is where we are going to group the hidden dimensions
2958
+ r->vh = onewayalloc_mallocz(owa, r->n * r->d * sizeof(*r->vh));
2959
+
2960
+ if(!final_grouping)
2961
+ // this is where we are going to store the slot in the next RRDR
2962
+ // that we are going to group by the dimension of this RRDR
2963
+ r->dgbs = onewayalloc_callocz(owa, r->d, sizeof(*r->dgbs));
2964
+
2965
+ if (label_keys) {
2966
+ r->dl = onewayalloc_callocz(owa, r->d, sizeof(DICTIONARY *));
2967
+ r->label_keys = label_keys;
2968
+ label_keys = NULL;
2969
+ }
2970
2693
- if(unlikely(priority < entries[pos].priority))
2694
- entries[pos].priority = priority;
2971
+ // zero r (dimension options, names, and ids)
2972
+ // this is required, because group-by may lead to empty dimensions
2973
+ for (size_t d = 0; d < r->d; d++) {
2974
+ r->di[d] = entries[d].id;
2975
+ r->dn[d] = entries[d].name;
2976
2696
- qm->grouped_as.slot = pos;
2697
- qm->grouped_as.id = entries[pos].id;
2698
- qm->grouped_as.name = entries[pos].name;
2699
- qm->grouped_as.units = entries[pos].units;
2977
+ r->od[d] = entries[d].od;
2978
+ r->du[d] = entries[d].units;
2979
+ r->dp[d] = entries[d].priority;
2980
+ r->dgbc[d] = entries[d].count;
2981
2701
- // copy the dimension flags decided by the query target
2702
- // we need this, because if a dimension is explicitly selected
2703
- // the query target adds to it the non-zero flag
2704
- qm->status |= RRDR_DIMENSION_GROUPED;
2705
- entries[pos].od |= qm->status;
2982
+ if (r->dl)
2983
+ r->dl[d] = entries[d].dl;
2984
+ }
2985
2707
- if(entries[pos].dl)
2708
- rrdlabels_walkthrough_read(rrdinstance_acquired_labels(qi->ria),
2709
- rrdlabels_traversal_cb_to_group_by_label_key, entries[pos].dl);
2986
+ // initialize partial trimming
2987
+ r->partial_data_trimming.max_update_every = update_every_max;
2988
+ r->partial_data_trimming.expected_after =
2989
+ (!(qt->window.options & RRDR_OPTION_RETURN_RAW) &&
2990
+ qt->window.before >= qt->window.now - update_every_max) ?
2991
+ qt->window.before - update_every_max :
2992
+ qt->window.before;
2993
+ r->partial_data_trimming.trimmed_after = qt->window.before;
2994
+
2995
+ // make all values empty
2996
+ for (size_t i = 0; i != r->n; i++) {
2997
+ NETDATA_DOUBLE *cn = &r->v[i * r->d];
2998
+ RRDR_VALUE_FLAGS *co = &r->o[i * r->d];
2999
+ NETDATA_DOUBLE *ar = &r->ar[i * r->d];
3000
+ NETDATA_DOUBLE *vh = r->vh ? &r->vh[i * r->d] : NULL;
3001
+
3002
+ for (size_t d = 0; d < r->d; d++) {
3003
+ cn[d] = NAN;
3004
+ ar[d] = 0.0;
3005
+ co[d] = RRDR_VALUE_EMPTY;
3006
+
3007
+ if(vh)
3008
+ *vh = NAN;
3009
+ }
3010
+ }
3011
}
3012
2712
- RRDR *r = rrdr_create(owa, qt, added, qt->window.points);
2713
- if(!r) {
2714
- internal_error(true, "QUERY: cannot create group by RRDR for %s, after=%ld, before=%ld, dimensions=%d, points=%zu",
2715
- qt->id, qt->window.after, qt->window.before, added, qt->window.points);
3013
+ if(!first_r || !last_r)
3014
goto cleanup;
2717
- }
3015
2719
- r->group_by.r = rrdr_create(owa, qt, 1, qt->window.points);
2720
- if(!r->group_by.r) {
2721
- internal_error(true, "QUERY: cannot create group by temporary RRDR for %s, after=%ld, before=%ld, dimensions=%d, points=%zu",
3016
+ RRDR *r_tmp = rrdr_create(owa, qt, 1, qt->window.points);
3017
+ if (!r_tmp) {
3018
+ internal_error(true,
3019
+ "QUERY: cannot create group by temporary RRDR for %s, after=%ld, before=%ld, dimensions=%d, points=%zu",
3020
qt->id, qt->window.after, qt->window.before, 1, qt->window.points);
3021
goto cleanup;
3022
}
3023
+ rrd2rrdr_set_timestamps(r_tmp);
3024
+ r_tmp->group_by.r = first_r;
3025
2726
- rrd2rrdr_set_timestamps(r);
2727
- rrd2rrdr_set_timestamps(r->group_by.r);
2728
-
2729
- r->dp = onewayalloc_callocz(r->internal.owa, r->d, sizeof(*r->dp));
2730
- r->dview = onewayalloc_callocz(r->internal.owa, r->d, sizeof(*r->dview));
2731
- r->dgbc = onewayalloc_callocz(r->internal.owa, r->d, sizeof(*r->dgbc));
2732
- r->gbc = onewayalloc_callocz(r->internal.owa, r->n * r->d, sizeof(*r->gbc));
2733
- r->dqp = onewayalloc_callocz(r->internal.owa, r->d, sizeof(STORAGE_POINT));
2734
-
2735
- if(options & RRDR_OPTION_GROUP_BY_LABELS) {
2736
- r->dl = onewayalloc_callocz(r->internal.owa, r->d, sizeof(DICTIONARY *));
2737
- r->label_keys = label_keys;
2738
- }
2739
-
2740
- // zero r (dimension options, names, and ids)
2741
- // this is required, because group-by may lead to empty dimensions
2742
- for(size_t d = 0; d < r->d ; d++) {
2743
- r->di[d] = entries[d].id;
2744
- r->dn[d] = entries[d].name;
2745
-
2746
- r->od[d] = entries[d].od;
2747
- r->du[d] = entries[d].units;
2748
- r->dp[d] = entries[d].priority;
2749
- r->dgbc[d] = entries[d].count;
2750
-
2751
- if(r->dl)
2752
- r->dl[d] = entries[d].dl;
2753
- }
2754
-
2755
- // initialize partial trimming
2756
- r->partial_data_trimming.max_update_every = update_every_max;
2757
- r->partial_data_trimming.expected_after =
2758
- (!(qt->window.options & RRDR_OPTION_RETURN_RAW) && qt->window.before >= qt->window.now - update_every_max) ?
2759
- qt->window.before - update_every_max :
2760
- qt->window.before;
2761
- r->partial_data_trimming.trimmed_after = qt->window.before;
2762
-
2763
- // make all values empty
2764
- for(size_t i = 0; i != r->n ;i++) {
2765
- NETDATA_DOUBLE *cn = &r->v[ i * r->d ];
2766
- RRDR_VALUE_FLAGS *co = &r->o[ i * r->d ];
2767
- NETDATA_DOUBLE *ar = &r->ar[ i * r->d ];
2768
- for (size_t d = 0; d < r->d; d++) {
2769
- cn[d] = 0.0;
2770
- ar[d] = 0.0;
2771
- co[d] = RRDR_VALUE_EMPTY;
3026
+cleanup:
3027
+ if(!first_r || !last_r || !r_tmp) {
3028
+ if(r_tmp) {
3029
+ r_tmp->group_by.r = NULL;
3030
+ rrdr_free(owa, r_tmp);
3031
}
2773
- }
3032
2775
-cleanup:
2776
- buffer_free(key);
3033
+ if(first_r) {
3034
+ RRDR *r = first_r;
3035
+ while (r) {
3036
+ r_tmp = r->group_by.r;
3037
+ r->group_by.r = NULL;
3038
+ rrdr_free(owa, r);
3039
+ r = r_tmp;
3040
+ }
3041
+ }
3042
2778
- if(!r) {
2779
- if(entries) {
2780
- for (int d2 = 0; d2 < added; d2++) {
2781
- string_freez(entries[d2].id);
2782
- string_freez(entries[d2].name);
2783
- dictionary_destroy(entries[d2].dl);
3043
+ if(entries && added) {
3044
+ for (int d = 0; d < added; d++) {
3045
+ string_freez(entries[d].id);
3046
+ string_freez(entries[d].name);
3047
+ string_freez(entries[d].units);
3048
+ dictionary_destroy(entries[d].dl);
3049
}
3050
}
3051
dictionary_destroy(label_keys);
2787
- query_target_release(qt);
2788
- }
2789
- else if(!r->group_by.r) {
2790
- rrdr_free(owa, r);
2791
- r = NULL;
3052
+
3053
+ first_r = last_r = r_tmp = NULL;
3054
}
3055
3056
+ buffer_free(key);
3057
onewayalloc_freez(owa, entries);
3058
dictionary_destroy(groups);
3059
2797
- return r;
3060
+ return r_tmp;
3061
}
3062
2800
-static void rrd2rrdr_group_by_add_metric(RRDR *r, size_t query_metric_id) {
2801
- if(!r->group_by.r)
3063
+static void rrd2rrdr_group_by_add_metric(RRDR *r_dst, size_t d_dst, RRDR *r_tmp, size_t d_tmp,
3064
+ RRDR_GROUP_BY_FUNCTION group_by_aggregate_function,
3065
+ STORAGE_POINT *query_points, size_t pass __maybe_unused) {
3066
+ if(!r_tmp || r_dst == r_tmp || !(r_tmp->od[d_tmp] & RRDR_DIMENSION_QUERIED))
3067
return;
3068
2804
- QUERY_TARGET *qt = r->internal.qt;
2805
- RRDR_OPTIONS options = qt->window.options;
2806
- RRDR *r_tmp = r->group_by.r;
3069
+ internal_fatal(r_dst->n != r_tmp->n, "QUERY: group-by source and destination do not have the same number of rows");
3070
+ internal_fatal(d_dst >= r_dst->d, "QUERY: group-by destination dimension number exceeds destination RRDR size");
3071
+ internal_fatal(d_tmp >= r_tmp->d, "QUERY: group-by source dimension number exceeds source RRDR size");
3072
+ internal_fatal(!r_dst->dqp, "QUERY: group-by destination is not properly prepared (missing dqp array)");
3073
+ internal_fatal(!r_dst->gbc, "QUERY: group-by destination is not properly prepared (missing gbc array)");
3074
+
3075
+ bool hidden_dimension_on_percentage_of_instance = (r_tmp->od[d_tmp] & RRDR_DIMENSION_HIDDEN) && r_dst->vh;
3076
2808
- QUERY_METRIC *qm = query_metric(qt, query_metric_id);
2809
- size_t d = qm->grouped_as.slot;
3077
+ if(!hidden_dimension_on_percentage_of_instance) {
3078
+ r_dst->od[d_dst] |= r_tmp->od[d_tmp];
3079
+ storage_point_merge_to(r_dst->dqp[d_dst], *query_points);
3080
+ }
3081
3082
// do the group_by
3083
for(size_t i = 0; i != rrdr_rows(r_tmp) ; i++) {
3084
2814
- size_t idx_tmp = i * r_tmp->d;
2815
- NETDATA_DOUBLE *cn_tmp_base = &r_tmp->v[ idx_tmp ];
2816
- RRDR_VALUE_FLAGS *co_tmp_base = &r_tmp->o[ idx_tmp ];
2817
- NETDATA_DOUBLE *ar_tmp_base = &r_tmp->ar[ idx_tmp ];
3085
+ size_t idx_tmp = i * r_tmp->d + d_tmp;
3086
+ NETDATA_DOUBLE n_tmp = r_tmp->v[ idx_tmp ];
3087
+ RRDR_VALUE_FLAGS o_tmp = r_tmp->o[ idx_tmp ];
3088
+ NETDATA_DOUBLE ar_tmp = r_tmp->ar[ idx_tmp ];
3089
2819
- size_t idx = i * r->d;
2820
- NETDATA_DOUBLE *cn_base = &r->v[ idx ];
2821
- RRDR_VALUE_FLAGS *co_base = &r->o[ idx ];
2822
- NETDATA_DOUBLE *ar_base = &r->ar[ idx ];
2823
- uint32_t *gbc_base = &r->gbc[ idx ];
2824
-
2825
- for(size_t d_tmp = 0; d_tmp < r_tmp->d ; d_tmp++) {
2826
- if(unlikely(!(r_tmp->od[d_tmp] & RRDR_DIMENSION_QUERIED)))
2827
- continue;
2828
-
2829
- NETDATA_DOUBLE n_tmp = cn_tmp_base[d_tmp];
2830
- RRDR_VALUE_FLAGS o_tmp = co_tmp_base[d_tmp];
2831
- NETDATA_DOUBLE ar_tmp = ar_tmp_base[d_tmp];
3090
+ if(o_tmp & RRDR_VALUE_EMPTY)
3091
+ continue;
3092
2833
- if(o_tmp & RRDR_VALUE_EMPTY) {
2834
- if(options & RRDR_OPTION_NULL2ZERO)
2835
- n_tmp = 0.0;
3093
+ size_t idx_dst = i * r_dst->d + d_dst;
3094
+ NETDATA_DOUBLE *cn = (hidden_dimension_on_percentage_of_instance) ? &r_dst->vh[ idx_dst ] : &r_dst->v[ idx_dst ];
3095
+ RRDR_VALUE_FLAGS *co = &r_dst->o[ idx_dst ];
3096
+ NETDATA_DOUBLE *ar = &r_dst->ar[ idx_dst ];
3097
+ uint32_t *gbc = &r_dst->gbc[ idx_dst ];
3098
+
3099
+ switch(group_by_aggregate_function) {
3100
+ default:
3101
+ case RRDR_GROUP_BY_FUNCTION_AVERAGE:
3102
+ case RRDR_GROUP_BY_FUNCTION_SUM:
3103
+ if(isnan(*cn))
3104
+ *cn = n_tmp;
3105
else
2837
- continue;
2838
- }
2839
-
2840
- r->od[d] |= RRDR_DIMENSION_QUERIED;
2841
-
2842
- NETDATA_DOUBLE *cn = &cn_base[d];
2843
- RRDR_VALUE_FLAGS *co = &co_base[d];
2844
- NETDATA_DOUBLE *ar = &ar_base[d];
2845
- uint32_t *gbc = &gbc_base[d];
2846
-
2847
- switch(qt->request.group_by_aggregate_function) {
2848
- default:
2849
- case RRDR_GROUP_BY_FUNCTION_AVERAGE:
2850
- case RRDR_GROUP_BY_FUNCTION_SUM:
3106
*cn += n_tmp;
2852
- break;
3107
+ break;
3108
2854
- case RRDR_GROUP_BY_FUNCTION_MIN:
2855
- if(!*gbc || n_tmp < *cn)
2856
- *cn = n_tmp;
2857
- break;
3109
+ case RRDR_GROUP_BY_FUNCTION_MIN:
3110
+ if(isnan(*cn) || n_tmp < *cn)
3111
+ *cn = n_tmp;
3112
+ break;
3113
2859
- case RRDR_GROUP_BY_FUNCTION_MAX:
2860
- if(!*gbc || n_tmp > *cn)
2861
- *cn = n_tmp;
2862
- break;
2863
- }
3114
+ case RRDR_GROUP_BY_FUNCTION_MAX:
3115
+ if(isnan(*cn) || n_tmp > *cn)
3116
+ *cn = n_tmp;
3117
+ break;
3118
+ }
3119
3120
+ if(!hidden_dimension_on_percentage_of_instance) {
3121
+ *co &= ~RRDR_VALUE_EMPTY;
3122
*co |= (o_tmp & (RRDR_VALUE_RESET | RRDR_VALUE_PARTIAL));
3123
*ar += ar_tmp;
3124
(*gbc)++;
3125
}
3126
}
2870
-
2871
- storage_point_merge_to(r->dqp[d], qm->query_points);
3127
}
3128
3129
static void rrdr2rrdr_group_by_partial_trimming(RRDR *r) {
2875
- // FIXME - this is not optimal, we should not traverse the entire array to go to the end of it
3130
+ time_t trimmable_after = r->partial_data_trimming.expected_after;
3131
+
3132
+ // find the point just before the trimmable ones
3133
+ ssize_t i = (ssize_t)r->n - 1;
3134
+ for( ; i >= 0 ;i--) {
3135
+ if (r->t[i] < trimmable_after)
3136
+ break;
3137
+ }
3138
+
3139
+ if(unlikely(i < 0))
3140
+ return;
3141
3142
size_t last_row_gbc = 0;
2878
- for (size_t i = 0; i != r->n; i++) {
3143
+ for (; i < (ssize_t)r->n; i++) {
3144
size_t row_gbc = 0;
3145
for (size_t d = 0; d < r->d; d++) {
3146
if (unlikely(!(r->od[d] & RRDR_DIMENSION_QUERIED)))
3149
row_gbc += r->gbc[ i * r->d + d ];
3150
}
3151
2887
- if (unlikely(r->t[i] > r->partial_data_trimming.expected_after && row_gbc < last_row_gbc)) {
3152
+ if (unlikely(r->t[i] >= trimmable_after && row_gbc < last_row_gbc)) {
3153
// discard the rest of the points
3154
r->partial_data_trimming.trimmed_after = r->t[i];
3155
r->rows = i;
3160
}
3161
}
3162
3163
+static void rrdr2rrdr_group_by_calculate_percentage_of_instance(RRDR *r) {
3164
+ if(!r->vh)
3165
+ return;
3166
+
3167
+ for(size_t i = 0; i < r->n ;i++) {
3168
+ NETDATA_DOUBLE *cn = &r->v[ i * r->d ];
3169
+ NETDATA_DOUBLE *ch = &r->vh[ i * r->d ];
3170
+
3171
+ for(size_t d = 0; d < r->d ;d++) {
3172
+ NETDATA_DOUBLE n = cn[d];
3173
+ NETDATA_DOUBLE h = ch[d];
3174
+
3175
+ if(isnan(n))
3176
+ cn[d] = 0.0;
3177
+
3178
+ else if(isnan(h))
3179
+ cn[d] = 100.0;
3180
+
3181
+ else
3182
+ cn[d] = n * 100.0 / (n + h);
3183
+ }
3184
+ }
3185
+}
3186
+
3187
static void rrd2rrdr_convert_to_percentage(RRDR *r) {
3188
size_t global_min_max_values = 0;
3189
NETDATA_DOUBLE global_min = NAN, global_max = NAN;
3276
}
3277
}
3278
2990
-static void rrd2rrdr_group_by_finalize(RRDR *r) {
2991
- QUERY_TARGET *qt = r->internal.qt;
3279
+static RRDR *rrd2rrdr_group_by_finalize(RRDR *r_tmp) {
3280
+ QUERY_TARGET *qt = r_tmp->internal.qt;
3281
RRDR_OPTIONS options = qt->window.options;
3282
2994
- if(!r->group_by.r) {
3283
+ if(!r_tmp->group_by.r) {
3284
// v1 query
3285
if(options & RRDR_OPTION_PERCENTAGE)
2997
- rrd2rrdr_convert_to_percentage(r);
2998
- return;
3286
+ rrd2rrdr_convert_to_percentage(r_tmp);
3287
+ return r_tmp;
3288
}
3289
// v2 query
3290
3002
- // copy the timestamps
3003
- for(size_t i = 0; i != r->n ;i++) {
3004
- r->t[i] = r->group_by.r->t[i];
3291
+ // do the additional passes on RRDRs
3292
+ RRDR *last_r = r_tmp->group_by.r;
3293
+ rrdr2rrdr_group_by_calculate_percentage_of_instance(last_r);
3294
+
3295
+ RRDR *r = last_r->group_by.r;
3296
+ size_t pass = 0;
3297
+ while(r) {
3298
+ pass++;
3299
+ for(size_t d = 0; d < last_r->d ;d++) {
3300
+ rrd2rrdr_group_by_add_metric(r, last_r->dgbs[d], last_r, d,
3301
+ qt->request.group_by[pass].aggregation,
3302
+ &last_r->dqp[d], pass);
3303
+ }
3304
+ rrdr2rrdr_group_by_calculate_percentage_of_instance(r);
3305
+
3306
+ last_r = r;
3307
+ r = last_r->group_by.r;
3308
+ }
3309
+
3310
+ // free all RRDRs except the last one
3311
+ r = r_tmp;
3312
+ while(r != last_r) {
3313
+ r_tmp = r->group_by.r;
3314
+ r->group_by.r = NULL;
3315
+ rrdr_free(r->internal.owa, r);
3316
+ r = r_tmp;
3317
}
3318
+ r = last_r;
3319
+
3320
+ // find the final aggregation
3321
+ RRDR_GROUP_BY_FUNCTION aggregation = qt->request.group_by[0].aggregation;
3322
+ for(size_t g = 0; g < MAX_QUERY_GROUP_BY_PASSES ;g++)
3323
+ if(qt->request.group_by[g].group_by != RRDR_GROUP_BY_NONE)
3324
+ aggregation = qt->request.group_by[g].aggregation;
3325
3326
if(!(options & RRDR_OPTION_RETURN_RAW) && r->partial_data_trimming.expected_after < qt->window.before)
3327
rrdr2rrdr_group_by_partial_trimming(r);
3357
sum += *cn;
3358
ars += *ar;
3359
3041
- if(qt->request.group_by_aggregate_function == RRDR_GROUP_BY_FUNCTION_AVERAGE && !query_target_aggregatable(qt))
3360
+ if(aggregation == RRDR_GROUP_BY_FUNCTION_AVERAGE && !query_target_aggregatable(qt))
3361
n = (*cn /= gbc);
3362
else
3363
n = *cn;
3448
}
3449
}
3450
}
3451
+
3452
+ return r;
3453
}
3454
3455
// ----------------------------------------------------------------------------
3479
.priority = priority,
3480
};
3481
3161
- return rrd2rrdr(owa, query_target_create(&qtr));
3482
+ QUERY_TARGET *qt = query_target_create(&qtr);
3483
+ RRDR *r = rrd2rrdr(owa, qt);
3484
+ if(!r) {
3485
+ query_target_release(qt);
3486
+ return NULL;
3487
+ }
3488
+
3489
+ r->internal.release_with_rrdr_qt = qt;
3490
+ return r;
3491
}
3492
3493
RRDR *rrd2rrdr(ONEWAYALLOC *owa, QUERY_TARGET *qt) {
3165
- if(!qt)
3494
+ if(!qt || !owa)
3495
return NULL;
3496
3168
- if(!owa) {
3169
- query_target_release(qt);
3170
- return NULL;
3171
- }
3172
-
3497
// qt.window members are the WANTED ones.
3498
// qt.request members are the REQUESTED ones.
3499
3176
- RRDR *r = rrd2rrdr_group_by_initialize(owa, qt);
3177
- if(!r)
3500
+ RRDR *r_tmp = rrd2rrdr_group_by_initialize(owa, qt);
3501
+ if(!r_tmp)
3502
return NULL;
3503
3504
+ // the RRDR we group-by at
3505
+ RRDR *r = (r_tmp->group_by.r) ? r_tmp->group_by.r : r_tmp;
3506
+
3507
+ // the final RRDR to return to callers
3508
+ RRDR *last_r = r_tmp;
3509
+ while(last_r->group_by.r)
3510
+ last_r = last_r->group_by.r;
3511
+
3512
if(qt->window.relative)
3181
- r->view.flags |= RRDR_RESULT_FLAG_RELATIVE;
3513
+ last_r->view.flags |= RRDR_RESULT_FLAG_RELATIVE;
3514
else
3183
- r->view.flags |= RRDR_RESULT_FLAG_ABSOLUTE;
3184
-
3185
- RRDR *r_tmp = r->group_by.r ? r->group_by.r : r;
3515
+ last_r->view.flags |= RRDR_RESULT_FLAG_ABSOLUTE;
3516
3517
// -------------------------------------------------------------------------
3518
// assign the processor functions
3601
r->view.before = r_tmp->view.before;
3602
r->rows = r_tmp->rows;
3603
3274
- rrd2rrdr_group_by_add_metric(r, d);
3604
+ rrd2rrdr_group_by_add_metric(r, qm->grouped_as.first_slot, r_tmp, dim_in_rrdr_tmp,
3605
+ qt->request.group_by[0].aggregation, &qm->query_points, 0);
3606
}
3607
3608
rrd2rrdr_query_ops_release(ops[d]); // reuse this ops allocation
3709
// free all resources used by the grouping method
3710
r_tmp->time_grouping.free(r_tmp);
3711
3381
- rrd2rrdr_group_by_finalize(r);
3712
+ // get the final RRDR to send to the caller
3713
+ r = rrd2rrdr_group_by_finalize(r_tmp);
3714
3715
#ifdef NETDATA_INTERNAL_CHECKS
3716
if (dimensions_used && !(r->view.flags & RRDR_RESULT_FLAG_CANCEL)) {