Collected and available metrics, instances and contexts (#19094)
* make sure there is a valid first_time_s after netdata starts for the first time * show detail in human depending on the time * show retention only when it is in the past * fix calculation of collected and available metrics and instances * recalculate metrics every 30 secs * recalculate every 33 seconds, but for the first 123 seconds do it every second * calculate available and collected metrics, instances and context, on the fly
Costa Tsaousis committed
Nov 27, 2024 at 12:27 UTC
5247096c851baa7c4e1234d26351cd30fedc4de6
13 files changed
+266
-139
src/database/contexts/api_v2_contexts.c
+4
-22
@@ -220,6 +220,9 @@ static void rrdhost_receiver_to_json(BUFFER *wb, RRDHOST_STATUS *s, const char *
220
buffer_json_member_add_string(wb, "status", rrdhost_ingest_status_to_string(s->ingest.status));
221
buffer_json_member_add_time_t(wb, "since", s->ingest.since);
222
buffer_json_member_add_time_t(wb, "age", s->now - s->ingest.since);
223
+ buffer_json_member_add_uint64(wb, "metrics", s->ingest.collected.metrics);
224
+ buffer_json_member_add_uint64(wb, "instances", s->ingest.collected.instances);
225
+ buffer_json_member_add_uint64(wb, "contexts", s->ingest.collected.contexts);
226
227
if(s->ingest.type == RRDHOST_INGEST_TYPE_CHILD) {
228
if(s->ingest.status == RRDHOST_INGEST_STATUS_OFFLINE)
@@ -447,29 +450,8 @@ static void rrdcontext_to_json_v2_rrdhost(BUFFER *wb, RRDHOST *host, struct rrdc
450
buffer_json_member_add_string(wb, "mode", rrd_memory_mode_name(s.db.mode));
451
buffer_json_member_add_time_t(wb, "first_time", s.db.first_time_s);
452
buffer_json_member_add_time_t(wb, "last_time", s.db.last_time_s);
450
- buffer_json_member_add_uint64(wb, "metrics", s.db.metrics);
453
452
- spinlock_lock(&s.host->accounting.spinlock);
453
- int64_t count = 0;
454
-
455
- if (s.host->accounting.cache_timestamp &&
456
- ctl->now - s.host->accounting.cache_timestamp < host->rrd_update_every * 1.5)
457
- count = s.host->accounting.currently_collected;
458
- else {
459
- Pvoid_t *Pvalue;
460
- bool first = true;
461
- Word_t dimension_id = 0;
462
- while ((Pvalue = JudyLFirstThenNext(s.host->accounting.JudyL, &dimension_id, &first))) {
463
- RRDDIM *rd = *Pvalue;
464
- if (rd->collector.last_collected_time.tv_sec > ctl->now - (rd->rrdset->update_every * 2))
465
- count++;
466
- }
467
- s.host->accounting.currently_collected = count;
468
- s.host->accounting.cache_timestamp = ctl->now;
469
- }
470
- spinlock_unlock(&s.host->accounting.spinlock);
471
-
472
- buffer_json_member_add_uint64(wb, "currently_collected_metrics", count);
454
+ buffer_json_member_add_uint64(wb, "metrics", s.db.metrics);
455
buffer_json_member_add_uint64(wb, "instances", s.db.instances);
456
buffer_json_member_add_uint64(wb, "contexts", s.db.contexts);
457
}
src/database/contexts/api_v2_contexts_agents.c
+54
-19
@@ -31,7 +31,12 @@ void buffer_json_agents_v2(BUFFER *wb, struct query_timings *timings, time_t now
31
32
buffer_json_cloud_status(wb, now_s);
33
34
- size_t currently_collected_metrics = 0;
34
+ size_t collected_metrics = 0;
35
+ size_t collected_instances = 0;
36
+ size_t collected_contexts = 0;
37
+ size_t available_metrics = 0;
38
+ size_t available_instances = 0;
39
+ size_t available_contexts = 0;
40
41
buffer_json_member_add_object(wb, "nodes");
42
{
@@ -40,16 +45,23 @@ void buffer_json_agents_v2(BUFFER *wb, struct query_timings *timings, time_t now
45
dfe_start_read(rrdhost_root_index, host) {
46
total++;
47
48
+ available_metrics += __atomic_load_n(&host->rrdctx.metrics_count, __ATOMIC_RELAXED);
49
+ available_instances += __atomic_load_n(&host->rrdctx.instances_count, __ATOMIC_RELAXED);
50
+ available_contexts += __atomic_load_n(&host->rrdctx.contexts_count, __ATOMIC_RELAXED);
51
+
52
if(rrdhost_flag_check(host, RRDHOST_FLAG_RRDPUSH_SENDER_CONNECTED))
53
sending++;
54
46
- if(host != localhost) {
47
- if (rrdhost_is_online(host))
55
+ if (rrdhost_is_online(host)) {
56
+ collected_metrics += __atomic_load_n(&host->collected.metrics_count, __ATOMIC_RELAXED);
57
+ collected_instances += __atomic_load_n(&host->collected.instances_count, __ATOMIC_RELAXED);
58
+ collected_contexts += __atomic_load_n(&host->collected.contexts_count, __ATOMIC_RELAXED);
59
+
60
+ if(host != localhost)
61
receiving++;
49
- else
50
- archived++;
62
}
52
- currently_collected_metrics += host->accounting.currently_collected;
63
+ else
64
+ archived++;
65
}
66
dfe_done(host);
67
@@ -60,6 +72,27 @@ void buffer_json_agents_v2(BUFFER *wb, struct query_timings *timings, time_t now
72
}
73
buffer_json_object_close(wb); // nodes
74
75
+ buffer_json_member_add_object(wb, "metrics");
76
+ {
77
+ buffer_json_member_add_uint64(wb, "collected", collected_metrics);
78
+ buffer_json_member_add_uint64(wb, "available", available_metrics);
79
+ }
80
+ buffer_json_object_close(wb);
81
+
82
+ buffer_json_member_add_object(wb, "instances");
83
+ {
84
+ buffer_json_member_add_uint64(wb, "collected", collected_instances);
85
+ buffer_json_member_add_uint64(wb, "available", available_instances);
86
+ }
87
+ buffer_json_object_close(wb);
88
+
89
+ buffer_json_member_add_object(wb, "contexts");
90
+ {
91
+ buffer_json_member_add_uint64(wb, "collected", collected_contexts);
92
+ buffer_json_member_add_uint64(wb, "available", available_contexts);
93
+ }
94
+ buffer_json_object_close(wb);
95
+
96
agent_capabilities_to_json(wb, localhost, "capabilities");
97
98
buffer_json_member_add_object(wb, "api");
@@ -108,15 +141,23 @@ void buffer_json_agents_v2(BUFFER *wb, struct query_timings *timings, time_t now
141
buffer_json_member_add_double(wb, "disk_percent", percent);
142
}
143
111
- if(first_time_s) {
144
+ if(first_time_s < now_s) {
145
time_t retention = now_s - first_time_s;
146
147
buffer_json_member_add_time_t(wb, "from", first_time_s);
148
buffer_json_member_add_time_t(wb, "to", now_s);
149
buffer_json_member_add_time_t(wb, "retention", retention);
150
118
- duration_snprintf_hours(human_retention, sizeof(human_retention),
119
- (int)duration_round_to_resolution(retention, 3600));
151
+ if(retention < 60)
152
+ duration_snprintf_time_t(human_retention, sizeof(human_retention), retention);
153
+ else if(retention < 24 * 60 * 60) {
154
+ int64_t rounded_retention_mins = duration_round_to_resolution(retention, 60);
155
+ duration_snprintf_mins(human_retention, sizeof(human_retention), rounded_retention_mins);
156
+ }
157
+ else {
158
+ int64_t rounded_retention_hours = duration_round_to_resolution(retention, 3600);
159
+ duration_snprintf_hours(human_retention, sizeof(human_retention), rounded_retention_hours);
160
+ }
161
162
buffer_json_member_add_string(wb, "retention_human", human_retention);
163
@@ -128,13 +169,11 @@ void buffer_json_agents_v2(BUFFER *wb, struct query_timings *timings, time_t now
169
time_t space_retention = (time_t)((NETDATA_DOUBLE)(now_s - first_time_s) * 100.0 / percent);
170
time_t actual_retention = MIN(space_retention, time_retention ? time_retention : space_retention);
171
131
- if (time_retention) {
132
- duration_snprintf_hours(human_retention, sizeof(human_retention),
133
- (int)duration_round_to_resolution(time_retention, 3600));
172
+ duration_snprintf_hours(human_retention, sizeof(human_retention),
173
+ (int)duration_round_to_resolution(time_retention, 3600));
174
135
- buffer_json_member_add_time_t(wb, "requested_retention", time_retention);
136
- buffer_json_member_add_string(wb, "requested_retention_human", human_retention);
137
- }
175
+ buffer_json_member_add_time_t(wb, "requested_retention", time_retention);
176
+ buffer_json_member_add_string(wb, "requested_retention_human", human_retention);
177
178
duration_snprintf_hours(human_retention, sizeof(human_retention),
179
(int)duration_round_to_resolution(actual_retention, 3600));
@@ -143,10 +182,6 @@ void buffer_json_agents_v2(BUFFER *wb, struct query_timings *timings, time_t now
182
buffer_json_member_add_string(wb, "expected_retention_human", human_retention);
183
}
184
}
146
-
147
- if(currently_collected_metrics)
148
- buffer_json_member_add_uint64(wb, "currently_collected_metrics", currently_collected_metrics);
149
-
185
buffer_json_object_close(wb);
186
}
187
buffer_json_array_close(wb); // db_size
src/database/contexts/context.c
+10
-4
@@ -64,12 +64,12 @@ static void rrdcontext_insert_callback(const DICTIONARY_ITEM *item __maybe_unuse
64
rc->last_time_s = (time_t)rc->hub.last_time_s;
65
66
if(rc->hub.deleted || !rc->hub.first_time_s)
67
- rrd_flag_set_deleted(rc, RRD_FLAG_NONE);
67
+ rrdcontext_set_deleted(rc, RRD_FLAG_NONE);
68
else {
69
if (rc->last_time_s == 0)
70
- rrd_flag_set_collected(rc);
70
+ rrdcontext_set_collected(rc);
71
else
72
- rrd_flag_set_archived(rc);
72
+ rrdcontext_set_archived(rc);
73
}
74
75
rc->flags |= RRD_FLAG_UPDATE_REASON_LOAD_SQL; // no need for atomics at constructor
@@ -82,6 +82,9 @@ static void rrdcontext_insert_callback(const DICTIONARY_ITEM *item __maybe_unuse
82
rrdinstances_create_in_rrdcontext(rc);
83
spinlock_init(&rc->spinlock);
84
85
+ // update the count of contexts
86
+ __atomic_add_fetch(&rc->rrdhost->rrdctx.contexts_count, 1, __ATOMIC_RELAXED);
87
+
88
// signal the react callback to do the job
89
rrd_flag_set_updated(rc, RRD_FLAG_UPDATE_REASON_NEW_OBJECT);
90
}
@@ -90,6 +93,9 @@ static void rrdcontext_delete_callback(const DICTIONARY_ITEM *item __maybe_unuse
93
94
RRDCONTEXT *rc = (RRDCONTEXT *)value;
95
96
+ // update the count of contexts
97
+ __atomic_sub_fetch(&rc->rrdhost->rrdctx.contexts_count, 1, __ATOMIC_RELAXED);
98
+
99
rrdinstances_destroy_from_rrdcontext(rc);
100
rrdcontext_freez(rc);
101
}
@@ -199,7 +205,7 @@ static bool rrdcontext_conflict_callback(const DICTIONARY_ITEM *item __maybe_unu
205
rrd_flag_set(rc, rc_new->flags & RRD_FLAGS_ALLOWED_EXTERNALLY_ON_NEW_OBJECTS); // no need for atomics on rc_new
206
207
if(rrd_flag_is_collected(rc) && rrd_flag_is_archived(rc))
202
- rrd_flag_set_collected(rc);
208
+ rrdcontext_set_collected(rc);
209
210
if(rrd_flag_is_updated(rc))
211
rrd_flag_set(rc, RRD_FLAG_UPDATE_REASON_UPDATED_OBJECT);
src/database/contexts/instance.c
+22
-12
@@ -122,6 +122,9 @@ static void rrdinstance_insert_callback(const DICTIONARY_ITEM *item __maybe_unus
122
123
rrdmetrics_create_in_rrdinstance(ri);
124
125
+ // update the count of instances
126
+ __atomic_add_fetch(&ri->rc->rrdhost->rrdctx.instances_count, 1, __ATOMIC_RELAXED);
127
+
128
// signal the react callback to do the job
129
rrd_flag_set_updated(ri, RRD_FLAG_UPDATE_REASON_NEW_OBJECT);
130
}
@@ -131,6 +134,9 @@ static void rrdinstance_delete_callback(const DICTIONARY_ITEM *item __maybe_unus
134
135
internal_error(ri->rrdset, "RRDINSTANCE: '%s' is freed but there is a RRDSET linked to it.", string2str(ri->id));
136
137
+ // update the count of instances
138
+ __atomic_sub_fetch(&ri->rc->rrdhost->rrdctx.instances_count, 1, __ATOMIC_RELAXED);
139
+
140
rrdinstance_free(ri);
141
}
142
@@ -237,7 +243,7 @@ static bool rrdinstance_conflict_callback(const DICTIONARY_ITEM *item __maybe_un
243
rrd_flag_set(ri, ri_new->flags & RRD_FLAGS_ALLOWED_EXTERNALLY_ON_NEW_OBJECTS); // no need for atomics on ri_new
244
245
if(rrd_flag_is_collected(ri) && rrd_flag_is_archived(ri))
240
- rrd_flag_set_collected(ri);
246
+ rrdinstance_set_collected(ri);
247
248
if(rrd_flag_is_updated(ri))
249
rrd_flag_set(ri, RRD_FLAG_UPDATE_REASON_UPDATED_OBJECT);
@@ -290,7 +296,7 @@ void rrdinstance_trigger_updates(RRDINSTANCE *ri, const char *function) {
296
else if(unlikely(rrd_flag_is_collected(ri))) {
297
// there is no rrdset, but we have it as collected!
298
293
- rrd_flag_set_archived(ri);
299
+ rrdinstance_set_archived(ri);
300
rrd_flag_set_updated(ri, RRD_FLAG_UPDATE_REASON_CHANGED_LINKING);
301
}
302
@@ -362,7 +368,7 @@ inline void rrdinstance_from_rrdset(RRDSET *st) {
368
if (!rd->rrdcontexts.rrdmetric) continue;
369
370
RRDMETRIC *rm_old = rrdmetric_acquired_value(rd->rrdcontexts.rrdmetric);
365
- rrd_flags_replace(rm_old, RRD_FLAG_DELETED|RRD_FLAG_UPDATED|RRD_FLAG_LIVE_RETENTION|RRD_FLAG_UPDATE_REASON_UNUSED|RRD_FLAG_UPDATE_REASON_ZERO_RETENTION);
371
+ rrdmetric_set_deleted_overwrite(rm_old, RRD_FLAG_UPDATED|RRD_FLAG_LIVE_RETENTION|RRD_FLAG_UPDATE_REASON_UNUSED|RRD_FLAG_UPDATE_REASON_ZERO_RETENTION);
372
rm_old->rrddim = NULL;
373
rm_old->first_time_s = 0;
374
rm_old->last_time_s = 0;
@@ -378,7 +384,7 @@ inline void rrdinstance_from_rrdset(RRDSET *st) {
384
if(!rrd_flag_check(ri_old, RRD_FLAG_OWN_LABELS))
385
ri_old->rrdlabels = rrdlabels_create();
386
381
- rrd_flags_replace(ri_old, RRD_FLAG_OWN_LABELS|RRD_FLAG_DELETED|RRD_FLAG_UPDATED|RRD_FLAG_LIVE_RETENTION|RRD_FLAG_UPDATE_REASON_UNUSED|RRD_FLAG_UPDATE_REASON_ZERO_RETENTION);
387
+ rrdinstance_set_deleted_overwrite(ri_old, RRD_FLAG_UPDATED|RRD_FLAG_OWN_LABELS|RRD_FLAG_LIVE_RETENTION|RRD_FLAG_UPDATE_REASON_UNUSED|RRD_FLAG_UPDATE_REASON_ZERO_RETENTION);
388
ri_old->rrdset = NULL;
389
ri_old->first_time_s = 0;
390
ri_old->last_time_s = 0;
@@ -428,11 +434,17 @@ static inline RRDINSTANCE *rrdset_get_rrdinstance_with_trace(RRDSET *st, const c
434
return ri;
435
}
436
437
+static inline void rrdinstance_rrdset_not_collected(RRDSET *st) {
438
+ st->rrdcontexts.collected = false;
439
+}
440
+
441
inline void rrdinstance_rrdset_is_freed(RRDSET *st) {
442
+ rrdinstance_rrdset_not_collected(st);
443
+
444
RRDINSTANCE *ri = rrdset_get_rrdinstance(st);
445
if(unlikely(!ri)) return;
446
435
- rrd_flag_set_archived(ri);
447
+ rrdinstance_set_archived(ri);
448
449
if(!rrd_flag_check(ri, RRD_FLAG_OWN_LABELS)) {
450
ri->rrdlabels = rrdlabels_create();
@@ -450,11 +462,10 @@ inline void rrdinstance_rrdset_is_freed(RRDSET *st) {
462
463
rrdcontext_release(st->rrdcontexts.rrdcontext);
464
st->rrdcontexts.rrdcontext = NULL;
453
- st->rrdcontexts.collected = false;
465
}
466
467
inline void rrdinstance_rrdset_has_updated_retention(RRDSET *st) {
457
- st->rrdcontexts.collected = false;
468
+ rrdinstance_rrdset_not_collected(st);
469
470
RRDINSTANCE *ri = rrdset_get_rrdinstance(st);
471
if(unlikely(!ri)) return;
@@ -464,7 +475,7 @@ inline void rrdinstance_rrdset_has_updated_retention(RRDSET *st) {
475
}
476
477
inline void rrdinstance_updated_rrdset_name(RRDSET *st) {
467
- st->rrdcontexts.collected = false;
478
+ rrdinstance_rrdset_not_collected(st);
479
480
// the chart may not be initialized when this is called
481
if(unlikely(!st->rrdcontexts.rrdinstance)) return;
@@ -502,13 +513,13 @@ inline void rrdinstance_updated_rrdset_flags_no_action(RRDINSTANCE *ri, RRDSET *
513
}
514
515
inline void rrdinstance_updated_rrdset_flags(RRDSET *st) {
505
- st->rrdcontexts.collected = false;
516
+ rrdinstance_rrdset_not_collected(st);
517
518
RRDINSTANCE *ri = rrdset_get_rrdinstance(st);
519
if(unlikely(!ri)) return;
520
521
if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_OBSOLETE)))
511
- rrd_flag_set_archived(ri);
522
+ rrdinstance_set_archived(ri);
523
524
rrdinstance_updated_rrdset_flags_no_action(ri, st);
525
@@ -532,11 +543,10 @@ inline void rrdinstance_collected_rrdset(RRDSET *st) {
543
rrdinstance_updated_rrdset_flags_no_action(ri, st);
544
545
if(unlikely(ri->internal.collected_metrics_count && !rrd_flag_is_collected(ri)))
535
- rrd_flag_set_collected(ri);
546
+ rrdinstance_set_collected(ri);
547
548
// we use this variable to detect BEGIN/END without SET
549
ri->internal.collected_metrics_count = 0;
550
551
rrdinstance_trigger_updates(ri, __FUNCTION__ );
552
}
542
-
src/database/contexts/internal.h
+103
-23
@@ -17,19 +17,19 @@
17
18
#define LOG_TRANSITIONS false
19
20
-#define WORKER_JOB_HOSTS 1
21
-#define WORKER_JOB_CHECK 2
22
-#define WORKER_JOB_SEND 3
23
-#define WORKER_JOB_DEQUEUE 4
24
-#define WORKER_JOB_RETENTION 5
25
-#define WORKER_JOB_QUEUED 6
26
-#define WORKER_JOB_CLEANUP 7
27
-#define WORKER_JOB_CLEANUP_DELETE 8
28
-#define WORKER_JOB_PP_METRIC 9 // post-processing metrics
29
-#define WORKER_JOB_PP_INSTANCE 10 // post-processing instances
30
-#define WORKER_JOB_PP_CONTEXT 11 // post-processing contexts
31
-#define WORKER_JOB_HUB_QUEUE_SIZE 12
32
-#define WORKER_JOB_PP_QUEUE_SIZE 13
20
+#define WORKER_JOB_HOSTS 1
21
+#define WORKER_JOB_CHECK 2
22
+#define WORKER_JOB_SEND 3
23
+#define WORKER_JOB_DEQUEUE 4
24
+#define WORKER_JOB_RETENTION 5
25
+#define WORKER_JOB_QUEUED 6
26
+#define WORKER_JOB_CLEANUP 7
27
+#define WORKER_JOB_CLEANUP_DELETE 8
28
+#define WORKER_JOB_PP_METRIC 9 // post-processing metrics
29
+#define WORKER_JOB_PP_INSTANCE 10 // post-processing instances
30
+#define WORKER_JOB_PP_CONTEXT 11 // post-processing contexts
31
+#define WORKER_JOB_HUB_QUEUE_SIZE 12
32
+#define WORKER_JOB_PP_QUEUE_SIZE 13
33
34
35
typedef enum __attribute__ ((__packed__)) {
@@ -118,15 +118,14 @@ extern struct rrdcontext_reason rrdcontext_reasons[];
118
#define rrd_flag_check_all(obj, flag) (rrd_flag_check(obj, flag) == (flag))
119
120
// set one or more flags (bits)
121
+// NEVER alter RRD_FLAG_COLLECTED, RRD_FLAG_ARCHIVED, RRD_FLAG_DELETED with this
122
#define rrd_flag_set(obj, flag) __atomic_or_fetch(&((obj)->flags), flag, __ATOMIC_SEQ_CST)
123
124
// clear one or more flags (bits)
125
+// NEVER alter RRD_FLAG_COLLECTED, RRD_FLAG_ARCHIVED, RRD_FLAG_DELETED with this
126
#define rrd_flag_clear(obj, flag) __atomic_and_fetch(&((obj)->flags), ~(flag), __ATOMIC_SEQ_CST)
127
126
-// replace the flags of an object, with the supplied ones
127
-#define rrd_flags_replace(obj, all_flags) __atomic_store_n(&((obj)->flags), all_flags, __ATOMIC_SEQ_CST)
128
-
129
-static inline void
128
+static inline RRD_FLAGS
129
rrd_flag_add_remove_atomic(RRD_FLAGS *flags, RRD_FLAGS check, RRD_FLAGS conditionally_add, RRD_FLAGS always_remove) {
130
RRD_FLAGS expected, desired;
131
@@ -140,6 +139,19 @@ rrd_flag_add_remove_atomic(RRD_FLAGS *flags, RRD_FLAGS check, RRD_FLAGS conditio
139
desired |= (check | conditionally_add);
140
141
} while(!__atomic_compare_exchange_n(flags, &expected, desired, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST));
142
+
143
+ return expected;
144
+}
145
+
146
+static inline RRD_FLAGS
147
+rrd_flags_replace_atomic(RRD_FLAGS *flags, RRD_FLAGS desired) {
148
+ RRD_FLAGS expected;
149
+
150
+ do {
151
+ expected = *flags;
152
+ } while(!__atomic_compare_exchange_n(flags, &expected, desired, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST));
153
+
154
+ return expected;
155
}
156
157
#define rrd_flag_set_collected(obj) \
@@ -266,25 +278,93 @@ typedef struct rrdcontext {
278
279
struct {
280
RRD_FLAGS queued_flags; // the last flags that triggered the post-processing
281
+ size_t executions; // how many times this context has been processed
282
usec_t queued_ut; // the last time this was queued
283
usec_t dequeued_ut; // the last time we sent (or deduplicated) this context
271
- size_t executions; // how many times this context has been processed
284
} pp;
285
286
struct {
287
RRD_FLAGS queued_flags; // the last flags that triggered the queueing
288
+ size_t dispatches; // the number of times this has been dispatched to hub
289
usec_t queued_ut; // the last time this was queued
290
usec_t delay_calc_ut; // the last time we calculated the scheduled_dispatched_ut
291
usec_t scheduled_dispatch_ut; // the time it was/is scheduled to be sent
292
usec_t dequeued_ut; // the last time we sent (or deduplicated) this context
280
- size_t dispatches; // the number of times this has been dispatched to hub
293
} queue;
282
-
283
- struct {
284
- uint32_t metrics; // the number of metrics in this context
285
- } stats;
294
} RRDCONTEXT;
295
296
+// ----------------------------------------------------------------------------
297
+// helpers for counting collected metrics, instances and contexts
298
+
299
+static inline void rrdmetric_set_collected(RRDMETRIC *rm) {
300
+ RRD_FLAGS old = rrd_flag_set_collected(rm);
301
+ if(!(old & RRD_FLAG_COLLECTED))
302
+ __atomic_add_fetch(&rm->ri->rc->rrdhost->collected.metrics_count, 1, __ATOMIC_RELAXED);
303
+}
304
+
305
+static inline void rrdmetric_set_archived(RRDMETRIC *rm) {
306
+ RRD_FLAGS old = rrd_flag_set_archived(rm);
307
+ if(old & RRD_FLAG_COLLECTED)
308
+ __atomic_sub_fetch(&rm->ri->rc->rrdhost->collected.metrics_count, 1, __ATOMIC_RELAXED);
309
+}
310
+
311
+static inline void rrdmetric_set_deleted(RRDMETRIC *rm, RRD_FLAGS reason) {
312
+ RRD_FLAGS old = rrd_flag_set_deleted(rm, reason);
313
+ if(old & RRD_FLAG_COLLECTED)
314
+ __atomic_sub_fetch(&rm->ri->rc->rrdhost->collected.metrics_count, 1, __ATOMIC_RELAXED);
315
+}
316
+
317
+static inline void rrdmetric_set_deleted_overwrite(RRDMETRIC *rm, RRD_FLAGS replacement) {
318
+ replacement &= ~(RRD_FLAG_COLLECTED|RRD_FLAG_ARCHIVED|RRD_FLAG_DELETED);
319
+ replacement |= RRD_FLAG_DELETED;
320
+ RRD_FLAGS old = rrd_flags_replace_atomic(&rm->flags, replacement);
321
+ if(old & RRD_FLAG_COLLECTED)
322
+ __atomic_sub_fetch(&rm->ri->rc->rrdhost->collected.metrics_count, 1, __ATOMIC_RELAXED);
323
+}
324
+
325
+static inline void rrdinstance_set_collected(RRDINSTANCE *ri) {
326
+ RRD_FLAGS old = rrd_flag_set_collected(ri);
327
+ if(!(old & RRD_FLAG_COLLECTED))
328
+ __atomic_add_fetch(&ri->rc->rrdhost->collected.instances_count, 1, __ATOMIC_RELAXED);
329
+}
330
+
331
+static inline void rrdinstance_set_archived(RRDINSTANCE *ri) {
332
+ RRD_FLAGS old = rrd_flag_set_archived(ri);
333
+ if(old & RRD_FLAG_COLLECTED)
334
+ __atomic_sub_fetch(&ri->rc->rrdhost->collected.instances_count, 1, __ATOMIC_RELAXED);
335
+}
336
+
337
+static inline void rrdinstance_set_deleted(RRDINSTANCE *ri, RRD_FLAGS reason) {
338
+ RRD_FLAGS old = rrd_flag_set_deleted(ri, reason);
339
+ if(old & RRD_FLAG_COLLECTED)
340
+ __atomic_sub_fetch(&ri->rc->rrdhost->collected.instances_count, 1, __ATOMIC_RELAXED);
341
+}
342
+
343
+static inline void rrdinstance_set_deleted_overwrite(RRDINSTANCE *ri, RRD_FLAGS replacement) {
344
+ replacement &= ~(RRD_FLAG_COLLECTED|RRD_FLAG_ARCHIVED|RRD_FLAG_DELETED);
345
+ replacement |= RRD_FLAG_DELETED;
346
+ RRD_FLAGS old = rrd_flags_replace_atomic(&ri->flags, replacement);
347
+ if(old & RRD_FLAG_COLLECTED)
348
+ __atomic_sub_fetch(&ri->rc->rrdhost->collected.instances_count, 1, __ATOMIC_RELAXED);
349
+}
350
+
351
+static inline void rrdcontext_set_collected(RRDCONTEXT *rc) {
352
+ RRD_FLAGS old = rrd_flag_set_collected(rc);
353
+ if(!(old & RRD_FLAG_COLLECTED))
354
+ __atomic_add_fetch(&rc->rrdhost->collected.contexts_count, 1, __ATOMIC_RELAXED);
355
+}
356
+
357
+static inline void rrdcontext_set_archived(RRDCONTEXT *rc) {
358
+ RRD_FLAGS old = rrd_flag_set_archived(rc);
359
+ if(old & RRD_FLAG_COLLECTED)
360
+ __atomic_sub_fetch(&rc->rrdhost->collected.contexts_count, 1, __ATOMIC_RELAXED);
361
+}
362
+
363
+static inline void rrdcontext_set_deleted(RRDCONTEXT *rc, RRD_FLAGS reason) {
364
+ RRD_FLAGS old = rrd_flag_set_deleted(rc, reason);
365
+ if(old & RRD_FLAG_COLLECTED)
366
+ __atomic_sub_fetch(&rc->rrdhost->collected.contexts_count, 1, __ATOMIC_RELAXED);
367
+}
368
369
// ----------------------------------------------------------------------------
370
// helper one-liners for RRDMETRIC
src/database/contexts/metric.c
+12
-6
@@ -52,7 +52,7 @@ inline time_t rrdmetric_acquired_first_entry(RRDMETRIC_ACQUIRED *rma) {
52
inline time_t rrdmetric_acquired_last_entry(RRDMETRIC_ACQUIRED *rma) {
53
RRDMETRIC *rm = rrdmetric_acquired_value(rma);
54
55
- if(rrd_flag_check(rm, RRD_FLAG_COLLECTED))
55
+ if(rrd_flag_is_collected(rm))
56
return 0;
57
58
return rm->last_time_s;
@@ -83,6 +83,9 @@ static void rrdmetric_insert_callback(const DICTIONARY_ITEM *item __maybe_unused
83
// remove flags that we need to figure out at runtime
84
rm->flags = rm->flags & RRD_FLAGS_ALLOWED_EXTERNALLY_ON_NEW_OBJECTS; // no need for atomics
85
86
+ // update the count of metrics
87
+ __atomic_add_fetch(&rm->ri->rc->rrdhost->rrdctx.metrics_count, 1, __ATOMIC_RELAXED);
88
+
89
// signal the react callback to do the job
90
rrd_flag_set_updated(rm, RRD_FLAG_UPDATE_REASON_NEW_OBJECT);
91
}
@@ -94,6 +97,9 @@ static void rrdmetric_delete_callback(const DICTIONARY_ITEM *item __maybe_unused
97
98
internal_error(rm->rrddim, "RRDMETRIC: '%s' is freed but there is a RRDDIM linked to it.", string2str(rm->id));
99
100
+ // update the count of metrics
101
+ __atomic_sub_fetch(&rm->ri->rc->rrdhost->rrdctx.metrics_count, 1, __ATOMIC_RELAXED);
102
+
103
// free the resources
104
rrdmetric_free(rm);
105
}
@@ -181,7 +187,7 @@ static bool rrdmetric_conflict_callback(const DICTIONARY_ITEM *item __maybe_unus
187
rrd_flag_set(rm, rm_new->flags & RRD_FLAGS_ALLOWED_EXTERNALLY_ON_NEW_OBJECTS); // no needs for atomics on rm_new
188
189
if(rrd_flag_is_collected(rm) && rrd_flag_is_archived(rm))
184
- rrd_flag_set_collected(rm);
190
+ rrdmetric_set_collected(rm);
191
192
if(rrd_flag_check(rm, RRD_FLAG_UPDATED))
193
rrd_flag_set(rm, RRD_FLAG_UPDATE_REASON_UPDATED_OBJECT);
@@ -221,7 +227,7 @@ void rrdmetrics_destroy_from_rrdinstance(RRDINSTANCE *ri) {
227
// trigger post-processing of the rrdmetric, escalating changes to the rrdinstance it belongs
228
static void rrdmetric_trigger_updates(RRDMETRIC *rm, const char *function) {
229
if(unlikely(rrd_flag_is_collected(rm)) && (!rm->rrddim || rrd_flag_check(rm, RRD_FLAG_UPDATE_REASON_DISCONNECTED_CHILD)))
224
- rrd_flag_set_archived(rm);
230
+ rrdmetric_set_archived(rm);
231
232
if(rrd_flag_is_updated(rm) || !rrd_flag_check(rm, RRD_FLAG_LIVE_RETENTION)) {
233
rrd_flag_set_updated(rm->ri, RRD_FLAG_UPDATE_REASON_TRIGGERED);
@@ -285,7 +291,7 @@ inline void rrdmetric_rrddim_is_freed(RRDDIM *rd) {
291
if(unlikely(!rm)) return;
292
293
if(unlikely(rrd_flag_is_collected(rm)))
288
- rrd_flag_set_archived(rm);
294
+ rrdmetric_set_archived(rm);
295
296
rm->rrddim = NULL;
297
rrdmetric_trigger_updates(rm, __FUNCTION__ );
@@ -302,7 +308,7 @@ inline void rrdmetric_updated_rrddim_flags(RRDDIM *rd) {
308
309
if(unlikely(rrddim_flag_check(rd, RRDDIM_FLAG_ARCHIVED|RRDDIM_FLAG_OBSOLETE))) {
310
if(unlikely(rrd_flag_is_collected(rm)))
305
- rrd_flag_set_archived(rm);
311
+ rrdmetric_set_archived(rm);
312
}
313
314
rrdmetric_trigger_updates(rm, __FUNCTION__ );
@@ -318,7 +324,7 @@ inline void rrdmetric_collected_rrddim(RRDDIM *rd) {
324
if(unlikely(!rm)) return;
325
326
if(unlikely(!rrd_flag_is_collected(rm)))
321
- rrd_flag_set_collected(rm);
327
+ rrdmetric_set_collected(rm);
328
329
// we use this variable to detect BEGIN/END without SET
330
rm->ri->internal.collected_metrics_count++;
src/database/contexts/worker.c
+14
-28
@@ -288,7 +288,7 @@ bool rrdmetric_update_retention(RRDMETRIC *rm) {
288
}
289
290
if(unlikely(!rm->first_time_s && !rm->last_time_s))
291
- rrd_flag_set_deleted(rm, RRD_FLAG_UPDATE_REASON_ZERO_RETENTION);
291
+ rrdmetric_set_deleted(rm, RRD_FLAG_UPDATE_REASON_ZERO_RETENTION);
292
293
rrd_flag_set(rm, RRD_FLAG_LIVE_RETENTION);
294
@@ -472,11 +472,11 @@ static void rrdmetric_process_updates(RRDMETRIC *rm, bool force, RRD_FLAGS reaso
472
worker_is_busy(WORKER_JOB_PP_METRIC);
473
474
if(reason & RRD_FLAG_UPDATE_REASON_DISCONNECTED_CHILD) {
475
- rrd_flag_set_archived(rm);
475
+ rrdmetric_set_archived(rm);
476
rrd_flag_set(rm, RRD_FLAG_UPDATE_REASON_DISCONNECTED_CHILD);
477
}
478
if(rrd_flag_is_deleted(rm) && (reason & RRD_FLAG_UPDATE_REASON_UPDATE_RETENTION))
479
- rrd_flag_set_archived(rm);
479
+ rrdmetric_set_archived(rm);
480
481
rrdmetric_update_retention(rm);
482
@@ -515,7 +515,7 @@ static void rrdinstance_post_process_updates(RRDINSTANCE *ri, bool force, RRD_FL
515
continue;
516
}
517
518
- if(!currently_collected && rrd_flag_check(rm, RRD_FLAG_COLLECTED) && rm->first_time_s)
518
+ if(!currently_collected && rrd_flag_is_collected(rm) && rm->first_time_s)
519
currently_collected = true;
520
521
metrics_active++;
@@ -547,7 +547,7 @@ static void rrdinstance_post_process_updates(RRDINSTANCE *ri, bool force, RRD_FL
547
rrd_flag_set_updated(ri, RRD_FLAG_UPDATE_REASON_CHANGED_LAST_TIME_T);
548
}
549
550
- rrd_flag_set_deleted(ri, RRD_FLAG_UPDATE_REASON_ZERO_RETENTION);
550
+ rrdinstance_set_deleted(ri, RRD_FLAG_UPDATE_REASON_ZERO_RETENTION);
551
}
552
else {
553
// we have active metrics...
@@ -567,7 +567,7 @@ static void rrdinstance_post_process_updates(RRDINSTANCE *ri, bool force, RRD_FL
567
}
568
569
if(likely(live_retention))
570
- rrd_flag_set_deleted(ri, RRD_FLAG_UPDATE_REASON_ZERO_RETENTION);
570
+ rrdinstance_set_deleted(ri, RRD_FLAG_UPDATE_REASON_ZERO_RETENTION);
571
}
572
else {
573
rrd_flag_clear(ri, RRD_FLAG_UPDATE_REASON_ZERO_RETENTION);
@@ -583,9 +583,9 @@ static void rrdinstance_post_process_updates(RRDINSTANCE *ri, bool force, RRD_FL
583
}
584
585
if(likely(currently_collected))
586
- rrd_flag_set_collected(ri);
586
+ rrdinstance_set_collected(ri);
587
else
588
- rrd_flag_set_archived(ri);
588
+ rrdinstance_set_archived(ri);
589
}
590
}
591
@@ -603,7 +603,7 @@ static void rrdcontext_post_process_updates(RRDCONTEXT *rc, bool force, RRD_FLAG
603
size_t min_priority_not_collected = LONG_MAX;
604
size_t min_priority = LONG_MAX;
605
time_t min_first_time_t = LONG_MAX, max_last_time_t = 0;
606
- size_t instances_active = 0, instances_deleted = 0, metrics = 0;
606
+ size_t instances_active = 0, instances_deleted = 0;
607
bool live_retention = true, currently_collected = false, hidden = true;
608
if(dictionary_entries(rc->rrdinstances) > 0) {
609
RRDINSTANCE *ri;
@@ -643,10 +643,9 @@ static void rrdcontext_post_process_updates(RRDCONTEXT *rc, bool force, RRD_FLAG
643
string2str(rc->units), string2str(ri->units));
644
645
instances_active++;
646
- metrics += dictionary_entries(ri->rrdmetrics);
646
647
if (ri->priority >= RRDCONTEXT_MINIMUM_ALLOWED_PRIORITY) {
649
- if(rrd_flag_check(ri, RRD_FLAG_COLLECTED)) {
648
+ if(rrd_flag_is_collected(ri)) {
649
if(ri->priority < min_priority_collected)
650
min_priority_collected = ri->priority;
651
}
@@ -664,8 +663,6 @@ static void rrdcontext_post_process_updates(RRDCONTEXT *rc, bool force, RRD_FLAG
663
}
664
dfe_done(ri);
665
667
- rc->stats.metrics = metrics;
668
-
666
if(min_priority_collected != LONG_MAX)
667
// use the collected priority
668
min_priority = min_priority_collected;
@@ -708,7 +705,7 @@ static void rrdcontext_post_process_updates(RRDCONTEXT *rc, bool force, RRD_FLAG
705
rrd_flag_set_updated(rc, RRD_FLAG_UPDATE_REASON_CHANGED_LAST_TIME_T);
706
}
707
711
- rrd_flag_set_deleted(rc, RRD_FLAG_UPDATE_REASON_ZERO_RETENTION);
708
+ rrdcontext_set_deleted(rc, RRD_FLAG_UPDATE_REASON_ZERO_RETENTION);
709
}
710
else {
711
// we have some active instances...
@@ -727,7 +724,7 @@ static void rrdcontext_post_process_updates(RRDCONTEXT *rc, bool force, RRD_FLAG
724
rrd_flag_set_updated(rc, RRD_FLAG_UPDATE_REASON_CHANGED_LAST_TIME_T);
725
}
726
730
- rrd_flag_set_deleted(rc, RRD_FLAG_UPDATE_REASON_ZERO_RETENTION);
727
+ rrdcontext_set_deleted(rc, RRD_FLAG_UPDATE_REASON_ZERO_RETENTION);
728
}
729
else {
730
rrd_flag_clear(rc, RRD_FLAG_UPDATE_REASON_ZERO_RETENTION);
@@ -743,9 +740,9 @@ static void rrdcontext_post_process_updates(RRDCONTEXT *rc, bool force, RRD_FLAG
740
}
741
742
if(likely(currently_collected))
746
- rrd_flag_set_collected(rc);
743
+ rrdcontext_set_collected(rc);
744
else
748
- rrd_flag_set_archived(rc);
745
+ rrdcontext_set_archived(rc);
746
}
747
748
if (min_priority != LONG_MAX && rc->priority != min_priority) {
@@ -1138,17 +1135,6 @@ void *rrdcontext_main(void *ptr) {
1135
1136
if (host->rrdctx.contexts)
1137
dictionary_garbage_collect(host->rrdctx.contexts);
1141
-
1142
- // calculate the number of metrics and instances in the host
1143
- RRDCONTEXT *rc;
1144
- uint32_t metrics = 0, instances = 0;
1145
- dfe_start_read(host->rrdctx.contexts, rc) {
1146
- metrics += rc->stats.metrics;
1147
- instances += dictionary_entries(rc->rrdinstances);
1148
- }
1149
- dfe_done(rc);
1150
- host->rrdctx.metrics = metrics;
1151
- host->rrdctx.instances = instances;
1138
}
1139
dfe_done(host);
1140
src/database/engine/rrdengineapi.c
+3
@@ -1125,6 +1125,9 @@ void rrdeng_readiness_wait(struct rrdengine_instance *ctx) {
1125
ctx->loading.populate_mrg.array = NULL;
1126
ctx->loading.populate_mrg.size = 0;
1127
1128
+ if(__atomic_load_n(&ctx->atomic.first_time_s, __ATOMIC_RELAXED) == LONG_MAX)
1129
+ __atomic_store_n(&ctx->atomic.first_time_s, now_realtime_sec(), __ATOMIC_RELAXED);
1130
+
1131
netdata_log_info("DBENGINE: tier %d is ready for data collection and queries", ctx->config.tier);
1132
}
1133
src/database/rrd.h
+9
-11
@@ -323,7 +323,6 @@ struct rrddim {
323
324
int32_t multiplier; // the multiplier of the collected values
325
int32_t divisor; // the divider of the collected values
326
- int32_t dimension_id; // Dimension id
326
327
// ------------------------------------------------------------------------
328
// operational state members
@@ -1175,14 +1174,6 @@ struct rrdhost {
1174
int32_t rrd_update_every; // the update frequency of the host
1175
int32_t rrd_history_entries; // the number of history entries for the host's charts
1176
1178
- struct {
1179
- uint32_t dimension_count; // Dimension count for this host
1180
- uint32_t currently_collected; // Currectly collected metrics cache
1181
- time_t cache_timestamp;
1182
- Pvoid_t JudyL; // Store metrics collected -- link to rrddim
1183
- SPINLOCK spinlock;
1184
- } accounting;
1185
-
1177
RRD_MEMORY_MODE rrd_memory_mode; // the configured memory more for the charts of this host
1178
// the actual per tier is at .db[tier].mode
1179
@@ -1305,12 +1296,19 @@ struct rrdhost {
1296
DICTIONARY *rrdvars; // the host's chart variables index
1297
// this includes custom host variables
1298
1299
+ struct {
1300
+ uint32_t metrics_count; // atomic
1301
+ uint32_t instances_count; // atomic
1302
+ uint32_t contexts_count; // atomic
1303
+ } collected;
1304
+
1305
struct {
1306
DICTIONARY *contexts;
1307
DICTIONARY *hub_queue;
1308
DICTIONARY *pp_queue;
1312
- uint32_t metrics;
1313
- uint32_t instances;
1309
+ uint32_t metrics_count; // atomic
1310
+ uint32_t instances_count; // atomic
1311
+ uint32_t contexts_count; // atomic
1312
} rrdctx;
1313
1314
struct {
src/database/rrddim.c
-11
@@ -41,13 +41,6 @@ static void rrddim_insert_callback(const DICTIONARY_ITEM *item __maybe_unused, v
41
RRDSET *st = ctr->st;
42
RRDHOST *host = st->rrdhost;
43
44
- rd->dimension_id = __atomic_add_fetch(&host->accounting.dimension_count, 1, __ATOMIC_RELAXED);
45
- spinlock_lock(&host->accounting.spinlock);
46
- Pvoid_t *Pvalue = JudyLIns(&host->accounting.JudyL, rd->dimension_id, PJE0);
47
- if (Pvalue)
48
- *Pvalue = rd;
49
- spinlock_unlock(&host->accounting.spinlock);
50
-
44
rd->flags = RRDDIM_FLAG_NONE;
45
46
rd->id = string_strdupz(ctr->id);
@@ -238,10 +231,6 @@ static void rrddim_delete_callback(const DICTIONARY_ITEM *item __maybe_unused, v
231
freez(rd->db.data);
232
}
233
241
- spinlock_lock(&host->accounting.spinlock);
242
- (void) JudyLDel(&host->accounting.JudyL, rd->dimension_id, PJE0);
243
- spinlock_unlock(&host->accounting.spinlock);
244
-
234
string_freez(rd->id);
235
string_freez(rd->name);
236
}
src/streaming/rrdhost-status.c
+7
-3
@@ -166,9 +166,9 @@ void rrdhost_status(RRDHOST *host, time_t now, RRDHOST_STATUS *s) {
166
bool online = rrdhost_is_online(host);
167
168
rrdhost_retention(host, now, online, &s->db.first_time_s, &s->db.last_time_s);
169
- s->db.metrics = host->rrdctx.metrics;
170
- s->db.instances = host->rrdctx.instances;
171
- s->db.contexts = dictionary_entries(host->rrdctx.contexts);
169
+ s->db.metrics = __atomic_load_n(&host->rrdctx.metrics_count, __ATOMIC_RELAXED);
170
+ s->db.instances = __atomic_load_n(&host->rrdctx.instances_count, __ATOMIC_RELAXED);
171
+ s->db.contexts = __atomic_load_n(&host->rrdctx.contexts_count, __ATOMIC_RELAXED);
172
if(!s->db.first_time_s || !s->db.last_time_s || !s->db.metrics || !s->db.instances || !s->db.contexts ||
173
(flags & (RRDHOST_FLAG_PENDING_CONTEXT_LOAD)))
174
s->db.status = RRDHOST_DB_STATUS_INITIALIZING;
@@ -222,6 +222,10 @@ void rrdhost_status(RRDHOST *host, time_t now, RRDHOST_STATUS *s) {
222
s->ingest.status = RRDHOST_INGEST_STATUS_OFFLINE;
223
}
224
225
+ s->ingest.collected.metrics = __atomic_load_n(&host->collected.metrics_count, __ATOMIC_RELAXED);
226
+ s->ingest.collected.instances = __atomic_load_n(&host->collected.instances_count, __ATOMIC_RELAXED);
227
+ s->ingest.collected.contexts = __atomic_load_n(&host->collected.contexts_count, __ATOMIC_RELAXED);
228
+
229
if(host == localhost)
230
s->ingest.type = RRDHOST_INGEST_TYPE_LOCALHOST;
231
else if(has_receiver)
src/streaming/rrdhost-status.h
+6
@@ -117,6 +117,12 @@ typedef struct {
117
time_t since;
118
STREAM_HANDSHAKE reason;
119
120
+ struct {
121
+ size_t metrics; // currently collected
122
+ size_t instances; // currently collected
123
+ size_t contexts; // currently collected
124
+ } collected;
125
+
126
struct {
127
bool in_progress;
128
NETDATA_DOUBLE completion;
src/web/api/functions/function-streaming.c
+22
@@ -90,6 +90,10 @@ int function_streaming(BUFFER *wb, const char *function __maybe_unused, BUFFER *
90
buffer_json_add_array_item_string(wb, s.ingest.ssl ? "SSL" : "PLAIN"); // InSSL
91
stream_capabilities_to_json_array(wb, s.ingest.capabilities, NULL); // InCapabilities
92
93
+ buffer_json_add_array_item_uint64(wb, s.ingest.collected.metrics); // CollectedMetrics
94
+ buffer_json_add_array_item_uint64(wb, s.ingest.collected.instances); // CollectedInstances
95
+ buffer_json_add_array_item_uint64(wb, s.ingest.collected.contexts); // CollectedContexts
96
+
97
// streaming
98
if(s.stream.since) {
99
buffer_json_add_array_item_uint64(wb, s.stream.since * MSEC_PER_SEC); // OutSince
@@ -316,6 +320,24 @@ int function_streaming(BUFFER *wb, const char *function __maybe_unused, BUFFER *
320
RRDF_FIELD_SUMMARY_COUNT, RRDF_FIELD_FILTER_MULTISELECT,
321
RRDF_FIELD_OPTS_NONE, NULL);
322
323
+ buffer_rrdf_table_add_field(wb, field_id++, "CollectedMetrics", "Time-series Metrics Currently Collected",
324
+ RRDF_FIELD_TYPE_INTEGER, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NUMBER,
325
+ 0, NULL, (double)max_db_metrics, RRDF_FIELD_SORT_DESCENDING, NULL,
326
+ RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_RANGE,
327
+ RRDF_FIELD_OPTS_VISIBLE, NULL);
328
+
329
+ buffer_rrdf_table_add_field(wb, field_id++, "CollectedInstances", "Instances Currently Collected",
330
+ RRDF_FIELD_TYPE_INTEGER, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NUMBER,
331
+ 0, NULL, (double)max_db_instances, RRDF_FIELD_SORT_DESCENDING, NULL,
332
+ RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_RANGE,
333
+ RRDF_FIELD_OPTS_VISIBLE, NULL);
334
+
335
+ buffer_rrdf_table_add_field(wb, field_id++, "CollectedContexts", "Contexts Currently Collected",
336
+ RRDF_FIELD_TYPE_INTEGER, RRDF_FIELD_VISUAL_VALUE, RRDF_FIELD_TRANSFORM_NUMBER,
337
+ 0, NULL, (double)max_db_contexts, RRDF_FIELD_SORT_DESCENDING, NULL,
338
+ RRDF_FIELD_SUMMARY_SUM, RRDF_FIELD_FILTER_RANGE,
339
+ RRDF_FIELD_OPTS_VISIBLE, NULL);
340
+
341
// --- streaming ---
342
343
buffer_rrdf_table_add_field(wb, field_id++, "OutSince", "Last Streaming Status Change",