@cryptotaxi247 / netdata-1 / commits / d92890b5f

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)