Configurable storage engine for Netdata agents: step 1 (#12776)
* rrd: move API structures out of rrddim_volatile In C, unlike C++, it's not possible to reference a nested structure from outside this structure. Since we later want to use rrddim_query_ops and rrddim_collect_ops separately from rrddim_volatile, move these nested structures out. * rrd: use opaque handle types for different memory modes
Adrien Béraud committed
May 3, 2022 at 04:34 UTC
d92890b5f180f13b5f680b3bd345e3674b8f8e8c
7 files changed
+112
-110
database/engine/rrdengine.h
+16
@@ -34,6 +34,22 @@ struct rrdengine_instance;
34
#define RRDENG_FILE_NUMBER_SCAN_TMPL "%1u-%10u"
35
#define RRDENG_FILE_NUMBER_PRINT_TMPL "%1.1u-%10.10u"
36
37
+struct rrdeng_collect_handle {
38
+ struct rrdeng_page_descr *descr, *prev_descr;
39
+ unsigned long page_correlation_id;
40
+ struct rrdengine_instance *ctx;
41
+ // set to 1 when this dimension is not page aligned with the other dimensions in the chart
42
+ uint8_t unaligned_page;
43
+};
44
+
45
+struct rrdeng_query_handle {
46
+ struct rrdeng_page_descr *descr;
47
+ struct rrdengine_instance *ctx;
48
+ struct pg_cache_page_index *page_index;
49
+ time_t next_page_time;
50
+ time_t now;
51
+ unsigned position;
52
+};
53
54
typedef enum {
55
RRDENGINE_STATUS_UNINITIALIZED = 0,
database/engine/rrdengineapi.c
+15
-18
@@ -126,12 +126,13 @@ void rrdeng_store_metric_init(RRDDIM *rd)
126
struct pg_cache_page_index *page_index;
127
128
ctx = get_rrdeng_ctx_from_host(rd->rrdset->rrdhost);
129
- handle = &rd->state->handle.rrdeng;
130
- handle->ctx = ctx;
129
130
+ handle = callocz(1, sizeof(struct rrdeng_collect_handle));
131
+ handle->ctx = ctx;
132
handle->descr = NULL;
133
handle->prev_descr = NULL;
134
handle->unaligned_page = 0;
135
+ rd->state->handle = (STORAGE_COLLECT_HANDLE *)handle;
136
137
page_index = rd->state->page_index;
138
uv_rwlock_wrlock(&page_index->lock);
@@ -162,7 +163,7 @@ void rrdeng_store_metric_flush_current_page(RRDDIM *rd)
163
struct rrdengine_instance *ctx;
164
struct rrdeng_page_descr *descr;
165
165
- handle = &rd->state->handle.rrdeng;
166
+ handle = (struct rrdeng_collect_handle *)rd->state->handle;
167
ctx = handle->ctx;
168
if (unlikely(!ctx))
169
return;
@@ -211,14 +212,13 @@ void rrdeng_store_metric_flush_current_page(RRDDIM *rd)
212
213
void rrdeng_store_metric_next(RRDDIM *rd, usec_t point_in_time, storage_number number)
214
{
214
- struct rrdeng_collect_handle *handle;
215
+ struct rrdeng_collect_handle *handle = (struct rrdeng_collect_handle *)rd->state->handle;
216
struct rrdengine_instance *ctx;
217
struct page_cache *pg_cache;
218
struct rrdeng_page_descr *descr;
219
storage_number *page;
220
uint8_t must_flush_unaligned_page = 0, perfect_page_alignment = 0;
221
221
- handle = &rd->state->handle.rrdeng;
222
ctx = handle->ctx;
223
pg_cache = &ctx->pg_cache;
224
descr = handle->descr;
@@ -301,7 +301,7 @@ int rrdeng_store_metric_finalize(RRDDIM *rd)
301
struct pg_cache_page_index *page_index;
302
uint8_t can_delete_metric = 0;
303
304
- handle = &rd->state->handle.rrdeng;
304
+ handle = (struct rrdeng_collect_handle *)rd->state->handle;
305
ctx = handle->ctx;
306
page_index = rd->state->page_index;
307
rrdeng_store_metric_flush_current_page(rd);
@@ -314,6 +314,7 @@ int rrdeng_store_metric_finalize(RRDDIM *rd)
314
can_delete_metric = 1;
315
}
316
uv_rwlock_wrunlock(&page_index->lock);
317
+ freez(handle);
318
319
return can_delete_metric;
320
}
@@ -535,12 +536,14 @@ void rrdeng_load_metric_init(RRDDIM *rd, struct rrddim_query_handle *rrdimm_hand
536
ctx = get_rrdeng_ctx_from_host(rd->rrdset->rrdhost);
537
rrdimm_handle->start_time = start_time;
538
rrdimm_handle->end_time = end_time;
538
- handle = &rrdimm_handle->rrdeng;
539
+
540
+ handle = calloc(1, sizeof(struct rrdeng_query_handle));
541
handle->next_page_time = start_time;
542
handle->now = start_time;
543
handle->position = 0;
544
handle->ctx = ctx;
545
handle->descr = NULL;
546
+ rrdimm_handle->handle = (STORAGE_QUERY_HANDLE *)handle;
547
pages_nr = pg_cache_preload(ctx, rd->state->rrdeng_uuid, start_time * USEC_PER_SEC, end_time * USEC_PER_SEC,
548
NULL, &handle->page_index);
549
if (unlikely(NULL == handle->page_index || 0 == pages_nr))
@@ -551,7 +554,7 @@ void rrdeng_load_metric_init(RRDDIM *rd, struct rrddim_query_handle *rrdimm_hand
554
/* Returns the metric and sets its timestamp into current_time */
555
storage_number rrdeng_load_metric_next(struct rrddim_query_handle *rrdimm_handle, time_t *current_time)
556
{
554
- struct rrdeng_query_handle *handle;
557
+ struct rrdeng_query_handle *handle = (struct rrdeng_query_handle *)rrdimm_handle->handle;
558
struct rrdengine_instance *ctx;
559
struct rrdeng_page_descr *descr;
560
storage_number *page, ret;
@@ -559,7 +562,6 @@ storage_number rrdeng_load_metric_next(struct rrddim_query_handle *rrdimm_handle
562
usec_t next_page_time = 0, current_position_time, page_end_time = 0;
563
uint32_t page_length;
564
562
- handle = &rrdimm_handle->rrdeng;
565
if (unlikely(INVALID_TIME == handle->next_page_time)) {
566
return SN_EMPTY_SLOT;
567
}
@@ -641,9 +643,7 @@ no_more_metrics:
643
644
int rrdeng_load_metric_is_finished(struct rrddim_query_handle *rrdimm_handle)
645
{
644
- struct rrdeng_query_handle *handle;
645
-
646
- handle = &rrdimm_handle->rrdeng;
646
+ struct rrdeng_query_handle *handle = (struct rrdeng_query_handle *)rrdimm_handle->handle;
647
return (INVALID_TIME == handle->next_page_time);
648
}
649
@@ -652,13 +652,10 @@ int rrdeng_load_metric_is_finished(struct rrddim_query_handle *rrdimm_handle)
652
*/
653
void rrdeng_load_metric_finalize(struct rrddim_query_handle *rrdimm_handle)
654
{
655
- struct rrdeng_query_handle *handle;
656
- struct rrdengine_instance *ctx;
657
- struct rrdeng_page_descr *descr;
655
+ struct rrdeng_query_handle *handle = (struct rrdeng_query_handle *)rrdimm_handle->handle;
656
+ struct rrdengine_instance *ctx = handle->ctx;
657
+ struct rrdeng_page_descr *descr = handle->descr;
658
659
- handle = &rrdimm_handle->rrdeng;
660
- ctx = handle->ctx;
661
- descr = handle->descr;
659
if (descr) {
660
#ifdef NETDATA_INTERNAL_CHECKS
661
rrd_stat_atomic_add(&ctx->stats.metric_API_consumers, -1);
database/rrd.h
+57
-74
@@ -326,53 +326,56 @@ struct rrddim {
326
};
327
328
// ----------------------------------------------------------------------------
329
-// iterator state for RRD dimension data collection
330
-union rrddim_collect_handle {
331
- struct {
332
- long slot;
333
- long entries;
334
- } slotted; // state the legacy code uses
335
-#ifdef ENABLE_DBENGINE
336
- struct rrdeng_collect_handle {
337
- struct rrdeng_page_descr *descr, *prev_descr;
338
- unsigned long page_correlation_id;
339
- struct rrdengine_instance *ctx;
340
- // set to 1 when this dimension is not page aligned with the other dimensions in the chart
341
- uint8_t unaligned_page;
342
- } rrdeng; // state the database engine uses
343
-#endif
344
-};
329
+// engine-specific iterator state for dimension data collection
330
+typedef struct storage_collect_handle STORAGE_COLLECT_HANDLE;
331
332
// ----------------------------------------------------------------------------
347
-// iterator state for RRD dimension data queries
348
-
349
-#ifdef ENABLE_DBENGINE
350
-struct rrdeng_query_handle {
351
- struct rrdeng_page_descr *descr;
352
- struct rrdengine_instance *ctx;
353
- struct pg_cache_page_index *page_index;
354
- time_t next_page_time;
355
- time_t now;
356
- unsigned position;
357
-};
358
-#endif
333
+// engine-specific iterator state for dimension data queries
334
+typedef struct storage_query_handle STORAGE_QUERY_HANDLE;
335
336
+// ----------------------------------------------------------------------------
337
+// iterator state for RRD dimension data queries
338
struct rrddim_query_handle {
339
RRDDIM *rd;
340
time_t start_time;
341
time_t end_time;
364
- union {
365
- struct {
366
- long slot;
367
- long last_slot;
368
- uint8_t finished;
369
- } slotted; // state the legacy code uses
370
-#ifdef ENABLE_DBENGINE
371
- struct rrdeng_query_handle rrdeng; // state the database engine uses
372
-#endif
373
- };
342
+ STORAGE_QUERY_HANDLE* handle;
343
};
344
345
+// ------------------------------------------------------------------------
346
+// function pointers that handle data collection
347
+struct rrddim_collect_ops {
348
+ // an initialization function to run before starting collection
349
+ void (*init)(RRDDIM *rd);
350
+
351
+ // run this to store each metric into the database
352
+ void (*store_metric)(RRDDIM *rd, usec_t point_in_time, storage_number number);
353
+
354
+ // an finalization function to run after collection is over
355
+ // returns 1 if it's safe to delete the dimension
356
+ int (*finalize)(RRDDIM *rd);
357
+};
358
+
359
+// function pointers that handle database queries
360
+struct rrddim_query_ops {
361
+ // run this before starting a series of next_metric() database queries
362
+ void (*init)(RRDDIM *rd, struct rrddim_query_handle *handle, time_t start_time, time_t end_time);
363
+
364
+ // run this to load each metric number from the database
365
+ storage_number (*next_metric)(struct rrddim_query_handle *handle, time_t *current_time);
366
+
367
+ // run this to test if the series of next_metric() database queries is finished
368
+ int (*is_finished)(struct rrddim_query_handle *handle);
369
+
370
+ // run this after finishing a series of load_metric() database queries
371
+ void (*finalize)(struct rrddim_query_handle *handle);
372
+
373
+ // get the timestamp of the last entry of this metric
374
+ time_t (*latest_time)(RRDDIM *rd);
375
+
376
+ // get the timestamp of the first entry of this metric
377
+ time_t (*oldest_time)(RRDDIM *rd);
378
+};
379
380
// ----------------------------------------------------------------------------
381
// volatile state per RRD dimension
@@ -385,42 +388,9 @@ struct rrddim_volatile {
388
int aclk_live_status;
389
#endif
390
uuid_t metric_uuid; // global UUID for this metric (unique_across hosts)
388
- union rrddim_collect_handle handle;
389
- // ------------------------------------------------------------------------
390
- // function pointers that handle data collection
391
- struct rrddim_collect_ops {
392
- // an initialization function to run before starting collection
393
- void (*init)(RRDDIM *rd);
394
-
395
- // run this to store each metric into the database
396
- void (*store_metric)(RRDDIM *rd, usec_t point_in_time, storage_number number);
397
-
398
- // an finalization function to run after collection is over
399
- // returns 1 if it's safe to delete the dimension
400
- int (*finalize)(RRDDIM *rd);
401
- } collect_ops;
402
-
403
- // function pointers that handle database queries
404
- struct rrddim_query_ops {
405
- // run this before starting a series of next_metric() database queries
406
- void (*init)(RRDDIM *rd, struct rrddim_query_handle *handle, time_t start_time, time_t end_time);
407
-
408
- // run this to load each metric number from the database
409
- storage_number (*next_metric)(struct rrddim_query_handle *handle, time_t *current_time);
410
-
411
- // run this to test if the series of next_metric() database queries is finished
412
- int (*is_finished)(struct rrddim_query_handle *handle);
413
-
414
- // run this after finishing a series of load_metric() database queries
415
- void (*finalize)(struct rrddim_query_handle *handle);
416
-
417
- // get the timestamp of the last entry of this metric
418
- time_t (*latest_time)(RRDDIM *rd);
419
-
420
- // get the timestamp of the first entry of this metric
421
- time_t (*oldest_time)(RRDDIM *rd);
422
- } query_ops;
423
-
391
+ STORAGE_COLLECT_HANDLE* handle;
392
+ struct rrddim_collect_ops collect_ops;
393
+ struct rrddim_query_ops query_ops;
394
ml_dimension_t ml_dimension;
395
};
396
@@ -435,6 +405,19 @@ struct rrdset_volatile {
405
bool is_ar_chart;
406
};
407
408
+// RRDDIM legacy data collection structures
409
+
410
+struct mem_collect_handle {
411
+ long slot;
412
+ long entries;
413
+};
414
+
415
+struct mem_query_handle {
416
+ long slot;
417
+ long last_slot;
418
+ uint8_t finished;
419
+};
420
+
421
// ----------------------------------------------------------------------------
422
// these loop macros make sure the linked list is accessed with the right lock
423
database/rrddim.c
+16
-12
@@ -99,6 +99,7 @@ inline int rrddim_set_divisor(RRDSET *st, RRDDIM *rd, collected_number divisor)
99
// RRDDIM legacy data collection functions
100
101
static void rrddim_collect_init(RRDDIM *rd) {
102
+ rd->state->handle = callocz(1, sizeof(struct mem_collect_handle));
103
rd->values[rd->rrdset->current_entry] = SN_EMPTY_SLOT;
104
}
105
static void rrddim_collect_store_metric(RRDDIM *rd, usec_t point_in_time, storage_number number) {
@@ -107,11 +108,11 @@ static void rrddim_collect_store_metric(RRDDIM *rd, usec_t point_in_time, storag
108
rd->values[rd->rrdset->current_entry] = number;
109
}
110
static int rrddim_collect_finalize(RRDDIM *rd) {
110
- (void)rd;
111
-
111
+ freez(rd->state->handle);
112
return 0;
113
}
114
115
+
116
// ----------------------------------------------------------------------------
117
// RRDDIM legacy database query functions
118
@@ -119,34 +120,37 @@ static void rrddim_query_init(RRDDIM *rd, struct rrddim_query_handle *handle, ti
120
handle->rd = rd;
121
handle->start_time = start_time;
122
handle->end_time = end_time;
122
- handle->slotted.slot = rrdset_time2slot(rd->rrdset, start_time);
123
- handle->slotted.last_slot = rrdset_time2slot(rd->rrdset, end_time);
124
- handle->slotted.finished = 0;
123
+ struct mem_query_handle* mem_handle = callocz(1, sizeof(struct mem_query_handle));
124
+ mem_handle->slot = rrdset_time2slot(rd->rrdset, start_time);
125
+ mem_handle->last_slot = rrdset_time2slot(rd->rrdset, end_time);
126
+ mem_handle->finished = 0;
127
+ handle->handle = (STORAGE_QUERY_HANDLE *)mem_handle;
128
}
129
130
static storage_number rrddim_query_next_metric(struct rrddim_query_handle *handle, time_t *current_time) {
131
RRDDIM *rd = handle->rd;
132
+ struct mem_query_handle* mem_handle = (struct mem_query_handle*)handle->handle;
133
long entries = rd->rrdset->entries;
130
- long slot = handle->slotted.slot;
134
+ long slot = mem_handle->slot;
135
136
(void)current_time;
133
- if (unlikely(handle->slotted.slot == handle->slotted.last_slot))
134
- handle->slotted.finished = 1;
137
+ if (unlikely(mem_handle->slot == mem_handle->last_slot))
138
+ mem_handle->finished = 1;
139
storage_number n = rd->values[slot++];
140
141
if(unlikely(slot >= entries)) slot = 0;
138
- handle->slotted.slot = slot;
142
+ mem_handle->slot = slot;
143
144
return n;
145
}
146
147
static int rrddim_query_is_finished(struct rrddim_query_handle *handle) {
144
- return handle->slotted.finished;
148
+ struct mem_query_handle* mem_handle = (struct mem_query_handle*)handle->handle;
149
+ return mem_handle->finished;
150
}
151
152
static void rrddim_query_finalize(struct rrddim_query_handle *handle) {
148
- (void)handle;
149
-
153
+ freez(handle->handle);
154
return;
155
}
156
ml/Dimension.h
+1
-1
@@ -45,7 +45,7 @@ private:
45
RRDDIM *RD;
46
RRDDIM *AnomalyRateRD;
47
48
- struct rrddim_volatile::rrddim_query_ops *Ops;
48
+ struct rrddim_query_ops *Ops;
49
50
std::string ID;
51
};
ml/Query.h
+1
-1
@@ -40,7 +40,7 @@ public:
40
private:
41
RRDDIM *RD;
42
43
- struct rrddim_volatile::rrddim_query_ops *Ops;
43
+ struct rrddim_query_ops *Ops;
44
struct rrddim_query_handle Handle;
45
};
46
web/api/queries/query.c
+6
-4
@@ -580,9 +580,10 @@ static inline void do_dimension_fixedstep(
580
// read the value from the database
581
//storage_number n = rd->values[slot];
582
#ifdef NETDATA_INTERNAL_CHECKS
583
+ struct mem_query_handle* mem_handle = (struct mem_query_handle*)handle.handle;
584
if ((rd->rrd_memory_mode != RRD_MEMORY_MODE_DBENGINE) &&
584
- (rrdset_time2slot(st, now) != (long unsigned)handle.slotted.slot)) {
585
- error("INTERNAL CHECK: Unaligned query for %s, database slot: %lu, expected slot: %lu", rd->id, (long unsigned)handle.slotted.slot, rrdset_time2slot(st, now));
585
+ (rrdset_time2slot(st, now) != (long unsigned)(mem_handle->slot))) {
586
+ error("INTERNAL CHECK: Unaligned query for %s, database slot: %lu, expected slot: %lu", rd->id, (long unsigned)mem_handle->slot, rrdset_time2slot(st, now));
587
}
588
#endif
589
db_now = now; // this is needed to set db_now in case the next_metric implementation does not set it
@@ -601,8 +602,9 @@ static inline void do_dimension_fixedstep(
602
calculated_number value = NAN;
603
if(likely(now >= db_now && does_storage_number_exist(n))) {
604
#if defined(NETDATA_INTERNAL_CHECKS) && defined(ENABLE_DBENGINE)
604
- if ((rd->rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE) && (now != handle.rrdeng.now)) {
605
- error("INTERNAL CHECK: Unaligned query for %s, database time: %ld, expected time: %ld", rd->id, (long)handle.rrdeng.now, (long)now);
605
+ struct rrdeng_query_handle* rrd_handle = (struct rrdeng_query_handle*)handle.handle;
606
+ if ((rd->rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE) && (now != rrd_handle->now)) {
607
+ error("INTERNAL CHECK: Unaligned query for %s, database time: %ld, expected time: %ld", rd->id, (long)rrd_handle->now, (long)now);
608
}
609
#endif
610
if (options & RRDR_OPTION_ANOMALY_BIT)