]> arthur.barton.de Git - netdata.git/commitdiff
Merge remote-tracking branch 'upstream/master' into health
authorCosta Tsaousis <costa@tsaousis.gr>
Thu, 11 Aug 2016 17:33:30 +0000 (20:33 +0300)
committerCosta Tsaousis <costa@tsaousis.gr>
Thu, 11 Aug 2016 17:33:30 +0000 (20:33 +0300)
71 files changed:
CMakeLists.txt
profile/benchmark-dictionary.c
profile/benchmark-registry.c
profile/test-eval.c [new file with mode: 0644]
src/Makefile.am
src/appconfig.c
src/appconfig.h
src/apps_plugin.c
src/avl.c
src/common.c
src/common.h
src/daemon.c
src/dictionary.c
src/dictionary.h
src/eval.c [new file with mode: 0644]
src/eval.h [new file with mode: 0644]
src/global_statistics.c
src/health.c [new file with mode: 0644]
src/health.h [new file with mode: 0644]
src/log.c
src/log.h
src/main.c
src/main.h
src/plugin_checks.c
src/plugin_idlejitter.c
src/plugin_nfacct.c
src/plugin_proc.c
src/plugin_tc.c
src/plugins_d.c
src/plugins_d.h
src/popen.c
src/popen.h
src/proc_diskstats.c
src/proc_interrupts.c
src/proc_loadavg.c
src/proc_meminfo.c
src/proc_net_dev.c
src/proc_net_ip_vs_stats.c
src/proc_net_netstat.c
src/proc_net_rpc_nfsd.c
src/proc_net_snmp.c
src/proc_net_snmp6.c
src/proc_net_stat_conntrack.c
src/proc_net_stat_synproxy.c
src/proc_self_mountinfo.c
src/proc_self_mountinfo.h
src/proc_softirqs.c
src/proc_stat.c
src/proc_sys_kernel_random_entropy_avail.c
src/proc_vmstat.c
src/procfile.c
src/registry.c
src/registry.h
src/rrd.c
src/rrd.h
src/rrd2json.c
src/rrd2json.h
src/storage_number.c
src/storage_number.h
src/sys_fs_cgroup.c
src/sys_kernel_mm_ksm.c
src/unit_test.c
src/url.c
src/web_buffer.c
src/web_buffer.h
src/web_buffer_svg.c
src/web_buffer_svg.h
src/web_client.c
src/web_client.h
src/web_server.c
web/index.html

index 30ea5fbf41056ae04636c6ec0acca0d87e1c88c8..d5e6d195e3b277b66913d99e5545306e7d286864 100755 (executable)
@@ -82,7 +82,7 @@ set(NETDATA_SOURCE_FILES
         src/web_client.h
         src/web_server.c
         src/web_server.h
-        config.h)
+        config.h src/health.h src/health.c src/eval.h src/eval.c)
 
 set(APPS_PLUGIN_SOURCE_FILES
         src/appconfig.c
index 846e3c61ac7427c333aabb32f061b5db273dd176..8ec3ae0318b4b266f1dad18fc250af9058062da6 100644 (file)
@@ -7,13 +7,6 @@
  *
  */
 
-#include <stdio.h>
-#include <stdlib.h>
-#include <inttypes.h>
-
-#include "dictionary.h"
-#include "main.h"
-#include "log.h"
 #include "common.h"
 
 struct myvalue {
index 68475eae09427b05d322dfe02aa86ac02c9e0f26..fd771a7a78e53f56d16db9af2e6a81370e5343fb 100755 (executable)
@@ -1,13 +1,15 @@
 
 /*
  * compile with
- *  gcc -O1 -ggdb -Wall -Wextra -I ../src/ -I ../ -o benchmark-registry benchmark-registry.c ../src/dictionary.o ../src/log.o ../src/avl.o ../src/common.o ../src/appconfig.o ../src/web_buffer.o ../src/storage_number.o ../src/rrd.o -pthread -luuid -lm -DHAVE_CONFIG_H -DVARLIB_DIR="\"/tmp\""
+ *  gcc -O1 -ggdb -Wall -Wextra -I ../src/ -I ../ -o benchmark-registry benchmark-registry.c ../src/dictionary.o ../src/log.o ../src/avl.o ../src/common.o ../src/appconfig.o ../src/web_buffer.o ../src/storage_number.o ../src/rrd.o ../src/health.o -pthread -luuid -lm -DHAVE_CONFIG_H -DVARLIB_DIR="\"/tmp\""
  */
 
 char *hostname = "me";
 
 #include "../src/registry.c"
 
+void netdata_cleanup_and_exit(int ret) { exit(ret); }
+
 // ----------------------------------------------------------------------------
 // TESTS
 
diff --git a/profile/test-eval.c b/profile/test-eval.c
new file mode 100644 (file)
index 0000000..2fc8678
--- /dev/null
@@ -0,0 +1,288 @@
+
+/*
+ * 1. build netdata (as normally)
+ * 2. cd profile/
+ * 3. compile with:
+ *    gcc -O1 -ggdb -Wall -Wextra -I ../src/ -I ../ -o test-eval test-eval.c ../src/log.o ../src/eval.o ../src/common.o ../src/web_buffer.o ../src/storage_number.o -pthread -lm
+ *
+ */
+
+#include "common.h"
+
+void netdata_cleanup_and_exit(int ret) { exit(ret); }
+
+/*
+void indent(int level, int show) {
+       int i = level;
+       while(i--) printf(" |  ");
+       if(show) printf(" \\_ ");
+       else printf(" \\_  ");
+}
+
+void print_node(EVAL_NODE *op, int level);
+
+void print_value(EVAL_VALUE *v, int level) {
+       indent(level, 0);
+
+       switch(v->type) {
+               case EVAL_VALUE_INVALID:
+                       printf("value (NOP)\n");
+                       break;
+
+               case EVAL_VALUE_NUMBER:
+                       printf("value %Lf (NUMBER)\n", v->number);
+                       break;
+
+               case EVAL_VALUE_EXPRESSION:
+                       printf("value (SUB-EXPRESSION)\n");
+                       print_node(v->expression, level+1);
+                       break;
+
+               default:
+                       printf("value (INVALID type %d)\n", v->type);
+                       break;
+
+       }
+}
+
+void print_node(EVAL_NODE *op, int level) {
+
+//     if(op->operator != EVAL_OPERATOR_NOP) {
+               indent(level, 1);
+               if(op->operator) printf("%c (node %d, precedence: %d)\n", op->operator, op->id, op->precedence);
+               else printf("NOP (node %d, precedence: %d)\n", op->id, op->precedence);
+//     }
+
+       int i = op->count;
+       while(i--) print_value(&op->ops[i], level + 1);
+}
+
+calculated_number evaluate(EVAL_NODE *op, int depth);
+
+calculated_number evaluate_value(EVAL_VALUE *v, int depth) {
+       switch(v->type) {
+               case EVAL_VALUE_NUMBER:
+                       return v->number;
+
+               case EVAL_VALUE_EXPRESSION:
+                       return evaluate(v->expression, depth);
+
+               default:
+                       fatal("I don't know how to handle EVAL_VALUE type %d", v->type);
+       }
+}
+
+void print_depth(int depth) {
+       static int count = 0;
+
+       printf("%d. ", ++count);
+       while(depth--) printf("    ");
+}
+
+calculated_number evaluate(EVAL_NODE *op, int depth) {
+       calculated_number n1, n2, r;
+
+       switch(op->operator) {
+               case EVAL_OPERATOR_SIGN_PLUS:
+                       r = evaluate_value(&op->ops[0], depth);
+                       break;
+
+               case EVAL_OPERATOR_SIGN_MINUS:
+                       r = -evaluate_value(&op->ops[0], depth);
+                       break;
+
+               case EVAL_OPERATOR_PLUS:
+                       if(op->count != 2)
+                               fatal("Operator '%c' requires 2 values, but we have %d", op->operator, op->count);
+                       n1 = evaluate_value(&op->ops[0], depth);
+                       n2 = evaluate_value(&op->ops[1], depth);
+                       r = n1 + n2;
+                       print_depth(depth);
+                       printf("%Lf = %Lf + %Lf\n", r, n1, n2);
+                       break;
+
+               case EVAL_OPERATOR_MINUS:
+                       if(op->count != 2)
+                               fatal("Operator '%c' requires 2 values, but we have %d", op->operator, op->count);
+                       n1 = evaluate_value(&op->ops[0], depth);
+                       n2 = evaluate_value(&op->ops[1], depth);
+                       r = n1 - n2;
+                       print_depth(depth);
+                       printf("%Lf = %Lf - %Lf\n", r, n1, n2);
+                       break;
+
+               case EVAL_OPERATOR_MULTIPLY:
+                       if(op->count != 2)
+                               fatal("Operator '%c' requires 2 values, but we have %d", op->operator, op->count);
+                       n1 = evaluate_value(&op->ops[0], depth);
+                       n2 = evaluate_value(&op->ops[1], depth);
+                       r = n1 * n2;
+                       print_depth(depth);
+                       printf("%Lf = %Lf * %Lf\n", r, n1, n2);
+                       break;
+
+               case EVAL_OPERATOR_DIVIDE:
+                       if(op->count != 2)
+                               fatal("Operator '%c' requires 2 values, but we have %d", op->operator, op->count);
+                       n1 = evaluate_value(&op->ops[0], depth);
+                       n2 = evaluate_value(&op->ops[1], depth);
+                       r = n1 / n2;
+                       print_depth(depth);
+                       printf("%Lf = %Lf / %Lf\n", r, n1, n2);
+                       break;
+
+               case EVAL_OPERATOR_NOT:
+                       n1 = evaluate_value(&op->ops[0], depth);
+                       r = !n1;
+                       print_depth(depth);
+                       printf("%Lf = NOT %Lf\n", r, n1);
+                       break;
+
+               case EVAL_OPERATOR_AND:
+                       if(op->count != 2)
+                               fatal("Operator '%c' requires 2 values, but we have %d", op->operator, op->count);
+                       n1 = evaluate_value(&op->ops[0], depth);
+                       n2 = evaluate_value(&op->ops[1], depth);
+                       r = n1 && n2;
+                       print_depth(depth);
+                       printf("%Lf = %Lf AND %Lf\n", r, n1, n2);
+                       break;
+
+               case EVAL_OPERATOR_OR:
+                       if(op->count != 2)
+                               fatal("Operator '%c' requires 2 values, but we have %d", op->operator, op->count);
+                       n1 = evaluate_value(&op->ops[0], depth);
+                       n2 = evaluate_value(&op->ops[1], depth);
+                       r = n1 || n2;
+                       print_depth(depth);
+                       printf("%Lf = %Lf OR %Lf\n", r, n1, n2);
+                       break;
+
+               case EVAL_OPERATOR_GREATER_THAN_OR_EQUAL:
+                       if(op->count != 2)
+                               fatal("Operator '%c' requires 2 values, but we have %d", op->operator, op->count);
+                       n1 = evaluate_value(&op->ops[0], depth);
+                       n2 = evaluate_value(&op->ops[1], depth);
+                       r = n1 >= n2;
+                       print_depth(depth);
+                       printf("%Lf = %Lf >= %Lf\n", r, n1, n2);
+                       break;
+
+               case EVAL_OPERATOR_LESS_THAN_OR_EQUAL:
+                       if(op->count != 2)
+                               fatal("Operator '%c' requires 2 values, but we have %d", op->operator, op->count);
+                       n1 = evaluate_value(&op->ops[0], depth);
+                       n2 = evaluate_value(&op->ops[1], depth);
+                       r = n1 <= n2;
+                       print_depth(depth);
+                       printf("%Lf = %Lf <= %Lf\n", r, n1, n2);
+                       break;
+
+               case EVAL_OPERATOR_GREATER:
+                       if(op->count != 2)
+                               fatal("Operator '%c' requires 2 values, but we have %d", op->operator, op->count);
+                       n1 = evaluate_value(&op->ops[0], depth);
+                       n2 = evaluate_value(&op->ops[1], depth);
+                       r = n1 > n2;
+                       print_depth(depth);
+                       printf("%Lf = %Lf > %Lf\n", r, n1, n2);
+                       break;
+
+               case EVAL_OPERATOR_LESS:
+                       if(op->count != 2)
+                               fatal("Operator '%c' requires 2 values, but we have %d", op->operator, op->count);
+                       n1 = evaluate_value(&op->ops[0], depth);
+                       n2 = evaluate_value(&op->ops[1], depth);
+                       r = n1 < n2;
+                       print_depth(depth);
+                       printf("%Lf = %Lf < %Lf\n", r, n1, n2);
+                       break;
+
+               case EVAL_OPERATOR_NOT_EQUAL:
+                       if(op->count != 2)
+                               fatal("Operator '%c' requires 2 values, but we have %d", op->operator, op->count);
+                       n1 = evaluate_value(&op->ops[0], depth);
+                       n2 = evaluate_value(&op->ops[1], depth);
+                       r = n1 != n2;
+                       print_depth(depth);
+                       printf("%Lf = %Lf <> %Lf\n", r, n1, n2);
+                       break;
+
+               case EVAL_OPERATOR_EQUAL:
+                       if(op->count != 2)
+                               fatal("Operator '%c' requires 2 values, but we have %d", op->operator, op->count);
+                       n1 = evaluate_value(&op->ops[0], depth);
+                       n2 = evaluate_value(&op->ops[1], depth);
+                       r = n1 == n2;
+                       print_depth(depth);
+                       printf("%Lf = %Lf == %Lf\n", r, n1, n2);
+                       break;
+
+               case EVAL_OPERATOR_EXPRESSION_OPEN:
+                       printf("BEGIN SUB-EXPRESSION\n");
+                       r = evaluate_value(&op->ops[0], depth + 1);
+                       printf("END SUB-EXPRESSION\n");
+                       break;
+
+               case EVAL_OPERATOR_NOP:
+               case EVAL_OPERATOR_VALUE:
+                       r = evaluate_value(&op->ops[0], depth);
+                       break;
+
+               default:
+                       error("I don't know how to handle operator '%c'", op->operator);
+                       r = 0;
+                       break;
+       }
+
+       return r;
+}
+
+
+void print_expression(EVAL_NODE *op, const char *failed_at, int error) {
+       if(op) {
+               printf("expression tree:\n");
+               print_node(op, 0);
+
+               printf("\nevaluation steps:\n");
+               evaluate(op, 0);
+               
+               int error;
+               calculated_number ret = expression_evaluate(op, &error);
+               printf("\ninternal evaluator:\nSTATUS: %d, RESULT = %Lf\n", error, ret);
+
+               expression_free(op);
+       }
+       else {
+               printf("error: %d, failed_at: '%s'\n", error, (failed_at)?failed_at:"<NONE>");
+       }
+}
+*/
+
+int main(int argc, char **argv) {
+       if(argc != 2) {
+               fprintf(stderr, "I need an epxression (enclose it in single-quotes (') as a single parameter)\n");
+               exit(1);
+       }
+
+       const char *failed_at = NULL;
+       int error;
+
+       EVAL_EXPRESSION *exp = expression_parse(argv[1], &failed_at, &error);
+       if(!exp)
+               printf("\nFAILED\nExpression: '%s'\nParsing stopped at: '%s'\nError code: %d (%s)\n", argv[1], (failed_at)?((*failed_at)?failed_at:"<END OF EXPRESSION>"):"<NONE>", error, expression_strerror(error));
+       
+       else {
+               printf("\nOK\nExpression: '%s'\nParsed as : '%s'\nError code: %d (%s)\n", argv[1], exp->parsed_as, error, expression_strerror(error));
+
+               if(expression_evaluate(exp)) {
+                       printf("\nEvaluates to: %Lf\n\n", exp->result);
+               }
+               else {
+                       printf("\nEvaluation failed with code %d and message: %s\n\n", exp->error, buffer_tostring(exp->error_msg));
+               }
+               expression_free(exp);
+       }
+
+       return 0;
+}
index 664be8b0bcbd8363d250a3c252e74623f1d4bc36..8fa6d5bdf71a4d9b870a1a60323e686cbebcf92f 100644 (file)
@@ -32,7 +32,9 @@ netdata_SOURCES = \
        common.c common.h \
        daemon.c daemon.h \
        dictionary.c dictionary.h \
+       eval.c eval.h \
        global_statistics.c global_statistics.h \
+       health.c health.h \
        log.c log.h \
        main.c main.h \
        plugin_checks.c plugin_checks.h \
index 748c6eff179a10ec1bb85d6afbb266c9073c43d1..c43f4cd731c433ee4380fb9d921232a6a17147b6 100644 (file)
@@ -1,22 +1,4 @@
-
-/*
- * TODO
- *
- * 1. Re-write this using DICTIONARY
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <pthread.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "avl.h"
 #include "common.h"
-#include "appconfig.h"
-#include "log.h"
 
 #define CONFIG_FILE_LINE_MAX ((CONFIG_MAX_NAME + CONFIG_MAX_VALUE + 1024) * 2)
 
@@ -139,11 +121,8 @@ static inline struct config *config_section_create(const char *section)
 {
        debug(D_CONFIG, "Creating section '%s'.", section);
 
-       struct config *co = calloc(1, sizeof(struct config));
-       if(!co) fatal("Cannot allocate config");
-
-       co->name = strdup(section);
-       if(!co->name) fatal("Cannot allocate config.name");
+       struct config *co = callocz(1, sizeof(struct config));
+       co->name = strdupz(section);
        co->hash = simple_hash(co->name);
 
        avl_init_lock(&co->values_index, config_value_compare);
@@ -170,15 +149,10 @@ static inline struct config_value *config_value_create(struct config *co, const
 {
        debug(D_CONFIG, "Creating config entry for name '%s', value '%s', in section '%s'.", name, value, co->name);
 
-       struct config_value *cv = calloc(1, sizeof(struct config_value));
-       if(!cv) fatal("Cannot allocate config_value");
-
-       cv->name = strdup(name);
-       if(!cv->name) fatal("Cannot allocate config.name");
+       struct config_value *cv = callocz(1, sizeof(struct config_value));
+       cv->name = strdupz(name);
        cv->hash = simple_hash(cv->name);
-
-       cv->value = strdup(value);
-       if(!cv->value) fatal("Cannot allocate config.value");
+       cv->value = strdupz(value);
 
        config_value_index_add(co, cv);
 
@@ -226,9 +200,8 @@ int config_rename(const char *section, const char *old, const char *new) {
 
        config_value_index_del(co, cv);
 
-       free(cv->name);
-       cv->name = strdup(new);
-       if(!cv->name) fatal("Cannot allocate memory for config_rename()");
+       freez(cv->name);
+       cv->name = strdupz(new);
 
        cv->hash = simple_hash(cv->name);
 
@@ -340,9 +313,8 @@ const char *config_set_default(const char *section, const char *name, const char
        if(strcmp(cv->value, value) != 0) {
                cv->flags |= CONFIG_VALUE_CHANGED;
 
-               free(cv->value);
-               cv->value = strdup(value);
-               if(!cv->value) fatal("Cannot allocate config.value");
+               freez(cv->value);
+               cv->value = strdupz(value);
        }
 
        return cv->value;
@@ -364,9 +336,8 @@ const char *config_set(const char *section, const char *name, const char *value)
        if(strcmp(cv->value, value) != 0) {
                cv->flags |= CONFIG_VALUE_CHANGED;
 
-               free(cv->value);
-               cv->value = strdup(value);
-               if(!cv->value) fatal("Cannot allocate config.value");
+               freez(cv->value);
+               cv->value = strdupz(value);
        }
 
        return value;
@@ -466,9 +437,8 @@ int load_config(char *filename, int overwrite_used)
                else {
                        if(((cv->flags & CONFIG_VALUE_USED) && overwrite_used) || !(cv->flags & CONFIG_VALUE_USED)) {
                                debug(D_CONFIG, "Line %d, overwriting '%s/%s'.", line, co->name, cv->name);
-                               free(cv->value);
-                               cv->value = strdup(value);
-                               if(!cv->value) fatal("Cannot allocate config.value");
+                               freez(cv->value);
+                               cv->value = strdupz(value);
                        }
                        else
                                debug(D_CONFIG, "Ignoring line %d, '%s/%s' is already present and used.", line, co->name, cv->name);
index b5245e554ce876d626f4c808ef2fd461b5f1ce84..08aae8348891c08fda9298a9a68046b50a59b973 100644 (file)
@@ -1,5 +1,3 @@
-#include "web_buffer.h"
-
 #ifndef NETDATA_CONFIG_H
 #define NETDATA_CONFIG_H 1
 
index 6b43216cb71a23b0b466e4f215109c20dd56555c..210b51038602810c1389df2c75529325df5a2f72 100644 (file)
@@ -1,44 +1,4 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/time.h>
-#include <sys/wait.h>
-#include <sys/stat.h>
-
-#include <sys/resource.h>
-#include <sys/stat.h>
-
-#include <errno.h>
-#include <stdarg.h>
-#include <locale.h>
-#include <ctype.h>
-#include <fcntl.h>
-
-#include <malloc.h>
-#include <dirent.h>
-#include <arpa/inet.h>
-
-#include <sys/types.h>
-#include <pwd.h>
-#include <grp.h>
-
-#include "avl.h"
-
 #include "common.h"
-#include "log.h"
-#include "procfile.h"
-#include "../config.h"
-#include "web_buffer.h"
-
-#ifdef NETDATA_INTERNAL_CHECKS
-#include <sys/prctl.h>
-#endif
 
 #define MAX_COMPARE_NAME 100
 #define MAX_NAME 100
@@ -223,12 +183,7 @@ struct target *get_users_target(uid_t uid)
        for(w = users_root_target ; w ; w = w->next)
                if(w->uid == uid) return w;
 
-       w = calloc(sizeof(struct target), 1);
-       if(unlikely(!w)) {
-               error("Cannot allocate %lu bytes of memory", (unsigned long)sizeof(struct target));
-               return NULL;
-       }
-
+       w = callocz(sizeof(struct target), 1);
        snprintfz(w->compare, MAX_COMPARE_NAME, "%u", uid);
        w->comparehash = simple_hash(w->compare);
        w->comparelen = strlen(w->compare);
@@ -261,12 +216,7 @@ struct target *get_groups_target(gid_t gid)
        for(w = groups_root_target ; w ; w = w->next)
                if(w->gid == gid) return w;
 
-       w = calloc(sizeof(struct target), 1);
-       if(unlikely(!w)) {
-               error("Cannot allocate %lu bytes of memory", (unsigned long)sizeof(struct target));
-               return NULL;
-       }
-
+       w = callocz(sizeof(struct target), 1);
        snprintfz(w->compare, MAX_COMPARE_NAME, "%u", gid);
        w->comparehash = simple_hash(w->compare);
        w->comparelen = strlen(w->compare);
@@ -295,8 +245,7 @@ struct target *get_groups_target(gid_t gid)
 
 // find or create a new target
 // there are targets that are just aggregated to other target (the second argument)
-struct target *get_apps_groups_target(const char *id, struct target *target)
-{
+struct target *get_apps_groups_target(const char *id, struct target *target) {
        int tdebug = 0, thidden = 0, ends_with = 0;
        const char *nid = id;
 
@@ -316,19 +265,14 @@ struct target *get_apps_groups_target(const char *id, struct target *target)
                last = w;
        }
 
-       w = calloc(sizeof(struct target), 1);
-       if(unlikely(!w)) {
-               error("Cannot allocate %lu bytes of memory", (unsigned long)sizeof(struct target));
-               return NULL;
-       }
-
+       w = callocz(sizeof(struct target), 1);
        strncpyz(w->id, nid, MAX_NAME);
        w->idhash = simple_hash(w->id);
 
        strncpyz(w->name, nid, MAX_NAME);
 
        strncpyz(w->compare, nid, MAX_COMPARE_NAME);
-       int len = strlen(w->compare);
+       size_t len = strlen(w->compare);
        if(w->compare[len - 1] == '*') {
                w->compare[len - 1] = '\0';
                w->starts_with = 1;
@@ -581,16 +525,9 @@ struct pid_stat *get_pid_entry(pid_t pid) {
                return all_pids[pid];
        }
 
-       all_pids[pid] = calloc(sizeof(struct pid_stat), 1);
-       if(!all_pids[pid]) {
-               error("Cannot allocate %zu bytes of memory", (size_t)sizeof(struct pid_stat));
-               return NULL;
-       }
-
-       all_pids[pid]->fds = calloc(sizeof(int), 100);
-       if(!all_pids[pid]->fds)
-               error("Cannot allocate %zu bytes of memory", (size_t)(sizeof(int) * 100));
-       else all_pids[pid]->fds_size = 100;
+       all_pids[pid] = callocz(sizeof(struct pid_stat), 1);
+       all_pids[pid]->fds = callocz(sizeof(int), 100);
+       all_pids[pid]->fds_size = 100;
 
        if(root_of_pids) root_of_pids->prev = all_pids[pid];
        all_pids[pid]->next = root_of_pids;
@@ -617,12 +554,12 @@ void del_pid_entry(pid_t pid) {
        if(all_pids[pid]->next) all_pids[pid]->next->prev = all_pids[pid]->prev;
        if(all_pids[pid]->prev) all_pids[pid]->prev->next = all_pids[pid]->next;
 
-       if(all_pids[pid]->fds) free(all_pids[pid]->fds);
-       if(all_pids[pid]->stat_filename) free(all_pids[pid]->stat_filename);
-       if(all_pids[pid]->statm_filename) free(all_pids[pid]->statm_filename);
-       if(all_pids[pid]->io_filename) free(all_pids[pid]->io_filename);
-       if(all_pids[pid]->cmdline_filename) free(all_pids[pid]->cmdline_filename);
-       free(all_pids[pid]);
+       if(all_pids[pid]->fds) freez(all_pids[pid]->fds);
+       if(all_pids[pid]->stat_filename) freez(all_pids[pid]->stat_filename);
+       if(all_pids[pid]->statm_filename) freez(all_pids[pid]->statm_filename);
+       if(all_pids[pid]->io_filename) freez(all_pids[pid]->io_filename);
+       if(all_pids[pid]->cmdline_filename) freez(all_pids[pid]->cmdline_filename);
+       freez(all_pids[pid]);
 
        all_pids[pid] = NULL;
        all_pids_count--;
@@ -637,14 +574,13 @@ int read_proc_pid_cmdline(struct pid_stat *p) {
        if(unlikely(!p->cmdline_filename)) {
                char filename[FILENAME_MAX + 1];
                snprintfz(filename, FILENAME_MAX, "%s/proc/%d/cmdline", host_prefix, p->pid);
-               if(!(p->cmdline_filename = strdup(filename)))
-                       fatal("Cannot allocate memory for filename '%s'", filename);
+               p->cmdline_filename = strdupz(filename);
        }
 
        int fd = open(p->cmdline_filename, O_RDONLY, 0666);
        if(unlikely(fd == -1)) goto cleanup;
 
-       int i, bytes = read(fd, p->cmdline, MAX_CMDLINE);
+       ssize_t i, bytes = read(fd, p->cmdline, MAX_CMDLINE);
        close(fd);
 
        if(unlikely(bytes <= 0)) goto cleanup;
@@ -691,8 +627,7 @@ int read_proc_pid_stat(struct pid_stat *p) {
        if(unlikely(!p->stat_filename)) {
                char filename[FILENAME_MAX + 1];
                snprintfz(filename, FILENAME_MAX, "%s/proc/%d/stat", host_prefix, p->pid);
-               if(!(p->stat_filename = strdup(filename)))
-                       fatal("Cannot allocate memory for filename '%s'", filename);
+               p->stat_filename = strdupz(filename);
        }
 
        int set_quotes = (!ff)?1:0;
@@ -838,8 +773,7 @@ int read_proc_pid_statm(struct pid_stat *p) {
        if(unlikely(!p->statm_filename)) {
                char filename[FILENAME_MAX + 1];
                snprintfz(filename, FILENAME_MAX, "%s/proc/%d/statm", host_prefix, p->pid);
-               if(!(p->statm_filename = strdup(filename)))
-                       fatal("Cannot allocate memory for filename '%s'", filename);
+               p->statm_filename = strdupz(filename);
        }
 
        ff = procfile_reopen(ff, p->statm_filename, NULL, PROCFILE_FLAG_NO_ERROR_ON_FILE_IO);
@@ -877,8 +811,7 @@ int read_proc_pid_io(struct pid_stat *p) {
        if(unlikely(!p->io_filename)) {
                char filename[FILENAME_MAX + 1];
                snprintfz(filename, FILENAME_MAX, "%s/proc/%d/io", host_prefix, p->pid);
-               if(!(p->io_filename = strdup(filename)))
-                       fatal("Cannot allocate memory for filename '%s'", filename);
+               p->io_filename = strdupz(filename);
        }
 
        // open the file
@@ -1147,7 +1080,7 @@ int file_descriptor_find_or_add(const char *name)
                if(unlikely(debug))
                        fprintf(stderr, "apps.plugin: extending fd array to %d entries\n", all_files_size + FILE_DESCRIPTORS_INCREASE_STEP);
 
-               all_files = realloc(all_files, (all_files_size + FILE_DESCRIPTORS_INCREASE_STEP) * sizeof(struct file_descriptor));
+               all_files = reallocz(all_files, (all_files_size + FILE_DESCRIPTORS_INCREASE_STEP) * sizeof(struct file_descriptor));
 
                // if the address changed, we have to rebuild the index
                // since all pointers are now invalid
@@ -1199,7 +1132,7 @@ int file_descriptor_find_or_add(const char *name)
                        if(unlikely(debug))
                                fprintf(stderr, "apps.plugin:   >> %s fd position %d for %s (last name: %s)\n", all_files[c].name?"re-using":"using", c, name, all_files[c].name);
 
-                       if(all_files[c].name) free((void *)all_files[c].name);
+                       if(all_files[c].name) freez((void *)all_files[c].name);
                        all_files[c].name = NULL;
                        last_pos = c;
                        break;
@@ -1239,7 +1172,7 @@ int file_descriptor_find_or_add(const char *name)
                type = FILETYPE_OTHER;
        }
 
-       all_files[c].name = strdup(name);
+       all_files[c].name = strdupz(name);
        all_files[c].hash = hash;
        all_files[c].type = type;
        all_files[c].pos  = c;
@@ -1282,7 +1215,7 @@ int read_pid_file_descriptors(struct pid_stat *p) {
                                if(unlikely(debug))
                                        fprintf(stderr, "apps.plugin: extending fd memory slots for %s from %d to %d\n", p->comm, p->fds_size, fdid + 100);
 
-                               p->fds = realloc(p->fds, (fdid + 100) * sizeof(int));
+                               p->fds = reallocz(p->fds, (fdid + 100) * sizeof(int));
                                if(!p->fds) {
                                        fatal("Cannot re-allocate fds for %s", p->comm);
                                        break;
@@ -1989,7 +1922,7 @@ long zero_all_targets(struct target *root) {
        for (w = root; w ; w = w->next) {
                count++;
 
-               if(w->fds) free(w->fds);
+               if(w->fds) freez(w->fds);
                w->fds = NULL;
 
                w->minflt = 0;
@@ -2029,11 +1962,8 @@ long zero_all_targets(struct target *root) {
 void aggregate_pid_on_target(struct target *w, struct pid_stat *p, struct target *o) {
        (void)o;
 
-       if(unlikely(!w->fds)) {
-               w->fds = calloc(sizeof(int), (size_t) all_files_size);
-               if(unlikely(!w->fds))
-                       error("Cannot allocate memory for fds in %s", w->name);
-       }
+       if(unlikely(!w->fds))
+               w->fds = callocz(sizeof(int), (size_t) all_files_size);
 
        if(likely(p->updated)) {
                w->cutime  += p->cutime;
@@ -2144,7 +2074,7 @@ void count_targets_fds(struct target *root) {
                        }
                }
 
-               free(w->fds);
+               freez(w->fds);
                w->fds = NULL;
        }
 }
@@ -2862,24 +2792,10 @@ int main(int argc, char **argv)
 
        parse_args(argc, argv);
 
-       all_pids_sortlist = calloc(sizeof(pid_t), (size_t)pid_max);
-       if(!all_pids_sortlist) {
-               error("Cannot allocate %zu bytes of memory.", sizeof(pid_t) * pid_max);
-               printf("DISABLE\n");
-               exit(1);
-       }
-
-       all_pids = calloc(sizeof(struct pid_stat *), (size_t) pid_max);
-       if(!all_pids) {
-               error("Cannot allocate %zu bytes of memory.", sizeof(struct pid_stat *) * pid_max);
-               printf("DISABLE\n");
-               exit(1);
-       }
+       all_pids_sortlist = callocz(sizeof(pid_t), (size_t)pid_max);
+       all_pids = callocz(sizeof(struct pid_stat *), (size_t) pid_max);
 
        output = buffer_create(1024);
-       if(!output)
-               fatal("Cannot create BUFFER.");
-
        buffer_sprintf(output,
                "CHART netdata.apps_cpu '' 'Apps Plugin CPU' 'milliseconds/s' apps.plugin netdata.apps_cpu stacked 140000 %1$d\n"
                "DIMENSION user '' incremental 1 1000\n"
index cf9705e257d01fbe8809e042caffa98d2ef968a2..71d206f23e45894f0d1cdb83364d18cef666cd8c 100644 (file)
--- a/src/avl.c
+++ b/src/avl.c
@@ -1,10 +1,4 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-// #include <assert.h>
-
-#include "avl.h"
-#include "log.h"
+#include "common.h"
 
 /* ------------------------------------------------------------------------- */
 /*
index 2566aa586ae67cde864e4ce5c0b38f867d9cc364..8d2c3aa8a40d1b7858ceeae32613bfbce86433f9 100644 (file)
@@ -1,25 +1,49 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <sys/syscall.h>
-#include <string.h>
-#include <ctype.h>
-#include <errno.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <sys/mman.h>
-#include <time.h>
-
-#include "log.h"
 #include "common.h"
-#include "appconfig.h"
-#include "../config.h"
 
 char *global_host_prefix = "";
 int enable_ksm = 1;
 
+volatile sig_atomic_t netdata_exit = 0;
+
+// ----------------------------------------------------------------------------
+// memory allocation functions that handle failures
+
+// although netdata does not use memory allocations too often (netdata tries to
+// maintain its memory footprint stable during runtime, i.e. all buffers are
+// allocated during initialization and are adapted to current use throughout
+// its lifetime), these can be used to override the default system allocation
+// routines.
+
+char *strdupz(const char *s) {
+    char *t = strdup(s);
+    if(unlikely(!t)) fatal("Cannot strdup() string '%s'", s);
+    return t;
+}
+
+void *mallocz(size_t size) {
+    void *p = malloc(size);
+    if(unlikely(!p)) fatal("Cannot allocate %zu bytes of memory.", size);
+    return p;
+}
+
+void *callocz(size_t nmemb, size_t size) {
+    void *p = calloc(nmemb, size);
+    if(unlikely(!p)) fatal("Cannot allocate %zu bytes of memory.", nmemb * size);
+    return p;
+}
+
+void *reallocz(void *ptr, size_t size) {
+    void *p = realloc(ptr, size);
+    if(unlikely(!p)) fatal("Cannot re-allocate memory to %zu bytes.", size);
+    return p;
+}
+
+void freez(void *ptr) {
+    free(ptr);
+}
+
+// ----------------------------------------------------------------------------
+
 // time(NULL) in milliseconds
 unsigned long long timems(void) {
        struct timeval now;
@@ -32,7 +56,10 @@ int usecsleep(unsigned long long usec) {
 #ifndef NETDATA_WITH_USLEEP
        // we expect microseconds (1.000.000 per second)
        // but timespec is nanoseconds (1.000.000.000 per second)
-       struct timespec req = { .tv_sec = usec / 1000000, .tv_nsec = (usec % 1000000) * 1000 }, rem;
+       struct timespec rem, req = {
+            .tv_sec = (time_t)(usec / 1000000),
+            .tv_nsec = (suseconds_t)((usec % 1000000) * 1000)
+    };
 
        while(nanosleep(&req, &rem) == -1) {
                if(likely(errno == EINTR)) {
index f6736df68470c2cb178b17c6f653c11d7bb49b00..9793adf66f0d9bddb0d45658357b15028ac59cb4 100644 (file)
+#ifndef NETDATA_COMMON_H
+#define NETDATA_COMMON_H 1
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <pthread.h>
+#include <errno.h>
+
+#include <stdio.h>
+#include <stdlib.h>
 #include <stdarg.h>
-#include <sys/time.h>
+#include <stddef.h>
+
+#include <ctype.h>
+#include <string.h>
+#include <strings.h>
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <grp.h>
+#include <pwd.h>
+#include <locale.h>
+#include <malloc.h>
+#include <netdb.h>
+#include <poll.h>
+#include <signal.h>
+#include <syslog.h>
+#include <sys/mman.h>
+#include <sys/prctl.h>
 #include <sys/resource.h>
-#include <stdio.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/statvfs.h>
+#include <sys/syscall.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+#include <uuid/uuid.h>
 
-#ifndef NETDATA_COMMON_H
-#define NETDATA_COMMON_H 1
+#ifdef STORAGE_WITH_MATH
+#include <math.h>
+#endif
 
 #if defined(HAVE_INTTYPES_H)
 #include <inttypes.h>
 #elif defined(HAVE_STDINT_H)
 #include <stdint.h>
 #endif
-#include <sys/types.h>
-#include <unistd.h>
 
+#ifdef NETDATA_WITH_ZLIB
+#include <zlib.h>
+#endif
+
+#include "avl.h"
+#include "log.h"
+#include "global_statistics.h"
+#include "storage_number.h"
+#include "web_buffer.h"
+#include "web_buffer_svg.h"
+#include "url.h"
+#include "popen.h"
+
+#include "procfile.h"
+#include "appconfig.h"
+#include "dictionary.h"
+#include "proc_self_mountinfo.h"
+#include "plugin_checks.h"
+#include "plugin_idlejitter.h"
+#include "plugin_nfacct.h"
+#include "plugin_proc.h"
+#include "plugin_tc.h"
+#include "plugins_d.h"
+
+#include "eval.h"
+#include "health.h"
+
+#include "rrd.h"
+#include "rrd2json.h"
+
+#include "web_client.h"
+#include "web_server.h"
+
+#include "registry.h"
+#include "daemon.h"
+#include "main.h"
+#include "unit_test.h"
+
+#if __GNUC__
+#if __x86_64__ || __ppc64__
+#define ENVIRONMENT64
+#else
+#define ENVIRONMENT32
+#endif
+#endif
+
+#ifdef abs
+#undef abs
+#endif
 #define abs(x) ((x < 0)? -x : x)
+
 #define usecdiff(now, last) (((((now)->tv_sec * 1000000ULL) + (now)->tv_usec) - (((last)->tv_sec * 1000000ULL) + (last)->tv_usec)))
 
 extern void netdata_fix_chart_id(char *s);
@@ -31,6 +123,13 @@ extern char *strncpyz(char *dst, const char *src, size_t n);
 extern int  vsnprintfz(char *dst, size_t n, const char *fmt, va_list args);
 extern int  snprintfz(char *dst, size_t n, const char *fmt, ...) __attribute__ (( format (printf, 3, 4)));
 
+// memory allocation functions that handle failures
+extern char *strdupz(const char *s);
+extern void *callocz(size_t nmemb, size_t size);
+extern void *mallocz(size_t size);
+extern void freez(void *ptr);
+extern void *reallocz(void *ptr, size_t size);
+
 extern void *mymmap(const char *filename, size_t size, int flags, int ksm);
 extern int savememory(const char *filename, void *mem, size_t size);
 
index b14b4d9a4a2d8adbded457fe9e686a855d6df1df..9d4d5b32b4c3822f93dd4c846ba9cfc1d059d39d 100644 (file)
@@ -1,29 +1,4 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <signal.h>
-#include <string.h>
-#include <sys/types.h>
-#include <pwd.h>
-#include <grp.h>
-#include <pthread.h>
-#include <sys/wait.h>
-#include <sys/stat.h>
-
 #include "common.h"
-#include "appconfig.h"
-#include "log.h"
-#include "web_client.h"
-#include "plugins_d.h"
-#include "rrd.h"
-#include "popen.h"
-#include "main.h"
-#include "daemon.h"
 
 char pidfile[FILENAME_MAX + 1] = "";
 
@@ -71,19 +46,16 @@ int become_user(const char *username, int access_fd, int output_fd, int error_fd
        uid_t uid = pw->pw_uid;
        gid_t gid = pw->pw_gid;
 
-       int ngroups =  sysconf(_SC_NGROUPS_MAX);
+       int ngroups = (int)sysconf(_SC_NGROUPS_MAX);
        gid_t *supplementary_groups = NULL;
        if(ngroups) {
-               supplementary_groups = malloc(sizeof(gid_t) * ngroups);
-               if(supplementary_groups) {
-                       if(getgrouplist(username, gid, supplementary_groups, &ngroups) == -1) {
-                               error("Cannot get supplementary groups of user '%s'.", username);
-                               free(supplementary_groups);
-                               supplementary_groups = NULL;
-                               ngroups = 0;
-                       }
+               supplementary_groups = mallocz(sizeof(gid_t) * ngroups);
+               if(getgrouplist(username, gid, supplementary_groups, &ngroups) == -1) {
+                       error("Cannot get supplementary groups of user '%s'.", username);
+                       freez(supplementary_groups);
+                       supplementary_groups = NULL;
+                       ngroups = 0;
                }
-               else fatal("Cannot allocate memory for %d supplementary groups", ngroups);
        }
 
        properly_chown_netdata_generated_file(access_fd, uid, gid);
@@ -95,7 +67,7 @@ int become_user(const char *username, int access_fd, int output_fd, int error_fd
                if(setgroups(ngroups, supplementary_groups) == -1)
                        error("Cannot set supplementary groups for user '%s'", username);
 
-               free(supplementary_groups);
+               freez(supplementary_groups);
                supplementary_groups = NULL;
                ngroups = 0;
        }
index 8bc048276b45e7667cacf4a4af27af863e5c7657..6f2a5902de1ea241b87f92c4b365d5c92b74992b 100644 (file)
@@ -1,16 +1,4 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <pthread.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "avl.h"
 #include "common.h"
-#include "log.h"
-
-#include "dictionary.h"
 
 // ----------------------------------------------------------------------------
 // dictionary statistics
@@ -89,15 +77,12 @@ static inline NAME_VALUE *dictionary_name_value_index_find_nolock(DICTIONARY *di
 static NAME_VALUE *dictionary_name_value_create_nolock(DICTIONARY *dict, const char *name, void *value, size_t value_len, uint32_t hash) {
        debug(D_DICTIONARY, "Creating name value entry for name '%s'.", name);
 
-       NAME_VALUE *nv = calloc(1, sizeof(NAME_VALUE));
-       if(unlikely(!nv)) fatal("Cannot allocate name_value of size %zu", sizeof(NAME_VALUE));
+       NAME_VALUE *nv = callocz(1, sizeof(NAME_VALUE));
 
        if(dict->flags & DICTIONARY_FLAG_NAME_LINK_DONT_CLONE)
                nv->name = (char *)name;
        else {
-               nv->name = strdup(name);
-               if (unlikely(!nv->name))
-                       fatal("Cannot allocate name_value.name of size %zu", strlen(name));
+               nv->name = strdupz(name);
        }
 
        nv->hash = (hash)?hash:simple_hash(nv->name);
@@ -105,10 +90,7 @@ static NAME_VALUE *dictionary_name_value_create_nolock(DICTIONARY *dict, const c
        if(dict->flags & DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE)
                nv->value = value;
        else {
-               nv->value = malloc(value_len);
-               if (unlikely(!nv->value))
-                       fatal("Cannot allocate name_value.value of size %zu", value_len);
-
+               nv->value = mallocz(value_len);
                memcpy(nv->value, value, value_len);
        }
 
@@ -128,34 +110,30 @@ static void dictionary_name_value_destroy_nolock(DICTIONARY *dict, NAME_VALUE *n
 
        if(!(dict->flags & DICTIONARY_FLAG_VALUE_LINK_DONT_CLONE)) {
                debug(D_REGISTRY, "Dictionary freeing value of '%s'", nv->name);
-               free(nv->value);
+               freez(nv->value);
        }
 
        if(!(dict->flags & DICTIONARY_FLAG_NAME_LINK_DONT_CLONE)) {
                debug(D_REGISTRY, "Dictionary freeing name '%s'", nv->name);
-               free(nv->name);
+               freez(nv->name);
        }
 
-       free(nv);
+       freez(nv);
 }
 
 // ----------------------------------------------------------------------------
 // API - basic methods
 
-DICTIONARY *dictionary_create(uint32_t flags) {
+DICTIONARY *dictionary_create(uint8_t flags) {
        debug(D_DICTIONARY, "Creating dictionary.");
 
-       DICTIONARY *dict = calloc(1, sizeof(DICTIONARY));
-       if(unlikely(!dict)) fatal("Cannot allocate DICTIONARY");
+       DICTIONARY *dict = callocz(1, sizeof(DICTIONARY));
 
-       if(flags & DICTIONARY_FLAG_WITH_STATISTICS) {
-               dict->stats = calloc(1, sizeof(struct dictionary_stats));
-               if(!dict->stats) fatal("Cannot allocate statistics for DICTIONARY");
-       }
+       if(flags & DICTIONARY_FLAG_WITH_STATISTICS)
+               dict->stats = callocz(1, sizeof(struct dictionary_stats));
 
        if(!(flags & DICTIONARY_FLAG_SINGLE_THREADED)) {
-               dict->rwlock = calloc(1, sizeof(pthread_rwlock_t));
-               if(!dict->rwlock) fatal("Cannot allocate pthread_rwlock_t for DICTIONARY");
+               dict->rwlock = callocz(1, sizeof(pthread_rwlock_t));
                pthread_rwlock_init(dict->rwlock, NULL);
        }
 
@@ -176,12 +154,12 @@ void dictionary_destroy(DICTIONARY *dict) {
        dictionary_unlock(dict);
 
        if(dict->stats)
-               free(dict->stats);
+               freez(dict->stats);
 
        if(dict->rwlock)
-               free(dict->rwlock);
+               freez(dict->rwlock);
 
-       free(dict);
+       freez(dict);
 }
 
 // ----------------------------------------------------------------------------
@@ -213,17 +191,14 @@ void *dictionary_set(DICTIONARY *dict, const char *name, void *value, size_t val
 
                        // copy the new value without breaking
                        // any other thread accessing the same entry
-                       void *new = malloc(value_len),
+                       void *new = mallocz(value_len),
                                        *old = nv->value;
 
-                       if(unlikely(!new))
-                               fatal("Cannot allocate value of size %zu", value_len);
-
                        memcpy(new, value, value_len);
                        nv->value = new;
 
                        debug(D_REGISTRY, "Dictionary: freeing old value of '%s'", name);
-                       free(old);
+                       freez(old);
                }
        }
 
index c32d8bd92d82514ca6694e88ebaf0f6e5c3d8147..4164b6dc7b28e9bd8b45ce89b628a65c67011aa2 100644 (file)
@@ -1,8 +1,3 @@
-#include <pthread.h>
-
-#include "web_buffer.h"
-#include "avl.h"
-
 #ifndef NETDATA_DICTIONARY_H
 #define NETDATA_DICTIONARY_H 1
 
@@ -38,12 +33,12 @@ typedef struct dictionary {
 #define DICTIONARY_FLAG_NAME_LINK_DONT_CLONE   0x00000004
 #define DICTIONARY_FLAG_WITH_STATISTICS                        0x00000008
 
-extern DICTIONARY *dictionary_create(uint32_t flags);
+extern DICTIONARY *dictionary_create(uint8_t flags);
 extern void dictionary_destroy(DICTIONARY *dict);
 extern void *dictionary_set(DICTIONARY *dict, const char *name, void *value, size_t value_len);
 extern void *dictionary_get(DICTIONARY *dict, const char *name);
 extern int dictionary_del(DICTIONARY *dict, const char *name);
 
-extern int dictionary_get_all(DICTIONARY *dict, int (*callback)(void *entry, void *data), void *data);
+extern int dictionary_get_all(DICTIONARY *dict, int (*callback)(void *entry, void *d), void *data);
 
 #endif /* NETDATA_DICTIONARY_H */
diff --git a/src/eval.c b/src/eval.c
new file mode 100644 (file)
index 0000000..e57a12c
--- /dev/null
@@ -0,0 +1,881 @@
+#include "common.h"
+
+// ----------------------------------------------------------------------------
+// data structures for storing the parsed expression in memory
+
+typedef struct eval_value {
+    int type;
+
+    union {
+        calculated_number number;
+        EVAL_VARIABLE *variable;
+        struct eval_node *expression;
+    };
+} EVAL_VALUE;
+
+typedef struct eval_node {
+    int id;
+    unsigned char operator;
+    int precedence;
+
+    int count;
+    EVAL_VALUE ops[];
+} EVAL_NODE;
+
+// these are used for EVAL_NODE.operator
+// they are used as internal IDs to identify an operator
+// THEY ARE NOT USED FOR PARSING OPERATORS LIKE THAT
+#define EVAL_OPERATOR_NOP                   '\0'
+#define EVAL_OPERATOR_VALUE                 ':'
+#define EVAL_OPERATOR_EXPRESSION_OPEN       '('
+#define EVAL_OPERATOR_EXPRESSION_CLOSE      ')'
+#define EVAL_OPERATOR_NOT                   '!'
+#define EVAL_OPERATOR_PLUS                  '+'
+#define EVAL_OPERATOR_MINUS                 '-'
+#define EVAL_OPERATOR_AND                   '&'
+#define EVAL_OPERATOR_OR                    '|'
+#define EVAL_OPERATOR_GREATER_THAN_OR_EQUAL 'G'
+#define EVAL_OPERATOR_LESS_THAN_OR_EQUAL    'L'
+#define EVAL_OPERATOR_NOT_EQUAL             '~'
+#define EVAL_OPERATOR_EQUAL                 '='
+#define EVAL_OPERATOR_LESS                  '<'
+#define EVAL_OPERATOR_GREATER               '>'
+#define EVAL_OPERATOR_MULTIPLY              '*'
+#define EVAL_OPERATOR_DIVIDE                '/'
+#define EVAL_OPERATOR_SIGN_PLUS             'P'
+#define EVAL_OPERATOR_SIGN_MINUS            'M'
+
+// ----------------------------------------------------------------------------
+// forward function definitions
+
+static inline void eval_node_free(EVAL_NODE *op);
+static inline EVAL_NODE *parse_full_expression(const char **string, int *error);
+static inline EVAL_NODE *parse_one_full_operand(const char **string, int *error);
+static inline calculated_number eval_node(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error);
+static inline void print_parsed_as_node(BUFFER *out, EVAL_NODE *op, int *error);
+
+// ----------------------------------------------------------------------------
+// evaluation of expressions
+
+static inline calculated_number eval_check_number(calculated_number n, int *error) {
+    if(unlikely(isnan(n))) {
+        *error = EVAL_ERROR_VALUE_IS_NAN;
+        return 0;
+    }
+
+    if(unlikely(isinf(n))) {
+        *error = EVAL_ERROR_VALUE_IS_INFINITE;
+        return 0;
+    }
+
+    return n;
+}
+
+static inline calculated_number eval_variable(EVAL_EXPRESSION *exp, EVAL_VARIABLE *v, int *error) {
+    // FIXME: do the variable look up here
+
+//    if(!exp->data) {
+    *error = EVAL_ERROR_UNKNOWN_VARIABLE;
+    buffer_sprintf(exp->error_msg, "unknown variable '%s'", v->name);
+//    }
+
+    return 0;
+}
+
+static inline calculated_number eval_value(EVAL_EXPRESSION *exp, EVAL_VALUE *v, int *error) {
+    calculated_number n;
+
+    switch(v->type) {
+        case EVAL_VALUE_EXPRESSION:
+            n = eval_node(exp, v->expression, error);
+            break;
+
+        case EVAL_VALUE_NUMBER:
+            n = v->number;
+            break;
+
+        case EVAL_VALUE_VARIABLE:
+            n = eval_variable(exp, v->variable, error);
+            break;
+
+        default:
+            *error = EVAL_ERROR_INVALID_VALUE;
+            n = 0;
+            break;
+    }
+
+    return eval_check_number(n, error);
+}
+
+calculated_number eval_and(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
+    return eval_value(exp, &op->ops[0], error) && eval_value(exp, &op->ops[1], error);
+}
+calculated_number eval_or(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
+    return eval_value(exp, &op->ops[0], error) || eval_value(exp, &op->ops[1], error);
+}
+calculated_number eval_greater_than_or_equal(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
+    return eval_value(exp, &op->ops[0], error) >= eval_value(exp, &op->ops[1], error);
+}
+calculated_number eval_less_than_or_equal(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
+    return eval_value(exp, &op->ops[0], error) <= eval_value(exp, &op->ops[1], error);
+}
+calculated_number eval_not_equal(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
+    return eval_value(exp, &op->ops[0], error) != eval_value(exp, &op->ops[1], error);
+}
+calculated_number eval_equal(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
+    return eval_value(exp, &op->ops[0], error) == eval_value(exp, &op->ops[1], error);
+}
+calculated_number eval_less(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
+    return eval_value(exp, &op->ops[0], error) < eval_value(exp, &op->ops[1], error);
+}
+calculated_number eval_greater(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
+    return eval_value(exp, &op->ops[0], error) > eval_value(exp, &op->ops[1], error);
+}
+calculated_number eval_plus(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
+    return eval_value(exp, &op->ops[0], error) + eval_value(exp, &op->ops[1], error);
+}
+calculated_number eval_minus(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
+    return eval_value(exp, &op->ops[0], error) - eval_value(exp, &op->ops[1], error);
+}
+calculated_number eval_multiply(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
+    return eval_value(exp, &op->ops[0], error) * eval_value(exp, &op->ops[1], error);
+}
+calculated_number eval_divide(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
+    return eval_value(exp, &op->ops[0], error) / eval_value(exp, &op->ops[1], error);
+}
+calculated_number eval_nop(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
+    return eval_value(exp, &op->ops[0], error);
+}
+calculated_number eval_not(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
+    return !eval_value(exp, &op->ops[0], error);
+}
+calculated_number eval_sign_plus(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
+    return eval_value(exp, &op->ops[0], error);
+}
+calculated_number eval_sign_minus(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
+    return -eval_value(exp, &op->ops[0], error);
+}
+
+static struct operator {
+    const char *print_as;
+    char precedence;
+    char parameters;
+    calculated_number (*eval)(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error);
+} operators[256] = {
+        // this is a random access array
+        // we always access it with a known EVAL_OPERATOR_X
+
+        [EVAL_OPERATOR_AND]                   = { "&&", 2, 2, eval_and },
+        [EVAL_OPERATOR_OR]                    = { "||", 2, 2, eval_or },
+        [EVAL_OPERATOR_GREATER_THAN_OR_EQUAL] = { ">=", 3, 2, eval_greater_than_or_equal },
+        [EVAL_OPERATOR_LESS_THAN_OR_EQUAL]    = { "<=", 3, 2, eval_less_than_or_equal },
+        [EVAL_OPERATOR_NOT_EQUAL]             = { "!=", 3, 2, eval_not_equal },
+        [EVAL_OPERATOR_EQUAL]                 = { "==", 3, 2, eval_equal },
+        [EVAL_OPERATOR_LESS]                  = { "<",  3, 2, eval_less },
+        [EVAL_OPERATOR_GREATER]               = { ">",  3, 2, eval_greater },
+        [EVAL_OPERATOR_PLUS]                  = { "+",  4, 2, eval_plus },
+        [EVAL_OPERATOR_MINUS]                 = { "-",  4, 2, eval_minus },
+        [EVAL_OPERATOR_MULTIPLY]              = { "*",  5, 2, eval_multiply },
+        [EVAL_OPERATOR_DIVIDE]                = { "/",  5, 2, eval_divide },
+        [EVAL_OPERATOR_NOT]                   = { "!",  6, 1, eval_not },
+        [EVAL_OPERATOR_SIGN_PLUS]             = { "+",  6, 1, eval_sign_plus },
+        [EVAL_OPERATOR_SIGN_MINUS]            = { "-",  6, 1, eval_sign_minus },
+        [EVAL_OPERATOR_NOP]                   = { NULL, 7, 1, eval_nop },
+        [EVAL_OPERATOR_VALUE]                 = { NULL, 7, 1, eval_nop },
+        [EVAL_OPERATOR_EXPRESSION_OPEN]       = { NULL, 7, 1, eval_nop },
+
+        // this should exist in our evaluation list
+        [EVAL_OPERATOR_EXPRESSION_CLOSE]      = { NULL, 7, 1, eval_nop }
+};
+
+#define eval_precedence(operator) (operators[(unsigned char)(operator)].precedence)
+
+static inline calculated_number eval_node(EVAL_EXPRESSION *exp, EVAL_NODE *op, int *error) {
+    if(unlikely(op->count != operators[op->operator].parameters)) {
+        *error = EVAL_ERROR_INVALID_NUMBER_OF_OPERANDS;
+        return 0;
+    }
+
+    calculated_number n = operators[op->operator].eval(exp, op, error);
+
+    return eval_check_number(n, error);
+}
+
+// ----------------------------------------------------------------------------
+// parsed-as generation
+
+static inline void print_parsed_as_variable(BUFFER *out, EVAL_VARIABLE *v, int *error) {
+    (void)error;
+    buffer_sprintf(out, "$%s", v->name);
+}
+
+static inline void print_parsed_as_constant(BUFFER *out, calculated_number n) {
+    char b[100+1], *s;
+    snprintfz(b, 100, CALCULATED_NUMBER_FORMAT, n);
+
+    s = &b[strlen(b) - 1];
+    while(s > b && *s == '0') {
+        *s ='\0';
+        s--;
+    }
+
+    if(s > b && *s == '.')
+        *s = '\0';
+
+    buffer_strcat(out, b);
+}
+
+static inline void print_parsed_as_value(BUFFER *out, EVAL_VALUE *v, int *error) {
+    switch(v->type) {
+        case EVAL_VALUE_EXPRESSION:
+            print_parsed_as_node(out, v->expression, error);
+            break;
+
+        case EVAL_VALUE_NUMBER:
+            print_parsed_as_constant(out, v->number);
+            break;
+
+        case EVAL_VALUE_VARIABLE:
+            print_parsed_as_variable(out, v->variable, error);
+            break;
+
+        default:
+            *error = EVAL_ERROR_INVALID_VALUE;
+            break;
+    }
+}
+
+static inline void print_parsed_as_node(BUFFER *out, EVAL_NODE *op, int *error) {
+    if(unlikely(op->count != operators[op->operator].parameters)) {
+        *error = EVAL_ERROR_INVALID_NUMBER_OF_OPERANDS;
+        return;
+    }
+
+    if(operators[op->operator].parameters == 1) {
+
+        if(operators[op->operator].print_as)
+            buffer_sprintf(out, "%s", operators[op->operator].print_as);
+
+        //if(op->operator == EVAL_OPERATOR_EXPRESSION_OPEN)
+        //    buffer_strcat(out, "(");
+
+        print_parsed_as_value(out, &op->ops[0], error);
+
+        //if(op->operator == EVAL_OPERATOR_EXPRESSION_OPEN)
+        //    buffer_strcat(out, ")");
+    }
+
+    else if(operators[op->operator].parameters == 2) {
+        buffer_strcat(out, "(");
+        print_parsed_as_value(out, &op->ops[0], error);
+
+        if(operators[op->operator].print_as)
+            buffer_sprintf(out, " %s ", operators[op->operator].print_as);
+
+        print_parsed_as_value(out, &op->ops[1], error);
+        buffer_strcat(out, ")");
+    }
+}
+
+// ----------------------------------------------------------------------------
+// parsing expressions
+
+// skip spaces
+static inline void skip_spaces(const char **string) {
+    const char *s = *string;
+    while(isspace(*s)) s++;
+    *string = s;
+}
+
+// what character can appear just after an operator keyword
+// like NOT AND OR ?
+static inline int isoperatorterm_word(const char s) {
+    if(isspace(s) || s == '(' || s == '$' || s == '!' || s == '-' || s == '+' || isdigit(s) || !s)
+        return 1;
+
+    return 0;
+}
+
+// what character can appear just after an operator symbol?
+static inline int isoperatorterm_symbol(const char s) {
+    if(isoperatorterm_word(s) || isalpha(s)) return 1;
+    return 0;
+}
+
+// ----------------------------------------------------------------------------
+// parse operators
+
+static inline int parse_and(const char **string) {
+    const char *s = *string;
+
+    // AND
+    if((s[0] == 'A' || s[0] == 'a') && (s[1] == 'N' || s[1] == 'n') && (s[2] == 'D' || s[2] == 'd') && isoperatorterm_word(s[3])) {
+        *string = &s[4];
+        return 1;
+    }
+
+    // &&
+    if(s[0] == '&' && s[1] == '&' && isoperatorterm_symbol(s[2])) {
+        *string = &s[2];
+        return 1;
+    }
+
+    return 0;
+}
+
+static inline int parse_or(const char **string) {
+    const char *s = *string;
+
+    // OR
+    if((s[0] == 'O' || s[0] == 'o') && (s[1] == 'R' || s[1] == 'r') && isoperatorterm_word(s[2])) {
+        *string = &s[3];
+        return 1;
+    }
+
+    // ||
+    if(s[0] == '|' && s[1] == '|' && isoperatorterm_symbol(s[2])) {
+        *string = &s[2];
+        return 1;
+    }
+
+    return 0;
+}
+
+static inline int parse_greater_than_or_equal(const char **string) {
+    const char *s = *string;
+
+    // >=
+    if(s[0] == '>' && s[1] == '=' && isoperatorterm_symbol(s[2])) {
+        *string = &s[2];
+        return 1;
+    }
+
+    return 0;
+}
+
+static inline int parse_less_than_or_equal(const char **string) {
+    const char *s = *string;
+
+    // <=
+    if (s[0] == '<' && s[1] == '=' && isoperatorterm_symbol(s[2])) {
+        *string = &s[2];
+        return 1;
+    }
+
+    return 0;
+}
+
+static inline int parse_greater(const char **string) {
+    const char *s = *string;
+
+    // >
+    if(s[0] == '>' && isoperatorterm_symbol(s[1])) {
+        *string = &s[1];
+        return 1;
+    }
+
+    return 0;
+}
+
+static inline int parse_less(const char **string) {
+    const char *s = *string;
+
+    // <
+    if(s[0] == '<' && isoperatorterm_symbol(s[1])) {
+        *string = &s[1];
+        return 1;
+    }
+
+    return 0;
+}
+
+static inline int parse_equal(const char **string) {
+    const char *s = *string;
+
+    // ==
+    if(s[0] == '=' && s[1] == '=' && isoperatorterm_symbol(s[2])) {
+        *string = &s[2];
+        return 1;
+    }
+
+    // =
+    if(s[0] == '=' && isoperatorterm_symbol(s[1])) {
+        *string = &s[1];
+        return 1;
+    }
+
+    return 0;
+}
+
+static inline int parse_not_equal(const char **string) {
+    const char *s = *string;
+
+    // !=
+    if(s[0] == '!' && s[1] == '=' && isoperatorterm_symbol(s[2])) {
+        *string = &s[2];
+        return 1;
+    }
+
+    // <>
+    if(s[0] == '<' && s[1] == '>' && isoperatorterm_symbol(s[2])) {
+        *string = &s[2];
+    }
+
+    return 0;
+}
+
+static inline int parse_not(const char **string) {
+    const char *s = *string;
+
+    // NOT
+    if((s[0] == 'N' || s[0] == 'n') && (s[1] == 'O' || s[1] == 'o') && (s[2] == 'T' || s[2] == 't') && isoperatorterm_word(s[3])) {
+        *string = &s[3];
+        return 1;
+    }
+
+    if(s[0] == '!') {
+        *string = &s[1];
+        return 1;
+    }
+
+    return 0;
+}
+
+static inline int parse_multiply(const char **string) {
+    const char *s = *string;
+
+    // *
+    if(s[0] == '*' && isoperatorterm_symbol(s[1])) {
+        *string = &s[1];
+        return 1;
+    }
+
+    return 0;
+}
+
+static inline int parse_divide(const char **string) {
+    const char *s = *string;
+
+    // /
+    if(s[0] == '/' && isoperatorterm_symbol(s[1])) {
+        *string = &s[1];
+        return 1;
+    }
+
+    return 0;
+}
+
+static inline int parse_minus(const char **string) {
+    const char *s = *string;
+
+    // -
+    if(s[0] == '-' && isoperatorterm_symbol(s[1])) {
+        *string = &s[1];
+        return 1;
+    }
+
+    return 0;
+}
+
+static inline int parse_plus(const char **string) {
+    const char *s = *string;
+
+    // +
+    if(s[0] == '+' && isoperatorterm_symbol(s[1])) {
+        *string = &s[1];
+        return 1;
+    }
+
+    return 0;
+}
+
+static inline int parse_open_subexpression(const char **string) {
+    const char *s = *string;
+
+    // (
+    if(s[0] == '(') {
+        *string = &s[1];
+        return 1;
+    }
+
+    return 0;
+}
+
+static inline int parse_close_subexpression(const char **string) {
+    const char *s = *string;
+
+    // (
+    if(s[0] == ')') {
+        *string = &s[1];
+        return 1;
+    }
+
+    return 0;
+}
+
+static inline int parse_constant(const char **string, calculated_number *number) {
+    char *end = NULL;
+    calculated_number n = strtold(*string, &end);
+    if(unlikely(!end || *string == end || isnan(n) || isinf(n))) {
+        *number = 0;
+        return 0;
+    }
+    *number = n;
+    *string = end;
+    return 1;
+}
+
+static struct operator_parser {
+    unsigned char id;
+    int (*parse)(const char **);
+} operator_parsers[] = {
+        // the order in this list is important!
+        // the first matching will be used
+        // so place the longer of overlapping ones
+        // at the top
+
+        { EVAL_OPERATOR_AND,                   parse_and },
+        { EVAL_OPERATOR_OR,                    parse_or },
+        { EVAL_OPERATOR_GREATER_THAN_OR_EQUAL, parse_greater_than_or_equal },
+        { EVAL_OPERATOR_LESS_THAN_OR_EQUAL,    parse_less_than_or_equal },
+        { EVAL_OPERATOR_NOT_EQUAL,             parse_not_equal },
+        { EVAL_OPERATOR_EQUAL,                 parse_equal },
+        { EVAL_OPERATOR_LESS,                  parse_less },
+        { EVAL_OPERATOR_GREATER,               parse_greater },
+        { EVAL_OPERATOR_PLUS,                  parse_plus },
+        { EVAL_OPERATOR_MINUS,                 parse_minus },
+        { EVAL_OPERATOR_MULTIPLY,              parse_multiply },
+        { EVAL_OPERATOR_DIVIDE,                parse_divide },
+
+        /* we should not put in this list the following:
+         *
+         *  - NOT
+         *  - (
+         *  - )
+         *
+         * these are handled in code
+         */
+
+        // termination
+        { EVAL_OPERATOR_NOP, NULL }
+};
+
+static inline unsigned char parse_operator(const char **string, int *precedence) {
+    skip_spaces(string);
+
+    int i;
+    for(i = 0 ; operator_parsers[i].parse != NULL ; i++)
+        if(operator_parsers[i].parse(string)) {
+            if(precedence) *precedence = eval_precedence(operator_parsers[i].id);
+            return operator_parsers[i].id;
+        }
+
+    return EVAL_OPERATOR_NOP;
+}
+
+// ----------------------------------------------------------------------------
+// memory management
+
+static inline EVAL_NODE *eval_node_alloc(int count) {
+    static int id = 1;
+
+    EVAL_NODE *op = callocz(1, sizeof(EVAL_NODE) + (sizeof(EVAL_VALUE) * count));
+
+    op->id = id++;
+    op->operator = EVAL_OPERATOR_NOP;
+    op->precedence = eval_precedence(EVAL_OPERATOR_NOP);
+    op->count = count;
+    return op;
+}
+
+static inline void eval_node_set_value_to_node(EVAL_NODE *op, int pos, EVAL_NODE *value) {
+    if(pos >= op->count)
+        fatal("Invalid request to set position %d of OPERAND that has only %d values", pos + 1, op->count + 1);
+
+    op->ops[pos].type = EVAL_VALUE_EXPRESSION;
+    op->ops[pos].expression = value;
+}
+
+static inline void eval_node_set_value_to_constant(EVAL_NODE *op, int pos, calculated_number value) {
+    if(pos >= op->count)
+        fatal("Invalid request to set position %d of OPERAND that has only %d values", pos + 1, op->count + 1);
+
+    op->ops[pos].type = EVAL_VALUE_NUMBER;
+    op->ops[pos].number = value;
+}
+
+static inline void eval_variable_free(EVAL_VARIABLE *v) {
+    freez(v);
+}
+
+static inline void eval_value_free(EVAL_VALUE *v) {
+    switch(v->type) {
+        case EVAL_VALUE_EXPRESSION:
+            eval_node_free(v->expression);
+            break;
+
+        case EVAL_VALUE_VARIABLE:
+            eval_variable_free(v->variable);
+            break;
+
+        default:
+            break;
+    }
+}
+
+static inline void eval_node_free(EVAL_NODE *op) {
+    if(op->count) {
+        int i;
+        for(i = op->count - 1; i >= 0 ;i--)
+            eval_value_free(&op->ops[i]);
+    }
+
+    freez(op);
+}
+
+// ----------------------------------------------------------------------------
+// the parsing logic
+
+// helper function to avoid allocations all over the place
+static inline EVAL_NODE *parse_next_operand_given_its_operator(const char **string, unsigned char operator_type, int *error) {
+    EVAL_NODE *sub = parse_one_full_operand(string, error);
+    if(!sub) return NULL;
+
+    EVAL_NODE *op = eval_node_alloc(1);
+    op->operator = operator_type;
+    eval_node_set_value_to_node(op, 0, sub);
+    return op;
+}
+
+// parse a full operand, including its sign or other associative operator (e.g. NOT)
+static inline EVAL_NODE *parse_one_full_operand(const char **string, int *error) {
+    EVAL_NODE *op1 = NULL;
+    calculated_number number;
+
+    *error = EVAL_ERROR_OK;
+
+    skip_spaces(string);
+    if(!(**string)) {
+        *error = EVAL_ERROR_MISSING_OPERAND;
+        return NULL;
+    }
+
+    if(parse_not(string)) {
+        op1 = parse_next_operand_given_its_operator(string, EVAL_OPERATOR_NOT, error);
+        op1->precedence = eval_precedence(EVAL_OPERATOR_NOT);
+    }
+    else if(parse_plus(string)) {
+        op1 = parse_next_operand_given_its_operator(string, EVAL_OPERATOR_SIGN_PLUS, error);
+        op1->precedence = eval_precedence(EVAL_OPERATOR_SIGN_PLUS);
+    }
+    else if(parse_minus(string)) {
+        op1 = parse_next_operand_given_its_operator(string, EVAL_OPERATOR_SIGN_MINUS, error);
+        op1->precedence = eval_precedence(EVAL_OPERATOR_SIGN_MINUS);
+    }
+    else if(parse_open_subexpression(string)) {
+        EVAL_NODE *sub = parse_full_expression(string, error);
+        if(sub) {
+            op1 = eval_node_alloc(1);
+            op1->operator = EVAL_OPERATOR_EXPRESSION_OPEN;
+            op1->precedence = eval_precedence(EVAL_OPERATOR_EXPRESSION_OPEN);
+            eval_node_set_value_to_node(op1, 0, sub);
+            if(!parse_close_subexpression(string)) {
+                *error = EVAL_ERROR_MISSING_CLOSE_SUBEXPRESSION;
+                eval_node_free(op1);
+                return NULL;
+            }
+        }
+    }
+//    else if(parse_variable(string)) {
+//
+//    }
+    else if(parse_constant(string, &number)) {
+        op1 = eval_node_alloc(1);
+        op1->operator = EVAL_OPERATOR_VALUE;
+        eval_node_set_value_to_constant(op1, 0, number);
+    }
+    else if(**string)
+        *error = EVAL_ERROR_UNKNOWN_OPERAND;
+    else
+        *error = EVAL_ERROR_MISSING_OPERAND;
+
+    return op1;
+}
+
+// parse an operator and the rest of the expression
+// precedence processing is handled here
+static inline EVAL_NODE *parse_rest_of_expression(const char **string, int *error, EVAL_NODE *op1) {
+    EVAL_NODE *op2 = NULL;
+    unsigned char operator;
+    int precedence;
+
+    operator = parse_operator(string, &precedence);
+    skip_spaces(string);
+
+    if(operator != EVAL_OPERATOR_NOP) {
+        op2 = parse_one_full_operand(string, error);
+        if(!op2) {
+            // error is already reported
+            eval_node_free(op1);
+            return NULL;
+        }
+
+        EVAL_NODE *op = eval_node_alloc(2);
+        op->operator = operator;
+        op->precedence = precedence;
+
+        eval_node_set_value_to_node(op, 1, op2);
+
+        // precedence processing
+        // if this operator has a higher precedence compared to its next
+        // put the next operator on top of us (top = evaluated later)
+        // function recursion does the rest...
+        if(op->precedence > op1->precedence && op1->count == 2 && op1->operator != '(' && op1->ops[1].type == EVAL_VALUE_EXPRESSION) {
+            eval_node_set_value_to_node(op, 0, op1->ops[1].expression);
+            op1->ops[1].expression = op;
+            op = op1;
+        }
+        else
+            eval_node_set_value_to_node(op, 0, op1);
+
+        return parse_rest_of_expression(string, error, op);
+    }
+    else if(**string == ')') {
+        ;
+    }
+    else if(**string) {
+        if(op1) eval_node_free(op1);
+        op1 = NULL;
+        *error = EVAL_ERROR_MISSING_OPERATOR;
+    }
+
+    return op1;
+}
+
+// high level function to parse an expression or a sub-expression
+static inline EVAL_NODE *parse_full_expression(const char **string, int *error) {
+    EVAL_NODE *op1 = NULL;
+
+    op1 = parse_one_full_operand(string, error);
+    if(!op1) {
+        *error = EVAL_ERROR_MISSING_OPERAND;
+        return NULL;
+    }
+
+    return parse_rest_of_expression(string, error, op1);
+}
+
+// ----------------------------------------------------------------------------
+// public API
+
+int expression_evaluate(EVAL_EXPRESSION *exp) {
+    exp->error = EVAL_ERROR_OK;
+
+    buffer_reset(exp->error_msg);
+    exp->result = eval_node(exp, (EVAL_NODE *)exp->nodes, &exp->error);
+
+    if(exp->error != EVAL_ERROR_OK) {
+        if(buffer_strlen(exp->error_msg))
+            buffer_strcat(exp->error_msg, "; ");
+
+        buffer_sprintf(exp->error_msg, "failed to evaluate expression with error %d (%s)", exp->error, expression_strerror(exp->error));
+        return 0;
+    }
+
+    return 1;
+}
+
+EVAL_EXPRESSION *expression_parse(const char *string, const char **failed_at, int *error) {
+    const char *s;
+    int err = EVAL_ERROR_OK;
+    unsigned long pos = 0;
+
+    s = string;
+    EVAL_NODE *op = parse_full_expression(&s, &err);
+
+    if(*s) {
+        if(op) {
+            eval_node_free(op);
+            op = NULL;
+        }
+        err = EVAL_ERROR_REMAINING_GARBAGE;
+    }
+
+    if (failed_at) *failed_at = s;
+    if (error) *error = err;
+
+    if(!op) {
+        pos = s - string + 1;
+        error("failed to parse expression '%s': %s at character %lu (i.e.: '%s').", string, expression_strerror(err), pos, s);
+        return NULL;
+    }
+
+    BUFFER *out = buffer_create(1024);
+    print_parsed_as_node(out, op, &err);
+    if(err != EVAL_ERROR_OK) {
+        error("failed to re-generate expression '%s' with reason: %s", string, expression_strerror(err));
+        eval_node_free(op);
+        buffer_free(out);
+        return NULL;
+    }
+
+    EVAL_EXPRESSION *exp = callocz(1, sizeof(EVAL_EXPRESSION));
+
+    exp->parsed_as = strdupz(buffer_tostring(out));
+    buffer_free(out);
+
+    exp->error_msg = buffer_create(100);
+    exp->nodes = (void *)op;
+
+    return exp;
+}
+
+void expression_free(EVAL_EXPRESSION *exp) {
+    if(!exp) return;
+
+    if(exp->nodes) eval_node_free((EVAL_NODE *)exp->nodes);
+    freez((void *)exp->source);
+    freez((void *)exp->parsed_as);
+    buffer_free(exp->error_msg);
+    freez(exp);
+}
+
+const char *expression_strerror(int error) {
+    switch(error) {
+        case EVAL_ERROR_OK:
+            return "success";
+
+        case EVAL_ERROR_MISSING_CLOSE_SUBEXPRESSION:
+            return "missing closing parenthesis";
+
+        case EVAL_ERROR_UNKNOWN_OPERAND:
+            return "unknown operand";
+
+        case EVAL_ERROR_MISSING_OPERAND:
+            return "expected operand";
+
+        case EVAL_ERROR_MISSING_OPERATOR:
+            return "expected operator";
+
+        case EVAL_ERROR_REMAINING_GARBAGE:
+            return "remaining characters after expression";
+
+        case EVAL_ERROR_INVALID_VALUE:
+            return "invalid value structure - internal error";
+
+        case EVAL_ERROR_INVALID_NUMBER_OF_OPERANDS:
+            return "wrong number of operands for operation - internal error";
+
+        case EVAL_ERROR_VALUE_IS_NAN:
+            return "value or variable is missing or is not a number";
+
+        case EVAL_ERROR_VALUE_IS_INFINITE:
+            return "computed value is infinite";
+
+        case EVAL_ERROR_UNKNOWN_VARIABLE:
+            return "undefined variable";
+
+        default:
+            return "unknown error";
+    }
+}
diff --git a/src/eval.h b/src/eval.h
new file mode 100644 (file)
index 0000000..1ac56bf
--- /dev/null
@@ -0,0 +1,63 @@
+#ifndef NETDATA_EVAL_H
+#define NETDATA_EVAL_H
+
+typedef struct eval_variable {
+    char *name;
+    struct rrdvar *rrdvar;
+    struct eval_variable *next;
+} EVAL_VARIABLE;
+
+typedef struct eval_expression {
+    const char *source;
+    const char *parsed_as;
+
+    calculated_number result;
+
+    int error;
+    BUFFER *error_msg;
+
+    // hidden EVAL_NODE *
+    void *nodes;
+
+    // custom data to be used for looking up variables
+    void *data;
+} EVAL_EXPRESSION;
+
+#define EVAL_VALUE_INVALID 0
+#define EVAL_VALUE_NUMBER 1
+#define EVAL_VALUE_VARIABLE 2
+#define EVAL_VALUE_EXPRESSION 3
+
+#define EVAL_ERROR_OK 0
+
+// parsing errors
+#define EVAL_ERROR_MISSING_CLOSE_SUBEXPRESSION 1
+#define EVAL_ERROR_UNKNOWN_OPERAND 2
+#define EVAL_ERROR_MISSING_OPERAND 3
+#define EVAL_ERROR_MISSING_OPERATOR 4
+#define EVAL_ERROR_REMAINING_GARBAGE 5
+
+// evaluation errors
+#define EVAL_ERROR_INVALID_VALUE 11
+#define EVAL_ERROR_INVALID_NUMBER_OF_OPERANDS 12
+#define EVAL_ERROR_VALUE_IS_NAN 13
+#define EVAL_ERROR_VALUE_IS_INFINITE 14
+#define EVAL_ERROR_UNKNOWN_VARIABLE 15
+
+// parse the given string as an expression and return:
+//   a pointer to an expression if it parsed OK
+//   NULL in which case the pointer to error has the error code
+extern EVAL_EXPRESSION *expression_parse(const char *string, const char **failed_at, int *error);
+
+// free all resources allocated for an expression
+extern void expression_free(EVAL_EXPRESSION *op);
+
+// convert an error code to a message
+extern const char *expression_strerror(int error);
+
+// evaluate an expression and return
+// 1 = OK, the result is in: expression->result
+// 2 = FAILED, the error message is in: buffer_tostring(expression->error_msg)
+extern int expression_evaluate(EVAL_EXPRESSION *expression);
+
+#endif //NETDATA_EVAL_H
index 40d3c3e3da83a6b38e9ea66a3da31a0fc8ae7425..e2852962a44507a30a9e57222e38ede8d0d3631a 100644 (file)
@@ -1,9 +1,4 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <pthread.h>
-
-#include "global_statistics.h"
+#include "common.h"
 
 struct global_statistics global_statistics = { 0, 0ULL, 0ULL, 0ULL, 0ULL, 0ULL, 0ULL};
 
diff --git a/src/health.c b/src/health.c
new file mode 100644 (file)
index 0000000..3173781
--- /dev/null
@@ -0,0 +1,607 @@
+#include "common.h"
+
+// ----------------------------------------------------------------------------
+// RRDVAR management
+
+int rrdvar_compare(void* a, void* b) {
+    if(((RRDVAR *)a)->hash < ((RRDVAR *)b)->hash) return -1;
+    else if(((RRDVAR *)a)->hash > ((RRDVAR *)b)->hash) return 1;
+    else return strcmp(((RRDVAR *)a)->name, ((RRDVAR *)b)->name);
+}
+
+static inline RRDVAR *rrdvar_index_add(avl_tree_lock *tree, RRDVAR *rv) {
+    RRDVAR *ret = (RRDVAR *)avl_insert_lock(tree, (avl *)(rv));
+    if(ret != rv)
+        debug(D_VARIABLES, "Request to insert RRDVAR '%s' into index failed. Already exists.", rv->name);
+
+    return ret;
+}
+
+static inline RRDVAR *rrdvar_index_del(avl_tree_lock *tree, RRDVAR *rv) {
+    RRDVAR *ret = (RRDVAR *)avl_remove_lock(tree, (avl *)(rv));
+    if(!ret)
+        fatal("Request to remove RRDVAR '%s' from index failed. Not Found.", rv->name);
+
+    return ret;
+}
+
+static inline RRDVAR *rrdvar_index_find(avl_tree_lock *tree, const char *name, uint32_t hash) {
+    RRDVAR tmp;
+    tmp.name = (char *)name;
+    tmp.hash = (hash)?hash:simple_hash(tmp.name);
+
+    return (RRDVAR *)avl_search_lock(tree, (avl *)&tmp);
+}
+
+static inline RRDVAR *rrdvar_create(const char *name, uint32_t hash, int type, calculated_number *value) {
+    RRDVAR *rv = callocz(1, sizeof(RRDVAR));
+
+    rv->name = (char *)name;
+    rv->hash = (hash)?hash:simple_hash((rv->name));
+    rv->type = type;
+    rv->value = value;
+
+    return rv;
+}
+
+static inline void rrdvar_free(RRDHOST *host, RRDVAR *rv) {
+    if(host) {
+        // FIXME: we may need some kind of locking here
+        // to have mutually exclusive access with eval()
+        EVAL_VARIABLE *rf;
+        for (rf = host->references; rf; rf = rf->next)
+            if (rf->rrdvar == rv) rf->rrdvar = NULL;
+    }
+
+    freez(rv);
+}
+
+static inline RRDVAR *rrdvar_create_and_index(const char *scope, avl_tree_lock *tree, const char *name, uint32_t hash, int type, calculated_number *value) {
+    RRDVAR *rv = rrdvar_index_find(tree, name, hash);
+    if(unlikely(!rv)) {
+        debug(D_VARIABLES, "Variable '%s' not found in scope '%s'. Creating a new one.", name, scope);
+
+        rv = rrdvar_create(name, hash, type, value);
+        RRDVAR *ret = rrdvar_index_add(tree, rv);
+        if(unlikely(ret != rv)) {
+            debug(D_VARIABLES, "Variable '%s' in scope '%s' already exists", name, scope);
+            rrdvar_free(NULL, rv);
+            rv = NULL;
+        }
+        else
+            debug(D_VARIABLES, "Variable '%s' created in scope '%s'", name, scope);
+    }
+    else {
+        // already exists
+        rv = NULL;
+    }
+
+    /*
+     * check
+    if(rv) {
+        RRDVAR *ret = rrdvar_index_find(tree, name, hash);
+        if(ret != rv) fatal("oops! 1");
+
+        ret = rrdvar_index_del(tree, rv);
+        if(ret != rv) fatal("oops! 2");
+
+        ret = rrdvar_index_add(tree, rv);
+        if(ret != rv) fatal("oops! 3");
+    }
+    */
+
+    return rv;
+}
+
+// ----------------------------------------------------------------------------
+// RRDSETVAR management
+
+#define RRDSETVAR_ID_MAX 1024
+
+RRDSETVAR *rrdsetvar_create(RRDSET *st, const char *variable, int type, void *value, uint32_t options) {
+    debug(D_VARIABLES, "RRDVARSET create for chart id '%s' name '%s' with variable name '%s'", st->id, st->name, variable);
+    RRDSETVAR *rs = (RRDSETVAR *)callocz(1, sizeof(RRDSETVAR));
+
+    char buffer[RRDSETVAR_ID_MAX + 1];
+    snprintfz(buffer, RRDSETVAR_ID_MAX, "%s.%s", st->id, variable);
+    rs->fullid = strdupz(buffer);
+    rs->hash_fullid = simple_hash(rs->fullid);
+
+    snprintfz(buffer, RRDSETVAR_ID_MAX, "%s.%s", st->name, variable);
+    rs->fullname = strdupz(buffer);
+    rs->hash_fullname = simple_hash(rs->fullname);
+
+    rs->variable = strdupz(variable);
+    rs->hash_variable = simple_hash(rs->variable);
+
+    rs->type = type;
+    rs->value = value;
+    rs->options = options;
+    rs->rrdset = st;
+
+    rs->local        = rrdvar_create_and_index("local",   &st->variables_root_index, rs->variable, rs->hash_variable, rs->type, rs->value);
+    rs->context      = rrdvar_create_and_index("context", &st->rrdcontext->variables_root_index, rs->fullid, rs->hash_fullid, rs->type, rs->value);
+    rs->host         = rrdvar_create_and_index("host",    &st->rrdhost->variables_root_index, rs->fullid, rs->hash_fullid, rs->type, rs->value);
+    rs->context_name = rrdvar_create_and_index("context", &st->rrdcontext->variables_root_index, rs->fullname, rs->hash_fullname, rs->type, rs->value);
+    rs->host_name    = rrdvar_create_and_index("host",    &st->rrdhost->variables_root_index, rs->fullname, rs->hash_fullname, rs->type, rs->value);
+
+    rs->next = st->variables;
+    st->variables = rs;
+
+    return rs;
+}
+
+void rrdsetvar_rename_all(RRDSET *st) {
+    debug(D_VARIABLES, "RRDSETVAR rename for chart id '%s' name '%s'", st->id, st->name);
+
+    // only these 2 can change name
+    // rs->context_name
+    // rs->host_name
+
+    char buffer[RRDSETVAR_ID_MAX + 1];
+    RRDSETVAR *rs, *next = st->variables;
+    while((rs = next)) {
+        next = rs->next;
+
+        snprintfz(buffer, RRDSETVAR_ID_MAX, "%s.%s", st->name, rs->variable);
+
+        if (strcmp(buffer, rs->fullname)) {
+            // name changed
+            if (rs->context_name) {
+                rrdvar_index_del(&st->rrdcontext->variables_root_index, rs->context_name);
+                rrdvar_free(st->rrdhost, rs->context_name);
+            }
+
+            if (rs->host_name) {
+                rrdvar_index_del(&st->rrdhost->variables_root_index, rs->host_name);
+                rrdvar_free(st->rrdhost, rs->host_name);
+            }
+
+            freez(rs->fullname);
+            rs->fullname = strdupz(st->name);
+            rs->hash_fullname = simple_hash(rs->fullname);
+            rs->context_name = rrdvar_create_and_index("context", &st->rrdcontext->variables_root_index, rs->fullname, rs->hash_fullname, rs->type, rs->value);
+            rs->host_name    = rrdvar_create_and_index("host",    &st->rrdhost->variables_root_index, rs->fullname, rs->hash_fullname, rs->type, rs->value);
+        }
+    }
+
+    rrdsetcalc_link_matching(st);
+}
+
+void rrdsetvar_free(RRDSETVAR *rs) {
+    RRDSET *st = rs->rrdset;
+    debug(D_VARIABLES, "RRDSETVAR free for chart id '%s' name '%s', variable '%s'", st->id, st->name, rs->variable);
+
+    if(rs->local) {
+        rrdvar_index_del(&st->variables_root_index, rs->local);
+        rrdvar_free(st->rrdhost, rs->local);
+    }
+
+    if(rs->context) {
+        rrdvar_index_del(&st->rrdcontext->variables_root_index, rs->context);
+        rrdvar_free(st->rrdhost, rs->context);
+    }
+
+    if(rs->host) {
+        rrdvar_index_del(&st->rrdhost->variables_root_index, rs->host);
+        rrdvar_free(st->rrdhost, rs->host);
+    }
+
+    if(rs->context_name) {
+        rrdvar_index_del(&st->rrdcontext->variables_root_index, rs->context_name);
+        rrdvar_free(st->rrdhost, rs->context_name);
+    }
+
+    if(rs->host_name) {
+        rrdvar_index_del(&st->rrdhost->variables_root_index, rs->host_name);
+        rrdvar_free(st->rrdhost, rs->host_name);
+    }
+
+    if(st->variables == rs) {
+        st->variables = rs->next;
+    }
+    else {
+        RRDSETVAR *t;
+        for (t = st->variables; t && t->next != rs; t = t->next);
+        if(!t) error("RRDSETVAR '%s' not found in chart '%s' variables linked list", rs->fullname, st->id);
+        else t->next = rs->next;
+    }
+
+    freez(rs->fullid);
+    freez(rs->fullname);
+    freez(rs->variable);
+    freez(rs);
+}
+
+// ----------------------------------------------------------------------------
+// RRDDIMVAR management
+
+#define RRDDIMVAR_ID_MAX 1024
+
+RRDDIMVAR *rrddimvar_create(RRDDIM *rd, int type, const char *prefix, const char *suffix, void *value, uint32_t options) {
+    RRDSET *st = rd->rrdset;
+
+    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:"");
+
+    if(!prefix) prefix = "";
+    if(!suffix) suffix = "";
+
+    char buffer[RRDDIMVAR_ID_MAX + 1];
+    RRDDIMVAR *rs = (RRDDIMVAR *)callocz(1, sizeof(RRDDIMVAR));
+
+    rs->prefix = strdupz(prefix);
+    rs->suffix = strdupz(suffix);
+
+    snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s%s%s", rs->prefix, rd->id, rs->suffix);
+    rs->id = strdupz(buffer);
+    rs->hash = simple_hash(rs->id);
+
+    snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s%s%s", rs->prefix, rd->name, rs->suffix);
+    rs->name = strdupz(buffer);
+    rs->hash_name = simple_hash(rs->name);
+
+    snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", rd->rrdset->id, rs->id);
+    rs->fullidid = strdupz(buffer);
+    rs->hash_fullidid = simple_hash(rs->fullidid);
+
+    snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", rd->rrdset->id, rs->name);
+    rs->fullidname = strdupz(buffer);
+    rs->hash_fullidname = simple_hash(rs->fullidname);
+
+    snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", rd->rrdset->name, rs->id);
+    rs->fullnameid = strdupz(buffer);
+    rs->hash_fullnameid = simple_hash(rs->fullnameid);
+
+    snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", rd->rrdset->name, rs->name);
+    rs->fullnamename = strdupz(buffer);
+    rs->hash_fullnamename = simple_hash(rs->fullnamename);
+
+    rs->type = type;
+    rs->value = value;
+    rs->options = options;
+    rs->rrddim = rd;
+
+    rs->local_id     = rrdvar_create_and_index("local",   &st->variables_root_index, rs->id, rs->hash, rs->type, rs->value);
+    rs->local_name   = rrdvar_create_and_index("local",   &st->variables_root_index, rs->name, rs->hash_name, rs->type, rs->value);
+
+    rs->context_fullidid     = rrdvar_create_and_index("context", &st->rrdcontext->variables_root_index, rs->fullidid, rs->hash_fullidid, rs->type, rs->value);
+    rs->context_fullidname   = rrdvar_create_and_index("context", &st->rrdcontext->variables_root_index, rs->fullidname, rs->hash_fullidname, rs->type, rs->value);
+    rs->context_fullnameid   = rrdvar_create_and_index("context", &st->rrdcontext->variables_root_index, rs->fullnameid, rs->hash_fullnameid, rs->type, rs->value);
+    rs->context_fullnamename = rrdvar_create_and_index("context", &st->rrdcontext->variables_root_index, rs->fullnamename, rs->hash_fullnamename, rs->type, rs->value);
+
+    rs->host_fullidid     = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->fullidid, rs->hash_fullidid, rs->type, rs->value);
+    rs->host_fullidname   = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->fullidname, rs->hash_fullidname, rs->type, rs->value);
+    rs->host_fullnameid   = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->fullnameid, rs->hash_fullnameid, rs->type, rs->value);
+    rs->host_fullnamename = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rs->fullnamename, rs->hash_fullnamename, rs->type, rs->value);
+
+    rs->next = rd->variables;
+    rd->variables = rs;
+
+    return rs;
+}
+
+void rrddimvar_rename_all(RRDDIM *rd) {
+    RRDSET *st = rd->rrdset;
+    debug(D_VARIABLES, "RRDDIMSET rename for chart id '%s' name '%s', dimension id '%s', name '%s'", st->id, st->name, rd->id, rd->name);
+
+    RRDDIMVAR *rs, *next = rd->variables;
+    while((rs = next)) {
+        next = rs->next;
+
+        if (strcmp(rd->name, rs->name)) {
+            char buffer[RRDDIMVAR_ID_MAX + 1];
+            // name changed
+
+            // name
+            if (rs->local_name) {
+                rrdvar_index_del(&st->variables_root_index, rs->local_name);
+                rrdvar_free(st->rrdhost, rs->local_name);
+            }
+            freez(rs->name);
+            snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s%s%s", rs->prefix, rd->name, rs->suffix);
+            rs->name = strdupz(buffer);
+            rs->hash_name = simple_hash(rs->name);
+            rs->local_name = rrdvar_create_and_index("local", &st->variables_root_index, rs->name, rs->hash_name, rs->type, rs->value);
+
+            // fullidname
+            if (rs->context_fullidname) {
+                rrdvar_index_del(&st->rrdcontext->variables_root_index, rs->context_fullidname);
+                rrdvar_free(st->rrdhost, rs->context_fullidname);
+            }
+            if (rs->host_fullidname) {
+                rrdvar_index_del(&st->rrdhost->variables_root_index, rs->context_fullidname);
+                rrdvar_free(st->rrdhost, rs->host_fullidname);
+            }
+            freez(rs->fullidname);
+            snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", st->id, rs->name);
+            rs->fullidname = strdupz(buffer);
+            rs->hash_fullidname = simple_hash(rs->fullidname);
+            rs->context_fullidname = rrdvar_create_and_index("context", &st->rrdcontext->variables_root_index,
+                                                             rs->fullidname, rs->hash_fullidname, rs->type, rs->value);
+            rs->host_fullidname = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index,
+                                                             rs->fullidname, rs->hash_fullidname, rs->type, rs->value);
+
+            // fullnameid
+            if (rs->context_fullnameid) {
+                rrdvar_index_del(&st->rrdcontext->variables_root_index, rs->context_fullnameid);
+                rrdvar_free(st->rrdhost, rs->context_fullnameid);
+            }
+            if (rs->host_fullnameid) {
+                rrdvar_index_del(&st->rrdhost->variables_root_index, rs->context_fullnameid);
+                rrdvar_free(st->rrdhost, rs->host_fullnameid);
+            }
+            freez(rs->fullnameid);
+            snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", st->name, rs->id);
+            rs->fullnameid = strdupz(buffer);
+            rs->hash_fullnameid = simple_hash(rs->fullnameid);
+            rs->context_fullnameid = rrdvar_create_and_index("context", &st->rrdcontext->variables_root_index,
+                                                             rs->fullnameid, rs->hash_fullnameid, rs->type, rs->value);
+            rs->host_fullnameid = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index,
+                                                          rs->fullnameid, rs->hash_fullnameid, rs->type, rs->value);
+
+            // fullnamename
+            if (rs->context_fullnamename) {
+                rrdvar_index_del(&st->rrdcontext->variables_root_index, rs->context_fullnamename);
+                rrdvar_free(st->rrdhost, rs->context_fullnamename);
+            }
+            if (rs->host_fullnamename) {
+                rrdvar_index_del(&st->rrdhost->variables_root_index, rs->context_fullnamename);
+                rrdvar_free(st->rrdhost, rs->host_fullnamename);
+            }
+            freez(rs->fullnamename);
+            snprintfz(buffer, RRDDIMVAR_ID_MAX, "%s.%s", st->name, rs->name);
+            rs->fullnamename = strdupz(buffer);
+            rs->hash_fullnamename = simple_hash(rs->fullnamename);
+            rs->context_fullnamename = rrdvar_create_and_index("context", &st->rrdcontext->variables_root_index,
+                                                             rs->fullnamename, rs->hash_fullnamename, rs->type, rs->value);
+            rs->host_fullnamename = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index,
+                                                          rs->fullnamename, rs->hash_fullnamename, rs->type, rs->value);
+        }
+    }
+}
+
+void rrddimvar_free(RRDDIMVAR *rs) {
+    RRDDIM *rd = rs->rrddim;
+    RRDSET *st = rd->rrdset;
+    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);
+
+    if(rs->local_id) {
+        rrdvar_index_del(&st->variables_root_index, rs->local_id);
+        rrdvar_free(st->rrdhost, rs->local_id);
+    }
+    if(rs->local_name) {
+        rrdvar_index_del(&st->variables_root_index, rs->local_name);
+        rrdvar_free(st->rrdhost, rs->local_name);
+    }
+
+    if(rs->context_fullidid) {
+        rrdvar_index_del(&st->rrdcontext->variables_root_index, rs->context_fullidid);
+        rrdvar_free(st->rrdhost, rs->context_fullidid);
+    }
+    if(rs->context_fullidname) {
+        rrdvar_index_del(&st->rrdcontext->variables_root_index, rs->context_fullidname);
+        rrdvar_free(st->rrdhost, rs->context_fullidname);
+    }
+    if(rs->context_fullnameid) {
+        rrdvar_index_del(&st->rrdcontext->variables_root_index, rs->context_fullnameid);
+        rrdvar_free(st->rrdhost, rs->context_fullnameid);
+    }
+    if(rs->context_fullnamename) {
+        rrdvar_index_del(&st->rrdcontext->variables_root_index, rs->context_fullnamename);
+        rrdvar_free(st->rrdhost, rs->context_fullnamename);
+    }
+
+    if(rs->host_fullidid) {
+        rrdvar_index_del(&st->rrdhost->variables_root_index, rs->host_fullidid);
+        rrdvar_free(st->rrdhost, rs->host_fullidid);
+    }
+    if(rs->host_fullidname) {
+        rrdvar_index_del(&st->rrdhost->variables_root_index, rs->host_fullidname);
+        rrdvar_free(st->rrdhost, rs->host_fullidname);
+    }
+    if(rs->host_fullnameid) {
+        rrdvar_index_del(&st->rrdhost->variables_root_index, rs->host_fullnameid);
+        rrdvar_free(st->rrdhost, rs->host_fullnameid);
+    }
+    if(rs->host_fullnamename) {
+        rrdvar_index_del(&st->rrdhost->variables_root_index, rs->host_fullnamename);
+        rrdvar_free(st->rrdhost, rs->host_fullnamename);
+    }
+
+    if(rd->variables == rs) {
+        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);
+        rd->variables = rs->next;
+    }
+    else {
+        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);
+        RRDDIMVAR *t;
+        for (t = rd->variables; t && t->next != rs; t = t->next) ;
+        if(!t) error("RRDDIMVAR '%s' not found in dimension '%s/%s' variables linked list", rs->name, st->id, rd->id);
+        else t->next = rs->next;
+    }
+
+    freez(rs->prefix);
+    freez(rs->suffix);
+    freez(rs->id);
+    freez(rs->name);
+    freez(rs->fullidid);
+    freez(rs->fullidname);
+    freez(rs->fullnameid);
+    freez(rs->fullnamename);
+    freez(rs);
+}
+
+// ----------------------------------------------------------------------------
+// RRDCALC management
+
+// this has to be called while the caller has locked
+// the RRDHOST
+static inline void rrdhostcalc_linked(RRDHOST *host, RRDCALC *rc) {
+    // move it to be last
+
+    if(!rc->next)
+        // we are last already
+        return;
+
+    RRDCALC *t, *last = NULL, *prev = NULL;
+    for (t = host->calculations; t ; t = t->next) {
+        if(t->next == rc)
+            prev = t;
+
+        if(!t->next)
+            last = t;
+    }
+
+    if(!last) {
+        error("RRDCALC '%s' cannot be linked to the end of host '%s' list", rc->name, host->hostname);
+        return;
+    }
+
+    if(prev)
+        prev->next = rc->next;
+    else {
+        if(host->calculations == rc)
+            host->calculations = rc->next;
+        else {
+            error("RRDCALC '%s' is not found in host '%s' list", rc->name, host->hostname);
+            return;
+        }
+    }
+
+    last->next = rc;
+    rc->next = NULL;
+}
+
+// this has to be called while the caller has locked
+// the RRDHOST
+static inline void rrdhostcalc_unlinked(RRDHOST *host, RRDCALC *rc) {
+    // move it to be first
+
+    if(host->calculations == rc) {
+        // ok, we are the first
+        return;
+    }
+    else {
+        // find the previous one
+        RRDCALC *t;
+        for (t = host->calculations; t && t->next != rc; rc = rc->next) ;
+        if(unlikely(!t)) {
+            error("RRDCALC '%s' is not linked to host '%s'.", rc->name, host->hostname);
+            return;
+        }
+        t->next = rc->next;
+        rc->next = host->calculations;
+        host->calculations = rc;
+    }
+}
+
+static void rrdsetcalc_link(RRDSET *st, RRDCALC *rc) {
+    rc->rrdset = st;
+
+    rc->local   = rrdvar_create_and_index("local", &st->variables_root_index, rc->name, rc->hash, RRDVAR_TYPE_CALCULATED, &rc->value);
+    rc->context = rrdvar_create_and_index("context", &st->rrdcontext->variables_root_index, rc->name, rc->hash, RRDVAR_TYPE_CALCULATED, &rc->value);
+    rc->host    = rrdvar_create_and_index("host", &st->rrdhost->variables_root_index, rc->name, rc->hash, RRDVAR_TYPE_CALCULATED, &rc->value);
+
+    rrdhostcalc_linked(st->rrdhost, rc);
+}
+
+// this has to be called while the RRDHOST is locked
+void rrdsetcalc_link_matching(RRDSET *st) {
+    RRDCALC *rc;
+
+    for(rc = st->rrdhost->calculations; rc ; rc = rc->next) {
+        // since unlinked ones are in front and linked at the end
+        // we stop on the first linked RRDCALC
+        if(rc->rrdset != NULL) break;
+
+        if((rc->hash_chart == st->hash && !strcmp(rc->name, st->id)) ||
+                (rc->hash_chart == st->hash_name && !strcmp(rc->name, st->name))) {
+            rrdsetcalc_link(st, rc);
+        }
+    }
+}
+
+// this has to be called while the RRDHOST is locked
+void rrdsetcalc_unlink(RRDCALC *rc) {
+    RRDSET *st = rc->rrdset;
+
+    if(!st) {
+        error("Requested to unlink RRDCALC '%s' which is not linked to any RRDSET", rc->name);
+        return;
+    }
+
+    RRDHOST *host = st->rrdhost;
+
+    // unlink it
+    if(rc->rrdset_prev)
+        rc->rrdset_prev->rrdset_next = rc->rrdset_next;
+
+    if(rc->rrdset_next)
+        rc->rrdset_next->rrdset_prev = rc->rrdset_prev;
+
+    if(st->calculations == rc)
+        st->calculations = rc->rrdset_next;
+
+    rc->rrdset_prev = rc->rrdset_next = NULL;
+
+    if(rc->local) {
+        rrdvar_index_del(&st->variables_root_index, rc->local);
+        rrdvar_free(st->rrdhost, rc->local);
+        rc->local = NULL;
+    }
+
+    if(rc->context) {
+        rrdvar_index_del(&st->rrdcontext->variables_root_index, rc->context);
+        rc->context = NULL;
+    }
+
+    if(rc->host) {
+        rrdvar_index_del(&st->rrdhost->variables_root_index, rc->host);
+        rc->host = NULL;
+    }
+
+    rc->rrdset = NULL;
+
+    // RRDCALC will remain in RRDHOST
+    // so that if the matching chart is found in the future
+    // it will be applied automatically
+
+    rrdhostcalc_unlinked(host, rc);
+}
+
+RRDCALC *rrdcalc_create(RRDHOST *host, const char *name, const char *chart, const char *dimensions, int group_method, uint32_t after, uint32_t before, int update_every, uint32_t options) {
+    uint32_t hash = simple_hash(name);
+
+    RRDCALC *rc;
+
+    // make sure it does not already exist
+    for(rc = host->calculations; rc ; rc = rc->next) {
+        if (rc->hash == hash && !strcmp(name, rc->name)) {
+            error("Attempted to create RRDCAL '%s' in host '%s', but it already exists. Ignoring it.", name, host->hostname);
+            return NULL;
+        }
+    }
+
+    rc = callocz(1, sizeof(RRDCALC));
+
+    rc->name = strdupz(name);
+    rc->hash = simple_hash(rc->name);
+
+    rc->chart = strdupz(chart);
+    rc->hash_chart = simple_hash(rc->chart);
+
+    if(dimensions) {
+        rc->dimensions = strdupz(dimensions);
+        rc->hash_chart = simple_hash(rc->chart);
+    }
+
+    return NULL;
+}
+
+void rrdcalc_free(RRDCALC *rc) {
+    if(!rc) return;
+
+    if(rc->rrdset) rrdsetcalc_unlink(rc);
+
+    freez(rc);
+}
\ No newline at end of file
diff --git a/src/health.h b/src/health.h
new file mode 100644 (file)
index 0000000..f30e432
--- /dev/null
@@ -0,0 +1,208 @@
+#ifndef NETDATA_HEALTH_H
+#define NETDATA_HEALTH_H
+
+extern int rrdvar_compare(void *a, void *b);
+
+/*
+ * RRDVAR
+ * a variable
+ *
+ * There are 4 scopes: local (chart), context, host and global variables
+ *
+ * Standard global variables:
+ *  $now
+ *
+ * Standard host variables:
+ *  - none -
+ *
+ * Standard context variables:
+ *  - none -
+ *
+ * Standard local variables:
+ *  $last_updated
+ *  $last_collected_value
+ *  $last_value
+ *
+ */
+
+#define RRDVAR_TYPE_CALCULATED 1
+#define RRDVAR_TYPE_TIME_T     2
+#define RRDVAR_TYPE_COLLECTED  3
+#define RRDVAR_TYPE_TOTAL      4
+
+// the variables as stored in the variables indexes
+typedef struct rrdvar {
+    avl avl;
+
+    char *name;
+    uint32_t hash;
+
+    int type;
+    void *value;
+
+    time_t last_updated;
+} RRDVAR;
+
+// variables linked to charts
+// We link variables to point the values that are already
+// calculated / processed by the normal data collection process
+// This means, there will be no speed penalty for using
+// these variables
+typedef struct rrdsetvar {
+    char *fullid;               // chart type.chart id.variable
+    uint32_t hash_fullid;
+
+    char *fullname;             // chart type.chart name.variable
+    uint32_t hash_fullname;
+
+    char *variable;             // variable
+    uint32_t hash_variable;
+
+    int type;
+    void *value;
+
+    uint32_t options;
+
+    RRDVAR *local;
+    RRDVAR *context;
+    RRDVAR *host;
+    RRDVAR *context_name;
+    RRDVAR *host_name;
+
+    struct rrdset *rrdset;
+
+    struct rrdsetvar *next;
+} RRDSETVAR;
+
+
+// variables linked to dimensions
+// We link variables to point the values that are already
+// calculated / processed by the normal data collection process
+// This means, there will be no speed penalty for using
+// these variables
+typedef struct rrddimvar {
+    char *prefix;
+    char *suffix;
+
+    char *id;                   // dimension id
+    uint32_t hash;
+
+    char *name;                 // dimension name
+    uint32_t hash_name;
+
+    char *fullidid;             // chart type.chart id.dimension id
+    uint32_t hash_fullidid;
+
+    char *fullidname;           // chart type.chart id.dimension name
+    uint32_t hash_fullidname;
+
+    char *fullnameid;           // chart type.chart name.dimension id
+    uint32_t hash_fullnameid;
+
+    char *fullnamename;         // chart type.chart name.dimension name
+    uint32_t hash_fullnamename;
+
+    int type;
+    void *value;
+
+    uint32_t options;
+
+    RRDVAR *local_id;
+    RRDVAR *local_name;
+
+    RRDVAR *context_fullidid;
+    RRDVAR *context_fullidname;
+    RRDVAR *context_fullnameid;
+    RRDVAR *context_fullnamename;
+
+    RRDVAR *host_fullidid;
+    RRDVAR *host_fullidname;
+    RRDVAR *host_fullnameid;
+    RRDVAR *host_fullnamename;
+
+    struct rrddim *rrddim;
+
+    struct rrddimvar *next;
+} RRDDIMVAR;
+
+// additional calculated variables
+// These aggregate time-series data at fixed intervals
+// (defined in their update_every member below)
+// These increase the overhead of netdata.
+//
+// These calculations are allocated and linked (->next)
+// to RRDHOST.
+// Then are also linked to RRDSET (of course only when the
+// chart is found, via ->rrdset_next and ->rrdset_prev).
+// This double-linked list is maintained sorted at all times
+// having as RRDSET->calculations the RRDCALC to be processed
+// next.
+typedef struct rrdcalc {
+    char *name;
+    uint32_t hash;
+
+    char *chart;        // the chart name
+    uint32_t hash_chart;
+
+    char *dimensions;   // the chart dimensions
+
+    int group;          // grouping method: average, max, etc.
+    int before;         // ending point in time-series
+    int after;          // starting point in time-series
+    uint32_t options;   // calculation options
+    int update_every;   // update frequency for the calculation
+
+    time_t last_updated;
+    time_t next_update;
+
+    EVAL_EXPRESSION *expression;
+
+    calculated_number value;
+
+    RRDVAR *local;
+    RRDVAR *context;
+    RRDVAR *host;
+
+    struct rrdset *rrdset;
+    struct rrdcalc *rrdset_next;
+    struct rrdcalc *rrdset_prev;
+
+    struct rrdcalc *next;
+} RRDCALC;
+
+
+// RRDCALCTEMPLATE
+// these are to be applied to charts found dynamically
+// based on their context.
+typedef struct rrdcalctemplate {
+    char *name;
+    uint32_t hash_name;
+
+    char *context;
+    uint32_t hash_context;
+
+    char *dimensions;
+
+    int group;          // grouping method: average, max, etc.
+    int before;         // ending point in time-series
+    int after;          // starting point in time-series
+    uint32_t options;   // calculation options
+    int update_every;   // update frequency for the calculation
+
+    struct rrdcalctemplate *next;
+} RRDCALCTEMPLATE;
+
+#include "rrd.h"
+
+extern void rrdsetvar_rename_all(RRDSET *st);
+extern RRDSETVAR *rrdsetvar_create(RRDSET *st, const char *variable, int type, void *value, uint32_t options);
+extern void rrdsetvar_free(RRDSETVAR *rs);
+
+extern void rrddimvar_rename_all(RRDDIM *rd);
+extern RRDDIMVAR *rrddimvar_create(RRDDIM *rd, int type, const char *prefix, const char *suffix, void *value, uint32_t options);
+extern void rrddimvar_free(RRDDIMVAR *rs);
+
+extern void rrdsetcalc_link_matching(RRDSET *st);
+extern void rrdsetcalc_unlink(RRDCALC *rc);
+
+#endif //NETDATA_HEALTH_H
index 62f07adde5017a29e8c940a9ff74074851fe69d9..aa0f1b21168f28f967348daf7e5b59a03b8b26f2 100644 (file)
--- a/src/log.c
+++ b/src/log.c
@@ -1,17 +1,5 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <time.h>
-#include <syslog.h>
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-#include <stdlib.h>
-
-#include "log.h"
 #include "common.h"
 
-
 // ----------------------------------------------------------------------------
 // LOG
 
@@ -137,6 +125,8 @@ void debug_int( const char *file, const char *function, const unsigned long line
                vsyslog(LOG_ERR,  fmt, args );
                va_end( args );
        }
+
+       fflush(stdout);
 }
 
 void info_int( const char *file, const char *function, const unsigned long line, const char *fmt, ... )
index 2c0f5cd7a1884c96afc520ad2ad4f122294e36a8..95b6b301ed7a9496d4d0c1bfa89fbe634b152353 100644 (file)
--- a/src/log.h
+++ b/src/log.h
@@ -1,9 +1,3 @@
-#include <stdio.h>
-#include <stdarg.h>
-#include <time.h>
-
-#include "main.h"
-
 #ifndef NETDATA_LOG_H
 #define NETDATA_LOG_H 1
 
@@ -29,6 +23,7 @@
 #define D_MEMORY                       0x00080000
 #define D_CGROUP            0x00100000
 #define D_REGISTRY                     0x00200000
+#define D_VARIABLES         0x00400000
 
 //#define DEBUG (D_WEB_CLIENT_ACCESS|D_LISTENER|D_RRD_STATS)
 //#define DEBUG 0xffffffff
index 41590c56daf1dde0d9ec47836df41d648e1a28f5..f93fef7b300a1e065bf03bcea78f3b211209b54e 100644 (file)
@@ -1,52 +1,18 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <errno.h>
-#include <getopt.h>
-#include <pthread.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <sys/prctl.h>
-#include <sys/wait.h>
-#include <syslog.h>
-#include <unistd.h>
-
-#include "appconfig.h"
 #include "common.h"
-#include "daemon.h"
-#include "log.h"
-#include "popen.h"
-#include "rrd.h"
-#include "rrd2json.h"
-#include "web_client.h"
-#include "web_server.h"
-
-#include "unit_test.h"
-
-#include "plugin_checks.h"
-#include "plugin_idlejitter.h"
-#include "plugin_nfacct.h"
-#include "registry.h"
-#include "plugin_proc.h"
-#include "plugin_tc.h"
-#include "plugins_d.h"
-
-#include "main.h"
 
 extern void *cgroups_main(void *ptr);
 
-volatile sig_atomic_t netdata_exit = 0;
-
 void netdata_cleanup_and_exit(int ret) {
        netdata_exit = 1;
 
        error_log_limit_unlimited();
 
        info("Called: netdata_cleanup_and_exit()");
+#ifdef NETDATA_INTERNAL_CHECKS
+    rrdset_free_all();
+#else
        rrdset_save_all();
+#endif
        // kill_childs();
 
        if(pidfile[0]) {
@@ -701,9 +667,7 @@ int main(int argc, char **argv)
                struct netdata_static_thread *st = &static_threads[i];
 
                if(st->enabled) {
-                       st->thread = malloc(sizeof(pthread_t));
-                       if(!st->thread)
-                               fatal("Cannot allocate pthread_t memory");
+                       st->thread = mallocz(sizeof(pthread_t));
 
                        info("Starting thread %s.", st->name);
 
index a41aa0c2bdcb1e01c25f1378ef82fa60a9c2763d..b1acf8a6abc02dc0392d79d2a5c518df6130d300 100644 (file)
@@ -1,10 +1,6 @@
-#include <getopt.h>
-
 #ifndef NETDATA_MAIN_H
 #define NETDATA_MAIN_H 1
 
-#include <signal.h>
-
 extern volatile sig_atomic_t netdata_exit;
 
 /**
index 379fb9a84616aefa04794ccbae238808526c707a..217cdc512ef03e9659c50f1dbc7c98fd0e0f3593 100644 (file)
@@ -1,17 +1,4 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <pthread.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-#include <strings.h>
-#include <unistd.h>
-
 #include "common.h"
-#include "appconfig.h"
-#include "log.h"
-#include "rrd.h"
-#include "plugin_checks.h"
 
 void *checks_main(void *ptr)
 {
index 56c22a160187b129115c252221b2a230c8748ab7..abdb03d1d91b4ffed8157334a0d17d1fd2e087b8 100644 (file)
@@ -1,18 +1,4 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <pthread.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-#include <strings.h>
-#include <unistd.h>
-
-#include "global_statistics.h"
 #include "common.h"
-#include "appconfig.h"
-#include "log.h"
-#include "rrd.h"
-#include "plugin_idlejitter.h"
 
 #define CPU_IDLEJITTER_SLEEP_TIME_MS 20
 
index 6cde66e0c70f77e7e86313e419b569383a1b057a..b61f9e53de83d8c57d1973d47e043d9711a6aa8a 100644 (file)
@@ -1,28 +1,8 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
 #ifdef INTERNAL_PLUGIN_NFACCT
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <dirent.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <time.h>
-#include <errno.h>
-
 #include <libmnl/libmnl.h>
 #include <libnetfilter_acct/libnetfilter_acct.h>
 
-#include "main.h"
-#include "global_statistics.h"
 #include "common.h"
-#include "appconfig.h"
-#include "log.h"
-#include "rrd.h"
-#include "plugin_proc.h"
 
 struct mynfacct {
        const char *name;
index e7b8d50c87d64c2695c4b63373eb92418f496cdf..1f69b284bc96145f882a310d7cfc030db2d5ffa7 100644 (file)
@@ -1,20 +1,4 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <pthread.h>
-#include <sys/time.h>
-#include <sys/resource.h>
-#include <strings.h>
-#include <unistd.h>
-
-#include "global_statistics.h"
 #include "common.h"
-#include "appconfig.h"
-#include "log.h"
-#include "rrd.h"
-#include "plugin_proc.h"
-#include "main.h"
-#include "registry.h"
 
 void *proc_main(void *ptr)
 {
index 251cfeeb4922e6b9ebc89b7089b1b2c3985a37d2..b7ccfba2574af54a5045e080966e0e41e50e31d0 100644 (file)
@@ -1,20 +1,4 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/resource.h>
-
-#include "avl.h"
-#include "log.h"
 #include "common.h"
-#include "appconfig.h"
-#include "rrd.h"
-#include "popen.h"
-#include "plugin_tc.h"
-#include "main.h"
 
 #define RRD_TYPE_TC                                    "tc"
 #define RRD_TYPE_TC_LEN                                strlen(RRD_TYPE_TC)
@@ -156,12 +140,11 @@ static inline void tc_class_free(struct tc_device *n, struct tc_class *c) {
 
        tc_class_index_del(n, c);
 
-       if(c->id) free(c->id);
-       if(c->name) free(c->name);
-       if(c->leafid) free(c->leafid);
-       if(c->parentid) free(c->parentid);
-
-       free(c);
+       freez(c->id);
+       freez(c->name);
+       freez(c->leafid);
+       freez(c->parentid);
+       freez(c);
 }
 
 static inline void tc_device_classes_cleanup(struct tc_device *d) {
@@ -445,45 +428,36 @@ static inline void tc_device_set_class_name(struct tc_device *d, char *id, char
 {
        struct tc_class *c = tc_class_index_find(d, id, 0);
        if(likely(c)) {
-               if(likely(c->name))
-                       free(c->name);
-
+               freez(c->name);
                c->name = NULL;
 
                if(likely(name && *name && strcmp(c->id, name) != 0)) {
                        debug(D_TC_LOOP, "TC: Setting device '%s', class '%s' name to '%s'", d->id, id, name);
-                       c->name = strdup(name);
-                       if(likely(c->name))
-                               c->name_updated = 1;
+                       c->name = strdupz(name);
+                       c->name_updated = 1;
                }
        }
 }
 
 static inline void tc_device_set_device_name(struct tc_device *d, char *name) {
-       if(likely(d->name))
-               free(d->name);
-
+       freez(d->name);
        d->name = NULL;
 
        if(likely(name && *name && strcmp(d->id, name) != 0)) {
                debug(D_TC_LOOP, "TC: Setting device '%s' name to '%s'", d->id, name);
-               d->name = strdup(name);
-               if(likely(d->name))
-                       d->name_updated = 1;
+               d->name = strdupz(name);
+               d->name_updated = 1;
        }
 }
 
 static inline void tc_device_set_device_family(struct tc_device *d, char *family) {
-       if(likely(d->family))
-               free(d->family);
-
+       freez(d->family);
        d->family = NULL;
 
        if(likely(family && *family && strcmp(d->id, family) != 0)) {
                debug(D_TC_LOOP, "TC: Setting device '%s' family to '%s'", d->id, family);
-               d->family = strdup(family);
-               if(likely(d->family))
-                       d->family_updated = 1;
+               d->family = strdupz(family);
+               d->family_updated = 1;
        }
        // no need for null termination - it is already null
 }
@@ -495,13 +469,9 @@ static inline struct tc_device *tc_device_create(char *id)
        if(!d) {
                debug(D_TC_LOOP, "TC: Creating device '%s'", id);
 
-               d = calloc(1, sizeof(struct tc_device));
-               if(!d) {
-                       fatal("Cannot allocate memory for tc_device %s", id);
-                       return NULL;
-               }
+               d = callocz(1, sizeof(struct tc_device));
 
-               d->id = strdup(id);
+               d->id = strdupz(id);
                d->hash = simple_hash(d->id);
                d->enabled = -1;
 
@@ -528,30 +498,22 @@ static inline struct tc_class *tc_class_add(struct tc_device *n, char *id, char
        if(!c) {
                debug(D_TC_LOOP, "TC: Creating in device '%s', class id '%s', parentid '%s', leafid '%s'", n->id, id, parentid?parentid:"", leafid?leafid:"");
 
-               c = calloc(1, sizeof(struct tc_class));
-               if(!c) {
-                       fatal("Cannot allocate memory for tc class");
-                       return NULL;
-               }
+               c = callocz(1, sizeof(struct tc_class));
 
                if(n->classes) n->classes->prev = c;
                c->next = n->classes;
                n->classes = c;
 
-               c->id = strdup(id);
-               if(!c->id) {
-                       free(c);
-                       return NULL;
-               }
+               c->id = strdupz(id);
                c->hash = simple_hash(c->id);
 
                if(parentid && *parentid) {
-                       c->parentid = strdup(parentid);
+                       c->parentid = strdupz(parentid);
                        c->parent_hash = simple_hash(c->parentid);
                }
 
                if(leafid && *leafid) {
-                       c->leafid = strdup(leafid);
+                       c->leafid = strdupz(leafid);
                        c->leaf_hash = simple_hash(c->leafid);
                }
 
@@ -576,11 +538,10 @@ static inline void tc_device_free(struct tc_device *n)
 
        while(n->classes) tc_class_free(n, n->classes);
 
-       if(n->id) free(n->id);
-       if(n->name) free(n->name);
-       if(n->family) free(n->family);
-
-       free(n);
+       freez(n->id);
+       freez(n->name);
+       freez(n->family);
+       freez(n);
 }
 
 static inline void tc_device_free_all()
index 23757bbe7d9f8af448045f90fdff798f2df2fa68..7e106bf81942b60a167a801efb08bc00580887f0 100644 (file)
@@ -1,22 +1,4 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <sys/types.h>
-#include <dirent.h>
-#include <pthread.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <signal.h>
-
-#include "main.h"
 #include "common.h"
-#include "appconfig.h"
-#include "log.h"
-#include "rrd.h"
-#include "popen.h"
-#include "plugins_d.h"
-#include "../config.h"
 
 struct plugind *pluginsd_root = NULL;
 
@@ -526,8 +508,7 @@ void *pluginsd_main(void *ptr)
                        // it is not running
                        // allocate a new one, or use the obsolete one
                        if(unlikely(!cd)) {
-                               cd = calloc(sizeof(struct plugind), 1);
-                               if(unlikely(!cd)) fatal("Cannot allocate memory for plugin.");
+                               cd = callocz(sizeof(struct plugind), 1);
 
                                snprintfz(cd->id, CONFIG_MAX_NAME, "plugin:%s", pluginname);
 
index 1a10dc0dc507dfce60dc4cfebf002e1aad8607b9..7e49b184146c03e87c9e19e4977968047113ff7b 100644 (file)
@@ -1,7 +1,3 @@
-#include <sys/types.h>
-#include <unistd.h>
-
-
 #ifndef NETDATA_PLUGINS_D_H
 #define NETDATA_PLUGINS_D_H 1
 
index 4e2874f4cd8b2609d19455785f36dd4e1a347ad3..a603c72db302bcc4f465c46a9dcc4040d38a377c 100644 (file)
@@ -1,14 +1,3 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <signal.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-
-#include "log.h"
-#include "popen.h"
 #include "common.h"
 
 /*
index 10680f0c8295903104a195f9576e8b9ba5958e9b..90845e1fb524e797632e0a8594d14c5bc088c6b9 100644 (file)
@@ -1,7 +1,3 @@
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/types.h>
-
 #ifndef NETDATA_POPEN_H
 #define NETDATA_POPEN_H 1
 
index 3e3df2465a7b517a40fd18902072a8ac3da62c44..f47cd4469243d04cf55d6d010eb7e38a7a3dcc18 100644 (file)
@@ -1,25 +1,4 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <dirent.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/statvfs.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-
 #include "common.h"
-#include "log.h"
-#include "appconfig.h"
-#include "procfile.h"
-#include "rrd.h"
-#include "plugin_proc.h"
-
-#include "proc_self_mountinfo.h"
 
 #define RRD_TYPE_DISK "disk"
 
@@ -72,10 +51,9 @@ static struct disk *get_disk(unsigned long major, unsigned long minor, char *dis
 
        // not found
        // create a new disk structure
-       d = (struct disk *)malloc(sizeof(struct disk));
-       if(!d) fatal("Cannot allocate memory for struct disk in proc_diskstats.");
+       d = (struct disk *)mallocz(sizeof(struct disk));
 
-       d->disk = strdup(disk);
+       d->disk = strdupz(disk);
        d->major = major;
        d->minor = minor;
        d->type = DISK_TYPE_PHYSICAL; // Default type. Changed later if not correct.
@@ -148,7 +126,7 @@ static struct disk *get_disk(unsigned long major, unsigned long minor, char *dis
        }
 
        if(mi)
-               d->mount_point = strdup(mi->mount_point);
+               d->mount_point = strdupz(mi->mount_point);
                // no need to check for NULL
        else
                d->mount_point = NULL;
index ad00c2022af532178f03cdc1c5b6cc5fd9788fb8..6f703434878eb7201a1d72889e2038401127ba63 100644 (file)
@@ -1,17 +1,4 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-
 #include "common.h"
-#include "appconfig.h"
-#include "procfile.h"
-#include "rrd.h"
-#include "plugin_proc.h"
-#include "log.h"
 
 #define MAX_INTERRUPT_NAME 50
 
@@ -36,10 +23,7 @@ static inline struct interrupt *get_interrupts_array(int lines, int cpus) {
 
        if(lines < allocated) return irrs;
        else {
-               irrs = (struct interrupt *)realloc(irrs, lines * recordsize(cpus));
-               if(!irrs)
-                       fatal("Cannot allocate memory for %d interrupts", lines);
-
+               irrs = (struct interrupt *)reallocz(irrs, lines * recordsize(cpus));
                allocated = lines;
        }
 
index c8e893b9990bf7f52eddfdfc9574a8feb87e7840..ec04ec250f5ccfa2798751ee0310617d60d97fa3 100644 (file)
@@ -1,16 +1,7 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "log.h"
 #include "common.h"
-#include "appconfig.h"
-#include "procfile.h"
-#include "rrd.h"
-#include "plugin_proc.h"
+
+// linux calculates this once every 5 seconds
+#define MIN_LOADAVG_UPDATE_EVERY 5
 
 int do_proc_loadavg(int update_every, unsigned long long dt) {
        static procfile *ff = NULL;
@@ -56,7 +47,7 @@ int do_proc_loadavg(int update_every, unsigned long long dt) {
        if(do_loadavg) {
                st = rrdset_find_byname("system.load");
                if(!st) {
-                       st = rrdset_create("system", "load", NULL, "load", NULL, "System Load Average", "load", 100, update_every, RRDSET_TYPE_LINE);
+                       st = rrdset_create("system", "load", NULL, "load", NULL, "System Load Average", "load", 100, (update_every < MIN_LOADAVG_UPDATE_EVERY)?MIN_LOADAVG_UPDATE_EVERY:update_every, RRDSET_TYPE_LINE);
 
                        rrddim_add(st, "load1", NULL, 1, 1000, RRDDIM_ABSOLUTE);
                        rrddim_add(st, "load5", NULL, 1, 1000, RRDDIM_ABSOLUTE);
index 611b4ed219ce396212409636b561406552fbc9bf..fc22ddf005a9aa95a9167317fae50212e708db2b 100644 (file)
@@ -1,16 +1,4 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
 #include "common.h"
-#include "log.h"
-#include "appconfig.h"
-#include "procfile.h"
-#include "rrd.h"
-#include "plugin_proc.h"
 
 #define MAX_PROC_MEMINFO_LINE 4096
 #define MAX_PROC_MEMINFO_NAME 1024
index 12d8078c72178321ead1a9afd2081af1a6ef0bbe..2c02b0697d3f836a38b4bd3ac62c6a4bdde3d858 100644 (file)
@@ -1,15 +1,4 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
 #include "common.h"
-#include "appconfig.h"
-#include "procfile.h"
-#include "rrd.h"
-#include "plugin_proc.h"
 
 int do_proc_net_dev(int update_every, unsigned long long dt) {
        static procfile *ff = NULL;
index ffb5da7b56702f781d64abcc8bc12f18c60b9354..ff038b9276a65cc78a93a4c7e08fecb9e8dab33d 100644 (file)
@@ -1,14 +1,4 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-
 #include "common.h"
-#include "appconfig.h"
-#include "procfile.h"
-#include "rrd.h"
-#include "plugin_proc.h"
 
 #define RRD_TYPE_NET_IPVS                      "ipvs"
 #define RRD_TYPE_NET_IPVS_LEN          strlen(RRD_TYPE_NET_IPVS)
index 70d8cd68d0e6f018b648a06ce2bbdd00739ef7fd..1f3bff303c71906673e926c3ab4cdd86cd81e25b 100644 (file)
@@ -1,16 +1,4 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
 #include "common.h"
-#include "log.h"
-#include "appconfig.h"
-#include "procfile.h"
-#include "rrd.h"
-#include "plugin_proc.h"
 
 int do_proc_net_netstat(int update_every, unsigned long long dt) {
        static int do_bandwidth = -1, do_inerrors = -1, do_mcast = -1, do_bcast = -1, do_mcast_p = -1, do_bcast_p = -1;
index b5d766e057adcc04193c5dcad98330f5c104e02f..69a18773b31b41759f1a303f7d09af7e1d8ce4c3 100644 (file)
@@ -1,16 +1,4 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
 #include "common.h"
-#include "log.h"
-#include "appconfig.h"
-#include "procfile.h"
-#include "rrd.h"
-#include "plugin_proc.h"
 
 struct nfsd_procs {
        char name[30];
index 69b2938aae159f005267d1f525cfbf6fc1ce2025..815eeac7df0deebdfb97a6a6ca773add7aa938d5 100644 (file)
@@ -1,16 +1,4 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
 #include "common.h"
-#include "log.h"
-#include "appconfig.h"
-#include "procfile.h"
-#include "rrd.h"
-#include "plugin_proc.h"
 
 #define RRD_TYPE_NET_SNMP                      "ipv4"
 #define RRD_TYPE_NET_SNMP_LEN          strlen(RRD_TYPE_NET_SNMP)
index 4586ee7d0d638dd9216f81833159bb5be55ad755..0d770ddd49e978b79690e480fad9acbe178ee422 100644 (file)
@@ -1,17 +1,4 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
 #include "common.h"
-#include "log.h"
-#include "appconfig.h"
-#include "procfile.h"
-#include "rrd.h"
-#include "plugin_proc.h"
 
 #define RRD_TYPE_NET_SNMP6                     "ipv6"
 #define RRD_TYPE_NET_SNMP6_LEN         strlen(RRD_TYPE_NET_SNMP6)
index 1fcf6ffceaf27491401ea539bf5265fcc4c3ee4d..3af66f19ff2534d4fe9dd3f7478006747c54d0d6 100644 (file)
@@ -1,16 +1,4 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
 #include "common.h"
-#include "log.h"
-#include "appconfig.h"
-#include "procfile.h"
-#include "rrd.h"
-#include "plugin_proc.h"
 
 #define RRD_TYPE_NET_STAT_NETFILTER            "netfilter"
 #define RRD_TYPE_NET_STAT_CONNTRACK    "conntrack"
index d90a376f0914bbe3a9b903ad74b9302fde6d1b20..c3874eeeef6fb0092f59b040ad8fd0106cf40b99 100644 (file)
@@ -1,15 +1,4 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-
 #include "common.h"
-#include "appconfig.h"
-#include "procfile.h"
-#include "rrd.h"
-#include "plugin_proc.h"
-#include "log.h"
 
 #define RRD_TYPE_NET_STAT_NETFILTER                    "netfilter"
 #define RRD_TYPE_NET_STAT_SYNPROXY                     "synproxy"
index ac5baa4e6e3b281280ff631c35ddaee8a7052e4d..623eb622a85c33e6f89d2241737830bd2a0542be 100644 (file)
@@ -1,19 +1,4 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <ctype.h>
-
 #include "common.h"
-#include "log.h"
-#include "appconfig.h"
-
-#include "proc_self_mountinfo.h"
 
 // find the mount info with the given major:minor
 // in the supplied linked list of mountinfo structures
@@ -84,9 +69,9 @@ void mountinfo_free(struct mountinfo *mi) {
        if(likely(mi->next))
                mountinfo_free(mi->next);
 
-       if(mi->root) free(mi->root);
-       if(mi->mount_point) free(mi->mount_point);
-       if(mi->mount_options) free(mi->mount_options);
+       freez(mi->root);
+       freez(mi->mount_point);
+       freez(mi->mount_options);
 
 /*
        if(mi->optional_fields_count) {
@@ -96,15 +81,14 @@ void mountinfo_free(struct mountinfo *mi) {
        }
        free(mi->optional_fields);
 */
-       free(mi->filesystem);
-       free(mi->mount_source);
-       free(mi->super_options);
-       free(mi);
+       freez(mi->filesystem);
+       freez(mi->mount_source);
+       freez(mi->super_options);
+       freez(mi);
 }
 
-static char *strdup_decoding_octal(const char *string) {
-       char *buffer = strdup(string);
-       if(!buffer) fatal("Cannot allocate memory.");
+static char *strdupz_decoding_octal(const char *string) {
+       char *buffer = strdupz(string);
 
        char *d = buffer;
        const char *s = string;
@@ -152,8 +136,7 @@ struct mountinfo *mountinfo_read() {
                if(procfile_linewords(ff, l) < 5)
                        continue;
 
-               mi = malloc(sizeof(struct mountinfo));
-               if(unlikely(!mi)) fatal("Cannot allocate memory for mountinfo");
+               mi = mallocz(sizeof(struct mountinfo));
 
                if(unlikely(!root))
                        root = last = mi;
@@ -175,16 +158,13 @@ struct mountinfo *mountinfo_read() {
                mi->major = strtoul(major, NULL, 10);
                mi->minor = strtoul(minor, NULL, 10);
 
-               mi->root = strdup(procfile_lineword(ff, l, w)); w++;
-               if(unlikely(!mi->root)) fatal("Cannot allocate memory");
+               mi->root = strdupz(procfile_lineword(ff, l, w)); w++;
                mi->root_hash = simple_hash(mi->root);
 
-               mi->mount_point = strdup_decoding_octal(procfile_lineword(ff, l, w)); w++;
-               if(unlikely(!mi->mount_point)) fatal("Cannot allocate memory");
+               mi->mount_point = strdupz_decoding_octal(procfile_lineword(ff, l, w)); w++;
                mi->mount_point_hash = simple_hash(mi->mount_point);
 
-               mi->mount_options = strdup(procfile_lineword(ff, l, w)); w++;
-               if(unlikely(!mi->mount_options)) fatal("Cannot allocate memory");
+               mi->mount_options = strdupz(procfile_lineword(ff, l, w)); w++;
 
                // count the optional fields
 /*
@@ -221,16 +201,13 @@ struct mountinfo *mountinfo_read() {
                if(likely(*s == '-')) {
                        w++;
 
-                       mi->filesystem = strdup(procfile_lineword(ff, l, w)); w++;
-                       if(!mi->filesystem) fatal("Cannot allocate memory");
+                       mi->filesystem = strdupz(procfile_lineword(ff, l, w)); w++;
                        mi->filesystem_hash = simple_hash(mi->filesystem);
 
-                       mi->mount_source = strdup(procfile_lineword(ff, l, w)); w++;
-                       if(!mi->mount_source) fatal("Cannot allocate memory");
+                       mi->mount_source = strdupz(procfile_lineword(ff, l, w)); w++;
                        mi->mount_source_hash = simple_hash(mi->mount_source);
 
-                       mi->super_options = strdup(procfile_lineword(ff, l, w)); w++;
-                       if(!mi->super_options) fatal("Cannot allocate memory");
+                       mi->super_options = strdupz(procfile_lineword(ff, l, w)); w++;
                }
                else {
                        mi->filesystem = NULL;
index 51712a58aa792dfc92ef981b1ef6390af54fc379..af98ca4a58f0ad8d14a48049d9c8513843f8426f 100644 (file)
@@ -1,5 +1,3 @@
-#include "procfile.h"
-
 #ifndef NETDATA_PROC_SELF_MOUNTINFO_H
 #define NETDATA_PROC_SELF_MOUNTINFO_H 1
 
index 96b5d3d30224fa42b18ce5917d838b4135bc7ee3..d966ab790f9b4b96757672dd8be05cdce393eef3 100644 (file)
@@ -1,17 +1,4 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-
 #include "common.h"
-#include "appconfig.h"
-#include "procfile.h"
-#include "rrd.h"
-#include "plugin_proc.h"
-#include "log.h"
 
 #define MAX_INTERRUPT_NAME 50
 
@@ -36,10 +23,7 @@ static inline struct interrupt *get_interrupts_array(int lines, int cpus) {
 
        if(lines < allocated) return irrs;
        else {
-               irrs = (struct interrupt *)realloc(irrs, lines * recordsize(cpus));
-               if(!irrs)
-                       fatal("Cannot allocate memory for %d interrupts", lines);
-
+               irrs = (struct interrupt *)reallocz(irrs, lines * recordsize(cpus));
                allocated = lines;
        }
 
index a1e9c2f520c10fa72ca3658fd51a900f7601b0a9..9450f38190edb3afaf80faf223bd164adedf24db 100644 (file)
@@ -1,16 +1,4 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
 #include "common.h"
-#include "log.h"
-#include "appconfig.h"
-#include "procfile.h"
-#include "rrd.h"
-#include "plugin_proc.h"
 
 int do_proc_stat(int update_every, unsigned long long dt) {
        (void)dt;
index d7d1e826110ef937f612eda3b2c4e7e38857976d..a08f494cd6461c730c68f20d19e508d24a6f8037 100644 (file)
@@ -1,14 +1,4 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-
 #include "common.h"
-#include "appconfig.h"
-#include "procfile.h"
-#include "rrd.h"
-#include "plugin_proc.h"
 
 int do_proc_sys_kernel_random_entropy_avail(int update_every, unsigned long long dt) {
        static procfile *ff = NULL;
index c69b389b6c875af18105087321046f2bfba41d47..dcddb14db9c4e7d170af53537dc1fc154e328fef 100644 (file)
@@ -1,17 +1,4 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
 #include "common.h"
-#include "log.h"
-#include "appconfig.h"
-#include "procfile.h"
-#include "rrd.h"
-#include "plugin_proc.h"
 
 int do_proc_vmstat(int update_every, unsigned long long dt) {
        static procfile *ff = NULL;
index 25f9d2e749639077cd7f879c6f819f66600ac6a9..efe569e593bd608f8459c7847778ef21530174bf 100644 (file)
@@ -1,26 +1,4 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <string.h>
-#include <malloc.h>
-#include <ctype.h>
-#include <time.h>
-#include <sys/time.h>
-#include <sys/wait.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-
 #include "common.h"
-#include "log.h"
-#include "procfile.h"
-#include "../config.h"
 
 #define PF_PREFIX "PROCFILE"
 
@@ -46,13 +24,7 @@ pfwords *pfwords_add(pfwords *fw, char *str) {
        if(unlikely(fw->len == fw->size)) {
                // debug(D_PROCFILE, PF_PREFIX ":       expanding words");
 
-               pfwords *new = realloc(fw, sizeof(pfwords) + (fw->size + PFWORDS_INCREASE_STEP) * sizeof(char *));
-               if(unlikely(!new)) {
-                       error(PF_PREFIX ":      failed to expand words");
-                       free(fw);
-                       return NULL;
-               }
-               fw = new;
+               fw = reallocz(fw, sizeof(pfwords) + (fw->size + PFWORDS_INCREASE_STEP) * sizeof(char *));
                fw->size += PFWORDS_INCREASE_STEP;
        }
 
@@ -66,9 +38,7 @@ pfwords *pfwords_new(void) {
 
        uint32_t size = (procfile_adaptive_initial_allocation) ? procfile_max_words : PFWORDS_INCREASE_STEP;
 
-       pfwords *new = malloc(sizeof(pfwords) + size * sizeof(char *));
-       if(unlikely(!new)) return NULL;
-
+       pfwords *new = mallocz(sizeof(pfwords) + size * sizeof(char *));
        new->len = 0;
        new->size = size;
        return new;
@@ -82,7 +52,7 @@ void pfwords_reset(pfwords *fw) {
 void pfwords_free(pfwords *fw) {
        // debug(D_PROCFILE, PF_PREFIX ":       freeing words");
 
-       free(fw);
+       freez(fw);
 }
 
 
@@ -95,13 +65,7 @@ pflines *pflines_add(pflines *fl, uint32_t first_word) {
        if(unlikely(fl->len == fl->size)) {
                // debug(D_PROCFILE, PF_PREFIX ":       expanding lines");
 
-               pflines *new = realloc(fl, sizeof(pflines) + (fl->size + PFLINES_INCREASE_STEP) * sizeof(ffline));
-               if(unlikely(!new)) {
-                       error(PF_PREFIX ":      failed to expand lines");
-                       free(fl);
-                       return NULL;
-               }
-               fl = new;
+               fl = reallocz(fl, sizeof(pflines) + (fl->size + PFLINES_INCREASE_STEP) * sizeof(ffline));
                fl->size += PFLINES_INCREASE_STEP;
        }
 
@@ -116,9 +80,7 @@ pflines *pflines_new(void) {
 
        uint32_t size = (unlikely(procfile_adaptive_initial_allocation)) ? procfile_max_words : PFLINES_INCREASE_STEP;
 
-       pflines *new = malloc(sizeof(pflines) + size * sizeof(ffline));
-       if(unlikely(!new)) return NULL;
-
+       pflines *new = mallocz(sizeof(pflines) + size * sizeof(ffline));
        new->len = 0;
        new->size = size;
        return new;
@@ -133,7 +95,7 @@ void pflines_reset(pflines *fl) {
 void pflines_free(pflines *fl) {
        // debug(D_PROCFILE, PF_PREFIX ":       freeing lines");
 
-       free(fl);
+       freez(fl);
 }
 
 
@@ -154,7 +116,7 @@ void procfile_close(procfile *ff) {
        if(likely(ff->words)) pfwords_free(ff->words);
 
        if(likely(ff->fd != -1)) close(ff->fd);
-       free(ff);
+       freez(ff);
 }
 
 procfile *procfile_parser(procfile *ff) {
@@ -315,13 +277,7 @@ procfile *procfile_readall(procfile *ff) {
                if(!x) {
                        debug(D_PROCFILE, PF_PREFIX ": Expanding data buffer for file '%s'.", ff->filename);
 
-                       procfile *new = realloc(ff, sizeof(procfile) + ff->size + PROCFILE_INCREMENT_BUFFER);
-                       if(unlikely(!new)) {
-                               error(PF_PREFIX ": Cannot allocate memory for file '%s'", ff->filename);
-                               procfile_close(ff);
-                               return NULL;
-                       }
-                       ff = new;
+                       ff = reallocz(ff, sizeof(procfile) + ff->size + PROCFILE_INCREMENT_BUFFER);
                        ff->size += PROCFILE_INCREMENT_BUFFER;
                }
 
@@ -438,13 +394,7 @@ procfile *procfile_open(const char *filename, const char *separators, uint32_t f
        }
 
        size_t size = (unlikely(procfile_adaptive_initial_allocation)) ? procfile_max_allocation : PROCFILE_INCREMENT_BUFFER;
-       procfile *ff = malloc(sizeof(procfile) + size);
-       if(unlikely(!ff)) {
-               error(PF_PREFIX ": Cannot allocate memory for file '%s'", filename);
-               close(fd);
-               return NULL;
-       }
-
+       procfile *ff = mallocz(sizeof(procfile) + size);
        strncpyz(ff->filename, filename, FILENAME_MAX);
 
        ff->fd = fd;
index 26004d4d9076d5596bbf4c78336105c57ce0ea8d..988ed78d67a3c8203efadbeea141b73ff392bb8d 100644 (file)
@@ -1,28 +1,4 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <uuid/uuid.h>
-#include <inttypes.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <errno.h>
-#include <fcntl.h>
-
-#include "log.h"
 #include "common.h"
-#include "dictionary.h"
-#include "appconfig.h"
-
-#include "web_client.h"
-#include "rrd.h"
-#include "rrd2json.h"
-#include "registry.h"
-
 
 // ----------------------------------------------------------------------------
 // TODO
@@ -336,14 +312,12 @@ static inline URL *registry_url_allocate_nolock(const char *url, size_t urllen)
                urllen = registry.max_url_length;
 
        debug(D_REGISTRY, "Registry: registry_url_allocate_nolock('%s'): allocating %zu bytes", url, sizeof(URL) + urllen);
-       URL *u = malloc(sizeof(URL) + urllen);
-       if(!u) fatal("Cannot allocate %zu bytes for URL '%s'", sizeof(URL) + urllen, url);
+       URL *u = mallocz(sizeof(URL) + urllen);
 
        // a simple strcpy() should do the job
        // but I prefer to be safe, since the caller specified urllen
-       strncpyz(u->url, url, urllen);
-
-       u->len = urllen;
+       u->len = (uint16_t)urllen;
+       strncpyz(u->url, url, u->len);
        u->links = 0;
 
        registry.urls_memory += sizeof(URL) + urllen;
@@ -380,7 +354,7 @@ static inline void registry_url_unlink_nolock(URL *u) {
        if(!u->links) {
                debug(D_REGISTRY, "Registry: registry_url_unlink_nolock('%s'): No more links for this URL", u->url);
                dictionary_del(registry.urls, u->url);
-               free(u);
+               freez(u);
        }
        else
                debug(D_REGISTRY, "Registry: registry_url_unlink_nolock('%s'): URL has %u links left", u->url, u->links);
@@ -398,13 +372,12 @@ static inline MACHINE *registry_machine_find(const char *machine_guid) {
 static inline MACHINE_URL *registry_machine_url_allocate(MACHINE *m, URL *u, time_t when) {
        debug(D_REGISTRY, "registry_machine_link_to_url('%s', '%s'): allocating %zu bytes", m->guid, u->url, sizeof(MACHINE_URL));
 
-       MACHINE_URL *mu = malloc(sizeof(MACHINE_URL));
-       if(!mu) fatal("registry_machine_link_to_url('%s', '%s'): cannot allocate %zu bytes.", m->guid, u->url, sizeof(MACHINE_URL));
+       MACHINE_URL *mu = mallocz(sizeof(MACHINE_URL));
 
        // mu->persons = dictionary_create(DICTIONARY_FLAGS);
        // dictionary_set(mu->persons, p->guid, p, sizeof(PERSON));
 
-       mu->first_t = mu->last_t = when;
+       mu->first_t = mu->last_t = (uint32_t)when;
        mu->usages = 1;
        mu->url = u;
        mu->flags = REGISTRY_URL_FLAGS_DEFAULT;
@@ -421,15 +394,14 @@ static inline MACHINE_URL *registry_machine_url_allocate(MACHINE *m, URL *u, tim
 static inline MACHINE *registry_machine_allocate(const char *machine_guid, time_t when) {
        debug(D_REGISTRY, "Registry: registry_machine_allocate('%s'): creating new machine, sizeof(MACHINE)=%zu", machine_guid, sizeof(MACHINE));
 
-       MACHINE *m = malloc(sizeof(MACHINE));
-       if(!m) fatal("Registry: cannot allocate memory for new machine '%s'", machine_guid);
+       MACHINE *m = mallocz(sizeof(MACHINE));
 
        strncpyz(m->guid, machine_guid, 36);
 
        debug(D_REGISTRY, "Registry: registry_machine_allocate('%s'): creating dictionary of urls", machine_guid);
        m->urls = dictionary_create(DICTIONARY_FLAGS);
 
-       m->first_t = m->last_t = when;
+       m->first_t = m->last_t = (uint32_t)when;
        m->usages = 0;
 
        registry.machines_memory += sizeof(MACHINE);
@@ -482,8 +454,7 @@ static inline PERSON_URL *registry_person_url_allocate(PERSON *p, MACHINE *m, UR
        debug(D_REGISTRY, "registry_person_url_allocate('%s', '%s', '%s'): allocating %zu bytes", p->guid, m->guid, u->url,
                  sizeof(PERSON_URL) + namelen);
 
-       PERSON_URL *pu = malloc(sizeof(PERSON_URL) + namelen);
-       if(!pu) fatal("registry_person_url_allocate('%s', '%s', '%s'): cannot allocate %zu bytes.", p->guid, m->guid, u->url, sizeof(PERSON_URL) + namelen);
+       PERSON_URL *pu = mallocz(sizeof(PERSON_URL) + namelen);
 
        // a simple strcpy() should do the job
        // but I prefer to be safe, since the caller specified urllen
@@ -522,7 +493,7 @@ static inline PERSON_URL *registry_person_url_reallocate(PERSON *p, MACHINE *m,
        registry.persons_urls_memory -= sizeof(PERSON_URL) + strlen(pu->name);
        registry_url_unlink_nolock(u);
 
-       free(pu);
+       freez(pu);
 
        return tpu;
 }
@@ -532,8 +503,7 @@ static inline PERSON *registry_person_allocate(const char *person_guid, time_t w
 
        debug(D_REGISTRY, "Registry: registry_person_allocate('%s'): allocating new person, sizeof(PERSON)=%zu", (person_guid)?person_guid:"", sizeof(PERSON));
 
-       p = malloc(sizeof(PERSON));
-       if(!p) fatal("Registry: cannot allocate memory for new person.");
+       p = mallocz(sizeof(PERSON));
 
        if(!person_guid) {
                for (; ;) {
@@ -938,7 +908,7 @@ PERSON *registry_request_delete(char *person_guid, char *machine_guid, char *url
 
        dictionary_del(p->urls, dpu->url->url);
        registry_url_unlink_nolock(dpu->url);
-       free(dpu);
+       freez(dpu);
 
        registry_person_urls_unlock(p);
        return p;
@@ -1744,7 +1714,7 @@ void registry_free(void) {
                        registry_url_unlink_nolock(pu->url);
 
                        debug(D_REGISTRY, "Registry: freeing person url");
-                       free(pu);
+                       freez(pu);
                }
 
                debug(D_REGISTRY, "Registry: deleting person '%s' from persons registry", p->guid);
@@ -1754,7 +1724,7 @@ void registry_free(void) {
                dictionary_destroy(p->urls);
 
                debug(D_REGISTRY, "Registry: freeing person '%s'", p->guid);
-               free(p);
+               freez(p);
        }
 
        while(registry.machines->values_index.root) {
@@ -1777,7 +1747,7 @@ void registry_free(void) {
                        registry_url_unlink_nolock(mu->url);
 
                        debug(D_REGISTRY, "Registry: freeing machine url");
-                       free(mu);
+                       freez(mu);
                }
 
                debug(D_REGISTRY, "Registry: deleting machine '%s' from machines registry", m->guid);
@@ -1787,7 +1757,7 @@ void registry_free(void) {
                dictionary_destroy(m->urls);
 
                debug(D_REGISTRY, "Registry: freeing machine '%s'", m->guid);
-               free(m);
+               freez(m);
        }
 
        // and free the memory of remaining dictionary structures
index 9e7a13ecbf80168edf179dd957017170fc876fcb..c2b57a23df4c1c6f4c86968d3bc992ee16de111b 100644 (file)
@@ -1,5 +1,3 @@
-#include "web_client.h"
-
 #ifndef NETDATA_REGISTRY_H
 #define NETDATA_REGISTRY_H 1
 
index 47a23ea31e8167642b3d51935afb00fc81377dbc..7e34a7f5e7b70b34a5823b6a803b29c2bb2fc581 100644 (file)
--- a/src/rrd.c
+++ b/src/rrd.c
@@ -1,25 +1,4 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <stddef.h>
-#include <string.h>
-#include <unistd.h>
-#include <time.h>
-#include <sys/time.h>
-#include <sys/mman.h>
-#include <pthread.h>
-#include <errno.h>
-#include <ctype.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <stdlib.h>
-
 #include "common.h"
-#include "log.h"
-#include "appconfig.h"
-
-#include "main.h"
-#include "rrd.h"
 
 #define RRD_DEFAULT_GAP_INTERPOLATIONS 1
 
@@ -33,36 +12,107 @@ int rrd_delete_unupdated_dimensions = 0;
 
 int rrd_update_every = UPDATE_EVERY;
 int rrd_default_history_entries = RRD_DEFAULT_HISTORY_ENTRIES;
+int rrd_memory_mode = RRD_MEMORY_MODE_SAVE;
 
-RRDSET *rrdset_root = NULL;
-pthread_rwlock_t rrdset_root_rwlock = PTHREAD_RWLOCK_INITIALIZER;
+static int rrdset_compare(void* a, void* b);
+static int rrdset_compare_name(void* a, void* b);
+static int rrdcontext_compare(void* a, void* b);
+
+RRDHOST localhost = {
+               .hostname = "localhost",
+               .rrdset_root = NULL,
+               .rrdset_root_rwlock = PTHREAD_RWLOCK_INITIALIZER,
+        .rrdset_root_index = {
+            { NULL, rrdset_compare },
+            AVL_LOCK_INITIALIZER
+        },
+        .rrdset_root_index_name = {
+            { NULL, rrdset_compare_name },
+            AVL_LOCK_INITIALIZER
+        },
+        .rrdcontext_root_index = {
+            { NULL, rrdcontext_compare },
+            AVL_LOCK_INITIALIZER
+        },
+        .variables_root_index = {
+            { NULL, rrdvar_compare },
+            AVL_LOCK_INITIALIZER
+        }
+};
 
-int rrd_memory_mode = RRD_MEMORY_MODE_SAVE;
+// ----------------------------------------------------------------------------
+// RRDCONTEXT index
+
+static int rrdcontext_compare(void* a, void* b) {
+    if(((RRDCONTEXT *)a)->hash < ((RRDCONTEXT *)b)->hash) return -1;
+    else if(((RRDCONTEXT *)a)->hash > ((RRDCONTEXT *)b)->hash) return 1;
+    else return strcmp(((RRDCONTEXT *)a)->id, ((RRDCONTEXT *)b)->id);
+}
+
+#define rrdcontext_index_add(host, rc) (RRDCONTEXT *)avl_insert_lock(&((host)->rrdcontext_root_index), (avl *)(rc))
+#define rrdcontext_index_del(host, rc) (RRDCONTEXT *)avl_remove_lock(&((host)->rrdcontext_root_index), (avl *)(rc))
+
+static RRDCONTEXT *rrdcontext_index_find(RRDHOST *host, const char *id, uint32_t hash) {
+    RRDCONTEXT tmp;
+    tmp.id = id;
+    tmp.hash = (hash)?hash:simple_hash(tmp.id);
+
+    return (RRDCONTEXT *)avl_search_lock(&(host->rrdcontext_root_index), (avl *) &tmp);
+}
+
+RRDCONTEXT *rrdcontext_create(const char *id) {
+    RRDCONTEXT *rc = rrdcontext_index_find(&localhost, id, 0);
+    if(!rc) {
+        rc = callocz(1, sizeof(RRDCONTEXT));
+
+        rc->id = strdupz(id);
+        rc->hash = simple_hash(rc->id);
+
+        // initialize the variables index
+        avl_init_lock(&rc->variables_root_index, rrdvar_compare);
+
+        RRDCONTEXT *ret = rrdcontext_index_add(&localhost, rc);
+        if(ret != rc)
+            fatal("INTERNAL ERROR: Expected to INSERT RRDCONTEXT '%s' into index, but inserted '%s'.", rc->id, (ret)?ret->id:"NONE");
+    }
+
+    rc->use_count++;
+    return rc;
+}
+
+void rrdcontext_free(RRDCONTEXT *rc) {
+    rc->use_count--;
+    if(!rc->use_count) {
+        RRDCONTEXT *ret = rrdcontext_index_del(&localhost, rc);
+        if(ret != rc)
+            fatal("INTERNAL ERROR: Expected to DELETE RRDCONTEXT '%s' from index, but deleted '%s'.", rc->id, (ret)?ret->id:"NONE");
+
+        if(rc->variables_root_index.avl_tree.root != NULL)
+            fatal("INTERNAL ERROR: Variables index of RRDCONTEXT '%s' that is freed, is not empty.", rc->id);
 
+        freez((void *)rc->id);
+        freez(rc);
+    }
+}
 
 // ----------------------------------------------------------------------------
 // RRDSET index
 
 static int rrdset_compare(void* a, void* b) {
-       if(((RRDSET *)a)->hash < ((RRDSET *)b)->hash) return -1;
-       else if(((RRDSET *)a)->hash > ((RRDSET *)b)->hash) return 1;
-       else return strcmp(((RRDSET *)a)->id, ((RRDSET *)b)->id);
+    if(((RRDSET *)a)->hash < ((RRDSET *)b)->hash) return -1;
+    else if(((RRDSET *)a)->hash > ((RRDSET *)b)->hash) return 1;
+    else return strcmp(((RRDSET *)a)->id, ((RRDSET *)b)->id);
 }
 
-avl_tree_lock rrdset_root_index = {
-               { NULL, rrdset_compare },
-               AVL_LOCK_INITIALIZER
-};
+#define rrdset_index_add(host, st) (RRDSET *)avl_insert_lock(&((host)->rrdset_root_index), (avl *)(st))
+#define rrdset_index_del(host, st) (RRDSET *)avl_remove_lock(&((host)->rrdset_root_index), (avl *)(st))
 
-#define rrdset_index_add(st) avl_insert_lock(&rrdset_root_index, (avl *)(st))
-#define rrdset_index_del(st) avl_remove_lock(&rrdset_root_index, (avl *)(st))
+static RRDSET *rrdset_index_find(RRDHOST *host, const char *id, uint32_t hash) {
+    RRDSET tmp;
+    strncpyz(tmp.id, id, RRD_ID_LENGTH_MAX);
+    tmp.hash = (hash)?hash:simple_hash(tmp.id);
 
-static RRDSET *rrdset_index_find(const char *id, uint32_t hash) {
-       RRDSET tmp;
-       strncpyz(tmp.id, id, RRD_ID_LENGTH_MAX);
-       tmp.hash = (hash)?hash:simple_hash(tmp.id);
-
-       return (RRDSET *)avl_search_lock(&(rrdset_root_index), (avl *) &tmp);
+    return (RRDSET *)avl_search_lock(&(host->rrdset_root_index), (avl *) &tmp);
 }
 
 // ----------------------------------------------------------------------------
@@ -81,26 +131,30 @@ static int rrdset_compare_name(void* a, void* b) {
        else return strcmp(A->name, B->name);
 }
 
-avl_tree_lock rrdset_root_index_name = {
-               { NULL, rrdset_compare_name },
-               AVL_LOCK_INITIALIZER
-};
-
-RRDSET *rrdset_index_add_name(RRDSET *st) {
+RRDSET *rrdset_index_add_name(RRDHOST *host, RRDSET *st) {
+    void *result;
        // fprintf(stderr, "ADDING: %s (name: %s)\n", st->id, st->name);
-       return (RRDSET *)avl_insert_lock(&rrdset_root_index_name, (avl *) (&st->avlname));
+       result = avl_insert_lock(&host->rrdset_root_index_name, (avl *) (&st->avlname));
+    if(result) return rrdset_from_avlname(result);
+    return NULL;
 }
 
-#define rrdset_index_del_name(st) avl_remove_lock(&rrdset_root_index_name, (avl *)(&st->avlname))
+RRDSET *rrdset_index_del_name(RRDHOST *host, RRDSET *st) {
+    void *result;
+    // fprintf(stderr, "DELETING: %s (name: %s)\n", st->id, st->name);
+    return (RRDSET *)avl_remove_lock(&((host)->rrdset_root_index_name), (avl *)(&st->avlname));
+    if(result) return rrdset_from_avlname(result);
+    return NULL;
+}
 
-static RRDSET *rrdset_index_find_name(const char *name, uint32_t hash) {
+static RRDSET *rrdset_index_find_name(RRDHOST *host, const char *name, uint32_t hash) {
        void *result = NULL;
        RRDSET tmp;
        tmp.name = name;
        tmp.hash_name = (hash)?hash:simple_hash(tmp.name);
 
        // fprintf(stderr, "SEARCHING: %s\n", name);
-       result = avl_search_lock(&(rrdset_root_index_name), (avl *) (&(tmp.avlname)));
+       result = avl_search_lock(&host->rrdset_root_index_name, (avl *) (&(tmp.avlname)));
        if(result) {
                RRDSET *st = rrdset_from_avlname(result);
                if(strcmp(st->magic, RRDSET_MAGIC))
@@ -256,7 +310,10 @@ void rrdset_set_name(RRDSET *st, const char *name)
 {
        debug(D_RRD_CALLS, "rrdset_set_name() old: %s, new: %s", st->name, name);
 
-       if(st->name) rrdset_index_del_name(st);
+       if(st->name) {
+        rrdset_index_del_name(&localhost, st);
+        rrdsetvar_rename_all(st);
+    }
 
        char b[CONFIG_MAX_VALUE + 1];
        char n[RRD_ID_LENGTH_MAX + 1];
@@ -266,7 +323,7 @@ void rrdset_set_name(RRDSET *st, const char *name)
        st->name = config_get(st->id, "name", b);
        st->hash_name = simple_hash(st->name);
 
-       rrdset_index_add_name(st);
+       rrdset_index_add_name(&localhost, st);
 }
 
 // ----------------------------------------------------------------------------
@@ -402,13 +459,10 @@ RRDSET *rrdset_create(const char *type, const char *id, const char *name, const
                st->dimensions = NULL;
                st->next = NULL;
                st->mapped = rrd_memory_mode;
+        st->variables = NULL;
        }
        else {
-               st = calloc(1, size);
-               if(!st) {
-                       fatal("Cannot allocate memory for RRD_STATS %s.%s", type, id);
-                       return NULL;
-               }
+               st = callocz(1, size);
                st->mapped = RRD_MEMORY_MODE_RAM;
        }
        st->memsize = size;
@@ -445,9 +499,10 @@ RRDSET *rrdset_create(const char *type, const char *id, const char *name, const
                        config_get_number(st->id, "gap when lost iterations above", RRD_DEFAULT_GAP_INTERPOLATIONS) + 2);
 
        avl_init_lock(&st->dimensions_index, rrddim_compare);
+    avl_init_lock(&st->variables_root_index, rrdvar_compare);
 
        pthread_rwlock_init(&st->rwlock, NULL);
-       pthread_rwlock_wrlock(&rrdset_root_rwlock);
+       pthread_rwlock_wrlock(&localhost.rrdset_root_rwlock);
 
        if(name && *name) rrdset_set_name(st, name);
        else rrdset_set_name(st, id);
@@ -458,12 +513,20 @@ RRDSET *rrdset_create(const char *type, const char *id, const char *name, const
                st->title = config_get(st->id, "title", varvalue);
        }
 
-       st->next = rrdset_root;
-       rrdset_root = st;
+    st->rrdcontext = rrdcontext_create(st->context);
+    st->rrdhost = &localhost;
+
+    st->next = localhost.rrdset_root;
+    localhost.rrdset_root = st;
+
+    rrdsetvar_create(st, "last_collected", RRDVAR_TYPE_TIME_T, &st->last_collected_time.tv_sec, 0);
+    rrdsetvar_create(st, "raw_total", RRDVAR_TYPE_TOTAL, &st->collected_total, 0);
 
-       rrdset_index_add(st);
+    rrdset_index_add(&localhost, st);
 
-       pthread_rwlock_unlock(&rrdset_root_rwlock);
+    rrdsetcalc_link_matching(st);
+
+       pthread_rwlock_unlock(&localhost.rrdset_root_rwlock);
 
        return(st);
 }
@@ -534,18 +597,14 @@ RRDDIM *rrddim_add(RRDSET *st, const char *id, const char *name, long multiplier
                // we have a file mapped for rd
                rd->mapped = rrd_memory_mode;
                rd->flags = 0x00000000;
+        rd->variables = NULL;
                rd->next = NULL;
                rd->name = NULL;
        }
        else {
                // if we didn't manage to get a mmap'd dimension, just create one
 
-               rd = calloc(1, size);
-               if(!rd) {
-                       fatal("Cannot allocate RRD_DIMENSION %s/%s.", st->id, id);
-                       return NULL;
-               }
-
+               rd = callocz(1, size);
                rd->mapped = RRD_MEMORY_MODE_RAM;
        }
        rd->memsize = size;
@@ -583,8 +642,9 @@ RRDDIM *rrddim_add(RRDSET *st, const char *id, const char *name, long multiplier
        rd->values[st->current_entry] = pack_storage_number(0, SN_NOT_EXISTS);
        rd->last_collected_time.tv_sec = 0;
        rd->last_collected_time.tv_usec = 0;
+    rd->rrdset = st;
 
-       // append this dimension
+    // append this dimension
        pthread_rwlock_wrlock(&st->rwlock);
        if(!st->dimensions)
                st->dimensions = rd;
@@ -593,6 +653,11 @@ RRDDIM *rrddim_add(RRDSET *st, const char *id, const char *name, long multiplier
                for(; td->next; td = td->next) ;
                td->next = rd;
        }
+
+    rrddimvar_create(rd, RRDVAR_TYPE_CALCULATED, NULL, NULL, &rd->calculated_value, 0);
+    rrddimvar_create(rd, RRDVAR_TYPE_COLLECTED, NULL, "_raw", &rd->collected_value, 0);
+    rrddimvar_create(rd, RRDVAR_TYPE_TIME_T, NULL, "_last_collected", &rd->last_collected_time.tv_sec, 0);
+
        pthread_rwlock_unlock(&st->rwlock);
 
        rrddim_index_add(st, rd);
@@ -607,6 +672,8 @@ void rrddim_set_name(RRDSET *st, RRDDIM *rd, const char *name)
        char varname[CONFIG_MAX_NAME + 1];
        snprintfz(varname, CONFIG_MAX_NAME, "dim %s name", rd->id);
        config_set_default(st->id, varname, name);
+
+    rrddimvar_rename_all(rd);
 }
 
 void rrddim_free(RRDSET *st, RRDDIM *rd)
@@ -625,7 +692,10 @@ void rrddim_free(RRDSET *st, RRDDIM *rd)
        else st->dimensions = rd->next;
        rd->next = NULL;
 
-       rrddim_index_del(st, rd);
+    while(rd->variables)
+        rrddimvar_free(rd->variables);
+
+    rrddim_index_del(st, rd);
 
        // free(rd->annotations);
        if(rd->mapped == RRD_MEMORY_MODE_SAVE) {
@@ -641,7 +711,7 @@ void rrddim_free(RRDSET *st, RRDDIM *rd)
        }
        else {
                debug(D_RRD_CALLS, "Removing dimension '%s'.", rd->name);
-               free(rd);
+               freez(rd);
        }
 }
 
@@ -649,14 +719,30 @@ void rrdset_free_all(void)
 {
        info("Freeing all memory...");
 
+    pthread_rwlock_wrlock(&localhost.rrdset_root_rwlock);
+
        RRDSET *st;
-       for(st = rrdset_root; st ;) {
+       for(st = localhost.rrdset_root; st ;) {
                RRDSET *next = st->next;
 
-               while(st->dimensions)
+        pthread_rwlock_wrlock(&st->rwlock);
+
+        while(st->variables)
+            rrdsetvar_free(st->variables);
+
+        while(st->calculations)
+            rrdsetcalc_unlink(st->calculations);
+
+        while(st->dimensions)
                        rrddim_free(st, st->dimensions);
 
-               rrdset_index_del(st);
+        rrdset_index_del(&localhost, st);
+
+        st->rrdcontext->use_count--;
+        if(!st->rrdcontext->use_count)
+            rrdcontext_free(st->rrdcontext);
+
+        pthread_rwlock_unlock(&st->rwlock);
 
                if(st->mapped == RRD_MEMORY_MODE_SAVE) {
                        debug(D_RRD_CALLS, "Saving stats '%s' to '%s'.", st->name, st->cache_filename);
@@ -670,11 +756,13 @@ void rrdset_free_all(void)
                        munmap(st, st->memsize);
                }
                else
-                       free(st);
+                       freez(st);
 
                st = next;
        }
-       rrdset_root = NULL;
+    localhost.rrdset_root = NULL;
+
+    pthread_rwlock_unlock(&localhost.rrdset_root_rwlock);
 
        info("Memory cleanup completed...");
 }
@@ -685,8 +773,8 @@ void rrdset_save_all(void) {
        RRDSET *st;
        RRDDIM *rd;
 
-       pthread_rwlock_wrlock(&rrdset_root_rwlock);
-       for(st = rrdset_root; st ; st = st->next) {
+       pthread_rwlock_wrlock(&localhost.rrdset_root_rwlock);
+       for(st = localhost.rrdset_root; st ; st = st->next) {
                pthread_rwlock_wrlock(&st->rwlock);
 
                if(st->mapped == RRD_MEMORY_MODE_SAVE) {
@@ -703,7 +791,7 @@ void rrdset_save_all(void) {
 
                pthread_rwlock_unlock(&st->rwlock);
        }
-       pthread_rwlock_unlock(&rrdset_root_rwlock);
+       pthread_rwlock_unlock(&localhost.rrdset_root_rwlock);
 }
 
 
@@ -711,7 +799,7 @@ RRDSET *rrdset_find(const char *id)
 {
        debug(D_RRD_CALLS, "rrdset_find() for chart %s", id);
 
-       RRDSET *st = rrdset_index_find(id, 0);
+       RRDSET *st = rrdset_index_find(&localhost, id, 0);
        return(st);
 }
 
@@ -733,7 +821,7 @@ RRDSET *rrdset_find_byname(const char *name)
 {
        debug(D_RRD_CALLS, "rrdset_find_byname() for chart %s", name);
 
-       RRDSET *st = rrdset_index_find_name(name, 0);
+       RRDSET *st = rrdset_index_find_name(&localhost, name, 0);
        return(st);
 }
 
index 83ab35b69938cebbfebb0316811a58ff2a65e50f..ca6165e924ba11aa3f0469acb09f24d4efaabb94 100644 (file)
--- a/src/rrd.h
+++ b/src/rrd.h
@@ -1,10 +1,3 @@
-#include <sys/time.h>
-#include <pthread.h>
-#include <stdint.h>
-
-#include "avl.h"
-#include "storage_number.h"
-
 #ifndef NETDATA_RRD_H
 #define NETDATA_RRD_H 1
 
@@ -22,8 +15,8 @@ extern int rrd_delete_unupdated_dimensions;
 
 #define RRD_ID_LENGTH_MAX 1024
 
-#define RRDSET_MAGIC           "NETDATA RRD SET FILE V017"
-#define RRDDIMENSION_MAGIC     "NETDATA RRD DIMENSION FILE V017"
+#define RRDSET_MAGIC           "NETDATA RRD SET FILE V018"
+#define RRDDIMENSION_MAGIC     "NETDATA RRD DIMENSION FILE V018"
 
 typedef long long total_number;
 #define TOTAL_NUMBER_FORMAT "%lld"
@@ -82,6 +75,21 @@ extern const char *rrddim_algorithm_name(int chart_type);
 #define RRDDIM_FLAG_HIDDEN 0x00000001 // this dimension will not be offered to callers
 #define RRDDIM_FLAG_DONT_DETECT_RESETS_OR_OVERFLOWS 0x00000002 // do not offer RESET or OVERFLOW info to callers
 
+// ----------------------------------------------------------------------------
+// RRD CONTEXT
+
+struct rrdcontext {
+    avl avl;
+
+    const char *id;
+    uint32_t hash;
+
+    size_t use_count;
+
+    avl_tree_lock variables_root_index;
+};
+typedef struct rrdcontext RRDCONTEXT;
+
 // ----------------------------------------------------------------------------
 // RRD DIMENSION
 
@@ -142,6 +150,7 @@ struct rrddim {
        calculated_number stored_volume;                                // the sum of all stored values so far
 
        struct rrddim *next;                                                    // linking of dimensions within the same data set
+    struct rrdset *rrdset;
 
        // ------------------------------------------------------------------------
        // members for checking the data when loading from disk
@@ -156,6 +165,8 @@ struct rrddim {
 
        char magic[sizeof(RRDDIMENSION_MAGIC) + 1];             // a string to be saved, used to identify our data file
 
+    struct rrddimvar *variables;
+
        // ------------------------------------------------------------------------
        // the values stored in this dimension, using our floating point numbers
 
@@ -237,8 +248,18 @@ struct rrdset {
        total_number collected_total;                                   // used internally to calculate percentages
        total_number last_collected_total;                              // used internally to calculate percentages
 
+    RRDCONTEXT *rrdcontext;
+    struct rrdhost *rrdhost;
+
        struct rrdset *next;                                                    // linking of rrdsets
 
+       // ------------------------------------------------------------------------
+       // local variables
+
+       avl_tree_lock variables_root_index;
+       RRDSETVAR *variables;
+       RRDCALC *calculations;
+
        // ------------------------------------------------------------------------
        // members for checking the data when loading from disk
 
@@ -251,11 +272,40 @@ struct rrdset {
 
        avl_tree_lock dimensions_index;                                         // the root of the dimensions index
        RRDDIM *dimensions;                                                             // the actual data for every dimension
+
 };
 typedef struct rrdset RRDSET;
 
-extern RRDSET *rrdset_root;
-extern pthread_rwlock_t rrdset_root_rwlock;
+// ----------------------------------------------------------------------------
+// RRD HOST
+
+struct rrdhost {
+    avl avl;
+
+    char *hostname;
+
+    RRDSET *rrdset_root;
+    pthread_rwlock_t rrdset_root_rwlock;
+
+    avl_tree_lock rrdset_root_index;
+    avl_tree_lock rrdset_root_index_name;
+
+    avl_tree_lock rrdcontext_root_index;
+    avl_tree_lock variables_root_index;
+
+       // all RRDCALCs are primarily allocated and linked here
+       // RRDCALCs may be linked to charts at any point
+       // (charts may or may not exist when these are loaded)
+       RRDCALC *calculations;
+
+    // all variable references are linked here
+    // RRDVARs may be free'd, so every time this happens
+    // we need to find all their references and invalidate them
+    EVAL_VARIABLE *references;
+};
+typedef struct rrdhost RRDHOST;
+
+extern RRDHOST localhost;
 
 // ----------------------------------------------------------------------------
 // RRD SET functions
index 0afb4531bc2e2e383603edab0f878c9e29450891..7958bca2ea2dd8cf6b4fc9a18588b89cf0350ed5 100644 (file)
@@ -1,15 +1,4 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <pthread.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdint.h>
-#include <math.h>
-
-#include "log.h"
 #include "common.h"
-#include "rrd2json.h"
 
 #define HOSTNAME_MAX 1024
 char *hostname = "unknown";
@@ -96,8 +85,8 @@ void rrd_stats_api_v1_charts(BUFFER *wb)
                , rrd_default_history_entries
                );
 
-       pthread_rwlock_rdlock(&rrdset_root_rwlock);
-       for(st = rrdset_root, c = 0; st ; st = st->next) {
+       pthread_rwlock_rdlock(&localhost.rrdset_root_rwlock);
+       for(st = localhost.rrdset_root, c = 0; st ; st = st->next) {
                if(st->enabled && st->dimensions) {
                        if(c) buffer_strcat(wb, ",");
                        buffer_strcat(wb, "\n\t\t\"");
@@ -107,7 +96,7 @@ void rrd_stats_api_v1_charts(BUFFER *wb)
                        c++;
                }
        }
-       pthread_rwlock_unlock(&rrdset_root_rwlock);
+       pthread_rwlock_unlock(&localhost.rrdset_root_rwlock);
 
        buffer_strcat(wb, "\n\t}\n}\n");
 }
@@ -237,15 +226,15 @@ void rrd_stats_all_json(BUFFER *wb)
 
        buffer_strcat(wb, RRD_GRAPH_JSON_HEADER);
 
-       pthread_rwlock_rdlock(&rrdset_root_rwlock);
-       for(st = rrdset_root, c = 0; st ; st = st->next) {
+       pthread_rwlock_rdlock(&localhost.rrdset_root_rwlock);
+       for(st = localhost.rrdset_root, c = 0; st ; st = st->next) {
                if(st->enabled && st->dimensions) {
                        if(c) buffer_strcat(wb, ",\n");
                        memory += rrd_stats_one_json(st, NULL, wb);
                        c++;
                }
        }
-       pthread_rwlock_unlock(&rrdset_root_rwlock);
+       pthread_rwlock_unlock(&localhost.rrdset_root_rwlock);
 
        buffer_sprintf(wb, "\n\t],\n"
                "\t\"hostname\": \"%s\",\n"
@@ -1161,11 +1150,11 @@ inline static void rrdr_free(RRDR *r)
        }
 
        rrdr_unlock_rrdset(r);
-       if(likely(r->t)) free(r->t);
-       if(likely(r->v)) free(r->v);
-       if(likely(r->o)) free(r->o);
-       if(likely(r->od)) free(r->od);
-       free(r);
+       freez(r->t);
+       freez(r->v);
+       freez(r->o);
+       freez(r->od);
+       freez(r);
 }
 
 inline void rrdr_done(RRDR *r)
@@ -1181,9 +1170,7 @@ static RRDR *rrdr_create(RRDSET *st, long n)
                return NULL;
        }
 
-       RRDR *r = calloc(1, sizeof(RRDR));
-       if(unlikely(!r)) goto cleanup;
-
+       RRDR *r = callocz(1, sizeof(RRDR));
        r->st = st;
 
        rrdr_lock_rrdset(r);
@@ -1193,17 +1180,10 @@ static RRDR *rrdr_create(RRDSET *st, long n)
 
        r->n = n;
 
-       r->t = malloc(n * sizeof(time_t));
-       if(unlikely(!r->t)) goto cleanup;
-
-       r->v = malloc(n * r->d * sizeof(calculated_number));
-       if(unlikely(!r->v)) goto cleanup;
-
-       r->o = malloc(n * r->d * sizeof(uint8_t));
-       if(unlikely(!r->o)) goto cleanup;
-
-       r->od = malloc(r->d * sizeof(uint8_t));
-       if(unlikely(!r->od)) goto cleanup;
+       r->t = mallocz(n * sizeof(time_t));
+       r->v = mallocz(n * r->d * sizeof(calculated_number));
+       r->o = mallocz(n * r->d * sizeof(uint8_t));
+       r->od = mallocz(r->d * sizeof(uint8_t));
 
        // set the hidden flag on hidden dimensions
        int c;
@@ -1213,16 +1193,10 @@ static RRDR *rrdr_create(RRDSET *st, long n)
        }
 
        r->c = -1;
-
        r->group = 1;
        r->update_every = 1;
 
        return r;
-
-cleanup:
-       error("Cannot allocate RRDR memory for %ld entries", n);
-       if(likely(r)) rrdr_free(r);
-       return NULL;
 }
 
 RRDR *rrd2rrdr(RRDSET *st, long points, long long after, long long before, int group_method, int aligned)
index 42a7e20097a74974a2ba554a73e9dfe88815c82a..bb7b04064971f402a9de756d4ae84185261c4746 100644 (file)
@@ -1,8 +1,3 @@
-#include <time.h>
-
-#include "web_buffer.h"
-#include "rrd.h"
-
 #ifndef NETDATA_RRD2JSON_H
 #define NETDATA_RRD2JSON_H 1
 
index df80bf725cfb310795a2b3c2201f3c514d0b2560..70eb638462825dc1faa3585a13a0ccdf76e3e7d6 100644 (file)
@@ -1,21 +1,4 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#ifdef STORAGE_WITH_MATH
-#include <math.h>
-#endif
-
 #include "common.h"
-#include "log.h"
-#include "storage_number.h"
-
-#if __GNUC__
-#if __x86_64__ || __ppc64__
-#define ENVIRONMENT64
-#else
-#define ENVIRONMENT32
-#endif
-#endif
 
 extern char *print_number_lu_r(char *str, unsigned long uvalue);
 extern char *print_number_llu_r(char *str, unsigned long long uvalue);
index 1b7da79f17026cc6086914f558c3927a22a13d4d..7ff839433f8639a655b029b88b2f503630720d1c 100644 (file)
@@ -1,5 +1,3 @@
-#include <stdint.h>
-
 #ifndef NETDATA_STORAGE_NUMBER_H
 #define NETDATA_STORAGE_NUMBER_H
 
index 5bc408c95a58ae79afbbb876a2fb03a48e0254d2..522aaf1744a7c541f3369a44fea19c225f7e55c7 100644 (file)
@@ -1,23 +1,4 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <inttypes.h>
-#include <sys/types.h>
-#include <dirent.h>
-#include <string.h>
-#include <sys/stat.h>
-
 #include "common.h"
-#include "appconfig.h"
-#include "procfile.h"
-#include "log.h"
-#include "rrd.h"
-#include "main.h"
-#include "popen.h"
-#include "proc_self_mountinfo.h"
 
 // ----------------------------------------------------------------------------
 // cgroup globals
@@ -280,13 +261,9 @@ void cgroup_read_cpuacct_usage(struct cpuacct_usage *ca) {
                }
 
                if(i != ca->cpus) {
-                       free(ca->cpu_percpu);
-
-                       ca->cpu_percpu = malloc(sizeof(unsigned long long) * i);
-                       if(!ca->cpu_percpu)
-                               fatal("Cannot allocate memory (%zu bytes)", sizeof(unsigned long long) * i);
-
-                       ca->cpus = i;
+                       freez(ca->cpu_percpu);
+                       ca->cpu_percpu = mallocz(sizeof(unsigned long long) * i);
+                       ca->cpus = (unsigned int)i;
                }
 
                for(i = 0; i < ca->cpus ;i++) {
@@ -631,17 +608,12 @@ void cgroup_get_chart_id(struct cgroup *cg) {
 
                trim(s);
 
-               free(cg->chart_title);
-               cg->chart_title = strdup(s);
-               if(!cg->chart_title)
-                       fatal("CGROUP: Cannot allocate memory for chart name of cgroup '%s' chart name: '%s'", cg->id, s);
-
+               freez(cg->chart_title);
+               cg->chart_title = strdupz(s);
                netdata_fix_chart_name(cg->chart_title);
 
-               free(cg->chart_id);
-               cg->chart_id = strdup(s);
-               if(!cg->chart_id)
-                       fatal("CGROUP: Cannot allocate memory for chart id of cgroup '%s' chart id: '%s'", cg->id, s);
+               freez(cg->chart_id);
+               cg->chart_id = strdupz(s);
 
                netdata_fix_chart_id(cg->chart_id);
 
@@ -702,21 +674,15 @@ struct cgroup *cgroup_add(const char *id) {
                }
        }
 
-       struct cgroup *cg = calloc(1, sizeof(struct cgroup));
-       if(!cg) fatal("Cannot allocate memory for cgroup '%s'", id);
+       struct cgroup *cg = callocz(1, sizeof(struct cgroup));
 
        debug(D_CGROUP, "adding cgroup '%s'", id);
 
-       cg->id = strdup(id);
-       if(!cg->id) fatal("Cannot allocate memory for cgroup '%s'", id);
-
+       cg->id = strdupz(id);
        cg->hash = simple_hash(cg->id);
 
-       cg->chart_id = strdup(chart_id);
-       if(!cg->chart_id) fatal("Cannot allocate memory for cgroup '%s'", id);
-
-       cg->chart_title = strdup(chart_id);
-       if(!cg->chart_title) fatal("Cannot allocate memory for cgroup '%s'", id);
+       cg->chart_id = strdupz(chart_id);
+       cg->chart_title = strdupz(chart_id);
 
        if(!cgroup_root)
                cgroup_root = cg;
@@ -744,22 +710,22 @@ struct cgroup *cgroup_add(const char *id) {
 void cgroup_free(struct cgroup *cg) {
        debug(D_CGROUP, "Removing cgroup '%s' with chart id '%s' (was %s and %s)", cg->id, cg->chart_id, (cg->enabled)?"enabled":"disabled", (cg->available)?"available":"not available");
 
-       free(cg->cpuacct_usage.cpu_percpu);
+       freez(cg->cpuacct_usage.cpu_percpu);
 
-       free(cg->cpuacct_stat.filename);
-       free(cg->cpuacct_usage.filename);
-       free(cg->memory.filename);
-       free(cg->io_service_bytes.filename);
-       free(cg->io_serviced.filename);
-       free(cg->throttle_io_service_bytes.filename);
-       free(cg->throttle_io_serviced.filename);
-       free(cg->io_merged.filename);
-       free(cg->io_queued.filename);
+       freez(cg->cpuacct_stat.filename);
+       freez(cg->cpuacct_usage.filename);
+       freez(cg->memory.filename);
+       freez(cg->io_service_bytes.filename);
+       freez(cg->io_serviced.filename);
+       freez(cg->throttle_io_service_bytes.filename);
+       freez(cg->throttle_io_serviced.filename);
+       freez(cg->io_merged.filename);
+       freez(cg->io_queued.filename);
 
-       free(cg->id);
-       free(cg->chart_id);
-       free(cg->chart_title);
-       free(cg);
+       freez(cg->id);
+       freez(cg->chart_id);
+       freez(cg->chart_title);
+       freez(cg);
 
        cgroup_root_count--;
 }
@@ -852,15 +818,12 @@ void find_dir_in_subdirs(const char *base, const char *this, void (*callback)(co
                        }
 
                        if(enabled) {
-                               char *s = malloc(dirlen + strlen(de->d_name) + 2);
-                               if(s) {
-                                       strcpy(s, this);
-                                       strcat(s, "/");
-                                       strcat(s, de->d_name);
-                                       find_dir_in_subdirs(base, s, callback);
-                                       free(s);
-                               }
-                               else error("Cannot allocate memory.");
+                               char *s = mallocz(dirlen + strlen(de->d_name) + 2);
+                strcpy(s, this);
+                strcat(s, "/");
+                strcat(s, de->d_name);
+                find_dir_in_subdirs(base, s, callback);
+                freez(s);
                        }
                }
        }
@@ -939,7 +902,7 @@ void find_all_cgroups() {
                if(cgroup_enable_cpuacct_stat && !cg->cpuacct_stat.filename) {
                        snprintfz(filename, FILENAME_MAX, "%s%s/cpuacct.stat", cgroup_cpuacct_base, cg->id);
                        if(stat(filename, &buf) != -1) {
-                               cg->cpuacct_stat.filename = strdup(filename);
+                               cg->cpuacct_stat.filename = strdupz(filename);
                                debug(D_CGROUP, "cpuacct.stat filename for cgroup '%s': '%s'", cg->id, cg->cpuacct_stat.filename);
                        }
                        else debug(D_CGROUP, "cpuacct.stat file for cgroup '%s': '%s' does not exist.", cg->id, filename);
@@ -947,7 +910,7 @@ void find_all_cgroups() {
                if(cgroup_enable_cpuacct_usage && !cg->cpuacct_usage.filename) {
                        snprintfz(filename, FILENAME_MAX, "%s%s/cpuacct.usage_percpu", cgroup_cpuacct_base, cg->id);
                        if(stat(filename, &buf) != -1) {
-                               cg->cpuacct_usage.filename = strdup(filename);
+                               cg->cpuacct_usage.filename = strdupz(filename);
                                debug(D_CGROUP, "cpuacct.usage_percpu filename for cgroup '%s': '%s'", cg->id, cg->cpuacct_usage.filename);
                        }
                        else debug(D_CGROUP, "cpuacct.usage_percpu file for cgroup '%s': '%s' does not exist.", cg->id, filename);
@@ -955,7 +918,7 @@ void find_all_cgroups() {
                if(cgroup_enable_memory && !cg->memory.filename) {
                        snprintfz(filename, FILENAME_MAX, "%s%s/memory.stat", cgroup_memory_base, cg->id);
                        if(stat(filename, &buf) != -1) {
-                               cg->memory.filename = strdup(filename);
+                               cg->memory.filename = strdupz(filename);
                                debug(D_CGROUP, "memory.stat filename for cgroup '%s': '%s'", cg->id, cg->memory.filename);
                        }
                        else debug(D_CGROUP, "memory.stat file for cgroup '%s': '%s' does not exist.", cg->id, filename);
@@ -964,7 +927,7 @@ void find_all_cgroups() {
                        if(!cg->io_service_bytes.filename) {
                                snprintfz(filename, FILENAME_MAX, "%s%s/blkio.io_service_bytes", cgroup_blkio_base, cg->id);
                                if(stat(filename, &buf) != -1) {
-                                       cg->io_service_bytes.filename = strdup(filename);
+                                       cg->io_service_bytes.filename = strdupz(filename);
                                        debug(D_CGROUP, "io_service_bytes filename for cgroup '%s': '%s'", cg->id, cg->io_service_bytes.filename);
                                }
                                else debug(D_CGROUP, "io_service_bytes file for cgroup '%s': '%s' does not exist.", cg->id, filename);
@@ -972,7 +935,7 @@ void find_all_cgroups() {
                        if(!cg->io_serviced.filename) {
                                snprintfz(filename, FILENAME_MAX, "%s%s/blkio.io_serviced", cgroup_blkio_base, cg->id);
                                if(stat(filename, &buf) != -1) {
-                                       cg->io_serviced.filename = strdup(filename);
+                                       cg->io_serviced.filename = strdupz(filename);
                                        debug(D_CGROUP, "io_serviced filename for cgroup '%s': '%s'", cg->id, cg->io_serviced.filename);
                                }
                                else debug(D_CGROUP, "io_serviced file for cgroup '%s': '%s' does not exist.", cg->id, filename);
@@ -980,7 +943,7 @@ void find_all_cgroups() {
                        if(!cg->throttle_io_service_bytes.filename) {
                                snprintfz(filename, FILENAME_MAX, "%s%s/blkio.throttle.io_service_bytes", cgroup_blkio_base, cg->id);
                                if(stat(filename, &buf) != -1) {
-                                       cg->throttle_io_service_bytes.filename = strdup(filename);
+                                       cg->throttle_io_service_bytes.filename = strdupz(filename);
                                        debug(D_CGROUP, "throttle_io_service_bytes filename for cgroup '%s': '%s'", cg->id, cg->throttle_io_service_bytes.filename);
                                }
                                else debug(D_CGROUP, "throttle_io_service_bytes file for cgroup '%s': '%s' does not exist.", cg->id, filename);
@@ -988,7 +951,7 @@ void find_all_cgroups() {
                        if(!cg->throttle_io_serviced.filename) {
                                snprintfz(filename, FILENAME_MAX, "%s%s/blkio.throttle.io_serviced", cgroup_blkio_base, cg->id);
                                if(stat(filename, &buf) != -1) {
-                                       cg->throttle_io_serviced.filename = strdup(filename);
+                                       cg->throttle_io_serviced.filename = strdupz(filename);
                                        debug(D_CGROUP, "throttle_io_serviced filename for cgroup '%s': '%s'", cg->id, cg->throttle_io_serviced.filename);
                                }
                                else debug(D_CGROUP, "throttle_io_serviced file for cgroup '%s': '%s' does not exist.", cg->id, filename);
@@ -996,7 +959,7 @@ void find_all_cgroups() {
                        if(!cg->io_merged.filename) {
                                snprintfz(filename, FILENAME_MAX, "%s%s/blkio.io_merged", cgroup_blkio_base, cg->id);
                                if(stat(filename, &buf) != -1) {
-                                       cg->io_merged.filename = strdup(filename);
+                                       cg->io_merged.filename = strdupz(filename);
                                        debug(D_CGROUP, "io_merged filename for cgroup '%s': '%s'", cg->id, cg->io_merged.filename);
                                }
                                else debug(D_CGROUP, "io_merged file for cgroup '%s': '%s' does not exist.", cg->id, filename);
@@ -1004,7 +967,7 @@ void find_all_cgroups() {
                        if(!cg->io_queued.filename) {
                                snprintfz(filename, FILENAME_MAX, "%s%s/blkio.io_queued", cgroup_blkio_base, cg->id);
                                if(stat(filename, &buf) != -1) {
-                                       cg->io_queued.filename = strdup(filename);
+                                       cg->io_queued.filename = strdupz(filename);
                                        debug(D_CGROUP, "io_queued filename for cgroup '%s': '%s'", cg->id, cg->io_queued.filename);
                                }
                                else debug(D_CGROUP, "io_queued file for cgroup '%s': '%s' does not exist.", cg->id, filename);
index 8064cb1818e5742a02d67ab87cf3118b9a899f2b..f6cf52f9cbb2033561c7fabc89ff86b146df3e5b 100644 (file)
@@ -1,21 +1,9 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
 #include "common.h"
-#include "log.h"
-#include "appconfig.h"
-#include "procfile.h"
-#include "rrd.h"
-#include "plugin_proc.h"
 
-typedef struct name_value {
+typedef struct ksm_name_value {
        char filename[FILENAME_MAX + 1];
        unsigned long long value;
-} NAME_VALUE;
+} KSM_NAME_VALUE;
 
 #define PAGES_SHARED 0
 #define PAGES_SHARING 1
@@ -23,7 +11,7 @@ typedef struct name_value {
 #define PAGES_VOLATILE 3
 #define PAGES_TO_SCAN 4
 
-NAME_VALUE values[] = {
+KSM_NAME_VALUE values[] = {
                [PAGES_SHARED] = { "/sys/kernel/mm/ksm/pages_shared", 0ULL },
                [PAGES_SHARING] = { "/sys/kernel/mm/ksm/pages_sharing", 0ULL },
                [PAGES_UNSHARED] = { "/sys/kernel/mm/ksm/pages_unshared", 0ULL },
index dbf9190ba4c7d66de2b9ace17379700a08d0ec03..1a8ef012acd19083f0bd89c1ccb5c101d3190fc9 100644 (file)
@@ -1,17 +1,4 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/resource.h>
-#include <math.h>
-
 #include "common.h"
-#include "storage_number.h"
-#include "rrd.h"
-#include "log.h"
-#include "web_buffer.h"
 
 int check_storage_number(calculated_number n, int debug) {
        char buffer[100];
index bd22b8187fe05d335d3400a26386bd6c0c7cdbd8..44c5a6dc9cc166406e06a7dcd8fe6a742e2dc945 100644 (file)
--- a/src/url.c
+++ b/src/url.c
@@ -1,13 +1,4 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-
 #include "common.h"
-#include "log.h"
-#include "url.h"
 
 // ----------------------------------------------------------------------------
 // URL encode / decode
@@ -29,10 +20,7 @@ char to_hex(char code) {
 char *url_encode(char *str) {
        char *buf, *pbuf;
 
-       pbuf = buf = malloc(strlen(str) * 3 + 1);
-
-       if(!buf)
-               fatal("Cannot allocate memory.");
+       pbuf = buf = mallocz(strlen(str) * 3 + 1);
 
        while (*str) {
                if (isalnum(*str) || *str == '-' || *str == '_' || *str == '.' || *str == '~')
@@ -48,16 +36,9 @@ char *url_encode(char *str) {
        }
        *pbuf = '\0';
 
-       // FIX: I think this is prudent. URLs can be as long as 2 KiB or more.
-       //      We allocated 3 times more space to accomodate %NN encoding of
-       //      non ASCII chars. If URL has none of these kind of chars we will
-       //      end up with a big unused buffer.
-       //
-       //      Try to shrink the buffer...
-       if (!!(pbuf = (char *)realloc(buf, strlen(buf)+1)))
-               buf = pbuf;
-
-       return buf;
+       pbuf = strdupz(buf);
+       freez(buf);
+       return pbuf;
 }
 
 /* Returns a url-decoded version of str */
@@ -65,10 +46,7 @@ char *url_encode(char *str) {
 char *url_decode(char *str) {
        size_t size = strlen(str) + 1;
 
-       char *buf = malloc(size);
-       if(!buf)
-               fatal("Cannot allocate %zu bytes of memory.", size);
-
+       char *buf = mallocz(size);
        return url_decode_r(buf, str, size);
 }
 
index 582890e1b566abe794a67c05447dab69da69d094..c4aa2f8d9811e058da9fd5a6ba2e7fedd028f6b4 100644 (file)
@@ -1,16 +1,4 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <stdlib.h>
-#include <string.h>
-
-#ifdef STORAGE_WITH_MATH
-#include <math.h>
-#endif
-
 #include "common.h"
-#include "web_buffer.h"
-#include "log.h"
 
 #define BUFFER_OVERFLOW_EOF "EOF"
 
@@ -335,18 +323,8 @@ BUFFER *buffer_create(size_t size)
 
        debug(D_WEB_BUFFER, "Creating new web buffer of size %zu.", size);
 
-       b = calloc(1, sizeof(BUFFER));
-       if(!b) {
-               error("Cannot allocate a web_buffer.");
-               return NULL;
-       }
-
-       b->buffer = malloc(size + sizeof(BUFFER_OVERFLOW_EOF) + 2);
-       if(!b->buffer) {
-               error("Cannot allocate a buffer of size %zu.", size + sizeof(BUFFER_OVERFLOW_EOF) + 2);
-               free(b);
-               return NULL;
-       }
+       b = callocz(1, sizeof(BUFFER));
+       b->buffer = mallocz(size + sizeof(BUFFER_OVERFLOW_EOF) + 2);
        b->buffer[0] = '\0';
        b->size = size;
        b->contenttype = CT_TEXT_PLAIN;
@@ -362,8 +340,8 @@ void buffer_free(BUFFER *b)
 
        debug(D_WEB_BUFFER, "Freeing web buffer of size %zu.", b->size);
 
-       free(b->buffer);
-       free(b);
+       freez(b->buffer);
+       freez(b);
 }
 
 void buffer_increase(BUFFER *b, size_t free_size_required)
@@ -379,12 +357,7 @@ void buffer_increase(BUFFER *b, size_t free_size_required)
 
        debug(D_WEB_BUFFER, "Increasing data buffer from size %zu to %zu.", b->size, b->size + increase);
 
-       b->buffer = realloc(b->buffer, b->size + increase + sizeof(BUFFER_OVERFLOW_EOF) + 2);
-       if(!b->buffer)
-               fatal("Failed to increase data buffer from size %zu to %zu.",
-                       b->size + sizeof(BUFFER_OVERFLOW_EOF) + 2,
-                       b->size + increase + sizeof(BUFFER_OVERFLOW_EOF) + 2);
-
+       b->buffer = reallocz(b->buffer, b->size + increase + sizeof(BUFFER_OVERFLOW_EOF) + 2);
        b->size += increase;
 
        buffer_overflow_init(b);
index 399eb84a52e189789ed065e208565fa5855fea63..0370491e2828f8c685a2b5bb5ffe9567ed39f1ea 100644 (file)
@@ -1,11 +1,7 @@
-#include <stdarg.h>
-#include <time.h>
-#include "storage_number.h"
-
 #ifndef NETDATA_WEB_BUFFER_H
 #define NETDATA_WEB_BUFFER_H 1
 
-#define WEB_DATA_LENGTH_INCREASE_STEP 16384
+#define WEB_DATA_LENGTH_INCREASE_STEP 1024
 
 typedef struct web_buffer {
        size_t size;            // allocation size of buffer
index 250bbc8985ef8d35a88d8ea73122c633a060960f..087c79a3f037cf6850f4a285adf7913b285494f5 100644 (file)
@@ -1,17 +1,4 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <math.h>
-#include <string.h>
-#include <ctype.h>
-#include <stdlib.h>
-
 #include "common.h"
-#include "log.h"
-#include "appconfig.h"
-#include "url.h"
-#include "web_buffer.h"
-#include "web_buffer_svg.h"
 
 #define BADGE_HORIZONTAL_PADDING 4
 #define VERDANA_KERNING 0.5
index b853e97dde49d1c3c75ec5f3f7a4c558225bc7ba..1281847eb49c4721c7d00cfe3cd61257f8981215 100644 (file)
@@ -1,6 +1,3 @@
-#include "web_buffer.h"
-#include "dictionary.h"
-
 #ifndef NETDATA_WEB_BUFFER_SVG_H
 #define NETDATA_WEB_BUFFER_SVG_H 1
 
index 4714ef8d979754d036944c53bbf703779aed344b..721310de6434f04125f2f5c46be029c34282a65d 100644 (file)
@@ -1,38 +1,4 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <unistd.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <errno.h>
-#include <pthread.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <malloc.h>
-#include <pwd.h>
-#include <grp.h>
-#include <ctype.h>
-#include <poll.h>
-
-// TCP_CORK
-#include <netinet/tcp.h>
-
 #include "common.h"
-#include "log.h"
-#include "main.h"
-#include "appconfig.h"
-#include "url.h"
-#include "web_buffer.h"
-#include "web_server.h"
-#include "global_statistics.h"
-#include "rrd.h"
-#include "rrd2json.h"
-#include "registry.h"
-#include "web_buffer_svg.h"
-#include "web_client.h"
 
 #define INITIAL_WEB_DATA_LENGTH 16384
 #define WEB_REQUEST_LENGTH 16384
@@ -82,12 +48,7 @@ struct web_client *web_client_create(int listener)
 {
        struct web_client *w;
 
-       w = calloc(1, sizeof(struct web_client));
-       if(!w) {
-               error("Cannot allocate new web_client memory.");
-               return NULL;
-       }
-
+       w = callocz(1, sizeof(struct web_client));
        w->id = ++web_clients_count;
        w->mode = WEB_CLIENT_MODE_NORMAL;
 
@@ -101,7 +62,7 @@ struct web_client *web_client_create(int listener)
                w->ifd = accept4(listener, sadr, &addrlen, SOCK_NONBLOCK);
                if (w->ifd == -1) {
                        error("%llu: Cannot accept new incoming connection.", w->id);
-                       free(w);
+                       freez(w);
                        return NULL;
                }
                w->ofd = w->ifd;
@@ -143,32 +104,8 @@ struct web_client *web_client_create(int listener)
        }
 
        w->response.data = buffer_create(INITIAL_WEB_DATA_LENGTH);
-       if(unlikely(!w->response.data)) {
-               // no need for error log - web_buffer_create already logged the error
-               close(w->ifd);
-               free(w);
-               return NULL;
-       }
-
        w->response.header = buffer_create(HTTP_RESPONSE_HEADER_SIZE);
-       if(unlikely(!w->response.header)) {
-               // no need for error log - web_buffer_create already logged the error
-               buffer_free(w->response.data);
-               close(w->ifd);
-               free(w);
-               return NULL;
-       }
-
        w->response.header_output = buffer_create(HTTP_RESPONSE_HEADER_SIZE);
-       if(unlikely(!w->response.header_output)) {
-               // no need for error log - web_buffer_create already logged the error
-               buffer_free(w->response.header);
-               buffer_free(w->response.data);
-               close(w->ifd);
-               free(w);
-               return NULL;
-       }
-
        w->origin[0] = '*';
        w->wait_receive = 1;
 
@@ -297,7 +234,7 @@ struct web_client *web_client_free(struct web_client *w) {
        if(w->response.data) buffer_free(w->response.data);
        if(w->ifd != -1) close(w->ifd);
        if(w->ofd != -1 && w->ofd != w->ifd) close(w->ofd);
-       free(w);
+       freez(w);
 
        global_statistics.connected_clients--;
 
@@ -732,12 +669,10 @@ int web_client_api_v1_badge(struct web_client *w, char *url) {
                if(!strcmp(name, "chart")) chart = value;
                else if(!strcmp(name, "dimension") || !strcmp(name, "dim") || !strcmp(name, "dimensions") || !strcmp(name, "dims")) {
                        if(!dimensions)
-                               dimensions = buffer_create(strlen(value));
+                               dimensions = buffer_create(100);
 
-                       if(dimensions) {
-                               buffer_strcat(dimensions, "|");
-                               buffer_strcat(dimensions, value);
-                       }
+            buffer_strcat(dimensions, "|");
+            buffer_strcat(dimensions, value);
                }
                else if(!strcmp(name, "after")) after_str = value;
                else if(!strcmp(name, "before")) before_str = value;
@@ -894,11 +829,9 @@ int web_client_api_request_v1_data(struct web_client *w, char *url)
 
                if(!strcmp(name, "chart")) chart = value;
                else if(!strcmp(name, "dimension") || !strcmp(name, "dim") || !strcmp(name, "dimensions") || !strcmp(name, "dims")) {
-                       if(!dimensions) dimensions = buffer_create(strlen(value));
-                       if(dimensions) {
-                               buffer_strcat(dimensions, "|");
-                               buffer_strcat(dimensions, value);
-                       }
+                       if(!dimensions) dimensions = buffer_create(100);
+            buffer_strcat(dimensions, "|");
+            buffer_strcat(dimensions, value);
                }
                else if(!strcmp(name, "after")) after_str = value;
                else if(!strcmp(name, "before")) before_str = value;
@@ -1852,7 +1785,7 @@ void web_client_process(struct web_client *w) {
                                        debug(D_WEB_CLIENT_ACCESS, "%llu: Sending list of RRD_STATS...", w->id);
 
                                        buffer_flush(w->response.data);
-                                       RRDSET *st = rrdset_root;
+                                       RRDSET *st = localhost.rrdset_root;
 
                                        for ( ; st ; st = st->next )
                                                buffer_sprintf(w->response.data, "%s\n", st->name);
@@ -1878,6 +1811,7 @@ void web_client_process(struct web_client *w) {
                                                buffer_strcat(w->response.data, "I am doing it already");
 
                                        error("web request to exit received.");
+                                       netdata_cleanup_and_exit(0);
                                        netdata_exit = 1;
                                }
                                else if(hash == hash_debug && strcmp(tok, "debug") == 0) {
index a3198857672d0ba3f13b78544340953670915bbe..a8339a3254549ecfe116620587e99e9773db183b 100644 (file)
@@ -1,19 +1,3 @@
-
-#ifdef NETDATA_WITH_ZLIB
-#include <zlib.h>
-#endif
-
-#include <sys/time.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <netdb.h>
-
-#include "web_buffer.h"
-#include "dictionary.h"
-
 #ifndef NETDATA_WEB_CLIENT_H
 #define NETDATA_WEB_CLIENT_H 1
 
index 14ac610fdb325884d4e5be48ead158ccfd51aeb1..4bd3f91edc9dd13281e52a9e6d338b020008ab52 100644 (file)
@@ -1,35 +1,7 @@
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-#include <unistd.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <errno.h>
-#include <pthread.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <netinet/tcp.h>
-#include <malloc.h>
-#include <poll.h>
-#include <ctype.h>
-
 #include "common.h"
-#include "log.h"
-#include "appconfig.h"
-#include "url.h"
-#include "web_buffer.h"
-#include "web_client.h"
-#include "web_server.h"
-#include "global_statistics.h"
-#include "rrd.h"
-#include "rrd2json.h"
-#include "../config.h"
 
 int listen_backlog = LISTEN_BACKLOG;
-int listen_fds_count = 0;
+size_t listen_fds_count = 0;
 int listen_fds[MAX_LISTEN_FDS] = { [0 ... 99] = -1 };
 char *listen_fds_names[MAX_LISTEN_FDS] = { [0 ... 99] = NULL };
 int listen_port = LISTEN_PORT;
@@ -193,14 +165,14 @@ static inline int add_listen_socket(int fd, const char *ip, int port) {
 
     char buffer[100 + 1];
     snprintfz(buffer, 100, "[%s]:%d", ip, port);
-    listen_fds_names[listen_fds_count] = strdup(buffer);
+    listen_fds_names[listen_fds_count] = strdupz(buffer);
 
     listen_fds_count++;
     return 0;
 }
 
 int is_listen_socket(int fd) {
-    int i;
+    size_t i;
     for(i = 0; i < listen_fds_count ;i++)
         if(listen_fds[i] == fd) return 1;
 
@@ -208,12 +180,12 @@ int is_listen_socket(int fd) {
 }
 
 static inline void close_listen_sockets(void) {
-    int i;
+    size_t i;
     for(i = 0; i < listen_fds_count ;i++) {
         close(listen_fds[i]);
         listen_fds[i] = -1;
 
-        if(listen_fds_names[i]) free(listen_fds_names[i]);
+        freez(listen_fds_names[i]);
         listen_fds_names[i] = NULL;
     }
 
@@ -223,7 +195,7 @@ static inline void close_listen_sockets(void) {
 static inline int bind_to_one(const char *definition, int default_port, int listen_backlog) {
     int added = 0;
     struct addrinfo hints;
-    struct addrinfo *result, *rp;
+    struct addrinfo *result = NULL, *rp = NULL;
 
     char buffer[strlen(definition) + 1];
     strcpy(buffer, definition);
@@ -303,6 +275,8 @@ static inline int bind_to_one(const char *definition, int default_port, int list
         }
     }
 
+       freeaddrinfo(result);
+
     return added;
 }
 
@@ -345,7 +319,7 @@ int create_listen_sockets(void) {
     if(!listen_fds_count)
         fatal("Cannot listen on any socket. Exiting...");
 
-       return listen_fds_count;
+       return (int)listen_fds_count;
 }
 
 // --------------------------------------------------------------------------------------
@@ -393,11 +367,9 @@ void *socket_listen_main_multi_threaded(void *ptr) {
        if(!listen_fds_count)
                fatal("LISTENER: No sockets to listen to.");
 
-       struct pollfd *fds = calloc(sizeof(struct pollfd), listen_fds_count);
-       if(!fds)
-               fatal("LISTENER: Cannot allocate memory for poll fds.");
+       struct pollfd *fds = callocz(sizeof(struct pollfd), listen_fds_count);
 
-       int i;
+       size_t i;
        for(i = 0; i < listen_fds_count ;i++) {
                fds[i].fd = listen_fds[i];
                fds[i].events = POLLIN;
@@ -515,20 +487,17 @@ void *socket_listen_main_single_threaded(void *ptr) {
        struct web_client *w;
        int retval;
 
-       if(ptr) { ; }
-
        if(pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL) != 0)
                error("Cannot set pthread cancel type to DEFERRED.");
 
        if(pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL) != 0)
                error("Cannot set pthread cancel state to ENABLE.");
 
-       int i;
-
        if(!listen_fds_count)
                fatal("LISTENER: no listen sockets available.");
 
-       for(i = 0; i < FD_SETSIZE ; i++)
+    size_t i;
+    for(i = 0; i < FD_SETSIZE ; i++)
                single_threaded_clients[i] = NULL;
 
        fd_set ifds, ofds, efds, rifds, rofds, refds;
@@ -575,7 +544,7 @@ void *socket_listen_main_single_threaded(void *ptr) {
                                }
                        }
 
-                       for(i = 0 ; i <= fdmax ; i++) {
+                       for(i = 0 ; i <= (size_t)fdmax ; i++) {
                                if(likely(!FD_ISSET(i, &rifds) && !FD_ISSET(i, &rofds) && !FD_ISSET(i, &refds)))
                                        continue;
 
index 1efb9760fe92bbf6e0b5d91901b632bbae16ce9b..59629ae1cf4888d7dbab6a985810221200f85b6a 100644 (file)
@@ -1570,7 +1570,7 @@ var chartData = {
        },
 
        'system.load': {
-               info: 'Current system load read from <code>/proc/loadavg</code>.',
+               info: 'Current system load, a measurement of the work the system is performing. A completely idle computer has a load average of 0. Each process either using or waiting for system resources (e.g. CPU, disk) adds 1 to the load average. So, if your system has a load of 5, five processes are either using or waiting for system resources. Linux calculates this once every 5 seconds. Netdata reads it from <code>/proc/loadavg</code>. For more information see: <a href="http://www.howtogeek.com/194642/understanding-the-load-average-on-linux-and-other-unix-like-systems/" target="_blank">this article</a>',
                height: 0.7
        },