Updated tc.plugin (linux bandwidth QoS) (#13634)
* modernized tc plugins (replacing AVL with DICTIONARY, char * with STRING *, linked list with DICTIONARY) and added labels * replace custom metrics with worker metrics and add monitoring number of devices and classes * revert bool to char * Revert "revert bool to char" This reverts commit fae9b92dc0be4b00a5694f8b90972787879ae8a7. * fixed typo * removed bitfield from bool * commented unused function * commented unused function again
Costa Tsaousis committed
Sep 7, 2022 at 16:48 UTC
b8d1ae8de761c616f7e29e43677675c65c119996
2 files changed
+389
-379
collectors/tc.plugin/plugin_tc.c
+388
-379
@@ -12,60 +12,46 @@
12
#define TC_LINE_MAX 1024
13
14
struct tc_class {
15
- avl_t avl;
15
+ STRING *id;
16
+ STRING *name;
17
+ STRING *leafid;
18
+ STRING *parentid;
19
+
20
+ bool hasparent;
21
+ bool isleaf;
22
+ bool isqdisc;
23
+ bool render;
24
+ bool name_updated;
25
+ bool updated;
26
17
- char *id;
18
- uint32_t hash;
19
-
20
- char *name;
21
-
22
- char *leafid;
23
- uint32_t leaf_hash;
24
-
25
- char *parentid;
26
- uint32_t parent_hash;
27
-
28
- char hasparent;
29
- char isleaf;
30
- char isqdisc;
31
- char render;
27
+ int unupdated; // the number of times, this has been found un-updated
28
29
unsigned long long bytes;
30
unsigned long long packets;
31
unsigned long long dropped;
36
- unsigned long long overlimits;
37
- unsigned long long requeues;
38
- unsigned long long lended;
39
- unsigned long long borrowed;
40
- unsigned long long giants;
32
unsigned long long tokens;
33
unsigned long long ctokens;
34
35
+ //unsigned long long overlimits;
36
+ //unsigned long long requeues;
37
+ //unsigned long long lended;
38
+ //unsigned long long borrowed;
39
+ //unsigned long long giants;
40
+
41
RRDDIM *rd_bytes;
42
RRDDIM *rd_packets;
43
RRDDIM *rd_dropped;
44
RRDDIM *rd_tokens;
45
RRDDIM *rd_ctokens;
49
-
50
- char name_updated;
51
- char updated; // updated bytes
52
- int unupdated; // the number of times, this has been found un-updated
53
-
54
- struct tc_class *next;
55
- struct tc_class *prev;
46
};
47
48
struct tc_device {
59
- avl_t avl;
60
-
61
- char *id;
62
- uint32_t hash;
49
+ STRING *id;
50
+ STRING *name;
51
+ STRING *family;
52
64
- char *name;
65
- char *family;
66
-
67
- char name_updated;
68
- char family_updated;
53
+ bool name_updated;
54
+ bool family_updated;
55
56
char enabled;
57
char enabled_bytes;
@@ -81,94 +67,121 @@ struct tc_device {
67
RRDSET *st_tokens;
68
RRDSET *st_ctokens;
69
84
- avl_tree_type classes_index;
70
+ DICTIONARY *classes;
71
+};
72
86
- struct tc_class *classes;
87
- struct tc_class *last_class;
73
89
- struct tc_device *next;
90
- struct tc_device *prev;
91
-};
74
+// ----------------------------------------------------------------------------
75
+// tc_class index
76
77
+static void tc_class_free_callback(const char *name __maybe_unused, void *value, void *data __maybe_unused) {
78
+ // struct tc_device *d = data;
79
+ struct tc_class *c = value;
80
94
-struct tc_device *tc_device_root = NULL;
81
+ string_freez(c->id);
82
+ string_freez(c->name);
83
+ string_freez(c->leafid);
84
+ string_freez(c->parentid);
85
+}
86
96
-// ----------------------------------------------------------------------------
97
-// tc_device index
87
+static void tc_class_conflict_callback(const char *name __maybe_unused, void *old_value, void *new_value, void *data __maybe_unused) {
88
+ struct tc_device *d = data; (void)d;
89
+ struct tc_class *c = old_value; (void)c;
90
+ struct tc_class *new_c = new_value; (void)new_c;
91
+
92
+ error("TC: class '%s' is already in device '%s'. Ignoring duplicate.", name, string2str(d->id));
93
99
-static int tc_device_compare(void* a, void* b) {
100
- if(((struct tc_device *)a)->hash < ((struct tc_device *)b)->hash) return -1;
101
- else if(((struct tc_device *)a)->hash > ((struct tc_device *)b)->hash) return 1;
102
- else return strcmp(((struct tc_device *)a)->id, ((struct tc_device *)b)->id);
94
+ tc_class_free_callback(name, new_value, data);
95
}
96
105
-avl_tree_type tc_device_root_index = {
106
- NULL,
107
- tc_device_compare
108
-};
97
+static void tc_class_index_init(struct tc_device *d) {
98
+ if(!d->classes) {
99
+ d->classes = dictionary_create(
100
+ DICTIONARY_FLAG_DONT_OVERWRITE_VALUE
101
+ |DICTIONARY_FLAG_SINGLE_THREADED
102
+ );
103
110
-#define tc_device_index_add(st) (struct tc_device *)avl_insert(&tc_device_root_index, (avl_t *)(st))
111
-#define tc_device_index_del(st) (struct tc_device *)avl_remove(&tc_device_root_index, (avl_t *)(st))
104
+ dictionary_register_delete_callback(d->classes, tc_class_free_callback, d);
105
+ dictionary_register_conflict_callback(d->classes, tc_class_conflict_callback, d);
106
+ }
107
+}
108
113
-static inline struct tc_device *tc_device_index_find(const char *id, uint32_t hash) {
114
- struct tc_device tmp;
115
- tmp.id = (char *)id;
116
- tmp.hash = (hash)?hash:simple_hash(tmp.id);
109
+static void tc_class_index_destroy(struct tc_device *d) {
110
+ dictionary_destroy(d->classes);
111
+ d->classes = NULL;
112
+}
113
118
- return (struct tc_device *)avl_search(&(tc_device_root_index), (avl_t *)&tmp);
114
+static struct tc_class *tc_class_index_add(struct tc_device *d, struct tc_class *c) {
115
+ return dictionary_set(d->classes, string2str(c->id), c, sizeof(*c));
116
}
117
118
+static void tc_class_index_del(struct tc_device *d, struct tc_class *c) {
119
+ dictionary_del(d->classes, string2str(c->id));
120
+}
121
+
122
+static inline struct tc_class *tc_class_index_find(struct tc_device *d, const char *id) {
123
+ return dictionary_get(d->classes, id);
124
+}
125
126
// ----------------------------------------------------------------------------
123
-// tc_class index
127
+// tc_device index
128
+
129
+static DICTIONARY *tc_device_root_index = NULL;
130
125
-static int tc_class_compare(void* a, void* b) {
126
- if(((struct tc_class *)a)->hash < ((struct tc_class *)b)->hash) return -1;
127
- else if(((struct tc_class *)a)->hash > ((struct tc_class *)b)->hash) return 1;
128
- else return strcmp(((struct tc_class *)a)->id, ((struct tc_class *)b)->id);
131
+static void tc_device_add_callback(const char *name __maybe_unused, void *value, void *data __maybe_unused) {
132
+ struct tc_device *d = value;
133
+ tc_class_index_init(d);
134
}
135
131
-#define tc_class_index_add(st, rd) (struct tc_class *)avl_insert(&((st)->classes_index), (avl_t *)(rd))
132
-#define tc_class_index_del(st, rd) (struct tc_class *)avl_remove(&((st)->classes_index), (avl_t *)(rd))
136
+static void tc_device_free_callback(const char *name __maybe_unused, void *value, void *data __maybe_unused) {
137
+ struct tc_device *d = value;
138
134
-static inline struct tc_class *tc_class_index_find(struct tc_device *st, const char *id, uint32_t hash) {
135
- struct tc_class tmp;
136
- tmp.id = (char *)id;
137
- tmp.hash = (hash)?hash:simple_hash(tmp.id);
139
+ tc_class_index_destroy(d);
140
139
- return (struct tc_class *)avl_search(&(st->classes_index), (avl_t *) &tmp);
141
+ string_freez(d->id);
142
+ string_freez(d->name);
143
+ string_freez(d->family);
144
}
145
142
-// ----------------------------------------------------------------------------
146
+static void tc_device_index_init() {
147
+ if(!tc_device_root_index) {
148
+ tc_device_root_index = dictionary_create(
149
+ DICTIONARY_FLAG_DONT_OVERWRITE_VALUE
150
+ |DICTIONARY_FLAG_SINGLE_THREADED
151
+ |DICTIONARY_FLAG_ADD_IN_FRONT
152
+ );
153
144
-static inline void tc_class_free(struct tc_device *n, struct tc_class *c) {
145
- if(c == n->classes) {
146
- if(likely(c->next))
147
- n->classes = c->next;
148
- else
149
- n->classes = c->prev;
154
+ dictionary_register_insert_callback(tc_device_root_index, tc_device_add_callback, NULL);
155
+ dictionary_register_delete_callback(tc_device_root_index, tc_device_free_callback, NULL);
156
}
157
+}
158
152
- if(c == n->last_class) {
153
- if(unlikely(c->next))
154
- n->last_class = c->next;
155
- else
156
- n->last_class = c->prev;
157
- }
159
+static void tc_device_index_destroy() {
160
+ dictionary_destroy(tc_device_root_index);
161
+ tc_device_root_index = NULL;
162
+}
163
159
- if(c->next) c->next->prev = c->prev;
160
- if(c->prev) c->prev->next = c->next;
164
+static struct tc_device *tc_device_index_add(struct tc_device *d) {
165
+ return dictionary_set(tc_device_root_index, string2str(d->id), d, sizeof(*d));
166
+}
167
162
- debug(D_TC_LOOP, "Removing from device '%s' class '%s', parentid '%s', leafid '%s', unused=%d", n->id, c->id, c->parentid?c->parentid:"", c->leafid?c->leafid:"", c->unupdated);
168
+//static struct tc_device *tc_device_index_del(struct tc_device *d) {
169
+// dictionary_del(tc_device_root_index, string2str(d->id));
170
+// return d;
171
+//}
172
164
- if(unlikely(tc_class_index_del(n, c) != c))
165
- error("plugin_tc: INTERNAL ERROR: attempt remove class '%s' from device '%s': removed a different calls", c->id, n->id);
173
+static inline struct tc_device *tc_device_index_find(const char *id) {
174
+ return dictionary_get(tc_device_root_index, id);
175
+}
176
167
- freez(c->id);
168
- freez(c->name);
169
- freez(c->leafid);
170
- freez(c->parentid);
171
- freez(c);
177
+// ----------------------------------------------------------------------------
178
+
179
+static inline void tc_class_free(struct tc_device *n, struct tc_class *c) {
180
+ debug(D_TC_LOOP, "Removing from device '%s' class '%s', parentid '%s', leafid '%s', unused=%d",
181
+ string2str(n->id), string2str(c->id), string2str(c->parentid), string2str(c->leafid),
182
+ c->unupdated);
183
+
184
+ tc_class_index_del(n, c);
185
}
186
187
static inline void tc_device_classes_cleanup(struct tc_device *d) {
@@ -179,23 +192,20 @@ static inline void tc_device_classes_cleanup(struct tc_device *d) {
192
if(cleanup_every < 0) cleanup_every = -cleanup_every;
193
}
194
182
- d->name_updated = 0;
183
- d->family_updated = 0;
195
+ d->name_updated = false;
196
+ d->family_updated = false;
197
185
- struct tc_class *c = d->classes;
186
- while(c) {
187
- if(unlikely(cleanup_every && c->unupdated >= cleanup_every)) {
188
- struct tc_class *nc = c->next;
198
+ struct tc_class *c;
199
+ dfe_start_unsafe(d->classes, c) {
200
+ if(unlikely(cleanup_every && c->unupdated >= cleanup_every))
201
tc_class_free(d, c);
190
- c = nc;
191
- }
192
- else {
193
- c->updated = 0;
194
- c->name_updated = 0;
202
196
- c = c->next;
203
+ else {
204
+ c->updated = false;
205
+ c->name_updated = false;
206
}
207
}
208
+ dfe_done(c);
209
}
210
211
static inline void tc_device_commit(struct tc_device *d) {
@@ -213,26 +223,26 @@ static inline void tc_device_commit(struct tc_device *d) {
223
224
if(unlikely(d->enabled == (char)-1)) {
225
char var_name[CONFIG_MAX_NAME + 1];
216
- snprintfz(var_name, CONFIG_MAX_NAME, "qos for %s", d->id);
226
+ snprintfz(var_name, CONFIG_MAX_NAME, "qos for %s", string2str(d->id));
227
228
d->enabled = (char)config_get_boolean_ondemand("plugin:tc", var_name, enable_new_interfaces);
229
220
- snprintfz(var_name, CONFIG_MAX_NAME, "traffic chart for %s", d->id);
230
+ snprintfz(var_name, CONFIG_MAX_NAME, "traffic chart for %s", string2str(d->id));
231
d->enabled_bytes = (char)config_get_boolean_ondemand("plugin:tc", var_name, enable_bytes);
232
223
- snprintfz(var_name, CONFIG_MAX_NAME, "packets chart for %s", d->id);
233
+ snprintfz(var_name, CONFIG_MAX_NAME, "packets chart for %s", string2str(d->id));
234
d->enabled_packets = (char)config_get_boolean_ondemand("plugin:tc", var_name, enable_packets);
235
226
- snprintfz(var_name, CONFIG_MAX_NAME, "dropped packets chart for %s", d->id);
236
+ snprintfz(var_name, CONFIG_MAX_NAME, "dropped packets chart for %s", string2str(d->id));
237
d->enabled_dropped = (char)config_get_boolean_ondemand("plugin:tc", var_name, enable_dropped);
238
229
- snprintfz(var_name, CONFIG_MAX_NAME, "tokens chart for %s", d->id);
239
+ snprintfz(var_name, CONFIG_MAX_NAME, "tokens chart for %s", string2str(d->id));
240
d->enabled_tokens = (char)config_get_boolean_ondemand("plugin:tc", var_name, enable_tokens);
241
232
- snprintfz(var_name, CONFIG_MAX_NAME, "ctokens chart for %s", d->id);
242
+ snprintfz(var_name, CONFIG_MAX_NAME, "ctokens chart for %s", string2str(d->id));
243
d->enabled_ctokens = (char)config_get_boolean_ondemand("plugin:tc", var_name, enable_ctokens);
244
235
- snprintfz(var_name, CONFIG_MAX_NAME, "show all classes for %s", d->id);
245
+ snprintfz(var_name, CONFIG_MAX_NAME, "show all classes for %s", string2str(d->id));
246
d->enabled_all_classes_qdiscs = (char)config_get_boolean_ondemand("plugin:tc", var_name, enabled_all_classes_qdiscs);
247
}
248
@@ -244,11 +254,10 @@ static inline void tc_device_commit(struct tc_device *d) {
254
// prepare all classes
255
// we set reasonable defaults for the rest of the code below
256
247
- for(c = d->classes ; c ; c = c->next) {
248
- c->render = 0; // do not render this class
249
-
250
- c->isleaf = 1; // this is a leaf class
251
- c->hasparent = 0; // without a parent
257
+ dfe_start_unsafe(d->classes, c) {
258
+ c->render = false; // do not render this class
259
+ c->isleaf = true; // this is a leaf class
260
+ c->hasparent = false; // without a parent
261
262
if(unlikely(!c->updated))
263
c->unupdated++; // increase its unupdated counter
@@ -262,21 +271,23 @@ static inline void tc_device_commit(struct tc_device *d) {
271
updated_classes++;
272
}
273
}
274
+ dfe_done(c);
275
276
if(unlikely(!d->enabled || (!updated_classes && !updated_qdiscs))) {
267
- debug(D_TC_LOOP, "TC: Ignoring TC device '%s'. It is not enabled/updated.", d->name?d->name:d->id);
277
+ debug(D_TC_LOOP, "TC: Ignoring TC device '%s'. It is not enabled/updated.", string2str(d->name?d->name:d->id));
278
tc_device_classes_cleanup(d);
279
return;
280
}
281
282
if(unlikely(updated_classes && updated_qdiscs)) {
273
- error("TC: device '%s' has active both classes (%d) and qdiscs (%d). Will render only qdiscs.", d->id, updated_classes, updated_qdiscs);
283
+ error("TC: device '%s' has active both classes (%d) and qdiscs (%d). Will render only qdiscs.", string2str(d->id), updated_classes, updated_qdiscs);
284
285
// set all classes to !updated
276
- for(c = d->classes ; c ; c = c->next)
277
- if(unlikely(!c->isqdisc && c->updated))
278
- c->updated = 0;
279
-
286
+ dfe_start_unsafe(d->classes, c) {
287
+ if (unlikely(!c->isqdisc && c->updated))
288
+ c->updated = false;
289
+ }
290
+ dfe_done(c);
291
updated_classes = 0;
292
}
293
@@ -296,8 +307,9 @@ static inline void tc_device_commit(struct tc_device *d) {
307
// so, here we remove the isleaf flag from nodes in the middle
308
// and we add the hasparent flag to leaf nodes we found their parent
309
if(likely(!d->enabled_all_classes_qdiscs)) {
299
- for(c = d->classes; c; c = c->next) {
300
- if(unlikely(!c->updated)) continue;
310
+ dfe_start_unsafe(d->classes, c) {
311
+ if(unlikely(!c->updated))
312
+ continue;
313
314
//debug(D_TC_LOOP, "TC: In device '%s', %s '%s' has leafid: '%s' and parentid '%s'.",
315
// d->id,
@@ -307,30 +319,34 @@ static inline void tc_device_commit(struct tc_device *d) {
319
// c->parentid?c->parentid:"NULL");
320
321
// find if c is leaf or not
310
- for(x = d->classes; x; x = x->next) {
311
- if(unlikely(!x->updated || c == x || !x->parentid)) continue;
322
+ dfe_start_unsafe(d->classes, x) {
323
+ if(unlikely(!x->updated || c == x || !x->parentid))
324
+ continue;
325
326
// classes have both parentid and leafid
327
// qdiscs have only parentid
328
// the following works for both (it is an OR)
329
317
- if((c->hash == x->parent_hash && strcmp(c->id, x->parentid) == 0) ||
318
- (c->leafid && c->leaf_hash == x->parent_hash && strcmp(c->leafid, x->parentid) == 0)) {
330
+ if((x->parentid && c->id == x->parentid) ||
331
+ (c->leafid && x->parentid && c->leafid == x->parentid)) {
332
// debug(D_TC_LOOP, "TC: In device '%s', %s '%s' (leafid: '%s') has as leaf %s '%s' (parentid: '%s').", d->name?d->name:d->id, c->isqdisc?"qdisc":"class", c->name?c->name:c->id, c->leafid?c->leafid:c->id, x->isqdisc?"qdisc":"class", x->name?x->name:x->id, x->parentid?x->parentid:x->id);
320
- c->isleaf = 0;
321
- x->hasparent = 1;
333
+ c->isleaf = false;
334
+ x->hasparent = true;
335
}
336
}
337
+ dfe_done(x);
338
}
339
+ dfe_done(c);
340
}
341
327
- for(c = d->classes ; c ; c = c->next) {
328
- if(unlikely(!c->updated)) continue;
342
+ dfe_start_unsafe(d->classes, c) {
343
+ if(unlikely(!c->updated))
344
+ continue;
345
346
// debug(D_TC_LOOP, "TC: device '%s', %s '%s' isleaf=%d, hasparent=%d", d->id, (c->isqdisc)?"qdisc":"class", c->id, c->isleaf, c->hasparent);
347
348
if(unlikely((c->isleaf && c->hasparent) || d->enabled_all_classes_qdiscs)) {
333
- c->render = 1;
349
+ c->render = true;
350
active_nodes++;
351
bytes_sum += c->bytes;
352
packets_sum += c->packets;
@@ -345,26 +361,29 @@ static inline void tc_device_commit(struct tc_device *d) {
361
// debug(D_TC_LOOP, "TC: found root class/qdisc '%s'", root->id);
362
//}
363
}
364
+ dfe_done(c);
365
366
#ifdef NETDATA_INTERNAL_CHECKS
367
// dump all the list to see what we know
368
369
if(unlikely(debug_flags & D_TC_LOOP)) {
353
- for(c = d->classes ; c ; c = c->next) {
354
- if(c->render) debug(D_TC_LOOP, "TC: final nodes dump for '%s': class %s, OK", d->name, c->id);
355
- else debug(D_TC_LOOP, "TC: final nodes dump for '%s': class %s, IGNORE (updated: %d, isleaf: %d, hasparent: %d, parent: %s)", d->name?d->name:d->id, c->id, c->updated, c->isleaf, c->hasparent, c->parentid?c->parentid:"(unset)");
370
+ dfe_start_unsafe(d->classes, c) {
371
+ if(c->render) debug(D_TC_LOOP, "TC: final nodes dump for '%s': class %s, OK", string2str(d->name), string2str(c->id));
372
+ else debug(D_TC_LOOP, "TC: final nodes dump for '%s': class '%s', IGNORE (updated: %d, isleaf: %d, hasparent: %d, parent: '%s')",
373
+ string2str(d->name?d->name:d->id), string2str(c->id), c->updated, c->isleaf, c->hasparent, string2str(c->parentid));
374
}
375
+ dfe_done(c);
376
}
377
#endif
378
379
if(unlikely(!active_nodes)) {
361
- debug(D_TC_LOOP, "TC: Ignoring TC device '%s'. No useful classes/qdiscs.", d->name?d->name:d->id);
380
+ debug(D_TC_LOOP, "TC: Ignoring TC device '%s'. No useful classes/qdiscs.", string2str(d->name?d->name:d->id));
381
tc_device_classes_cleanup(d);
382
return;
383
}
384
385
debug(D_TC_LOOP, "TC: evaluating TC device '%s'. enabled = %d/%d (bytes: %d/%d, packets: %d/%d, dropped: %d/%d, tokens: %d/%d, ctokens: %d/%d, all_classes_qdiscs: %d/%d), classes: (bytes = %llu, packets = %llu, dropped = %llu, tokens = %llu, ctokens = %llu).",
367
- d->name?d->name:d->id,
386
+ string2str(d->name?d->name:d->id),
387
d->enabled, enable_new_interfaces,
388
d->enabled_bytes, enable_bytes,
389
d->enabled_packets, enable_packets,
@@ -383,44 +402,54 @@ static inline void tc_device_commit(struct tc_device *d) {
402
// bytes
403
404
if(d->enabled_bytes == CONFIG_BOOLEAN_YES || (d->enabled_bytes == CONFIG_BOOLEAN_AUTO &&
386
- (bytes_sum ||
387
- netdata_zero_metrics_enabled == CONFIG_BOOLEAN_YES))) {
405
+ (bytes_sum || netdata_zero_metrics_enabled == CONFIG_BOOLEAN_YES))) {
406
d->enabled_bytes = CONFIG_BOOLEAN_YES;
407
390
- if(unlikely(!d->st_bytes))
408
+ if(unlikely(!d->st_bytes)) {
409
d->st_bytes = rrdset_create_localhost(
392
- RRD_TYPE_TC
393
- , d->id
394
- , d->name ? d->name : d->id
395
- , d->family ? d->family : d->id
396
- , RRD_TYPE_TC ".qos"
397
- , "Class Usage"
398
- , "kilobits/s"
399
- , PLUGIN_TC_NAME
400
- , NULL
401
- , NETDATA_CHART_PRIO_TC_QOS
402
- , localhost->rrd_update_every
403
- , d->enabled_all_classes_qdiscs ? RRDSET_TYPE_LINE : RRDSET_TYPE_STACKED
404
- );
405
-
410
+ RRD_TYPE_TC,
411
+ string2str(d->id),
412
+ string2str(d->name ? d->name : d->id),
413
+ string2str(d->family ? d->family : d->id),
414
+ RRD_TYPE_TC ".qos",
415
+ "Class Usage",
416
+ "kilobits/s",
417
+ PLUGIN_TC_NAME,
418
+ NULL,
419
+ NETDATA_CHART_PRIO_TC_QOS,
420
+ localhost->rrd_update_every,
421
+ d->enabled_all_classes_qdiscs ? RRDSET_TYPE_LINE : RRDSET_TYPE_STACKED);
422
+
423
+ rrdlabels_add(d->st_bytes->state->chart_labels, "device", string2str(d->id), RRDLABEL_SRC_AUTO);
424
+ rrdlabels_add(d->st_bytes->state->chart_labels, "name", string2str(d->name?d->name:d->id), RRDLABEL_SRC_AUTO);
425
+ rrdlabels_add(d->st_bytes->state->chart_labels, "family", string2str(d->family?d->family:d->id), RRDLABEL_SRC_AUTO);
426
+ }
427
else {
428
rrdset_next(d->st_bytes);
408
- if(unlikely(d->name_updated)) rrdset_set_name(d->st_bytes, d->name);
429
+ if(unlikely(d->name_updated)) rrdset_set_name(d->st_bytes, string2str(d->name));
430
+
431
+ if(d->name && d->name_updated)
432
+ rrdlabels_add(d->st_bytes->state->chart_labels, "name", string2str(d->name), RRDLABEL_SRC_AUTO);
433
+
434
+ if(d->family && d->family_updated)
435
+ rrdlabels_add(d->st_bytes->state->chart_labels, "family", string2str(d->family), RRDLABEL_SRC_AUTO);
436
437
// TODO
438
// update the family
439
}
440
414
- for(c = d->classes ; c ; c = c->next) {
441
+ dfe_start_unsafe(d->classes, c) {
442
if(unlikely(!c->render)) continue;
443
444
if(unlikely(!c->rd_bytes))
418
- c->rd_bytes = rrddim_add(d->st_bytes, c->id, c->name?c->name:c->id, 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
445
+ c->rd_bytes = rrddim_add(d->st_bytes, string2str(c->id), string2str(c->name?c->name:c->id), 8, BITS_IN_A_KILOBIT, RRD_ALGORITHM_INCREMENTAL);
446
else if(unlikely(c->name_updated))
420
- rrddim_set_name(d->st_bytes, c->rd_bytes, c->name);
447
+ rrddim_set_name(d->st_bytes, c->rd_bytes, string2str(c->name));
448
449
rrddim_set_by_pointer(d->st_bytes, c->rd_bytes, c->bytes);
450
}
451
+ dfe_done(c);
452
+
453
rrdset_done(d->st_bytes);
454
}
455
@@ -435,47 +464,58 @@ static inline void tc_device_commit(struct tc_device *d) {
464
if(unlikely(!d->st_packets)) {
465
char id[RRD_ID_LENGTH_MAX + 1];
466
char name[RRD_ID_LENGTH_MAX + 1];
438
- snprintfz(id, RRD_ID_LENGTH_MAX, "%s_packets", d->id);
439
- snprintfz(name, RRD_ID_LENGTH_MAX, "%s_packets", d->name?d->name:d->id);
467
+ snprintfz(id, RRD_ID_LENGTH_MAX, "%s_packets", string2str(d->id));
468
+ snprintfz(name, RRD_ID_LENGTH_MAX, "%s_packets", string2str(d->name ? d->name : d->id));
469
470
d->st_packets = rrdset_create_localhost(
442
- RRD_TYPE_TC
443
- , id
444
- , name
445
- , d->family ? d->family : d->id
446
- , RRD_TYPE_TC ".qos_packets"
447
- , "Class Packets"
448
- , "packets/s"
449
- , PLUGIN_TC_NAME
450
- , NULL
451
- , NETDATA_CHART_PRIO_TC_QOS_PACKETS
452
- , localhost->rrd_update_every
453
- , d->enabled_all_classes_qdiscs ? RRDSET_TYPE_LINE : RRDSET_TYPE_STACKED
454
- );
471
+ RRD_TYPE_TC,
472
+ id,
473
+ name,
474
+ string2str(d->family ? d->family : d->id),
475
+ RRD_TYPE_TC ".qos_packets",
476
+ "Class Packets",
477
+ "packets/s",
478
+ PLUGIN_TC_NAME,
479
+ NULL,
480
+ NETDATA_CHART_PRIO_TC_QOS_PACKETS,
481
+ localhost->rrd_update_every,
482
+ d->enabled_all_classes_qdiscs ? RRDSET_TYPE_LINE : RRDSET_TYPE_STACKED);
483
+
484
+ rrdlabels_add(d->st_bytes->state->chart_labels, "device", string2str(d->id), RRDLABEL_SRC_AUTO);
485
+ rrdlabels_add(d->st_bytes->state->chart_labels, "name", string2str(d->name?d->name:d->id), RRDLABEL_SRC_AUTO);
486
+ rrdlabels_add(d->st_bytes->state->chart_labels, "family", string2str(d->family?d->family:d->id), RRDLABEL_SRC_AUTO);
487
}
488
else {
489
rrdset_next(d->st_packets);
490
491
if(unlikely(d->name_updated)) {
492
char name[RRD_ID_LENGTH_MAX + 1];
461
- snprintfz(name, RRD_ID_LENGTH_MAX, "%s_packets", d->name?d->name:d->id);
493
+ snprintfz(name, RRD_ID_LENGTH_MAX, "%s_packets", string2str(d->name?d->name:d->id));
494
rrdset_set_name(d->st_packets, name);
495
}
496
497
+ if(d->name && d->name_updated)
498
+ rrdlabels_add(d->st_bytes->state->chart_labels, "name", string2str(d->name), RRDLABEL_SRC_AUTO);
499
+
500
+ if(d->family && d->family_updated)
501
+ rrdlabels_add(d->st_bytes->state->chart_labels, "family", string2str(d->family), RRDLABEL_SRC_AUTO);
502
+
503
// TODO
504
// update the family
505
}
506
469
- for(c = d->classes ; c ; c = c->next) {
507
+ dfe_start_unsafe(d->classes, c) {
508
if(unlikely(!c->render)) continue;
509
510
if(unlikely(!c->rd_packets))
473
- c->rd_packets = rrddim_add(d->st_packets, c->id, c->name?c->name:c->id, 1, 1, RRD_ALGORITHM_INCREMENTAL);
511
+ c->rd_packets = rrddim_add(d->st_packets, string2str(c->id), string2str(c->name?c->name:c->id), 1, 1, RRD_ALGORITHM_INCREMENTAL);
512
else if(unlikely(c->name_updated))
475
- rrddim_set_name(d->st_packets, c->rd_packets, c->name);
513
+ rrddim_set_name(d->st_packets, c->rd_packets, string2str(c->name));
514
515
rrddim_set_by_pointer(d->st_packets, c->rd_packets, c->packets);
516
}
517
+ dfe_done(c);
518
+
519
rrdset_done(d->st_packets);
520
}
521
@@ -490,47 +530,58 @@ static inline void tc_device_commit(struct tc_device *d) {
530
if(unlikely(!d->st_dropped)) {
531
char id[RRD_ID_LENGTH_MAX + 1];
532
char name[RRD_ID_LENGTH_MAX + 1];
493
- snprintfz(id, RRD_ID_LENGTH_MAX, "%s_dropped", d->id);
494
- snprintfz(name, RRD_ID_LENGTH_MAX, "%s_dropped", d->name?d->name:d->id);
533
+ snprintfz(id, RRD_ID_LENGTH_MAX, "%s_dropped", string2str(d->id));
534
+ snprintfz(name, RRD_ID_LENGTH_MAX, "%s_dropped", string2str(d->name ? d->name : d->id));
535
536
d->st_dropped = rrdset_create_localhost(
497
- RRD_TYPE_TC
498
- , id
499
- , name
500
- , d->family ? d->family : d->id
501
- , RRD_TYPE_TC ".qos_dropped"
502
- , "Class Dropped Packets"
503
- , "packets/s"
504
- , PLUGIN_TC_NAME
505
- , NULL
506
- , NETDATA_CHART_PRIO_TC_QOS_DROPPED
507
- , localhost->rrd_update_every
508
- , d->enabled_all_classes_qdiscs ? RRDSET_TYPE_LINE : RRDSET_TYPE_STACKED
509
- );
537
+ RRD_TYPE_TC,
538
+ id,
539
+ name,
540
+ string2str(d->family ? d->family : d->id),
541
+ RRD_TYPE_TC ".qos_dropped",
542
+ "Class Dropped Packets",
543
+ "packets/s",
544
+ PLUGIN_TC_NAME,
545
+ NULL,
546
+ NETDATA_CHART_PRIO_TC_QOS_DROPPED,
547
+ localhost->rrd_update_every,
548
+ d->enabled_all_classes_qdiscs ? RRDSET_TYPE_LINE : RRDSET_TYPE_STACKED);
549
+
550
+ rrdlabels_add(d->st_bytes->state->chart_labels, "device", string2str(d->id), RRDLABEL_SRC_AUTO);
551
+ rrdlabels_add(d->st_bytes->state->chart_labels, "name", string2str(d->name?d->name:d->id), RRDLABEL_SRC_AUTO);
552
+ rrdlabels_add(d->st_bytes->state->chart_labels, "family", string2str(d->family?d->family:d->id), RRDLABEL_SRC_AUTO);
553
}
554
else {
555
rrdset_next(d->st_dropped);
556
557
if(unlikely(d->name_updated)) {
558
char name[RRD_ID_LENGTH_MAX + 1];
516
- snprintfz(name, RRD_ID_LENGTH_MAX, "%s_dropped", d->name?d->name:d->id);
559
+ snprintfz(name, RRD_ID_LENGTH_MAX, "%s_dropped", string2str(d->name?d->name:d->id));
560
rrdset_set_name(d->st_dropped, name);
561
}
562
563
+ if(d->name && d->name_updated)
564
+ rrdlabels_add(d->st_bytes->state->chart_labels, "name", string2str(d->name), RRDLABEL_SRC_AUTO);
565
+
566
+ if(d->family && d->family_updated)
567
+ rrdlabels_add(d->st_bytes->state->chart_labels, "family", string2str(d->family), RRDLABEL_SRC_AUTO);
568
+
569
// TODO
570
// update the family
571
}
572
524
- for(c = d->classes ; c ; c = c->next) {
573
+ dfe_start_unsafe(d->classes, c) {
574
if(unlikely(!c->render)) continue;
575
576
if(unlikely(!c->rd_dropped))
528
- c->rd_dropped = rrddim_add(d->st_dropped, c->id, c->name?c->name:c->id, 1, 1, RRD_ALGORITHM_INCREMENTAL);
577
+ c->rd_dropped = rrddim_add(d->st_dropped, string2str(c->id), string2str(c->name?c->name:c->id), 1, 1, RRD_ALGORITHM_INCREMENTAL);
578
else if(unlikely(c->name_updated))
530
- rrddim_set_name(d->st_dropped, c->rd_dropped, c->name);
579
+ rrddim_set_name(d->st_dropped, c->rd_dropped, string2str(c->name));
580
581
rrddim_set_by_pointer(d->st_dropped, c->rd_dropped, c->dropped);
582
}
583
+ dfe_done(c);
584
+
585
rrdset_done(d->st_dropped);
586
}
587
@@ -545,48 +596,59 @@ static inline void tc_device_commit(struct tc_device *d) {
596
if(unlikely(!d->st_tokens)) {
597
char id[RRD_ID_LENGTH_MAX + 1];
598
char name[RRD_ID_LENGTH_MAX + 1];
548
- snprintfz(id, RRD_ID_LENGTH_MAX, "%s_tokens", d->id);
549
- snprintfz(name, RRD_ID_LENGTH_MAX, "%s_tokens", d->name?d->name:d->id);
599
+ snprintfz(id, RRD_ID_LENGTH_MAX, "%s_tokens", string2str(d->id));
600
+ snprintfz(name, RRD_ID_LENGTH_MAX, "%s_tokens", string2str(d->name ? d->name : d->id));
601
602
d->st_tokens = rrdset_create_localhost(
552
- RRD_TYPE_TC
553
- , id
554
- , name
555
- , d->family ? d->family : d->id
556
- , RRD_TYPE_TC ".qos_tokens"
557
- , "Class Tokens"
558
- , "tokens"
559
- , PLUGIN_TC_NAME
560
- , NULL
561
- , NETDATA_CHART_PRIO_TC_QOS_TOKENS
562
- , localhost->rrd_update_every
563
- , RRDSET_TYPE_LINE
564
- );
603
+ RRD_TYPE_TC,
604
+ id,
605
+ name,
606
+ string2str(d->family ? d->family : d->id),
607
+ RRD_TYPE_TC ".qos_tokens",
608
+ "Class Tokens",
609
+ "tokens",
610
+ PLUGIN_TC_NAME,
611
+ NULL,
612
+ NETDATA_CHART_PRIO_TC_QOS_TOKENS,
613
+ localhost->rrd_update_every,
614
+ RRDSET_TYPE_LINE);
615
+
616
+ rrdlabels_add(d->st_bytes->state->chart_labels, "device", string2str(d->id), RRDLABEL_SRC_AUTO);
617
+ rrdlabels_add(d->st_bytes->state->chart_labels, "name", string2str(d->name?d->name:d->id), RRDLABEL_SRC_AUTO);
618
+ rrdlabels_add(d->st_bytes->state->chart_labels, "family", string2str(d->family?d->family:d->id), RRDLABEL_SRC_AUTO);
619
}
620
else {
621
rrdset_next(d->st_tokens);
622
623
if(unlikely(d->name_updated)) {
624
char name[RRD_ID_LENGTH_MAX + 1];
571
- snprintfz(name, RRD_ID_LENGTH_MAX, "%s_tokens", d->name?d->name:d->id);
625
+ snprintfz(name, RRD_ID_LENGTH_MAX, "%s_tokens", string2str(d->name?d->name:d->id));
626
rrdset_set_name(d->st_tokens, name);
627
}
628
629
+ if(d->name && d->name_updated)
630
+ rrdlabels_add(d->st_bytes->state->chart_labels, "name", string2str(d->name), RRDLABEL_SRC_AUTO);
631
+
632
+ if(d->family && d->family_updated)
633
+ rrdlabels_add(d->st_bytes->state->chart_labels, "family", string2str(d->family), RRDLABEL_SRC_AUTO);
634
+
635
// TODO
636
// update the family
637
}
638
579
- for(c = d->classes ; c ; c = c->next) {
639
+ dfe_start_unsafe(d->classes, c) {
640
if(unlikely(!c->render)) continue;
641
642
if(unlikely(!c->rd_tokens)) {
583
- c->rd_tokens = rrddim_add(d->st_tokens, c->id, c->name?c->name:c->id, 1, 1, RRD_ALGORITHM_ABSOLUTE);
643
+ c->rd_tokens = rrddim_add(d->st_tokens, string2str(c->id), string2str(c->name?c->name:c->id), 1, 1, RRD_ALGORITHM_ABSOLUTE);
644
}
645
else if(unlikely(c->name_updated))
586
- rrddim_set_name(d->st_tokens, c->rd_tokens, c->name);
646
+ rrddim_set_name(d->st_tokens, c->rd_tokens, string2str(c->name));
647
648
rrddim_set_by_pointer(d->st_tokens, c->rd_tokens, c->tokens);
649
}
650
+ dfe_done(c);
651
+
652
rrdset_done(d->st_tokens);
653
}
654
@@ -601,48 +663,59 @@ static inline void tc_device_commit(struct tc_device *d) {
663
if(unlikely(!d->st_ctokens)) {
664
char id[RRD_ID_LENGTH_MAX + 1];
665
char name[RRD_ID_LENGTH_MAX + 1];
604
- snprintfz(id, RRD_ID_LENGTH_MAX, "%s_ctokens", d->id);
605
- snprintfz(name, RRD_ID_LENGTH_MAX, "%s_ctokens", d->name?d->name:d->id);
666
+ snprintfz(id, RRD_ID_LENGTH_MAX, "%s_ctokens", string2str(d->id));
667
+ snprintfz(name, RRD_ID_LENGTH_MAX, "%s_ctokens", string2str(d->name ? d->name : d->id));
668
669
d->st_ctokens = rrdset_create_localhost(
608
- RRD_TYPE_TC
609
- , id
610
- , name
611
- , d->family ? d->family : d->id
612
- , RRD_TYPE_TC ".qos_ctokens"
613
- , "Class cTokens"
614
- , "ctokens"
615
- , PLUGIN_TC_NAME
616
- , NULL
617
- , NETDATA_CHART_PRIO_TC_QOS_CTOKENS
618
- , localhost->rrd_update_every
619
- , RRDSET_TYPE_LINE
620
- );
670
+ RRD_TYPE_TC,
671
+ id,
672
+ name,
673
+ string2str(d->family ? d->family : d->id),
674
+ RRD_TYPE_TC ".qos_ctokens",
675
+ "Class cTokens",
676
+ "ctokens",
677
+ PLUGIN_TC_NAME,
678
+ NULL,
679
+ NETDATA_CHART_PRIO_TC_QOS_CTOKENS,
680
+ localhost->rrd_update_every,
681
+ RRDSET_TYPE_LINE);
682
+
683
+ rrdlabels_add(d->st_bytes->state->chart_labels, "device", string2str(d->id), RRDLABEL_SRC_AUTO);
684
+ rrdlabels_add(d->st_bytes->state->chart_labels, "name", string2str(d->name?d->name:d->id), RRDLABEL_SRC_AUTO);
685
+ rrdlabels_add(d->st_bytes->state->chart_labels, "family", string2str(d->family?d->family:d->id), RRDLABEL_SRC_AUTO);
686
}
687
else {
623
- debug(D_TC_LOOP, "TC: Updating _ctokens chart for device '%s'", d->name?d->name:d->id);
688
+ debug(D_TC_LOOP, "TC: Updating _ctokens chart for device '%s'", string2str(d->name?d->name:d->id));
689
rrdset_next(d->st_ctokens);
690
691
if(unlikely(d->name_updated)) {
692
char name[RRD_ID_LENGTH_MAX + 1];
628
- snprintfz(name, RRD_ID_LENGTH_MAX, "%s_ctokens", d->name?d->name:d->id);
693
+ snprintfz(name, RRD_ID_LENGTH_MAX, "%s_ctokens", string2str(d->name?d->name:d->id));
694
rrdset_set_name(d->st_ctokens, name);
695
}
696
697
+ if(d->name && d->name_updated)
698
+ rrdlabels_add(d->st_bytes->state->chart_labels, "name", string2str(d->name), RRDLABEL_SRC_AUTO);
699
+
700
+ if(d->family && d->family_updated)
701
+ rrdlabels_add(d->st_bytes->state->chart_labels, "family", string2str(d->family), RRDLABEL_SRC_AUTO);
702
+
703
// TODO
704
// update the family
705
}
706
636
- for(c = d->classes ; c ; c = c->next) {
707
+ dfe_start_unsafe(d->classes, c) {
708
if(unlikely(!c->render)) continue;
709
710
if(unlikely(!c->rd_ctokens))
640
- c->rd_ctokens = rrddim_add(d->st_ctokens, c->id, c->name?c->name:c->id, 1, 1, RRD_ALGORITHM_ABSOLUTE);
711
+ c->rd_ctokens = rrddim_add(d->st_ctokens, string2str(c->id), string2str(c->name?c->name:c->id), 1, 1, RRD_ALGORITHM_ABSOLUTE);
712
else if(unlikely(c->name_updated))
642
- rrddim_set_name(d->st_ctokens, c->rd_ctokens, c->name);
713
+ rrddim_set_name(d->st_ctokens, c->rd_ctokens, string2str(c->name));
714
715
rrddim_set_by_pointer(d->st_ctokens, c->rd_ctokens, c->ctokens);
716
}
717
+ dfe_done(c);
718
+
719
rrdset_done(d->st_ctokens);
720
}
721
@@ -652,18 +725,18 @@ static inline void tc_device_commit(struct tc_device *d) {
725
static inline void tc_device_set_class_name(struct tc_device *d, char *id, char *name) {
726
if(unlikely(!name || !*name)) return;
727
655
- struct tc_class *c = tc_class_index_find(d, id, 0);
728
+ struct tc_class *c = tc_class_index_find(d, id);
729
if(likely(c)) {
730
if(likely(c->name)) {
658
- if(!strcmp(c->name, name)) return;
659
- freez(c->name);
731
+ if(!strcmp(string2str(c->name), name)) return;
732
+ string_freez(c->name);
733
c->name = NULL;
734
}
735
663
- if(likely(name && *name && strcmp(c->id, name) != 0)) {
664
- debug(D_TC_LOOP, "TC: Setting device '%s', class '%s' name to '%s'", d->id, id, name);
665
- c->name = strdupz(name);
666
- c->name_updated = 1;
736
+ if(likely(name && *name && strcmp(string2str(c->id), name) != 0)) {
737
+ debug(D_TC_LOOP, "TC: Setting device '%s', class '%s' name to '%s'", string2str(d->id), id, name);
738
+ c->name = string_strdupz(name);
739
+ c->name_updated = true;
740
}
741
}
742
}
@@ -672,124 +745,68 @@ static inline void tc_device_set_device_name(struct tc_device *d, char *name) {
745
if(unlikely(!name || !*name)) return;
746
747
if(d->name) {
675
- if(!strcmp(d->name, name)) return;
676
- freez(d->name);
748
+ if(!strcmp(string2str(d->name), name)) return;
749
+ string_freez(d->name);
750
d->name = NULL;
751
}
752
680
- if(likely(name && *name && strcmp(d->id, name) != 0)) {
681
- debug(D_TC_LOOP, "TC: Setting device '%s' name to '%s'", d->id, name);
682
- d->name = strdupz(name);
683
- d->name_updated = 1;
753
+ if(likely(name && *name && strcmp(string2str(d->id), name) != 0)) {
754
+ debug(D_TC_LOOP, "TC: Setting device '%s' name to '%s'", string2str(d->id), name);
755
+ d->name = string_strdupz(name);
756
+ d->name_updated = true;
757
}
758
}
759
760
static inline void tc_device_set_device_family(struct tc_device *d, char *family) {
688
- freez(d->family);
761
+ string_freez(d->family);
762
d->family = NULL;
763
691
- if(likely(family && *family && strcmp(d->id, family) != 0)) {
692
- debug(D_TC_LOOP, "TC: Setting device '%s' family to '%s'", d->id, family);
693
- d->family = strdupz(family);
694
- d->family_updated = 1;
764
+ if(likely(family && *family && strcmp(string2str(d->id), family) != 0)) {
765
+ debug(D_TC_LOOP, "TC: Setting device '%s' family to '%s'", string2str(d->id), family);
766
+ d->family = string_strdupz(family);
767
+ d->family_updated = true;
768
}
769
// no need for null termination - it is already null
770
}
771
699
-static inline struct tc_device *tc_device_create(char *id)
700
-{
701
- struct tc_device *d = tc_device_index_find(id, 0);
772
+static inline struct tc_device *tc_device_create(char *id) {
773
+ struct tc_device *d = tc_device_index_find(id);
774
775
if(!d) {
776
debug(D_TC_LOOP, "TC: Creating device '%s'", id);
777
706
- d = callocz(1, sizeof(struct tc_device));
707
-
708
- d->id = strdupz(id);
709
- d->hash = simple_hash(d->id);
710
- d->enabled = (char)-1;
711
-
712
- avl_init(&d->classes_index, tc_class_compare);
713
- if(unlikely(tc_device_index_add(d) != d))
714
- error("plugin_tc: INTERNAL ERROR: removing device '%s' removed a different device.", d->id);
715
-
716
- if(!tc_device_root) {
717
- tc_device_root = d;
718
- }
719
- else {
720
- d->next = tc_device_root;
721
- tc_device_root->prev = d;
722
- tc_device_root = d;
723
- }
778
+ struct tc_device tmp = {
779
+ .id = string_strdupz(id),
780
+ .enabled = (char)-1,
781
+ };
782
+ d = tc_device_index_add(&tmp);
783
}
784
785
return(d);
786
}
787
729
-static inline struct tc_class *tc_class_add(struct tc_device *n, char *id, char qdisc, char *parentid, char *leafid)
730
-{
731
- struct tc_class *c = tc_class_index_find(n, id, 0);
788
+static inline struct tc_class *tc_class_add(struct tc_device *n, char *id, bool qdisc, char *parentid, char *leafid) {
789
+ struct tc_class *c = tc_class_index_find(n, id);
790
791
if(!c) {
734
- debug(D_TC_LOOP, "TC: Creating in device '%s', class id '%s', parentid '%s', leafid '%s'", n->id, id, parentid?parentid:"", leafid?leafid:"");
735
-
736
- c = callocz(1, sizeof(struct tc_class));
792
+ debug(D_TC_LOOP, "TC: Creating in device '%s', class id '%s', parentid '%s', leafid '%s'",
793
+ string2str(n->id), id, parentid?parentid:"", leafid?leafid:"");
794
738
- if(unlikely(!n->classes))
739
- n->classes = c;
740
-
741
- else if(likely(n->last_class)) {
742
- n->last_class->next = c;
743
- c->prev = n->last_class;
744
- }
795
+ struct tc_class tmp = {
796
+ .id = string_strdupz(id),
797
+ .isqdisc = qdisc,
798
+ .parentid = string_strdupz(parentid),
799
+ .leafid = string_strdupz(leafid),
800
+ };
801
746
- n->last_class = c;
747
-
748
- c->id = strdupz(id);
749
- c->hash = simple_hash(c->id);
750
-
751
- c->isqdisc = qdisc;
752
- if(parentid && *parentid) {
753
- c->parentid = strdupz(parentid);
754
- c->parent_hash = simple_hash(c->parentid);
755
- }
756
-
757
- if(leafid && *leafid) {
758
- c->leafid = strdupz(leafid);
759
- c->leaf_hash = simple_hash(c->leafid);
760
- }
761
-
762
- if(unlikely(tc_class_index_add(n, c) != c))
763
- error("plugin_tc: INTERNAL ERROR: attempt index class '%s' on device '%s': already exists", c->id, n->id);
802
+ tc_class_index_add(n, &tmp);
803
}
804
return(c);
805
}
806
768
-static inline void tc_device_free(struct tc_device *n)
769
-{
770
- if(n->next) n->next->prev = n->prev;
771
- if(n->prev) n->prev->next = n->next;
772
- if(tc_device_root == n) {
773
- if(n->next) tc_device_root = n->next;
774
- else tc_device_root = n->prev;
775
- }
776
-
777
- if(unlikely(tc_device_index_del(n) != n))
778
- error("plugin_tc: INTERNAL ERROR: removing device '%s' removed a different device.", n->id);
779
-
780
- while(n->classes) tc_class_free(n, n->classes);
781
-
782
- freez(n->id);
783
- freez(n->name);
784
- freez(n->family);
785
- freez(n);
786
-}
787
-
788
-static inline void tc_device_free_all()
789
-{
790
- while(tc_device_root)
791
- tc_device_free(tc_device_root);
792
-}
807
+//static inline void tc_device_free(struct tc_device *d) {
808
+// tc_device_index_del(d);
809
+//}
810
811
#define PLUGINSD_MAX_WORDS 20
812
@@ -846,6 +863,8 @@ static pid_t tc_child_pid = 0;
863
static void tc_main_cleanup(void *ptr) {
864
worker_unregister();
865
866
+ tc_device_index_destroy();
867
+
868
struct netdata_static_thread *static_thread = (struct netdata_static_thread *)ptr;
869
static_thread->enabled = NETDATA_MAIN_THREAD_EXITING;
870
@@ -876,8 +895,11 @@ static void tc_main_cleanup(void *ptr) {
895
#define WORKER_TC_SETDEVICEGROUP 7
896
#define WORKER_TC_SETCLASSNAME 8
897
#define WORKER_TC_WORKTIME 9
898
+#define WORKER_TC_PLUGIN_TIME 10
899
+#define WORKER_TC_DEVICES 11
900
+#define WORKER_TC_CLASSES 12
901
880
-#if WORKER_UTILIZATION_MAX_JOB_TYPES < 10
902
+#if WORKER_UTILIZATION_MAX_JOB_TYPES < 13
903
#error WORKER_UTILIZATION_MAX_JOB_TYPES has to be at least 10
904
#endif
905
@@ -894,6 +916,11 @@ void *tc_main(void *ptr) {
916
worker_register_job_name(WORKER_TC_SETCLASSNAME, "classname");
917
worker_register_job_name(WORKER_TC_WORKTIME, "worktime");
918
919
+ worker_register_job_custom_metric(WORKER_TC_PLUGIN_TIME, "tc script execution time", "milliseconds/run", WORKER_METRIC_ABSOLUTE);
920
+ worker_register_job_custom_metric(WORKER_TC_DEVICES, "number of devices", "devices", WORKER_METRIC_ABSOLUTE);
921
+ worker_register_job_custom_metric(WORKER_TC_CLASSES, "number of classes", "classes", WORKER_METRIC_ABSOLUTE);
922
+
923
+ tc_device_index_init();
924
netdata_thread_cleanup_push(tc_main_cleanup, ptr);
925
926
char command[FILENAME_MAX + 1];
@@ -969,10 +996,10 @@ void *tc_main(void *ptr) {
996
}
997
998
if(likely(type && id && (parent_is_root || parent_is_parent))) {
972
- char qdisc = 0;
999
+ bool qdisc = false;
1000
1001
if(first_hash == QDISC_HASH) {
975
- qdisc = 1;
1002
+ qdisc = true;
1003
1004
if(!strcmp(type, "ingress")) {
1005
// we don't want to get the ingress qdisc
@@ -1051,10 +1078,10 @@ void *tc_main(void *ptr) {
1078
// debug(D_TC_LOOP, "SENT line '%s'", words[1]);
1079
if(likely(words[1] && *words[1])) {
1080
class->bytes = str2ull(words[1]);
1054
- class->updated = 1;
1081
+ class->updated = true;
1082
}
1083
else {
1057
- class->updated = 0;
1084
+ class->updated = false;
1085
}
1086
1087
if(likely(words[3] && *words[3]))
@@ -1063,24 +1090,24 @@ void *tc_main(void *ptr) {
1090
if(likely(words[6] && *words[6]))
1091
class->dropped = str2ull(words[6]);
1092
1066
- if(likely(words[8] && *words[8]))
1067
- class->overlimits = str2ull(words[8]);
1093
+ //if(likely(words[8] && *words[8]))
1094
+ // class->overlimits = str2ull(words[8]);
1095
1069
- if(likely(words[10] && *words[10]))
1070
- class->requeues = str2ull(words[8]);
1096
+ //if(likely(words[10] && *words[10]))
1097
+ // class->requeues = str2ull(words[8]);
1098
}
1099
else if(unlikely(device && class && class->updated && first_hash == LENDED_HASH && strcmp(words[0], "lended:") == 0)) {
1100
worker_is_busy(WORKER_TC_LENDED);
1101
1102
// debug(D_TC_LOOP, "LENDED line '%s'", words[1]);
1076
- if(likely(words[1] && *words[1]))
1077
- class->lended = str2ull(words[1]);
1103
+ //if(likely(words[1] && *words[1]))
1104
+ // class->lended = str2ull(words[1]);
1105
1079
- if(likely(words[3] && *words[3]))
1080
- class->borrowed = str2ull(words[3]);
1106
+ //if(likely(words[3] && *words[3]))
1107
+ // class->borrowed = str2ull(words[3]);
1108
1082
- if(likely(words[5] && *words[5]))
1083
- class->giants = str2ull(words[5]);
1109
+ //if(likely(words[5] && *words[5]))
1110
+ // class->giants = str2ull(words[5]);
1111
}
1112
else if(unlikely(device && class && class->updated && first_hash == TOKENS_HASH && strcmp(words[0], "tokens:") == 0)) {
1113
worker_is_busy(WORKER_TC_TOKENS);
@@ -1117,33 +1144,19 @@ void *tc_main(void *ptr) {
1144
}
1145
else if(unlikely(first_hash == WORKTIME_HASH && strcmp(words[0], "WORKTIME") == 0)) {
1146
worker_is_busy(WORKER_TC_WORKTIME);
1147
+ worker_set_metric(WORKER_TC_PLUGIN_TIME, str2ll(words[1], NULL));
1148
1121
- // debug(D_TC_LOOP, "WORKTIME line '%s' '%s'", words[1], words[2]);
1122
- static RRDSET *sttime = NULL;
1123
- static RRDDIM *rd_run_time = NULL;
1124
-
1125
- if(unlikely(!sttime)) {
1126
- sttime = rrdset_create_localhost(
1127
- "netdata"
1128
- , "plugin_tc_time"
1129
- , NULL
1130
- , "workers plugin tc"
1131
- , "netdata.workers.tc.script_time"
1132
- , "Netdata TC script execution"
1133
- , "milliseconds/run"
1134
- , PLUGIN_TC_NAME
1135
- , NULL
1136
- , NETDATA_CHART_PRIO_NETDATA_TC_TIME
1137
- , localhost->rrd_update_every
1138
- , RRDSET_TYPE_AREA
1139
- );
1140
- rd_run_time = rrddim_add(sttime, "run_time", "run time", 1, 1, RRD_ALGORITHM_ABSOLUTE);
1141
- }
1142
- else rrdset_next(sttime);
1149
+ size_t number_of_devices = dictionary_stats_entries(tc_device_root_index);
1150
+ size_t number_of_classes = 0;
1151
1144
- rrddim_set_by_pointer(sttime, rd_run_time, str2ll(words[1], NULL));
1145
- rrdset_done(sttime);
1152
+ struct tc_device *d;
1153
+ dfe_start_unsafe(tc_device_root_index, d) {
1154
+ number_of_classes += dictionary_stats_entries(d->classes);
1155
+ }
1156
+ dfe_done(d);
1157
1158
+ worker_set_metric(WORKER_TC_DEVICES, number_of_devices);
1159
+ worker_set_metric(WORKER_TC_CLASSES, number_of_classes);
1160
}
1161
//else {
1162
// debug(D_TC_LOOP, "IGNORED line");
@@ -1162,17 +1175,13 @@ void *tc_main(void *ptr) {
1175
class = NULL;
1176
}
1177
1165
- if(unlikely(netdata_exit)) {
1166
- tc_device_free_all();
1178
+ if(unlikely(netdata_exit))
1179
goto cleanup;
1168
- }
1180
1181
if(code == 1 || code == 127) {
1182
// 1 = DISABLE
1183
// 127 = cannot even run it
1184
error("TC: tc-qos-helper.sh exited with code %d. Disabling it.", code);
1174
-
1175
- tc_device_free_all();
1185
goto cleanup;
1186
}
1187
libnetdata/dictionary/dictionary.h
+1
@@ -199,6 +199,7 @@ typedef DICTFE_CONST struct dictionary_foreach {
199
#define dfe_start_read(dict, value) dfe_start_rw(dict, value, DICTIONARY_LOCK_READ)
200
#define dfe_start_write(dict, value) dfe_start_rw(dict, value, DICTIONARY_LOCK_WRITE)
201
#define dfe_start_reentrant(dict, value) dfe_start_rw(dict, value, DICTIONARY_LOCK_REENTRANT)
202
+#define dfe_start_unsafe(dict, value) dfe_start_rw(dict, value, DICTIONARY_LOCK_NONE)
203
#define dfe_start_rw(dict, value, mode) \
204
do { \
205
DICTFE value ## _dfe = {}; \