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;
// this has to be called while the caller has locked
// the RRDHOST
-static inline void rrdhostcalc_linked(RRDHOST *host, RRDCALC *rc) {
+static inline void rrdset_linked_optimize_rrdhost(RRDHOST *host, RRDCALC *rc) {
+ rrdhost_check_wrlock(host);
+
// move it to be last
if(!rc->next)
// this has to be called while the caller has locked
// the RRDHOST
-static inline void rrdhostcalc_unlinked(RRDHOST *host, RRDCALC *rc) {
+static inline void rrdcalc_unlinked_optimize_rrdhost(RRDHOST *host, RRDCALC *rc) {
+ rrdhost_check_wrlock(host);
+
// move it to be first
if(host->calculations == rc) {
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);
+ rrdset_linked_optimize_rrdhost(st->rrdhost, rc);
+}
+
+static inline int rrdcalc_is_matching_this_rrdset(RRDCALC *rc, RRDSET *st) {
+ if((rc->hash_chart == st->hash && !strcmp(rc->name, st->id)) ||
+ (rc->hash_chart == st->hash_name && !strcmp(rc->name, st->name)))
+ return 1;
+
+ return 0;
}
// this has to be called while the RRDHOST is locked
// 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))) {
+ if(rrdcalc_is_matching_this_rrdset(rc, st))
rrdsetcalc_link(st, rc);
- }
}
}
// so that if the matching chart is found in the future
// it will be applied automatically
- rrdhostcalc_unlinked(host, rc);
+ rrdcalc_unlinked_optimize_rrdhost(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) {
rc->hash_chart = simple_hash(rc->chart);
}
+ rc->group = group_method;
+ rc->after = after;
+ rc->before = before;
+ rc->update_every = update_every;
+ rc->options = options;
+
+ // link it to the host
+ rc->next = host->calculations;
+ host->calculations = rc;
+
+ // link it to its chart
+ RRDSET *st;
+ for(st = host->rrdset_root; st ; st = st->next) {
+ if(rrdcalc_is_matching_this_rrdset(rc, st)) {
+ rrdsetcalc_link(st, rc);
+ break;
+ }
+ }
+
return NULL;
}
-void rrdcalc_free(RRDCALC *rc) {
+void rrdcalc_free(RRDHOST *host, RRDCALC *rc) {
if(!rc) return;
+ // unlink it from RRDSET
if(rc->rrdset) rrdsetcalc_unlink(rc);
+ // unlink it from RRDHOST
+ if(rc == host->calculations)
+ host->calculations = rc->next;
+
+ else if(host->calculations) {
+ RRDCALC *t, *last = host->calculations;
+
+ for(t = last->next; t ; last = t, t = t->next)
+ if(t == rc) break;
+
+ if(last)
+ last->next = rc->next;
+ else
+ error("Cannot unlink RRDCALC '%s' from RRDHOST '%s': not found", rc->name, host->hostname);
+ }
+ else
+ error("Cannot unlink RRDCALC '%s' from RRDHOST '%s': RRDHOST does not have any calculations", rc->name, host->hostname);
+
+ freez(rc->name);
+ freez(rc->chart);
+ freez(rc->dimensions);
+
freez(rc);
-}
\ No newline at end of file
+}
#define RRDVAR_TYPE_TOTAL 4
// the variables as stored in the variables indexes
+// there are 3 indexes:
+// 1. at each chart (RRDSET.variables_root_index)
+// 2. at each context (RRDCONTEXT.variables_root_index)
+// 3. at each host (RRDHOST.variables_root_index)
typedef struct rrdvar {
avl avl;
} RRDVAR;
// variables linked to charts
-// We link variables to point the values that are already
+// We link variables to point to 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
} RRDSETVAR;
-// variables linked to dimensions
+// variables linked to individual 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
struct rrddimvar *next;
} RRDDIMVAR;
-// additional calculated variables
+// calculated variables (defined in health configuration)
// 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.
+// under 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
+// having as RRDSET.calculations the RRDCALC to be processed
// next.
typedef struct rrdcalc {
char *name;
struct rrdcalctemplate *next;
} RRDCALCTEMPLATE;
+
#include "rrd.h"
extern void rrdsetvar_rename_all(RRDSET *st);
static int rrdset_compare_name(void* a, void* b);
static int rrdcontext_compare(void* a, void* b);
+// ----------------------------------------------------------------------------
+// RRDHOST
+
RRDHOST localhost = {
.hostname = "localhost",
.rrdset_root = NULL,
}
};
+void rrdhost_rwlock(RRDHOST *host) {
+ pthread_rwlock_wrlock(&host->rrdset_root_rwlock);
+}
+
+void rrdhost_rdlock(RRDHOST *host) {
+ pthread_rwlock_rdlock(&host->rrdset_root_rwlock);
+}
+
+void rrdhost_unlock(RRDHOST *host) {
+ pthread_rwlock_unlock(&host->rrdset_root_rwlock);
+}
+
+void rrdhost_check_wrlock_int(RRDHOST *host, const char *file, const char *function, const unsigned long line) {
+ if(pthread_rwlock_tryrdlock(&host->rrdset_root_rwlock) == 0) {
+ fatal("RRDHOST '%s' should be write-locked, but it is not, at function %s() at line %lu of file '%s'", host->hostname, function, line, file);
+ }
+}
+
// ----------------------------------------------------------------------------
// RRDCONTEXT index