@cryptotaxi247 / netdata-1 / commits / 35f61482b

fixed incomplete code in avl.c; added comments about the status of appconfig.c

Costa Tsaousis committed May 12, 2016 at 22:20 UTC 35f61482be4bced0db62e16dc2afa38d8ee8a594
4 files changed +208 -138
src/appconfig.c
+176 -127
@@ -1,3 +1,20 @@
1 +
2 +/*
3 + * TODO
4 + *
5 + * 1. Re-write this using DICTIONARY
6 + *
7 + * FIXME
8 + * The way it is now, concurrency locking is incomplete!
9 + * It makes sure that only one writes to the structures
10 + * but at the same time there may be unlimited readers.
11 + * This can cause crashes.
12 + *
13 + * Of course, rewriting this to use DICTIONARY instead of
14 + * directly accessing AVL structures, will solve the problem.
15 + *
16 + */
17 +
18 #ifdef HAVE_CONFIG_H
19 #include <config.h>
20 #endif
@@ -54,7 +71,35 @@ struct config {
71
72
73 // ----------------------------------------------------------------------------
57 -// config value
74 +// locking
75 +
76 +static inline void config_global_read_lock(void) {
77 + pthread_rwlock_rdlock(&config_rwlock);
78 +}
79 +
80 +static inline void config_global_write_lock(void) {
81 + pthread_rwlock_wrlock(&config_rwlock);
82 +}
83 +
84 +static inline void config_global_unlock(void) {
85 + pthread_rwlock_unlock(&config_rwlock);
86 +}
87 +
88 +static inline void config_section_read_lock(struct config *co) {
89 + pthread_rwlock_rdlock(&co->rwlock);
90 +}
91 +
92 +static inline void config_section_write_lock(struct config *co) {
93 + pthread_rwlock_wrlock(&co->rwlock);
94 +}
95 +
96 +static inline void config_section_unlock(struct config *co) {
97 + pthread_rwlock_unlock(&co->rwlock);
98 +}
99 +
100 +
101 +// ----------------------------------------------------------------------------
102 +// config name-value index
103
104 static int config_value_iterator(avl *a) { if(a) {}; return 0; }
105
@@ -76,8 +121,9 @@ static struct config_value *config_value_index_find(struct config *co, const cha
121 return result;
122 }
123
124 +
125 // ----------------------------------------------------------------------------
80 -// config
126 +// config sections index
127
128 static int config_iterator(avl *a) { if(a) {}; return 0; }
129
@@ -104,39 +150,15 @@ static struct config *config_index_find(const char *name, uint32_t hash) {
150 return result;
151 }
152
107 -struct config_value *config_value_create(struct config *co, const char *name, const char *value)
108 -{
109 - debug(D_CONFIG, "Creating config entry for name '%s', value '%s', in section '%s'.", name, value, co->name);
110 -
111 - struct config_value *cv = calloc(1, sizeof(struct config_value));
112 - if(!cv) fatal("Cannot allocate config_value");
153
114 - cv->name = strdup(name);
115 - if(!cv->name) fatal("Cannot allocate config.name");
116 - cv->hash = simple_hash(cv->name);
117 -
118 - cv->value = strdup(value);
119 - if(!cv->value) fatal("Cannot allocate config.value");
120 -
121 - config_value_index_add(co, cv);
122 -
123 - // no need for string termination, due to calloc()
124 -
125 - pthread_rwlock_wrlock(&co->rwlock);
126 -
127 - struct config_value *cv2 = co->values;
128 - if(cv2) {
129 - while (cv2->next) cv2 = cv2->next;
130 - cv2->next = cv;
131 - }
132 - else co->values = cv;
133 -
134 - pthread_rwlock_unlock(&co->rwlock);
154 +// ----------------------------------------------------------------------------
155 +// config section methods
156
136 - return cv;
157 +static inline struct config *config_section_find(const char *section) {
158 + return config_index_find(section, 0);
159 }
160
139 -struct config *config_create(const char *section)
161 +static inline struct config *config_section_create(const char *section)
162 {
163 debug(D_CONFIG, "Creating section '%s'.", section);
164
@@ -147,14 +169,11 @@ struct config *config_create(const char *section)
169 if(!co->name) fatal("Cannot allocate config.name");
170 co->hash = simple_hash(co->name);
171
150 - pthread_rwlock_init(&co->rwlock, NULL);
172 avl_init_lock(&co->values_index, config_value_compare);
173
153 - config_index_add(co);
154 -
155 - // no need for string termination, due to calloc()
174 + config_global_write_lock();
175
157 - pthread_rwlock_wrlock(&config_rwlock);
176 + config_index_add(co);
177
178 struct config *co2 = config_root;
179 if(co2) {
@@ -163,98 +182,43 @@ struct config *config_create(const char *section)
182 }
183 else config_root = co;
184
166 - pthread_rwlock_unlock(&config_rwlock);
185 + config_global_unlock();
186
187 return co;
188 }
189
171 -struct config *config_find_section(const char *section)
172 -{
173 - return config_index_find(section, 0);
174 -}
190
176 -int load_config(char *filename, int overwrite_used)
177 -{
178 - int line = 0;
179 - struct config *co = NULL;
180 -
181 - char buffer[CONFIG_FILE_LINE_MAX + 1], *s;
182 -
183 - if(!filename) filename = CONFIG_DIR "/" CONFIG_FILENAME;
184 - FILE *fp = fopen(filename, "r");
185 - if(!fp) {
186 - error("Cannot open file '%s'", filename);
187 - return 0;
188 - }
189 -
190 - while(fgets(buffer, CONFIG_FILE_LINE_MAX, fp) != NULL) {
191 - buffer[CONFIG_FILE_LINE_MAX] = '\0';
192 - line++;
193 -
194 - s = trim(buffer);
195 - if(!s) {
196 - debug(D_CONFIG, "Ignoring line %d, it is empty.", line);
197 - continue;
198 - }
199 -
200 - int len = (int) strlen(s);
201 - if(*s == '[' && s[len - 1] == ']') {
202 - // new section
203 - s[len - 1] = '\0';
204 - s++;
191 +// ----------------------------------------------------------------------------
192 +// config name-value methods
193
206 - co = config_find_section(s);
207 - if(!co) co = config_create(s);
194 +static inline struct config_value *config_value_create(struct config *co, const char *name, const char *value)
195 +{
196 + debug(D_CONFIG, "Creating config entry for name '%s', value '%s', in section '%s'.", name, value, co->name);
197
209 - continue;
210 - }
198 + struct config_value *cv = calloc(1, sizeof(struct config_value));
199 + if(!cv) fatal("Cannot allocate config_value");
200
212 - if(!co) {
213 - // line outside a section
214 - error("Ignoring line %d ('%s'), it is outside all sections.", line, s);
215 - continue;
216 - }
201 + cv->name = strdup(name);
202 + if(!cv->name) fatal("Cannot allocate config.name");
203 + cv->hash = simple_hash(cv->name);
204
218 - char *name = s;
219 - char *value = strchr(s, '=');
220 - if(!value) {
221 - error("Ignoring line %d ('%s'), there is no = in it.", line, s);
222 - continue;
223 - }
224 - *value = '\0';
225 - value++;
205 + cv->value = strdup(value);
206 + if(!cv->value) fatal("Cannot allocate config.value");
207
227 - name = trim(name);
228 - value = trim(value);
208 + config_section_write_lock(co);
209
230 - if(!name) {
231 - error("Ignoring line %d, name is empty.", line);
232 - continue;
233 - }
234 - if(!value) {
235 - debug(D_CONFIG, "Ignoring line %d, value is empty.", line);
236 - continue;
237 - }
238 -
239 - struct config_value *cv = config_value_index_find(co, name, 0);
210 + config_value_index_add(co, cv);
211
241 - if(!cv) cv = config_value_create(co, name, value);
242 - else {
243 - if(((cv->flags & CONFIG_VALUE_USED) && overwrite_used) || !(cv->flags & CONFIG_VALUE_USED)) {
244 - debug(D_CONFIG, "Overwriting '%s/%s'.", line, co->name, cv->name);
245 - free(cv->value);
246 - cv->value = strdup(value);
247 - if(!cv->value) fatal("Cannot allocate config.value");
248 - }
249 - else
250 - debug(D_CONFIG, "Ignoring line %d, '%s/%s' is already present and used.", line, co->name, cv->name);
251 - }
252 - cv->flags |= CONFIG_VALUE_LOADED;
212 + struct config_value *cv2 = co->values;
213 + if(cv2) {
214 + while (cv2->next) cv2 = cv2->next;
215 + cv2->next = cv;
216 }
217 + else co->values = cv;
218
255 - fclose(fp);
219 + config_section_unlock(co);
220
257 - return 1;
221 + return cv;
222 }
223
224 char *config_get(const char *section, const char *name, const char *default_value)
@@ -263,8 +227,8 @@ char *config_get(const char *section, const char *name, const char *default_valu
227
228 debug(D_CONFIG, "request to get config in section '%s', name '%s', default_value '%s'", section, name, default_value);
229
266 - struct config *co = config_find_section(section);
267 - if(!co) co = config_create(section);
230 + struct config *co = config_section_find(section);
231 + if(!co) co = config_section_create(section);
232
233 cv = config_value_index_find(co, name, 0);
234 if(!cv) {
@@ -341,7 +305,7 @@ const char *config_set_default(const char *section, const char *name, const char
305
306 debug(D_CONFIG, "request to set config in section '%s', name '%s', value '%s'", section, name, value);
307
344 - struct config *co = config_find_section(section);
308 + struct config *co = config_section_find(section);
309 if(!co) return config_set(section, name, value);
310
311 cv = config_value_index_find(co, name, 0);
@@ -369,8 +333,8 @@ const char *config_set(const char *section, const char *name, const char *value)
333
334 debug(D_CONFIG, "request to set config in section '%s', name '%s', value '%s'", section, name, value);
335
372 - struct config *co = config_find_section(section);
373 - if(!co) co = config_create(section);
336 + struct config *co = config_section_find(section);
337 + if(!co) co = config_section_create(section);
338
339 cv = config_value_index_find(co, name, 0);
340 if(!cv) cv = config_value_create(co, name, value);
@@ -408,6 +372,94 @@ int config_set_boolean(const char *section, const char *name, int value)
372 return value;
373 }
374
375 +
376 +// ----------------------------------------------------------------------------
377 +// config load/save
378 +
379 +int load_config(char *filename, int overwrite_used)
380 +{
381 + int line = 0;
382 + struct config *co = NULL;
383 +
384 + char buffer[CONFIG_FILE_LINE_MAX + 1], *s;
385 +
386 + if(!filename) filename = CONFIG_DIR "/" CONFIG_FILENAME;
387 + FILE *fp = fopen(filename, "r");
388 + if(!fp) {
389 + error("Cannot open file '%s'", filename);
390 + return 0;
391 + }
392 +
393 + while(fgets(buffer, CONFIG_FILE_LINE_MAX, fp) != NULL) {
394 + buffer[CONFIG_FILE_LINE_MAX] = '\0';
395 + line++;
396 +
397 + s = trim(buffer);
398 + if(!s) {
399 + debug(D_CONFIG, "Ignoring line %d, it is empty.", line);
400 + continue;
401 + }
402 +
403 + int len = (int) strlen(s);
404 + if(*s == '[' && s[len - 1] == ']') {
405 + // new section
406 + s[len - 1] = '\0';
407 + s++;
408 +
409 + co = config_section_find(s);
410 + if(!co) co = config_section_create(s);
411 +
412 + continue;
413 + }
414 +
415 + if(!co) {
416 + // line outside a section
417 + error("Ignoring line %d ('%s'), it is outside all sections.", line, s);
418 + continue;
419 + }
420 +
421 + char *name = s;
422 + char *value = strchr(s, '=');
423 + if(!value) {
424 + error("Ignoring line %d ('%s'), there is no = in it.", line, s);
425 + continue;
426 + }
427 + *value = '\0';
428 + value++;
429 +
430 + name = trim(name);
431 + value = trim(value);
432 +
433 + if(!name) {
434 + error("Ignoring line %d, name is empty.", line);
435 + continue;
436 + }
437 + if(!value) {
438 + debug(D_CONFIG, "Ignoring line %d, value is empty.", line);
439 + continue;
440 + }
441 +
442 + struct config_value *cv = config_value_index_find(co, name, 0);
443 +
444 + if(!cv) cv = config_value_create(co, name, value);
445 + else {
446 + if(((cv->flags & CONFIG_VALUE_USED) && overwrite_used) || !(cv->flags & CONFIG_VALUE_USED)) {
447 + debug(D_CONFIG, "Overwriting '%s/%s'.", line, co->name, cv->name);
448 + free(cv->value);
449 + cv->value = strdup(value);
450 + if(!cv->value) fatal("Cannot allocate config.value");
451 + }
452 + else
453 + debug(D_CONFIG, "Ignoring line %d, '%s/%s' is already present and used.", line, co->name, cv->name);
454 + }
455 + cv->flags |= CONFIG_VALUE_LOADED;
456 + }
457 +
458 + fclose(fp);
459 +
460 + return 1;
461 +}
462 +
463 void generate_config(BUFFER *wb, int only_changed)
464 {
465 int i, pri;
@@ -433,7 +485,7 @@ void generate_config(BUFFER *wb, int only_changed)
485 break;
486 }
487
436 - pthread_rwlock_wrlock(&config_rwlock);
488 + config_global_write_lock();
489 for(co = config_root; co ; co = co->next) {
490 if(strcmp(co->name, "global") == 0 || strcmp(co->name, "plugins") == 0 || strcmp(co->name, "registry") == 0) pri = 0;
491 else if(strncmp(co->name, "plugin:", 7) == 0) pri = 1;
@@ -444,15 +496,13 @@ void generate_config(BUFFER *wb, int only_changed)
496 int changed = 0;
497 int count = 0;
498
447 - pthread_rwlock_wrlock(&co->rwlock);
448 -
499 + config_section_write_lock(co);
500 for(cv = co->values; cv ; cv = cv->next) {
501 used += (cv->flags & CONFIG_VALUE_USED)?1:0;
502 changed += (cv->flags & CONFIG_VALUE_CHANGED)?1:0;
503 count++;
504 }
454 -
455 - pthread_rwlock_unlock(&co->rwlock);
505 + config_section_unlock(co);
506
507 if(!count) continue;
508 if(only_changed && !changed) continue;
@@ -463,7 +513,7 @@ void generate_config(BUFFER *wb, int only_changed)
513
514 buffer_sprintf(wb, "\n[%s]\n", co->name);
515
466 - pthread_rwlock_wrlock(&co->rwlock);
516 + config_section_write_lock(co);
517 for(cv = co->values; cv ; cv = cv->next) {
518
519 if(used && !(cv->flags & CONFIG_VALUE_USED)) {
@@ -471,10 +521,9 @@ void generate_config(BUFFER *wb, int only_changed)
521 }
522 buffer_sprintf(wb, "\t%s%s = %s\n", ((!(cv->flags & CONFIG_VALUE_CHANGED)) && (cv->flags & CONFIG_VALUE_USED))?"# ":"", cv->name, cv->value);
523 }
474 - pthread_rwlock_unlock(&co->rwlock);
524 + config_section_unlock(co);
525 }
526 }
477 - pthread_rwlock_unlock(&config_rwlock);
527 + config_global_unlock();
528 }
529 }
480 -
src/apps_plugin.c
+13
@@ -39,6 +39,10 @@
39 #include "procfile.h"
40 #include "../config.h"
41
42 +#ifdef NETDATA_INTERNAL_CHECKS
43 +#include <sys/prctl.h>
44 +#endif
45 +
46 #define MAX_COMPARE_NAME 100
47 #define MAX_NAME 100
48 #define MAX_CMDLINE 1024
@@ -2408,6 +2412,15 @@ int main(int argc, char **argv)
2412 }
2413 else info("Found NETDATA_CONFIG_DIR='%s'", config_dir);
2414
2415 +#ifdef NETDATA_INTERNAL_CHECKS
2416 + if(debug_flags != 0) {
2417 + struct rlimit rl = { RLIM_INFINITY, RLIM_INFINITY };
2418 + if(setrlimit(RLIMIT_CORE, &rl) != 0)
2419 + info("Cannot request unlimited core dumps for debugging... Proceeding anyway...");
2420 + prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
2421 + }
2422 +#endif /* NETDATA_INTERNAL_CHECKS */
2423 +
2424 info("starting...");
2425
2426 procfile_adaptive_initial_allocation = 1;
src/avl.c
+16 -6
@@ -316,7 +316,17 @@ void avl_init(avl_tree *t, int (*compar)(void *a, void *b)) {
316
317 /* ------------------------------------------------------------------------- */
318
319 -void avl_lock(avl_tree_lock *t) {
319 +void avl_read_lock(avl_tree_lock *t) {
320 +#ifndef AVL_WITHOUT_PTHREADS
321 +#ifdef AVL_LOCK_WITH_MUTEX
322 + pthread_mutex_lock(&t->mutex);
323 +#else
324 + pthread_rwlock_rdlock(&t->rwlock);
325 +#endif
326 +#endif /* AVL_WITHOUT_PTHREADS */
327 +}
328 +
329 +void avl_write_lock(avl_tree_lock *t) {
330 #ifndef AVL_WITHOUT_PTHREADS
331 #ifdef AVL_LOCK_WITH_MUTEX
332 pthread_mutex_lock(&t->mutex);
@@ -357,29 +367,29 @@ void avl_init_lock(avl_tree_lock *t, int (*compar)(void *a, void *b)) {
367 }
368
369 int avl_range_lock(avl_tree_lock *t, avl *a, avl *b, int (*iter)(avl *), avl **ret) {
360 - avl_lock(t);
370 + avl_read_lock(t);
371 int ret2 = avl_range(&t->avl_tree, a, b, iter, ret);
372 avl_unlock(t);
373 return ret2;
374 }
375
376 int avl_removeroot_lock(avl_tree_lock *t) {
367 - avl_lock(t);
377 + avl_write_lock(t);
378 int ret = avl_removeroot(&t->avl_tree);
379 avl_unlock(t);
380 return ret;
381 }
382
383 int avl_remove_lock(avl_tree_lock *t, avl *a) {
374 - avl_lock(t);
384 + avl_write_lock(t);
385 int ret = avl_remove(&t->avl_tree, a);
386 avl_unlock(t);
387 return ret;
388 }
389
390 int avl_insert_lock(avl_tree_lock *t, avl *a) {
381 - avl_lock(t);
391 + avl_write_lock(t);
392 int ret = avl_insert(&t->avl_tree, a);
383 - avl_lock(t);
393 + avl_unlock(t);
394 return ret;
395 }
src/main.c
+3 -5
@@ -496,18 +496,17 @@ int main(int argc, char **argv)
496 // never become a problem
497 if(nice(20) == -1) error("Cannot lower my CPU priority.");
498
499 - if(become_daemon(dont_fork, 0, user, input_log_file, output_log_file, error_log_file, access_log_file, &access_fd, &stdaccess) == -1) {
499 + if(become_daemon(dont_fork, 0, user, input_log_file, output_log_file, error_log_file, access_log_file, &access_fd, &stdaccess) == -1)
500 fatal("Cannot demonize myself.");
501 - exit(1);
502 - }
501
502 +#ifdef NETDATA_INTERNAL_CHECKS
503 if(debug_flags != 0) {
504 struct rlimit rl = { RLIM_INFINITY, RLIM_INFINITY };
505 if(setrlimit(RLIMIT_CORE, &rl) != 0)
506 info("Cannot request unlimited core dumps for debugging... Proceeding anyway...");
508 -
507 prctl(PR_SET_DUMPABLE, 1, 0, 0, 0);
508 }
509 +#endif /* NETDATA_INTERNAL_CHECKS */
510
511 if(output_log_syslog || error_log_syslog || access_log_syslog)
512 openlog("netdata", LOG_PID, LOG_DAEMON);
@@ -515,7 +514,6 @@ int main(int argc, char **argv)
514 info("NetData started on pid %d", getpid());
515
516
518 -
517 // ------------------------------------------------------------------------
518 // get default pthread stack size
519