@cryptotaxi247 / netdata-1 / commits / 5e1b95cf9

Deduplicate all netdata strings (#13570)

* rrdfamily * rrddim * rrdset plugin and module names * rrdset units * rrdset type * rrdset family * rrdset title * rrdset title more * rrdset context * rrdcalctemplate context and removal of context hash from rrdset * strings statistics * rrdset name * rearranged members of rrdset * eliminate rrdset name hash; rrdcalc chart converted to STRING * rrdset id, eliminated rrdset hash * rrdcalc, alarm_entry, alert_config and some of rrdcalctemplate * rrdcalctemplate * rrdvar * eval_variable * rrddimvar and rrdsetvar * rrdhost hostname, os and tags * fix master commits * added thread cache; implemented string_dup without locks * faster thread cache * rrdset and rrddim now use dictionaries for indexing * rrdhost now uses dictionary * rrdfamily now uses DICTIONARY * rrdvar using dictionary instead of AVL * allocate the right size to rrdvar flag members * rrdhost remaining char * members to STRING * * better error handling on indexing * strings now use a read/write lock to allow parallel searches to the index * removed AVL support from dictionaries; implemented STRING with native Judy calls * string releases should be negative * only 31 bits are allowed for enum flags * proper locking on strings * string threading unittest and fixes * fix lgtm finding * fixed naming * stream chart/dimension definitions at the beginning of a streaming session * thread stack variable is undefined on thread cancel * rrdcontext garbage collect per host on startup * worker control in garbage collection * relaxed deletion of rrdmetrics * type checking on dictfe * netdata chart to monitor rrdcontext triggers * Group chart label updates * rrdcontext better handling of collected rrdsets * rrdpush incremental transmition of definitions should use as much buffer as possible * require 1MB per chart * empty the sender buffer before enabling metrics streaming * fill up to 50% of buffer * reset signaling metrics sending * use the shared variable for status * use separate host flag for enabling streaming of metrics * make sure the flag is clear * add logging for streaming * add logging for streaming on buffer overflow * circular_buffer proper sizing * removed obsolete logs * do not execute worker jobs if not necessary * better messages about compression disabling * proper use of flags and updating rrdset last access time every time the obsoletion flag is flipped * monitor stream sender used buffer ratio * Update exporting unit tests * no need to compare label value with strcmp * streaming send workers now monitor bandwidth * workers now use strings * streaming receiver monitors incoming bandwidth * parser shift of worker ids * minor fixes * Group chart label updates * Populate context with dimensions that have data * Fix chart id * better shift of parser worker ids * fix for streaming compression * properly count received bytes * ensure LZ4 compression ring buffer does not wrap prematurely * do not stream empty charts; do not process empty instances in rrdcontext * need_to_send_chart_definition() does not need an rrdset lock any more * rrdcontext objects are collected, after data have been written to the db * better logging of RRDCONTEXT transitions * always set all variables needed by the worker utilization charts * implemented double linked list for most objects; eliminated alarm indexes from rrdhost; and many more fixes * lockless strings design - string_dup() and string_freez() are totally lockless when they dont need to touch Judy - only Judy is protected with a read/write lock * STRING code re-organization for clarity * thread_cache improvements; double numbers precision on worker threads * STRING_ENTRY now shadown STRING, so no duplicate definition is required; string_length() renamed to string_strlen() to follow the paradigm of all other functions, STRING internal statistics are now only compiled with NETDATA_INTERNAL_CHECKS * rrdhost index by hostname now cleans up; aclk queries of archieved hosts do not index hosts * Add index to speed up database context searches * Removed last_updated optimization (was also buggy after latest merge with master) Co-authored-by: Stelios Fragkakis <52996999+stelfrag@users.noreply.github.com> Co-authored-by: Vladimir Kobal <vlad@prokk.net>

Costa Tsaousis committed Sep 5, 2022 at 19:31 UTC 5e1b95cf92168c4df74586fb4430dc284806da82
99 files changed +4239 -3436
CMakeLists.txt
+1
@@ -1498,6 +1498,7 @@ if(BUILD_TESTING)
1498 exporting/tests/netdata_doubles.c
1499 exporting/tests/system_doubles.c
1500 database/rrdlabels.c
1501 + database/rrdvar.c
1502 )
1503 set(TEST_NAME exporting_engine)
1504 set(PROMETHEUS_REMOTE_WRITE_LINK_OPTIONS)
Makefile.am
+1
@@ -1252,6 +1252,7 @@ if ENABLE_UNITTESTS
1252 $(EXPORTING_ENGINE_FILES) \
1253 $(LIBNETDATA_FILES) \
1254 database/rrdlabels.c \
1255 + database/rrdvar.c \
1256 $(NULL)
1257 exporting_tests_exporting_engine_testdriver_CFLAGS = \
1258 $(AM_CFLAGS) \
aclk/aclk.c
+5 -5
@@ -762,7 +762,7 @@ void aclk_host_state_update(RRDHOST *host, int cmd)
762 node_instance_creation_t node_instance_creation = {
763 .claim_id = localhost->aclk_state.claimed_id,
764 .hops = host->system_info->hops,
765 - .hostname = host->hostname,
765 + .hostname = rrdhost_hostname(host),
766 .machine_guid = host->machine_guid
767 };
768 create_query->data.bin_payload.payload = generate_node_instance_creation(&create_query->data.bin_payload.size, &node_instance_creation);
@@ -829,7 +829,7 @@ void aclk_send_node_instances()
829 char host_id[UUID_STR_LEN];
830 uuid_unparse_lower(list->host_id, host_id);
831
832 - RRDHOST *host = rrdhost_find_by_guid(host_id, 0);
832 + RRDHOST *host = rrdhost_find_by_guid(host_id);
833 struct capability caps[] = {
834 { .name = "proto", .version = 1, .enabled = 1 },
835 { .name = "ml", .version = ml_capable(localhost), .enabled = host ? ml_enabled(host) : 0 },
@@ -867,7 +867,7 @@ void aclk_send_node_instances()
867 rrdhost_aclk_state_unlock(localhost);
868 info("Queuing registration for host=%s, hops=%d",(char*)node_instance_creation.machine_guid,
869 list->hops);
870 - freez(node_instance_creation.machine_guid);
870 + freez((void *)node_instance_creation.machine_guid);
871 aclk_queue_query(create_query);
872 }
873 freez(list->hostname);
@@ -992,7 +992,7 @@ char *aclk_state(void)
992 RRDHOST *host;
993 rrd_rdlock();
994 rrdhost_foreach_read(host) {
995 - buffer_sprintf(wb, "\n\n> Node Instance for mGUID: \"%s\" hostname \"%s\"\n", host->machine_guid, host->hostname);
995 + buffer_sprintf(wb, "\n\n> Node Instance for mGUID: \"%s\" hostname \"%s\"\n", host->machine_guid, rrdhost_hostname(host));
996
997 buffer_strcat(wb, "\tClaimed ID: ");
998 rrdhost_aclk_state_lock(host);
@@ -1179,7 +1179,7 @@ char *aclk_state_json(void)
1179 rrdhost_foreach_read(host) {
1180 json_object *nodeinstance = json_object_new_object();
1181
1182 - tmp = json_object_new_string(host->hostname);
1182 + tmp = json_object_new_string(rrdhost_hostname(host));
1183 json_object_object_add(nodeinstance, "hostname", tmp);
1184
1185 tmp = json_object_new_string(host->machine_guid);
aclk/aclk_query.c
+2 -4
@@ -38,9 +38,7 @@ static RRDHOST *node_id_2_rrdhost(const char *node_id)
38 int res;
39 uuid_t node_id_bin, host_id_bin;
40
41 - rrd_rdlock();
42 - RRDHOST *host = find_host_by_node_id((char *) node_id);
43 - rrd_unlock();
41 + RRDHOST *host = find_host_by_node_id((char *)node_id);
42 if (host)
43 return host;
44
@@ -54,7 +52,7 @@ static RRDHOST *node_id_2_rrdhost(const char *node_id)
52 return NULL;
53 }
54 uuid_unparse_lower(host_id_bin, host_id);
57 - return rrdhost_find_by_guid(host_id, 0);
55 + return rrdhost_find_by_guid(host_id);
56 }
57
58 #define NODE_ID_QUERY "/node/"
aclk/aclk_rx_msgs.c
+2 -2
@@ -274,7 +274,7 @@ int create_node_instance_result(const char *msg, size_t msg_len)
274 .node_id = res.node_id
275 };
276
277 - RRDHOST *host = rrdhost_find_by_guid(res.machine_guid, 0);
277 + RRDHOST *host = rrdhost_find_by_guid(res.machine_guid);
278 if (host) {
279 // not all host must have RRDHOST struct created for them
280 // if they never connected during runtime of agent
@@ -527,7 +527,7 @@ unsigned int aclk_init_rx_msg_handlers(void)
527 return i;
528 }
529
530 -void aclk_handle_new_cloud_msg(const char *message_type, const char *msg, size_t msg_len, const char *topic)
530 +void aclk_handle_new_cloud_msg(const char *message_type, const char *msg, size_t msg_len, const char *topic __maybe_unused)
531 {
532 if (aclk_stats_enabled) {
533 ACLK_STATS_LOCK;
aclk/schema-wrappers/node_creation.h
+3 -3
@@ -8,9 +8,9 @@ extern "C" {
8 #endif
9
10 typedef struct {
11 - char* claim_id;
12 - char* machine_guid;
13 - char* hostname;
11 + const char *claim_id;
12 + const char *machine_guid;
13 + const char *hostname;
14
15 int32_t hops;
16 } node_instance_creation_t;
aclk/schema-wrappers/node_info.h
+20 -34
@@ -19,41 +19,27 @@ struct machine_learning_info {
19 };
20
21 struct aclk_node_info {
22 - char *name;
23 -
24 - char *os;
25 - char *os_name;
26 - char *os_version;
27 -
28 - char *kernel_name;
29 - char *kernel_version;
30 -
31 - char *architecture;
32 -
22 + const char *name;
23 +
24 + const char *os;
25 + const char *os_name;
26 + const char *os_version;
27 + const char *kernel_name;
28 + const char *kernel_version;
29 + const char *architecture;
30 uint32_t cpus;
34 -
35 - char *cpu_frequency;
36 -
37 - char *memory;
38 -
39 - char *disk_space;
40 -
41 - char *version;
42 -
43 - char *release_channel;
44 -
45 - char *timezone;
46 -
47 - char *virtualization_type;
48 -
49 - char *container_type;
50 -
51 - char *custom_info;
52 -
53 - char *machine_guid;
31 + const char *cpu_frequency;
32 + const char *memory;
33 + const char *disk_space;
34 + const char *version;
35 + const char *release_channel;
36 + const char *timezone;
37 + const char *virtualization_type;
38 + const char *container_type;
39 + const char *custom_info;
40 + const char *machine_guid;
41
42 DICTIONARY *host_labels_ptr;
56 -
43 struct machine_learning_info ml_info;
44 };
45
@@ -72,8 +58,8 @@ struct update_node_info {
58 };
59
60 struct collector_info {
75 - char *module;
76 - char *plugin;
61 + const char *module;
62 + const char *plugin;
63 };
64
65 struct update_node_collectors {
collectors/cgroups.plugin/tests/test_doubles.c
+5
@@ -157,3 +157,8 @@ void sql_store_chart_label(uuid_t *chart_uuid, int source_type, char *label, cha
157 void rrdcalc_update_rrdlabels(RRDSET *st) {
158 (void)st;
159 }
160 +
161 +void db_execute(const char *cmd)
162 +{
163 + UNUSED(cmd);
164 +}
collectors/plugins.d/pluginsd_parser.c
+21 -21
@@ -105,13 +105,13 @@ PARSER_RC pluginsd_variable_action(void *user, RRDHOST *host, RRDSET *st, char *
105 if (rv)
106 rrdvar_custom_host_variable_set(host, rv, value);
107 else
108 - error("cannot find/create HOST VARIABLE '%s' on host '%s'", name, host->hostname);
108 + error("cannot find/create HOST VARIABLE '%s' on host '%s'", name, rrdhost_hostname(host));
109 } else {
110 RRDSETVAR *rs = rrdsetvar_custom_chart_variable_create(st, name);
111 if (rs)
112 rrdsetvar_custom_chart_variable_set(rs, value);
113 else
114 - error("cannot find/create CHART VARIABLE '%s' on host '%s', chart '%s'", name, host->hostname, st->id);
114 + error("cannot find/create CHART VARIABLE '%s' on host '%s', chart '%s'", name, rrdhost_hostname(host), rrdset_id(st));
115 }
116 return PARSER_RC_OK;
117 }
@@ -184,7 +184,7 @@ PARSER_RC pluginsd_clabel_commit_action(void *user, RRDHOST *host, DICTIONARY *n
184 {
185 RRDSET *st = ((PARSER_USER_OBJECT *)user)->st;
186 if (unlikely(!st)) {
187 - error("requested CLABEL_COMMIT on host '%s', without a BEGIN, ignoring it.", host->hostname);
187 + error("requested CLABEL_COMMIT on host '%s', without a BEGIN, ignoring it.", rrdhost_hostname(host));
188 return PARSER_RC_OK;
189 }
190
@@ -215,7 +215,7 @@ PARSER_RC pluginsd_set(char **words, void *user, PLUGINSD_ACTION *plugins_actio
215 RRDHOST *host = ((PARSER_USER_OBJECT *) user)->host;
216
217 if (unlikely(!dimension || !*dimension)) {
218 - error("requested a SET on chart '%s' of host '%s', without a dimension. Disabling it.", st->id, host->hostname);
218 + error("requested a SET on chart '%s' of host '%s', without a dimension. Disabling it.", rrdset_id(st), rrdhost_hostname(host));
219 goto disable;
220 }
221
@@ -225,19 +225,19 @@ PARSER_RC pluginsd_set(char **words, void *user, PLUGINSD_ACTION *plugins_actio
225 if (unlikely(!st)) {
226 error(
227 "requested a SET on dimension %s with value %s on host '%s', without a BEGIN. Disabling it.", dimension,
228 - value ? value : "<nothing>", host->hostname);
228 + value ? value : "<nothing>", rrdhost_hostname(host));
229 goto disable;
230 }
231
232 if (unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
233 - debug(D_PLUGINSD, "is setting dimension %s/%s to %s", st->id, dimension, value ? value : "<nothing>");
233 + debug(D_PLUGINSD, "is setting dimension '%s'/'%s' to '%s'", rrdset_id(st), dimension, value ? value : "<nothing>");
234
235 if (value) {
236 RRDDIM *rd = rrddim_find(st, dimension);
237 if (unlikely(!rd)) {
238 error(
239 "requested a SET to dimension with id '%s' on stats '%s' (%s) on host '%s', which does not exist. Disabling it.",
240 - dimension, st->name, st->id, st->rrdhost->hostname);
240 + dimension, rrdset_name(st), rrdset_id(st), rrdhost_hostname(st->rrdhost));
241 goto disable;
242 } else {
243 if (plugins_action->set_action) {
@@ -262,13 +262,13 @@ PARSER_RC pluginsd_begin(char **words, void *user, PLUGINSD_ACTION *plugins_act
262 RRDHOST *host = ((PARSER_USER_OBJECT *)user)->host;
263
264 if (unlikely(!id)) {
265 - error("requested a BEGIN without a chart id for host '%s'. Disabling it.", host->hostname);
265 + error("requested a BEGIN without a chart id for host '%s'. Disabling it.", rrdhost_hostname(host));
266 goto disable;
267 }
268
269 st = rrdset_find(host, id);
270 if (unlikely(!st)) {
271 - error("requested a BEGIN on chart '%s', which does not exist on host '%s'. Disabling it.", id, host->hostname);
271 + error("requested a BEGIN on chart '%s', which does not exist on host '%s'. Disabling it.", id, rrdhost_hostname(host));
272 goto disable;
273 }
274 ((PARSER_USER_OBJECT *)user)->st = st;
@@ -294,13 +294,13 @@ PARSER_RC pluginsd_end(char **words, void *user, PLUGINSD_ACTION *plugins_actio
294 RRDHOST *host = ((PARSER_USER_OBJECT *) user)->host;
295
296 if (unlikely(!st)) {
297 - error("requested an END, without a BEGIN on host '%s'. Disabling it.", host->hostname);
297 + error("requested an END, without a BEGIN on host '%s'. Disabling it.", rrdhost_hostname(host));
298 ((PARSER_USER_OBJECT *) user)->enabled = 0;
299 return PARSER_RC_ERROR;
300 }
301
302 if (unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
303 - debug(D_PLUGINSD, "requested an END on chart %s", st->id);
303 + debug(D_PLUGINSD, "requested an END on chart '%s'", rrdset_id(st));
304
305 ((PARSER_USER_OBJECT *) user)->st = NULL;
306 ((PARSER_USER_OBJECT *) user)->count++;
@@ -343,7 +343,7 @@ PARSER_RC pluginsd_chart(char **words, void *user, PLUGINSD_ACTION *plugins_act
343 // make sure we have the required variables
344 if (unlikely((!type || !*type || !id || !*id))) {
345 if (likely(host))
346 - error("requested a CHART, without a type.id, on host '%s'. Disabling it.", host->hostname);
346 + error("requested a CHART, without a type.id, on host '%s'. Disabling it.", rrdhost_hostname(host));
347 else
348 error("requested a CHART, without a type.id. Disabling it.");
349 ((PARSER_USER_OBJECT *) user)->enabled = 0;
@@ -424,13 +424,13 @@ PARSER_RC pluginsd_dimension(char **words, void *user, PLUGINSD_ACTION *plugins
424
425 if (unlikely(!id)) {
426 error(
427 - "requested a DIMENSION, without an id, host '%s' and chart '%s'. Disabling it.", host->hostname,
428 - st ? st->id : "UNSET");
427 + "requested a DIMENSION, without an id, host '%s' and chart '%s'. Disabling it.", rrdhost_hostname(host),
428 + st ? rrdset_id(st) : "UNSET");
429 goto disable;
430 }
431
432 if (unlikely(!st && !((PARSER_USER_OBJECT *) user)->st_exists)) {
433 - error("requested a DIMENSION, without a CHART, on host '%s'. Disabling it.", host->hostname);
433 + error("requested a DIMENSION, without a CHART, on host '%s'. Disabling it.", rrdhost_hostname(host));
434 goto disable;
435 }
436
@@ -455,7 +455,7 @@ PARSER_RC pluginsd_dimension(char **words, void *user, PLUGINSD_ACTION *plugins
455 debug(
456 D_PLUGINSD,
457 "creating dimension in chart %s, id='%s', name='%s', algorithm='%s', multiplier=%ld, divisor=%ld, hidden='%s'",
458 - st->id, id, name ? name : "", rrd_algorithm_name(rrd_algorithm_id(algorithm)), multiplier, divisor,
458 + rrdset_id(st), id, name ? name : "", rrd_algorithm_name(rrd_algorithm_id(algorithm)), multiplier, divisor,
459 options ? options : "");
460
461 if (plugins_action->dimension_action) {
@@ -494,7 +494,7 @@ PARSER_RC pluginsd_variable(char **words, void *user, PLUGINSD_ACTION *plugins_
494 }
495
496 if (unlikely(!name || !*name)) {
497 - error("requested a VARIABLE on host '%s', without a variable name. Disabling it.", host->hostname);
497 + error("requested a VARIABLE on host '%s', without a variable name. Disabling it.", rrdhost_hostname(host));
498 ((PARSER_USER_OBJECT *)user)->enabled = 0;
499 return PARSER_RC_ERROR;
500 }
@@ -504,12 +504,12 @@ PARSER_RC pluginsd_variable(char **words, void *user, PLUGINSD_ACTION *plugins_
504
505 if (unlikely(!value)) {
506 error("cannot set %s VARIABLE '%s' on host '%s' to an empty value", (global) ? "HOST" : "CHART", name,
507 - host->hostname);
507 + rrdhost_hostname(host));
508 return PARSER_RC_OK;
509 }
510
511 if (!global && !st) {
512 - error("cannot find/create CHART VARIABLE '%s' on host '%s' without a chart", name, host->hostname);
512 + error("cannot find/create CHART VARIABLE '%s' on host '%s' without a chart", name, rrdhost_hostname(host));
513 return PARSER_RC_OK;
514 }
515
@@ -519,10 +519,10 @@ PARSER_RC pluginsd_variable(char **words, void *user, PLUGINSD_ACTION *plugins_
519 if (endptr == value)
520 error(
521 "the value '%s' of VARIABLE '%s' on host '%s' cannot be parsed as a number", value, name,
522 - host->hostname);
522 + rrdhost_hostname(host));
523 else
524 error(
525 - "the value '%s' of VARIABLE '%s' on host '%s' has leftovers: '%s'", value, name, host->hostname,
525 + "the value '%s' of VARIABLE '%s' on host '%s' has leftovers: '%s'", value, name, rrdhost_hostname(host),
526 endptr);
527 }
528
collectors/proc.plugin/ipc.c
+2 -2
@@ -499,11 +499,11 @@ int do_ipc(int update_every, usec_t dt) {
499 do_msg = CONFIG_BOOLEAN_NO;
500 }
501 else if(unlikely(!message_queue_root)) {
502 - info("Making chart %s (%s) obsolete since it does not have any dimensions", st_msq_messages->name, st_msq_messages->id);
502 + info("Making chart %s (%s) obsolete since it does not have any dimensions", rrdset_name(st_msq_messages), rrdset_id(st_msq_messages));
503 rrdset_is_obsolete(st_msq_messages);
504 st_msq_messages = NULL;
505
506 - info("Making chart %s (%s) obsolete since it does not have any dimensions", st_msq_bytes->name, st_msq_bytes->id);
506 + info("Making chart %s (%s) obsolete since it does not have any dimensions", rrdset_name(st_msq_bytes), rrdset_id(st_msq_bytes));
507 rrdset_is_obsolete(st_msq_bytes);
508 st_msq_bytes = NULL;
509 }
collectors/proc.plugin/proc_interrupts.c
+1 -1
@@ -173,7 +173,7 @@ int do_proc_interrupts(int update_every, usec_t dt) {
173 // some interrupt may have changed without changing the total number of lines
174 // if the same number of interrupts have been added and removed between two
175 // calls of this function.
176 - if(unlikely(!irr->rd || strncmp(irr->rd->name, irr->name, MAX_INTERRUPT_NAME) != 0)) {
176 + if(unlikely(!irr->rd || strncmp(rrddim_name(irr->rd), irr->name, MAX_INTERRUPT_NAME) != 0)) {
177 irr->rd = rrddim_add(st_system_interrupts, irr->id, irr->name, 1, 1, RRD_ALGORITHM_INCREMENTAL);
178 rrddim_set_name(st_system_interrupts, irr->rd, irr->name);
179
collectors/proc.plugin/proc_softirqs.c
+1 -1
@@ -153,7 +153,7 @@ int do_proc_softirqs(int update_every, usec_t dt) {
153 // some interrupt may have changed without changing the total number of lines
154 // if the same number of interrupts have been added and removed between two
155 // calls of this function.
156 - if(unlikely(!irr->rd || strncmp(irr->name, irr->rd->name, MAX_INTERRUPT_NAME) != 0)) {
156 + if(unlikely(!irr->rd || strncmp(irr->name, rrddim_name(irr->rd), MAX_INTERRUPT_NAME) != 0)) {
157 irr->rd = rrddim_add(st_system_softirqs, irr->id, irr->name, 1, 1, RRD_ALGORITHM_INCREMENTAL);
158 rrddim_set_name(st_system_softirqs, irr->rd, irr->name);
159
collectors/statsd.plugin/statsd.c
+1 -1
@@ -2228,7 +2228,7 @@ static inline void statsd_update_app_chart(STATSD_APP *app, STATSD_APP_CHART *ch
2228 statsd_add_dim_to_app_chart(app, chart, dim);
2229
2230 if (unlikely(dim->value_ptr)) {
2231 - debug(D_STATSD, "updating dimension '%s' (%s) of chart '%s' (%s) for app '%s' with value " COLLECTED_NUMBER_FORMAT, dim->name, dim->rd->id, chart->id, chart->st->id, app->name, *dim->value_ptr);
2231 + debug(D_STATSD, "updating dimension '%s' (%s) of chart '%s' (%s) for app '%s' with value " COLLECTED_NUMBER_FORMAT, dim->name, rrddim_id(dim->rd), chart->id, rrdset_id(chart->st), app->name, *dim->value_ptr);
2232 rrddim_set_by_pointer(chart->st, dim->rd, *dim->value_ptr);
2233 }
2234 }
daemon/analytics.c
+8 -6
@@ -10,8 +10,8 @@ extern void analytics_build_info (BUFFER *b);
10 extern int aclk_connected;
11
12 struct collector {
13 - char *plugin;
14 - char *module;
13 + const char *plugin;
14 + const char *module;
15 };
16
17 struct array_printer {
@@ -286,8 +286,10 @@ void analytics_collectors(void)
286 rrdset_foreach_read(st, localhost)
287 {
288 if (rrdset_is_available_for_viewers(st)) {
289 - struct collector col = { .plugin = st->plugin_name ? st->plugin_name : "",
290 - .module = st->module_name ? st->module_name : "" };
289 + struct collector col = {
290 + .plugin = rrdset_plugin_name(st),
291 + .module = rrdset_module_name(st)
292 + };
293 snprintfz(name, 499, "%s:%s", col.plugin, col.module);
294 dictionary_set(dict, name, &col, sizeof(struct collector));
295 }
@@ -441,7 +443,7 @@ void analytics_alarms(void)
443 int alarm_warn = 0, alarm_crit = 0, alarm_normal = 0;
444 char b[10];
445 RRDCALC *rc;
444 - for (rc = localhost->alarms; rc; rc = rc->next) {
446 + foreach_rrdcalc_in_rrdhost(localhost, rc) {
447 if (unlikely(!rc->rrdset || !rc->rrdset->last_collected_time.tv_sec))
448 continue;
449
@@ -539,7 +541,7 @@ void analytics_gather_mutable_meta_data(void)
541 analytics_alarms_notifications();
542
543 analytics_set_data(
542 - &analytics_data.netdata_config_is_parent, (localhost->next || configured_as_parent()) ? "true" : "false");
544 + &analytics_data.netdata_config_is_parent, (rrdhost_hosts_available() > 1 || configured_as_parent()) ? "true" : "false");
545
546 char *claim_id = get_agent_claimid();
547 analytics_set_data(&analytics_data.netdata_host_agent_claimed, claim_id ? "true" : "false");
daemon/global_statistics.c
+357 -26
@@ -9,8 +9,9 @@
9 #define WORKER_JOB_WORKERS 2
10 #define WORKER_JOB_DBENGINE 3
11 #define WORKER_JOB_HEARTBEAT 4
12 +#define WORKER_JOB_STRINGS 5
13
13 -#if WORKER_UTILIZATION_MAX_JOB_TYPES < 5
14 +#if WORKER_UTILIZATION_MAX_JOB_TYPES < 6
15 #error WORKER_UTILIZATION_MAX_JOB_TYPES has to be at least 5
16 #endif
17
@@ -38,6 +39,10 @@ static struct global_statistics {
39 volatile uint64_t sqlite3_queries_failed_locked;
40 volatile uint64_t sqlite3_rows;
41
42 + volatile uint64_t rrdcontext_metric_triggers;
43 + volatile uint64_t rrdcontext_instance_triggers;
44 + volatile uint64_t rrdcontext_context_triggers;
45 +
46 } global_statistics = {
47 .connected_clients = 0,
48 .web_requests = 0,
@@ -80,6 +85,18 @@ void rrdr_query_completed(uint64_t db_points_read, uint64_t result_points_genera
85 __atomic_fetch_add(&global_statistics.rrdr_result_points_generated, result_points_generated, __ATOMIC_RELAXED);
86 }
87
88 +void rrdcontext_triggered_update_on_rrdmetric() {
89 + __atomic_fetch_add(&global_statistics.rrdcontext_metric_triggers, 1, __ATOMIC_RELAXED);
90 +}
91 +
92 +void rrdcontext_triggered_update_on_rrdinstance() {
93 + __atomic_fetch_add(&global_statistics.rrdcontext_instance_triggers, 1, __ATOMIC_RELAXED);
94 +}
95 +
96 +void rrdcontext_triggered_update_on_rrdcontext() {
97 + __atomic_fetch_add(&global_statistics.rrdcontext_context_triggers, 1, __ATOMIC_RELAXED);
98 +}
99 +
100 void finished_web_request_statistics(uint64_t dt,
101 uint64_t bytes_received,
102 uint64_t bytes_sent,
@@ -133,6 +150,10 @@ static inline void global_statistics_copy(struct global_statistics *gs, uint8_t
150 gs->sqlite3_queries_failed_busy = __atomic_load_n(&global_statistics.sqlite3_queries_failed_busy, __ATOMIC_RELAXED);
151 gs->sqlite3_queries_failed_locked = __atomic_load_n(&global_statistics.sqlite3_queries_failed_locked, __ATOMIC_RELAXED);
152 gs->sqlite3_rows = __atomic_load_n(&global_statistics.sqlite3_rows, __ATOMIC_RELAXED);
153 +
154 + gs->rrdcontext_metric_triggers = __atomic_load_n(&global_statistics.rrdcontext_metric_triggers, __ATOMIC_RELAXED);
155 + gs->rrdcontext_instance_triggers = __atomic_load_n(&global_statistics.rrdcontext_instance_triggers, __ATOMIC_RELAXED);
156 + gs->rrdcontext_context_triggers = __atomic_load_n(&global_statistics.rrdcontext_context_triggers, __ATOMIC_RELAXED);
157 }
158
159 static void global_statistics_charts(void) {
@@ -579,6 +600,42 @@ static void global_statistics_charts(void) {
600
601 rrdset_done(st_sqlite3_rows);
602 }
603 +
604 + // ----------------------------------------------------------------
605 +
606 + if(gs.rrdcontext_context_triggers || gs.rrdcontext_instance_triggers || gs.rrdcontext_metric_triggers) {
607 + static RRDSET *st_rrdcontext_triggers = NULL;
608 + static RRDDIM *rd_context = NULL, *rd_instance = NULL, *rd_metric = NULL;
609 +
610 + if (unlikely(!st_rrdcontext_triggers)) {
611 + st_rrdcontext_triggers = rrdset_create_localhost(
612 + "netdata"
613 + , "rrdcontext_triggers"
614 + , NULL
615 + , "rrdcontext"
616 + , NULL
617 + , "Netdata RRD context triggers"
618 + , "triggers/s"
619 + , "netdata"
620 + , "stats"
621 + , 131200
622 + , localhost->rrd_update_every
623 + , RRDSET_TYPE_LINE
624 + );
625 +
626 + rd_metric = rrddim_add(st_rrdcontext_triggers, "metric", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
627 + rd_instance = rrddim_add(st_rrdcontext_triggers, "instance", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
628 + rd_context = rrddim_add(st_rrdcontext_triggers, "context", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
629 + }
630 + else
631 + rrdset_next(st_rrdcontext_triggers);
632 +
633 + rrddim_set_by_pointer(st_rrdcontext_triggers, rd_metric, (collected_number)gs.rrdcontext_metric_triggers);
634 + rrddim_set_by_pointer(st_rrdcontext_triggers, rd_instance, (collected_number)gs.rrdcontext_instance_triggers);
635 + rrddim_set_by_pointer(st_rrdcontext_triggers, rd_context, (collected_number)gs.rrdcontext_context_triggers);
636 +
637 + rrdset_done(st_rrdcontext_triggers);
638 + }
639 }
640
641 static void dbengine_statistics_charts(void) {
@@ -988,6 +1045,93 @@ static void dbengine_statistics_charts(void) {
1045 #endif
1046 }
1047
1048 +static void update_strings_charts() {
1049 + static RRDSET *st_ops = NULL, *st_entries = NULL, *st_mem = NULL;
1050 + static RRDDIM *rd_ops_inserts = NULL, *rd_ops_deletes = NULL, *rd_ops_searches = NULL, *rd_ops_duplications = NULL, *rd_ops_releases = NULL;
1051 + static RRDDIM *rd_entries_entries = NULL, *rd_entries_refs = NULL;
1052 + static RRDDIM *rd_mem = NULL;
1053 +
1054 + size_t inserts, deletes, searches, entries, references, memory, duplications, releases;
1055 +
1056 + string_statistics(&inserts, &deletes, &searches, &entries, &references, &memory, &duplications, &releases);
1057 +
1058 + if (unlikely(!st_ops)) {
1059 + st_ops = rrdset_create_localhost(
1060 + "netdata"
1061 + , "strings_ops"
1062 + , NULL
1063 + , "strings"
1064 + , NULL
1065 + , "Strings operations"
1066 + , "ops/s"
1067 + , "netdata"
1068 + , "stats"
1069 + , 910000
1070 + , localhost->rrd_update_every
1071 + , RRDSET_TYPE_LINE);
1072 +
1073 + rd_ops_inserts = rrddim_add(st_ops, "inserts", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1074 + rd_ops_deletes = rrddim_add(st_ops, "deletes", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
1075 + rd_ops_searches = rrddim_add(st_ops, "searches", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1076 + rd_ops_duplications = rrddim_add(st_ops, "duplications", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1077 + rd_ops_releases = rrddim_add(st_ops, "releases", NULL, -1, 1, RRD_ALGORITHM_INCREMENTAL);
1078 + } else
1079 + rrdset_next(st_ops);
1080 +
1081 + rrddim_set_by_pointer(st_ops, rd_ops_inserts, (collected_number)inserts);
1082 + rrddim_set_by_pointer(st_ops, rd_ops_deletes, (collected_number)deletes);
1083 + rrddim_set_by_pointer(st_ops, rd_ops_searches, (collected_number)searches);
1084 + rrddim_set_by_pointer(st_ops, rd_ops_duplications, (collected_number)duplications);
1085 + rrddim_set_by_pointer(st_ops, rd_ops_releases, (collected_number)releases);
1086 + rrdset_done(st_ops);
1087 +
1088 + if (unlikely(!st_entries)) {
1089 + st_entries = rrdset_create_localhost(
1090 + "netdata"
1091 + , "strings_entries"
1092 + , NULL
1093 + , "strings"
1094 + , NULL
1095 + , "Strings entries"
1096 + , "entries"
1097 + , "netdata"
1098 + , "stats"
1099 + , 910001
1100 + , localhost->rrd_update_every
1101 + , RRDSET_TYPE_AREA);
1102 +
1103 + rd_entries_entries = rrddim_add(st_entries, "entries", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
1104 + rd_entries_refs = rrddim_add(st_entries, "references", NULL, 1, -1, RRD_ALGORITHM_ABSOLUTE);
1105 + } else
1106 + rrdset_next(st_entries);
1107 +
1108 + rrddim_set_by_pointer(st_entries, rd_entries_entries, (collected_number)entries);
1109 + rrddim_set_by_pointer(st_entries, rd_entries_refs, (collected_number)references);
1110 + rrdset_done(st_entries);
1111 +
1112 + if (unlikely(!st_mem)) {
1113 + st_mem = rrdset_create_localhost(
1114 + "netdata"
1115 + , "strings_memory"
1116 + , NULL
1117 + , "strings"
1118 + , NULL
1119 + , "Strings memory"
1120 + , "bytes"
1121 + , "netdata"
1122 + , "stats"
1123 + , 910001
1124 + , localhost->rrd_update_every
1125 + , RRDSET_TYPE_AREA);
1126 +
1127 + rd_mem = rrddim_add(st_mem, "memory", NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
1128 + } else
1129 + rrdset_next(st_mem);
1130 +
1131 + rrddim_set_by_pointer(st_mem, rd_mem, (collected_number)memory);
1132 + rrdset_done(st_mem);
1133 +}
1134 +
1135 static void update_heartbeat_charts() {
1136 static RRDSET *st_heartbeat = NULL;
1137 static RRDDIM *rd_heartbeat_min = NULL;
@@ -1032,13 +1176,26 @@ static void update_heartbeat_charts() {
1176
1177 #define WORKERS_MIN_PERCENT_DEFAULT 10000.0
1178
1035 -struct worker_job_type {
1036 - char name[WORKER_UTILIZATION_MAX_JOB_NAME_LENGTH + 1];
1179 +struct worker_job_type_gs {
1180 + STRING *name;
1181 + STRING *units;
1182 +
1183 size_t jobs_started;
1184 usec_t busy_time;
1185
1186 RRDDIM *rd_jobs_started;
1187 RRDDIM *rd_busy_time;
1188 +
1189 + WORKER_METRIC_TYPE type;
1190 + NETDATA_DOUBLE min_value;
1191 + NETDATA_DOUBLE max_value;
1192 + NETDATA_DOUBLE sum_value;
1193 + size_t count_value;
1194 +
1195 + RRDSET *st;
1196 + RRDDIM *rd_min;
1197 + RRDDIM *rd_max;
1198 + RRDDIM *rd_avg;
1199 };
1200
1201 struct worker_thread {
@@ -1071,7 +1228,7 @@ struct worker_utilization {
1228
1229 char *name_lowercase;
1230
1074 - struct worker_job_type per_job_type[WORKER_UTILIZATION_MAX_JOB_TYPES];
1231 + struct worker_job_type_gs per_job_type[WORKER_UTILIZATION_MAX_JOB_TYPES];
1232
1233 size_t workers_registered;
1234 size_t workers_busy;
@@ -1170,14 +1327,16 @@ static void workers_total_cpu_utilization_chart(void) {
1327 if(!wu->workers_cpu_registered) continue;
1328
1329 if(!wu->rd_total_cpu_utilizaton)
1173 - wu->rd_total_cpu_utilizaton = rrddim_add(st, wu->name_lowercase, NULL, 1, 10000ULL, RRD_ALGORITHM_ABSOLUTE);
1330 + wu->rd_total_cpu_utilizaton = rrddim_add(st, wu->name_lowercase, NULL, 1, 100, RRD_ALGORITHM_ABSOLUTE);
1331
1175 - rrddim_set_by_pointer(st, wu->rd_total_cpu_utilizaton, (collected_number)((double)wu->workers_cpu_total * 10000.0));
1332 + rrddim_set_by_pointer(st, wu->rd_total_cpu_utilizaton, (collected_number)((double)wu->workers_cpu_total * 100.0));
1333 }
1334
1335 rrdset_done(st);
1336 }
1337
1338 +#define WORKER_CHART_DECIMAL_PRECISION 100
1339 +
1340 static void workers_utilization_update_chart(struct worker_utilization *wu) {
1341 if(!wu->workers_registered) return;
1342
@@ -1215,28 +1374,28 @@ static void workers_utilization_update_chart(struct worker_utilization *wu) {
1374 // we add the min and max dimensions only when we have multiple workers
1375
1376 if(unlikely(!wu->rd_workers_time_min && wu->workers_registered > 1))
1218 - wu->rd_workers_time_min = rrddim_add(wu->st_workers_time, "min", NULL, 1, 10000, RRD_ALGORITHM_ABSOLUTE);
1377 + wu->rd_workers_time_min = rrddim_add(wu->st_workers_time, "min", NULL, 1, WORKER_CHART_DECIMAL_PRECISION, RRD_ALGORITHM_ABSOLUTE);
1378
1379 if(unlikely(!wu->rd_workers_time_max && wu->workers_registered > 1))
1221 - wu->rd_workers_time_max = rrddim_add(wu->st_workers_time, "max", NULL, 1, 10000, RRD_ALGORITHM_ABSOLUTE);
1380 + wu->rd_workers_time_max = rrddim_add(wu->st_workers_time, "max", NULL, 1, WORKER_CHART_DECIMAL_PRECISION, RRD_ALGORITHM_ABSOLUTE);
1381
1382 if(unlikely(!wu->rd_workers_time_avg))
1224 - wu->rd_workers_time_avg = rrddim_add(wu->st_workers_time, "average", NULL, 1, 10000, RRD_ALGORITHM_ABSOLUTE);
1383 + wu->rd_workers_time_avg = rrddim_add(wu->st_workers_time, "average", NULL, 1, WORKER_CHART_DECIMAL_PRECISION, RRD_ALGORITHM_ABSOLUTE);
1384
1385 rrdset_next(wu->st_workers_time);
1386
1387 if(unlikely(wu->workers_min_busy_time == WORKERS_MIN_PERCENT_DEFAULT)) wu->workers_min_busy_time = 0.0;
1388
1389 if(wu->rd_workers_time_min)
1231 - rrddim_set_by_pointer(wu->st_workers_time, wu->rd_workers_time_min, (collected_number)((double)wu->workers_min_busy_time * 10000.0));
1390 + rrddim_set_by_pointer(wu->st_workers_time, wu->rd_workers_time_min, (collected_number)((double)wu->workers_min_busy_time * WORKER_CHART_DECIMAL_PRECISION));
1391
1392 if(wu->rd_workers_time_max)
1234 - rrddim_set_by_pointer(wu->st_workers_time, wu->rd_workers_time_max, (collected_number)((double)wu->workers_max_busy_time * 10000.0));
1393 + rrddim_set_by_pointer(wu->st_workers_time, wu->rd_workers_time_max, (collected_number)((double)wu->workers_max_busy_time * WORKER_CHART_DECIMAL_PRECISION));
1394
1395 if(wu->workers_total_duration == 0)
1396 rrddim_set_by_pointer(wu->st_workers_time, wu->rd_workers_time_avg, 0);
1397 else
1239 - rrddim_set_by_pointer(wu->st_workers_time, wu->rd_workers_time_avg, (collected_number)((double)wu->workers_total_busy_time * 100.0 * 10000.0 / (double)wu->workers_total_duration));
1398 + rrddim_set_by_pointer(wu->st_workers_time, wu->rd_workers_time_avg, (collected_number)((double)wu->workers_total_busy_time * 100.0 * WORKER_CHART_DECIMAL_PRECISION / (double)wu->workers_total_duration));
1399
1400 rrdset_done(wu->st_workers_time);
1401
@@ -1268,28 +1427,28 @@ static void workers_utilization_update_chart(struct worker_utilization *wu) {
1427 }
1428
1429 if (unlikely(!wu->rd_workers_cpu_min && wu->workers_registered > 1))
1271 - wu->rd_workers_cpu_min = rrddim_add(wu->st_workers_cpu, "min", NULL, 1, 10000ULL, RRD_ALGORITHM_ABSOLUTE);
1430 + wu->rd_workers_cpu_min = rrddim_add(wu->st_workers_cpu, "min", NULL, 1, WORKER_CHART_DECIMAL_PRECISION, RRD_ALGORITHM_ABSOLUTE);
1431
1432 if (unlikely(!wu->rd_workers_cpu_max && wu->workers_registered > 1))
1274 - wu->rd_workers_cpu_max = rrddim_add(wu->st_workers_cpu, "max", NULL, 1, 10000ULL, RRD_ALGORITHM_ABSOLUTE);
1433 + wu->rd_workers_cpu_max = rrddim_add(wu->st_workers_cpu, "max", NULL, 1, WORKER_CHART_DECIMAL_PRECISION, RRD_ALGORITHM_ABSOLUTE);
1434
1435 if(unlikely(!wu->rd_workers_cpu_avg))
1277 - wu->rd_workers_cpu_avg = rrddim_add(wu->st_workers_cpu, "average", NULL, 1, 10000ULL, RRD_ALGORITHM_ABSOLUTE);
1436 + wu->rd_workers_cpu_avg = rrddim_add(wu->st_workers_cpu, "average", NULL, 1, WORKER_CHART_DECIMAL_PRECISION, RRD_ALGORITHM_ABSOLUTE);
1437
1438 rrdset_next(wu->st_workers_cpu);
1439
1440 if(unlikely(wu->workers_cpu_min == WORKERS_MIN_PERCENT_DEFAULT)) wu->workers_cpu_min = 0.0;
1441
1442 if(wu->rd_workers_cpu_min)
1284 - rrddim_set_by_pointer(wu->st_workers_cpu, wu->rd_workers_cpu_min, (collected_number)(wu->workers_cpu_min * 10000ULL));
1443 + rrddim_set_by_pointer(wu->st_workers_cpu, wu->rd_workers_cpu_min, (collected_number)(wu->workers_cpu_min * WORKER_CHART_DECIMAL_PRECISION));
1444
1445 if(wu->rd_workers_cpu_max)
1287 - rrddim_set_by_pointer(wu->st_workers_cpu, wu->rd_workers_cpu_max, (collected_number)(wu->workers_cpu_max * 10000ULL));
1446 + rrddim_set_by_pointer(wu->st_workers_cpu, wu->rd_workers_cpu_max, (collected_number)(wu->workers_cpu_max * WORKER_CHART_DECIMAL_PRECISION));
1447
1448 if(wu->workers_cpu_registered == 0)
1449 rrddim_set_by_pointer(wu->st_workers_cpu, wu->rd_workers_cpu_avg, 0);
1450 else
1292 - rrddim_set_by_pointer(wu->st_workers_cpu, wu->rd_workers_cpu_avg, (collected_number)( wu->workers_cpu_total * 10000ULL / (NETDATA_DOUBLE)wu->workers_cpu_registered ));
1451 + rrddim_set_by_pointer(wu->st_workers_cpu, wu->rd_workers_cpu_avg, (collected_number)( wu->workers_cpu_total * WORKER_CHART_DECIMAL_PRECISION / (NETDATA_DOUBLE)wu->workers_cpu_registered ));
1452
1453 rrdset_done(wu->st_workers_cpu);
1454 }
@@ -1325,10 +1484,13 @@ static void workers_utilization_update_chart(struct worker_utilization *wu) {
1484 {
1485 size_t i;
1486 for(i = 0; i < WORKER_UTILIZATION_MAX_JOB_TYPES ;i++) {
1328 - if (wu->per_job_type[i].name[0]) {
1487 + if(unlikely(wu->per_job_type[i].type != WORKER_METRIC_IDLE_BUSY))
1488 + continue;
1489 +
1490 + if (wu->per_job_type[i].name) {
1491
1492 if(unlikely(!wu->per_job_type[i].rd_jobs_started))
1331 - wu->per_job_type[i].rd_jobs_started = rrddim_add(wu->st_workers_jobs_per_job_type, wu->per_job_type[i].name, NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
1493 + wu->per_job_type[i].rd_jobs_started = rrddim_add(wu->st_workers_jobs_per_job_type, string2str(wu->per_job_type[i].name), NULL, 1, 1, RRD_ALGORITHM_ABSOLUTE);
1494
1495 rrddim_set_by_pointer(wu->st_workers_jobs_per_job_type, wu->per_job_type[i].rd_jobs_started, (collected_number)(wu->per_job_type[i].jobs_started));
1496 }
@@ -1367,10 +1529,13 @@ static void workers_utilization_update_chart(struct worker_utilization *wu) {
1529 {
1530 size_t i;
1531 for(i = 0; i < WORKER_UTILIZATION_MAX_JOB_TYPES ;i++) {
1370 - if (wu->per_job_type[i].name[0]) {
1532 + if(unlikely(wu->per_job_type[i].type != WORKER_METRIC_IDLE_BUSY))
1533 + continue;
1534 +
1535 + if (wu->per_job_type[i].name) {
1536
1537 if(unlikely(!wu->per_job_type[i].rd_busy_time))
1373 - wu->per_job_type[i].rd_busy_time = rrddim_add(wu->st_workers_busy_per_job_type, wu->per_job_type[i].name, NULL, 1, USEC_PER_MS, RRD_ALGORITHM_ABSOLUTE);
1538 + wu->per_job_type[i].rd_busy_time = rrddim_add(wu->st_workers_busy_per_job_type, string2str(wu->per_job_type[i].name), NULL, 1, USEC_PER_MS, RRD_ALGORITHM_ABSOLUTE);
1539
1540 rrddim_set_by_pointer(wu->st_workers_busy_per_job_type, wu->per_job_type[i].rd_busy_time, (collected_number)(wu->per_job_type[i].busy_time));
1541 }
@@ -1414,6 +1579,122 @@ static void workers_utilization_update_chart(struct worker_utilization *wu) {
1579 rrddim_set_by_pointer(wu->st_workers_threads, wu->rd_workers_threads_busy, (collected_number)(wu->workers_busy));
1580 rrdset_done(wu->st_workers_threads);
1581 }
1582 +
1583 + // ----------------------------------------------------------------------
1584 + // custom metric types WORKER_METRIC_ABSOLUTE
1585 +
1586 + {
1587 + size_t i;
1588 + for (i = 0; i < WORKER_UTILIZATION_MAX_JOB_TYPES; i++) {
1589 + if(wu->per_job_type[i].type != WORKER_METRIC_ABSOLUTE)
1590 + continue;
1591 +
1592 + if(!wu->per_job_type[i].count_value)
1593 + continue;
1594 +
1595 + if(!wu->per_job_type[i].st) {
1596 + size_t job_name_len = string_strlen(wu->per_job_type[i].name);
1597 + if(job_name_len > RRD_ID_LENGTH_MAX) job_name_len = RRD_ID_LENGTH_MAX;
1598 +
1599 + char job_name_sanitized[job_name_len + 1];
1600 + rrdset_strncpyz_name(job_name_sanitized, string2str(wu->per_job_type[i].name), job_name_len);
1601 +
1602 + char name[RRD_ID_LENGTH_MAX + 1];
1603 + snprintfz(name, RRD_ID_LENGTH_MAX, "workers_%s_value_%s", wu->name_lowercase, job_name_sanitized);
1604 +
1605 + char context[RRD_ID_LENGTH_MAX + 1];
1606 + snprintf(context, RRD_ID_LENGTH_MAX, "netdata.workers.%s.value.%s", wu->name_lowercase, job_name_sanitized);
1607 +
1608 + char title[1000 + 1];
1609 + snprintf(title, 1000, "Netdata Workers %s Value of %s", wu->name_lowercase, string2str(wu->per_job_type[i].name));
1610 +
1611 + wu->per_job_type[i].st = rrdset_create_localhost(
1612 + "netdata"
1613 + , name
1614 + , NULL
1615 + , wu->family
1616 + , context
1617 + , title
1618 + , (wu->per_job_type[i].units)?string2str(wu->per_job_type[i].units):"value"
1619 + , "netdata"
1620 + , "stats"
1621 + , wu->priority + 5
1622 + , localhost->rrd_update_every
1623 + , RRDSET_TYPE_LINE
1624 + );
1625 +
1626 + wu->per_job_type[i].rd_min = rrddim_add(wu->per_job_type[i].st, "min", NULL, 1, WORKER_CHART_DECIMAL_PRECISION, RRD_ALGORITHM_ABSOLUTE);
1627 + wu->per_job_type[i].rd_max = rrddim_add(wu->per_job_type[i].st, "max", NULL, 1, WORKER_CHART_DECIMAL_PRECISION, RRD_ALGORITHM_ABSOLUTE);
1628 + wu->per_job_type[i].rd_avg = rrddim_add(wu->per_job_type[i].st, "average", NULL, 1, WORKER_CHART_DECIMAL_PRECISION, RRD_ALGORITHM_ABSOLUTE);
1629 + }
1630 + else
1631 + rrdset_next(wu->per_job_type[i].st);
1632 +
1633 + rrddim_set_by_pointer(wu->per_job_type[i].st, wu->per_job_type[i].rd_min, (collected_number)(wu->per_job_type[i].min_value * WORKER_CHART_DECIMAL_PRECISION));
1634 + rrddim_set_by_pointer(wu->per_job_type[i].st, wu->per_job_type[i].rd_max, (collected_number)(wu->per_job_type[i].max_value * WORKER_CHART_DECIMAL_PRECISION));
1635 + rrddim_set_by_pointer(wu->per_job_type[i].st, wu->per_job_type[i].rd_avg, (collected_number)(wu->per_job_type[i].sum_value / wu->per_job_type[i].count_value * WORKER_CHART_DECIMAL_PRECISION));
1636 +
1637 + rrdset_done(wu->per_job_type[i].st);
1638 + }
1639 + }
1640 +
1641 + // ----------------------------------------------------------------------
1642 + // custom metric types WORKER_METRIC_INCREMENTAL
1643 +
1644 + {
1645 + size_t i;
1646 + for (i = 0; i < WORKER_UTILIZATION_MAX_JOB_TYPES; i++) {
1647 + if(wu->per_job_type[i].type != WORKER_METRIC_INCREMENTAL)
1648 + continue;
1649 +
1650 + if(!wu->per_job_type[i].count_value)
1651 + continue;
1652 +
1653 + if(!wu->per_job_type[i].st) {
1654 + size_t job_name_len = string_strlen(wu->per_job_type[i].name);
1655 + if(job_name_len > RRD_ID_LENGTH_MAX) job_name_len = RRD_ID_LENGTH_MAX;
1656 +
1657 + char job_name_sanitized[job_name_len + 1];
1658 + rrdset_strncpyz_name(job_name_sanitized, string2str(wu->per_job_type[i].name), job_name_len);
1659 +
1660 + char name[RRD_ID_LENGTH_MAX + 1];
1661 + snprintfz(name, RRD_ID_LENGTH_MAX, "workers_%s_rate_%s", wu->name_lowercase, job_name_sanitized);
1662 +
1663 + char context[RRD_ID_LENGTH_MAX + 1];
1664 + snprintf(context, RRD_ID_LENGTH_MAX, "netdata.workers.%s.rate.%s", wu->name_lowercase, job_name_sanitized);
1665 +
1666 + char title[1000 + 1];
1667 + snprintf(title, 1000, "Netdata Workers %s Rate of %s", wu->name_lowercase, string2str(wu->per_job_type[i].name));
1668 +
1669 + wu->per_job_type[i].st = rrdset_create_localhost(
1670 + "netdata"
1671 + , name
1672 + , NULL
1673 + , wu->family
1674 + , context
1675 + , title
1676 + , (wu->per_job_type[i].units)?string2str(wu->per_job_type[i].units):"rate"
1677 + , "netdata"
1678 + , "stats"
1679 + , wu->priority + 5
1680 + , localhost->rrd_update_every
1681 + , RRDSET_TYPE_LINE
1682 + );
1683 +
1684 + wu->per_job_type[i].rd_min = rrddim_add(wu->per_job_type[i].st, "min", NULL, 1, WORKER_CHART_DECIMAL_PRECISION, RRD_ALGORITHM_ABSOLUTE);
1685 + wu->per_job_type[i].rd_max = rrddim_add(wu->per_job_type[i].st, "max", NULL, 1, WORKER_CHART_DECIMAL_PRECISION, RRD_ALGORITHM_ABSOLUTE);
1686 + wu->per_job_type[i].rd_avg = rrddim_add(wu->per_job_type[i].st, "average", NULL, 1, WORKER_CHART_DECIMAL_PRECISION, RRD_ALGORITHM_ABSOLUTE);
1687 + }
1688 + else
1689 + rrdset_next(wu->per_job_type[i].st);
1690 +
1691 + rrddim_set_by_pointer(wu->per_job_type[i].st, wu->per_job_type[i].rd_min, (collected_number)(wu->per_job_type[i].min_value * WORKER_CHART_DECIMAL_PRECISION));
1692 + rrddim_set_by_pointer(wu->per_job_type[i].st, wu->per_job_type[i].rd_max, (collected_number)(wu->per_job_type[i].max_value * WORKER_CHART_DECIMAL_PRECISION));
1693 + rrddim_set_by_pointer(wu->per_job_type[i].st, wu->per_job_type[i].rd_avg, (collected_number)(wu->per_job_type[i].sum_value / wu->per_job_type[i].count_value * WORKER_CHART_DECIMAL_PRECISION));
1694 +
1695 + rrdset_done(wu->per_job_type[i].st);
1696 + }
1697 + }
1698 }
1699
1700 static void workers_utilization_reset_statistics(struct worker_utilization *wu) {
@@ -1440,6 +1721,11 @@ static void workers_utilization_reset_statistics(struct worker_utilization *wu)
1721
1722 wu->per_job_type[i].jobs_started = 0;
1723 wu->per_job_type[i].busy_time = 0;
1724 +
1725 + wu->per_job_type[i].min_value = NAN;
1726 + wu->per_job_type[i].max_value = NAN;
1727 + wu->per_job_type[i].sum_value = NAN;
1728 + wu->per_job_type[i].count_value = 0;
1729 }
1730
1731 struct worker_thread *wt;
@@ -1522,7 +1808,20 @@ static struct worker_thread *worker_thread_find_or_create(struct worker_utilizat
1808 return wt;
1809 }
1810
1525 -static void worker_utilization_charts_callback(void *ptr, pid_t pid __maybe_unused, const char *thread_tag __maybe_unused, size_t utilization_usec __maybe_unused, size_t duration_usec __maybe_unused, size_t jobs_started __maybe_unused, size_t is_running __maybe_unused, const char **job_types_names __maybe_unused, size_t *job_types_jobs_started __maybe_unused, usec_t *job_types_busy_time __maybe_unused) {
1811 +static void worker_utilization_charts_callback(void *ptr
1812 + , pid_t pid __maybe_unused
1813 + , const char *thread_tag __maybe_unused
1814 + , size_t utilization_usec __maybe_unused
1815 + , size_t duration_usec __maybe_unused
1816 + , size_t jobs_started __maybe_unused
1817 + , size_t is_running __maybe_unused
1818 + , STRING **job_types_names __maybe_unused
1819 + , STRING **job_types_units __maybe_unused
1820 + , WORKER_METRIC_TYPE *job_types_metric_types __maybe_unused
1821 + , size_t *job_types_jobs_started __maybe_unused
1822 + , usec_t *job_types_busy_time __maybe_unused
1823 + , NETDATA_DOUBLE *job_types_custom_metrics __maybe_unused
1824 + ) {
1825 struct worker_utilization *wu = (struct worker_utilization *)ptr;
1826
1827 // find the worker_thread in the list
@@ -1552,12 +1851,32 @@ static void worker_utilization_charts_callback(void *ptr, pid_t pid __maybe_unus
1851 // accumulate per job type statistics
1852 size_t i;
1853 for(i = 0; i < WORKER_UTILIZATION_MAX_JOB_TYPES ;i++) {
1854 + if(!wu->per_job_type[i].name && job_types_names[i])
1855 + wu->per_job_type[i].name = string_dup(job_types_names[i]);
1856 +
1857 + if(!wu->per_job_type[i].units && job_types_units[i])
1858 + wu->per_job_type[i].units = string_dup(job_types_units[i]);
1859 +
1860 + wu->per_job_type[i].type = job_types_metric_types[i];
1861 +
1862 wu->per_job_type[i].jobs_started += job_types_jobs_started[i];
1863 wu->per_job_type[i].busy_time += job_types_busy_time[i];
1864
1558 - // new job type found
1559 - if(unlikely(!wu->per_job_type[i].name[0] && job_types_names[i]))
1560 - strncpyz(wu->per_job_type[i].name, job_types_names[i], WORKER_UTILIZATION_MAX_JOB_NAME_LENGTH);
1865 + NETDATA_DOUBLE value = job_types_custom_metrics[i];
1866 + if(netdata_double_isnumber(value)) {
1867 + if(!wu->per_job_type[i].count_value) {
1868 + wu->per_job_type[i].count_value = 1;
1869 + wu->per_job_type[i].min_value = value;
1870 + wu->per_job_type[i].max_value = value;
1871 + wu->per_job_type[i].sum_value = value;
1872 + }
1873 + else {
1874 + wu->per_job_type[i].count_value++;
1875 + wu->per_job_type[i].sum_value += value;
1876 + if(value < wu->per_job_type[i].min_value) wu->per_job_type[i].min_value = value;
1877 + if(value > wu->per_job_type[i].max_value) wu->per_job_type[i].max_value = value;
1878 + }
1879 + }
1880 }
1881
1882 // find its CPU utilization
@@ -1607,6 +1926,14 @@ static void worker_utilization_finish(void) {
1926 wu->name_lowercase = NULL;
1927 }
1928
1929 + for(i = 0; i < WORKER_UTILIZATION_MAX_JOB_TYPES ;i++) {
1930 + string_freez(wu->per_job_type[i].name);
1931 + wu->per_job_type[i].name = NULL;
1932 +
1933 + string_freez(wu->per_job_type[i].units);
1934 + wu->per_job_type[i].units = NULL;
1935 + }
1936 +
1937 // mark all threads as not enabled
1938 struct worker_thread *t;
1939 for(t = wu->threads; t ; t = t->next) t->enabled = 0;
@@ -1639,6 +1966,7 @@ void *global_statistics_main(void *ptr)
1966 worker_register_job_name(WORKER_JOB_REGISTRY, "registry");
1967 worker_register_job_name(WORKER_JOB_WORKERS, "workers");
1968 worker_register_job_name(WORKER_JOB_DBENGINE, "dbengine");
1969 + worker_register_job_name(WORKER_JOB_STRINGS, "strings");
1970
1971 netdata_thread_cleanup_push(global_statistics_cleanup, ptr);
1972
@@ -1673,6 +2001,9 @@ void *global_statistics_main(void *ptr)
2001
2002 worker_is_busy(WORKER_JOB_HEARTBEAT);
2003 update_heartbeat_charts();
2004 +
2005 + worker_is_busy(WORKER_JOB_STRINGS);
2006 + update_strings_charts();
2007 }
2008
2009 netdata_thread_cleanup_pop(1);
daemon/global_statistics.h
+4
@@ -12,6 +12,10 @@ extern void rrdr_query_completed(uint64_t db_points_read, uint64_t result_points
12 extern void sqlite3_query_completed(bool success, bool busy, bool locked);
13 extern void sqlite3_row_completed(void);
14
15 +extern void rrdcontext_triggered_update_on_rrdmetric(void);
16 +extern void rrdcontext_triggered_update_on_rrdinstance(void);
17 +extern void rrdcontext_triggered_update_on_rrdcontext(void);
18 +
19 extern void finished_web_request_statistics(uint64_t dt,
20 uint64_t bytes_received,
21 uint64_t bytes_sent,
daemon/unit_test.c
+31 -31
@@ -1197,12 +1197,12 @@ int run_test(struct test *test)
1197 fprintf(stderr, " > %s: feeding position %lu\n", test->name, c+1);
1198 }
1199
1200 - fprintf(stderr, " >> %s with value " COLLECTED_NUMBER_FORMAT "\n", rd->name, test->feed[c].value);
1200 + fprintf(stderr, " >> %s with value " COLLECTED_NUMBER_FORMAT "\n", rrddim_name(rd), test->feed[c].value);
1201 rrddim_set(st, "dim1", test->feed[c].value);
1202 last = test->feed[c].value;
1203
1204 if(rd2) {
1205 - fprintf(stderr, " >> %s with value " COLLECTED_NUMBER_FORMAT "\n", rd2->name, test->feed2[c]);
1205 + fprintf(stderr, " >> %s with value " COLLECTED_NUMBER_FORMAT "\n", rrddim_name(rd2), test->feed2[c]);
1206 rrddim_set(st, "dim2", test->feed2[c]);
1207 }
1208
@@ -1231,7 +1231,7 @@ int run_test(struct test *test)
1231 int same = (roundndd(v * 10000000.0) == roundndd(n * 10000000.0))?1:0;
1232 fprintf(stderr, " %s/%s: checking position %lu (at %"PRId64" secs), expecting value " NETDATA_DOUBLE_FORMAT
1233 ", found " NETDATA_DOUBLE_FORMAT ", %s\n",
1234 - test->name, rd->name, c+1,
1234 + test->name, rrddim_name(rd), c+1,
1235 (int64_t)((rrdset_first_entry_t(st) + c * st->update_every) - time_start),
1236 n, v, (same)?"OK":"### E R R O R ###");
1237
@@ -1243,7 +1243,7 @@ int run_test(struct test *test)
1243 same = (roundndd(v * 10000000.0) == roundndd(n * 10000000.0))?1:0;
1244 fprintf(stderr, " %s/%s: checking position %lu (at %"PRId64" secs), expecting value " NETDATA_DOUBLE_FORMAT
1245 ", found " NETDATA_DOUBLE_FORMAT ", %s\n",
1246 - test->name, rd2->name, c+1,
1246 + test->name, rrddim_name(rd2), c+1,
1247 (int64_t)((rrdset_first_entry_t(st) + c * st->update_every) - time_start),
1248 n, v, (same)?"OK":"### E R R O R ###");
1249 if(!same) errors++;
@@ -1258,39 +1258,39 @@ static int test_variable_renames(void) {
1258
1259 fprintf(stderr, "Creating chart\n");
1260 RRDSET *st = rrdset_create_localhost("chart", "ID", NULL, "family", "context", "Unit Testing", "a value", "unittest", NULL, 1, 1, RRDSET_TYPE_LINE);
1261 - fprintf(stderr, "Created chart with id '%s', name '%s'\n", st->id, st->name);
1261 + fprintf(stderr, "Created chart with id '%s', name '%s'\n", rrdset_id(st), rrdset_name(st));
1262
1263 fprintf(stderr, "Creating dimension DIM1\n");
1264 RRDDIM *rd1 = rrddim_add(st, "DIM1", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1265 - fprintf(stderr, "Created dimension with id '%s', name '%s'\n", rd1->id, rd1->name);
1265 + fprintf(stderr, "Created dimension with id '%s', name '%s'\n", rrddim_id(rd1), rrddim_name(rd1));
1266
1267 fprintf(stderr, "Creating dimension DIM2\n");
1268 RRDDIM *rd2 = rrddim_add(st, "DIM2", NULL, 1, 1, RRD_ALGORITHM_INCREMENTAL);
1269 - fprintf(stderr, "Created dimension with id '%s', name '%s'\n", rd2->id, rd2->name);
1269 + fprintf(stderr, "Created dimension with id '%s', name '%s'\n", rrddim_id(rd2), rrddim_name(rd2));
1270
1271 fprintf(stderr, "Renaming chart to CHARTNAME1\n");
1272 rrdset_set_name(st, "CHARTNAME1");
1273 - fprintf(stderr, "Renamed chart with id '%s' to name '%s'\n", st->id, st->name);
1273 + fprintf(stderr, "Renamed chart with id '%s' to name '%s'\n", rrdset_id(st), rrdset_name(st));
1274
1275 fprintf(stderr, "Renaming chart to CHARTNAME2\n");
1276 rrdset_set_name(st, "CHARTNAME2");
1277 - fprintf(stderr, "Renamed chart with id '%s' to name '%s'\n", st->id, st->name);
1277 + fprintf(stderr, "Renamed chart with id '%s' to name '%s'\n", rrdset_id(st), rrdset_name(st));
1278
1279 fprintf(stderr, "Renaming dimension DIM1 to DIM1NAME1\n");
1280 rrddim_set_name(st, rd1, "DIM1NAME1");
1281 - fprintf(stderr, "Renamed dimension with id '%s' to name '%s'\n", rd1->id, rd1->name);
1281 + fprintf(stderr, "Renamed dimension with id '%s' to name '%s'\n", rrddim_id(rd1), rrddim_name(rd1));
1282
1283 fprintf(stderr, "Renaming dimension DIM1 to DIM1NAME2\n");
1284 rrddim_set_name(st, rd1, "DIM1NAME2");
1285 - fprintf(stderr, "Renamed dimension with id '%s' to name '%s'\n", rd1->id, rd1->name);
1285 + fprintf(stderr, "Renamed dimension with id '%s' to name '%s'\n", rrddim_id(rd1), rrddim_name(rd1));
1286
1287 fprintf(stderr, "Renaming dimension DIM2 to DIM2NAME1\n");
1288 rrddim_set_name(st, rd2, "DIM2NAME1");
1289 - fprintf(stderr, "Renamed dimension with id '%s' to name '%s'\n", rd2->id, rd2->name);
1289 + fprintf(stderr, "Renamed dimension with id '%s' to name '%s'\n", rrddim_id(rd2), rrddim_name(rd2));
1290
1291 fprintf(stderr, "Renaming dimension DIM2 to DIM2NAME2\n");
1292 rrddim_set_name(st, rd2, "DIM2NAME2");
1293 - fprintf(stderr, "Renamed dimension with id '%s' to name '%s'\n", rd2->id, rd2->name);
1293 + fprintf(stderr, "Renamed dimension with id '%s' to name '%s'\n", rrddim_id(rd2), rrddim_name(rd2));
1294
1295 BUFFER *buf = buffer_create(1);
1296 health_api_v1_chart_variables2json(st, buf);
@@ -1449,7 +1449,7 @@ int unit_test(long delay, long shift)
1449
1450 unsigned long c, dimensions = 0;
1451 RRDDIM *rd;
1452 - for(rd = st->dimensions ; rd ; rd = rd->next) dimensions++;
1452 + for(rd = st->dimensions; rd ; rd = rd->next) dimensions++;
1453
1454 for(c = 0; c < 20 ;c++) {
1455 i += increment;
@@ -1470,7 +1470,7 @@ int unit_test(long delay, long shift)
1470 }
1471
1472 // prevent it from deleting the dimensions
1473 - for(rd = st->dimensions ; rd ; rd = rd->next)
1473 + for(rd = st->dimensions; rd ; rd = rd->next)
1474 rd->last_collected_time.tv_sec = st->last_collected_time.tv_sec;
1475
1476 rrdset_done(st);
@@ -1486,10 +1486,10 @@ int unit_test(long delay, long shift)
1486 for(c = 0 ; c < st->counter ; c++) {
1487 fprintf(stderr, "\nPOSITION: c = %lu, EXPECTED VALUE %lu\n", c, (oincrement + c * increment + increment * (1000000 - shift) / 1000000 )* 10);
1488
1489 - for(rd = st->dimensions ; rd ; rd = rd->next) {
1489 + for(rd = st->dimensions; rd ; rd = rd->next) {
1490 sn = rd->db[c];
1491 cn = unpack_storage_number(sn);
1492 - fprintf(stderr, "\t %s " NETDATA_DOUBLE_FORMAT " (PACKED AS " STORAGE_NUMBER_FORMAT ") -> ", rd->id, cn, sn);
1492 + fprintf(stderr, "\t %s " NETDATA_DOUBLE_FORMAT " (PACKED AS " STORAGE_NUMBER_FORMAT ") -> ", rrddim_id(rd), cn, sn);
1493
1494 if(rd == rdabs) v =
1495 ( oincrement
@@ -1909,14 +1909,14 @@ static int test_dbengine_check_metrics(RRDSET *st[CHARTS], RRDDIM *rd[CHARTS][DI
1909 if(!value_errors)
1910 fprintf(stderr, " DB-engine unittest %s/%s: at %lu secs, expecting value " NETDATA_DOUBLE_FORMAT
1911 ", found " NETDATA_DOUBLE_FORMAT ", ### E R R O R ###\n",
1912 - st[i]->name, rd[i][j]->name, (unsigned long)time_now + k * update_every, expected, value);
1912 + rrdset_name(st[i]), rrddim_name(rd[i][j]), (unsigned long)time_now + k * update_every, expected, value);
1913 value_errors++;
1914 errors++;
1915 }
1916 if(end_time != time_now + k * update_every) {
1917 if(!time_errors)
1918 fprintf(stderr, " DB-engine unittest %s/%s: at %lu secs, found timestamp %lu ### E R R O R ###\n",
1919 - st[i]->name, rd[i][j]->name, (unsigned long)time_now + k * update_every, (unsigned long)time_retrieved);
1919 + rrdset_name(st[i]), rrddim_name(rd[i][j]), (unsigned long)time_now + k * update_every, (unsigned long)time_retrieved);
1920 time_errors++;
1921 errors++;
1922 }
@@ -1957,7 +1957,7 @@ static int test_dbengine_check_rrdr(RRDSET *st[CHARTS], RRDDIM *rd[CHARTS][DIMS]
1957 NULL, NULL, NULL, 0, 0);
1958
1959 if (!r) {
1960 - fprintf(stderr, " DB-engine unittest %s: empty RRDR on region %d ### E R R O R ###\n", st[i]->name, current_region);
1960 + fprintf(stderr, " DB-engine unittest %s: empty RRDR on region %d ### E R R O R ###\n", rrdset_name(st[i]), current_region);
1961 return ++errors;
1962 } else {
1963 assert(r->st == st[i]);
@@ -1967,7 +1967,7 @@ static int test_dbengine_check_rrdr(RRDSET *st[CHARTS], RRDDIM *rd[CHARTS][DIMS]
1967 time_retrieved = r->t[c];
1968
1969 // for each dimension
1970 - for (j = 0, d = r->st->dimensions ; d && j < r->d ; ++j, d = d->next) {
1970 + for (j = 0, d = r->st->dimensions; d && j < r->d ; ++j, d = d->next) {
1971 NETDATA_DOUBLE *cn = &r->v[ c * r->d ];
1972 value = cn[j];
1973 assert(rd[i][j] == d);
@@ -1980,13 +1980,13 @@ static int test_dbengine_check_rrdr(RRDSET *st[CHARTS], RRDDIM *rd[CHARTS][DIMS]
1980 if(value_errors < 20)
1981 fprintf(stderr, " DB-engine unittest %s/%s: at %lu secs, expecting value " NETDATA_DOUBLE_FORMAT
1982 ", RRDR found " NETDATA_DOUBLE_FORMAT ", ### E R R O R ###\n",
1983 - st[i]->name, rd[i][j]->name, (unsigned long)time_now, expected, value);
1983 + rrdset_name(st[i]), rrddim_name(rd[i][j]), (unsigned long)time_now, expected, value);
1984 value_errors++;
1985 }
1986 if(time_retrieved != time_now) {
1987 if(time_errors < 20)
1988 fprintf(stderr, " DB-engine unittest %s/%s: at %lu secs, found RRDR timestamp %lu ### E R R O R ###\n",
1989 - st[i]->name, rd[i][j]->name, (unsigned long)time_now, (unsigned long)time_retrieved);
1989 + rrdset_name(st[i]), rrddim_name(rd[i][j]), (unsigned long)time_now, (unsigned long)time_retrieved);
1990 time_errors++;
1991 }
1992 }
@@ -2090,7 +2090,7 @@ int test_dbengine(void)
2090 time_end[REGIONS - 1], RRDR_GROUPING_AVERAGE, 0,
2091 RRDR_OPTION_NATURAL_POINTS, NULL, NULL, NULL, 0, 0);
2092 if (!r) {
2093 - fprintf(stderr, " DB-engine unittest %s: empty RRDR ### E R R O R ###\n", st[i]->name);
2093 + fprintf(stderr, " DB-engine unittest %s: empty RRDR ### E R R O R ###\n", rrdset_name(st[i]));
2094 ++errors;
2095 } else {
2096 long c;
@@ -2103,7 +2103,7 @@ int test_dbengine(void)
2103 time_t time_retrieved = r->t[c];
2104
2105 // for each dimension
2106 - for(j = 0, d = r->st->dimensions ; d && j < r->d ; ++j, d = d->next) {
2106 + for(j = 0, d = r->st->dimensions; d && j < r->d ; ++j, d = d->next) {
2107 NETDATA_DOUBLE *cn = &r->v[ c * r->d ];
2108 NETDATA_DOUBLE value = cn[j];
2109 assert(rd[i][j] == d);
@@ -2116,13 +2116,13 @@ int test_dbengine(void)
2116 if(!value_errors)
2117 fprintf(stderr, " DB-engine unittest %s/%s: at %lu secs, expecting value " NETDATA_DOUBLE_FORMAT
2118 ", RRDR found " NETDATA_DOUBLE_FORMAT ", ### E R R O R ###\n",
2119 - st[i]->name, rd[i][j]->name, (unsigned long)time_now, expected, value);
2119 + rrdset_name(st[i]), rrddim_name(rd[i][j]), (unsigned long)time_now, expected, value);
2120 value_errors++;
2121 }
2122 if(time_retrieved != time_now) {
2123 if(!time_errors)
2124 fprintf(stderr, " DB-engine unittest %s/%s: at %lu secs, found RRDR timestamp %lu ### E R R O R ###\n",
2125 - st[i]->name, rd[i][j]->name, (unsigned long)time_now, (unsigned long)time_retrieved);
2125 + rrdset_name(st[i]), rrddim_name(rd[i][j]), (unsigned long)time_now, (unsigned long)time_retrieved);
2126 time_errors++;
2127 }
2128 }
@@ -2350,7 +2350,7 @@ static void query_dbengine_chart(void *arg)
2350 if (!thread_info->delete_old_data) { /* data validation only when we don't delete */
2351 fprintf(stderr, " DB-engine stresstest %s/%s: at %lu secs, expecting value " NETDATA_DOUBLE_FORMAT
2352 ", found data gap, ### E R R O R ###\n",
2353 - st->name, rd->name, (unsigned long) time_now, expected);
2353 + rrdset_name(st), rrddim_name(rd), (unsigned long) time_now, expected);
2354 ++thread_info->errors;
2355 }
2356 break;
@@ -2365,7 +2365,7 @@ static void query_dbengine_chart(void *arg)
2365 if (!thread_info->delete_old_data) { /* data validation only when we don't delete */
2366 fprintf(stderr, " DB-engine stresstest %s/%s: at %lu secs, expecting value " NETDATA_DOUBLE_FORMAT
2367 ", found data gap, ### E R R O R ###\n",
2368 - st->name, rd->name, (unsigned long) time_now, expected);
2368 + rrdset_name(st), rrddim_name(rd), (unsigned long) time_now, expected);
2369 ++thread_info->errors;
2370 }
2371 break;
@@ -2378,7 +2378,7 @@ static void query_dbengine_chart(void *arg)
2378 if(!value_errors)
2379 fprintf(stderr, " DB-engine stresstest %s/%s: at %lu secs, expecting value " NETDATA_DOUBLE_FORMAT
2380 ", found " NETDATA_DOUBLE_FORMAT ", ### E R R O R ###\n",
2381 - st->name, rd->name, (unsigned long) time_now, expected, value);
2381 + rrdset_name(st), rrddim_name(rd), (unsigned long) time_now, expected, value);
2382 value_errors++;
2383 thread_info->errors++;
2384 }
@@ -2388,7 +2388,7 @@ static void query_dbengine_chart(void *arg)
2388 if(!time_errors)
2389 fprintf(stderr,
2390 " DB-engine stresstest %s/%s: at %lu secs, found timestamp %lu ### E R R O R ###\n",
2391 - st->name, rd->name, (unsigned long) time_now, (unsigned long) time_retrieved);
2391 + rrdset_name(st), rrddim_name(rd), (unsigned long) time_now, (unsigned long) time_retrieved);
2392 time_errors++;
2393 thread_info->errors++;
2394 }
database/engine/metadata_log/metalogpluginsd.c
+2 -2
@@ -12,11 +12,11 @@ PARSER_RC metalog_pluginsd_host_action(
12 {
13 struct metalog_pluginsd_state *state = ((PARSER_USER_OBJECT *)user)->private;
14
15 - RRDHOST *host = rrdhost_find_by_guid(machine_guid, 0);
15 + RRDHOST *host = rrdhost_find_by_guid(machine_guid);
16 if (host) {
17 if (unlikely(host->rrd_memory_mode != RRD_MEMORY_MODE_DBENGINE)) {
18 error("Archived host '%s' has memory mode '%s', but the archived one is '%s'. Ignoring archived state.",
19 - host->hostname, rrd_memory_mode_name(host->rrd_memory_mode),
19 + rrdhost_hostname(host), rrd_memory_mode_name(host->rrd_memory_mode),
20 rrd_memory_mode_name(RRD_MEMORY_MODE_DBENGINE));
21 ((PARSER_USER_OBJECT *) user)->host = NULL; /* Ignore objects if memory mode is not dbengine */
22 }
database/engine/rrdengineapi.c
+2 -3
@@ -98,7 +98,7 @@ STORAGE_METRIC_HANDLE *rrdeng_metric_init(RRDDIM *rd, STORAGE_INSTANCE *db_insta
98
99 pg_cache = &ctx->pg_cache;
100
101 - rrdeng_generate_legacy_uuid(rd->id, rd->rrdset->id, &legacy_uuid);
101 + rrdeng_generate_legacy_uuid(rrddim_id(rd), (char *)rrdset_id(rd->rrdset), &legacy_uuid);
102 if (host != localhost && is_storage_engine_shared((STORAGE_INSTANCE *)ctx))
103 is_multihost_child = 1;
104
@@ -138,8 +138,7 @@ STORAGE_METRIC_HANDLE *rrdeng_metric_init(RRDDIM *rd, STORAGE_INSTANCE *db_insta
138 uuid_copy(rd->metric_uuid, multihost_legacy_uuid);
139
140 if (unlikely(need_to_store && !ctx->tier))
141 - (void)sql_store_dimension(&rd->metric_uuid, rd->rrdset->chart_uuid, rd->id, rd->name, rd->multiplier, rd->divisor,
142 - rd->algorithm);
141 + (void)sql_store_dimension(&rd->metric_uuid, rd->rrdset->chart_uuid, rrddim_id(rd), rrddim_name(rd), rd->multiplier, rd->divisor, rd->algorithm);
142 }
143
144 struct rrdeng_metric_handle *mh = mallocz(sizeof(struct rrdeng_metric_handle));
database/ram/rrddim_mem.c
+4 -4
@@ -91,7 +91,7 @@ static inline size_t rrddim_time2slot(RRDDIM *rd, time_t t) {
91 }
92
93 if(unlikely(ret >= entries)) {
94 - error("INTERNAL ERROR: rrddim_time2slot() on %s returns values outside entries", rd->name);
94 + error("INTERNAL ERROR: rrddim_time2slot() on %s returns values outside entries", rrddim_name(rd));
95 ret = entries - 1;
96 }
97
@@ -119,12 +119,12 @@ static inline time_t rrddim_slot2time(RRDDIM *rd, size_t slot) {
119 ret = last_entry_t - (time_t)(update_every * (last_slot - slot));
120
121 if(unlikely(ret < first_entry_t)) {
122 - error("INTERNAL ERROR: rrddim_slot2time() on %s returns time too far in the past", rd->name);
122 + error("INTERNAL ERROR: rrddim_slot2time() on %s returns time too far in the past", rrddim_name(rd));
123 ret = first_entry_t;
124 }
125
126 if(unlikely(ret > last_entry_t)) {
127 - error("INTERNAL ERROR: rrddim_slot2time() on %s returns time into the future", rd->name);
127 + error("INTERNAL ERROR: rrddim_slot2time() on %s returns time into the future", rrddim_name(rd));
128 ret = last_entry_t;
129 }
130
@@ -206,7 +206,7 @@ int rrddim_query_is_finished(struct rrddim_query_handle *handle) {
206 void rrddim_query_finalize(struct rrddim_query_handle *handle) {
207 #ifdef NETDATA_INTERNAL_CHECKS
208 if(!rrddim_query_is_finished(handle))
209 - error("QUERY: query for chart '%s' dimension '%s' has been stopped unfinished", handle->rd->rrdset->id, handle->rd->name);
209 + error("QUERY: query for chart '%s' dimension '%s' has been stopped unfinished", rrdset_id(handle->rd->rrdset), rrddim_name(handle->rd));
210 #endif
211 freez(handle->handle);
212 }
database/rrd.c
+12
@@ -154,3 +154,15 @@ char *rrdset_cache_dir(RRDHOST *host, const char *id) {
154 return ret;
155 }
156
157 +// ----------------------------------------------------------------------------
158 +// RRD - string management
159 +
160 +STRING *rrd_string_strdupz(const char *s) {
161 + if(unlikely(!s || !*s)) return string_strdupz(s);
162 +
163 + char *tmp = strdupz(s);
164 + json_fix_string(tmp);
165 + STRING *ret = string_strdupz(tmp);
166 + freez(tmp);
167 + return ret;
168 +}
database/rrd.h
+164 -185
@@ -160,14 +160,10 @@ extern const char *rrd_algorithm_name(RRD_ALGORITHM algorithm);
160 // RRD FAMILY
161
162 struct rrdfamily {
163 - avl_t avl;
164 -
165 - const char *family;
166 - uint32_t hash_family;
163 + STRING *family;
164 + DICTIONARY *rrdvar_root_index;
165
166 size_t use_count;
169 -
170 - avl_tree_lock rrdvar_root_index;
167 };
168 typedef struct rrdfamily RRDFAMILY;
169
@@ -190,6 +186,7 @@ typedef enum rrddim_flags {
186
187 RRDDIM_FLAG_PENDING_FOREACH_ALARM = (1 << 5), // set when foreach alarm has not been initialized yet
188 RRDDIM_FLAG_META_HIDDEN = (1 << 6), // Status of hidden option in the metadata database
189 + RRDDIM_FLAG_INDEXED_ID = (1 << 7),
190 } RRDDIM_FLAGS;
191
192 #define rrddim_flag_check(rd, flag) (__atomic_load_n(&((rd)->flags), __ATOMIC_SEQ_CST) & (flag))
@@ -244,27 +241,13 @@ extern bool exporting_labels_filter_callback(const char *name, const char *value
241 // RRD DIMENSION - this is a metric
242
243 struct rrddim {
247 - // ------------------------------------------------------------------------
248 - // binary indexing structures
249 -
250 - avl_t avl; // the binary index - this has to be first member!
251 -
244 uuid_t metric_uuid; // global UUID for this metric (unique_across hosts)
245
246 // ------------------------------------------------------------------------
247 // the dimension definition
248
257 - const char *id; // the id of this dimension (for internal identification)
258 - const char *name; // the name of this dimension (as presented to user)
259 - // this is a pointer to the config structure
260 - // since the config always has a higher priority
261 - // (the user overwrites the name of the charts)
262 - uint32_t hash; // a simple hash of the id, to speed up searching / indexing
263 - // instead of strcmp() every item in the binary index
264 - // we first compare the hashes
265 - uint32_t hash_name; // a simple hash of the name
266 -
267 -
249 + STRING *id; // the id of this dimension (for internal identification)
250 + STRING *name; // the name of this dimension (as presented to user)
251 RRD_ALGORITHM algorithm; // the algorithm that is applied to add new collected values
252 RRD_MEMORY_MODE rrd_memory_mode; // the memory mode for this dimension
253 RRDDIM_FLAGS flags; // configuration flags for the dimension
@@ -305,6 +288,8 @@ struct rrddim {
288 NETDATA_DOUBLE stored_volume; // the sum of all stored values so far
289
290 struct rrddim *next; // linking of dimensions within the same data set
291 + struct rrddim *prev; // linking of dimensions within the same data set
292 +
293 struct rrdset *rrdset;
294 RRDMETRIC_ACQUIRED *rrdmetric; // the rrdmetric of this dimension
295
@@ -328,6 +313,9 @@ struct rrddim {
313 storage_number *db; // the array of values
314 };
315
316 +#define rrddim_id(rd) string2str((rd)->id)
317 +#define rrddim_name(rd) string2str((rd) ->name)
318 +
319 // returns the RRDDIM cache filename, or NULL if it does not exist
320 extern const char *rrddim_cache_filename(RRDDIM *rd);
321
@@ -459,9 +447,6 @@ extern void rrdr_fill_tier_gap_from_smaller_tiers(RRDDIM *rd, int tier, time_t n
447 // ----------------------------------------------------------------------------
448 // volatile state per chart
449 struct rrdset_volatile {
462 - char *old_title;
463 - char *old_units;
464 - char *old_context;
450 uuid_t hash_id;
451 DICTIONARY *chart_labels;
452 bool is_ar_chart;
@@ -485,88 +470,75 @@ struct rrdset_volatile {
470 // and may lead to missing information.
471
472 typedef enum rrdset_flags {
488 - RRDSET_FLAG_DETAIL = 1 << 1, // if set, the data set should be considered as a detail of another
489 - // (the master data set should be the one that has the same family and is not detail)
490 - RRDSET_FLAG_DEBUG = 1 << 2, // enables or disables debugging for a chart
491 - RRDSET_FLAG_OBSOLETE = 1 << 3, // this is marked by the collector/module as obsolete
492 - RRDSET_FLAG_EXPORTING_SEND = 1 << 4, // if set, this chart should be sent to Prometheus web API and external databases
493 - RRDSET_FLAG_EXPORTING_IGNORE = 1 << 5, // if set, this chart should not be sent to Prometheus web API and external databases
494 - RRDSET_FLAG_UPSTREAM_SEND = 1 << 6, // if set, this chart should be sent upstream (streaming)
495 - RRDSET_FLAG_UPSTREAM_IGNORE = 1 << 7, // if set, this chart should not be sent upstream (streaming)
496 - RRDSET_FLAG_UPSTREAM_EXPOSED = 1 << 8, // if set, we have sent this chart definition to netdata parent (streaming)
497 - RRDSET_FLAG_STORE_FIRST = 1 << 9, // if set, do not eliminate the first collection during interpolation
498 - RRDSET_FLAG_HETEROGENEOUS = 1 << 10, // if set, the chart is not homogeneous (dimensions in it have multiple algorithms, multipliers or dividers)
499 - RRDSET_FLAG_HOMOGENEOUS_CHECK = 1 << 11, // if set, the chart should be checked to determine if the dimensions are homogeneous
500 - RRDSET_FLAG_HIDDEN = 1 << 12, // if set, do not show this chart on the dashboard, but use it for exporting
501 - RRDSET_FLAG_SYNC_CLOCK = 1 << 13, // if set, microseconds on next data collection will be ignored (the chart will be synced to now)
502 - RRDSET_FLAG_OBSOLETE_DIMENSIONS = 1 << 14, // this is marked by the collector/module when a chart has obsolete dimensions
503 - // No new values have been collected for this chart since agent start or it was marked RRDSET_FLAG_OBSOLETE at
504 - // least rrdset_free_obsolete_time seconds ago.
505 - RRDSET_FLAG_ARCHIVED = 1 << 15,
506 - RRDSET_FLAG_ACLK = 1 << 16,
507 - RRDSET_FLAG_PENDING_FOREACH_ALARMS = 1 << 17, // contains dims with uninitialized foreach alarms
508 - RRDSET_FLAG_ANOMALY_DETECTION = 1 << 18 // flag to identify anomaly detection charts.
473 + RRDSET_FLAG_DETAIL = (1 << 1), // if set, the data set should be considered as a detail of another
474 + // (the master data set should be the one that has the same family and is not detail)
475 + RRDSET_FLAG_DEBUG = (1 << 2), // enables or disables debugging for a chart
476 + RRDSET_FLAG_OBSOLETE = (1 << 3), // this is marked by the collector/module as obsolete
477 + RRDSET_FLAG_EXPORTING_SEND = (1 << 4), // if set, this chart should be sent to Prometheus web API and external databases
478 + RRDSET_FLAG_EXPORTING_IGNORE = (1 << 5), // if set, this chart should not be sent to Prometheus web API and external databases
479 + RRDSET_FLAG_UPSTREAM_SEND = (1 << 6), // if set, this chart should be sent upstream (streaming)
480 + RRDSET_FLAG_UPSTREAM_IGNORE = (1 << 7), // if set, this chart should not be sent upstream (streaming)
481 + RRDSET_FLAG_UPSTREAM_EXPOSED = (1 << 8), // if set, we have sent this chart definition to netdata parent (streaming)
482 + RRDSET_FLAG_STORE_FIRST = (1 << 9), // if set, do not eliminate the first collection during interpolation
483 + RRDSET_FLAG_HETEROGENEOUS = (1 << 10), // if set, the chart is not homogeneous (dimensions in it have multiple algorithms, multipliers or dividers)
484 + RRDSET_FLAG_HOMOGENEOUS_CHECK = (1 << 11), // if set, the chart should be checked to determine if the dimensions are homogeneous
485 + RRDSET_FLAG_HIDDEN = (1 << 12), // if set, do not show this chart on the dashboard, but use it for exporting
486 + RRDSET_FLAG_SYNC_CLOCK = (1 << 13), // if set, microseconds on next data collection will be ignored (the chart will be synced to now)
487 + RRDSET_FLAG_OBSOLETE_DIMENSIONS = (1 << 14), // this is marked by the collector/module when a chart has obsolete dimensions
488 + // No new values have been collected for this chart since agent start or it was marked RRDSET_FLAG_OBSOLETE at
489 + // least rrdset_free_obsolete_time seconds ago.
490 + RRDSET_FLAG_ARCHIVED = (1 << 15),
491 + RRDSET_FLAG_ACLK = (1 << 16),
492 + RRDSET_FLAG_PENDING_FOREACH_ALARMS = (1 << 17), // contains dims with uninitialized foreach alarms
493 + RRDSET_FLAG_ANOMALY_DETECTION = (1 << 18), // flag to identify anomaly detection charts.
494 + RRDSET_FLAG_INDEXED_ID = (1 << 19),
495 + RRDSET_FLAG_INDEXED_NAME = (1 << 20),
496 } RRDSET_FLAGS;
497
498 #define rrdset_flag_check(st, flag) (__atomic_load_n(&((st)->flags), __ATOMIC_SEQ_CST) & (flag))
499 #define rrdset_flag_set(st, flag) __atomic_or_fetch(&((st)->flags), flag, __ATOMIC_SEQ_CST)
513 -#define rrdset_flag_clear(st, flag) __atomic_and_fetch(&((st)->flags), ~flag, __ATOMIC_SEQ_CST)
500 +#define rrdset_flag_clear(st, flag) __atomic_and_fetch(&((st)->flags), ~(flag), __ATOMIC_SEQ_CST)
501
502 struct rrdset {
516 - // ------------------------------------------------------------------------
517 - // binary indexing structures
518 -
519 - avl_t avl; // the index, with key the id - this has to be first!
520 - avl_t avlname; // the index, with key the name
521 -
503 // ------------------------------------------------------------------------
504 // the set configuration
505
525 - char id[RRD_ID_LENGTH_MAX + 1]; // id of the data set
526 -
527 - const char *name; // the name of this dimension (as presented to user)
528 - // this is a pointer to the config structure
529 - // since the config always has a higher priority
530 - // (the user overwrites the name of the charts)
531 -
532 - char *type; // the type of graph RRD_TYPE_* (a category, for determining graphing options)
533 - char *family; // grouping sets under the same family
534 - char *title; // title shown to user
535 - char *units; // units of measurement
536 -
537 - char *context; // the template of this data set
538 - uint32_t hash_context; // the hash of the chart's context
506 + STRING *id; // the ID of the data set
507 + STRING *name; // the name of this dimension (as presented to user)
508 + STRING *type; // the type of graph RRD_TYPE_* (a category, for determining graphing options)
509 + STRING *family; // grouping sets under the same family
510 + STRING *title; // title shown to user
511 + STRING *units; // units of measurement
512 + STRING *context; // the template of this data set
513 + STRING *plugin_name; // the name of the plugin that generated this
514 + STRING *module_name; // the name of the plugin module that generated this
515
516 RRDINSTANCE_ACQUIRED *rrdinstance; // the rrdinstance of this chart
517 RRDCONTEXT_ACQUIRED *rrdcontext; // the rrdcontext this chart belongs to
518
519 + RRD_MEMORY_MODE rrd_memory_mode; // the db mode of this rrdset
520 RRDSET_TYPE chart_type; // line, area, stacked
521 + RRDSET_FLAGS flags; // configuration flags
522 + RRDSET_FLAGS *exporting_flags; // array of flags for exporting connector instances
523
524 int update_every; // every how many seconds is this updated?
525
526 + int gap_when_lost_iterations_above; // after how many lost iterations a gap should be stored
527 + // netdata will interpolate values for gaps lower than this
528 +
529 long entries; // total number of entries in the data set
530
531 long current_entry; // the entry that is currently being updated
532 // it goes around in a round-robin fashion
533
552 - RRDSET_FLAGS flags; // configuration flags
553 - RRDSET_FLAGS *exporting_flags; // array of flags for exporting connector instances
554 -
555 - int gap_when_lost_iterations_above; // after how many lost iterations a gap should be stored
556 - // netdata will interpolate values for gaps lower than this
557 -
534 long priority; // the sorting priority of this chart
535
536
537 // ------------------------------------------------------------------------
538 // members for temporary data we need for calculations
539
564 - RRD_MEMORY_MODE rrd_memory_mode; // if set to 1, this is memory mapped
565 -
540 char *cache_dir; // the directory to store dimensions
541
568 - netdata_rwlock_t rrdset_rwlock; // protects dimensions linked list
569 -
542 size_t counter; // the number of times we added values to this database
543 size_t counter_done; // the number of times rrdset_done() has been called
544
@@ -576,19 +548,12 @@ struct rrdset {
548 };
549 time_t upstream_resync_time; // the timestamp up to which we should resync clock upstream
550
579 - char *plugin_name; // the name of the plugin that generated this
580 - char *module_name; // the name of the plugin module that generated this
551 uuid_t *chart_uuid; // Store the global GUID for this chart
552 // this object.
553 struct rrdset_volatile *state; // volatile state that is not persistently stored
554
555 size_t rrddim_page_alignment; // keeps metric pages in alignment when using dbengine
556
587 - uint32_t hash; // a simple hash on the id, to speed up searching
588 - // we first compare hashes, and only if the hashes are equal we do string comparisons
589 -
590 - uint32_t hash_name; // a simple hash on the name
591 -
557 usec_t usec_since_last_update; // the time in microseconds since the last collection of data
558
559 struct timeval last_updated; // when this data set was last updated (updated every time the rrd_stats_done() function)
@@ -601,14 +566,15 @@ struct rrdset {
566 RRDHOST *rrdhost; // pointer to RRDHOST this chart belongs to
567
568 struct rrdset *next; // linking of rrdsets
569 + struct rrdset *prev; // linking of rrdsets
570
571 // ------------------------------------------------------------------------
572 // local variables
573
608 - NETDATA_DOUBLE green; // green threshold for this chart
609 - NETDATA_DOUBLE red; // red threshold for this chart
574 + NETDATA_DOUBLE green; // green threshold for this chart
575 + NETDATA_DOUBLE red; // red threshold for this chart
576
611 - avl_tree_lock rrdvar_root_index; // RRDVAR index for this chart
577 + DICTIONARY *rrdvar_root_index; // RRDVAR index for this chart
578 RRDSETVAR *variables; // RRDSETVAR linked list for this chart (one RRDSETVAR, many RRDVARs)
579 RRDCALC *alarms; // RRDCALC linked list for this chart
580
@@ -621,14 +587,27 @@ struct rrdset {
587 // ------------------------------------------------------------------------
588 // the dimensions
589
624 - avl_tree_lock dimensions_index; // the root of the dimensions index
590 + DICTIONARY *rrddim_root_index; // the root of the dimensions index
591 +
592 + netdata_rwlock_t rrdset_rwlock; // protects dimensions linked list
593 RRDDIM *dimensions; // the actual data for every dimension
594 };
595
596 +#define rrdset_plugin_name(st) string2str((st)->plugin_name)
597 +#define rrdset_module_name(st) string2str((st)->module_name)
598 +#define rrdset_units(st) string2str((st)->units)
599 +#define rrdset_type(st) string2str((st)->type)
600 +#define rrdset_family(st) string2str((st)->family)
601 +#define rrdset_title(st) string2str((st)->title)
602 +#define rrdset_context(st) string2str((st)->context)
603 +#define rrdset_name(st) string2str((st)->name)
604 +#define rrdset_id(st) string2str((st)->id)
605 +
606 #define rrdset_rdlock(st) netdata_rwlock_rdlock(&((st)->rrdset_rwlock))
607 #define rrdset_wrlock(st) netdata_rwlock_wrlock(&((st)->rrdset_rwlock))
608 #define rrdset_unlock(st) netdata_rwlock_unlock(&((st)->rrdset_rwlock))
609
610 +extern STRING *rrd_string_strdupz(const char *s);
611
612 // ----------------------------------------------------------------------------
613 // these loop macros make sure the linked list is accessed with the right lock
@@ -653,26 +632,29 @@ extern bool rrdset_memory_load_or_create_map_save(RRDSET *st_on_file, RRD_MEMORY
632 // and may lead to missing information.
633
634 typedef enum rrdhost_flags {
656 - RRDHOST_FLAG_ORPHAN = (1 << 0), // this host is orphan (not receiving data)
657 - RRDHOST_FLAG_DELETE_OBSOLETE_CHARTS = (1 << 1), // delete files of obsolete charts
658 - RRDHOST_FLAG_DELETE_ORPHAN_HOST = (1 << 2), // delete the entire host when orphan
659 - RRDHOST_FLAG_EXPORTING_SEND = (1 << 3), // send it to external databases
660 - RRDHOST_FLAG_EXPORTING_DONT_SEND = (1 << 4), // don't send it to external databases
661 - RRDHOST_FLAG_ARCHIVED = (1 << 5), // The host is archived, no collected charts yet
662 - RRDHOST_FLAG_MULTIHOST = (1 << 6), // Host belongs to localhost/megadb
663 - RRDHOST_FLAG_PENDING_FOREACH_ALARMS = (1 << 7), // contains dims with uninitialized foreach alarms
664 - RRDHOST_FLAG_STREAM_LABELS_UPDATE = (1 << 8),
665 - RRDHOST_FLAG_STREAM_LABELS_STOP = (1 << 9),
666 - RRDHOST_FLAG_ACLK_STREAM_CONTEXTS = (1 << 10), // when set, we should send ACLK stream context updates
635 + RRDHOST_FLAG_ORPHAN = (1 << 0), // this host is orphan (not receiving data)
636 + RRDHOST_FLAG_DELETE_OBSOLETE_CHARTS = (1 << 1), // delete files of obsolete charts
637 + RRDHOST_FLAG_DELETE_ORPHAN_HOST = (1 << 2), // delete the entire host when orphan
638 + RRDHOST_FLAG_EXPORTING_SEND = (1 << 3), // send it to external databases
639 + RRDHOST_FLAG_EXPORTING_DONT_SEND = (1 << 4), // don't send it to external databases
640 + RRDHOST_FLAG_ARCHIVED = (1 << 5), // The host is archived, no collected charts yet
641 + RRDHOST_FLAG_MULTIHOST = (1 << 6), // Host belongs to localhost/megadb
642 + RRDHOST_FLAG_PENDING_FOREACH_ALARMS = (1 << 7), // contains dims with uninitialized foreach alarms
643 + RRDHOST_FLAG_STREAM_LABELS_UPDATE = (1 << 8),
644 + RRDHOST_FLAG_STREAM_LABELS_STOP = (1 << 9),
645 + RRDHOST_FLAG_ACLK_STREAM_CONTEXTS = (1 << 10), // when set, we should send ACLK stream context updates
646 + RRDHOST_FLAG_INDEXED_MACHINE_GUID = (1 << 11), // when set, we have indexed its machine guid
647 + RRDHOST_FLAG_INDEXED_HOSTNAME = (1 << 12), // when set, we have indexed its hostname
648 + RRDHOST_FLAG_STREAM_COLLECTED_METRICS = (1 << 13), // when set, rrdset_done() should push metrics to parent
649 } RRDHOST_FLAGS;
650
651 #define rrdhost_flag_check(host, flag) (__atomic_load_n(&((host)->flags), __ATOMIC_SEQ_CST) & (flag))
652 #define rrdhost_flag_set(host, flag) __atomic_or_fetch(&((host)->flags), flag, __ATOMIC_SEQ_CST)
671 -#define rrdhost_flag_clear(host, flag) __atomic_and_fetch(&((host)->flags), ~flag, __ATOMIC_SEQ_CST)
653 +#define rrdhost_flag_clear(host, flag) __atomic_and_fetch(&((host)->flags), ~(flag), __ATOMIC_SEQ_CST)
654
655 #ifdef NETDATA_INTERNAL_CHECKS
656 #define rrdset_debug(st, fmt, args...) do { if(unlikely(debug_flags & D_RRD_STATS && rrdset_flag_check(st, RRDSET_FLAG_DEBUG))) \
675 - debug_int(__FILE__, __FUNCTION__, __LINE__, "%s: " fmt, st->name, ##args); } while(0)
657 + debug_int(__FILE__, __FUNCTION__, __LINE__, "%s: " fmt, rrdset_name(st), ##args); } while(0)
658 #else
659 #define rrdset_debug(st, fmt, args...) debug_dummy()
660 #endif
@@ -690,34 +672,30 @@ struct alarm_entry {
672 time_t duration;
673 time_t non_clear_duration;
674
693 - char *name;
694 - uint32_t hash_name;
695 -
696 - char *chart;
697 - uint32_t hash_chart;
698 - char *chart_context;
675 + STRING *name;
676 + STRING *chart;
677 + STRING *chart_context;
678 + STRING *family;
679
700 - char *family;
680 + STRING *classification;
681 + STRING *component;
682 + STRING *type;
683
702 - char *classification;
703 - char *component;
704 - char *type;
705 -
706 - char *exec;
707 - char *recipient;
684 + STRING *exec;
685 + STRING *recipient;
686 time_t exec_run_timestamp;
687 int exec_code;
688 uint64_t exec_spawn_serial;
689
712 - char *source;
713 - char *units;
714 - char *info;
690 + STRING *source;
691 + STRING *units;
692 + STRING *info;
693
694 NETDATA_DOUBLE old_value;
695 NETDATA_DOUBLE new_value;
696
719 - char *old_value_string;
720 - char *new_value_string;
697 + STRING *old_value_string;
698 + STRING *new_value_string;
699
700 RRDCALC_STATUS old_status;
701 RRDCALC_STATUS new_status;
@@ -737,6 +715,20 @@ struct alarm_entry {
715 struct alarm_entry *prev_in_progress;
716 };
717
718 +#define ae_name(ae) string2str((ae)->name)
719 +#define ae_chart_name(ae) string2str((ae)->chart)
720 +#define ae_chart_context(ae) string2str((ae)->chart_context)
721 +#define ae_family(ae) string2str((ae)->family)
722 +#define ae_classification(ae) string2str((ae)->classification)
723 +#define ae_component(ae) string2str((ae)->component)
724 +#define ae_type(ae) string2str((ae)->type)
725 +#define ae_exec(ae) string2str((ae)->exec)
726 +#define ae_recipient(ae) string2str((ae)->recipient)
727 +#define ae_source(ae) string2str((ae)->source)
728 +#define ae_units(ae) string2str((ae)->units)
729 +#define ae_info(ae) string2str((ae)->info)
730 +#define ae_old_value_string(ae) string2str((ae)->old_value_string)
731 +#define ae_new_value_string(ae) string2str((ae)->new_value_string)
732
733 typedef struct alarm_log {
734 uint32_t next_log_id;
@@ -790,24 +782,20 @@ struct rrdhost_system_info {
782 };
783
784 struct rrdhost {
793 - avl_t avl; // the index of hosts
785 + char machine_guid[GUID_LEN + 1]; // the unique ID of this host
786
787 // ------------------------------------------------------------------------
788 // host information
789
798 - char *hostname; // the hostname of this host
799 - uint32_t hash_hostname; // the hostname hash
790 + STRING *hostname; // the hostname of this host
791 + STRING *registry_hostname; // the registry hostname for this host
792 + STRING *os; // the O/S type of the host
793 + STRING *tags; // tags for this host
794 + STRING *timezone; // the timezone of the host
795 + STRING *abbrev_timezone; // the abbriviated timezone of the host
796 + STRING *program_name; // the program name that collects metrics for this host
797 + STRING *program_version; // the program version that collects metrics for this host
798
801 - char *registry_hostname; // the registry hostname for this host
802 -
803 - char machine_guid[GUID_LEN + 1]; // the unique ID of this host
804 - uint32_t hash_machine_guid; // the hash of the unique ID
805 -
806 - const char *os; // the O/S type of the host
807 - const char *tags; // tags for this host
808 - const char *timezone; // the timezone of the host
809 -
810 - const char *abbrev_timezone; // the abbriviated timezone of the host
799 int32_t utc_offset; // the offset in seconds from utc
800
801 RRDHOST_FLAGS flags; // flags about this RRDHOST
@@ -820,9 +808,6 @@ struct rrdhost {
808 char *cache_dir; // the directory to save RRD cache files
809 char *varlib_dir; // the directory to save health log
810
823 - char *program_name; // the program name that collects metrics for this host
824 - char *program_version; // the program version that collects metrics for this host
825 -
811 struct rrdhost_system_info *system_info; // information collected from the host environment
812
813 // ------------------------------------------------------------------------
@@ -873,23 +858,21 @@ struct rrdhost {
858 // health monitoring options
859
860 unsigned int health_enabled; // 1 when this host has health enabled
876 - time_t health_delay_up_to; // a timestamp to delay alarms processing up to
877 - char *health_default_exec; // the full path of the alarms notifications program
878 - char *health_default_recipient; // the default recipient for all alarms
879 - char *health_log_filename; // the alarms event log filename
880 - size_t health_log_entries_written; // the number of alarm events written to the alarms event log
881 - FILE *health_log_fp; // the FILE pointer to the open alarms event log file
882 - uint32_t health_default_warn_repeat_every; // the default value for the interval between repeating warning notifications
883 - uint32_t health_default_crit_repeat_every; // the default value for the interval between repeating critical notifications
861 + time_t health_delay_up_to; // a timestamp to delay alarms processing up to
862 + STRING *health_default_exec; // the full path of the alarms notifications program
863 + STRING *health_default_recipient; // the default recipient for all alarms
864 + char *health_log_filename; // the alarms event log filename
865 + size_t health_log_entries_written; // the number of alarm events written to the alarms event log
866 + FILE *health_log_fp; // the FILE pointer to the open alarms event log file
867 + uint32_t health_default_warn_repeat_every; // the default value for the interval between repeating warning notifications
868 + uint32_t health_default_crit_repeat_every; // the default value for the interval between repeating critical notifications
869
870
871 // all RRDCALCs are primarily allocated and linked here
872 // RRDCALCs may be linked to charts at any point
873 // (charts may or may not exist when these are loaded)
889 - RRDCALC *alarms;
874 + RRDCALC *host_alarms;
875 RRDCALC *alarms_with_foreach;
891 - avl_tree_lock alarms_idx_health_log;
892 - avl_tree_lock alarms_idx_name;
876
877 ALARM_LOG health_log; // alarms historical events (event log)
878 uint32_t health_last_processed_id; // the last processed health id from the log
@@ -899,9 +882,7 @@ struct rrdhost {
882 // templates of alarms
883 // these are used to create alarms when charts
884 // are created or renamed, that match them
902 - RRDCALCTEMPLATE *templates;
903 - RRDCALCTEMPLATE *alarms_template_with_foreach;
904 -
885 + RRDCALCTEMPLATE *alarms_templates;
886
887 // ------------------------------------------------------------------------
888 // the charts of the host
@@ -927,11 +908,11 @@ struct rrdhost {
908 // ------------------------------------------------------------------------
909 // indexes
910
930 - avl_tree_lock rrdset_root_index; // the host's charts index (by id)
931 - avl_tree_lock rrdset_root_index_name; // the host's charts index (by name)
911 + DICTIONARY *rrdset_root_index; // the host's charts index (by id)
912 + DICTIONARY *rrdset_root_index_name; // the host's charts index (by name)
913
933 - avl_tree_lock rrdfamily_root_index; // the host's chart families index
934 - avl_tree_lock rrdvar_root_index; // the host's chart variables index
914 + DICTIONARY *rrdfamily_root_index; // the host's chart families index
915 + DICTIONARY *rrdvar_root_index; // the host's chart variables index
916
917 STORAGE_INSTANCE *storage_instance[RRD_STORAGE_TIERS]; // the database instances of the storage tiers
918
@@ -950,9 +931,19 @@ struct rrdhost {
931 aclk_rrdhost_state aclk_state;
932
933 struct rrdhost *next;
934 + struct rrdhost *prev;
935 };
936 extern RRDHOST *localhost;
937
938 +#define rrdhost_hostname(host) string2str((host)->hostname)
939 +#define rrdhost_registry_hostname(host) string2str((host)->registry_hostname)
940 +#define rrdhost_os(host) string2str((host)->os)
941 +#define rrdhost_tags(host) string2str((host)->tags)
942 +#define rrdhost_timezone(host) string2str((host)->timezone)
943 +#define rrdhost_abbrev_timezone(host) string2str((host)->abbrev_timezone)
944 +#define rrdhost_program_name(host) string2str((host)->program_name)
945 +#define rrdhost_program_version(host) string2str((host)->program_version)
946 +
947 #define rrdhost_rdlock(host) netdata_rwlock_rdlock(&((host)->rrdhost_rwlock))
948 #define rrdhost_wrlock(host) netdata_rwlock_wrlock(&((host)->rrdhost_rwlock))
949 #define rrdhost_unlock(host) netdata_rwlock_unlock(&((host)->rrdhost_rwlock))
@@ -960,6 +951,8 @@ extern RRDHOST *localhost;
951 #define rrdhost_aclk_state_lock(host) netdata_mutex_lock(&((host)->aclk_state_lock))
952 #define rrdhost_aclk_state_unlock(host) netdata_mutex_unlock(&((host)->aclk_state_lock))
953
954 +extern long rrdhost_hosts_available(void);
955 +
956 // ----------------------------------------------------------------------------
957 // these loop macros make sure the linked list is accessed with the right lock
958
@@ -990,8 +983,8 @@ extern time_t rrdhost_free_orphan_time;
983
984 extern int rrd_init(char *hostname, struct rrdhost_system_info *system_info);
985
993 -extern RRDHOST *rrdhost_find_by_hostname(const char *hostname, uint32_t hash);
994 -extern RRDHOST *rrdhost_find_by_guid(const char *guid, uint32_t hash);
986 +extern RRDHOST *rrdhost_find_by_hostname(const char *hostname);
987 +extern RRDHOST *rrdhost_find_by_guid(const char *guid);
988
989 extern RRDHOST *rrdhost_find_or_create(
990 const char *hostname
@@ -1237,11 +1230,18 @@ time_t rrdhost_last_entry_t(RRDHOST *h);
1230 // RRD DIMENSION functions
1231
1232 extern void rrdcalc_link_to_rrddim(RRDDIM *rd, RRDSET *st, RRDHOST *host);
1240 -extern RRDDIM *rrddim_add_custom(RRDSET *st, const char *id, const char *name, collected_number multiplier,
1241 - collected_number divisor, RRD_ALGORITHM algorithm, RRD_MEMORY_MODE memory_mode);//,
1242 - //int is_archived, uuid_t *dim_uuid);
1243 -#define rrddim_add(st, id, name, multiplier, divisor, algorithm) rrddim_add_custom(st, id, name, multiplier, divisor, \
1244 - algorithm, (st)->rrd_memory_mode)//, 0, NULL)
1233 +
1234 +extern RRDDIM *rrddim_add_custom(RRDSET *st
1235 + , const char *id
1236 + , const char *name
1237 + , collected_number multiplier
1238 + , collected_number divisor
1239 + , RRD_ALGORITHM algorithm
1240 + , RRD_MEMORY_MODE memory_mode
1241 + );
1242 +
1243 +#define rrddim_add(st, id, name, multiplier, divisor, algorithm) \
1244 + rrddim_add_custom(st, id, name, multiplier, divisor, algorithm, (st)->rrd_memory_mode)
1245
1246 extern int rrddim_set_name(RRDSET *st, RRDDIM *rd, const char *name);
1247 extern int rrddim_set_algorithm(RRDSET *st, RRDDIM *rd, RRD_ALGORITHM algorithm);
@@ -1249,15 +1249,7 @@ extern int rrddim_set_multiplier(RRDSET *st, RRDDIM *rd, collected_number multip
1249 extern int rrddim_set_divisor(RRDSET *st, RRDDIM *rd, collected_number divisor);
1250
1251 extern RRDDIM *rrddim_find(RRDSET *st, const char *id);
1252 -/* This will not return dimensions that are archived */
1253 -static inline RRDDIM *rrddim_find_active(RRDSET *st, const char *id)
1254 -{
1255 - RRDDIM *rd = rrddim_find(st, id);
1256 - if (unlikely(rd && rrddim_flag_check(rd, RRDDIM_FLAG_ARCHIVED)))
1257 - return NULL;
1258 - return rd;
1259 -}
1260 -
1252 +extern RRDDIM *rrddim_find_active(RRDSET *st, const char *id);
1253
1254 extern int rrddim_hide(RRDSET *st, const char *id);
1255 extern int rrddim_unhide(RRDSET *st, const char *id);
@@ -1275,33 +1267,20 @@ extern long align_entries_to_pagesize(RRD_MEMORY_MODE mode, long entries);
1267 // ----------------------------------------------------------------------------
1268 // Miscellaneous functions
1269
1278 -extern int alarm_compare_id(void *a, void *b);
1279 -extern int alarm_compare_name(void *a, void *b);
1270 +extern char *rrdset_strncpyz_name(char *to, const char *from, size_t length);
1271
1272 // ----------------------------------------------------------------------------
1273 // RRD internal functions
1274
1275 #ifdef NETDATA_RRD_INTERNALS
1276
1286 -extern avl_tree_lock rrdhost_root_index;
1287 -
1288 -extern char *rrdset_strncpyz_name(char *to, const char *from, size_t length);
1277 extern char *rrdset_cache_dir(RRDHOST *host, const char *id);
1278
1279 extern void rrddim_free(RRDSET *st, RRDDIM *rd);
1280
1293 -extern int rrddim_compare(void* a, void* b);
1294 -extern int rrdset_compare(void* a, void* b);
1295 -extern int rrdset_compare_name(void* a, void* b);
1296 -extern int rrdfamily_compare(void *a, void *b);
1297 -
1281 extern RRDFAMILY *rrdfamily_create(RRDHOST *host, const char *id);
1282 extern void rrdfamily_free(RRDHOST *host, RRDFAMILY *rc);
1283
1301 -#define rrdset_index_add(host, st) (RRDSET *)avl_insert_lock(&((host)->rrdset_root_index), (avl_t *)(st))
1302 -#define rrdset_index_del(host, st) (RRDSET *)avl_remove_lock(&((host)->rrdset_root_index), (avl_t *)(st))
1303 -extern RRDSET *rrdset_index_del_name(RRDHOST *host, RRDSET *st);
1304 -
1284 extern void rrdset_free(RRDSET *st);
1285 extern void rrdset_reset(RRDSET *st);
1286 extern void rrdset_save(RRDSET *st);
@@ -1318,8 +1297,8 @@ extern RRDHOST *rrdhost_create(
1297 #endif /* NETDATA_RRD_INTERNALS */
1298
1299 extern void set_host_properties(
1321 - RRDHOST *host, int update_every, RRD_MEMORY_MODE memory_mode, const char *hostname, const char *registry_hostname,
1322 - const char *guid, const char *os, const char *tags, const char *tzone, const char *abbrev_tzone, int32_t utc_offset,
1300 + RRDHOST *host, int update_every, RRD_MEMORY_MODE memory_mode, const char *registry_hostname,
1301 + const char *os, const char *tags, const char *tzone, const char *abbrev_tzone, int32_t utc_offset,
1302 const char *program_name, const char *program_version);
1303
1304 extern int get_tier_grouping(int tier);
database/rrdcalc.c
+168 -286
@@ -35,9 +35,8 @@ inline const char *rrdcalc_status2string(RRDCALC_STATUS status) {
35 }
36 }
37
38 -char *rrdcalc_replace_variables(const char *line, RRDCALC *rc)
39 -{
40 - if (!line)
38 +static STRING *rrdcalc_replace_variables(const char *line, RRDCALC *rc) {
39 + if (!line || !*line)
40 return NULL;
41
42 size_t pos = 0;
@@ -46,24 +45,28 @@ char *rrdcalc_replace_variables(const char *line, RRDCALC *rc)
45 char *m, *lbl_value = NULL;
46
47 while ((m = strchr(temp + pos, '$'))) {
49 - int i=0;
48 + int i = 0;
49 char *e = m;
50 while (*e) {
52 - if (*e == ' ' || i == RRDCALC_VAR_MAX - 1) {
51 +
52 + if (*e == ' ' || i == RRDCALC_VAR_MAX - 1)
53 break;
54 - }
54 else
56 - var[i]=*e;
55 + var[i] = *e;
56 +
57 e++;
58 i++;
59 }
60 - var[i]='\0';
60 +
61 + var[i] = '\0';
62 pos = m - temp + 1;
63 +
64 if (!strcmp(var, RRDCALC_VAR_FAMILY)) {
63 - char *buf = find_and_replace(temp, var, (rc->rrdset && rc->rrdset->family) ? rc->rrdset->family : "", m);
65 + char *buf = find_and_replace(temp, var, (rc->rrdset && rc->rrdset->family) ? rrdset_family(rc->rrdset) : "", m);
66 freez(temp);
67 temp = buf;
66 - } else if (!strncmp(var, RRDCALC_VAR_LABEL, RRDCALC_VAR_LABEL_LEN)) {
68 + }
69 + else if (!strncmp(var, RRDCALC_VAR_LABEL, RRDCALC_VAR_LABEL_LEN)) {
70 if(likely(rc->rrdset && rc->rrdset->state && rc->rrdset->state->chart_labels)) {
71 rrdlabels_get_value_to_char_or_null(rc->rrdset->state->chart_labels, &lbl_value, var+RRDCALC_VAR_LABEL_LEN);
72 if (lbl_value) {
@@ -76,17 +79,20 @@ char *rrdcalc_replace_variables(const char *line, RRDCALC *rc)
79 }
80 }
81
79 - return temp;
82 + STRING *ret = string_strdupz(temp);
83 + freez(temp);
84 +
85 + return ret;
86 }
87
88 void rrdcalc_update_rrdlabels(RRDSET *st) {
89 RRDCALC *rc;
84 - for( rc = st->alarms; rc ; rc = rc->rrdset_next ) {
90 + foreach_rrdcalc_in_rrdset(st, rc) {
91 if (rc->original_info) {
92 if (rc->info)
87 - freez(rc->info);
93 + string_freez(rc->info);
94
89 - rc->info = rrdcalc_replace_variables(rc->original_info, rc);
95 + rc->info = rrdcalc_replace_variables(rrdcalc_original_info(rc), rc);
96 }
97 }
98 }
@@ -94,58 +100,57 @@ void rrdcalc_update_rrdlabels(RRDSET *st) {
100 static void rrdsetcalc_link(RRDSET *st, RRDCALC *rc) {
101 RRDHOST *host = st->rrdhost;
102
97 - debug(D_HEALTH, "Health linking alarm '%s.%s' to chart '%s' of host '%s'", rc->chart?rc->chart:"NOCHART", rc->name, st->id, host->hostname);
103 + debug(D_HEALTH, "Health linking alarm '%s.%s' to chart '%s' of host '%s'", rrdcalc_chart_name(rc), rrdcalc_name(rc), rrdset_id(st), rrdhost_hostname(host));
104
105 rc->last_status_change = now_realtime_sec();
106 rc->rrdset = st;
107
102 - rc->rrdset_next = st->alarms;
103 - rc->rrdset_prev = NULL;
104 -
105 - if(rc->rrdset_next)
106 - rc->rrdset_next->rrdset_prev = rc;
107 -
108 - st->alarms = rc;
108 + DOUBLE_LINKED_LIST_PREPEND_UNSAFE(st->alarms, rc, rrdset_prev, rrdset_next);
109
110 if(rc->update_every < rc->rrdset->update_every) {
111 - error("Health alarm '%s.%s' has update every %d, less than chart update every %d. Setting alarm update frequency to %d.", rc->rrdset->id, rc->name, rc->update_every, rc->rrdset->update_every, rc->rrdset->update_every);
111 + error("Health alarm '%s.%s' has update every %d, less than chart update every %d. Setting alarm update frequency to %d.", rrdset_id(rc->rrdset), rrdcalc_name(rc), rc->update_every, rc->rrdset->update_every, rc->rrdset->update_every);
112 rc->update_every = rc->rrdset->update_every;
113 }
114
115 if(!isnan(rc->green) && isnan(st->green)) {
116 debug(D_HEALTH, "Health alarm '%s.%s' green threshold set from " NETDATA_DOUBLE_FORMAT_AUTO
117 - " to " NETDATA_DOUBLE_FORMAT_AUTO ".", rc->rrdset->id, rc->name, rc->rrdset->green, rc->green);
117 + " to " NETDATA_DOUBLE_FORMAT_AUTO ".", rrdset_id(rc->rrdset), rrdcalc_name(rc), rc->rrdset->green, rc->green);
118 st->green = rc->green;
119 }
120
121 if(!isnan(rc->red) && isnan(st->red)) {
122 debug(D_HEALTH, "Health alarm '%s.%s' red threshold set from " NETDATA_DOUBLE_FORMAT_AUTO " to " NETDATA_DOUBLE_FORMAT_AUTO
123 - ".", rc->rrdset->id, rc->name, rc->rrdset->red, rc->red);
123 + ".", rrdset_id(rc->rrdset), rrdcalc_name(rc), rc->rrdset->red, rc->red);
124 st->red = rc->red;
125 }
126
127 - rc->local = rrdvar_create_and_index("local", &st->rrdvar_root_index, rc->name, RRDVAR_TYPE_CALCULATED, RRDVAR_OPTION_RRDCALC_LOCAL_VAR, &rc->value);
128 - rc->family = rrdvar_create_and_index("family", &st->rrdfamily->rrdvar_root_index, rc->name, RRDVAR_TYPE_CALCULATED, RRDVAR_OPTION_RRDCALC_FAMILY_VAR, &rc->value);
127 + rc->local = rrdvar_create_and_index("local", st->rrdvar_root_index, rc->name, RRDVAR_TYPE_CALCULATED, RRDVAR_OPTION_RRDCALC_LOCAL_VAR, &rc->value);
128 + rc->family = rrdvar_create_and_index("family", st->rrdfamily->rrdvar_root_index, rc->name, RRDVAR_TYPE_CALCULATED, RRDVAR_OPTION_RRDCALC_FAMILY_VAR, &rc->value);
129
130 char fullname[RRDVAR_MAX_LENGTH + 1];
131 - snprintfz(fullname, RRDVAR_MAX_LENGTH, "%s.%s", st->id, rc->name);
132 - rc->hostid = rrdvar_create_and_index("host", &host->rrdvar_root_index, fullname, RRDVAR_TYPE_CALCULATED, RRDVAR_OPTION_RRDCALC_HOST_CHARTID_VAR, &rc->value);
131 + snprintfz(fullname, RRDVAR_MAX_LENGTH, "%s.%s", rrdset_id(st), rrdcalc_name(rc));
132 + STRING *fullname_string = string_strdupz(fullname);
133 + rc->hostid = rrdvar_create_and_index("host", host->rrdvar_root_index, fullname_string, RRDVAR_TYPE_CALCULATED, RRDVAR_OPTION_RRDCALC_HOST_CHARTID_VAR, &rc->value);
134
134 - snprintfz(fullname, RRDVAR_MAX_LENGTH, "%s.%s", st->name, rc->name);
135 - rc->hostname = rrdvar_create_and_index("host", &host->rrdvar_root_index, fullname, RRDVAR_TYPE_CALCULATED, RRDVAR_OPTION_RRDCALC_HOST_CHARTNAME_VAR, &rc->value);
135 + snprintfz(fullname, RRDVAR_MAX_LENGTH, "%s.%s", rrdset_name(st), rrdcalc_name(rc));
136 + rc->hostname = rrdvar_create_and_index("host", host->rrdvar_root_index, fullname_string, RRDVAR_TYPE_CALCULATED, RRDVAR_OPTION_RRDCALC_HOST_CHARTNAME_VAR, &rc->value);
137 +
138 + string_freez(fullname_string);
139
140 if(rc->hostid && !rc->hostname)
141 rc->hostid->options |= RRDVAR_OPTION_RRDCALC_HOST_CHARTNAME_VAR;
142
140 - if(!rc->units) rc->units = strdupz(st->units);
143 + if(!rc->units) rc->units = string_dup(st->units);
144
145 if (rc->original_info) {
146 if (rc->info)
144 - freez(rc->info);
145 - rc->info = rrdcalc_replace_variables(rc->original_info, rc);
147 + string_freez(rc->info);
148 +
149 + rc->info = rrdcalc_replace_variables(rrdcalc_original_info(rc), rc);
150 }
151
152 time_t now = now_realtime_sec();
153 +
154 ALARM_ENTRY *ae = health_create_alarm_entry(
155 host,
156 rc->id,
@@ -170,19 +175,20 @@ static void rrdsetcalc_link(RRDSET *st, RRDCALC *rc) {
175 rc->units,
176 rc->info,
177 0,
173 - 0);
178 + rrdcalc_isrepeating(rc)?HEALTH_ENTRY_FLAG_IS_REPEATING:0);
179 +
180 health_alarm_log(host, ae);
181 }
182
177 -static int rrdcalc_is_matching_rrdset(RRDCALC *rc, RRDSET *st) {
178 - if((rc->hash_chart != st->hash || strcmp(rc->chart, st->id) != 0) &&
179 - (rc->hash_chart != st->hash_name || strcmp(rc->chart, st->name) != 0))
183 +static inline int rrdcalc_is_matching_rrdset(RRDCALC *rc, RRDSET *st) {
184 + if ( (rc->chart != st->id)
185 + && (rc->chart != st->name))
186 return 0;
187
182 - if (rc->module_pattern && !simple_pattern_matches(rc->module_pattern, st->module_name))
188 + if (rc->module_pattern && !simple_pattern_matches(rc->module_pattern, rrdset_module_name(st)))
189 return 0;
190
185 - if (rc->plugin_pattern && !simple_pattern_matches(rc->plugin_pattern, st->plugin_name))
191 + if (rc->plugin_pattern && !simple_pattern_matches(rc->plugin_pattern, rrdset_plugin_name(st)))
192 return 0;
193
194 if (st->rrdhost->host_labels && rc->host_labels_pattern && !rrdlabels_match_simple_pattern_parsed(st->rrdhost->host_labels, rc->host_labels_pattern, '='))
@@ -197,7 +203,7 @@ inline void rrdsetcalc_link_matching(RRDSET *st) {
203 // debug(D_HEALTH, "find matching alarms for chart '%s'", st->id);
204
205 RRDCALC *rc;
200 - for(rc = host->alarms; rc ; rc = rc->next) {
206 + foreach_rrdcalc_in_rrdhost(host, rc) {
207 if(unlikely(rc->rrdset))
208 continue;
209
@@ -211,14 +217,15 @@ inline void rrdsetcalc_unlink(RRDCALC *rc) {
217 RRDSET *st = rc->rrdset;
218
219 if(!st) {
214 - debug(D_HEALTH, "Requested to unlink RRDCALC '%s.%s' which is not linked to any RRDSET", rc->chart?rc->chart:"NOCHART", rc->name);
215 - error("Requested to unlink RRDCALC '%s.%s' which is not linked to any RRDSET", rc->chart?rc->chart:"NOCHART", rc->name);
220 + debug(D_HEALTH, "Requested to unlink RRDCALC '%s.%s' which is not linked to any RRDSET", rrdcalc_chart_name(rc), rrdcalc_name(rc));
221 + error("Requested to unlink RRDCALC '%s.%s' which is not linked to any RRDSET", rrdcalc_chart_name(rc), rrdcalc_name(rc));
222 return;
223 }
224
225 RRDHOST *host = st->rrdhost;
226
227 time_t now = now_realtime_sec();
228 +
229 ALARM_ENTRY *ae = health_create_alarm_entry(
230 host,
231 rc->id,
@@ -244,32 +251,24 @@ inline void rrdsetcalc_unlink(RRDCALC *rc) {
251 rc->info,
252 0,
253 0);
254 +
255 health_alarm_log(host, ae);
256
249 - debug(D_HEALTH, "Health unlinking alarm '%s.%s' from chart '%s' of host '%s'", rc->chart?rc->chart:"NOCHART", rc->name, st->id, host->hostname);
257 + debug(D_HEALTH, "Health unlinking alarm '%s.%s' from chart '%s' of host '%s'", rrdcalc_chart_name(rc), rrdcalc_name(rc), rrdset_id(st), rrdhost_hostname(host));
258
259 // unlink it
252 - if(rc->rrdset_prev)
253 - rc->rrdset_prev->rrdset_next = rc->rrdset_next;
254 -
255 - if(rc->rrdset_next)
256 - rc->rrdset_next->rrdset_prev = rc->rrdset_prev;
260 + DOUBLE_LINKED_LIST_REMOVE_UNSAFE(st->alarms, rc, rrdset_prev, rrdset_next);
261
258 - if(st->alarms == rc)
259 - st->alarms = rc->rrdset_next;
260 -
261 - rc->rrdset_prev = rc->rrdset_next = NULL;
262 -
263 - rrdvar_free(host, &st->rrdvar_root_index, rc->local);
262 + rrdvar_free(host, st->rrdvar_root_index, rc->local);
263 rc->local = NULL;
264
266 - rrdvar_free(host, &st->rrdfamily->rrdvar_root_index, rc->family);
265 + rrdvar_free(host, st->rrdfamily->rrdvar_root_index, rc->family);
266 rc->family = NULL;
267
269 - rrdvar_free(host, &host->rrdvar_root_index, rc->hostid);
268 + rrdvar_free(host, host->rrdvar_root_index, rc->hostid);
269 rc->hostid = NULL;
270
272 - rrdvar_free(host, &host->rrdvar_root_index, rc->hostname);
271 + rrdvar_free(host, host->rrdvar_root_index, rc->hostname);
272 rc->hostname = NULL;
273
274 rc->rrdset = NULL;
@@ -280,18 +279,21 @@ inline void rrdsetcalc_unlink(RRDCALC *rc) {
279 }
280
281 RRDCALC *rrdcalc_find(RRDSET *st, const char *name) {
283 - RRDCALC *rc;
284 - uint32_t hash = simple_hash(name);
282 + RRDCALC *rc = NULL;
283
286 - for( rc = st->alarms; rc ; rc = rc->rrdset_next ) {
287 - if(unlikely(rc->hash == hash && !strcmp(rc->name, name)))
288 - return rc;
284 + STRING *name_string = string_strdupz(name);
285 +
286 + foreach_rrdcalc_in_rrdset(st, rc) {
287 + if(unlikely(rc->name == name_string))
288 + break;
289 }
290
291 - return NULL;
291 + string_freez(name_string);
292 +
293 + return rc;
294 }
295
294 -inline int rrdcalc_exists(RRDHOST *host, const char *chart, const char *name, uint32_t hash_chart, uint32_t hash_name) {
296 +inline int rrdcalc_exists(RRDHOST *host, const char *chart, const char *name) {
297 RRDCALC *rc;
298
299 if(unlikely(!chart)) {
@@ -299,36 +301,39 @@ inline int rrdcalc_exists(RRDHOST *host, const char *chart, const char *name, ui
301 return 1;
302 }
303
302 - if(unlikely(!hash_chart)) hash_chart = simple_hash(chart);
303 - if(unlikely(!hash_name)) hash_name = simple_hash(name);
304 + STRING *name_string = string_strdupz(name);
305 + STRING *chart_string = string_strdupz(chart);
306 + int ret = 0;
307
308 // make sure it does not already exist
306 - for(rc = host->alarms; rc ; rc = rc->next) {
307 - if (unlikely(rc->chart && rc->hash == hash_name && rc->hash_chart == hash_chart && !strcmp(name, rc->name) && !strcmp(chart, rc->chart))) {
308 - debug(D_HEALTH, "Health alarm '%s.%s' already exists in host '%s'.", chart, name, host->hostname);
309 - info("Health alarm '%s.%s' already exists in host '%s'.", chart, name, host->hostname);
310 - return 1;
309 + foreach_rrdcalc_in_rrdhost(host, rc) {
310 + if (unlikely(rc->chart == chart_string && rc->name == name_string)) {
311 + debug(D_HEALTH, "Health alarm '%s/%s' already exists in host '%s'.", chart, name, rrdhost_hostname(host));
312 + info("Health alarm '%s/%s' already exists in host '%s'.", chart, name, rrdhost_hostname(host));
313 + ret = 1;
314 + break;
315 }
316 }
317
314 - return 0;
318 + string_freez(name_string);
319 + string_freez(chart_string);
320 +
321 + return ret;
322 }
323
317 -inline uint32_t rrdcalc_get_unique_id(RRDHOST *host, const char *chart, const char *name, uint32_t *next_event_id) {
318 - if(chart && name) {
319 - uint32_t hash_chart = simple_hash(chart);
320 - uint32_t hash_name = simple_hash(name);
321 -
322 - // re-use old IDs, by looking them up in the alarm log
323 - ALARM_ENTRY *ae;
324 - for(ae = host->health_log.alarms; ae ;ae = ae->next) {
325 - if(unlikely(ae->hash_name == hash_name && ae->hash_chart == hash_chart && !strcmp(name, ae->name) && !strcmp(chart, ae->chart))) {
326 - if(next_event_id) *next_event_id = ae->alarm_event_id + 1;
327 - return ae->alarm_id;
328 - }
324 +inline uint32_t rrdcalc_get_unique_id(RRDHOST *host, STRING *chart, STRING *name, uint32_t *next_event_id) {
325 + // re-use old IDs, by looking them up in the alarm log
326 + ALARM_ENTRY *ae = NULL;
327 + for(ae = host->health_log.alarms; ae ;ae = ae->next) {
328 + if(unlikely(name == ae->name && chart == ae->chart)) {
329 + if(next_event_id) *next_event_id = ae->alarm_event_id + 1;
330 + break;
331 }
332 }
333
334 + if(ae)
335 + return ae->alarm_id;
336 +
337 if (unlikely(!host->health_log.next_alarm_id))
338 host->health_log.next_alarm_id = (uint32_t)now_realtime_sec();
339
@@ -347,7 +352,7 @@ inline uint32_t rrdcalc_get_unique_id(RRDHOST *host, const char *chart, const ch
352 *
353 * @return It returns the new name on success and the old otherwise
354 */
350 -char *alarm_name_with_dim(char *name, size_t namelen, const char *dim, size_t dimlen) {
355 +char *alarm_name_with_dim(const char *name, size_t namelen, const char *dim, size_t dimlen) {
356 char *newname,*move;
357
358 newname = mallocz(namelen + dimlen + 2);
@@ -407,15 +412,7 @@ inline void rrdcalc_add_to_host(RRDHOST *host, RRDCALC *rc) {
412
413 if(!rc->foreachdim) {
414 // link it to the host alarms list
410 - if(likely(host->alarms)) {
411 - // append it
412 - RRDCALC *t;
413 - for(t = host->alarms; t && t->next ; t = t->next) ;
414 - t->next = rc;
415 - }
416 - else {
417 - host->alarms = rc;
418 - }
415 + DOUBLE_LINKED_LIST_APPEND_UNSAFE(host->host_alarms, rc, prev, next);
416
417 // link it to its chart
418 RRDSET *st;
@@ -425,43 +422,33 @@ inline void rrdcalc_add_to_host(RRDHOST *host, RRDCALC *rc) {
422 break;
423 }
424 }
428 - } else {
429 - //link it case there is a foreach
430 - if(likely(host->alarms_with_foreach)) {
431 - // append it
432 - RRDCALC *t;
433 - for(t = host->alarms_with_foreach; t && t->next ; t = t->next) ;
434 - t->next = rc;
435 - }
436 - else {
437 - host->alarms_with_foreach = rc;
438 - }
439 -
440 - //I am not linking this alarm direct to the host here, this will be done when the children is created
425 + }
426 + else {
427 + DOUBLE_LINKED_LIST_APPEND_UNSAFE(host->alarms_with_foreach, rc, prev, next);
428 + // We are not linking this alarm directly to the host here
429 + // It will eventually be done if it matches the dimensions
430 }
431 }
432
433 inline RRDCALC *rrdcalc_create_from_template(RRDHOST *host, RRDCALCTEMPLATE *rt, const char *chart) {
445 - debug(D_HEALTH, "Health creating dynamic alarm (from template) '%s.%s'", chart, rt->name);
434 + debug(D_HEALTH, "Health creating dynamic alarm (from template) '%s.%s'", chart, rrdcalctemplate_name(rt));
435
447 - if(rrdcalc_exists(host, chart, rt->name, 0, 0))
436 + if(rrdcalc_exists(host, chart, rrdcalctemplate_name(rt)))
437 return NULL;
438
439 RRDCALC *rc = callocz(1, sizeof(RRDCALC));
440 rc->next_event_id = 1;
452 - rc->name = strdupz(rt->name);
453 - rc->hash = simple_hash(rc->name);
454 - rc->chart = strdupz(chart);
455 - rc->hash_chart = simple_hash(rc->chart);
441 + rc->name = string_dup(rt->name);
442 + rc->chart = string_strdupz(chart);
443 uuid_copy(rc->config_hash_id, rt->config_hash_id);
444
445 rc->id = rrdcalc_get_unique_id(host, rc->chart, rc->name, &rc->next_event_id);
446
460 - if(rt->dimensions) rc->dimensions = strdupz(rt->dimensions);
461 - if(rt->foreachdim) {
462 - rc->foreachdim = strdupz(rt->foreachdim);
463 - rc->spdim = health_pattern_from_foreach(rc->foreachdim);
464 - }
447 + rc->dimensions = string_dup(rt->dimensions);
448 + rc->foreachdim = string_dup(rt->foreachdim);
449 + if(rt->foreachdim)
450 + rc->spdim = health_pattern_from_foreach(rrdcalc_foreachdim(rc));
451 +
452 rc->foreachcounter = rt->foreachcounter;
453
454 rc->green = rt->green;
@@ -485,55 +472,53 @@ inline RRDCALC *rrdcalc_create_from_template(RRDHOST *host, RRDCALCTEMPLATE *rt,
472 rc->update_every = rt->update_every;
473 rc->options = rt->options;
474
488 - if(rt->exec) rc->exec = strdupz(rt->exec);
489 - if(rt->recipient) rc->recipient = strdupz(rt->recipient);
490 - if(rt->source) rc->source = strdupz(rt->source);
491 - if(rt->units) rc->units = strdupz(rt->units);
492 - if(rt->info) {
493 - rc->info = strdupz(rt->info);
494 - rc->original_info = strdupz(rt->info);
495 - }
475 + rc->exec = string_dup(rt->exec);
476 + rc->recipient = string_dup(rt->recipient);
477 + rc->source = string_dup(rt->source);
478 + rc->units = string_dup(rt->units);
479 + rc->info = string_dup(rt->info);
480 + rc->original_info = string_dup(rt->info);
481
497 - if (rt->classification) rc->classification = strdupz(rt->classification);
498 - if (rt->component) rc->component = strdupz(rt->component);
499 - if (rt->type) rc->type = strdupz(rt->type);
482 + rc->classification = string_dup(rt->classification);
483 + rc->component = string_dup(rt->component);
484 + rc->type = string_dup(rt->type);
485
486 if(rt->calculation) {
487 rc->calculation = expression_parse(rt->calculation->source, NULL, NULL);
488 if(!rc->calculation)
504 - error("Health alarm '%s.%s': failed to parse calculation expression '%s'", chart, rt->name, rt->calculation->source);
489 + error("Health alarm '%s.%s': failed to parse calculation expression '%s'", chart, rrdcalctemplate_name(rt), rt->calculation->source);
490 }
491 if(rt->warning) {
492 rc->warning = expression_parse(rt->warning->source, NULL, NULL);
493 if(!rc->warning)
509 - error("Health alarm '%s.%s': failed to re-parse warning expression '%s'", chart, rt->name, rt->warning->source);
494 + error("Health alarm '%s.%s': failed to re-parse warning expression '%s'", chart, rrdcalctemplate_name(rt), rt->warning->source);
495 }
496 if(rt->critical) {
497 rc->critical = expression_parse(rt->critical->source, NULL, NULL);
498 if(!rc->critical)
514 - error("Health alarm '%s.%s': failed to re-parse critical expression '%s'", chart, rt->name, rt->critical->source);
499 + error("Health alarm '%s.%s': failed to re-parse critical expression '%s'", chart, rrdcalctemplate_name(rt), rt->critical->source);
500 }
501
502 debug(D_HEALTH, "Health runtime added alarm '%s.%s': exec '%s', recipient '%s', green " NETDATA_DOUBLE_FORMAT_AUTO
503 ", red " NETDATA_DOUBLE_FORMAT_AUTO
504 ", lookup: group %d, after %d, before %d, options %u, dimensions '%s', for each dimension '%s', update every %d, calculation '%s', warning '%s', critical '%s', source '%s', delay up %d, delay down %d, delay max %d, delay_multiplier %f, warn_repeat_every %u, crit_repeat_every %u",
520 - (rc->chart)?rc->chart:"NOCHART",
521 - rc->name,
522 - (rc->exec)?rc->exec:"DEFAULT",
523 - (rc->recipient)?rc->recipient:"DEFAULT",
505 + rrdcalc_chart_name(rc),
506 + rrdcalc_name(rc),
507 + (rc->exec)?rrdcalc_exec(rc):"DEFAULT",
508 + (rc->recipient)?rrdcalc_recipient(rc):"DEFAULT",
509 rc->green,
510 rc->red,
511 (int)rc->group,
512 rc->after,
513 rc->before,
514 rc->options,
530 - (rc->dimensions)?rc->dimensions:"NONE",
531 - (rc->foreachdim)?rc->foreachdim:"NONE",
515 + (rc->dimensions)?rrdcalc_dimensions(rc):"NONE",
516 + (rc->foreachdim)?rrdcalc_foreachdim(rc):"NONE",
517 rc->update_every,
518 (rc->calculation)?rc->calculation->parsed_as:"NONE",
519 (rc->warning)?rc->warning->parsed_as:"NONE",
520 (rc->critical)?rc->critical->parsed_as:"NONE",
536 - rc->source,
521 + rrdcalc_source(rc),
522 rc->delay_up_duration,
523 rc->delay_down_duration,
524 rc->delay_max_duration,
@@ -543,13 +528,6 @@ inline RRDCALC *rrdcalc_create_from_template(RRDHOST *host, RRDCALCTEMPLATE *rt,
528 );
529
530 rrdcalc_add_to_host(host, rc);
546 - if(!rt->foreachdim) {
547 - RRDCALC *rdcmp = (RRDCALC *) avl_insert_lock(&(host)->alarms_idx_health_log,(avl_t *)rc);
548 - if (rdcmp != rc) {
549 - error("Cannot insert the alarm index ID %s",rc->name);
550 - }
551 - }
552 -
531 return rc;
532 }
533
@@ -570,14 +548,12 @@ inline RRDCALC *rrdcalc_create_from_rrdcalc(RRDCALC *rc, RRDHOST *host, const ch
548 RRDCALC *newrc = callocz(1, sizeof(RRDCALC));
549
550 newrc->next_event_id = 1;
573 - newrc->id = rrdcalc_get_unique_id(host, rc->chart, name, &rc->next_event_id);
574 - newrc->name = (char *)name;
575 - newrc->hash = simple_hash(newrc->name);
576 - newrc->chart = strdupz(rc->chart);
577 - newrc->hash_chart = simple_hash(rc->chart);
551 + newrc->name = string_strdupz(name);
552 + newrc->chart = string_dup(rc->chart);
553 + newrc->id = rrdcalc_get_unique_id(host, newrc->chart, newrc->name, &rc->next_event_id);
554 uuid_copy(newrc->config_hash_id, *((uuid_t *) &rc->config_hash_id));
555
580 - newrc->dimensions = strdupz(dimension);
556 + newrc->dimensions = string_strdupz(dimension);
557 newrc->foreachdim = NULL;
558 rc->foreachcounter++;
559 newrc->foreachcounter = rc->foreachcounter;
@@ -603,33 +579,33 @@ inline RRDCALC *rrdcalc_create_from_rrdcalc(RRDCALC *rc, RRDHOST *host, const ch
579 newrc->update_every = rc->update_every;
580 newrc->options = rc->options;
581
606 - if(rc->exec) newrc->exec = strdupz(rc->exec);
607 - if(rc->recipient) newrc->recipient = strdupz(rc->recipient);
608 - if(rc->source) newrc->source = strdupz(rc->source);
609 - if(rc->units) newrc->units = strdupz(rc->units);
610 - if(rc->info) newrc->info = strdupz(rc->info);
611 - if(rc->original_info) newrc->original_info = strdupz(rc->original_info);
582 + newrc->exec = string_dup(rc->exec);
583 + newrc->recipient = string_dup(rc->recipient);
584 + newrc->source = string_dup(rc->source);
585 + newrc->units = string_dup(rc->units);
586 + newrc->info = string_dup(rc->info);
587 + newrc->original_info = string_dup(rc->original_info);
588
613 - if (rc->classification) newrc->classification = strdupz(rc->classification);
614 - if (rc->component) newrc->component = strdupz(rc->component);
615 - if (rc->type) newrc->type = strdupz(rc->type);
589 + newrc->classification = string_dup(rc->classification);
590 + newrc->component = string_dup(rc->component);
591 + newrc->type = string_dup(rc->type);
592
593 if(rc->calculation) {
594 newrc->calculation = expression_parse(rc->calculation->source, NULL, NULL);
595 if(!newrc->calculation)
620 - error("Health alarm '%s.%s': failed to parse calculation expression '%s'", rc->chart, rc->name, rc->calculation->source);
596 + error("Health alarm '%s.%s': failed to parse calculation expression '%s'", rrdcalc_chart_name(rc), rrdcalc_name(rc), rc->calculation->source);
597 }
598
599 if(rc->warning) {
600 newrc->warning = expression_parse(rc->warning->source, NULL, NULL);
601 if(!newrc->warning)
626 - error("Health alarm '%s.%s': failed to re-parse warning expression '%s'", rc->chart, rc->name, rc->warning->source);
602 + error("Health alarm '%s.%s': failed to re-parse warning expression '%s'", rrdcalc_chart_name(rc), rrdcalc_name(rc), rc->warning->source);
603 }
604
605 if(rc->critical) {
606 newrc->critical = expression_parse(rc->critical->source, NULL, NULL);
607 if(!newrc->critical)
632 - error("Health alarm '%s.%s': failed to re-parse critical expression '%s'", rc->chart, rc->name, rc->critical->source);
608 + error("Health alarm '%s.%s': failed to re-parse critical expression '%s'", rrdcalc_chart_name(rc), rrdcalc_name(rc), rc->critical->source);
609 }
610
611 return newrc;
@@ -642,86 +618,48 @@ void rrdcalc_free(RRDCALC *rc) {
618 expression_free(rc->warning);
619 expression_free(rc->critical);
620
645 - freez(rc->name);
646 - freez(rc->chart);
647 - freez(rc->family);
648 - freez(rc->dimensions);
649 - freez(rc->foreachdim);
650 - freez(rc->exec);
651 - freez(rc->recipient);
652 - freez(rc->source);
653 - freez(rc->units);
654 - freez(rc->info);
655 - freez(rc->original_info);
656 - freez(rc->classification);
657 - freez(rc->component);
658 - freez(rc->type);
621 + string_freez(rc->name);
622 + string_freez(rc->chart);
623 + string_freez(rc->dimensions);
624 + string_freez(rc->foreachdim);
625 + string_freez(rc->exec);
626 + string_freez(rc->recipient);
627 + string_freez(rc->source);
628 + string_freez(rc->units);
629 + string_freez(rc->info);
630 + string_freez(rc->original_info);
631 + string_freez(rc->classification);
632 + string_freez(rc->component);
633 + string_freez(rc->type);
634 + string_freez(rc->host_labels);
635 + string_freez(rc->module_match);
636 + string_freez(rc->plugin_match);
637 +
638 simple_pattern_free(rc->spdim);
660 - freez(rc->host_labels);
639 simple_pattern_free(rc->host_labels_pattern);
662 - freez(rc->module_match);
640 simple_pattern_free(rc->module_pattern);
664 - freez(rc->plugin_match);
641 simple_pattern_free(rc->plugin_pattern);
642 +
643 + freez(rc->family);
644 freez(rc);
645 }
646
647 void rrdcalc_unlink_and_free(RRDHOST *host, RRDCALC *rc) {
648 if(unlikely(!rc)) return;
649
672 - debug(D_HEALTH, "Health removing alarm '%s.%s' of host '%s'", rc->chart?rc->chart:"NOCHART", rc->name, host->hostname);
650 + debug(D_HEALTH, "Health removing alarm '%s.%s' of host '%s'", rrdcalc_chart_name(rc), rrdcalc_name(rc), rrdhost_hostname(host));
651
652 // unlink it from RRDSET
653 if(rc->rrdset) rrdsetcalc_unlink(rc);
654
655 // unlink it from RRDHOST
678 - if(unlikely(rc == host->alarms))
679 - host->alarms = rc->next;
680 - else {
681 - RRDCALC *t;
682 - for(t = host->alarms; t && t->next != rc; t = t->next) ;
683 - if(t) {
684 - t->next = rc->next;
685 - rc->next = NULL;
686 - }
687 - else
688 - error("Cannot unlink alarm '%s.%s' from host '%s': not found", rc->chart?rc->chart:"NOCHART", rc->name, host->hostname);
689 - }
690 -
691 - RRDCALC *rdcmp = (RRDCALC *) avl_search_lock(&(host)->alarms_idx_health_log, (avl_t *)rc);
692 - if (rdcmp) {
693 - rdcmp = (RRDCALC *) avl_remove_lock(&(host)->alarms_idx_health_log, (avl_t *)rc);
694 - if (!rdcmp) {
695 - error("Cannot remove the health alarm index from health_log");
696 - }
697 - }
698 -
699 - rdcmp = (RRDCALC *) avl_search_lock(&(host)->alarms_idx_name, (avl_t *)rc);
700 - if (rdcmp) {
701 - rdcmp = (RRDCALC *) avl_remove_lock(&(host)->alarms_idx_name, (avl_t *)rc);
702 - if (!rdcmp) {
703 - error("Cannot remove the health alarm index from idx_name");
704 - }
705 - }
656 + DOUBLE_LINKED_LIST_REMOVE_UNSAFE(host->host_alarms, rc, prev, next);
657
658 rrdcalc_free(rc);
659 }
660
661 void rrdcalc_foreach_unlink_and_free(RRDHOST *host, RRDCALC *rc) {
711 -
712 - if(unlikely(rc == host->alarms_with_foreach))
713 - host->alarms_with_foreach = rc->next;
714 - else {
715 - RRDCALC *t;
716 - for(t = host->alarms_with_foreach; t && t->next != rc; t = t->next) ;
717 - if(t) {
718 - t->next = rc->next;
719 - rc->next = NULL;
720 - }
721 - else
722 - error("Cannot unlink alarm '%s.%s' from host '%s': not found", rc->chart?rc->chart:"NOCHART", rc->name, host->hostname);
723 - }
724 -
662 + DOUBLE_LINKED_LIST_REMOVE_UNSAFE(host->alarms_with_foreach, rc, prev, next);
663 rrdcalc_free(rc);
664 }
665
@@ -736,11 +674,11 @@ static void rrdcalc_labels_unlink_alarm_loop(RRDHOST *host, RRDCALC *alarms) {
674
675 if(!rrdlabels_match_simple_pattern_parsed(host->host_labels, rc->host_labels_pattern, '=')) {
676 info("Health configuration for alarm '%s' cannot be applied, because the host %s does not have the label(s) '%s'",
739 - rc->name,
740 - host->hostname,
741 - rc->host_labels);
677 + rrdcalc_name(rc),
678 + rrdhost_hostname(host),
679 + rrdcalc_host_labels(rc));
680
743 - if(host->alarms == alarms)
681 + if(host->host_alarms == alarms)
682 rrdcalc_unlink_and_free(host, rc);
683 else
684 rrdcalc_foreach_unlink_and_free(host, rc);
@@ -750,7 +688,7 @@ static void rrdcalc_labels_unlink_alarm_loop(RRDHOST *host, RRDCALC *alarms) {
688 }
689
690 void rrdcalc_labels_unlink_alarm_from_host(RRDHOST *host) {
753 - rrdcalc_labels_unlink_alarm_loop(host, host->alarms);
691 + rrdcalc_labels_unlink_alarm_loop(host, host->host_alarms);
692 rrdcalc_labels_unlink_alarm_loop(host, host->alarms_with_foreach);
693 }
694
@@ -773,59 +711,3 @@ void rrdcalc_labels_unlink() {
711
712 rrd_unlock();
713 }
776 -
777 -// ----------------------------------------------------------------------------
778 -// Alarm
779 -
780 -
781 -/**
782 - * Alarm is repeating
783 - *
784 - * Is this alarm repeating ?
785 - *
786 - * @param host The structure that has the binary tree
787 - * @param alarm_id the id of the alarm to search
788 - *
789 - * @return It returns 1 case it is repeating and 0 otherwise
790 - */
791 -int alarm_isrepeating(RRDHOST *host, uint32_t alarm_id) {
792 - RRDCALC findme;
793 - findme.id = alarm_id;
794 - RRDCALC *rc = (RRDCALC *)avl_search_lock(&host->alarms_idx_health_log, (avl_t *)&findme);
795 - if (!rc) {
796 - return 0;
797 - }
798 - return rrdcalc_isrepeating(rc);
799 -}
800 -
801 -/**
802 - * Entry is repeating
803 - *
804 - * Check whether the id of alarm entry is yet present in the host structure
805 - *
806 - * @param host The structure that has the binary tree
807 - * @param ae the alarm entry
808 - *
809 - * @return It returns 1 case it is repeating and 0 otherwise
810 - */
811 -int alarm_entry_isrepeating(RRDHOST *host, ALARM_ENTRY *ae) {
812 - return alarm_isrepeating(host, ae->alarm_id);
813 -}
814 -
815 -/**
816 - * Max last repeat
817 - *
818 - * Check the maximum last_repeat for the alarms associated a host
819 - *
820 - * @param host The structure that has the binary tree
821 - *
822 - * @return It returns 1 case it is repeating and 0 otherwise
823 - */
824 -RRDCALC *alarm_max_last_repeat(RRDHOST *host, char *alarm_name,uint32_t hash) {
825 - RRDCALC findme;
826 - findme.name = alarm_name;
827 - findme.hash = hash;
828 - RRDCALC *rc = (RRDCALC *)avl_search_lock(&host->alarms_idx_name, (avl_t *)&findme);
829 -
830 - return rc;
831 -}
database/rrdcalc.h
+81 -61
@@ -33,33 +33,32 @@
33
34 struct rrdcalc {
35 avl_t avl; // the index, with key the id - this has to be first!
36 +
37 uint32_t id; // the unique id of this alarm
38 uint32_t next_event_id; // the next event id that will be used for this alarm
39
39 - char *name; // the name of this alarm
40 - uint32_t hash; // the hash of the alarm name
40 uuid_t config_hash_id; // a predictable hash_id based on specific alert configuration
41
43 - char *exec; // the command to execute when this alarm switches state
44 - char *recipient; // the recipient of the alarm (the first parameter to exec)
42 + STRING *name; // the name of this alarm
43 + STRING *chart; // the chart id this should be linked to
44
46 - char *classification; // the class that this alarm belongs
47 - char *component; // the component that this alarm refers to
48 - char *type; // type of the alarm
45 + STRING *exec; // the command to execute when this alarm switches state
46 + STRING *recipient; // the recipient of the alarm (the first parameter to exec)
47
50 - char *chart; // the chart id this should be linked to
51 - uint32_t hash_chart;
48 + STRING *classification; // the class that this alarm belongs
49 + STRING *component; // the component that this alarm refers to
50 + STRING *type; // type of the alarm
51
53 - char *plugin_match; //the plugin name that should be linked to
52 + STRING *plugin_match; // the plugin name that should be linked to
53 SIMPLE_PATTERN *plugin_pattern;
54
56 - char *module_match; //the module name that should be linked to
55 + STRING *module_match; // the module name that should be linked to
56 SIMPLE_PATTERN *module_pattern;
57
59 - char *source; // the source of this alarm
60 - char *units; // the units of the alarm
61 - char *original_info; // the original info field before any variable replacement
62 - char *info; // a short description of the alarm
58 + STRING *source; // the source of this alarm
59 + STRING *units; // the units of the alarm
60 + STRING *original_info; // the original info field before any variable replacement
61 + STRING *info; // a short description of the alarm
62
63 int update_every; // update frequency for the alarm
64
@@ -70,8 +69,8 @@ struct rrdcalc {
69 // ------------------------------------------------------------------------
70 // database lookup settings
71
73 - char *dimensions; // the chart dimensions
74 - char *foreachdim; // the group of dimensions that the `foreach` will be applied.
72 + STRING *dimensions; // the chart dimensions
73 + STRING *foreachdim; // the group of dimensions that the `foreach` will be applied.
74 SIMPLE_PATTERN *spdim; // used if and only if there is a simple pattern for the chart.
75 int foreachcounter; // the number of alarms created with foreachdim, this also works as an id of the
76 // children
@@ -99,29 +98,29 @@ struct rrdcalc {
98 // ------------------------------------------------------------------------
99 // notification repeat settings
100
102 - uint32_t warn_repeat_every; // interval between repeating warning notifications
103 - uint32_t crit_repeat_every; // interval between repeating critical notifications
101 + uint32_t warn_repeat_every; // interval between repeating warning notifications
102 + uint32_t crit_repeat_every; // interval between repeating critical notifications
103
104 // ------------------------------------------------------------------------
105 // Labels settings
107 - char *host_labels; // the label read from an alarm file
106 + STRING *host_labels; // the label read from an alarm file
107 SIMPLE_PATTERN *host_labels_pattern; // the simple pattern of labels
108
109 // ------------------------------------------------------------------------
110 // runtime information
111
113 - RRDCALC_STATUS old_status; // the old status of the alarm
112 + RRDCALC_STATUS old_status; // the old status of the alarm
113 RRDCALC_STATUS status; // the current status of the alarm
114
116 - NETDATA_DOUBLE value; // the current value of the alarm
117 - NETDATA_DOUBLE old_value; // the previous value of the alarm
115 + NETDATA_DOUBLE value; // the current value of the alarm
116 + NETDATA_DOUBLE old_value; // the previous value of the alarm
117
118 uint32_t rrdcalc_flags; // check RRDCALC_FLAG_*
119
120 time_t last_updated; // the last update timestamp of the alarm
121 time_t next_update; // the next update timestamp of the alarm
122 time_t last_status_change; // the timestamp of the last time this alarm changed status
124 - time_t last_repeat; // the last time the alarm got repeated
123 + time_t last_repeat; // the last time the alarm got repeated
124 uint32_t times_repeat; // number of times the alarm got repeated
125
126 time_t db_after; // the first timestamp evaluated by the db lookup
@@ -150,49 +149,70 @@ struct rrdcalc {
149 struct rrdcalc *rrdset_prev;
150
151 struct rrdcalc *next;
152 + struct rrdcalc *prev;
153 };
154
155 +#define rrdcalc_name(rc) string2str((rc)->name)
156 +#define rrdcalc_chart_name(rc) string2str((rc)->chart)
157 +#define rrdcalc_exec(rc) string2str((rc)->exec)
158 +#define rrdcalc_recipient(rc) string2str((rc)->recipient)
159 +#define rrdcalc_classification(rc) string2str((rc)->classification)
160 +#define rrdcalc_component(rc) string2str((rc)->component)
161 +#define rrdcalc_type(rc) string2str((rc)->type)
162 +#define rrdcalc_plugin_match(rc) string2str((rc)->plugin_match)
163 +#define rrdcalc_module_match(rc) string2str((rc)->module_match)
164 +#define rrdcalc_source(rc) string2str((rc)->source)
165 +#define rrdcalc_units(rc) string2str((rc)->units)
166 +#define rrdcalc_original_info(rc) string2str((rc)->original_info)
167 +#define rrdcalc_info(rc) string2str((rc)->info)
168 +#define rrdcalc_dimensions(rc) string2str((rc)->dimensions)
169 +#define rrdcalc_foreachdim(rc) string2str((rc)->foreachdim)
170 +#define rrdcalc_host_labels(rc) string2str((rc)->host_labels)
171 +
172 +#define foreach_rrdcalc_in_rrdset(st, rc) \
173 + DOUBLE_LINKED_LIST_FOREACH_FORWARD((st)->alarms, rc, rrdset_prev, rrdset_next)
174 +
175 +#define foreach_rrdcalc_in_rrdhost(host, rc) \
176 + DOUBLE_LINKED_LIST_FOREACH_FORWARD((host)->host_alarms, rc, prev, next)
177 +
178 struct alert_config {
156 - char *alarm;
157 - char *template_key;
158 - char *os;
159 - char *host;
160 - char *on;
161 - char *families;
162 - char *plugin;
163 - char *module;
164 - char *charts;
165 - char *lookup;
166 - char *calc;
167 - char *warn;
168 - char *crit;
169 - char *every;
170 - char *green;
171 - char *red;
172 - char *exec;
173 - char *to;
174 - char *units;
175 - char *info;
176 - char *classification;
177 - char *component;
178 - char *type;
179 - char *delay;
180 - char *options;
181 - char *repeat;
182 - char *host_labels;
183 -
184 - char *p_db_lookup_dimensions;
185 - char *p_db_lookup_method;
179 + STRING *alarm;
180 + STRING *template_key;
181 + STRING *os;
182 + STRING *host;
183 + STRING *on;
184 + STRING *families;
185 + STRING *plugin;
186 + STRING *module;
187 + STRING *charts;
188 + STRING *lookup;
189 + STRING *calc;
190 + STRING *warn;
191 + STRING *crit;
192 + STRING *every;
193 + STRING *green;
194 + STRING *red;
195 + STRING *exec;
196 + STRING *to;
197 + STRING *units;
198 + STRING *info;
199 + STRING *classification;
200 + STRING *component;
201 + STRING *type;
202 + STRING *delay;
203 + STRING *options;
204 + STRING *repeat;
205 + STRING *host_labels;
206 +
207 + STRING *p_db_lookup_dimensions;
208 + STRING *p_db_lookup_method;
209 +
210 uint32_t p_db_lookup_options;
211 int32_t p_db_lookup_after;
212 int32_t p_db_lookup_before;
213 int32_t p_update_every;
214 };
215
192 -extern int alarm_isrepeating(RRDHOST *host, uint32_t alarm_id);
193 -extern int alarm_entry_isrepeating(RRDHOST *host, ALARM_ENTRY *ae);
194 -extern RRDCALC *alarm_max_last_repeat(RRDHOST *host, char *alarm_name, uint32_t hash);
195 -
216 #define RRDCALC_HAS_DB_LOOKUP(rc) ((rc)->after)
217
218 extern void rrdsetcalc_link_matching(RRDSET *st);
@@ -204,13 +224,13 @@ extern const char *rrdcalc_status2string(RRDCALC_STATUS status);
224 extern void rrdcalc_free(RRDCALC *rc);
225 extern void rrdcalc_unlink_and_free(RRDHOST *host, RRDCALC *rc);
226
207 -extern int rrdcalc_exists(RRDHOST *host, const char *chart, const char *name, uint32_t hash_chart, uint32_t hash_name);
208 -extern uint32_t rrdcalc_get_unique_id(RRDHOST *host, const char *chart, const char *name, uint32_t *next_event_id);
227 +extern int rrdcalc_exists(RRDHOST *host, const char *chart, const char *name);
228 +extern uint32_t rrdcalc_get_unique_id(RRDHOST *host, STRING *chart, STRING *name, uint32_t *next_event_id);
229 extern RRDCALC *rrdcalc_create_from_template(RRDHOST *host, RRDCALCTEMPLATE *rt, const char *chart);
230 extern RRDCALC *rrdcalc_create_from_rrdcalc(RRDCALC *rc, RRDHOST *host, const char *name, const char *dimension);
231 extern void rrdcalc_add_to_host(RRDHOST *host, RRDCALC *rc);
232 extern void dimension_remove_pipe_comma(char *str);
213 -extern char *alarm_name_with_dim(char *name, size_t namelen, const char *dim, size_t dimlen);
233 +extern char *alarm_name_with_dim(const char *name, size_t namelen, const char *dim, size_t dimlen);
234 extern void rrdcalc_update_rrdlabels(RRDSET *st);
235
236 extern void rrdcalc_labels_unlink();
database/rrdcalctemplate.c
+30 -45
@@ -12,30 +12,30 @@
12 * @param st is the chart where the alarm will be attached.
13 */
14 void rrdcalctemplate_check_conditions_and_link(RRDCALCTEMPLATE *rt, RRDSET *st, RRDHOST *host) {
15 - if(rt->hash_context != st->hash_context || strcmp(rt->context, st->context) != 0)
15 + if(rt->context != st->context)
16 return;
17
18 - if (rt->charts_pattern && !simple_pattern_matches(rt->charts_pattern, st->name))
18 + if (rt->charts_pattern && !simple_pattern_matches(rt->charts_pattern, rrdset_name(st)))
19 return;
20
21 - if (rt->family_pattern && !simple_pattern_matches(rt->family_pattern, st->family))
21 + if (rt->family_pattern && !simple_pattern_matches(rt->family_pattern, rrdset_family(st)))
22 return;
23
24 - if (rt->module_pattern && !simple_pattern_matches(rt->module_pattern, st->module_name))
24 + if (rt->module_pattern && !simple_pattern_matches(rt->module_pattern, rrdset_module_name(st)))
25 return;
26
27 - if (rt->plugin_pattern && !simple_pattern_matches(rt->plugin_pattern, st->plugin_name))
27 + if (rt->plugin_pattern && !simple_pattern_matches(rt->plugin_pattern, rrdset_plugin_name(st)))
28 return;
29
30 if(host->host_labels && rt->host_labels_pattern && !rrdlabels_match_simple_pattern_parsed(host->host_labels, rt->host_labels_pattern, '='))
31 return;
32
33 - RRDCALC *rc = rrdcalc_create_from_template(host, rt, st->id);
33 + RRDCALC *rc = rrdcalc_create_from_template(host, rt, rrdset_id(st));
34 if (unlikely(!rc))
35 - info("Health tried to create alarm from template '%s' on chart '%s' of host '%s', but it failed", rt->name, st->id, host->hostname);
35 + info("Health tried to create alarm from template '%s' on chart '%s' of host '%s', but it failed", rrdcalctemplate_name(rt), rrdset_id(st), rrdhost_hostname(host));
36 #ifdef NETDATA_INTERNAL_CHECKS
37 - else if (rc->rrdset != st && !rc->foreachdim) //When we have a template with foreadhdim, the child will be added to the index late
38 - error("Health alarm '%s.%s' should be linked to chart '%s', but it is not", rc->chart ? rc->chart : "NOCHART", rc->name, st->id);
37 + else if (rc->rrdset != st && !rc->foreachdim) //When we have a template with foreachdim, the child will be added to the index late
38 + error("Health alarm '%s.%s' should be linked to chart '%s', but it is not", rrdcalc_chart_name(rc), rrdcalc_name(rc), rrdset_id(st));
39 #endif
40 }
41
@@ -43,10 +43,7 @@ void rrdcalctemplate_link_matching(RRDSET *st) {
43 RRDHOST *host = st->rrdhost;
44 RRDCALCTEMPLATE *rt;
45
46 - for(rt = host->templates; rt ; rt = rt->next)
47 - rrdcalctemplate_check_conditions_and_link(rt, st, host);
48 -
49 - for(rt = host->alarms_template_with_foreach; rt ; rt = rt->next)
46 + foreach_rrdcalctemplate_in_rrdhost(host, rt)
47 rrdcalctemplate_check_conditions_and_link(rt, st, host);
48 }
49
@@ -57,31 +54,31 @@ inline void rrdcalctemplate_free(RRDCALCTEMPLATE *rt) {
54 expression_free(rt->warning);
55 expression_free(rt->critical);
56
60 - freez(rt->family_match);
57 + string_freez(rt->family_match);
58 simple_pattern_free(rt->family_pattern);
59
63 - freez(rt->plugin_match);
60 + string_freez(rt->plugin_match);
61 simple_pattern_free(rt->plugin_pattern);
62
66 - freez(rt->module_match);
63 + string_freez(rt->module_match);
64 simple_pattern_free(rt->module_pattern);
65
69 - freez(rt->charts_match);
66 + string_freez(rt->charts_match);
67 simple_pattern_free(rt->charts_pattern);
68
72 - freez(rt->name);
73 - freez(rt->exec);
74 - freez(rt->recipient);
75 - freez(rt->classification);
76 - freez(rt->component);
77 - freez(rt->type);
78 - freez(rt->context);
79 - freez(rt->source);
80 - freez(rt->units);
81 - freez(rt->info);
82 - freez(rt->dimensions);
83 - freez(rt->foreachdim);
84 - freez(rt->host_labels);
69 + string_freez(rt->name);
70 + string_freez(rt->exec);
71 + string_freez(rt->recipient);
72 + string_freez(rt->classification);
73 + string_freez(rt->component);
74 + string_freez(rt->type);
75 + string_freez(rt->context);
76 + string_freez(rt->source);
77 + string_freez(rt->units);
78 + string_freez(rt->info);
79 + string_freez(rt->dimensions);
80 + string_freez(rt->foreachdim);
81 + string_freez(rt->host_labels);
82 simple_pattern_free(rt->spdim);
83 simple_pattern_free(rt->host_labels_pattern);
84 freez(rt);
@@ -90,21 +87,9 @@ inline void rrdcalctemplate_free(RRDCALCTEMPLATE *rt) {
87 inline void rrdcalctemplate_unlink_and_free(RRDHOST *host, RRDCALCTEMPLATE *rt) {
88 if(unlikely(!rt)) return;
89
93 - debug(D_HEALTH, "Health removing template '%s' of host '%s'", rt->name, host->hostname);
94 -
95 - if(host->templates == rt) {
96 - host->templates = rt->next;
97 - }
98 - else {
99 - RRDCALCTEMPLATE *t;
100 - for (t = host->templates; t && t->next != rt; t = t->next ) ;
101 - if(t) {
102 - t->next = rt->next;
103 - rt->next = NULL;
104 - }
105 - else
106 - error("Cannot find RRDCALCTEMPLATE '%s' linked in host '%s'", rt->name, host->hostname);
107 - }
90 + debug(D_HEALTH, "Health removing template '%s' of host '%s'", rrdcalctemplate_name(rt), rrdhost_hostname(host));
91 +
92 + DOUBLE_LINKED_LIST_REMOVE_UNSAFE(host->alarms_templates, rt, prev, next);
93
94 rrdcalctemplate_free(rt);
95 }
database/rrdcalctemplate.h
+39 -19
@@ -9,35 +9,34 @@
9 // these are to be applied to charts found dynamically
10 // based on their context.
11 struct rrdcalctemplate {
12 - char *name;
13 - uint32_t hash_name;
12 uuid_t config_hash_id;
13
16 - char *exec;
17 - char *recipient;
14 + STRING *name;
15
19 - char *classification;
20 - char *component;
21 - char *type;
16 + STRING *exec;
17 + STRING *recipient;
18
23 - char *context;
24 - uint32_t hash_context;
19 + STRING *classification;
20 + STRING *component;
21 + STRING *type;
22
26 - char *family_match;
23 + STRING *context;
24 +
25 + STRING *family_match;
26 SIMPLE_PATTERN *family_pattern;
27
29 - char *plugin_match;
28 + STRING *plugin_match;
29 SIMPLE_PATTERN *plugin_pattern;
30
32 - char *module_match;
31 + STRING *module_match;
32 SIMPLE_PATTERN *module_pattern;
33
35 - char *charts_match;
34 + STRING *charts_match;
35 SIMPLE_PATTERN *charts_pattern;
36
38 - char *source; // the source of this alarm
39 - char *units; // the units of the alarm
40 - char *info; // a short description of the alarm
37 + STRING *source; // the source of this alarm
38 + STRING *units; // the units of the alarm
39 + STRING *info; // a short description of the alarm
40
41 int update_every; // update frequency for the alarm
42
@@ -48,8 +47,8 @@ struct rrdcalctemplate {
47 // ------------------------------------------------------------------------
48 // database lookup settings
49
51 - char *dimensions; // the chart dimensions
52 - char *foreachdim; // the group of dimensions that the lookup will be applied.
50 + STRING *dimensions; // the chart dimensions
51 + STRING *foreachdim; // the group of dimensions that the lookup will be applied.
52 SIMPLE_PATTERN *spdim; // used if and only if there is a simple pattern for the chart.
53 int foreachcounter; // the number of alarms created with foreachdim, this also works as an id of the
54 // children
@@ -74,7 +73,7 @@ struct rrdcalctemplate {
73
74 // ------------------------------------------------------------------------
75 // Labels settings
77 - char *host_labels; // the label read from an alarm file
76 + STRING *host_labels; // the label read from an alarm file
77 SIMPLE_PATTERN *host_labels_pattern; // the simple pattern of labels
78
79 // ------------------------------------------------------------------------
@@ -85,8 +84,29 @@ struct rrdcalctemplate {
84 EVAL_EXPRESSION *critical;
85
86 struct rrdcalctemplate *next;
87 + struct rrdcalctemplate *prev;
88 };
89
90 +#define foreach_rrdcalctemplate_in_rrdhost(host, rt) \
91 + DOUBLE_LINKED_LIST_FOREACH_FORWARD((host)->alarms_templates, rt, prev, next)
92 +
93 +#define rrdcalctemplate_name(rt) string2str((rt)->name)
94 +#define rrdcalctemplate_exec(rt) string2str((rt)->exec)
95 +#define rrdcalctemplate_recipient(rt) string2str((rt)->recipient)
96 +#define rrdcalctemplate_classification(rt) string2str((rt)->classification)
97 +#define rrdcalctemplate_component(rt) string2str((rt)->component)
98 +#define rrdcalctemplate_type(rt) string2str((rt)->type)
99 +#define rrdcalctemplate_family_match(rt) string2str((rt)->family_match)
100 +#define rrdcalctemplate_plugin_match(rt) string2str((rt)->plugin_match)
101 +#define rrdcalctemplate_module_match(rt) string2str((rt)->module_match)
102 +#define rrdcalctemplate_charts_match(rt) string2str((rt)->charts_match)
103 +#define rrdcalctemplate_units(rt) string2str((rt)->units)
104 +#define rrdcalctemplate_info(rt) string2str((rt)->info)
105 +#define rrdcalctemplate_source(rt) string2str((rt)->source)
106 +#define rrdcalctemplate_dimensions(rt) string2str((rt)->dimensions)
107 +#define rrdcalctemplate_foreachdim(rt) string2str((rt)->foreachdim)
108 +#define rrdcalctemplate_host_labels(rt) string2str((rt)->host_labels)
109 +
110 #define RRDCALCTEMPLATE_HAS_DB_LOOKUP(rt) ((rt)->after)
111
112 extern void rrdcalctemplate_link_matching(RRDSET *st);
database/rrdcontext.c
+212 -232
@@ -14,7 +14,6 @@ int rrdcontext_enabled = CONFIG_BOOLEAN_YES;
14 #define RRDCONTEXT_MINIMUM_ALLOWED_PRIORITY 10
15
16 // #define LOG_TRANSITIONS 1
17 -// #define LOG_RRDINSTANCES 1
17
18 typedef enum {
19 RRD_FLAG_NONE = 0,
@@ -49,6 +48,9 @@ typedef enum {
48 RRD_FLAG_UPDATE_REASON_DB_ROTATION = (1 << 28), // this context changed because of a db rotation
49 RRD_FLAG_UPDATE_REASON_UNUSED = (1 << 29), // this context is not used anymore
50 RRD_FLAG_UPDATE_REASON_CHANGED_FLAGS = (1 << 30), // this context is not used anymore
51 +
52 + // DO NOT ADD (1 << 31) or bigger!
53 + // runtime error: left shift of 1 by 31 places cannot be represented in type 'int'
54 } RRD_FLAGS;
55
56 #define RRD_FLAG_ALL_UPDATE_REASONS ( \
@@ -85,10 +87,6 @@ typedef enum {
87 #define RRD_FLAGS_PREVENTING_DELETIONS ( \
88 RRD_FLAG_QUEUED \
89 |RRD_FLAG_COLLECTED \
88 - |RRD_FLAG_UPDATE_REASON_LOAD_SQL \
89 - |RRD_FLAG_UPDATE_REASON_NEW_OBJECT \
90 - |RRD_FLAG_UPDATE_REASON_UPDATED_OBJECT \
91 - |RRD_FLAG_UPDATE_REASON_CHANGED_LINKING \
90 )
91
92 #define rrd_flag_set_updated(obj, reason) (obj)->flags |= (RRD_FLAG_UPDATED | (reason))
@@ -295,6 +293,8 @@ static void rrdcontext_recalculate_host_retention(RRDHOST *host, RRD_FLAGS reaso
293 #define rrdcontext_version_hash(host) rrdcontext_version_hash_with_callback(host, NULL, false, NULL)
294 static uint64_t rrdcontext_version_hash_with_callback(RRDHOST *host, void (*callback)(RRDCONTEXT *, bool, void *), bool snapshot, void *bundle);
295
296 +static void rrdcontext_garbage_collect_single_host(RRDHOST *host, bool worker);
297 +static void rrdcontext_garbage_collect(void);
298 void rrdcontext_delete_from_sql_unsafe(RRDCONTEXT *rc);
299
300 #define rrdcontext_lock(rc) netdata_mutex_lock(&((rc)->mutex))
@@ -303,9 +303,9 @@ void rrdcontext_delete_from_sql_unsafe(RRDCONTEXT *rc);
303 // ----------------------------------------------------------------------------
304 // Updates triggers
305
306 -static void rrdmetric_trigger_updates(RRDMETRIC *rm, bool force, bool escalate);
307 -static void rrdinstance_trigger_updates(RRDINSTANCE *ri, bool force, bool escalate);
308 -static void rrdcontext_trigger_updates(RRDCONTEXT *rc, bool force);
306 +static void rrdmetric_trigger_updates(RRDMETRIC *rm, bool force, bool escalate, const char *function);
307 +static void rrdinstance_trigger_updates(RRDINSTANCE *ri, bool force, bool escalate, const char *function);
308 +static void rrdcontext_trigger_updates(RRDCONTEXT *rc, bool force, const char *function);
309
310 // ----------------------------------------------------------------------------
311 // visualizing flags
@@ -354,109 +354,46 @@ static void rrd_reasons_to_buffer(RRD_FLAGS flags, BUFFER *wb) {
354 // logging of all data collected
355
356 #ifdef LOG_TRANSITIONS
357 -static void log_transition(STRING *metric, STRING *instance, STRING *context, RRD_FLAGS flags, const char *msg) {
357 +static void log_transition(RRDMETRIC *rm, RRDINSTANCE *ri, RRDCONTEXT *rc, const char *function) {
358 BUFFER *wb = buffer_create(1000);
359 + const char *triggered_on = "triggered on ";
360 +
361 + buffer_sprintf(wb, "RRD TRANSITION: %s() ", function);
362
360 - buffer_sprintf(wb, "RRD TRANSITION: context '%s'", string2str(context));
363 + if(rm) {
364 + buffer_sprintf(wb, "%smetric '%s' of ", triggered_on, string2str(rm->id));
365 + triggered_on = "";
366 + }
367
362 - if(instance)
363 - buffer_sprintf(wb, ", instance '%s'", string2str(instance));
368 + if(ri) {
369 + buffer_sprintf(wb, "%sinstance '%s' of ", triggered_on, string2str(ri->id));
370 + triggered_on = "";
371 + }
372
365 - if(metric)
366 - buffer_sprintf(wb, ", metric '%s'", string2str(metric));
373 + buffer_sprintf(wb, "%scontext '%s' ", triggered_on, string2str(rc->id));
374
368 - buffer_sprintf(wb, ", triggered by %s: ", msg);
375 + RRD_FLAGS flags = rc->flags;
376 + const char *we_are = "context";
377 + if(ri) {
378 + flags = ri->flags;
379 + we_are = "instance";
380 + }
381 + if(rm) {
382 + flags = rm->flags;
383 + we_are = "metric";
384 + }
385
386 + buffer_sprintf(wb, "%s flags: ", we_are);
387 rrd_flags_to_buffer(flags, wb);
388
372 - buffer_strcat(wb, ", reasons: ");
373 -
389 + buffer_strcat(wb, ", having reasons: ");
390 rrd_reasons_to_buffer(flags, wb);
391
392 internal_error(true, "%s", buffer_tostring(wb));
393 buffer_free(wb);
394 }
395 #else
380 -#define log_transition(metric, instance, context, flags, msg) debug_dummy()
381 -#endif
382 -
383 -#ifdef LOG_RRDINSTANCES
384 -static void rrdinstance_log(RRDINSTANCE *ri, const char *msg) {
385 - char uuid[UUID_STR_LEN];
386 -
387 - uuid_unparse(ri->uuid, uuid);
388 -
389 - BUFFER *wb = buffer_create(1000);
390 -
391 - buffer_sprintf(wb,
392 - "RRDINSTANCE: %s id '%s' (host '%s'), uuid '%s', name '%s', context '%s', title '%s', units '%s', family '%s', priority %zu, chart type '%s', update every %d, rrdset '%s', flags %s%s%s%s%s%s%s%s, first_time_t %ld, last_time_t %ld",
393 - msg,
394 - string2str(ri->id),
395 - ri->rc->rrdhost->hostname,
396 - uuid,
397 - string2str(ri->name),
398 - string2str(ri->rc->id),
399 - string2str(ri->title),
400 - string2str(ri->units),
401 - string2str(ri->family),
402 - ri->priority,
403 - rrdset_type_name(ri->chart_type),
404 - ri->update_every,
405 - ri->rrdset?ri->rrdset->id:"NONE",
406 - ri->flags & RRD_FLAG_DELETED ?"DELETED ":"",
407 - ri->flags & RRD_FLAG_UPDATED ?"UPDATED ":"",
408 - rrd_flag_is_collected(ri) ?"COLLECTED ":"",
409 - rrd_flag_is_archived(ri) ?"ARCHIVED ":"",
410 - ri->flags & RRD_FLAG_OWNLABELS ?"OWNLABELS ":"",
411 - ri->flags & RRD_FLAG_LIVE_RETENTION ?"LIVE ":"",
412 - ri->flags & RRD_FLAG_QUEUED ?"QUEUED ":"",
413 - ri->flags & RRD_FLAG_DONT_TRIGGER ?"BLOCKED ":"",
414 - ri->first_time_t,
415 - ri->last_time_t
416 - );
417 -
418 - buffer_strcat(wb, ", update reasons: { ");
419 - for(int i = 0, added = 0; rrdcontext_reasons[i].name ;i++)
420 - if(ri->flags & rrdcontext_reasons[i].flag) {
421 - if(added) buffer_strcat(wb, ", ");
422 - buffer_strcat(wb, rrdcontext_reasons[i].name);
423 - added++;
424 - }
425 - buffer_strcat(wb, " }");
426 -
427 - buffer_strcat(wb, ", labels: { ");
428 - if(ri->rrdlabels) {
429 - if(!rrdlabels_to_buffer(ri->rrdlabels, wb, "", "=", "'", ", ", NULL, NULL, NULL, NULL))
430 - buffer_strcat(wb, "EMPTY }");
431 - else
432 - buffer_strcat(wb, " }");
433 - }
434 - else
435 - buffer_strcat(wb, "NONE }");
436 -
437 - buffer_strcat(wb, ", metrics: { ");
438 - if(ri->rrdmetrics) {
439 - RRDMETRIC *v;
440 - int i = 0;
441 - dfe_start_read((DICTIONARY *)ri->rrdmetrics, v) {
442 - buffer_sprintf(wb, "%s%s", i?",":"", v_name);
443 - i++;
444 - }
445 - dfe_done(v);
446 -
447 - if(!i)
448 - buffer_strcat(wb, "EMPTY }");
449 - else
450 - buffer_strcat(wb, " }");
451 - }
452 - else
453 - buffer_strcat(wb, "NONE }");
454 -
455 - internal_error(true, "%s", buffer_tostring(wb));
456 - buffer_free(wb);
457 -}
458 -#else
459 -#define rrdinstance_log(ir, msg) debug_dummy()
396 +#define log_transition(rm, ri, rc, function) debug_dummy()
397 #endif
398
399 // ----------------------------------------------------------------------------
@@ -577,7 +514,7 @@ static void rrdmetric_conflict_callback(const char *id __maybe_unused, void *old
514 char uuid1[UUID_STR_LEN], uuid2[UUID_STR_LEN];
515 uuid_unparse(rm->uuid, uuid1);
516 uuid_unparse(rm_new->uuid, uuid2);
580 - internal_error(true, "RRDMETRIC: '%s' is linked to RRDDIM '%s' but they have different UUIDs. RRDMETRIC has '%s', RRDDIM has '%s'", string2str(rm->id), rm->rrddim->id, uuid1, uuid2);
517 + internal_error(true, "RRDMETRIC: '%s' is linked to RRDDIM '%s' but they have different UUIDs. RRDMETRIC has '%s', RRDDIM has '%s'", string2str(rm->id), rrddim_id(rm->rrddim), uuid1, uuid2);
518 }
519
520 if(rm->rrddim != rm_new->rrddim)
@@ -616,7 +553,7 @@ static void rrdmetric_conflict_callback(const char *id __maybe_unused, void *old
553 static void rrdmetric_react_callback(const char *id __maybe_unused, void *value, void *data __maybe_unused) {
554 RRDMETRIC *rm = value;
555
619 - rrdmetric_trigger_updates(rm, false, true);
556 + rrdmetric_trigger_updates(rm, false, true, __FUNCTION__);
557 }
558
559 static void rrdmetrics_create(RRDINSTANCE *ri) {
@@ -649,8 +586,8 @@ static inline bool rrdmetric_should_be_deleted(RRDMETRIC *rm) {
586 if(likely(rm->rrddim))
587 return false;
588
652 - if((now_realtime_usec() - rm->created_ut) < 600 * USEC_PER_SEC)
653 - return false;
589 + //if((now_realtime_usec() - rm->created_ut) < 600 * USEC_PER_SEC)
590 + // return false;
591
592 rrdmetric_update_retention(rm);
593 if(rm->first_time_t || rm->last_time_t)
@@ -659,38 +596,37 @@ static inline bool rrdmetric_should_be_deleted(RRDMETRIC *rm) {
596 return true;
597 }
598
662 -static void rrdmetric_trigger_updates(RRDMETRIC *rm, bool force, bool escalate) {
599 +static void rrdmetric_trigger_updates(RRDMETRIC *rm, bool force, bool escalate, const char *function __maybe_unused) {
600 if(likely(!force && !(rm->flags & RRD_FLAG_UPDATED))) return;
601
665 - if(unlikely(rrd_flag_is_collected(rm) && !rm->rrddim))
666 - rrd_flag_set_archived(rm);
602 + // logs and statistics
603 + log_transition(rm, rm->ri, rm->ri->rc, function);
604 + rrdcontext_triggered_update_on_rrdmetric();
605
668 - if(unlikely((rm->flags & RRD_FLAG_UPDATE_REASON_DISCONNECTED_CHILD) && rrd_flag_is_collected(rm)))
669 - rrd_flag_set_archived(rm);
606 + if(unlikely(rrd_flag_is_collected(rm)) && (!rm->rrddim || rm->flags & RRD_FLAG_UPDATE_REASON_DISCONNECTED_CHILD))
607 + rrd_flag_set_archived(rm);
608
609 rrdmetric_update_retention(rm);
610
673 - if(unlikely(escalate && rm->flags & RRD_FLAG_UPDATED && !(rm->ri->flags & RRD_FLAG_DONT_PROCESS))) {
674 - log_transition(rm->id, rm->ri->id, rm->ri->rc->id, rm->flags, "RRDMETRIC");
675 - rrdinstance_trigger_updates(rm->ri, true, true);
676 - }
611 + if(unlikely(escalate && rm->flags & RRD_FLAG_UPDATED))
612 + rrdinstance_trigger_updates(rm->ri, true, true, __FUNCTION__);
613 }
614
615 static inline void rrdmetric_from_rrddim(RRDDIM *rd) {
616 if(unlikely(!rd->rrdset))
681 - fatal("RRDMETRIC: rrddim '%s' does not have a rrdset.", rd->id);
617 + fatal("RRDMETRIC: rrddim '%s' does not have a rrdset.", rrddim_id(rd));
618
619 if(unlikely(!rd->rrdset->rrdhost))
684 - fatal("RRDMETRIC: rrdset '%s' does not have a rrdhost", rd->rrdset->id);
620 + fatal("RRDMETRIC: rrdset '%s' does not have a rrdhost", rrdset_id(rd->rrdset));
621
622 if(unlikely(!rd->rrdset->rrdinstance))
687 - fatal("RRDMETRIC: rrdset '%s' does not have a rrdinstance", rd->rrdset->id);
623 + fatal("RRDMETRIC: rrdset '%s' does not have a rrdinstance", rrdset_id(rd->rrdset));
624
625 RRDINSTANCE *ri = rrdinstance_acquired_value(rd->rrdset->rrdinstance);
626
627 RRDMETRIC trm = {
692 - .id = string_strdupz(rd->id),
693 - .name = string_strdupz(rd->name),
628 + .id = string_dup(rd->id),
629 + .name = string_dup(rd->name),
630 .flags = RRD_FLAG_NONE,
631 .rrddim = rd,
632 };
@@ -707,14 +643,14 @@ static inline void rrdmetric_from_rrddim(RRDDIM *rd) {
643 #define rrddim_get_rrdmetric(rd) rrddim_get_rrdmetric_with_trace(rd, __FUNCTION__)
644 static inline RRDMETRIC *rrddim_get_rrdmetric_with_trace(RRDDIM *rd, const char *function) {
645 if(unlikely(!rd->rrdmetric)) {
710 - error("RRDMETRIC: RRDDIM '%s' is not linked to an RRDMETRIC at %s()", rd->id, function);
646 + error("RRDMETRIC: RRDDIM '%s' is not linked to an RRDMETRIC at %s()", rrddim_id(rd), function);
647 return NULL;
648 }
649
650 RRDMETRIC *rm = rrdmetric_acquired_value(rd->rrdmetric);
651
652 if(unlikely(rm->rrddim != rd))
717 - fatal("RRDMETRIC: '%s' is not linked to RRDDIM '%s' at %s()", string2str(rm->id), rd->id, function);
653 + fatal("RRDMETRIC: '%s' is not linked to RRDDIM '%s' at %s()", string2str(rm->id), rrddim_id(rd), function);
654
655 return rm;
656 }
@@ -727,7 +663,7 @@ static inline void rrdmetric_rrddim_is_freed(RRDDIM *rd) {
663 rrd_flag_set_archived(rm);
664
665 rm->rrddim = NULL;
730 - rrdmetric_trigger_updates(rm, false, true);
666 + rrdmetric_trigger_updates(rm, false, true, __FUNCTION__);
667 rrdmetric_release(rd->rrdmetric);
668 rd->rrdmetric = NULL;
669 }
@@ -736,12 +672,12 @@ static inline void rrdmetric_updated_rrddim_flags(RRDDIM *rd) {
672 RRDMETRIC *rm = rrddim_get_rrdmetric(rd);
673 if(unlikely(!rm)) return;
674
739 - if(unlikely(rd->flags & (RRDDIM_FLAG_ARCHIVED | RRDDIM_FLAG_OBSOLETE))) {
675 + if(unlikely(rrddim_flag_check(rd, RRDDIM_FLAG_ARCHIVED|RRDDIM_FLAG_OBSOLETE))) {
676 if(unlikely(rrd_flag_is_collected(rm)))
677 rrd_flag_set_archived(rm);
678 }
679
744 - rrdmetric_trigger_updates(rm, false, true);
680 + rrdmetric_trigger_updates(rm, false, true, __FUNCTION__);
681 }
682
683 static inline void rrdmetric_collected_rrddim(RRDDIM *rd) {
@@ -751,7 +687,7 @@ static inline void rrdmetric_collected_rrddim(RRDDIM *rd) {
687 if(unlikely(!rrd_flag_is_collected(rm)))
688 rrd_flag_set_collected(rm);
689
754 - rrdmetric_trigger_updates(rm, false, true);
690 + rrdmetric_trigger_updates(rm, false, true, __FUNCTION__);
691 }
692
693 // ----------------------------------------------------------------------------
@@ -807,7 +743,7 @@ static void rrdinstance_insert_callback(const char *id __maybe_unused, void *val
743 }
744
745 if(ri->rrdset) {
810 - if(unlikely((ri->rrdset->flags & RRDSET_FLAG_HIDDEN) || (ri->rrdset->state && ri->rrdset->state->is_ar_chart)))
746 + if(unlikely((rrdset_flag_check(ri->rrdset, RRDSET_FLAG_HIDDEN)) || (ri->rrdset->state && ri->rrdset->state->is_ar_chart)))
747 ri->flags |= RRD_FLAG_HIDDEN;
748 else
749 ri->flags &= ~RRD_FLAG_HIDDEN;
@@ -818,7 +754,6 @@ static void rrdinstance_insert_callback(const char *id __maybe_unused, void *val
754 ri->flags |= RRD_FLAG_HIDDEN;
755
756 rrdmetrics_create(ri);
821 - rrdinstance_log(ri, "INSERT");
757
758 // signal the react callback to do the job
759 rrd_flag_set_updated(ri, RRD_FLAG_UPDATE_REASON_NEW_OBJECT);
@@ -829,8 +764,6 @@ static void rrdinstance_delete_callback(const char *id, void *value, void *data)
764 RRDCONTEXT *rc = data; (void)rc;
765 RRDINSTANCE *ri = (RRDINSTANCE *)value;
766
832 - rrdinstance_log(ri, "DELETE");
833 -
767 internal_error(ri->rrdset, "RRDINSTANCE: '%s' is freed but there is a RRDSET linked to it.", string2str(ri->id));
768
769 rrdinstance_free(ri);
@@ -858,7 +791,7 @@ static void rrdinstance_conflict_callback(const char *id __maybe_unused, void *o
791 char uuid1[UUID_STR_LEN], uuid2[UUID_STR_LEN];
792 uuid_unparse(ri->uuid, uuid1);
793 uuid_unparse(*ri->rrdset->chart_uuid, uuid2);
861 - internal_error(true, "RRDINSTANCE: '%s' is linked to RRDSET '%s' but they have different UUIDs. RRDINSTANCE has '%s', RRDSET has '%s'", string2str(ri->id), ri->rrdset->id, uuid1, uuid2);
794 + internal_error(true, "RRDINSTANCE: '%s' is linked to RRDSET '%s' but they have different UUIDs. RRDINSTANCE has '%s', RRDSET has '%s'", string2str(ri->id), rrdset_id(ri->rrdset), uuid1, uuid2);
795 }
796
797 if(ri->name != ri_new->name) {
@@ -920,7 +853,7 @@ static void rrdinstance_conflict_callback(const char *id __maybe_unused, void *o
853 }
854
855 if(ri->rrdset) {
923 - if(unlikely((ri->rrdset->flags & RRDSET_FLAG_HIDDEN) || (ri->rrdset->state && ri->rrdset->state->is_ar_chart)))
856 + if(unlikely((rrdset_flag_check(ri->rrdset, RRDSET_FLAG_HIDDEN)) || (ri->rrdset->state && ri->rrdset->state->is_ar_chart)))
857 ri->flags |= RRD_FLAG_HIDDEN;
858 else
859 ri->flags &= ~RRD_FLAG_HIDDEN;
@@ -934,8 +867,6 @@ static void rrdinstance_conflict_callback(const char *id __maybe_unused, void *o
867 if(ri->flags & RRD_FLAG_UPDATED)
868 ri->flags |= RRD_FLAG_UPDATE_REASON_UPDATED_OBJECT;
869
937 - rrdinstance_log(ri, "CONFLICT");
938 -
870 // free the new one
871 rrdinstance_free(ri_new);
872
@@ -945,7 +876,7 @@ static void rrdinstance_conflict_callback(const char *id __maybe_unused, void *o
876 static void rrdinstance_react_callback(const char *id __maybe_unused, void *value, void *data __maybe_unused) {
877 RRDINSTANCE *ri = value;
878
948 - rrdinstance_trigger_updates(ri, false, true);
879 + rrdinstance_trigger_updates(ri, false, true, __FUNCTION__);
880 }
881
882 void rrdinstances_create(RRDCONTEXT *rc) {
@@ -993,10 +924,14 @@ static inline bool rrdinstance_should_be_deleted(RRDINSTANCE *ri) {
924 return true;
925 }
926
996 -static void rrdinstance_trigger_updates(RRDINSTANCE *ri, bool force, bool escalate) {
927 +static void rrdinstance_trigger_updates(RRDINSTANCE *ri, bool force, bool escalate, const char *function __maybe_unused) {
928 if(unlikely(ri->flags & RRD_FLAG_DONT_PROCESS)) return;
929 if(unlikely(!force && !(ri->flags & RRD_FLAG_UPDATED))) return;
930
931 + // logs and stats
932 + log_transition(NULL, ri, ri->rc, function);
933 + rrdcontext_triggered_update_on_rrdinstance();
934 +
935 if(likely(ri->rrdset)) {
936 if(unlikely(ri->rrdset->priority != ri->priority)) {
937 ri->priority = ri->rrdset->priority;
@@ -1015,10 +950,10 @@ static void rrdinstance_trigger_updates(RRDINSTANCE *ri, bool force, bool escala
950 time_t min_first_time_t = LONG_MAX, max_last_time_t = 0;
951 size_t metrics_active = 0, metrics_deleted = 0;
952 bool live_retention = true, currently_collected = false;
1018 - {
953 + if(dictionary_stats_entries(ri->rrdmetrics) > 0) {
954 RRDMETRIC *rm;
955 dfe_start_read((DICTIONARY *)ri->rrdmetrics, rm) {
1021 - if(!(rm->flags & RRD_FLAG_LIVE_RETENTION))
956 + if(unlikely(!(rm->flags & RRD_FLAG_LIVE_RETENTION)))
957 live_retention = false;
958
959 if (unlikely((rrdmetric_should_be_deleted(rm)))) {
@@ -1027,7 +962,7 @@ static void rrdinstance_trigger_updates(RRDINSTANCE *ri, bool force, bool escala
962 continue;
963 }
964
1030 - if(rm->flags & RRD_FLAG_COLLECTED)
965 + if(rm->flags & RRD_FLAG_COLLECTED && rm->first_time_t)
966 currently_collected = true;
967
968 metrics_active++;
@@ -1043,9 +978,9 @@ static void rrdinstance_trigger_updates(RRDINSTANCE *ri, bool force, bool escala
978 dfe_done(rm);
979 }
980
1046 - if(live_retention && !(ri->flags & RRD_FLAG_LIVE_RETENTION))
981 + if(unlikely(live_retention && !(ri->flags & RRD_FLAG_LIVE_RETENTION)))
982 ri->flags |= RRD_FLAG_LIVE_RETENTION;
1048 - else if(!live_retention && (ri->flags & RRD_FLAG_LIVE_RETENTION))
983 + else if(unlikely(!live_retention && (ri->flags & RRD_FLAG_LIVE_RETENTION)))
984 ri->flags &= ~RRD_FLAG_LIVE_RETENTION;
985
986 if(unlikely(!metrics_active)) {
@@ -1080,7 +1015,7 @@ static void rrdinstance_trigger_updates(RRDINSTANCE *ri, bool force, bool escala
1015 rrd_flag_set_updated(ri, RRD_FLAG_UPDATE_REASON_CHANGED_LAST_TIME_T);
1016 }
1017
1083 - if(unlikely(live_retention))
1018 + if(likely(live_retention))
1019 rrd_flag_set_deleted(ri, RRD_FLAG_UPDATE_REASON_ZERO_RETENTION);
1020 }
1021 else {
@@ -1103,18 +1038,16 @@ static void rrdinstance_trigger_updates(RRDINSTANCE *ri, bool force, bool escala
1038 }
1039 }
1040
1106 - if(unlikely(escalate && ri->flags & RRD_FLAG_UPDATED && !(ri->rc->flags & RRD_FLAG_DONT_PROCESS))) {
1107 - log_transition(NULL, ri->id, ri->rc->id, ri->flags, "RRDINSTANCE");
1108 - rrdcontext_trigger_updates(ri->rc, true);
1109 - }
1041 + if(unlikely(escalate && ri->flags & RRD_FLAG_UPDATED))
1042 + rrdcontext_trigger_updates(ri->rc, true, __FUNCTION__);
1043 }
1044
1045 static inline void rrdinstance_from_rrdset(RRDSET *st) {
1046 RRDCONTEXT trc = {
1114 - .id = string_strdupz(st->context),
1115 - .title = string_strdupz(st->title),
1116 - .units = string_strdupz(st->units),
1117 - .family = string_strdupz(st->family),
1047 + .id = string_dup(st->context),
1048 + .title = string_dup(st->title),
1049 + .units = string_dup(st->units),
1050 + .family = string_dup(st->family),
1051 .priority = st->priority,
1052 .chart_type = st->chart_type,
1053 .flags = RRD_FLAG_NONE,
@@ -1125,11 +1058,11 @@ static inline void rrdinstance_from_rrdset(RRDSET *st) {
1058 RRDCONTEXT *rc = rrdcontext_acquired_value(rca);
1059
1060 RRDINSTANCE tri = {
1128 - .id = string_strdupz(st->id),
1129 - .name = string_strdupz(st->name),
1130 - .units = string_strdupz(st->units),
1131 - .family = string_strdupz(st->family),
1132 - .title = string_strdupz(st->title),
1061 + .id = string_dup(st->id),
1062 + .name = string_dup(st->name),
1063 + .units = string_dup(st->units),
1064 + .family = string_dup(st->family),
1065 + .title = string_dup(st->title),
1066 .chart_type = st->chart_type,
1067 .priority = st->priority,
1068 .update_every = st->update_every,
@@ -1192,7 +1125,7 @@ static inline void rrdinstance_from_rrdset(RRDSET *st) {
1125 ri_old->flags &= ~RRD_FLAG_DONT_PROCESS;
1126 rc_old->flags &= ~RRD_FLAG_DONT_PROCESS;
1127
1195 - rrdinstance_trigger_updates(ri_old, true, true);
1128 + rrdinstance_trigger_updates(ri_old, true, true, __FUNCTION__);
1129
1130 ri_old->flags |= RRD_FLAG_DONT_PROCESS;
1131 rrdinstance_release(ria_old);
@@ -1205,10 +1138,10 @@ static inline void rrdinstance_from_rrdset(RRDSET *st) {
1138 rc_old->first_time_t = 0;
1139 rc_old->last_time_t = 0;
1140 rrdcontext_unlock(rc_old);
1208 - rrdcontext_trigger_updates(rc_old, true);
1141 + rrdcontext_trigger_updates(rc_old, true, __FUNCTION__);
1142 }
1143 else
1211 - rrdcontext_trigger_updates(rc_old, true);
1144 + rrdcontext_trigger_updates(rc_old, true, __FUNCTION__);
1145 */
1146
1147 rrdcontext_release(rca_old);
@@ -1223,14 +1156,14 @@ static inline void rrdinstance_from_rrdset(RRDSET *st) {
1156 #define rrdset_get_rrdinstance(st) rrdset_get_rrdinstance_with_trace(st, __FUNCTION__);
1157 static inline RRDINSTANCE *rrdset_get_rrdinstance_with_trace(RRDSET *st, const char *function) {
1158 if(unlikely(!st->rrdinstance)) {
1226 - error("RRDINSTANCE: RRDSET '%s' is not linked to an RRDINSTANCE at %s()", st->id, function);
1159 + error("RRDINSTANCE: RRDSET '%s' is not linked to an RRDINSTANCE at %s()", rrdset_id(st), function);
1160 return NULL;
1161 }
1162
1163 RRDINSTANCE *ri = rrdinstance_acquired_value(st->rrdinstance);
1164
1165 if(unlikely(ri->rrdset != st))
1233 - fatal("RRDINSTANCE: '%s' is not linked to RRDSET '%s' at %s()", string2str(ri->id), st->id, function);
1166 + fatal("RRDINSTANCE: '%s' is not linked to RRDSET '%s' at %s()", string2str(ri->id), rrdset_id(st), function);
1167
1168 return ri;
1169 }
@@ -1250,7 +1183,7 @@ static inline void rrdinstance_rrdset_is_freed(RRDSET *st) {
1183 ri->rrdset = NULL;
1184
1185 ri->flags &= ~RRD_FLAG_DONT_PROCESS;
1253 - rrdinstance_trigger_updates(ri, false, true);
1186 + rrdinstance_trigger_updates(ri, false, true, __FUNCTION__);
1187 ri->flags |= RRD_FLAG_DONT_PROCESS;
1188
1189 rrdinstance_release(st->rrdinstance);
@@ -1267,26 +1200,26 @@ static inline void rrdinstance_updated_rrdset_name(RRDSET *st) {
1200 RRDINSTANCE *ri = rrdset_get_rrdinstance(st);
1201 if(unlikely(!ri)) return;
1202
1270 - STRING *old = ri->name;
1271 - ri->name = string_strdupz(st->name);
1203 + if(st->name != ri->name) {
1204 + STRING *old = ri->name;
1205 + ri->name = string_dup(st->name);
1206 + string_freez(old);
1207
1273 - if(ri->name != old)
1208 rrd_flag_set_updated(ri, RRD_FLAG_UPDATE_REASON_CHANGED_NAME);
1275 -
1276 - string_freez(old);
1277 -
1278 - rrdinstance_trigger_updates(ri, false, true);
1209 + rrdinstance_trigger_updates(ri, false, true, __FUNCTION__);
1210 + }
1211 }
1212
1213 static inline void rrdinstance_updated_rrdset_flags_no_action(RRDINSTANCE *ri, RRDSET *st) {
1282 - if(unlikely(st->flags & (RRDSET_FLAG_ARCHIVED | RRDSET_FLAG_OBSOLETE)))
1283 - rrd_flag_set_archived(ri);
1214 + if(unlikely(ri->rrdset != st))
1215 + fatal("RRDCONTEXT: instance '%s' is not linked to chart '%s' on host '%s'",
1216 + string2str(ri->id), rrdset_id(st), rrdhost_hostname(st->rrdhost));
1217
1285 - if(unlikely((st->flags & RRDSET_FLAG_HIDDEN) && !(ri->flags & RRD_FLAG_HIDDEN))) {
1218 + if(unlikely((rrdset_flag_check(st, RRDSET_FLAG_HIDDEN)) && !(ri->flags & RRD_FLAG_HIDDEN))) {
1219 ri->flags |= RRD_FLAG_HIDDEN;
1220 rrd_flag_set_updated(ri, RRD_FLAG_UPDATE_REASON_CHANGED_FLAGS);
1221 }
1289 - else if(unlikely(!(st->flags & RRDSET_FLAG_HIDDEN) && (ri->flags & RRD_FLAG_HIDDEN))) {
1222 + else if(unlikely(!(rrdset_flag_check(st, RRDSET_FLAG_HIDDEN)) && (ri->flags & RRD_FLAG_HIDDEN))) {
1223 ri->flags &= ~RRD_FLAG_HIDDEN;
1224 rrd_flag_set_updated(ri, RRD_FLAG_UPDATE_REASON_CHANGED_FLAGS);
1225 }
@@ -1296,10 +1229,13 @@ static inline void rrdinstance_updated_rrdset_flags(RRDSET *st) {
1229 RRDINSTANCE *ri = rrdset_get_rrdinstance(st);
1230 if(unlikely(!ri)) return;
1231
1232 + if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_ARCHIVED|RRDSET_FLAG_OBSOLETE)))
1233 + rrd_flag_set_archived(ri);
1234 +
1235 rrdinstance_updated_rrdset_flags_no_action(ri, st);
1236
1237 ri->flags &= ~RRD_FLAG_DONT_PROCESS;
1302 - rrdinstance_trigger_updates(ri, false, true);
1238 + rrdinstance_trigger_updates(ri, false, true, __FUNCTION__);
1239 ri->flags |= RRD_FLAG_DONT_PROCESS;
1240 }
1241
@@ -1309,13 +1245,16 @@ static inline void rrdinstance_collected_rrdset(RRDSET *st) {
1245
1246 rrdinstance_updated_rrdset_flags_no_action(ri, st);
1247
1312 - if(unlikely(!rrd_flag_is_collected(ri)))
1313 - rrd_flag_set_collected(ri);
1248 + if(dictionary_stats_entries(ri->rrdmetrics) > 0) {
1249
1315 - if(unlikely(ri->flags & RRD_FLAG_DONT_PROCESS))
1316 - ri->flags &= ~RRD_FLAG_DONT_PROCESS;
1250 + if(unlikely(!rrd_flag_is_collected(ri)))
1251 + rrd_flag_set_collected(ri);
1252 +
1253 + if(unlikely(ri->flags & RRD_FLAG_DONT_PROCESS))
1254 + ri->flags &= ~RRD_FLAG_DONT_PROCESS;
1255
1318 - rrdinstance_trigger_updates(ri, false, true);
1256 + rrdinstance_trigger_updates(ri, false, true, __FUNCTION__);
1257 + }
1258 }
1259
1260 // ----------------------------------------------------------------------------
@@ -1595,7 +1534,7 @@ static void rrdcontext_conflict_callback(const char *id, void *oldv, void *newv,
1534 static void rrdcontext_react_callback(const char *id __maybe_unused, void *value, void *data __maybe_unused) {
1535 RRDCONTEXT *rc = (RRDCONTEXT *)value;
1536
1598 - rrdcontext_trigger_updates(rc, false);
1537 + rrdcontext_trigger_updates(rc, false, __FUNCTION__);
1538 }
1539
1540 void rrdhost_create_rrdcontexts(RRDHOST *host) {
@@ -1649,17 +1588,21 @@ static inline bool rrdcontext_should_be_deleted(RRDCONTEXT *rc) {
1588 return true;
1589 }
1590
1652 -static void rrdcontext_trigger_updates(RRDCONTEXT *rc, bool force) {
1591 +static void rrdcontext_trigger_updates(RRDCONTEXT *rc, bool force, const char *function __maybe_unused) {
1592 if(unlikely(rc->flags & RRD_FLAG_DONT_PROCESS)) return;
1593 if(unlikely(!force && !(rc->flags & RRD_FLAG_UPDATED))) return;
1594
1595 + // logs and stats
1596 + log_transition(NULL, NULL, rc, function);
1597 + rrdcontext_triggered_update_on_rrdcontext();
1598 +
1599 rrdcontext_lock(rc);
1600
1601 size_t min_priority = LONG_MAX;
1602 time_t min_first_time_t = LONG_MAX, max_last_time_t = 0;
1603 size_t instances_active = 0, instances_deleted = 0;
1604 bool live_retention = true, currently_collected = false, hidden = true;
1662 - {
1605 + if(dictionary_stats_entries(rc->rrdinstances) > 0) {
1606 RRDINSTANCE *ri;
1607 dfe_start_read(rc->rrdinstances, ri) {
1608 if(likely(!(ri->flags & RRD_FLAG_HIDDEN)))
@@ -1674,7 +1617,7 @@ static void rrdcontext_trigger_updates(RRDCONTEXT *rc, bool force) {
1617 continue;
1618 }
1619
1677 - if(ri->flags & RRD_FLAG_COLLECTED)
1620 + if(ri->flags & RRD_FLAG_COLLECTED && ri->first_time_t)
1621 currently_collected = true;
1622
1623 internal_error(rc->units != ri->units,
@@ -1768,8 +1711,6 @@ static void rrdcontext_trigger_updates(RRDCONTEXT *rc, bool force) {
1711 }
1712
1713 if(unlikely(rc->flags & RRD_FLAG_UPDATED)) {
1771 - log_transition(NULL, NULL, rc->id, rc->flags, "RRDCONTEXT");
1772 -
1714 if(check_if_cloud_version_changed_unsafe(rc, false)) {
1715 rc->version = rrdcontext_get_next_version(rc);
1716
@@ -1945,7 +1886,7 @@ void rrdcontext_hub_checkpoint_command(void *ptr) {
1886
1887 if(rrdhost_flag_check(host, RRDHOST_FLAG_ACLK_STREAM_CONTEXTS)) {
1888 info("RRDCONTEXT: received checkpoint command for claim id '%s', node id '%s', while node '%s' has an active context streaming.",
1948 - cmd->claim_id, cmd->node_id, host->hostname);
1889 + cmd->claim_id, cmd->node_id, rrdhost_hostname(host));
1890
1891 // disable it temporarily, so that our worker will not attempt to send messages in parallel
1892 rrdhost_flag_clear(host, RRDHOST_FLAG_ACLK_STREAM_CONTEXTS);
@@ -1955,7 +1896,7 @@ void rrdcontext_hub_checkpoint_command(void *ptr) {
1896
1897 if(cmd->version_hash != our_version_hash) {
1898 error("RRDCONTEXT: received version hash %"PRIu64" for host '%s', does not match our version hash %"PRIu64". Sending snapshot of all contexts.",
1958 - cmd->version_hash, host->hostname, our_version_hash);
1899 + cmd->version_hash, rrdhost_hostname(host), our_version_hash);
1900
1901 #ifdef ENABLE_ACLK
1902 // prepare the snapshot
@@ -1977,11 +1918,11 @@ void rrdcontext_hub_checkpoint_command(void *ptr) {
1918 #endif
1919 }
1920
1980 - internal_error(true, "RRDCONTEXT: host '%s' enabling streaming of contexts", host->hostname);
1921 + internal_error(true, "RRDCONTEXT: host '%s' enabling streaming of contexts", rrdhost_hostname(host));
1922 rrdhost_flag_set(host, RRDHOST_FLAG_ACLK_STREAM_CONTEXTS);
1923 char node_str[UUID_STR_LEN];
1924 uuid_unparse_lower(*host->node_id, node_str);
1984 - log_access("ACLK REQ [%s (%s)]: STREAM CONTEXTS ENABLED", node_str, host->hostname);
1925 + log_access("ACLK REQ [%s (%s)]: STREAM CONTEXTS ENABLED", node_str, rrdhost_hostname(host));
1926 }
1927
1928 void rrdcontext_hub_stop_streaming_command(void *ptr) {
@@ -2006,12 +1947,12 @@ void rrdcontext_hub_stop_streaming_command(void *ptr) {
1947
1948 if(!rrdhost_flag_check(host, RRDHOST_FLAG_ACLK_STREAM_CONTEXTS)) {
1949 error("RRDCONTEXT: received stop streaming command for claim id '%s', node id '%s', but node '%s' does not have active context streaming. Ignoring command.",
2009 - cmd->claim_id, cmd->node_id, host->hostname);
1950 + cmd->claim_id, cmd->node_id, rrdhost_hostname(host));
1951
1952 return;
1953 }
1954
2014 - internal_error(true, "RRDCONTEXT: host '%s' disabling streaming of contexts", host->hostname);
1955 + internal_error(true, "RRDCONTEXT: host '%s' disabling streaming of contexts", rrdhost_hostname(host));
1956 rrdhost_flag_clear(host, RRDHOST_FLAG_ACLK_STREAM_CONTEXTS);
1957 }
1958
@@ -2378,7 +2319,7 @@ static inline int rrdcontext_to_json_callback(const char *id, void *value, void
2319
2320 int rrdcontext_to_json(RRDHOST *host, BUFFER *wb, time_t after, time_t before, RRDCONTEXT_TO_JSON_OPTIONS options, const char *context, SIMPLE_PATTERN *chart_label_key, SIMPLE_PATTERN *chart_labels_filter, SIMPLE_PATTERN *chart_dimensions) {
2321 if(!host->rrdctx) {
2381 - error("%s(): request for host '%s' that does not have rrdcontexts initialized.", __FUNCTION__, host->hostname);
2322 + error("%s(): request for host '%s' that does not have rrdcontexts initialized.", __FUNCTION__, rrdhost_hostname(host));
2323 return HTTP_RESP_NOT_FOUND;
2324 }
2325
@@ -2418,7 +2359,7 @@ int rrdcontext_to_json(RRDHOST *host, BUFFER *wb, time_t after, time_t before, R
2359
2360 int rrdcontexts_to_json(RRDHOST *host, BUFFER *wb, time_t after, time_t before, RRDCONTEXT_TO_JSON_OPTIONS options, SIMPLE_PATTERN *chart_label_key, SIMPLE_PATTERN *chart_labels_filter, SIMPLE_PATTERN *chart_dimensions) {
2361 if(!host->rrdctx) {
2421 - error("%s(): request for host '%s' that does not have rrdcontexts initialized.", __FUNCTION__, host->hostname);
2362 + error("%s(): request for host '%s' that does not have rrdcontexts initialized.", __FUNCTION__, rrdhost_hostname(host));
2363 return HTTP_RESP_NOT_FOUND;
2364 }
2365
@@ -2440,7 +2381,7 @@ int rrdcontexts_to_json(RRDHOST *host, BUFFER *wb, time_t after, time_t before,
2381 ",\n\t\"machine_guid\": \"%s\""
2382 ",\n\t\"node_id\": \"%s\""
2383 ",\n\t\"claim_id\": \"%s\""
2443 - , host->hostname
2384 + , rrdhost_hostname(host)
2385 , host->machine_guid
2386 , node_uuid
2387 , host->aclk_state.claimed_id ? host->aclk_state.claimed_id : ""
@@ -2529,7 +2470,7 @@ static void rrdinstance_load_chart_callback(SQL_CHART_DATA *sc, void *data) {
2470 ctx_get_dimension_list(&ri->uuid, rrdinstance_load_dimension, ri);
2471 ctx_get_label_list(&ri->uuid, rrdinstance_load_clabel, ri);
2472 ri->flags &= ~RRD_FLAG_DONT_PROCESS;
2532 - rrdinstance_trigger_updates(ri, true, true);
2473 + rrdinstance_trigger_updates(ri, true, true, __FUNCTION__);
2474
2475 // let the instance be in "don't process" mode
2476 // so that we process it once, when it is collected
@@ -2568,9 +2509,11 @@ void rrdhost_load_rrdcontext_data(RRDHOST *host) {
2509 RRDCONTEXT *rc;
2510 dfe_start_read((DICTIONARY *)host->rrdctx, rc) {
2511 rc->flags &= ~RRD_FLAG_DONT_PROCESS;
2571 - rrdcontext_trigger_updates(rc, true);
2512 + rrdcontext_trigger_updates(rc, true, __FUNCTION__);
2513 }
2514 dfe_done(rc);
2515 +
2516 + rrdcontext_garbage_collect_single_host(host, false);
2517 }
2518
2519 // ----------------------------------------------------------------------------
@@ -2679,19 +2622,18 @@ static void rrdcontext_recalculate_context_retention(RRDCONTEXT *rc, RRD_FLAGS r
2622
2623 rrd_flag_set_updated(rm, reason);
2624
2682 - rm->flags &= ~RRD_FLAG_DONT_PROCESS;
2683 - rrdmetric_trigger_updates(rm, true, false);
2625 + rrdmetric_trigger_updates(rm, true, false, __FUNCTION__);
2626 }
2627 dfe_done(rm);
2628
2629 ri->flags &= ~RRD_FLAG_DONT_PROCESS;
2688 - rrdinstance_trigger_updates(ri, true, false);
2630 + rrdinstance_trigger_updates(ri, true, false, __FUNCTION__);
2631 ri->flags |= RRD_FLAG_DONT_PROCESS;
2632 }
2633 dfe_done(ri);
2634
2635 rc->flags &= ~RRD_FLAG_DONT_PROCESS;
2694 - rrdcontext_trigger_updates(rc, true);
2636 + rrdcontext_trigger_updates(rc, true, __FUNCTION__);
2637 }
2638
2639 static void rrdcontext_recalculate_host_retention(RRDHOST *host, RRD_FLAGS reason, int job_id) {
@@ -2727,50 +2669,88 @@ void rrdcontext_delete_from_sql_unsafe(RRDCONTEXT *rc) {
2669 error("RRDCONTEXT: failed to delete context '%s' version %"PRIu64" from SQL.", rc->hub.id, rc->hub.version);
2670 }
2671
2730 -static void rrdcontext_garbage_collect(void) {
2731 - rrd_rdlock();
2732 - RRDHOST *host;
2733 - rrdhost_foreach_read(host) {
2734 - RRDCONTEXT *rc;
2735 - dfe_start_write((DICTIONARY *)host->rrdctx, rc) {
2736 - worker_is_busy(WORKER_JOB_CLEANUP);
2672 +static void rrdcontext_garbage_collect_single_host(RRDHOST *host, bool worker) {
2673
2738 - rrdcontext_lock(rc);
2674 + internal_error(true, "RRDCONTEXT: garbage collecting context structures of host '%s'", rrdhost_hostname(host));
2675
2740 - if(unlikely(rrdcontext_should_be_deleted(rc))) {
2741 - worker_is_busy(WORKER_JOB_CLEANUP_DELETE);
2742 - rrdcontext_delete_from_sql_unsafe(rc);
2676 + RRDCONTEXT *rc;
2677 + dfe_start_write((DICTIONARY *)host->rrdctx, rc) {
2678 + if(worker) worker_is_busy(WORKER_JOB_CLEANUP);
2679
2744 - if(dictionary_del_having_write_lock((DICTIONARY *)host->rrdctx, string2str(rc->id)) != 0)
2745 - error("RRDCONTEXT: '%s' of host '%s' failed to be deleted from rrdcontext dictionary.",
2746 - string2str(rc->id), host->hostname);
2747 - }
2748 - else {
2749 - RRDINSTANCE *ri;
2750 - dfe_start_write(rc->rrdinstances, ri) {
2751 - if(rrdinstance_should_be_deleted(ri)) {
2752 - worker_is_busy(WORKER_JOB_CLEANUP_DELETE);
2753 - dictionary_del_having_write_lock(rc->rrdinstances, string2str(ri->id));
2754 - }
2755 - else {
2756 - RRDMETRIC *rm;
2757 - dfe_start_write(ri->rrdmetrics, rm) {
2758 - if(rrdmetric_should_be_deleted(rm)) {
2759 - worker_is_busy(WORKER_JOB_CLEANUP_DELETE);
2760 - dictionary_del_having_write_lock(ri->rrdmetrics, string2str(rm->id));
2761 - }
2762 - }
2763 - dfe_done(rm);
2764 - }
2680 + rrdcontext_lock(rc);
2681 +
2682 + RRDINSTANCE *ri;
2683 + dfe_start_write(rc->rrdinstances, ri) {
2684 + RRDMETRIC *rm;
2685 + dfe_start_write(ri->rrdmetrics, rm) {
2686 + if(rrdmetric_should_be_deleted(rm)) {
2687 + if(worker) worker_is_busy(WORKER_JOB_CLEANUP_DELETE);
2688 + if(dictionary_del_having_write_lock(ri->rrdmetrics, string2str(rm->id)) != 0)
2689 + error("RRDCONTEXT: metric '%s' of instance '%s' of context '%s' of host '%s', failed to be deleted from rrdmetrics dictionary.",
2690 + string2str(rm->id),
2691 + string2str(ri->id),
2692 + string2str(rc->id),
2693 + rrdhost_hostname(host));
2694 + else
2695 + internal_error(
2696 + true,
2697 + "RRDCONTEXT: metric '%s' of instance '%s' of context '%s' of host '%s', deleted from rrdmetrics dictionary.",
2698 + string2str(rm->id),
2699 + string2str(ri->id),
2700 + string2str(rc->id),
2701 + rrdhost_hostname(host));
2702 }
2766 - dfe_done(ri);
2703 }
2704 + dfe_done(rm);
2705 +
2706 + if(rrdinstance_should_be_deleted(ri)) {
2707 + if(worker) worker_is_busy(WORKER_JOB_CLEANUP_DELETE);
2708 + if(dictionary_del_having_write_lock(rc->rrdinstances, string2str(ri->id)) != 0)
2709 + error("RRDCONTEXT: instance '%s' of context '%s' of host '%s', failed to be deleted from rrdmetrics dictionary.",
2710 + string2str(ri->id),
2711 + string2str(rc->id),
2712 + rrdhost_hostname(host));
2713 + else
2714 + internal_error(
2715 + true,
2716 + "RRDCONTEXT: instance '%s' of context '%s' of host '%s', deleted from rrdmetrics dictionary.",
2717 + string2str(ri->id),
2718 + string2str(rc->id),
2719 + rrdhost_hostname(host));
2720 + }
2721 + }
2722 + dfe_done(ri);
2723
2769 - // the item is referenced in the dictionary
2770 - // so, it is still here to unlock, even if we have deleted it
2771 - rrdcontext_unlock(rc);
2724 + if(unlikely(rrdcontext_should_be_deleted(rc))) {
2725 + if(worker) worker_is_busy(WORKER_JOB_CLEANUP_DELETE);
2726 + rrdcontext_delete_from_sql_unsafe(rc);
2727 +
2728 + if(dictionary_del_having_write_lock((DICTIONARY *)host->rrdctx, string2str(rc->id)) != 0)
2729 + error("RRDCONTEXT: context '%s' of host '%s', failed to be deleted from rrdmetrics dictionary.",
2730 + string2str(rc->id),
2731 + rrdhost_hostname(host));
2732 + else
2733 + internal_error(
2734 + true,
2735 + "RRDCONTEXT: context '%s' of host '%s', deleted from rrdmetrics dictionary.",
2736 + string2str(rc->id),
2737 + rrdhost_hostname(host));
2738 +
2739 + fprintf(stderr, "RRDCONTEXT: deleted context '%s'", string2str(rc->id));
2740 }
2773 - dfe_done(rc);
2741 +
2742 + // the item is referenced in the dictionary
2743 + // so, it is still here to unlock, even if we have deleted it
2744 + rrdcontext_unlock(rc);
2745 + }
2746 + dfe_done(rc);
2747 +}
2748 +
2749 +static void rrdcontext_garbage_collect(void) {
2750 + rrd_rdlock();
2751 + RRDHOST *host;
2752 + rrdhost_foreach_read(host) {
2753 + rrdcontext_garbage_collect_single_host(host, true);
2754 }
2755 rrd_unlock();
2756 }
@@ -2895,7 +2875,7 @@ void *rrdcontext_main(void *ptr) {
2875 // delete it from the master dictionary
2876 if(dictionary_del((DICTIONARY *)host->rrdctx, string2str(rc->id)) != 0)
2877 error("RRDCONTEXT: '%s' of host '%s' failed to be deleted from rrdcontext dictionary.",
2898 - string2str(id), host->hostname);
2878 + string2str(id), rrdhost_hostname(host));
2879
2880 string_freez(id);
2881 }
database/rrddim.c
+88 -95
@@ -10,48 +10,59 @@
10 // ----------------------------------------------------------------------------
11 // RRDDIM index
12
13 -int rrddim_compare(void* a, void* b) {
14 - if(((RRDDIM *)a)->hash < ((RRDDIM *)b)->hash) return -1;
15 - else if(((RRDDIM *)a)->hash > ((RRDDIM *)b)->hash) return 1;
16 - else return strcmp(((RRDDIM *)a)->id, ((RRDDIM *)b)->id);
13 +static inline void rrddim_index_add(RRDSET *st, RRDDIM *rd) {
14 + if(likely(dictionary_set(st->rrddim_root_index, string2str(rd->id), rd, sizeof(RRDDIM)) == rd)) {
15 + rrddim_flag_set(rd, RRDDIM_FLAG_INDEXED_ID);
16 + }
17 + else {
18 + rrddim_flag_clear(rd, RRDDIM_FLAG_INDEXED_ID);
19 + error("RRDDIM: %s() attempted to index duplicate dimension with key '%s' of chart '%s' of host '%s'", __FUNCTION__, rrddim_id(rd), rrdset_id(st), rrdhost_hostname(st->rrdhost));
20 + }
21 }
22
19 -#define rrddim_index_add(st, rd) (RRDDIM *)avl_insert_lock(&((st)->dimensions_index), (avl_t *)(rd))
20 -#define rrddim_index_del(st,rd ) (RRDDIM *)avl_remove_lock(&((st)->dimensions_index), (avl_t *)(rd))
21 -
22 -static inline RRDDIM *rrddim_index_find(RRDSET *st, const char *id, uint32_t hash) {
23 - RRDDIM tmp = {
24 - .id = id,
25 - .hash = (hash)?hash:simple_hash(id)
26 - };
27 - return (RRDDIM *)avl_search_lock(&(st->dimensions_index), (avl_t *) &tmp);
23 +static inline void rrddim_index_del(RRDSET *st, RRDDIM *rd) {
24 + if(rrddim_flag_check(rd, RRDDIM_FLAG_INDEXED_ID)) {
25 + if (likely(dictionary_del(st->rrddim_root_index, string2str(rd->id)) == 0))
26 + rrddim_flag_clear(rd, RRDDIM_FLAG_INDEXED_ID);
27 + else
28 + error("RRDDIM: %s() attempted to delete non-indexed dimension with key '%s' of chart '%s' of host '%s'", __FUNCTION__, rrddim_id(rd), rrdset_id(st), rrdhost_hostname(st->rrdhost));
29 + }
30 }
31
32 +static inline RRDDIM *rrddim_index_find(RRDSET *st, const char *id) {
33 + return dictionary_get(st->rrddim_root_index, id);
34 +}
35
36 // ----------------------------------------------------------------------------
37 // RRDDIM - find a dimension
38
39 inline RRDDIM *rrddim_find(RRDSET *st, const char *id) {
35 - debug(D_RRD_CALLS, "rrddim_find() for chart %s, dimension %s", st->name, id);
40 + debug(D_RRD_CALLS, "rrddim_find() for chart %s, dimension %s", rrdset_name(st), id);
41
37 - return rrddim_index_find(st, id, 0);
42 + return rrddim_index_find(st, id);
43 }
44
45 +// This will not return dimensions that are archived
46 +RRDDIM *rrddim_find_active(RRDSET *st, const char *id) {
47 + RRDDIM *rd = rrddim_find(st, id);
48 +
49 + if (unlikely(rd && rrddim_flag_check(rd, RRDDIM_FLAG_ARCHIVED)))
50 + return NULL;
51 +
52 + return rd;
53 +}
54
55 // ----------------------------------------------------------------------------
56 // RRDDIM rename a dimension
57
58 inline int rrddim_set_name(RRDSET *st, RRDDIM *rd, const char *name) {
45 - if(unlikely(!name || !*name || (rd->name && !strcmp(rd->name, name))))
59 + if(unlikely(!name || !*name || !strcmp(rrddim_name(rd), name)))
60 return 0;
61
48 - debug(D_RRD_CALLS, "rrddim_set_name() from %s.%s to %s.%s", st->name, rd->name, st->name, name);
49 -
50 - if (rd->name)
51 - freez((void *) rd->name);
62 + debug(D_RRD_CALLS, "rrddim_set_name() from %s.%s to %s.%s", rrdset_name(st), rrddim_name(rd), rrdset_name(st), name);
63
53 - rd->name = strdupz(name);
54 - rd->hash_name = simple_hash(rd->name);
64 + string_freez(rd->name);
65 + rd->name = rrd_string_strdupz(name);
66
67 if (!st->state->is_ar_chart)
68 rrddimvar_rename_all(rd);
@@ -68,7 +79,7 @@ inline int rrddim_set_algorithm(RRDSET *st, RRDDIM *rd, RRD_ALGORITHM algorithm)
79 if(unlikely(rd->algorithm == algorithm))
80 return 0;
81
71 - debug(D_RRD_CALLS, "Updating algorithm of dimension '%s/%s' from %s to %s", st->id, rd->name, rrd_algorithm_name(rd->algorithm), rrd_algorithm_name(algorithm));
82 + debug(D_RRD_CALLS, "Updating algorithm of dimension '%s/%s' from %s to %s", rrdset_id(st), rrddim_name(rd), rrd_algorithm_name(rd->algorithm), rrd_algorithm_name(algorithm));
83 rd->algorithm = algorithm;
84 rd->exposed = 0;
85 rrdset_flag_set(st, RRDSET_FLAG_HOMOGENEOUS_CHECK);
@@ -81,7 +92,7 @@ inline int rrddim_set_multiplier(RRDSET *st, RRDDIM *rd, collected_number multip
92 if(unlikely(rd->multiplier == multiplier))
93 return 0;
94
84 - debug(D_RRD_CALLS, "Updating multiplier of dimension '%s/%s' from " COLLECTED_NUMBER_FORMAT " to " COLLECTED_NUMBER_FORMAT, st->id, rd->name, rd->multiplier, multiplier);
95 + debug(D_RRD_CALLS, "Updating multiplier of dimension '%s/%s' from " COLLECTED_NUMBER_FORMAT " to " COLLECTED_NUMBER_FORMAT, rrdset_id(st), rrddim_name(rd), rd->multiplier, multiplier);
96 rd->multiplier = multiplier;
97 rd->exposed = 0;
98 rrdset_flag_set(st, RRDSET_FLAG_HOMOGENEOUS_CHECK);
@@ -94,7 +105,7 @@ inline int rrddim_set_divisor(RRDSET *st, RRDDIM *rd, collected_number divisor)
105 if(unlikely(rd->divisor == divisor))
106 return 0;
107
97 - debug(D_RRD_CALLS, "Updating divisor of dimension '%s/%s' from " COLLECTED_NUMBER_FORMAT " to " COLLECTED_NUMBER_FORMAT, st->id, rd->name, rd->divisor, divisor);
108 + debug(D_RRD_CALLS, "Updating divisor of dimension '%s/%s' from " COLLECTED_NUMBER_FORMAT " to " COLLECTED_NUMBER_FORMAT, rrdset_id(st), rrddim_name(rd), rd->divisor, divisor);
109 rd->divisor = divisor;
110 rd->exposed = 0;
111 rrdset_flag_set(st, RRDSET_FLAG_HOMOGENEOUS_CHECK);
@@ -107,31 +118,27 @@ inline int rrddim_set_divisor(RRDSET *st, RRDDIM *rd, collected_number divisor)
118 // RRDDIM create a dimension
119
120 void rrdcalc_link_to_rrddim(RRDDIM *rd, RRDSET *st, RRDHOST *host) {
110 - RRDCALC *rrdc;
121 + RRDCALC *rc;
122
112 - for (rrdc = host->alarms_with_foreach; rrdc ; rrdc = rrdc->next) {
113 - if (simple_pattern_matches(rrdc->spdim, rd->id) || simple_pattern_matches(rrdc->spdim, rd->name)) {
114 - if (rrdc->hash_chart == st->hash_name || !strcmp(rrdc->chart, st->name) || !strcmp(rrdc->chart, st->id)) {
115 - char *name = alarm_name_with_dim(rrdc->name, strlen(rrdc->name), rd->name, strlen(rd->name));
116 - if(rrdcalc_exists(host, st->name, name, 0, 0)) {
123 + for (rc = host->alarms_with_foreach; rc; rc = rc->next) {
124 + if (simple_pattern_matches(rc->spdim, rrddim_id(rd)) || simple_pattern_matches(rc->spdim, rrddim_name(rd))) {
125 + if (rc->chart == st->name || rc->chart == st->id) {
126 + char *name = alarm_name_with_dim(rrdcalc_name(rc), string_strlen(rc->name), rrddim_name(rd), string_strlen(rd->name));
127 + if(rrdcalc_exists(host, rrdset_name(st), name)) {
128 freez(name);
129 continue;
130 }
131
132 netdata_rwlock_wrlock(&host->health_log.alarm_log_rwlock);
122 - RRDCALC *child = rrdcalc_create_from_rrdcalc(rrdc, host, name, rd->name);
133 + RRDCALC *child = rrdcalc_create_from_rrdcalc(rc, host, name, rrddim_name(rd));
134 netdata_rwlock_unlock(&host->health_log.alarm_log_rwlock);
135
125 - if (child) {
136 + if (child)
137 rrdcalc_add_to_host(host, child);
127 - RRDCALC *rdcmp = (RRDCALC *) avl_insert_lock(&(host)->alarms_idx_health_log,(avl_t *)child);
128 - if (rdcmp != child) {
129 - error("Cannot insert the alarm index ID %s",child->name);
130 - }
131 - }
138 +
139 else {
140 error("Cannot allocate a new alarm.");
134 - rrdc->foreachcounter--;
141 + rc->foreachcounter--;
142 }
143 }
144 }
@@ -157,15 +164,20 @@ time_t calc_dimension_liveness(RRDDIM *rd, time_t now)
164 }
165 #endif
166
160 -RRDDIM *rrddim_add_custom(RRDSET *st, const char *id, const char *name, collected_number multiplier,
161 - collected_number divisor, RRD_ALGORITHM algorithm, RRD_MEMORY_MODE memory_mode)
162 -{
167 +RRDDIM *rrddim_add_custom(RRDSET *st
168 + , const char *id
169 + , const char *name
170 + , collected_number multiplier
171 + , collected_number divisor
172 + , RRD_ALGORITHM algorithm
173 + , RRD_MEMORY_MODE memory_mode
174 + ) {
175 RRDHOST *host = st->rrdhost;
176 rrdset_wrlock(st);
177
178 RRDDIM *rd = rrddim_find(st, id);
179 if(unlikely(rd)) {
168 - debug(D_RRD_CALLS, "Cannot create rrd dimension '%s/%s', it already exists.", st->id, name?name:"<NONAME>");
180 + debug(D_RRD_CALLS, "Cannot create rrd dimension '%s/%s', it already exists.", rrdset_id(st), name?name:"<NONAME>");
181
182 int rc = rrddim_set_name(st, rd, name);
183 rc += rrddim_set_algorithm(st, rd, algorithm);
@@ -192,8 +204,8 @@ RRDDIM *rrddim_add_custom(RRDSET *st, const char *id, const char *name, collecte
204 }
205
206 if (unlikely(rc)) {
195 - debug(D_METADATALOG, "DIMENSION [%s] metadata updated", rd->id);
196 - (void)sql_store_dimension(&rd->metric_uuid, rd->rrdset->chart_uuid, rd->id, rd->name, rd->multiplier, rd->divisor,
207 + debug(D_METADATALOG, "DIMENSION [%s] metadata updated", rrddim_id(rd));
208 + (void)sql_store_dimension(&rd->metric_uuid, rd->rrdset->chart_uuid, rrddim_id(rd), rrddim_name(rd), rd->multiplier, rd->divisor,
209 rd->algorithm);
210 #ifdef ENABLE_ACLK
211 queue_dimension_to_aclk(rd, calc_dimension_liveness(rd, now_realtime_sec()));
@@ -210,11 +222,9 @@ RRDDIM *rrddim_add_custom(RRDSET *st, const char *id, const char *name, collecte
222 rrdset_flag_clear(st, RRDSET_FLAG_UPSTREAM_EXPOSED);
223
224 rd = callocz(1, sizeof(RRDDIM));
213 - rd->id = strdupz(id);
214 - rd->hash = simple_hash(rd->id);
225 + rd->id = string_strdupz(id);
226
216 - rd->name = (name && *name)?strdupz(name):strdupz(rd->id);
217 - rd->hash_name = simple_hash(rd->name);
227 + rd->name = (name && *name)?rrd_string_strdupz(name):string_dup(rd->id);
228
229 rd->algorithm = algorithm;
230 rd->multiplier = multiplier;
@@ -231,7 +241,7 @@ RRDDIM *rrddim_add_custom(RRDSET *st, const char *id, const char *name, collecte
241
242 if(memory_mode == RRD_MEMORY_MODE_MAP || memory_mode == RRD_MEMORY_MODE_SAVE) {
243 if(!rrddim_memory_load_or_create_map_save(st, rd, memory_mode)) {
234 - info("Failed to use memory mode %s for chart '%s', dimension '%s', falling back to ram", (memory_mode == RRD_MEMORY_MODE_MAP)?"map":"save", st->name, rd->name);
244 + info("Failed to use memory mode %s for chart '%s', dimension '%s', falling back to ram", (memory_mode == RRD_MEMORY_MODE_MAP)?"map":"save", rrdset_name(st), rrddim_name(rd));
245 memory_mode = RRD_MEMORY_MODE_RAM;
246 }
247 }
@@ -242,7 +252,7 @@ RRDDIM *rrddim_add_custom(RRDSET *st, const char *id, const char *name, collecte
252
253 rd->db = netdata_mmap(NULL, entries * sizeof(storage_number), MAP_PRIVATE, 1);
254 if(!rd->db) {
245 - info("Failed to use memory mode ram for chart '%s', dimension '%s', falling back to alloc", st->name, rd->name);
255 + info("Failed to use memory mode ram for chart '%s', dimension '%s', falling back to alloc", rrdset_name(st), rrddim_name(rd));
256 memory_mode = RRD_MEMORY_MODE_ALLOC;
257 }
258 else rd->memsize = entries * sizeof(storage_number);
@@ -261,6 +271,7 @@ RRDDIM *rrddim_add_custom(RRDSET *st, const char *id, const char *name, collecte
271 #ifdef ENABLE_ACLK
272 rd->aclk_live_status = -1;
273 #endif
274 +
275 (void) find_dimension_uuid(st, rd, &(rd->metric_uuid));
276
277 // initialize the db tiers
@@ -284,10 +295,10 @@ RRDDIM *rrddim_add_custom(RRDSET *st, const char *id, const char *name, collecte
295 }
296
297 if(!initialized)
287 - error("Failed to initialize all db tiers for chart '%s', dimension '%s", st->name, rd->name);
298 + error("Failed to initialize all db tiers for chart '%s', dimension '%s", rrdset_name(st), rrddim_name(rd));
299
300 if(!rd->tiers[0])
290 - error("Failed to initialize the first db tier for chart '%s', dimension '%s", st->name, rd->name);
301 + error("Failed to initialize the first db tier for chart '%s', dimension '%s", rrdset_name(st), rrddim_name(rd));
302 }
303
304 store_active_dimension(&rd->metric_uuid);
@@ -303,22 +314,19 @@ RRDDIM *rrddim_add_custom(RRDSET *st, const char *id, const char *name, collecte
314 }
315
316 if(!initialized)
306 - error("Failed to initialize data collection for all db tiers for chart '%s', dimension '%s", st->name, rd->name);
317 + error("Failed to initialize data collection for all db tiers for chart '%s', dimension '%s", rrdset_name(st), rrddim_name(rd));
318 }
319
309 - // append this dimension
310 - if(!st->dimensions)
311 - st->dimensions = rd;
312 - else {
320 + if(st->dimensions) {
321 RRDDIM *td = st->dimensions;
322
323 if(td->algorithm != rd->algorithm || ABS(td->multiplier) != ABS(rd->multiplier) || ABS(td->divisor) != ABS(rd->divisor)) {
324 if(!rrdset_flag_check(st, RRDSET_FLAG_HETEROGENEOUS)) {
325 #ifdef NETDATA_INTERNAL_CHECKS
326 info("Dimension '%s' added on chart '%s' of host '%s' is not homogeneous to other dimensions already present (algorithm is '%s' vs '%s', multiplier is " COLLECTED_NUMBER_FORMAT " vs " COLLECTED_NUMBER_FORMAT ", divisor is " COLLECTED_NUMBER_FORMAT " vs " COLLECTED_NUMBER_FORMAT ").",
319 - rd->name,
320 - st->name,
321 - host->hostname,
327 + rrddim_name(rd),
328 + rrdset_name(st),
329 + rrdhost_hostname(host),
330 rrd_algorithm_name(rd->algorithm), rrd_algorithm_name(td->algorithm),
331 rd->multiplier, td->multiplier,
332 rd->divisor, td->divisor
@@ -327,19 +335,18 @@ RRDDIM *rrddim_add_custom(RRDSET *st, const char *id, const char *name, collecte
335 rrdset_flag_set(st, RRDSET_FLAG_HETEROGENEOUS);
336 }
337 }
330 -
331 - for(; td->next; td = td->next) ;
332 - td->next = rd;
338 }
339
340 + // append this dimension
341 + DOUBLE_LINKED_LIST_APPEND_UNSAFE(st->dimensions, rd, prev, next);
342 +
343 if(host->health_enabled && !st->state->is_ar_chart) {
344 rrddimvar_create(rd, RRDVAR_TYPE_CALCULATED, NULL, NULL, &rd->last_stored_value, RRDVAR_OPTION_DEFAULT);
345 rrddimvar_create(rd, RRDVAR_TYPE_COLLECTED, NULL, "_raw", &rd->last_collected_value, RRDVAR_OPTION_DEFAULT);
346 rrddimvar_create(rd, RRDVAR_TYPE_TIME_T, NULL, "_last_collected_t", &rd->last_collected_time.tv_sec, RRDVAR_OPTION_DEFAULT);
347 }
348
341 - if(unlikely(rrddim_index_add(st, rd) != rd))
342 - error("RRDDIM: INTERNAL ERROR: attempt to index duplicate dimension '%s' on chart '%s'", rd->id, st->id);
349 + rrddim_index_add(st, rd);
350
351 rrddim_flag_set(rd, RRDDIM_FLAG_PENDING_FOREACH_ALARM);
352 rrdset_flag_set(st, RRDSET_FLAG_PENDING_FOREACH_ALARMS);
@@ -360,7 +367,7 @@ void rrddim_free(RRDSET *st, RRDDIM *rd)
367 rrdcontext_removed_rrddim(rd);
368 ml_delete_dimension(rd);
369
363 - debug(D_RRD_CALLS, "rrddim_free() %s.%s", st->name, rd->name);
370 + debug(D_RRD_CALLS, "rrddim_free() %s.%s", rrdset_name(st), rrddim_name(rd));
371
372 if (!rrddim_flag_check(rd, RRDDIM_FLAG_ARCHIVED)) {
373
@@ -382,24 +389,12 @@ void rrddim_free(RRDSET *st, RRDDIM *rd)
389 }
390 }
391
385 - if(rd == st->dimensions)
386 - st->dimensions = rd->next;
387 - else {
388 - RRDDIM *i;
389 - for (i = st->dimensions; i && i->next != rd; i = i->next) ;
390 -
391 - if (i && i->next == rd)
392 - i->next = rd->next;
393 - else
394 - error("Request to free dimension '%s.%s' but it is not linked.", st->id, rd->name);
395 - }
396 - rd->next = NULL;
392 + DOUBLE_LINKED_LIST_REMOVE_UNSAFE(st->dimensions, rd, prev, next);
393
394 while(rd->variables)
395 rrddimvar_free(rd->variables);
396
401 - if(unlikely(rrddim_index_del(st, rd) != rd))
402 - error("RRDDIM: INTERNAL ERROR: attempt to remove from index dimension '%s' on chart '%s', removed a different dimension.", rd->id, st->id);
397 + rrddim_index_del(st, rd);
398
399 // free(rd->annotations);
400 //#ifdef ENABLE_ACLK
@@ -428,8 +423,8 @@ void rrddim_free(RRDSET *st, RRDDIM *rd)
423 freez(rd->db);
424 }
425
431 - freez((void *)rd->id);
432 - freez((void *)rd->name);
426 + string_freez(rd->id);
427 + string_freez(rd->name);
428 freez(rd);
429 }
430
@@ -438,13 +433,13 @@ void rrddim_free(RRDSET *st, RRDDIM *rd)
433 // RRDDIM - set dimension options
434
435 int rrddim_hide(RRDSET *st, const char *id) {
441 - debug(D_RRD_CALLS, "rrddim_hide() for chart %s, dimension %s", st->name, id);
436 + debug(D_RRD_CALLS, "rrddim_hide() for chart %s, dimension %s", rrdset_name(st), id);
437
438 RRDHOST *host = st->rrdhost;
439
440 RRDDIM *rd = rrddim_find(st, id);
441 if(unlikely(!rd)) {
447 - error("Cannot find dimension with id '%s' on stats '%s' (%s) on host '%s'.", id, st->name, st->id, host->hostname);
442 + error("Cannot find dimension with id '%s' on stats '%s' (%s) on host '%s'.", id, rrdset_name(st), rrdset_id(st), rrdhost_hostname(host));
443 return 1;
444 }
445 if (!rrddim_flag_check(rd, RRDDIM_FLAG_META_HIDDEN))
@@ -457,12 +452,12 @@ int rrddim_hide(RRDSET *st, const char *id) {
452 }
453
454 int rrddim_unhide(RRDSET *st, const char *id) {
460 - debug(D_RRD_CALLS, "rrddim_unhide() for chart %s, dimension %s", st->name, id);
455 + debug(D_RRD_CALLS, "rrddim_unhide() for chart %s, dimension %s", rrdset_name(st), id);
456
457 RRDHOST *host = st->rrdhost;
458 RRDDIM *rd = rrddim_find(st, id);
459 if(unlikely(!rd)) {
465 - error("Cannot find dimension with id '%s' on stats '%s' (%s) on host '%s'.", id, st->name, st->id, host->hostname);
460 + error("Cannot find dimension with id '%s' on stats '%s' (%s) on host '%s'.", id, rrdset_name(st), rrdset_id(st), rrdhost_hostname(host));
461 return 1;
462 }
463 if (rrddim_flag_check(rd, RRDDIM_FLAG_META_HIDDEN))
@@ -475,10 +470,10 @@ int rrddim_unhide(RRDSET *st, const char *id) {
470 }
471
472 inline void rrddim_is_obsolete(RRDSET *st, RRDDIM *rd) {
478 - debug(D_RRD_CALLS, "rrddim_is_obsolete() for chart %s, dimension %s", st->name, rd->name);
473 + debug(D_RRD_CALLS, "rrddim_is_obsolete() for chart %s, dimension %s", rrdset_name(st), rrddim_name(rd));
474
475 if(unlikely(rrddim_flag_check(rd, RRDDIM_FLAG_ARCHIVED))) {
481 - info("Cannot obsolete already archived dimension %s from chart %s", rd->name, st->name);
476 + info("Cannot obsolete already archived dimension %s from chart %s", rrddim_name(rd), rrdset_name(st));
477 return;
478 }
479 rrddim_flag_set(rd, RRDDIM_FLAG_OBSOLETE);
@@ -487,7 +482,7 @@ inline void rrddim_is_obsolete(RRDSET *st, RRDDIM *rd) {
482 }
483
484 inline void rrddim_isnot_obsolete(RRDSET *st __maybe_unused, RRDDIM *rd) {
490 - debug(D_RRD_CALLS, "rrddim_isnot_obsolete() for chart %s, dimension %s", st->name, rd->name);
485 + debug(D_RRD_CALLS, "rrddim_isnot_obsolete() for chart %s, dimension %s", rrdset_name(st), rrddim_name(rd));
486
487 rrddim_flag_clear(rd, RRDDIM_FLAG_OBSOLETE);
488 rrdcontext_updated_rrddim_flags(rd);
@@ -497,9 +492,7 @@ inline void rrddim_isnot_obsolete(RRDSET *st __maybe_unused, RRDDIM *rd) {
492 // RRDDIM - collect values for a dimension
493
494 inline collected_number rrddim_set_by_pointer(RRDSET *st __maybe_unused, RRDDIM *rd, collected_number value) {
500 - debug(D_RRD_CALLS, "rrddim_set_by_pointer() for chart %s, dimension %s, value " COLLECTED_NUMBER_FORMAT, st->name, rd->name, value);
501 -
502 - rrdcontext_collected_rrddim(rd);
495 + debug(D_RRD_CALLS, "rrddim_set_by_pointer() for chart %s, dimension %s, value " COLLECTED_NUMBER_FORMAT, rrdset_name(st), rrddim_name(rd), value);
496
497 now_realtime_timeval(&rd->last_collected_time);
498 rd->collected_value = value;
@@ -519,7 +512,7 @@ collected_number rrddim_set(RRDSET *st, const char *id, collected_number value)
512 RRDHOST *host = st->rrdhost;
513 RRDDIM *rd = rrddim_find(st, id);
514 if(unlikely(!rd)) {
522 - error("Cannot find dimension with id '%s' on stats '%s' (%s) on host '%s'.", id, st->name, st->id, host->hostname);
515 + error("Cannot find dimension with id '%s' on stats '%s' (%s) on host '%s'.", id, rrdset_name(st), rrdset_id(st), rrdhost_hostname(host));
516 return 0;
517 }
518
@@ -627,7 +620,7 @@ bool rrddim_memory_load_or_create_map_save(RRDSET *st, RRDDIM *rd, RRD_MEMORY_MO
620
621 char filename[FILENAME_MAX + 1];
622 char fullfilename[FILENAME_MAX + 1];
630 - rrdset_strncpyz_name(filename, rd->id, FILENAME_MAX);
623 + rrdset_strncpyz_name(filename, rrddim_id(rd), FILENAME_MAX);
624 snprintfz(fullfilename, FILENAME_MAX, "%s/%s.db", st->cache_dir, filename);
625
626 rd_on_file = (struct rrddim_map_save_v019 *)netdata_mmap(fullfilename, size,
database/rrddimvar.c
+53 -66
@@ -16,64 +16,64 @@ static inline void rrddimvar_free_variables(RRDDIMVAR *rs) {
16
17 // CHART VARIABLES FOR THIS DIMENSION
18
19 - rrdvar_free(host, &st->rrdvar_root_index, rs->var_local_id);
19 + rrdvar_free(host, st->rrdvar_root_index, rs->var_local_id);
20 rs->var_local_id = NULL;
21
22 - rrdvar_free(host, &st->rrdvar_root_index, rs->var_local_name);
22 + rrdvar_free(host, st->rrdvar_root_index, rs->var_local_name);
23 rs->var_local_name = NULL;
24
25 // FAMILY VARIABLES FOR THIS DIMENSION
26
27 - rrdvar_free(host, &st->rrdfamily->rrdvar_root_index, rs->var_family_id);
27 + rrdvar_free(host, st->rrdfamily->rrdvar_root_index, rs->var_family_id);
28 rs->var_family_id = NULL;
29
30 - rrdvar_free(host, &st->rrdfamily->rrdvar_root_index, rs->var_family_name);
30 + rrdvar_free(host, st->rrdfamily->rrdvar_root_index, rs->var_family_name);
31 rs->var_family_name = NULL;
32
33 - rrdvar_free(host, &st->rrdfamily->rrdvar_root_index, rs->var_family_contextid);
33 + rrdvar_free(host, st->rrdfamily->rrdvar_root_index, rs->var_family_contextid);
34 rs->var_family_contextid = NULL;
35
36 - rrdvar_free(host, &st->rrdfamily->rrdvar_root_index, rs->var_family_contextname);
36 + rrdvar_free(host, st->rrdfamily->rrdvar_root_index, rs->var_family_contextname);
37 rs->var_family_contextname = NULL;
38
39 // HOST VARIABLES FOR THIS DIMENSION
40
41 - rrdvar_free(host, &host->rrdvar_root_index, rs->var_host_chartidid);
41 + rrdvar_free(host, host->rrdvar_root_index, rs->var_host_chartidid);
42 rs->var_host_chartidid = NULL;
43
44 - rrdvar_free(host, &host->rrdvar_root_index, rs->var_host_chartidname);
44 + rrdvar_free(host, host->rrdvar_root_index, rs->var_host_chartidname);
45 rs->var_host_chartidname = NULL;
46
47 - rrdvar_free(host, &host->rrdvar_root_index, rs->var_host_chartnameid);
47 + rrdvar_free(host, host->rrdvar_root_index, rs->var_host_chartnameid);
48 rs->var_host_chartnameid = NULL;
49
50 - rrdvar_free(host, &host->rrdvar_root_index, rs->var_host_chartnamename);
50 + rrdvar_free(host, host->rrdvar_root_index, rs->var_host_chartnamename);
51 rs->var_host_chartnamename = NULL;
52
53 // KEYS
54
55 - freez(rs->key_id);
55 + string_freez(rs->key_id);
56 rs->key_id = NULL;
57
58 - freez(rs->key_name);
58 + string_freez(rs->key_name);
59 rs->key_name = NULL;
60
61 - freez(rs->key_fullidid);
61 + string_freez(rs->key_fullidid);
62 rs->key_fullidid = NULL;
63
64 - freez(rs->key_fullidname);
64 + string_freez(rs->key_fullidname);
65 rs->key_fullidname = NULL;
66
67 - freez(rs->key_contextid);
67 + string_freez(rs->key_contextid);
68 rs->key_contextid = NULL;
69
70 - freez(rs->key_contextname);
70 + string_freez(rs->key_contextname);
71 rs->key_contextname = NULL;
72
73 - freez(rs->key_fullnameid);
73 + string_freez(rs->key_fullnameid);
74 rs->key_fullnameid = NULL;
75
76 - freez(rs->key_fullnamename);
76 + string_freez(rs->key_fullnamename);
77 rs->key_fullnamename = NULL;
78 }
79
@@ -88,29 +88,29 @@ static inline void rrddimvar_create_variables(RRDDIMVAR *rs) {
88
89 // KEYS
90
91 - snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s%s%s", rs->prefix, rd->id, rs->suffix);
92 - rs->key_id = strdupz(buffer);
91 + snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s%s%s", string2str(rs->prefix), rrddim_id(rd), string2str(rs->suffix));
92 + rs->key_id = string_strdupz(buffer);
93
94 - snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s%s%s", rs->prefix, rd->name, rs->suffix);
95 - rs->key_name = strdupz(buffer);
94 + snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s%s%s", string2str(rs->prefix), rrddim_name(rd), string2str(rs->suffix));
95 + rs->key_name = string_strdupz(buffer);
96
97 - snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", st->id, rs->key_id);
98 - rs->key_fullidid = strdupz(buffer);
97 + snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", rrdset_id(st), string2str(rs->key_id));
98 + rs->key_fullidid = string_strdupz(buffer);
99
100 - snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", st->id, rs->key_name);
101 - rs->key_fullidname = strdupz(buffer);
100 + snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", rrdset_id(st), string2str(rs->key_name));
101 + rs->key_fullidname = string_strdupz(buffer);
102
103 - snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", st->context, rs->key_id);
104 - rs->key_contextid = strdupz(buffer);
103 + snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", rrdset_context(st), string2str(rs->key_id));
104 + rs->key_contextid = string_strdupz(buffer);
105
106 - snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", st->context, rs->key_name);
107 - rs->key_contextname = strdupz(buffer);
106 + snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", rrdset_context(st), string2str(rs->key_name));
107 + rs->key_contextname = string_strdupz(buffer);
108
109 - snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", st->name, rs->key_id);
110 - rs->key_fullnameid = strdupz(buffer);
109 + snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", rrdset_name(st), string2str(rs->key_id));
110 + rs->key_fullnameid = string_strdupz(buffer);
111
112 - snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", st->name, rs->key_name);
113 - rs->key_fullnamename = strdupz(buffer);
112 + snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", rrdset_name(st), string2str(rs->key_name));
113 + rs->key_fullnamename = string_strdupz(buffer);
114
115 // CHART VARIABLES FOR THIS DIMENSION
116 // -----------------------------------
@@ -119,8 +119,8 @@ static inline void rrddimvar_create_variables(RRDDIMVAR *rs) {
119 // - $id
120 // - $name
121
122 - rs->var_local_id = rrdvar_create_and_index("local", &st->rrdvar_root_index, rs->key_id, rs->type, RRDVAR_OPTION_DEFAULT, rs->value);
123 - rs->var_local_name = rrdvar_create_and_index("local", &st->rrdvar_root_index, rs->key_name, rs->type, RRDVAR_OPTION_DEFAULT, rs->value);
122 + rs->var_local_id = rrdvar_create_and_index("local", st->rrdvar_root_index, rs->key_id, rs->type, RRDVAR_OPTION_DEFAULT, rs->value);
123 + rs->var_local_name = rrdvar_create_and_index("local", st->rrdvar_root_index, rs->key_name, rs->type, RRDVAR_OPTION_DEFAULT, rs->value);
124
125 // FAMILY VARIABLES FOR THIS DIMENSION
126 // -----------------------------------
@@ -131,10 +131,10 @@ static inline void rrddimvar_create_variables(RRDDIMVAR *rs) {
131 // - $chart-context.id
132 // - $chart-context.name
133
134 - rs->var_family_id = rrdvar_create_and_index("family", &st->rrdfamily->rrdvar_root_index, rs->key_id, rs->type, RRDVAR_OPTION_DEFAULT, rs->value);
135 - rs->var_family_name = rrdvar_create_and_index("family", &st->rrdfamily->rrdvar_root_index, rs->key_name, rs->type, RRDVAR_OPTION_DEFAULT, rs->value);
136 - rs->var_family_contextid = rrdvar_create_and_index("family", &st->rrdfamily->rrdvar_root_index, rs->key_contextid, rs->type, RRDVAR_OPTION_DEFAULT, rs->value);
137 - rs->var_family_contextname = rrdvar_create_and_index("family", &st->rrdfamily->rrdvar_root_index, rs->key_contextname, rs->type, RRDVAR_OPTION_DEFAULT, rs->value);
134 + rs->var_family_id = rrdvar_create_and_index("family", st->rrdfamily->rrdvar_root_index, rs->key_id, rs->type, RRDVAR_OPTION_DEFAULT, rs->value);
135 + rs->var_family_name = rrdvar_create_and_index("family", st->rrdfamily->rrdvar_root_index, rs->key_name, rs->type, RRDVAR_OPTION_DEFAULT, rs->value);
136 + rs->var_family_contextid = rrdvar_create_and_index("family", st->rrdfamily->rrdvar_root_index, rs->key_contextid, rs->type, RRDVAR_OPTION_DEFAULT, rs->value);
137 + rs->var_family_contextname = rrdvar_create_and_index("family", st->rrdfamily->rrdvar_root_index, rs->key_contextname, rs->type, RRDVAR_OPTION_DEFAULT, rs->value);
138
139 // HOST VARIABLES FOR THIS DIMENSION
140 // -----------------------------------
@@ -145,33 +145,32 @@ static inline void rrddimvar_create_variables(RRDDIMVAR *rs) {
145 // - $chart-name.id
146 // - $chart-name.name
147
148 - rs->var_host_chartidid = rrdvar_create_and_index("host", &host->rrdvar_root_index, rs->key_fullidid, rs->type, RRDVAR_OPTION_DEFAULT, rs->value);
149 - rs->var_host_chartidname = rrdvar_create_and_index("host", &host->rrdvar_root_index, rs->key_fullidname, rs->type, RRDVAR_OPTION_DEFAULT, rs->value);
150 - rs->var_host_chartnameid = rrdvar_create_and_index("host", &host->rrdvar_root_index, rs->key_fullnameid, rs->type, RRDVAR_OPTION_DEFAULT, rs->value);
151 - rs->var_host_chartnamename = rrdvar_create_and_index("host", &host->rrdvar_root_index, rs->key_fullnamename, rs->type, RRDVAR_OPTION_DEFAULT, rs->value);
148 + rs->var_host_chartidid = rrdvar_create_and_index("host", host->rrdvar_root_index, rs->key_fullidid, rs->type, RRDVAR_OPTION_DEFAULT, rs->value);
149 + rs->var_host_chartidname = rrdvar_create_and_index("host", host->rrdvar_root_index, rs->key_fullidname, rs->type, RRDVAR_OPTION_DEFAULT, rs->value);
150 + rs->var_host_chartnameid = rrdvar_create_and_index("host", host->rrdvar_root_index, rs->key_fullnameid, rs->type, RRDVAR_OPTION_DEFAULT, rs->value);
151 + rs->var_host_chartnamename = rrdvar_create_and_index("host", host->rrdvar_root_index, rs->key_fullnamename, rs->type, RRDVAR_OPTION_DEFAULT, rs->value);
152 }
153
154 RRDDIMVAR *rrddimvar_create(RRDDIM *rd, RRDVAR_TYPE type, const char *prefix, const char *suffix, void *value, RRDVAR_OPTIONS options) {
155 RRDSET *st = rd->rrdset;
156 (void)st;
157
158 - debug(D_VARIABLES, "RRDDIMSET create for chart id '%s' name '%s', dimension id '%s', name '%s%s%s'", st->id, st->name, rd->id, (prefix)?prefix:"", rd->name, (suffix)?suffix:"");
158 + debug(D_VARIABLES, "RRDDIMSET create for chart id '%s' name '%s', dimension id '%s', name '%s%s%s'", rrdset_id(st), rrdset_name(st), rrddim_id(rd), (prefix)?prefix:"", rrddim_name(rd), (suffix)?suffix:"");
159
160 if(!prefix) prefix = "";
161 if(!suffix) suffix = "";
162
163 RRDDIMVAR *rs = (RRDDIMVAR *)callocz(1, sizeof(RRDDIMVAR));
164
165 - rs->prefix = strdupz(prefix);
166 - rs->suffix = strdupz(suffix);
165 + rs->prefix = string_strdupz(prefix);
166 + rs->suffix = string_strdupz(suffix);
167
168 rs->type = type;
169 rs->value = value;
170 rs->options = options;
171 rs->rrddim = rd;
172
173 - rs->next = rd->variables;
174 - rd->variables = rs;
173 + DOUBLE_LINKED_LIST_PREPEND_UNSAFE(rd->variables, rs, prev, next);
174
175 rrddimvar_create_variables(rs);
176
@@ -182,7 +181,7 @@ void rrddimvar_rename_all(RRDDIM *rd) {
181 RRDSET *st = rd->rrdset;
182 (void)st;
183
185 - debug(D_VARIABLES, "RRDDIMSET rename for chart id '%s' name '%s', dimension id '%s', name '%s'", st->id, st->name, rd->id, rd->name);
184 + debug(D_VARIABLES, "RRDDIMSET rename for chart id '%s' name '%s', dimension id '%s', name '%s'", rrdset_id(st), rrdset_name(st), rrddim_id(rd), rrddim_name(rd));
185
186 RRDDIMVAR *rs, *next = rd->variables;
187 while((rs = next)) {
@@ -193,25 +192,13 @@ void rrddimvar_rename_all(RRDDIM *rd) {
192
193 void rrddimvar_free(RRDDIMVAR *rs) {
194 RRDDIM *rd = rs->rrddim;
196 - RRDSET *st = rd->rrdset;
197 - debug(D_VARIABLES, "RRDDIMSET free for chart id '%s' name '%s', dimension id '%s', name '%s', prefix='%s', suffix='%s'", st->id, st->name, rd->id, rd->name, rs->prefix, rs->suffix);
195 + debug(D_VARIABLES, "RRDDIMSET free for chart id '%s' name '%s', dimension id '%s', name '%s', prefix='%s', suffix='%s'", rrdset_id(rd->rrdset), rrdset_name(rd->rrdset), rrddim_id(rd), rrddim_name(rd), string2str(rs->prefix), string2str(rs->suffix));
196
197 rrddimvar_free_variables(rs);
198
201 - if(rd->variables == rs) {
202 - debug(D_VARIABLES, "RRDDIMSET removing first entry for chart id '%s' name '%s', dimension id '%s', name '%s'", st->id, st->name, rd->id, rd->name);
203 - rd->variables = rs->next;
204 - }
205 - else {
206 - debug(D_VARIABLES, "RRDDIMSET removing non-first entry for chart id '%s' name '%s', dimension id '%s', name '%s'", st->id, st->name, rd->id, rd->name);
207 - RRDDIMVAR *t;
208 - for (t = rd->variables; t && t->next != rs; t = t->next) ;
209 - if(!t) error("RRDDIMVAR '%s' not found in dimension '%s/%s' variables linked list", rs->key_name, st->id, rd->id);
210 - else t->next = rs->next;
211 - }
199 + DOUBLE_LINKED_LIST_REMOVE_UNSAFE(rd->variables, rs, prev, next);
200
213 - freez(rs->prefix);
214 - freez(rs->suffix);
201 + string_freez(rs->prefix);
202 + string_freez(rs->suffix);
203 freez(rs);
204 }
217 -
database/rrddimvar.h
+12 -11
@@ -11,17 +11,17 @@
11 // This means, there will be no speed penalty for using
12 // these variables
13 struct rrddimvar {
14 - char *prefix;
15 - char *suffix;
16 -
17 - char *key_id; // dimension id
18 - char *key_name; // dimension name
19 - char *key_contextid; // context + dimension id
20 - char *key_contextname; // context + dimension name
21 - char *key_fullidid; // chart type.chart id + dimension id
22 - char *key_fullidname; // chart type.chart id + dimension name
23 - char *key_fullnameid; // chart type.chart name + dimension id
24 - char *key_fullnamename; // chart type.chart name + dimension name
14 + STRING *prefix;
15 + STRING *suffix;
16 +
17 + STRING *key_id; // dimension id
18 + STRING *key_name; // dimension name
19 + STRING *key_contextid; // context + dimension id
20 + STRING *key_contextname; // context + dimension name
21 + STRING *key_fullidid; // chart type.chart id + dimension id
22 + STRING *key_fullidname; // chart type.chart id + dimension name
23 + STRING *key_fullnameid; // chart type.chart name + dimension id
24 + STRING *key_fullnamename; // chart type.chart name + dimension name
25
26 RRDVAR_TYPE type;
27 void *value;
@@ -44,6 +44,7 @@ struct rrddimvar {
44 struct rrddim *rrddim;
45
46 struct rrddimvar *next;
47 + struct rrddimvar *prev;
48 };
49
50
database/rrdfamily.c
+24 -22
@@ -6,37 +6,38 @@
6 // ----------------------------------------------------------------------------
7 // RRDFAMILY index
8
9 -int rrdfamily_compare(void *a, void *b) {
10 - if(((RRDFAMILY *)a)->hash_family < ((RRDFAMILY *)b)->hash_family) return -1;
11 - else if(((RRDFAMILY *)a)->hash_family > ((RRDFAMILY *)b)->hash_family) return 1;
12 - else return strcmp(((RRDFAMILY *)a)->family, ((RRDFAMILY *)b)->family);
9 +static inline RRDFAMILY *rrdfamily_index_add(RRDHOST *host, RRDFAMILY *rc) {
10 + return dictionary_set(host->rrdfamily_root_index, string2str(rc->family), rc, sizeof(RRDFAMILY));
11 }
12
15 -#define rrdfamily_index_add(host, rc) (RRDFAMILY *)avl_insert_lock(&((host)->rrdfamily_root_index), (avl_t *)(rc))
16 -#define rrdfamily_index_del(host, rc) (RRDFAMILY *)avl_remove_lock(&((host)->rrdfamily_root_index), (avl_t *)(rc))
17 -
18 -static RRDFAMILY *rrdfamily_index_find(RRDHOST *host, const char *id, uint32_t hash) {
19 - RRDFAMILY tmp;
20 - tmp.family = id;
21 - tmp.hash_family = (hash)?hash:simple_hash(tmp.family);
13 +static inline RRDFAMILY *rrdfamily_index_del(RRDHOST *host, RRDFAMILY *rc) {
14 + dictionary_del(host->rrdfamily_root_index, string2str(rc->family));
15 + return rc;
16 +}
17
23 - return (RRDFAMILY *)avl_search_lock(&(host->rrdfamily_root_index), (avl_t *) &tmp);
18 +static inline RRDFAMILY *rrdfamily_index_find(RRDHOST *host, const char *id) {
19 + return dictionary_get(host->rrdfamily_root_index, id);
20 }
21
22 +// ----------------------------------------------------------------------------
23 +// RRDFAMILY management
24 +
25 RRDFAMILY *rrdfamily_create(RRDHOST *host, const char *id) {
27 - RRDFAMILY *rc = rrdfamily_index_find(host, id, 0);
26 + RRDFAMILY *rc = rrdfamily_index_find(host, id);
27 if(!rc) {
28 rc = callocz(1, sizeof(RRDFAMILY));
29
31 - rc->family = strdupz(id);
32 - rc->hash_family = simple_hash(rc->family);
30 + rc->family = string_strdupz(id);
31
34 - // initialize the variables index
35 - avl_init_lock(&rc->rrdvar_root_index, rrdvar_compare);
32 + rc->rrdvar_root_index = dictionary_create(
33 + DICTIONARY_FLAG_NAME_LINK_DONT_CLONE
34 + |DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE
35 + |DICTIONARY_FLAG_DONT_OVERWRITE_VALUE
36 + );
37
38 RRDFAMILY *ret = rrdfamily_index_add(host, rc);
39 if(ret != rc)
39 - error("RRDFAMILY: INTERNAL ERROR: Expected to INSERT RRDFAMILY '%s' into index, but inserted '%s'.", rc->family, (ret)?ret->family:"NONE");
40 + error("RRDFAMILY: INTERNAL ERROR: Expected to INSERT RRDFAMILY '%s' into index, but inserted '%s'.", string2str(rc->family), (ret)?string2str(ret->family):"NONE");
41 }
42
43 rc->use_count++;
@@ -48,12 +49,13 @@ void rrdfamily_free(RRDHOST *host, RRDFAMILY *rc) {
49 if(!rc->use_count) {
50 RRDFAMILY *ret = rrdfamily_index_del(host, rc);
51 if(ret != rc)
51 - error("RRDFAMILY: INTERNAL ERROR: Expected to DELETE RRDFAMILY '%s' from index, but deleted '%s'.", rc->family, (ret)?ret->family:"NONE");
52 + error("RRDFAMILY: INTERNAL ERROR: Expected to DELETE RRDFAMILY '%s' from index, but deleted '%s'.", string2str(rc->family), (ret)?string2str(ret->family):"NONE");
53 else {
53 - debug(D_RRD_CALLS, "RRDFAMILY: Cleaning up remaining family variables for host '%s', family '%s'", host->hostname, rc->family);
54 - rrdvar_free_remaining_variables(host, &rc->rrdvar_root_index);
54 + debug(D_RRD_CALLS, "RRDFAMILY: Cleaning up remaining family variables for host '%s', family '%s'", rrdhost_hostname(host), string2str(rc->family));
55 + rrdvar_free_remaining_variables(host, rc->rrdvar_root_index);
56
56 - freez((void *) rc->family);
57 + dictionary_destroy(rc->rrdvar_root_index);
58 + string_freez(rc->family);
59 freez(rc);
60 }
61 }
database/rrdhost.c
+204 -221
@@ -43,107 +43,150 @@ bool is_storage_engine_shared(STORAGE_INSTANCE *engine) {
43
44
45 // ----------------------------------------------------------------------------
46 -// RRDHOST index
46 +// RRDHOST indexes management
47
48 -int rrdhost_compare(void* a, void* b) {
49 - if(((RRDHOST *)a)->hash_machine_guid < ((RRDHOST *)b)->hash_machine_guid) return -1;
50 - else if(((RRDHOST *)a)->hash_machine_guid > ((RRDHOST *)b)->hash_machine_guid) return 1;
51 - else return strcmp(((RRDHOST *)a)->machine_guid, ((RRDHOST *)b)->machine_guid);
48 +static DICTIONARY *rrdhost_root_index = NULL;
49 +static DICTIONARY *rrdhost_root_index_hostname = NULL;
50 +
51 +static inline void rrdhost_init() {
52 + if(unlikely(!rrdhost_root_index)) {
53 + rrdhost_root_index = dictionary_create(
54 + DICTIONARY_FLAG_NAME_LINK_DONT_CLONE
55 + | DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE
56 + | DICTIONARY_FLAG_DONT_OVERWRITE_VALUE
57 + );
58 + }
59 +
60 + if(unlikely(!rrdhost_root_index_hostname)) {
61 + rrdhost_root_index_hostname = dictionary_create(
62 + DICTIONARY_FLAG_NAME_LINK_DONT_CLONE
63 + | DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE
64 + | DICTIONARY_FLAG_DONT_OVERWRITE_VALUE
65 + );
66 + }
67 +}
68 +
69 +// ----------------------------------------------------------------------------
70 +// RRDHOST index by UUID
71 +
72 +inline long rrdhost_hosts_available(void) {
73 + return dictionary_stats_entries(rrdhost_root_index);
74 +}
75 +
76 +inline RRDHOST *rrdhost_find_by_guid(const char *guid) {
77 + return dictionary_get(rrdhost_root_index, guid);
78 }
79
54 -avl_tree_lock rrdhost_root_index = {
55 - .avl_tree = { NULL, rrdhost_compare },
56 - .rwlock = AVL_LOCK_INITIALIZER
57 -};
80 +static inline RRDHOST *rrdhost_index_add_by_guid(RRDHOST *host) {
81 + RRDHOST *ret_machine_guid = dictionary_set(rrdhost_root_index, host->machine_guid, host, sizeof(RRDHOST));
82 + if(ret_machine_guid == host)
83 + rrdhost_flag_set(host, RRDHOST_FLAG_INDEXED_MACHINE_GUID);
84 + else {
85 + rrdhost_flag_clear(host, RRDHOST_FLAG_INDEXED_MACHINE_GUID);
86 + error("RRDHOST: %s() host with machine guid '%s' is already indexed", __FUNCTION__, host->machine_guid);
87 + }
88
59 -RRDHOST *rrdhost_find_by_guid(const char *guid, uint32_t hash) {
60 - debug(D_RRDHOST, "Searching in index for host with guid '%s'", guid);
89 + return host;
90 +}
91
62 - RRDHOST tmp;
63 - strncpyz(tmp.machine_guid, guid, GUID_LEN);
64 - tmp.hash_machine_guid = (hash)?hash:simple_hash(tmp.machine_guid);
92 +static void rrdhost_index_del_by_guid(RRDHOST *host) {
93 + if(rrdhost_flag_check(host, RRDHOST_FLAG_INDEXED_MACHINE_GUID)) {
94 + if(dictionary_del(rrdhost_root_index, host->machine_guid) != 0)
95 + error("RRDHOST: %s() failed to delete machine guid '%s' from index", __FUNCTION__, host->machine_guid);
96
66 - return (RRDHOST *)avl_search_lock(&(rrdhost_root_index), (avl_t *) &tmp);
97 + rrdhost_flag_clear(host, RRDHOST_FLAG_INDEXED_MACHINE_GUID);
98 + }
99 }
100
69 -RRDHOST *rrdhost_find_by_hostname(const char *hostname, uint32_t hash) {
101 +// ----------------------------------------------------------------------------
102 +// RRDHOST index by hostname
103 +
104 +inline RRDHOST *rrdhost_find_by_hostname(const char *hostname) {
105 if(unlikely(!strcmp(hostname, "localhost")))
106 return localhost;
107
73 - if(unlikely(!hash)) hash = simple_hash(hostname);
108 + return dictionary_get(rrdhost_root_index_hostname, hostname);
109 +}
110 +
111 +static inline RRDHOST *rrdhost_index_add_hostname(RRDHOST *host) {
112 + if(!host->hostname) return host;
113
75 - rrd_rdlock();
76 - RRDHOST *host;
77 - rrdhost_foreach_read(host) {
78 - if(unlikely((hash == host->hash_hostname && !strcmp(hostname, host->hostname)))) {
79 - rrd_unlock();
80 - return host;
81 - }
114 + RRDHOST *ret_hostname = dictionary_set(rrdhost_root_index_hostname, rrdhost_hostname(host), host, sizeof(RRDHOST));
115 + if(ret_hostname == host)
116 + rrdhost_flag_set(host, RRDHOST_FLAG_INDEXED_HOSTNAME);
117 + else {
118 + rrdhost_flag_clear(host, RRDHOST_FLAG_INDEXED_HOSTNAME);
119 + error("RRDHOST: %s() host with hostname '%s' is already indexed", __FUNCTION__, rrdhost_hostname(host));
120 }
83 - rrd_unlock();
121
85 - return NULL;
122 + return host;
123 }
124
88 -#define rrdhost_index_add(rrdhost) (RRDHOST *)avl_insert_lock(&(rrdhost_root_index), (avl_t *)(rrdhost))
89 -#define rrdhost_index_del(rrdhost) (RRDHOST *)avl_remove_lock(&(rrdhost_root_index), (avl_t *)(rrdhost))
125 +static inline void rrdhost_index_del_hostname(RRDHOST *host) {
126 + if(unlikely(!host->hostname)) return;
127
128 + if(rrdhost_flag_check(host, RRDHOST_FLAG_INDEXED_HOSTNAME)) {
129 + if(dictionary_del(rrdhost_root_index_hostname, rrdhost_hostname(host)) != 0)
130 + error("RRDHOST: %s() failed to delete hostname '%s' from index", __FUNCTION__, rrdhost_hostname(host));
131 +
132 + rrdhost_flag_clear(host, RRDHOST_FLAG_INDEXED_HOSTNAME);
133 + }
134 +}
135
136 // ----------------------------------------------------------------------------
137 // RRDHOST - internal helpers
138
139 static inline void rrdhost_init_tags(RRDHOST *host, const char *tags) {
96 - if(host->tags && tags && !strcmp(host->tags, tags))
140 + if(host->tags && tags && !strcmp(rrdhost_tags(host), tags))
141 return;
142
99 - void *old = (void *)host->tags;
100 - host->tags = (tags && *tags)?strdupz(tags):NULL;
101 - freez(old);
143 + STRING *old = host->tags;
144 + host->tags = string_strdupz((tags && *tags)?tags:NULL);
145 + string_freez(old);
146 }
147
148 static inline void rrdhost_init_hostname(RRDHOST *host, const char *hostname) {
105 - if(host->hostname && hostname && !strcmp(host->hostname, hostname))
149 + if(unlikely(hostname && !*hostname)) hostname = NULL;
150 +
151 + if(host->hostname && hostname && !strcmp(rrdhost_hostname(host), hostname))
152 return;
153
108 - void *old = host->hostname;
109 - host->hostname = strdupz(hostname?hostname:"localhost");
110 - host->hash_hostname = simple_hash(host->hostname);
111 - freez(old);
154 + rrdhost_index_del_hostname(host);
155 +
156 + STRING *old = host->hostname;
157 + host->hostname = string_strdupz(hostname?hostname:"localhost");
158 + string_freez(old);
159 +
160 + rrdhost_index_add_hostname(host);
161 }
162
163 static inline void rrdhost_init_os(RRDHOST *host, const char *os) {
115 - if(host->os && os && !strcmp(host->os, os))
164 + if(host->os && os && !strcmp(rrdhost_os(host), os))
165 return;
166
118 - void *old = (void *)host->os;
119 - host->os = strdupz(os?os:"unknown");
120 - freez(old);
167 + STRING *old = host->os;
168 + host->os = string_strdupz(os?os:"unknown");
169 + string_freez(old);
170 }
171
172 static inline void rrdhost_init_timezone(RRDHOST *host, const char *timezone, const char *abbrev_timezone, int32_t utc_offset) {
124 - if (host->timezone && timezone && !strcmp(host->timezone, timezone) && host->abbrev_timezone && abbrev_timezone &&
125 - !strcmp(host->abbrev_timezone, abbrev_timezone) && host->utc_offset == utc_offset)
173 + if (host->timezone && timezone && !strcmp(rrdhost_timezone(host), timezone) && host->abbrev_timezone && abbrev_timezone &&
174 + !strcmp(rrdhost_abbrev_timezone(host), abbrev_timezone) && host->utc_offset == utc_offset)
175 return;
176
128 - void *old = (void *)host->timezone;
129 - host->timezone = strdupz((timezone && *timezone)?timezone:"unknown");
130 - freez(old);
177 + STRING *old = host->timezone;
178 + host->timezone = string_strdupz((timezone && *timezone)?timezone:"unknown");
179 + string_freez(old);
180
181 old = (void *)host->abbrev_timezone;
133 - host->abbrev_timezone = strdupz((abbrev_timezone && *abbrev_timezone) ? abbrev_timezone : "UTC");
182 + host->abbrev_timezone = string_strdupz((abbrev_timezone && *abbrev_timezone) ? abbrev_timezone : "UTC");
183 freez(old);
184
185 host->utc_offset = utc_offset;
186 }
187
139 -static inline void rrdhost_init_machine_guid(RRDHOST *host, const char *machine_guid) {
140 - strncpy(host->machine_guid, machine_guid, GUID_LEN);
141 - host->machine_guid[GUID_LEN] = '\0';
142 - host->hash_machine_guid = simple_hash(host->machine_guid);
143 -}
144 -
145 -void set_host_properties(RRDHOST *host, int update_every, RRD_MEMORY_MODE memory_mode, const char *hostname,
146 - const char *registry_hostname, const char *guid, const char *os, const char *tags,
188 +void set_host_properties(RRDHOST *host, int update_every, RRD_MEMORY_MODE memory_mode,
189 + const char *registry_hostname, const char *os, const char *tags,
190 const char *tzone, const char *abbrev_tzone, int32_t utc_offset, const char *program_name,
191 const char *program_version)
192 {
@@ -151,18 +194,13 @@ void set_host_properties(RRDHOST *host, int update_every, RRD_MEMORY_MODE memory
194 host->rrd_update_every = update_every;
195 host->rrd_memory_mode = memory_mode;
196
154 - rrdhost_init_hostname(host, hostname);
155 -
156 - rrdhost_init_machine_guid(host, guid);
157 -
197 rrdhost_init_os(host, os);
198 rrdhost_init_timezone(host, tzone, abbrev_tzone, utc_offset);
199 rrdhost_init_tags(host, tags);
200
162 - host->program_name = strdupz((program_name && *program_name) ? program_name : "unknown");
163 - host->program_version = strdupz((program_version && *program_version) ? program_version : "unknown");
164 -
165 - host->registry_hostname = strdupz((registry_hostname && *registry_hostname) ? registry_hostname : host->hostname);
201 + host->program_name = string_strdupz((program_name && *program_name) ? program_name : "unknown");
202 + host->program_version = string_strdupz((program_version && *program_version) ? program_version : "unknown");
203 + host->registry_hostname = string_strdupz((registry_hostname && *registry_hostname) ? registry_hostname : rrdhost_hostname(host));
204 }
205
206 // ----------------------------------------------------------------------------
@@ -202,9 +240,14 @@ RRDHOST *rrdhost_create(const char *hostname,
240 int is_in_multihost = (memory_mode == RRD_MEMORY_MODE_DBENGINE && !is_legacy);
241 RRDHOST *host = callocz(1, sizeof(RRDHOST));
242
205 - set_host_properties(host, (update_every > 0)?update_every:1, memory_mode, hostname, registry_hostname, guid, os,
243 + strncpy(host->machine_guid, guid, GUID_LEN);
244 + host->machine_guid[GUID_LEN] = '\0';
245 +
246 + set_host_properties(host, (update_every > 0)?update_every:1, memory_mode, registry_hostname, os,
247 tags, timezone, abbrev_timezone, utc_offset, program_name, program_version);
248
249 + rrdhost_init_hostname(host, hostname);
250 +
251 host->rrd_history_entries = align_entries_to_pagesize(memory_mode, entries);
252 host->health_enabled = ((memory_mode == RRD_MEMORY_MODE_NONE)) ? 0 : health_enabled;
253
@@ -237,10 +280,10 @@ RRDHOST *rrdhost_create(const char *hostname,
280
281 host->system_info = system_info;
282
240 - avl_init_lock(&(host->rrdset_root_index), rrdset_compare);
241 - avl_init_lock(&(host->rrdset_root_index_name), rrdset_compare_name);
242 - avl_init_lock(&(host->rrdfamily_root_index), rrdfamily_compare);
243 - avl_init_lock(&(host->rrdvar_root_index), rrdvar_compare);
283 + host->rrdset_root_index = dictionary_create(DICTIONARY_FLAG_NAME_LINK_DONT_CLONE|DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE|DICTIONARY_FLAG_DONT_OVERWRITE_VALUE);
284 + host->rrdset_root_index_name = dictionary_create(DICTIONARY_FLAG_NAME_LINK_DONT_CLONE|DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE|DICTIONARY_FLAG_DONT_OVERWRITE_VALUE);
285 + host->rrdfamily_root_index = dictionary_create(DICTIONARY_FLAG_NAME_LINK_DONT_CLONE|DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE|DICTIONARY_FLAG_DONT_OVERWRITE_VALUE);
286 + host->rrdvar_root_index = dictionary_create(DICTIONARY_FLAG_NAME_LINK_DONT_CLONE|DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE|DICTIONARY_FLAG_DONT_OVERWRITE_VALUE);
287
288 if(config_get_boolean(CONFIG_SECTION_DB, "delete obsolete charts files", 1))
289 rrdhost_flag_set(host, RRDHOST_FLAG_DELETE_OBSOLETE_CHARTS);
@@ -250,8 +293,6 @@ RRDHOST *rrdhost_create(const char *hostname,
293
294 host->health_default_warn_repeat_every = config_get_duration(CONFIG_SECTION_HEALTH, "default repeat warning", "never");
295 host->health_default_crit_repeat_every = config_get_duration(CONFIG_SECTION_HEALTH, "default repeat critical", "never");
253 - avl_init_lock(&(host->alarms_idx_health_log), alarm_compare_id);
254 - avl_init_lock(&(host->alarms_idx_name), alarm_compare_name);
296
297 // ------------------------------------------------------------------------
298 // initialize health variables
@@ -264,7 +305,7 @@ RRDHOST *rrdhost_create(const char *hostname,
305
306 long n = config_get_number(CONFIG_SECTION_HEALTH, "in memory max health log entries", host->health_log.max);
307 if(n < 10) {
267 - error("Host '%s': health configuration has invalid max log entries %ld. Using default %u", host->hostname, n, host->health_log.max);
308 + error("Host '%s': health configuration has invalid max log entries %ld. Using default %u", rrdhost_hostname(host), n, host->health_log.max);
309 config_set_number(CONFIG_SECTION_HEALTH, "in memory max health log entries", (long)host->health_log.max);
310 }
311 else
@@ -293,7 +334,7 @@ RRDHOST *rrdhost_create(const char *hostname,
334 host->rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE && is_legacy))) {
335 int r = mkdir(host->cache_dir, 0775);
336 if(r != 0 && errno != EEXIST)
296 - error("Host '%s': cannot create directory '%s'", host->hostname, host->cache_dir);
337 + error("Host '%s': cannot create directory '%s'", rrdhost_hostname(host), host->cache_dir);
338 }
339
340 snprintfz(filename, FILENAME_MAX, "%s/%s", netdata_configured_varlib_dir, host->machine_guid);
@@ -302,7 +343,7 @@ RRDHOST *rrdhost_create(const char *hostname,
343 if(host->health_enabled) {
344 int r = mkdir(host->varlib_dir, 0775);
345 if(r != 0 && errno != EEXIST)
305 - error("Host '%s': cannot create directory '%s'", host->hostname, host->varlib_dir);
346 + error("Host '%s': cannot create directory '%s'", rrdhost_hostname(host), host->varlib_dir);
347 }
348
349 }
@@ -311,15 +352,15 @@ RRDHOST *rrdhost_create(const char *hostname,
352 snprintfz(filename, FILENAME_MAX, "%s/health", host->varlib_dir);
353 int r = mkdir(filename, 0775);
354 if(r != 0 && errno != EEXIST)
314 - error("Host '%s': cannot create directory '%s'", host->hostname, filename);
355 + error("Host '%s': cannot create directory '%s'", rrdhost_hostname(host), filename);
356 }
357
358 snprintfz(filename, FILENAME_MAX, "%s/health/health-log.db", host->varlib_dir);
359 host->health_log_filename = strdupz(filename);
360
361 snprintfz(filename, FILENAME_MAX, "%s/alarm-notify.sh", netdata_configured_primary_plugins_dir);
321 - host->health_default_exec = strdupz(config_get(CONFIG_SECTION_HEALTH, "script to execute on alarm", filename));
322 - host->health_default_recipient = strdupz("root");
362 + host->health_default_exec = string_strdupz(config_get(CONFIG_SECTION_HEALTH, "script to execute on alarm", filename));
363 + host->health_default_recipient = string_strdupz("root");
364
365
366 // ------------------------------------------------------------------------
@@ -331,10 +372,9 @@ RRDHOST *rrdhost_create(const char *hostname,
372 rrdhost_unlock(host);
373 }
374
334 - RRDHOST *t = rrdhost_index_add(host);
335 -
375 + RRDHOST *t = rrdhost_index_add_by_guid(host);
376 if(t != host) {
337 - error("Host '%s': cannot add host with machine guid '%s' to index. It already exists as host '%s' with machine guid '%s'.", host->hostname, host->machine_guid, t->hostname, t->machine_guid);
377 + error("Host '%s': cannot add host with machine guid '%s' to index. It already exists as host '%s' with machine guid '%s'.", rrdhost_hostname(host), host->machine_guid, rrdhost_hostname(t), t->machine_guid);
378 rrdhost_free(host, 1);
379 return NULL;
380 }
@@ -376,7 +416,7 @@ RRDHOST *rrdhost_create(const char *hostname,
416 snprintfz(dbenginepath, FILENAME_MAX, "%s/dbengine", host->cache_dir);
417 ret = mkdir(dbenginepath, 0775);
418 if (ret != 0 && errno != EEXIST)
379 - error("Host '%s': cannot create directory '%s'", host->hostname, dbenginepath);
419 + error("Host '%s': cannot create directory '%s'", rrdhost_hostname(host), dbenginepath);
420 else ret = 0; // succeed
421 if (is_legacy) {
422 // initialize legacy dbengine instance as needed
@@ -403,7 +443,7 @@ RRDHOST *rrdhost_create(const char *hostname,
443 if (ret) { // check legacy or multihost initialization success
444 error(
445 "Host '%s': cannot initialize host with machine guid '%s'. Failed to initialize DB engine at '%s'.",
406 - host->hostname, host->machine_guid, host->cache_dir);
446 + rrdhost_hostname(host), host->machine_guid, host->cache_dir);
447 rrdhost_free(host, 1);
448 host = NULL;
449 //rrd_hosts_available++; //TODO: maybe we want this?
@@ -426,17 +466,10 @@ RRDHOST *rrdhost_create(const char *hostname,
466 // ------------------------------------------------------------------------
467 // link it and add it to the index
468
429 - if(is_localhost) {
430 - host->next = localhost;
431 - localhost = host;
432 - }
433 - else {
434 - if(localhost) {
435 - host->next = localhost->next;
436 - localhost->next = host;
437 - }
438 - else localhost = host;
439 - }
469 + if(is_localhost)
470 + DOUBLE_LINKED_LIST_PREPEND_UNSAFE(localhost, host, prev, next);
471 + else
472 + DOUBLE_LINKED_LIST_APPEND_UNSAFE(localhost, host, prev, next);
473
474 // ------------------------------------------------------------------------
475 // init new ML host and update system_info to let upstreams know
@@ -466,14 +499,14 @@ RRDHOST *rrdhost_create(const char *hostname,
499 ", health_log '%s'"
500 ", alarms default handler '%s'"
501 ", alarms default recipient '%s'"
469 - , host->hostname
470 - , host->registry_hostname
502 + , rrdhost_hostname(host)
503 + , rrdhost_registry_hostname(host)
504 , host->machine_guid
472 - , host->os
473 - , host->timezone
474 - , (host->tags)?host->tags:""
475 - , host->program_name
476 - , host->program_version
505 + , rrdhost_os(host)
506 + , rrdhost_timezone(host)
507 + , rrdhost_tags(host)
508 + , rrdhost_program_name(host)
509 + , rrdhost_program_version(host)
510 , host->rrd_update_every
511 , rrd_memory_mode_name(host->rrd_memory_mode)
512 , host->rrd_history_entries
@@ -484,8 +517,8 @@ RRDHOST *rrdhost_create(const char *hostname,
517 , host->cache_dir
518 , host->varlib_dir
519 , host->health_log_filename
487 - , host->health_default_exec
488 - , host->health_default_recipient
520 + , string2str(host->health_default_exec)
521 + , string2str(host->health_default_recipient)
522 );
523 sql_store_host_system_info(&host->host_uuid, system_info);
524
@@ -537,39 +570,36 @@ void rrdhost_update(RRDHOST *host
570 rrdhost_init_os(host, os);
571 rrdhost_init_timezone(host, timezone, abbrev_timezone, utc_offset);
572
540 - freez(host->registry_hostname);
541 - host->registry_hostname = strdupz((registry_hostname && *registry_hostname)?registry_hostname:hostname);
573 + string_freez(host->registry_hostname);
574 + host->registry_hostname = string_strdupz((registry_hostname && *registry_hostname)?registry_hostname:hostname);
575
543 - if(strcmp(host->hostname, hostname) != 0) {
544 - info("Host '%s' has been renamed to '%s'. If this is not intentional it may mean multiple hosts are using the same machine_guid.", host->hostname, hostname);
545 - char *t = host->hostname;
546 - host->hostname = strdupz(hostname);
547 - host->hash_hostname = simple_hash(host->hostname);
548 - freez(t);
576 + if(strcmp(rrdhost_hostname(host), hostname) != 0) {
577 + info("Host '%s' has been renamed to '%s'. If this is not intentional it may mean multiple hosts are using the same machine_guid.", rrdhost_hostname(host), hostname);
578 + rrdhost_init_hostname(host, hostname);
579 }
580
551 - if(strcmp(host->program_name, program_name) != 0) {
552 - info("Host '%s' switched program name from '%s' to '%s'", host->hostname, host->program_name, program_name);
553 - char *t = host->program_name;
554 - host->program_name = strdupz(program_name);
555 - freez(t);
581 + if(strcmp(rrdhost_program_name(host), program_name) != 0) {
582 + info("Host '%s' switched program name from '%s' to '%s'", rrdhost_hostname(host), rrdhost_program_name(host), program_name);
583 + STRING *t = host->program_name;
584 + host->program_name = string_strdupz(program_name);
585 + string_freez(t);
586 }
587
558 - if(strcmp(host->program_version, program_version) != 0) {
559 - info("Host '%s' switched program version from '%s' to '%s'", host->hostname, host->program_version, program_version);
560 - char *t = host->program_version;
561 - host->program_version = strdupz(program_version);
562 - freez(t);
588 + if(strcmp(rrdhost_program_version(host), program_version) != 0) {
589 + info("Host '%s' switched program version from '%s' to '%s'", rrdhost_hostname(host), rrdhost_program_version(host), program_version);
590 + STRING *t = host->program_version;
591 + host->program_version = string_strdupz(program_version);
592 + string_freez(t);
593 }
594
595 if(host->rrd_update_every != update_every)
566 - error("Host '%s' has an update frequency of %d seconds, but the wanted one is %d seconds. Restart netdata here to apply the new settings.", host->hostname, host->rrd_update_every, update_every);
596 + error("Host '%s' has an update frequency of %d seconds, but the wanted one is %d seconds. Restart netdata here to apply the new settings.", rrdhost_hostname(host), host->rrd_update_every, update_every);
597
598 if(host->rrd_history_entries < history)
569 - error("Host '%s' has history of %ld entries, but the wanted one is %ld entries. Restart netdata here to apply the new settings.", host->hostname, host->rrd_history_entries, history);
599 + error("Host '%s' has history of %ld entries, but the wanted one is %ld entries. Restart netdata here to apply the new settings.", rrdhost_hostname(host), host->rrd_history_entries, history);
600
601 if(host->rrd_memory_mode != mode)
572 - error("Host '%s' has memory mode '%s', but the wanted one is '%s'. Restart netdata here to apply the new settings.", host->hostname, rrd_memory_mode_name(host->rrd_memory_mode), rrd_memory_mode_name(mode));
602 + error("Host '%s' has memory mode '%s', but the wanted one is '%s'. Restart netdata here to apply the new settings.", rrdhost_hostname(host), rrd_memory_mode_name(host->rrd_memory_mode), rrd_memory_mode_name(mode));
603
604 // update host tags
605 rrdhost_init_tags(host, tags);
@@ -591,12 +621,12 @@ void rrdhost_update(RRDHOST *host
621 if (host != localhost) {
622 r = mkdir(host->varlib_dir, 0775);
623 if (r != 0 && errno != EEXIST)
594 - error("Host '%s': cannot create directory '%s'", host->hostname, host->varlib_dir);
624 + error("Host '%s': cannot create directory '%s'", rrdhost_hostname(host), host->varlib_dir);
625 }
626 snprintfz(filename, FILENAME_MAX, "%s/health", host->varlib_dir);
627 r = mkdir(filename, 0775);
628 if(r != 0 && errno != EEXIST)
599 - error("Host '%s': cannot create directory '%s'", host->hostname, filename);
629 + error("Host '%s': cannot create directory '%s'", rrdhost_hostname(host), filename);
630
631 rrdhost_wrlock(host);
632 health_readdir(host, health_user_config_dir(), health_stock_config_dir(), NULL);
@@ -621,7 +651,7 @@ void rrdhost_update(RRDHOST *host
651 rrd_hosts_available++;
652 ml_new_host(host);
653 rrdhost_load_rrdcontext_data(host);
624 - info("Host %s is not in archived mode anymore", host->hostname);
654 + info("Host %s is not in archived mode anymore", rrdhost_hostname(host));
655 }
656
657 return;
@@ -652,11 +682,11 @@ RRDHOST *rrdhost_find_or_create(
682 debug(D_RRDHOST, "Searching for host '%s' with guid '%s'", hostname, guid);
683
684 rrd_wrlock();
655 - RRDHOST *host = rrdhost_find_by_guid(guid, 0);
685 + RRDHOST *host = rrdhost_find_by_guid(guid);
686 if (unlikely(host && RRD_MEMORY_MODE_DBENGINE != mode && rrdhost_flag_check(host, RRDHOST_FLAG_ARCHIVED))) {
687 /* If a legacy memory mode instantiates all dbengine state must be discarded to avoid inconsistencies */
688 error("Archived host '%s' has memory mode '%s', but the wanted one is '%s'. Discarding archived state.",
659 - host->hostname, rrd_memory_mode_name(host->rrd_memory_mode), rrd_memory_mode_name(mode));
689 + rrdhost_hostname(host), rrd_memory_mode_name(host->rrd_memory_mode), rrd_memory_mode_name(mode));
690 rrdhost_free(host, 1);
691 host = NULL;
692 }
@@ -739,7 +769,7 @@ void rrdhost_cleanup_orphan_hosts_nolock(RRDHOST *protected_host) {
769 restart_after_removal:
770 rrdhost_foreach_write(host) {
771 if(rrdhost_should_be_removed(host, protected_host, now)) {
742 - info("Host '%s' with machine guid '%s' is obsolete - cleaning up.", host->hostname, host->machine_guid);
772 + info("Host '%s' with machine guid '%s' is obsolete - cleaning up.", rrdhost_hostname(host), host->machine_guid);
773
774 if (rrdhost_flag_check(host, RRDHOST_FLAG_DELETE_ORPHAN_HOST)
775 #ifdef ENABLE_DBENGINE
@@ -761,6 +791,7 @@ restart_after_removal:
791 // RRDHOST global / startup initialization
792
793 int rrd_init(char *hostname, struct rrdhost_system_info *system_info) {
794 + rrdhost_init();
795
796 if (unlikely(sql_init_database(DB_CHECK_NONE, system_info ? 0 : 1))) {
797 if (default_rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE)
@@ -940,19 +971,19 @@ unittest:
971 // there are only used when NETDATA_INTERNAL_CHECKS is set
972
973 void __rrdhost_check_rdlock(RRDHOST *host, const char *file, const char *function, const unsigned long line) {
943 - debug(D_RRDHOST, "Checking read lock on host '%s'", host->hostname);
974 + debug(D_RRDHOST, "Checking read lock on host '%s'", rrdhost_hostname(host));
975
976 int ret = netdata_rwlock_trywrlock(&host->rrdhost_rwlock);
977 if(ret == 0)
947 - fatal("RRDHOST '%s' should be read-locked, but it is not, at function %s() at line %lu of file '%s'", host->hostname, function, line, file);
978 + fatal("RRDHOST '%s' should be read-locked, but it is not, at function %s() at line %lu of file '%s'", rrdhost_hostname(host), function, line, file);
979 }
980
981 void __rrdhost_check_wrlock(RRDHOST *host, const char *file, const char *function, const unsigned long line) {
951 - debug(D_RRDHOST, "Checking write lock on host '%s'", host->hostname);
982 + debug(D_RRDHOST, "Checking write lock on host '%s'", rrdhost_hostname(host));
983
984 int ret = netdata_rwlock_tryrdlock(&host->rrdhost_rwlock);
985 if(ret == 0)
955 - fatal("RRDHOST '%s' should be write-locked, but it is not, at function %s() at line %lu of file '%s'", host->hostname, function, line, file);
986 + fatal("RRDHOST '%s' should be write-locked, but it is not, at function %s() at line %lu of file '%s'", rrdhost_hostname(host), function, line, file);
987 }
988
989 void __rrd_check_rdlock(const char *file, const char *function, const unsigned long line) {
@@ -1051,7 +1082,7 @@ void rrdhost_free(RRDHOST *host, bool force) {
1082 if(!host) return;
1083
1084 if (netdata_exit || force)
1054 - info("Freeing all memory for host '%s'...", host->hostname);
1085 + info("Freeing all memory for host '%s'...", rrdhost_hostname(host));
1086
1087 rrd_check_wrlock(); // make sure the RRDs are write locked
1088
@@ -1084,8 +1115,8 @@ void rrdhost_free(RRDHOST *host, bool force) {
1115
1116 freez(host->exporting_flags);
1117
1087 - while(host->alarms)
1088 - rrdcalc_unlink_and_free(host, host->alarms);
1118 + while(host->host_alarms)
1119 + rrdcalc_unlink_and_free(host, host->host_alarms);
1120
1121 RRDCALC *rc,*nc;
1122 for(rc = host->alarms_with_foreach; rc ; rc = nc) {
@@ -1094,18 +1125,11 @@ void rrdhost_free(RRDHOST *host, bool force) {
1125 }
1126 host->alarms_with_foreach = NULL;
1127
1097 - while(host->templates)
1098 - rrdcalctemplate_unlink_and_free(host, host->templates);
1099 -
1100 - RRDCALCTEMPLATE *rt,*next;
1101 - for(rt = host->alarms_template_with_foreach; rt ; rt = next) {
1102 - next = rt->next;
1103 - rrdcalctemplate_free(rt);
1104 - }
1105 - host->alarms_template_with_foreach = NULL;
1128 + while(host->alarms_templates)
1129 + rrdcalctemplate_unlink_and_free(host, host->alarms_templates);
1130
1107 - debug(D_RRD_CALLS, "RRDHOST: Cleaning up remaining host variables for host '%s'", host->hostname);
1108 - rrdvar_free_remaining_variables(host, &host->rrdvar_root_index);
1131 + debug(D_RRD_CALLS, "RRDHOST: Cleaning up remaining host variables for host '%s'", rrdhost_hostname(host));
1132 + rrdvar_free_remaining_variables(host, host->rrdvar_root_index);
1133
1134 health_alarm_log_free(host);
1135
@@ -1119,7 +1143,7 @@ void rrdhost_free(RRDHOST *host, bool force) {
1143 #endif
1144
1145 if (!netdata_exit && !force) {
1122 - info("Setting archive mode for host '%s'...", host->hostname);
1146 + info("Setting archive mode for host '%s'...", rrdhost_hostname(host));
1147 rrdhost_flag_set(host, RRDHOST_FLAG_ARCHIVED);
1148 rrdhost_unlock(host);
1149 return;
@@ -1143,24 +1167,13 @@ void rrdhost_free(RRDHOST *host, bool force) {
1167 // ------------------------------------------------------------------------
1168 // remove it from the indexes
1169
1146 - if(rrdhost_index_del(host) != host)
1147 - error("RRDHOST '%s' removed from index, deleted the wrong entry.", host->hostname);
1170 + rrdhost_index_del_hostname(host);
1171 + rrdhost_index_del_by_guid(host);
1172
1173 // ------------------------------------------------------------------------
1174 // unlink it from the host
1175
1152 - if(host == localhost) {
1153 - localhost = host->next;
1154 - }
1155 - else {
1156 - // find the previous one
1157 - RRDHOST *h;
1158 - for(h = localhost; h && h->next != host ; h = h->next) ;
1159 -
1160 - // bypass it
1161 - if(h) h->next = host->next;
1162 - else error("Request to free RRDHOST '%s': cannot find it", host->hostname);
1163 - }
1176 + DOUBLE_LINKED_LIST_REMOVE_UNSAFE(localhost, host, prev, next);
1177
1178 // ------------------------------------------------------------------------
1179 // free it
@@ -1168,13 +1181,13 @@ void rrdhost_free(RRDHOST *host, bool force) {
1181 pthread_mutex_destroy(&host->aclk_state_lock);
1182 freez(host->aclk_state.claimed_id);
1183 freez(host->aclk_state.prev_claimed_id);
1171 - freez((void *)host->tags);
1184 + string_freez(host->tags);
1185 rrdlabels_destroy(host->host_labels);
1173 - freez((void *)host->os);
1174 - freez((void *)host->timezone);
1175 - freez((void *)host->abbrev_timezone);
1176 - freez(host->program_version);
1177 - freez(host->program_name);
1186 + string_freez(host->os);
1187 + string_freez(host->timezone);
1188 + string_freez(host->abbrev_timezone);
1189 + string_freez(host->program_name);
1190 + string_freez(host->program_version);
1191 rrdhost_system_info_free(host->system_info);
1192 freez(host->cache_dir);
1193 freez(host->varlib_dir);
@@ -1186,19 +1199,24 @@ void rrdhost_free(RRDHOST *host, bool force) {
1199 freez(host->destinations);
1200 host->destinations = tmp_destination;
1201 }
1189 - freez(host->health_default_exec);
1190 - freez(host->health_default_recipient);
1202 + string_freez(host->health_default_exec);
1203 + string_freez(host->health_default_recipient);
1204 freez(host->health_log_filename);
1192 - freez(host->hostname);
1193 - freez(host->registry_hostname);
1205 + string_freez(host->registry_hostname);
1206 simple_pattern_free(host->rrdpush_send_charts_matching);
1207 rrdhost_unlock(host);
1208 netdata_rwlock_destroy(&host->health_log.alarm_log_rwlock);
1209 netdata_rwlock_destroy(&host->rrdhost_rwlock);
1210 freez(host->node_id);
1211
1212 + dictionary_destroy(host->rrdset_root_index);
1213 + dictionary_destroy(host->rrdset_root_index_name);
1214 + dictionary_destroy(host->rrdfamily_root_index);
1215 + dictionary_destroy(host->rrdvar_root_index);
1216 +
1217 rrdhost_destroy_rrdcontexts(host);
1218
1219 + string_freez(host->hostname);
1220 freez(host);
1221 #ifdef ENABLE_ACLK
1222 if (wc)
@@ -1209,9 +1227,14 @@ void rrdhost_free(RRDHOST *host, bool force) {
1227
1228 void rrdhost_free_all(void) {
1229 rrd_wrlock();
1230 +
1231 /* Make sure child-hosts are released before the localhost. */
1213 - while(localhost->next) rrdhost_free(localhost->next, 1);
1214 - rrdhost_free(localhost, 1);
1232 + while(localhost && localhost->next)
1233 + rrdhost_free(localhost->next, 1);
1234 +
1235 + if(localhost)
1236 + rrdhost_free(localhost, 1);
1237 +
1238 rrd_unlock();
1239 }
1240
@@ -1221,7 +1244,7 @@ void rrdhost_free_all(void) {
1244 void rrdhost_save_charts(RRDHOST *host) {
1245 if(!host) return;
1246
1224 - info("Saving/Closing database of host '%s'...", host->hostname);
1247 + info("Saving/Closing database of host '%s'...", rrdhost_hostname(host));
1248
1249 RRDSET *st;
1250
@@ -1302,7 +1325,7 @@ static void rrdhost_load_auto_labels(void) {
1325 add_aclk_host_labels();
1326
1327 rrdlabels_add(
1305 - labels, "_is_parent", (localhost->next || configured_as_parent()) ? "true" : "false", RRDLABEL_SRC_AUTO);
1328 + labels, "_is_parent", (rrdhost_hosts_available() > 1 || configured_as_parent()) ? "true" : "false", RRDLABEL_SRC_AUTO);
1329
1330 if (localhost->rrdpush_send_destination)
1331 rrdlabels_add(labels, "_streams_to", localhost->rrdpush_send_destination, RRDLABEL_SRC_AUTO);
@@ -1383,7 +1406,7 @@ void reload_host_labels(void) {
1406 void rrdhost_delete_charts(RRDHOST *host) {
1407 if(!host) return;
1408
1386 - info("Deleting database of host '%s'...", host->hostname);
1409 + info("Deleting database of host '%s'...", rrdhost_hostname(host));
1410
1411 RRDSET *st;
1412
@@ -1408,7 +1431,7 @@ void rrdhost_delete_charts(RRDHOST *host) {
1431 void rrdhost_cleanup_charts(RRDHOST *host) {
1432 if(!host) return;
1433
1411 - info("Cleaning up database of host '%s'...", host->hostname);
1434 + info("Cleaning up database of host '%s'...", rrdhost_hostname(host));
1435
1436 RRDSET *st;
1437 uint32_t rrdhost_delete_obsolete_charts = rrdhost_flag_check(host, RRDHOST_FLAG_DELETE_OBSOLETE_CHARTS);
@@ -1497,8 +1520,8 @@ restart_after_removal:
1520 RRDDIM *rd, *last;
1521
1522 rrdset_flag_set(st, RRDSET_FLAG_ARCHIVED);
1500 - while (st->variables) rrdsetvar_free(st->variables);
1501 - while (st->alarms) rrdsetcalc_unlink(st->alarms);
1523 + while (st->variables) rrdsetvar_free(st->variables);
1524 + while (st->alarms) rrdsetcalc_unlink(st->alarms);
1525 rrdset_wrlock(st);
1526 for (rd = st->dimensions, last = NULL ; likely(rd) ; ) {
1527 if (rrddim_flag_check(rd, RRDDIM_FLAG_ARCHIVED)) {
@@ -1555,8 +1578,8 @@ restart_after_removal:
1578 }
1579 rrdset_unlock(st);
1580
1558 - debug(D_RRD_CALLS, "RRDSET: Cleaning up remaining chart variables for host '%s', chart '%s'", host->hostname, st->id);
1559 - rrdvar_free_remaining_variables(host, &st->rrdvar_root_index);
1581 + debug(D_RRD_CALLS, "RRDSET: Cleaning up remaining chart variables for host '%s', chart '%s'", rrdhost_hostname(host), rrdset_id(st));
1582 + rrdvar_free_remaining_variables(host, st->rrdvar_root_index);
1583
1584 rrdset_flag_clear(st, RRDSET_FLAG_OBSOLETE);
1585
@@ -1761,46 +1784,6 @@ int rrdhost_set_system_info_variable(struct rrdhost_system_info *system_info, ch
1784 return res;
1785 }
1786
1764 -/**
1765 - * Alarm Compare ID
1766 - *
1767 - * Callback function used with the binary trees to compare the id of RRDCALC
1768 - *
1769 - * @param a a pointer to the RRDCAL item to insert,compare or update the binary tree
1770 - * @param b the pointer to the binary tree.
1771 - *
1772 - * @return It returns 0 case the values are equal, 1 case a is bigger than b and -1 case a is smaller than b.
1773 - */
1774 -int alarm_compare_id(void *a, void *b) {
1775 - register uint32_t hash1 = ((RRDCALC *)a)->id;
1776 - register uint32_t hash2 = ((RRDCALC *)b)->id;
1777 -
1778 - if(hash1 < hash2) return -1;
1779 - else if(hash1 > hash2) return 1;
1780 -
1781 - return 0;
1782 -}
1783 -
1784 -/**
1785 - * Alarm Compare NAME
1786 - *
1787 - * Callback function used with the binary trees to compare the name of RRDCALC
1788 - *
1789 - * @param a a pointer to the RRDCAL item to insert,compare or update the binary tree
1790 - * @param b the pointer to the binary tree.
1791 - *
1792 - * @return It returns 0 case the values are equal, 1 case a is bigger than b and -1 case a is smaller than b.
1793 - */
1794 -int alarm_compare_name(void *a, void *b) {
1795 - RRDCALC *in1 = (RRDCALC *)a;
1796 - RRDCALC *in2 = (RRDCALC *)b;
1797 -
1798 - if(in1->hash < in2->hash) return -1;
1799 - else if(in1->hash > in2->hash) return 1;
1800 -
1801 - return strcmp(in1->name,in2->name);
1802 -}
1803 -
1787 // Added for gap-filling, if this proves to be a bottleneck in large-scale systems then we will need to cache
1788 // the last entry times as the metric updates, but let's see if it is a problem first.
1789 time_t rrdhost_last_entry_t(RRDHOST *h) {
database/rrdlabels.c
+20 -4
@@ -503,7 +503,7 @@ static void rrdlabel_conflict_callback(const char *name, void *oldvalue, void *n
503 RRDLABEL *lbold = (RRDLABEL *)oldvalue;
504 RRDLABEL *lbnew = (RRDLABEL *)newvalue;
505
506 - if(lbold->label_value == lbnew->label_value || strcmp(string2str(lbold->label_value), string2str(lbnew->label_value)) == 0) {
506 + if(lbold->label_value == lbnew->label_value) {
507 // they are the same
508 lbold->label_source |= lbnew->label_source;
509 lbold->label_source |= RRDLABEL_FLAG_OLD;
@@ -937,9 +937,20 @@ int rrdlabels_to_buffer(DICTIONARY *labels, BUFFER *wb, const char *before_each,
937 return dictionary_walkthrough_read(labels, label_to_buffer_callback, (void *)&tmp);
938 }
939
940 +struct label_str {
941 + BUFFER *sql;
942 + int count;
943 + char uuid_str[UUID_STR_LEN];
944 +};
945 +
946 static int chart_label_store_to_sql_callback(const char *name, const char *value, RRDLABEL_SRC ls, void *data) {
941 - RRDSET *st = (RRDSET *)data;
942 - sql_store_chart_label(st->chart_uuid, (int)ls, (char *)name, (char *)value);
947 + struct label_str *lb = data;
948 + if (unlikely(!lb->count))
949 + buffer_sprintf(lb->sql, "INSERT OR REPLACE INTO chart_label (chart_id, source_type, label_key, label_value, date_created) VALUES ");
950 + else
951 + buffer_strcat(lb->sql, ", ");
952 + buffer_sprintf(lb->sql, "(u2h('%s'), %d,'%s','%s', unixepoch())", lb->uuid_str, ls, name, value);
953 + lb->count++;
954 return 1;
955 }
956
@@ -953,7 +964,12 @@ void rrdset_update_rrdlabels(RRDSET *st, DICTIONARY *new_rrdlabels) {
964 rrdcalc_update_rrdlabels(st);
965
966 // TODO - we should also cleanup sqlite from old new_rrdlabels that have been removed
956 - rrdlabels_walkthrough_read(st->state->chart_labels, chart_label_store_to_sql_callback, st);
967 + BUFFER *sql_buf = buffer_create(1024);
968 + struct label_str tmp = {.sql = sql_buf, .count = 0 };
969 + uuid_unparse_lower(*st->chart_uuid, tmp.uuid_str);
970 + rrdlabels_walkthrough_read(st->state->chart_labels, chart_label_store_to_sql_callback, &tmp);
971 + db_execute(buffer_tostring(sql_buf));
972 + buffer_free(sql_buf);
973 }
974
975 // ----------------------------------------------------------------------------
database/rrdset.c
+200 -249
@@ -5,95 +5,85 @@
5 #include <sched.h>
6
7 void __rrdset_check_rdlock(RRDSET *st, const char *file, const char *function, const unsigned long line) {
8 - debug(D_RRD_CALLS, "Checking read lock on chart '%s'", st->id);
8 + debug(D_RRD_CALLS, "Checking read lock on chart '%s'", rrdset_id(st));
9
10 int ret = netdata_rwlock_trywrlock(&st->rrdset_rwlock);
11 if(ret == 0)
12 - fatal("RRDSET '%s' should be read-locked, but it is not, at function %s() at line %lu of file '%s'", st->id, function, line, file);
12 + fatal("RRDSET '%s' should be read-locked, but it is not, at function %s() at line %lu of file '%s'", rrdset_id(st), function, line, file);
13 }
14
15 void __rrdset_check_wrlock(RRDSET *st, const char *file, const char *function, const unsigned long line) {
16 - debug(D_RRD_CALLS, "Checking write lock on chart '%s'", st->id);
16 + debug(D_RRD_CALLS, "Checking write lock on chart '%s'", rrdset_id(st));
17
18 int ret = netdata_rwlock_tryrdlock(&st->rrdset_rwlock);
19 if(ret == 0)
20 - fatal("RRDSET '%s' should be write-locked, but it is not, at function %s() at line %lu of file '%s'", st->id, function, line, file);
20 + fatal("RRDSET '%s' should be write-locked, but it is not, at function %s() at line %lu of file '%s'", rrdset_id(st), function, line, file);
21 }
22
23
24 // ----------------------------------------------------------------------------
25 // RRDSET index
26
27 -int rrdset_compare(void* a, void* b) {
28 - if(((RRDSET *)a)->hash < ((RRDSET *)b)->hash) return -1;
29 - else if(((RRDSET *)a)->hash > ((RRDSET *)b)->hash) return 1;
30 - else return strcmp(((RRDSET *)a)->id, ((RRDSET *)b)->id);
27 +static inline void rrdset_index_add(RRDHOST *host, RRDSET *st) {
28 + if(likely(dictionary_set(host->rrdset_root_index, rrdset_id(st), st, sizeof(RRDSET)) == st)) {
29 + rrdset_flag_set(st, RRDSET_FLAG_INDEXED_ID);
30 + }
31 + else {
32 + rrdset_flag_clear(st, RRDSET_FLAG_INDEXED_ID);
33 + error("RRDSET: %s() attempted to index duplicate object with key '%s'", __FUNCTION__, rrdset_id(st));
34 + }
35 }
36
33 -static RRDSET *rrdset_index_find(RRDHOST *host, const char *id, uint32_t hash) {
34 - RRDSET tmp;
35 - strncpyz(tmp.id, id, RRD_ID_LENGTH_MAX);
36 - tmp.hash = (hash)?hash:simple_hash(tmp.id);
37 +static inline void rrdset_index_del(RRDHOST *host, RRDSET *st) {
38 + if(rrdset_flag_check(st, RRDSET_FLAG_INDEXED_ID)) {
39 + if(likely(dictionary_del(host->rrdset_root_index, rrdset_id(st)) == 0))
40 + rrdset_flag_clear(st, RRDSET_FLAG_INDEXED_ID);
41 + else
42 + error("RRDSET: %s() attempted to delete non-indexed object with key '%s'", __FUNCTION__, rrdset_id(st));
43 + }
44 +}
45
38 - return (RRDSET *)avl_search_lock(&(host->rrdset_root_index), (avl_t *) &tmp);
46 +static RRDSET *rrdset_index_find(RRDHOST *host, const char *id) {
47 + return dictionary_get(host->rrdset_root_index, id);
48 }
49
50 // ----------------------------------------------------------------------------
51 // RRDSET name index
52
44 -#define rrdset_from_avlname(avlname_ptr) ((RRDSET *)((avlname_ptr) - offsetof(RRDSET, avlname)))
45 -
46 -int rrdset_compare_name(void* a, void* b) {
47 - RRDSET *A = rrdset_from_avlname(a);
48 - RRDSET *B = rrdset_from_avlname(b);
49 -
50 - // fprintf(stderr, "COMPARING: %s with %s\n", A->name, B->name);
51 -
52 - if(A->hash_name < B->hash_name) return -1;
53 - else if(A->hash_name > B->hash_name) return 1;
54 - else return strcmp(A->name, B->name);
53 +static inline void rrdset_index_add_name(RRDHOST *host, RRDSET *st) {
54 + if(likely(dictionary_set(host->rrdset_root_index_name, rrdset_name(st), st, sizeof(RRDSET)) == st)) {
55 + rrdset_flag_set(st, RRDSET_FLAG_INDEXED_NAME);
56 + }
57 + else {
58 + rrdset_flag_clear(st, RRDSET_FLAG_INDEXED_NAME);
59 + error("RRDSET: %s() attempted to index duplicate object with key '%s'", __FUNCTION__, rrdset_name(st));
60 + }
61 }
62
57 -RRDSET *rrdset_index_add_name(RRDHOST *host, RRDSET *st) {
58 - void *result;
59 - // fprintf(stderr, "ADDING: %s (name: %s)\n", st->id, st->name);
60 - result = avl_insert_lock(&host->rrdset_root_index_name, (avl_t *) (&st->avlname));
61 - if(result) return rrdset_from_avlname(result);
62 - return NULL;
63 +static inline void rrdset_index_del_name(RRDHOST *host, RRDSET *st) {
64 + if(rrdset_flag_check(st, RRDSET_FLAG_INDEXED_ID)) {
65 + if(likely(dictionary_del(host->rrdset_root_index_name, rrdset_name(st)) != 0))
66 + rrdset_flag_clear(st, RRDSET_FLAG_INDEXED_NAME);
67 + else
68 + error("RRDSET: %s() attempted to delete non-index object with key '%s'", __FUNCTION__, rrdset_name(st));
69 + }
70 }
71
65 -RRDSET *rrdset_index_del_name(RRDHOST *host, RRDSET *st) {
66 - void *result;
67 - // fprintf(stderr, "DELETING: %s (name: %s)\n", st->id, st->name);
68 - result = (RRDSET *)avl_remove_lock(&((host)->rrdset_root_index_name), (avl_t *)(&st->avlname));
69 - if(result) return rrdset_from_avlname(result);
70 - return NULL;
72 +static inline RRDSET *rrdset_index_find_name(RRDHOST *host, const char *name) {
73 + return dictionary_get(host->rrdset_root_index_name, name);
74 }
75
73 -
76 // ----------------------------------------------------------------------------
77 // RRDSET - find charts
78
77 -static inline RRDSET *rrdset_index_find_name(RRDHOST *host, const char *name, uint32_t hash) {
78 - void *result = NULL;
79 - RRDSET tmp;
80 - tmp.name = name;
81 - tmp.hash_name = (hash)?hash:simple_hash(tmp.name);
82 -
83 - result = avl_search_lock(&host->rrdset_root_index_name, (avl_t *) (&(tmp.avlname)));
84 - if(result) return rrdset_from_avlname(result);
85 -
86 - return NULL;
87 -}
88 -
79 inline RRDSET *rrdset_find(RRDHOST *host, const char *id) {
90 - debug(D_RRD_CALLS, "rrdset_find() for chart '%s' in host '%s'", id, host->hostname);
91 - RRDSET *st = rrdset_index_find(host, id, 0);
80 + debug(D_RRD_CALLS, "rrdset_find() for chart '%s' in host '%s'", id, rrdhost_hostname(host));
81 + RRDSET *st = rrdset_index_find(host, id);
82 return(st);
83 }
84
85 inline RRDSET *rrdset_find_bytype(RRDHOST *host, const char *type, const char *id) {
96 - debug(D_RRD_CALLS, "rrdset_find_bytype() for chart '%s.%s' in host '%s'", type, id, host->hostname);
86 + debug(D_RRD_CALLS, "rrdset_find_bytype() for chart '%s.%s' in host '%s'", type, id, rrdhost_hostname(host));
87
88 char buf[RRD_ID_LENGTH_MAX + 1];
89 strncpyz(buf, type, RRD_ID_LENGTH_MAX - 1);
@@ -105,8 +95,8 @@ inline RRDSET *rrdset_find_bytype(RRDHOST *host, const char *type, const char *i
95 }
96
97 inline RRDSET *rrdset_find_byname(RRDHOST *host, const char *name) {
108 - debug(D_RRD_CALLS, "rrdset_find_byname() for chart '%s' in host '%s'", name, host->hostname);
109 - RRDSET *st = rrdset_index_find_name(host, name, 0);
98 + debug(D_RRD_CALLS, "rrdset_find_byname() for chart '%s' in host '%s'", name, rrdhost_hostname(host));
99 + RRDSET *st = rrdset_index_find_name(host, name);
100 return(st);
101 }
102
@@ -129,32 +119,32 @@ char *rrdset_strncpyz_name(char *to, const char *from, size_t length) {
119 }
120
121 int rrdset_set_name(RRDSET *st, const char *name) {
132 - if(unlikely(st->name && !strcmp(st->name, name)))
122 + if(unlikely(!strcmp(rrdset_name(st), name)))
123 return 1;
124
125 RRDHOST *host = st->rrdhost;
126
137 - debug(D_RRD_CALLS, "rrdset_set_name() old: '%s', new: '%s'", st->name?st->name:"", name);
127 + debug(D_RRD_CALLS, "rrdset_set_name() old: '%s', new: '%s'", rrdset_name(st), name);
128
129 char full_name[RRD_ID_LENGTH_MAX + 1];
130 char sanitized_name[CONFIG_MAX_VALUE + 1];
131 char new_name[CONFIG_MAX_VALUE + 1];
132
143 - snprintfz(full_name, RRD_ID_LENGTH_MAX, "%s.%s", st->type, name);
133 + snprintfz(full_name, RRD_ID_LENGTH_MAX, "%s.%s", rrdset_type(st), name);
134 rrdset_strncpyz_name(sanitized_name, full_name, CONFIG_MAX_VALUE);
135 strncpyz(new_name, sanitized_name, CONFIG_MAX_VALUE);
136
147 - if(rrdset_index_find_name(host, new_name, 0)) {
148 - debug(D_RRD_CALLS, "RRDSET: chart name '%s' on host '%s' already exists.", new_name, host->hostname);
149 - if(!strcmp(st->id, full_name) && !st->name) {
137 + if(rrdset_index_find_name(host, new_name)) {
138 + debug(D_RRD_CALLS, "RRDSET: chart name '%s' on host '%s' already exists.", new_name, rrdhost_hostname(host));
139 + if(!strcmp(rrdset_id(st), full_name) && !st->name) {
140 unsigned i = 1;
141
142 do {
143 snprintfz(new_name, CONFIG_MAX_VALUE, "%s_%u", sanitized_name, i);
144 i++;
155 - } while (rrdset_index_find_name(host, new_name, 0));
145 + } while (rrdset_index_find_name(host, new_name));
146
157 - info("RRDSET: using name '%s' for chart '%s' on host '%s'.", new_name, full_name, host->hostname);
147 + info("RRDSET: using name '%s' for chart '%s' on host '%s'.", new_name, full_name, rrdhost_hostname(host));
148 } else {
149 return 0;
150 }
@@ -162,13 +152,12 @@ int rrdset_set_name(RRDSET *st, const char *name) {
152
153 if(st->name) {
154 rrdset_index_del_name(host, st);
165 - st->name = strdupz(new_name);
166 - st->hash_name = simple_hash(st->name);
155 + string_freez(st->name);
156 + st->name = string_strdupz(new_name);
157 rrdsetvar_rename_all(st);
158 }
159 else {
170 - st->name = strdupz(new_name);
171 - st->hash_name = simple_hash(st->name);
160 + st->name = string_strdupz(new_name);
161 }
162
163 rrdset_wrlock(st);
@@ -177,8 +166,7 @@ int rrdset_set_name(RRDSET *st, const char *name) {
166 rrddimvar_rename_all(rd);
167 rrdset_unlock(st);
168
180 - if(unlikely(rrdset_index_add_name(host, st) != st))
181 - error("RRDSET: INTERNAL ERROR: attempted to index duplicate chart name '%s'", st->name);
169 + rrdset_index_add_name(host, st);
170
171 rrdset_flag_clear(st, RRDSET_FLAG_EXPORTING_SEND);
172 rrdset_flag_clear(st, RRDSET_FLAG_EXPORTING_IGNORE);
@@ -192,12 +180,13 @@ int rrdset_set_name(RRDSET *st, const char *name) {
180
181 inline void rrdset_is_obsolete(RRDSET *st) {
182 if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_ARCHIVED))) {
195 - info("Cannot obsolete already archived chart %s", st->name);
183 + info("Cannot obsolete already archived chart %s", rrdset_name(st));
184 return;
185 }
186
187 if(unlikely(!(rrdset_flag_check(st, RRDSET_FLAG_OBSOLETE)))) {
188 rrdset_flag_set(st, RRDSET_FLAG_OBSOLETE);
189 + st->last_accessed_time = now_realtime_sec();
190 st->rrdhost->obsolete_charts_count++;
191
192 rrdset_flag_clear(st, RRDSET_FLAG_UPSTREAM_EXPOSED);
@@ -212,6 +201,7 @@ inline void rrdset_is_obsolete(RRDSET *st) {
201 inline void rrdset_isnot_obsolete(RRDSET *st) {
202 if(unlikely((rrdset_flag_check(st, RRDSET_FLAG_OBSOLETE)))) {
203 rrdset_flag_clear(st, RRDSET_FLAG_OBSOLETE);
204 + st->last_accessed_time = now_realtime_sec();
205 st->rrdhost->obsolete_charts_count--;
206
207 rrdset_flag_clear(st, RRDSET_FLAG_UPSTREAM_EXPOSED);
@@ -239,12 +229,12 @@ inline void rrdset_update_heterogeneous_flag(RRDSET *st) {
229 if(!rrdset_flag_check(st, RRDSET_FLAG_HETEROGENEOUS)) {
230 #ifdef NETDATA_INTERNAL_CHECKS
231 info("Dimension '%s' added on chart '%s' of host '%s' is not homogeneous to other dimensions already present (algorithm is '%s' vs '%s', multiplier is " COLLECTED_NUMBER_FORMAT " vs " COLLECTED_NUMBER_FORMAT ", divisor is " COLLECTED_NUMBER_FORMAT " vs " COLLECTED_NUMBER_FORMAT ").",
242 - rd->name,
243 - st->name,
244 - host->hostname,
245 - rrd_algorithm_name(rd->algorithm), rrd_algorithm_name(algorithm),
246 - rd->multiplier, multiplier,
247 - rd->divisor, divisor
232 + rrddim_name(rd),
233 + rrdset_name(st),
234 + rrdhost_hostname(host),
235 + rrd_algorithm_name(rd->algorithm), rrd_algorithm_name(algorithm),
236 + rd->multiplier, multiplier,
237 + rd->divisor, divisor
238 );
239 #endif
240 rrdset_flag_set(st, RRDSET_FLAG_HETEROGENEOUS);
@@ -261,7 +251,7 @@ inline void rrdset_update_heterogeneous_flag(RRDSET *st) {
251 // RRDSET - reset a chart
252
253 void rrdset_reset(RRDSET *st) {
264 - debug(D_RRD_CALLS, "rrdset_reset() %s", st->name);
254 + debug(D_RRD_CALLS, "rrdset_reset() %s", rrdset_name(st));
255
256 st->last_collected_time.tv_sec = 0;
257 st->last_collected_time.tv_usec = 0;
@@ -346,9 +336,7 @@ void rrdset_free(RRDSET *st) {
336 // ------------------------------------------------------------------------
337 // remove it from the indexes
338
349 - if(unlikely(rrdset_index_del(host, st) != st))
350 - error("RRDSET: INTERNAL ERROR: attempt to remove from index chart '%s', removed a different chart.", st->id);
351 -
339 + rrdset_index_del(host, st);
340 rrdset_index_del_name(host, st);
341
342 // ------------------------------------------------------------------------
@@ -361,29 +349,18 @@ void rrdset_free(RRDSET *st) {
349 /* We must free all connected alarms here in case this has been an ephemeral chart whose alarm was
350 * created by a template. This leads to an effective memory leak, which cannot be detected since the
351 * alarms will still be connected to the host, and freed during shutdown. */
364 - while(st->alarms) rrdcalc_unlink_and_free(st->rrdhost, st->alarms);
365 - while(st->dimensions) rrddim_free(st, st->dimensions);
352 + while(st->alarms) rrdcalc_unlink_and_free(st->rrdhost, st->alarms);
353 + while(st->dimensions) rrddim_free(st, st->dimensions);
354
355 rrdfamily_free(host, st->rrdfamily);
356
369 - debug(D_RRD_CALLS, "RRDSET: Cleaning up remaining chart variables for host '%s', chart '%s'", host->hostname, st->id);
370 - rrdvar_free_remaining_variables(host, &st->rrdvar_root_index);
357 + debug(D_RRD_CALLS, "RRDSET: Cleaning up remaining chart variables for host '%s', chart '%s'", rrdhost_hostname(host), rrdset_id(st));
358 + rrdvar_free_remaining_variables(host, st->rrdvar_root_index);
359
360 // ------------------------------------------------------------------------
361 // unlink it from the host
362
375 - if(st == host->rrdset_root) {
376 - host->rrdset_root = st->next;
377 - }
378 - else {
379 - // find the previous one
380 - RRDSET *s;
381 - for(s = host->rrdset_root; s && s->next != st ; s = s->next) ;
382 -
383 - // bypass it
384 - if(s) s->next = st->next;
385 - else error("Request to free RRDSET '%s': cannot find it under host '%s'", st->id, host->hostname);
386 - }
363 + DOUBLE_LINKED_LIST_REMOVE_UNSAFE(host->rrdset_root, st, prev, next);
364
365 rrdset_unlock(st);
366
@@ -395,24 +372,28 @@ void rrdset_free(RRDSET *st) {
372
373 netdata_rwlock_destroy(&st->rrdset_rwlock);
374
375 + rrdset_memory_file_free(st);
376 + rrdlabels_destroy(st->state->chart_labels);
377 +
378 // free directly allocated members
399 - freez((void *)st->name);
400 - freez(st->type);
401 - freez(st->family);
402 - freez(st->title);
403 - freez(st->units);
404 - freez(st->context);
379 +
380 + dictionary_destroy(st->rrddim_root_index);
381 + dictionary_destroy(st->rrdvar_root_index);
382 +
383 + string_freez(st->id);
384 + string_freez(st->name);
385 + string_freez(st->type);
386 + string_freez(st->family);
387 + string_freez(st->title);
388 + string_freez(st->units);
389 + string_freez(st->context);
390 + string_freez(st->plugin_name);
391 + string_freez(st->module_name);
392 +
393 freez(st->cache_dir);
406 - freez(st->plugin_name);
407 - freez(st->module_name);
408 - freez(st->state->old_title);
409 - freez(st->state->old_units);
410 - freez(st->state->old_context);
411 - rrdlabels_destroy(st->state->chart_labels);
394 freez(st->state);
395 freez(st->chart_uuid);
396
415 - rrdset_memory_file_free(st);
397 freez(st);
398 }
399
@@ -430,7 +411,7 @@ void rrdset_delete_files(RRDSET *st) {
411 RRDDIM *rd;
412 rrdset_check_rdlock(st);
413
433 - info("Deleting chart '%s' ('%s') from disk...", st->id, st->name);
414 + info("Deleting chart '%s' ('%s') from disk...", rrdset_id(st), rrdset_name(st));
415
416 if(st->rrd_memory_mode == RRD_MEMORY_MODE_SAVE || st->rrd_memory_mode == RRD_MEMORY_MODE_MAP) {
417 const char *cache_filename = rrdset_cache_filename(st);
@@ -440,7 +421,7 @@ void rrdset_delete_files(RRDSET *st) {
421 error("Cannot delete chart header file '%s'", cache_filename);
422 }
423 else
443 - error("Cannot find the cache filename of chart '%s'", st->id);
424 + error("Cannot find the cache filename of chart '%s'", rrdset_id(st));
425 }
426
427 rrddim_foreach_read(rd, st) {
@@ -460,7 +441,7 @@ void rrdset_delete_obsolete_dimensions(RRDSET *st) {
441
442 rrdset_check_rdlock(st);
443
463 - info("Deleting dimensions of chart '%s' ('%s') from disk...", st->id, st->name);
444 + info("Deleting dimensions of chart '%s' ('%s') from disk...", rrdset_id(st), rrdset_name(st));
445
446 rrddim_foreach_read(rd, st) {
447 if(rrddim_flag_check(rd, RRDDIM_FLAG_OBSOLETE)) {
@@ -490,9 +471,9 @@ static inline RRDSET *rrdset_find_on_create(RRDHOST *host, const char *fullid) {
471 static inline void rrdset_update_permanent_labels(RRDSET *st) {
472 if(!st->state || !st->state->chart_labels) return;
473
493 - rrdlabels_add(st->state->chart_labels, "_collect_plugin", st->plugin_name, RRDLABEL_SRC_AUTO| RRDLABEL_FLAG_PERMANENT);
494 - rrdlabels_add(st->state->chart_labels, "_collect_module", st->module_name, RRDLABEL_SRC_AUTO| RRDLABEL_FLAG_PERMANENT);
495 - rrdlabels_add(st->state->chart_labels, "_instance_family", st->family, RRDLABEL_SRC_AUTO| RRDLABEL_FLAG_PERMANENT);
474 + rrdlabels_add(st->state->chart_labels, "_collect_plugin", rrdset_plugin_name(st), RRDLABEL_SRC_AUTO| RRDLABEL_FLAG_PERMANENT);
475 + rrdlabels_add(st->state->chart_labels, "_collect_module", rrdset_module_name(st), RRDLABEL_SRC_AUTO| RRDLABEL_FLAG_PERMANENT);
476 + rrdlabels_add(st->state->chart_labels, "_instance_family",rrdset_family(st), RRDLABEL_SRC_AUTO| RRDLABEL_FLAG_PERMANENT);
477 }
478
479 RRDSET *rrdset_create_custom(
@@ -549,6 +530,7 @@ RRDSET *rrdset_create_custom(
530
531 char fullid[RRD_ID_LENGTH_MAX + 1];
532 snprintfz(fullid, RRD_ID_LENGTH_MAX, "%s.%s", type, id);
533 + json_fix_string(fullid);
534
535 int changed_from_archived_to_active = 0;
536 RRDSET *st = rrdset_find_on_create(host, fullid);
@@ -559,11 +541,9 @@ RRDSET *rrdset_create_custom(
541 changed_from_archived_to_active = 1;
542 mark_rebuild |= META_CHART_ACTIVATED;
543 }
562 - char *old_plugin = NULL, *old_module = NULL, *old_title = NULL, *old_context = NULL,
563 - *old_title_v = NULL, *old_context_v = NULL, *old_units_v = NULL, *old_units = NULL;
564 - int rc;
544
566 - if(unlikely(name))
545 + int rc;
546 + if(unlikely(name && *name))
547 rc = rrdset_set_name(st, name);
548 else
549 rc = rrdset_set_name(st, id);
@@ -580,91 +560,61 @@ RRDSET *rrdset_create_custom(
560 mark_rebuild |= META_CHART_UPDATED;
561 }
562
583 - if (plugin && st->plugin_name) {
584 - if (unlikely(strcmp(plugin, st->plugin_name))) {
585 - old_plugin = st->plugin_name;
586 - st->plugin_name = strdupz(plugin);
563 + if(plugin && *plugin) {
564 + STRING *old_plugin = st->plugin_name;
565 + st->plugin_name = rrd_string_strdupz(plugin);
566 + if (old_plugin != st->plugin_name)
567 mark_rebuild |= META_PLUGIN_UPDATED;
588 - }
589 - } else {
590 - if (plugin != st->plugin_name) { // one is NULL?
591 - old_plugin = st->plugin_name;
592 - st->plugin_name = plugin ? strdupz(plugin) : NULL;
593 - mark_rebuild |= META_PLUGIN_UPDATED;
594 - }
568 + string_freez(old_plugin);
569 }
570
597 - if (module && st->module_name) {
598 - if (unlikely(strcmp(module, st->module_name))) {
599 - old_module = st->module_name;
600 - st->module_name = strdupz(module);
571 + if(module && *module) {
572 + STRING *old_module = st->module_name;
573 + st->module_name = rrd_string_strdupz(module);
574 + if (old_module != st->module_name)
575 mark_rebuild |= META_MODULE_UPDATED;
602 - }
603 - } else {
604 - if (module != st->module_name) {
605 - if (st->module_name && *st->module_name) {
606 - old_module = st->module_name;
607 - st->module_name = module ? strdupz(module) : NULL;
608 - mark_rebuild |= META_MODULE_UPDATED;
609 - }
610 - }
576 + string_freez(old_module);
577 }
578
613 - if (unlikely(title && st->state->old_title && strcmp(st->state->old_title, title))) {
614 - char *new_title = strdupz(title);
615 - old_title_v = st->state->old_title;
616 - st->state->old_title = strdupz(title);
617 - json_fix_string(new_title);
618 - old_title = st->title;
619 - st->title = new_title;
620 - mark_rebuild |= META_CHART_UPDATED;
579 + if(title && *title) {
580 + STRING *old_title = st->title;
581 + st->title = rrd_string_strdupz(title);
582 + if(old_title != st->title)
583 + mark_rebuild |= META_CHART_UPDATED;
584 + string_freez(old_title);
585 }
586
623 - if (unlikely(units && st->state->old_units && strcmp(st->state->old_units, units))) {
624 - char *new_units = strdupz(units);
625 - old_units_v = st->state->old_units;
626 - st->state->old_units = strdupz(units);
627 - json_fix_string(new_units);
628 - old_units= st->units;
629 - st->units = new_units;
630 - mark_rebuild |= META_CHART_UPDATED;
587 + if(units && *units) {
588 + STRING *old_units = st->units;
589 + st->units = rrd_string_strdupz(units);
590 + if(old_units != st->units)
591 + mark_rebuild |= META_CHART_UPDATED;
592 + string_freez(old_units);
593 }
594
595 + if(context && *context) {
596 + STRING *old_context = st->context;
597 + st->context = rrd_string_strdupz(context);
598 + if(old_context != st->context)
599 + mark_rebuild |= META_CHART_UPDATED;
600 + string_freez(old_context);
601 + }
602
603 if (st->chart_type != chart_type) {
604 st->chart_type = chart_type;
605 mark_rebuild |= META_CHART_UPDATED;
606 }
607
639 - if (unlikely(context && st->state->old_context && strcmp(st->state->old_context, context))) {
640 - char *new_context = strdupz(context);
641 - old_context_v = st->state->old_context;
642 - st->state->old_context = strdupz(context);
643 - json_fix_string(new_context);
644 - old_context = st->context;
645 - st->context = new_context;
646 - st->hash_context = simple_hash(st->context);
647 - mark_rebuild |= META_CHART_UPDATED;
648 - }
649 -
608 if (mark_rebuild) {
609 rrdset_flag_clear(st, RRDSET_FLAG_ACLK);
652 - freez(old_plugin);
653 - freez(old_module);
654 - freez(old_title);
655 - freez(old_units);
656 - freez(old_context);
657 - freez(old_title_v);
658 - freez(old_units_v);
659 - freez(old_context_v);
610 if (mark_rebuild != META_CHART_ACTIVATED) {
661 - info("Collector updated metadata for chart %s", st->id);
611 + info("Collector updated metadata for chart %s", rrdset_id(st));
612 sched_yield();
613 }
614 }
615 if (mark_rebuild & (META_CHART_UPDATED | META_PLUGIN_UPDATED | META_MODULE_UPDATED)) {
666 - debug(D_METADATALOG, "CHART [%s] metadata updated", st->id);
667 - int rc = update_chart_metadata(st->chart_uuid, st, id, name);
616 + debug(D_METADATALOG, "CHART [%s] metadata updated", rrdset_id(st));
617 + rc = update_chart_metadata(st->chart_uuid, st, id, name);
618 if (unlikely(rc))
619 error_report("Failed to update chart metadata in the database");
620
@@ -719,8 +669,7 @@ RRDSET *rrdset_create_custom(
669 st = callocz(1, sizeof(RRDSET));
670 st->state = callocz(1, sizeof(*st->state));
671
722 - strcpy(st->id, fullid);
723 - st->hash = simple_hash(st->id);
672 + st->id = string_strdupz(fullid); // fullid is already json_fix'ed
673
674 st->rrdhost = host;
675 st->cache_dir = cache_dir;
@@ -729,29 +678,23 @@ RRDSET *rrdset_create_custom(
678
679 if(memory_mode == RRD_MEMORY_MODE_SAVE || memory_mode == RRD_MEMORY_MODE_MAP) {
680 if(!rrdset_memory_load_or_create_map_save(st, memory_mode)) {
732 - info("Failed to use memory mode %s for chart '%s', falling back to ram", (memory_mode == RRD_MEMORY_MODE_MAP)?"map":"save", st->name);
681 + info("Failed to use memory mode %s for chart '%s', falling back to ram", (memory_mode == RRD_MEMORY_MODE_MAP)?"map":"save", rrdset_name(st));
682 memory_mode = RRD_MEMORY_MODE_RAM;
683 }
684 }
685 st->rrd_memory_mode = memory_mode;
686
738 - st->plugin_name = plugin?strdupz(plugin):NULL;
739 - st->module_name = module?strdupz(module):NULL;
687 + st->plugin_name = rrd_string_strdupz(plugin);
688 + st->module_name = rrd_string_strdupz(module);
689 st->chart_type = chart_type;
741 - st->type = strdupz(type);
742 - st->family = family ? strdupz(family) : strdupz(st->type);
743 - json_fix_string(st->family);
690 + st->type = rrd_string_strdupz(type);
691 + st->family = family ? rrd_string_strdupz(family) : string_dup(st->type);
692
745 - st->state->is_ar_chart = strcmp(st->id, ML_ANOMALY_RATES_CHART_ID) == 0;
693 + st->state->is_ar_chart = strcmp(rrdset_id(st), ML_ANOMALY_RATES_CHART_ID) == 0;
694
747 - st->units = units ? strdupz(units) : strdupz("");
748 - st->state->old_units = strdupz(st->units);
749 - json_fix_string(st->units);
695 + st->units = rrd_string_strdupz(units);
696
751 - st->context = context ? strdupz(context) : strdupz(st->id);
752 - st->state->old_context = strdupz(st->context);
753 - json_fix_string(st->context);
754 - st->hash_context = simple_hash(st->context);
697 + st->context = (context && *context) ? rrd_string_strdupz(context) : string_dup(st->id);
698
699 st->priority = priority;
700
@@ -762,8 +705,17 @@ RRDSET *rrdset_create_custom(
705
706 st->gap_when_lost_iterations_above = (int) (gap_when_lost_iterations_above + 2);
707
765 - avl_init_lock(&st->dimensions_index, rrddim_compare);
766 - avl_init_lock(&st->rrdvar_root_index, rrdvar_compare);
708 + st->rrddim_root_index = dictionary_create(
709 + DICTIONARY_FLAG_NAME_LINK_DONT_CLONE
710 + | DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE
711 + | DICTIONARY_FLAG_DONT_OVERWRITE_VALUE
712 + );
713 +
714 + st->rrdvar_root_index = dictionary_create(
715 + DICTIONARY_FLAG_NAME_LINK_DONT_CLONE
716 + | DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE
717 + | DICTIONARY_FLAG_DONT_OVERWRITE_VALUE
718 + );
719
720 netdata_rwlock_init(&st->rrdset_rwlock);
721 st->state->chart_labels = rrdlabels_create();
@@ -776,14 +728,11 @@ RRDSET *rrdset_create_custom(
728 // could not use the name, use the id
729 rrdset_set_name(st, id);
730
779 - st->title = strdupz(title);
780 - st->state->old_title = strdupz(st->title);
781 - json_fix_string(st->title);
731 + st->title = rrd_string_strdupz(title);
732
783 - st->rrdfamily = rrdfamily_create(host, st->family);
733 + st->rrdfamily = rrdfamily_create(host, rrdset_family(st));
734
785 - st->next = host->rrdset_root;
786 - host->rrdset_root = st;
735 + DOUBLE_LINKED_LIST_APPEND_UNSAFE(host->rrdset_root, st, prev, next);
736
737 if(host->health_enabled) {
738 rrdsetvar_create(st, "last_collected_t", RRDVAR_TYPE_TIME_T, &st->last_collected_time.tv_sec, RRDVAR_OPTION_DEFAULT);
@@ -793,9 +742,7 @@ RRDSET *rrdset_create_custom(
742 rrdsetvar_create(st, "update_every", RRDVAR_TYPE_INT, &st->update_every, RRDVAR_OPTION_DEFAULT);
743 }
744
796 - if(unlikely(rrdset_index_add(host, st) != st))
797 - error("RRDSET: INTERNAL ERROR: attempt to index duplicate chart '%s'", st->id);
798 -
745 + rrdset_index_add(host, st);
746 rrdsetcalc_link_matching(st);
747 rrdcalctemplate_link_matching(st);
748
@@ -870,7 +817,7 @@ inline void rrdset_next_usec(RRDSET *st, usec_t microseconds) {
817 // oops! the database is in the future
818 #ifdef NETDATA_INTERNAL_CHECKS
819 info("RRD database for chart '%s' on host '%s' is %0.5" NETDATA_DOUBLE_MODIFIER
873 - " secs in the future (counter #%zu, update #%zu). Adjusting it to current time.", st->id, st->rrdhost->hostname, (NETDATA_DOUBLE)-since_last_usec / USEC_PER_SEC, st->counter, st->counter_done);
820 + " secs in the future (counter #%zu, update #%zu). Adjusting it to current time.", rrdset_id(st), rrdhost_hostname(st->rrdhost), (NETDATA_DOUBLE)-since_last_usec / USEC_PER_SEC, st->counter, st->counter_done);
821 #endif
822
823 st->last_collected_time.tv_sec = now.tv_sec - st->update_every;
@@ -890,7 +837,7 @@ inline void rrdset_next_usec(RRDSET *st, usec_t microseconds) {
837 // oops! the database is too far behind
838 #ifdef NETDATA_INTERNAL_CHECKS
839 info("RRD database for chart '%s' on host '%s' is %0.5" NETDATA_DOUBLE_MODIFIER
893 - " secs in the past (counter #%zu, update #%zu). Adjusting it to current time.", st->id, st->rrdhost->hostname, (NETDATA_DOUBLE)since_last_usec / USEC_PER_SEC, st->counter, st->counter_done);
840 + " secs in the past (counter #%zu, update #%zu). Adjusting it to current time.", rrdset_id(st), rrdhost_hostname(st->rrdhost), (NETDATA_DOUBLE)since_last_usec / USEC_PER_SEC, st->counter, st->counter_done);
841 #endif
842
843 microseconds = (usec_t)since_last_usec;
@@ -925,11 +872,11 @@ inline void rrdset_next_usec(RRDSET *st, usec_t microseconds) {
872 }
873
874 #ifdef NETDATA_INTERNAL_CHECKS
928 - debug(D_RRD_CALLS, "rrdset_next_usec() for chart %s with microseconds %llu", st->name, microseconds);
875 + debug(D_RRD_CALLS, "rrdset_next_usec() for chart %s with microseconds %llu", rrdset_name(st), microseconds);
876 rrdset_debug(st, "NEXT: %llu microseconds", microseconds);
877
878 if(discarded && discarded != microseconds)
932 - info("host '%s', chart '%s': discarded data collection time of %llu usec, replaced with %llu usec, reason: '%s'", st->rrdhost->hostname, st->id, discarded, microseconds, discard_reason?discard_reason:"UNDEFINED");
879 + info("host '%s', chart '%s': discarded data collection time of %llu usec, replaced with %llu usec, reason: '%s'", rrdhost_hostname(st->rrdhost), rrdset_id(st), discarded, microseconds, discard_reason?discard_reason:"UNDEFINED");
880
881 #endif
882
@@ -1081,6 +1028,8 @@ static void store_metric(RRDDIM *rd, usec_t point_end_time_ut, NETDATA_DOUBLE n,
1028 t->last_collected_ut = point_end_time_ut;
1029 store_metric_at_tier(rd, t, sp, point_end_time_ut);
1030 }
1031 +
1032 + rrdcontext_collected_rrddim(rd);
1033 }
1034
1035 static inline size_t rrdset_done_interpolate(
@@ -1114,7 +1063,7 @@ static inline size_t rrdset_done_interpolate(
1063 for( ; next_store_ut <= now_collect_ut ; last_collect_ut = next_store_ut, next_store_ut += update_every_ut, iterations-- ) {
1064
1065 #ifdef NETDATA_INTERNAL_CHECKS
1117 - if(iterations < 0) { error("INTERNAL CHECK: %s: iterations calculation wrapped! first_ut = %llu, last_stored_ut = %llu, next_store_ut = %llu, now_collect_ut = %llu", st->name, first_ut, last_stored_ut, next_store_ut, now_collect_ut); }
1066 + if(iterations < 0) { error("INTERNAL CHECK: %s: iterations calculation wrapped! first_ut = %llu, last_stored_ut = %llu, next_store_ut = %llu, now_collect_ut = %llu", rrdset_name(st), first_ut, last_stored_ut, next_store_ut, now_collect_ut); }
1067 rrdset_debug(st, "last_stored_ut = %0.3" NETDATA_DOUBLE_MODIFIER " (last updated time)", (NETDATA_DOUBLE)last_stored_ut/USEC_PER_SEC);
1068 rrdset_debug(st, "next_store_ut = %0.3" NETDATA_DOUBLE_MODIFIER " (next interpolation point)", (NETDATA_DOUBLE)next_store_ut/USEC_PER_SEC);
1069 #endif
@@ -1140,7 +1089,7 @@ static inline size_t rrdset_done_interpolate(
1089 NETDATA_DOUBLE_FORMAT
1090 " * (%llu - %llu)"
1091 " / (%llu - %llu)"
1143 - , rd->name
1092 + , rrddim_name(rd)
1093 , new_value
1094 , rd->calculated_value
1095 , next_store_ut, last_collect_ut
@@ -1157,7 +1106,7 @@ static inline size_t rrdset_done_interpolate(
1106
1107 #ifdef NETDATA_INTERNAL_CHECKS
1108 rrdset_debug(st, "%s: COLLECTION POINT IS SHORT " NETDATA_DOUBLE_FORMAT " - EXTRAPOLATING",
1160 - rd->name
1109 + rrddim_name(rd)
1110 , (NETDATA_DOUBLE)(next_store_ut - last_stored_ut)
1111 );
1112 #endif
@@ -1193,7 +1142,7 @@ static inline size_t rrdset_done_interpolate(
1142 rrdset_debug(st, "%s: CALC2 DEF " NETDATA_DOUBLE_FORMAT " = ((("
1143 "(" NETDATA_DOUBLE_FORMAT " - " NETDATA_DOUBLE_FORMAT ")"
1144 " * %llu"
1196 - " / %llu) + " NETDATA_DOUBLE_FORMAT, rd->name
1145 + " / %llu) + " NETDATA_DOUBLE_FORMAT, rrddim_name(rd)
1146 , new_value
1147 , rd->calculated_value, rd->last_calculated_value
1148 , (next_store_ut - first_ut)
@@ -1225,7 +1174,7 @@ static inline size_t rrdset_done_interpolate(
1174 (void) ml_is_anomalous(rd, 0, false);
1175
1176 #ifdef NETDATA_INTERNAL_CHECKS
1228 - rrdset_debug(st, "%s: STORE[%ld] = NON EXISTING ", rd->name, current_entry);
1177 + rrdset_debug(st, "%s: STORE[%ld] = NON EXISTING ", rrddim_name(rd), current_entry);
1178 #endif
1179
1180 store_metric(rd, next_store_ut, NAN, SN_FLAG_NONE);
@@ -1275,7 +1224,7 @@ static inline void rrdset_done_fill_the_gap(RRDSET *st) {
1224 current_entry = ((current_entry + 1) >= entries) ? 0 : current_entry + 1;
1225
1226 #ifdef NETDATA_INTERNAL_CHECKS
1278 - rrdset_debug(st, "%s: STORE[%ld] = NON EXISTING (FILLED THE GAP)", rd->name, current_entry);
1227 + rrdset_debug(st, "%s: STORE[%ld] = NON EXISTING (FILLED THE GAP)", rrddim_name(rd), current_entry);
1228 #endif
1229 }
1230 }
@@ -1294,8 +1243,7 @@ static inline void rrdset_done_fill_the_gap(RRDSET *st) {
1243 void rrdset_done(RRDSET *st) {
1244 if(unlikely(netdata_exit)) return;
1245
1297 - debug(D_RRD_CALLS, "rrdset_done() for chart %s", st->name);
1298 - rrdcontext_collected_rrdset(st);
1246 + debug(D_RRD_CALLS, "rrdset_done() for chart %s", rrdset_name(st));
1247
1248 RRDDIM *rd;
1249
@@ -1326,7 +1274,7 @@ void rrdset_done(RRDSET *st) {
1274 #endif
1275
1276 if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_OBSOLETE))) {
1329 - error("Chart '%s' has the OBSOLETE flag set, but it is collected.", st->id);
1277 + error("Chart '%s' has the OBSOLETE flag set, but it is collected.", rrdset_id(st));
1278 rrdset_isnot_obsolete(st);
1279 }
1280
@@ -1334,7 +1282,7 @@ void rrdset_done(RRDSET *st) {
1282 if(unlikely(st->usec_since_last_update > st->entries * update_every_ut &&
1283 st->rrd_memory_mode != RRD_MEMORY_MODE_DBENGINE && st->rrd_memory_mode != RRD_MEMORY_MODE_NONE)) {
1284 info("host '%s', chart %s: took too long to be updated (counter #%zu, update #%zu, %0.3" NETDATA_DOUBLE_MODIFIER
1337 - " secs). Resetting it.", st->rrdhost->hostname, st->name, st->counter, st->counter_done, (NETDATA_DOUBLE)st->usec_since_last_update / USEC_PER_SEC);
1285 + " secs). Resetting it.", rrdhost_hostname(st->rrdhost), rrdset_name(st), st->counter, st->counter_done, (NETDATA_DOUBLE)st->usec_since_last_update / USEC_PER_SEC);
1286 rrdset_reset(st);
1287 st->usec_since_last_update = update_every_ut;
1288 store_this_entry = 0;
@@ -1382,7 +1330,7 @@ void rrdset_done(RRDSET *st) {
1330 info(
1331 "%s: too old data (last updated at %"PRId64".%"PRId64", last collected at %"PRId64".%"PRId64"). "
1332 "Resetting it. Will not store the next entry.",
1385 - st->name,
1333 + rrdset_name(st),
1334 (int64_t)st->last_updated.tv_sec,
1335 (int64_t)st->last_updated.tv_usec,
1336 (int64_t)st->last_collected_time.tv_sec,
@@ -1404,7 +1352,7 @@ void rrdset_done(RRDSET *st) {
1352 info(
1353 "%s: too old data (last updated at %" PRId64 ".%" PRId64 ", last collected at %" PRId64 ".%" PRId64 "). "
1354 "Resetting it. Will not store the next entry.",
1407 - st->name,
1355 + rrdset_name(st),
1356 (int64_t)st->last_updated.tv_sec,
1357 (int64_t)st->last_updated.tv_usec,
1358 (int64_t)st->last_collected_time.tv_sec,
@@ -1467,9 +1415,9 @@ after_first_database_work:
1415
1416 if(unlikely(st->rrdhost->rrdpush_send_enabled))
1417 rrdset_done_push(st);
1470 - if (unlikely(st->rrd_memory_mode == RRD_MEMORY_MODE_NONE)) {
1418 +
1419 + if (unlikely(st->rrd_memory_mode == RRD_MEMORY_MODE_NONE))
1420 goto after_second_database_work;
1472 - }
1421
1422 #ifdef NETDATA_INTERNAL_CHECKS
1423 rrdset_debug(st, "last_collect_ut = %0.3" NETDATA_DOUBLE_MODIFIER " (last collection time)", (NETDATA_DOUBLE)last_collect_ut/USEC_PER_SEC);
@@ -1506,7 +1454,7 @@ after_first_database_work:
1454 }
1455
1456 if(unlikely(rrddim_flag_check(rd, RRDDIM_FLAG_OBSOLETE))) {
1509 - error("Dimension %s in chart '%s' has the OBSOLETE flag set, but it is collected.", rd->name, st->id);
1457 + error("Dimension %s in chart '%s' has the OBSOLETE flag set, but it is collected.", rrddim_name(rd), rrdset_id(st));
1458 rrddim_isnot_obsolete(st, rd);
1459 }
1460
@@ -1515,11 +1463,12 @@ after_first_database_work:
1463 " last_collected_value = " COLLECTED_NUMBER_FORMAT
1464 " collected_value = " COLLECTED_NUMBER_FORMAT
1465 " last_calculated_value = " NETDATA_DOUBLE_FORMAT
1518 - " calculated_value = " NETDATA_DOUBLE_FORMAT, rd->name
1519 - , rd->last_collected_value
1520 - , rd->collected_value
1521 - , rd->last_calculated_value
1522 - , rd->calculated_value
1466 + " calculated_value = " NETDATA_DOUBLE_FORMAT
1467 + , rrddim_name(rd)
1468 + , rd->last_collected_value
1469 + , rd->collected_value
1470 + , rd->last_calculated_value
1471 + , rd->calculated_value
1472 );
1473 #endif
1474
@@ -1533,7 +1482,7 @@ after_first_database_work:
1482 rrdset_debug(st, "%s: CALC ABS/ABS-NO-IN " NETDATA_DOUBLE_FORMAT " = "
1483 COLLECTED_NUMBER_FORMAT
1484 " * " NETDATA_DOUBLE_FORMAT
1536 - " / " NETDATA_DOUBLE_FORMAT, rd->name
1485 + " / " NETDATA_DOUBLE_FORMAT, rrddim_name(rd)
1486 , rd->calculated_value
1487 , rd->collected_value
1488 , (NETDATA_DOUBLE)rd->multiplier
@@ -1558,7 +1507,7 @@ after_first_database_work:
1507 rrdset_debug(st, "%s: CALC PCENT-ROW " NETDATA_DOUBLE_FORMAT " = 100"
1508 " * " COLLECTED_NUMBER_FORMAT
1509 " / " COLLECTED_NUMBER_FORMAT
1561 - , rd->name
1510 + , rrddim_name(rd)
1511 , rd->calculated_value
1512 , rd->collected_value
1513 , st->collected_total
@@ -1579,7 +1528,7 @@ after_first_database_work:
1528 // produces wrong results as far as incremental counters are concerned.
1529 if(unlikely((uint64_t)rd->last_collected_value > (uint64_t)rd->collected_value)) {
1530 debug(D_RRD_STATS, "%s.%s: RESET or OVERFLOW. Last collected value = " COLLECTED_NUMBER_FORMAT ", current = " COLLECTED_NUMBER_FORMAT
1582 - , st->name, rd->name
1531 + , rrdset_name(st), rrddim_name(rd)
1532 , rd->last_collected_value
1533 , rd->collected_value);
1534
@@ -1627,7 +1576,7 @@ after_first_database_work:
1576 COLLECTED_NUMBER_FORMAT " - " COLLECTED_NUMBER_FORMAT
1577 ")"
1578 " * " NETDATA_DOUBLE_FORMAT
1630 - " / " NETDATA_DOUBLE_FORMAT, rd->name
1579 + " / " NETDATA_DOUBLE_FORMAT, rrddim_name(rd)
1580 , rd->calculated_value
1581 , rd->collected_value, rd->last_collected_value
1582 , (NETDATA_DOUBLE)rd->multiplier
@@ -1647,7 +1596,7 @@ after_first_database_work:
1596 // to reset the calculation (it will give zero as the calculation for this second)
1597 if(unlikely(rd->last_collected_value > rd->collected_value)) {
1598 debug(D_RRD_STATS, "%s.%s: RESET or OVERFLOW. Last collected value = " COLLECTED_NUMBER_FORMAT ", current = " COLLECTED_NUMBER_FORMAT
1650 - , st->name, rd->name
1599 + , rrdset_name(st), rrddim_name(rd)
1600 , rd->last_collected_value
1601 , rd->collected_value
1602 );
@@ -1672,7 +1621,7 @@ after_first_database_work:
1621 rrdset_debug(st, "%s: CALC PCENT-DIFF " NETDATA_DOUBLE_FORMAT " = 100"
1622 " * (" COLLECTED_NUMBER_FORMAT " - " COLLECTED_NUMBER_FORMAT ")"
1623 " / (" COLLECTED_NUMBER_FORMAT " - " COLLECTED_NUMBER_FORMAT ")"
1675 - , rd->name
1624 + , rrddim_name(rd)
1625 , rd->calculated_value
1626 , rd->collected_value, rd->last_collected_value
1627 , st->collected_total, st->last_collected_total
@@ -1688,7 +1637,7 @@ after_first_database_work:
1637
1638 #ifdef NETDATA_INTERNAL_CHECKS
1639 rrdset_debug(st, "%s: CALC " NETDATA_DOUBLE_FORMAT " = 0"
1691 - , rd->name
1640 + , rrddim_name(rd)
1641 , rd->calculated_value
1642 );
1643 #endif
@@ -1701,7 +1650,7 @@ after_first_database_work:
1650 " last_collected_value = " COLLECTED_NUMBER_FORMAT
1651 " collected_value = " COLLECTED_NUMBER_FORMAT
1652 " last_calculated_value = " NETDATA_DOUBLE_FORMAT
1704 - " calculated_value = " NETDATA_DOUBLE_FORMAT, rd->name
1653 + " calculated_value = " NETDATA_DOUBLE_FORMAT, rrddim_name(rd)
1654 , rd->last_collected_value
1655 , rd->collected_value
1656 , rd->last_calculated_value
@@ -1718,7 +1667,7 @@ after_first_database_work:
1667 // if(unlikely(now_collect_ut < next_store_ut && st->counter_done > 1)) {
1668 // // this is collected in the same interpolation point
1669 // rrdset_debug(st, "THIS IS IN THE SAME INTERPOLATION POINT");
1721 -// info("INTERNAL CHECK: host '%s', chart '%s' collection %zu is in the same interpolation point: short by %llu microseconds", st->rrdhost->hostname, st->name, st->counter_done, next_store_ut - now_collect_ut);
1670 +// info("INTERNAL CHECK: host '%s', chart '%s' collection %zu is in the same interpolation point: short by %llu microseconds", st->rrdhost->hostname, rrdset_name(st), st->counter_done, next_store_ut - now_collect_ut);
1671 // }
1672 // #endif
1673
@@ -1738,6 +1687,7 @@ after_second_database_work:
1687 #ifdef ENABLE_ACLK
1688 time_t mark = now_realtime_sec();
1689 #endif
1690 +
1691 rrddim_foreach_read(rd, st) {
1692 if (rrddim_flag_check(rd, RRDDIM_FLAG_ARCHIVED))
1693 continue;
@@ -1752,7 +1702,7 @@ after_second_database_work:
1702 continue;
1703
1704 #ifdef NETDATA_INTERNAL_CHECKS
1755 - rrdset_debug(st, "%s: setting last_collected_value (old: " COLLECTED_NUMBER_FORMAT ") to last_collected_value (new: " COLLECTED_NUMBER_FORMAT ")", rd->name, rd->last_collected_value, rd->collected_value);
1705 + rrdset_debug(st, "%s: setting last_collected_value (old: " COLLECTED_NUMBER_FORMAT ") to last_collected_value (new: " COLLECTED_NUMBER_FORMAT ")", rrddim_name(rd), rd->last_collected_value, rd->collected_value);
1706 #endif
1707
1708 rd->last_collected_value = rd->collected_value;
@@ -1762,7 +1712,7 @@ after_second_database_work:
1712 if(unlikely(!first_entry)) {
1713 #ifdef NETDATA_INTERNAL_CHECKS
1714 rrdset_debug(st, "%s: setting last_calculated_value (old: " NETDATA_DOUBLE_FORMAT
1765 - ") to last_calculated_value (new: " NETDATA_DOUBLE_FORMAT ")", rd->name, rd->last_calculated_value + rd->calculated_value, rd->calculated_value);
1715 + ") to last_calculated_value (new: " NETDATA_DOUBLE_FORMAT ")", rrddim_name(rd), rd->last_calculated_value + rd->calculated_value, rd->calculated_value);
1716 #endif
1717
1718 rd->last_calculated_value += rd->calculated_value;
@@ -1779,7 +1729,7 @@ after_second_database_work:
1729 case RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL:
1730 #ifdef NETDATA_INTERNAL_CHECKS
1731 rrdset_debug(st, "%s: setting last_calculated_value (old: " NETDATA_DOUBLE_FORMAT
1782 - ") to last_calculated_value (new: " NETDATA_DOUBLE_FORMAT ")", rd->name, rd->last_calculated_value, rd->calculated_value);
1732 + ") to last_calculated_value (new: " NETDATA_DOUBLE_FORMAT ")", rrddim_name(rd), rd->last_calculated_value, rd->calculated_value);
1733 #endif
1734
1735 rd->last_calculated_value = rd->calculated_value;
@@ -1795,7 +1745,7 @@ after_second_database_work:
1745 " last_collected_value = " COLLECTED_NUMBER_FORMAT
1746 " collected_value = " COLLECTED_NUMBER_FORMAT
1747 " last_calculated_value = " NETDATA_DOUBLE_FORMAT
1798 - " calculated_value = " NETDATA_DOUBLE_FORMAT, rd->name
1748 + " calculated_value = " NETDATA_DOUBLE_FORMAT, rrddim_name(rd)
1749 , rd->last_collected_value
1750 , rd->collected_value
1751 , rd->last_calculated_value
@@ -1835,7 +1785,7 @@ after_second_database_work:
1785 for( rd = st->dimensions, last = NULL ; likely(rd) ; ) {
1786 if(unlikely(rrddim_flag_check(rd, RRDDIM_FLAG_OBSOLETE) && !rrddim_flag_check(rd, RRDDIM_FLAG_ACLK)
1787 && (rd->last_collected_time.tv_sec + rrdset_free_obsolete_time < now))) {
1838 - info("Removing obsolete dimension '%s' (%s) of '%s' (%s).", rd->name, rd->id, st->name, st->id);
1788 + info("Removing obsolete dimension '%s' (%s) of '%s' (%s).", rrddim_name(rd), rrddim_id(rd), rrdset_name(st), rrdset_id(st));
1789
1790 const char *cache_filename = rrddim_cache_filename(rd);
1791 if(cache_filename) {
@@ -1900,8 +1850,9 @@ after_second_database_work:
1850 }
1851 }
1852
1903 - rrdset_unlock(st);
1853 + rrdcontext_collected_rrdset(st);
1854
1855 + rrdset_unlock(st);
1856 netdata_thread_enable_cancelability();
1857 }
1858
@@ -2047,8 +1998,8 @@ bool rrdset_memory_load_or_create_map_save(RRDSET *st, RRD_MEMORY_MODE memory_mo
1998 info("Initializing file '%s'.", fullfilename);
1999 memset(st_on_file, 0, size);
2000 }
2050 - else if(strncmp(st_on_file->id, st->id, RRD_ID_LENGTH_MAX_V019) != 0) {
2051 - error("File '%s' contents are not for chart '%s'. Clearing it.", fullfilename, st->id);
2001 + else if(strncmp(st_on_file->id, rrdset_id(st), RRD_ID_LENGTH_MAX_V019) != 0) {
2002 + error("File '%s' contents are not for chart '%s'. Clearing it.", fullfilename, rrdset_id(st));
2003 memset(st_on_file, 0, size);
2004 }
2005 else if(st_on_file->memsize != size || st_on_file->entries != st->entries) {
@@ -2094,7 +2045,7 @@ bool rrdset_memory_load_or_create_map_save(RRDSET *st, RRD_MEMORY_MODE memory_mo
2045 memset(st_on_file, 0, size);
2046
2047 // set the values we need
2097 - strncpyz(st_on_file->id, st->id, RRD_ID_LENGTH_MAX_V019 + 1);
2048 + strncpyz(st_on_file->id, rrdset_id(st), RRD_ID_LENGTH_MAX_V019 + 1);
2049 strcpy(st_on_file->cache_filename, fullfilename);
2050 strcpy(st_on_file->magic, RRDSET_MAGIC_V019);
2051 st_on_file->memsize = size;
database/rrdsetvar.c
+31 -43
@@ -13,31 +13,31 @@ static inline void rrdsetvar_free_variables(RRDSETVAR *rs) {
13
14 // ------------------------------------------------------------------------
15 // CHART
16 - rrdvar_free(host, &st->rrdvar_root_index, rs->var_local);
16 + rrdvar_free(host, st->rrdvar_root_index, rs->var_local);
17 rs->var_local = NULL;
18
19 // ------------------------------------------------------------------------
20 // FAMILY
21 - rrdvar_free(host, &st->rrdfamily->rrdvar_root_index, rs->var_family);
21 + rrdvar_free(host, st->rrdfamily->rrdvar_root_index, rs->var_family);
22 rs->var_family = NULL;
23
24 - rrdvar_free(host, &st->rrdfamily->rrdvar_root_index, rs->var_family_name);
24 + rrdvar_free(host, st->rrdfamily->rrdvar_root_index, rs->var_family_name);
25 rs->var_family_name = NULL;
26
27 // ------------------------------------------------------------------------
28 // HOST
29 - rrdvar_free(host, &host->rrdvar_root_index, rs->var_host);
29 + rrdvar_free(host, host->rrdvar_root_index, rs->var_host);
30 rs->var_host = NULL;
31
32 - rrdvar_free(host, &host->rrdvar_root_index, rs->var_host_name);
32 + rrdvar_free(host, host->rrdvar_root_index, rs->var_host_name);
33 rs->var_host_name = NULL;
34
35 // ------------------------------------------------------------------------
36 // KEYS
37 - freez(rs->key_fullid);
37 + string_freez(rs->key_fullid);
38 rs->key_fullid = NULL;
39
40 - freez(rs->key_fullname);
40 + string_freez(rs->key_fullname);
41 rs->key_fullname = NULL;
42 }
43
@@ -58,40 +58,38 @@ static inline void rrdsetvar_create_variables(RRDSETVAR *rs) {
58 // KEYS
59
60 char buffer[RRDVAR_MAX_LENGTH + 1];
61 - snprintfz(buffer, RRDVAR_MAX_LENGTH, "%s.%s", st->id, rs->variable);
62 - rs->key_fullid = strdupz(buffer);
61 + snprintfz(buffer, RRDVAR_MAX_LENGTH, "%s.%s", rrdset_id(st), string2str(rs->variable));
62 + rs->key_fullid = string_strdupz(buffer);
63
64 - snprintfz(buffer, RRDVAR_MAX_LENGTH, "%s.%s", st->name, rs->variable);
65 - rs->key_fullname = strdupz(buffer);
64 + snprintfz(buffer, RRDVAR_MAX_LENGTH, "%s.%s", rrdset_name(st), string2str(rs->variable));
65 + rs->key_fullname = string_strdupz(buffer);
66
67 // ------------------------------------------------------------------------
68 // CHART
69 - rs->var_local = rrdvar_create_and_index("local", &st->rrdvar_root_index, rs->variable, rs->type, options, rs->value);
69 + rs->var_local = rrdvar_create_and_index("local", st->rrdvar_root_index, rs->variable, rs->type, options, rs->value);
70
71 // ------------------------------------------------------------------------
72 // FAMILY
73 - rs->var_family = rrdvar_create_and_index("family", &st->rrdfamily->rrdvar_root_index, rs->key_fullid, rs->type, options, rs->value);
74 - rs->var_family_name = rrdvar_create_and_index("family", &st->rrdfamily->rrdvar_root_index, rs->key_fullname, rs->type, options, rs->value);
73 + rs->var_family = rrdvar_create_and_index("family", st->rrdfamily->rrdvar_root_index, rs->key_fullid, rs->type, options, rs->value);
74 + rs->var_family_name = rrdvar_create_and_index("family", st->rrdfamily->rrdvar_root_index, rs->key_fullname, rs->type, options, rs->value);
75
76 // ------------------------------------------------------------------------
77 // HOST
78 - rs->var_host = rrdvar_create_and_index("host", &host->rrdvar_root_index, rs->key_fullid, rs->type, options, rs->value);
79 - rs->var_host_name = rrdvar_create_and_index("host", &host->rrdvar_root_index, rs->key_fullname, rs->type, options, rs->value);
78 + rs->var_host = rrdvar_create_and_index("host", host->rrdvar_root_index, rs->key_fullid, rs->type, options, rs->value);
79 + rs->var_host_name = rrdvar_create_and_index("host", host->rrdvar_root_index, rs->key_fullname, rs->type, options, rs->value);
80 }
81
82 RRDSETVAR *rrdsetvar_create(RRDSET *st, const char *variable, RRDVAR_TYPE type, void *value, RRDVAR_OPTIONS options) {
83 - debug(D_VARIABLES, "RRDVARSET create for chart id '%s' name '%s' with variable name '%s'", st->id, st->name, variable);
83 + debug(D_VARIABLES, "RRDVARSET create for chart id '%s' name '%s' with variable name '%s'", rrdset_id(st), rrdset_name(st), variable);
84 RRDSETVAR *rs = (RRDSETVAR *)callocz(1, sizeof(RRDSETVAR));
85
86 - rs->variable = strdupz(variable);
87 - rs->hash = simple_hash(rs->variable);
86 + rs->variable = string_strdupz(variable);
87 rs->type = type;
88 rs->value = value;
89 rs->options = options;
90 rs->rrdset = st;
91
93 - rs->next = st->variables;
94 - st->variables = rs;
92 + DOUBLE_LINKED_LIST_PREPEND_UNSAFE(st->variables, rs, prev, next);
93
94 rrdsetvar_create_variables(rs);
95
@@ -99,7 +97,7 @@ RRDSETVAR *rrdsetvar_create(RRDSET *st, const char *variable, RRDVAR_TYPE type,
97 }
98
99 void rrdsetvar_rename_all(RRDSET *st) {
102 - debug(D_VARIABLES, "RRDSETVAR rename for chart id '%s' name '%s'", st->id, st->name);
100 + debug(D_VARIABLES, "RRDSETVAR rename for chart id '%s' name '%s'", rrdset_id(st), rrdset_name(st));
101
102 RRDSETVAR *rs;
103 for(rs = st->variables; rs ; rs = rs->next)
@@ -110,21 +108,13 @@ void rrdsetvar_rename_all(RRDSET *st) {
108
109 void rrdsetvar_free(RRDSETVAR *rs) {
110 RRDSET *st = rs->rrdset;
113 - debug(D_VARIABLES, "RRDSETVAR free for chart id '%s' name '%s', variable '%s'", st->id, st->name, rs->variable);
111 + debug(D_VARIABLES, "RRDSETVAR free for chart id '%s' name '%s', variable '%s'", rrdset_id(st), rrdset_name(st), string2str(rs->variable));
112
115 - if(st->variables == rs) {
116 - st->variables = rs->next;
117 - }
118 - else {
119 - RRDSETVAR *t;
120 - for (t = st->variables; t && t->next != rs; t = t->next);
121 - if(!t) error("RRDSETVAR '%s' not found in chart '%s' variables linked list", rs->key_fullname, st->id);
122 - else t->next = rs->next;
123 - }
113 + DOUBLE_LINKED_LIST_REMOVE_UNSAFE(st->variables, rs, prev, next);
114
115 rrdsetvar_free_variables(rs);
116
127 - freez(rs->variable);
117 + string_freez(rs->variable);
118
119 if(rs->options & RRDVAR_OPTION_ALLOCATED)
120 freez(rs->value);
@@ -138,24 +128,22 @@ void rrdsetvar_free(RRDSETVAR *rs) {
128 RRDSETVAR *rrdsetvar_custom_chart_variable_create(RRDSET *st, const char *name) {
129 RRDHOST *host = st->rrdhost;
130
141 - char *n = strdupz(name);
142 - rrdvar_fix_name(n);
143 - uint32_t hash = simple_hash(n);
131 + STRING *n = rrdvar_name_to_string(name);
132
133 rrdset_wrlock(st);
134
135 // find it
136 RRDSETVAR *rs;
137 for(rs = st->variables; rs ; rs = rs->next) {
150 - if(hash == rs->hash && strcmp(n, rs->variable) == 0) {
138 + if(rs->variable == n) {
139 rrdset_unlock(st);
140 if(rs->options & RRDVAR_OPTION_CUSTOM_CHART_VAR) {
153 - freez(n);
141 + string_freez(n);
142 return rs;
143 }
144 else {
157 - error("RRDSETVAR: custom variable '%s' on chart '%s' of host '%s', conflicts with an internal chart variable", n, st->id, host->hostname);
158 - freez(n);
145 + error("RRDSETVAR: custom variable '%s' on chart '%s' of host '%s', conflicts with an internal chart variable", string2str(n), rrdset_id(st), rrdhost_hostname(host));
146 + string_freez(n);
147 return NULL;
148 }
149 }
@@ -166,17 +154,17 @@ RRDSETVAR *rrdsetvar_custom_chart_variable_create(RRDSET *st, const char *name)
154 NETDATA_DOUBLE *v = mallocz(sizeof(NETDATA_DOUBLE));
155 *v = NAN;
156
169 - rs = rrdsetvar_create(st, n, RRDVAR_TYPE_CALCULATED, v, RRDVAR_OPTION_ALLOCATED|RRDVAR_OPTION_CUSTOM_CHART_VAR);
157 + rs = rrdsetvar_create(st, string2str(n), RRDVAR_TYPE_CALCULATED, v, RRDVAR_OPTION_ALLOCATED|RRDVAR_OPTION_CUSTOM_CHART_VAR);
158 rrdset_unlock(st);
159
172 - freez(n);
160 + string_freez(n);
161 return rs;
162 }
163
164 void rrdsetvar_custom_chart_variable_set(RRDSETVAR *rs, NETDATA_DOUBLE value) {
165 if(rs->type != RRDVAR_TYPE_CALCULATED || !(rs->options & RRDVAR_OPTION_CUSTOM_CHART_VAR) || !(rs->options & RRDVAR_OPTION_ALLOCATED)) {
166 error("RRDSETVAR: requested to set variable '%s' of chart '%s' on host '%s' to value " NETDATA_DOUBLE_FORMAT
179 - " but the variable is not a custom chart one.", rs->variable, rs->rrdset->id, rs->rrdset->rrdhost->hostname, value);
167 + " but the variable is not a custom chart one.", string2str(rs->variable), rrdset_id(rs->rrdset), rrdhost_hostname(rs->rrdset->rrdhost), value);
168 }
169 else {
170 NETDATA_DOUBLE *v = rs->value;
database/rrdsetvar.h
+4 -4
@@ -12,11 +12,10 @@
12 // these variables
13
14 struct rrdsetvar {
15 - char *variable; // variable name
16 - uint32_t hash; // variable name hash
15 + STRING *variable; // variable name
16
18 - char *key_fullid; // chart type.chart id.variable
19 - char *key_fullname; // chart type.chart name.variable
17 + STRING *key_fullid; // chart type.chart id.variable
18 + STRING *key_fullname; // chart type.chart name.variable
19
20 RRDVAR_TYPE type;
21 void *value;
@@ -32,6 +31,7 @@ struct rrdsetvar {
31 struct rrdset *rrdset;
32
33 struct rrdsetvar *next;
34 + struct rrdsetvar *prev;
35 };
36
37 extern RRDSETVAR *rrdsetvar_custom_chart_variable_create(RRDSET *st, const char *name);
database/rrdvar.c
+62 -88
@@ -20,87 +20,74 @@ inline int rrdvar_fix_name(char *variable) {
20 return fixed;
21 }
22
23 -int rrdvar_compare(void* a, void* b) {
24 - if(((RRDVAR *)a)->hash < ((RRDVAR *)b)->hash) return -1;
25 - else if(((RRDVAR *)a)->hash > ((RRDVAR *)b)->hash) return 1;
26 - else return strcmp(((RRDVAR *)a)->name, ((RRDVAR *)b)->name);
23 +static inline RRDVAR *rrdvar_index_add(DICTIONARY *dict, RRDVAR *rv) {
24 + return dictionary_set(dict, rrdvar_name(rv), rv, sizeof(RRDVAR));
25 }
26
29 -static inline RRDVAR *rrdvar_index_add(avl_tree_lock *tree, RRDVAR *rv) {
30 - RRDVAR *ret = (RRDVAR *)avl_insert_lock(tree, (avl_t *)(rv));
31 - if(ret != rv)
32 - debug(D_VARIABLES, "Request to insert RRDVAR '%s' into index failed. Already exists.", rv->name);
33 -
34 - return ret;
35 -}
36 -
37 -static inline RRDVAR *rrdvar_index_del(avl_tree_lock *tree, RRDVAR *rv) {
38 - RRDVAR *ret = (RRDVAR *)avl_remove_lock(tree, (avl_t *)(rv));
39 - if(!ret)
40 - error("Request to remove RRDVAR '%s' from index failed. Not Found.", rv->name);
27 +static inline RRDVAR *rrdvar_index_del(DICTIONARY *dict, RRDVAR *rv) {
28 + if(dictionary_del(dict, rrdvar_name(rv)) != 0) {
29 + error("Request to remove RRDVAR '%s' from index failed. Not Found.", rrdvar_name(rv));
30 + return NULL;
31 + }
32
42 - return ret;
33 + return rv;
34 }
35
45 -static inline RRDVAR *rrdvar_index_find(avl_tree_lock *tree, const char *name, uint32_t hash) {
46 - RRDVAR tmp;
47 - tmp.name = (char *)name;
48 - tmp.hash = (hash)?hash:simple_hash(tmp.name);
49 -
50 - return (RRDVAR *)avl_search_lock(tree, (avl_t *)&tmp);
36 +static inline RRDVAR *rrdvar_index_find(DICTIONARY *dict, STRING *name) {
37 + return dictionary_get(dict, string2str(name));
38 }
39
53 -inline void rrdvar_free(RRDHOST *host, avl_tree_lock *tree, RRDVAR *rv) {
40 +inline void rrdvar_free(RRDHOST *host, DICTIONARY *dict, RRDVAR *rv) {
41 (void)host;
42
43 if(!rv) return;
44
58 - if(tree) {
59 - debug(D_VARIABLES, "Deleting variable '%s'", rv->name);
60 - if(unlikely(!rrdvar_index_del(tree, rv)))
61 - error("RRDVAR: Attempted to delete variable '%s' from host '%s', but it is not found.", rv->name, host->hostname);
45 + if(dict) {
46 + debug(D_VARIABLES, "Deleting variable '%s'", rrdvar_name(rv));
47 + if(unlikely(!rrdvar_index_del(dict, rv)))
48 + error("RRDVAR: Attempted to delete variable '%s' from host '%s', but it is not found.", rrdvar_name(rv), rrdhost_hostname(host));
49 }
50
51 if(rv->options & RRDVAR_OPTION_ALLOCATED)
52 freez(rv->value);
53
67 - freez(rv->name);
54 + string_freez(rv->name);
55 freez(rv);
56 }
57
71 -inline RRDVAR *rrdvar_create_and_index(const char *scope __maybe_unused, avl_tree_lock *tree, const char *name,
72 - RRDVAR_TYPE type, RRDVAR_OPTIONS options, void *value) {
58 +inline STRING *rrdvar_name_to_string(const char *name) {
59 char *variable = strdupz(name);
60 rrdvar_fix_name(variable);
75 - uint32_t hash = simple_hash(variable);
61 + STRING *name_string = string_strdupz(variable);
62 + freez(variable);
63 + return name_string;
64 +}
65 +
66 +inline RRDVAR *rrdvar_create_and_index(const char *scope __maybe_unused, DICTIONARY *dict, STRING *name,
67 + RRDVAR_TYPE type, RRDVAR_OPTIONS options, void *value) {
68
77 - RRDVAR *rv = rrdvar_index_find(tree, variable, hash);
69 + RRDVAR *rv = rrdvar_index_find(dict, name);
70 if(unlikely(!rv)) {
79 - debug(D_VARIABLES, "Variable '%s' not found in scope '%s'. Creating a new one.", variable, scope);
71 + debug(D_VARIABLES, "Variable '%s' not found in scope '%s'. Creating a new one.", string2str(name), scope);
72
73 rv = callocz(1, sizeof(RRDVAR));
82 - rv->name = variable;
83 - rv->hash = hash;
74 + rv->name = string_dup(name);
75 rv->type = type;
76 rv->options = options;
77 rv->value = value;
78 rv->last_updated = now_realtime_sec();
79
89 - RRDVAR *ret = rrdvar_index_add(tree, rv);
80 + RRDVAR *ret = rrdvar_index_add(dict, rv);
81 if(unlikely(ret != rv)) {
91 - debug(D_VARIABLES, "Variable '%s' in scope '%s' already exists", variable, scope);
82 + debug(D_VARIABLES, "Variable '%s' in scope '%s' already exists", string2str(name), scope);
83 freez(rv);
93 - freez(variable);
84 rv = NULL;
85 }
86 else
97 - debug(D_VARIABLES, "Variable '%s' created in scope '%s'", variable, scope);
87 + debug(D_VARIABLES, "Variable '%s' created in scope '%s'", string2str(name), scope);
88 }
89 else {
100 - debug(D_VARIABLES, "Variable '%s' is already found in scope '%s'.", variable, scope);
101 -
102 - // already exists
103 - freez(variable);
90 + debug(D_VARIABLES, "Variable '%s' is already found in scope '%s'.", string2str(name), scope);
91
92 // this is important
93 // it must return NULL - not the existing variable - or double-free will happen
@@ -110,57 +97,48 @@ inline RRDVAR *rrdvar_create_and_index(const char *scope __maybe_unused, avl_tre
97 return rv;
98 }
99
113 -void rrdvar_free_remaining_variables(RRDHOST *host, avl_tree_lock *tree_lock) {
114 - // This is not bullet proof - avl should support some means to destroy it
115 - // with a callback for each item already in the index
116 -
117 - RRDVAR *rv, *last = NULL;
118 - while((rv = (RRDVAR *)tree_lock->avl_tree.root)) {
119 - if(unlikely(rv == last)) {
120 - error("RRDVAR: INTERNAL ERROR: Cannot cleanup tree of RRDVARs");
121 - break;
122 - }
123 - last = rv;
124 - rrdvar_free(host, tree_lock, rv);
100 +void rrdvar_free_remaining_variables(RRDHOST *host, DICTIONARY *dict) {
101 + RRDVAR *rv;
102 + dfe_start_rw(dict, rv, DICTIONARY_LOCK_REENTRANT) {
103 + rrdvar_free(host, dict, rv);
104 }
105 + dfe_done(rv);
106 }
107
108 // ----------------------------------------------------------------------------
109 // CUSTOM HOST VARIABLES
110
131 -inline int rrdvar_callback_for_all_host_variables(RRDHOST *host, int (*callback)(void * /*rrdvar*/, void * /*data*/), void *data) {
132 - return avl_traverse_lock(&host->rrdvar_root_index, callback, data);
111 +inline int rrdvar_walkthrough_read(DICTIONARY *dict, int (*callback)(const char *name, void *rrdvar, void *data), void *data) {
112 + return dictionary_walkthrough_read(dict, callback, data);
113 }
114
135 -static RRDVAR *rrdvar_custom_variable_create(const char *scope, avl_tree_lock *tree_lock, const char *name) {
115 +static RRDVAR *rrdvar_custom_variable_create(const char *scope, DICTIONARY *dict, const char *name) {
116 NETDATA_DOUBLE *v = callocz(1, sizeof(NETDATA_DOUBLE));
117 *v = NAN;
118
139 - RRDVAR *rv = rrdvar_create_and_index(scope, tree_lock, name, RRDVAR_TYPE_CALCULATED, RRDVAR_OPTION_CUSTOM_HOST_VAR|RRDVAR_OPTION_ALLOCATED, v);
119 + STRING *name_string = rrdvar_name_to_string(name);
120 +
121 + RRDVAR *rv = rrdvar_create_and_index(scope, dict, name_string, RRDVAR_TYPE_CALCULATED, RRDVAR_OPTION_CUSTOM_HOST_VAR|RRDVAR_OPTION_ALLOCATED, v);
122 if(unlikely(!rv)) {
123 freez(v);
142 - debug(D_VARIABLES, "Requested variable '%s' already exists - possibly 2 plugins are updating it at the same time.", name);
143 -
144 - char *variable = strdupz(name);
145 - rrdvar_fix_name(variable);
146 - uint32_t hash = simple_hash(variable);
124 + debug(D_VARIABLES, "Requested variable '%s' already exists - possibly 2 plugins are updating it at the same time.", string2str(name_string));
125
126 // find the existing one to return it
149 - rv = rrdvar_index_find(tree_lock, variable, hash);
150 -
151 - freez(variable);
127 + rv = rrdvar_index_find(dict, name_string);
128 }
129
130 + string_freez(name_string);
131 +
132 return rv;
133 }
134
135 RRDVAR *rrdvar_custom_host_variable_create(RRDHOST *host, const char *name) {
158 - return rrdvar_custom_variable_create("host", &host->rrdvar_root_index, name);
136 + return rrdvar_custom_variable_create("host", host->rrdvar_root_index, name);
137 }
138
139 void rrdvar_custom_host_variable_set(RRDHOST *host, RRDVAR *rv, NETDATA_DOUBLE value) {
140 if(rv->type != RRDVAR_TYPE_CALCULATED || !(rv->options & RRDVAR_OPTION_CUSTOM_HOST_VAR) || !(rv->options & RRDVAR_OPTION_ALLOCATED))
163 - error("requested to set variable '%s' to value " NETDATA_DOUBLE_FORMAT " but the variable is not a custom one.", rv->name, value);
141 + error("requested to set variable '%s' to value " NETDATA_DOUBLE_FORMAT " but the variable is not a custom one.", rrdvar_name(rv), value);
142 else {
143 NETDATA_DOUBLE *v = rv->value;
144 if(*v != value) {
@@ -174,10 +152,6 @@ void rrdvar_custom_host_variable_set(RRDHOST *host, RRDVAR *rv, NETDATA_DOUBLE v
152 }
153 }
154
177 -int foreach_host_variable_callback(RRDHOST *host, int (*callback)(RRDVAR * /*rv*/, void * /*data*/), void *data) {
178 - return avl_traverse_lock(&host->rrdvar_root_index, (int (*)(void *, void *))callback, data);
179 -}
180 -
155 // ----------------------------------------------------------------------------
156 // RRDVAR lookup
157
@@ -214,26 +188,26 @@ NETDATA_DOUBLE rrdvar2number(RRDVAR *rv) {
188 }
189 }
190
217 -int health_variable_lookup(const char *variable, uint32_t hash, RRDCALC *rc, NETDATA_DOUBLE *result) {
191 +int health_variable_lookup(STRING *variable, RRDCALC *rc, NETDATA_DOUBLE *result) {
192 RRDSET *st = rc->rrdset;
193 if(!st) return 0;
194
195 RRDHOST *host = st->rrdhost;
196 RRDVAR *rv;
197
224 - rv = rrdvar_index_find(&st->rrdvar_root_index, variable, hash);
198 + rv = rrdvar_index_find(st->rrdvar_root_index, variable);
199 if(rv) {
200 *result = rrdvar2number(rv);
201 return 1;
202 }
203
230 - rv = rrdvar_index_find(&st->rrdfamily->rrdvar_root_index, variable, hash);
204 + rv = rrdvar_index_find(st->rrdfamily->rrdvar_root_index, variable);
205 if(rv) {
206 *result = rrdvar2number(rv);
207 return 1;
208 }
209
236 - rv = rrdvar_index_find(&host->rrdvar_root_index, variable, hash);
210 + rv = rrdvar_index_find(host->rrdvar_root_index, variable);
211 if(rv) {
212 *result = rrdvar2number(rv);
213 return 1;
@@ -251,16 +225,16 @@ struct variable2json_helper {
225 RRDVAR_OPTIONS options;
226 };
227
254 -static int single_variable2json(void *entry, void *data) {
228 +static int single_variable2json(const char *name __maybe_unused, void *entry, void *data) {
229 struct variable2json_helper *helper = (struct variable2json_helper *)data;
230 RRDVAR *rv = (RRDVAR *)entry;
231 NETDATA_DOUBLE value = rrdvar2number(rv);
232
233 if (helper->options == RRDVAR_OPTION_DEFAULT || rv->options & helper->options) {
234 if(unlikely(isnan(value) || isinf(value)))
261 - buffer_sprintf(helper->buf, "%s\n\t\t\"%s\": null", helper->counter?",":"", rv->name);
235 + buffer_sprintf(helper->buf, "%s\n\t\t\"%s\": null", helper->counter?",":"", rrdvar_name(rv));
236 else
263 - buffer_sprintf(helper->buf, "%s\n\t\t\"%s\": %0.5" NETDATA_DOUBLE_MODIFIER, helper->counter?",":"", rv->name, (NETDATA_DOUBLE)value);
237 + buffer_sprintf(helper->buf, "%s\n\t\t\"%s\": %0.5" NETDATA_DOUBLE_MODIFIER, helper->counter?",":"", rrdvar_name(rv), (NETDATA_DOUBLE)value);
238
239 helper->counter++;
240 }
@@ -276,7 +250,7 @@ void health_api_v1_chart_custom_variables2json(RRDSET *st, BUFFER *buf) {
250 };
251
252 buffer_sprintf(buf, "{");
279 - avl_traverse_lock(&st->rrdvar_root_index, single_variable2json, (void *)&helper);
253 + rrdvar_walkthrough_read(st->rrdvar_root_index, single_variable2json, &helper);
254 buffer_strcat(buf, "\n\t\t\t}");
255 }
256
@@ -289,16 +263,16 @@ void health_api_v1_chart_variables2json(RRDSET *st, BUFFER *buf) {
263 .options = RRDVAR_OPTION_DEFAULT
264 };
265
292 - buffer_sprintf(buf, "{\n\t\"chart\": \"%s\",\n\t\"chart_name\": \"%s\",\n\t\"chart_context\": \"%s\",\n\t\"chart_variables\": {", st->id, st->name, st->context);
293 - avl_traverse_lock(&st->rrdvar_root_index, single_variable2json, (void *)&helper);
266 + buffer_sprintf(buf, "{\n\t\"chart\": \"%s\",\n\t\"chart_name\": \"%s\",\n\t\"chart_context\": \"%s\",\n\t\"chart_variables\": {", rrdset_id(st), rrdset_name(st), rrdset_context(st));
267 + rrdvar_walkthrough_read(st->rrdvar_root_index, single_variable2json, &helper);
268
295 - buffer_sprintf(buf, "\n\t},\n\t\"family\": \"%s\",\n\t\"family_variables\": {", st->family);
269 + buffer_sprintf(buf, "\n\t},\n\t\"family\": \"%s\",\n\t\"family_variables\": {", rrdset_family(st));
270 helper.counter = 0;
297 - avl_traverse_lock(&st->rrdfamily->rrdvar_root_index, single_variable2json, (void *)&helper);
271 + rrdvar_walkthrough_read(st->rrdfamily->rrdvar_root_index, single_variable2json, &helper);
272
299 - buffer_sprintf(buf, "\n\t},\n\t\"host\": \"%s\",\n\t\"host_variables\": {", host->hostname);
273 + buffer_sprintf(buf, "\n\t},\n\t\"host\": \"%s\",\n\t\"host_variables\": {", rrdhost_hostname(host));
274 helper.counter = 0;
301 - avl_traverse_lock(&host->rrdvar_root_index, single_variable2json, (void *)&helper);
275 + rrdvar_walkthrough_read(host->rrdvar_root_index, single_variable2json, &helper);
276
277 buffer_strcat(buf, "\n\t}\n}\n");
278 }
database/rrdvar.h
+12 -15
@@ -5,8 +5,6 @@
5
6 #include "libnetdata/libnetdata.h"
7
8 -extern int rrdvar_compare(void *a, void *b);
9 -
8 typedef enum rrdvar_type {
9 RRDVAR_TYPE_CALCULATED = 1,
10 RRDVAR_TYPE_TIME_T = 2,
@@ -32,35 +30,34 @@ typedef enum rrdvar_options {
30 // 2. at each context (RRDFAMILY.rrdvar_root_index)
31 // 3. at each host (RRDHOST.rrdvar_root_index)
32 struct rrdvar {
35 - avl_t avl;
36 -
37 - char *name;
38 - uint32_t hash;
39 -
40 - RRDVAR_TYPE type;
41 - RRDVAR_OPTIONS options;
33 + STRING *name;
34
35 void *value;
44 -
36 time_t last_updated;
37 +
38 + RRDVAR_OPTIONS options:16;
39 + RRDVAR_TYPE type:8;
40 };
41
42 +#define rrdvar_name(rv) string2str((rv)->name)
43 +
44 #define RRDVAR_MAX_LENGTH 1024
45
46 extern int rrdvar_fix_name(char *variable);
47
48 #include "rrd.h"
49
50 +extern STRING *rrdvar_name_to_string(const char *name);
51 +
52 extern RRDVAR *rrdvar_custom_host_variable_create(RRDHOST *host, const char *name);
53 extern void rrdvar_custom_host_variable_set(RRDHOST *host, RRDVAR *rv, NETDATA_DOUBLE value);
56 -extern int foreach_host_variable_callback(RRDHOST *host, int (*callback)(RRDVAR *rv, void *data), void *data);
57 -extern void rrdvar_free_remaining_variables(RRDHOST *host, avl_tree_lock *tree_lock);
54 +extern void rrdvar_free_remaining_variables(RRDHOST *host, DICTIONARY *dict);
55
59 -extern int rrdvar_callback_for_all_host_variables(RRDHOST *host, int (*callback)(void *rrdvar, void *data), void *data);
56 +extern int rrdvar_walkthrough_read(DICTIONARY *dict, int (*callback)(const char *name, void *rrdvar, void *data), void *data);
57
58 extern NETDATA_DOUBLE rrdvar2number(RRDVAR *rv);
59
63 -extern RRDVAR *rrdvar_create_and_index(const char *scope, avl_tree_lock *tree, const char *name, RRDVAR_TYPE type, RRDVAR_OPTIONS options, void *value);
64 -extern void rrdvar_free(RRDHOST *host, avl_tree_lock *tree, RRDVAR *rv);
60 +extern RRDVAR *rrdvar_create_and_index(const char *scope, DICTIONARY *dict, STRING *name, RRDVAR_TYPE type, RRDVAR_OPTIONS options, void *value);
61 +extern void rrdvar_free(RRDHOST *host, DICTIONARY *dict, RRDVAR *rv);
62
63 #endif //NETDATA_RRDVAR_H
database/sqlite/sqlite_aclk.c
+12 -14
@@ -237,15 +237,14 @@ struct aclk_database_worker_config *find_inactive_wc_by_node_id(char *node_id)
237 void aclk_sync_exit_all()
238 {
239 rrd_rdlock();
240 - RRDHOST *host = localhost;
241 - while(host) {
240 + RRDHOST *host;
241 + rrdhost_foreach_read(host) {
242 struct aclk_database_worker_config *wc = host->dbsync_worker;
243 if (wc) {
244 wc->is_shutting_down = 1;
245 (void) aclk_database_deq_cmd(wc);
246 uv_cond_signal(&wc->cmd_cond);
247 }
248 - host = host->next;
248 }
249 rrd_unlock();
250
@@ -320,7 +319,7 @@ static int create_host_callback(void *data, int argc, char **argv, char **column
319 char node_str[UUID_STR_LEN] = "<none>";
320 if (likely(host->node_id))
321 uuid_unparse_lower(*host->node_id, node_str);
323 - internal_error(true, "Adding archived host \"%s\" with GUID \"%s\" node id = \"%s\"", host->hostname, host->machine_guid, node_str);
322 + internal_error(true, "Adding archived host \"%s\" with GUID \"%s\" node id = \"%s\"", rrdhost_hostname(host), host->machine_guid, node_str);
323 #endif
324 return 0;
325 }
@@ -335,7 +334,7 @@ int aclk_start_sync_thread(void *data, int argc, char **argv, char **column)
334
335 uuid_unparse_lower(*((uuid_t *) argv[0]), uuid_str);
336
338 - RRDHOST *host = rrdhost_find_by_guid(uuid_str, 0);
337 + RRDHOST *host = rrdhost_find_by_guid(uuid_str);
338 if (host == localhost)
339 return 0;
340
@@ -526,7 +525,7 @@ void aclk_database_worker(void *arg)
525
526 char threadname[NETDATA_THREAD_NAME_MAX+1];
527 if (wc->host)
529 - snprintfz(threadname, NETDATA_THREAD_NAME_MAX, "AS_%s", wc->host->hostname);
528 + snprintfz(threadname, NETDATA_THREAD_NAME_MAX, "AS_%s", rrdhost_hostname(wc->host));
529 else {
530 snprintfz(threadname, NETDATA_THREAD_NAME_MAX, "AS_%s", wc->uuid_str);
531 threadname[11] = '\0';
@@ -705,14 +704,14 @@ void aclk_database_worker(void *arg)
704 case ACLK_DATABASE_TIMER:
705 if (unlikely(localhost && !wc->host && !wc->is_orphan)) {
706 if (claimed()) {
708 - wc->host = rrdhost_find_by_guid(wc->host_guid, 0);
707 + wc->host = rrdhost_find_by_guid(wc->host_guid);
708 if (wc->host) {
710 - info("HOST %s (%s) detected as active", wc->host->hostname, wc->host_guid);
711 - snprintfz(threadname, NETDATA_THREAD_NAME_MAX, "AS_%s", wc->host->hostname);
709 + info("HOST %s (%s) detected as active", rrdhost_hostname(wc->host), wc->host_guid);
710 + snprintfz(threadname, NETDATA_THREAD_NAME_MAX, "AS_%s", rrdhost_hostname(wc->host));
711 uv_thread_set_name_np(wc->thread, threadname);
712 wc->host->dbsync_worker = wc;
713 if (unlikely(!wc->hostname))
715 - wc->hostname = strdupz(wc->host->hostname);
714 + wc->hostname = strdupz(rrdhost_hostname(wc->host));
715 aclk_del_worker_thread(wc);
716 wc->node_info_send = 1;
717 }
@@ -844,7 +843,7 @@ void sql_create_aclk_table(RRDHOST *host, uuid_t *host_uuid, uuid_t *node_id)
843 uuid_unparse_lower(*node_id, wc->node_id);
844 if (likely(host)) {
845 host->dbsync_worker = (void *)wc;
847 - wc->hostname = strdupz(host->hostname);
846 + wc->hostname = strdupz(rrdhost_hostname(host));
847 }
848 else
849 wc->hostname = get_hostname_by_node_id(wc->node_id);
@@ -1039,12 +1038,11 @@ void aclk_data_rotated(void)
1038
1039 time_t next_rotation_time = now_realtime_sec()+ACLK_DATABASE_ROTATION_DELAY;
1040 rrd_rdlock();
1042 - RRDHOST *this_host = localhost;
1043 - while (this_host) {
1041 + RRDHOST *this_host;
1042 + rrdhost_foreach_read(this_host) {
1043 struct aclk_database_worker_config *wc = this_host->dbsync_worker;
1044 if (wc)
1045 wc->rotation_after = next_rotation_time;
1047 - this_host = this_host->next;
1046 }
1047 rrd_unlock();
1048
database/sqlite/sqlite_aclk.h
+10 -6
@@ -216,13 +216,17 @@ static inline RRDHOST *find_host_by_node_id(char *node_id)
216 if (uuid_parse(node_id, node_uuid))
217 return NULL;
218
219 - RRDHOST *host = localhost;
220 - while(host) {
221 - if (host->node_id && !(uuid_compare(*host->node_id, node_uuid)))
222 - return host;
223 - host = host->next;
219 + rrd_rdlock();
220 + RRDHOST *host, *ret = NULL;
221 + rrdhost_foreach_read(host) {
222 + if (host->node_id && !(uuid_compare(*host->node_id, node_uuid))) {
223 + ret = host;
224 + break;
225 + }
226 }
225 - return NULL;
227 + rrd_unlock();
228 +
229 + return ret;
230 }
231
232
database/sqlite/sqlite_aclk_alert.c
+24 -32
@@ -220,7 +220,7 @@ void aclk_push_alert_event(struct aclk_database_worker_config *wc, struct aclk_d
220 int rc;
221
222 if (unlikely(!wc->alert_updates)) {
223 - log_access("ACLK STA [%s (%s)]: Ignoring alert push event, updates have been turned off for this node.", wc->node_id, wc->host ? wc->host->hostname : "N/A");
223 + log_access("ACLK STA [%s (%s)]: Ignoring alert push event, updates have been turned off for this node.", wc->node_id, wc->host ? rrdhost_hostname(wc->host) : "N/A");
224 return;
225 }
226
@@ -300,9 +300,9 @@ void aclk_push_alert_event(struct aclk_database_worker_config *wc, struct aclk_d
300 alarm_log.config_hash = strdupz((char *)uuid_str);
301
302 alarm_log.utc_offset = wc->host->utc_offset;
303 - alarm_log.timezone = strdupz((char *)wc->host->abbrev_timezone);
303 + alarm_log.timezone = strdupz(rrdhost_abbrev_timezone(wc->host));
304 alarm_log.exec_path = sqlite3_column_bytes(res, 14) > 0 ? strdupz((char *)sqlite3_column_text(res, 14)) :
305 - strdupz((char *)wc->host->health_default_exec);
305 + strdupz((char *)string2str(wc->host->health_default_exec));
306 alarm_log.conf_source = strdupz((char *)sqlite3_column_text(res, 16));
307
308 char *edit_command = sqlite3_column_bytes(res, 16) > 0 ?
@@ -374,7 +374,7 @@ void aclk_push_alert_event(struct aclk_database_worker_config *wc, struct aclk_d
374 log_access(
375 "ACLK RES [%s (%s)]: ALERTS SENT from %" PRIu64 " to %" PRIu64 " batch=%" PRIu64,
376 wc->node_id,
377 - wc->host ? wc->host->hostname : "N/A",
377 + wc->host ? rrdhost_hostname(wc->host) : "N/A",
378 log_first_sequence_id,
379 log_last_sequence_id,
380 wc->alerts_batch_id);
@@ -424,9 +424,7 @@ void aclk_send_alarm_health_log(char *node_id)
424 struct aclk_database_worker_config *wc = find_inactive_wc_by_node_id(node_id);
425
426 if (likely(!wc)) {
427 - rrd_rdlock();
427 RRDHOST *host = find_host_by_node_id(node_id);
429 - rrd_unlock();
428 if (likely(host))
429 wc = (struct aclk_database_worker_config *)host->dbsync_worker;
430 }
@@ -460,9 +458,7 @@ void aclk_push_alarm_health_log(struct aclk_database_worker_config *wc, struct a
458
459 RRDHOST *host = wc->host;
460 if (unlikely(!host)) {
463 - rrd_rdlock();
461 host = find_host_by_node_id(wc->node_id);
465 - rrd_unlock();
462
463 if (unlikely(!host)) {
464 log_access(
@@ -554,7 +550,7 @@ void aclk_send_alarm_configuration(char *config_hash)
550 return;
551 }
552
557 - log_access("ACLK REQ [%s (%s)]: Request to send alert config %s.", wc->node_id, wc->host ? wc->host->hostname : "N/A", config_hash);
553 + log_access("ACLK REQ [%s (%s)]: Request to send alert config %s.", wc->node_id, wc->host ? rrdhost_hostname(wc->host) : "N/A", config_hash);
554
555 struct aclk_database_cmd cmd;
556 memset(&cmd, 0, sizeof(cmd));
@@ -664,14 +660,14 @@ int aclk_push_alert_config_event(struct aclk_database_worker_config *wc, struct
660 }
661
662 if (likely(p_alarm_config.cfg_hash)) {
667 - log_access("ACLK RES [%s (%s)]: Sent alert config %s.", wc->node_id, wc->host ? wc->host->hostname : "N/A", config_hash);
663 + log_access("ACLK RES [%s (%s)]: Sent alert config %s.", wc->node_id, wc->host ? rrdhost_hostname(wc->host) : "N/A", config_hash);
664 aclk_send_provide_alarm_cfg(&p_alarm_config);
665 freez((char *) cmd.data_param);
666 freez(p_alarm_config.cfg_hash);
667 destroy_aclk_alarm_configuration(&alarm_config);
668 }
669 else
674 - log_access("ACLK STA [%s (%s)]: Alert config for %s not found.", wc->node_id, wc->host ? wc->host->hostname : "N/A", config_hash);
670 + log_access("ACLK STA [%s (%s)]: Alert config for %s not found.", wc->node_id, wc->host ? rrdhost_hostname(wc->host) : "N/A", config_hash);
671
672 bind_fail:
673 rc = sqlite3_finalize(res);
@@ -697,9 +693,7 @@ void aclk_start_alert_streaming(char *node_id, uint64_t batch_id, uint64_t start
693 return;
694
695 struct aclk_database_worker_config *wc = NULL;
700 - rrd_rdlock();
696 RRDHOST *host = find_host_by_node_id(node_id);
702 - rrd_unlock();
697 if (likely(host)) {
698 wc = (struct aclk_database_worker_config *)host->dbsync_worker ?
699 (struct aclk_database_worker_config *)host->dbsync_worker :
@@ -716,7 +710,7 @@ void aclk_start_alert_streaming(char *node_id, uint64_t batch_id, uint64_t start
710 wc = (struct aclk_database_worker_config *)find_inactive_wc_by_node_id(node_id);
711
712 if (likely(wc)) {
719 - log_access("ACLK REQ [%s (%s)]: ALERTS STREAM from %"PRIu64" batch=%"PRIu64, node_id, wc->host ? wc->host->hostname : "N/A", start_seq_id, batch_id);
713 + log_access("ACLK REQ [%s (%s)]: ALERTS STREAM from %"PRIu64" batch=%"PRIu64, node_id, wc->host ? rrdhost_hostname(wc->host) : "N/A", start_seq_id, batch_id);
714 __sync_synchronize();
715 wc->alerts_batch_id = batch_id;
716 wc->alerts_start_seq_id = start_seq_id;
@@ -744,7 +738,7 @@ void sql_process_queue_removed_alerts_to_aclk(struct aclk_database_worker_config
738
739 db_execute(buffer_tostring(sql));
740
747 - log_access("ACLK STA [%s (%s)]: QUEUED REMOVED ALERTS", wc->node_id, wc->host ? wc->host->hostname : "N/A");
741 + log_access("ACLK STA [%s (%s)]: QUEUED REMOVED ALERTS", wc->node_id, wc->host ? rrdhost_hostname(wc->host) : "N/A");
742
743 buffer_free(sql);
744
@@ -780,17 +774,15 @@ void aclk_process_send_alarm_snapshot(char *node_id, char *claim_id, uint64_t sn
774 return;
775
776 struct aclk_database_worker_config *wc = NULL;
783 - rrd_rdlock();
777 RRDHOST *host = find_host_by_node_id(node_id);
778 if (likely(host))
779 wc = (struct aclk_database_worker_config *)host->dbsync_worker;
787 - rrd_unlock();
780
781 if (likely(wc)) {
782 log_access(
783 "IN [%s (%s)]: Request to send alerts snapshot, snapshot_id %" PRIu64 " and ack_sequence_id %" PRIu64,
784 wc->node_id,
793 - wc->host ? wc->host->hostname : "N/A",
785 + wc->host ? rrdhost_hostname(wc->host) : "N/A",
786 snapshot_id,
787 sequence_id);
788 if (wc->alerts_snapshot_id == snapshot_id)
@@ -831,13 +823,13 @@ void aclk_mark_alert_cloud_ack(char *uuid_str, uint64_t alerts_ack_sequence_id)
823 #ifdef ENABLE_ACLK
824 void health_alarm_entry2proto_nolock(struct alarm_log_entry *alarm_log, ALARM_ENTRY *ae, RRDHOST *host)
825 {
834 - char *edit_command = ae->source ? health_edit_command_from_source(ae->source) : strdupz("UNKNOWN=0=UNKNOWN");
826 + char *edit_command = ae->source ? health_edit_command_from_source(ae_source(ae)) : strdupz("UNKNOWN=0=UNKNOWN");
827 char config_hash_id[GUID_LEN + 1];
828 uuid_unparse_lower(ae->config_hash_id, config_hash_id);
829
838 - alarm_log->chart = strdupz((char *)ae->chart);
839 - alarm_log->name = strdupz((char *)ae->name);
840 - alarm_log->family = strdupz((char *)ae->family);
830 + alarm_log->chart = strdupz(ae_chart_name(ae));
831 + alarm_log->name = strdupz(ae_name(ae));
832 + alarm_log->family = strdupz(ae_family(ae));
833
834 alarm_log->batch_id = 0;
835 alarm_log->sequence_id = 0;
@@ -846,9 +838,9 @@ void health_alarm_entry2proto_nolock(struct alarm_log_entry *alarm_log, ALARM_EN
838 alarm_log->config_hash = strdupz((char *)config_hash_id);
839
840 alarm_log->utc_offset = host->utc_offset;
849 - alarm_log->timezone = strdupz((char *)host->abbrev_timezone);
850 - alarm_log->exec_path = ae->exec ? strdupz((char *)ae->exec) : strdupz((char *)host->health_default_exec);
851 - alarm_log->conf_source = ae->source ? strdupz((char *)ae->source) : strdupz((char *)"");
841 + alarm_log->timezone = strdupz(rrdhost_abbrev_timezone(host));
842 + alarm_log->exec_path = ae->exec ? strdupz(ae_exec(ae)) : strdupz((char *)string2str(host->health_default_exec));
843 + alarm_log->conf_source = ae->source ? strdupz(ae_source(ae)) : strdupz((char *)"");
844
845 alarm_log->command = strdupz((char *)edit_command);
846
@@ -861,19 +853,19 @@ void health_alarm_entry2proto_nolock(struct alarm_log_entry *alarm_log, ALARM_EN
853 alarm_log->last_repeat = (time_t)ae->last_repeat;
854
855 alarm_log->silenced =
864 - ((ae->flags & HEALTH_ENTRY_FLAG_SILENCED) || (ae->recipient && !strncmp((char *)ae->recipient, "silent", 6))) ?
856 + ((ae->flags & HEALTH_ENTRY_FLAG_SILENCED) || (ae->recipient && !strncmp(ae_recipient(ae), "silent", 6))) ?
857 1 :
858 0;
859
868 - alarm_log->value_string = strdupz(ae->new_value_string);
869 - alarm_log->old_value_string = strdupz(ae->old_value_string);
860 + alarm_log->value_string = strdupz(ae_new_value_string(ae));
861 + alarm_log->old_value_string = strdupz(ae_old_value_string(ae));
862
863 alarm_log->value = (!isnan(ae->new_value)) ? (NETDATA_DOUBLE)ae->new_value : 0;
864 alarm_log->old_value = (!isnan(ae->old_value)) ? (NETDATA_DOUBLE)ae->old_value : 0;
865
866 alarm_log->updated = (ae->flags & HEALTH_ENTRY_FLAG_UPDATED) ? 1 : 0;
875 - alarm_log->rendered_info = ae->info ? strdupz(ae->info) : strdupz((char *)"");
876 - alarm_log->chart_context = ae->chart_context ? strdupz(ae->chart_context) : strdupz((char *)"");
867 + alarm_log->rendered_info = strdupz(ae_info(ae));
868 + alarm_log->chart_context = strdupz(ae_chart_context(ae));
869
870 freez(edit_command);
871 }
@@ -905,7 +897,7 @@ void aclk_push_alert_snapshot_event(struct aclk_database_worker_config *wc, stru
897 UNUSED(cmd);
898 // we perhaps we don't need this for snapshots
899 if (unlikely(!wc->alert_updates)) {
908 - log_access("ACLK STA [%s (%s)]: Ignoring alert snapshot event, updates have been turned off for this node.", wc->node_id, wc->host ? wc->host->hostname : "N/A");
900 + log_access("ACLK STA [%s (%s)]: Ignoring alert snapshot event, updates have been turned off for this node.", wc->node_id, wc->host ? rrdhost_hostname(wc->host) : "N/A");
901 return;
902 }
903
@@ -921,7 +913,7 @@ void aclk_push_alert_snapshot_event(struct aclk_database_worker_config *wc, stru
913 if (unlikely(!claim_id))
914 return;
915
924 - log_access("ACLK REQ [%s (%s)]: Sending alerts snapshot, snapshot_id %" PRIu64, wc->node_id, wc->host ? wc->host->hostname : "N/A", wc->alerts_snapshot_id);
916 + log_access("ACLK REQ [%s (%s)]: Sending alerts snapshot, snapshot_id %" PRIu64, wc->node_id, wc->host ? rrdhost_hostname(wc->host) : "N/A", wc->alerts_snapshot_id);
917
918 aclk_mark_alert_cloud_ack(wc->uuid_str, wc->alerts_ack_sequence_id);
919
database/sqlite/sqlite_aclk_chart.c
+26 -29
@@ -153,10 +153,10 @@ int aclk_add_chart_event(struct aclk_database_worker_config *wc, struct aclk_dat
153 chart_payload.config_hash = get_str_from_uuid(&st->state->hash_id);
154 chart_payload.update_every = st->update_every;
155 chart_payload.memory_mode = st->rrd_memory_mode;
156 - chart_payload.name = (char *)st->name;
156 + chart_payload.name = (char *)rrdset_name(st);
157 chart_payload.node_id = wc->node_id;
158 chart_payload.claim_id = claim_id;
159 - chart_payload.id = strdupz(st->id);
159 + chart_payload.id = strdupz(rrdset_id(st));
160
161 chart_payload.chart_labels = rrdlabels_create();
162 rrdlabels_copy(chart_payload.chart_labels, st->state->chart_labels);
@@ -304,7 +304,7 @@ void aclk_send_chart_event(struct aclk_database_worker_config *wc, struct aclk_d
304 log_access(
305 "ACLK STA [%s (%s)]: Ignoring chart push event, updates have been turned off for this node.",
306 wc->node_id,
307 - wc->host ? wc->host->hostname : "N/A");
307 + wc->host ? rrdhost_hostname(wc->host) : "N/A");
308 return;
309 }
310
@@ -504,7 +504,7 @@ int aclk_send_chart_config(struct aclk_database_worker_config *wc, struct aclk_d
504 log_access(
505 "ACLK REQ [%s (%s)]: Sending chart config for %s.",
506 wc->node_id,
507 - wc->host ? wc->host->hostname : "N/A",
507 + wc->host ? rrdhost_hostname(wc->host) : "N/A",
508 hash_id);
509 aclk_chart_config_updated(&chart_config, 1);
510 destroy_chart_config_updated(&chart_config);
@@ -512,7 +512,7 @@ int aclk_send_chart_config(struct aclk_database_worker_config *wc, struct aclk_d
512 log_access(
513 "ACLK STA [%s (%s)]: Chart config for %s not found.",
514 wc->node_id,
515 - wc->host ? wc->host->hostname : "N/A",
515 + wc->host ? rrdhost_hostname(wc->host) : "N/A",
516 hash_id);
517
518 bind_fail:
@@ -552,7 +552,7 @@ void aclk_receive_chart_ack(struct aclk_database_worker_config *wc, struct aclk_
552 log_access(
553 "ACLK STA [%s (%s)]: CHARTS ACKNOWLEDGED IN THE DATABASE UP TO %" PRIu64,
554 wc->node_id,
555 - wc->host ? wc->host->hostname : "N/A",
555 + wc->host ? rrdhost_hostname(wc->host) : "N/A",
556 cmd.param1);
557
558 bind_fail:
@@ -637,7 +637,7 @@ void aclk_get_chart_config(char **hash_id)
637 log_access(
638 "ACLK REQ [%s (%s)]: Request %d for chart config with hash %s received.",
639 wc->node_id,
640 - wc->host ? wc->host->hostname : "N/A",
640 + wc->host ? rrdhost_hostname(wc->host) : "N/A",
641 i,
642 hash_id[i]);
643 cmd.data_param = (void *)strdupz(hash_id[i]);
@@ -660,11 +660,10 @@ static void aclk_submit_param_command(char *node_id, enum aclk_database_opcode a
660 cmd.opcode = aclk_command;
661 cmd.param1 = param;
662
663 - rrd_rdlock();
663 RRDHOST *host = find_host_by_node_id(node_id);
664 if (likely(host))
665 wc = (struct aclk_database_worker_config *)host->dbsync_worker;
667 - rrd_unlock();
666 +
667 if (wc)
668 aclk_database_enq_cmd(wc, &cmd);
669 else {
@@ -702,8 +701,8 @@ void aclk_start_streaming(char *node_id, uint64_t sequence_id, time_t created_at
701
702 struct aclk_database_worker_config *wc = find_inactive_wc_by_node_id(node_id);
703 rrd_rdlock();
705 - RRDHOST *host = localhost;
706 - while(host) {
704 + RRDHOST *host;
705 + rrdhost_foreach_read(host) {
706 if (wc || (host->node_id && !(uuid_compare(*host->node_id, node_uuid)))) {
707 rrd_unlock();
708 if (!wc)
@@ -771,10 +770,8 @@ void aclk_start_streaming(char *node_id, uint64_t sequence_id, time_t created_at
770 }
771 return;
772 }
774 - host = host->next;
773 }
774 rrd_unlock();
777 - return;
775 }
776
777 #define SQL_SELECT_HOST_MEMORY_MODE "SELECT memory_mode FROM chart WHERE host_id = @host_id LIMIT 1;"
@@ -826,7 +823,7 @@ void aclk_update_retention(struct aclk_database_worker_config *wc)
823 return;
824
825 if (wc->host && rrdhost_flag_check(wc->host, RRDHOST_FLAG_ACLK_STREAM_CONTEXTS)) {
829 - internal_error(true, "Skipping aclk_update_retention for host %s because context streaming is enabled", wc->host->hostname);
826 + internal_error(true, "Skipping aclk_update_retention for host %s because context streaming is enabled", rrdhost_hostname(wc->host));
827 return;
828 }
829
@@ -1093,9 +1090,9 @@ void queue_dimension_to_aclk(RRDDIM *rd, time_t last_updated)
1090 memset(&dim_payload, 0, sizeof(dim_payload));
1091 dim_payload.node_id = wc->node_id;
1092 dim_payload.claim_id = claim_id;
1096 - dim_payload.name = rd->name;
1097 - dim_payload.id = rd->id;
1098 - dim_payload.chart_id = rd->rrdset->id;
1093 + dim_payload.name = rrddim_name(rd);
1094 + dim_payload.id = rrddim_id(rd);
1095 + dim_payload.chart_id = rrdset_id(rd->rrdset);
1096 dim_payload.created_at.tv_sec = created_at;
1097 dim_payload.last_timestamp.tv_sec = last_updated;
1098
@@ -1144,9 +1141,9 @@ void aclk_send_dimension_update(RRDDIM *rd)
1141 rd->rrdset->rrdhost->dbsync_worker,
1142 claim_id,
1143 &rd->metric_uuid,
1147 - rd->id,
1148 - rd->name,
1149 - rd->rrdset->id,
1144 + rrddim_id(rd),
1145 + rrddim_name(rd),
1146 + rrdset_id(rd->rrdset),
1147 first_entry_t,
1148 live ? 0 : last_entry_t,
1149 NULL);
@@ -1155,9 +1152,9 @@ void aclk_send_dimension_update(RRDDIM *rd)
1152 debug(
1153 D_ACLK_SYNC,
1154 "%s: Update dimension chart=%s dim=%s live=%d (%ld, %ld)",
1158 - rd->rrdset->rrdhost->hostname,
1159 - rd->rrdset->name,
1160 - rd->name,
1155 + rrdhost_hostname(rd->rrdset->rrdhost),
1156 + rrdset_name(rd->rrdset),
1157 + rrddim_name(rd),
1158 live,
1159 first_entry_t,
1160 last_entry_t);
@@ -1165,9 +1162,9 @@ void aclk_send_dimension_update(RRDDIM *rd)
1162 debug(
1163 D_ACLK_SYNC,
1164 "%s: Update dimension chart=%s dim=%s live=%d (%ld, %ld) collected %ld seconds ago",
1168 - rd->rrdset->rrdhost->hostname,
1169 - rd->rrdset->name,
1170 - rd->name,
1165 + rrdhost_hostname(rd->rrdset->rrdhost),
1166 + rrdset_name(rd->rrdset),
1167 + rrddim_name(rd),
1168 live,
1169 first_entry_t,
1170 last_entry_t,
@@ -1280,15 +1277,15 @@ void sql_check_chart_liveness(RRDSET *st) {
1277
1278 if (unlikely(!rrdset_flag_check(st, RRDSET_FLAG_ACLK))) {
1279 if (likely(st->dimensions && st->counter_done && !queue_chart_to_aclk(st))) {
1283 - debug(D_ACLK_SYNC,"Check chart liveness [%s] submit chart definition", st->name);
1280 + debug(D_ACLK_SYNC,"Check chart liveness [%s] submit chart definition", rrdset_name(st));
1281 rrdset_flag_set(st, RRDSET_FLAG_ACLK);
1282 }
1283 }
1284 else
1288 - debug(D_ACLK_SYNC,"Check chart liveness [%s] chart definition already submitted", st->name);
1285 + debug(D_ACLK_SYNC,"Check chart liveness [%s] chart definition already submitted", rrdset_name(st));
1286 time_t mark = now_realtime_sec();
1287
1291 - debug(D_ACLK_SYNC,"Check chart liveness [%s] scanning dimensions", st->name);
1288 + debug(D_ACLK_SYNC,"Check chart liveness [%s] scanning dimensions", rrdset_name(st));
1289 rrddim_foreach_read(rd, st) {
1290 if (!rrddim_flag_check(rd, RRDDIM_FLAG_HIDDEN))
1291 queue_dimension_to_aclk(rd, calc_dimension_liveness(rd, mark));
database/sqlite/sqlite_aclk_node.c
+8 -8
@@ -16,8 +16,8 @@ DICTIONARY *collectors_from_charts(RRDHOST *host, DICTIONARY *dict) {
16 rrdset_foreach_read(st, host) {
17 if (rrdset_is_available_for_viewers(st)) {
18 struct collector_info col = {
19 - .plugin = st->plugin_name ? st->plugin_name : "",
20 - .module = st->module_name ? st->module_name : ""
19 + .plugin = rrdset_plugin_name(st),
20 + .module = rrdset_module_name(st)
21 };
22 snprintfz(name, 499, "%s:%s", col.plugin, col.module);
23 dictionary_set(dict, name, &col, sizeof(struct collector_info));
@@ -47,7 +47,7 @@ void sql_build_node_collectors(struct aclk_database_worker_config *wc)
47 dictionary_destroy(dict);
48 freez(upd_node_collectors.claim_id);
49
50 - log_access("ACLK RES [%s (%s)]: NODE COLLECTORS SENT", wc->node_id, wc->host->hostname);
50 + log_access("ACLK RES [%s (%s)]: NODE COLLECTORS SENT", wc->node_id, rrdhost_hostname(wc->host));
51 #else
52 UNUSED(wc);
53 #endif
@@ -94,8 +94,8 @@ void sql_build_node_info(struct aclk_database_worker_config *wc, struct aclk_dat
94 netdata_mutex_unlock(&host->receiver_lock);
95 }
96
97 - node_info.data.name = host->hostname;
98 - node_info.data.os = (char *) host->os;
97 + node_info.data.name = rrdhost_hostname(host);
98 + node_info.data.os = rrdhost_os(host);
99 node_info.data.os_name = host->system_info->host_os_name;
100 node_info.data.os_version = host->system_info->host_os_version;
101 node_info.data.kernel_name = host->system_info->kernel_name;
@@ -106,8 +106,8 @@ void sql_build_node_info(struct aclk_database_worker_config *wc, struct aclk_dat
106 node_info.data.memory = host->system_info->host_ram_total ? host->system_info->host_ram_total : "0";
107 node_info.data.disk_space = host->system_info->host_disk_space ? host->system_info->host_disk_space : "0";
108 node_info.data.version = host_version ? host_version : VERSION;
109 - node_info.data.release_channel = (char *) get_release_channel();
110 - node_info.data.timezone = (char *) host->abbrev_timezone;
109 + node_info.data.release_channel = get_release_channel();
110 + node_info.data.timezone = rrdhost_abbrev_timezone(host);
111 node_info.data.virtualization_type = host->system_info->virtualization ? host->system_info->virtualization : "unknown";
112 node_info.data.container_type = host->system_info->container ? host->system_info->container : "unknown";
113 node_info.data.custom_info = config_get(CONFIG_SECTION_WEB, "custom dashboard_info.js", "");
@@ -126,7 +126,7 @@ void sql_build_node_info(struct aclk_database_worker_config *wc, struct aclk_dat
126 node_info.data.host_labels_ptr = host->host_labels;
127
128 aclk_update_node_info(&node_info);
129 - log_access("ACLK RES [%s (%s)]: NODE INFO SENT for guid [%s] (%s)", wc->node_id, wc->host->hostname, wc->host_guid, wc->host == localhost ? "parent" : "child");
129 + log_access("ACLK RES [%s (%s)]: NODE INFO SENT for guid [%s] (%s)", wc->node_id, rrdhost_hostname(wc->host), wc->host_guid, wc->host == localhost ? "parent" : "child");
130
131 rrd_unlock();
132 freez(node_info.claim_id);
database/sqlite/sqlite_context.c
-1
@@ -21,7 +21,6 @@ const char *database_context_cleanup[] = {
21 };
22
23 sqlite3 *db_context_meta = NULL;
24 -
24 /*
25 * Initialize the SQLite database
26 * Return 0 on success
database/sqlite/sqlite_functions.c
+100 -69
@@ -29,6 +29,7 @@ const char *database_config[] = {
29 "CREATE TABLE IF NOT EXISTS metadata_migration(filename text, file_size, date_created int);",
30 "CREATE INDEX IF NOT EXISTS ind_d1 on dimension (chart_id, id, name);",
31 "CREATE INDEX IF NOT EXISTS ind_c1 on chart (host_id, id, type, name);",
32 + "CREATE INDEX IF NOT EXISTS ind_c2 on chart (host_id, context);",
33 "CREATE TABLE IF NOT EXISTS chart_label(chart_id blob, source_type int, label_key text, "
34 "label_value text, date_created int, PRIMARY KEY (chart_id, label_key));",
35 "CREATE TABLE IF NOT EXISTS node_instance (host_id blob PRIMARY KEY, claim_id, node_id, date_created);",
@@ -408,6 +409,24 @@ int init_database_batch(sqlite3 *database, int rebuild, int init_type, const cha
409 return 0;
410 }
411
412 +static void _uuid_parse(sqlite3_context *context, int argc, sqlite3_value **argv)
413 +{
414 + uuid_t uuid;
415 +
416 + if ( argc != 1 ){
417 + sqlite3_result_null(context);
418 + return ;
419 + }
420 + int rc = uuid_parse((const char *) sqlite3_value_text(argv[0]), uuid);
421 + if (rc == -1) {
422 + sqlite3_result_null(context);
423 + return ;
424 + }
425 +
426 + sqlite3_result_blob(context, &uuid, sizeof(uuid_t), SQLITE_TRANSIENT);
427 +}
428 +
429 +
430 /*
431 * Initialize the SQLite database
432 * Return 0 on success
@@ -527,6 +546,9 @@ int sql_init_database(db_check_action_type_t rebuild, int memory)
546 for (int i = 0; i < MAX_PREPARED_STATEMENTS; i++)
547 (void)pthread_key_create(&key_pool[i], release_statement);
548
549 + rc = sqlite3_create_function(db_meta, "u2h", 1, SQLITE_ANY | SQLITE_DETERMINISTIC, 0, _uuid_parse, 0, 0);
550 + if (unlikely(rc != SQLITE_OK))
551 + error_report("Failed to register internal u2h function");
552 return 0;
553 }
554
@@ -605,11 +627,11 @@ int find_dimension_uuid(RRDSET *st, RRDDIM *rd, uuid_t *store_uuid)
627 if (unlikely(rc != SQLITE_OK))
628 goto bind_fail;
629
608 - rc = sqlite3_bind_text(res, 2, rd->id, -1, SQLITE_STATIC);
630 + rc = sqlite3_bind_text(res, 2, rrddim_id(rd), -1, SQLITE_STATIC);
631 if (unlikely(rc != SQLITE_OK))
632 goto bind_fail;
633
612 - rc = sqlite3_bind_text(res, 3, rd->name, -1, SQLITE_STATIC);
634 + rc = sqlite3_bind_text(res, 3, rrddim_name(rd), -1, SQLITE_STATIC);
635 if (unlikely(rc != SQLITE_OK))
636 goto bind_fail;
637
@@ -620,7 +642,7 @@ int find_dimension_uuid(RRDSET *st, RRDDIM *rd, uuid_t *store_uuid)
642 }
643 else {
644 uuid_generate(*store_uuid);
623 - status = sql_store_dimension(store_uuid, st->chart_uuid, rd->id, rd->name, rd->multiplier, rd->divisor, rd->algorithm);
645 + status = sql_store_dimension(store_uuid, st->chart_uuid, rrddim_id(rd), rrddim_name(rd), rd->multiplier, rd->divisor, rd->algorithm);
646 if (unlikely(status))
647 error_report("Failed to store dimension metadata in the database");
648 }
@@ -745,8 +767,11 @@ int update_chart_metadata(uuid_t *chart_uuid, RRDSET *st, const char *id, const
767 return 0;
768
769 rc = sql_store_chart(
748 - chart_uuid, &st->rrdhost->host_uuid, st->type, id, name, st->family, st->context, st->title, st->units, st->plugin_name,
749 - st->module_name, st->priority, st->update_every, st->chart_type, st->rrd_memory_mode, st->entries);
770 + chart_uuid, &st->rrdhost->host_uuid, rrdset_type(st), id, name,
771 + rrdset_family(st), rrdset_context(st), rrdset_title(st), rrdset_units(st),
772 + rrdset_plugin_name(st), rrdset_module_name(st),
773 + st->priority, st->update_every, st->chart_type,
774 + st->rrd_memory_mode, st->entries);
775
776 return rc;
777 }
@@ -762,7 +787,7 @@ uuid_t *create_chart_uuid(RRDSET *st, const char *id, const char *name)
787 #ifdef NETDATA_INTERNAL_CHECKS
788 char uuid_str[GUID_LEN + 1];
789 uuid_unparse_lower(*uuid, uuid_str);
765 - debug(D_METADATALOG,"Generating uuid [%s] for chart %s under host %s", uuid_str, st->id, st->rrdhost->hostname);
790 + debug(D_METADATALOG,"Generating uuid [%s] for chart %s under host %s", uuid_str, rrdset_id(st), rrdhost_hostname(st->rrdhost));
791 #endif
792
793 rc = update_chart_metadata(uuid, st, id, name);
@@ -922,11 +947,11 @@ int sql_store_host_info(RRDHOST *host)
947 if (unlikely(rc != SQLITE_OK))
948 goto bind_fail;
949
925 - rc = bind_text_null(res, 2, host->hostname, 0);
950 + rc = bind_text_null(res, 2, rrdhost_hostname(host), 0);
951 if (unlikely(rc != SQLITE_OK))
952 goto bind_fail;
953
929 - rc = bind_text_null(res, 3, host->registry_hostname, 1);
954 + rc = bind_text_null(res, 3, rrdhost_registry_hostname(host), 1);
955 if (unlikely(rc != SQLITE_OK))
956 goto bind_fail;
957
@@ -934,15 +959,15 @@ int sql_store_host_info(RRDHOST *host)
959 if (unlikely(rc != SQLITE_OK))
960 goto bind_fail;
961
937 - rc = bind_text_null(res, 5, host->os, 1);
962 + rc = bind_text_null(res, 5, rrdhost_os(host), 1);
963 if (unlikely(rc != SQLITE_OK))
964 goto bind_fail;
965
941 - rc = bind_text_null(res, 6, host->timezone, 1);
966 + rc = bind_text_null(res, 6, rrdhost_timezone(host), 1);
967 if (unlikely(rc != SQLITE_OK))
968 goto bind_fail;
969
945 - rc = bind_text_null(res, 7, host->tags, 1);
970 + rc = bind_text_null(res, 7, rrdhost_tags(host), 1);
971 if (unlikely(rc != SQLITE_OK))
972 goto bind_fail;
973
@@ -954,7 +979,7 @@ int sql_store_host_info(RRDHOST *host)
979 if (unlikely(rc != SQLITE_OK))
980 goto bind_fail;
981
957 - rc = bind_text_null(res, 10, host->abbrev_timezone, 1);
982 + rc = bind_text_null(res, 10, rrdhost_abbrev_timezone(host), 1);
983 if (unlikely(rc != SQLITE_OK))
984 goto bind_fail;
985
@@ -962,11 +987,11 @@ int sql_store_host_info(RRDHOST *host)
987 if (unlikely(rc != SQLITE_OK))
988 goto bind_fail;
989
965 - rc = bind_text_null(res, 12, host->program_name, 1);
990 + rc = bind_text_null(res, 12, rrdhost_program_name(host), 1);
991 if (unlikely(rc != SQLITE_OK))
992 goto bind_fail;
993
969 - rc = bind_text_null(res, 13, host->program_version, 1);
994 + rc = bind_text_null(res, 13, rrdhost_program_version(host), 1);
995 if (unlikely(rc != SQLITE_OK))
996 goto bind_fail;
997
@@ -980,18 +1005,18 @@ int sql_store_host_info(RRDHOST *host)
1005
1006 int store_rc = sqlite3_step_monitored(res);
1007 if (unlikely(store_rc != SQLITE_DONE))
983 - error_report("Failed to store host %s, rc = %d", host->hostname, rc);
1008 + error_report("Failed to store host %s, rc = %d", rrdhost_hostname(host), rc);
1009
1010 rc = sqlite3_reset(res);
1011 if (unlikely(rc != SQLITE_OK))
987 - error_report("Failed to reset statement to store host %s, rc = %d", host->hostname, rc);
1012 + error_report("Failed to reset statement to store host %s, rc = %d", rrdhost_hostname(host), rc);
1013
1014 return !(store_rc == SQLITE_DONE);
1015 bind_fail:
991 - error_report("Failed to bind parameter to store host %s, rc = %d", host->hostname, rc);
1016 + error_report("Failed to bind parameter to store host %s, rc = %d", rrdhost_hostname(host), rc);
1017 rc = sqlite3_reset(res);
1018 if (unlikely(rc != SQLITE_OK))
994 - error_report("Failed to reset statement to store host %s, rc = %d", host->hostname, rc);
1019 + error_report("Failed to reset statement to store host %s, rc = %d", rrdhost_hostname(host), rc);
1020 return 1;
1021 }
1022
@@ -1315,11 +1340,11 @@ void sql_rrdset2json(RRDHOST *host, BUFFER *wb)
1340 ",\n\t\"memory_mode\": \"%s\""
1341 ",\n\t\"custom_info\": \"%s\""
1342 ",\n\t\"charts\": {"
1318 - , host->hostname
1319 - , host->program_version
1343 + , rrdhost_hostname(host)
1344 + , rrdhost_program_version(host)
1345 , get_release_channel()
1321 - , host->os
1322 - , host->timezone
1346 + , rrdhost_os(host)
1347 + , rrdhost_timezone(host)
1348 , host->rrd_update_every
1349 , host->rrd_history_entries
1350 , rrd_memory_mode_name(host->rrd_memory_mode)
@@ -1410,7 +1435,7 @@ void sql_rrdset2json(RRDHOST *host, BUFFER *wb)
1435 "\n\t\t\t\"hostname\": \"%s\""
1436 "\n\t\t}"
1437 , (found > 0) ? "," : ""
1413 - , h->hostname
1438 + , rrdhost_hostname(h)
1439 );
1440
1441 found++;
@@ -1424,7 +1449,7 @@ void sql_rrdset2json(RRDHOST *host, BUFFER *wb)
1449 , "\n\t\t{"
1450 "\n\t\t\t\"hostname\": \"%s\""
1451 "\n\t\t}"
1427 - , host->hostname
1452 + , rrdhost_hostname(host)
1453 );
1454 }
1455
@@ -1445,13 +1470,13 @@ failed:
1470 void free_temporary_host(RRDHOST *host)
1471 {
1472 if (host) {
1448 - freez(host->hostname);
1449 - freez((char *)host->os);
1450 - freez((char *)host->tags);
1451 - freez((char *)host->timezone);
1452 - freez(host->program_name);
1453 - freez(host->program_version);
1454 - freez(host->registry_hostname);
1473 + string_freez(host->hostname);
1474 + string_freez(host->os);
1475 + string_freez(host->tags);
1476 + string_freez(host->timezone);
1477 + string_freez(host->program_name);
1478 + string_freez(host->program_version);
1479 + string_freez(host->registry_hostname);
1480 freez(host->system_info);
1481 freez(host);
1482 }
@@ -1506,10 +1531,13 @@ RRDHOST *sql_create_host_by_uuid(char *hostname)
1531
1532 host = callocz(1, sizeof(RRDHOST));
1533
1509 - set_host_properties(host, sqlite3_column_int(res, 2), RRD_MEMORY_MODE_DBENGINE, hostname,
1510 - (char *) sqlite3_column_text(res, 1), (const char *) uuid_str,
1511 - (char *) sqlite3_column_text(res, 3), (char *) sqlite3_column_text(res, 5),
1512 - (char *) sqlite3_column_text(res, 4), NULL, 0, NULL, NULL);
1534 + set_host_properties(host, sqlite3_column_int(res, 2),
1535 + RRD_MEMORY_MODE_DBENGINE,
1536 + (char *) sqlite3_column_text(res, 1),
1537 + (char *) sqlite3_column_text(res, 3),
1538 + (char *) sqlite3_column_text(res, 5),
1539 + (char *) sqlite3_column_text(res, 4),
1540 + NULL, 0, NULL, NULL);
1541
1542 uuid_copy(host->host_uuid, *((uuid_t *) sqlite3_column_blob(res, 0)));
1543
@@ -1778,8 +1806,8 @@ static RRDDIM *create_rrdim_entry(ONEWAYALLOC *owa, RRDSET *st, char *id, char *
1806 rrddim_flag_set(rd, RRDDIM_FLAG_NONE);
1807
1808 uuid_copy(rd->metric_uuid, *metric_uuid);
1781 - rd->id = onewayalloc_strdupz(owa, id);
1782 - rd->name = onewayalloc_strdupz(owa, name);
1809 + rd->id = string_strdupz(id);
1810 + rd->name = string_strdupz(name);
1811
1812 for(int tier = 0; tier < storage_tiers ;tier++) {
1813 rd->tiers[tier] = onewayalloc_callocz(owa, 1, sizeof(*rd->tiers[tier]));
@@ -1869,8 +1897,9 @@ void sql_build_context_param_list(ONEWAYALLOC *owa, struct context_param **para
1897
1898 if (!st || uuid_compare(*(uuid_t *)sqlite3_column_blob(res, 7), chart_id)) {
1899 if (unlikely(st && !st->counter)) {
1872 - onewayalloc_freez(owa, st->context);
1873 - onewayalloc_freez(owa, (char *) st->name);
1900 + string_freez(st->context);
1901 + string_freez(st->name);
1902 + string_freez(st->id);
1903 onewayalloc_freez(owa, st);
1904 }
1905 st = onewayalloc_callocz(owa, 1, sizeof(*st));
@@ -1879,19 +1908,21 @@ void sql_build_context_param_list(ONEWAYALLOC *owa, struct context_param **para
1908 snprintfz(
1909 n, RRD_ID_LENGTH_MAX, "%s.%s", (char *)sqlite3_column_text(res, 4),
1910 (char *)sqlite3_column_text(res, 3));
1882 - st->name = onewayalloc_strdupz(owa, n);
1911 + st->name = string_strdupz(n);
1912 st->update_every = sqlite3_column_int(res, 6);
1913 st->counter = 0;
1914 if (chart) {
1886 - st->context = onewayalloc_strdupz(owa, (char *)sqlite3_column_text(res, 8));
1887 - strncpyz(st->id, chart, RRD_ID_LENGTH_MAX);
1888 - }
1915 + st->context = string_strdupz((char *)sqlite3_column_text(res, 8));
1916 + st->id = string_strdupz(chart);
1917 + } else
1918 + st->id = string_strdupz(n);
1919 +
1920 uuid_copy(chart_id, *(uuid_t *)sqlite3_column_blob(res, 7));
1921 st->last_entry_t = 0;
1922 st->rrdhost = host;
1923 }
1924
1894 - if (unlikely(find_dimension_first_last_t(machine_guid, (char *)st->name, (char *)sqlite3_column_text(res, 1),
1925 + if (unlikely(find_dimension_first_last_t(machine_guid, (char *)rrdset_name(st), (char *)sqlite3_column_text(res, 1),
1926 (uuid_t *)sqlite3_column_blob(res, 0), &(*param_list)->first_entry_t, &(*param_list)->last_entry_t,
1927 &rrdeng_uuid, 0)))
1928 continue;
@@ -1909,13 +1940,14 @@ void sql_build_context_param_list(ONEWAYALLOC *owa, struct context_param **para
1940 }
1941 if (st) {
1942 if (!st->counter) {
1912 - onewayalloc_freez(owa,st->context);
1913 - onewayalloc_freez(owa,(char *)st->name);
1943 + string_freez(st->context);
1944 + string_freez(st->name);
1945 + string_freez(st->id);
1946 onewayalloc_freez(owa,st);
1947 }
1948 else
1949 if (!st->context && context)
1918 - st->context = onewayalloc_strdupz(owa,context);
1950 + st->context = string_strdupz(context);
1951 }
1952
1953 failed:
@@ -2063,7 +2095,7 @@ void compute_chart_hash(RRDSET *st)
2095 char priority_str[32];
2096
2097 if (rrdhost_flag_check(st->rrdhost, RRDHOST_FLAG_ACLK_STREAM_CONTEXTS)) {
2066 - internal_error(true, "Skipping compute_chart_hash for host %s because context streaming is enabled", st->rrdhost->hostname);
2098 + internal_error(true, "Skipping compute_chart_hash for host %s because context streaming is enabled", rrdhost_hostname(st->rrdhost));
2099 return;
2100 }
2101
@@ -2072,15 +2104,14 @@ void compute_chart_hash(RRDSET *st)
2104 evpctx = EVP_MD_CTX_create();
2105 EVP_DigestInit_ex(evpctx, EVP_sha256(), NULL);
2106 //EVP_DigestUpdate(evpctx, st->type, strlen(st->type));
2075 - EVP_DigestUpdate(evpctx, st->id, strlen(st->id));
2076 - EVP_DigestUpdate(evpctx, st->name, strlen(st->name));
2077 - EVP_DigestUpdate(evpctx, st->family, strlen(st->family));
2078 - EVP_DigestUpdate(evpctx, st->context, strlen(st->context));
2079 - EVP_DigestUpdate(evpctx, st->title, strlen(st->title));
2080 - EVP_DigestUpdate(evpctx, st->units, strlen(st->units));
2081 - EVP_DigestUpdate(evpctx, st->plugin_name, strlen(st->plugin_name));
2082 - if (st->module_name)
2083 - EVP_DigestUpdate(evpctx, st->module_name, strlen(st->module_name));
2107 + EVP_DigestUpdate(evpctx, rrdset_id(st), string_strlen(st->id));
2108 + EVP_DigestUpdate(evpctx, rrdset_name(st), string_strlen(st->name));
2109 + EVP_DigestUpdate(evpctx, rrdset_family(st), string_strlen(st->family));
2110 + EVP_DigestUpdate(evpctx, rrdset_context(st), string_strlen(st->context));
2111 + EVP_DigestUpdate(evpctx, rrdset_title(st), string_strlen(st->title));
2112 + EVP_DigestUpdate(evpctx, rrdset_units(st), string_strlen(st->units));
2113 + EVP_DigestUpdate(evpctx, rrdset_plugin_name(st), string_strlen(st->plugin_name));
2114 + EVP_DigestUpdate(evpctx, rrdset_module_name(st), string_strlen(st->module_name));
2115 // EVP_DigestUpdate(evpctx, priority_str, strlen(priority_str));
2116 EVP_DigestUpdate(evpctx, &st->priority, sizeof(st->priority));
2117 EVP_DigestUpdate(evpctx, &st->chart_type, sizeof(st->chart_type));
@@ -2096,15 +2127,15 @@ void compute_chart_hash(RRDSET *st)
2127 (void)sql_store_chart_hash(
2128 (uuid_t *)&hash_value,
2129 st->chart_uuid,
2099 - st->type,
2100 - st->id,
2101 - st->name,
2102 - st->family,
2103 - st->context,
2104 - st->title,
2105 - st->units,
2106 - st->plugin_name,
2107 - st->module_name,
2130 + rrdset_type(st),
2131 + rrdset_id(st),
2132 + rrdset_name(st),
2133 + rrdset_family(st),
2134 + rrdset_context(st),
2135 + rrdset_title(st),
2136 + rrdset_units(st),
2137 + rrdset_plugin_name(st),
2138 + rrdset_module_name(st),
2139 st->priority,
2140 st->chart_type);
2141 #else
@@ -2224,7 +2255,7 @@ int update_node_id(uuid_t *host_id, uuid_t *node_id)
2255 char host_guid[GUID_LEN + 1];
2256 uuid_unparse_lower(*host_id, host_guid);
2257 rrd_wrlock();
2227 - host = rrdhost_find_by_guid(host_guid, 0);
2258 + host = rrdhost_find_by_guid(host_guid);
2259 if (likely(host))
2260 set_host_node_id(host, node_id);
2261 rrd_unlock();
@@ -2439,7 +2470,7 @@ struct node_instance_list *get_node_list(void)
2470 uuid_copy(node_list[row].host_id, *host_id);
2471 node_list[row].queryable = 1;
2472 uuid_unparse_lower(*host_id, host_guid);
2442 - RRDHOST *host = rrdhost_find_by_guid(host_guid, 0);
2473 + RRDHOST *host = rrdhost_find_by_guid(host_guid);
2474 node_list[row].live = host && (host == localhost || host->receiver) ? 1 : 0;
2475 node_list[row].hops = (host && host->system_info) ? host->system_info->hops :
2476 uuid_compare(*host_id, localhost->host_uuid) ? 1 : 0;
@@ -2677,7 +2708,7 @@ void sql_store_host_labels(RRDHOST *host)
2708 {
2709 int rc = exec_statement_with_uuid(SQL_DELETE_HOST_LABELS, &host->host_uuid);
2710 if (rc != SQLITE_OK)
2680 - error_report("Failed to remove old host labels for host %s", host->hostname);
2711 + error_report("Failed to remove old host labels for host %s", rrdhost_hostname(host));
2712
2713 rrdlabels_walkthrough_read(host->host_labels, save_host_label_callback, host);
2714 }
database/sqlite/sqlite_health.c
+94 -101
@@ -15,7 +15,7 @@ int sql_create_health_log_table(RRDHOST *host) {
15
16 if (unlikely(!db_meta)) {
17 if (default_rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE)
18 - error_report("HEALTH [%s]: Database has not been initialized", host->hostname);
18 + error_report("HEALTH [%s]: Database has not been initialized", rrdhost_hostname(host));
19 return 1;
20 }
21
@@ -26,7 +26,7 @@ int sql_create_health_log_table(RRDHOST *host) {
26
27 rc = sqlite3_exec_monitored(db_meta, command, 0, 0, &err_msg);
28 if (rc != SQLITE_OK) {
29 - error_report("HEALTH [%s]: SQLite error during creation of health log table, rc = %d (%s)", host->hostname, rc, err_msg);
29 + error_report("HEALTH [%s]: SQLite error during creation of health log table, rc = %d (%s)", rrdhost_hostname(host), rc, err_msg);
30 sqlite3_free(err_msg);
31 return 1;
32 }
@@ -49,7 +49,7 @@ void sql_health_alarm_log_update(RRDHOST *host, ALARM_ENTRY *ae) {
49
50 if (unlikely(!db_meta)) {
51 if (default_rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE)
52 - error_report("HEALTH [%s]: Database has not been initialized", host->hostname);
52 + error_report("HEALTH [%s]: Database has not been initialized", rrdhost_hostname(host));
53 return;
54 }
55
@@ -60,7 +60,7 @@ void sql_health_alarm_log_update(RRDHOST *host, ALARM_ENTRY *ae) {
60
61 rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0);
62 if (unlikely(rc != SQLITE_OK)) {
63 - error_report("HEALTH [%s]: Failed to prepare statement for SQL_UPDATE_HEALTH_LOG", host->hostname);
63 + error_report("HEALTH [%s]: Failed to prepare statement for SQL_UPDATE_HEALTH_LOG", rrdhost_hostname(host));
64 return;
65 }
66
@@ -96,12 +96,12 @@ void sql_health_alarm_log_update(RRDHOST *host, ALARM_ENTRY *ae) {
96
97 rc = execute_insert(res);
98 if (unlikely(rc != SQLITE_DONE)) {
99 - error_report("HEALTH [%s]: Failed to update health log, rc = %d", host->hostname, rc);
99 + error_report("HEALTH [%s]: Failed to update health log, rc = %d", rrdhost_hostname(host), rc);
100 }
101
102 failed:
103 if (unlikely(sqlite3_finalize(res) != SQLITE_OK))
104 - error_report("HEALTH [%s]: Failed to finalize the prepared statement for updating health log.", host->hostname);
104 + error_report("HEALTH [%s]: Failed to finalize the prepared statement for updating health log.", rrdhost_hostname(host));
105
106 return;
107 }
@@ -122,7 +122,7 @@ void sql_health_alarm_log_insert(RRDHOST *host, ALARM_ENTRY *ae) {
122
123 if (unlikely(!db_meta)) {
124 if (default_rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE)
125 - error_report("HEALTH [%s]: Database has not been initialized", host->hostname);
125 + error_report("HEALTH [%s]: Database has not been initialized", rrdhost_hostname(host));
126 return;
127 }
128
@@ -133,11 +133,11 @@ void sql_health_alarm_log_insert(RRDHOST *host, ALARM_ENTRY *ae) {
133
134 rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0);
135 if (unlikely(rc != SQLITE_OK)) {
136 - error_report("HEALTH [%s]: Failed to prepare statement for SQL_INSERT_HEALTH_LOG", host->hostname);
136 + error_report("HEALTH [%s]: Failed to prepare statement for SQL_INSERT_HEALTH_LOG", rrdhost_hostname(host));
137 return;
138 }
139
140 - rc = sqlite3_bind_text(res, 1, host->hostname, -1, SQLITE_STATIC);
140 + rc = sqlite3_bind_text(res, 1, rrdhost_hostname(host), -1, SQLITE_STATIC);
141 if (unlikely(rc != SQLITE_OK)) {
142 error_report("Failed to bind hostname parameter for SQL_INSERT_HEALTH_LOG");
143 goto failed;
@@ -215,49 +215,49 @@ void sql_health_alarm_log_insert(RRDHOST *host, ALARM_ENTRY *ae) {
215 goto failed;
216 }
217
218 - rc = sqlite3_bind_text(res, 14, ae->name, -1, SQLITE_STATIC);
218 + rc = sqlite3_bind_text(res, 14, ae_name(ae), -1, SQLITE_STATIC);
219 if (unlikely(rc != SQLITE_OK)) {
220 error_report("Failed to bind name parameter for SQL_INSERT_HEALTH_LOG");
221 goto failed;
222 }
223
224 - rc = sqlite3_bind_text(res, 15, ae->chart, -1, SQLITE_STATIC);
224 + rc = sqlite3_bind_text(res, 15, ae_chart_name(ae), -1, SQLITE_STATIC);
225 if (unlikely(rc != SQLITE_OK)) {
226 error_report("Failed to bind chart parameter for SQL_INSERT_HEALTH_LOG");
227 goto failed;
228 }
229
230 - rc = sqlite3_bind_text(res, 16, ae->family, -1, SQLITE_STATIC);
230 + rc = sqlite3_bind_text(res, 16, ae_family(ae), -1, SQLITE_STATIC);
231 if (unlikely(rc != SQLITE_OK)) {
232 error_report("Failed to bind family parameter for SQL_INSERT_HEALTH_LOG");
233 goto failed;
234 }
235
236 - rc = sqlite3_bind_text(res, 17, ae->exec, -1, SQLITE_STATIC);
236 + rc = sqlite3_bind_text(res, 17, ae_exec(ae), -1, SQLITE_STATIC);
237 if (unlikely(rc != SQLITE_OK)) {
238 error_report("Failed to bind exec parameter for SQL_INSERT_HEALTH_LOG");
239 goto failed;
240 }
241
242 - rc = sqlite3_bind_text(res, 18, ae->recipient, -1, SQLITE_STATIC);
242 + rc = sqlite3_bind_text(res, 18, ae_recipient(ae), -1, SQLITE_STATIC);
243 if (unlikely(rc != SQLITE_OK)) {
244 error_report("Failed to bind recipient parameter for SQL_INSERT_HEALTH_LOG");
245 goto failed;
246 }
247
248 - rc = sqlite3_bind_text(res, 19, ae->source, -1, SQLITE_STATIC);
248 + rc = sqlite3_bind_text(res, 19, ae_source(ae), -1, SQLITE_STATIC);
249 if (unlikely(rc != SQLITE_OK)) {
250 error_report("Failed to bind source parameter for SQL_INSERT_HEALTH_LOG");
251 goto failed;
252 }
253
254 - rc = sqlite3_bind_text(res, 20, ae->units, -1, SQLITE_STATIC);
254 + rc = sqlite3_bind_text(res, 20, ae_units(ae), -1, SQLITE_STATIC);
255 if (unlikely(rc != SQLITE_OK)) {
256 error_report("Failed to bind host_id parameter to store node instance information");
257 goto failed;
258 }
259
260 - rc = sqlite3_bind_text(res, 21, ae->info, -1, SQLITE_STATIC);
260 + rc = sqlite3_bind_text(res, 21, ae_info(ae), -1, SQLITE_STATIC);
261 if (unlikely(rc != SQLITE_OK)) {
262 error_report("Failed to bind info parameter for SQL_INSERT_HEALTH_LOG");
263 goto failed;
@@ -305,25 +305,25 @@ void sql_health_alarm_log_insert(RRDHOST *host, ALARM_ENTRY *ae) {
305 goto failed;
306 }
307
308 - rc = sqlite3_bind_text(res, 29, ae->classification, -1, SQLITE_STATIC);
308 + rc = sqlite3_bind_text(res, 29, ae_classification(ae), -1, SQLITE_STATIC);
309 if (unlikely(rc != SQLITE_OK)) {
310 error_report("Failed to bind classification parameter for SQL_INSERT_HEALTH_LOG");
311 goto failed;
312 }
313
314 - rc = sqlite3_bind_text(res, 30, ae->component, -1, SQLITE_STATIC);
314 + rc = sqlite3_bind_text(res, 30, ae_component(ae), -1, SQLITE_STATIC);
315 if (unlikely(rc != SQLITE_OK)) {
316 error_report("Failed to bind component parameter for SQL_INSERT_HEALTH_LOG");
317 goto failed;
318 }
319
320 - rc = sqlite3_bind_text(res, 31, ae->type, -1, SQLITE_STATIC);
320 + rc = sqlite3_bind_text(res, 31, ae_type(ae), -1, SQLITE_STATIC);
321 if (unlikely(rc != SQLITE_OK)) {
322 error_report("Failed to bind type parameter for SQL_INSERT_HEALTH_LOG");
323 goto failed;
324 }
325
326 - rc = sqlite3_bind_text(res, 32, ae->chart_context, -1, SQLITE_STATIC);
326 + rc = sqlite3_bind_text(res, 32, ae_chart_context(ae), -1, SQLITE_STATIC);
327 if (unlikely(rc != SQLITE_OK)) {
328 error_report("Failed to bind chart_context parameter for SQL_INSERT_HEALTH_LOG");
329 goto failed;
@@ -331,7 +331,7 @@ void sql_health_alarm_log_insert(RRDHOST *host, ALARM_ENTRY *ae) {
331
332 rc = execute_insert(res);
333 if (unlikely(rc != SQLITE_DONE)) {
334 - error_report("HEALTH [%s]: Failed to execute SQL_INSERT_HEALTH_LOG, rc = %d", host->hostname, rc);
334 + error_report("HEALTH [%s]: Failed to execute SQL_INSERT_HEALTH_LOG, rc = %d", rrdhost_hostname(host), rc);
335 goto failed;
336 }
337
@@ -340,7 +340,7 @@ void sql_health_alarm_log_insert(RRDHOST *host, ALARM_ENTRY *ae) {
340
341 failed:
342 if (unlikely(sqlite3_finalize(res) != SQLITE_OK))
343 - error_report("HEALTH [%s]: Failed to finalize the prepared statement for inserting to health log.", host->hostname);
343 + error_report("HEALTH [%s]: Failed to finalize the prepared statement for inserting to health log.", rrdhost_hostname(host));
344
345 return;
346 }
@@ -436,7 +436,7 @@ void sql_health_alarm_log_count(RRDHOST *host) {
436 if (unlikely(rc != SQLITE_OK))
437 error_report("Failed to finalize the prepared statement to count health log entries from db");
438
439 - info("HEALTH [%s]: Table health_log_%s, contains %lu entries.", host->hostname, uuid_str, host->health_log_entries_written);
439 + info("HEALTH [%s]: Table health_log_%s, contains %lu entries.", rrdhost_hostname(host), uuid_str, host->health_log_entries_written);
440 }
441
442 #define SQL_INJECT_REMOVED(guid, guid2) "insert into health_log_%s (hostname, unique_id, alarm_id, alarm_event_id, config_hash_id, updated_by_id, updates_id, when_key, duration, non_clear_duration, flags, exec_run_timestamp, " \
@@ -607,7 +607,7 @@ void sql_check_removed_alerts_state(char *uuid_str)
607 #define SQL_LOAD_HEALTH_LOG(guid,limit) "SELECT hostname, unique_id, alarm_id, alarm_event_id, config_hash_id, updated_by_id, updates_id, when_key, duration, non_clear_duration, flags, exec_run_timestamp, delay_up_to_timestamp, name, chart, family, exec, recipient, source, units, info, exec_code, new_status, old_status, delay, new_value, old_value, last_repeat, class, component, type, chart_context FROM (SELECT hostname, unique_id, alarm_id, alarm_event_id, config_hash_id, updated_by_id, updates_id, when_key, duration, non_clear_duration, flags, exec_run_timestamp, delay_up_to_timestamp, name, chart, family, exec, recipient, source, units, info, exec_code, new_status, old_status, delay, new_value, old_value, last_repeat, class, component, type, chart_context FROM health_log_%s order by unique_id desc limit %u) order by unique_id asc;", guid, limit
608 void sql_health_alarm_log_load(RRDHOST *host) {
609 sqlite3_stmt *res = NULL;
610 - int rc;
610 + int ret;
611 ssize_t errored = 0, loaded = 0;
612 char command[MAX_HEALTH_SQL_SIZE + 1];
613
@@ -615,7 +615,7 @@ void sql_health_alarm_log_load(RRDHOST *host) {
615
616 if (unlikely(!db_meta)) {
617 if (default_rrd_memory_mode == RRD_MEMORY_MODE_DBENGINE)
618 - error_report("HEALTH [%s]: Database has not been initialized", host->hostname);
618 + error_report("HEALTH [%s]: Database has not been initialized", rrdhost_hostname(host));
619 return;
620 }
621
@@ -626,47 +626,52 @@ void sql_health_alarm_log_load(RRDHOST *host) {
626
627 snprintfz(command, MAX_HEALTH_SQL_SIZE, SQL_LOAD_HEALTH_LOG(uuid_str, host->health_log.max));
628
629 - rc = sqlite3_prepare_v2(db_meta, command, -1, &res, 0);
630 - if (unlikely(rc != SQLITE_OK)) {
631 - error_report("HEALTH [%s]: Failed to prepare sql statement to load health log.", host->hostname);
629 + ret = sqlite3_prepare_v2(db_meta, command, -1, &res, 0);
630 + if (unlikely(ret != SQLITE_OK)) {
631 + error_report("HEALTH [%s]: Failed to prepare sql statement to load health log.", rrdhost_hostname(host));
632 return;
633 }
634
635 netdata_rwlock_rdlock(&host->health_log.alarm_log_rwlock);
636
637 + DICTIONARY *all_rrdcalcs = dictionary_create(DICTIONARY_FLAG_NAME_LINK_DONT_CLONE|DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE|DICTIONARY_FLAG_DONT_OVERWRITE_VALUE);
638 + RRDCALC *rc;
639 + foreach_rrdcalc_in_rrdhost(host, rc)
640 + dictionary_set(all_rrdcalcs, rrdcalc_name(rc), rc, sizeof(*rc));
641 +
642 while (sqlite3_step_monitored(res) == SQLITE_ROW) {
643 ALARM_ENTRY *ae = NULL;
644
645 // check that we have valid ids
646 uint32_t unique_id = (uint32_t) sqlite3_column_int64(res, 1);
647 if(!unique_id) {
643 - error_report("HEALTH [%s]: Got invalid unique id. Ignoring it.", host->hostname);
648 + error_report("HEALTH [%s]: Got invalid unique id. Ignoring it.", rrdhost_hostname(host));
649 errored++;
650 continue;
651 }
652
653 uint32_t alarm_id = (uint32_t) sqlite3_column_int64(res, 2);
654 if(!alarm_id) {
650 - error_report("HEALTH [%s]: Got invalid alarm id. Ignoring it.", host->hostname);
655 + error_report("HEALTH [%s]: Got invalid alarm id. Ignoring it.", rrdhost_hostname(host));
656 errored++;
657 continue;
658 }
659
660 //need name, chart and family
661 if (sqlite3_column_type(res, 13) == SQLITE_NULL) {
657 - error_report("HEALTH [%s]: Got null name field. Ignoring it.", host->hostname);
662 + error_report("HEALTH [%s]: Got null name field. Ignoring it.", rrdhost_hostname(host));
663 errored++;
664 continue;
665 }
666
667 if (sqlite3_column_type(res, 14) == SQLITE_NULL) {
663 - error_report("HEALTH [%s]: Got null chart field. Ignoring it.", host->hostname);
668 + error_report("HEALTH [%s]: Got null chart field. Ignoring it.", rrdhost_hostname(host));
669 errored++;
670 continue;
671 }
672
673 if (sqlite3_column_type(res, 15) == SQLITE_NULL) {
669 - error_report("HEALTH [%s]: Got null family field. Ignoring it.", host->hostname);
674 + error_report("HEALTH [%s]: Got null family field. Ignoring it.", rrdhost_hostname(host));
675 errored++;
676 continue;
677 }
@@ -675,18 +680,7 @@ void sql_health_alarm_log_load(RRDHOST *host) {
680 time_t last_repeat = 0;
681 last_repeat = (time_t)sqlite3_column_int64(res, 27);
682
678 - RRDCALC *rc = alarm_max_last_repeat(host, (char *) sqlite3_column_text(res, 14), simple_hash((char *) sqlite3_column_text(res, 14)));
679 - if (!rc) {
680 - for(rc = host->alarms; rc ; rc = rc->next) {
681 - RRDCALC *rdcmp = (RRDCALC *) avl_insert_lock(&(host)->alarms_idx_name, (avl_t *)rc);
682 - if(rdcmp != rc) {
683 - error("Cannot insert the alarm index ID using log %s", rc->name);
684 - }
685 - }
686 -
687 - rc = alarm_max_last_repeat(host, (char *) sqlite3_column_text(res, 14), simple_hash((char *) sqlite3_column_text(res, 14)));
688 - }
689 -
683 + rc = dictionary_get(all_rrdcalcs, (char *) sqlite3_column_text(res, 14));
684 if(unlikely(rc)) {
685 if (rrdcalc_isrepeating(rc)) {
686 rc->last_repeat = last_repeat;
@@ -719,36 +713,32 @@ void sql_health_alarm_log_load(RRDHOST *host) {
713 ae->exec_run_timestamp = (time_t) sqlite3_column_int64(res, 11);
714 ae->delay_up_to_timestamp = (time_t) sqlite3_column_int64(res, 12);
715
722 - ae->name = strdupz((char *) sqlite3_column_text(res, 13));
723 - ae->hash_name = simple_hash(ae->name);
724 -
725 - ae->chart = strdupz((char *) sqlite3_column_text(res, 14));
726 - ae->hash_chart = simple_hash(ae->chart);
727 -
728 - ae->family = strdupz((char *) sqlite3_column_text(res, 15));
716 + ae->name = string_strdupz((char *) sqlite3_column_text(res, 13));
717 + ae->chart = string_strdupz((char *) sqlite3_column_text(res, 14));
718 + ae->family = string_strdupz((char *) sqlite3_column_text(res, 15));
719
720 if (sqlite3_column_type(res, 16) != SQLITE_NULL)
731 - ae->exec = strdupz((char *) sqlite3_column_text(res, 16));
721 + ae->exec = string_strdupz((char *) sqlite3_column_text(res, 16));
722 else
723 ae->exec = NULL;
724
725 if (sqlite3_column_type(res, 17) != SQLITE_NULL)
736 - ae->recipient = strdupz((char *) sqlite3_column_text(res, 17));
726 + ae->recipient = string_strdupz((char *) sqlite3_column_text(res, 17));
727 else
728 ae->recipient = NULL;
729
730 if (sqlite3_column_type(res, 18) != SQLITE_NULL)
741 - ae->source = strdupz((char *) sqlite3_column_text(res, 18));
731 + ae->source = string_strdupz((char *) sqlite3_column_text(res, 18));
732 else
733 ae->source = NULL;
734
735 if (sqlite3_column_type(res, 19) != SQLITE_NULL)
746 - ae->units = strdupz((char *) sqlite3_column_text(res, 19));
736 + ae->units = string_strdupz((char *) sqlite3_column_text(res, 19));
737 else
738 ae->units = NULL;
739
740 if (sqlite3_column_type(res, 20) != SQLITE_NULL)
751 - ae->info = strdupz((char *) sqlite3_column_text(res, 20));
741 + ae->info = string_strdupz((char *) sqlite3_column_text(res, 20));
742 else
743 ae->info = NULL;
744
@@ -763,30 +753,30 @@ void sql_health_alarm_log_load(RRDHOST *host) {
753 ae->last_repeat = last_repeat;
754
755 if (sqlite3_column_type(res, 28) != SQLITE_NULL)
766 - ae->classification = strdupz((char *) sqlite3_column_text(res, 28));
756 + ae->classification = string_strdupz((char *) sqlite3_column_text(res, 28));
757 else
758 ae->classification = NULL;
759
760 if (sqlite3_column_type(res, 29) != SQLITE_NULL)
771 - ae->component = strdupz((char *) sqlite3_column_text(res, 29));
761 + ae->component = string_strdupz((char *) sqlite3_column_text(res, 29));
762 else
763 ae->component = NULL;
764
765 if (sqlite3_column_type(res, 30) != SQLITE_NULL)
776 - ae->type = strdupz((char *) sqlite3_column_text(res, 30));
766 + ae->type = string_strdupz((char *) sqlite3_column_text(res, 30));
767 else
768 ae->type = NULL;
769
770 if (sqlite3_column_type(res, 31) != SQLITE_NULL)
781 - ae->chart_context = strdupz((char *) sqlite3_column_text(res, 31));
771 + ae->chart_context = string_strdupz((char *) sqlite3_column_text(res, 31));
772 else
773 ae->chart_context = NULL;
774
775 char value_string[100 + 1];
786 - freez(ae->old_value_string);
787 - freez(ae->new_value_string);
788 - ae->old_value_string = strdupz(format_value_and_unit(value_string, 100, ae->old_value, ae->units, -1));
789 - ae->new_value_string = strdupz(format_value_and_unit(value_string, 100, ae->new_value, ae->units, -1));
776 + string_freez(ae->old_value_string);
777 + string_freez(ae->new_value_string);
778 + ae->old_value_string = string_strdupz(format_value_and_unit(value_string, 100, ae->old_value, ae_units(ae), -1));
779 + ae->new_value_string = string_strdupz(format_value_and_unit(value_string, 100, ae->new_value, ae_units(ae), -1));
780
781 ae->next = host->health_log.alarms;
782 host->health_log.alarms = ae;
@@ -800,6 +790,9 @@ void sql_health_alarm_log_load(RRDHOST *host) {
790 loaded++;
791 }
792
793 + dictionary_destroy(all_rrdcalcs);
794 + all_rrdcalcs = NULL;
795 +
796 netdata_rwlock_unlock(&host->health_log.alarm_log_rwlock);
797
798 if(!host->health_max_unique_id) host->health_max_unique_id = (uint32_t)now_realtime_sec();
@@ -809,10 +802,10 @@ void sql_health_alarm_log_load(RRDHOST *host) {
802 if (unlikely(!host->health_log.next_alarm_id || host->health_log.next_alarm_id <= host->health_max_alarm_id))
803 host->health_log.next_alarm_id = host->health_max_alarm_id + 1;
804
812 - info("HEALTH [%s]: Table health_log_%s, loaded %zd alarm entries, errors in %zd entries.", host->hostname, uuid_str, loaded, errored);
805 + info("HEALTH [%s]: Table health_log_%s, loaded %zd alarm entries, errors in %zd entries.", rrdhost_hostname(host), uuid_str, loaded, errored);
806
814 - rc = sqlite3_finalize(res);
815 - if (unlikely(rc != SQLITE_OK))
807 + ret = sqlite3_finalize(res);
808 + if (unlikely(ret != SQLITE_OK))
809 error_report("Failed to finalize the health log read statement");
810
811 sql_health_alarm_log_count(host);
@@ -854,154 +847,154 @@ int sql_store_alert_config_hash(uuid_t *hash_id, struct alert_config *cfg)
847 goto bind_fail;
848
849 param++;
857 - if (cfg->alarm && *cfg->alarm)
858 - rc = sqlite3_bind_text(res, 2, cfg->alarm, -1, SQLITE_STATIC);
850 + if (cfg->alarm)
851 + rc = sqlite3_bind_text(res, 2, string2str(cfg->alarm), -1, SQLITE_STATIC);
852 else
853 rc = sqlite3_bind_null(res, 2);
854 if (unlikely(rc != SQLITE_OK))
855 goto bind_fail;
856
857 param++;
865 - if (cfg->template_key && *cfg->template_key)
866 - rc = sqlite3_bind_text(res, 3, cfg->template_key, -1, SQLITE_STATIC);
858 + if (cfg->template_key)
859 + rc = sqlite3_bind_text(res, 3, string2str(cfg->template_key), -1, SQLITE_STATIC);
860 else
861 rc = sqlite3_bind_null(res, 3);
862 if (unlikely(rc != SQLITE_OK))
863 goto bind_fail;
864
865 param++;
873 - rc = sqlite3_bind_text(res, 4, cfg->on, -1, SQLITE_STATIC);
866 + rc = sqlite3_bind_text(res, 4, string2str(cfg->on), -1, SQLITE_STATIC);
867 if (unlikely(rc != SQLITE_OK))
868 goto bind_fail;
869
870 param++;
878 - rc = sqlite3_bind_text(res, 5, cfg->classification, -1, SQLITE_STATIC);
871 + rc = sqlite3_bind_text(res, 5, string2str(cfg->classification), -1, SQLITE_STATIC);
872 if (unlikely(rc != SQLITE_OK))
873 goto bind_fail;
874
875 param++;
883 - rc = sqlite3_bind_text(res, 6, cfg->component, -1, SQLITE_STATIC);
876 + rc = sqlite3_bind_text(res, 6, string2str(cfg->component), -1, SQLITE_STATIC);
877 if (unlikely(rc != SQLITE_OK))
878 goto bind_fail;
879
880 param++;
888 - rc = sqlite3_bind_text(res, 7, cfg->type, -1, SQLITE_STATIC);
881 + rc = sqlite3_bind_text(res, 7, string2str(cfg->type), -1, SQLITE_STATIC);
882 if (unlikely(rc != SQLITE_OK))
883 goto bind_fail;
884
885 param++;
893 - rc = sqlite3_bind_text(res, 8, cfg->os, -1, SQLITE_STATIC);
886 + rc = sqlite3_bind_text(res, 8, string2str(cfg->os), -1, SQLITE_STATIC);
887 if (unlikely(rc != SQLITE_OK))
888 goto bind_fail;
889
890 param++;
898 - rc = sqlite3_bind_text(res, 9, cfg->host, -1, SQLITE_STATIC);
891 + rc = sqlite3_bind_text(res, 9, string2str(cfg->host), -1, SQLITE_STATIC);
892 if (unlikely(rc != SQLITE_OK))
893 goto bind_fail;
894
895 param++;
903 - rc = sqlite3_bind_text(res, 10, cfg->lookup, -1, SQLITE_STATIC);
896 + rc = sqlite3_bind_text(res, 10, string2str(cfg->lookup), -1, SQLITE_STATIC);
897 if (unlikely(rc != SQLITE_OK))
898 goto bind_fail;
899
900 param++;
908 - rc = sqlite3_bind_text(res, 11, cfg->every, -1, SQLITE_STATIC);
901 + rc = sqlite3_bind_text(res, 11, string2str(cfg->every), -1, SQLITE_STATIC);
902 if (unlikely(rc != SQLITE_OK))
903 goto bind_fail;
904
905 param++;
913 - rc = sqlite3_bind_text(res, 12, cfg->units, -1, SQLITE_STATIC);
906 + rc = sqlite3_bind_text(res, 12, string2str(cfg->units), -1, SQLITE_STATIC);
907 if (unlikely(rc != SQLITE_OK))
908 goto bind_fail;
909
910 param++;
918 - rc = sqlite3_bind_text(res, 13, cfg->calc, -1, SQLITE_STATIC);
911 + rc = sqlite3_bind_text(res, 13, string2str(cfg->calc), -1, SQLITE_STATIC);
912 if (unlikely(rc != SQLITE_OK))
913 goto bind_fail;
914
915 param++;
923 - rc = sqlite3_bind_text(res, 14, cfg->families, -1, SQLITE_STATIC);
916 + rc = sqlite3_bind_text(res, 14, string2str(cfg->families), -1, SQLITE_STATIC);
917 if (unlikely(rc != SQLITE_OK))
918 goto bind_fail;
919
920 param++;
928 - rc = sqlite3_bind_text(res, 15, cfg->plugin, -1, SQLITE_STATIC);
921 + rc = sqlite3_bind_text(res, 15, string2str(cfg->plugin), -1, SQLITE_STATIC);
922 if (unlikely(rc != SQLITE_OK))
923 goto bind_fail;
924
925 param++;
933 - rc = sqlite3_bind_text(res, 16, cfg->module, -1, SQLITE_STATIC);
926 + rc = sqlite3_bind_text(res, 16, string2str(cfg->module), -1, SQLITE_STATIC);
927 if (unlikely(rc != SQLITE_OK))
928 goto bind_fail;
929
930 param++;
938 - rc = sqlite3_bind_text(res, 17, cfg->charts, -1, SQLITE_STATIC);
931 + rc = sqlite3_bind_text(res, 17, string2str(cfg->charts), -1, SQLITE_STATIC);
932 if (unlikely(rc != SQLITE_OK))
933 goto bind_fail;
934
935 param++;
943 - rc = sqlite3_bind_text(res, 18, cfg->green, -1, SQLITE_STATIC);
936 + rc = sqlite3_bind_text(res, 18, string2str(cfg->green), -1, SQLITE_STATIC);
937 if (unlikely(rc != SQLITE_OK))
938 goto bind_fail;
939
940 param++;
948 - rc = sqlite3_bind_text(res, 19, cfg->red, -1, SQLITE_STATIC);
941 + rc = sqlite3_bind_text(res, 19, string2str(cfg->red), -1, SQLITE_STATIC);
942 if (unlikely(rc != SQLITE_OK))
943 goto bind_fail;
944
945 param++;
953 - rc = sqlite3_bind_text(res, 20, cfg->warn, -1, SQLITE_STATIC);
946 + rc = sqlite3_bind_text(res, 20, string2str(cfg->warn), -1, SQLITE_STATIC);
947 if (unlikely(rc != SQLITE_OK))
948 goto bind_fail;
949
950 param++;
958 - rc = sqlite3_bind_text(res, 21, cfg->crit, -1, SQLITE_STATIC);
951 + rc = sqlite3_bind_text(res, 21, string2str(cfg->crit), -1, SQLITE_STATIC);
952 if (unlikely(rc != SQLITE_OK))
953 goto bind_fail;
954
955 param++;
963 - rc = sqlite3_bind_text(res, 22, cfg->exec, -1, SQLITE_STATIC);
956 + rc = sqlite3_bind_text(res, 22, string2str(cfg->exec), -1, SQLITE_STATIC);
957 if (unlikely(rc != SQLITE_OK))
958 goto bind_fail;
959
960 param++;
968 - rc = sqlite3_bind_text(res, 23, cfg->to, -1, SQLITE_STATIC);
961 + rc = sqlite3_bind_text(res, 23, string2str(cfg->to), -1, SQLITE_STATIC);
962 if (unlikely(rc != SQLITE_OK))
963 goto bind_fail;
964
965 param++;
973 - rc = sqlite3_bind_text(res, 24, cfg->info, -1, SQLITE_STATIC);
966 + rc = sqlite3_bind_text(res, 24, string2str(cfg->info), -1, SQLITE_STATIC);
967 if (unlikely(rc != SQLITE_OK))
968 goto bind_fail;
969
970 param++;
978 - rc = sqlite3_bind_text(res, 25, cfg->delay, -1, SQLITE_STATIC);
971 + rc = sqlite3_bind_text(res, 25, string2str(cfg->delay), -1, SQLITE_STATIC);
972 if (unlikely(rc != SQLITE_OK))
973 goto bind_fail;
974
975 param++;
983 - rc = sqlite3_bind_text(res, 26, cfg->options, -1, SQLITE_STATIC);
976 + rc = sqlite3_bind_text(res, 26, string2str(cfg->options), -1, SQLITE_STATIC);
977 if (unlikely(rc != SQLITE_OK))
978 goto bind_fail;
979
980 param++;
988 - rc = sqlite3_bind_text(res, 27, cfg->repeat, -1, SQLITE_STATIC);
981 + rc = sqlite3_bind_text(res, 27, string2str(cfg->repeat), -1, SQLITE_STATIC);
982 if (unlikely(rc != SQLITE_OK))
983 goto bind_fail;
984
985 param++;
993 - rc = sqlite3_bind_text(res, 28, cfg->host_labels, -1, SQLITE_STATIC);
986 + rc = sqlite3_bind_text(res, 28, string2str(cfg->host_labels), -1, SQLITE_STATIC);
987 if (unlikely(rc != SQLITE_OK))
988 goto bind_fail;
989
990 if (cfg->p_db_lookup_after) {
991 param++;
999 - rc = sqlite3_bind_text(res, 29, cfg->p_db_lookup_dimensions, -1, SQLITE_STATIC);
992 + rc = sqlite3_bind_text(res, 29, string2str(cfg->p_db_lookup_dimensions), -1, SQLITE_STATIC);
993 if (unlikely(rc != SQLITE_OK))
994 goto bind_fail;
995
996 param++;
1004 - rc = sqlite3_bind_text(res, 30, cfg->p_db_lookup_method, -1, SQLITE_STATIC);
997 + rc = sqlite3_bind_text(res, 30, string2str(cfg->p_db_lookup_method), -1, SQLITE_STATIC);
998 if (unlikely(rc != SQLITE_OK))
999 goto bind_fail;
1000
@@ -1071,7 +1064,7 @@ int sql_store_alert_config_hash(uuid_t *hash_id, struct alert_config *cfg)
1064 skip hash calculations
1065 */
1066 #if !defined DISABLE_CLOUD && defined ENABLE_HTTPS
1074 -#define DIGEST_ALERT_CONFIG_VAL(v) ((v) ? EVP_DigestUpdate(evpctx, (v), strlen((v))) : EVP_DigestUpdate(evpctx, "", 1))
1067 +#define DIGEST_ALERT_CONFIG_VAL(v) EVP_DigestUpdate(evpctx, (string2str(v)), string_strlen(v))
1068 #endif
1069 int alert_hash_and_store_config(
1070 uuid_t hash_id,
exporting/check_filters.c
+5 -5
@@ -25,7 +25,7 @@ int rrdhost_is_exportable(struct instance *instance, RRDHOST *host)
25 RRDHOST_FLAGS *flags = &host->exporting_flags[instance->index];
26
27 if (unlikely((*flags & (RRDHOST_FLAG_EXPORTING_SEND | RRDHOST_FLAG_EXPORTING_DONT_SEND)) == 0)) {
28 - char *host_name = (host == localhost) ? "localhost" : host->hostname;
28 + const char *host_name = (host == localhost) ? "localhost" : rrdhost_hostname(host);
29
30 if (!instance->config.hosts_pattern || simple_pattern_matches(instance->config.hosts_pattern, host_name)) {
31 *flags |= RRDHOST_FLAG_EXPORTING_SEND;
@@ -69,22 +69,22 @@ int rrdset_is_exportable(struct instance *instance, RRDSET *st)
69
70 if(unlikely(!(*flags & RRDSET_FLAG_EXPORTING_SEND))) {
71 // we have not checked this chart
72 - if(simple_pattern_matches(instance->config.charts_pattern, st->id) || simple_pattern_matches(instance->config.charts_pattern, st->name))
72 + if(simple_pattern_matches(instance->config.charts_pattern, rrdset_id(st)) || simple_pattern_matches(instance->config.charts_pattern, rrdset_name(st)))
73 *flags |= RRDSET_FLAG_EXPORTING_SEND;
74 else {
75 *flags |= RRDSET_FLAG_EXPORTING_IGNORE;
76 - debug(D_EXPORTING, "EXPORTING: not sending chart '%s' of host '%s', because it is disabled for exporting.", st->id, host->hostname);
76 + debug(D_EXPORTING, "EXPORTING: not sending chart '%s' of host '%s', because it is disabled for exporting.", rrdset_id(st), rrdhost_hostname(host));
77 return 0;
78 }
79 }
80
81 if(unlikely(!rrdset_is_available_for_exporting_and_alarms(st))) {
82 - debug(D_EXPORTING, "EXPORTING: not sending chart '%s' of host '%s', because it is not available for exporting.", st->id, host->hostname);
82 + debug(D_EXPORTING, "EXPORTING: not sending chart '%s' of host '%s', because it is not available for exporting.", rrdset_id(st), rrdhost_hostname(host));
83 return 0;
84 }
85
86 if(unlikely(st->rrd_memory_mode == RRD_MEMORY_MODE_NONE && !(EXPORTING_OPTIONS_DATA_SOURCE(instance->config.options) == EXPORTING_SOURCE_DATA_AS_COLLECTED))) {
87 - debug(D_EXPORTING, "EXPORTING: not sending chart '%s' of host '%s' because its memory mode is '%s' and the exporting engine requires database access.", st->id, host->hostname, rrd_memory_mode_name(host->rrd_memory_mode));
87 + debug(D_EXPORTING, "EXPORTING: not sending chart '%s' of host '%s' because its memory mode is '%s' and the exporting engine requires database access.", rrdset_id(st), rrdhost_hostname(host), rrd_memory_mode_name(host->rrd_memory_mode));
88 return 0;
89 }
90
exporting/graphite/graphite.c
+8 -8
@@ -123,24 +123,24 @@ int format_dimension_collected_graphite_plaintext(struct instance *instance, RRD
123 char chart_name[RRD_ID_LENGTH_MAX + 1];
124 exporting_name_copy(
125 chart_name,
126 - (instance->config.options & EXPORTING_OPTION_SEND_NAMES && st->name) ? st->name : st->id,
126 + (instance->config.options & EXPORTING_OPTION_SEND_NAMES && st->name) ? rrdset_name(st) : rrdset_id(st),
127 RRD_ID_LENGTH_MAX);
128
129 char dimension_name[RRD_ID_LENGTH_MAX + 1];
130 exporting_name_copy(
131 dimension_name,
132 - (instance->config.options & EXPORTING_OPTION_SEND_NAMES && rd->name) ? rd->name : rd->id,
132 + (instance->config.options & EXPORTING_OPTION_SEND_NAMES && rd->name) ? rrddim_name(rd) : rrddim_id(rd),
133 RRD_ID_LENGTH_MAX);
134
135 buffer_sprintf(
136 instance->buffer,
137 "%s.%s.%s.%s%s%s%s " COLLECTED_NUMBER_FORMAT " %llu\n",
138 instance->config.prefix,
139 - (host == localhost) ? instance->config.hostname : host->hostname,
139 + (host == localhost) ? instance->config.hostname : rrdhost_hostname(host),
140 chart_name,
141 dimension_name,
142 (host->tags) ? ";" : "",
143 - (host->tags) ? host->tags : "",
143 + (host->tags) ? rrdhost_tags(host) : "",
144 (instance->labels_buffer) ? buffer_tostring(instance->labels_buffer) : "",
145 rd->last_collected_value,
146 (unsigned long long)rd->last_collected_time.tv_sec);
@@ -163,13 +163,13 @@ int format_dimension_stored_graphite_plaintext(struct instance *instance, RRDDIM
163 char chart_name[RRD_ID_LENGTH_MAX + 1];
164 exporting_name_copy(
165 chart_name,
166 - (instance->config.options & EXPORTING_OPTION_SEND_NAMES && st->name) ? st->name : st->id,
166 + (instance->config.options & EXPORTING_OPTION_SEND_NAMES && st->name) ? rrdset_name(st) : rrdset_id(st),
167 RRD_ID_LENGTH_MAX);
168
169 char dimension_name[RRD_ID_LENGTH_MAX + 1];
170 exporting_name_copy(
171 dimension_name,
172 - (instance->config.options & EXPORTING_OPTION_SEND_NAMES && rd->name) ? rd->name : rd->id,
172 + (instance->config.options & EXPORTING_OPTION_SEND_NAMES && rd->name) ? rrddim_name(rd) : rrddim_id(rd),
173 RRD_ID_LENGTH_MAX);
174
175 time_t last_t;
@@ -182,11 +182,11 @@ int format_dimension_stored_graphite_plaintext(struct instance *instance, RRDDIM
182 instance->buffer,
183 "%s.%s.%s.%s%s%s%s " NETDATA_DOUBLE_FORMAT " %llu\n",
184 instance->config.prefix,
185 - (host == localhost) ? instance->config.hostname : host->hostname,
185 + (host == localhost) ? instance->config.hostname : rrdhost_hostname(host),
186 chart_name,
187 dimension_name,
188 (host->tags) ? ";" : "",
189 - (host->tags) ? host->tags : "",
189 + (host->tags) ? rrdhost_tags(host) : "",
190 (instance->labels_buffer) ? buffer_tostring(instance->labels_buffer) : "",
191 value,
192 (unsigned long long)last_t);
exporting/json/json.c
+20 -22
@@ -145,7 +145,7 @@ int format_dimension_collected_json_plaintext(struct instance *instance, RRDDIM
145 RRDSET *st = rd->rrdset;
146 RRDHOST *host = st->rrdhost;
147
148 - const char *tags_pre = "", *tags_post = "", *tags = host->tags;
148 + const char *tags_pre = "", *tags_post = "", *tags = rrdhost_tags(host);
149 if (!tags)
150 tags = "";
151
@@ -187,21 +187,20 @@ int format_dimension_collected_json_plaintext(struct instance *instance, RRDDIM
187 "\"timestamp\":%llu}",
188
189 instance->config.prefix,
190 - (host == localhost) ? instance->config.hostname : host->hostname,
190 + (host == localhost) ? instance->config.hostname : rrdhost_hostname(host),
191 tags_pre,
192 tags,
193 tags_post,
194 instance->labels_buffer ? buffer_tostring(instance->labels_buffer) : "",
195
196 - st->id,
197 - st->name,
198 - st->family,
199 - st->context,
200 - st->type,
201 - st->units,
202 -
203 - rd->id,
204 - rd->name,
196 + rrdset_id(st),
197 + rrdset_name(st),
198 + rrdset_family(st),
199 + rrdset_context(st),
200 + rrdset_type(st),
201 + rrdset_units(st),
202 + rrddim_id(rd),
203 + rrddim_name(rd),
204 rd->last_collected_value,
205
206 (unsigned long long)rd->last_collected_time.tv_sec);
@@ -231,7 +230,7 @@ int format_dimension_stored_json_plaintext(struct instance *instance, RRDDIM *rd
230 if(isnan(value))
231 return 0;
232
234 - const char *tags_pre = "", *tags_post = "", *tags = host->tags;
233 + const char *tags_pre = "", *tags_post = "", *tags = rrdhost_tags(host);
234 if (!tags)
235 tags = "";
236
@@ -272,21 +271,20 @@ int format_dimension_stored_json_plaintext(struct instance *instance, RRDDIM *rd
271 "\"timestamp\": %llu}",
272
273 instance->config.prefix,
275 - (host == localhost) ? instance->config.hostname : host->hostname,
274 + (host == localhost) ? instance->config.hostname : rrdhost_hostname(host),
275 tags_pre,
276 tags,
277 tags_post,
278 instance->labels_buffer ? buffer_tostring(instance->labels_buffer) : "",
279
281 - st->id,
282 - st->name,
283 - st->family,
284 - st->context,
285 - st->type,
286 - st->units,
287 -
288 - rd->id,
289 - rd->name,
280 + rrdset_id(st),
281 + rrdset_name(st),
282 + rrdset_family(st),
283 + rrdset_context(st),
284 + rrdset_type(st),
285 + rrdset_units(st),
286 + rrddim_id(rd),
287 + rrddim_name(rd),
288 value,
289
290 (unsigned long long)last_t);
exporting/opentsdb/opentsdb.c
+16 -16
@@ -177,13 +177,13 @@ int format_dimension_collected_opentsdb_telnet(struct instance *instance, RRDDIM
177 char chart_name[RRD_ID_LENGTH_MAX + 1];
178 exporting_name_copy(
179 chart_name,
180 - (instance->config.options & EXPORTING_OPTION_SEND_NAMES && st->name) ? st->name : st->id,
180 + (instance->config.options & EXPORTING_OPTION_SEND_NAMES && st->name) ? rrdset_name(st) : rrdset_id(st),
181 RRD_ID_LENGTH_MAX);
182
183 char dimension_name[RRD_ID_LENGTH_MAX + 1];
184 exporting_name_copy(
185 dimension_name,
186 - (instance->config.options & EXPORTING_OPTION_SEND_NAMES && rd->name) ? rd->name : rd->id,
186 + (instance->config.options & EXPORTING_OPTION_SEND_NAMES && rd->name) ? rrddim_name(rd) : rrddim_id(rd),
187 RRD_ID_LENGTH_MAX);
188
189 buffer_sprintf(
@@ -194,9 +194,9 @@ int format_dimension_collected_opentsdb_telnet(struct instance *instance, RRDDIM
194 dimension_name,
195 (unsigned long long)rd->last_collected_time.tv_sec,
196 rd->last_collected_value,
197 - (host == localhost) ? instance->config.hostname : host->hostname,
197 + (host == localhost) ? instance->config.hostname : rrdhost_hostname(host),
198 (host->tags) ? " " : "",
199 - (host->tags) ? host->tags : "",
199 + (host->tags) ? rrdhost_tags(host) : "",
200 (instance->labels_buffer) ? buffer_tostring(instance->labels_buffer) : "");
201
202 return 0;
@@ -217,13 +217,13 @@ int format_dimension_stored_opentsdb_telnet(struct instance *instance, RRDDIM *r
217 char chart_name[RRD_ID_LENGTH_MAX + 1];
218 exporting_name_copy(
219 chart_name,
220 - (instance->config.options & EXPORTING_OPTION_SEND_NAMES && st->name) ? st->name : st->id,
220 + (instance->config.options & EXPORTING_OPTION_SEND_NAMES && st->name) ? rrdset_name(st) : rrdset_id(st),
221 RRD_ID_LENGTH_MAX);
222
223 char dimension_name[RRD_ID_LENGTH_MAX + 1];
224 exporting_name_copy(
225 dimension_name,
226 - (instance->config.options & EXPORTING_OPTION_SEND_NAMES && rd->name) ? rd->name : rd->id,
226 + (instance->config.options & EXPORTING_OPTION_SEND_NAMES && rd->name) ? rrddim_name(rd) : rrddim_id(rd),
227 RRD_ID_LENGTH_MAX);
228
229 time_t last_t;
@@ -240,9 +240,9 @@ int format_dimension_stored_opentsdb_telnet(struct instance *instance, RRDDIM *r
240 dimension_name,
241 (unsigned long long)last_t,
242 value,
243 - (host == localhost) ? instance->config.hostname : host->hostname,
243 + (host == localhost) ? instance->config.hostname : rrdhost_hostname(host),
244 (host->tags) ? " " : "",
245 - (host->tags) ? host->tags : "",
245 + (host->tags) ? rrdhost_tags(host) : "",
246 (instance->labels_buffer) ? buffer_tostring(instance->labels_buffer) : "");
247
248 return 0;
@@ -309,13 +309,13 @@ int format_dimension_collected_opentsdb_http(struct instance *instance, RRDDIM *
309 char chart_name[RRD_ID_LENGTH_MAX + 1];
310 exporting_name_copy(
311 chart_name,
312 - (instance->config.options & EXPORTING_OPTION_SEND_NAMES && st->name) ? st->name : st->id,
312 + (instance->config.options & EXPORTING_OPTION_SEND_NAMES && st->name) ? rrdset_name(st) : rrdset_id(st),
313 RRD_ID_LENGTH_MAX);
314
315 char dimension_name[RRD_ID_LENGTH_MAX + 1];
316 exporting_name_copy(
317 dimension_name,
318 - (instance->config.options & EXPORTING_OPTION_SEND_NAMES && rd->name) ? rd->name : rd->id,
318 + (instance->config.options & EXPORTING_OPTION_SEND_NAMES && rd->name) ? rrddim_name(rd) : rrddim_id(rd),
319 RRD_ID_LENGTH_MAX);
320
321 if (buffer_strlen((BUFFER *)instance->buffer) > 2)
@@ -336,9 +336,9 @@ int format_dimension_collected_opentsdb_http(struct instance *instance, RRDDIM *
336 dimension_name,
337 (unsigned long long)rd->last_collected_time.tv_sec,
338 rd->last_collected_value,
339 - (host == localhost) ? instance->config.hostname : host->hostname,
339 + (host == localhost) ? instance->config.hostname : rrdhost_hostname(host),
340 (host->tags) ? " " : "",
341 - (host->tags) ? host->tags : "",
341 + (host->tags) ? rrdhost_tags(host) : "",
342 instance->labels_buffer ? buffer_tostring(instance->labels_buffer) : "");
343
344 return 0;
@@ -359,13 +359,13 @@ int format_dimension_stored_opentsdb_http(struct instance *instance, RRDDIM *rd)
359 char chart_name[RRD_ID_LENGTH_MAX + 1];
360 exporting_name_copy(
361 chart_name,
362 - (instance->config.options & EXPORTING_OPTION_SEND_NAMES && st->name) ? st->name : st->id,
362 + (instance->config.options & EXPORTING_OPTION_SEND_NAMES && st->name) ? rrdset_name(st) : rrdset_id(st),
363 RRD_ID_LENGTH_MAX);
364
365 char dimension_name[RRD_ID_LENGTH_MAX + 1];
366 exporting_name_copy(
367 dimension_name,
368 - (instance->config.options & EXPORTING_OPTION_SEND_NAMES && rd->name) ? rd->name : rd->id,
368 + (instance->config.options & EXPORTING_OPTION_SEND_NAMES && rd->name) ? rrddim_name(rd) : rrddim_id(rd),
369 RRD_ID_LENGTH_MAX);
370
371 time_t last_t;
@@ -392,9 +392,9 @@ int format_dimension_stored_opentsdb_http(struct instance *instance, RRDDIM *rd)
392 dimension_name,
393 (unsigned long long)last_t,
394 value,
395 - (host == localhost) ? instance->config.hostname : host->hostname,
395 + (host == localhost) ? instance->config.hostname : rrdhost_hostname(host),
396 (host->tags) ? " " : "",
397 - (host->tags) ? host->tags : "",
397 + (host->tags) ? rrdhost_tags(host) : "",
398 instance->labels_buffer ? buffer_tostring(instance->labels_buffer) : "");
399
400 return 0;
exporting/process_data.c
+6 -6
@@ -110,9 +110,9 @@ NETDATA_DOUBLE exporting_calculate_value_from_stored_data(
110 debug(
111 D_EXPORTING,
112 "EXPORTING: %s.%s.%s: aligned timeframe %lu to %lu is outside the chart's database range %lu to %lu",
113 - host->hostname,
114 - st->id,
115 - rd->id,
113 + rrdhost_hostname(host),
114 + rrdset_id(st),
115 + rrddim_id(rd),
116 (unsigned long)after,
117 (unsigned long)before,
118 (unsigned long)first_t,
@@ -142,9 +142,9 @@ NETDATA_DOUBLE exporting_calculate_value_from_stored_data(
142 debug(
143 D_EXPORTING,
144 "EXPORTING: %s.%s.%s: no values stored in database for range %lu to %lu",
145 - host->hostname,
146 - st->id,
147 - rd->id,
145 + rrdhost_hostname(host),
146 + rrdset_id(st),
147 + rrddim_id(rd),
148 (unsigned long)after,
149 (unsigned long)before);
150 return NAN;
exporting/prometheus/prometheus.c
+49 -45
@@ -9,9 +9,9 @@
9
10 static int is_matches_rrdset(struct instance *instance, RRDSET *st, SIMPLE_PATTERN *filter) {
11 if (instance->config.options & EXPORTING_OPTION_SEND_NAMES) {
12 - return simple_pattern_matches(filter, st->name);
12 + return simple_pattern_matches(filter, rrdset_name(st));
13 }
14 - return simple_pattern_matches(filter, st->id);
14 + return simple_pattern_matches(filter, rrdset_id(st));
15 }
16
17 /**
@@ -48,8 +48,8 @@ inline int can_send_rrdset(struct instance *instance, RRDSET *st, SIMPLE_PATTERN
48 debug(
49 D_EXPORTING,
50 "EXPORTING: not sending chart '%s' of host '%s', because it is disabled for exporting.",
51 - st->id,
52 - host->hostname);
51 + rrdset_id(st),
52 + rrdhost_hostname(host));
53 return 0;
54 }
55 }
@@ -58,8 +58,8 @@ inline int can_send_rrdset(struct instance *instance, RRDSET *st, SIMPLE_PATTERN
58 debug(
59 D_EXPORTING,
60 "EXPORTING: not sending chart '%s' of host '%s', because it is not available for exporting.",
61 - st->id,
62 - host->hostname);
61 + rrdset_id(st),
62 + rrdhost_hostname(host));
63 return 0;
64 }
65
@@ -69,8 +69,8 @@ inline int can_send_rrdset(struct instance *instance, RRDSET *st, SIMPLE_PATTERN
69 debug(
70 D_EXPORTING,
71 "EXPORTING: not sending chart '%s' of host '%s' because its memory mode is '%s' and the exporting connector requires database access.",
72 - st->id,
73 - host->hostname,
72 + rrdset_id(st),
73 + rrdhost_hostname(host),
74 rrd_memory_mode_name(host->rrd_memory_mode));
75 return 0;
76 }
@@ -349,8 +349,9 @@ struct host_variables_callback_options {
349 * @param data callback options.
350 * @return Returns 1 if the chart can be sent, 0 otherwise.
351 */
352 -static int print_host_variables(RRDVAR *rv, void *data)
353 -{
352 +static int print_host_variables(const char *name __maybe_unused, void *rv_ptr, void *data) {
353 + RRDVAR *rv = rv_ptr;
354 +
355 struct host_variables_callback_options *opts = data;
356
357 if (rv->options & (RRDVAR_OPTION_CUSTOM_HOST_VAR | RRDVAR_OPTION_CUSTOM_CHART_VAR)) {
@@ -366,7 +367,7 @@ static int print_host_variables(RRDVAR *rv, void *data)
367 if (isnan(value) || isinf(value)) {
368 if (opts->output_options & PROMETHEUS_OUTPUT_HELP)
369 buffer_sprintf(
369 - opts->wb, "# COMMENT variable \"%s\" is %s. Skipped.\n", rv->name, (isnan(value)) ? "NAN" : "INF");
370 + opts->wb, "# COMMENT variable \"%s\" is %s. Skipped.\n", rrdvar_name(rv), (isnan(value)) ? "NAN" : "INF");
371
372 return 0;
373 }
@@ -378,7 +379,7 @@ static int print_host_variables(RRDVAR *rv, void *data)
379 label_post = "}";
380 }
381
381 - prometheus_name_copy(opts->name, rv->name, sizeof(opts->name));
382 + prometheus_name_copy(opts->name, rrdvar_name(rv), sizeof(opts->name));
383
384 if (opts->output_options & PROMETHEUS_OUTPUT_TIMESTAMPS)
385 buffer_sprintf(
@@ -445,17 +446,17 @@ static void generate_as_collected_prom_help(BUFFER *wb, struct gen_parameters *p
446 wb,
447 "%s: chart \"%s\", context \"%s\", family \"%s\", dimension \"%s\", value * ",
448 p->suffix,
448 - (p->output_options & PROMETHEUS_OUTPUT_NAMES && p->st->name) ? p->st->name : p->st->id,
449 - p->st->context,
450 - p->st->family,
451 - (p->output_options & PROMETHEUS_OUTPUT_NAMES && p->rd->name) ? p->rd->name : p->rd->id);
449 + (p->output_options & PROMETHEUS_OUTPUT_NAMES && p->st->name) ? rrdset_name(p->st) : rrdset_id(p->st),
450 + rrdset_context(p->st),
451 + rrdset_family(p->st),
452 + (p->output_options & PROMETHEUS_OUTPUT_NAMES && p->rd->name) ? rrddim_name(p->rd) : rrddim_id(p->rd));
453
454 if (prometheus_collector)
455 buffer_sprintf(wb, "1 / 1");
456 else
457 buffer_sprintf(wb, COLLECTED_NUMBER_FORMAT " / " COLLECTED_NUMBER_FORMAT, p->rd->multiplier, p->rd->divisor);
458
458 - buffer_sprintf(wb, " %s %s (%s)\n", p->relation, p->st->units, p->type);
459 + buffer_sprintf(wb, " %s %s (%s)\n", p->relation, rrdset_units(p->st), p->type);
460 }
461
462 /**
@@ -521,7 +522,7 @@ static void rrd_stats_api_v1_charts_allmetrics_prometheus(
522 rrdhost_rdlock(host);
523
524 char hostname[PROMETHEUS_ELEMENT_MAX + 1];
524 - prometheus_label_copy(hostname, host->hostname, PROMETHEUS_ELEMENT_MAX);
525 + prometheus_label_copy(hostname, rrdhost_hostname(host), PROMETHEUS_ELEMENT_MAX);
526
527 format_host_labels_prometheus(instance, host);
528
@@ -529,8 +530,8 @@ static void rrd_stats_api_v1_charts_allmetrics_prometheus(
530 wb,
531 "netdata_info{instance=\"%s\",application=\"%s\",version=\"%s\"",
532 hostname,
532 - host->program_name,
533 - host->program_version);
533 + rrdhost_program_name(host),
534 + rrdhost_program_version(host));
535
536 if (instance->labels_buffer && *buffer_tostring(instance->labels_buffer)) {
537 buffer_sprintf(wb, ",%s", buffer_tostring(instance->labels_buffer));
@@ -551,15 +552,19 @@ static void rrd_stats_api_v1_charts_allmetrics_prometheus(
552
553 // send custom variables set for the host
554 if (output_options & PROMETHEUS_OUTPUT_VARIABLES) {
554 - struct host_variables_callback_options opts = { .host = host,
555 - .wb = wb,
556 - .labels = (labels[0] == ',') ? &labels[1] : labels,
557 - .exporting_options = exporting_options,
558 - .output_options = output_options,
559 - .prefix = prefix,
560 - .now = now_realtime_sec(),
561 - .host_header_printed = 0 };
562 - foreach_host_variable_callback(host, print_host_variables, &opts);
555 +
556 + struct host_variables_callback_options opts = {
557 + .host = host,
558 + .wb = wb,
559 + .labels = (labels[0] == ',') ? &labels[1] : labels,
560 + .exporting_options = exporting_options,
561 + .output_options = output_options,
562 + .prefix = prefix,
563 + .now = now_realtime_sec(),
564 + .host_header_printed = 0
565 + };
566 +
567 + rrdvar_walkthrough_read(host->rrdvar_root_index, print_host_variables, &opts);
568 }
569
570 // for each chart
@@ -575,10 +580,9 @@ static void rrd_stats_api_v1_charts_allmetrics_prometheus(
580 char family[PROMETHEUS_ELEMENT_MAX + 1];
581 char units[PROMETHEUS_ELEMENT_MAX + 1] = "";
582
578 - prometheus_label_copy(
579 - chart, (output_options & PROMETHEUS_OUTPUT_NAMES && st->name) ? st->name : st->id, PROMETHEUS_ELEMENT_MAX);
580 - prometheus_label_copy(family, st->family, PROMETHEUS_ELEMENT_MAX);
581 - prometheus_name_copy(context, st->context, PROMETHEUS_ELEMENT_MAX);
583 + prometheus_label_copy(chart, (output_options & PROMETHEUS_OUTPUT_NAMES && st->name) ? rrdset_name(st) : rrdset_id(st), PROMETHEUS_ELEMENT_MAX);
584 + prometheus_label_copy(family, rrdset_family(st), PROMETHEUS_ELEMENT_MAX);
585 + prometheus_name_copy(context, rrdset_context(st), PROMETHEUS_ELEMENT_MAX);
586
587 int as_collected = (EXPORTING_OPTIONS_DATA_SOURCE(exporting_options) == EXPORTING_SOURCE_DATA_AS_COLLECTED);
588 int homogeneous = 1;
@@ -590,13 +594,13 @@ static void rrd_stats_api_v1_charts_allmetrics_prometheus(
594 if (rrdset_flag_check(st, RRDSET_FLAG_HETEROGENEOUS))
595 homogeneous = 0;
596
593 - if (st->module_name && !strcmp(st->module_name, "prometheus"))
597 + if (!strcmp(rrdset_module_name(st), "prometheus"))
598 prometheus_collector = 1;
599 } else {
600 if (EXPORTING_OPTIONS_DATA_SOURCE(exporting_options) == EXPORTING_SOURCE_DATA_AVERAGE &&
601 !(output_options & PROMETHEUS_OUTPUT_HIDEUNITS))
602 prometheus_units_copy(
599 - units, st->units, PROMETHEUS_ELEMENT_MAX, output_options & PROMETHEUS_OUTPUT_OLDUNITS);
603 + units, rrdset_units(st), PROMETHEUS_ELEMENT_MAX, output_options & PROMETHEUS_OUTPUT_OLDUNITS);
604 }
605
606 if (unlikely(output_options & PROMETHEUS_OUTPUT_HELP))
@@ -604,10 +608,10 @@ static void rrd_stats_api_v1_charts_allmetrics_prometheus(
608 wb,
609 "\n# COMMENT %s chart \"%s\", context \"%s\", family \"%s\", units \"%s\"\n",
610 (homogeneous) ? "homogeneous" : "heterogeneous",
607 - (output_options & PROMETHEUS_OUTPUT_NAMES && st->name) ? st->name : st->id,
608 - st->context,
609 - st->family,
610 - st->units);
611 + (output_options & PROMETHEUS_OUTPUT_NAMES && st->name) ? rrdset_name(st) : rrdset_id(st),
612 + rrdset_context(st),
613 + rrdset_family(st),
614 + rrdset_units(st));
615
616 // for each dimension
617 RRDDIM *rd;
@@ -651,7 +655,7 @@ static void rrd_stats_api_v1_charts_allmetrics_prometheus(
655
656 prometheus_label_copy(
657 dimension,
654 - (output_options & PROMETHEUS_OUTPUT_NAMES && rd->name) ? rd->name : rd->id,
658 + (output_options & PROMETHEUS_OUTPUT_NAMES && rd->name) ? rrddim_name(rd) : rrddim_id(rd),
659 PROMETHEUS_ELEMENT_MAX);
660
661 if (unlikely(output_options & PROMETHEUS_OUTPUT_HELP))
@@ -667,7 +671,7 @@ static void rrd_stats_api_v1_charts_allmetrics_prometheus(
671
672 prometheus_name_copy(
673 dimension,
670 - (output_options & PROMETHEUS_OUTPUT_NAMES && rd->name) ? rd->name : rd->id,
674 + (output_options & PROMETHEUS_OUTPUT_NAMES && rd->name) ? rrddim_name(rd) : rrddim_id(rd),
675 PROMETHEUS_ELEMENT_MAX);
676
677 if (unlikely(output_options & PROMETHEUS_OUTPUT_HELP))
@@ -694,7 +698,7 @@ static void rrd_stats_api_v1_charts_allmetrics_prometheus(
698
699 prometheus_label_copy(
700 dimension,
697 - (output_options & PROMETHEUS_OUTPUT_NAMES && rd->name) ? rd->name : rd->id,
701 + (output_options & PROMETHEUS_OUTPUT_NAMES && rd->name) ? rrddim_name(rd) : rrddim_id(rd),
702 PROMETHEUS_ELEMENT_MAX);
703
704 if (unlikely(output_options & PROMETHEUS_OUTPUT_HELP))
@@ -705,8 +709,8 @@ static void rrd_stats_api_v1_charts_allmetrics_prometheus(
709 context,
710 units,
711 suffix,
708 - (output_options & PROMETHEUS_OUTPUT_NAMES && rd->name) ? rd->name : rd->id,
709 - st->units,
712 + (output_options & PROMETHEUS_OUTPUT_NAMES && rd->name) ? rrddim_name(rd) : rrddim_id(rd),
713 + rrdset_units(st),
714 (unsigned long long)first_time,
715 (unsigned long long)last_time);
716
@@ -809,7 +813,7 @@ static inline time_t prometheus_preparation(
813 buffer_sprintf(
814 wb,
815 "# COMMENT netdata \"%s\" to %sprometheus \"%s\", source \"%s\", last seen %lu %s, time range %lu to %lu\n\n",
812 - host->hostname,
816 + rrdhost_hostname(host),
817 (first_seen) ? "FIRST SEEN " : "",
818 server,
819 mode,
exporting/prometheus/remote_write/remote_write.c
+20 -18
@@ -171,12 +171,12 @@ int format_host_prometheus_remote_write(struct instance *instance, RRDHOST *host
171 char hostname[PROMETHEUS_ELEMENT_MAX + 1];
172 prometheus_label_copy(
173 hostname,
174 - (host == localhost) ? instance->config.hostname : host->hostname,
174 + (host == localhost) ? instance->config.hostname : rrdhost_hostname(host),
175 PROMETHEUS_ELEMENT_MAX);
176
177 add_host_info(
178 connector_specific_data->write_request,
179 - "netdata_info", hostname, host->program_name, host->program_version, now_realtime_usec() / USEC_PER_MS);
179 + "netdata_info", hostname, rrdhost_program_name(host), rrdhost_program_version(host), now_realtime_usec() / USEC_PER_MS);
180
181 if (unlikely(sending_labels_configured(instance))) {
182 struct format_remote_write_label_callback tmp = {
@@ -200,10 +200,10 @@ int format_chart_prometheus_remote_write(struct instance *instance, RRDSET *st)
200 {
201 prometheus_label_copy(
202 chart,
203 - (instance->config.options & EXPORTING_OPTION_SEND_NAMES && st->name) ? st->name : st->id,
203 + (instance->config.options & EXPORTING_OPTION_SEND_NAMES && st->name) ? rrdset_name(st) : rrdset_id(st),
204 PROMETHEUS_ELEMENT_MAX);
205 - prometheus_label_copy(family, st->family, PROMETHEUS_ELEMENT_MAX);
206 - prometheus_name_copy(context, st->context, PROMETHEUS_ELEMENT_MAX);
205 + prometheus_label_copy(family, rrdset_family(st), PROMETHEUS_ELEMENT_MAX);
206 + prometheus_name_copy(context, rrdset_context(st), PROMETHEUS_ELEMENT_MAX);
207
208 as_collected = (EXPORTING_OPTIONS_DATA_SOURCE(instance->config.options) == EXPORTING_SOURCE_DATA_AS_COLLECTED);
209 homogeneous = 1;
@@ -215,7 +215,7 @@ int format_chart_prometheus_remote_write(struct instance *instance, RRDSET *st)
215 homogeneous = 0;
216 } else {
217 if (EXPORTING_OPTIONS_DATA_SOURCE(instance->config.options) == EXPORTING_SOURCE_DATA_AVERAGE)
218 - prometheus_units_copy(units, st->units, PROMETHEUS_ELEMENT_MAX, 0);
218 + prometheus_units_copy(units, rrdset_units(st), PROMETHEUS_ELEMENT_MAX, 0);
219 }
220
221 return 0;
@@ -249,8 +249,8 @@ int format_dimension_prometheus_remote_write(struct instance *instance, RRDDIM *
249 D_EXPORTING,
250 "EXPORTING: not sending dimension '%s' of chart '%s' from host '%s', "
251 "its last data collection (%lu) is not within our timeframe (%lu to %lu)",
252 - rd->id, rd->rrdset->id,
253 - (host == localhost) ? instance->config.hostname : host->hostname,
252 + rrddim_id(rd), rrdset_id(rd->rrdset),
253 + (host == localhost) ? instance->config.hostname : rrdhost_hostname(host),
254 (unsigned long)rd->last_collected_time.tv_sec,
255 (unsigned long)instance->after,
256 (unsigned long)instance->before);
@@ -263,14 +263,14 @@ int format_dimension_prometheus_remote_write(struct instance *instance, RRDDIM *
263
264 prometheus_label_copy(
265 dimension,
266 - (instance->config.options & EXPORTING_OPTION_SEND_NAMES && rd->name) ? rd->name : rd->id,
266 + (instance->config.options & EXPORTING_OPTION_SEND_NAMES && rd->name) ? rrddim_name(rd) : rrddim_id(rd),
267 PROMETHEUS_ELEMENT_MAX);
268 snprintf(name, PROMETHEUS_LABELS_MAX, "%s_%s%s", instance->config.prefix, context, suffix);
269
270 add_metric(
271 connector_specific_data->write_request,
272 name, chart, family, dimension,
273 - (host == localhost) ? instance->config.hostname : host->hostname,
273 + (host == localhost) ? instance->config.hostname : rrdhost_hostname(host),
274 rd->last_collected_value, timeval_msec(&rd->last_collected_time));
275 } else {
276 // the dimensions of the chart, do not have the same algorithm, multiplier or divisor
@@ -278,7 +278,7 @@ int format_dimension_prometheus_remote_write(struct instance *instance, RRDDIM *
278
279 prometheus_name_copy(
280 dimension,
281 - (instance->config.options & EXPORTING_OPTION_SEND_NAMES && rd->name) ? rd->name : rd->id,
281 + (instance->config.options & EXPORTING_OPTION_SEND_NAMES && rd->name) ? rrddim_name(rd) : rrddim_id(rd),
282 PROMETHEUS_ELEMENT_MAX);
283 snprintf(
284 name, PROMETHEUS_LABELS_MAX, "%s_%s_%s%s", instance->config.prefix, context, dimension,
@@ -287,7 +287,7 @@ int format_dimension_prometheus_remote_write(struct instance *instance, RRDDIM *
287 add_metric(
288 connector_specific_data->write_request,
289 name, chart, family, NULL,
290 - (host == localhost) ? instance->config.hostname : host->hostname,
290 + (host == localhost) ? instance->config.hostname : rrdhost_hostname(host),
291 rd->last_collected_value, timeval_msec(&rd->last_collected_time));
292 }
293 } else {
@@ -304,7 +304,7 @@ int format_dimension_prometheus_remote_write(struct instance *instance, RRDDIM *
304
305 prometheus_label_copy(
306 dimension,
307 - (instance->config.options & EXPORTING_OPTION_SEND_NAMES && rd->name) ? rd->name : rd->id,
307 + (instance->config.options & EXPORTING_OPTION_SEND_NAMES && rd->name) ? rrddim_name(rd) : rrddim_id(rd),
308 PROMETHEUS_ELEMENT_MAX);
309 snprintf(
310 name, PROMETHEUS_LABELS_MAX, "%s_%s%s%s", instance->config.prefix, context, units, suffix);
@@ -312,7 +312,7 @@ int format_dimension_prometheus_remote_write(struct instance *instance, RRDDIM *
312 add_metric(
313 connector_specific_data->write_request,
314 name, chart, family, dimension,
315 - (host == localhost) ? instance->config.hostname : host->hostname,
315 + (host == localhost) ? instance->config.hostname : rrdhost_hostname(host),
316 value, last_t * MSEC_PER_SEC);
317 }
318 }
@@ -321,7 +321,9 @@ int format_dimension_prometheus_remote_write(struct instance *instance, RRDDIM *
321 return 0;
322 }
323
324 -int format_variable_prometheus_remote_write_callback(RRDVAR *rv, void *data) {
324 +static int format_variable_prometheus_remote_write_callback(const char *name_txt __maybe_unused, void *rv_ptr, void *data) {
325 + RRDVAR *rv = rv_ptr;
326 +
327 struct prometheus_remote_write_variables_callback_options *opts = data;
328
329 if (rv->options & (RRDVAR_OPTION_CUSTOM_HOST_VAR | RRDVAR_OPTION_CUSTOM_CHART_VAR)) {
@@ -335,12 +337,12 @@ int format_variable_prometheus_remote_write_callback(RRDVAR *rv, void *data) {
337 char name[PROMETHEUS_LABELS_MAX + 1];
338 char *suffix = "";
339
338 - prometheus_name_copy(context, rv->name, PROMETHEUS_ELEMENT_MAX);
340 + prometheus_name_copy(context, rrdvar_name(rv), PROMETHEUS_ELEMENT_MAX);
341 snprintf(name, PROMETHEUS_LABELS_MAX, "%s_%s%s", instance->config.prefix, context, suffix);
342
343 NETDATA_DOUBLE value = rrdvar2number(rv);
344 add_variable(connector_specific_data->write_request, name,
343 - (host == localhost) ? instance->config.hostname : host->hostname, value, opts->now / USEC_PER_MS);
345 + (host == localhost) ? instance->config.hostname : rrdhost_hostname(host), value, opts->now / USEC_PER_MS);
346 }
347
348 return 0;
@@ -361,7 +363,7 @@ int format_variables_prometheus_remote_write(struct instance *instance, RRDHOST
363 .now = now_realtime_usec(),
364 };
365
364 - return foreach_host_variable_callback(host, format_variable_prometheus_remote_write_callback, &opt);
366 + return rrdvar_walkthrough_read(host->rrdvar_root_index, format_variable_prometheus_remote_write_callback, &opt);
367 }
368
369 /**
exporting/tests/exporting_fixtures.c
+9 -9
@@ -39,7 +39,7 @@ int setup_rrdhost()
39
40 localhost->rrd_update_every = 1;
41
42 - localhost->tags = strdupz("TAG1=VALUE1 TAG2=VALUE2");
42 + localhost->tags = string_strdupz("TAG1=VALUE1 TAG2=VALUE2");
43
44 localhost->host_labels = rrdlabels_create();
45 rrdlabels_add(localhost->host_labels, "key1", "value1", RRDLABEL_SRC_CONFIG);
@@ -48,16 +48,16 @@ int setup_rrdhost()
48 localhost->rrdset_root = calloc(1, sizeof(RRDSET));
49 RRDSET *st = localhost->rrdset_root;
50 st->rrdhost = localhost;
51 - strcpy(st->id, "chart_id");
52 - st->name = strdupz("chart_name");
51 + st->id = string_strdupz("chart_id");
52 + st->name = string_strdupz("chart_name");
53 st->rrd_memory_mode |= RRD_MEMORY_MODE_SAVE;
54 st->update_every = 1;
55
56 localhost->rrdset_root->dimensions = calloc(1, sizeof(RRDDIM));
57 RRDDIM *rd = localhost->rrdset_root->dimensions;
58 rd->rrdset = st;
59 - rd->id = strdupz("dimension_id");
60 - rd->name = strdupz("dimension_name");
59 + rd->id = string_strdupz("dimension_id");
60 + rd->name = string_strdupz("dimension_name");
61 rd->last_collected_value = 123000321;
62 rd->last_collected_time.tv_sec = 15051;
63 rd->collections_counter++;
@@ -77,18 +77,18 @@ int setup_rrdhost()
77 int teardown_rrdhost()
78 {
79 RRDDIM *rd = localhost->rrdset_root->dimensions;
80 - free((void *)rd->name);
81 - free((void *)rd->id);
80 + string_freez(rd->name);
81 + string_freez(rd->id);
82 free(rd->tiers[0]);
83 free(rd);
84
85 RRDSET *st = localhost->rrdset_root;
86 - free((void *)st->name);
86 + string_freez(st->name);
87 free(st);
88
89 rrdlabels_destroy(localhost->host_labels);
90
91 - free((void *)localhost->tags);
91 + string_freez(localhost->tags);
92 free(localhost);
93
94 return 0;
exporting/tests/netdata_doubles.c
+13 -7
@@ -177,12 +177,6 @@ const char *rrd_memory_mode_name(RRD_MEMORY_MODE id)
177 return RRD_MEMORY_MODE_NONE_NAME;
178 }
179
180 -NETDATA_DOUBLE rrdvar2number(RRDVAR *rv)
181 -{
182 - (void)rv;
183 - return 0;
184 -}
185 -
180 int foreach_host_variable_callback(RRDHOST *host, int (*callback)(RRDVAR *rv, void *data), void *data)
181 {
182 (void)host;
@@ -256,6 +250,18 @@ void sql_store_chart_label(uuid_t *chart_uuid, int source_type, char *label, cha
250 (void)value;
251 }
252
259 -void rrdcalc_update_rrdlabels(RRDSET *st) {
253 +void rrdcalc_update_rrdlabels(RRDSET *st)
254 +{
255 (void)st;
256 }
257 +
258 +void rrdpush_sender_send_this_host_variable_now(RRDHOST *host, RRDVAR *rv)
259 +{
260 + (void)host;
261 + (void)rv;
262 +}
263 +
264 +void db_execute(const char *cmd)
265 +{
266 + (void)cmd;
267 +}
exporting/tests/test_exporting_engine.c
+12 -12
@@ -442,8 +442,8 @@ static void test_format_dimension_collected_json_plaintext(void **state)
442 assert_string_equal(
443 buffer_tostring(engine->instance_root->buffer),
444 "{\"prefix\":\"netdata\",\"hostname\":\"test-host\",\"host_tags\":\"TAG1=VALUE1 TAG2=VALUE2\","
445 - "\"chart_id\":\"chart_id\",\"chart_name\":\"chart_name\",\"chart_family\":\"(null)\","
446 - "\"chart_context\":\"(null)\",\"chart_type\":\"(null)\",\"units\":\"(null)\",\"id\":\"dimension_id\","
445 + "\"chart_id\":\"chart_id\",\"chart_name\":\"chart_name\",\"chart_family\":\"\","
446 + "\"chart_context\":\"\",\"chart_type\":\"\",\"units\":\"\",\"id\":\"dimension_id\","
447 "\"name\":\"dimension_name\",\"value\":123000321,\"timestamp\":15051}\n");
448 }
449
@@ -459,8 +459,8 @@ static void test_format_dimension_stored_json_plaintext(void **state)
459 assert_string_equal(
460 buffer_tostring(engine->instance_root->buffer),
461 "{\"prefix\":\"netdata\",\"hostname\":\"test-host\",\"host_tags\":\"TAG1=VALUE1 TAG2=VALUE2\","
462 - "\"chart_id\":\"chart_id\",\"chart_name\":\"chart_name\",\"chart_family\":\"(null)\"," \
463 - "\"chart_context\": \"(null)\",\"chart_type\":\"(null)\",\"units\": \"(null)\",\"id\":\"dimension_id\","
462 + "\"chart_id\":\"chart_id\",\"chart_name\":\"chart_name\",\"chart_family\":\"\"," \
463 + "\"chart_context\": \"\",\"chart_type\":\"\",\"units\": \"\",\"id\":\"dimension_id\","
464 "\"name\":\"dimension_name\",\"value\":690565856.0000000,\"timestamp\": 15052}\n");
465 }
466
@@ -1055,9 +1055,9 @@ static void rrd_stats_api_v1_charts_allmetrics_prometheus(void **state)
1055
1056 BUFFER *buffer = buffer_create(0);
1057
1058 - localhost->hostname = strdupz("test_hostname");
1059 - localhost->rrdset_root->family = strdupz("test_family");
1060 - localhost->rrdset_root->context = strdupz("test_context");
1058 + localhost->hostname = string_strdupz("test_hostname");
1059 + localhost->rrdset_root->family = string_strdupz("test_family");
1060 + localhost->rrdset_root->context = string_strdupz("test_context");
1061
1062 expect_function_call(__wrap_now_realtime_sec);
1063 will_return(__wrap_now_realtime_sec, 2);
@@ -1069,7 +1069,7 @@ static void rrd_stats_api_v1_charts_allmetrics_prometheus(void **state)
1069
1070 assert_string_equal(
1071 buffer_tostring(buffer),
1072 - "netdata_info{instance=\"test_hostname\",application=\"(null)\",version=\"(null)\",key1=\"value1\",key2=\"value2\"} 1\n"
1072 + "netdata_info{instance=\"test_hostname\",application=\"\",version=\"\",key1=\"value1\",key2=\"value2\"} 1\n"
1073 "test_prefix_test_context{chart=\"chart_id\",family=\"test_family\",dimension=\"dimension_id\"} 690565856.0000000\n");
1074
1075 buffer_flush(buffer);
@@ -1085,7 +1085,7 @@ static void rrd_stats_api_v1_charts_allmetrics_prometheus(void **state)
1085
1086 assert_string_equal(
1087 buffer_tostring(buffer),
1088 - "netdata_info{instance=\"test_hostname\",application=\"(null)\",version=\"(null)\",key1=\"value1\",key2=\"value2\"} 1\n"
1088 + "netdata_info{instance=\"test_hostname\",application=\"\",version=\"\",key1=\"value1\",key2=\"value2\"} 1\n"
1089 "# TYPE test_prefix_test_context gauge\n"
1090 "test_prefix_test_context{chart=\"chart_name\",family=\"test_family\",dimension=\"dimension_name\"} 690565856.0000000\n");
1091
@@ -1101,7 +1101,7 @@ static void rrd_stats_api_v1_charts_allmetrics_prometheus(void **state)
1101
1102 assert_string_equal(
1103 buffer_tostring(buffer),
1104 - "netdata_info{instance=\"test_hostname\",application=\"(null)\",version=\"(null)\",key1=\"value1\",key2=\"value2\"} 1\n"
1104 + "netdata_info{instance=\"test_hostname\",application=\"\",version=\"\",key1=\"value1\",key2=\"value2\"} 1\n"
1105 "test_prefix_test_context{chart=\"chart_id\",family=\"test_family\",dimension=\"dimension_id\",instance=\"test_hostname\"} 690565856.0000000\n");
1106
1107 free(localhost->rrdset_root->context);
@@ -1207,8 +1207,8 @@ static void test_format_host_prometheus_remote_write(void **state)
1207 simple_connector_data->connector_specific_data = (void *)connector_specific_data;
1208 connector_specific_data->write_request = (void *)0xff;
1209
1210 - localhost->program_name = strdupz("test_program");
1211 - localhost->program_version = strdupz("test_version");
1210 + localhost->program_name = string_strdupz("test_program");
1211 + localhost->program_version = string_strdupz("test_version");
1212
1213 expect_function_call(__wrap_add_host_info);
1214 expect_value(__wrap_add_host_info, write_request_p, 0xff);
exporting/tests/test_exporting_engine.h
+1
@@ -4,6 +4,7 @@
4 #define TEST_EXPORTING_ENGINE_H 1
5
6 #include "libnetdata/libnetdata.h"
7 +#include "database/rrdvar.h"
8
9 #include "exporting/exporting_engine.h"
10 #include "exporting/graphite/graphite.h"
health/health.c
+156 -94
@@ -155,18 +155,11 @@ static void health_reload_host(RRDHOST *host) {
155 // free all running alarms
156 rrdhost_wrlock(host);
157
158 - while(host->templates)
159 - rrdcalctemplate_unlink_and_free(host, host->templates);
158 + while(host->alarms_templates)
159 + rrdcalctemplate_unlink_and_free(host, host->alarms_templates);
160
161 - RRDCALCTEMPLATE *rt,*next;
162 - for(rt = host->alarms_template_with_foreach; rt ; rt = next) {
163 - next = rt->next;
164 - rrdcalctemplate_free(rt);
165 - }
166 - host->alarms_template_with_foreach = NULL;
167 -
168 - while(host->alarms)
169 - rrdcalc_unlink_and_free(host, host->alarms);
161 + while(host->host_alarms)
162 + rrdcalc_unlink_and_free(host, host->host_alarms);
163
164 RRDCALC *rc,*nc;
165 for(rc = host->alarms_with_foreach; rc ; rc = nc) {
@@ -266,13 +259,13 @@ static inline void health_alarm_execute(RRDHOST *host, ALARM_ENTRY *ae) {
259
260 if(unlikely(ae->new_status < RRDCALC_STATUS_CLEAR)) {
261 // do not send notifications for internal statuses
269 - debug(D_HEALTH, "Health not sending notification for alarm '%s.%s' status %s (internal statuses)", ae->chart, ae->name, rrdcalc_status2string(ae->new_status));
262 + debug(D_HEALTH, "Health not sending notification for alarm '%s.%s' status %s (internal statuses)", ae_chart_name(ae), ae_name(ae), rrdcalc_status2string(ae->new_status));
263 goto done;
264 }
265
266 if(unlikely(ae->new_status <= RRDCALC_STATUS_CLEAR && (ae->flags & HEALTH_ENTRY_FLAG_NO_CLEAR_NOTIFICATION))) {
267 // do not send notifications for disabled statuses
275 - debug(D_HEALTH, "Health not sending notification for alarm '%s.%s' status %s (it has no-clear-notification enabled)", ae->chart, ae->name, rrdcalc_status2string(ae->new_status));
268 + debug(D_HEALTH, "Health not sending notification for alarm '%s.%s' status %s (it has no-clear-notification enabled)", ae_chart_name(ae), ae_name(ae), rrdcalc_status2string(ae->new_status));
269 // mark it as run, so that we will send the same alarm if it happens again
270 goto done;
271 }
@@ -292,7 +285,7 @@ static inline void health_alarm_execute(RRDHOST *host, ALARM_ENTRY *ae) {
285 // we have executed this alarm notification in the past
286 if(t && t->new_status == ae->new_status) {
287 // don't send the notification for the same status again
295 - debug(D_HEALTH, "Health not sending again notification for alarm '%s.%s' status %s", ae->chart, ae->name
288 + debug(D_HEALTH, "Health not sending again notification for alarm '%s.%s' status %s", ae_chart_name(ae), ae_name(ae)
289 , rrdcalc_status2string(ae->new_status));
290 goto done;
291 }
@@ -303,7 +296,7 @@ static inline void health_alarm_execute(RRDHOST *host, ALARM_ENTRY *ae) {
296 if(unlikely(ae->new_status == RRDCALC_STATUS_CLEAR)) {
297 if((!(ae->flags & HEALTH_ENTRY_RUN_ONCE)) || (ae->flags & HEALTH_ENTRY_RUN_ONCE && ae->old_status < RRDCALC_STATUS_RAISED) ) {
298 debug(D_HEALTH, "Health not sending notification for first initialization of alarm '%s.%s' status %s"
306 - , ae->chart, ae->name, rrdcalc_status2string(ae->new_status));
299 + , ae_chart_name(ae), ae_name(ae), rrdcalc_status2string(ae->new_status));
300 goto done;
301 }
302 }
@@ -312,14 +305,14 @@ static inline void health_alarm_execute(RRDHOST *host, ALARM_ENTRY *ae) {
305
306 // Check if alarm notifications are silenced
307 if (ae->flags & HEALTH_ENTRY_FLAG_SILENCED) {
315 - info("Health not sending notification for alarm '%s.%s' status %s (command API has disabled notifications)", ae->chart, ae->name, rrdcalc_status2string(ae->new_status));
308 + info("Health not sending notification for alarm '%s.%s' status %s (command API has disabled notifications)", ae_chart_name(ae), ae_name(ae), rrdcalc_status2string(ae->new_status));
309 goto done;
310 }
311
312 static char command_to_run[ALARM_EXEC_COMMAND_LENGTH + 1];
313
321 - const char *exec = (ae->exec) ? ae->exec : host->health_default_exec;
322 - const char *recipient = (ae->recipient) ? ae->recipient : host->health_default_recipient;
314 + const char *exec = (ae->exec) ? ae_exec(ae) : string2str(host->health_default_exec);
315 + const char *recipient = (ae->recipient) ? ae_recipient(ae) : string2str(host->health_default_recipient);
316
317 int n_warn=0, n_crit=0;
318 RRDCALC *rc;
@@ -330,13 +323,16 @@ static inline void health_alarm_execute(RRDHOST *host, ALARM_ENTRY *ae) {
323 warn_alarms = buffer_create(NETDATA_WEB_RESPONSE_INITIAL_SIZE);
324 crit_alarms = buffer_create(NETDATA_WEB_RESPONSE_INITIAL_SIZE);
325
333 - for(rc = host->alarms; rc && (n_warn + n_crit) < ACTIVE_ALARMS_LIST_EXAMINE ; rc = rc->next) {
326 + foreach_rrdcalc_in_rrdhost(host, rc) {
327 if(unlikely(!rc->rrdset || !rc->rrdset->last_collected_time.tv_sec))
328 continue;
329
330 + if(unlikely((n_warn + n_crit) >= ACTIVE_ALARMS_LIST_EXAMINE))
331 + break;
332 +
333 if (unlikely(rc->status == RRDCALC_STATUS_WARNING)) {
334 if (likely(ae->alarm_id != rc->id) || likely(ae->alarm_event_id != rc->next_event_id - 1)) {
339 - active_alerts[n_warn+n_crit].name = rc->name;
335 + active_alerts[n_warn+n_crit].name = (char *)rrdcalc_name(rc);
336 active_alerts[n_warn+n_crit].last_status_change = rc->last_status_change;
337 active_alerts[n_warn+n_crit].status = rc->status;
338 n_warn++;
@@ -344,7 +340,7 @@ static inline void health_alarm_execute(RRDHOST *host, ALARM_ENTRY *ae) {
340 expr = rc->warning;
341 } else if (unlikely(rc->status == RRDCALC_STATUS_CRITICAL)) {
342 if (likely(ae->alarm_id != rc->id) || likely(ae->alarm_event_id != rc->next_event_id - 1)) {
347 - active_alerts[n_warn+n_crit].name = rc->name;
343 + active_alerts[n_warn+n_crit].name = (char *)rrdcalc_name(rc);
344 active_alerts[n_warn+n_crit].last_status_change = rc->last_status_change;
345 active_alerts[n_warn+n_crit].status = rc->status;
346 n_crit++;
@@ -379,39 +375,39 @@ static inline void health_alarm_execute(RRDHOST *host, ALARM_ENTRY *ae) {
375 }
376 }
377
382 - char *edit_command = ae->source ? health_edit_command_from_source(ae->source) : strdupz("UNKNOWN=0=UNKNOWN");
378 + char *edit_command = ae->source ? health_edit_command_from_source(ae_source(ae)) : strdupz("UNKNOWN=0=UNKNOWN");
379
380 snprintfz(command_to_run, ALARM_EXEC_COMMAND_LENGTH, "exec %s '%s' '%s' '%u' '%u' '%u' '%lu' '%s' '%s' '%s' '%s' '%s' '" NETDATA_DOUBLE_FORMAT_ZERO
381 "' '" NETDATA_DOUBLE_FORMAT_ZERO
382 "' '%s' '%u' '%u' '%s' '%s' '%s' '%s' '%s' '%s' '%d' '%d' '%s' '%s' '%s' '%s' '%s'",
383 exec,
384 recipient,
389 - host->registry_hostname,
385 + rrdhost_registry_hostname(host),
386 ae->unique_id,
387 ae->alarm_id,
388 ae->alarm_event_id,
389 (unsigned long)ae->when,
394 - ae->name,
395 - ae->chart?ae->chart:"NOCHART",
396 - ae->family?ae->family:"NOFAMILY",
390 + ae_name(ae),
391 + ae->chart?ae_chart_name(ae):"NOCHART",
392 + ae->family?ae_family(ae):"NOFAMILY",
393 rrdcalc_status2string(ae->new_status),
394 rrdcalc_status2string(ae->old_status),
395 ae->new_value,
396 ae->old_value,
401 - ae->source?ae->source:"UNKNOWN",
397 + ae->source?ae_source(ae):"UNKNOWN",
398 (uint32_t)ae->duration,
399 (uint32_t)ae->non_clear_duration,
404 - ae->units?ae->units:"",
405 - ae->info?ae->info:"",
406 - ae->new_value_string,
407 - ae->old_value_string,
400 + ae_units(ae),
401 + ae_info(ae),
402 + ae_new_value_string(ae),
403 + ae_old_value_string(ae),
404 (expr && expr->source)?expr->source:"NOSOURCE",
405 (expr && expr->error_msg)?buffer_tostring(expr->error_msg):"NOERRMSG",
406 n_warn,
407 n_crit,
408 buffer_tostring(warn_alarms),
409 buffer_tostring(crit_alarms),
414 - ae->classification?ae->classification:"Unknown",
410 + ae->classification?ae_classification(ae):"Unknown",
411 edit_command,
412 host != localhost ? host->machine_guid:""
413 );
@@ -450,7 +446,7 @@ static inline void health_alarm_wait_for_execution(ALARM_ENTRY *ae) {
446
447 static inline void health_process_notifications(RRDHOST *host, ALARM_ENTRY *ae) {
448 debug(D_HEALTH, "Health alarm '%s.%s' = " NETDATA_DOUBLE_FORMAT_AUTO " - changed status from %s to %s",
453 - ae->chart?ae->chart:"NOCHART", ae->name,
449 + ae->chart?ae_chart_name(ae):"NOCHART", ae_name(ae),
450 ae->new_value,
451 rrdcalc_status2string(ae->old_status),
452 rrdcalc_status2string(ae->new_status)
@@ -467,7 +463,7 @@ static inline void health_alarm_log_process(RRDHOST *host) {
463
464 ALARM_ENTRY *ae;
465 for(ae = host->health_log.alarms; ae && ae->unique_id >= host->health_last_processed_id; ae = ae->next) {
470 - if(likely(!alarm_entry_isrepeating(host, ae))) {
466 + if(likely(!(ae->flags & HEALTH_ENTRY_FLAG_IS_REPEATING))) {
467 if(unlikely(
468 !(ae->flags & HEALTH_ENTRY_FLAG_PROCESSED) &&
469 !(ae->flags & HEALTH_ENTRY_FLAG_UPDATED)
@@ -508,7 +504,7 @@ static inline void health_alarm_log_process(RRDHOST *host) {
504
505 ALARM_ENTRY *t = ae->next;
506
511 - if(likely(!alarm_entry_isrepeating(host, ae))) {
507 + if(likely(!(ae->flags & HEALTH_ENTRY_FLAG_IS_REPEATING))) {
508 health_alarm_wait_for_execution(ae);
509 health_alarm_log_free_one_nochecks_nounlink(ae);
510 host->health_log.count--;
@@ -522,7 +518,7 @@ static inline void health_alarm_log_process(RRDHOST *host) {
518
519 static inline int rrdcalc_isrunnable(RRDCALC *rc, time_t now, time_t *next_run) {
520 if(unlikely(!rc->rrdset)) {
525 - debug(D_HEALTH, "Health not running alarm '%s.%s'. It is not linked to a chart.", rc->chart?rc->chart:"NOCHART", rc->name);
521 + debug(D_HEALTH, "Health not running alarm '%s.%s'. It is not linked to a chart.", rrdcalc_chart_name(rc), rrdcalc_name(rc));
522 return 0;
523 }
524
@@ -533,27 +529,27 @@ static inline int rrdcalc_isrunnable(RRDCALC *rc, time_t now, time_t *next_run)
529 *next_run = rc->next_update;
530 }
531
536 - debug(D_HEALTH, "Health not examining alarm '%s.%s' yet (will do in %d secs).", rc->chart?rc->chart:"NOCHART", rc->name, (int) (rc->next_update - now));
532 + debug(D_HEALTH, "Health not examining alarm '%s.%s' yet (will do in %d secs).", rrdcalc_chart_name(rc), rrdcalc_name(rc), (int) (rc->next_update - now));
533 return 0;
534 }
535
536 if(unlikely(!rc->update_every)) {
541 - debug(D_HEALTH, "Health not running alarm '%s.%s'. It does not have an update frequency", rc->chart?rc->chart:"NOCHART", rc->name);
537 + debug(D_HEALTH, "Health not running alarm '%s.%s'. It does not have an update frequency", rrdcalc_chart_name(rc), rrdcalc_name(rc));
538 return 0;
539 }
540
541 if(unlikely(rrdset_flag_check(rc->rrdset, RRDSET_FLAG_OBSOLETE))) {
546 - debug(D_HEALTH, "Health not running alarm '%s.%s'. The chart has been marked as obsolete", rc->chart?rc->chart:"NOCHART", rc->name);
542 + debug(D_HEALTH, "Health not running alarm '%s.%s'. The chart has been marked as obsolete", rrdcalc_chart_name(rc), rrdcalc_name(rc));
543 return 0;
544 }
545
546 if(unlikely(rrdset_flag_check(rc->rrdset, RRDSET_FLAG_ARCHIVED))) {
551 - debug(D_HEALTH, "Health not running alarm '%s.%s'. The chart has been marked as archived", rc->chart?rc->chart:"NOCHART", rc->name);
547 + debug(D_HEALTH, "Health not running alarm '%s.%s'. The chart has been marked as archived", rrdcalc_chart_name(rc), rrdcalc_name(rc));
548 return 0;
549 }
550
551 if(unlikely(!rc->rrdset->last_collected_time.tv_sec || rc->rrdset->counter_done < 2)) {
556 - debug(D_HEALTH, "Health not running alarm '%s.%s'. Chart is not fully collected yet.", rc->chart?rc->chart:"NOCHART", rc->name);
552 + debug(D_HEALTH, "Health not running alarm '%s.%s'. Chart is not fully collected yet.", rrdcalc_chart_name(rc), rrdcalc_name(rc));
553 return 0;
554 }
555
@@ -566,7 +562,7 @@ static inline int rrdcalc_isrunnable(RRDCALC *rc, time_t now, time_t *next_run)
562 if(unlikely(now + update_every < first /* || now - update_every > last */)) {
563 debug(D_HEALTH
564 , "Health not examining alarm '%s.%s' yet (wanted time is out of bounds - we need %lu but got %lu - %lu)."
569 - , rc->chart ? rc->chart : "NOCHART", rc->name, (unsigned long) now, (unsigned long) first
565 + , rrdcalc_chart_name(rc), rrdcalc_name(rc), (unsigned long) now, (unsigned long) first
566 , (unsigned long) last);
567 return 0;
568 }
@@ -577,7 +573,7 @@ static inline int rrdcalc_isrunnable(RRDCALC *rc, time_t now, time_t *next_run)
573 if(needed + update_every < first || needed - update_every > last) {
574 debug(D_HEALTH
575 , "Health not examining alarm '%s.%s' yet (not enough data yet - we need %lu but got %lu - %lu)."
580 - , rc->chart ? rc->chart : "NOCHART", rc->name, (unsigned long) needed, (unsigned long) first
576 + , rrdcalc_chart_name(rc), rrdcalc_name(rc), (unsigned long) needed, (unsigned long) first
577 , (unsigned long) last);
578 return 0;
579 }
@@ -614,30 +610,30 @@ static void health_main_cleanup(void *ptr) {
610 static_thread->enabled = NETDATA_MAIN_THREAD_EXITED;
611 }
612
617 -static SILENCE_TYPE check_silenced(RRDCALC *rc, char* host, SILENCERS *silencers) {
613 +static SILENCE_TYPE check_silenced(RRDCALC *rc, const char *host, SILENCERS *silencers) {
614 SILENCER *s;
615 debug(D_HEALTH, "Checking if alarm was silenced via the command API. Alarm info name:%s context:%s chart:%s host:%s family:%s",
620 - rc->name, (rc->rrdset)?rc->rrdset->context:"", rc->chart, host, (rc->rrdset)?rc->rrdset->family:"");
616 + rrdcalc_name(rc), (rc->rrdset)?rrdset_context(rc->rrdset):"", rrdcalc_chart_name(rc), host, (rc->rrdset)?rrdset_family(rc->rrdset):"");
617
618 for (s = silencers->silencers; s!=NULL; s=s->next){
619 if (
624 - (!s->alarms_pattern || (rc->name && s->alarms_pattern && simple_pattern_matches(s->alarms_pattern,rc->name))) &&
625 - (!s->contexts_pattern || (rc->rrdset && rc->rrdset->context && s->contexts_pattern && simple_pattern_matches(s->contexts_pattern,rc->rrdset->context))) &&
620 + (!s->alarms_pattern || (rc->name && s->alarms_pattern && simple_pattern_matches(s->alarms_pattern, rrdcalc_name(rc)))) &&
621 + (!s->contexts_pattern || (rc->rrdset && rc->rrdset->context && s->contexts_pattern && simple_pattern_matches(s->contexts_pattern, rrdset_context(rc->rrdset)))) &&
622 (!s->hosts_pattern || (host && s->hosts_pattern && simple_pattern_matches(s->hosts_pattern,host))) &&
627 - (!s->charts_pattern || (rc->chart && s->charts_pattern && simple_pattern_matches(s->charts_pattern,rc->chart))) &&
628 - (!s->families_pattern || (rc->rrdset && rc->rrdset->family && s->families_pattern && simple_pattern_matches(s->families_pattern,rc->rrdset->family)))
623 + (!s->charts_pattern || (rc->chart && s->charts_pattern && simple_pattern_matches(s->charts_pattern, rrdcalc_chart_name(rc)))) &&
624 + (!s->families_pattern || (rc->rrdset && rc->rrdset->family && s->families_pattern && simple_pattern_matches(s->families_pattern, rrdset_family(rc->rrdset))))
625 ) {
626 debug(D_HEALTH, "Alarm matches command API silence entry %s:%s:%s:%s:%s", s->alarms,s->charts, s->contexts, s->hosts, s->families);
627 if (unlikely(silencers->stype == STYPE_NONE)) {
632 - debug(D_HEALTH, "Alarm %s matched a silence entry, but no SILENCE or DISABLE command was issued via the command API. The match has no effect.", rc->name);
628 + debug(D_HEALTH, "Alarm %s matched a silence entry, but no SILENCE or DISABLE command was issued via the command API. The match has no effect.", rrdcalc_name(rc));
629 } else {
630 debug(D_HEALTH, "Alarm %s via the command API - name:%s context:%s chart:%s host:%s family:%s"
631 , (silencers->stype == STYPE_DISABLE_ALARMS)?"Disabled":"Silenced"
636 - , rc->name
637 - , (rc->rrdset)?rc->rrdset->context:""
638 - , rc->chart
632 + , rrdcalc_name(rc)
633 + , (rc->rrdset)?rrdset_context(rc->rrdset):""
634 + , rrdcalc_chart_name(rc)
635 , host
640 - , (rc->rrdset)?rc->rrdset->family:""
636 + , (rc->rrdset)?rrdset_family(rc->rrdset):""
637 );
638 }
639 return silencers->stype;
@@ -664,15 +660,15 @@ static int update_disabled_silenced(RRDHOST *host, RRDCALC *rc) {
660 if (silencers->stype == STYPE_DISABLE_ALARMS) rc->rrdcalc_flags |= RRDCALC_FLAG_DISABLED;
661 else if (silencers->stype == STYPE_SILENCE_NOTIFICATIONS) rc->rrdcalc_flags |= RRDCALC_FLAG_SILENCED;
662 } else {
667 - SILENCE_TYPE st = check_silenced(rc, host->hostname, silencers);
663 + SILENCE_TYPE st = check_silenced(rc, rrdhost_hostname(host), silencers);
664 if (st == STYPE_DISABLE_ALARMS) rc->rrdcalc_flags |= RRDCALC_FLAG_DISABLED;
665 else if (st == STYPE_SILENCE_NOTIFICATIONS) rc->rrdcalc_flags |= RRDCALC_FLAG_SILENCED;
666 }
667
668 if (rrdcalc_flags_old != rc->rrdcalc_flags) {
669 info("Alarm silencing changed for host '%s' alarm '%s': Disabled %s->%s Silenced %s->%s",
674 - host->hostname,
675 - rc->name,
670 + rrdhost_hostname(host),
671 + rrdcalc_name(rc),
672 (rrdcalc_flags_old & RRDCALC_FLAG_DISABLED)?"true":"false",
673 (rc->rrdcalc_flags & RRDCALC_FLAG_DISABLED)?"true":"false",
674 (rrdcalc_flags_old & RRDCALC_FLAG_SILENCED)?"true":"false",
@@ -812,7 +808,7 @@ void *health_main(void *ptr) {
808 info(
809 "Postponing health checks for %"PRId64" seconds, on host '%s'.",
810 (int64_t)hibernation_delay,
815 - host->hostname);
811 + rrdhost_hostname(host));
812
813 host->health_delay_up_to = now + hibernation_delay;
814 }
@@ -821,7 +817,7 @@ void *health_main(void *ptr) {
817 if (unlikely(now < host->health_delay_up_to))
818 continue;
819
824 - info("Resuming health checks on host '%s'.", host->hostname);
820 + info("Resuming health checks on host '%s'.", rrdhost_hostname(host));
821 host->health_delay_up_to = 0;
822 }
823
@@ -839,7 +835,7 @@ void *health_main(void *ptr) {
835 rrdhost_rdlock(host);
836
837 // the first loop is to lookup values from the db
842 - for (rc = host->alarms; rc; rc = rc->next) {
838 + foreach_rrdcalc_in_rrdhost(host, rc) {
839
840 if (update_disabled_silenced(host, rc))
841 continue;
@@ -852,10 +848,33 @@ void *health_main(void *ptr) {
848 if (!rrdcalc_isrepeating(rc)) {
849 worker_is_busy(WORKER_HEALTH_JOB_ALARM_LOG_ENTRY);
850 time_t now = now_realtime_sec();
851 +
852 ALARM_ENTRY *ae = health_create_alarm_entry(
856 - host, rc->id, rc->next_event_id++, rc->config_hash_id, now, rc->name, rc->rrdset->id, rc->rrdset->context,
857 - rc->rrdset->family, rc->classification, rc->component, rc->type, rc->exec, rc->recipient, now - rc->last_status_change,
858 - rc->value, NAN, rc->status, RRDCALC_STATUS_REMOVED, rc->source, rc->units, rc->info, 0, 0);
853 + host,
854 + rc->id,
855 + rc->next_event_id++,
856 + rc->config_hash_id,
857 + now,
858 + rc->name,
859 + rc->rrdset->id,
860 + rc->rrdset->context,
861 + rc->rrdset->family,
862 + rc->classification,
863 + rc->component,
864 + rc->type,
865 + rc->exec,
866 + rc->recipient,
867 + now - rc->last_status_change,
868 + rc->value,
869 + NAN,
870 + rc->status,
871 + RRDCALC_STATUS_REMOVED,
872 + rc->source,
873 + rc->units,
874 + rc->info,
875 + 0,
876 + rrdcalc_isrepeating(rc)?HEALTH_ENTRY_FLAG_IS_REPEATING:0);
877 +
878 if (ae) {
879 health_alarm_log(host, ae);
880 rc->old_status = rc->status;
@@ -890,7 +909,7 @@ void *health_main(void *ptr) {
909 /* time_t old_db_timestamp = rc->db_before; */
910 int value_is_null = 0;
911
893 - int ret = rrdset2value_api_v1(rc->rrdset, NULL, &rc->value, rc->dimensions, 1,
912 + int ret = rrdset2value_api_v1(rc->rrdset, NULL, &rc->value, rrdcalc_dimensions(rc), 1,
913 rc->after, rc->before, rc->group, NULL,
914 0, rc->options,
915 &rc->db_after,&rc->db_before,
@@ -903,7 +922,7 @@ void *health_main(void *ptr) {
922 rc->rrdcalc_flags |= RRDCALC_FLAG_DB_ERROR;
923
924 debug(D_HEALTH, "Health on host '%s', alarm '%s.%s': database lookup returned error %d",
906 - host->hostname, rc->chart ? rc->chart : "NOCHART", rc->name, ret
925 + rrdhost_hostname(host), rrdcalc_chart_name(rc), rrdcalc_name(rc), ret
926 );
927 } else
928 rc->rrdcalc_flags &= ~RRDCALC_FLAG_DB_ERROR;
@@ -930,13 +949,13 @@ void *health_main(void *ptr) {
949
950 debug(D_HEALTH,
951 "Health on host '%s', alarm '%s.%s': database lookup returned empty value (possibly value is not collected yet)",
933 - host->hostname, rc->chart ? rc->chart : "NOCHART", rc->name
952 + rrdhost_hostname(host), rrdcalc_chart_name(rc), rrdcalc_name(rc)
953 );
954 } else
955 rc->rrdcalc_flags &= ~RRDCALC_FLAG_DB_NAN;
956
938 - debug(D_HEALTH, "Health on host '%s', alarm '%s.%s': database lookup gave value " NETDATA_DOUBLE_FORMAT, host->hostname, rc->chart ? rc->chart : "NOCHART", rc->name,
939 - rc->value
957 + debug(D_HEALTH, "Health on host '%s', alarm '%s.%s': database lookup gave value " NETDATA_DOUBLE_FORMAT,
958 + rrdhost_hostname(host), rrdcalc_chart_name(rc), rrdcalc_name(rc), rc->value
959 );
960 }
961
@@ -952,7 +971,7 @@ void *health_main(void *ptr) {
971 rc->rrdcalc_flags |= RRDCALC_FLAG_CALC_ERROR;
972
973 debug(D_HEALTH, "Health on host '%s', alarm '%s.%s': expression '%s' failed: %s",
955 - host->hostname, rc->chart ? rc->chart : "NOCHART", rc->name,
974 + rrdhost_hostname(host), rrdcalc_chart_name(rc), rrdcalc_name(rc),
975 rc->calculation->parsed_as, buffer_tostring(rc->calculation->error_msg)
976 );
977 } else {
@@ -960,9 +979,9 @@ void *health_main(void *ptr) {
979
980 debug(D_HEALTH, "Health on host '%s', alarm '%s.%s': expression '%s' gave value "
981 NETDATA_DOUBLE_FORMAT
963 - ": %s (source: %s)", host->hostname, rc->chart ? rc->chart : "NOCHART", rc->name,
982 + ": %s (source: %s)", rrdhost_hostname(host), rrdcalc_chart_name(rc), rrdcalc_name(rc),
983 rc->calculation->parsed_as, rc->calculation->result,
965 - buffer_tostring(rc->calculation->error_msg), rc->source
984 + buffer_tostring(rc->calculation->error_msg), rrdcalc_source(rc)
985 );
986
987 rc->value = rc->calculation->result;
@@ -980,7 +999,7 @@ void *health_main(void *ptr) {
999 if (unlikely(runnable && !netdata_exit)) {
1000 rrdhost_rdlock(host);
1001
983 - for (rc = host->alarms; rc; rc = rc->next) {
1002 + foreach_rrdcalc_in_rrdhost(host, rc) {
1003 if (unlikely(!(rc->rrdcalc_flags & RRDCALC_FLAG_RUNNABLE)))
1004 continue;
1005
@@ -1002,15 +1021,15 @@ void *health_main(void *ptr) {
1021
1022 debug(D_HEALTH,
1023 "Health on host '%s', alarm '%s.%s': warning expression failed with error: %s",
1005 - host->hostname, rc->chart ? rc->chart : "NOCHART", rc->name,
1024 + rrdhost_hostname(host), rrdcalc_chart_name(rc), rrdcalc_name(rc),
1025 buffer_tostring(rc->warning->error_msg)
1026 );
1027 } else {
1028 rc->rrdcalc_flags &= ~RRDCALC_FLAG_WARN_ERROR;
1029 debug(D_HEALTH, "Health on host '%s', alarm '%s.%s': warning expression gave value "
1030 NETDATA_DOUBLE_FORMAT
1012 - ": %s (source: %s)", host->hostname, rc->chart ? rc->chart : "NOCHART",
1013 - rc->name, rc->warning->result, buffer_tostring(rc->warning->error_msg), rc->source
1031 + ": %s (source: %s)", rrdhost_hostname(host), rrdcalc_chart_name(rc),
1032 + rrdcalc_name(rc), rc->warning->result, buffer_tostring(rc->warning->error_msg), rrdcalc_source(rc)
1033 );
1034 warning_status = rrdcalc_value2status(rc->warning->result);
1035 }
@@ -1028,16 +1047,16 @@ void *health_main(void *ptr) {
1047
1048 debug(D_HEALTH,
1049 "Health on host '%s', alarm '%s.%s': critical expression failed with error: %s",
1031 - host->hostname, rc->chart ? rc->chart : "NOCHART", rc->name,
1050 + rrdhost_hostname(host), rrdcalc_chart_name(rc), rrdcalc_name(rc),
1051 buffer_tostring(rc->critical->error_msg)
1052 );
1053 } else {
1054 rc->rrdcalc_flags &= ~RRDCALC_FLAG_CRIT_ERROR;
1055 debug(D_HEALTH, "Health on host '%s', alarm '%s.%s': critical expression gave value "
1056 NETDATA_DOUBLE_FORMAT
1038 - ": %s (source: %s)", host->hostname, rc->chart ? rc->chart : "NOCHART",
1039 - rc->name, rc->critical->result, buffer_tostring(rc->critical->error_msg),
1040 - rc->source
1057 + ": %s (source: %s)", rrdhost_hostname(host), rrdcalc_chart_name(rc),
1058 + rrdcalc_name(rc), rc->critical->result, buffer_tostring(rc->critical->error_msg),
1059 + rrdcalc_source(rc)
1060 );
1061 critical_status = rrdcalc_value2status(rc->critical->result);
1062 }
@@ -1113,15 +1132,36 @@ void *health_main(void *ptr) {
1132
1133
1134 ALARM_ENTRY *ae = health_create_alarm_entry(
1116 - host, rc->id, rc->next_event_id++, rc->config_hash_id, now, rc->name, rc->rrdset->id, rc->rrdset->context,
1117 - rc->rrdset->family, rc->classification, rc->component, rc->type, rc->exec, rc->recipient, now - rc->last_status_change,
1118 - rc->old_value, rc->value, rc->status, status, rc->source, rc->units, rc->info,
1119 - rc->delay_last,
1120 - (
1121 - ((rc->options & RRDCALC_FLAG_NO_CLEAR_NOTIFICATION)? HEALTH_ENTRY_FLAG_NO_CLEAR_NOTIFICATION : 0) |
1122 - ((rc->rrdcalc_flags & RRDCALC_FLAG_SILENCED)? HEALTH_ENTRY_FLAG_SILENCED : 0)
1135 + host,
1136 + rc->id,
1137 + rc->next_event_id++,
1138 + rc->config_hash_id,
1139 + now,
1140 + rc->name,
1141 + rc->rrdset->id,
1142 + rc->rrdset->context,
1143 + rc->rrdset->family,
1144 + rc->classification,
1145 + rc->component,
1146 + rc->type,
1147 + rc->exec,
1148 + rc->recipient,
1149 + now - rc->last_status_change,
1150 + rc->old_value,
1151 + rc->value,
1152 + rc->status,
1153 + status,
1154 + rc->source,
1155 + rc->units,
1156 + rc->info,
1157 + rc->delay_last,
1158 + (
1159 + ((rc->options & RRDCALC_FLAG_NO_CLEAR_NOTIFICATION)? HEALTH_ENTRY_FLAG_NO_CLEAR_NOTIFICATION : 0) |
1160 + ((rc->rrdcalc_flags & RRDCALC_FLAG_SILENCED)? HEALTH_ENTRY_FLAG_SILENCED : 0) |
1161 + (rrdcalc_isrepeating(rc)?HEALTH_ENTRY_FLAG_IS_REPEATING:0)
1162 )
1163 );
1164 +
1165 health_alarm_log(host, ae);
1166
1167 rc->last_status_change = now;
@@ -1138,7 +1178,7 @@ void *health_main(void *ptr) {
1178
1179 // process repeating alarms
1180 RRDCALC *rc;
1141 - for(rc = host->alarms; rc ; rc = rc->next) {
1181 + foreach_rrdcalc_in_rrdhost(host, rc) {
1182 int repeat_every = 0;
1183 if(unlikely(rrdcalc_isrepeating(rc) && rc->delay_up_to_timestamp <= now)) {
1184 if(unlikely(rc->status == RRDCALC_STATUS_WARNING)) {
@@ -1164,16 +1204,38 @@ void *health_main(void *ptr) {
1204 worker_is_busy(WORKER_HEALTH_JOB_ALARM_LOG_ENTRY);
1205 rc->last_repeat = now;
1206 if (likely(rc->times_repeat < UINT32_MAX)) rc->times_repeat++;
1207 +
1208 ALARM_ENTRY *ae = health_create_alarm_entry(
1168 - host, rc->id, rc->next_event_id++, rc->config_hash_id, now, rc->name, rc->rrdset->id, rc->rrdset->context,
1169 - rc->rrdset->family, rc->classification, rc->component, rc->type, rc->exec, rc->recipient, now - rc->last_status_change,
1170 - rc->old_value, rc->value, rc->old_status, rc->status, rc->source, rc->units, rc->info,
1171 - rc->delay_last,
1172 - (
1173 - ((rc->options & RRDCALC_FLAG_NO_CLEAR_NOTIFICATION)? HEALTH_ENTRY_FLAG_NO_CLEAR_NOTIFICATION : 0) |
1174 - ((rc->rrdcalc_flags & RRDCALC_FLAG_SILENCED)? HEALTH_ENTRY_FLAG_SILENCED : 0)
1209 + host,
1210 + rc->id,
1211 + rc->next_event_id++,
1212 + rc->config_hash_id,
1213 + now,
1214 + rc->name,
1215 + rc->rrdset->id,
1216 + rc->rrdset->context,
1217 + rc->rrdset->family,
1218 + rc->classification,
1219 + rc->component,
1220 + rc->type,
1221 + rc->exec,
1222 + rc->recipient,
1223 + now - rc->last_status_change,
1224 + rc->old_value,
1225 + rc->value,
1226 + rc->old_status,
1227 + rc->status,
1228 + rc->source,
1229 + rc->units,
1230 + rc->info,
1231 + rc->delay_last,
1232 + (
1233 + ((rc->options & RRDCALC_FLAG_NO_CLEAR_NOTIFICATION)? HEALTH_ENTRY_FLAG_NO_CLEAR_NOTIFICATION : 0) |
1234 + ((rc->rrdcalc_flags & RRDCALC_FLAG_SILENCED)? HEALTH_ENTRY_FLAG_SILENCED : 0) |
1235 + (rrdcalc_isrepeating(rc)?HEALTH_ENTRY_FLAG_IS_REPEATING:0)
1236 )
1237 );
1238 +
1239 ae->last_repeat = rc->last_repeat;
1240 if (!(rc->rrdcalc_flags & RRDCALC_FLAG_RUN_ONCE) && rc->status == RRDCALC_STATUS_CLEAR) {
1241 ae->flags |= HEALTH_ENTRY_RUN_ONCE;
health/health.h
+26 -26
@@ -14,6 +14,7 @@ extern unsigned int default_health_enabled;
14 #define HEALTH_ENTRY_FLAG_SILENCED 0x00000010
15 #define HEALTH_ENTRY_RUN_ONCE 0x00000020
16 #define HEALTH_ENTRY_FLAG_EXEC_IN_PROGRESS 0x00000040
17 +#define HEALTH_ENTRY_FLAG_IS_REPEATING 0x00000080
18
19 #define HEALTH_ENTRY_FLAG_SAVED 0x10000000
20 #define HEALTH_ENTRY_FLAG_ACLK_QUEUED 0x20000000
@@ -35,7 +36,6 @@ extern void health_init(void);
36
37 extern void health_reload(void);
38
38 -extern int health_variable_lookup(const char *variable, uint32_t hash, RRDCALC *rc, NETDATA_DOUBLE *result);
39 extern void health_aggregate_alarms(RRDHOST *host, BUFFER *wb, BUFFER* context, RRDCALC_STATUS status);
40 extern void health_alarms2json(RRDHOST *host, BUFFER *wb, int all);
41 extern void health_alarms_values2json(RRDHOST *host, BUFFER *wb, int all);
@@ -49,30 +49,30 @@ extern void health_alarm_log_save(RRDHOST *host, ALARM_ENTRY *ae);
49 extern void health_alarm_log_load(RRDHOST *host);
50
51 extern ALARM_ENTRY* health_create_alarm_entry(
52 - RRDHOST *host,
53 - uint32_t alarm_id,
54 - uint32_t alarm_event_id,
55 - uuid_t config_hash_id,
56 - time_t when,
57 - const char *name,
58 - const char *chart,
59 - const char *chart_context,
60 - const char *family,
61 - const char *classification,
62 - const char *component,
63 - const char *type,
64 - const char *exec,
65 - const char *recipient,
66 - time_t duration,
67 - NETDATA_DOUBLE old_value,
68 - NETDATA_DOUBLE new_value,
69 - RRDCALC_STATUS old_status,
70 - RRDCALC_STATUS new_status,
71 - const char *source,
72 - const char *units,
73 - const char *info,
74 - int delay,
75 - uint32_t flags);
52 + RRDHOST *host,
53 + uint32_t alarm_id,
54 + uint32_t alarm_event_id,
55 + const uuid_t config_hash_id,
56 + time_t when,
57 + STRING *name,
58 + STRING *chart,
59 + STRING *chart_context,
60 + STRING *family,
61 + STRING *classification,
62 + STRING *component,
63 + STRING *type,
64 + STRING *exec,
65 + STRING *recipient,
66 + time_t duration,
67 + NETDATA_DOUBLE old_value,
68 + NETDATA_DOUBLE new_value,
69 + RRDCALC_STATUS old_status,
70 + RRDCALC_STATUS new_status,
71 + STRING *source,
72 + STRING *units,
73 + STRING *info,
74 + int delay,
75 + uint32_t flags);
76
77 extern void health_alarm_log(RRDHOST *host, ALARM_ENTRY *ae);
78
@@ -90,6 +90,6 @@ extern void health_label_log_save(RRDHOST *host);
90 extern char *health_edit_command_from_source(const char *source);
91 extern void sql_refresh_hashes(void);
92
93 -extern SIMPLE_PATTERN *health_pattern_from_foreach(char *s);
93 +extern SIMPLE_PATTERN *health_pattern_from_foreach(const char *s);
94
95 #endif //NETDATA_HEALTH_H
health/health_config.c
+297 -295
@@ -35,21 +35,21 @@
35
36 static inline int rrdcalc_add_alarm_from_config(RRDHOST *host, RRDCALC *rc) {
37 if(!rc->chart) {
38 - error("Health configuration for alarm '%s' does not have a chart", rc->name);
38 + error("Health configuration for alarm '%s' does not have a chart", rrdcalc_name(rc));
39 return 0;
40 }
41
42 if(!rc->update_every) {
43 - error("Health configuration for alarm '%s.%s' has no frequency (parameter 'every'). Ignoring it.", rc->chart?rc->chart:"NOCHART", rc->name);
43 + error("Health configuration for alarm '%s.%s' has no frequency (parameter 'every'). Ignoring it.", rrdcalc_chart_name(rc), rrdcalc_name(rc));
44 return 0;
45 }
46
47 if(!RRDCALC_HAS_DB_LOOKUP(rc) && !rc->calculation && !rc->warning && !rc->critical) {
48 - error("Health configuration for alarm '%s.%s' is useless (no db lookup, no calculation, no warning and no critical expressions)", rc->chart?rc->chart:"NOCHART", rc->name);
48 + error("Health configuration for alarm '%s.%s' is useless (no db lookup, no calculation, no warning and no critical expressions)", rrdcalc_chart_name(rc), rrdcalc_name(rc));
49 return 0;
50 }
51
52 - if (rrdcalc_exists(host, rc->chart, rc->name, rc->hash_chart, rc->hash))
52 + if (rrdcalc_exists(host, rrdcalc_chart_name(rc), rrdcalc_name(rc)))
53 return 0;
54
55 rc->id = rrdcalc_get_unique_id(host, rc->chart, rc->name, &rc->next_event_id);
@@ -57,24 +57,24 @@ static inline int rrdcalc_add_alarm_from_config(RRDHOST *host, RRDCALC *rc) {
57 debug(D_HEALTH, "Health configuration adding alarm '%s.%s' (%u): exec '%s', recipient '%s', green " NETDATA_DOUBLE_FORMAT_AUTO
58 ", red " NETDATA_DOUBLE_FORMAT_AUTO
59 ", lookup: group %d, after %d, before %d, options %u, dimensions '%s', for each dimension '%s', update every %d, calculation '%s', warning '%s', critical '%s', source '%s', delay up %d, delay down %d, delay max %d, delay_multiplier %f, warn_repeat_every %u, crit_repeat_every %u",
60 - rc->chart?rc->chart:"NOCHART",
61 - rc->name,
60 + rrdcalc_chart_name(rc),
61 + rrdcalc_name(rc),
62 rc->id,
63 - (rc->exec)?rc->exec:"DEFAULT",
64 - (rc->recipient)?rc->recipient:"DEFAULT",
63 + (rc->exec)?rrdcalc_exec(rc):"DEFAULT",
64 + (rc->recipient)?rrdcalc_recipient(rc):"DEFAULT",
65 rc->green,
66 rc->red,
67 (int)rc->group,
68 rc->after,
69 rc->before,
70 rc->options,
71 - (rc->dimensions)?rc->dimensions:"NONE",
72 - (rc->foreachdim)?rc->foreachdim:"NONE",
71 + (rc->dimensions)?rrdcalc_dimensions(rc):"NONE",
72 + (rc->foreachdim)?rrdcalc_foreachdim(rc):"NONE",
73 rc->update_every,
74 (rc->calculation)?rc->calculation->parsed_as:"NONE",
75 (rc->warning)?rc->warning->parsed_as:"NONE",
76 (rc->critical)?rc->critical->parsed_as:"NONE",
77 - rc->source,
77 + rrdcalc_source(rc),
78 rc->delay_up_duration,
79 rc->delay_down_duration,
80 rc->delay_max_duration,
@@ -90,79 +90,53 @@ static inline int rrdcalc_add_alarm_from_config(RRDHOST *host, RRDCALC *rc) {
90
91 static inline int rrdcalctemplate_add_template_from_config(RRDHOST *host, RRDCALCTEMPLATE *rt) {
92 if(unlikely(!rt->context)) {
93 - error("Health configuration for template '%s' does not have a context", rt->name);
93 + error("Health configuration for template '%s' does not have a context", rrdcalctemplate_name(rt));
94 return 0;
95 }
96
97 if(unlikely(!rt->update_every)) {
98 - error("Health configuration for template '%s' has no frequency (parameter 'every'). Ignoring it.", rt->name);
98 + error("Health configuration for template '%s' has no frequency (parameter 'every'). Ignoring it.", rrdcalctemplate_name(rt));
99 return 0;
100 }
101
102 if(unlikely(!RRDCALCTEMPLATE_HAS_DB_LOOKUP(rt) && !rt->calculation && !rt->warning && !rt->critical)) {
103 - error("Health configuration for template '%s' is useless (no calculation, no warning and no critical evaluation)", rt->name);
103 + error("Health configuration for template '%s' is useless (no calculation, no warning and no critical evaluation)", rrdcalctemplate_name(rt));
104 return 0;
105 }
106
107 - RRDCALCTEMPLATE *t, *last = NULL;
108 - if(!rt->foreachdim) {
109 - for (t = host->templates; t ; last = t, t = t->next) {
110 - if(unlikely(t->hash_name == rt->hash_name
111 - && !strcmp(t->name, rt->name)
112 - && !strcmp(t->family_match?t->family_match:"*", rt->family_match?rt->family_match:"*")
113 - )) {
114 - info("Health configuration template '%s' already exists for host '%s'.", rt->name, host->hostname);
115 - return 0;
116 - }
117 - }
118 -
119 - if(likely(last)) {
120 - last->next = rt;
121 - }
122 - else {
123 - rt->next = host->templates;
124 - host->templates = rt;
125 - }
126 - } else {
127 - for (t = host->alarms_template_with_foreach; t ; last = t, t = t->next) {
128 - if(unlikely(t->hash_name == rt->hash_name
129 - && !strcmp(t->name, rt->name)
130 - && !strcmp(t->family_match?t->family_match:"*", rt->family_match?rt->family_match:"*")
131 - )) {
132 - info("Health configuration template '%s' already exists for host '%s'.", rt->name, host->hostname);
133 - return 0;
134 - }
135 - }
136 -
137 - if(likely(last)) {
138 - last->next = rt;
139 - }
140 - else {
141 - rt->next = host->alarms_template_with_foreach;
142 - host->alarms_template_with_foreach = rt;
107 + RRDCALCTEMPLATE *t;
108 + foreach_rrdcalctemplate_in_rrdhost(host, t) {
109 + if(unlikely(t->name == rt->name && !strcmp(t->family_match?rrdcalctemplate_family_match(t):"*", rt->family_match?rrdcalctemplate_family_match(rt):"*"))) {
110 + info("Health configuration template '%s' already exists for host '%s'.", rrdcalctemplate_name(rt), rrdhost_hostname(host));
111 + return 0;
112 }
113 }
114
115 + if(rt->foreachdim)
116 + DOUBLE_LINKED_LIST_PREPEND_UNSAFE(host->alarms_templates, rt, prev, next);
117 + else
118 + DOUBLE_LINKED_LIST_APPEND_UNSAFE(host->alarms_templates, rt, prev, next);
119 +
120 debug(D_HEALTH, "Health configuration adding template '%s': context '%s', exec '%s', recipient '%s', green " NETDATA_DOUBLE_FORMAT_AUTO
121 ", red " NETDATA_DOUBLE_FORMAT_AUTO
122 ", lookup: group %d, after %d, before %d, options %u, dimensions '%s', for each dimension '%s', update every %d, calculation '%s', warning '%s', critical '%s', source '%s', delay up %d, delay down %d, delay max %d, delay_multiplier %f, warn_repeat_every %u, crit_repeat_every %u",
149 - rt->name,
150 - (rt->context)?rt->context:"NONE",
151 - (rt->exec)?rt->exec:"DEFAULT",
152 - (rt->recipient)?rt->recipient:"DEFAULT",
123 + rrdcalctemplate_name(rt),
124 + (rt->context)?string2str(rt->context):"NONE",
125 + (rt->exec)?rrdcalctemplate_exec(rt):"DEFAULT",
126 + (rt->recipient)?rrdcalctemplate_recipient(rt):"DEFAULT",
127 rt->green,
128 rt->red,
129 (int)rt->group,
130 rt->after,
131 rt->before,
132 rt->options,
159 - (rt->dimensions)?rt->dimensions:"NONE",
160 - (rt->foreachdim)?rt->foreachdim:"NONE",
133 + (rt->dimensions)?rrdcalctemplate_dimensions(rt):"NONE",
134 + (rt->foreachdim)?rrdcalctemplate_foreachdim(rt):"NONE",
135 rt->update_every,
136 (rt->calculation)?rt->calculation->parsed_as:"NONE",
137 (rt->warning)?rt->warning->parsed_as:"NONE",
138 (rt->critical)?rt->critical->parsed_as:"NONE",
165 - rt->source,
139 + rrdcalctemplate_source(rt),
140 rt->delay_up_duration,
141 rt->delay_down_duration,
142 rt->delay_max_duration,
@@ -334,7 +308,7 @@ static inline int health_parse_repeat(
308 *
309 * @param s the string that will be used to create the simple pattern.
310 */
337 -SIMPLE_PATTERN *health_pattern_from_foreach(char *s) {
311 +SIMPLE_PATTERN *health_pattern_from_foreach(const char *s) {
312 char *convert= strdupz(s);
313 SIMPLE_PATTERN *val = NULL;
314 if(convert) {
@@ -350,12 +324,12 @@ SIMPLE_PATTERN *health_pattern_from_foreach(char *s) {
324 static inline int health_parse_db_lookup(
325 size_t line, const char *filename, char *string,
326 RRDR_GROUPING *group_method, int *after, int *before, int *every,
353 - uint32_t *options, char **dimensions, char **foreachdim
327 + uint32_t *options, STRING **dimensions, STRING **foreachdim
328 ) {
329 debug(D_HEALTH, "Health configuration parsing database lookup %zu@%s: %s", line, filename, string);
330
357 - if(*dimensions) freez(*dimensions);
358 - if(*foreachdim) freez(*foreachdim);
331 + if(*dimensions) string_freez(*dimensions);
332 + if(*foreachdim) string_freez(*foreachdim);
333 *dimensions = NULL;
334 *foreachdim = NULL;
335 *after = 0;
@@ -453,7 +427,7 @@ static inline int health_parse_db_lookup(
427 if(find) {
428 *find = '\0';
429 }
456 - *dimensions = strdupz(s);
430 + *dimensions = string_strdupz(s);
431 }
432
433 if(!find) {
@@ -462,7 +436,7 @@ static inline int health_parse_db_lookup(
436 s = ++find;
437 }
438 else if(!strcasecmp(key, HEALTH_FOREACH_KEY )) {
465 - *foreachdim = strdupz(s);
439 + *foreachdim = string_strdupz(s);
440 break;
441 }
442 else {
@@ -474,10 +448,10 @@ static inline int health_parse_db_lookup(
448 return 1;
449 }
450
477 -static inline char *health_source_file(size_t line, const char *file) {
451 +static inline STRING *health_source_file(size_t line, const char *file) {
452 char buffer[FILENAME_MAX + 1];
453 snprintfz(buffer, FILENAME_MAX, "%zu@%s", line, file);
480 - return strdupz(buffer);
454 + return string_strdupz(buffer);
455 }
456
457 char *health_edit_command_from_source(const char *source)
@@ -496,7 +470,7 @@ char *health_edit_command_from_source(const char *source)
470 netdata_configured_user_config_dir,
471 file_no_path + 1,
472 temp,
499 - localhost->registry_hostname);
473 + rrdhost_registry_hostname(localhost));
474 } else
475 buffer[0] = '\0';
476
@@ -513,35 +487,35 @@ static inline void strip_quotes(char *s) {
487
488 static inline void alert_config_free(struct alert_config *cfg)
489 {
516 - freez(cfg->alarm);
517 - freez(cfg->template_key);
518 - freez(cfg->os);
519 - freez(cfg->host);
520 - freez(cfg->on);
521 - freez(cfg->families);
522 - freez(cfg->plugin);
523 - freez(cfg->module);
524 - freez(cfg->charts);
525 - freez(cfg->lookup);
526 - freez(cfg->calc);
527 - freez(cfg->warn);
528 - freez(cfg->crit);
529 - freez(cfg->every);
530 - freez(cfg->green);
531 - freez(cfg->red);
532 - freez(cfg->exec);
533 - freez(cfg->to);
534 - freez(cfg->units);
535 - freez(cfg->info);
536 - freez(cfg->classification);
537 - freez(cfg->component);
538 - freez(cfg->type);
539 - freez(cfg->delay);
540 - freez(cfg->options);
541 - freez(cfg->repeat);
542 - freez(cfg->host_labels);
543 - freez(cfg->p_db_lookup_dimensions);
544 - freez(cfg->p_db_lookup_method);
490 + string_freez(cfg->alarm);
491 + string_freez(cfg->template_key);
492 + string_freez(cfg->os);
493 + string_freez(cfg->host);
494 + string_freez(cfg->on);
495 + string_freez(cfg->families);
496 + string_freez(cfg->plugin);
497 + string_freez(cfg->module);
498 + string_freez(cfg->charts);
499 + string_freez(cfg->lookup);
500 + string_freez(cfg->calc);
501 + string_freez(cfg->warn);
502 + string_freez(cfg->crit);
503 + string_freez(cfg->every);
504 + string_freez(cfg->green);
505 + string_freez(cfg->red);
506 + string_freez(cfg->exec);
507 + string_freez(cfg->to);
508 + string_freez(cfg->units);
509 + string_freez(cfg->info);
510 + string_freez(cfg->classification);
511 + string_freez(cfg->component);
512 + string_freez(cfg->type);
513 + string_freez(cfg->delay);
514 + string_freez(cfg->options);
515 + string_freez(cfg->repeat);
516 + string_freez(cfg->host_labels);
517 + string_freez(cfg->p_db_lookup_dimensions);
518 + string_freez(cfg->p_db_lookup_method);
519 freez(cfg);
520 }
521
@@ -685,7 +659,16 @@ static int health_readfile(const char *filename, void *data) {
659
660 rc = callocz(1, sizeof(RRDCALC));
661 rc->next_event_id = 1;
688 - rc->name = strdupz(value);
662 +
663 + {
664 + char *tmp = strdupz(value);
665 + if(rrdvar_fix_name(tmp))
666 + error("Health configuration renamed alarm '%s' to '%s'", value, tmp);
667 +
668 + rc->name = string_strdupz(tmp);
669 + freez(tmp);
670 + }
671 +
672 rc->source = health_source_file(line, filename);
673 rc->green = NAN;
674 rc->red = NAN;
@@ -699,59 +682,58 @@ static int health_readfile(const char *filename, void *data) {
682 alert_config_free(alert_cfg);
683 alert_cfg = callocz(1, sizeof(struct alert_config));
684
702 - if(rrdvar_fix_name(rc->name))
703 - error("Health configuration renamed alarm '%s' to '%s'", value, rc->name);
704 -
705 - rc->hash = simple_hash(rc->name);
706 - alert_cfg->alarm = strdupz(rc->name);
685 + alert_cfg->alarm = string_dup(rc->name);
686 ignore_this = 0;
687 }
688 else if(hash == hash_template && !strcasecmp(key, HEALTH_TEMPLATE_KEY)) {
689 if(rc) {
690 // health_add_alarms_loop(host, rc, ignore_this) ;
712 - if(!alert_hash_and_store_config(rc->config_hash_id, alert_cfg, sql_store_hashes) || ignore_this || !rrdcalc_add_alarm_from_config(host, rc)) {
691 + if(!alert_hash_and_store_config(rc->config_hash_id, alert_cfg, sql_store_hashes) || ignore_this || !rrdcalc_add_alarm_from_config(host, rc))
692 rrdcalc_free(rc);
714 - }
693
694 rc = NULL;
695 }
696
697 if(rt) {
720 - if(!alert_hash_and_store_config(rt->config_hash_id, alert_cfg, sql_store_hashes) || ignore_this || !rrdcalctemplate_add_template_from_config(host, rt)) {
698 + if(!alert_hash_and_store_config(rt->config_hash_id, alert_cfg, sql_store_hashes) || ignore_this || !rrdcalctemplate_add_template_from_config(host, rt))
699 rrdcalctemplate_free(rt);
722 - }
700 }
701
702 rt = callocz(1, sizeof(RRDCALCTEMPLATE));
726 - rt->name = strdupz(value);
703 +
704 + {
705 + char *tmp = strdupz(value);
706 + if(rrdvar_fix_name(tmp))
707 + error("Health configuration renamed template '%s' to '%s'", value, tmp);
708 +
709 + rt->name = string_strdupz(tmp);
710 + freez(tmp);
711 + }
712 +
713 rt->source = health_source_file(line, filename);
714 rt->green = NAN;
715 rt->red = NAN;
730 - rt->delay_multiplier = 1.0;
716 + rt->delay_multiplier = (float)1.0;
717 rt->warn_repeat_every = host->health_default_warn_repeat_every;
718 rt->crit_repeat_every = host->health_default_crit_repeat_every;
719 if (alert_cfg)
720 alert_config_free(alert_cfg);
721 alert_cfg = callocz(1, sizeof(struct alert_config));
722
737 - if(rrdvar_fix_name(rt->name))
738 - error("Health configuration renamed template '%s' to '%s'", value, rt->name);
739 -
740 - rt->hash_name = simple_hash(rt->name);
741 - alert_cfg->template_key = strdupz(rt->name);
723 + alert_cfg->template_key = string_dup(rt->name);
724 ignore_this = 0;
725 }
726 else if(hash == hash_os && !strcasecmp(key, HEALTH_OS_KEY)) {
727 char *os_match = value;
746 - if (alert_cfg) alert_cfg->os = strdupz(value);
728 + if (alert_cfg) alert_cfg->os = string_strdupz(value);
729 SIMPLE_PATTERN *os_pattern = simple_pattern_create(os_match, NULL, SIMPLE_PATTERN_EXACT);
730
749 - if(!simple_pattern_matches(os_pattern, host->os)) {
731 + if(!simple_pattern_matches(os_pattern, rrdhost_os(host))) {
732 if(rc)
751 - debug(D_HEALTH, "HEALTH on '%s' ignoring alarm '%s' defined at %zu@%s: host O/S does not match '%s'", host->hostname, rc->name, line, filename, os_match);
733 + debug(D_HEALTH, "HEALTH on '%s' ignoring alarm '%s' defined at %zu@%s: host O/S does not match '%s'", rrdhost_hostname(host), rrdcalc_name(rc), line, filename, os_match);
734
735 if(rt)
754 - debug(D_HEALTH, "HEALTH on '%s' ignoring template '%s' defined at %zu@%s: host O/S does not match '%s'", host->hostname, rt->name, line, filename, os_match);
736 + debug(D_HEALTH, "HEALTH on '%s' ignoring template '%s' defined at %zu@%s: host O/S does not match '%s'", rrdhost_hostname(host), rrdcalctemplate_name(rt), line, filename, os_match);
737
738 ignore_this = 1;
739 }
@@ -760,15 +742,15 @@ static int health_readfile(const char *filename, void *data) {
742 }
743 else if(hash == hash_host && !strcasecmp(key, HEALTH_HOST_KEY)) {
744 char *host_match = value;
763 - if (alert_cfg) alert_cfg->host = strdupz(value);
745 + if (alert_cfg) alert_cfg->host = string_strdupz(value);
746 SIMPLE_PATTERN *host_pattern = simple_pattern_create(host_match, NULL, SIMPLE_PATTERN_EXACT);
747
766 - if(!simple_pattern_matches(host_pattern, host->hostname)) {
748 + if(!simple_pattern_matches(host_pattern, rrdhost_hostname(host))) {
749 if(rc)
768 - debug(D_HEALTH, "HEALTH on '%s' ignoring alarm '%s' defined at %zu@%s: hostname does not match '%s'", host->hostname, rc->name, line, filename, host_match);
750 + debug(D_HEALTH, "HEALTH on '%s' ignoring alarm '%s' defined at %zu@%s: hostname does not match '%s'", rrdhost_hostname(host), rrdcalc_name(rc), line, filename, host_match);
751
752 if(rt)
771 - debug(D_HEALTH, "HEALTH on '%s' ignoring template '%s' defined at %zu@%s: hostname does not match '%s'", host->hostname, rt->name, line, filename, host_match);
753 + debug(D_HEALTH, "HEALTH on '%s' ignoring template '%s' defined at %zu@%s: hostname does not match '%s'", rrdhost_hostname(host), rrdcalctemplate_name(rt), line, filename, host_match);
754
755 ignore_this = 1;
756 }
@@ -777,65 +759,68 @@ static int health_readfile(const char *filename, void *data) {
759 }
760 else if(rc) {
761 if(hash == hash_on && !strcasecmp(key, HEALTH_ON_KEY)) {
780 - alert_cfg->on = strdupz(value);
762 + alert_cfg->on = string_strdupz(value);
763 if(rc->chart) {
782 - if(strcmp(rc->chart, value) != 0)
764 + if(strcmp(rrdcalc_chart_name(rc), value) != 0)
765 error("Health configuration at line %zu of file '%s' for alarm '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
784 - line, filename, rc->name, key, rc->chart, value, value);
766 + line, filename, rrdcalc_name(rc), key, rrdcalc_chart_name(rc), value, value);
767
786 - freez(rc->chart);
768 + string_freez(rc->chart);
769 }
788 - rc->chart = strdupz(value);
789 - rc->hash_chart = simple_hash(rc->chart);
770 + rc->chart = string_strdupz(value);
771 }
772 else if(hash == hash_class && !strcasecmp(key, HEALTH_CLASS_KEY)) {
792 - alert_cfg->classification = strdupz(value);
773 + strip_quotes(value);
774 +
775 + alert_cfg->classification = string_strdupz(value);
776 if(rc->classification) {
794 - if(strcmp(rc->classification, value) != 0)
777 + if(strcmp(rrdcalc_classification(rc), value) != 0)
778 error("Health configuration at line %zu of file '%s' for alarm '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
796 - line, filename, rc->name, key, rc->classification, value, value);
779 + line, filename, rrdcalc_name(rc), key, rrdcalc_classification(rc), value, value);
780
798 - freez(rc->classification);
781 + string_freez(rc->classification);
782 }
800 - rc->classification = strdupz(value);
801 - strip_quotes(rc->classification);
783 + rc->classification = string_strdupz(value);
784 }
785 else if(hash == hash_component && !strcasecmp(key, HEALTH_COMPONENT_KEY)) {
804 - alert_cfg->component = strdupz(value);
786 + strip_quotes(value);
787 +
788 + alert_cfg->component = string_strdupz(value);
789 if(rc->component) {
806 - if(strcmp(rc->component, value) != 0)
790 + if(strcmp(rrdcalc_component(rc), value) != 0)
791 error("Health configuration at line %zu of file '%s' for alarm '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
808 - line, filename, rc->name, key, rc->component, value, value);
792 + line, filename, rrdcalc_name(rc), key, rrdcalc_component(rc), value, value);
793
810 - freez(rc->component);
794 + string_freez(rc->component);
795 }
812 - rc->component = strdupz(value);
813 - strip_quotes(rc->component);
796 + rc->component = string_strdupz(value);
797 }
798 else if(hash == hash_type && !strcasecmp(key, HEALTH_TYPE_KEY)) {
816 - alert_cfg->type = strdupz(value);
799 + strip_quotes(value);
800 +
801 + alert_cfg->type = string_strdupz(value);
802 if(rc->type) {
818 - if(strcmp(rc->type, value) != 0)
803 + if(strcmp(rrdcalc_type(rc), value) != 0)
804 error("Health configuration at line %zu of file '%s' for alarm '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
820 - line, filename, rc->name, key, rc->type, value, value);
805 + line, filename, rrdcalc_name(rc), key, rrdcalc_type(rc), value, value);
806
822 - freez(rc->type);
807 + string_freez(rc->type);
808 }
824 - rc->type = strdupz(value);
825 - strip_quotes(rc->type);
809 + rc->type = string_strdupz(value);
810 }
811 else if(hash == hash_lookup && !strcasecmp(key, HEALTH_LOOKUP_KEY)) {
828 - alert_cfg->lookup = strdupz(value);
812 + alert_cfg->lookup = string_strdupz(value);
813 health_parse_db_lookup(line, filename, value, &rc->group, &rc->after, &rc->before,
814 &rc->update_every, &rc->options, &rc->dimensions, &rc->foreachdim);
831 - if(rc->foreachdim) {
832 - rc->spdim = health_pattern_from_foreach(rc->foreachdim);
833 - }
815 +
816 + if(rc->foreachdim)
817 + rc->spdim = health_pattern_from_foreach(rrdcalc_foreachdim(rc));
818 +
819 if (rc->after) {
820 if (rc->dimensions)
836 - alert_cfg->p_db_lookup_dimensions = strdupz(rc->dimensions);
821 + alert_cfg->p_db_lookup_dimensions = string_dup(rc->dimensions);
822 if (rc->group)
838 - alert_cfg->p_db_lookup_method = strdupz(group_method2string(rc->group));
823 + alert_cfg->p_db_lookup_method = string_strdupz(group_method2string(rc->group));
824 alert_cfg->p_db_lookup_options = rc->options;
825 alert_cfg->p_db_lookup_after = rc->after;
826 alert_cfg->p_db_lookup_before = rc->before;
@@ -843,250 +828,261 @@ static int health_readfile(const char *filename, void *data) {
828 }
829 }
830 else if(hash == hash_every && !strcasecmp(key, HEALTH_EVERY_KEY)) {
846 - alert_cfg->every = strdupz(value);
831 + alert_cfg->every = string_strdupz(value);
832 if(!config_parse_duration(value, &rc->update_every))
833 error("Health configuration at line %zu of file '%s' for alarm '%s' at key '%s' cannot parse duration: '%s'.",
849 - line, filename, rc->name, key, value);
834 + line, filename, rrdcalc_name(rc), key, value);
835 alert_cfg->p_update_every = rc->update_every;
836 }
837 else if(hash == hash_green && !strcasecmp(key, HEALTH_GREEN_KEY)) {
853 - alert_cfg->green = strdupz(value);
838 + alert_cfg->green = string_strdupz(value);
839 char *e;
840 rc->green = str2ndd(value, &e);
841 if(e && *e) {
842 error("Health configuration at line %zu of file '%s' for alarm '%s' at key '%s' leaves this string unmatched: '%s'.",
858 - line, filename, rc->name, key, e);
843 + line, filename, rrdcalc_name(rc), key, e);
844 }
845 }
846 else if(hash == hash_red && !strcasecmp(key, HEALTH_RED_KEY)) {
862 - alert_cfg->red = strdupz(value);
847 + alert_cfg->red = string_strdupz(value);
848 char *e;
849 rc->red = str2ndd(value, &e);
850 if(e && *e) {
851 error("Health configuration at line %zu of file '%s' for alarm '%s' at key '%s' leaves this string unmatched: '%s'.",
867 - line, filename, rc->name, key, e);
852 + line, filename, rrdcalc_name(rc), key, e);
853 }
854 }
855 else if(hash == hash_calc && !strcasecmp(key, HEALTH_CALC_KEY)) {
871 - alert_cfg->calc = strdupz(value);
856 + alert_cfg->calc = string_strdupz(value);
857 const char *failed_at = NULL;
858 int error = 0;
859 rc->calculation = expression_parse(value, &failed_at, &error);
860 if(!rc->calculation) {
861 error("Health configuration at line %zu of file '%s' for alarm '%s' at key '%s' has unparse-able expression '%s': %s at '%s'",
877 - line, filename, rc->name, key, value, expression_strerror(error), failed_at);
862 + line, filename, rrdcalc_name(rc), key, value, expression_strerror(error), failed_at);
863 }
864 }
865 else if(hash == hash_warn && !strcasecmp(key, HEALTH_WARN_KEY)) {
881 - alert_cfg->warn = strdupz(value);
866 + alert_cfg->warn = string_strdupz(value);
867 const char *failed_at = NULL;
868 int error = 0;
869 rc->warning = expression_parse(value, &failed_at, &error);
870 if(!rc->warning) {
871 error("Health configuration at line %zu of file '%s' for alarm '%s' at key '%s' has unparse-able expression '%s': %s at '%s'",
887 - line, filename, rc->name, key, value, expression_strerror(error), failed_at);
872 + line, filename, rrdcalc_name(rc), key, value, expression_strerror(error), failed_at);
873 }
874 }
875 else if(hash == hash_crit && !strcasecmp(key, HEALTH_CRIT_KEY)) {
891 - alert_cfg->crit = strdupz(value);
876 + alert_cfg->crit = string_strdupz(value);
877 const char *failed_at = NULL;
878 int error = 0;
879 rc->critical = expression_parse(value, &failed_at, &error);
880 if(!rc->critical) {
881 error("Health configuration at line %zu of file '%s' for alarm '%s' at key '%s' has unparse-able expression '%s': %s at '%s'",
897 - line, filename, rc->name, key, value, expression_strerror(error), failed_at);
882 + line, filename, rrdcalc_name(rc), key, value, expression_strerror(error), failed_at);
883 }
884 }
885 else if(hash == hash_exec && !strcasecmp(key, HEALTH_EXEC_KEY)) {
901 - alert_cfg->exec = strdupz(value);
886 + alert_cfg->exec = string_strdupz(value);
887 if(rc->exec) {
903 - if(strcmp(rc->exec, value) != 0)
888 + if(strcmp(rrdcalc_exec(rc), value) != 0)
889 error("Health configuration at line %zu of file '%s' for alarm '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
905 - line, filename, rc->name, key, rc->exec, value, value);
890 + line, filename, rrdcalc_name(rc), key, rrdcalc_exec(rc), value, value);
891
907 - freez(rc->exec);
892 + string_freez(rc->exec);
893 }
909 - rc->exec = strdupz(value);
894 + rc->exec = string_strdupz(value);
895 }
896 else if(hash == hash_recipient && !strcasecmp(key, HEALTH_RECIPIENT_KEY)) {
912 - alert_cfg->to = strdupz(value);
897 + alert_cfg->to = string_strdupz(value);
898 if(rc->recipient) {
914 - if(strcmp(rc->recipient, value) != 0)
899 + if(strcmp(rrdcalc_recipient(rc), value) != 0)
900 error("Health configuration at line %zu of file '%s' for alarm '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
916 - line, filename, rc->name, key, rc->recipient, value, value);
901 + line, filename, rrdcalc_name(rc), key, rrdcalc_recipient(rc), value, value);
902
918 - freez(rc->recipient);
903 + string_freez(rc->recipient);
904 }
920 - rc->recipient = strdupz(value);
905 + rc->recipient = string_strdupz(value);
906 }
907 else if(hash == hash_units && !strcasecmp(key, HEALTH_UNITS_KEY)) {
923 - alert_cfg->units = strdupz(value);
908 + strip_quotes(value);
909 +
910 + alert_cfg->units = string_strdupz(value);
911 if(rc->units) {
925 - if(strcmp(rc->units, value) != 0)
912 + if(strcmp(rrdcalc_units(rc), value) != 0)
913 error("Health configuration at line %zu of file '%s' for alarm '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
927 - line, filename, rc->name, key, rc->units, value, value);
914 + line, filename, rrdcalc_name(rc), key, rrdcalc_units(rc), value, value);
915
929 - freez(rc->units);
916 + string_freez(rc->units);
917 }
931 - rc->units = strdupz(value);
932 - strip_quotes(rc->units);
918 + rc->units = string_strdupz(value);
919 }
920 else if(hash == hash_info && !strcasecmp(key, HEALTH_INFO_KEY)) {
935 - alert_cfg->info = strdupz(value);
921 + strip_quotes(value);
922 +
923 + alert_cfg->info = string_strdupz(value);
924 if(rc->info) {
937 - if(strcmp(rc->info, value) != 0)
925 + if(strcmp(rrdcalc_info(rc), value) != 0)
926 error("Health configuration at line %zu of file '%s' for alarm '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
939 - line, filename, rc->name, key, rc->info, value, value);
927 + line, filename, rrdcalc_name(rc), key, rrdcalc_info(rc), value, value);
928
941 - freez(rc->info);
929 + string_freez(rc->info);
930 + string_freez(rc->original_info);
931 }
943 - rc->info = strdupz(value);
944 - strip_quotes(rc->info);
945 - rc->original_info = strdupz(value);
946 - strip_quotes(rc->original_info);
932 + rc->info = string_strdupz(value);
933 + rc->original_info = string_dup(rc->info);
934 }
935 else if(hash == hash_delay && !strcasecmp(key, HEALTH_DELAY_KEY)) {
949 - alert_cfg->delay = strdupz(value);
936 + alert_cfg->delay = string_strdupz(value);
937 health_parse_delay(line, filename, value, &rc->delay_up_duration, &rc->delay_down_duration, &rc->delay_max_duration, &rc->delay_multiplier);
938 }
939 else if(hash == hash_options && !strcasecmp(key, HEALTH_OPTIONS_KEY)) {
953 - alert_cfg->options = strdupz(value);
940 + alert_cfg->options = string_strdupz(value);
941 rc->options |= health_parse_options(value);
942 }
943 else if(hash == hash_repeat && !strcasecmp(key, HEALTH_REPEAT_KEY)){
957 - alert_cfg->repeat = strdupz(value);
944 + alert_cfg->repeat = string_strdupz(value);
945 health_parse_repeat(line, filename, value,
946 &rc->warn_repeat_every,
947 &rc->crit_repeat_every);
948 }
949 else if(hash == hash_host_label && !strcasecmp(key, HEALTH_HOST_LABEL_KEY)) {
963 - alert_cfg->host_labels = strdupz(value);
950 + alert_cfg->host_labels = string_strdupz(value);
951 if(rc->host_labels) {
965 - if(strcmp(rc->host_labels, value) != 0)
952 + if(strcmp(rrdcalc_host_labels(rc), value) != 0)
953 error("Health configuration at line %zu of file '%s' for alarm '%s' has key '%s' twice, once with value '%s' and later with value '%s'.",
967 - line, filename, rc->name, key, value, value);
954 + line, filename, rrdcalc_name(rc), key, value, value);
955
969 - freez(rc->host_labels);
956 + string_freez(rc->host_labels);
957 simple_pattern_free(rc->host_labels_pattern);
958 }
959
973 - rc->host_labels = simple_pattern_trim_around_equal(value);
974 - rc->host_labels_pattern = simple_pattern_create(rc->host_labels, NULL, SIMPLE_PATTERN_EXACT);
960 + {
961 + char *tmp = simple_pattern_trim_around_equal(value);
962 + rc->host_labels = string_strdupz(tmp);
963 + freez(tmp);
964 + }
965 + rc->host_labels_pattern = simple_pattern_create(rrdcalc_host_labels(rc), NULL, SIMPLE_PATTERN_EXACT);
966 }
967 else if(hash == hash_plugin && !strcasecmp(key, HEALTH_PLUGIN_KEY)) {
977 - alert_cfg->plugin = strdupz(value);
978 - freez(rc->plugin_match);
968 + alert_cfg->plugin = string_strdupz(value);
969 + string_freez(rc->plugin_match);
970 simple_pattern_free(rc->plugin_pattern);
971
981 - rc->plugin_match = strdupz(value);
982 - rc->plugin_pattern = simple_pattern_create(rc->plugin_match, NULL, SIMPLE_PATTERN_EXACT);
972 + rc->plugin_match = string_strdupz(value);
973 + rc->plugin_pattern = simple_pattern_create(rrdcalc_plugin_match(rc), NULL, SIMPLE_PATTERN_EXACT);
974 }
975 else if(hash == hash_module && !strcasecmp(key, HEALTH_MODULE_KEY)) {
985 - alert_cfg->module = strdupz(value);
986 - freez(rc->module_match);
976 + alert_cfg->module = string_strdupz(value);
977 + string_freez(rc->module_match);
978 simple_pattern_free(rc->module_pattern);
979
989 - rc->module_match = strdupz(value);
990 - rc->module_pattern = simple_pattern_create(rc->module_match, NULL, SIMPLE_PATTERN_EXACT);
980 + rc->module_match = string_strdupz(value);
981 + rc->module_pattern = simple_pattern_create(rrdcalc_module_match(rc), NULL, SIMPLE_PATTERN_EXACT);
982 }
983 else {
984 error("Health configuration at line %zu of file '%s' for alarm '%s' has unknown key '%s'.",
994 - line, filename, rc->name, key);
985 + line, filename, rrdcalc_name(rc), key);
986 }
987 }
988 else if(rt) {
989 if(hash == hash_on && !strcasecmp(key, HEALTH_ON_KEY)) {
999 - alert_cfg->on = strdupz(value);
990 + alert_cfg->on = string_strdupz(value);
991 if(rt->context) {
1001 - if(strcmp(rt->context, value) != 0)
992 + if(strcmp(string2str(rt->context), value) != 0)
993 error("Health configuration at line %zu of file '%s' for template '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
1003 - line, filename, rt->name, key, rt->context, value, value);
994 + line, filename, rrdcalctemplate_name(rt), key, string2str(rt->context), value, value);
995
1005 - freez(rt->context);
996 + string_freez(rt->context);
997 }
1007 - rt->context = strdupz(value);
1008 - rt->hash_context = simple_hash(rt->context);
998 + rt->context = string_strdupz(value);
999 }
1000 else if(hash == hash_class && !strcasecmp(key, HEALTH_CLASS_KEY)) {
1011 - alert_cfg->classification = strdupz(value);
1001 + strip_quotes(value);
1002 +
1003 + alert_cfg->classification = string_strdupz(value);
1004 if(rt->classification) {
1013 - if(strcmp(rt->classification, value) != 0)
1005 + if(strcmp(rrdcalctemplate_classification(rt), value) != 0)
1006 error("Health configuration at line %zu of file '%s' for alarm '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
1015 - line, filename, rt->name, key, rt->classification, value, value);
1007 + line, filename, rrdcalctemplate_name(rt), key, rrdcalctemplate_classification(rt), value, value);
1008
1017 - freez(rt->classification);
1009 + string_freez(rt->classification);
1010 }
1019 - rt->classification = strdupz(value);
1020 - strip_quotes(rt->classification);
1011 + rt->classification = string_strdupz(value);
1012 }
1013 else if(hash == hash_component && !strcasecmp(key, HEALTH_COMPONENT_KEY)) {
1023 - alert_cfg->component = strdupz(value);
1014 + strip_quotes(value);
1015 +
1016 + alert_cfg->component = string_strdupz(value);
1017 if(rt->component) {
1025 - if(strcmp(rt->component, value) != 0)
1018 + if(strcmp(rrdcalctemplate_component(rt), value) != 0)
1019 error("Health configuration at line %zu of file '%s' for alarm '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
1027 - line, filename, rt->name, key, rt->component, value, value);
1020 + line, filename, rrdcalctemplate_name(rt), key, rrdcalctemplate_component(rt), value, value);
1021
1029 - freez(rt->component);
1022 + string_freez(rt->component);
1023 }
1031 - rt->component = strdupz(value);
1032 - strip_quotes(rt->component);
1024 + rt->component = string_strdupz(value);
1025 }
1026 else if(hash == hash_type && !strcasecmp(key, HEALTH_TYPE_KEY)) {
1035 - alert_cfg->type = strdupz(value);
1027 + strip_quotes(value);
1028 +
1029 + alert_cfg->type = string_strdupz(value);
1030 if(rt->type) {
1037 - if(strcmp(rt->type, value) != 0)
1031 + if(strcmp(rrdcalctemplate_type(rt), value) != 0)
1032 error("Health configuration at line %zu of file '%s' for alarm '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
1039 - line, filename, rt->name, key, rt->type, value, value);
1033 + line, filename, rrdcalctemplate_name(rt), key, rrdcalctemplate_type(rt), value, value);
1034
1041 - freez(rt->type);
1035 + string_freez(rt->type);
1036 }
1043 - rt->type = strdupz(value);
1044 - strip_quotes(rt->type);
1037 + rt->type = string_strdupz(value);
1038 }
1039 else if(hash == hash_families && !strcasecmp(key, HEALTH_FAMILIES_KEY)) {
1047 - alert_cfg->families = strdupz(value);
1048 - freez(rt->family_match);
1040 + alert_cfg->families = string_strdupz(value);
1041 + string_freez(rt->family_match);
1042 simple_pattern_free(rt->family_pattern);
1043
1051 - rt->family_match = strdupz(value);
1052 - rt->family_pattern = simple_pattern_create(rt->family_match, NULL, SIMPLE_PATTERN_EXACT);
1044 + rt->family_match = string_strdupz(value);
1045 + rt->family_pattern = simple_pattern_create(rrdcalctemplate_family_match(rt), NULL, SIMPLE_PATTERN_EXACT);
1046 }
1047 else if(hash == hash_plugin && !strcasecmp(key, HEALTH_PLUGIN_KEY)) {
1055 - alert_cfg->plugin = strdupz(value);
1056 - freez(rt->plugin_match);
1048 + alert_cfg->plugin = string_strdupz(value);
1049 + string_freez(rt->plugin_match);
1050 simple_pattern_free(rt->plugin_pattern);
1051
1059 - rt->plugin_match = strdupz(value);
1060 - rt->plugin_pattern = simple_pattern_create(rt->plugin_match, NULL, SIMPLE_PATTERN_EXACT);
1052 + rt->plugin_match = string_strdupz(value);
1053 + rt->plugin_pattern = simple_pattern_create(rrdcalctemplate_plugin_match(rt), NULL, SIMPLE_PATTERN_EXACT);
1054 }
1055 else if(hash == hash_module && !strcasecmp(key, HEALTH_MODULE_KEY)) {
1063 - alert_cfg->module = strdupz(value);
1064 - freez(rt->module_match);
1056 + alert_cfg->module = string_strdupz(value);
1057 + string_freez(rt->module_match);
1058 simple_pattern_free(rt->module_pattern);
1059
1067 - rt->module_match = strdupz(value);
1068 - rt->module_pattern = simple_pattern_create(rt->module_match, NULL, SIMPLE_PATTERN_EXACT);
1060 + rt->module_match = string_strdupz(value);
1061 + rt->module_pattern = simple_pattern_create(rrdcalctemplate_module_match(rt), NULL, SIMPLE_PATTERN_EXACT);
1062 }
1063 else if(hash == hash_charts && !strcasecmp(key, HEALTH_CHARTS_KEY)) {
1071 - alert_cfg->charts = strdupz(value);
1072 - freez(rt->charts_match);
1064 + alert_cfg->charts = string_strdupz(value);
1065 + string_freez(rt->charts_match);
1066 simple_pattern_free(rt->charts_pattern);
1067
1075 - rt->charts_match = strdupz(value);
1076 - rt->charts_pattern = simple_pattern_create(rt->charts_match, NULL, SIMPLE_PATTERN_EXACT);
1068 + rt->charts_match = string_strdupz(value);
1069 + rt->charts_pattern = simple_pattern_create(rrdcalctemplate_charts_match(rt), NULL, SIMPLE_PATTERN_EXACT);
1070 }
1071 else if(hash == hash_lookup && !strcasecmp(key, HEALTH_LOOKUP_KEY)) {
1079 - alert_cfg->lookup = strdupz(value);
1072 + alert_cfg->lookup = string_strdupz(value);
1073 health_parse_db_lookup(line, filename, value, &rt->group, &rt->after, &rt->before,
1074 &rt->update_every, &rt->options, &rt->dimensions, &rt->foreachdim);
1082 - if(rt->foreachdim) {
1083 - rt->spdim = health_pattern_from_foreach(rt->foreachdim);
1084 - }
1075 +
1076 + if(rt->foreachdim)
1077 + rt->spdim = health_pattern_from_foreach(rrdcalctemplate_foreachdim(rt));
1078 +
1079 if (rt->after) {
1080 if (rt->dimensions)
1087 - alert_cfg->p_db_lookup_dimensions = strdupz(rt->dimensions);
1081 + alert_cfg->p_db_lookup_dimensions = string_dup(rt->dimensions);
1082 +
1083 if (rt->group)
1089 - alert_cfg->p_db_lookup_method = strdupz(group_method2string(rt->group));
1084 + alert_cfg->p_db_lookup_method = string_strdupz(group_method2string(rt->group));
1085 +
1086 alert_cfg->p_db_lookup_options = rt->options;
1087 alert_cfg->p_db_lookup_after = rt->after;
1088 alert_cfg->p_db_lookup_before = rt->before;
@@ -1094,137 +1090,143 @@ static int health_readfile(const char *filename, void *data) {
1090 }
1091 }
1092 else if(hash == hash_every && !strcasecmp(key, HEALTH_EVERY_KEY)) {
1097 - alert_cfg->every = strdupz(value);
1093 + alert_cfg->every = string_strdupz(value);
1094 if(!config_parse_duration(value, &rt->update_every))
1095 error("Health configuration at line %zu of file '%s' for template '%s' at key '%s' cannot parse duration: '%s'.",
1100 - line, filename, rt->name, key, value);
1096 + line, filename, rrdcalctemplate_name(rt), key, value);
1097 alert_cfg->p_update_every = rt->update_every;
1098 }
1099 else if(hash == hash_green && !strcasecmp(key, HEALTH_GREEN_KEY)) {
1104 - alert_cfg->green = strdupz(value);
1100 + alert_cfg->green = string_strdupz(value);
1101 char *e;
1102 rt->green = str2ndd(value, &e);
1103 if(e && *e) {
1104 error("Health configuration at line %zu of file '%s' for template '%s' at key '%s' leaves this string unmatched: '%s'.",
1109 - line, filename, rt->name, key, e);
1105 + line, filename, rrdcalctemplate_name(rt), key, e);
1106 }
1107 }
1108 else if(hash == hash_red && !strcasecmp(key, HEALTH_RED_KEY)) {
1113 - alert_cfg->red = strdupz(value);
1109 + alert_cfg->red = string_strdupz(value);
1110 char *e;
1111 rt->red = str2ndd(value, &e);
1112 if(e && *e) {
1113 error("Health configuration at line %zu of file '%s' for template '%s' at key '%s' leaves this string unmatched: '%s'.",
1118 - line, filename, rt->name, key, e);
1114 + line, filename, rrdcalctemplate_name(rt), key, e);
1115 }
1116 }
1117 else if(hash == hash_calc && !strcasecmp(key, HEALTH_CALC_KEY)) {
1122 - alert_cfg->calc = strdupz(value);
1118 + alert_cfg->calc = string_strdupz(value);
1119 const char *failed_at = NULL;
1120 int error = 0;
1121 rt->calculation = expression_parse(value, &failed_at, &error);
1122 if(!rt->calculation) {
1123 error("Health configuration at line %zu of file '%s' for template '%s' at key '%s' has unparse-able expression '%s': %s at '%s'",
1128 - line, filename, rt->name, key, value, expression_strerror(error), failed_at);
1124 + line, filename, rrdcalctemplate_name(rt), key, value, expression_strerror(error), failed_at);
1125 }
1126 }
1127 else if(hash == hash_warn && !strcasecmp(key, HEALTH_WARN_KEY)) {
1132 - alert_cfg->warn = strdupz(value);
1128 + alert_cfg->warn = string_strdupz(value);
1129 const char *failed_at = NULL;
1130 int error = 0;
1131 rt->warning = expression_parse(value, &failed_at, &error);
1132 if(!rt->warning) {
1133 error("Health configuration at line %zu of file '%s' for template '%s' at key '%s' has unparse-able expression '%s': %s at '%s'",
1138 - line, filename, rt->name, key, value, expression_strerror(error), failed_at);
1134 + line, filename, rrdcalctemplate_name(rt), key, value, expression_strerror(error), failed_at);
1135 }
1136 }
1137 else if(hash == hash_crit && !strcasecmp(key, HEALTH_CRIT_KEY)) {
1142 - alert_cfg->crit = strdupz(value);
1138 + alert_cfg->crit = string_strdupz(value);
1139 const char *failed_at = NULL;
1140 int error = 0;
1141 rt->critical = expression_parse(value, &failed_at, &error);
1142 if(!rt->critical) {
1143 error("Health configuration at line %zu of file '%s' for template '%s' at key '%s' has unparse-able expression '%s': %s at '%s'",
1148 - line, filename, rt->name, key, value, expression_strerror(error), failed_at);
1144 + line, filename, rrdcalctemplate_name(rt), key, value, expression_strerror(error), failed_at);
1145 }
1146 }
1147 else if(hash == hash_exec && !strcasecmp(key, HEALTH_EXEC_KEY)) {
1152 - alert_cfg->exec = strdupz(value);
1148 + alert_cfg->exec = string_strdupz(value);
1149 if(rt->exec) {
1154 - if(strcmp(rt->exec, value) != 0)
1150 + if(strcmp(rrdcalctemplate_exec(rt), value) != 0)
1151 error("Health configuration at line %zu of file '%s' for template '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
1156 - line, filename, rt->name, key, rt->exec, value, value);
1152 + line, filename, rrdcalctemplate_name(rt), key, rrdcalctemplate_exec(rt), value, value);
1153
1158 - freez(rt->exec);
1154 + string_freez(rt->exec);
1155 }
1160 - rt->exec = strdupz(value);
1156 + rt->exec = string_strdupz(value);
1157 }
1158 else if(hash == hash_recipient && !strcasecmp(key, HEALTH_RECIPIENT_KEY)) {
1163 - alert_cfg->to = strdupz(value);
1159 + alert_cfg->to = string_strdupz(value);
1160 if(rt->recipient) {
1165 - if(strcmp(rt->recipient, value) != 0)
1161 + if(strcmp(rrdcalctemplate_recipient(rt), value) != 0)
1162 error("Health configuration at line %zu of file '%s' for template '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
1167 - line, filename, rt->name, key, rt->recipient, value, value);
1163 + line, filename, rrdcalctemplate_name(rt), key, rrdcalctemplate_recipient(rt), value, value);
1164
1169 - freez(rt->recipient);
1165 + string_freez(rt->recipient);
1166 }
1171 - rt->recipient = strdupz(value);
1167 + rt->recipient = string_strdupz(value);
1168 }
1169 else if(hash == hash_units && !strcasecmp(key, HEALTH_UNITS_KEY)) {
1174 - alert_cfg->units = strdupz(value);
1170 + strip_quotes(value);
1171 +
1172 + alert_cfg->units = string_strdupz(value);
1173 if(rt->units) {
1176 - if(strcmp(rt->units, value) != 0)
1174 + if(strcmp(rrdcalctemplate_units(rt), value) != 0)
1175 error("Health configuration at line %zu of file '%s' for template '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
1178 - line, filename, rt->name, key, rt->units, value, value);
1176 + line, filename, rrdcalctemplate_name(rt), key, rrdcalctemplate_units(rt), value, value);
1177
1180 - freez(rt->units);
1178 + string_freez(rt->units);
1179 }
1182 - rt->units = strdupz(value);
1183 - strip_quotes(rt->units);
1180 + rt->units = string_strdupz(value);
1181 }
1182 else if(hash == hash_info && !strcasecmp(key, HEALTH_INFO_KEY)) {
1186 - alert_cfg->info = strdupz(value);
1183 + strip_quotes(value);
1184 +
1185 + alert_cfg->info = string_strdupz(value);
1186 if(rt->info) {
1188 - if(strcmp(rt->info, value) != 0)
1187 + if(strcmp(rrdcalctemplate_info(rt), value) != 0)
1188 error("Health configuration at line %zu of file '%s' for template '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
1190 - line, filename, rt->name, key, rt->info, value, value);
1189 + line, filename, rrdcalctemplate_name(rt), key, rrdcalctemplate_info(rt), value, value);
1190
1192 - freez(rt->info);
1191 + string_freez(rt->info);
1192 }
1194 - rt->info = strdupz(value);
1195 - strip_quotes(rt->info);
1193 + rt->info = string_strdupz(value);
1194 }
1195 else if(hash == hash_delay && !strcasecmp(key, HEALTH_DELAY_KEY)) {
1198 - alert_cfg->delay = strdupz(value);
1196 + alert_cfg->delay = string_strdupz(value);
1197 health_parse_delay(line, filename, value, &rt->delay_up_duration, &rt->delay_down_duration, &rt->delay_max_duration, &rt->delay_multiplier);
1198 }
1199 else if(hash == hash_options && !strcasecmp(key, HEALTH_OPTIONS_KEY)) {
1202 - alert_cfg->options = strdupz(value);
1200 + alert_cfg->options = string_strdupz(value);
1201 rt->options |= health_parse_options(value);
1202 }
1203 else if(hash == hash_repeat && !strcasecmp(key, HEALTH_REPEAT_KEY)){
1206 - alert_cfg->repeat = strdupz(value);
1204 + alert_cfg->repeat = string_strdupz(value);
1205 health_parse_repeat(line, filename, value,
1206 &rt->warn_repeat_every,
1207 &rt->crit_repeat_every);
1208 }
1209 else if(hash == hash_host_label && !strcasecmp(key, HEALTH_HOST_LABEL_KEY)) {
1212 - alert_cfg->host_labels = strdupz(value);
1210 + alert_cfg->host_labels = string_strdupz(value);
1211 if(rt->host_labels) {
1214 - if(strcmp(rt->host_labels, value) != 0)
1212 + if(strcmp(rrdcalctemplate_host_labels(rt), value) != 0)
1213 error("Health configuration at line %zu of file '%s' for template '%s' has key '%s' twice, once with value '%s' and later with value '%s'. Using ('%s').",
1216 - line, filename, rt->name, key, rt->host_labels, value, value);
1214 + line, filename, rrdcalctemplate_name(rt), key, rrdcalctemplate_host_labels(rt), value, value);
1215
1218 - freez(rt->host_labels);
1216 + string_freez(rt->host_labels);
1217 simple_pattern_free(rt->host_labels_pattern);
1218 }
1219
1222 - rt->host_labels = simple_pattern_trim_around_equal(value);
1223 - rt->host_labels_pattern = simple_pattern_create(rt->host_labels, NULL, SIMPLE_PATTERN_EXACT);
1220 + {
1221 + char *tmp = simple_pattern_trim_around_equal(value);
1222 + rt->host_labels = string_strdupz(tmp);
1223 + freez(tmp);
1224 + }
1225 + rt->host_labels_pattern = simple_pattern_create(rrdcalctemplate_host_labels(rt), NULL, SIMPLE_PATTERN_EXACT);
1226 }
1227 else {
1228 error("Health configuration at line %zu of file '%s' for template '%s' has unknown key '%s'.",
1227 - line, filename, rt->name, key);
1229 + line, filename, rrdcalctemplate_name(rt), key);
1230 }
1231 }
1232 else {
@@ -1260,7 +1262,7 @@ void sql_refresh_hashes(void)
1262
1263 void health_readdir(RRDHOST *host, const char *user_path, const char *stock_path, const char *subpath) {
1264 if(unlikely(!host->health_enabled)) {
1263 - debug(D_HEALTH, "CONFIG health is not enabled for host '%s'", host->hostname);
1265 + debug(D_HEALTH, "CONFIG health is not enabled for host '%s'", rrdhost_hostname(host));
1266 return;
1267 }
1268
health/health_json.c
+52 -45
@@ -14,7 +14,7 @@ void health_string2json(BUFFER *wb, const char *prefix, const char *label, const
14 }
15
16 void health_alarm_entry2json_nolock(BUFFER *wb, ALARM_ENTRY *ae, RRDHOST *host) {
17 - char *edit_command = ae->source ? health_edit_command_from_source(ae->source) : strdupz("UNKNOWN=0=UNKNOWN");
17 + char *edit_command = ae->source ? health_edit_command_from_source(ae_source(ae)) : strdupz("UNKNOWN=0=UNKNOWN");
18 char config_hash_id[GUID_LEN + 1];
19 uuid_unparse_lower(ae->config_hash_id, config_hash_id);
20
@@ -57,30 +57,30 @@ void health_alarm_entry2json_nolock(BUFFER *wb, ALARM_ENTRY *ae, RRDHOST *host)
57 "\t\t\"old_value_string\": \"%s\",\n"
58 "\t\t\"last_repeat\": \"%lu\",\n"
59 "\t\t\"silenced\": \"%s\",\n"
60 - , host->hostname
60 + , rrdhost_hostname(host)
61 , host->utc_offset
62 - , host->abbrev_timezone
62 + , rrdhost_abbrev_timezone(host)
63 , ae->unique_id
64 , ae->alarm_id
65 , ae->alarm_event_id
66 , config_hash_id
67 - , ae->name
68 - , ae->chart
69 - , ae->chart_context
70 - , ae->family
71 - , ae->classification?ae->classification:"Unknown"
72 - , ae->component?ae->component:"Unknown"
73 - , ae->type?ae->type:"Unknown"
67 + , ae_name(ae)
68 + , ae_chart_name(ae)
69 + , ae_chart_context(ae)
70 + , ae_family(ae)
71 + , ae->classification?ae_classification(ae):"Unknown"
72 + , ae->component?ae_component(ae):"Unknown"
73 + , ae->type?ae_type(ae):"Unknown"
74 , (ae->flags & HEALTH_ENTRY_FLAG_PROCESSED)?"true":"false"
75 , (ae->flags & HEALTH_ENTRY_FLAG_UPDATED)?"true":"false"
76 , (unsigned long)ae->exec_run_timestamp
77 , (ae->flags & HEALTH_ENTRY_FLAG_EXEC_FAILED)?"true":"false"
78 - , ae->exec?ae->exec:host->health_default_exec
79 - , ae->recipient?ae->recipient:host->health_default_recipient
78 + , ae->exec?ae_exec(ae):string2str(host->health_default_exec)
79 + , ae->recipient?ae_recipient(ae):string2str(host->health_default_recipient)
80 , ae->exec_code
81 - , ae->source
81 + , ae_source(ae)
82 , edit_command
83 - , ae->units?ae->units:""
83 + , ae_units(ae)
84 , (unsigned long)ae->when
85 , (unsigned long)ae->duration
86 , (unsigned long)ae->non_clear_duration
@@ -90,13 +90,13 @@ void health_alarm_entry2json_nolock(BUFFER *wb, ALARM_ENTRY *ae, RRDHOST *host)
90 , (unsigned long)ae->delay_up_to_timestamp
91 , ae->updated_by_id
92 , ae->updates_id
93 - , ae->new_value_string
94 - , ae->old_value_string
93 + , ae_new_value_string(ae)
94 + , ae_old_value_string(ae)
95 , (unsigned long)ae->last_repeat
96 , (ae->flags & HEALTH_ENTRY_FLAG_SILENCED)?"true":"false"
97 );
98
99 - health_string2json(wb, "\t\t", "info", ae->info ? ae->info : "", ",\n");
99 + health_string2json(wb, "\t\t", "info", ae->info ? ae_info(ae) : "", ",\n");
100
101 if(unlikely(ae->flags & HEALTH_ENTRY_FLAG_NO_CLEAR_NOTIFICATION)) {
102 buffer_strcat(wb, "\t\t\"no_clear_notification\": true,\n");
@@ -122,11 +122,12 @@ void health_alarm_log2json(RRDHOST *host, BUFFER *wb, uint32_t after, char *char
122
123 unsigned int max = host->health_log.max;
124 unsigned int count = 0;
125 - uint32_t hash_chart = 0;
126 - if (chart) hash_chart = simple_hash(chart);
125 +
126 + STRING *chart_string = string_strdupz(chart);
127 +
128 ALARM_ENTRY *ae;
129 for (ae = host->health_log.alarms; ae && count < max; ae = ae->next) {
129 - if ((ae->unique_id > after) && (!chart || (ae->hash_chart == hash_chart && !strcmp(ae->chart, chart)))) {
130 + if ((ae->unique_id > after) && (!chart || chart_string == ae->chart)) {
131 if (likely(count))
132 buffer_strcat(wb, ",");
133 health_alarm_entry2json_nolock(wb, ae, host);
@@ -134,6 +135,8 @@ void health_alarm_log2json(RRDHOST *host, BUFFER *wb, uint32_t after, char *char
135 }
136 }
137
138 + string_freez(chart_string);
139 +
140 buffer_strcat(wb, "\n]\n");
141
142 netdata_rwlock_unlock(&host->health_log.alarm_log_rwlock);
@@ -144,7 +147,7 @@ static inline void health_rrdcalc_values2json_nolock(RRDHOST *host, BUFFER *wb,
147 buffer_sprintf(wb,
148 "\t\t\"%s.%s\": {\n"
149 "\t\t\t\"id\": %lu,\n"
147 - , rc->chart, rc->name
150 + , rrdcalc_chart_name(rc), rrdcalc_name(rc)
151 , (unsigned long)rc->id);
152
153 buffer_strcat(wb, "\t\t\t\"value\":");
@@ -164,7 +167,7 @@ static inline void health_rrdcalc_values2json_nolock(RRDHOST *host, BUFFER *wb,
167
168 static inline void health_rrdcalc2json_nolock(RRDHOST *host, BUFFER *wb, RRDCALC *rc) {
169 char value_string[100 + 1];
167 - format_value_and_unit(value_string, 100, rc->value, rc->units, -1);
170 + format_value_and_unit(value_string, 100, rc->value, rrdcalc_units(rc), -1);
171
172 char hash_id[GUID_LEN + 1];
173 uuid_unparse_lower(rc->config_hash_id, hash_id);
@@ -203,23 +206,23 @@ static inline void health_rrdcalc2json_nolock(RRDHOST *host, BUFFER *wb, RRDCALC
206 "\t\t\t\"value_string\": \"%s\",\n"
207 "\t\t\t\"last_repeat\": \"%lu\",\n"
208 "\t\t\t\"times_repeat\": %lu,\n"
206 - , rc->chart, rc->name
209 + , rrdcalc_chart_name(rc), rrdcalc_name(rc)
210 , (unsigned long)rc->id
211 , hash_id
209 - , rc->name
210 - , rc->chart
211 - , (rc->rrdset && rc->rrdset->family)?rc->rrdset->family:""
212 - , rc->classification?rc->classification:"Unknown"
213 - , rc->component?rc->component:"Unknown"
214 - , rc->type?rc->type:"Unknown"
212 + , rrdcalc_name(rc)
213 + , rrdcalc_chart_name(rc)
214 + , (rc->rrdset)?rrdset_family(rc->rrdset):""
215 + , rc->classification?rrdcalc_classification(rc):"Unknown"
216 + , rc->component?rrdcalc_component(rc):"Unknown"
217 + , rc->type?rrdcalc_type(rc):"Unknown"
218 , (rc->rrdset)?"true":"false"
219 , (rc->rrdcalc_flags & RRDCALC_FLAG_DISABLED)?"true":"false"
220 , (rc->rrdcalc_flags & RRDCALC_FLAG_SILENCED)?"true":"false"
218 - , rc->exec?rc->exec:host->health_default_exec
219 - , rc->recipient?rc->recipient:host->health_default_recipient
220 - , rc->source
221 - , rc->units?rc->units:""
222 - , rc->info?rc->info:""
221 + , rc->exec?rrdcalc_exec(rc):string2str(host->health_default_exec)
222 + , rc->recipient?rrdcalc_recipient(rc):string2str(host->health_default_recipient)
223 + , rrdcalc_source(rc)
224 + , rrdcalc_units(rc)
225 + , rrdcalc_info(rc)
226 , rrdcalc_status2string(rc->status)
227 , (unsigned long)rc->last_status_change
228 , (unsigned long)rc->last_updated
@@ -243,8 +246,8 @@ static inline void health_rrdcalc2json_nolock(RRDHOST *host, BUFFER *wb, RRDCALC
246 }
247
248 if(RRDCALC_HAS_DB_LOOKUP(rc)) {
246 - if(rc->dimensions && *rc->dimensions)
247 - health_string2json(wb, "\t\t\t", "lookup_dimensions", rc->dimensions, ",\n");
249 + if(rc->dimensions)
250 + health_string2json(wb, "\t\t\t", "lookup_dimensions", rrdcalc_dimensions(rc), ",\n");
251
252 buffer_sprintf(wb,
253 "\t\t\t\"db_after\": %lu,\n"
@@ -310,20 +313,24 @@ void health_aggregate_alarms(RRDHOST *host, BUFFER *wb, BUFFER* contexts, RRDCAL
313 while(p && *p && (tok = mystrsep(&p, ", |"))) {
314 if(!*tok) continue;
315
313 - for(rc = host->alarms; rc ; rc = rc->next) {
316 + STRING *tok_string = string_strdupz(tok);
317 +
318 + foreach_rrdcalc_in_rrdhost(host, rc) {
319 if(unlikely(!rc->rrdset || !rc->rrdset->last_collected_time.tv_sec))
320 continue;
321 if (unlikely(!rrdset_is_available_for_exporting_and_alarms(rc->rrdset)))
322 continue;
318 - if(unlikely(rc->rrdset && rc->rrdset->hash_context == simple_hash(tok)
319 - && !strcmp(rc->rrdset->context, tok)
320 - && ((status==RRDCALC_STATUS_RAISED)?(rc->status >= RRDCALC_STATUS_WARNING):rc->status == status)))
323 + if(unlikely(rc->rrdset
324 + && rc->rrdset->context == tok_string
325 + && ((status==RRDCALC_STATUS_RAISED)?(rc->status >= RRDCALC_STATUS_WARNING):rc->status == status)))
326 numberOfAlarms++;
327 }
328 +
329 + string_freez(tok_string);
330 }
331 }
332 else {
326 - for(rc = host->alarms; rc ; rc = rc->next) {
333 + foreach_rrdcalc_in_rrdhost(host, rc) {
334 if(unlikely(!rc->rrdset || !rc->rrdset->last_collected_time.tv_sec))
335 continue;
336 if (unlikely(!rrdset_is_available_for_exporting_and_alarms(rc->rrdset)))
@@ -339,8 +346,8 @@ void health_aggregate_alarms(RRDHOST *host, BUFFER *wb, BUFFER* contexts, RRDCAL
346
347 static void health_alarms2json_fill_alarms(RRDHOST *host, BUFFER *wb, int all, void (*fp)(RRDHOST *, BUFFER *, RRDCALC *)) {
348 RRDCALC *rc;
342 - int i;
343 - for(i = 0, rc = host->alarms; rc ; rc = rc->next) {
349 + int i = 0;
350 + foreach_rrdcalc_in_rrdhost(host, rc) {
351 if(unlikely(!rc->rrdset || !rc->rrdset->last_collected_time.tv_sec))
352 continue;
353
@@ -363,7 +370,7 @@ void health_alarms2json(RRDHOST *host, BUFFER *wb, int all) {
370 "\n\t\"status\": %s,"
371 "\n\t\"now\": %lu,"
372 "\n\t\"alarms\": {\n",
366 - host->hostname,
373 + rrdhost_hostname(host),
374 (host->health_log.next_log_id > 0)?(host->health_log.next_log_id - 1):0,
375 host->health_enabled?"true":"false",
376 (unsigned long)now_realtime_sec());
@@ -383,7 +390,7 @@ void health_alarms_values2json(RRDHOST *host, BUFFER *wb, int all) {
390 rrdhost_rdlock(host);
391 buffer_sprintf(wb, "{\n\t\"hostname\": \"%s\","
392 "\n\t\"alarms\": {\n",
386 - host->hostname);
393 + rrdhost_hostname(host));
394
395 health_alarms2json_fill_alarms(host, wb, all, health_rrdcalc_values2json_nolock);
396
health/health_log.c
+136 -156
@@ -14,11 +14,11 @@ inline int health_alarm_log_open(RRDHOST *host) {
14
15 if(host->health_log_fp) {
16 if (setvbuf(host->health_log_fp, NULL, _IOLBF, 0) != 0)
17 - error("HEALTH [%s]: cannot set line buffering on health log file '%s'.", host->hostname, host->health_log_filename);
17 + error("HEALTH [%s]: cannot set line buffering on health log file '%s'.", rrdhost_hostname(host), host->health_log_filename);
18 return 0;
19 }
20
21 - error("HEALTH [%s]: cannot open health log file '%s'. Health data will be lost in case of netdata or server crash.", host->hostname, host->health_log_filename);
21 + error("HEALTH [%s]: cannot open health log file '%s'. Health data will be lost in case of netdata or server crash.", rrdhost_hostname(host), host->health_log_filename);
22 return -1;
23 }
24
@@ -45,13 +45,13 @@ static inline void health_log_rotate(RRDHOST *host) {
45 snprintfz(old_filename, FILENAME_MAX, "%s.old", host->health_log_filename);
46
47 if(unlink(old_filename) == -1 && errno != ENOENT)
48 - error("HEALTH [%s]: cannot remove old alarms log file '%s'", host->hostname, old_filename);
48 + error("HEALTH [%s]: cannot remove old alarms log file '%s'", rrdhost_hostname(host), old_filename);
49
50 if(link(host->health_log_filename, old_filename) == -1 && errno != ENOENT)
51 - error("HEALTH [%s]: cannot move file '%s' to '%s'.", host->hostname, host->health_log_filename, old_filename);
51 + error("HEALTH [%s]: cannot move file '%s' to '%s'.", rrdhost_hostname(host), host->health_log_filename, old_filename);
52
53 if(unlink(host->health_log_filename) == -1 && errno != ENOENT)
54 - error("HEALTH [%s]: cannot remove old alarms log file '%s'", host->hostname, host->health_log_filename);
54 + error("HEALTH [%s]: cannot remove old alarms log file '%s'", rrdhost_hostname(host), host->health_log_filename);
55
56 // open it with truncate
57 host->health_log_fp = fopen(host->health_log_filename, "w");
@@ -59,7 +59,7 @@ static inline void health_log_rotate(RRDHOST *host) {
59 if(host->health_log_fp)
60 fclose(host->health_log_fp);
61 else
62 - error("HEALTH [%s]: cannot truncate health log '%s'", host->hostname, host->health_log_filename);
62 + error("HEALTH [%s]: cannot truncate health log '%s'", rrdhost_hostname(host), host->health_log_filename);
63
64 host->health_log_fp = NULL;
65
@@ -80,7 +80,7 @@ inline void health_label_log_save(RRDHOST *host) {
80
81 if (unlikely(fprintf(host->health_log_fp, "L\t%s", write) < 0))
82 error("HEALTH [%s]: failed to save alarm log entry to '%s'. Health data may be lost in case of abnormal restart.",
83 - host->hostname, host->health_log_filename);
83 + rrdhost_hostname(host), host->health_log_filename);
84 else
85 host->health_log_entries_written++;
86
@@ -103,7 +103,7 @@ inline void health_alarm_log_save(RRDHOST *host, ALARM_ENTRY *ae) {
103 "\t%s\t%s\t%s"
104 "\n"
105 , (ae->flags & HEALTH_ENTRY_FLAG_SAVED)?'U':'A'
106 - , host->hostname
106 + , rrdhost_hostname(host)
107
108 , ae->unique_id
109 , ae->alarm_id
@@ -118,14 +118,14 @@ inline void health_alarm_log_save(RRDHOST *host, ALARM_ENTRY *ae) {
118 , (uint32_t)ae->exec_run_timestamp
119 , (uint32_t)ae->delay_up_to_timestamp
120
121 - , (ae->name)?ae->name:""
122 - , (ae->chart)?ae->chart:""
123 - , (ae->family)?ae->family:""
124 - , (ae->exec)?ae->exec:""
125 - , (ae->recipient)?ae->recipient:""
126 - , (ae->source)?ae->source:""
127 - , (ae->units)?ae->units:""
128 - , (ae->info)?ae->info:""
121 + , ae_name(ae)
122 + , ae_chart_name(ae)
123 + , ae_family(ae)
124 + , ae_exec(ae)
125 + , ae_recipient(ae)
126 + , ae_source(ae)
127 + , ae_units(ae)
128 + , ae_info(ae)
129
130 , ae->exec_code
131 , ae->new_status
@@ -135,11 +135,11 @@ inline void health_alarm_log_save(RRDHOST *host, ALARM_ENTRY *ae) {
135 , ae->new_value
136 , ae->old_value
137 , (uint64_t)ae->last_repeat
138 - , (ae->classification)?ae->classification:"Unknown"
139 - , (ae->component)?ae->component:"Unknown"
140 - , (ae->type)?ae->type:"Unknown"
138 + , (ae->classification)?ae_classification(ae):"Unknown"
139 + , (ae->component)?ae_component(ae):"Unknown"
140 + , (ae->type)?ae_type(ae):"Unknown"
141 ) < 0))
142 - error("HEALTH [%s]: failed to save alarm log entry to '%s'. Health data may be lost in case of abnormal restart.", host->hostname, host->health_log_filename);
142 + error("HEALTH [%s]: failed to save alarm log entry to '%s'. Health data may be lost in case of abnormal restart.", rrdhost_hostname(host), host->health_log_filename);
143 else {
144 ae->flags |= HEALTH_ENTRY_FLAG_SAVED;
145 host->health_log_entries_written++;
@@ -156,18 +156,23 @@ inline void health_alarm_log_save(RRDHOST *host, ALARM_ENTRY *ae) {
156
157 static uint32_t is_valid_alarm_id(RRDHOST *host, const char *chart, const char *name, uint32_t alarm_id)
158 {
159 - uint32_t hash_chart = simple_hash(chart);
160 - uint32_t hash_name = simple_hash(name);
159 + STRING *chart_string = string_strdupz(chart);
160 + STRING *name_string = string_strdupz(name);
161 +
162 + uint32_t ret = 1;
163
164 ALARM_ENTRY *ae;
165 for(ae = host->health_log.alarms; ae ;ae = ae->next) {
164 - if (unlikely(
165 - ae->alarm_id == alarm_id && (!(ae->hash_name == hash_name && ae->hash_chart == hash_chart &&
166 - !strcmp(name, ae->name) && !strcmp(chart, ae->chart))))) {
167 - return 0;
166 + if (unlikely(ae->alarm_id == alarm_id && (!(chart_string == ae->chart && name_string == ae->name)))) {
167 + ret = 0;
168 + break;
169 }
170 }
170 - return 1;
171 +
172 + string_freez(chart_string);
173 + string_freez(name_string);
174 +
175 + return ret;
176 }
177
178 static inline ssize_t health_alarm_log_read(RRDHOST *host, FILE *fp, const char *filename) {
@@ -179,6 +184,11 @@ static inline ssize_t health_alarm_log_read(RRDHOST *host, FILE *fp, const char
184
185 netdata_rwlock_rdlock(&host->health_log.alarm_log_rwlock);
186
187 + DICTIONARY *all_rrdcalcs = dictionary_create(DICTIONARY_FLAG_NAME_LINK_DONT_CLONE|DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE|DICTIONARY_FLAG_DONT_OVERWRITE_VALUE);
188 + RRDCALC *rc;
189 + foreach_rrdcalc_in_rrdhost(host, rc)
190 + dictionary_set(all_rrdcalcs, rrdcalc_name(rc), rc, sizeof(*rc));
191 +
192 while((s = fgets_trim_len(buf, 65536, fp, &len))) {
193 host->health_log_entries_written++;
194 line++;
@@ -192,7 +202,7 @@ static inline ssize_t health_alarm_log_read(RRDHOST *host, FILE *fp, const char
202 *s = '\0';
203 pointers[entries++] = ++s;
204 if(entries >= max_entries) {
195 - error("HEALTH [%s]: line %zu of file '%s' has more than %d entries. Ignoring excessive entries.", host->hostname, line, filename, max_entries);
205 + error("HEALTH [%s]: line %zu of file '%s' has more than %d entries. Ignoring excessive entries.", rrdhost_hostname(host), line, filename, max_entries);
206 break;
207 }
208 }
@@ -206,7 +216,7 @@ static inline ssize_t health_alarm_log_read(RRDHOST *host, FILE *fp, const char
216 ALARM_ENTRY *ae = NULL;
217
218 if(entries < 27) {
209 - error("HEALTH [%s]: line %zu of file '%s' should have at least 27 entries, but it has %d. Ignoring it.", host->hostname, line, filename, entries);
219 + error("HEALTH [%s]: line %zu of file '%s' should have at least 27 entries, but it has %d. Ignoring it.", rrdhost_hostname(host), line, filename, entries);
220 errored++;
221 continue;
222 }
@@ -214,14 +224,14 @@ static inline ssize_t health_alarm_log_read(RRDHOST *host, FILE *fp, const char
224 // check that we have valid ids
225 uint32_t unique_id = (uint32_t)strtoul(pointers[2], NULL, 16);
226 if(!unique_id) {
217 - error("HEALTH [%s]: line %zu of file '%s' states alarm entry with invalid unique id %u (%s). Ignoring it.", host->hostname, line, filename, unique_id, pointers[2]);
227 + error("HEALTH [%s]: line %zu of file '%s' states alarm entry with invalid unique id %u (%s). Ignoring it.", rrdhost_hostname(host), line, filename, unique_id, pointers[2]);
228 errored++;
229 continue;
230 }
231
232 uint32_t alarm_id = (uint32_t)strtoul(pointers[3], NULL, 16);
233 if(!alarm_id) {
224 - error("HEALTH [%s]: line %zu of file '%s' states alarm entry for invalid alarm id %u (%s). Ignoring it.", host->hostname, line, filename, alarm_id, pointers[3]);
234 + error("HEALTH [%s]: line %zu of file '%s' states alarm entry for invalid alarm id %u (%s). Ignoring it.", rrdhost_hostname(host), line, filename, alarm_id, pointers[3]);
235 errored++;
236 continue;
237 }
@@ -232,18 +242,7 @@ static inline ssize_t health_alarm_log_read(RRDHOST *host, FILE *fp, const char
242 char* alarm_name = pointers[13];
243 last_repeat = (time_t)strtoul(pointers[27], NULL, 16);
244
235 - RRDCALC *rc = alarm_max_last_repeat(host, alarm_name,simple_hash(alarm_name));
236 - if (!rc) {
237 - for(rc = host->alarms; rc ; rc = rc->next) {
238 - RRDCALC *rdcmp = (RRDCALC *) avl_insert_lock(&(host)->alarms_idx_name, (avl_t *)rc);
239 - if(rdcmp != rc) {
240 - error("Cannot insert the alarm index ID using log %s", rc->name);
241 - }
242 - }
243 -
244 - rc = alarm_max_last_repeat(host, alarm_name,simple_hash(alarm_name));
245 - }
246 -
245 + rc = dictionary_get(all_rrdcalcs, alarm_name);
246 if(unlikely(rc)) {
247 if (rrdcalc_isrepeating(rc)) {
248 rc->last_repeat = last_repeat;
@@ -259,7 +258,7 @@ static inline ssize_t health_alarm_log_read(RRDHOST *host, FILE *fp, const char
258 // make sure it is properly numbered
259 if(unlikely(host->health_log.alarms && unique_id < host->health_log.alarms->unique_id)) {
260 error( "HEALTH [%s]: line %zu of file '%s' has alarm log entry %u in wrong order. Ignoring it."
262 - , host->hostname, line, filename, unique_id);
261 + , rrdhost_hostname(host), line, filename, unique_id);
262 errored++;
263 continue;
264 }
@@ -272,7 +271,7 @@ static inline ssize_t health_alarm_log_read(RRDHOST *host, FILE *fp, const char
271 if(unlikely(unique_id == ae->unique_id)) {
272 if(unlikely(*pointers[0] == 'A')) {
273 error("HEALTH [%s]: line %zu of file '%s' adds duplicate alarm log entry %u. Using the later."
275 - , host->hostname, line, filename, unique_id);
274 + , rrdhost_hostname(host), line, filename, unique_id);
275 *pointers[0] = 'U';
276 duplicate++;
277 }
@@ -298,8 +297,13 @@ static inline ssize_t health_alarm_log_read(RRDHOST *host, FILE *fp, const char
297 // error("HEALTH [%s]: line %zu of file '%s' provides an alarm for host '%s' but this is named '%s'.", host->hostname, line, filename, pointers[1], host->hostname);
298
299 ae->unique_id = unique_id;
301 - if (!is_valid_alarm_id(host, pointers[14], pointers[13], alarm_id))
302 - alarm_id = rrdcalc_get_unique_id(host, pointers[14], pointers[13], NULL);
300 + if (!is_valid_alarm_id(host, pointers[14], pointers[13], alarm_id)) {
301 + STRING *chart = string_strdupz(pointers[14]);
302 + STRING *name = string_strdupz(pointers[13]);
303 + alarm_id = rrdcalc_get_unique_id(host, chart, name, NULL);
304 + string_freez(chart);
305 + string_freez(name);
306 + }
307 ae->alarm_id = alarm_id;
308 ae->alarm_event_id = (uint32_t)strtoul(pointers[4], NULL, 16);
309 ae->updated_by_id = (uint32_t)strtoul(pointers[5], NULL, 16);
@@ -315,36 +319,29 @@ static inline ssize_t health_alarm_log_read(RRDHOST *host, FILE *fp, const char
319 ae->exec_run_timestamp = (uint32_t)strtoul(pointers[11], NULL, 16);
320 ae->delay_up_to_timestamp = (uint32_t)strtoul(pointers[12], NULL, 16);
321
318 - freez(ae->name);
319 - ae->name = strdupz(pointers[13]);
320 - ae->hash_name = simple_hash(ae->name);
322 + string_freez(ae->name);
323 + ae->name = string_strdupz(pointers[13]);
324
322 - freez(ae->chart);
323 - ae->chart = strdupz(pointers[14]);
324 - ae->hash_chart = simple_hash(ae->chart);
325 + string_freez(ae->chart);
326 + ae->chart = string_strdupz(pointers[14]);
327
326 - freez(ae->family);
327 - ae->family = strdupz(pointers[15]);
328 + string_freez(ae->family);
329 + ae->family = string_strdupz(pointers[15]);
330
329 - freez(ae->exec);
330 - ae->exec = strdupz(pointers[16]);
331 - if(!*ae->exec) { freez(ae->exec); ae->exec = NULL; }
331 + string_freez(ae->exec);
332 + ae->exec = string_strdupz(pointers[16]);
333
333 - freez(ae->recipient);
334 - ae->recipient = strdupz(pointers[17]);
335 - if(!*ae->recipient) { freez(ae->recipient); ae->recipient = NULL; }
334 + string_freez(ae->recipient);
335 + ae->recipient = string_strdupz(pointers[17]);
336
337 - freez(ae->source);
338 - ae->source = strdupz(pointers[18]);
339 - if(!*ae->source) { freez(ae->source); ae->source = NULL; }
337 + string_freez(ae->source);
338 + ae->source = string_strdupz(pointers[18]);
339
341 - freez(ae->units);
342 - ae->units = strdupz(pointers[19]);
343 - if(!*ae->units) { freez(ae->units); ae->units = NULL; }
340 + string_freez(ae->units);
341 + ae->units = string_strdupz(pointers[19]);
342
345 - freez(ae->info);
346 - ae->info = strdupz(pointers[20]);
347 - if(!*ae->info) { freez(ae->info); ae->info = NULL; }
343 + string_freez(ae->info);
344 + ae->info = string_strdupz(pointers[20]);
345
346 ae->exec_code = str2i(pointers[21]);
347 ae->new_status = str2i(pointers[22]);
@@ -357,24 +354,21 @@ static inline ssize_t health_alarm_log_read(RRDHOST *host, FILE *fp, const char
354 ae->last_repeat = last_repeat;
355
356 if (likely(entries > 30)) {
360 - freez(ae->classification);
361 - ae->classification = strdupz(pointers[28]);
362 - if(!*ae->classification) { freez(ae->classification); ae->classification = NULL; }
357 + string_freez(ae->classification);
358 + ae->classification = string_strdupz(pointers[28]);
359
364 - freez(ae->component);
365 - ae->component = strdupz(pointers[29]);
366 - if(!*ae->component) { freez(ae->component); ae->component = NULL; }
360 + string_freez(ae->component);
361 + ae->component = string_strdupz(pointers[29]);
362
368 - freez(ae->type);
369 - ae->type = strdupz(pointers[30]);
370 - if(!*ae->type) { freez(ae->type); ae->type = NULL; }
363 + string_freez(ae->type);
364 + ae->type = string_strdupz(pointers[30]);
365 }
366
367 char value_string[100 + 1];
374 - freez(ae->old_value_string);
375 - freez(ae->new_value_string);
376 - ae->old_value_string = strdupz(format_value_and_unit(value_string, 100, ae->old_value, ae->units, -1));
377 - ae->new_value_string = strdupz(format_value_and_unit(value_string, 100, ae->new_value, ae->units, -1));
368 + string_freez(ae->old_value_string);
369 + string_freez(ae->new_value_string);
370 + ae->old_value_string = string_strdupz(format_value_and_unit(value_string, 100, ae->old_value, ae_units(ae), -1));
371 + ae->new_value_string = string_strdupz(format_value_and_unit(value_string, 100, ae->new_value, ae_units(ae), -1));
372
373 // add it to host if not already there
374 if(unlikely(*pointers[0] == 'A')) {
@@ -395,11 +389,14 @@ static inline ssize_t health_alarm_log_read(RRDHOST *host, FILE *fp, const char
389 host->health_max_alarm_id = ae->alarm_id;
390 }
391 else {
398 - error("HEALTH [%s]: line %zu of file '%s' is invalid (unrecognized entry type '%s').", host->hostname, line, filename, pointers[0]);
392 + error("HEALTH [%s]: line %zu of file '%s' is invalid (unrecognized entry type '%s').", rrdhost_hostname(host), line, filename, pointers[0]);
393 errored++;
394 }
395 }
396
397 + dictionary_destroy(all_rrdcalcs);
398 + all_rrdcalcs = NULL;
399 +
400 netdata_rwlock_unlock(&host->health_log.alarm_log_rwlock);
401
402 freez(buf);
@@ -411,7 +408,7 @@ static inline ssize_t health_alarm_log_read(RRDHOST *host, FILE *fp, const char
408 if (unlikely(!host->health_log.next_alarm_id || host->health_log.next_alarm_id <= host->health_max_alarm_id))
409 host->health_log.next_alarm_id = host->health_max_alarm_id + 1;
410
414 - debug(D_HEALTH, "HEALTH [%s]: loaded file '%s' with %zd new alarm entries, updated %zd alarms, errors %zd entries, duplicate %zd", host->hostname, filename, loaded, updated, errored, duplicate);
411 + debug(D_HEALTH, "HEALTH [%s]: loaded file '%s' with %zd new alarm entries, updated %zd alarms, errors %zd entries, duplicate %zd", rrdhost_hostname(host), filename, loaded, updated, errored, duplicate);
412 return loaded;
413 }
414
@@ -422,7 +419,7 @@ inline void health_alarm_log_load(RRDHOST *host) {
419 snprintfz(filename, FILENAME_MAX, "%s.old", host->health_log_filename);
420 FILE *fp = fopen(filename, "r");
421 if(!fp)
425 - error("HEALTH [%s]: cannot open health file: %s", host->hostname, filename);
422 + error("HEALTH [%s]: cannot open health file: %s", rrdhost_hostname(host), filename);
423 else {
424 health_alarm_log_read(host, fp, filename);
425 fclose(fp);
@@ -431,7 +428,7 @@ inline void health_alarm_log_load(RRDHOST *host) {
428 host->health_log_entries_written = 0;
429 fp = fopen(host->health_log_filename, "r");
430 if(!fp)
434 - error("HEALTH [%s]: cannot open health file: %s", host->hostname, host->health_log_filename);
431 + error("HEALTH [%s]: cannot open health file: %s", rrdhost_hostname(host), host->health_log_filename);
432 else {
433 health_alarm_log_read(host, fp, host->health_log_filename);
434 fclose(fp);
@@ -443,63 +440,48 @@ inline void health_alarm_log_load(RRDHOST *host) {
440 // health alarm log management
441
442 inline ALARM_ENTRY* health_create_alarm_entry(
446 - RRDHOST *host,
447 - uint32_t alarm_id,
448 - uint32_t alarm_event_id,
449 - uuid_t config_hash_id,
450 - time_t when,
451 - const char *name,
452 - const char *chart,
453 - const char *chart_context,
454 - const char *family,
455 - const char *class,
456 - const char *component,
457 - const char *type,
458 - const char *exec,
459 - const char *recipient,
460 - time_t duration,
461 - NETDATA_DOUBLE old_value,
462 - NETDATA_DOUBLE new_value,
463 - RRDCALC_STATUS old_status,
464 - RRDCALC_STATUS new_status,
465 - const char *source,
466 - const char *units,
467 - const char *info,
468 - int delay,
469 - uint32_t flags
443 + RRDHOST *host,
444 + uint32_t alarm_id,
445 + uint32_t alarm_event_id,
446 + const uuid_t config_hash_id,
447 + time_t when,
448 + STRING *name,
449 + STRING *chart,
450 + STRING *chart_context,
451 + STRING *family,
452 + STRING *class,
453 + STRING *component,
454 + STRING *type,
455 + STRING *exec,
456 + STRING *recipient,
457 + time_t duration,
458 + NETDATA_DOUBLE old_value,
459 + NETDATA_DOUBLE new_value,
460 + RRDCALC_STATUS old_status,
461 + RRDCALC_STATUS new_status,
462 + STRING *source,
463 + STRING *units,
464 + STRING *info,
465 + int delay,
466 + uint32_t flags
467 ) {
468 debug(D_HEALTH, "Health adding alarm log entry with id: %u", host->health_log.next_log_id);
469
470 ALARM_ENTRY *ae = callocz(1, sizeof(ALARM_ENTRY));
474 - ae->name = strdupz(name);
475 - ae->hash_name = simple_hash(ae->name);
476 -
477 - if(chart) {
478 - ae->chart = strdupz(chart);
479 - ae->hash_chart = simple_hash(ae->chart);
480 - }
481 -
482 - if(chart_context)
483 - ae->chart_context = strdupz(chart_context);
471 + ae->name = string_dup(name);
472 + ae->chart = string_dup(chart);
473 + ae->chart_context = string_dup(chart_context);
474
475 uuid_copy(ae->config_hash_id, *((uuid_t *) config_hash_id));
476
487 - if(family)
488 - ae->family = strdupz(family);
489 -
490 - if (class)
491 - ae->classification = strdupz(class);
492 -
493 - if (component)
494 - ae->component = strdupz(component);
495 -
496 - if (type)
497 - ae->type = strdupz(type);
498 -
499 - if(exec) ae->exec = strdupz(exec);
500 - if(recipient) ae->recipient = strdupz(recipient);
501 - if(source) ae->source = strdupz(source);
502 - if(units) ae->units = strdupz(units);
477 + ae->family = string_dup(family);
478 + ae->classification = string_dup(class);
479 + ae->component = string_dup(component);
480 + ae->type = string_dup(type);
481 + ae->exec = string_dup(exec);
482 + ae->recipient = string_dup(recipient);
483 + ae->source = string_dup(source);
484 + ae->units = string_dup(units);
485
486 ae->unique_id = host->health_log.next_log_id++;
487 ae->alarm_id = alarm_id;
@@ -509,12 +491,10 @@ inline ALARM_ENTRY* health_create_alarm_entry(
491 ae->new_value = new_value;
492
493 char value_string[100 + 1];
512 - ae->old_value_string = strdupz(format_value_and_unit(value_string, 100, ae->old_value, ae->units, -1));
513 - ae->new_value_string = strdupz(format_value_and_unit(value_string, 100, ae->new_value, ae->units, -1));
514 -
515 - if (info)
516 - ae->info = strdupz(info);
494 + ae->old_value_string = string_strdupz(format_value_and_unit(value_string, 100, ae->old_value, ae_units(ae), -1));
495 + ae->new_value_string = string_strdupz(format_value_and_unit(value_string, 100, ae->new_value, ae_units(ae), -1));
496
497 + ae->info = string_dup(info);
498 ae->old_status = old_status;
499 ae->new_status = new_status;
500 ae->duration = duration;
@@ -570,20 +550,20 @@ inline void health_alarm_log(
550 }
551
552 inline void health_alarm_log_free_one_nochecks_nounlink(ALARM_ENTRY *ae) {
573 - freez(ae->name);
574 - freez(ae->chart);
575 - freez(ae->chart_context);
576 - freez(ae->family);
577 - freez(ae->classification);
578 - freez(ae->component);
579 - freez(ae->type);
580 - freez(ae->exec);
581 - freez(ae->recipient);
582 - freez(ae->source);
583 - freez(ae->units);
584 - freez(ae->info);
585 - freez(ae->old_value_string);
586 - freez(ae->new_value_string);
553 + string_freez(ae->name);
554 + string_freez(ae->chart);
555 + string_freez(ae->chart_context);
556 + string_freez(ae->family);
557 + string_freez(ae->classification);
558 + string_freez(ae->component);
559 + string_freez(ae->type);
560 + string_freez(ae->exec);
561 + string_freez(ae->recipient);
562 + string_freez(ae->source);
563 + string_freez(ae->units);
564 + string_freez(ae->info);
565 + string_freez(ae->old_value_string);
566 + string_freez(ae->new_value_string);
567 freez(ae);
568 }
569
libnetdata/circular_buffer/circular_buffer.c
+6
@@ -46,6 +46,11 @@ static int cbuffer_realloc_unsafe(struct circular_buffer *buf) {
46 return 0;
47 }
48
49 +size_t cbuffer_available_size_unsafe(struct circular_buffer *buf) {
50 + size_t len = (buf->write >= buf->read) ? (buf->write - buf->read) : (buf->size - buf->read + buf->write);
51 + return buf->max_size - len;
52 +}
53 +
54 int cbuffer_add_unsafe(struct circular_buffer *buf, const char *d, size_t d_len) {
55 size_t len = (buf->write >= buf->read) ? (buf->write - buf->read) : (buf->size - buf->read + buf->write);
56 while (d_len + len >= buf->size) {
@@ -78,6 +83,7 @@ void cbuffer_remove_unsafe(struct circular_buffer *buf, size_t num) {
83 size_t cbuffer_next_unsafe(struct circular_buffer *buf, char **start) {
84 if (start != NULL)
85 *start = buf->data + buf->read;
86 +
87 if (buf->read <= buf->write) {
88 return buf->write - buf->read; // Includes empty case
89 }
libnetdata/circular_buffer/circular_buffer.h
+2
@@ -13,4 +13,6 @@ extern void cbuffer_free(struct circular_buffer *buf);
13 extern int cbuffer_add_unsafe(struct circular_buffer *buf, const char *d, size_t d_len);
14 extern void cbuffer_remove_unsafe(struct circular_buffer *buf, size_t num);
15 extern size_t cbuffer_next_unsafe(struct circular_buffer *buf, char **start);
16 +extern size_t cbuffer_available_size_unsafe(struct circular_buffer *buf);
17 +
18 #endif
libnetdata/dictionary/dictionary.c
+416 -192
@@ -1,28 +1,17 @@
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 // NOT TO BE USED BY USERS
4 -#define DICTIONARY_FLAG_EXCLUSIVE_ACCESS (1 << 29) // there is only one thread accessing the dictionary
5 -#define DICTIONARY_FLAG_DESTROYED (1 << 30) // this dictionary has been destroyed
6 -#define DICTIONARY_FLAG_DEFER_ALL_DELETIONS (1 << 31) // defer all deletions of items in the dictionary
4 +#define DICTIONARY_FLAG_EXCLUSIVE_ACCESS (1 << 28) // there is only one thread accessing the dictionary
5 +#define DICTIONARY_FLAG_DESTROYED (1 << 29) // this dictionary has been destroyed
6 +#define DICTIONARY_FLAG_DEFER_ALL_DELETIONS (1 << 30) // defer all deletions of items in the dictionary
7
8 // our reserved flags that cannot be set by users
9 #define DICTIONARY_FLAGS_RESERVED (DICTIONARY_FLAG_EXCLUSIVE_ACCESS|DICTIONARY_FLAG_DESTROYED|DICTIONARY_FLAG_DEFER_ALL_DELETIONS)
10
11 -typedef struct dictionary DICTIONARY;
11 #define DICTIONARY_INTERNALS
12
13 #include "../libnetdata.h"
15 -
16 -#ifndef ENABLE_DBENGINE
17 -#define DICTIONARY_WITH_AVL
18 -#warning Compiling DICTIONARY with an AVL index
19 -#else
20 -#define DICTIONARY_WITH_JUDYHS
21 -#endif
22 -
23 -#ifdef DICTIONARY_WITH_JUDYHS
14 #include <Judy.h>
25 -#endif
15
16 typedef enum name_value_flags {
17 NAME_VALUE_FLAG_NONE = 0,
@@ -38,10 +27,6 @@ typedef enum name_value_flags {
27 */
28
29 typedef struct name_value {
41 -#ifdef DICTIONARY_WITH_AVL
42 - avl_t avl_node;
43 -#endif
44 -
30 #ifdef NETDATA_INTERNAL_CHECKS
31 DICTIONARY *dict;
32 #endif
@@ -72,15 +57,7 @@ struct dictionary {
57 NAME_VALUE *first_item; // the double linked list base pointers
58 NAME_VALUE *last_item;
59
75 -#ifdef DICTIONARY_WITH_AVL
76 - avl_tree_type values_index;
77 - NAME_VALUE *hash_base;
78 - void *(*get_thread_static_name_value)(const char *name);
79 -#endif
80 -
81 -#ifdef DICTIONARY_WITH_JUDYHS
60 Pvoid_t JudyHSArray; // the hash table
83 -#endif
61
62 netdata_rwlock_t rwlock; // the r/w lock when DICTIONARY_FLAG_SINGLE_THREADED is not set
63
@@ -315,9 +292,9 @@ static inline size_t dictionary_lock_free(DICTIONARY *dict) {
292 }
293
294 static void dictionary_lock(DICTIONARY *dict, char rw) {
318 - if(rw == 'u' || rw == 'U') return;
295 + if(rw == DICTIONARY_LOCK_NONE || rw == 'U') return;
296
320 - if(rw == 'r' || rw == 'R') {
297 + if(rw == DICTIONARY_LOCK_READ || rw == DICTIONARY_LOCK_REENTRANT || rw == 'R') {
298 // read lock
299 __atomic_add_fetch(&dict->readers, 1, __ATOMIC_RELAXED);
300 }
@@ -329,7 +306,7 @@ static void dictionary_lock(DICTIONARY *dict, char rw) {
306 if(likely(dict->flags & DICTIONARY_FLAG_SINGLE_THREADED))
307 return;
308
332 - if(rw == 'r' || rw == 'R') {
309 + if(rw == DICTIONARY_LOCK_READ || rw == DICTIONARY_LOCK_REENTRANT || rw == 'R') {
310 // read lock
311 netdata_rwlock_rdlock(&dict->rwlock);
312
@@ -347,9 +324,9 @@ static void dictionary_lock(DICTIONARY *dict, char rw) {
324 }
325
326 static void dictionary_unlock(DICTIONARY *dict, char rw) {
350 - if(rw == 'u' || rw == 'U') return;
327 + if(rw == DICTIONARY_LOCK_NONE || rw == 'U') return;
328
352 - if(rw == 'r' || rw == 'R') {
329 + if(rw == DICTIONARY_LOCK_READ || rw == DICTIONARY_LOCK_REENTRANT || rw == 'R') {
330 // read unlock
331 __atomic_sub_fetch(&dict->readers, 1, __ATOMIC_RELAXED);
332 }
@@ -480,68 +457,6 @@ static uint32_t reference_counter_release(DICTIONARY *dict, NAME_VALUE *nv, bool
457 // ----------------------------------------------------------------------------
458 // hash table
459
483 -#ifdef DICTIONARY_WITH_AVL
484 -static inline const char *namevalue_get_name(NAME_VALUE *nv);
485 -
486 -static int name_value_compare(void* a, void* b) {
487 - return strcmp(namevalue_get_name((NAME_VALUE *)a), namevalue_get_name((NAME_VALUE *)b));
488 -}
489 -
490 -static void *get_thread_static_name_value(const char *name) {
491 - static __thread NAME_VALUE tmp = { 0 };
492 - tmp.flags = NAME_VALUE_FLAG_NONE;
493 - tmp.caller_name = (char *)name;
494 - return &tmp;
495 -}
496 -
497 -static void hashtable_init_unsafe(DICTIONARY *dict) {
498 - avl_init(&dict->values_index, name_value_compare);
499 - dict->get_thread_static_name_value = get_thread_static_name_value;
500 -}
501 -
502 -static size_t hashtable_destroy_unsafe(DICTIONARY *dict) {
503 - (void)dict;
504 - return 0;
505 -}
506 -
507 -static inline int hashtable_delete_unsafe(DICTIONARY *dict, const char *name, size_t name_len, void *nv) {
508 - (void)name;
509 - (void)name_len;
510 -
511 - if(unlikely(avl_remove(&(dict->values_index), (avl_t *)(nv)) != (avl_t *)nv))
512 - return 0;
513 -
514 - return 1;
515 -}
516 -
517 -static inline NAME_VALUE *hashtable_get_unsafe(DICTIONARY *dict, const char *name, size_t name_len) {
518 - (void)name_len;
519 -
520 - void *tmp = dict->get_thread_static_name_value(name);
521 - return (NAME_VALUE *)avl_search(&(dict->values_index), (avl_t *)tmp);
522 -}
523 -
524 -static inline NAME_VALUE **hashtable_insert_unsafe(DICTIONARY *dict, const char *name, size_t name_len) {
525 - // AVL needs a NAME_VALUE to insert into the dictionary but we don't have it yet.
526 - // So, the only thing we can do, is return an existing one if it is already there.
527 - // Returning NULL will make the caller thing we added it, will allocate one
528 - // and will call hashtable_inserted_name_value_unsafe(), at which we will do
529 - // the actual indexing.
530 -
531 - dict->hash_base = hashtable_get_unsafe(dict, name, name_len);
532 - return &dict->hash_base;
533 -}
534 -
535 -static inline void hashtable_inserted_name_value_unsafe(DICTIONARY *dict, void *nv) {
536 - // we have our new NAME_VALUE object.
537 - // Let's index it.
538 -
539 - if(unlikely(avl_insert(&((dict)->values_index), (avl_t *)(nv)) != (avl_t *)nv))
540 - error("dictionary: INTERNAL ERROR: duplicate insertion to dictionary.");
541 -}
542 -#endif
543 -
544 -#ifdef DICTIONARY_WITH_JUDYHS
460 static void hashtable_init_unsafe(DICTIONARY *dict) {
461 dict->JudyHSArray = NULL;
462 }
@@ -562,7 +477,7 @@ static size_t hashtable_destroy_unsafe(DICTIONARY *dict) {
477 return (size_t)ret;
478 }
479
565 -static inline NAME_VALUE **hashtable_insert_unsafe(DICTIONARY *dict, const char *name, size_t name_len) {
480 +static inline void **hashtable_insert_unsafe(DICTIONARY *dict, const char *name, size_t name_len) {
481 internal_error(!(dict->flags & DICTIONARY_FLAG_EXCLUSIVE_ACCESS), "DICTIONARY: inserting item from the index without exclusive access to the dictionary created by %s() (%zu@%s)", dict->creation_function, dict->creation_line, dict->creation_file);
482
483 JError_t J_Error;
@@ -579,7 +494,7 @@ static inline NAME_VALUE **hashtable_insert_unsafe(DICTIONARY *dict, const char
494 // put anything needed at the value of the index.
495 // The pointer to pointer we return has to be used before
496 // any other operation that may change the index (insert/delete).
582 - return (NAME_VALUE **)Rc;
497 + return Rc;
498 }
499
500 static inline int hashtable_delete_unsafe(DICTIONARY *dict, const char *name, size_t name_len, void *nv) {
@@ -632,8 +547,6 @@ static inline void hashtable_inserted_name_value_unsafe(DICTIONARY *dict, void *
547 ;
548 }
549
635 -#endif // DICTIONARY_WITH_JUDYHS
636 -
550 // ----------------------------------------------------------------------------
551 // linked list management
552
@@ -979,7 +892,7 @@ static NAME_VALUE *dictionary_set_name_value_unsafe(DICTIONARY *dict, const char
892 // But the caller has the option to do this on his/her own.
893 // So, let's do the fastest here and let the caller decide the flow of calls.
894
982 - NAME_VALUE *nv, **pnv = hashtable_insert_unsafe(dict, name, name_len);
895 + NAME_VALUE *nv, **pnv = (NAME_VALUE **)hashtable_insert_unsafe(dict, name, name_len);
896 if(likely(*pnv == 0)) {
897 // a new item added to the index
898 nv = *pnv = namevalue_create_unsafe(dict, name, name_len, value, value_len);
@@ -1280,6 +1193,9 @@ void *dictionary_foreach_start_rw(DICTFE *dfe, DICTIONARY *dict, char rw) {
1193 dfe->value = NULL;
1194 }
1195
1196 + if(unlikely(dfe->rw == DICTIONARY_LOCK_REENTRANT))
1197 + dictionary_unlock(dfe->dict, dfe->rw);
1198 +
1199 return dfe->value;
1200 }
1201
@@ -1294,6 +1210,9 @@ void *dictionary_foreach_next(DICTFE *dfe) {
1210 return NULL;
1211 }
1212
1213 + if(unlikely(dfe->rw == DICTIONARY_LOCK_REENTRANT))
1214 + dictionary_lock(dfe->dict, dfe->rw);
1215 +
1216 // the item we just did
1217 NAME_VALUE *nv = (NAME_VALUE *)dfe->last_item;
1218
@@ -1320,6 +1239,9 @@ void *dictionary_foreach_next(DICTFE *dfe) {
1239 dfe->value = NULL;
1240 }
1241
1242 + if(unlikely(dfe->rw == DICTIONARY_LOCK_REENTRANT))
1243 + dictionary_unlock(dfe->dict, dfe->rw);
1244 +
1245 return dfe->value;
1246 }
1247
@@ -1338,7 +1260,9 @@ usec_t dictionary_foreach_done(DICTFE *dfe) {
1260 if(likely(nv))
1261 reference_counter_release(dfe->dict, nv, false);
1262
1341 - dictionary_unlock(dfe->dict, dfe->rw);
1263 + if(likely(dfe->rw != DICTIONARY_LOCK_REENTRANT))
1264 + dictionary_unlock(dfe->dict, dfe->rw);
1265 +
1266 dfe->dict = NULL;
1267 dfe->last_item = NULL;
1268 dfe->name = NULL;
@@ -1383,8 +1307,14 @@ int dictionary_walkthrough_rw(DICTIONARY *dict, char rw, int (*callback)(const c
1307 // while we are using it
1308 reference_counter_acquire(dict, nv);
1309
1310 + if(unlikely(rw == DICTIONARY_LOCK_REENTRANT))
1311 + dictionary_unlock(dict, rw);
1312 +
1313 int r = callback(namevalue_get_name(nv), nv->value, data);
1314
1315 + if(unlikely(rw == DICTIONARY_LOCK_REENTRANT))
1316 + dictionary_lock(dict, rw);
1317 +
1318 // since we have a reference counter, this item cannot be deleted
1319 // until we release the reference counter, so the pointers are there
1320 nv_next = nv->next;
@@ -1449,7 +1379,15 @@ int dictionary_sorted_walkthrough_rw(DICTIONARY *dict, char rw, int (*callback)(
1379 nv = array[i];
1380 if(likely(!(nv->flags & NAME_VALUE_FLAG_DELETED))) {
1381 reference_counter_acquire(dict, nv);
1382 +
1383 + if(unlikely(rw == DICTIONARY_LOCK_REENTRANT))
1384 + dictionary_unlock(dict, rw);
1385 +
1386 int r = callback(namevalue_get_name(nv), nv->value, data);
1387 +
1388 + if(unlikely(rw == DICTIONARY_LOCK_REENTRANT))
1389 + dictionary_lock(dict, rw);
1390 +
1391 reference_counter_release(dict, nv, false);
1392 if (r < 0) {
1393 ret = r;
@@ -1469,132 +1407,293 @@ int dictionary_sorted_walkthrough_rw(DICTIONARY *dict, char rw, int (*callback)(
1407 // ----------------------------------------------------------------------------
1408 // STRING implementation - dedup all STRINGs
1409
1472 -typedef struct string_entry {
1473 -#ifdef DICTIONARY_WITH_AVL
1474 - avl_t avl_node;
1410 +struct netdata_string {
1411 + uint32_t length; // the string length including the terminating '\0'
1412 +
1413 + int32_t refcount; // how many times this string is used
1414 + // We use a signed number to be able to detect duplicate frees of a string.
1415 + // If at any point this goes below zero, we have a duplicate free.
1416 +
1417 + const char str[]; // the string itself, is appended to this structure
1418 +};
1419 +
1420 +static struct string_hashtable {
1421 + Pvoid_t JudyHSArray; // the Judy array - hashtable
1422 + netdata_rwlock_t rwlock; // the R/W lock to protect the Judy array
1423 +
1424 + long int entries; // the number of entries in the index
1425 + long int active_references; // the number of active references alive
1426 + long int memory; // the memory used, without the JudyHS index
1427 +
1428 + size_t inserts; // the number of successful inserts to the index
1429 + size_t deletes; // the number of successful deleted from the index
1430 + size_t searches; // the number of successful searches in the index
1431 + size_t duplications; // when a string is referenced
1432 + size_t releases; // when a string is unreferenced
1433 +
1434 +#ifdef NETDATA_INTERNAL_CHECKS
1435 + // internal statistics
1436 + size_t found_deleted_on_search;
1437 + size_t found_available_on_search;
1438 + size_t found_deleted_on_insert;
1439 + size_t found_available_on_insert;
1440 + size_t spins;
1441 +#endif
1442 +
1443 +} string_base = {
1444 + .JudyHSArray = NULL,
1445 + .rwlock = NETDATA_RWLOCK_INITIALIZER,
1446 +};
1447 +
1448 +#ifdef NETDATA_INTERNAL_CHECKS
1449 +#define string_internal_stats_add(var, val) __atomic_add_fetch(&string_base.var, val, __ATOMIC_RELAXED)
1450 +#else
1451 +#define string_internal_stats_add(var, val) do {;} while(0)
1452 #endif
1476 - uint32_t length; // the string length with the terminating '\0'
1477 - uint32_t refcount; // how many times this string is used
1478 - const char str[]; // the string itself
1479 -} STRING_ENTRY;
1453
1481 -#ifdef DICTIONARY_WITH_AVL
1482 -static int string_entry_compare(void* a, void* b) {
1483 - return strcmp(((STRING_ENTRY *)a)->str, ((STRING_ENTRY *)b)->str);
1454 +#define string_stats_atomic_increment(var) __atomic_add_fetch(&string_base.var, 1, __ATOMIC_RELAXED)
1455 +#define string_stats_atomic_decrement(var) __atomic_sub_fetch(&string_base.var, 1, __ATOMIC_RELAXED)
1456 +
1457 +void string_statistics(size_t *inserts, size_t *deletes, size_t *searches, size_t *entries, size_t *references, size_t *memory, size_t *duplications, size_t *releases) {
1458 + *inserts = string_base.inserts;
1459 + *deletes = string_base.deletes;
1460 + *searches = string_base.searches;
1461 + *entries = (size_t)string_base.entries;
1462 + *references = (size_t)string_base.active_references;
1463 + *memory = (size_t)string_base.memory;
1464 + *duplications = string_base.duplications;
1465 + *releases = string_base.releases;
1466 }
1467
1486 -static void *get_thread_static_string_entry(const char *name) {
1487 - static __thread size_t _length = 0;
1488 - static __thread STRING_ENTRY *_tmp = NULL;
1468 +#define string_entry_acquire(se) __atomic_add_fetch(&((se)->refcount), 1, __ATOMIC_SEQ_CST);
1469 +#define string_entry_release(se) __atomic_sub_fetch(&((se)->refcount), 1, __ATOMIC_SEQ_CST);
1470
1490 - size_t size = sizeof(STRING_ENTRY) + strlen(name) + 1;
1491 - if(likely(_tmp && _length < size)) {
1492 - freez(_tmp);
1493 - _tmp = NULL;
1494 - _length = 0;
1495 - }
1471 +static inline bool string_entry_check_and_acquire(STRING *se) {
1472 + int32_t expected, desired, count = 0;
1473 + do {
1474 + count++;
1475 +
1476 + expected = se->refcount;
1477 +
1478 + if(expected <= 0) {
1479 + // We cannot use this.
1480 + // The reference counter reached value zero,
1481 + // so another thread is deleting this.
1482 + string_internal_stats_add(spins, count - 1);
1483 + return false;
1484 + }
1485
1497 - if(unlikely(!_tmp)) {
1498 - _tmp = callocz(1, size);
1499 - _length = size;
1486 + desired = expected + 1;
1487 }
1488 + while(!__atomic_compare_exchange_n(&se->refcount, &expected, desired, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST));
1489 +
1490 + string_internal_stats_add(spins, count - 1);
1491 +
1492 + // statistics
1493 + // string_base.active_references is altered at the in string_strdupz() and string_freez()
1494 + string_stats_atomic_increment(duplications);
1495
1502 - strcpy((char *)&_tmp->str[0], name);
1503 - return _tmp;
1496 + return true;
1497 }
1505 -#endif
1498
1507 -DICTIONARY string_dictionary = {
1508 -#ifdef DICTIONARY_WITH_AVL
1509 - .values_index = {
1510 - .root = NULL,
1511 - .compar = string_entry_compare
1512 - },
1513 - .get_thread_static_name_value = get_thread_static_string_entry,
1499 +STRING *string_dup(STRING *string) {
1500 + if(unlikely(!string)) return NULL;
1501 +
1502 +#ifdef NETDATA_INTERNAL_CHECKS
1503 + if(unlikely(__atomic_load_n(&string->refcount, __ATOMIC_SEQ_CST) <= 0))
1504 + fatal("STRING: tried to %s() a string that is freed (it has %d references).", __FUNCTION__, string->refcount);
1505 #endif
1506
1516 - .flags = DICTIONARY_FLAG_EXCLUSIVE_ACCESS,
1517 - .rwlock = NETDATA_RWLOCK_INITIALIZER
1518 -};
1507 + string_entry_acquire(string);
1508
1520 -static netdata_mutex_t string_mutex = NETDATA_MUTEX_INITIALIZER;
1509 + // statistics
1510 + string_stats_atomic_increment(active_references);
1511 + string_stats_atomic_increment(duplications);
1512
1522 -STRING *string_dup(STRING *string) {
1523 - if(unlikely(!string)) return NULL;
1513 + return string;
1514 +}
1515 +
1516 +// Search the index and return an ACQUIRED string entry, or NULL
1517 +static inline STRING *string_index_search(const char *str, size_t length) {
1518 + if(unlikely(!string_base.JudyHSArray))
1519 + return NULL;
1520 +
1521 + STRING *string;
1522 +
1523 + // Find the string in the index
1524 + // With a read-lock so that multiple readers can use the index concurrently.
1525 +
1526 + netdata_rwlock_rdlock(&string_base.rwlock);
1527 +
1528 + Pvoid_t *Rc;
1529 + Rc = JudyHSGet(string_base.JudyHSArray, (void *)str, length);
1530 + if(likely(Rc)) {
1531 + // found in the hash table
1532 + string = *Rc;
1533 +
1534 + if(string_entry_check_and_acquire(string)) {
1535 + // we can use this entry
1536 + string_internal_stats_add(found_available_on_search, 1);
1537 + }
1538 + else {
1539 + // this entry is about to be deleted by another thread
1540 + // do not touch it, let it go...
1541 + string = NULL;
1542 + string_internal_stats_add(found_deleted_on_search, 1);
1543 + }
1544 + }
1545 + else {
1546 + // not found in the hash table
1547 + string = NULL;
1548 + }
1549 +
1550 + string_stats_atomic_increment(searches);
1551 + netdata_rwlock_unlock(&string_base.rwlock);
1552
1525 - STRING_ENTRY *se = (STRING_ENTRY *)string;
1526 - netdata_mutex_lock(&string_mutex);
1527 - se->refcount++;
1528 - netdata_mutex_unlock(&string_mutex);
1553 return string;
1554 }
1555
1532 -STRING *string_strdupz(const char *str) {
1533 - if(unlikely(!str || !*str)) return NULL;
1556 +// Insert a string to the index and return an ACQUIRED string entry,
1557 +// or NULL if the call needs to be retried (a deleted entry with the same key is still in the index)
1558 +// The returned entry is ACQUIRED and it can either be:
1559 +// 1. a new item inserted, or
1560 +// 2. an item found in the index that is not currently deleted
1561 +static inline STRING *string_index_insert(const char *str, size_t length) {
1562 + STRING *string;
1563
1535 - netdata_mutex_lock(&string_mutex);
1564 + netdata_rwlock_wrlock(&string_base.rwlock);
1565
1537 - size_t length = strlen(str) + 1;
1538 - STRING_ENTRY *se;
1539 - STRING_ENTRY **ptr = (STRING_ENTRY **)hashtable_insert_unsafe(&string_dictionary, str, length);
1540 - if(unlikely(*ptr == 0)) {
1566 + STRING **ptr;
1567 + {
1568 + JError_t J_Error;
1569 + Pvoid_t *Rc = JudyHSIns(&string_base.JudyHSArray, (void *)str, length, &J_Error);
1570 + if (unlikely(Rc == PJERR)) {
1571 + fatal(
1572 + "STRING: Cannot insert entry with name '%s' to JudyHS, JU_ERRNO_* == %u, ID == %d",
1573 + str,
1574 + JU_ERRNO(&J_Error),
1575 + JU_ERRID(&J_Error));
1576 + }
1577 + ptr = (STRING **)Rc;
1578 + }
1579 +
1580 + if (likely(*ptr == 0)) {
1581 // a new item added to the index
1542 - size_t mem_size = sizeof(STRING_ENTRY) + length;
1543 - se = mallocz(mem_size);
1544 - strcpy((char *)se->str, str);
1545 - se->length = length;
1546 - se->refcount = 1;
1547 - *ptr = se;
1548 - hashtable_inserted_name_value_unsafe(&string_dictionary, se);
1549 - string_dictionary.version++;
1550 - string_dictionary.inserts++;
1551 - string_dictionary.entries++;
1552 - string_dictionary.memory += (long)mem_size;
1582 + size_t mem_size = sizeof(STRING) + length;
1583 + string = mallocz(mem_size);
1584 + strcpy((char *)string->str, str);
1585 + string->length = length;
1586 + string->refcount = 1;
1587 + *ptr = string;
1588 + string_base.inserts++;
1589 + string_base.entries++;
1590 + string_base.memory += (long)mem_size;
1591 }
1592 else {
1593 // the item is already in the index
1556 - se = *ptr;
1557 - se->refcount++;
1558 - string_dictionary.searches++;
1594 + string = *ptr;
1595 +
1596 + if(string_entry_check_and_acquire(string)) {
1597 + // we can use this entry
1598 + string_internal_stats_add(found_available_on_insert, 1);
1599 + }
1600 + else {
1601 + // this entry is about to be deleted by another thread
1602 + // do not touch it, let it go...
1603 + string = NULL;
1604 + string_internal_stats_add(found_deleted_on_insert, 1);
1605 + }
1606 +
1607 + string_stats_atomic_increment(searches);
1608 }
1609
1561 - netdata_mutex_unlock(&string_mutex);
1562 - return (STRING *)se;
1610 + netdata_rwlock_unlock(&string_base.rwlock);
1611 + return string;
1612 }
1613
1565 -void string_freez(STRING *string) {
1566 - if(unlikely(!string)) return;
1567 - netdata_mutex_lock(&string_mutex);
1614 +// delete an entry from the index
1615 +static inline void string_index_delete(STRING *string) {
1616 + netdata_rwlock_wrlock(&string_base.rwlock);
1617
1569 - STRING_ENTRY *se = (STRING_ENTRY *)string;
1618 +#ifdef NETDATA_INTERNAL_CHECKS
1619 + if(unlikely(__atomic_load_n(&string->refcount, __ATOMIC_SEQ_CST) != 0))
1620 + fatal("STRING: tried to delete a string at %s() that is already freed (it has %d references).", __FUNCTION__, string->refcount);
1621 +#endif
1622
1571 - if(se->refcount == 0)
1572 - fatal("STRING: tried to free string that has zero references.");
1623 + bool deleted = false;
1624
1574 - se->refcount--;
1575 - if(unlikely(se->refcount == 0)) {
1576 - if(hashtable_delete_unsafe(&string_dictionary, se->str, se->length, se) == 0)
1577 - error("STRING: INTERNAL ERROR: tried to delete '%s' that is not in the index", se->str);
1625 + if (likely(string_base.JudyHSArray)) {
1626 + JError_t J_Error;
1627 + int ret = JudyHSDel(&string_base.JudyHSArray, (void *)string->str, string->length, &J_Error);
1628 + if (unlikely(ret == JERR)) {
1629 + error(
1630 + "STRING: Cannot delete entry with name '%s' from JudyHS, JU_ERRNO_* == %u, ID == %d",
1631 + string->str,
1632 + JU_ERRNO(&J_Error),
1633 + JU_ERRID(&J_Error));
1634 + } else
1635 + deleted = true;
1636 + }
1637
1579 - size_t mem_size = sizeof(STRING_ENTRY) + se->length;
1580 - freez(se);
1581 - string_dictionary.version++;
1582 - string_dictionary.deletes++;
1583 - string_dictionary.entries--;
1584 - string_dictionary.memory -= (long)mem_size;
1638 + if (unlikely(!deleted))
1639 + error("STRING: tried to delete '%s' that is not in the index. Ignoring it.", string->str);
1640 + else {
1641 + size_t mem_size = sizeof(STRING) + string->length;
1642 + string_base.deletes++;
1643 + string_base.entries--;
1644 + string_base.memory -= (long)mem_size;
1645 + freez(string);
1646 }
1647
1587 - netdata_mutex_unlock(&string_mutex);
1648 + netdata_rwlock_unlock(&string_base.rwlock);
1649 }
1650
1590 -size_t string_length(STRING *string) {
1651 +STRING *string_strdupz(const char *str) {
1652 + if(unlikely(!str || !*str)) return NULL;
1653 +
1654 + size_t length = strlen(str) + 1;
1655 + STRING *string = string_index_search(str, length);
1656 +
1657 + while(!string) {
1658 + // The search above did not find anything,
1659 + // We loop here, because during insert we may find an entry that is being deleted by another thread.
1660 + // So, we have to let it go and retry to insert it again.
1661 +
1662 + string = string_index_insert(str, length);
1663 + }
1664 +
1665 + // statistics
1666 + string_stats_atomic_increment(active_references);
1667 +
1668 + return string;
1669 +}
1670 +
1671 +void string_freez(STRING *string) {
1672 + if(unlikely(!string)) return;
1673 +
1674 + int32_t refcount = string_entry_release(string);
1675 +
1676 +#ifdef NETDATA_INTERNAL_CHECKS
1677 + if(unlikely(refcount < 0))
1678 + fatal("STRING: tried to %s() a string that is already freed (it has %d references).", __FUNCTION__, string->refcount);
1679 +#endif
1680 +
1681 + if(unlikely(refcount == 0))
1682 + string_index_delete(string);
1683 +
1684 + // statistics
1685 + string_stats_atomic_decrement(active_references);
1686 + string_stats_atomic_increment(releases);
1687 +}
1688 +
1689 +size_t string_strlen(STRING *string) {
1690 if(unlikely(!string)) return 0;
1592 - return ((STRING_ENTRY *)string)->length - 1;
1691 + return string->length - 1;
1692 }
1693
1694 const char *string2str(STRING *string) {
1695 if(unlikely(!string)) return "";
1597 - return ((STRING_ENTRY *)string)->str;
1696 + return string->str;
1697 }
1698
1699 STRING *string_2way_merge(STRING *a, STRING *b) {
@@ -1610,9 +1709,9 @@ STRING *string_2way_merge(STRING *a, STRING *b) {
1709 if(unlikely(!a)) return string_dup(X);
1710 if(unlikely(!b)) return string_dup(X);
1711
1613 - size_t alen = string_length(a);
1614 - size_t blen = string_length(b);
1615 - size_t length = alen + blen + string_length(X) + 1;
1712 + size_t alen = string_strlen(a);
1713 + size_t blen = string_strlen(b);
1714 + size_t length = alen + blen + string_strlen(X) + 1;
1715 char buf1[length + 1], buf2[length + 1], *dst1;
1716 const char *s1, *s2;
1717
@@ -1642,6 +1741,52 @@ STRING *string_2way_merge(STRING *a, STRING *b) {
1741 return string_strdupz(buf1);
1742 }
1743
1744 +// ----------------------------------------------------------------------------
1745 +// THREAD_CACHE
1746 +
1747 +static __thread Pvoid_t thread_cache_judy_array = NULL;
1748 +
1749 +void *thread_cache_entry_get_or_set(void *key,
1750 + ssize_t key_length,
1751 + void *value,
1752 + void *(*transform_the_value_before_insert)(void *key, size_t key_length, void *value)
1753 + ) {
1754 + if(unlikely(!key || !key_length)) return NULL;
1755 +
1756 + if(key_length == -1)
1757 + key_length = (ssize_t)strlen((char *)key) + 1;
1758 +
1759 + JError_t J_Error;
1760 + Pvoid_t *Rc = JudyHSIns(&thread_cache_judy_array, key, key_length, &J_Error);
1761 + if (unlikely(Rc == PJERR)) {
1762 + fatal("THREAD_CACHE: Cannot insert entry to JudyHS, JU_ERRNO_* == %u, ID == %d",
1763 + JU_ERRNO(&J_Error), JU_ERRID(&J_Error));
1764 + }
1765 +
1766 + if(*Rc == 0) {
1767 + // new item added
1768 +
1769 + *Rc = (transform_the_value_before_insert) ? transform_the_value_before_insert(key, key_length, value) : value;
1770 + }
1771 +
1772 + return *Rc;
1773 +}
1774 +
1775 +void thread_cache_destroy(void) {
1776 + if(unlikely(!thread_cache_judy_array)) return;
1777 +
1778 + JError_t J_Error;
1779 + Word_t ret = JudyHSFreeArray(&thread_cache_judy_array, &J_Error);
1780 + if(unlikely(ret == (Word_t) JERR)) {
1781 + error("THREAD_CACHE: Cannot destroy JudyHS, JU_ERRNO_* == %u, ID == %d",
1782 + JU_ERRNO(&J_Error), JU_ERRID(&J_Error));
1783 + }
1784 +
1785 + internal_error(true, "THREAD_CACHE: hash table freed %lu bytes", ret);
1786 +
1787 + thread_cache_judy_array = NULL;
1788 +}
1789 +
1790 // ----------------------------------------------------------------------------
1791 // unit test
1792
@@ -2153,6 +2298,27 @@ static size_t check_name_value_deleted_flag(DICTIONARY *dict, NAME_VALUE *nv, co
2298 return errors;
2299 }
2300
2301 +static int string_threads_join = 0;
2302 +static void *string_thread(void *arg __maybe_unused) {
2303 + int dups = 1; //(gettid() % 10);
2304 + for(; 1 ;) {
2305 + if(string_threads_join)
2306 + break;
2307 +
2308 + STRING *s = string_strdupz("string thread checking 1234567890");
2309 +
2310 + for(int i = 0; i < dups ; i++)
2311 + string_dup(s);
2312 +
2313 + for(int i = 0; i < dups ; i++)
2314 + string_freez(s);
2315 +
2316 + string_freez(s);
2317 + }
2318 +
2319 + return arg;
2320 +}
2321 +
2322 int dictionary_unittest(size_t entries) {
2323 if(entries < 10) entries = 10;
2324
@@ -2291,7 +2457,7 @@ int dictionary_unittest(size_t entries) {
2457
2458 // check string
2459 {
2294 - long string_entries_starting = dictionary_stats_entries(&string_dictionary);
2460 + long int string_entries_starting = string_base.entries;
2461
2462 fprintf(stderr, "\nChecking strings...\n");
2463
@@ -2312,8 +2478,7 @@ int dictionary_unittest(size_t entries) {
2478 else
2479 fprintf(stderr, "OK: cloning string are deduplicated\n");
2480
2315 - STRING_ENTRY *se = (STRING_ENTRY *)s1;
2316 - if(se->refcount != 3) {
2481 + if(s1->refcount != 3) {
2482 errors++;
2483 fprintf(stderr, "ERROR: string refcount is not 3\n");
2484 }
@@ -2355,9 +2520,9 @@ int dictionary_unittest(size_t entries) {
2520
2521 freez(strings);
2522
2358 - if(dictionary_stats_entries(&string_dictionary) != string_entries_starting + 2) {
2523 + if(string_base.entries != string_entries_starting + 2) {
2524 errors++;
2360 - fprintf(stderr, "ERROR: strings dictionary should have %ld items but it has %ld\n", string_entries_starting + 2, dictionary_stats_entries(&string_dictionary));
2525 + fprintf(stderr, "ERROR: strings dictionary should have %ld items but it has %ld\n", string_entries_starting + 2, string_base.entries);
2526 }
2527 else
2528 fprintf(stderr, "OK: strings dictionary has 2 items\n");
@@ -2405,6 +2570,65 @@ int dictionary_unittest(size_t entries) {
2570 dictionary_unittest_free_char_pp(names, entries);
2571 dictionary_unittest_free_char_pp(values, entries);
2572
2573 + {
2574 +#ifdef NETDATA_INTERNAL_CHECKS
2575 + size_t ofound_deleted_on_search = string_base.found_deleted_on_search,
2576 + ofound_available_on_search = string_base.found_available_on_search,
2577 + ofound_deleted_on_insert = string_base.found_deleted_on_insert,
2578 + ofound_available_on_insert = string_base.found_available_on_insert,
2579 + ospins = string_base.spins;
2580 +#endif
2581 +
2582 + size_t oinserts, odeletes, osearches, oentries, oreferences, omemory, oduplications, oreleases;
2583 + string_statistics(&oinserts, &odeletes, &osearches, &oentries, &oreferences, &omemory, &oduplications, &oreleases);
2584 +
2585 + time_t seconds_to_run = 5;
2586 + int threads_to_create = 2;
2587 + fprintf(
2588 + stderr,
2589 + "Checking string concurrency with %d threads for %ld seconds...\n",
2590 + threads_to_create,
2591 + seconds_to_run);
2592 + // check string concurrency
2593 + netdata_thread_t threads[threads_to_create];
2594 + string_threads_join = 0;
2595 + for (int i = 0; i < threads_to_create; i++) {
2596 + char buf[100 + 1];
2597 + snprintf(buf, 100, "string%d", i);
2598 + netdata_thread_create(
2599 + &threads[i], buf, NETDATA_THREAD_OPTION_DONT_LOG | NETDATA_THREAD_OPTION_JOINABLE, string_thread, NULL);
2600 + }
2601 + sleep_usec(seconds_to_run * USEC_PER_SEC);
2602 +
2603 + string_threads_join = 1;
2604 + for (int i = 0; i < threads_to_create; i++) {
2605 + void *retval;
2606 + netdata_thread_join(threads[i], &retval);
2607 + }
2608 +
2609 + size_t inserts, deletes, searches, sentries, references, memory, duplications, releases;
2610 + string_statistics(&inserts, &deletes, &searches, &sentries, &references, &memory, &duplications, &releases);
2611 +
2612 + fprintf(stderr, "inserts %zu, deletes %zu, searches %zu, entries %zu, references %zu, memory %zu, duplications %zu, releases %zu\n",
2613 + inserts - oinserts, deletes - odeletes, searches - osearches, sentries - oentries, references - oreferences, memory - omemory, duplications - oduplications, releases - oreleases);
2614 +
2615 +#ifdef NETDATA_INTERNAL_CHECKS
2616 + size_t found_deleted_on_search = string_base.found_deleted_on_search,
2617 + found_available_on_search = string_base.found_available_on_search,
2618 + found_deleted_on_insert = string_base.found_deleted_on_insert,
2619 + found_available_on_insert = string_base.found_available_on_insert,
2620 + spins = string_base.spins;
2621 +
2622 + fprintf(stderr, "on insert: %zu ok + %zu deleted\non search: %zu ok + %zu deleted\nspins: %zu\n",
2623 + found_available_on_insert - ofound_available_on_insert,
2624 + found_deleted_on_insert - ofound_deleted_on_insert,
2625 + found_available_on_search - ofound_available_on_search,
2626 + found_deleted_on_search - ofound_deleted_on_search,
2627 + spins - ospins
2628 + );
2629 +#endif
2630 + }
2631 +
2632 fprintf(stderr, "\n%zu errors found\n", errors);
2633 return errors ? 1 : 0;
2634 }
libnetdata/dictionary/dictionary.h
+22 -11
@@ -47,9 +47,9 @@ typedef enum dictionary_flags {
47 DICTIONARY_FLAG_ADD_IN_FRONT = (1 << 4), // add dictionary items at the front of the linked list (default: at the end)
48
49 // to change the value of the following, you also need to change the corresponding #defines in dictionary.c
50 - DICTIONARY_FLAG_RESERVED1 = (1 << 29), // reserved for DICTIONARY_FLAG_EXCLUSIVE_ACCESS
51 - DICTIONARY_FLAG_RESERVED2 = (1 << 30), // reserved for DICTIONARY_FLAG_DESTROYED
52 - DICTIONARY_FLAG_RESERVED3 = (1 << 31), // reserved for DICTIONARY_FLAG_DEFER_ALL_DELETIONS
50 + DICTIONARY_FLAG_RESERVED1 = (1 << 28), // reserved for DICTIONARY_FLAG_EXCLUSIVE_ACCESS
51 + DICTIONARY_FLAG_RESERVED2 = (1 << 29), // reserved for DICTIONARY_FLAG_DESTROYED
52 + DICTIONARY_FLAG_RESERVED3 = (1 << 30), // reserved for DICTIONARY_FLAG_DEFER_ALL_DELETIONS
53 } DICTIONARY_FLAGS;
54
55 // Create a dictionary
@@ -179,9 +179,10 @@ int dictionary_sorted_walkthrough_rw(DICTIONARY *dict, char rw, int (*callback)(
179 #define DICTFE_CONST const
180 #endif
181
182 -#define DICTIONARY_LOCK_READ 'r'
183 -#define DICTIONARY_LOCK_WRITE 'w'
184 -#define DICTIONARY_LOCK_NONE 'u'
182 +#define DICTIONARY_LOCK_READ 'r'
183 +#define DICTIONARY_LOCK_WRITE 'w'
184 +#define DICTIONARY_LOCK_REENTRANT 'z'
185 +#define DICTIONARY_LOCK_NONE 'u'
186
187 typedef DICTFE_CONST struct dictionary_foreach {
188 DICTFE_CONST char *name; // the dictionary name of the last item used
@@ -235,7 +236,7 @@ typedef struct netdata_string STRING;
236 extern STRING *string_strdupz(const char *str);
237 extern STRING *string_dup(STRING *string);
238 extern void string_freez(STRING *string);
238 -extern size_t string_length(STRING *string);
239 +extern size_t string_strlen(STRING *string);
240 extern const char *string2str(STRING *string) NEVERNULL;
241
242 // keep common prefix/suffix and replace everything else with [x]
@@ -243,10 +244,20 @@ extern STRING *string_2way_merge(STRING *a, STRING *b);
244
245 static inline int string_cmp(STRING *s1, STRING *s2) {
246 // STRINGs are deduplicated, so the same strings have the same pointer
246 - if(unlikely(s1 == s2)) return 0;
247 -
248 - // they differ, do the typical comparison
249 - return strcmp(string2str(s1), string2str(s2));
247 + // when they differ, we do the typical strcmp() comparison
248 + return (s1 == s2)?0:strcmp(string2str(s1), string2str(s2));
249 }
250
251 +extern void string_statistics(size_t *inserts, size_t *deletes, size_t *searches, size_t *entries, size_t *references, size_t *memory, size_t *duplications, size_t *releases);
252 +
253 +// ----------------------------------------------------------------------------
254 +// THREAD CACHE
255 +
256 +extern void *thread_cache_entry_get_or_set(void *key,
257 + ssize_t key_length,
258 + void *value,
259 + void *(*transform_the_value_before_insert)(void *key, size_t key_length, void *value));
260 +
261 +extern void thread_cache_destroy(void);
262 +
263 #endif /* NETDATA_DICTIONARY_H */
libnetdata/eval/eval.c
+45 -34
@@ -62,24 +62,36 @@ static inline void print_parsed_as_constant(BUFFER *out, NETDATA_DOUBLE n);
62 // evaluation of expressions
63
64 static inline NETDATA_DOUBLE eval_variable(EVAL_EXPRESSION *exp, EVAL_VARIABLE *v, int *error) {
65 - static uint32_t this_hash = 0, now_hash = 0, after_hash = 0, before_hash = 0, status_hash = 0, removed_hash = 0, uninitialized_hash = 0, undefined_hash = 0, clear_hash = 0, warning_hash = 0, critical_hash = 0;
65 + static STRING
66 + *this_string = NULL,
67 + *now_string = NULL,
68 + *after_string = NULL,
69 + *before_string = NULL,
70 + *status_string = NULL,
71 + *removed_string = NULL,
72 + *uninitialized_string = NULL,
73 + *undefined_string = NULL,
74 + *clear_string = NULL,
75 + *warning_string = NULL,
76 + *critical_string = NULL;
77 +
78 NETDATA_DOUBLE n;
79
68 - if(unlikely(this_hash == 0)) {
69 - this_hash = simple_hash("this");
70 - now_hash = simple_hash("now");
71 - after_hash = simple_hash("after");
72 - before_hash = simple_hash("before");
73 - status_hash = simple_hash("status");
74 - removed_hash = simple_hash("REMOVED");
75 - uninitialized_hash = simple_hash("UNINITIALIZED");
76 - undefined_hash = simple_hash("UNDEFINED");
77 - clear_hash = simple_hash("CLEAR");
78 - warning_hash = simple_hash("WARNING");
79 - critical_hash = simple_hash("CRITICAL");
80 - }
81 -
82 - if(unlikely(v->hash == this_hash && !strcmp(v->name, "this"))) {
80 + if(unlikely(this_string == NULL)) {
81 + this_string = string_strdupz("this");
82 + now_string = string_strdupz("now");
83 + after_string = string_strdupz("after");
84 + before_string = string_strdupz("before");
85 + status_string = string_strdupz("status");
86 + removed_string = string_strdupz("REMOVED");
87 + uninitialized_string = string_strdupz("UNINITIALIZED");
88 + undefined_string = string_strdupz("UNDEFINED");
89 + clear_string = string_strdupz("CLEAR");
90 + warning_string = string_strdupz("WARNING");
91 + critical_string = string_strdupz("CRITICAL");
92 + }
93 +
94 + if(unlikely(v->name == this_string)) {
95 n = (exp->myself)?*exp->myself:NAN;
96 buffer_strcat(exp->error_msg, "[ $this = ");
97 print_parsed_as_constant(exp->error_msg, n);
@@ -87,7 +99,7 @@ static inline NETDATA_DOUBLE eval_variable(EVAL_EXPRESSION *exp, EVAL_VARIABLE *
99 return n;
100 }
101
90 - if(unlikely(v->hash == after_hash && !strcmp(v->name, "after"))) {
102 + if(unlikely(v->name == after_string)) {
103 n = (exp->after && *exp->after)?*exp->after:NAN;
104 buffer_strcat(exp->error_msg, "[ $after = ");
105 print_parsed_as_constant(exp->error_msg, n);
@@ -95,7 +107,7 @@ static inline NETDATA_DOUBLE eval_variable(EVAL_EXPRESSION *exp, EVAL_VARIABLE *
107 return n;
108 }
109
98 - if(unlikely(v->hash == before_hash && !strcmp(v->name, "before"))) {
110 + if(unlikely(v->name == before_string)) {
111 n = (exp->before && *exp->before)?*exp->before:NAN;
112 buffer_strcat(exp->error_msg, "[ $before = ");
113 print_parsed_as_constant(exp->error_msg, n);
@@ -103,15 +115,15 @@ static inline NETDATA_DOUBLE eval_variable(EVAL_EXPRESSION *exp, EVAL_VARIABLE *
115 return n;
116 }
117
106 - if(unlikely(v->hash == now_hash && !strcmp(v->name, "now"))) {
107 - n = now_realtime_sec();
118 + if(unlikely(v->name == now_string)) {
119 + n = (NETDATA_DOUBLE)now_realtime_sec();
120 buffer_strcat(exp->error_msg, "[ $now = ");
121 print_parsed_as_constant(exp->error_msg, n);
122 buffer_strcat(exp->error_msg, " ] ");
123 return n;
124 }
125
114 - if(unlikely(v->hash == status_hash && !strcmp(v->name, "status"))) {
126 + if(unlikely(v->name == status_string)) {
127 n = (exp->status)?*exp->status:RRDCALC_STATUS_UNINITIALIZED;
128 buffer_strcat(exp->error_msg, "[ $status = ");
129 print_parsed_as_constant(exp->error_msg, n);
@@ -119,7 +131,7 @@ static inline NETDATA_DOUBLE eval_variable(EVAL_EXPRESSION *exp, EVAL_VARIABLE *
131 return n;
132 }
133
122 - if(unlikely(v->hash == removed_hash && !strcmp(v->name, "REMOVED"))) {
134 + if(unlikely(v->name == removed_string)) {
135 n = RRDCALC_STATUS_REMOVED;
136 buffer_strcat(exp->error_msg, "[ $REMOVED = ");
137 print_parsed_as_constant(exp->error_msg, n);
@@ -127,7 +139,7 @@ static inline NETDATA_DOUBLE eval_variable(EVAL_EXPRESSION *exp, EVAL_VARIABLE *
139 return n;
140 }
141
130 - if(unlikely(v->hash == uninitialized_hash && !strcmp(v->name, "UNINITIALIZED"))) {
142 + if(unlikely(v->name == uninitialized_string)) {
143 n = RRDCALC_STATUS_UNINITIALIZED;
144 buffer_strcat(exp->error_msg, "[ $UNINITIALIZED = ");
145 print_parsed_as_constant(exp->error_msg, n);
@@ -135,7 +147,7 @@ static inline NETDATA_DOUBLE eval_variable(EVAL_EXPRESSION *exp, EVAL_VARIABLE *
147 return n;
148 }
149
138 - if(unlikely(v->hash == undefined_hash && !strcmp(v->name, "UNDEFINED"))) {
150 + if(unlikely(v->name == undefined_string)) {
151 n = RRDCALC_STATUS_UNDEFINED;
152 buffer_strcat(exp->error_msg, "[ $UNDEFINED = ");
153 print_parsed_as_constant(exp->error_msg, n);
@@ -143,7 +155,7 @@ static inline NETDATA_DOUBLE eval_variable(EVAL_EXPRESSION *exp, EVAL_VARIABLE *
155 return n;
156 }
157
146 - if(unlikely(v->hash == clear_hash && !strcmp(v->name, "CLEAR"))) {
158 + if(unlikely(v->name == clear_string)) {
159 n = RRDCALC_STATUS_CLEAR;
160 buffer_strcat(exp->error_msg, "[ $CLEAR = ");
161 print_parsed_as_constant(exp->error_msg, n);
@@ -151,7 +163,7 @@ static inline NETDATA_DOUBLE eval_variable(EVAL_EXPRESSION *exp, EVAL_VARIABLE *
163 return n;
164 }
165
154 - if(unlikely(v->hash == warning_hash && !strcmp(v->name, "WARNING"))) {
166 + if(unlikely(v->name == warning_string)) {
167 n = RRDCALC_STATUS_WARNING;
168 buffer_strcat(exp->error_msg, "[ $WARNING = ");
169 print_parsed_as_constant(exp->error_msg, n);
@@ -159,7 +171,7 @@ static inline NETDATA_DOUBLE eval_variable(EVAL_EXPRESSION *exp, EVAL_VARIABLE *
171 return n;
172 }
173
162 - if(unlikely(v->hash == critical_hash && !strcmp(v->name, "CRITICAL"))) {
174 + if(unlikely(v->name == critical_string)) {
175 n = RRDCALC_STATUS_CRITICAL;
176 buffer_strcat(exp->error_msg, "[ $CRITICAL = ");
177 print_parsed_as_constant(exp->error_msg, n);
@@ -167,15 +179,15 @@ static inline NETDATA_DOUBLE eval_variable(EVAL_EXPRESSION *exp, EVAL_VARIABLE *
179 return n;
180 }
181
170 - if(exp->rrdcalc && health_variable_lookup(v->name, v->hash, exp->rrdcalc, &n)) {
171 - buffer_sprintf(exp->error_msg, "[ ${%s} = ", v->name);
182 + if(exp->rrdcalc && health_variable_lookup(v->name, exp->rrdcalc, &n)) {
183 + buffer_sprintf(exp->error_msg, "[ ${%s} = ", string2str(v->name));
184 print_parsed_as_constant(exp->error_msg, n);
185 buffer_strcat(exp->error_msg, " ] ");
186 return n;
187 }
188
189 *error = EVAL_ERROR_UNKNOWN_VARIABLE;
178 - buffer_sprintf(exp->error_msg, "[ undefined variable '%s' ] ", v->name);
190 + buffer_sprintf(exp->error_msg, "[ undefined variable '%s' ] ", string2str(v->name));
191 return NAN;
192 }
193
@@ -357,7 +369,7 @@ static inline NETDATA_DOUBLE eval_node(EVAL_EXPRESSION *exp, EVAL_NODE *op, int
369
370 static inline void print_parsed_as_variable(BUFFER *out, EVAL_VARIABLE *v, int *error) {
371 (void)error;
360 - buffer_sprintf(out, "${%s}", v->name);
372 + buffer_sprintf(out, "${%s}", string2str(v->name));
373 }
374
375 static inline void print_parsed_as_constant(BUFFER *out, NETDATA_DOUBLE n) {
@@ -859,12 +871,11 @@ static inline void eval_node_set_value_to_variable(EVAL_NODE *op, int pos, const
871
872 op->ops[pos].type = EVAL_VALUE_VARIABLE;
873 op->ops[pos].variable = callocz(1, sizeof(EVAL_VARIABLE));
862 - op->ops[pos].variable->name = strdupz(variable);
863 - op->ops[pos].variable->hash = simple_hash(op->ops[pos].variable->name);
874 + op->ops[pos].variable->name = string_strdupz(variable);
875 }
876
877 static inline void eval_variable_free(EVAL_VARIABLE *v) {
867 - freez(v->name);
878 + string_freez(v->name);
879 freez(v);
880 }
881
libnetdata/eval/eval.h
+2 -3
@@ -18,8 +18,7 @@ typedef enum rrdcalc_status {
18 } RRDCALC_STATUS;
19
20 typedef struct eval_variable {
21 - char *name;
22 - uint32_t hash;
21 + STRING *name;
22 struct eval_variable *next;
23 } EVAL_VARIABLE;
24
@@ -83,6 +82,6 @@ extern const char *expression_strerror(int error);
82 // 2 = FAILED, the error message is in: buffer_tostring(expression->error_msg)
83 extern int expression_evaluate(EVAL_EXPRESSION *expression);
84
86 -extern int health_variable_lookup(const char *variable, uint32_t hash, struct rrdcalc *rc, NETDATA_DOUBLE *result);
85 +extern int health_variable_lookup(STRING *variable, struct rrdcalc *rc, NETDATA_DOUBLE *result);
86
87 #endif //NETDATA_EVAL_H
libnetdata/libnetdata.h
+70
@@ -214,6 +214,76 @@ extern "C" {
214
215 #define GUID_LEN 36
216
217 +// ---------------------------------------------------------------------------------------------
218 +// double linked list management
219 +
220 +#define DOUBLE_LINKED_LIST_PREPEND_UNSAFE(head, item, prev, next) \
221 + do { \
222 + (item)->next = (head); \
223 + \
224 + if(likely(head)) { \
225 + (item)->prev = (head)->prev; \
226 + (head)->prev = (item); \
227 + } \
228 + else \
229 + (item)->prev = (item); \
230 + \
231 + (head) = (item); \
232 + } while (0)
233 +
234 +#define DOUBLE_LINKED_LIST_APPEND_UNSAFE(head, item, prev, next) \
235 + do { \
236 + if(likely(head)) { \
237 + (item)->prev = (head)->prev; \
238 + (head)->prev->next = (item); \
239 + (head)->prev = (item); \
240 + (item)->next = NULL; \
241 + } \
242 + else { \
243 + (head) = (item); \
244 + (head)->prev = (head); \
245 + (head)->next = NULL; \
246 + } \
247 + \
248 + } while (0)
249 +
250 +#define DOUBLE_LINKED_LIST_REMOVE_UNSAFE(head, item, prev, next) \
251 + do { \
252 + fatal_assert((head) != NULL); \
253 + fatal_assert((item)->prev != NULL); \
254 + \
255 + if((item)->prev == (item)) { \
256 + /* it is the only item in the list */ \
257 + (head) = NULL; \
258 + } \
259 + else if((item) == (head)) { \
260 + /* it is the first item */ \
261 + (item)->next->prev = (item)->prev; \
262 + (head) = (item)->next; \
263 + } \
264 + else { \
265 + (item)->prev->next = (item)->next; \
266 + if ((item)->next) { \
267 + (item)->next->prev = (item)->prev; \
268 + } \
269 + else { \
270 + (head)->prev = (item)->prev; \
271 + } \
272 + } \
273 + \
274 + (item)->next = NULL; \
275 + (item)->prev = NULL; \
276 + } while (0)
277 +
278 +#define DOUBLE_LINKED_LIST_FOREACH_FORWARD(head, var, prev, next) \
279 + for ((var) = (head); (var) ; (var) = (var)->next)
280 +
281 +#define DOUBLE_LINKED_LIST_FOREACH_BACKWARD(head, var, prev, next) \
282 + for ((var) = (head)?(head)->prev:NULL; (var) && (var) != (head)->prev ; (var) = (var)->prev)
283 +
284 +// ---------------------------------------------------------------------------------------------
285 +
286 +
287 extern void netdata_fix_chart_id(char *s);
288 extern void netdata_fix_chart_name(char *s);
289
libnetdata/log/log.c
+2 -2
@@ -747,7 +747,7 @@ void debug_int( const char *file, const char *function, const unsigned long line
747 // ----------------------------------------------------------------------------
748 // info log
749
750 -void info_int( const char *file, const char *function, const unsigned long line, const char *fmt, ... )
750 +void info_int( const char *file __maybe_unused, const char *function __maybe_unused, const unsigned long line __maybe_unused, const char *fmt, ... )
751 {
752 va_list args;
753
@@ -807,7 +807,7 @@ static const char *strerror_result_string(const char *a, const char *b) { (void)
807 #error "cannot detect the format of function strerror_r()"
808 #endif
809
810 -void error_int( const char *prefix, const char *file, const char *function, const unsigned long line, const char *fmt, ... ) {
810 +void error_int( const char *prefix, const char *file __maybe_unused, const char *function __maybe_unused, const unsigned long line __maybe_unused, const char *fmt, ... ) {
811 // save a copy of errno - just in case this function generates a new error
812 int __errno = errno;
813
libnetdata/required_dummies.h
+3 -2
@@ -22,15 +22,16 @@ void signals_block(void){};
22 void signals_unblock(void){};
23 void signals_reset(void){};
24
25 +#ifndef UNIT_TESTING
26 // callback required by eval()
26 -int health_variable_lookup(const char *variable, uint32_t hash, struct rrdcalc *rc, NETDATA_DOUBLE *result)
27 +int health_variable_lookup(STRING *variable, struct rrdcalc *rc, NETDATA_DOUBLE *result)
28 {
29 (void)variable;
29 - (void)hash;
30 (void)rc;
31 (void)result;
32 return 0;
33 };
34 +#endif
35
36 // required by get_system_cpus()
37 char *netdata_configured_host_prefix = "";
libnetdata/simple_pattern/simple_pattern.c
+1 -3
@@ -333,9 +333,7 @@ extern int simple_pattern_is_potential_name(SIMPLE_PATTERN *p)
333 }
334
335 char *simple_pattern_trim_around_equal(char *src) {
336 - char *store = mallocz(strlen(src) +1);
337 - if(!store)
338 - return NULL;
336 + char *store = mallocz(strlen(src) + 1);
337
338 char *dst = store;
339 while (*src) {
libnetdata/threads/threads.c
+2
@@ -106,6 +106,8 @@ static void thread_cleanup(void *ptr) {
106 if(!(netdata_thread->options & NETDATA_THREAD_OPTION_DONT_LOG_CLEANUP))
107 info("thread with task id %d finished", gettid());
108
109 + thread_cache_destroy();
110 +
111 freez((void *)netdata_thread->tag);
112 netdata_thread->tag = NULL;
113
libnetdata/worker_utilization/worker_utilization.c
+116 -33
@@ -4,15 +4,20 @@
4 #define WORKER_BUSY 'B'
5
6 struct worker_job_type {
7 - char name[WORKER_UTILIZATION_MAX_JOB_NAME_LENGTH + 1];
7 + STRING *name;
8 + STRING *units;
9
10 // statistics controlled variables
11 size_t statistics_last_jobs_started;
12 usec_t statistics_last_busy_time;
13 + NETDATA_DOUBLE statistics_last_custom_value;
14
15 // worker controlled variables
16 volatile size_t worker_jobs_started;
17 volatile usec_t worker_busy_time;
18 +
19 + WORKER_METRIC_TYPE type;
20 + NETDATA_DOUBLE custom_value;
21 };
22
23 struct worker {
@@ -36,6 +41,7 @@ struct worker {
41 struct worker_job_type per_job_type[WORKER_UTILIZATION_MAX_JOB_TYPES];
42
43 struct worker *next;
44 + struct worker *prev;
45 };
46
47 static netdata_mutex_t base_lock = NETDATA_MUTEX_INITIALIZER;
@@ -57,40 +63,44 @@ void worker_register(const char *workname) {
63 worker->last_action = WORKER_IDLE;
64
65 netdata_mutex_lock(&base_lock);
60 - worker->next = base;
61 - base = worker;
66 + DOUBLE_LINKED_LIST_PREPEND_UNSAFE(base, worker, prev, next);
67 netdata_mutex_unlock(&base_lock);
68 }
69
65 -void worker_register_job_name(size_t job_id, const char *name) {
70 +void worker_register_job_custom_metric(size_t job_id, const char *name, const char *units, WORKER_METRIC_TYPE type) {
71 if(unlikely(!worker)) return;
72
73 if(unlikely(job_id >= WORKER_UTILIZATION_MAX_JOB_TYPES)) {
74 error("WORKER_UTILIZATION: job_id %zu is too big. Max is %zu", job_id, (size_t)(WORKER_UTILIZATION_MAX_JOB_TYPES - 1));
75 return;
76 }
72 - if (*worker->per_job_type[job_id].name) {
73 - error("WORKER_UTILIZATION: duplicate job registration: worker '%s' job id %zu is '%s', ignoring '%s'", worker->workname, job_id, worker->per_job_type[job_id].name, name);
77 + if(worker->per_job_type[job_id].name) {
78 + if(strcmp(string2str(worker->per_job_type[job_id].name), name) != 0 || worker->per_job_type[job_id].type != type || strcmp(string2str(worker->per_job_type[job_id].units), units) != 0)
79 + error("WORKER_UTILIZATION: duplicate job registration: worker '%s' job id %zu is '%s', ignoring the later '%s'", worker->workname, job_id, string2str(worker->per_job_type[job_id].name), name);
80 return;
81 }
82
77 - strncpy(worker->per_job_type[job_id].name, name, WORKER_UTILIZATION_MAX_JOB_NAME_LENGTH);
83 + worker->per_job_type[job_id].name = string_strdupz(name);
84 + worker->per_job_type[job_id].units = string_strdupz(units);
85 + worker->per_job_type[job_id].type = type;
86 +}
87 +
88 +void worker_register_job_name(size_t job_id, const char *name) {
89 + worker_register_job_custom_metric(job_id, name, "", WORKER_METRIC_IDLE_BUSY);
90 }
91
92 void worker_unregister(void) {
93 if(unlikely(!worker)) return;
94
95 netdata_mutex_lock(&base_lock);
84 - if(base == worker)
85 - base = worker->next;
86 - else {
87 - struct worker *p;
88 - for(p = base; p && p->next && p->next != worker ;p = p->next);
89 - if(p && p->next == worker)
90 - p->next = worker->next;
91 - }
96 + DOUBLE_LINKED_LIST_REMOVE_UNSAFE(base, worker, prev, next);
97 netdata_mutex_unlock(&base_lock);
98
99 + for(int i = 0; i < WORKER_UTILIZATION_MAX_JOB_TYPES ;i++) {
100 + string_freez(worker->per_job_type[i].name);
101 + string_freez(worker->per_job_type[i].units);
102 + }
103 +
104 freez((void *)worker->tag);
105 freez((void *)worker->workname);
106 freez(worker);
@@ -112,16 +122,14 @@ static inline void worker_is_idle_with_time(usec_t now) {
122 }
123
124 void worker_is_idle(void) {
115 - if(unlikely(!worker)) return;
116 - if(unlikely(worker->last_action != WORKER_BUSY)) return;
125 + if(unlikely(!worker || worker->last_action != WORKER_BUSY)) return;
126
127 worker_is_idle_with_time(now_realtime_usec());
128 }
129
130 void worker_is_busy(size_t job_id) {
122 - if(unlikely(!worker)) return;
123 - if(unlikely(job_id >= WORKER_UTILIZATION_MAX_JOB_TYPES))
124 - job_id = 0;
131 + if(unlikely(!worker || job_id >= WORKER_UTILIZATION_MAX_JOB_TYPES))
132 + return;
133
134 usec_t now = now_realtime_usec();
135
@@ -138,35 +146,97 @@ void worker_is_busy(size_t job_id) {
146 worker->last_action = WORKER_BUSY;
147 }
148
149 +void worker_set_metric(size_t job_id, NETDATA_DOUBLE value) {
150 + if(unlikely(!worker)) return;
151 + if(unlikely(job_id >= WORKER_UTILIZATION_MAX_JOB_TYPES))
152 + return;
153 +
154 + if(worker->per_job_type[job_id].type == WORKER_METRIC_INCREMENTAL)
155 + worker->per_job_type[job_id].custom_value += value;
156 + else
157 + worker->per_job_type[job_id].custom_value = value;
158 +}
159
160 // statistics interface
161
144 -void workers_foreach(const char *workname, void (*callback)(void *data, pid_t pid, const char *thread_tag, size_t utilization_usec, size_t duration_usec, size_t jobs_started, size_t is_running, const char **job_types_names, size_t *job_types_jobs_started, usec_t *job_types_busy_time), void *data) {
162 +void workers_foreach(const char *workname, void (*callback)(
163 + void *data
164 + , pid_t pid
165 + , const char *thread_tag
166 + , size_t utilization_usec
167 + , size_t duration_usec
168 + , size_t jobs_started, size_t is_running
169 + , STRING **job_types_names
170 + , STRING **job_types_units
171 + , WORKER_METRIC_TYPE *job_metric_types
172 + , size_t *job_types_jobs_started
173 + , usec_t *job_types_busy_time
174 + , NETDATA_DOUBLE *job_custom_values
175 + )
176 + , void *data) {
177 netdata_mutex_lock(&base_lock);
178 uint32_t hash = simple_hash(workname);
179 usec_t busy_time, delta;
180 size_t i, jobs_started, jobs_running;
181
182 struct worker *p;
151 - for(p = base; p ; p = p->next) {
152 - if(hash != p->workname_hash || strcmp(workname, p->workname)) continue;
183 + DOUBLE_LINKED_LIST_FOREACH_FORWARD(base, p, prev, next) {
184 + if(hash != p->workname_hash || strcmp(workname, p->workname) != 0) continue;
185
186 usec_t now = now_realtime_usec();
187
188 // find per job type statistics
157 - const char *per_job_type_name[WORKER_UTILIZATION_MAX_JOB_TYPES];
189 + STRING *per_job_type_name[WORKER_UTILIZATION_MAX_JOB_TYPES];
190 + STRING *per_job_type_units[WORKER_UTILIZATION_MAX_JOB_TYPES];
191 + WORKER_METRIC_TYPE per_job_metric_type[WORKER_UTILIZATION_MAX_JOB_TYPES];
192 size_t per_job_type_jobs_started[WORKER_UTILIZATION_MAX_JOB_TYPES];
193 usec_t per_job_type_busy_time[WORKER_UTILIZATION_MAX_JOB_TYPES];
194 + NETDATA_DOUBLE per_job_custom_values[WORKER_UTILIZATION_MAX_JOB_TYPES];
195 +
196 for(i = 0; i < WORKER_UTILIZATION_MAX_JOB_TYPES ;i++) {
197 per_job_type_name[i] = p->per_job_type[i].name;
162 -
163 - size_t tmp_jobs_started = p->per_job_type[i].worker_jobs_started;
164 - per_job_type_jobs_started[i] = tmp_jobs_started - p->per_job_type[i].statistics_last_jobs_started;
165 - p->per_job_type[i].statistics_last_jobs_started = tmp_jobs_started;
166 -
167 - usec_t tmp_busy_time = p->per_job_type[i].worker_busy_time;
168 - per_job_type_busy_time[i] = tmp_busy_time - p->per_job_type[i].statistics_last_busy_time;
169 - p->per_job_type[i].statistics_last_busy_time = tmp_busy_time;
198 + per_job_type_units[i] = p->per_job_type[i].units;
199 + per_job_metric_type[i] = p->per_job_type[i].type;
200 +
201 + switch(p->per_job_type[i].type) {
202 + default:
203 + case WORKER_METRIC_EMPTY:
204 + per_job_type_jobs_started[i] = 0;
205 + per_job_type_busy_time[i] = 0;
206 + per_job_custom_values[i] = NAN;
207 + break;
208 +
209 + case WORKER_METRIC_IDLE_BUSY: {
210 + size_t tmp_jobs_started = p->per_job_type[i].worker_jobs_started;
211 + per_job_type_jobs_started[i] = tmp_jobs_started - p->per_job_type[i].statistics_last_jobs_started;
212 + p->per_job_type[i].statistics_last_jobs_started = tmp_jobs_started;
213 +
214 + usec_t tmp_busy_time = p->per_job_type[i].worker_busy_time;
215 + per_job_type_busy_time[i] = tmp_busy_time - p->per_job_type[i].statistics_last_busy_time;
216 + p->per_job_type[i].statistics_last_busy_time = tmp_busy_time;
217 +
218 + per_job_custom_values[i] = NAN;
219 + break;
220 + }
221 +
222 + case WORKER_METRIC_ABSOLUTE:
223 + per_job_type_jobs_started[i] = 0;
224 + per_job_type_busy_time[i] = 0;
225 +
226 + per_job_custom_values[i] = p->per_job_type[i].custom_value;
227 + break;
228 +
229 + case WORKER_METRIC_INCREMENTAL: {
230 + per_job_type_jobs_started[i] = 0;
231 + per_job_type_busy_time[i] = 0;
232 +
233 + NETDATA_DOUBLE tmp_custom_value = p->per_job_type[i].custom_value;
234 + per_job_custom_values[i] = tmp_custom_value - p->per_job_type[i].statistics_last_custom_value;
235 + p->per_job_type[i].statistics_last_custom_value = tmp_custom_value;
236 +
237 + break;
238 + }
239 + }
240 }
241
242 // get a copy of the worker variables
@@ -203,7 +273,20 @@ void workers_foreach(const char *workname, void (*callback)(void *data, pid_t pi
273 jobs_running = 1;
274 }
275
206 - callback(data, p->pid, p->tag, busy_time, delta, jobs_started, jobs_running, per_job_type_name, per_job_type_jobs_started, per_job_type_busy_time);
276 + callback(data
277 + , p->pid
278 + , p->tag
279 + , busy_time
280 + , delta
281 + , jobs_started
282 + , jobs_running
283 + , per_job_type_name
284 + , per_job_type_units
285 + , per_job_metric_type
286 + , per_job_type_jobs_started
287 + , per_job_type_busy_time
288 + , per_job_custom_values
289 + );
290 }
291
292 netdata_mutex_unlock(&base_lock);
libnetdata/worker_utilization/worker_utilization.h
+25 -2
@@ -6,17 +6,40 @@
6 // workers interfaces
7
8 #define WORKER_UTILIZATION_MAX_JOB_TYPES 50
9 -#define WORKER_UTILIZATION_MAX_JOB_NAME_LENGTH 25
9 +
10 +typedef enum {
11 + WORKER_METRIC_EMPTY = 0,
12 + WORKER_METRIC_IDLE_BUSY = 1,
13 + WORKER_METRIC_ABSOLUTE = 2,
14 + WORKER_METRIC_INCREMENTAL = 3,
15 +} WORKER_METRIC_TYPE;
16
17 extern void worker_register(const char *workname);
18 extern void worker_register_job_name(size_t job_id, const char *name);
19 +extern void worker_register_job_custom_metric(size_t job_id, const char *name, const char *units, WORKER_METRIC_TYPE type);
20 extern void worker_unregister(void);
21
22 extern void worker_is_idle(void);
23 extern void worker_is_busy(size_t job_id);
24 +extern void worker_set_metric(size_t job_id, NETDATA_DOUBLE value);
25
26 // statistics interface
27
20 -extern void workers_foreach(const char *workname, void (*callback)(void *data, pid_t pid, const char *thread_tag, size_t utilization_usec, size_t duration_usec, size_t jobs_started, size_t is_running, const char **job_types_names, size_t *job_types_jobs_started, usec_t *job_types_busy_time), void *data);
28 +extern void workers_foreach(const char *workname, void (*callback)(
29 + void *data
30 + , pid_t pid
31 + , const char *thread_tag
32 + , size_t utilization_usec
33 + , size_t duration_usec
34 + , size_t jobs_started
35 + , size_t is_running
36 + , STRING **job_types_names
37 + , STRING **job_types_units
38 + , WORKER_METRIC_TYPE *job_metric_types
39 + , size_t *job_types_jobs_started
40 + , usec_t *job_types_busy_time
41 + , NETDATA_DOUBLE *job_custom_values
42 + )
43 + , void *data);
44
45 #endif // WORKER_UTILIZATION_H
ml/Dimension.h
+1 -1
@@ -26,7 +26,7 @@ public:
26 RRDSET *RS = RD->rrdset;
27
28 std::stringstream SS;
29 - SS << RS->context << "|" << RS->id << "|" << RD->name;
29 + SS << rrdset_context(RS) << "|" << rrdset_id(RS) << "|" << rrddim_name(RD);
30 return SS.str();
31 }
32
ml/Host.cc
+6 -6
@@ -23,7 +23,7 @@ static void updateDimensionsChart(RRDHOST *RH,
23 std::stringstream IdSS, NameSS;
24
25 IdSS << "dimensions_on_" << localhost->machine_guid;
26 - NameSS << "dimensions_on_" << localhost->hostname;
26 + NameSS << "dimensions_on_" << rrdhost_hostname(localhost);
27
28 RS = rrdset_create(
29 RH,
@@ -69,7 +69,7 @@ static void updateRateChart(RRDHOST *RH, collected_number AnomalyRate) {
69 std::stringstream IdSS, NameSS;
70
71 IdSS << "anomaly_rate_on_" << localhost->machine_guid;
72 - NameSS << "anomaly_rate_on_" << localhost->hostname;
72 + NameSS << "anomaly_rate_on_" << rrdhost_hostname(localhost);
73
74 RS = rrdset_create(
75 RH,
@@ -106,7 +106,7 @@ static void updateWindowLengthChart(RRDHOST *RH, collected_number WindowLength)
106 std::stringstream IdSS, NameSS;
107
108 IdSS << "detector_window_on_" << localhost->machine_guid;
109 - NameSS << "detector_window_on_" << localhost->hostname;
109 + NameSS << "detector_window_on_" << rrdhost_hostname(localhost);
110
111 RS = rrdset_create(
112 RH,
@@ -147,7 +147,7 @@ static void updateEventsChart(RRDHOST *RH,
147 std::stringstream IdSS, NameSS;
148
149 IdSS << "detector_events_on_" << localhost->machine_guid;
150 - NameSS << "detector_events_on_" << localhost->hostname;
150 + NameSS << "detector_events_on_" << rrdhost_hostname(localhost);
151
152 RS = rrdset_create(
153 RH,
@@ -193,7 +193,7 @@ static void updateDetectionChart(RRDHOST *RH) {
193 std::stringstream IdSS, NameSS;
194
195 IdSS << "prediction_stats_" << RH->machine_guid;
196 - NameSS << "prediction_stats_for_" << RH->hostname;
196 + NameSS << "prediction_stats_for_" << rrdhost_hostname(RH);
197
198 RS = rrdset_create_localhost(
199 "netdata", // type
@@ -233,7 +233,7 @@ static void updateTrainingChart(RRDHOST *RH, struct rusage *TRU)
233 std::stringstream IdSS, NameSS;
234
235 IdSS << "training_stats_" << RH->machine_guid;
236 - NameSS << "training_stats_for_" << RH->hostname;
236 + NameSS << "training_stats_for_" << rrdhost_hostname(RH);
237
238 RS = rrdset_create_localhost(
239 "netdata", // type
ml/Host.h
+1 -3
@@ -31,9 +31,7 @@ public:
31 RRDSET_TYPE_LINE
32 );
33
34 - AnomalyRateRS->flags = static_cast<RRDSET_FLAGS>(
35 - static_cast<int>(AnomalyRateRS->flags) | RRDSET_FLAG_HIDDEN
36 - );
34 + rrdset_flag_set(AnomalyRateRS, RRDSET_FLAG_HIDDEN);
35 }
36
37 RRDHOST *getRH() { return RH; }
ml/ml.cc
+2 -2
@@ -16,7 +16,7 @@ bool ml_enabled(RRDHOST *RH) {
16 if (!Cfg.EnableAnomalyDetection)
17 return false;
18
19 - if (simple_pattern_matches(Cfg.SP_HostsToSkip, RH->hostname))
19 + if (simple_pattern_matches(Cfg.SP_HostsToSkip, rrdhost_hostname(RH)))
20 return false;
21
22 return true;
@@ -76,7 +76,7 @@ void ml_new_dimension(RRDDIM *RD) {
76 if (static_cast<unsigned>(RD->update_every) != H->updateEvery())
77 return;
78
79 - if (simple_pattern_matches(Cfg.SP_ChartsToSkip, RS->name))
79 + if (simple_pattern_matches(Cfg.SP_ChartsToSkip, rrdset_name(RS)))
80 return;
81
82 Dimension *D = new Dimension(RD);
parser/parser.c
+3 -2
@@ -38,6 +38,7 @@ PARSER *parser_init(RRDHOST *host, void *user, void *input, PARSER_INPUT_TYPE fl
38 parser->input = input;
39 parser->flags = flags;
40 parser->host = host;
41 + parser->worker_job_next_id = WORKER_PARSER_FIRST_JOB;
42
43 #ifdef ENABLE_HTTPS
44 parser->bytesleft = 0;
@@ -133,7 +134,7 @@ int parser_add_keyword(PARSER *parser, char *keyword, keyword_function func)
134
135 tmp_keyword = callocz(1, sizeof(*tmp_keyword));
136
136 - tmp_keyword->worker_job_id = parser->worker_job_ids++;
137 + tmp_keyword->worker_job_id = parser->worker_job_next_id++;
138 tmp_keyword->keyword = strdupz(keyword);
139 tmp_keyword->keyword_hash = keyword_hash;
140 tmp_keyword->func[tmp_keyword->func_no++] = (void *) func;
@@ -268,7 +269,7 @@ inline int parser_action(PARSER *parser, char *input)
269
270 uint32_t command_hash = simple_hash(command);
271
271 - size_t worker_job_id = 0;
272 + size_t worker_job_id = WORKER_UTILIZATION_MAX_JOB_TYPES + 1; // set an invalid value by default
273 while(tmp_keyword) {
274 if (command_hash == tmp_keyword->keyword_hash &&
275 (!strcmp(command, tmp_keyword->keyword))) {
parser/parser.h
+2 -1
@@ -7,6 +7,7 @@
7
8 #define PARSER_MAX_CALLBACKS 20
9 #define PARSER_MAX_RECOVER_KEYWORDS 128
10 +#define WORKER_PARSER_FIRST_JOB 1
11
12 // PARSER return codes
13 typedef enum parser_rc {
@@ -68,7 +69,7 @@ typedef struct parser_data {
69 } PARSER_DATA;
70
71 typedef struct parser {
71 - size_t worker_job_ids;
72 + size_t worker_job_next_id;
73 uint8_t version; // Parser version
74 RRDHOST *host;
75 void *input; // Input source e.g. stream
registry/registry.c
+1 -1
@@ -61,7 +61,7 @@ static inline void registry_json_header(RRDHOST *host, struct web_client *w, con
61 buffer_flush(w->response.data);
62 w->response.data->contenttype = CT_APPLICATION_JSON;
63 buffer_sprintf(w->response.data, "{\n\t\"action\": \"%s\",\n\t\"status\": \"%s\",\n\t\"hostname\": \"%s\",\n\t\"machine_guid\": \"%s\"",
64 - action, status, host->registry_hostname, host->machine_guid);
64 + action, status, rrdhost_registry_hostname(host), host->machine_guid);
65 }
66
67 static inline void registry_json_footer(struct web_client *w) {
streaming/compression.c
+44 -27
@@ -5,9 +5,6 @@
5
6 #define STREAM_COMPRESSION_MSG "STREAM_COMPRESSION"
7
8 -#define LZ4_MAX_MSG_SIZE 0x4000
9 -#define LZ4_STREAM_BUFFER_SIZE (0x10000 + LZ4_MAX_MSG_SIZE)
10 -
8 #define SIGNATURE ((uint32_t)('z' | 0x80) | (0x80 << 8) | (0x80 << 16) | ('\n' << 24))
9 #define SIGNATURE_MASK ((uint32_t)0xff | (0x80 << 8) | (0x80 << 16) | (0xff << 24))
10 #define SIGNATURE_SIZE 4
@@ -18,8 +15,9 @@
15 */
16 struct compressor_data {
17 LZ4_stream_t *stream;
21 - char *stream_buffer;
22 - size_t stream_buffer_pos;
18 + char *input_ring_buffer;
19 + size_t input_ring_buffer_size;
20 + size_t input_ring_buffer_pos;
21 };
22
23
@@ -33,7 +31,7 @@ static void lz4_compressor_reset(struct compressor_state *state)
31 LZ4_resetStream_fast(state->data->stream);
32 info("%s: Compressor Reset", STREAM_COMPRESSION_MSG);
33 }
36 - state->data->stream_buffer_pos = 0;
34 + state->data->input_ring_buffer_pos = 0;
35 }
36 }
37
@@ -47,10 +45,10 @@ static void lz4_compressor_destroy(struct compressor_state **state)
45 if (s->data) {
46 if (s->data->stream)
47 LZ4_freeStream(s->data->stream);
50 - freez(s->data->stream_buffer);
48 + freez(s->data->input_ring_buffer);
49 freez(s->data);
50 }
53 - freez(s->buffer);
51 + freez(s->compression_result_buffer);
52 freez(s);
53 *state = NULL;
54 debug(D_STREAM, "%s: Compressor Destroyed.", STREAM_COMPRESSION_MSG);
@@ -65,37 +63,53 @@ static void lz4_compressor_destroy(struct compressor_state **state)
63 */
64 static size_t lz4_compressor_compress(struct compressor_state *state, const char *data, size_t size, char **out)
65 {
68 - if (!state || !size || !out)
66 + if(unlikely(!state || !size || !out))
67 return 0;
70 - if (size > LZ4_MAX_MSG_SIZE) {
68 +
69 + if(unlikely(size > LZ4_MAX_MSG_SIZE)) {
70 error("%s: Compression Failed - Message size %lu above compression buffer limit: %d", STREAM_COMPRESSION_MSG, size, LZ4_MAX_MSG_SIZE);
71 return 0;
72 }
73 +
74 size_t max_dst_size = LZ4_COMPRESSBOUND(size);
75 size_t data_size = max_dst_size + SIGNATURE_SIZE;
76
77 - if (!state->buffer) {
78 - state->buffer = mallocz(data_size);
79 - state->buffer_size = data_size;
80 - } else if (state->buffer_size < data_size) {
81 - state->buffer = reallocz(state->buffer, data_size);
82 - state->buffer_size = data_size;
77 + if (!state->compression_result_buffer) {
78 + state->compression_result_buffer = mallocz(data_size);
79 + state->compression_result_buffer_size = data_size;
80 + }
81 + else if(unlikely(state->compression_result_buffer_size < data_size)) {
82 + state->compression_result_buffer = reallocz(state->compression_result_buffer, data_size);
83 + state->compression_result_buffer_size = data_size;
84 }
85
85 - memcpy(state->data->stream_buffer + state->data->stream_buffer_pos, data, size);
86 - long int compressed_data_size = LZ4_compress_fast_continue(state->data->stream,
87 - state->data->stream_buffer + state->data->stream_buffer_pos,
88 - state->buffer + SIGNATURE_SIZE, size, max_dst_size, 1);
86 + // the ring buffer always has space for LZ4_MAX_MSG_SIZE
87 + memcpy(state->data->input_ring_buffer + state->data->input_ring_buffer_pos, data, size);
88 +
89 + // this call needs the last 64K of our previous data
90 + // they are available in the ring buffer
91 + long int compressed_data_size = LZ4_compress_fast_continue(
92 + state->data->stream,
93 + state->data->input_ring_buffer + state->data->input_ring_buffer_pos,
94 + state->compression_result_buffer + SIGNATURE_SIZE,
95 + size,
96 + max_dst_size,
97 + 1);
98 +
99 if (compressed_data_size < 0) {
100 error("Data compression error: %ld", compressed_data_size);
101 return 0;
102 }
93 - state->data->stream_buffer_pos += size;
94 - if (state->data->stream_buffer_pos >= LZ4_STREAM_BUFFER_SIZE - LZ4_MAX_MSG_SIZE)
95 - state->data->stream_buffer_pos = 0;
103 +
104 + // update the next writing position of the ring buffer
105 + state->data->input_ring_buffer_pos += size;
106 + if(unlikely(state->data->input_ring_buffer_pos >= state->data->input_ring_buffer_size - LZ4_MAX_MSG_SIZE))
107 + state->data->input_ring_buffer_pos = 0;
108 +
109 + // update the signature header
110 uint32_t len = ((compressed_data_size & 0x7f) | 0x80 | (((compressed_data_size & (0x7f << 7)) << 1) | 0x8000)) << 8;
97 - *(uint32_t *)state->buffer = len | SIGNATURE;
98 - *out = state->buffer;
111 + *(uint32_t *)state->compression_result_buffer = len | SIGNATURE;
112 + *out = state->compression_result_buffer;
113 debug(D_STREAM, "%s: Compressed data header: %ld", STREAM_COMPRESSION_MSG, compressed_data_size);
114 return compressed_data_size + SIGNATURE_SIZE;
115 }
@@ -114,8 +128,9 @@ struct compressor_state *create_compressor()
128
129 state->data = callocz(1, sizeof(struct compressor_data));
130 state->data->stream = LZ4_createStream();
117 - state->data->stream_buffer = callocz(1, LZ4_DECODER_RING_BUFFER_SIZE(LZ4_MAX_MSG_SIZE));
118 - state->buffer_size = LZ4_STREAM_BUFFER_SIZE;
131 + state->data->input_ring_buffer_size = LZ4_DECODER_RING_BUFFER_SIZE(LZ4_MAX_MSG_SIZE * 2);
132 + state->data->input_ring_buffer = callocz(1, state->data->input_ring_buffer_size);
133 + state->compression_result_buffer_size = 0;
134 state->reset(state);
135 debug(D_STREAM, "%s: Initialize streaming compression!", STREAM_COMPRESSION_MSG);
136 return state;
@@ -281,6 +296,8 @@ static size_t lz4_decompressor_decompress(struct decompressor_state *state)
296 size_t avg_saving = saving_percent(state->total_compressed, state->total_uncompressed);
297 size_t avg_size = state->total_uncompressed / state->packet_count;
298
299 + (void)saving;
300 +
301 if (old_avg_saving != avg_saving || old_avg_size != avg_size){
302 debug(D_STREAM, "%s: Saving: %lu%% (avg. %lu%%), avg.size: %lu", STREAM_COMPRESSION_MSG, saving, avg_saving, avg_size);
303 }
streaming/receiver.c
+44 -28
@@ -1,6 +1,13 @@
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "rrdpush.h"
4 +#include "parser/parser.h"
5 +
6 +#define WORKER_RECEIVER_JOB_BYTES_READ (WORKER_PARSER_FIRST_JOB - 1)
7 +
8 +#if WORKER_PARSER_FIRST_JOB < 1
9 +#error The define WORKER_PARSER_FIRST_JOB needs to be at least 1
10 +#endif
11
12 extern struct config stream_config;
13
@@ -66,7 +73,7 @@ PARSER_RC streaming_timestamp(char **words, void *user, PLUGINSD_ACTION *plugins
73 RRDHOST *host = ((PARSER_USER_OBJECT *)user)->host;
74 struct plugind *cd = ((PARSER_USER_OBJECT *)user)->cd;
75 if (cd->version < VERSION_GAP_FILLING ) {
69 - error("STREAM %s from %s: Child negotiated version %u but sent TIMESTAMP!", host->hostname, cd->cmd,
76 + error("STREAM %s from %s: Child negotiated version %u but sent TIMESTAMP!", rrdhost_hostname(host), cd->cmd,
77 cd->version);
78 return PARSER_RC_OK; // Ignore error and continue stream
79 }
@@ -78,7 +85,7 @@ PARSER_RC streaming_timestamp(char **words, void *user, PLUGINSD_ACTION *plugins
85 info(
86 "STREAM %s from %s: Initial connection (no gap to check), "
87 "remote=%"PRId64" local=%"PRId64" slew=%"PRId64"",
81 - host->hostname,
88 + rrdhost_hostname(host),
89 cd->cmd,
90 (int64_t)remote_time,
91 (int64_t)now,
@@ -88,7 +95,7 @@ PARSER_RC streaming_timestamp(char **words, void *user, PLUGINSD_ACTION *plugins
95 info(
96 "STREAM %s from %s: Checking for gaps... "
97 "remote=%"PRId64" local=%"PRId64"..%"PRId64" slew=%"PRId64" %"PRId64"-sec gap",
91 - host->hostname,
98 + rrdhost_hostname(host),
99 cd->cmd,
100 (int64_t)remote_time,
101 (int64_t)prev,
@@ -177,6 +184,7 @@ static int receiver_read(struct receiver_state *r, FILE *fp) {
184 int ret = SSL_read(r->ssl.conn, r->read_buffer + r->read_len, desired);
185 if (ret > 0 ) {
186 r->read_len += ret;
187 + worker_set_metric(WORKER_RECEIVER_JOB_BYTES_READ, ret);
188 return 0;
189 }
190 // Don't treat SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE differently on blocking socket
@@ -192,6 +200,7 @@ static int receiver_read(struct receiver_state *r, FILE *fp) {
200 if (!fgets(r->read_buffer, sizeof(r->read_buffer), fp))
201 return 1;
202 r->read_len = strlen(r->read_buffer);
203 + worker_set_metric(WORKER_RECEIVER_JOB_BYTES_READ, r->read_len);
204 return 0;
205 }
206 #else
@@ -279,22 +288,24 @@ static int read_stream(struct receiver_state *r, FILE *fp, char* buffer, size_t
288 */
289 static int receiver_read(struct receiver_state *r, FILE *fp) {
290 // check any decompressed data present
282 - if (r->decompressor &&
283 - r->decompressor->decompressed_bytes_in_buffer(r->decompressor)) {
291 + if (r->decompressor && r->decompressor->decompressed_bytes_in_buffer(r->decompressor)) {
292 size_t available = sizeof(r->read_buffer) - r->read_len;
293 if (available) {
286 - size_t len = r->decompressor->get(r->decompressor,
287 - r->read_buffer + r->read_len, available);
294 + size_t len = r->decompressor->get(r->decompressor, r->read_buffer + r->read_len, available);
295 if (!len)
296 return 1;
297 +
298 r->read_len += len;
299 }
300 return 0;
301 }
302 +
303 int ret = 0;
304 if (read_stream(r, fp, r->read_buffer + r->read_len, sizeof(r->read_buffer) - r->read_len - 1, &ret))
305 return 1;
306
307 + worker_set_metric(WORKER_RECEIVER_JOB_BYTES_READ, ret);
308 +
309 if (!is_compressed_data(r->read_buffer, ret)) {
310 r->read_len += ret;
311 return 0;
@@ -303,8 +314,7 @@ static int receiver_read(struct receiver_state *r, FILE *fp) {
314 if (unlikely(!r->decompressor))
315 r->decompressor = create_decompressor();
316
306 - size_t bytes_to_read = r->decompressor->start(r->decompressor,
307 - r->read_buffer, ret);
317 + size_t bytes_to_read = r->decompressor->start(r->decompressor, r->read_buffer, ret);
318
319 // Read the entire block of compressed data because
320 // we're unable to decompress incomplete block
@@ -312,18 +322,23 @@ static int receiver_read(struct receiver_state *r, FILE *fp) {
322 do {
323 if (read_stream(r, fp, compressed, bytes_to_read, &ret))
324 return 1;
325 +
326 + worker_set_metric(WORKER_RECEIVER_JOB_BYTES_READ, ret);
327 +
328 // Send input data to decompressor
329 if (ret)
330 r->decompressor->put(r->decompressor, compressed, ret);
331 +
332 bytes_to_read -= ret;
333 } while (bytes_to_read > 0);
334 +
335 // Decompress
336 size_t bytes_to_parse = r->decompressor->decompress(r->decompressor);
337 if (!bytes_to_parse)
338 return 1;
339 +
340 // Fill read buffer with decompressed data
325 - r->read_len = r->decompressor->get(r->decompressor,
326 - r->read_buffer, sizeof(r->read_buffer));
341 + r->read_len = r->decompressor->get(r->decompressor, r->read_buffer, sizeof(r->read_buffer));
342 return 0;
343 }
344
@@ -486,8 +501,8 @@ static int rrdpush_receive(struct receiver_state *rpt)
501 #else
502 if(send_timeout(rpt->fd, initial_response, strlen(initial_response), 0, 60) != strlen(initial_response)) {
503 #endif
489 - log_stream_connection(rpt->client_ip, rpt->client_port, rpt->key, rpt->host->machine_guid, rpt->host->hostname, "FAILED - CANNOT REPLY");
490 - error("STREAM %s [receive from [%s]:%s]: cannot send command.", rpt->host->hostname, rpt->client_ip, rpt->client_port);
504 + log_stream_connection(rpt->client_ip, rpt->client_port, rpt->key, rpt->host->machine_guid, rrdhost_hostname(rpt->host), "FAILED - CANNOT REPLY");
505 + error("STREAM %s [receive from [%s]:%s]: cannot send command.", rrdhost_hostname(rpt->host), rpt->client_ip, rpt->client_port);
506 close(rpt->fd);
507 return 0;
508 }
@@ -575,14 +590,14 @@ static int rrdpush_receive(struct receiver_state *rpt)
590 , rpt->hostname
591 , rpt->client_ip
592 , rpt->client_port
578 - , rpt->host->hostname
593 + , rrdhost_hostname(rpt->host)
594 , rpt->host->machine_guid
595 , rpt->host->rrd_update_every
596 , rpt->host->rrd_history_entries
597 , rrd_memory_mode_name(rpt->host->rrd_memory_mode)
598 , (health_enabled == CONFIG_BOOLEAN_NO)?"disabled":((health_enabled == CONFIG_BOOLEAN_YES)?"enabled":"auto")
599 , ssl ? " SSL," : ""
585 - , rpt->host->tags?rpt->host->tags:""
600 + , rrdhost_tags(rpt->host)
601 );
602 #endif // NETDATA_INTERNAL_CHECKS
603
@@ -605,7 +620,7 @@ static int rrdpush_receive(struct receiver_state *rpt)
620 snprintfz(cd.fullfilename, FILENAME_MAX, "%s:%s", rpt->client_ip, rpt->client_port);
621 snprintfz(cd.cmd, PLUGINSD_CMD_MAX, "%s:%s", rpt->client_ip, rpt->client_port);
622
608 - info("STREAM %s [receive from [%s]:%s]: initializing communication...", rpt->host->hostname, rpt->client_ip, rpt->client_port);
623 + info("STREAM %s [receive from [%s]:%s]: initializing communication...", rrdhost_hostname(rpt->host), rpt->client_ip, rpt->client_port);
624 char initial_response[HTTP_HEADER_SIZE];
625 if (rpt->stream_version > 1) {
626 if(rpt->stream_version >= STREAM_VERSION_COMPRESSION){
@@ -618,13 +633,13 @@ static int rrdpush_receive(struct receiver_state *rpt)
633 }
634 #endif
635 }
621 - info("STREAM %s [receive from [%s]:%s]: Netdata is using the stream version %u.", rpt->host->hostname, rpt->client_ip, rpt->client_port, rpt->stream_version);
636 + info("STREAM %s [receive from [%s]:%s]: Netdata is using the stream version %u.", rrdhost_hostname(rpt->host), rpt->client_ip, rpt->client_port, rpt->stream_version);
637 sprintf(initial_response, "%s%u", START_STREAMING_PROMPT_VN, rpt->stream_version);
638 } else if (rpt->stream_version == 1) {
624 - info("STREAM %s [receive from [%s]:%s]: Netdata is using the stream version %u.", rpt->host->hostname, rpt->client_ip, rpt->client_port, rpt->stream_version);
639 + info("STREAM %s [receive from [%s]:%s]: Netdata is using the stream version %u.", rrdhost_hostname(rpt->host), rpt->client_ip, rpt->client_port, rpt->stream_version);
640 sprintf(initial_response, "%s", START_STREAMING_PROMPT_V2);
641 } else {
627 - info("STREAM %s [receive from [%s]:%s]: Netdata is using first stream protocol.", rpt->host->hostname, rpt->client_ip, rpt->client_port);
642 + info("STREAM %s [receive from [%s]:%s]: Netdata is using first stream protocol.", rrdhost_hostname(rpt->host), rpt->client_ip, rpt->client_port);
643 sprintf(initial_response, "%s", START_STREAMING_PROMPT);
644 }
645 debug(D_STREAM, "Initial response to %s: %s", rpt->client_ip, initial_response);
@@ -635,27 +650,27 @@ static int rrdpush_receive(struct receiver_state *rpt)
650 #else
651 if(send_timeout(rpt->fd, initial_response, strlen(initial_response), 0, 60) != strlen(initial_response)) {
652 #endif
638 - log_stream_connection(rpt->client_ip, rpt->client_port, rpt->key, rpt->host->machine_guid, rpt->host->hostname, "FAILED - CANNOT REPLY");
639 - error("STREAM %s [receive from [%s]:%s]: cannot send ready command.", rpt->host->hostname, rpt->client_ip, rpt->client_port);
653 + log_stream_connection(rpt->client_ip, rpt->client_port, rpt->key, rpt->host->machine_guid, rrdhost_hostname(rpt->host), "FAILED - CANNOT REPLY");
654 + error("STREAM %s [receive from [%s]:%s]: cannot send ready command.", rrdhost_hostname(rpt->host), rpt->client_ip, rpt->client_port);
655 close(rpt->fd);
656 return 0;
657 }
658
659 // remove the non-blocking flag from the socket
660 if(sock_delnonblock(rpt->fd) < 0)
646 - error("STREAM %s [receive from [%s]:%s]: cannot remove the non-blocking flag from socket %d", rpt->host->hostname, rpt->client_ip, rpt->client_port, rpt->fd);
661 + error("STREAM %s [receive from [%s]:%s]: cannot remove the non-blocking flag from socket %d", rrdhost_hostname(rpt->host), rpt->client_ip, rpt->client_port, rpt->fd);
662
663 struct timeval timeout;
664 timeout.tv_sec = 120;
665 timeout.tv_usec = 0;
666 if (unlikely(setsockopt(rpt->fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof timeout) != 0))
652 - error("STREAM %s [receive from [%s]:%s]: cannot set timeout for socket %d", rpt->host->hostname, rpt->client_ip, rpt->client_port, rpt->fd);
667 + error("STREAM %s [receive from [%s]:%s]: cannot set timeout for socket %d", rrdhost_hostname(rpt->host), rpt->client_ip, rpt->client_port, rpt->fd);
668
669 // convert the socket to a FILE *
670 FILE *fp = fdopen(rpt->fd, "r");
671 if(!fp) {
657 - log_stream_connection(rpt->client_ip, rpt->client_port, rpt->key, rpt->host->machine_guid, rpt->host->hostname, "FAILED - SOCKET ERROR");
658 - error("STREAM %s [receive from [%s]:%s]: failed to get a FILE for FD %d.", rpt->host->hostname, rpt->client_ip, rpt->client_port, rpt->fd);
672 + log_stream_connection(rpt->client_ip, rpt->client_port, rpt->key, rpt->host->machine_guid, rrdhost_hostname(rpt->host), "FAILED - SOCKET ERROR");
673 + error("STREAM %s [receive from [%s]:%s]: failed to get a FILE for FD %d.", rrdhost_hostname(rpt->host), rpt->client_ip, rpt->client_port, rpt->fd);
674 close(rpt->fd);
675 return 0;
676 }
@@ -686,7 +701,7 @@ static int rrdpush_receive(struct receiver_state *rpt)
701 info(
702 "Postponing health checks for %" PRId64 " seconds, on host '%s', because it was just connected.",
703 (int64_t)alarms_delay,
689 - rpt->host->hostname);
704 + rrdhost_hostname(rpt->host));
705 }
706 }
707 rpt->host->senders_connect_time = now_realtime_sec();
@@ -695,8 +710,8 @@ static int rrdpush_receive(struct receiver_state *rpt)
710 rrdhost_unlock(rpt->host);
711
712 // call the plugins.d processor to receive the metrics
698 - info("STREAM %s [receive from [%s]:%s]: receiving metrics...", rpt->host->hostname, rpt->client_ip, rpt->client_port);
699 - log_stream_connection(rpt->client_ip, rpt->client_port, rpt->key, rpt->host->machine_guid, rpt->host->hostname, "CONNECTED");
713 + info("STREAM %s [receive from [%s]:%s]: receiving metrics...", rrdhost_hostname(rpt->host), rpt->client_ip, rpt->client_port);
714 + log_stream_connection(rpt->client_ip, rpt->client_port, rpt->key, rpt->host->machine_guid, rrdhost_hostname(rpt->host), "CONNECTED");
715
716 cd.version = rpt->stream_version;
717
@@ -758,6 +773,7 @@ void *rrdpush_receiver_thread(void *ptr) {
773 info("STREAM %s [%s]:%s: receive thread created (task id %d)", rpt->hostname, rpt->client_ip, rpt->client_port, gettid());
774
775 worker_register("STREAMRCV");
776 + worker_register_job_custom_metric(WORKER_RECEIVER_JOB_BYTES_READ, "received bytes", "bytes/s", WORKER_METRIC_INCREMENTAL);
777 rrdpush_receive(rpt);
778 worker_unregister();
779
streaming/rrdpush.c
+90 -50
@@ -140,8 +140,8 @@ static inline int should_send_chart_matching(RRDSET *st) {
140 if(!rrdset_flag_check(st, RRDSET_FLAG_UPSTREAM_SEND|RRDSET_FLAG_UPSTREAM_IGNORE)) {
141 RRDHOST *host = st->rrdhost;
142
143 - if(simple_pattern_matches(host->rrdpush_send_charts_matching, st->id) ||
144 - simple_pattern_matches(host->rrdpush_send_charts_matching, st->name)) {
143 + if(simple_pattern_matches(host->rrdpush_send_charts_matching, rrdset_id(st)) ||
144 + simple_pattern_matches(host->rrdpush_send_charts_matching, rrdset_name(st))) {
145 rrdset_flag_clear(st, RRDSET_FLAG_UPSTREAM_IGNORE);
146 rrdset_flag_set(st, RRDSET_FLAG_UPSTREAM_SEND);
147 }
@@ -175,20 +175,17 @@ int configured_as_parent() {
175
176 // checks if the current chart definition has been sent
177 static inline int need_to_send_chart_definition(RRDSET *st) {
178 - rrdset_check_rdlock(st);
179 -
178 if(unlikely(!(rrdset_flag_check(st, RRDSET_FLAG_UPSTREAM_EXPOSED))))
179 return 1;
180
181 RRDDIM *rd;
184 - rrddim_foreach_read(rd, st) {
182 + dfe_start_read(st->rrddim_root_index, rd) {
183 if(unlikely(!rd->exposed)) {
186 - #ifdef NETDATA_INTERNAL_CHECKS
187 - info("host '%s', chart '%s', dimension '%s' flag 'exposed' triggered chart refresh to upstream", st->rrdhost->hostname, st->id, rd->id);
188 - #endif
184 + internal_error(true, "host '%s', chart '%s', dimension '%s' flag 'exposed' triggered chart refresh to upstream", rrdhost_hostname(st->rrdhost), rrdset_id(st), rrddim_id(rd));
185 return 1;
186 }
187 }
188 + dfe_done(rd);
189
190 return 0;
191 }
@@ -216,9 +213,9 @@ static inline void rrdpush_send_chart_definition_nolock(RRDSET *st) {
213 // properly set the name for the remote end to parse it
214 char *name = "";
215 if(likely(st->name)) {
219 - if(unlikely(strcmp(st->id, st->name))) {
216 + if(unlikely(st->id != st->name)) {
217 // they differ
221 - name = strchr(st->name, '.');
218 + name = strchr(rrdset_name(st), '.');
219 if(name)
220 name++;
221 else
@@ -230,12 +227,12 @@ static inline void rrdpush_send_chart_definition_nolock(RRDSET *st) {
227 buffer_sprintf(
228 host->sender->build
229 , "CHART \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" \"%s\" %ld %d \"%s %s %s %s\" \"%s\" \"%s\"\n"
233 - , st->id
230 + , rrdset_id(st)
231 , name
235 - , st->title
236 - , st->units
237 - , st->family
238 - , st->context
232 + , rrdset_title(st)
233 + , rrdset_units(st)
234 + , rrdset_family(st)
235 + , rrdset_context(st)
236 , rrdset_type_name(st->chart_type)
237 , st->priority
238 , st->update_every
@@ -243,8 +240,8 @@ static inline void rrdpush_send_chart_definition_nolock(RRDSET *st) {
240 , rrdset_flag_check(st, RRDSET_FLAG_DETAIL)?"detail":""
241 , rrdset_flag_check(st, RRDSET_FLAG_STORE_FIRST)?"store_first":""
242 , rrdset_flag_check(st, RRDSET_FLAG_HIDDEN)?"hidden":""
246 - , (st->plugin_name)?st->plugin_name:""
247 - , (st->module_name)?st->module_name:""
243 + , rrdset_plugin_name(st)
244 + , rrdset_module_name(st)
245 );
246
247 // send the chart labels
@@ -257,8 +254,8 @@ static inline void rrdpush_send_chart_definition_nolock(RRDSET *st) {
254 buffer_sprintf(
255 host->sender->build
256 , "DIMENSION \"%s\" \"%s\" \"%s\" " COLLECTED_NUMBER_FORMAT " " COLLECTED_NUMBER_FORMAT " \"%s %s %s\"\n"
260 - , rd->id
261 - , rd->name
257 + , rrddim_id(rd)
258 + , rrddim_name(rd)
259 , rrd_algorithm_name(rd->algorithm)
260 , rd->multiplier
261 , rd->divisor
@@ -278,7 +275,7 @@ static inline void rrdpush_send_chart_definition_nolock(RRDSET *st) {
275 buffer_sprintf(
276 host->sender->build
277 , "VARIABLE CHART %s = " NETDATA_DOUBLE_FORMAT "\n"
281 - , rs->variable
278 + , string2str(rs->variable)
279 , *value
280 );
281 }
@@ -288,40 +285,75 @@ static inline void rrdpush_send_chart_definition_nolock(RRDSET *st) {
285 }
286
287 // sends the current chart dimensions
291 -static inline void rrdpush_send_chart_metrics_nolock(RRDSET *st, struct sender_state *s) {
288 +static inline bool rrdpush_send_chart_metrics_nolock(RRDSET *st, struct sender_state *s) {
289 RRDHOST *host = st->rrdhost;
293 - buffer_sprintf(host->sender->build, "BEGIN \"%s\" %llu", st->id, (st->last_collected_time.tv_sec > st->upstream_resync_time)?st->usec_since_last_update:0);
290 + buffer_sprintf(host->sender->build, "BEGIN \"%s\" %llu", rrdset_id(st), (st->last_collected_time.tv_sec > st->upstream_resync_time)?st->usec_since_last_update:0);
291 if (s->version >= VERSION_GAP_FILLING)
292 buffer_sprintf(host->sender->build, " %"PRId64"\n", (int64_t)st->last_collected_time.tv_sec);
293 else
294 buffer_strcat(host->sender->build, "\n");
295
296 + size_t count_of_dimensions_written = 0;
297 RRDDIM *rd;
298 rrddim_foreach_read(rd, st) {
301 - if(rd->updated && rd->exposed)
302 - buffer_sprintf(host->sender->build
303 - , "SET \"%s\" = " COLLECTED_NUMBER_FORMAT "\n"
304 - , rd->id
305 - , rd->collected_value
306 - );
299 + if(rd->updated && rd->exposed) {
300 + buffer_sprintf(host->sender->build, "SET \"%s\" = " COLLECTED_NUMBER_FORMAT "\n", rrddim_id(rd), rd->collected_value);
301 + count_of_dimensions_written++;
302 + }
303 }
304 buffer_strcat(host->sender->build, "END\n");
305 +
306 + return count_of_dimensions_written != 0;
307 }
308
309 static void rrdpush_sender_thread_spawn(RRDHOST *host);
310
311 // Called from the internal collectors to mark a chart obsolete.
314 -void rrdset_push_chart_definition_now(RRDSET *st) {
312 +bool rrdset_push_chart_definition_now(RRDSET *st) {
313 RRDHOST *host = st->rrdhost;
314
315 if(unlikely(!host->rrdpush_send_enabled || !should_send_chart_matching(st)))
318 - return;
316 + return false;
317
318 rrdset_rdlock(st);
319 sender_start(host->sender);
320 rrdpush_send_chart_definition_nolock(st);
321 sender_commit(host->sender);
322 rrdset_unlock(st);
323 +
324 + return true;
325 +}
326 +
327 +bool rrdpush_incremental_transmission_of_chart_definitions(RRDHOST *host, DICTFE *dictfe, bool restart, bool stop) {
328 + if(stop || restart)
329 + dictionary_foreach_done(dictfe);
330 +
331 + if(stop)
332 + return false;
333 +
334 + RRDSET *st = NULL;
335 +
336 + if(unlikely(!dictfe->dict)) {
337 + st = dictionary_foreach_start_rw(dictfe, host->rrdset_root_index, DICTIONARY_LOCK_REENTRANT);
338 + }
339 + else
340 + st = dictionary_foreach_next(dictfe);
341 +
342 + do {
343 + while(st && !need_to_send_chart_definition(st))
344 + st = dictionary_foreach_next(dictfe);
345 +
346 + if(st && rrdset_push_chart_definition_now(st))
347 + break;
348 +
349 + } while((st = dictionary_foreach_next(dictfe)));
350 +
351 + if (!st) {
352 + dictionary_foreach_done(dictfe);
353 + return false;
354 + }
355 +
356 + return true;
357 }
358
359 void rrdset_done_push(RRDSET *st) {
@@ -334,29 +366,37 @@ void rrdset_done_push(RRDSET *st) {
366 rrdpush_sender_thread_spawn(host);
367
368 // Handle non-connected case
337 - if(unlikely(!__atomic_load_n(&host->rrdpush_sender_connected, __ATOMIC_SEQ_CST))) {
369 + if(unlikely(!__atomic_load_n(&host->rrdpush_sender_connected, __ATOMIC_SEQ_CST)
370 + || !rrdhost_flag_check(host, RRDHOST_FLAG_STREAM_COLLECTED_METRICS))) {
371 +
372 if(unlikely(!host->rrdpush_sender_error_shown))
339 - error("STREAM %s [send]: not ready - discarding collected metrics.", host->hostname);
373 + error("STREAM %s [send]: not ready - collected metrics are not sent to parent.", rrdhost_hostname(host));
374 host->rrdpush_sender_error_shown = 1;
375 +
376 return;
377 }
378 else if(unlikely(host->rrdpush_sender_error_shown)) {
344 - info("STREAM %s [send]: sending metrics...", host->hostname);
379 + info("STREAM %s [send]: sending metrics to parent...", rrdhost_hostname(host));
380 host->rrdpush_sender_error_shown = 0;
381 }
382
383 + if(dictionary_stats_entries(st->rrddim_root_index) == 0)
384 + return;
385 +
386 sender_start(host->sender);
387
388 if(need_to_send_chart_definition(st))
389 rrdpush_send_chart_definition_nolock(st);
390
353 - rrdpush_send_chart_metrics_nolock(st, host->sender);
354 -
355 - // signal the sender there are more data
356 - if(host->rrdpush_sender_pipe[PIPE_WRITE] != -1 && write(host->rrdpush_sender_pipe[PIPE_WRITE], " ", 1) == -1)
357 - error("STREAM %s [send]: cannot write to internal pipe", host->hostname);
391 + if(rrdpush_send_chart_metrics_nolock(st, host->sender)) {
392 + // signal the sender there are more data
393 + if (host->rrdpush_sender_pipe[PIPE_WRITE] != -1 && write(host->rrdpush_sender_pipe[PIPE_WRITE], " ", 1) == -1)
394 + error("STREAM %s [send]: cannot write to internal pipe", rrdhost_hostname(host));
395
359 - sender_commit(host->sender);
396 + sender_commit(host->sender);
397 + }
398 + else
399 + sender_cancel(host->sender);
400 }
401
402 // labels
@@ -376,7 +416,7 @@ void rrdpush_send_labels(RRDHOST *host) {
416 sender_commit(host->sender);
417
418 if(host->rrdpush_sender_pipe[PIPE_WRITE] != -1 && write(host->rrdpush_sender_pipe[PIPE_WRITE], " ", 1) == -1)
379 - error("STREAM %s [send]: cannot write to internal pipe", host->hostname);
419 + error("STREAM %s [send]: cannot write to internal pipe", rrdhost_hostname(host));
420
421 rrdhost_flag_clear(host, RRDHOST_FLAG_STREAM_LABELS_UPDATE);
422 }
@@ -399,7 +439,7 @@ void rrdpush_claimed_id(RRDHOST *host)
439
440 // signal the sender there are more data
441 if(host->rrdpush_sender_pipe[PIPE_WRITE] != -1 && write(host->rrdpush_sender_pipe[PIPE_WRITE], " ", 1) == -1)
402 - error("STREAM %s [send]: cannot write to internal pipe", host->hostname);
442 + error("STREAM %s [send]: cannot write to internal pipe", rrdhost_hostname(host));
443 }
444
445 int connect_to_one_of_destinations(
@@ -496,7 +536,7 @@ void rrdpush_sender_thread_stop(RRDHOST *host) {
536 netdata_thread_t thr = 0;
537
538 if(host->rrdpush_sender_spawn) {
499 - info("STREAM %s [send]: signaling sending thread to stop...", host->hostname);
539 + info("STREAM %s [send]: signaling sending thread to stop...", rrdhost_hostname(host));
540
541 // signal the thread that we want to join it
542 host->rrdpush_sender_join = 1;
@@ -512,10 +552,10 @@ void rrdpush_sender_thread_stop(RRDHOST *host) {
552 netdata_mutex_unlock(&host->sender->mutex);
553
554 if(thr != 0) {
515 - info("STREAM %s [send]: waiting for the sending thread to stop...", host->hostname);
555 + info("STREAM %s [send]: waiting for the sending thread to stop...", rrdhost_hostname(host));
556 void *result;
557 netdata_thread_join(thr, &result);
518 - info("STREAM %s [send]: sending thread has exited.", host->hostname);
558 + info("STREAM %s [send]: sending thread has exited.", rrdhost_hostname(host));
559 }
560 }
561
@@ -533,10 +573,10 @@ static void rrdpush_sender_thread_spawn(RRDHOST *host) {
573
574 if(!host->rrdpush_sender_spawn) {
575 char tag[NETDATA_THREAD_TAG_MAX + 1];
536 - snprintfz(tag, NETDATA_THREAD_TAG_MAX, "STREAM_SENDER[%s]", host->hostname);
576 + snprintfz(tag, NETDATA_THREAD_TAG_MAX, "STREAM_SENDER[%s]", rrdhost_hostname(host));
577
578 if(netdata_thread_create(&host->rrdpush_sender_thread, tag, NETDATA_THREAD_OPTION_JOINABLE, rrdpush_sender_thread, (void *) host->sender))
539 - error("STREAM %s [send]: failed to create new thread for client.", host->hostname);
579 + error("STREAM %s [send]: failed to create new thread for client.", rrdhost_hostname(host));
580 else
581 host->rrdpush_sender_spawn = 1;
582 }
@@ -746,7 +786,7 @@ int rrdpush_receiver_thread_spawn(struct web_client *w, char *url) {
786 struct receiver_state *rpt = callocz(1, sizeof(*rpt));
787
788 rrd_rdlock();
749 - RRDHOST *host = rrdhost_find_by_guid(machine_guid, 0);
789 + RRDHOST *host = rrdhost_find_by_guid(machine_guid);
790 if (unlikely(host && rrdhost_flag_check(host, RRDHOST_FLAG_ARCHIVED))) /* Ignore archived hosts. */
791 host = NULL;
792 if (host) {
@@ -763,7 +803,7 @@ int rrdpush_receiver_thread_spawn(struct web_client *w, char *url) {
803 info(
804 "STREAM %s [receive from [%s]:%s]: multiple connections for same host detected - "
805 "existing connection is dead (%"PRId64" sec), accepting new connection.",
766 - host->hostname,
806 + rrdhost_hostname(host),
807 w->client_ip,
808 w->client_port,
809 (int64_t)age);
@@ -772,12 +812,12 @@ int rrdpush_receiver_thread_spawn(struct web_client *w, char *url) {
812 netdata_mutex_unlock(&host->receiver_lock);
813 rrdhost_unlock(host);
814 rrd_unlock();
775 - log_stream_connection(w->client_ip, w->client_port, key, host->machine_guid, host->hostname,
815 + log_stream_connection(w->client_ip, w->client_port, key, host->machine_guid, rrdhost_hostname(host),
816 "REJECTED - ALREADY CONNECTED");
817 info(
818 "STREAM %s [receive from [%s]:%s]: multiple connections for same host detected - "
819 "existing connection is active (within last %"PRId64" sec), rejecting new connection.",
780 - host->hostname,
820 + rrdhost_hostname(host),
821 w->client_ip,
822 w->client_port,
823 (int64_t)age);
streaming/rrdpush.h
+6 -3
@@ -46,9 +46,10 @@ typedef struct {
46 } stream_encoded_t;
47
48 #ifdef ENABLE_COMPRESSION
49 +#define LZ4_MAX_MSG_SIZE 0x4000
50 struct compressor_state {
50 - char *buffer;
51 - size_t buffer_size;
51 + char *compression_result_buffer;
52 + size_t compression_result_buffer_size;
53 struct compressor_data *data; // Compression API specific data
54 void (*reset)(struct compressor_state *state);
55 size_t (*compress)(struct compressor_state *state, const char *data, size_t size, char **buffer);
@@ -164,10 +165,12 @@ extern void sender_init(RRDHOST *parent);
165 extern struct rrdpush_destinations *destinations_init(const char *destinations);
166 void sender_start(struct sender_state *s);
167 void sender_commit(struct sender_state *s);
168 +void sender_cancel(struct sender_state *s);
169 extern int rrdpush_init();
170 extern int configured_as_parent();
171 extern void rrdset_done_push(RRDSET *st);
170 -extern void rrdset_push_chart_definition_now(RRDSET *st);
172 +extern bool rrdset_push_chart_definition_now(RRDSET *st);
173 +extern bool rrdpush_incremental_transmission_of_chart_definitions(RRDHOST *host, DICTFE *dictfe, bool restart, bool stop);
174 extern void *rrdpush_sender_thread(void *ptr);
175 extern void rrdpush_send_labels(RRDHOST *host);
176 extern void rrdpush_claimed_id(RRDHOST *host);
streaming/sender.c
+216 -91
@@ -17,9 +17,12 @@
17 #define WORKER_SENDER_JOB_DISCONNECT_RECEIVE_ERROR 12
18 #define WORKER_SENDER_JOB_DISCONNECT_SEND_ERROR 13
19 #define WORKER_SENDER_JOB_DISCONNECT_NO_COMPRESSION 14
20 +#define WORKER_SENDER_JOB_BUFFER_RATIO 15
21 +#define WORKER_SENDER_JOB_BYTES_RECEIVED 16
22 +#define WORKER_SENDER_JOB_BYTES_SENT 17
23
21 -#if WORKER_UTILIZATION_MAX_JOB_TYPES < 15
22 -#error WORKER_UTILIZATION_MAX_JOB_TYPES has to be at least 15
24 +#if WORKER_UTILIZATION_MAX_JOB_TYPES < 18
25 +#error WORKER_UTILIZATION_MAX_JOB_TYPES has to be at least 18
26 #endif
27
28 extern struct config stream_config;
@@ -33,6 +36,11 @@ void sender_start(struct sender_state *s) {
36 buffer_flush(s->build);
37 }
38
39 +void sender_cancel(struct sender_state *s) {
40 + buffer_flush(s->build);
41 + netdata_mutex_unlock(&s->mutex);
42 +}
43 +
44 static inline void rrdpush_sender_thread_close_socket(RRDHOST *host);
45
46 #ifdef ENABLE_COMPRESSION
@@ -43,11 +51,11 @@ static inline void rrdpush_sender_thread_close_socket(RRDHOST *host);
51 */
52 static inline void deactivate_compression(struct sender_state *s) {
53 worker_is_busy(WORKER_SENDER_JOB_DISCONNECT_NO_COMPRESSION);
46 - error("STREAM_COMPRESSION: Deactivating compression to avoid stream corruption");
54 + error("STREAM_COMPRESSION: Compression returned error, disabling it.");
55 default_compression_enabled = 0;
56 s->rrdpush_compression = 0;
57 s->version = STREAM_VERSION_CLABELS;
50 - error("STREAM_COMPRESSION %s [send to %s]: Restarting connection without compression", s->host->hostname, s->connected_to);
58 + error("STREAM %s [send to %s]: Restarting connection without compression.", rrdhost_hostname(s->host), s->connected_to);
59 rrdpush_sender_thread_close_socket(s->host);
60 }
61 #endif
@@ -59,27 +67,55 @@ void sender_commit(struct sender_state *s) {
67 #ifdef ENABLE_COMPRESSION
68 if (src && src_len) {
69 if (s->compressor && s->rrdpush_compression) {
62 - src_len = s->compressor->compress(s->compressor, src, src_len, &src);
63 - if (!src_len) {
64 - deactivate_compression(s);
65 - buffer_flush(s->build);
66 - netdata_mutex_unlock(&s->mutex);
67 - return;
70 + while(src_len) {
71 + size_t size_to_compress = src_len;
72 +
73 + if(size_to_compress > LZ4_MAX_MSG_SIZE) {
74 + // we need to find the last newline
75 + // so that the decompressor will have a whole line to work with
76 +
77 + const char *t = &src[LZ4_MAX_MSG_SIZE - 1];
78 + while(t-- > src)
79 + if(*t == '\n')
80 + break;
81 +
82 + if(t == src)
83 + size_to_compress = LZ4_MAX_MSG_SIZE;
84 + else
85 + size_to_compress = t - src + 1;
86 + }
87 +
88 + char *dst;
89 + size_t dst_len = s->compressor->compress(s->compressor, src, size_to_compress, &dst);
90 + if (!dst_len) {
91 + deactivate_compression(s);
92 + buffer_flush(s->build);
93 + netdata_mutex_unlock(&s->mutex);
94 + return;
95 + }
96 +
97 + if(cbuffer_add_unsafe(s->host->sender->buffer, dst, dst_len))
98 + s->overflow = 1;
99 +
100 + src = src + size_to_compress;
101 + src_len -= size_to_compress;
102 }
103 }
70 - if(cbuffer_add_unsafe(s->host->sender->buffer, src, src_len))
104 + else if(cbuffer_add_unsafe(s->host->sender->buffer, src, src_len))
105 s->overflow = 1;
106 }
107 #else
108 if(cbuffer_add_unsafe(s->host->sender->buffer, src, src_len))
109 s->overflow = 1;
110 #endif
111 +
112 buffer_flush(s->build);
113 netdata_mutex_unlock(&s->mutex);
114 }
115
116
117 static inline void rrdpush_sender_thread_close_socket(RRDHOST *host) {
118 + rrdhost_flag_clear(host, RRDHOST_FLAG_STREAM_COLLECTED_METRICS);
119 __atomic_clear(&host->rrdpush_sender_connected, __ATOMIC_SEQ_CST);
120
121 if(host->rrdpush_sender_socket != -1) {
@@ -94,11 +130,11 @@ static inline void rrdpush_sender_add_host_variable_to_buffer_nolock(RRDHOST *ho
130 buffer_sprintf(
131 host->sender->build
132 , "VARIABLE HOST %s = " NETDATA_DOUBLE_FORMAT "\n"
97 - , rv->name
133 + , rrdvar_name(rv)
134 , *value
135 );
136
101 - debug(D_STREAM, "RRDVAR pushed HOST VARIABLE %s = " NETDATA_DOUBLE_FORMAT, rv->name, *value);
137 + debug(D_STREAM, "RRDVAR pushed HOST VARIABLE %s = " NETDATA_DOUBLE_FORMAT, rrdvar_name(rv), *value);
138 }
139
140 void rrdpush_sender_send_this_host_variable_now(RRDHOST *host, RRDVAR *rv) {
@@ -110,7 +146,7 @@ void rrdpush_sender_send_this_host_variable_now(RRDHOST *host, RRDVAR *rv) {
146 }
147
148
113 -static int rrdpush_sender_thread_custom_host_variables_callback(void *rrdvar_ptr, void *host_ptr) {
149 +static int rrdpush_sender_thread_custom_host_variables_callback(const char *name __maybe_unused, void *rrdvar_ptr, void *host_ptr) {
150 RRDVAR *rv = (RRDVAR *)rrdvar_ptr;
151 RRDHOST *host = (RRDHOST *)host_ptr;
152
@@ -127,7 +163,7 @@ static int rrdpush_sender_thread_custom_host_variables_callback(void *rrdvar_ptr
163
164 static void rrdpush_sender_thread_send_custom_host_variables(RRDHOST *host) {
165 sender_start(host->sender);
130 - int ret = rrdvar_callback_for_all_host_variables(host, rrdpush_sender_thread_custom_host_variables_callback, host);
166 + int ret = rrdvar_walkthrough_read(host->rrdvar_root_index, rrdpush_sender_thread_custom_host_variables_callback, host);
167 (void)ret;
168 sender_commit(host->sender);
169
@@ -162,7 +198,7 @@ static inline void rrdpush_sender_thread_data_flush(RRDHOST *host) {
198
199 size_t len = cbuffer_next_unsafe(host->sender->buffer, NULL);
200 if (len)
165 - error("STREAM %s [send]: discarding %zu bytes of metrics already in the buffer.", host->hostname, len);
201 + error("STREAM %s [send]: discarding %zu bytes of metrics already in the buffer.", rrdhost_hostname(host), len);
202
203 cbuffer_remove_unsafe(host->sender->buffer, len);
204 netdata_mutex_unlock(&host->sender->mutex);
@@ -259,7 +295,7 @@ static int rrdpush_sender_thread_connect_to_parent(RRDHOST *host, int default_po
295 rrdpush_sender_thread_close_socket(host);
296
297 debug(D_STREAM, "STREAM: Attempting to connect...");
262 - info("STREAM %s [send to %s]: connecting...", host->hostname, host->rrdpush_send_destination);
298 + info("STREAM %s [send to %s]: connecting...", rrdhost_hostname(host), host->rrdpush_send_destination);
299
300 host->rrdpush_sender_socket = connect_to_one_of_destinations(
301 host->destinations
@@ -272,11 +308,11 @@ static int rrdpush_sender_thread_connect_to_parent(RRDHOST *host, int default_po
308 );
309
310 if(unlikely(host->rrdpush_sender_socket == -1)) {
275 - error("STREAM %s [send to %s]: failed to connect", host->hostname, host->rrdpush_send_destination);
311 + error("STREAM %s [send to %s]: failed to connect", rrdhost_hostname(host), host->rrdpush_send_destination);
312 return 0;
313 }
314
279 - info("STREAM %s [send to %s]: initializing communication...", host->hostname, s->connected_to);
315 + info("STREAM %s [send to %s]: initializing communication...", rrdhost_hostname(host), s->connected_to);
316
317 #ifdef ENABLE_HTTPS
318 if( netdata_client_ctx ){
@@ -370,19 +406,19 @@ if(!s->rrdpush_compression)
406 "User-Agent: %s/%s\r\n"
407 "Accept: */*\r\n\r\n"
408 , host->rrdpush_send_api_key
373 - , host->hostname
374 - , host->registry_hostname
409 + , rrdhost_hostname(host)
410 + , rrdhost_registry_hostname(host)
411 , host->machine_guid
412 , default_rrd_update_every
377 - , host->os
378 - , host->timezone
379 - , host->abbrev_timezone
413 + , rrdhost_os(host)
414 + , rrdhost_timezone(host)
415 + , rrdhost_abbrev_timezone(host)
416 , host->utc_offset
417 , host->system_info->hops + 1
418 , host->system_info->ml_capable
419 , host->system_info->ml_enabled
420 , host->system_info->mc_version
385 - , (host->tags) ? host->tags : ""
421 + , rrdhost_tags(host)
422 , s->version
423 , (host->system_info->cloud_provider_type) ? host->system_info->cloud_provider_type : ""
424 , (host->system_info->cloud_instance_type) ? host->system_info->cloud_instance_type : ""
@@ -412,8 +448,8 @@ if(!s->rrdpush_compression)
448 , (host->system_info->host_ram_total) ? host->system_info->host_ram_total : ""
449 , (host->system_info->host_disk_space) ? host->system_info->host_disk_space : ""
450 , STREAMING_PROTOCOL_VERSION
415 - , host->program_name
416 - , host->program_version
451 + , rrdhost_program_name(host)
452 + , rrdhost_program_version(host)
453 );
454 http[eol] = 0x00;
455 rrdpush_clean_encoded(&se);
@@ -456,12 +492,12 @@ if(!s->rrdpush_compression)
492 if(send_timeout(host->rrdpush_sender_socket, http, strlen(http), 0, timeout) == -1) {
493 #endif
494 worker_is_busy(WORKER_SENDER_JOB_DISCONNECT_TIMEOUT);
459 - error("STREAM %s [send to %s]: failed to send HTTP header to remote netdata.", host->hostname, s->connected_to);
495 + error("STREAM %s [send to %s]: failed to send HTTP header to remote netdata.", rrdhost_hostname(host), s->connected_to);
496 rrdpush_sender_thread_close_socket(host);
497 return 0;
498 }
499
464 - info("STREAM %s [send to %s]: waiting response from remote netdata...", host->hostname, s->connected_to);
500 + info("STREAM %s [send to %s]: waiting response from remote netdata...", rrdhost_hostname(host), s->connected_to);
501
502 ssize_t received;
503 #ifdef ENABLE_HTTPS
@@ -472,7 +508,7 @@ if(!s->rrdpush_compression)
508 if(received == -1) {
509 #endif
510 worker_is_busy(WORKER_SENDER_JOB_DISCONNECT_TIMEOUT);
475 - error("STREAM %s [send to %s]: remote netdata does not respond.", host->hostname, s->connected_to);
511 + error("STREAM %s [send to %s]: remote netdata does not respond.", rrdhost_hostname(host), s->connected_to);
512 rrdpush_sender_thread_close_socket(host);
513 return 0;
514 }
@@ -482,7 +518,7 @@ if(!s->rrdpush_compression)
518 int32_t version = (int32_t)parse_stream_version(host, http);
519 if(version == -1) {
520 worker_is_busy(WORKER_SENDER_JOB_DISCONNECT_BAD_HANDSHAKE);
485 - error("STREAM %s [send to %s]: server is not replying properly (is it a netdata?).", host->hostname, s->connected_to);
521 + error("STREAM %s [send to %s]: server is not replying properly (is it a netdata?).", rrdhost_hostname(host), s->connected_to);
522 rrdpush_sender_thread_close_socket(host);
523 //catch other reject reasons and force to check other destinations
524 if (host->destination->next)
@@ -490,19 +526,19 @@ if(!s->rrdpush_compression)
526 return 0;
527 }
528 else if(version == -2) {
493 - error("STREAM %s [send to %s]: remote server is the localhost for [%s].", host->hostname, s->connected_to, host->hostname);
529 + error("STREAM %s [send to %s]: remote server is the localhost for [%s].", rrdhost_hostname(host), s->connected_to, rrdhost_hostname(host));
530 rrdpush_sender_thread_close_socket(host);
531 host->destination->disabled_because_of_localhost = 1;
532 return 0;
533 }
534 else if(version == -3) {
499 - error("STREAM %s [send to %s]: remote server already receives metrics for [%s].", host->hostname, s->connected_to, host->hostname);
535 + error("STREAM %s [send to %s]: remote server already receives metrics for [%s].", rrdhost_hostname(host), s->connected_to, rrdhost_hostname(host));
536 rrdpush_sender_thread_close_socket(host);
537 host->destination->disabled_already_streaming = now_realtime_sec();
538 return 0;
539 }
540 else if(version == -4) {
505 - error("STREAM %s [send to %s]: remote server denied access for [%s].", host->hostname, s->connected_to, host->hostname);
541 + error("STREAM %s [send to %s]: remote server denied access for [%s].", rrdhost_hostname(host), s->connected_to, rrdhost_hostname(host));
542 rrdpush_sender_thread_close_socket(host);
543 if (host->destination->next)
544 host->destination->disabled_because_of_denied_access = 1;
@@ -520,23 +556,23 @@ if(!s->rrdpush_compression)
556 }
557 else {
558 //parent does not support compression or has compression disabled
523 - debug(D_STREAM, "Stream is uncompressed! One of the agents (%s <-> %s) does not support compression OR compression is disabled.", s->connected_to, s->host->hostname);
524 - infoerr("Stream is uncompressed! One of the agents (%s <-> %s) does not support compression OR compression is disabled.", s->connected_to, s->host->hostname);
559 + debug(D_STREAM, "Stream is uncompressed! One of the agents (%s <-> %s) does not support compression OR compression is disabled.", s->connected_to, rrdhost_hostname(s->host));
560 + infoerr("Stream is uncompressed! One of the agents (%s <-> %s) does not support compression OR compression is disabled.", s->connected_to, rrdhost_hostname(s->host));
561 s->version = STREAM_VERSION_CLABELS;
562 }
563 #endif //ENABLE_COMPRESSION
564
565
530 - info("STREAM %s [send to %s]: established communication with a parent using protocol version %d - ready to send metrics..."
531 - , host->hostname
566 + info("STREAM %s [send to %s]: established communication with a parent using protocol version %d"
567 + , rrdhost_hostname(host)
568 , s->connected_to
569 , s->version);
570
571 if(sock_setnonblock(host->rrdpush_sender_socket) < 0)
536 - error("STREAM %s [send to %s]: cannot set non-blocking mode for socket.", host->hostname, s->connected_to);
572 + error("STREAM %s [send to %s]: cannot set non-blocking mode for socket.", rrdhost_hostname(host), s->connected_to);
573
574 if(sock_enlarge_out(host->rrdpush_sender_socket) < 0)
539 - error("STREAM %s [send to %s]: cannot enlarge the socket buffer.", host->hostname, s->connected_to);
575 + error("STREAM %s [send to %s]: cannot enlarge the socket buffer.", rrdhost_hostname(host), s->connected_to);
576
577 debug(D_STREAM, "STREAM: Connected on fd %d...", host->rrdpush_sender_socket);
578
@@ -578,7 +614,8 @@ static void attempt_to_connect(struct sender_state *state)
614 }
615
616 // TCP window is open and we have data to transmit.
581 -void attempt_to_send(struct sender_state *s) {
617 +static ssize_t attempt_to_send(struct sender_state *s) {
618 + ssize_t ret = 0;
619
620 rrdpush_send_labels(s->host);
621
@@ -591,42 +628,44 @@ void attempt_to_send(struct sender_state *s) {
628 char *chunk;
629 size_t outstanding = cbuffer_next_unsafe(s->buffer, &chunk);
630 debug(D_STREAM, "STREAM: Sending data. Buffer r=%zu w=%zu s=%zu, next chunk=%zu", cb->read, cb->write, cb->size, outstanding);
594 - ssize_t ret;
631 +
632 #ifdef ENABLE_HTTPS
633 SSL *conn = s->host->ssl.conn ;
597 - if(conn && !s->host->ssl.flags) {
634 + if(conn && !s->host->ssl.flags)
635 ret = SSL_write(conn, chunk, outstanding);
599 - } else {
636 + else
637 ret = send(s->host->rrdpush_sender_socket, chunk, outstanding, MSG_DONTWAIT);
601 - }
638 #else
639 ret = send(s->host->rrdpush_sender_socket, chunk, outstanding, MSG_DONTWAIT);
640 #endif
641 +
642 if (likely(ret > 0)) {
643 cbuffer_remove_unsafe(s->buffer, ret);
644 s->sent_bytes_on_this_connection += ret;
645 s->sent_bytes += ret;
609 - debug(D_STREAM, "STREAM %s [send to %s]: Sent %zd bytes", s->host->hostname, s->connected_to, ret);
646 + debug(D_STREAM, "STREAM %s [send to %s]: Sent %zd bytes", rrdhost_hostname(s->host), s->connected_to, ret);
647 s->last_sent_t = now_monotonic_sec();
648 }
649 else if (ret == -1 && (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK))
613 - debug(D_STREAM, "STREAM %s [send to %s]: unavailable after polling POLLOUT", s->host->hostname, s->connected_to);
650 + debug(D_STREAM, "STREAM %s [send to %s]: unavailable after polling POLLOUT", rrdhost_hostname(s->host), s->connected_to);
651 else if (ret == -1) {
652 worker_is_busy(WORKER_SENDER_JOB_DISCONNECT_SEND_ERROR);
653 debug(D_STREAM, "STREAM: Send failed - closing socket...");
617 - error("STREAM %s [send to %s]: failed to send metrics - closing connection - we have sent %zu bytes on this connection.", s->host->hostname, s->connected_to, s->sent_bytes_on_this_connection);
654 + error("STREAM %s [send to %s]: failed to send metrics - closing connection - we have sent %zu bytes on this connection.", rrdhost_hostname(s->host), s->connected_to, s->sent_bytes_on_this_connection);
655 rrdpush_sender_thread_close_socket(s->host);
656 }
620 - else {
657 + else
658 debug(D_STREAM, "STREAM: send() returned 0 -> no error but no transmission");
622 - }
659
660 netdata_mutex_unlock(&s->mutex);
661 netdata_thread_enable_cancelability();
662 +
663 + return ret;
664 }
665
628 -void attempt_read(struct sender_state *s) {
629 -int ret;
666 +static ssize_t attempt_read(struct sender_state *s) {
667 + ssize_t ret = 0;
668 +
669 #ifdef ENABLE_HTTPS
670 if (s->host->ssl.conn && !s->host->stream_ssl.flags) {
671 ERR_clear_error();
@@ -634,44 +673,46 @@ int ret;
673 ret = SSL_read(s->host->ssl.conn, s->read_buffer, desired);
674 if (ret > 0 ) {
675 s->read_len += ret;
637 - return;
676 + return ret;
677 }
678 int sslerrno = SSL_get_error(s->host->ssl.conn, desired);
679 if (sslerrno == SSL_ERROR_WANT_READ || sslerrno == SSL_ERROR_WANT_WRITE)
641 - return;
680 + return ret;
681
682 worker_is_busy(WORKER_SENDER_JOB_DISCONNECT_SSL_ERROR);
683 u_long err;
684 char buf[256];
685 while ((err = ERR_get_error()) != 0) {
686 ERR_error_string_n(err, buf, sizeof(buf));
648 - error("STREAM %s [send to %s] ssl error: %s", s->host->hostname, s->connected_to, buf);
687 + error("STREAM %s [send to %s] ssl error: %s", rrdhost_hostname(s->host), s->connected_to, buf);
688 }
689 error("Restarting connection");
690 rrdpush_sender_thread_close_socket(s->host);
652 - return;
691 + return ret;
692 }
693 #endif
694 ret = recv(s->host->rrdpush_sender_socket, s->read_buffer + s->read_len, sizeof(s->read_buffer) - s->read_len - 1,MSG_DONTWAIT);
656 - if (ret>0) {
695 + if (ret > 0) {
696 s->read_len += ret;
658 - return;
697 + return ret;
698 }
699
661 - debug(D_STREAM, "Socket was POLLIN, but req %zu bytes gave %d", sizeof(s->read_buffer) - s->read_len - 1, ret);
700 + debug(D_STREAM, "Socket was POLLIN, but req %zu bytes gave %zd", sizeof(s->read_buffer) - s->read_len - 1, ret);
701
663 - if (ret<0 && (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR))
664 - return;
702 + if (ret < 0 && (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR))
703 + return ret;
704
666 - if (ret==0) {
705 + if (ret == 0) {
706 worker_is_busy(WORKER_SENDER_JOB_DISCONNECT_PARENT_CLOSED);
668 - error("STREAM %s [send to %s]: connection closed by far end. Restarting connection", s->host->hostname, s->connected_to);
707 + error("STREAM %s [send to %s]: connection closed by far end. Restarting connection", rrdhost_hostname(s->host), s->connected_to);
708 }
709 else {
710 worker_is_busy(WORKER_SENDER_JOB_DISCONNECT_RECEIVE_ERROR);
672 - error("STREAM %s [send to %s]: error during receive (%d). Restarting connection", s->host->hostname, s->connected_to, ret);
711 + error("STREAM %s [send to %s]: error during receive (%zd). Restarting connection", rrdhost_hostname(s->host), s->connected_to, ret);
712 }
713 rrdpush_sender_thread_close_socket(s->host);
714 +
715 + return ret;
716 }
717
718 // This is just a placeholder until the gap filling state machine is inserted
@@ -680,7 +721,7 @@ void execute_commands(struct sender_state *s) {
721 *end = 0;
722 while( start<end && (newline=strchr(start, '\n')) ) {
723 *newline = 0;
683 - info("STREAM %s [send to %s] received command over connection: %s", s->host->hostname, s->connected_to, start);
724 + info("STREAM %s [send to %s] received command over connection: %s", rrdhost_hostname(s->host), s->connected_to, start);
725 start = newline+1;
726 }
727 if (start<end) {
@@ -689,15 +730,57 @@ void execute_commands(struct sender_state *s) {
730 }
731 }
732
733 +struct rrdpush_sender_thread_data {
734 + struct sender_state *sender_state;
735 + RRDHOST *host;
736 + DICTFE dictfe;
737 + enum {
738 + SENDING_DEFINITIONS_RESTART,
739 + SENDING_DEFINITIONS_CONTINUE,
740 + SENDING_DEFINITIONS_DONE,
741 + } sending_definitions_status;
742 +};
743 +
744 +static size_t cbuffer_available_bytes_with_lock(struct rrdpush_sender_thread_data *thread_data) {
745 + netdata_mutex_lock(&thread_data->sender_state->mutex);
746 + size_t outstanding = cbuffer_available_size_unsafe(thread_data->sender_state->host->sender->buffer);
747 + netdata_mutex_unlock(&thread_data->sender_state->mutex);
748 + return outstanding;
749 +}
750 +
751 +static void rrdpush_queue_incremental_definitions(struct rrdpush_sender_thread_data *thread_data) {
752 +
753 + while(__atomic_load_n(&thread_data->host->rrdpush_sender_connected, __ATOMIC_SEQ_CST)
754 + && thread_data->sending_definitions_status != SENDING_DEFINITIONS_DONE
755 + && cbuffer_available_bytes_with_lock(thread_data) > (thread_data->sender_state->buffer->max_size / 2)) {
756 +
757 + if(thread_data->sending_definitions_status == SENDING_DEFINITIONS_RESTART)
758 + info("STREAM %s [send to %s]: sending metric definitions...", rrdhost_hostname(thread_data->host), thread_data->sender_state->connected_to);
759 +
760 + bool more_defs_available = rrdpush_incremental_transmission_of_chart_definitions(
761 + thread_data->sender_state->host, &thread_data->dictfe,
762 + thread_data->sending_definitions_status == SENDING_DEFINITIONS_RESTART, false);
763 +
764 + if (unlikely(!more_defs_available)) {
765 + thread_data->sending_definitions_status = SENDING_DEFINITIONS_DONE;
766 + info("STREAM %s [send to %s]: sending metric definitions finished.", rrdhost_hostname(thread_data->host), thread_data->sender_state->connected_to);
767 + }
768 + else
769 + thread_data->sending_definitions_status = SENDING_DEFINITIONS_CONTINUE;
770 + }
771 +}
772
773 static void rrdpush_sender_thread_cleanup_callback(void *ptr) {
774 + struct rrdpush_sender_thread_data *data = ptr;
775 worker_unregister();
776
696 - RRDHOST *host = (RRDHOST *)ptr;
777 + RRDHOST *host = data->host;
778 +
779 + rrdpush_incremental_transmission_of_chart_definitions(host, &data->dictfe, false, true);
780
781 netdata_mutex_lock(&host->sender->mutex);
782
700 - info("STREAM %s [send]: sending thread cleans up...", host->hostname);
783 + info("STREAM %s [send]: sending thread cleans up...", rrdhost_hostname(host));
784
785 rrdpush_sender_thread_close_socket(host);
786
@@ -713,15 +796,17 @@ static void rrdpush_sender_thread_cleanup_callback(void *ptr) {
796 }
797
798 if(!host->rrdpush_sender_join) {
716 - info("STREAM %s [send]: sending thread detaches itself.", host->hostname);
799 + info("STREAM %s [send]: sending thread detaches itself.", rrdhost_hostname(host));
800 netdata_thread_detach(netdata_thread_self());
801 }
802
803 host->rrdpush_sender_spawn = 0;
804
722 - info("STREAM %s [send]: sending thread now exits.", host->hostname);
805 + info("STREAM %s [send]: sending thread now exits.", rrdhost_hostname(host));
806
807 netdata_mutex_unlock(&host->sender->mutex);
808 +
809 + freez(data);
810 }
811
812 void sender_init(RRDHOST *parent)
@@ -749,7 +834,7 @@ void *rrdpush_sender_thread(void *ptr) {
834 !*s->host->rrdpush_send_destination || !s->host->rrdpush_send_api_key ||
835 !*s->host->rrdpush_send_api_key) {
836 error("STREAM %s [send]: thread created (task id %d), but host has streaming disabled.",
752 - s->host->hostname, s->task_id);
837 + rrdhost_hostname(s->host), s->task_id);
838 return NULL;
839 }
840
@@ -760,7 +845,7 @@ void *rrdpush_sender_thread(void *ptr) {
845 }
846 #endif
847
763 - info("STREAM %s [send]: thread created (task id %d)", s->host->hostname, s->task_id);
848 + info("STREAM %s [send]: thread created (task id %d)", rrdhost_hostname(s->host), s->task_id);
849
850 s->timeout = (int)appconfig_get_number(&stream_config, CONFIG_SECTION_STREAM, "timeout seconds", 60);
851 s->default_port = (int)appconfig_get_number(&stream_config, CONFIG_SECTION_STREAM, "default port", 19999);
@@ -774,9 +859,10 @@ void *rrdpush_sender_thread(void *ptr) {
859 remote_clock_resync_iterations); // TODO: REMOVE FOR SLEW / GAPFILLING
860
861 // initialize rrdpush globals
862 + rrdhost_flag_clear(s->host, RRDHOST_FLAG_STREAM_COLLECTED_METRICS);
863 __atomic_clear(&s->host->rrdpush_sender_connected, __ATOMIC_SEQ_CST);
864 if(pipe(s->host->rrdpush_sender_pipe) == -1) {
779 - error("STREAM %s [send]: cannot create required pipe. DISABLING STREAMING THREAD", s->host->hostname);
865 + error("STREAM %s [send]: cannot create required pipe. DISABLING STREAMING THREAD", rrdhost_hostname(s->host));
866 return NULL;
867 }
868 s->version = STREAMING_PROTOCOL_CURRENT_VERSION;
@@ -808,7 +894,17 @@ void *rrdpush_sender_thread(void *ptr) {
894 worker_register_job_name(WORKER_SENDER_JOB_DISCONNECT_NO_COMPRESSION, "disconnect no compression");
895 worker_register_job_name(WORKER_SENDER_JOB_DISCONNECT_BAD_HANDSHAKE, "disconnect bad handshake");
896
811 - netdata_thread_cleanup_push(rrdpush_sender_thread_cleanup_callback, s->host);
897 + worker_register_job_custom_metric(WORKER_SENDER_JOB_BUFFER_RATIO, "used buffer ratio", "%", WORKER_METRIC_ABSOLUTE);
898 + worker_register_job_custom_metric(WORKER_SENDER_JOB_BYTES_RECEIVED, "bytes received", "bytes/s", WORKER_METRIC_INCREMENTAL);
899 + worker_register_job_custom_metric(WORKER_SENDER_JOB_BYTES_SENT, "bytes sent", "bytes/s", WORKER_METRIC_INCREMENTAL);
900 +
901 + struct rrdpush_sender_thread_data *thread_data = callocz(1, sizeof(struct rrdpush_sender_thread_data));
902 + thread_data->sender_state = s;
903 + thread_data->host = s->host;
904 + thread_data->sending_definitions_status = SENDING_DEFINITIONS_RESTART;
905 +
906 + netdata_thread_cleanup_push(rrdpush_sender_thread_cleanup_callback, thread_data);
907 +
908 for(; s->host->rrdpush_send_enabled && !netdata_exit ;) {
909 // check for outstanding cancellation requests
910 netdata_thread_testcancel();
@@ -816,6 +912,8 @@ void *rrdpush_sender_thread(void *ptr) {
912 // The connection attempt blocks (after which we use the socket in nonblocking)
913 if(unlikely(s->host->rrdpush_sender_socket == -1)) {
914 worker_is_busy(WORKER_SENDER_JOB_CONNECT);
915 + thread_data->sending_definitions_status = SENDING_DEFINITIONS_RESTART;
916 + rrdhost_flag_clear(s->host, RRDHOST_FLAG_STREAM_COLLECTED_METRICS);
917 s->overflow = 0;
918 s->read_len = 0;
919 s->buffer->read = 0;
@@ -828,17 +926,27 @@ void *rrdpush_sender_thread(void *ptr) {
926 sender_commit(s);
927 }
928 rrdpush_claimed_id(s->host);
929 +
930 + // TO PUSH METRICS WITH DEFINITIONS:
931 + //if(unlikely(s->host->rrdpush_sender_socket != -1 && __atomic_load_n(&s->host->rrdpush_sender_connected, __ATOMIC_SEQ_CST))) {
932 + // thread_data->sending_definitions_status = SENDING_DEFINITIONS_DONE;
933 + // rrdhost_flag_set(s->host, RRDHOST_FLAG_STREAM_COLLECTED_METRICS);
934 + //}
935 +
936 continue;
937 }
938
939 // If the TCP window never opened then something is wrong, restart connection
940 if(unlikely(now_monotonic_sec() - s->last_sent_t > s->timeout)) {
941 worker_is_busy(WORKER_SENDER_JOB_DISCONNECT_TIMEOUT);
837 - error("STREAM %s [send to %s]: could not send metrics for %d seconds - closing connection - we have sent %zu bytes on this connection via %zu send attempts.", s->host->hostname, s->connected_to, s->timeout, s->sent_bytes_on_this_connection, s->send_attempts);
942 + error("STREAM %s [send to %s]: could not send metrics for %d seconds - closing connection - we have sent %zu bytes on this connection via %zu send attempts.", rrdhost_hostname(s->host), s->connected_to, s->timeout, s->sent_bytes_on_this_connection, s->send_attempts);
943 rrdpush_sender_thread_close_socket(s->host);
944 continue;
945 }
946
947 + if(unlikely(thread_data->sending_definitions_status != SENDING_DEFINITIONS_DONE))
948 + rrdpush_queue_incremental_definitions(thread_data);
949 +
950 worker_is_idle();
951
952 // Wait until buffer opens in the socket or a rrdset_done_push wakes us
@@ -847,16 +955,27 @@ void *rrdpush_sender_thread(void *ptr) {
955 fds[Socket].fd = s->host->rrdpush_sender_socket;
956
957 netdata_mutex_lock(&s->mutex);
850 - char *chunk;
851 - size_t outstanding = cbuffer_next_unsafe(s->host->sender->buffer, &chunk);
852 - chunk = NULL; // Do not cache pointer outside of region - could be invalidated
958 + size_t outstanding = cbuffer_next_unsafe(s->host->sender->buffer, NULL);
959 + size_t available = cbuffer_available_size_unsafe(s->host->sender->buffer);
960 netdata_mutex_unlock(&s->mutex);
961 +
962 + worker_set_metric(WORKER_SENDER_JOB_BUFFER_RATIO, (NETDATA_DOUBLE)(s->host->sender->buffer->max_size - available) * 100.0 / (NETDATA_DOUBLE)s->host->sender->buffer->max_size);
963 +
964 if(outstanding) {
965 s->send_attempts++;
966 fds[Socket].events = POLLIN | POLLOUT;
967 }
968 else {
969 fds[Socket].events = POLLIN;
970 +
971 + if(unlikely(thread_data->sending_definitions_status == SENDING_DEFINITIONS_DONE
972 + && __atomic_load_n(&s->host->rrdpush_sender_connected, __ATOMIC_SEQ_CST)
973 + && !rrdhost_flag_check(s->host, RRDHOST_FLAG_STREAM_COLLECTED_METRICS)
974 + )) {
975 + // let the data collection threads know we are ready to push metrics
976 + rrdhost_flag_set(s->host, RRDHOST_FLAG_STREAM_COLLECTED_METRICS);
977 + info("STREAM %s [send to %s]: enabling metrics streaming...", rrdhost_hostname(s->host), s->connected_to);
978 + }
979 }
980
981 int retval = poll(fds, 2, 1000);
@@ -874,7 +993,7 @@ void *rrdpush_sender_thread(void *ptr) {
993 // Only errors from poll() are internal, but try restarting the connection
994 if(unlikely(retval == -1)) {
995 worker_is_busy(WORKER_SENDER_JOB_DISCONNECT_POLL_ERROR);
877 - error("STREAM %s [send to %s]: failed to poll(). Closing socket.", s->host->hostname, s->connected_to);
996 + error("STREAM %s [send to %s]: failed to poll(). Closing socket.", rrdhost_hostname(s->host), s->connected_to);
997 rrdpush_sender_thread_close_socket(s->host);
998 continue;
999 }
@@ -884,28 +1003,34 @@ void *rrdpush_sender_thread(void *ptr) {
1003 worker_is_busy(WORKER_SENDER_JOB_PIPE_READ);
1004 debug(D_STREAM, "STREAM: Data added to send buffer (current buffer chunk %zu bytes)...", outstanding);
1005
887 - char buffer[1000 + 1];
888 - if (read(s->host->rrdpush_sender_pipe[PIPE_READ], buffer, 1000) == -1)
889 - error("STREAM %s [send to %s]: cannot read from internal pipe.", s->host->hostname, s->connected_to);
1006 + char buffer[10000 + 1];
1007 + if (read(s->host->rrdpush_sender_pipe[PIPE_READ], buffer, 10000) == -1)
1008 + error("STREAM %s [send to %s]: cannot read from internal pipe.", rrdhost_hostname(s->host), s->connected_to);
1009 }
1010
1011 // Read as much as possible to fill the buffer, split into full lines for execution.
1012 if (fds[Socket].revents & POLLIN) {
1013 worker_is_busy(WORKER_SENDER_JOB_SOCKET_RECEIVE);
895 - attempt_read(s);
1014 + ssize_t bytes = attempt_read(s);
1015 + if(bytes > 0)
1016 + worker_set_metric(WORKER_SENDER_JOB_BYTES_RECEIVED, bytes);
1017 }
1018
898 - worker_is_busy(WORKER_SENDER_JOB_EXECUTE);
899 - execute_commands(s);
1019 + if(unlikely(s->read_len)) {
1020 + worker_is_busy(WORKER_SENDER_JOB_EXECUTE);
1021 + execute_commands(s);
1022 + }
1023
1024 // If we have data and have seen the TCP window open then try to close it by a transmission.
902 - if (outstanding && fds[Socket].revents & POLLOUT) {
1025 + if(likely(outstanding && fds[Socket].revents & POLLOUT)) {
1026 worker_is_busy(WORKER_SENDER_JOB_SOCKET_SEND);
904 - attempt_to_send(s);
1027 + ssize_t bytes = attempt_to_send(s);
1028 + if(bytes > 0)
1029 + worker_set_metric(WORKER_SENDER_JOB_BYTES_SENT, bytes);
1030 }
1031
1032 // TODO-GAPS - why do we only check this on the socket, not the pipe?
908 - if (outstanding) {
1033 + if(outstanding) {
1034 char *error = NULL;
1035 if (unlikely(fds[Socket].revents & POLLERR))
1036 error = "socket reports errors (POLLERR)";
@@ -915,18 +1040,18 @@ void *rrdpush_sender_thread(void *ptr) {
1040 error = "connection is invalid (POLLNVAL)";
1041 if(unlikely(error)) {
1042 worker_is_busy(WORKER_SENDER_JOB_DISCONNECT_SOCKER_ERROR);
918 - error("STREAM %s [send to %s]: restart stream because %s - %zu bytes transmitted.", s->host->hostname,
1043 + error("STREAM %s [send to %s]: restart stream because %s - %zu bytes transmitted.", rrdhost_hostname(s->host),
1044 s->connected_to, error, s->sent_bytes_on_this_connection);
1045 rrdpush_sender_thread_close_socket(s->host);
1046 }
1047 }
1048
1049 // protection from overflow
925 - if (s->overflow) {
1050 + if(unlikely(s->overflow)) {
1051 worker_is_busy(WORKER_SENDER_JOB_DISCONNECT_OVERFLOW);
1052 errno = 0;
928 - error("STREAM %s [send to %s]: buffer full (%zu-bytes) after %zu bytes. Restarting connection",
929 - s->host->hostname, s->connected_to, s->buffer->size, s->sent_bytes_on_this_connection);
1053 + error("STREAM %s [send to %s]: buffer full (allocated %zu bytes) after sending %zu bytes. Restarting connection",
1054 + rrdhost_hostname(s->host), s->connected_to, s->buffer->size, s->sent_bytes_on_this_connection);
1055 rrdpush_sender_thread_close_socket(s->host);
1056 }
1057 }
web/api/badges/web_buffer_svg.c
+3 -3
@@ -1020,19 +1020,19 @@ int web_client_api_request_v1_badge(RRDHOST *host, struct web_client *w, char *u
1020 label = dim;
1021 }
1022 else
1023 - label = st->name;
1023 + label = rrdset_name(st);
1024 }
1025 if(!units) {
1026 if(alarm) {
1027 if(rc->units)
1028 - units = rc->units;
1028 + units = rrdcalc_units(rc);
1029 else
1030 units = "";
1031 }
1032 else if(options & RRDR_OPTION_PERCENTAGE)
1033 units = "%";
1034 else
1035 - units = st->units;
1035 + units = rrdset_units(st);
1036 }
1037
1038 debug(D_WEB_CLIENT, "%llu: API command 'badge.svg' for chart '%s', alarm '%s', dimensions '%s', after '%lld', before '%lld', points '%d', group '%d', options '0x%08x'"
web/api/exporters/shell/allmetrics_shell.c
+20 -20
@@ -30,14 +30,14 @@ void rrd_stats_api_v1_charts_allmetrics_shell(RRDHOST *host, const char *filter_
30 // for each chart
31 RRDSET *st;
32 rrdset_foreach_read(st, host) {
33 - if (filter && !simple_pattern_matches(filter, st->name))
33 + if (filter && !simple_pattern_matches(filter, rrdset_name(st)))
34 continue;
35
36 NETDATA_DOUBLE total = 0.0;
37 char chart[SHELL_ELEMENT_MAX + 1];
38 - shell_name_copy(chart, st->name?st->name:st->id, SHELL_ELEMENT_MAX);
38 + shell_name_copy(chart, st->name?rrdset_name(st):rrdset_id(st), SHELL_ELEMENT_MAX);
39
40 - buffer_sprintf(wb, "\n# chart: %s (name: %s)\n", st->id, st->name);
40 + buffer_sprintf(wb, "\n# chart: %s (name: %s)\n", rrdset_id(st), rrdset_name(st));
41 if(rrdset_is_available_for_viewers(st)) {
42 rrdset_rdlock(st);
43
@@ -46,23 +46,23 @@ void rrd_stats_api_v1_charts_allmetrics_shell(RRDHOST *host, const char *filter_
46 rrddim_foreach_read(rd, st) {
47 if(rd->collections_counter && !rrddim_flag_check(rd, RRDDIM_FLAG_OBSOLETE)) {
48 char dimension[SHELL_ELEMENT_MAX + 1];
49 - shell_name_copy(dimension, rd->name?rd->name:rd->id, SHELL_ELEMENT_MAX);
49 + shell_name_copy(dimension, rd->name?rrddim_name(rd):rrddim_id(rd), SHELL_ELEMENT_MAX);
50
51 NETDATA_DOUBLE n = rd->last_stored_value;
52
53 if(isnan(n) || isinf(n))
54 - buffer_sprintf(wb, "NETDATA_%s_%s=\"\" # %s\n", chart, dimension, st->units);
54 + buffer_sprintf(wb, "NETDATA_%s_%s=\"\" # %s\n", chart, dimension, rrdset_units(st));
55 else {
56 if(rd->multiplier < 0 || rd->divisor < 0) n = -n;
57 n = roundndd(n);
58 if(!rrddim_flag_check(rd, RRDDIM_FLAG_HIDDEN)) total += n;
59 - buffer_sprintf(wb, "NETDATA_%s_%s=\"" NETDATA_DOUBLE_FORMAT_ZERO "\" # %s\n", chart, dimension, n, st->units);
59 + buffer_sprintf(wb, "NETDATA_%s_%s=\"" NETDATA_DOUBLE_FORMAT_ZERO "\" # %s\n", chart, dimension, n, rrdset_units(st));
60 }
61 }
62 }
63
64 total = roundndd(total);
65 - buffer_sprintf(wb, "NETDATA_%s_VISIBLETOTAL=\"" NETDATA_DOUBLE_FORMAT_ZERO "\" # %s\n", chart, total, st->units);
65 + buffer_sprintf(wb, "NETDATA_%s_VISIBLETOTAL=\"" NETDATA_DOUBLE_FORMAT_ZERO "\" # %s\n", chart, total, rrdset_units(st));
66 rrdset_unlock(st);
67 }
68 }
@@ -70,22 +70,22 @@ void rrd_stats_api_v1_charts_allmetrics_shell(RRDHOST *host, const char *filter_
70 buffer_strcat(wb, "\n# NETDATA ALARMS RUNNING\n");
71
72 RRDCALC *rc;
73 - for(rc = host->alarms; rc ;rc = rc->next) {
73 + foreach_rrdcalc_in_rrdhost(host, rc) {
74 if(!rc->rrdset) continue;
75
76 char chart[SHELL_ELEMENT_MAX + 1];
77 - shell_name_copy(chart, rc->rrdset->name?rc->rrdset->name:rc->rrdset->id, SHELL_ELEMENT_MAX);
77 + shell_name_copy(chart, rc->rrdset->name?rrdset_name(rc->rrdset):rrdset_id(rc->rrdset), SHELL_ELEMENT_MAX);
78
79 char alarm[SHELL_ELEMENT_MAX + 1];
80 - shell_name_copy(alarm, rc->name, SHELL_ELEMENT_MAX);
80 + shell_name_copy(alarm, rrdcalc_name(rc), SHELL_ELEMENT_MAX);
81
82 NETDATA_DOUBLE n = rc->value;
83
84 if(isnan(n) || isinf(n))
85 - buffer_sprintf(wb, "NETDATA_ALARM_%s_%s_VALUE=\"\" # %s\n", chart, alarm, rc->units);
85 + buffer_sprintf(wb, "NETDATA_ALARM_%s_%s_VALUE=\"\" # %s\n", chart, alarm, rrdcalc_units(rc));
86 else {
87 n = roundndd(n);
88 - buffer_sprintf(wb, "NETDATA_ALARM_%s_%s_VALUE=\"" NETDATA_DOUBLE_FORMAT_ZERO "\" # %s\n", chart, alarm, n, rc->units);
88 + buffer_sprintf(wb, "NETDATA_ALARM_%s_%s_VALUE=\"" NETDATA_DOUBLE_FORMAT_ZERO "\" # %s\n", chart, alarm, n, rrdcalc_units(rc));
89 }
90
91 buffer_sprintf(wb, "NETDATA_ALARM_%s_%s_STATUS=\"%s\"\n", chart, alarm, rrdcalc_status2string(rc->status));
@@ -110,7 +110,7 @@ void rrd_stats_api_v1_charts_allmetrics_json(RRDHOST *host, const char *filter_s
110 // for each chart
111 RRDSET *st;
112 rrdset_foreach_read(st, host) {
113 - if (filter && !(simple_pattern_matches(filter, st->id) || simple_pattern_matches(filter, st->name)))
113 + if (filter && !(simple_pattern_matches(filter, rrdset_id(st)) || simple_pattern_matches(filter, rrdset_name(st))))
114 continue;
115
116 if(rrdset_is_available_for_viewers(st)) {
@@ -127,11 +127,11 @@ void rrd_stats_api_v1_charts_allmetrics_json(RRDHOST *host, const char *filter_s
127 "\t\t\"last_updated\": %"PRId64",\n"
128 "\t\t\"dimensions\": {",
129 chart_counter ? "," : "",
130 - st->id,
131 - st->name,
132 - st->family,
133 - st->context,
134 - st->units,
130 + rrdset_id(st),
131 + rrdset_name(st),
132 + rrdset_family(st),
133 + rrdset_context(st),
134 + rrdset_units(st),
135 (int64_t)rrdset_last_entry_t_nolock(st));
136
137 chart_counter++;
@@ -148,8 +148,8 @@ void rrd_stats_api_v1_charts_allmetrics_json(RRDHOST *host, const char *filter_s
148 "\t\t\t\t\"name\": \"%s\",\n"
149 "\t\t\t\t\"value\": ",
150 dimension_counter ? "," : "",
151 - rd->id,
152 - rd->name);
151 + rrddim_id(rd),
152 + rrddim_name(rd));
153
154 if(isnan(rd->last_stored_value))
155 buffer_strcat(wb, "null");
web/api/formatters/charts2json.c
+12 -12
@@ -57,11 +57,11 @@ void charts2json(RRDHOST *host, BUFFER *wb, int skip_volatile, int show_archived
57 ",\n\t\"memory_mode\": \"%s\""
58 ",\n\t\"custom_info\": \"%s\""
59 ",\n\t\"charts\": {"
60 - , host->hostname
61 - , host->program_version
60 + , rrdhost_hostname(host)
61 + , rrdhost_program_version(host)
62 , get_release_channel()
63 - , host->os
64 - , host->timezone
63 + , rrdhost_os(host)
64 + , rrdhost_timezone(host)
65 , host->rrd_update_every
66 , host->rrd_history_entries
67 , rrd_memory_mode_name(host->rrd_memory_mode)
@@ -74,7 +74,7 @@ void charts2json(RRDHOST *host, BUFFER *wb, int skip_volatile, int show_archived
74 if ((!show_archived && rrdset_is_available_for_viewers(st)) || (show_archived && rrdset_is_archived(st))) {
75 if(c) buffer_strcat(wb, ",");
76 buffer_strcat(wb, "\n\t\t\"");
77 - buffer_strcat(wb, st->id);
77 + buffer_strcat(wb, rrdset_id(st));
78 buffer_strcat(wb, "\": ");
79 rrdset2json(st, wb, &dimensions, &memory, skip_volatile);
80
@@ -84,7 +84,7 @@ void charts2json(RRDHOST *host, BUFFER *wb, int skip_volatile, int show_archived
84 }
85
86 RRDCALC *rc;
87 - for(rc = host->alarms; rc ; rc = rc->next) {
87 + foreach_rrdcalc_in_rrdhost(host, rc) {
88 if(rc->rrdset)
89 alarms++;
90 }
@@ -117,7 +117,7 @@ void charts2json(RRDHOST *host, BUFFER *wb, int skip_volatile, int show_archived
117 "\n\t\t\t\"hostname\": \"%s\""
118 "\n\t\t}"
119 , (found > 0) ? "," : ""
120 - , h->hostname
120 + , rrdhost_hostname(h)
121 );
122
123 found++;
@@ -131,7 +131,7 @@ void charts2json(RRDHOST *host, BUFFER *wb, int skip_volatile, int show_archived
131 , "\n\t\t{"
132 "\n\t\t\t\"hostname\": \"%s\""
133 "\n\t\t}"
134 - , host->hostname
134 + , rrdhost_hostname(host)
135 );
136 }
137
@@ -141,8 +141,8 @@ void charts2json(RRDHOST *host, BUFFER *wb, int skip_volatile, int show_archived
141 // generate collectors list for the api/v1/info call
142
143 struct collector {
144 - char *plugin;
145 - char *module;
144 + const char *plugin;
145 + const char *module;
146 };
147
148 struct array_printer {
@@ -176,8 +176,8 @@ void chartcollectors2json(RRDHOST *host, BUFFER *wb) {
176 rrdset_foreach_read(st, host) {
177 if (rrdset_is_available_for_viewers(st)) {
178 struct collector col = {
179 - .plugin = st->plugin_name ? st->plugin_name : "",
180 - .module = st->module_name ? st->module_name : ""
179 + .plugin = rrdset_plugin_name(st),
180 + .module = rrdset_module_name(st)
181 };
182 sprintf(name, "%s:%s", col.plugin, col.module);
183 dictionary_set(dict, name, &col, sizeof(struct collector));
web/api/formatters/csv/csv.c
+1 -1
@@ -23,7 +23,7 @@ void rrdr2csv(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS options, const
23 }
24 buffer_strcat(wb, separator);
25 if(options & RRDR_OPTION_LABEL_QUOTES) buffer_strcat(wb, "\"");
26 - buffer_strcat(wb, d->name);
26 + buffer_strcat(wb, rrddim_name(d));
27 if(options & RRDR_OPTION_LABEL_QUOTES) buffer_strcat(wb, "\"");
28 i++;
29 }
web/api/formatters/json/json.c
+2 -2
@@ -121,7 +121,7 @@ void rrdr2json(RRDR *r, BUFFER *wb, RRDR_OPTIONS options, int datatable, struct
121 if(unlikely((options & RRDR_OPTION_NONZERO) && !(r->od[c] & RRDR_DIMENSION_NONZERO))) continue;
122
123 buffer_fast_strcat(wb, pre_label, pre_label_len);
124 - buffer_strcat(wb, rd->name);
124 + buffer_strcat(wb, rrddim_name(rd));
125 // buffer_strcat(wb, ".");
126 // buffer_strcat(wb, rd->rrdset->name);
127 buffer_fast_strcat(wb, post_label, post_label_len);
@@ -253,7 +253,7 @@ void rrdr2json(RRDR *r, BUFFER *wb, RRDR_OPTIONS options, int datatable, struct
253 buffer_fast_strcat(wb, pre_value, pre_value_len);
254
255 if(unlikely( options & RRDR_OPTION_OBJECTSROWS ))
256 - buffer_sprintf(wb, "%s%s%s: ", kq, rd->name, kq);
256 + buffer_sprintf(wb, "%s%s%s: ", kq, rrddim_name(rd), kq);
257
258 if(co[c] & RRDR_VALUE_EMPTY && !(options & RRDR_OPTION_INTERNAL_AR)) {
259 if(unlikely(options & RRDR_OPTION_NULL2ZERO))
web/api/formatters/json_wrapper.c
+10 -10
@@ -79,8 +79,8 @@ void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS
79 " %sgroup%s: %s%s%s,\n"
80 " %soptions%s: %s"
81 , kq, kq
82 - , kq, kq, sq, context_mode && temp_rd?r->st->context:r->st->id, sq
83 - , kq, kq, sq, context_mode && temp_rd?r->st->context:r->st->name, sq
82 + , kq, kq, sq, context_mode && temp_rd?rrdset_context(r->st):rrdset_id(r->st), sq
83 + , kq, kq, sq, context_mode && temp_rd?rrdset_context(r->st):rrdset_name(r->st), sq
84 , kq, kq, r->update_every
85 , kq, kq, r->st->update_every
86 , kq, kq, (uint32_t) (context_param_list ? context_param_list->first_entry_t : rrdset_first_entry_t_nolock(r->st))
@@ -103,13 +103,13 @@ void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS
103
104 if(i) buffer_strcat(wb, ", ");
105 buffer_strcat(wb, sq);
106 - buffer_strcat(wb, rd->name);
106 + buffer_strcat(wb, rrddim_name(rd));
107 buffer_strcat(wb, sq);
108 i++;
109 }
110 if(!i) {
111 #ifdef NETDATA_INTERNAL_CHECKS
112 - error("RRDR is empty for %s (RRDR has %d dimensions, options is 0x%08x)", r->st->id, r->d, options);
112 + error("RRDR is empty for %s (RRDR has %d dimensions, options is 0x%08x)", rrdset_id(r->st), r->d, options);
113 #endif
114 rows = 0;
115 buffer_strcat(wb, sq);
@@ -127,7 +127,7 @@ void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS
127
128 if(i) buffer_strcat(wb, ", ");
129 buffer_strcat(wb, sq);
130 - buffer_strcat(wb, rd->id);
130 + buffer_strcat(wb, rrddim_id(rd));
131 buffer_strcat(wb, sq);
132 i++;
133 }
@@ -149,8 +149,8 @@ void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS
149
150 DICTIONARY *dict = dictionary_create(DICTIONARY_FLAG_SINGLE_THREADED);
151 for (i = 0, rd = temp_rd ? temp_rd : r->st->dimensions; rd; rd = rd->next) {
152 - snprintfz(name, RRD_ID_LENGTH_MAX * 2, "%s:%s", rd->id, rd->name);
153 - int len = snprintfz(output, RRD_ID_LENGTH_MAX * 2 + 7, "[\"%s\",\"%s\"]", rd->id, rd->name);
152 + snprintfz(name, RRD_ID_LENGTH_MAX * 2, "%s:%s", rrddim_id(rd), rrddim_name(rd));
153 + int len = snprintfz(output, RRD_ID_LENGTH_MAX * 2 + 7, "[\"%s\",\"%s\"]", rrddim_id(rd), rrddim_name(rd));
154 dictionary_set(dict, name, output, len+1);
155 }
156 dictionary_walkthrough_read(dict, value_list_output, &co);
@@ -160,8 +160,8 @@ void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS
160 buffer_sprintf(wb, "],\n %sfull_chart_list%s: [", kq, kq);
161 dict = dictionary_create(DICTIONARY_FLAG_SINGLE_THREADED);
162 for (i = 0, rd = temp_rd ? temp_rd : r->st->dimensions; rd; rd = rd->next) {
163 - int len = snprintfz(output, RRD_ID_LENGTH_MAX * 2 + 7, "[\"%s\",\"%s\"]", rd->rrdset->id, rd->rrdset->name);
164 - snprintfz(name, RRD_ID_LENGTH_MAX * 2, "%s:%s", rd->rrdset->id, rd->rrdset->name);
163 + int len = snprintfz(output, RRD_ID_LENGTH_MAX * 2 + 7, "[\"%s\",\"%s\"]", rrdset_id(rd->rrdset), rrdset_name(rd->rrdset));
164 + snprintfz(name, RRD_ID_LENGTH_MAX * 2, "%s:%s", rrdset_id(rd->rrdset), rrdset_name(rd->rrdset));
165 dictionary_set(dict, name, output, len + 1);
166 }
167
@@ -198,7 +198,7 @@ void rrdr_json_wrapper_begin(RRDR *r, BUFFER *wb, uint32_t format, RRDR_OPTIONS
198 if (i)
199 buffer_strcat(wb, ", ");
200 buffer_strcat(wb, sq);
201 - buffer_strcat(wb, rd->rrdset->id);
201 + buffer_strcat(wb, rrdset_id(rd->rrdset));
202 buffer_strcat(wb, sq);
203 i++;
204 }
web/api/formatters/rrd2json.c
+7 -5
@@ -8,13 +8,15 @@ static inline void free_single_rrdrim(ONEWAYALLOC *owa, RRDDIM *temp_rd, int arc
8 if (unlikely(!temp_rd))
9 return;
10
11 - onewayalloc_freez(owa, (char *)temp_rd->id);
11 + string_freez(temp_rd->id);
12 + string_freez(temp_rd->name);
13
14 if (unlikely(archive_mode)) {
15 temp_rd->rrdset->counter--;
16 if (!temp_rd->rrdset->counter) {
16 - onewayalloc_freez(owa, (char *)temp_rd->rrdset->name);
17 - onewayalloc_freez(owa, temp_rd->rrdset->context);
17 + string_freez(temp_rd->rrdset->id);
18 + string_freez(temp_rd->rrdset->name);
19 + string_freez(temp_rd->rrdset->context);
20 onewayalloc_freez(owa, temp_rd->rrdset);
21 }
22 }
@@ -111,8 +113,8 @@ void build_context_param_list(ONEWAYALLOC *owa, struct context_param **param_lis
113
114 rrddim_foreach_read(rd1, st) {
115 RRDDIM *rd = onewayalloc_memdupz(owa, rd1, sizeof(RRDDIM));
114 - rd->id = onewayalloc_strdupz(owa, rd1->id);
115 - rd->name = onewayalloc_strdupz(owa, rd1->name);
116 + rd->id = string_dup(rd1->id);
117 + rd->name = string_dup(rd1->name);
118 for(int tier = 0; tier < storage_tiers ;tier++) {
119 if(rd1->tiers[tier])
120 rd->tiers[tier] = onewayalloc_memdupz(owa, rd1->tiers[tier], sizeof(*rd->tiers[tier]));
web/api/formatters/rrdset2json.c
+15 -15
@@ -45,18 +45,18 @@ void rrdset2json(RRDSET *st, BUFFER *wb, size_t *dimensions_count, size_t *memor
45 "\t\t\t\"units\": \"%s\",\n"
46 "\t\t\t\"data_url\": \"/api/v1/data?chart=%s\",\n"
47 "\t\t\t\"chart_type\": \"%s\",\n",
48 - st->id,
49 - st->name,
50 - st->type,
51 - st->family,
52 - st->context,
53 - st->title,
54 - st->name,
48 + rrdset_id(st),
49 + rrdset_name(st),
50 + rrdset_type(st),
51 + rrdset_family(st),
52 + rrdset_context(st),
53 + rrdset_title(st),
54 + rrdset_name(st),
55 st->priority,
56 - st->plugin_name ? st->plugin_name : "",
57 - st->module_name ? st->module_name : "",
58 - st->units,
59 - st->name,
56 + rrdset_plugin_name(st),
57 + rrdset_module_name(st),
58 + rrdset_units(st),
59 + rrdset_name(st),
60 rrdset_type_name(st->chart_type));
61
62 if (likely(!skip_volatile))
@@ -98,9 +98,9 @@ void rrdset2json(RRDSET *st, BUFFER *wb, size_t *dimensions_count, size_t *memor
98 buffer_strcat(wb, ",\n\t\t\t\t\"");
99 else
100 buffer_strcat(wb, "\t\t\t\t\"");
101 - buffer_strcat_jsonescape(wb, rd->id);
101 + buffer_strcat_jsonescape(wb, rrddim_id(rd));
102 buffer_strcat(wb, "\": { \"name\": \"");
103 - buffer_strcat_jsonescape(wb, rd->name);
103 + buffer_strcat_jsonescape(wb, rrddim_name(rd));
104 buffer_strcat(wb, "\" }");
105
106 dimensions++;
@@ -121,7 +121,7 @@ void rrdset2json(RRDSET *st, BUFFER *wb, size_t *dimensions_count, size_t *memor
121 buffer_strcat(wb, ",\n\t\t\t\"alarms\": {\n");
122 size_t alarms = 0;
123 RRDCALC *rc;
124 - for (rc = st->alarms; rc; rc = rc->rrdset_next) {
124 + foreach_rrdcalc_in_rrdset(st, rc) {
125 buffer_sprintf(
126 wb,
127 "%s"
@@ -131,7 +131,7 @@ void rrdset2json(RRDSET *st, BUFFER *wb, size_t *dimensions_count, size_t *memor
131 "\t\t\t\t\t\"units\": \"%s\",\n"
132 "\t\t\t\t\t\"update_every\": %d\n"
133 "\t\t\t\t}",
134 - (alarms) ? ",\n" : "", rc->name, rc->id, rrdcalc_status2string(rc->status), rc->units,
134 + (alarms) ? ",\n" : "", rrdcalc_name(rc), rc->id, rrdcalc_status2string(rc->status), rrdcalc_units(rc),
135 rc->update_every);
136
137 alarms++;
web/api/queries/query.c
+25 -26
@@ -665,11 +665,11 @@ static void rrdr_disable_not_selected_dimensions(RRDR *r, RRDR_OPTIONS options,
665 RRDDIM *temp_rd = context_param_list ? context_param_list->rd : NULL;
666 int should_lock = (!context_param_list || !(context_param_list->flags & CONTEXT_FLAGS_ARCHIVE));
667
668 + if(unlikely(!dims || !*dims || (dims[0] == '*' && dims[1] == '\0'))) return;
669 +
670 if (should_lock)
671 rrdset_check_rdlock(r->st);
672
671 - if(unlikely(!dims || !*dims || (dims[0] == '*' && dims[1] == '\0'))) return;
672 -
673 int match_ids = 0, match_names = 0;
674
675 if(unlikely(options & RRDR_OPTION_MATCH_IDS))
@@ -685,8 +685,8 @@ static void rrdr_disable_not_selected_dimensions(RRDR *r, RRDR_OPTIONS options,
685 RRDDIM *d;
686 long c, dims_selected = 0, dims_not_hidden_not_zero = 0;
687 for(c = 0, d = temp_rd?temp_rd:r->st->dimensions; d ;c++, d = d->next) {
688 - if( (match_ids && simple_pattern_matches(pattern, d->id))
689 - || (match_names && simple_pattern_matches(pattern, d->name))
688 + if( (match_ids && simple_pattern_matches(pattern, rrddim_id(d)))
689 + || (match_names && simple_pattern_matches(pattern, rrddim_name(d)))
690 ) {
691 r->od[c] |= RRDR_DIMENSION_SELECTED;
692 if(unlikely(r->od[c] & RRDR_DIMENSION_HIDDEN)) r->od[c] &= ~RRDR_DIMENSION_HIDDEN;
@@ -738,11 +738,11 @@ static inline long rrdr_line_init(RRDR *r, time_t t, long rrdr_line) {
738
739 internal_error(rrdr_line >= r->n,
740 "QUERY: requested to step above RRDR size for chart '%s'",
741 - r->st->name);
741 + rrdset_name(r->st));
742
743 internal_error(r->t[rrdr_line] != 0 && r->t[rrdr_line] != t,
744 "QUERY: overwriting the timestamp of RRDR line %zu from %zu to %zu, of chart '%s'",
745 - (size_t)rrdr_line, (size_t)r->t[rrdr_line], (size_t)t, r->st->name);
745 + (size_t)rrdr_line, (size_t)r->t[rrdr_line], (size_t)t, rrdset_name(r->st));
746
747 // save the time
748 r->t[rrdr_line] = t;
@@ -768,7 +768,7 @@ static int rrddim_find_best_tier_for_timeframe(RRDDIM *rd, time_t after_wanted,
768 internal_error(true, "QUERY: NULL dimension - invalid params to tier calculation");
769 else
770 internal_error(true, "QUERY: chart '%s' dimension '%s' invalid params to tier calculation",
771 - (rd->rrdset)?rd->rrdset->name:"unknown", rd->name);
771 + (rd->rrdset)?rrdset_name(rd->rrdset):"unknown", rrddim_name(rd));
772
773 return 0;
774 }
@@ -782,7 +782,7 @@ static int rrddim_find_best_tier_for_timeframe(RRDDIM *rd, time_t after_wanted,
782 for(int tier = 0; tier < storage_tiers ; tier++) {
783 if(unlikely(!rd->tiers[tier])) {
784 internal_error(true, "QUERY: tier %d of chart '%s' dimension '%s' not initialized",
785 - tier, rd->rrdset->name, rd->name);
785 + tier, rrdset_name(rd->rrdset), rrddim_name(rd));
786 // buffer_free(wb);
787 return 0;
788 }
@@ -799,7 +799,7 @@ static int rrddim_find_best_tier_for_timeframe(RRDDIM *rd, time_t after_wanted,
799 int update_every = (int)rd->tiers[tier]->tier_grouping * (int)rd->update_every;
800 if(unlikely(update_every == 0)) {
801 internal_error(true, "QUERY: update_every of tier %d for chart '%s' dimension '%s' is zero. tg = %d, ue = %d",
802 - tier, rd->rrdset->name, rd->name, rd->tiers[tier]->tier_grouping, rd->update_every);
802 + tier, rrdset_name(rd->rrdset), rrddim_name(rd), rd->tiers[tier]->tier_grouping, rd->update_every);
803 // buffer_free(wb);
804 return 0;
805 }
@@ -851,7 +851,7 @@ static int rrdset_find_natural_update_every_for_timeframe(RRDSET *st, time_t aft
851 if(!st->dimensions->tiers[best_tier]) {
852 internal_error(
853 true,
854 - "QUERY: tier %d on chart '%s', is not initialized", best_tier, st->name);
854 + "QUERY: tier %d on chart '%s', is not initialized", best_tier, rrdset_name(st));
855 }
856 else {
857 ret = (int)st->dimensions->tiers[best_tier]->tier_grouping * (int)st->update_every;
@@ -859,7 +859,7 @@ static int rrdset_find_natural_update_every_for_timeframe(RRDSET *st, time_t aft
859 internal_error(
860 true,
861 "QUERY: update_every calculated to be zero on chart '%s', tier_grouping %d, update_every %d",
862 - st->name, st->dimensions->tiers[best_tier]->tier_grouping, st->update_every);
862 + rrdset_name(st), st->dimensions->tiers[best_tier]->tier_grouping, st->update_every);
863
864 ret = st->update_every;
865 }
@@ -1259,7 +1259,7 @@ static inline void rrd2rrdr_do_dimension(
1259 // check if the db is giving us zero duration points
1260 if(unlikely(new_point.start_time == new_point.end_time)) {
1261 internal_error(true, "QUERY: next_metric(%s, %s) returned point %zu start time %ld, end time %ld, that are both equal",
1262 - rd->rrdset->name, rd->name, new_point.id, new_point.start_time, new_point.end_time);
1262 + rrdset_name(rd->rrdset), rrddim_name(rd), new_point.id, new_point.start_time, new_point.end_time);
1263
1264 new_point.start_time = new_point.end_time - ((time_t)ops.tier_ptr->tier_grouping * (time_t)ops.rd->update_every);
1265 }
@@ -1267,7 +1267,7 @@ static inline void rrd2rrdr_do_dimension(
1267 // check if the db is advancing the query
1268 if(unlikely(new_point.end_time <= last1_point.end_time)) {
1269 internal_error(true, "QUERY: next_metric(%s, %s) returned point %zu from %ld time %ld, before the last point %zu end time %ld, now is %ld to %ld",
1270 - rd->rrdset->name, rd->name, new_point.id, new_point.start_time, new_point.end_time,
1270 + rrdset_name(rd->rrdset), rrddim_name(rd), new_point.id, new_point.start_time, new_point.end_time,
1271 last1_point.id, last1_point.end_time, now_start_time, now_end_time);
1272
1273 count_same_end_time++;
@@ -1295,7 +1295,7 @@ static inline void rrd2rrdr_do_dimension(
1295 // we only log if this is not point 1
1296 internal_error(new_point.end_time < after_wanted && new_point.id > 1,
1297 "QUERY: next_metric(%s, %s) returned point %zu from %ld time %ld, which is entirely before our current timeframe %ld to %ld (and before the entire query, after %ld, before %ld)",
1298 - rd->rrdset->name, rd->name,
1298 + rrdset_name(rd->rrdset), rrddim_name(rd),
1299 new_point.id, new_point.start_time, new_point.end_time,
1300 now_start_time, now_end_time,
1301 after_wanted, before_wanted);
@@ -1339,7 +1339,7 @@ static inline void rrd2rrdr_do_dimension(
1339 internal_error(current_point.id > 0 && last1_point.id == 0 && current_point.end_time > after_wanted && current_point.end_time > now_end_time,
1340 "QUERY: on '%s', dim '%s', after %ld, before %ld, view update every %ld, query granularity %ld,"
1341 " interpolating point %zu (from %ld to %ld) at %ld, but we could really favor by having last_point1 in this query.",
1342 - rd->rrdset->name, rd->name, after_wanted, before_wanted, ops.view_update_every, ops.query_granularity,
1342 + rrdset_name(rd->rrdset), rrddim_name(rd), after_wanted, before_wanted, ops.view_update_every, ops.query_granularity,
1343 current_point.id, current_point.start_time, current_point.end_time, now_end_time);
1344 }
1345 else if(likely(now_end_time <= last1_point.end_time)) {
@@ -1350,7 +1350,7 @@ static inline void rrd2rrdr_do_dimension(
1350 internal_error(current_point.id > 0 && last2_point.id == 0 && current_point.end_time > after_wanted && current_point.end_time > now_end_time,
1351 "QUERY: on '%s', dim '%s', after %ld, before %ld, view update every %ld, query granularity %ld,"
1352 " interpolating point %zu (from %ld to %ld) at %ld, but we could really favor by having last_point2 in this query.",
1353 - rd->rrdset->name, rd->name, after_wanted, before_wanted, ops.view_update_every, ops.query_granularity,
1353 + rrdset_name(rd->rrdset), rrddim_name(rd), after_wanted, before_wanted, ops.view_update_every, ops.query_granularity,
1354 current_point.id, current_point.start_time, current_point.end_time, now_end_time);
1355 }
1356 else {
@@ -1425,7 +1425,7 @@ static inline void rrd2rrdr_do_dimension(
1425
1426 internal_error((long)points_added != points_wanted,
1427 "QUERY: query on %s/%s requested %zu points, but RRDR added %zu (%zu db points read).",
1428 - r->st->name, rd->name, (size_t)points_wanted, (size_t)points_added, ops.db_total_points_read);
1428 + rrdset_name(r->st), rrddim_name(rd), (size_t)points_wanted, (size_t)points_added, ops.db_total_points_read);
1429 }
1430
1431 // ----------------------------------------------------------------------------
@@ -1518,7 +1518,7 @@ static void rrd2rrdr_log_request_response_metadata(RRDR *r
1518 //"slot (after: %zu, before: %zu, delta: %zu), "
1519 "points (got: %ld, want: %ld, req: %ld, db: %ld), "
1520 "%s"
1521 - , r->st->name
1521 + , rrdset_name(r->st)
1522 , r->st->update_every
1523
1524 // grouping
@@ -1733,7 +1733,7 @@ RRDR *rrd2rrdr(
1733 rrdset_unlock(st);
1734
1735 if(first_entry_t == 0 || last_entry_t == 0) {
1736 - internal_error(true, "QUERY: chart without data detected on '%s'", st->name);
1736 + internal_error(true, "QUERY: chart without data detected on '%s'", rrdset_name(st));
1737 query_debug_log_free();
1738 return NULL;
1739 }
@@ -1932,13 +1932,13 @@ RRDR *rrd2rrdr(
1932 RRDR *r = rrdr_create(owa, st, points_wanted, context_param_list);
1933 if(unlikely(!r)) {
1934 internal_error(true, "QUERY: cannot create RRDR for %s, after=%u, before=%u, duration=%u, points=%ld",
1935 - st->id, (uint32_t)after_wanted, (uint32_t)before_wanted, (uint32_t)duration, points_wanted);
1935 + rrdset_id(st), (uint32_t)after_wanted, (uint32_t)before_wanted, (uint32_t)duration, points_wanted);
1936 return NULL;
1937 }
1938
1939 if(unlikely(!r->d || !points_wanted)) {
1940 internal_error(true, "QUERY: returning empty RRDR (no dimensions in RRDSET) for %s, after=%u, before=%u, duration=%zu, points=%ld",
1941 - st->id, (uint32_t)after_wanted, (uint32_t)before_wanted, (size_t)duration, points_wanted);
1941 + rrdset_id(st), (uint32_t)after_wanted, (uint32_t)before_wanted, (size_t)duration, points_wanted);
1942 return r;
1943 }
1944
@@ -1977,10 +1977,9 @@ RRDR *rrd2rrdr(
1977 if (context_param_list && !(context_param_list->flags & CONTEXT_FLAGS_ARCHIVE))
1978 rrdset_check_rdlock(st);
1979
1980 - if(dimensions)
1980 + if(dimensions && *dimensions)
1981 rrdr_disable_not_selected_dimensions(r, options, dimensions, context_param_list);
1982
1983 -
1983 query_debug_log_fin();
1984
1985 // -------------------------------------------------------------------------
@@ -2024,21 +2023,21 @@ RRDR *rrd2rrdr(
2023 else {
2024 if(r->after != max_after) {
2025 internal_error(true, "QUERY: 'after' mismatch between dimensions for chart '%s': max is %zu, dimension '%s' has %zu",
2027 - st->name, (size_t)max_after, rd->name, (size_t)r->after);
2026 + rrdset_name(st), (size_t)max_after, rrddim_name(rd), (size_t)r->after);
2027
2028 r->after = (r->after > max_after) ? r->after : max_after;
2029 }
2030
2031 if(r->before != min_before) {
2032 internal_error(true, "QUERY: 'before' mismatch between dimensions for chart '%s': max is %zu, dimension '%s' has %zu",
2034 - st->name, (size_t)min_before, rd->name, (size_t)r->before);
2033 + rrdset_name(st), (size_t)min_before, rrddim_name(rd), (size_t)r->before);
2034
2035 r->before = (r->before < min_before) ? r->before : min_before;
2036 }
2037
2038 if(r->rows != max_rows) {
2039 internal_error(true, "QUERY: 'rows' mismatch between dimensions for chart '%s': max is %zu, dimension '%s' has %zu",
2041 - st->name, (size_t)max_rows, rd->name, (size_t)r->rows);
2040 + rrdset_name(st), (size_t)max_rows, rrddim_name(rd), (size_t)r->rows);
2041
2042 r->rows = (r->rows > max_rows) ? r->rows : max_rows;
2043 }
web/api/queries/weights.c
+18 -18
@@ -121,14 +121,14 @@ static void register_result(DICTIONARY *results,
121 struct register_result t = {
122 .flags = flags,
123 .st = st,
124 - .chart_id = st->id,
125 - .context = st->context,
126 - .dim_name = d->name,
124 + .chart_id = rrdset_id(st),
125 + .context = rrdset_context(st),
126 + .dim_name = rrddim_name(d),
127 .value = v
128 };
129
130 char buf[5000 + 1];
131 - snprintfz(buf, 5000, "%s:%s", st->id, d->name);
131 + snprintfz(buf, 5000, "%s:%s", rrdset_id(st), rrddim_name(d));
132 dictionary_set(results, buf, &t, sizeof(struct register_result));
133 }
134
@@ -541,7 +541,7 @@ static int rrdset_metric_correlations_ks2(RRDSET *st, DICTIONARY *results,
541 group_time, options, NULL, context_param_list, group_options,
542 timeout, tier);
543 if(!high_rrdr) {
544 - info("Metric correlations: rrd2rrdr() failed for the highlighted window on chart '%s'.", st->name);
544 + info("Metric correlations: rrd2rrdr() failed for the highlighted window on chart '%s'.", rrdset_name(st));
545 goto cleanup;
546 }
547
@@ -551,11 +551,11 @@ static int rrdset_metric_correlations_ks2(RRDSET *st, DICTIONARY *results,
551 stats->db_points += high_rrdr->internal.db_points_read;
552 stats->result_points += high_rrdr->internal.result_points_generated;
553 if(!high_rrdr->d) {
554 - info("Metric correlations: rrd2rrdr() did not return any dimensions on chart '%s'.", st->name);
554 + info("Metric correlations: rrd2rrdr() did not return any dimensions on chart '%s'.", rrdset_name(st));
555 goto cleanup;
556 }
557 if(high_rrdr->result_options & RRDR_RESULT_OPTION_CANCEL) {
558 - info("Metric correlations: rrd2rrdr() on highlighted window timed out '%s'.", st->name);
558 + info("Metric correlations: rrd2rrdr() on highlighted window timed out '%s'.", rrdset_name(st));
559 goto cleanup;
560 }
561 int high_points = rrdr_rows(high_rrdr);
@@ -571,7 +571,7 @@ static int rrdset_metric_correlations_ks2(RRDSET *st, DICTIONARY *results,
571 group_time, options, NULL, context_param_list, group_options,
572 (int)(timeout - ((now_usec - started_usec) / USEC_PER_MS)), tier);
573 if(!base_rrdr) {
574 - info("Metric correlations: rrd2rrdr() failed for the baseline window on chart '%s'.", st->name);
574 + info("Metric correlations: rrd2rrdr() failed for the baseline window on chart '%s'.", rrdset_name(st));
575 goto cleanup;
576 }
577
@@ -581,15 +581,15 @@ static int rrdset_metric_correlations_ks2(RRDSET *st, DICTIONARY *results,
581 stats->db_points += base_rrdr->internal.db_points_read;
582 stats->result_points += base_rrdr->internal.result_points_generated;
583 if(!base_rrdr->d) {
584 - info("Metric correlations: rrd2rrdr() did not return any dimensions on chart '%s'.", st->name);
584 + info("Metric correlations: rrd2rrdr() did not return any dimensions on chart '%s'.", rrdset_name(st));
585 goto cleanup;
586 }
587 if (base_rrdr->d != high_rrdr->d) {
588 - info("Cannot generate metric correlations for chart '%s' when the baseline and the highlight have different number of dimensions.", st->name);
588 + info("Cannot generate metric correlations for chart '%s' when the baseline and the highlight have different number of dimensions.", rrdset_name(st));
589 goto cleanup;
590 }
591 if(base_rrdr->result_options & RRDR_RESULT_OPTION_CANCEL) {
592 - info("Metric correlations: rrd2rrdr() on baseline window timed out '%s'.", st->name);
592 + info("Metric correlations: rrd2rrdr() on baseline window timed out '%s'.", rrdset_name(st));
593 goto cleanup;
594 }
595 int base_points = rrdr_rows(base_rrdr);
@@ -605,7 +605,7 @@ static int rrdset_metric_correlations_ks2(RRDSET *st, DICTIONARY *results,
605 // for each dimension
606 RRDDIM *d;
607 int i;
608 - for(i = 0, d = base_rrdr->st->dimensions ; d && i < base_rrdr->d; i++, d = d->next) {
608 + for(i = 0, d = base_rrdr->st->dimensions; d && i < base_rrdr->d; i++, d = d->next) {
609
610 // skip the not evaluated ones
611 if(unlikely(base_rrdr->od[i] & RRDR_DIMENSION_HIDDEN) || (high_rrdr->od[i] & RRDR_DIMENSION_HIDDEN))
@@ -692,7 +692,7 @@ static int rrdset_metric_correlations_volume(RRDSET *st, DICTIONARY *results,
692 NETDATA_DOUBLE baseline_average = NAN;
693 NETDATA_DOUBLE base_anomaly_rate = 0;
694 value_is_null = 1;
695 - ret = rrdset2value_api_v1(st, NULL, &baseline_average, d->id, 1,
695 + ret = rrdset2value_api_v1(st, NULL, &baseline_average, rrddim_id(d), 1,
696 baseline_after, baseline_before,
697 group, group_options, group_time, options,
698 NULL, NULL,
@@ -709,7 +709,7 @@ static int rrdset_metric_correlations_volume(RRDSET *st, DICTIONARY *results,
709 NETDATA_DOUBLE highlight_average = NAN;
710 NETDATA_DOUBLE high_anomaly_rate = 0;
711 value_is_null = 1;
712 - ret = rrdset2value_api_v1(st, NULL, &highlight_average, d->id, 1,
712 + ret = rrdset2value_api_v1(st, NULL, &highlight_average, rrddim_id(d), 1,
713 after, before,
714 group, group_options, group_time, options,
715 NULL, NULL,
@@ -734,7 +734,7 @@ static int rrdset_metric_correlations_volume(RRDSET *st, DICTIONARY *results,
734 char highlighted_countif_options[50 + 1];
735 snprintfz(highlighted_countif_options, 50, "%s" NETDATA_DOUBLE_FORMAT, highlight_average < baseline_average ? "<":">", baseline_average);
736
737 - ret = rrdset2value_api_v1(st, NULL, &highlight_countif, d->id, 1,
737 + ret = rrdset2value_api_v1(st, NULL, &highlight_countif, rrddim_id(d), 1,
738 after, before,
739 RRDR_GROUPING_COUNTIF,highlighted_countif_options,
740 group_time, options,
@@ -803,7 +803,7 @@ static int rrdset_weights_anomaly_rate(RRDSET *st, DICTIONARY *results,
803 NETDATA_DOUBLE average = NAN;
804 NETDATA_DOUBLE anomaly_rate = 0;
805 value_is_null = 1;
806 - ret = rrdset2value_api_v1(st, NULL, &average, d->id, 1,
806 + ret = rrdset2value_api_v1(st, NULL, &average, rrddim_id(d), 1,
807 after, before,
808 group, group_options, group_time, options,
809 NULL, NULL,
@@ -1006,8 +1006,8 @@ int web_api_v1_weights(RRDHOST *host, BUFFER *wb, WEIGHTS_METHOD method, WEIGHTS
1006 rrdhost_rdlock(host);
1007 rrdset_foreach_read(st, host) {
1008 if (rrdset_is_available_for_viewers(st)) {
1009 - if(!contexts || simple_pattern_matches(contexts, st->context))
1010 - dictionary_set(charts, st->name, NULL, 0);
1009 + if(!contexts || simple_pattern_matches(contexts, rrdset_context(st)))
1010 + dictionary_set(charts, rrdset_name(st), NULL, 0);
1011 }
1012 }
1013 rrdhost_unlock(host);
web/api/web_api_v1.c
+7 -7
@@ -701,8 +701,6 @@ inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, c
701 if (context && !chart) {
702 RRDSET *st1;
703
704 - uint32_t context_hash = simple_hash(context);
705 -
704 SIMPLE_PATTERN *chart_label_key_pattern = NULL;
705 if(chart_label_key)
706 chart_label_key_pattern = simple_pattern_create(chart_label_key, ",|\t\r\n\f\v", SIMPLE_PATTERN_EXACT);
@@ -711,14 +709,16 @@ inline int web_client_api_request_v1_data(RRDHOST *host, struct web_client *w, c
709 if(chart_labels_filter)
710 chart_labels_filter_pattern = simple_pattern_create(chart_labels_filter, ",|\t\r\n\f\v", SIMPLE_PATTERN_EXACT);
711
712 + STRING *context_string = string_strdupz(context);
713 rrdhost_rdlock(host);
714 rrdset_foreach_read(st1, host) {
716 - if (st1->hash_context == context_hash && !strcmp(st1->context, context) &&
715 + if (st1->context == context_string &&
716 (!chart_label_key_pattern || rrdlabels_match_simple_pattern_parsed(st1->state->chart_labels, chart_label_key_pattern, ':')) &&
717 (!chart_labels_filter_pattern || rrdlabels_match_simple_pattern_parsed(st1->state->chart_labels, chart_labels_filter_pattern, ':')))
718 build_context_param_list(owa, &context_param_list, st1);
719 }
720 rrdhost_unlock(host);
721 + string_freez(context_string);
722
723 if (likely(context_param_list && context_param_list->rd)) // Just set the first one
724 st = context_param_list->rd->rrdset;
@@ -1055,7 +1055,7 @@ static inline void web_client_api_request_v1_info_summary_alarm_statuses(RRDHOST
1055 int alarm_normal = 0, alarm_warn = 0, alarm_crit = 0;
1056 RRDCALC *rc;
1057 rrdhost_rdlock(host);
1058 - for(rc = host->alarms; rc ; rc = rc->next) {
1058 + foreach_rrdcalc_in_rrdhost(host, rc) {
1059 if(unlikely(!rc->rrdset || !rc->rrdset->last_collected_time.tv_sec))
1060 continue;
1061
@@ -1086,7 +1086,7 @@ static inline void web_client_api_request_v1_info_mirrored_hosts(BUFFER *wb) {
1086 if (count > 0)
1087 buffer_strcat(wb, ",\n");
1088
1089 - buffer_sprintf(wb, "\t\t\"%s\"", host->hostname);
1089 + buffer_sprintf(wb, "\t\t\"%s\"", rrdhost_hostname(host));
1090 count++;
1091 }
1092
@@ -1101,7 +1101,7 @@ static inline void web_client_api_request_v1_info_mirrored_hosts(BUFFER *wb) {
1101 buffer_sprintf(
1102 wb, "\t\t{ \"guid\": \"%s\", \"hostname\": \"%s\", \"reachable\": %s, \"hops\": %d"
1103 , host->machine_guid
1104 - , host->hostname
1104 + , rrdhost_hostname(host)
1105 , (host->receiver || host == localhost) ? "true" : "false"
1106 , host->system_info ? host->system_info->hops : (host == localhost) ? 0 : 1
1107 );
@@ -1148,7 +1148,7 @@ extern int aclk_connected;
1148 inline int web_client_api_request_v1_info_fill_buffer(RRDHOST *host, BUFFER *wb)
1149 {
1150 buffer_strcat(wb, "{\n");
1151 - buffer_sprintf(wb, "\t\"version\": \"%s\",\n", host->program_version);
1151 + buffer_sprintf(wb, "\t\"version\": \"%s\",\n", rrdhost_program_version(host));
1152 buffer_sprintf(wb, "\t\"uid\": \"%s\",\n", host->machine_guid);
1153
1154 web_client_api_request_v1_info_mirrored_hosts(wb);
web/server/web_client.c
+2 -4
@@ -1305,11 +1305,9 @@ static inline int web_client_switch_host(RRDHOST *host, struct web_client *w, ch
1305 if(url && *url) strncpyz(&w->last_url[1], url, NETDATA_WEB_REQUEST_URL_SIZE - 1);
1306 else w->last_url[1] = '\0';
1307
1308 - uint32_t hash = simple_hash(tok);
1309 -
1310 - host = rrdhost_find_by_hostname(tok, hash);
1308 + host = rrdhost_find_by_hostname(tok);
1309 if (!host)
1312 - host = rrdhost_find_by_guid(tok, hash);
1310 + host = rrdhost_find_by_guid(tok);
1311 if (!host) {
1312 host = sql_create_host_by_uuid(tok);
1313 if (likely(host)) {