Rrddim acquire on replay set (#13932)
* prevent RRDDIM from vanishing while replay is working with it * set chart last access time * set chart last access time everytime someone finds it * do not replay dimensions that are archived * remove the obsolete flag from dimensions that replayed; do not process archived dimensions * cleanup db_metric_handle refcount of hidden dimensions * more information in page alignment fatal * do not fatal() of page alignment reset when the caller is the only writer
Costa Tsaousis committed
Nov 1, 2022 at 20:32 UTC
c2b8b9a8073b28ac780a949f847ef14d74296fee
6 files changed
+85
-42
collectors/plugins.d/pluginsd_parser.c
+28
-12
@@ -56,14 +56,15 @@ PARSER_RC pluginsd_set(char **words, size_t num_words, void *user, PLUGINSD_ACTI
56
debug(D_PLUGINSD, "is setting dimension '%s'/'%s' to '%s'", rrdset_id(st), dimension, value ? value : "<nothing>");
57
58
if (value) {
59
- RRDDIM *rd = rrddim_find(st, dimension);
59
+ RRDDIM_ACQUIRED *rda = rrddim_find_and_acquire(st, dimension);
60
+ RRDDIM *rd = rrddim_acquired_to_rrddim(rda);
61
if (unlikely(!rd)) {
61
- error(
62
- "requested a SET to dimension with id '%s' on stats '%s' (%s) on host '%s', which does not exist. Disabling it.",
63
- dimension, rrdset_name(st), rrdset_id(st), rrdhost_hostname(st->rrdhost));
62
+ error( "requested a SET to dimension with id '%s' on stats '%s' (%s) on host '%s', which does not exist. Disabling it.",
63
+ dimension, rrdset_name(st), rrdset_id(st), rrdhost_hostname(st->rrdhost));
64
goto disable;
65
- } else
66
- rrddim_set_by_pointer(st, rd, strtoll(value, NULL, 0));
65
+ }
66
+ rrddim_set_by_pointer(st, rd, strtoll(value, NULL, 0));
67
+ rrddim_acquired_release(rda);
68
}
69
return PARSER_RC_OK;
70
@@ -1024,19 +1025,28 @@ PARSER_RC pluginsd_replay_set(char **words, size_t num_words, void *user, PLUGIN
1025
debug(D_PLUGINSD, "REPLAY: is replaying dimension '%s'/'%s' to '%s'", rrdset_id(st), dimension, value_str);
1026
1027
if (likely(value_str)) {
1027
- RRDDIM *rd = rrddim_find(st, dimension);
1028
+ RRDDIM_ACQUIRED *rda = rrddim_find_and_acquire(st, dimension);
1029
+ RRDDIM *rd = rrddim_acquired_to_rrddim(rda);
1030
if(unlikely(!rd)) {
1031
error("REPLAY: requested a " PLUGINSD_KEYWORD_REPLAY_SET " to dimension with id '%s' on chart '%s' ('%s') on host '%s', which does not exist. Disabling it.",
1032
dimension, rrdset_name(st), rrdset_id(st), rrdhost_hostname(st->rrdhost));
1033
goto disable;
1034
}
1033
- else {
1035
+
1036
+ RRDDIM_FLAGS rd_flags = rrddim_flag_check(rd, RRDDIM_FLAG_OBSOLETE | RRDDIM_FLAG_ARCHIVED);
1037
+
1038
+ if(unlikely(rd_flags & RRDDIM_FLAG_OBSOLETE)) {
1039
+ error("Dimension %s in chart '%s' has the OBSOLETE flag set, but it is collected.", rrddim_name(rd), rrdset_id(st));
1040
+ rrddim_isnot_obsolete(st, rd);
1041
+ }
1042
+
1043
+ if(!(rd_flags & RRDDIM_FLAG_ARCHIVED)) {
1044
NETDATA_DOUBLE value = strtondd(value_str, NULL);
1045
SN_FLAGS flags = SN_FLAG_NONE;
1046
1047
char c;
1038
- while((c = *flags_str++)) {
1039
- switch(c) {
1048
+ while ((c = *flags_str++)) {
1049
+ switch (c) {
1050
case 'R':
1051
flags |= SN_FLAG_RESET;
1052
break;
@@ -1052,7 +1062,7 @@ PARSER_RC pluginsd_replay_set(char **words, size_t num_words, void *user, PLUGIN
1062
}
1063
}
1064
1055
- if(!netdata_double_isnumber(value)) {
1065
+ if (!netdata_double_isnumber(value)) {
1066
value = NAN;
1067
flags = SN_EMPTY_SLOT;
1068
}
@@ -1062,6 +1072,10 @@ PARSER_RC pluginsd_replay_set(char **words, size_t num_words, void *user, PLUGIN
1072
rd->last_collected_time.tv_usec = 0;
1073
rd->collections_counter++;
1074
}
1075
+ else
1076
+ error("Dimension %s in chart '%s' has the ARCHIVED flag set, but it is collected. Ignoring data.", rrddim_name(rd), rrdset_id(st));
1077
+
1078
+ rrddim_acquired_release(rda);
1079
}
1080
return PARSER_RC_OK;
1081
@@ -1093,7 +1107,8 @@ PARSER_RC pluginsd_replay_rrddim_collection_state(char **words, size_t num_words
1107
goto disable;
1108
}
1109
1096
- RRDDIM *rd = rrddim_find(st, dimension);
1110
+ RRDDIM_ACQUIRED *rda = rrddim_find_and_acquire(st, dimension);
1111
+ RRDDIM *rd = rrddim_acquired_to_rrddim(rda);
1112
if(unlikely(!rd)) {
1113
error("REPLAY: requested a " PLUGINSD_KEYWORD_REPLAY_RRDDIM_STATE " to dimension with id '%s' on chart '%s' ('%s') on host '%s', which does not exist. Disabling it.",
1114
dimension, rrdset_name(st), rrdset_id(st), rrdhost_hostname(st->rrdhost));
@@ -1110,6 +1125,7 @@ PARSER_RC pluginsd_replay_rrddim_collection_state(char **words, size_t num_words
1125
rd->last_collected_value = last_collected_value_str ? str2ll(last_collected_value_str, NULL) : 0;
1126
rd->last_calculated_value = last_calculated_value_str ? str2ndd(last_calculated_value_str, NULL) : 0;
1127
rd->last_stored_value = last_stored_value_str ? str2ndd(last_stored_value_str, NULL) : 0.0;
1128
+ rrddim_acquired_release(rda);
1129
return PARSER_RC_OK;
1130
1131
disable:
database/engine/rrdengineapi.c
+5
-6
@@ -134,13 +134,12 @@ STORAGE_METRIC_HANDLE *rrdeng_metric_get(STORAGE_INSTANCE *db_instance, uuid_t *
134
__atomic_add_fetch(&page_index->refcount, 1, __ATOMIC_SEQ_CST);
135
136
if(pa) {
137
- if(page_index->alignment && page_index->alignment != pa)
138
- fatal("DBENGINE: page_index has a different alignment.");
137
+ if(page_index->alignment && page_index->alignment != pa && page_index->writers > 0)
138
+ fatal("DBENGINE: page_index has a different alignment (page_index refcount is %u, writers is %u).",
139
+ page_index->refcount, page_index->writers);
140
140
- if(!page_index->alignment) {
141
- page_index->alignment = pa;
142
- __atomic_add_fetch(&pa->refcount, 1, __ATOMIC_SEQ_CST);
143
- }
141
+ page_index->alignment = pa;
142
+ __atomic_add_fetch(&pa->refcount, 1, __ATOMIC_SEQ_CST);
143
}
144
}
145
database/rrd.h
+3
@@ -1280,6 +1280,9 @@ int rrddim_set_multiplier(RRDSET *st, RRDDIM *rd, collected_number multiplier);
1280
int rrddim_set_divisor(RRDSET *st, RRDDIM *rd, collected_number divisor);
1281
1282
RRDDIM *rrddim_find(RRDSET *st, const char *id);
1283
+RRDDIM_ACQUIRED *rrddim_find_and_acquire(RRDSET *st, const char *id);
1284
+RRDDIM *rrddim_acquired_to_rrddim(RRDDIM_ACQUIRED *rda);
1285
+void rrddim_acquired_release(RRDDIM_ACQUIRED *rda);
1286
RRDDIM *rrddim_find_active(RRDSET *st, const char *id);
1287
1288
int rrddim_hide(RRDSET *st, const char *id);
database/rrdcontext.c
+5
-2
@@ -2406,7 +2406,7 @@ static void query_target_add_metric(QUERY_TARGET_LOCALS *qtl, RRDMETRIC_ACQUIRED
2406
tier_retention[tier].eng = eng;
2407
tier_retention[tier].db_update_every = (time_t) (qtl->host->db[tier].tier_grouping * ri->update_every);
2408
2409
- if(rm->rrddim && rm->rrddim->tiers[tier]->db_metric_handle)
2409
+ if(rm->rrddim && rm->rrddim->tiers[tier] && rm->rrddim->tiers[tier]->db_metric_handle)
2410
tier_retention[tier].db_metric_handle = eng->api.metric_dup(rm->rrddim->tiers[tier]->db_metric_handle);
2411
else
2412
tier_retention[tier].db_metric_handle = eng->api.metric_get(qtl->host->db[tier].instance, &rm->uuid, NULL);
@@ -2439,6 +2439,7 @@ static void query_target_add_metric(QUERY_TARGET_LOCALS *qtl, RRDMETRIC_ACQUIRED
2439
}
2440
}
2441
2442
+ bool release_retention = true;
2443
bool timeframe_matches =
2444
(tiers_added
2445
&& (common_first_time_t - common_update_every * 2) <= qt->window.before
@@ -2521,11 +2522,13 @@ static void query_target_add_metric(QUERY_TARGET_LOCALS *qtl, RRDMETRIC_ACQUIRED
2522
qm->tiers[tier].db_last_time_t = tier_retention[tier].db_last_time_t;
2523
qm->tiers[tier].db_update_every = tier_retention[tier].db_update_every;
2524
}
2525
+ release_retention = false;
2526
}
2527
}
2526
- else {
2528
+ else
2529
qtl->metrics_skipped_due_to_not_matching_timeframe++;
2530
2531
+ if(release_retention) {
2532
// cleanup anything we allocated to the retention we will not use
2533
for(size_t tier = 0; tier < storage_tiers ;tier++) {
2534
if (tier_retention[tier].db_metric_handle)
database/rrddim.c
+38
-22
@@ -180,24 +180,21 @@ static void rrddim_delete_callback(const DICTIONARY_ITEM *item __maybe_unused, v
180
181
debug(D_RRD_CALLS, "rrddim_free() %s.%s", rrdset_name(st), rrddim_name(rd));
182
183
- if (!rrddim_flag_check(rd, RRDDIM_FLAG_ARCHIVED)) {
184
-
185
- size_t tiers_available = 0, tiers_said_yes = 0;
186
- for(size_t tier = 0; tier < storage_tiers ;tier++) {
187
- if(rd->tiers[tier]) {
188
- tiers_available++;
183
+ size_t tiers_available = 0, tiers_said_yes = 0;
184
+ for(size_t tier = 0; tier < storage_tiers ;tier++) {
185
+ if(rd->tiers[tier] && rd->tiers[tier]->db_collection_handle) {
186
+ tiers_available++;
187
190
- if(rd->tiers[tier]->collect_ops->finalize(rd->tiers[tier]->db_collection_handle))
191
- tiers_said_yes++;
188
+ if(rd->tiers[tier]->collect_ops->finalize(rd->tiers[tier]->db_collection_handle))
189
+ tiers_said_yes++;
190
193
- rd->tiers[tier]->db_collection_handle = NULL;
194
- }
191
+ rd->tiers[tier]->db_collection_handle = NULL;
192
}
193
+ }
194
197
- if (tiers_available == tiers_said_yes && tiers_said_yes && rd->rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE) {
198
- /* This metric has no data and no references */
199
- metaqueue_delete_dimension_uuid(&rd->metric_uuid);
200
- }
195
+ if (tiers_available == tiers_said_yes && tiers_said_yes && rd->rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE) {
196
+ /* This metric has no data and no references */
197
+ metaqueue_delete_dimension_uuid(&rd->metric_uuid);
198
}
199
200
rrddimvar_delete_all(rd);
@@ -246,16 +243,14 @@ static bool rrddim_conflict_callback(const DICTIONARY_ITEM *item __maybe_unused,
243
rc += rrddim_set_multiplier(st, rd, ctr->multiplier);
244
rc += rrddim_set_divisor(st, rd, ctr->divisor);
245
249
- if(rrddim_flag_check(rd, RRDDIM_FLAG_ARCHIVED)) {
250
-
251
- for(size_t tier = 0; tier < storage_tiers ;tier++) {
252
- if (rd->tiers[tier])
253
- rd->tiers[tier]->db_collection_handle =
254
- rd->tiers[tier]->collect_ops->init(rd->tiers[tier]->db_metric_handle, st->rrdhost->db[tier].tier_grouping * st->update_every);
255
- }
246
+ for(size_t tier = 0; tier < storage_tiers ;tier++) {
247
+ if (rd->tiers[tier] && !rd->tiers[tier]->db_collection_handle)
248
+ rd->tiers[tier]->db_collection_handle =
249
+ rd->tiers[tier]->collect_ops->init(rd->tiers[tier]->db_metric_handle, st->rrdhost->db[tier].tier_grouping * st->update_every);
250
+ }
251
252
+ if(rrddim_flag_check(rd, RRDDIM_FLAG_ARCHIVED)) {
253
rrddim_flag_clear(rd, RRDDIM_FLAG_ARCHIVED);
258
-
254
if(!rrdset_is_ar_chart(st)) {
255
rrddim_flag_set(rd, RRDDIM_FLAG_PENDING_HEALTH_INITIALIZATION);
256
rrdset_flag_set(rd->rrdset, RRDSET_FLAG_PENDING_HEALTH_INITIALIZATION);
@@ -318,6 +313,27 @@ inline RRDDIM *rrddim_find(RRDSET *st, const char *id) {
313
return rrddim_index_find(st, id);
314
}
315
316
+inline RRDDIM_ACQUIRED *rrddim_find_and_acquire(RRDSET *st, const char *id) {
317
+ debug(D_RRD_CALLS, "rrddim_find() for chart %s, dimension %s", rrdset_name(st), id);
318
+
319
+ return (RRDDIM_ACQUIRED *)dictionary_get_and_acquire_item(st->rrddim_root_index, id);
320
+}
321
+
322
+RRDDIM *rrddim_acquired_to_rrddim(RRDDIM_ACQUIRED *rda) {
323
+ if(unlikely(!rda))
324
+ return NULL;
325
+
326
+ return (RRDDIM *) dictionary_acquired_item_value((const DICTIONARY_ITEM *)rda);
327
+}
328
+
329
+void rrddim_acquired_release(RRDDIM_ACQUIRED *rda) {
330
+ if(unlikely(!rda))
331
+ return;
332
+
333
+ RRDDIM *rd = rrddim_acquired_to_rrddim(rda);
334
+ dictionary_acquired_item_release(rd->rrdset->rrddim_root_index, (const DICTIONARY_ITEM *)rda);
335
+}
336
+
337
// This will not return dimensions that are archived
338
RRDDIM *rrddim_find_active(RRDSET *st, const char *id) {
339
RRDDIM *rd = rrddim_find(st, id);
database/rrdset.c
+6
@@ -353,6 +353,8 @@ static void rrdset_react_callback(const DICTIONARY_ITEM *item __maybe_unused, vo
353
RRDSET *st = rrdset;
354
RRDHOST *host = st->rrdhost;
355
356
+ st->last_accessed_time = now_realtime_sec();
357
+
358
if((host->health_enabled && (ctr->react_action & (RRDSET_REACT_NEW | RRDSET_REACT_CHART_ACTIVATED))) && !rrdset_is_ar_chart(st)) {
359
rrdset_flag_set(st, RRDSET_FLAG_PENDING_HEALTH_INITIALIZATION);
360
rrdhost_flag_set(st->rrdhost, RRDHOST_FLAG_PENDING_HEALTH_INITIALIZATION);
@@ -420,6 +422,10 @@ static RRDSET *rrdset_index_find(RRDHOST *host, const char *id) {
422
inline RRDSET *rrdset_find(RRDHOST *host, const char *id) {
423
debug(D_RRD_CALLS, "rrdset_find() for chart '%s' in host '%s'", id, rrdhost_hostname(host));
424
RRDSET *st = rrdset_index_find(host, id);
425
+
426
+ if(st)
427
+ st->last_accessed_time = now_realtime_sec();
428
+
429
return(st);
430
}
431