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
}