summaryrefslogtreecommitdiffstats
path: root/database/rrdset.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--database/rrdset.c372
1 files changed, 310 insertions, 62 deletions
diff --git a/database/rrdset.c b/database/rrdset.c
index 0f5297030..d16fe737c 100644
--- a/database/rrdset.c
+++ b/database/rrdset.c
@@ -2,6 +2,7 @@
#define NETDATA_RRD_INTERNALS
#include "rrd.h"
+#include <sched.h>
void __rrdset_check_rdlock(RRDSET *st, const char *file, const char *function, const unsigned long line) {
debug(D_RRD_CALLS, "Checking read lock on chart '%s'", st->id);
@@ -180,10 +181,15 @@ int rrdset_set_name(RRDSET *st, const char *name) {
rrdset_flag_clear(st, RRDSET_FLAG_UPSTREAM_IGNORE);
rrdset_flag_clear(st, RRDSET_FLAG_UPSTREAM_EXPOSED);
- return 1;
+ return 2;
}
inline void rrdset_is_obsolete(RRDSET *st) {
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_ARCHIVED))) {
+ info("Cannot obsolete already archived chart %s", st->name);
+ return;
+ }
+
if(unlikely(!(rrdset_flag_check(st, RRDSET_FLAG_OBSOLETE)))) {
rrdset_flag_set(st, RRDSET_FLAG_OBSOLETE);
rrdset_flag_clear(st, RRDSET_FLAG_UPSTREAM_EXPOSED);
@@ -260,7 +266,7 @@ void rrdset_reset(RRDSET *st) {
rd->collections_counter = 0;
// memset(rd->values, 0, rd->entries * sizeof(storage_number));
#ifdef ENABLE_DBENGINE
- if (RRD_MEMORY_MODE_DBENGINE == st->rrd_memory_mode) {
+ if (RRD_MEMORY_MODE_DBENGINE == st->rrd_memory_mode && !rrddim_flag_check(rd, RRDDIM_FLAG_ARCHIVED)) {
rrdeng_store_metric_flush_current_page(rd);
}
#endif
@@ -314,7 +320,6 @@ void rrdset_free(RRDSET *st) {
rrdhost_check_wrlock(host); // make sure we have a write lock on the host
rrdset_wrlock(st); // lock this RRDSET
-
// info("Removing chart '%s' ('%s')", st->id, st->name);
// ------------------------------------------------------------------------
@@ -328,8 +333,14 @@ void rrdset_free(RRDSET *st) {
// ------------------------------------------------------------------------
// free its children structures
+ freez(st->exporting_flags);
+
while(st->variables) rrdsetvar_free(st->variables);
- while(st->alarms) rrdsetcalc_unlink(st->alarms);
+// while(st->alarms) rrdsetcalc_unlink(st->alarms);
+ /* We must free all connected alarms here in case this has been an ephemeral chart whose alarm was
+ * created by a template. This leads to an effective memory leak, which cannot be detected since the
+ * alarms will still be connected to the host, and freed during shutdown. */
+ while(st->alarms) rrdcalc_unlink_and_free(st->rrdhost, st->alarms);
while(st->dimensions) rrddim_free(st, st->dimensions);
rrdfamily_free(host, st->rrdfamily);
@@ -338,6 +349,11 @@ void rrdset_free(RRDSET *st) {
rrdvar_free_remaining_variables(host, &st->rrdvar_root_index);
// ------------------------------------------------------------------------
+ // remove it from the configuration
+
+ appconfig_section_destroy_non_loaded(&netdata_config, st->config_section);
+
+ // ------------------------------------------------------------------------
// unlink it from the host
if(st == host->rrdset_root) {
@@ -359,11 +375,16 @@ void rrdset_free(RRDSET *st) {
// free it
netdata_rwlock_destroy(&st->rrdset_rwlock);
+ netdata_rwlock_destroy(&st->state->labels.labels_rwlock);
// free directly allocated members
freez(st->config_section);
freez(st->plugin_name);
freez(st->module_name);
+ freez(st->state->old_title);
+ freez(st->state->old_context);
+ free_label_list(st->state->labels.head);
+ freez(st->state);
switch(st->rrd_memory_mode) {
case RRD_MEMORY_MODE_SAVE:
@@ -376,9 +397,14 @@ void rrdset_free(RRDSET *st) {
case RRD_MEMORY_MODE_ALLOC:
case RRD_MEMORY_MODE_NONE:
case RRD_MEMORY_MODE_DBENGINE:
+#ifdef ENABLE_DBENGINE
+ if (st->rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE)
+ freez(st->chart_uuid);
+#endif
freez(st);
break;
}
+
}
void rrdset_save(RRDSET *st) {
@@ -400,9 +426,11 @@ void rrdset_save(RRDSET *st) {
}
}
-void rrdset_delete(RRDSET *st) {
+void rrdset_delete_custom(RRDSET *st, int db_rotated) {
RRDDIM *rd;
-
+#ifndef ENABLE_ACLK
+ UNUSED(db_rotated);
+#endif
rrdset_check_rdlock(st);
info("Deleting chart '%s' ('%s') from disk...", st->id, st->name);
@@ -422,6 +450,13 @@ void rrdset_delete(RRDSET *st) {
}
recursively_delete_dir(st->cache_dir, "left-over chart");
+#ifdef ENABLE_ACLK
+ if ((netdata_cloud_setting) && (db_rotated || RRD_MEMORY_MODE_DBENGINE != st->rrd_memory_mode)) {
+ aclk_del_collector(st->rrdhost, st->plugin_name, st->module_name);
+ aclk_update_chart(st->rrdhost, st->id, ACLK_CMD_CHARTDEL);
+ }
+#endif
+
}
void rrdset_delete_obsolete_dimensions(RRDSET *st) {
@@ -507,23 +542,152 @@ RRDSET *rrdset_create_custom(
char fullid[RRD_ID_LENGTH_MAX + 1];
snprintfz(fullid, RRD_ID_LENGTH_MAX, "%s.%s", type, id);
+ int changed_from_archived_to_active = 0;
RRDSET *st = rrdset_find_on_create(host, fullid);
- if(st) {
+ if (st) {
+ int mark_rebuild = 0;
rrdset_flag_set(st, RRDSET_FLAG_SYNC_CLOCK);
rrdset_flag_clear(st, RRDSET_FLAG_UPSTREAM_EXPOSED);
+ if (rrdset_flag_check(st, RRDSET_FLAG_ARCHIVED)) {
+ rrdset_flag_clear(st, RRDSET_FLAG_ARCHIVED);
+ changed_from_archived_to_active = 1;
+ mark_rebuild |= META_CHART_ACTIVATED;
+ }
+ char *old_plugin = NULL, *old_module = NULL, *old_title = NULL, *old_context = NULL,
+ *old_title_v = NULL, *old_context_v = NULL;
+ int rc;
if(unlikely(name))
- rrdset_set_name(st, name);
+ rc = rrdset_set_name(st, name);
else
- rrdset_set_name(st, id);
+ rc = rrdset_set_name(st, id);
- return st;
+ if (rc == 2)
+ mark_rebuild |= META_CHART_UPDATED;
+
+ if (unlikely(st->priority != priority)) {
+ st->priority = priority;
+ mark_rebuild |= META_CHART_UPDATED;
+ }
+ if (unlikely(st->rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE && st->update_every != update_every)) {
+ st->update_every = update_every;
+ mark_rebuild |= META_CHART_UPDATED;
+ }
+
+ if (plugin && st->plugin_name) {
+ if (unlikely(strcmp(plugin, st->plugin_name))) {
+ old_plugin = st->plugin_name;
+ st->plugin_name = strdupz(plugin);
+ mark_rebuild |= META_PLUGIN_UPDATED;
+ }
+ } else {
+ if (plugin != st->plugin_name) { // one is NULL?
+ old_plugin = st->plugin_name;
+ st->plugin_name = plugin ? strdupz(plugin) : NULL;
+ mark_rebuild |= META_PLUGIN_UPDATED;
+ }
+ }
+
+ if (module && st->module_name) {
+ if (unlikely(strcmp(module, st->module_name))) {
+ old_module = st->module_name;
+ st->module_name = strdupz(module);
+ mark_rebuild |= META_MODULE_UPDATED;
+ }
+ } else {
+ if (module != st->module_name) {
+ if (st->module_name && *st->module_name) {
+ old_module = st->module_name;
+ st->module_name = module ? strdupz(module) : NULL;
+ mark_rebuild |= META_MODULE_UPDATED;
+ }
+ }
+ }
+
+ if (unlikely(title && st->state->old_title && strcmp(st->state->old_title, title))) {
+ char *new_title = strdupz(title);
+ old_title_v = st->state->old_title;
+ st->state->old_title = strdupz(title);
+ json_fix_string(new_title);
+ old_title = st->title;
+ st->title = new_title;
+ mark_rebuild |= META_CHART_UPDATED;
+ }
+
+ RRDSET_TYPE new_chart_type =
+ rrdset_type_id(config_get(st->config_section, "chart type", rrdset_type_name(chart_type)));
+ if (st->chart_type != new_chart_type) {
+ st->chart_type = new_chart_type;
+ mark_rebuild |= META_CHART_UPDATED;
+ }
+
+ if (unlikely(context && st->state->old_context && strcmp(st->state->old_context, context))) {
+ char *new_context = strdupz(context);
+ old_context_v = st->state->old_context;
+ st->state->old_context = strdupz(context);
+ json_fix_string(new_context);
+ old_context = st->context;
+ st->context = new_context;
+ st->hash_context = simple_hash(st->context);
+ mark_rebuild |= META_CHART_UPDATED;
+ }
+
+ if (mark_rebuild) {
+#ifdef ENABLE_ACLK
+ if (netdata_cloud_setting) {
+ if (mark_rebuild & META_CHART_ACTIVATED) {
+ aclk_add_collector(host, st->plugin_name, st->module_name);
+ }
+ else {
+ if (mark_rebuild & (META_PLUGIN_UPDATED | META_MODULE_UPDATED)) {
+ aclk_del_collector(
+ host, mark_rebuild & META_PLUGIN_UPDATED ? old_plugin : st->plugin_name,
+ mark_rebuild & META_MODULE_UPDATED ? old_module : st->module_name);
+ aclk_add_collector(host, st->plugin_name, st->module_name);
+ }
+ }
+ rrdset_flag_set(st, RRDSET_FLAG_ACLK);
+ }
+#endif
+ freez(old_plugin);
+ freez(old_module);
+ freez(old_title);
+ freez(old_context);
+ freez(old_title_v);
+ freez(old_context_v);
+ if (mark_rebuild != META_CHART_ACTIVATED) {
+ info("Collector updated metadata for chart %s", st->id);
+ sched_yield();
+ }
+ }
+#ifdef ENABLE_DBENGINE
+ if (st->rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE &&
+ (mark_rebuild & (META_CHART_UPDATED | META_PLUGIN_UPDATED | META_MODULE_UPDATED))) {
+ debug(D_METADATALOG, "CHART [%s] metadata updated", st->id);
+ int rc = update_chart_metadata(st->chart_uuid, st, id, name);
+ if (unlikely(rc))
+ error_report("Failed to update chart metadata in the database");
+ }
+#endif
+ /* Fall-through during switch from archived to active so that the host lock is taken and health is linked */
+ if (!changed_from_archived_to_active)
+ return st;
}
rrdhost_wrlock(host);
st = rrdset_find_on_create(host, fullid);
if(st) {
+ if (changed_from_archived_to_active) {
+ rrdset_flag_clear(st, RRDSET_FLAG_ARCHIVED);
+ rrdsetvar_create(st, "last_collected_t", RRDVAR_TYPE_TIME_T, &st->last_collected_time.tv_sec, RRDVAR_OPTION_DEFAULT);
+ rrdsetvar_create(st, "collected_total_raw", RRDVAR_TYPE_TOTAL, &st->last_collected_total, RRDVAR_OPTION_DEFAULT);
+ rrdsetvar_create(st, "green", RRDVAR_TYPE_CALCULATED, &st->green, RRDVAR_OPTION_DEFAULT);
+ rrdsetvar_create(st, "red", RRDVAR_TYPE_CALCULATED, &st->red, RRDVAR_OPTION_DEFAULT);
+ rrdsetvar_create(st, "update_every", RRDVAR_TYPE_INT, &st->update_every, RRDVAR_OPTION_DEFAULT);
+ rrdsetcalc_link_matching(st);
+ rrdcalctemplate_link_matching(st);
+ }
rrdhost_unlock(host);
rrdset_flag_set(st, RRDSET_FLAG_SYNC_CLOCK);
rrdset_flag_clear(st, RRDSET_FLAG_UPSTREAM_EXPOSED);
@@ -544,19 +708,21 @@ RRDSET *rrdset_create_custom(
// ------------------------------------------------------------------------
// get the options from the config, we need to create it
- long rentries = config_get_number(config_section, "history", history_entries);
- long entries = align_entries_to_pagesize(memory_mode, rentries);
- if(entries != rentries) entries = config_set_number(config_section, "history", entries);
-
- if(memory_mode == RRD_MEMORY_MODE_NONE && entries != rentries)
- entries = config_set_number(config_section, "history", 10);
-
+ long entries;
+ if(memory_mode == RRD_MEMORY_MODE_DBENGINE) {
+ // only sets it the first time
+ entries = config_get_number(config_section, "history", 5);
+ } else {
+ long rentries = config_get_number(config_section, "history", history_entries);
+ entries = align_entries_to_pagesize(memory_mode, rentries);
+ if (entries != rentries) entries = config_set_number(config_section, "history", entries);
+
+ if (memory_mode == RRD_MEMORY_MODE_NONE && entries != rentries)
+ entries = config_set_number(config_section, "history", 10);
+ }
int enabled = config_get_boolean(config_section, "enabled", 1);
if(!enabled) entries = 5;
- if(memory_mode == RRD_MEMORY_MODE_DBENGINE)
- entries = config_set_number(config_section, "history", 5);
-
unsigned long size = sizeof(RRDSET);
char *cache_dir = rrdset_cache_dir(host, fullid, config_section);
@@ -601,6 +767,7 @@ RRDSET *rrdset_create_custom(
st->variables = NULL;
st->alarms = NULL;
st->flags = 0x00000000;
+ st->exporting_flags = NULL;
if(memory_mode == RRD_MEMORY_MODE_RAM) {
memset(st, 0, size);
@@ -676,6 +843,7 @@ RRDSET *rrdset_create_custom(
st->chart_type = rrdset_type_id(config_get(st->config_section, "chart type", rrdset_type_name(chart_type)));
st->type = config_get(st->config_section, "type", type);
+ st->state = callocz(1, sizeof(*st->state));
st->family = config_get(st->config_section, "family", family?family:st->type);
json_fix_string(st->family);
@@ -683,6 +851,7 @@ RRDSET *rrdset_create_custom(
json_fix_string(st->units);
st->context = config_get(st->config_section, "context", context?context:st->id);
+ st->state->old_context = strdupz(st->context);
json_fix_string(st->context);
st->hash_context = simple_hash(st->context);
@@ -725,6 +894,7 @@ RRDSET *rrdset_create_custom(
avl_init_lock(&st->rrdvar_root_index, rrdvar_compare);
netdata_rwlock_init(&st->rrdset_rwlock);
+ netdata_rwlock_init(&st->state->labels.labels_rwlock);
if(name && *name && rrdset_set_name(st, name))
// we did set the name
@@ -734,6 +904,7 @@ RRDSET *rrdset_create_custom(
rrdset_set_name(st, id);
st->title = config_get(st->config_section, "title", title);
+ st->state->old_title = strdupz(st->title);
json_fix_string(st->title);
st->rrdfamily = rrdfamily_create(host, st->family);
@@ -754,11 +925,24 @@ RRDSET *rrdset_create_custom(
rrdsetcalc_link_matching(st);
rrdcalctemplate_link_matching(st);
+#ifdef ENABLE_DBENGINE
+ if (st->rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE) {
+ st->chart_uuid = find_chart_uuid(host, type, id, name);
+ if (unlikely(!st->chart_uuid))
+ st->chart_uuid = create_chart_uuid(st, id, name);
+
+ store_active_chart(st->chart_uuid);
+ }
+#endif
rrdhost_cleanup_obsolete_charts(host);
rrdhost_unlock(host);
-
+#ifdef ENABLE_ACLK
+ if (netdata_cloud_setting)
+ aclk_add_collector(host, plugin, module);
+ rrdset_flag_set(st, RRDSET_FLAG_ACLK);
+#endif
return(st);
}
@@ -928,34 +1112,6 @@ static inline usec_t rrdset_init_last_updated_time(RRDSET *st) {
return last_updated_ut;
}
-static inline void rrdset_done_push_exclusive(RRDSET *st) {
-// usec_t update_every_ut = st->update_every * USEC_PER_SEC; // st->update_every in microseconds
-//
-// if(unlikely(st->usec_since_last_update > update_every_ut * remote_clock_resync_iterations)) {
-// error("Chart '%s' was last collected %llu usec before. Resetting it.", st->id, st->usec_since_last_update);
-// rrdset_reset(st);
-// st->usec_since_last_update = update_every_ut;
-// }
-
- if(unlikely(!st->last_collected_time.tv_sec)) {
- // it is the first entry
- // set the last_collected_time to now
- rrdset_init_last_collected_time(st);
- }
- else {
- // it is not the first entry
- // calculate the proper last_collected_time, using usec_since_last_update
- rrdset_update_last_collected_time(st);
- }
-
- st->counter_done++;
-
- rrdset_rdlock(st);
- rrdset_done_push(st);
- rrdset_unlock(st);
-}
-
-
static inline size_t rrdset_done_interpolate(
RRDSET *st
, usec_t update_every_ut
@@ -990,6 +1146,9 @@ static inline size_t rrdset_done_interpolate(
last_ut = next_store_ut;
rrddim_foreach_read(rd, st) {
+ if (rrddim_flag_check(rd, RRDDIM_FLAG_ARCHIVED))
+ continue;
+
calculated_number new_value;
switch(rd->algorithm) {
@@ -1198,13 +1357,6 @@ static inline void rrdset_done_fill_the_gap(RRDSET *st) {
void rrdset_done(RRDSET *st) {
if(unlikely(netdata_exit)) return;
- if(unlikely(st->rrd_memory_mode == RRD_MEMORY_MODE_NONE)) {
- if(unlikely(st->rrdhost->rrdpush_send_enabled))
- rrdset_done_push_exclusive(st);
-
- return;
- }
-
debug(D_RRD_CALLS, "rrdset_done() for chart %s", st->name);
RRDDIM *rd;
@@ -1214,10 +1366,10 @@ void rrdset_done(RRDSET *st) {
first_entry = 0; // boolean: 1 = this is the first entry seen for this chart, 0 = all other entries
usec_t
- last_collect_ut, // the timestamp in microseconds, of the last collected value
- now_collect_ut, // the timestamp in microseconds, of this collected value (this is NOW)
- last_stored_ut, // the timestamp in microseconds, of the last stored entry in the db
- next_store_ut, // the timestamp in microseconds, of the next entry to store in the db
+ last_collect_ut = 0, // the timestamp in microseconds, of the last collected value
+ now_collect_ut = 0, // the timestamp in microseconds, of this collected value (this is NOW)
+ last_stored_ut = 0, // the timestamp in microseconds, of the last stored entry in the db
+ next_store_ut = 0, // the timestamp in microseconds, of the next entry to store in the db
update_every_ut = st->update_every * USEC_PER_SEC; // st->update_every in microseconds
netdata_thread_disable_cancelability();
@@ -1225,6 +1377,13 @@ void rrdset_done(RRDSET *st) {
// a read lock is OK here
rrdset_rdlock(st);
+#ifdef ENABLE_ACLK
+ if (unlikely(rrdset_flag_check(st, RRDSET_FLAG_ACLK))) {
+ rrdset_flag_clear(st, RRDSET_FLAG_ACLK);
+ aclk_update_chart(st->rrdhost, st->id, ACLK_CMD_CHART);
+ }
+#endif
+
if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_OBSOLETE))) {
error("Chart '%s' has the OBSOLETE flag set, but it is collected.", st->id);
rrdset_isnot_obsolete(st);
@@ -1232,7 +1391,7 @@ void rrdset_done(RRDSET *st) {
// check if the chart has a long time to be updated
if(unlikely(st->usec_since_last_update > st->entries * update_every_ut &&
- st->rrd_memory_mode != RRD_MEMORY_MODE_DBENGINE)) {
+ st->rrd_memory_mode != RRD_MEMORY_MODE_DBENGINE && st->rrd_memory_mode != RRD_MEMORY_MODE_NONE)) {
info("host '%s', chart %s: took too long to be updated (counter #%zu, update #%zu, %0.3" LONG_DOUBLE_MODIFIER " secs). Resetting it.", st->rrdhost->hostname, st->name, st->counter, st->counter_done, (LONG_DOUBLE)st->usec_since_last_update / USEC_PER_SEC);
rrdset_reset(st);
st->usec_since_last_update = update_every_ut;
@@ -1259,6 +1418,9 @@ void rrdset_done(RRDSET *st) {
// calculate the proper last_collected_time, using usec_since_last_update
last_collect_ut = rrdset_update_last_collected_time(st);
}
+ if (unlikely(st->rrd_memory_mode == RRD_MEMORY_MODE_NONE)) {
+ goto after_first_database_work;
+ }
// if this set has not been updated in the past
// we fake the last_update time to be = now - usec_since_last_update
@@ -1342,10 +1504,14 @@ void rrdset_done(RRDSET *st) {
#endif
}
}
+after_first_database_work:
st->counter_done++;
if(unlikely(st->rrdhost->rrdpush_send_enabled))
rrdset_done_push(st);
+ if (unlikely(st->rrd_memory_mode == RRD_MEMORY_MODE_NONE)) {
+ goto after_second_database_work;
+ }
#ifdef NETDATA_INTERNAL_CHECKS
rrdset_debug(st, "last_collect_ut = %0.3" LONG_DOUBLE_MODIFIER " (last collection time)", (LONG_DOUBLE)last_collect_ut/USEC_PER_SEC);
@@ -1358,6 +1524,8 @@ void rrdset_done(RRDSET *st) {
int dimensions = 0;
st->collected_total = 0;
rrddim_foreach_read(rd, st) {
+ if (rrddim_flag_check(rd, RRDDIM_FLAG_ARCHIVED))
+ continue;
dimensions++;
if(likely(rd->updated))
st->collected_total += rd->collected_value;
@@ -1369,6 +1537,8 @@ void rrdset_done(RRDSET *st) {
// based on the collected figures only
// at this stage we do not interpolate anything
rrddim_foreach_read(rd, st) {
+ if (rrddim_flag_check(rd, RRDDIM_FLAG_ARCHIVED))
+ continue;
if(unlikely(!rd->updated)) {
rd->calculated_value = 0;
@@ -1611,9 +1781,12 @@ void rrdset_done(RRDSET *st) {
, storage_flags
);
+after_second_database_work:
st->last_collected_total = st->collected_total;
rrddim_foreach_read(rd, st) {
+ if (rrddim_flag_check(rd, RRDDIM_FLAG_ARCHIVED))
+ continue;
if(unlikely(!rd->updated))
continue;
@@ -1676,7 +1849,7 @@ void rrdset_done(RRDSET *st) {
// find if there are any obsolete dimensions
time_t now = now_realtime_sec();
- if(unlikely(rrddim_flag_check(st, RRDSET_FLAG_OBSOLETE_DIMENSIONS))) {
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_OBSOLETE_DIMENSIONS))) {
rrddim_foreach_read(rd, st)
if(unlikely(rrddim_flag_check(rd, RRDDIM_FLAG_OBSOLETE)))
break;
@@ -1698,6 +1871,26 @@ void rrdset_done(RRDSET *st) {
error("Cannot delete dimension file '%s'", rd->cache_filename);
}
+#ifdef ENABLE_DBENGINE
+ if (rd->rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE) {
+ rrddim_flag_set(rd, RRDDIM_FLAG_ARCHIVED);
+ while(rd->variables)
+ rrddimvar_free(rd->variables);
+
+ rrddim_flag_clear(rd, RRDDIM_FLAG_OBSOLETE);
+ /* only a collector can mark a chart as obsolete, so we must remove the reference */
+ uint8_t can_delete_metric = rd->state->collect_ops.finalize(rd);
+ if (can_delete_metric) {
+ /* This metric has no data and no references */
+ delete_dimension_uuid(rd->state->metric_uuid);
+ } else {
+ /* Do not delete this dimension */
+ last = rd;
+ rd = rd->next;
+ continue;
+ }
+ }
+#endif
if(unlikely(!last)) {
rrddim_free(st, rd);
rd = st->dimensions;
@@ -1723,3 +1916,58 @@ void rrdset_done(RRDSET *st) {
netdata_thread_enable_cancelability();
}
+
+void rrdset_add_label_to_new_list(RRDSET *st, char *key, char *value, LABEL_SOURCE source)
+{
+ st->state->new_labels = add_label_to_list(st->state->new_labels, key, value, source);
+}
+
+void rrdset_finalize_labels(RRDSET *st)
+{
+ struct label *new_labels = st->state->new_labels;
+ struct label_index *labels = &st->state->labels;
+
+ if (!labels->head) {
+ labels->head = new_labels;
+ } else {
+ replace_label_list(labels, new_labels);
+ }
+ st->state->new_labels = NULL;
+}
+
+void rrdset_update_labels(RRDSET *st, struct label *labels)
+{
+ if (!labels)
+ return;
+
+ update_label_list(&st->state->new_labels, labels);
+ rrdset_finalize_labels(st);
+}
+
+int rrdset_contains_label_keylist(RRDSET *st, char *keylist)
+{
+ struct label_index *labels = &st->state->labels;
+ int ret;
+
+ if (!labels->head)
+ return 0;
+
+ netdata_rwlock_rdlock(&labels->labels_rwlock);
+ ret = label_list_contains_keylist(labels->head, keylist);
+ netdata_rwlock_unlock(&labels->labels_rwlock);
+
+ return ret;
+}
+
+struct label *rrdset_lookup_label_key(RRDSET *st, char *key, uint32_t key_hash)
+{
+ struct label_index *labels = &st->state->labels;
+ struct label *ret = NULL;
+
+ if (labels->head) {
+ netdata_rwlock_rdlock(&labels->labels_rwlock);
+ ret = label_list_lookup_key(labels->head, key, key_hash);
+ netdata_rwlock_unlock(&labels->labels_rwlock);
+ }
+ return ret;
+}