@cryptotaxi247 / netdata-1 / commits / e19a6cb6b

RRDHOSTs free all their memory (all substructures) when they are deallocated

Costa Tsaousis (ktsaou) committed Feb 19, 2017 at 17:39 UTC e19a6cb6bd31e175842dc4c3b61fd3fe78eeab2c
15 files changed +1244 -1116
CMakeLists.txt
+1 -1
@@ -124,7 +124,7 @@ set(NETDATA_SOURCE_FILES
124 src/web_client.h
125 src/web_server.c
126 src/web_server.h
127 - src/rrdhost.c src/rrdfamily.c src/rrdset.c src/rrddim.c src/health_log.c src/health_config.c src/health_json.c)
127 + src/rrdhost.c src/rrdfamily.c src/rrdset.c src/rrddim.c src/health_log.c src/health_config.c src/health_json.c src/rrdcalc.c src/rrdcalctemplate.c src/rrdvar.c src/rrddimvar.c src/rrdsetvar.c)
128
129 set(APPS_PLUGIN_SOURCE_FILES
130 src/appconfig.c
src/Makefile.am
+5
@@ -69,6 +69,11 @@ netdata_SOURCES = \
69 rrdfamily.c \
70 rrdhost.c \
71 rrdset.c \
72 + rrdcalc.c \
73 + rrdcalctemplate.c \
74 + rrdvar.c \
75 + rrddimvar.c \
76 + rrdsetvar.c \
77 rrd2json.c rrd2json.h \
78 storage_number.c storage_number.h \
79 unit_test.c unit_test.h \
src/health.c
+7 -1079
@@ -1,1068 +1,8 @@
1 #define NETDATA_HEALTH_INTERNALS
2 #include "common.h"
3
4 -#define RRDVAR_MAX_LENGTH 1024
5 -
4 int default_localhost_health_enabled = 1;
5
8 -// ----------------------------------------------------------------------------
9 -// RRDVAR management
10 -
11 -inline int rrdvar_fix_name(char *variable) {
12 - int fixed = 0;
13 - while(*variable) {
14 - if (!isalnum(*variable) && *variable != '.' && *variable != '_') {
15 - *variable++ = '_';
16 - fixed++;
17 - }
18 - else
19 - variable++;
20 - }
21 -
22 - return fixed;
23 -}
24 -
25 -int rrdvar_compare(void* a, void* b) {
26 - if(((RRDVAR *)a)->hash < ((RRDVAR *)b)->hash) return -1;
27 - else if(((RRDVAR *)a)->hash > ((RRDVAR *)b)->hash) return 1;
28 - else return strcmp(((RRDVAR *)a)->name, ((RRDVAR *)b)->name);
29 -}
30 -
31 -static inline RRDVAR *rrdvar_index_add(avl_tree_lock *tree, RRDVAR *rv) {
32 - RRDVAR *ret = (RRDVAR *)avl_insert_lock(tree, (avl *)(rv));
33 - if(ret != rv)
34 - debug(D_VARIABLES, "Request to insert RRDVAR '%s' into index failed. Already exists.", rv->name);
35 -
36 - return ret;
37 -}
38 -
39 -static inline RRDVAR *rrdvar_index_del(avl_tree_lock *tree, RRDVAR *rv) {
40 - RRDVAR *ret = (RRDVAR *)avl_remove_lock(tree, (avl *)(rv));
41 - if(!ret)
42 - error("Request to remove RRDVAR '%s' from index failed. Not Found.", rv->name);
43 -
44 - return ret;
45 -}
46 -
47 -static inline RRDVAR *rrdvar_index_find(avl_tree_lock *tree, const char *name, uint32_t hash) {
48 - RRDVAR tmp;
49 - tmp.name = (char *)name;
50 - tmp.hash = (hash)?hash:simple_hash(tmp.name);
51 -
52 - return (RRDVAR *)avl_search_lock(tree, (avl *)&tmp);
53 -}
54 -
55 -static inline void rrdvar_free(RRDHOST *host, avl_tree_lock *tree, RRDVAR *rv) {
56 - (void)host;
57 -
58 - if(!rv) return;
59 -
60 - if(tree) {
61 - debug(D_VARIABLES, "Deleting variable '%s'", rv->name);
62 - if(unlikely(!rrdvar_index_del(tree, rv)))
63 - error("Attempted to delete variable '%s' from host '%s', but it is not found.", rv->name, host->hostname);
64 - }
65 -
66 - freez(rv->name);
67 - freez(rv);
68 -}
69 -
70 -static inline RRDVAR *rrdvar_create_and_index(const char *scope, avl_tree_lock *tree, const char *name, int type, void *value) {
71 - char *variable = strdupz(name);
72 - rrdvar_fix_name(variable);
73 - uint32_t hash = simple_hash(variable);
74 -
75 - RRDVAR *rv = rrdvar_index_find(tree, variable, hash);
76 - if(unlikely(!rv)) {
77 - debug(D_VARIABLES, "Variable '%s' not found in scope '%s'. Creating a new one.", variable, scope);
78 -
79 - rv = callocz(1, sizeof(RRDVAR));
80 - rv->name = variable;
81 - rv->hash = hash;
82 - rv->type = type;
83 - rv->value = value;
84 -
85 - RRDVAR *ret = rrdvar_index_add(tree, rv);
86 - if(unlikely(ret != rv)) {
87 - debug(D_VARIABLES, "Variable '%s' in scope '%s' already exists", variable, scope);
88 - rrdvar_free(NULL, NULL, rv);
89 - rv = NULL;
90 - }
91 - else
92 - debug(D_VARIABLES, "Variable '%s' created in scope '%s'", variable, scope);
93 - }
94 - else {
95 - debug(D_VARIABLES, "Variable '%s' is already found in scope '%s'.", variable, scope);
96 -
97 - // already exists
98 - freez(variable);
99 -
100 - // this is important
101 - // it must return NULL - not the existing variable - or double-free will happen
102 - rv = NULL;
103 - }
104 -
105 - return rv;
106 -}
107 -
108 -// ----------------------------------------------------------------------------
109 -// CUSTOM VARIABLES
110 -
111 -RRDVAR *rrdvar_custom_host_variable_create(RRDHOST *host, const char *name) {
112 - calculated_number *v = callocz(1, sizeof(calculated_number));
113 - *v = NAN;
114 - RRDVAR *rv = rrdvar_create_and_index("host", &host->variables_root_index, name, RRDVAR_TYPE_CALCULATED_ALLOCATED, v);
115 - if(unlikely(!rv)) {
116 - free(v);
117 - error("Requested variable '%s' already exists - possibly 2 plugins will be updating it at the same time", name);
118 -
119 - char *variable = strdupz(name);
120 - rrdvar_fix_name(variable);
121 - uint32_t hash = simple_hash(variable);
122 -
123 - rv = rrdvar_index_find(&host->variables_root_index, variable, hash);
124 - }
125 -
126 - return rv;
127 -}
128 -
129 -void rrdvar_custom_host_variable_destroy(RRDHOST *host, const char *name) {
130 - char *variable = strdupz(name);
131 - rrdvar_fix_name(variable);
132 - uint32_t hash = simple_hash(variable);
133 -
134 - RRDVAR *rv = rrdvar_index_find(&host->variables_root_index, variable, hash);
135 - freez(variable);
136 -
137 - if(!rv) {
138 - error("Attempted to remove variable '%s' from host '%s', but it does not exist.", name, host->hostname);
139 - return;
140 - }
141 -
142 - if(rv->type != RRDVAR_TYPE_CALCULATED_ALLOCATED) {
143 - error("Attempted to remove variable '%s' from host '%s', but it does not a custom allocated variable.", name, host->hostname);
144 - return;
145 - }
146 -
147 - if(!rrdvar_index_del(&host->variables_root_index, rv)) {
148 - error("Attempted to remove variable '%s' from host '%s', but it cannot be found.", name, host->hostname);
149 - return;
150 - }
151 -
152 - freez(rv->name);
153 - freez(rv->value);
154 - freez(rv);
155 -}
156 -
157 -void rrdvar_custom_host_variable_set(RRDVAR *rv, calculated_number value) {
158 - if(rv->type != RRDVAR_TYPE_CALCULATED_ALLOCATED)
159 - error("requested to set variable '%s' to value " CALCULATED_NUMBER_FORMAT " but the variable is not a custom one.", rv->name, value);
160 - else {
161 - calculated_number *v = rv->value;
162 - *v = value;
163 - }
164 -}
165 -
166 -// ----------------------------------------------------------------------------
167 -// RRDVAR lookup
168 -
169 -static calculated_number rrdvar2number(RRDVAR *rv) {
170 - switch(rv->type) {
171 - case RRDVAR_TYPE_CALCULATED_ALLOCATED:
172 - case RRDVAR_TYPE_CALCULATED: {
173 - calculated_number *n = (calculated_number *)rv->value;
174 - return *n;
175 - }
176 -
177 - case RRDVAR_TYPE_TIME_T: {
178 - time_t *n = (time_t *)rv->value;
179 - return *n;
180 - }
181 -
182 - case RRDVAR_TYPE_COLLECTED: {
183 - collected_number *n = (collected_number *)rv->value;
184 - return *n;
185 - }
186 -
187 - case RRDVAR_TYPE_TOTAL: {
188 - total_number *n = (total_number *)rv->value;
189 - return *n;
190 - }
191 -
192 - case RRDVAR_TYPE_INT: {
193 - int *n = (int *)rv->value;
194 - return *n;
195 - }
196 -
197 - default:
198 - error("I don't know how to convert RRDVAR type %d to calculated_number", rv->type);
199 - return NAN;
200 - }
201 -}
202 -
203 -int health_variable_lookup(const char *variable, uint32_t hash, RRDCALC *rc, calculated_number *result) {
204 - RRDSET *st = rc->rrdset;
205 - RRDVAR *rv;
206 -
207 - if(!st) return 0;
208 -
209 - rv = rrdvar_index_find(&st->variables_root_index, variable, hash);
210 - if(rv) {
211 - *result = rrdvar2number(rv);
212 - return 1;
213 - }
214 -
215 - rv = rrdvar_index_find(&st->rrdfamily->variables_root_index, variable, hash);
216 - if(rv) {
217 - *result = rrdvar2number(rv);
218 - return 1;
219 - }
220 -
221 - rv = rrdvar_index_find(&st->rrdhost->variables_root_index, variable, hash);
222 - if(rv) {
223 - *result = rrdvar2number(rv);
224 - return 1;
225 - }
226 -
227 - return 0;
228 -}
229 -
230 -// ----------------------------------------------------------------------------
231 -// RRDVAR to JSON
232 -
233 -struct variable2json_helper {
234 - BUFFER *buf;
235 - size_t counter;
236 -};
237 -
238 -static int single_variable2json(void *entry, void *data) {
239 - struct variable2json_helper *helper = (struct variable2json_helper *)data;
240 - RRDVAR *rv = (RRDVAR *)entry;
241 - calculated_number value = rrdvar2number(rv);
242 -
243 - if(unlikely(isnan(value) || isinf(value)))
244 - buffer_sprintf(helper->buf, "%s\n\t\t\"%s\": null", helper->counter?",":"", rv->name);
245 - else
246 - buffer_sprintf(helper->buf, "%s\n\t\t\"%s\": %0.5Lf", helper->counter?",":"", rv->name, (long double)value);
247 -
248 - helper->counter++;
249 -
250 - return 0;
251 -}
252 -
253 -void health_api_v1_chart_variables2json(RRDSET *st, BUFFER *buf) {
254 - struct variable2json_helper helper = {
255 - .buf = buf,
256 - .counter = 0
257 - };
258 -
259 - 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);
260 - avl_traverse_lock(&st->variables_root_index, single_variable2json, (void *)&helper);
261 - buffer_sprintf(buf, "\n\t},\n\t\"family\": \"%s\",\n\t\"family_variables\": {", st->family);
262 - helper.counter = 0;
263 - avl_traverse_lock(&st->rrdfamily->variables_root_index, single_variable2json, (void *)&helper);
264 - buffer_sprintf(buf, "\n\t},\n\t\"host\": \"%s\",\n\t\"host_variables\": {", st->rrdhost->hostname);
265 - helper.counter = 0;
266 - avl_traverse_lock(&st->rrdhost->variables_root_index, single_variable2json, (void *)&helper);
267 - buffer_strcat(buf, "\n\t}\n}\n");
268 -}
269 -
270 -
271 -// ----------------------------------------------------------------------------
272 -// RRDDIMVAR management
273 -// DIMENSION VARIABLES
274 -
275 -#define RRDDIMVAR_ID_MAX 1024
276 -
277 -static inline void rrddimvar_free_variables(RRDDIMVAR *rs) {
278 - RRDDIM *rd = rs->rrddim;
279 - RRDSET *st = rd->rrdset;
280 -
281 - // CHART VARIABLES FOR THIS DIMENSION
282 -
283 - rrdvar_free(st->rrdhost, &st->variables_root_index, rs->var_local_id);
284 - rs->var_local_id = NULL;
285 -
286 - rrdvar_free(st->rrdhost, &st->variables_root_index, rs->var_local_name);
287 - rs->var_local_name = NULL;
288 -
289 - // FAMILY VARIABLES FOR THIS DIMENSION
290 -
291 - rrdvar_free(st->rrdhost, &st->rrdfamily->variables_root_index, rs->var_family_id);
292 - rs->var_family_id = NULL;
293 -
294 - rrdvar_free(st->rrdhost, &st->rrdfamily->variables_root_index, rs->var_family_name);
295 - rs->var_family_name = NULL;
296 -
297 - rrdvar_free(st->rrdhost, &st->rrdfamily->variables_root_index, rs->var_family_contextid);
298 - rs->var_family_contextid = NULL;
299 -
300 - rrdvar_free(st->rrdhost, &st->rrdfamily->variables_root_index, rs->var_family_contextname);
301 - rs->var_family_contextname = NULL;
302 -
303 - // HOST VARIABLES FOR THIS DIMENSION
304 -
305 - rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->var_host_chartidid);
306 - rs->var_host_chartidid = NULL;
307 -
308 - rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->var_host_chartidname);
309 - rs->var_host_chartidname = NULL;
310 -
311 - rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->var_host_chartnameid);
312 - rs->var_host_chartnameid = NULL;
313 -
314 - rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->var_host_chartnamename);
315 - rs->var_host_chartnamename = NULL;
316 -
317 - // KEYS
318 -
319 - freez(rs->key_id);
320 - rs->key_id = NULL;
321 -
322 - freez(rs->key_name);
323 - rs->key_name = NULL;
324 -
325 - freez(rs->key_fullidid);
326 - rs->key_fullidid = NULL;
327 -
328 - freez(rs->key_fullidname);
329 - rs->key_fullidname = NULL;
330 -
331 - freez(rs->key_contextid);
332 - rs->key_contextid = NULL;
333 -
334 - freez(rs->key_contextname);
335 - rs->key_contextname = NULL;
336 -
337 - freez(rs->key_fullnameid);
338 - rs->key_fullnameid = NULL;
339 -
340 - freez(rs->key_fullnamename);
341 - rs->key_fullnamename = NULL;
342 -}
343 -
344 -static inline void rrddimvar_create_variables(RRDDIMVAR *rs) {
345 - rrddimvar_free_variables(rs);
346 -
347 - RRDDIM *rd = rs->rrddim;
348 - RRDSET *st = rd->rrdset;
349 -
350 - char buffer[RRDDIMVAR_ID_MAX + 1];
351 -
352 - // KEYS
353 -
354 - snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s%s%s", rs->prefix, rd->id, rs->suffix);
355 - rs->key_id = strdupz(buffer);
356 -
357 - snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s%s%s", rs->prefix, rd->name, rs->suffix);
358 - rs->key_name = strdupz(buffer);
359 -
360 - snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", st->id, rs->key_id);
361 - rs->key_fullidid = strdupz(buffer);
362 -
363 - snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", st->id, rs->key_name);
364 - rs->key_fullidname = strdupz(buffer);
365 -
366 - snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", st->context, rs->key_id);
367 - rs->key_contextid = strdupz(buffer);
368 -
369 - snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", st->context, rs->key_name);
370 - rs->key_contextname = strdupz(buffer);
371 -
372 - snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", st->name, rs->key_id);
373 - rs->key_fullnameid = strdupz(buffer);
374 -
375 - snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", st->name, rs->key_name);
376 - rs->key_fullnamename = strdupz(buffer);
377 -
378 - // CHART VARIABLES FOR THIS DIMENSION
379 - // -----------------------------------
380 - //
381 - // dimensions are available as:
382 - // - $id
383 - // - $name
384 -
385 - rs->var_local_id = rrdvar_create_and_index("local", &st->variables_root_index, rs->key_id, rs->type, rs->value);
386 - rs->var_local_name = rrdvar_create_and_index("local", &st->variables_root_index, rs->key_name, rs->type, rs->value);
387 -
388 - // FAMILY VARIABLES FOR THIS DIMENSION
389 - // -----------------------------------
390 - //
391 - // dimensions are available as:
392 - // - $id (only the first, when multiple overlap)
393 - // - $name (only the first, when multiple overlap)
394 - // - $chart-context.id
395 - // - $chart-context.name
396 -
397 - rs->var_family_id = rrdvar_create_and_index("family", &st->rrdfamily->variables_root_index, rs->key_id, rs->type, rs->value);
398 - rs->var_family_name = rrdvar_create_and_index("family", &st->rrdfamily->variables_root_index, rs->key_name, rs->type, rs->value);
399 - rs->var_family_contextid = rrdvar_create_and_index("family", &st->rrdfamily->variables_root_index, rs->key_contextid, rs->type, rs->value);
400 - rs->var_family_contextname = rrdvar_create_and_index("family", &st->rrdfamily->variables_root_index, rs->key_contextname, rs->type, rs->value);
401 -
402 - // HOST VARIABLES FOR THIS DIMENSION
403 - // -----------------------------------
404 - //
405 - // dimensions are available as:
406 - // - $chart-id.id
407 - // - $chart-id.name
408 - // - $chart-name.id
409 - // - $chart-name.name
410 -
411 - rs->var_host_chartidid = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->key_fullidid, rs->type, rs->value);
412 - rs->var_host_chartidname = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->key_fullidname, rs->type, rs->value);
413 - rs->var_host_chartnameid = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->key_fullnameid, rs->type, rs->value);
414 - rs->var_host_chartnamename = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->key_fullnamename, rs->type, rs->value);
415 -}
416 -
417 -RRDDIMVAR *rrddimvar_create(RRDDIM *rd, int type, const char *prefix, const char *suffix, void *value, uint32_t options) {
418 - RRDSET *st = rd->rrdset;
419 -
420 - 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:"");
421 -
422 - if(!prefix) prefix = "";
423 - if(!suffix) suffix = "";
424 -
425 - RRDDIMVAR *rs = (RRDDIMVAR *)callocz(1, sizeof(RRDDIMVAR));
426 -
427 - rs->prefix = strdupz(prefix);
428 - rs->suffix = strdupz(suffix);
429 -
430 - rs->type = type;
431 - rs->value = value;
432 - rs->options = options;
433 - rs->rrddim = rd;
434 -
435 - rs->next = rd->variables;
436 - rd->variables = rs;
437 -
438 - rrddimvar_create_variables(rs);
439 -
440 - return rs;
441 -}
442 -
443 -void rrddimvar_rename_all(RRDDIM *rd) {
444 - RRDSET *st = rd->rrdset;
445 - debug(D_VARIABLES, "RRDDIMSET rename for chart id '%s' name '%s', dimension id '%s', name '%s'", st->id, st->name, rd->id, rd->name);
446 -
447 - RRDDIMVAR *rs, *next = rd->variables;
448 - while((rs = next)) {
449 - next = rs->next;
450 - rrddimvar_create_variables(rs);
451 - }
452 -}
453 -
454 -void rrddimvar_free(RRDDIMVAR *rs) {
455 - RRDDIM *rd = rs->rrddim;
456 - RRDSET *st = rd->rrdset;
457 - 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);
458 -
459 - rrddimvar_free_variables(rs);
460 -
461 - if(rd->variables == rs) {
462 - 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);
463 - rd->variables = rs->next;
464 - }
465 - else {
466 - 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);
467 - RRDDIMVAR *t;
468 - for (t = rd->variables; t && t->next != rs; t = t->next) ;
469 - if(!t) error("RRDDIMVAR '%s' not found in dimension '%s/%s' variables linked list", rs->key_name, st->id, rd->id);
470 - else t->next = rs->next;
471 - }
472 -
473 - freez(rs->prefix);
474 - freez(rs->suffix);
475 - freez(rs);
476 -}
477 -
478 -// ----------------------------------------------------------------------------
479 -// RRDSETVAR management
480 -// CHART VARIABLES
481 -
482 -static inline void rrdsetvar_free_variables(RRDSETVAR *rs) {
483 - RRDSET *st = rs->rrdset;
484 -
485 - // CHART
486 -
487 - rrdvar_free(st->rrdhost, &st->variables_root_index, rs->var_local);
488 - rs->var_local = NULL;
489 -
490 - // FAMILY
491 -
492 - rrdvar_free(st->rrdhost, &st->rrdfamily->variables_root_index, rs->var_family);
493 - rs->var_family = NULL;
494 -
495 - rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->var_host);
496 - rs->var_host = NULL;
497 -
498 - // HOST
499 -
500 - rrdvar_free(st->rrdhost, &st->rrdfamily->variables_root_index, rs->var_family_name);
501 - rs->var_family_name = NULL;
502 -
503 - rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->var_host_name);
504 - rs->var_host_name = NULL;
505 -
506 - // KEYS
507 -
508 - freez(rs->key_fullid);
509 - rs->key_fullid = NULL;
510 -
511 - freez(rs->key_fullname);
512 - rs->key_fullname = NULL;
513 -}
514 -
515 -static inline void rrdsetvar_create_variables(RRDSETVAR *rs) {
516 - rrdsetvar_free_variables(rs);
517 -
518 - RRDSET *st = rs->rrdset;
519 -
520 - // KEYS
521 -
522 - char buffer[RRDVAR_MAX_LENGTH + 1];
523 - snprintfz(buffer, RRDVAR_MAX_LENGTH, "%s.%s", st->id, rs->variable);
524 - rs->key_fullid = strdupz(buffer);
525 -
526 - snprintfz(buffer, RRDVAR_MAX_LENGTH, "%s.%s", st->name, rs->variable);
527 - rs->key_fullname = strdupz(buffer);
528 -
529 - // CHART
530 -
531 - rs->var_local = rrdvar_create_and_index("local", &st->variables_root_index, rs->variable, rs->type, rs->value);
532 -
533 - // FAMILY
534 -
535 - rs->var_family = rrdvar_create_and_index("family", &st->rrdfamily->variables_root_index, rs->key_fullid, rs->type, rs->value);
536 - rs->var_family_name = rrdvar_create_and_index("family", &st->rrdfamily->variables_root_index, rs->key_fullname, rs->type, rs->value);
537 -
538 - // HOST
539 -
540 - rs->var_host = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->key_fullid, rs->type, rs->value);
541 - rs->var_host_name = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->key_fullname, rs->type, rs->value);
542 -
543 -}
544 -
545 -RRDSETVAR *rrdsetvar_create(RRDSET *st, const char *variable, int type, void *value, uint32_t options) {
546 - debug(D_VARIABLES, "RRDVARSET create for chart id '%s' name '%s' with variable name '%s'", st->id, st->name, variable);
547 - RRDSETVAR *rs = (RRDSETVAR *)callocz(1, sizeof(RRDSETVAR));
548 -
549 - rs->variable = strdupz(variable);
550 - rs->type = type;
551 - rs->value = value;
552 - rs->options = options;
553 - rs->rrdset = st;
554 -
555 - rs->next = st->variables;
556 - st->variables = rs;
557 -
558 - rrdsetvar_create_variables(rs);
559 -
560 - return rs;
561 -}
562 -
563 -void rrdsetvar_rename_all(RRDSET *st) {
564 - debug(D_VARIABLES, "RRDSETVAR rename for chart id '%s' name '%s'", st->id, st->name);
565 -
566 - RRDSETVAR *rs, *next = st->variables;
567 - while((rs = next)) {
568 - next = rs->next;
569 - rrdsetvar_create_variables(rs);
570 - }
571 -
572 - rrdsetcalc_link_matching(st);
573 -}
574 -
575 -void rrdsetvar_free(RRDSETVAR *rs) {
576 - RRDSET *st = rs->rrdset;
577 - debug(D_VARIABLES, "RRDSETVAR free for chart id '%s' name '%s', variable '%s'", st->id, st->name, rs->variable);
578 -
579 - if(st->variables == rs) {
580 - st->variables = rs->next;
581 - }
582 - else {
583 - RRDSETVAR *t;
584 - for (t = st->variables; t && t->next != rs; t = t->next);
585 - if(!t) error("RRDSETVAR '%s' not found in chart '%s' variables linked list", rs->key_fullname, st->id);
586 - else t->next = rs->next;
587 - }
588 -
589 - rrdsetvar_free_variables(rs);
590 -
591 - freez(rs->variable);
592 - freez(rs);
593 -}
594 -
595 -// ----------------------------------------------------------------------------
596 -// RRDCALC management
597 -
598 -inline const char *rrdcalc_status2string(int status) {
599 - switch(status) {
600 - case RRDCALC_STATUS_REMOVED:
601 - return "REMOVED";
602 -
603 - case RRDCALC_STATUS_UNDEFINED:
604 - return "UNDEFINED";
605 -
606 - case RRDCALC_STATUS_UNINITIALIZED:
607 - return "UNINITIALIZED";
608 -
609 - case RRDCALC_STATUS_CLEAR:
610 - return "CLEAR";
611 -
612 - case RRDCALC_STATUS_RAISED:
613 - return "RAISED";
614 -
615 - case RRDCALC_STATUS_WARNING:
616 - return "WARNING";
617 -
618 - case RRDCALC_STATUS_CRITICAL:
619 - return "CRITICAL";
620 -
621 - default:
622 - error("Unknown alarm status %d", status);
623 - return "UNKNOWN";
624 - }
625 -}
626 -
627 -static void rrdsetcalc_link(RRDSET *st, RRDCALC *rc) {
628 - debug(D_HEALTH, "Health linking alarm '%s.%s' to chart '%s' of host '%s'", rc->chart?rc->chart:"NOCHART", rc->name, st->id, st->rrdhost->hostname);
629 -
630 - rc->last_status_change = now_realtime_sec();
631 - rc->rrdset = st;
632 -
633 - rc->rrdset_next = st->alarms;
634 - rc->rrdset_prev = NULL;
635 -
636 - if(rc->rrdset_next)
637 - rc->rrdset_next->rrdset_prev = rc;
638 -
639 - st->alarms = rc;
640 -
641 - if(rc->update_every < rc->rrdset->update_every) {
642 - 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);
643 - rc->update_every = rc->rrdset->update_every;
644 - }
645 -
646 - if(!isnan(rc->green) && isnan(st->green)) {
647 - debug(D_HEALTH, "Health alarm '%s.%s' green threshold set from %Lf to %Lf.", rc->rrdset->id, rc->name, rc->rrdset->green, rc->green);
648 - st->green = rc->green;
649 - }
650 -
651 - if(!isnan(rc->red) && isnan(st->red)) {
652 - debug(D_HEALTH, "Health alarm '%s.%s' red threshold set from %Lf to %Lf.", rc->rrdset->id, rc->name, rc->rrdset->red, rc->red);
653 - st->red = rc->red;
654 - }
655 -
656 - rc->local = rrdvar_create_and_index("local", &st->variables_root_index, rc->name, RRDVAR_TYPE_CALCULATED, &rc->value);
657 - rc->family = rrdvar_create_and_index("family", &st->rrdfamily->variables_root_index, rc->name, RRDVAR_TYPE_CALCULATED, &rc->value);
658 -
659 - char fullname[RRDVAR_MAX_LENGTH + 1];
660 - snprintfz(fullname, RRDVAR_MAX_LENGTH, "%s.%s", st->id, rc->name);
661 - rc->hostid = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, fullname, RRDVAR_TYPE_CALCULATED, &rc->value);
662 -
663 - snprintfz(fullname, RRDVAR_MAX_LENGTH, "%s.%s", st->name, rc->name);
664 - rc->hostname = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, fullname, RRDVAR_TYPE_CALCULATED, &rc->value);
665 -
666 - if(!rc->units) rc->units = strdupz(st->units);
667 -
668 - {
669 - time_t now = now_realtime_sec();
670 - health_alarm_log(
671 - st->rrdhost,
672 - rc->id,
673 - rc->next_event_id++,
674 - now,
675 - rc->name,
676 - rc->rrdset->id,
677 - rc->rrdset->family,
678 - rc->exec,
679 - rc->recipient,
680 - now - rc->last_status_change,
681 - rc->old_value,
682 - rc->value,
683 - rc->status,
684 - RRDCALC_STATUS_UNINITIALIZED,
685 - rc->source,
686 - rc->units,
687 - rc->info,
688 - 0,
689 - 0
690 - );
691 - }
692 -}
693 -
694 -static inline int rrdcalc_is_matching_this_rrdset(RRDCALC *rc, RRDSET *st) {
695 - if( (rc->hash_chart == st->hash && !strcmp(rc->chart, st->id)) ||
696 - (rc->hash_chart == st->hash_name && !strcmp(rc->chart, st->name)))
697 - return 1;
698 -
699 - return 0;
700 -}
701 -
702 -// this has to be called while the RRDHOST is locked
703 -inline void rrdsetcalc_link_matching(RRDSET *st) {
704 - // debug(D_HEALTH, "find matching alarms for chart '%s'", st->id);
705 -
706 - RRDCALC *rc;
707 - for(rc = st->rrdhost->alarms; rc ; rc = rc->next) {
708 - if(unlikely(rc->rrdset))
709 - continue;
710 -
711 - if(unlikely(rrdcalc_is_matching_this_rrdset(rc, st)))
712 - rrdsetcalc_link(st, rc);
713 - }
714 -}
715 -
716 -// this has to be called while the RRDHOST is locked
717 -inline void rrdsetcalc_unlink(RRDCALC *rc) {
718 - RRDSET *st = rc->rrdset;
719 -
720 - if(!st) {
721 - debug(D_HEALTH, "Requested to unlink RRDCALC '%s.%s' which is not linked to any RRDSET", rc->chart?rc->chart:"NOCHART", rc->name);
722 - error("Requested to unlink RRDCALC '%s.%s' which is not linked to any RRDSET", rc->chart?rc->chart:"NOCHART", rc->name);
723 - return;
724 - }
725 -
726 - {
727 - time_t now = now_realtime_sec();
728 - health_alarm_log(
729 - st->rrdhost,
730 - rc->id,
731 - rc->next_event_id++,
732 - now,
733 - rc->name,
734 - rc->rrdset->id,
735 - rc->rrdset->family,
736 - rc->exec,
737 - rc->recipient,
738 - now - rc->last_status_change,
739 - rc->old_value,
740 - rc->value,
741 - rc->status,
742 - RRDCALC_STATUS_REMOVED,
743 - rc->source,
744 - rc->units,
745 - rc->info,
746 - 0,
747 - 0
748 - );
749 - }
750 -
751 - RRDHOST *host = st->rrdhost;
752 -
753 - 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);
754 -
755 - // unlink it
756 - if(rc->rrdset_prev)
757 - rc->rrdset_prev->rrdset_next = rc->rrdset_next;
758 -
759 - if(rc->rrdset_next)
760 - rc->rrdset_next->rrdset_prev = rc->rrdset_prev;
761 -
762 - if(st->alarms == rc)
763 - st->alarms = rc->rrdset_next;
764 -
765 - rc->rrdset_prev = rc->rrdset_next = NULL;
766 -
767 - rrdvar_free(st->rrdhost, &st->variables_root_index, rc->local);
768 - rc->local = NULL;
769 -
770 - rrdvar_free(st->rrdhost, &st->rrdfamily->variables_root_index, rc->family);
771 - rc->family = NULL;
772 -
773 - rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rc->hostid);
774 - rc->hostid = NULL;
775 -
776 - rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rc->hostname);
777 - rc->hostname = NULL;
778 -
779 - rc->rrdset = NULL;
780 -
781 - // RRDCALC will remain in RRDHOST
782 - // so that if the matching chart is found in the future
783 - // it will be applied automatically
784 -}
785 -
786 -RRDCALC *rrdcalc_find(RRDSET *st, const char *name) {
787 - RRDCALC *rc;
788 - uint32_t hash = simple_hash(name);
789 -
790 - for( rc = st->alarms; rc ; rc = rc->rrdset_next ) {
791 - if(unlikely(rc->hash == hash && !strcmp(rc->name, name)))
792 - return rc;
793 - }
794 -
795 - return NULL;
796 -}
797 -
798 -inline int rrdcalc_exists(RRDHOST *host, const char *chart, const char *name, uint32_t hash_chart, uint32_t hash_name) {
799 - RRDCALC *rc;
800 -
801 - if(unlikely(!chart)) {
802 - error("attempt to find RRDCALC '%s' without giving a chart name", name);
803 - return 1;
804 - }
805 -
806 - if(unlikely(!hash_chart)) hash_chart = simple_hash(chart);
807 - if(unlikely(!hash_name)) hash_name = simple_hash(name);
808 -
809 - // make sure it does not already exist
810 - for(rc = host->alarms; rc ; rc = rc->next) {
811 - if (unlikely(rc->chart && rc->hash == hash_name && rc->hash_chart == hash_chart && !strcmp(name, rc->name) && !strcmp(chart, rc->chart))) {
812 - debug(D_HEALTH, "Health alarm '%s.%s' already exists in host '%s'.", chart, name, host->hostname);
813 - error("Health alarm '%s.%s' already exists in host '%s'.", chart, name, host->hostname);
814 - return 1;
815 - }
816 - }
817 -
818 - return 0;
819 -}
820 -
821 -inline uint32_t rrdcalc_get_unique_id(RRDHOST *host, const char *chart, const char *name, uint32_t *next_event_id) {
822 - if(chart && name) {
823 - uint32_t hash_chart = simple_hash(chart);
824 - uint32_t hash_name = simple_hash(name);
825 -
826 - // re-use old IDs, by looking them up in the alarm log
827 - ALARM_ENTRY *ae;
828 - for(ae = host->health_log.alarms; ae ;ae = ae->next) {
829 - if(unlikely(ae->hash_name == hash_name && ae->hash_chart == hash_chart && !strcmp(name, ae->name) && !strcmp(chart, ae->chart))) {
830 - if(next_event_id) *next_event_id = ae->alarm_event_id + 1;
831 - return ae->alarm_id;
832 - }
833 - }
834 - }
835 -
836 - return host->health_log.next_alarm_id++;
837 -}
838 -
839 -inline void rrdcalc_create_part2(RRDHOST *host, RRDCALC *rc) {
840 - rrdhost_check_rdlock(host);
841 -
842 - if(rc->calculation) {
843 - rc->calculation->status = &rc->status;
844 - rc->calculation->this = &rc->value;
845 - rc->calculation->after = &rc->db_after;
846 - rc->calculation->before = &rc->db_before;
847 - rc->calculation->rrdcalc = rc;
848 - }
849 -
850 - if(rc->warning) {
851 - rc->warning->status = &rc->status;
852 - rc->warning->this = &rc->value;
853 - rc->warning->after = &rc->db_after;
854 - rc->warning->before = &rc->db_before;
855 - rc->warning->rrdcalc = rc;
856 - }
857 -
858 - if(rc->critical) {
859 - rc->critical->status = &rc->status;
860 - rc->critical->this = &rc->value;
861 - rc->critical->after = &rc->db_after;
862 - rc->critical->before = &rc->db_before;
863 - rc->critical->rrdcalc = rc;
864 - }
865 -
866 - // link it to the host
867 - if(likely(host->alarms)) {
868 - // append it
869 - RRDCALC *t;
870 - for(t = host->alarms; t && t->next ; t = t->next) ;
871 - t->next = rc;
872 - }
873 - else {
874 - host->alarms = rc;
875 - }
876 -
877 - // link it to its chart
878 - RRDSET *st;
879 - for(st = host->rrdset_root; st ; st = st->next) {
880 - if(rrdcalc_is_matching_this_rrdset(rc, st)) {
881 - rrdsetcalc_link(st, rc);
882 - break;
883 - }
884 - }
885 -}
886 -
887 -static inline RRDCALC *rrdcalc_create(RRDHOST *host, RRDCALCTEMPLATE *rt, const char *chart) {
888 -
889 - debug(D_HEALTH, "Health creating dynamic alarm (from template) '%s.%s'", chart, rt->name);
890 -
891 - if(rrdcalc_exists(host, chart, rt->name, 0, 0))
892 - return NULL;
893 -
894 - RRDCALC *rc = callocz(1, sizeof(RRDCALC));
895 - rc->next_event_id = 1;
896 - rc->id = rrdcalc_get_unique_id(host, chart, rt->name, &rc->next_event_id);
897 - rc->name = strdupz(rt->name);
898 - rc->hash = simple_hash(rc->name);
899 - rc->chart = strdupz(chart);
900 - rc->hash_chart = simple_hash(rc->chart);
901 -
902 - if(rt->dimensions) rc->dimensions = strdupz(rt->dimensions);
903 -
904 - rc->green = rt->green;
905 - rc->red = rt->red;
906 - rc->value = NAN;
907 - rc->old_value = NAN;
908 -
909 - rc->delay_up_duration = rt->delay_up_duration;
910 - rc->delay_down_duration = rt->delay_down_duration;
911 - rc->delay_max_duration = rt->delay_max_duration;
912 - rc->delay_multiplier = rt->delay_multiplier;
913 -
914 - rc->group = rt->group;
915 - rc->after = rt->after;
916 - rc->before = rt->before;
917 - rc->update_every = rt->update_every;
918 - rc->options = rt->options;
919 -
920 - if(rt->exec) rc->exec = strdupz(rt->exec);
921 - if(rt->recipient) rc->recipient = strdupz(rt->recipient);
922 - if(rt->source) rc->source = strdupz(rt->source);
923 - if(rt->units) rc->units = strdupz(rt->units);
924 - if(rt->info) rc->info = strdupz(rt->info);
925 -
926 - if(rt->calculation) {
927 - rc->calculation = expression_parse(rt->calculation->source, NULL, NULL);
928 - if(!rc->calculation)
929 - error("Health alarm '%s.%s': failed to parse calculation expression '%s'", chart, rt->name, rt->calculation->source);
930 - }
931 - if(rt->warning) {
932 - rc->warning = expression_parse(rt->warning->source, NULL, NULL);
933 - if(!rc->warning)
934 - error("Health alarm '%s.%s': failed to re-parse warning expression '%s'", chart, rt->name, rt->warning->source);
935 - }
936 - if(rt->critical) {
937 - rc->critical = expression_parse(rt->critical->source, NULL, NULL);
938 - if(!rc->critical)
939 - error("Health alarm '%s.%s': failed to re-parse critical expression '%s'", chart, rt->name, rt->critical->source);
940 - }
941 -
942 - debug(D_HEALTH, "Health runtime added alarm '%s.%s': exec '%s', recipient '%s', green %Lf, red %Lf, lookup: group %d, after %d, before %d, options %u, dimensions '%s', update every %d, calculation '%s', warning '%s', critical '%s', source '%s', delay up %d, delay down %d, delay max %d, delay_multiplier %f",
943 - (rc->chart)?rc->chart:"NOCHART",
944 - rc->name,
945 - (rc->exec)?rc->exec:"DEFAULT",
946 - (rc->recipient)?rc->recipient:"DEFAULT",
947 - rc->green,
948 - rc->red,
949 - rc->group,
950 - rc->after,
951 - rc->before,
952 - rc->options,
953 - (rc->dimensions)?rc->dimensions:"NONE",
954 - rc->update_every,
955 - (rc->calculation)?rc->calculation->parsed_as:"NONE",
956 - (rc->warning)?rc->warning->parsed_as:"NONE",
957 - (rc->critical)?rc->critical->parsed_as:"NONE",
958 - rc->source,
959 - rc->delay_up_duration,
960 - rc->delay_down_duration,
961 - rc->delay_max_duration,
962 - rc->delay_multiplier
963 - );
964 -
965 - rrdcalc_create_part2(host, rc);
966 - return rc;
967 -}
968 -
969 -void rrdcalc_free(RRDHOST *host, RRDCALC *rc) {
970 - if(!rc) return;
971 -
972 - debug(D_HEALTH, "Health removing alarm '%s.%s' of host '%s'", rc->chart?rc->chart:"NOCHART", rc->name, host->hostname);
973 -
974 - // unlink it from RRDSET
975 - if(rc->rrdset) rrdsetcalc_unlink(rc);
976 -
977 - // unlink it from RRDHOST
978 - if(unlikely(rc == host->alarms))
979 - host->alarms = rc->next;
980 -
981 - else if(likely(host->alarms)) {
982 - RRDCALC *t, *last = host->alarms;
983 - for(t = last->next; t && t != rc; last = t, t = t->next) ;
984 - if(last->next == rc)
985 - last->next = rc->next;
986 - else
987 - error("Cannot unlink alarm '%s.%s' from host '%s': not found", rc->chart?rc->chart:"NOCHART", rc->name, host->hostname);
988 - }
989 - else
990 - error("Cannot unlink unlink '%s.%s' from host '%s': This host does not have any calculations", rc->chart?rc->chart:"NOCHART", rc->name, host->hostname);
991 -
992 - expression_free(rc->calculation);
993 - expression_free(rc->warning);
994 - expression_free(rc->critical);
995 -
996 - freez(rc->name);
997 - freez(rc->chart);
998 - freez(rc->family);
999 - freez(rc->dimensions);
1000 - freez(rc->exec);
1001 - freez(rc->recipient);
1002 - freez(rc->source);
1003 - freez(rc->units);
1004 - freez(rc->info);
1005 - freez(rc);
1006 -}
1007 -
1008 -// ----------------------------------------------------------------------------
1009 -// RRDCALCTEMPLATE management
1010 -
1011 -void rrdcalctemplate_link_matching(RRDSET *st) {
1012 - RRDCALCTEMPLATE *rt;
1013 -
1014 - for(rt = st->rrdhost->templates; rt ; rt = rt->next) {
1015 - if(rt->hash_context == st->hash_context && !strcmp(rt->context, st->context)
1016 - && (!rt->family_pattern || simple_pattern_matches(rt->family_pattern, st->family))) {
1017 - RRDCALC *rc = rrdcalc_create(st->rrdhost, rt, st->id);
1018 - if(unlikely(!rc))
1019 - error("Health tried to create alarm from template '%s', but it failed", rt->name);
1020 -
1021 -#ifdef NETDATA_INTERNAL_CHECKS
1022 - else if(rc->rrdset != st)
1023 - error("Health alarm '%s.%s' should be linked to chart '%s', but it is not", rc->chart?rc->chart:"NOCHART", rc->name, st->id);
1024 -#endif
1025 - }
1026 - }
1027 -}
1028 -
1029 -inline void rrdcalctemplate_free(RRDHOST *host, RRDCALCTEMPLATE *rt) {
1030 - debug(D_HEALTH, "Health removing template '%s' of host '%s'", rt->name, host->hostname);
1031 -
1032 - if(host->templates) {
1033 - if(host->templates == rt) {
1034 - host->templates = rt->next;
1035 - }
1036 - else {
1037 - RRDCALCTEMPLATE *t, *last = host->templates;
1038 - for (t = last->next; t && t != rt; last = t, t = t->next ) ;
1039 - if(last && last->next == rt) {
1040 - last->next = rt->next;
1041 - rt->next = NULL;
1042 - }
1043 - else
1044 - error("Cannot find RRDCALCTEMPLATE '%s' linked in host '%s'", rt->name, host->hostname);
1045 - }
1046 - }
1047 -
1048 - expression_free(rt->calculation);
1049 - expression_free(rt->warning);
1050 - expression_free(rt->critical);
1051 -
1052 - freez(rt->family_match);
1053 - simple_pattern_free(rt->family_pattern);
1054 -
1055 - freez(rt->name);
1056 - freez(rt->exec);
1057 - freez(rt->recipient);
1058 - freez(rt->context);
1059 - freez(rt->source);
1060 - freez(rt->units);
1061 - freez(rt->info);
1062 - freez(rt->dimensions);
1063 - freez(rt);
1064 -}
1065 -
6 // ----------------------------------------------------------------------------
7 // health initialization
8
@@ -1089,20 +29,18 @@ void health_init(void) {
29 // ----------------------------------------------------------------------------
30 // re-load health configuration
31
1092 -inline void health_free_host_nolock(RRDHOST *host) {
32 +void health_reload_host(RRDHOST *host) {
33 + char *path = health_config_dir();
34 +
35 + // free all running alarms
36 + rrdhost_wrlock(host);
37 +
38 while(host->templates)
39 rrdcalctemplate_free(host, host->templates);
40
41 while(host->alarms)
42 rrdcalc_free(host, host->alarms);
1098 -}
43
1100 -void health_reload_host(RRDHOST *host) {
1101 - char *path = health_config_dir();
1102 -
1103 - // free all running alarms
1104 - rrdhost_wrlock(host);
1105 - health_free_host_nolock(host);
44 rrdhost_unlock(host);
45
46 // invalidate all previous entries in the alarm log
@@ -1311,17 +249,7 @@ static inline void health_alarm_log_process(RRDHOST *host) {
249
250 ALARM_ENTRY *t = ae->next;
251
1314 - freez(ae->name);
1315 - freez(ae->chart);
1316 - freez(ae->family);
1317 - freez(ae->exec);
1318 - freez(ae->recipient);
1319 - freez(ae->source);
1320 - freez(ae->units);
1321 - freez(ae->info);
1322 - freez(ae->old_value_string);
1323 - freez(ae->new_value_string);
1324 - freez(ae);
252 + health_alarm_log_free_one_nochecks_nounlink(ae);
253
254 ae = t;
255 host->health_log.count--;
src/health.h
+16 -5
@@ -400,16 +400,27 @@ extern void health_alarm_log(
400
401 extern void health_readdir(RRDHOST *host, const char *path);
402 extern char *health_config_dir(void);
403 -extern void health_free_host_nolock(RRDHOST *host);
403 extern void health_reload_host(RRDHOST *host);
404 +extern void health_alarm_log_free(RRDHOST *host);
405 +
406 +extern void rrdcalc_free(RRDHOST *host, RRDCALC *rc);
407 +extern void rrdcalctemplate_free(RRDHOST *host, RRDCALCTEMPLATE *rt);
408
409 #ifdef NETDATA_HEALTH_INTERNALS
410 +#define RRDVAR_MAX_LENGTH 1024
411 +
412 extern int rrdcalc_exists(RRDHOST *host, const char *chart, const char *name, uint32_t hash_chart, uint32_t hash_name);
413 extern uint32_t rrdcalc_get_unique_id(RRDHOST *host, const char *chart, const char *name, uint32_t *next_event_id);
409 -extern void rrdcalc_create_part2(RRDHOST *host, RRDCALC *rc);
410 -extern void rrdcalc_free(RRDHOST *host, RRDCALC *rc);
411 -extern void rrdcalctemplate_free(RRDHOST *host, RRDCALCTEMPLATE *rt);
414 extern int rrdvar_fix_name(char *variable);
413 -#endif
415 +
416 +extern RRDCALC *rrdcalc_create(RRDHOST *host, RRDCALCTEMPLATE *rt, const char *chart);
417 +extern void rrdcalc_create_part2(RRDHOST *host, RRDCALC *rc);
418 +
419 +extern RRDVAR *rrdvar_create_and_index(const char *scope, avl_tree_lock *tree, const char *name, int type, void *value);
420 +extern void rrdvar_free(RRDHOST *host, avl_tree_lock *tree, RRDVAR *rv);
421 +
422 +extern void health_alarm_log_free_one_nochecks_nounlink(ALARM_ENTRY *ae);
423 +
424 +#endif // NETDATA_HEALTH_INTERNALS
425
426 #endif //NETDATA_HEALTH_H
src/health_log.c
+27
@@ -436,3 +436,30 @@ inline void health_alarm_log(
436 health_alarm_log_save(host, ae);
437 }
438
439 +inline void health_alarm_log_free_one_nochecks_nounlink(ALARM_ENTRY *ae) {
440 + freez(ae->name);
441 + freez(ae->chart);
442 + freez(ae->family);
443 + freez(ae->exec);
444 + freez(ae->recipient);
445 + freez(ae->source);
446 + freez(ae->units);
447 + freez(ae->info);
448 + freez(ae->old_value_string);
449 + freez(ae->new_value_string);
450 + freez(ae);
451 +}
452 +
453 +inline void health_alarm_log_free(RRDHOST *host) {
454 + rrdhost_check_wrlock(host);
455 +
456 + pthread_rwlock_wrlock(&host->health_log.alarm_log_rwlock);
457 +
458 + ALARM_ENTRY *ae;
459 + while((ae = host->health_log.alarms)) {
460 + host->health_log.alarms = ae->next;
461 + health_alarm_log_free_one_nochecks_nounlink(ae);
462 + }
463 +
464 + pthread_rwlock_unlock(&host->health_log.alarm_log_rwlock);
465 +}
src/plugin_idlejitter.c
+2
@@ -31,6 +31,8 @@ void *cpuidlejitter_main(void *ptr) {
31 for(counter = 0; 1 ;counter++) {
32 usec_t usec = 0, susec = 0;
33
34 + if(netdata_exit) break;
35 +
36 while(susec < (localhost->rrd_update_every * USEC_PER_SEC)) {
37
38 now_monotonic_timeval(&before);
src/rrd.h
+13
@@ -371,14 +371,27 @@ extern RRDHOST *rrdhost_find_or_create(const char *hostname, const char *guid);
371 #ifdef NETDATA_INTERNAL_CHECKS
372 #define rrdhost_check_rdlock(host) rrdhost_check_rdlock_int(host, __FILE__, __FUNCTION__, __LINE__)
373 #define rrdhost_check_wrlock(host) rrdhost_check_wrlock_int(host, __FILE__, __FUNCTION__, __LINE__)
374 +#define rrd_check_rdlock() rrd_check_rdlock_int(__FILE__, __FUNCTION__, __LINE__)
375 +#define rrd_check_wrlock() rrd_check_wrlock_int(__FILE__, __FUNCTION__, __LINE__)
376 #else
377 #define rrdhost_check_rdlock(host) (void)0
378 #define rrdhost_check_wrlock(host) (void)0
379 +#define rrd_check_rdlock() (void)0
380 +#define rrd_check_wrlock() (void)0
381 #endif
382
383 extern void rrdhost_check_wrlock_int(RRDHOST *host, const char *file, const char *function, const unsigned long line);
384 extern void rrdhost_check_rdlock_int(RRDHOST *host, const char *file, const char *function, const unsigned long line);
385
386 +// ----------------------------------------------------------------------------
387 +// global lock for all RRDHOSTs
388 +
389 +extern pthread_rwlock_t rrd_rwlock;
390 +#define rrd_rdlock() pthread_rwlock_rdlock(&rrd_rwlock)
391 +#define rrd_wrlock() pthread_rwlock_wrlock(&rrd_rwlock)
392 +#define rrd_unlock() pthread_rwlock_unlock(&rrd_rwlock)
393 +
394 +
395 // ----------------------------------------------------------------------------
396 // RRDSET functions
397
src/rrdcalc.c new
+415
@@ -0,0 +1,415 @@
1 +#define NETDATA_HEALTH_INTERNALS
2 +#include "common.h"
3 +
4 +// ----------------------------------------------------------------------------
5 +// RRDCALC management
6 +
7 +inline const char *rrdcalc_status2string(int status) {
8 + switch(status) {
9 + case RRDCALC_STATUS_REMOVED:
10 + return "REMOVED";
11 +
12 + case RRDCALC_STATUS_UNDEFINED:
13 + return "UNDEFINED";
14 +
15 + case RRDCALC_STATUS_UNINITIALIZED:
16 + return "UNINITIALIZED";
17 +
18 + case RRDCALC_STATUS_CLEAR:
19 + return "CLEAR";
20 +
21 + case RRDCALC_STATUS_RAISED:
22 + return "RAISED";
23 +
24 + case RRDCALC_STATUS_WARNING:
25 + return "WARNING";
26 +
27 + case RRDCALC_STATUS_CRITICAL:
28 + return "CRITICAL";
29 +
30 + default:
31 + error("Unknown alarm status %d", status);
32 + return "UNKNOWN";
33 + }
34 +}
35 +
36 +static void rrdsetcalc_link(RRDSET *st, RRDCALC *rc) {
37 + debug(D_HEALTH, "Health linking alarm '%s.%s' to chart '%s' of host '%s'", rc->chart?rc->chart:"NOCHART", rc->name, st->id, st->rrdhost->hostname);
38 +
39 + rc->last_status_change = now_realtime_sec();
40 + rc->rrdset = st;
41 +
42 + rc->rrdset_next = st->alarms;
43 + rc->rrdset_prev = NULL;
44 +
45 + if(rc->rrdset_next)
46 + rc->rrdset_next->rrdset_prev = rc;
47 +
48 + st->alarms = rc;
49 +
50 + if(rc->update_every < rc->rrdset->update_every) {
51 + 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);
52 + rc->update_every = rc->rrdset->update_every;
53 + }
54 +
55 + if(!isnan(rc->green) && isnan(st->green)) {
56 + debug(D_HEALTH, "Health alarm '%s.%s' green threshold set from %Lf to %Lf.", rc->rrdset->id, rc->name, rc->rrdset->green, rc->green);
57 + st->green = rc->green;
58 + }
59 +
60 + if(!isnan(rc->red) && isnan(st->red)) {
61 + debug(D_HEALTH, "Health alarm '%s.%s' red threshold set from %Lf to %Lf.", rc->rrdset->id, rc->name, rc->rrdset->red, rc->red);
62 + st->red = rc->red;
63 + }
64 +
65 + rc->local = rrdvar_create_and_index("local", &st->variables_root_index, rc->name, RRDVAR_TYPE_CALCULATED, &rc->value);
66 + rc->family = rrdvar_create_and_index("family", &st->rrdfamily->variables_root_index, rc->name, RRDVAR_TYPE_CALCULATED, &rc->value);
67 +
68 + char fullname[RRDVAR_MAX_LENGTH + 1];
69 + snprintfz(fullname, RRDVAR_MAX_LENGTH, "%s.%s", st->id, rc->name);
70 + rc->hostid = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, fullname, RRDVAR_TYPE_CALCULATED, &rc->value);
71 +
72 + snprintfz(fullname, RRDVAR_MAX_LENGTH, "%s.%s", st->name, rc->name);
73 + rc->hostname = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, fullname, RRDVAR_TYPE_CALCULATED, &rc->value);
74 +
75 + if(!rc->units) rc->units = strdupz(st->units);
76 +
77 + {
78 + time_t now = now_realtime_sec();
79 + health_alarm_log(
80 + st->rrdhost,
81 + rc->id,
82 + rc->next_event_id++,
83 + now,
84 + rc->name,
85 + rc->rrdset->id,
86 + rc->rrdset->family,
87 + rc->exec,
88 + rc->recipient,
89 + now - rc->last_status_change,
90 + rc->old_value,
91 + rc->value,
92 + rc->status,
93 + RRDCALC_STATUS_UNINITIALIZED,
94 + rc->source,
95 + rc->units,
96 + rc->info,
97 + 0,
98 + 0
99 + );
100 + }
101 +}
102 +
103 +static inline int rrdcalc_is_matching_this_rrdset(RRDCALC *rc, RRDSET *st) {
104 + if( (rc->hash_chart == st->hash && !strcmp(rc->chart, st->id)) ||
105 + (rc->hash_chart == st->hash_name && !strcmp(rc->chart, st->name)))
106 + return 1;
107 +
108 + return 0;
109 +}
110 +
111 +// this has to be called while the RRDHOST is locked
112 +inline void rrdsetcalc_link_matching(RRDSET *st) {
113 + // debug(D_HEALTH, "find matching alarms for chart '%s'", st->id);
114 +
115 + RRDCALC *rc;
116 + for(rc = st->rrdhost->alarms; rc ; rc = rc->next) {
117 + if(unlikely(rc->rrdset))
118 + continue;
119 +
120 + if(unlikely(rrdcalc_is_matching_this_rrdset(rc, st)))
121 + rrdsetcalc_link(st, rc);
122 + }
123 +}
124 +
125 +// this has to be called while the RRDHOST is locked
126 +inline void rrdsetcalc_unlink(RRDCALC *rc) {
127 + RRDSET *st = rc->rrdset;
128 +
129 + if(!st) {
130 + debug(D_HEALTH, "Requested to unlink RRDCALC '%s.%s' which is not linked to any RRDSET", rc->chart?rc->chart:"NOCHART", rc->name);
131 + error("Requested to unlink RRDCALC '%s.%s' which is not linked to any RRDSET", rc->chart?rc->chart:"NOCHART", rc->name);
132 + return;
133 + }
134 +
135 + {
136 + time_t now = now_realtime_sec();
137 + health_alarm_log(
138 + st->rrdhost,
139 + rc->id,
140 + rc->next_event_id++,
141 + now,
142 + rc->name,
143 + rc->rrdset->id,
144 + rc->rrdset->family,
145 + rc->exec,
146 + rc->recipient,
147 + now - rc->last_status_change,
148 + rc->old_value,
149 + rc->value,
150 + rc->status,
151 + RRDCALC_STATUS_REMOVED,
152 + rc->source,
153 + rc->units,
154 + rc->info,
155 + 0,
156 + 0
157 + );
158 + }
159 +
160 + RRDHOST *host = st->rrdhost;
161 +
162 + 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);
163 +
164 + // unlink it
165 + if(rc->rrdset_prev)
166 + rc->rrdset_prev->rrdset_next = rc->rrdset_next;
167 +
168 + if(rc->rrdset_next)
169 + rc->rrdset_next->rrdset_prev = rc->rrdset_prev;
170 +
171 + if(st->alarms == rc)
172 + st->alarms = rc->rrdset_next;
173 +
174 + rc->rrdset_prev = rc->rrdset_next = NULL;
175 +
176 + rrdvar_free(st->rrdhost, &st->variables_root_index, rc->local);
177 + rc->local = NULL;
178 +
179 + rrdvar_free(st->rrdhost, &st->rrdfamily->variables_root_index, rc->family);
180 + rc->family = NULL;
181 +
182 + rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rc->hostid);
183 + rc->hostid = NULL;
184 +
185 + rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rc->hostname);
186 + rc->hostname = NULL;
187 +
188 + rc->rrdset = NULL;
189 +
190 + // RRDCALC will remain in RRDHOST
191 + // so that if the matching chart is found in the future
192 + // it will be applied automatically
193 +}
194 +
195 +RRDCALC *rrdcalc_find(RRDSET *st, const char *name) {
196 + RRDCALC *rc;
197 + uint32_t hash = simple_hash(name);
198 +
199 + for( rc = st->alarms; rc ; rc = rc->rrdset_next ) {
200 + if(unlikely(rc->hash == hash && !strcmp(rc->name, name)))
201 + return rc;
202 + }
203 +
204 + return NULL;
205 +}
206 +
207 +inline int rrdcalc_exists(RRDHOST *host, const char *chart, const char *name, uint32_t hash_chart, uint32_t hash_name) {
208 + RRDCALC *rc;
209 +
210 + if(unlikely(!chart)) {
211 + error("attempt to find RRDCALC '%s' without giving a chart name", name);
212 + return 1;
213 + }
214 +
215 + if(unlikely(!hash_chart)) hash_chart = simple_hash(chart);
216 + if(unlikely(!hash_name)) hash_name = simple_hash(name);
217 +
218 + // make sure it does not already exist
219 + for(rc = host->alarms; rc ; rc = rc->next) {
220 + if (unlikely(rc->chart && rc->hash == hash_name && rc->hash_chart == hash_chart && !strcmp(name, rc->name) && !strcmp(chart, rc->chart))) {
221 + debug(D_HEALTH, "Health alarm '%s.%s' already exists in host '%s'.", chart, name, host->hostname);
222 + error("Health alarm '%s.%s' already exists in host '%s'.", chart, name, host->hostname);
223 + return 1;
224 + }
225 + }
226 +
227 + return 0;
228 +}
229 +
230 +inline uint32_t rrdcalc_get_unique_id(RRDHOST *host, const char *chart, const char *name, uint32_t *next_event_id) {
231 + if(chart && name) {
232 + uint32_t hash_chart = simple_hash(chart);
233 + uint32_t hash_name = simple_hash(name);
234 +
235 + // re-use old IDs, by looking them up in the alarm log
236 + ALARM_ENTRY *ae;
237 + for(ae = host->health_log.alarms; ae ;ae = ae->next) {
238 + if(unlikely(ae->hash_name == hash_name && ae->hash_chart == hash_chart && !strcmp(name, ae->name) && !strcmp(chart, ae->chart))) {
239 + if(next_event_id) *next_event_id = ae->alarm_event_id + 1;
240 + return ae->alarm_id;
241 + }
242 + }
243 + }
244 +
245 + return host->health_log.next_alarm_id++;
246 +}
247 +
248 +inline void rrdcalc_create_part2(RRDHOST *host, RRDCALC *rc) {
249 + rrdhost_check_rdlock(host);
250 +
251 + if(rc->calculation) {
252 + rc->calculation->status = &rc->status;
253 + rc->calculation->this = &rc->value;
254 + rc->calculation->after = &rc->db_after;
255 + rc->calculation->before = &rc->db_before;
256 + rc->calculation->rrdcalc = rc;
257 + }
258 +
259 + if(rc->warning) {
260 + rc->warning->status = &rc->status;
261 + rc->warning->this = &rc->value;
262 + rc->warning->after = &rc->db_after;
263 + rc->warning->before = &rc->db_before;
264 + rc->warning->rrdcalc = rc;
265 + }
266 +
267 + if(rc->critical) {
268 + rc->critical->status = &rc->status;
269 + rc->critical->this = &rc->value;
270 + rc->critical->after = &rc->db_after;
271 + rc->critical->before = &rc->db_before;
272 + rc->critical->rrdcalc = rc;
273 + }
274 +
275 + // link it to the host
276 + if(likely(host->alarms)) {
277 + // append it
278 + RRDCALC *t;
279 + for(t = host->alarms; t && t->next ; t = t->next) ;
280 + t->next = rc;
281 + }
282 + else {
283 + host->alarms = rc;
284 + }
285 +
286 + // link it to its chart
287 + RRDSET *st;
288 + for(st = host->rrdset_root; st ; st = st->next) {
289 + if(rrdcalc_is_matching_this_rrdset(rc, st)) {
290 + rrdsetcalc_link(st, rc);
291 + break;
292 + }
293 + }
294 +}
295 +
296 +inline RRDCALC *rrdcalc_create(RRDHOST *host, RRDCALCTEMPLATE *rt, const char *chart) {
297 +
298 + debug(D_HEALTH, "Health creating dynamic alarm (from template) '%s.%s'", chart, rt->name);
299 +
300 + if(rrdcalc_exists(host, chart, rt->name, 0, 0))
301 + return NULL;
302 +
303 + RRDCALC *rc = callocz(1, sizeof(RRDCALC));
304 + rc->next_event_id = 1;
305 + rc->id = rrdcalc_get_unique_id(host, chart, rt->name, &rc->next_event_id);
306 + rc->name = strdupz(rt->name);
307 + rc->hash = simple_hash(rc->name);
308 + rc->chart = strdupz(chart);
309 + rc->hash_chart = simple_hash(rc->chart);
310 +
311 + if(rt->dimensions) rc->dimensions = strdupz(rt->dimensions);
312 +
313 + rc->green = rt->green;
314 + rc->red = rt->red;
315 + rc->value = NAN;
316 + rc->old_value = NAN;
317 +
318 + rc->delay_up_duration = rt->delay_up_duration;
319 + rc->delay_down_duration = rt->delay_down_duration;
320 + rc->delay_max_duration = rt->delay_max_duration;
321 + rc->delay_multiplier = rt->delay_multiplier;
322 +
323 + rc->group = rt->group;
324 + rc->after = rt->after;
325 + rc->before = rt->before;
326 + rc->update_every = rt->update_every;
327 + rc->options = rt->options;
328 +
329 + if(rt->exec) rc->exec = strdupz(rt->exec);
330 + if(rt->recipient) rc->recipient = strdupz(rt->recipient);
331 + if(rt->source) rc->source = strdupz(rt->source);
332 + if(rt->units) rc->units = strdupz(rt->units);
333 + if(rt->info) rc->info = strdupz(rt->info);
334 +
335 + if(rt->calculation) {
336 + rc->calculation = expression_parse(rt->calculation->source, NULL, NULL);
337 + if(!rc->calculation)
338 + error("Health alarm '%s.%s': failed to parse calculation expression '%s'", chart, rt->name, rt->calculation->source);
339 + }
340 + if(rt->warning) {
341 + rc->warning = expression_parse(rt->warning->source, NULL, NULL);
342 + if(!rc->warning)
343 + error("Health alarm '%s.%s': failed to re-parse warning expression '%s'", chart, rt->name, rt->warning->source);
344 + }
345 + if(rt->critical) {
346 + rc->critical = expression_parse(rt->critical->source, NULL, NULL);
347 + if(!rc->critical)
348 + error("Health alarm '%s.%s': failed to re-parse critical expression '%s'", chart, rt->name, rt->critical->source);
349 + }
350 +
351 + debug(D_HEALTH, "Health runtime added alarm '%s.%s': exec '%s', recipient '%s', green %Lf, red %Lf, lookup: group %d, after %d, before %d, options %u, dimensions '%s', update every %d, calculation '%s', warning '%s', critical '%s', source '%s', delay up %d, delay down %d, delay max %d, delay_multiplier %f",
352 + (rc->chart)?rc->chart:"NOCHART",
353 + rc->name,
354 + (rc->exec)?rc->exec:"DEFAULT",
355 + (rc->recipient)?rc->recipient:"DEFAULT",
356 + rc->green,
357 + rc->red,
358 + rc->group,
359 + rc->after,
360 + rc->before,
361 + rc->options,
362 + (rc->dimensions)?rc->dimensions:"NONE",
363 + rc->update_every,
364 + (rc->calculation)?rc->calculation->parsed_as:"NONE",
365 + (rc->warning)?rc->warning->parsed_as:"NONE",
366 + (rc->critical)?rc->critical->parsed_as:"NONE",
367 + rc->source,
368 + rc->delay_up_duration,
369 + rc->delay_down_duration,
370 + rc->delay_max_duration,
371 + rc->delay_multiplier
372 + );
373 +
374 + rrdcalc_create_part2(host, rc);
375 + return rc;
376 +}
377 +
378 +void rrdcalc_free(RRDHOST *host, RRDCALC *rc) {
379 + if(!rc) return;
380 +
381 + debug(D_HEALTH, "Health removing alarm '%s.%s' of host '%s'", rc->chart?rc->chart:"NOCHART", rc->name, host->hostname);
382 +
383 + // unlink it from RRDSET
384 + if(rc->rrdset) rrdsetcalc_unlink(rc);
385 +
386 + // unlink it from RRDHOST
387 + if(unlikely(rc == host->alarms))
388 + host->alarms = rc->next;
389 +
390 + else {
391 + RRDCALC *t;
392 + for(t = host->alarms; t && t->next != rc; t = t->next) ;
393 + if(t) {
394 + t->next = rc->next;
395 + rc->next = NULL;
396 + }
397 + else
398 + error("Cannot unlink alarm '%s.%s' from host '%s': not found", rc->chart?rc->chart:"NOCHART", rc->name, host->hostname);
399 + }
400 +
401 + expression_free(rc->calculation);
402 + expression_free(rc->warning);
403 + expression_free(rc->critical);
404 +
405 + freez(rc->name);
406 + freez(rc->chart);
407 + freez(rc->family);
408 + freez(rc->dimensions);
409 + freez(rc->exec);
410 + freez(rc->recipient);
411 + freez(rc->source);
412 + freez(rc->units);
413 + freez(rc->info);
414 + freez(rc);
415 +}
src/rrdcalctemplate.c new
+60
@@ -0,0 +1,60 @@
1 +#define NETDATA_HEALTH_INTERNALS
2 +#include "common.h"
3 +
4 +// ----------------------------------------------------------------------------
5 +// RRDCALCTEMPLATE management
6 +
7 +void rrdcalctemplate_link_matching(RRDSET *st) {
8 + RRDCALCTEMPLATE *rt;
9 +
10 + for(rt = st->rrdhost->templates; rt ; rt = rt->next) {
11 + if(rt->hash_context == st->hash_context && !strcmp(rt->context, st->context)
12 + && (!rt->family_pattern || simple_pattern_matches(rt->family_pattern, st->family))) {
13 + RRDCALC *rc = rrdcalc_create(st->rrdhost, rt, st->id);
14 + if(unlikely(!rc))
15 + error("Health tried to create alarm from template '%s', but it failed", rt->name);
16 +
17 +#ifdef NETDATA_INTERNAL_CHECKS
18 + else if(rc->rrdset != st)
19 + error("Health alarm '%s.%s' should be linked to chart '%s', but it is not", rc->chart?rc->chart:"NOCHART", rc->name, st->id);
20 +#endif
21 + }
22 + }
23 +}
24 +
25 +inline void rrdcalctemplate_free(RRDHOST *host, RRDCALCTEMPLATE *rt) {
26 + debug(D_HEALTH, "Health removing template '%s' of host '%s'", rt->name, host->hostname);
27 +
28 + if(host->templates == rt) {
29 + host->templates = rt->next;
30 + }
31 + else {
32 + RRDCALCTEMPLATE *t;
33 + for (t = host->templates; t && t->next != rt; t = t->next ) ;
34 + if(t) {
35 + t->next = rt->next;
36 + rt->next = NULL;
37 + }
38 + else
39 + error("Cannot find RRDCALCTEMPLATE '%s' linked in host '%s'", rt->name, host->hostname);
40 + }
41 +
42 + expression_free(rt->calculation);
43 + expression_free(rt->warning);
44 + expression_free(rt->critical);
45 +
46 + freez(rt->family_match);
47 + simple_pattern_free(rt->family_pattern);
48 +
49 + freez(rt->name);
50 + freez(rt->exec);
51 + freez(rt->recipient);
52 + freez(rt->context);
53 + freez(rt->source);
54 + freez(rt->units);
55 + freez(rt->info);
56 + freez(rt->dimensions);
57 + freez(rt);
58 +}
59 +
60 +
src/rrddimvar.c new
+210
@@ -0,0 +1,210 @@
1 +#define NETDATA_HEALTH_INTERNALS
2 +#include "common.h"
3 +
4 +// ----------------------------------------------------------------------------
5 +// RRDDIMVAR management
6 +// DIMENSION VARIABLES
7 +
8 +#define RRDDIMVAR_ID_MAX 1024
9 +
10 +static inline void rrddimvar_free_variables(RRDDIMVAR *rs) {
11 + RRDDIM *rd = rs->rrddim;
12 + RRDSET *st = rd->rrdset;
13 +
14 + // CHART VARIABLES FOR THIS DIMENSION
15 +
16 + rrdvar_free(st->rrdhost, &st->variables_root_index, rs->var_local_id);
17 + rs->var_local_id = NULL;
18 +
19 + rrdvar_free(st->rrdhost, &st->variables_root_index, rs->var_local_name);
20 + rs->var_local_name = NULL;
21 +
22 + // FAMILY VARIABLES FOR THIS DIMENSION
23 +
24 + rrdvar_free(st->rrdhost, &st->rrdfamily->variables_root_index, rs->var_family_id);
25 + rs->var_family_id = NULL;
26 +
27 + rrdvar_free(st->rrdhost, &st->rrdfamily->variables_root_index, rs->var_family_name);
28 + rs->var_family_name = NULL;
29 +
30 + rrdvar_free(st->rrdhost, &st->rrdfamily->variables_root_index, rs->var_family_contextid);
31 + rs->var_family_contextid = NULL;
32 +
33 + rrdvar_free(st->rrdhost, &st->rrdfamily->variables_root_index, rs->var_family_contextname);
34 + rs->var_family_contextname = NULL;
35 +
36 + // HOST VARIABLES FOR THIS DIMENSION
37 +
38 + rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->var_host_chartidid);
39 + rs->var_host_chartidid = NULL;
40 +
41 + rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->var_host_chartidname);
42 + rs->var_host_chartidname = NULL;
43 +
44 + rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->var_host_chartnameid);
45 + rs->var_host_chartnameid = NULL;
46 +
47 + rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->var_host_chartnamename);
48 + rs->var_host_chartnamename = NULL;
49 +
50 + // KEYS
51 +
52 + freez(rs->key_id);
53 + rs->key_id = NULL;
54 +
55 + freez(rs->key_name);
56 + rs->key_name = NULL;
57 +
58 + freez(rs->key_fullidid);
59 + rs->key_fullidid = NULL;
60 +
61 + freez(rs->key_fullidname);
62 + rs->key_fullidname = NULL;
63 +
64 + freez(rs->key_contextid);
65 + rs->key_contextid = NULL;
66 +
67 + freez(rs->key_contextname);
68 + rs->key_contextname = NULL;
69 +
70 + freez(rs->key_fullnameid);
71 + rs->key_fullnameid = NULL;
72 +
73 + freez(rs->key_fullnamename);
74 + rs->key_fullnamename = NULL;
75 +}
76 +
77 +static inline void rrddimvar_create_variables(RRDDIMVAR *rs) {
78 + rrddimvar_free_variables(rs);
79 +
80 + RRDDIM *rd = rs->rrddim;
81 + RRDSET *st = rd->rrdset;
82 +
83 + char buffer[RRDDIMVAR_ID_MAX + 1];
84 +
85 + // KEYS
86 +
87 + snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s%s%s", rs->prefix, rd->id, rs->suffix);
88 + rs->key_id = strdupz(buffer);
89 +
90 + snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s%s%s", rs->prefix, rd->name, rs->suffix);
91 + rs->key_name = strdupz(buffer);
92 +
93 + snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", st->id, rs->key_id);
94 + rs->key_fullidid = strdupz(buffer);
95 +
96 + snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", st->id, rs->key_name);
97 + rs->key_fullidname = strdupz(buffer);
98 +
99 + snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", st->context, rs->key_id);
100 + rs->key_contextid = strdupz(buffer);
101 +
102 + snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", st->context, rs->key_name);
103 + rs->key_contextname = strdupz(buffer);
104 +
105 + snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", st->name, rs->key_id);
106 + rs->key_fullnameid = strdupz(buffer);
107 +
108 + snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", st->name, rs->key_name);
109 + rs->key_fullnamename = strdupz(buffer);
110 +
111 + // CHART VARIABLES FOR THIS DIMENSION
112 + // -----------------------------------
113 + //
114 + // dimensions are available as:
115 + // - $id
116 + // - $name
117 +
118 + rs->var_local_id = rrdvar_create_and_index("local", &st->variables_root_index, rs->key_id, rs->type, rs->value);
119 + rs->var_local_name = rrdvar_create_and_index("local", &st->variables_root_index, rs->key_name, rs->type, rs->value);
120 +
121 + // FAMILY VARIABLES FOR THIS DIMENSION
122 + // -----------------------------------
123 + //
124 + // dimensions are available as:
125 + // - $id (only the first, when multiple overlap)
126 + // - $name (only the first, when multiple overlap)
127 + // - $chart-context.id
128 + // - $chart-context.name
129 +
130 + rs->var_family_id = rrdvar_create_and_index("family", &st->rrdfamily->variables_root_index, rs->key_id, rs->type, rs->value);
131 + rs->var_family_name = rrdvar_create_and_index("family", &st->rrdfamily->variables_root_index, rs->key_name, rs->type, rs->value);
132 + rs->var_family_contextid = rrdvar_create_and_index("family", &st->rrdfamily->variables_root_index, rs->key_contextid, rs->type, rs->value);
133 + rs->var_family_contextname = rrdvar_create_and_index("family", &st->rrdfamily->variables_root_index, rs->key_contextname, rs->type, rs->value);
134 +
135 + // HOST VARIABLES FOR THIS DIMENSION
136 + // -----------------------------------
137 + //
138 + // dimensions are available as:
139 + // - $chart-id.id
140 + // - $chart-id.name
141 + // - $chart-name.id
142 + // - $chart-name.name
143 +
144 + rs->var_host_chartidid = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->key_fullidid, rs->type, rs->value);
145 + rs->var_host_chartidname = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->key_fullidname, rs->type, rs->value);
146 + rs->var_host_chartnameid = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->key_fullnameid, rs->type, rs->value);
147 + rs->var_host_chartnamename = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->key_fullnamename, rs->type, rs->value);
148 +}
149 +
150 +RRDDIMVAR *rrddimvar_create(RRDDIM *rd, int type, const char *prefix, const char *suffix, void *value, uint32_t options) {
151 + RRDSET *st = rd->rrdset;
152 +
153 + 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:"");
154 +
155 + if(!prefix) prefix = "";
156 + if(!suffix) suffix = "";
157 +
158 + RRDDIMVAR *rs = (RRDDIMVAR *)callocz(1, sizeof(RRDDIMVAR));
159 +
160 + rs->prefix = strdupz(prefix);
161 + rs->suffix = strdupz(suffix);
162 +
163 + rs->type = type;
164 + rs->value = value;
165 + rs->options = options;
166 + rs->rrddim = rd;
167 +
168 + rs->next = rd->variables;
169 + rd->variables = rs;
170 +
171 + rrddimvar_create_variables(rs);
172 +
173 + return rs;
174 +}
175 +
176 +void rrddimvar_rename_all(RRDDIM *rd) {
177 + RRDSET *st = rd->rrdset;
178 + debug(D_VARIABLES, "RRDDIMSET rename for chart id '%s' name '%s', dimension id '%s', name '%s'", st->id, st->name, rd->id, rd->name);
179 +
180 + RRDDIMVAR *rs, *next = rd->variables;
181 + while((rs = next)) {
182 + next = rs->next;
183 + rrddimvar_create_variables(rs);
184 + }
185 +}
186 +
187 +void rrddimvar_free(RRDDIMVAR *rs) {
188 + RRDDIM *rd = rs->rrddim;
189 + RRDSET *st = rd->rrdset;
190 + 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);
191 +
192 + rrddimvar_free_variables(rs);
193 +
194 + if(rd->variables == rs) {
195 + 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);
196 + rd->variables = rs->next;
197 + }
198 + else {
199 + 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);
200 + RRDDIMVAR *t;
201 + for (t = rd->variables; t && t->next != rs; t = t->next) ;
202 + if(!t) error("RRDDIMVAR '%s' not found in dimension '%s/%s' variables linked list", rs->key_name, st->id, rd->id);
203 + else t->next = rs->next;
204 + }
205 +
206 + freez(rs->prefix);
207 + freez(rs->suffix);
208 + freez(rs);
209 +}
210 +
src/rrdhost.c
+69 -23
@@ -3,6 +3,9 @@
3
4 RRDHOST *localhost = NULL;
5
6 +pthread_rwlock_t rrd_rwlock = PTHREAD_RWLOCK_INITIALIZER;
7 +
8 +
9 // ----------------------------------------------------------------------------
10 // RRDHOST index
11
@@ -46,6 +49,7 @@ static inline void rrdhost_init_machine_guid(RRDHOST *host, const char *machine_
49 host->hash_machine_guid = simple_hash(host->machine_guid);
50 }
51
52 +
53 // ----------------------------------------------------------------------------
54 // RRDHOST - add a host
55
@@ -75,7 +79,6 @@ RRDHOST *rrdhost_create(const char *hostname,
79 avl_init_lock(&(host->rrdfamily_root_index), rrdfamily_compare);
80 avl_init_lock(&(host->variables_root_index), rrdvar_compare);
81
78 -
82 // ------------------------------------------------------------------------
83 // initialize health variables
84
@@ -150,11 +153,20 @@ RRDHOST *rrdhost_create(const char *hostname,
153
154
155 // ------------------------------------------------------------------------
153 - // add it to the index
156 + // link it and add it to the index
157 +
158 + rrd_wrlock();
159 +
160 + if(localhost) {
161 + host->next = localhost->next;
162 + localhost->next = host;
163 + }
164
165 if(rrdhost_index_add(host) != host)
166 fatal("Cannot add host '%s' to index. It already exists.", hostname);
167
168 + rrd_unlock();
169 +
170 debug(D_RRDHOST, "Added host '%s' with guid '%s'", host->hostname, host->machine_guid);
171 return host;
172 }
@@ -210,6 +222,22 @@ void rrdhost_check_wrlock_int(RRDHOST *host, const char *file, const char *funct
222 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);
223 }
224
225 +void rrd_check_rdlock_int(const char *file, const char *function, const unsigned long line) {
226 + debug(D_RRDHOST, "Checking read lock on all RRDs");
227 +
228 + int ret = pthread_rwlock_trywrlock(&rrd_rwlock);
229 + if(ret == 0)
230 + fatal("RRDs should be read-locked, but it are not, at function %s() at line %lu of file '%s'", function, line, file);
231 +}
232 +
233 +void rrd_check_wrlock_int(const char *file, const char *function, const unsigned long line) {
234 + debug(D_RRDHOST, "Checking write lock on all RRDs");
235 +
236 + int ret = pthread_rwlock_tryrdlock(&rrd_rwlock);
237 + if(ret == 0)
238 + fatal("RRDs should be write-locked, but it are not, at function %s() at line %lu of file '%s'", function, line, file);
239 +}
240 +
241 // ----------------------------------------------------------------------------
242 // RRDHOST - free
243
@@ -218,21 +246,45 @@ void rrdhost_free(RRDHOST *host) {
246
247 info("Freeing all memory for host '%s'...", host->hostname);
248
221 - rrdhost_wrlock(host);
249 + rrd_check_wrlock(); // make sure the RRDs are write locked
250 + rrdhost_wrlock(host); // lock this RRDHOST
251
223 - RRDSET *st;
224 - for(st = host->rrdset_root; st ;) {
225 - RRDSET *next = st->next;
252 + // ------------------------------------------------------------------------
253 + // release its children resources
254
227 - rrdset_free(st);
255 + while(host->rrdset_root) rrdset_free(host->rrdset_root);
256
229 - st = next;
230 - }
231 - host->rrdset_root = NULL;
257 + while(host->alarms) rrdcalc_free(host, host->alarms);
258 + while(host->templates) rrdcalctemplate_free(host, host->templates);
259 + health_alarm_log_free(host);
260 +
261 +
262 + // ------------------------------------------------------------------------
263 + // remove it from the indexes
264
265 if(rrdhost_index_del(host) != host)
266 error("RRDHOST '%s' removed from index, deleted the wrong entry.", host->hostname);
267
268 +
269 + // ------------------------------------------------------------------------
270 + // unlink it from the host
271 +
272 + if(host == localhost) {
273 + localhost = host->next;
274 + }
275 + else {
276 + // find the previous one
277 + RRDHOST *h;
278 + for(h = localhost; h && h->next != host ; h = h->next) ;
279 +
280 + // bypass it
281 + if(h) h->next = host->next;
282 + else error("Request to free RRDHOST '%s': cannot find it", host->hostname);
283 + }
284 +
285 + // ------------------------------------------------------------------------
286 + // free it
287 +
288 freez(host->cache_dir);
289 freez(host->varlib_dir);
290 freez(host->health_default_exec);
@@ -246,19 +298,9 @@ void rrdhost_free(RRDHOST *host) {
298 }
299
300 void rrdhost_free_all(void) {
249 - RRDHOST *host = localhost;
250 -
251 - // FIXME: lock all hosts
252 -
253 - while(host) {
254 - RRDHOST *next = host = host->next;
255 - rrdhost_free(host);
256 - host = next;
257 - }
258 -
259 - localhost = NULL;
260 -
261 - // FIXME: unlock all hosts
301 + rrd_wrlock();
302 + while(localhost) rrdhost_free(localhost);
303 + rrd_unlock();
304 }
305
306 // ----------------------------------------------------------------------------
@@ -300,7 +342,11 @@ void rrdhost_save(RRDHOST *host) {
342 void rrdhost_save_all(void) {
343 info("Saving database...");
344
345 + rrd_rdlock();
346 +
347 RRDHOST *host;
348 for(host = localhost; host ; host = host->next)
349 rrdhost_save(host);
350 +
351 + rrd_unlock();
352 }
src/rrdset.c
+31 -5
@@ -209,24 +209,50 @@ static inline void timeval_align(struct timeval *tv, int update_every) {
209 // RRDSET - free a chart
210
211 void rrdset_free(RRDSET *st) {
212 - rrdset_wrlock(st);
212 + if(unlikely(!st)) return;
213 +
214 + rrdhost_check_wrlock(st->rrdhost); // make sure we have a write lock on the host
215 + rrdset_wrlock(st); // lock this RRDSET
216 +
217 + // ------------------------------------------------------------------------
218 + // free its children structures
219
220 while(st->variables) rrdsetvar_free(st->variables);
221 while(st->alarms) rrdsetcalc_unlink(st->alarms);
222 while(st->dimensions) rrddim_free(st, st->dimensions);
223
224 + rrdfamily_free(st->rrdhost, st->rrdfamily);
225 +
226 + // ------------------------------------------------------------------------
227 + // remove it from the indexes
228 +
229 if(unlikely(rrdset_index_del(st->rrdhost, st) != st))
230 error("RRDSET: INTERNAL ERROR: attempt to remove from index chart '%s', removed a different chart.", st->id);
231
232 rrdset_index_del_name(st->rrdhost, st);
233
223 - st->rrdfamily->use_count--;
224 - if(!st->rrdfamily->use_count)
225 - rrdfamily_free(st->rrdhost, st->rrdfamily);
234 + // ------------------------------------------------------------------------
235 + // unlink it from the host
236 +
237 + if(st == st->rrdhost->rrdset_root) {
238 + st->rrdhost->rrdset_root = st->next;
239 + }
240 + else {
241 + // find the previous one
242 + RRDSET *s;
243 + for(s = st->rrdhost->rrdset_root; s && s->next != st ; s = s->next) ;
244 +
245 + // bypass it
246 + if(s) s->next = st->next;
247 + else error("Request to free RRDSET '%s': cannot find it under host '%s'", st->id, st->rrdhost->hostname);
248 + }
249
250 rrdset_unlock(st);
251
229 - // free directly allocated memory
252 + // ------------------------------------------------------------------------
253 + // free it
254 +
255 + // free directly allocated members
256 freez(st->config_section);
257
258 if(st->rrd_memory_mode == RRD_MEMORY_MODE_SAVE || st->rrd_memory_mode == RRD_MEMORY_MODE_MAP) {
src/rrdsetvar.c new
+120
@@ -0,0 +1,120 @@
1 +#define NETDATA_HEALTH_INTERNALS
2 +#include "common.h"
3 +
4 +// ----------------------------------------------------------------------------
5 +// RRDSETVAR management
6 +// CHART VARIABLES
7 +
8 +static inline void rrdsetvar_free_variables(RRDSETVAR *rs) {
9 + RRDSET *st = rs->rrdset;
10 +
11 + // CHART
12 +
13 + rrdvar_free(st->rrdhost, &st->variables_root_index, rs->var_local);
14 + rs->var_local = NULL;
15 +
16 + // FAMILY
17 +
18 + rrdvar_free(st->rrdhost, &st->rrdfamily->variables_root_index, rs->var_family);
19 + rs->var_family = NULL;
20 +
21 + rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->var_host);
22 + rs->var_host = NULL;
23 +
24 + // HOST
25 +
26 + rrdvar_free(st->rrdhost, &st->rrdfamily->variables_root_index, rs->var_family_name);
27 + rs->var_family_name = NULL;
28 +
29 + rrdvar_free(st->rrdhost, &st->rrdhost->variables_root_index, rs->var_host_name);
30 + rs->var_host_name = NULL;
31 +
32 + // KEYS
33 +
34 + freez(rs->key_fullid);
35 + rs->key_fullid = NULL;
36 +
37 + freez(rs->key_fullname);
38 + rs->key_fullname = NULL;
39 +}
40 +
41 +static inline void rrdsetvar_create_variables(RRDSETVAR *rs) {
42 + rrdsetvar_free_variables(rs);
43 +
44 + RRDSET *st = rs->rrdset;
45 +
46 + // KEYS
47 +
48 + char buffer[RRDVAR_MAX_LENGTH + 1];
49 + snprintfz(buffer, RRDVAR_MAX_LENGTH, "%s.%s", st->id, rs->variable);
50 + rs->key_fullid = strdupz(buffer);
51 +
52 + snprintfz(buffer, RRDVAR_MAX_LENGTH, "%s.%s", st->name, rs->variable);
53 + rs->key_fullname = strdupz(buffer);
54 +
55 + // CHART
56 +
57 + rs->var_local = rrdvar_create_and_index("local", &st->variables_root_index, rs->variable, rs->type, rs->value);
58 +
59 + // FAMILY
60 +
61 + rs->var_family = rrdvar_create_and_index("family", &st->rrdfamily->variables_root_index, rs->key_fullid, rs->type, rs->value);
62 + rs->var_family_name = rrdvar_create_and_index("family", &st->rrdfamily->variables_root_index, rs->key_fullname, rs->type, rs->value);
63 +
64 + // HOST
65 +
66 + rs->var_host = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->key_fullid, rs->type, rs->value);
67 + rs->var_host_name = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->key_fullname, rs->type, rs->value);
68 +
69 +}
70 +
71 +RRDSETVAR *rrdsetvar_create(RRDSET *st, const char *variable, int type, void *value, uint32_t options) {
72 + debug(D_VARIABLES, "RRDVARSET create for chart id '%s' name '%s' with variable name '%s'", st->id, st->name, variable);
73 + RRDSETVAR *rs = (RRDSETVAR *)callocz(1, sizeof(RRDSETVAR));
74 +
75 + rs->variable = strdupz(variable);
76 + rs->type = type;
77 + rs->value = value;
78 + rs->options = options;
79 + rs->rrdset = st;
80 +
81 + rs->next = st->variables;
82 + st->variables = rs;
83 +
84 + rrdsetvar_create_variables(rs);
85 +
86 + return rs;
87 +}
88 +
89 +void rrdsetvar_rename_all(RRDSET *st) {
90 + debug(D_VARIABLES, "RRDSETVAR rename for chart id '%s' name '%s'", st->id, st->name);
91 +
92 + RRDSETVAR *rs, *next = st->variables;
93 + while((rs = next)) {
94 + next = rs->next;
95 + rrdsetvar_create_variables(rs);
96 + }
97 +
98 + rrdsetcalc_link_matching(st);
99 +}
100 +
101 +void rrdsetvar_free(RRDSETVAR *rs) {
102 + RRDSET *st = rs->rrdset;
103 + debug(D_VARIABLES, "RRDSETVAR free for chart id '%s' name '%s', variable '%s'", st->id, st->name, rs->variable);
104 +
105 + if(st->variables == rs) {
106 + st->variables = rs->next;
107 + }
108 + else {
109 + RRDSETVAR *t;
110 + for (t = st->variables; t && t->next != rs; t = t->next);
111 + if(!t) error("RRDSETVAR '%s' not found in chart '%s' variables linked list", rs->key_fullname, st->id);
112 + else t->next = rs->next;
113 + }
114 +
115 + rrdsetvar_free_variables(rs);
116 +
117 + freez(rs->variable);
118 + freez(rs);
119 +}
120 +
src/rrdvar.c new
+265
@@ -0,0 +1,265 @@
1 +#define NETDATA_HEALTH_INTERNALS
2 +#include "common.h"
3 +
4 +// ----------------------------------------------------------------------------
5 +// RRDVAR management
6 +
7 +inline int rrdvar_fix_name(char *variable) {
8 + int fixed = 0;
9 + while(*variable) {
10 + if (!isalnum(*variable) && *variable != '.' && *variable != '_') {
11 + *variable++ = '_';
12 + fixed++;
13 + }
14 + else
15 + variable++;
16 + }
17 +
18 + return fixed;
19 +}
20 +
21 +int rrdvar_compare(void* a, void* b) {
22 + if(((RRDVAR *)a)->hash < ((RRDVAR *)b)->hash) return -1;
23 + else if(((RRDVAR *)a)->hash > ((RRDVAR *)b)->hash) return 1;
24 + else return strcmp(((RRDVAR *)a)->name, ((RRDVAR *)b)->name);
25 +}
26 +
27 +static inline RRDVAR *rrdvar_index_add(avl_tree_lock *tree, RRDVAR *rv) {
28 + RRDVAR *ret = (RRDVAR *)avl_insert_lock(tree, (avl *)(rv));
29 + if(ret != rv)
30 + debug(D_VARIABLES, "Request to insert RRDVAR '%s' into index failed. Already exists.", rv->name);
31 +
32 + return ret;
33 +}
34 +
35 +static inline RRDVAR *rrdvar_index_del(avl_tree_lock *tree, RRDVAR *rv) {
36 + RRDVAR *ret = (RRDVAR *)avl_remove_lock(tree, (avl *)(rv));
37 + if(!ret)
38 + error("Request to remove RRDVAR '%s' from index failed. Not Found.", rv->name);
39 +
40 + return ret;
41 +}
42 +
43 +static inline RRDVAR *rrdvar_index_find(avl_tree_lock *tree, const char *name, uint32_t hash) {
44 + RRDVAR tmp;
45 + tmp.name = (char *)name;
46 + tmp.hash = (hash)?hash:simple_hash(tmp.name);
47 +
48 + return (RRDVAR *)avl_search_lock(tree, (avl *)&tmp);
49 +}
50 +
51 +inline void rrdvar_free(RRDHOST *host, avl_tree_lock *tree, RRDVAR *rv) {
52 + (void)host;
53 +
54 + if(!rv) return;
55 +
56 + if(tree) {
57 + debug(D_VARIABLES, "Deleting variable '%s'", rv->name);
58 + if(unlikely(!rrdvar_index_del(tree, rv)))
59 + error("Attempted to delete variable '%s' from host '%s', but it is not found.", rv->name, host->hostname);
60 + }
61 +
62 + freez(rv->name);
63 + freez(rv);
64 +}
65 +
66 +inline RRDVAR *rrdvar_create_and_index(const char *scope, avl_tree_lock *tree, const char *name, int type, void *value) {
67 + char *variable = strdupz(name);
68 + rrdvar_fix_name(variable);
69 + uint32_t hash = simple_hash(variable);
70 +
71 + RRDVAR *rv = rrdvar_index_find(tree, variable, hash);
72 + if(unlikely(!rv)) {
73 + debug(D_VARIABLES, "Variable '%s' not found in scope '%s'. Creating a new one.", variable, scope);
74 +
75 + rv = callocz(1, sizeof(RRDVAR));
76 + rv->name = variable;
77 + rv->hash = hash;
78 + rv->type = type;
79 + rv->value = value;
80 +
81 + RRDVAR *ret = rrdvar_index_add(tree, rv);
82 + if(unlikely(ret != rv)) {
83 + debug(D_VARIABLES, "Variable '%s' in scope '%s' already exists", variable, scope);
84 + rrdvar_free(NULL, NULL, rv);
85 + rv = NULL;
86 + }
87 + else
88 + debug(D_VARIABLES, "Variable '%s' created in scope '%s'", variable, scope);
89 + }
90 + else {
91 + debug(D_VARIABLES, "Variable '%s' is already found in scope '%s'.", variable, scope);
92 +
93 + // already exists
94 + freez(variable);
95 +
96 + // this is important
97 + // it must return NULL - not the existing variable - or double-free will happen
98 + rv = NULL;
99 + }
100 +
101 + return rv;
102 +}
103 +
104 +// ----------------------------------------------------------------------------
105 +// CUSTOM VARIABLES
106 +
107 +RRDVAR *rrdvar_custom_host_variable_create(RRDHOST *host, const char *name) {
108 + calculated_number *v = callocz(1, sizeof(calculated_number));
109 + *v = NAN;
110 + RRDVAR *rv = rrdvar_create_and_index("host", &host->variables_root_index, name, RRDVAR_TYPE_CALCULATED_ALLOCATED, v);
111 + if(unlikely(!rv)) {
112 + free(v);
113 + error("Requested variable '%s' already exists - possibly 2 plugins will be updating it at the same time", name);
114 +
115 + char *variable = strdupz(name);
116 + rrdvar_fix_name(variable);
117 + uint32_t hash = simple_hash(variable);
118 +
119 + rv = rrdvar_index_find(&host->variables_root_index, variable, hash);
120 + }
121 +
122 + return rv;
123 +}
124 +
125 +void rrdvar_custom_host_variable_destroy(RRDHOST *host, const char *name) {
126 + char *variable = strdupz(name);
127 + rrdvar_fix_name(variable);
128 + uint32_t hash = simple_hash(variable);
129 +
130 + RRDVAR *rv = rrdvar_index_find(&host->variables_root_index, variable, hash);
131 + freez(variable);
132 +
133 + if(!rv) {
134 + error("Attempted to remove variable '%s' from host '%s', but it does not exist.", name, host->hostname);
135 + return;
136 + }
137 +
138 + if(rv->type != RRDVAR_TYPE_CALCULATED_ALLOCATED) {
139 + error("Attempted to remove variable '%s' from host '%s', but it does not a custom allocated variable.", name, host->hostname);
140 + return;
141 + }
142 +
143 + if(!rrdvar_index_del(&host->variables_root_index, rv)) {
144 + error("Attempted to remove variable '%s' from host '%s', but it cannot be found.", name, host->hostname);
145 + return;
146 + }
147 +
148 + freez(rv->name);
149 + freez(rv->value);
150 + freez(rv);
151 +}
152 +
153 +void rrdvar_custom_host_variable_set(RRDVAR *rv, calculated_number value) {
154 + if(rv->type != RRDVAR_TYPE_CALCULATED_ALLOCATED)
155 + error("requested to set variable '%s' to value " CALCULATED_NUMBER_FORMAT " but the variable is not a custom one.", rv->name, value);
156 + else {
157 + calculated_number *v = rv->value;
158 + *v = value;
159 + }
160 +}
161 +
162 +// ----------------------------------------------------------------------------
163 +// RRDVAR lookup
164 +
165 +static calculated_number rrdvar2number(RRDVAR *rv) {
166 + switch(rv->type) {
167 + case RRDVAR_TYPE_CALCULATED_ALLOCATED:
168 + case RRDVAR_TYPE_CALCULATED: {
169 + calculated_number *n = (calculated_number *)rv->value;
170 + return *n;
171 + }
172 +
173 + case RRDVAR_TYPE_TIME_T: {
174 + time_t *n = (time_t *)rv->value;
175 + return *n;
176 + }
177 +
178 + case RRDVAR_TYPE_COLLECTED: {
179 + collected_number *n = (collected_number *)rv->value;
180 + return *n;
181 + }
182 +
183 + case RRDVAR_TYPE_TOTAL: {
184 + total_number *n = (total_number *)rv->value;
185 + return *n;
186 + }
187 +
188 + case RRDVAR_TYPE_INT: {
189 + int *n = (int *)rv->value;
190 + return *n;
191 + }
192 +
193 + default:
194 + error("I don't know how to convert RRDVAR type %d to calculated_number", rv->type);
195 + return NAN;
196 + }
197 +}
198 +
199 +int health_variable_lookup(const char *variable, uint32_t hash, RRDCALC *rc, calculated_number *result) {
200 + RRDSET *st = rc->rrdset;
201 + RRDVAR *rv;
202 +
203 + if(!st) return 0;
204 +
205 + rv = rrdvar_index_find(&st->variables_root_index, variable, hash);
206 + if(rv) {
207 + *result = rrdvar2number(rv);
208 + return 1;
209 + }
210 +
211 + rv = rrdvar_index_find(&st->rrdfamily->variables_root_index, variable, hash);
212 + if(rv) {
213 + *result = rrdvar2number(rv);
214 + return 1;
215 + }
216 +
217 + rv = rrdvar_index_find(&st->rrdhost->variables_root_index, variable, hash);
218 + if(rv) {
219 + *result = rrdvar2number(rv);
220 + return 1;
221 + }
222 +
223 + return 0;
224 +}
225 +
226 +// ----------------------------------------------------------------------------
227 +// RRDVAR to JSON
228 +
229 +struct variable2json_helper {
230 + BUFFER *buf;
231 + size_t counter;
232 +};
233 +
234 +static int single_variable2json(void *entry, void *data) {
235 + struct variable2json_helper *helper = (struct variable2json_helper *)data;
236 + RRDVAR *rv = (RRDVAR *)entry;
237 + calculated_number value = rrdvar2number(rv);
238 +
239 + if(unlikely(isnan(value) || isinf(value)))
240 + buffer_sprintf(helper->buf, "%s\n\t\t\"%s\": null", helper->counter?",":"", rv->name);
241 + else
242 + buffer_sprintf(helper->buf, "%s\n\t\t\"%s\": %0.5Lf", helper->counter?",":"", rv->name, (long double)value);
243 +
244 + helper->counter++;
245 +
246 + return 0;
247 +}
248 +
249 +void health_api_v1_chart_variables2json(RRDSET *st, BUFFER *buf) {
250 + struct variable2json_helper helper = {
251 + .buf = buf,
252 + .counter = 0
253 + };
254 +
255 + 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);
256 + avl_traverse_lock(&st->variables_root_index, single_variable2json, (void *)&helper);
257 + buffer_sprintf(buf, "\n\t},\n\t\"family\": \"%s\",\n\t\"family_variables\": {", st->family);
258 + helper.counter = 0;
259 + avl_traverse_lock(&st->rrdfamily->variables_root_index, single_variable2json, (void *)&helper);
260 + buffer_sprintf(buf, "\n\t},\n\t\"host\": \"%s\",\n\t\"host_variables\": {", st->rrdhost->hostname);
261 + helper.counter = 0;
262 + avl_traverse_lock(&st->rrdhost->variables_root_index, single_variable2json, (void *)&helper);
263 + buffer_strcat(buf, "\n\t}\n}\n");
264 +}
265 +
src/simple_pattern.c
+3 -3
@@ -184,8 +184,8 @@ int simple_pattern_matches(SIMPLE_PATTERN *list, const char *str) {
184 static inline void free_pattern(struct simple_pattern *m) {
185 if(!m) return;
186
187 - if(m->next) free_pattern(m->next);
188 - if(m->child) free_pattern(m->child);
187 + free_pattern(m->child);
188 + free_pattern(m->next);
189 freez((void *)m->match);
190 freez(m);
191 }
@@ -193,5 +193,5 @@ static inline void free_pattern(struct simple_pattern *m) {
193 void simple_pattern_free(SIMPLE_PATTERN *list) {
194 if(!list) return;
195
196 - free_pattern(((struct simple_pattern *)list)->next);
196 + free_pattern(((struct simple_pattern *)list));
197 }