rrddim_foreach_read(rd, st) {
rd->last_collected_time.tv_sec = 0;
rd->last_collected_time.tv_usec = 0;
- rd->counter = 0;
+ rd->collections_counter = 0;
memset(rd->values, 0, rd->entries * sizeof(storage_number));
}
}
// ----------------------------------------------------------------------------
// RRDSET - helpers for rrdset_create()
-inline long align_entries_to_pagesize(long entries) {
- if(rrdpush_exclusive)
- return entries;
+inline long align_entries_to_pagesize(RRD_MEMORY_MODE mode, long entries) {
+ if(unlikely(entries < 5)) entries = 5;
+ if(unlikely(entries > RRD_HISTORY_ENTRIES_MAX)) entries = RRD_HISTORY_ENTRIES_MAX;
- if(entries < 5) entries = 5;
- if(entries > RRD_HISTORY_ENTRIES_MAX) entries = RRD_HISTORY_ENTRIES_MAX;
+ if(unlikely(mode == RRD_MEMORY_MODE_NONE || mode == RRD_MEMORY_MODE_RAM))
+ return entries;
long page = (size_t)sysconf(_SC_PAGESIZE);
long size = sizeof(RRDDIM) + entries * sizeof(storage_number);
- if(size % page) {
+ if(unlikely(size % page)) {
size -= (size % page);
size += page;
return entries;
}
-static inline void timeval_align(struct timeval *tv, int update_every) {
+static inline void last_collected_time_align(struct timeval *tv, int update_every) {
tv->tv_sec -= tv->tv_sec % update_every;
tv->tv_usec = 500000;
}
+static inline void last_updated_time_align(struct timeval *tv, int update_every) {
+ tv->tv_sec -= tv->tv_sec % update_every;
+ tv->tv_usec = 0;
+}
+
// ----------------------------------------------------------------------------
// RRDSET - free a chart
rrdhost_check_wrlock(st->rrdhost); // make sure we have a write lock on the host
rrdset_wrlock(st); // lock this RRDSET
- // ------------------------------------------------------------------------
- // free its children structures
-
- while(st->variables) rrdsetvar_free(st->variables);
- while(st->alarms) rrdsetcalc_unlink(st->alarms);
- while(st->dimensions) rrddim_free(st, st->dimensions);
-
- rrdfamily_free(st->rrdhost, st->rrdfamily);
+ // info("Removing chart '%s' ('%s')", st->id, st->name);
// ------------------------------------------------------------------------
// remove it from the indexes
rrdset_index_del_name(st->rrdhost, st);
+ // ------------------------------------------------------------------------
+ // free its children structures
+
+ while(st->variables) rrdsetvar_free(st->variables);
+ while(st->alarms) rrdsetcalc_unlink(st->alarms);
+ while(st->dimensions) rrddim_free(st, st->dimensions);
+
+ rrdfamily_free(st->rrdhost, st->rrdfamily);
+
// ------------------------------------------------------------------------
// unlink it from the host
freez(st);
}
+void rrdset_save(RRDSET *st) {
+ RRDDIM *rd;
+
+ rrdset_check_rdlock(st);
+
+ // info("Saving chart '%s' ('%s')", st->id, st->name);
+
+ if(st->rrd_memory_mode == RRD_MEMORY_MODE_SAVE) {
+ debug(D_RRD_STATS, "Saving stats '%s' to '%s'.", st->name, st->cache_filename);
+ savememory(st->cache_filename, st, st->memsize);
+ }
+
+ rrddim_foreach_read(rd, st) {
+ if(likely(rd->rrd_memory_mode == RRD_MEMORY_MODE_SAVE)) {
+ debug(D_RRD_STATS, "Saving dimension '%s' to '%s'.", rd->name, rd->cache_filename);
+ savememory(rd->cache_filename, rd, rd->memsize);
+ }
+ }
+}
+
+void rrdset_delete(RRDSET *st) {
+ RRDDIM *rd;
+
+ rrdset_check_rdlock(st);
+
+ // info("Deleting chart '%s' ('%s')", st->id, st->name);
+
+ if(st->rrd_memory_mode == RRD_MEMORY_MODE_SAVE) {
+ debug(D_RRD_STATS, "Deleting stats '%s' to '%s'.", st->name, st->cache_filename);
+ unlink(st->cache_filename);
+ }
+
+ rrddim_foreach_read(rd, st) {
+ if(likely(rd->rrd_memory_mode == RRD_MEMORY_MODE_SAVE)) {
+ debug(D_RRD_STATS, "Deleting dimension '%s' to '%s'.", rd->name, rd->cache_filename);
+ unlink(rd->cache_filename);
+ }
+ }
+}
+
// ----------------------------------------------------------------------------
// RRDSET - create a chart
-RRDSET *rrdset_create(RRDHOST *host, const char *type, const char *id, const char *name, const char *family
- , const char *context, const char *title, const char *units, long priority
- , int update_every, RRDSET_TYPE chart_type) {
-
+RRDSET *rrdset_create(
+ RRDHOST *host
+ , const char *type
+ , const char *id
+ , const char *name
+ , const char *family
+ , const char *context
+ , const char *title
+ , const char *units
+ , long priority
+ , int update_every
+ , RRDSET_TYPE chart_type
+) {
if(!type || !type[0]) {
fatal("Cannot create rrd stats without a type.");
return NULL;
RRDSET *st = rrdset_find(host, fullid);
if(st) {
+ rrdset_flag_clear(st, RRDSET_FLAG_OBSOLETE);
debug(D_RRD_CALLS, "RRDSET '%s', already exists.", fullid);
return st;
}
// get the options from the config, we need to create it
long rentries = config_get_number(config_section, "history", host->rrd_history_entries);
- long entries = align_entries_to_pagesize(rentries);
+ long entries = align_entries_to_pagesize(host->rrd_memory_mode, rentries);
if(entries != rentries) entries = config_set_number(config_section, "history", entries);
+ if(host->rrd_memory_mode == RRD_MEMORY_MODE_NONE && entries != rentries)
+ entries = config_set_number(config_section, "history", 10);
+
int enabled = config_get_boolean(config_section, "enabled", 1);
if(!enabled) entries = 5;
debug(D_RRD_CALLS, "Creating RRD_STATS for '%s.%s'.", type, id);
snprintfz(fullfilename, FILENAME_MAX, "%s/main.db", cache_dir);
- if(host->rrd_memory_mode != RRD_MEMORY_MODE_RAM) {
+ if(host->rrd_memory_mode == RRD_MEMORY_MODE_SAVE || host->rrd_memory_mode == RRD_MEMORY_MODE_MAP) {
st = (RRDSET *) mymmap(fullfilename, size, ((host->rrd_memory_mode == RRD_MEMORY_MODE_MAP) ? MAP_SHARED : MAP_PRIVATE), 0);
if(st) {
memset(&st->avl, 0, sizeof(avl));
// make sure the database is aligned
if(st->last_updated.tv_sec)
- timeval_align(&st->last_updated, update_every);
+ last_updated_time_align(&st->last_updated, update_every);
+
// make sure we have the right memory mode
// even if we cleared the memory
if(unlikely(!st)) {
st = callocz(1, size);
- st->rrd_memory_mode = RRD_MEMORY_MODE_RAM;
+ st->rrd_memory_mode = (host->rrd_memory_mode == RRD_MEMORY_MODE_NONE) ? RRD_MEMORY_MODE_NONE : RRD_MEMORY_MODE_RAM;
}
st->config_section = strdup(config_section);
rrdset_flag_clear(st, RRDSET_FLAG_DETAIL);
rrdset_flag_clear(st, RRDSET_FLAG_DEBUG);
+ rrdset_flag_clear(st, RRDSET_FLAG_OBSOLETE);
// if(!strcmp(st->id, "disk_util.dm-0")) {
// st->debug = 1;
rrdsetcalc_link_matching(st);
rrdcalctemplate_link_matching(st);
+ rrdhost_cleanup_obsolete(host);
+
rrdhost_unlock(host);
return(st);
if(unlikely(since_last_usec < 0)) {
// oops! the database is in the future
- error("Database for chart '%s' on host '%s' is %lld microseconds in the future.", st->id, st->rrdhost->hostname, -since_last_usec);
- memcpy(&st->last_collected_time, &now, sizeof(struct timeval));
- st->last_collected_time.tv_sec -= st->update_every;
+ error("Database for chart '%s' on host '%s' is %lld microseconds in the future. Adjusting it to current time.", st->id, st->rrdhost->hostname, -since_last_usec);
- memcpy(&st->last_updated, &now, sizeof(struct timeval));
- timeval_align(&st->last_updated, st->update_every);
- st->last_updated.tv_sec -= st->update_every;
+ st->last_collected_time.tv_sec = now.tv_sec - st->update_every;
+ st->last_collected_time.tv_usec = now.tv_usec;
+ last_collected_time_align(&st->last_collected_time, st->update_every);
- microseconds = st->update_every * USEC_PER_SEC;
+ st->last_updated.tv_sec = now.tv_sec - st->update_every;
+ st->last_updated.tv_usec = now.tv_usec;
+ last_updated_time_align(&st->last_updated, st->update_every);
+
+ microseconds = st->update_every * USEC_PER_SEC;
since_last_usec = st->update_every * USEC_PER_SEC;
}
static inline void rrdset_init_last_collected_time(RRDSET *st) {
now_realtime_timeval(&st->last_collected_time);
- timeval_align(&st->last_collected_time, st->update_every);
+ last_collected_time_align(&st->last_collected_time, st->update_every);
}
static inline usec_t rrdset_update_last_collected_time(RRDSET *st) {
static inline void rrdset_init_last_updated_time(RRDSET *st) {
// copy the last collected time to last updated time
- memcpy(&st->last_updated, &st->last_collected_time, sizeof(struct timeval));
- timeval_align(&st->last_updated, st->update_every);
- st->last_updated.tv_usec = 0;
+ st->last_updated.tv_sec = st->last_collected_time.tv_sec;
+ st->last_updated.tv_usec = st->last_collected_time.tv_usec;
+ last_updated_time_align(&st->last_updated, st->update_every);
}
-static inline void rrdset_done_push_int(RRDSET *st) {
+static inline void rrdset_done_push_exclusive(RRDSET *st) {
if(unlikely(!st->last_collected_time.tv_sec)) {
// it is the first entry
// set the last_collected_time to now
rrdset_update_last_collected_time(st);
}
- st->counter++;
st->counter_done++;
+ rrdset_rdlock(st);
rrdset_done_push(st);
+ rrdset_unlock(st);
}
void rrdset_done(RRDSET *st) {
if(unlikely(netdata_exit)) return;
- if(unlikely(rrdpush_exclusive)) {
- rrdset_done_push_int(st);
+ if(unlikely(st->rrd_memory_mode == RRD_MEMORY_MODE_NONE)) {
+ if(unlikely(st->rrdhost->rrdpush_enabled))
+ rrdset_done_push_exclusive(st);
+
return;
}
st->enabled = 1;
*/
+ if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_OBSOLETE))) {
+ error("Chart '%s' has the OBSOLETE flag set, but it is collected.", st->id);
+ rrdset_flag_clear(st, RRDSET_FLAG_OBSOLETE);
+ }
+
// check if the chart has a long time to be updated
if(unlikely(st->usec_since_last_update > st->entries * update_every_ut)) {
info("%s: took too long to be updated (%0.3Lf secs). Resetting it.", st->name, (long double)(st->usec_since_last_update / 1000000.0));
}
st->counter_done++;
+ if(unlikely(st->rrdhost->rrdpush_enabled))
+ rrdset_done_push(st);
+
// calculate totals and count the dimensions
int dimensions = 0;
st->collected_total = 0;
rrddim_foreach_read(rd, st) {
dimensions++;
- if(likely(rrddim_flag_check(rd, RRDDIM_FLAG_UPDATED)))
+ if(likely(rd->updated))
st->collected_total += rd->collected_value;
}
// at this stage we do not interpolate anything
rrddim_foreach_read(rd, st) {
- if(unlikely(!rrddim_flag_check(rd, RRDDIM_FLAG_UPDATED))) {
+ if(unlikely(!rd->updated)) {
rd->calculated_value = 0;
continue;
}
break;
case RRD_ALGORITHM_INCREMENTAL:
- if(unlikely(rd->counter <= 1)) {
+ if(unlikely(rd->collections_counter <= 1)) {
rd->calculated_value = 0;
continue;
}
break;
case RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL:
- if(unlikely(rd->counter <= 1)) {
+ if(unlikely(rd->collections_counter <= 1)) {
rd->calculated_value = 0;
continue;
}
continue;
}
- if(likely(rrddim_flag_check(rd, RRDDIM_FLAG_UPDATED) && rd->counter > 1 && iterations < st->gap_when_lost_iterations_above)) {
+ if(likely(rd->updated && rd->collections_counter > 1 && iterations < st->gap_when_lost_iterations_above)) {
rd->values[st->current_entry] = pack_storage_number(new_value, storage_flags );
rd->last_stored_value = new_value;
st->last_collected_total = st->collected_total;
rrddim_foreach_read(rd, st) {
- if(unlikely(!rrddim_flag_check(rd, RRDDIM_FLAG_UPDATED)))
+ if(unlikely(!rd->updated))
continue;
if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
rd->calculated_value = 0;
rd->collected_value = 0;
- rrddim_flag_clear(rd, RRDDIM_FLAG_UPDATED);
+ rd->updated = 0;
if(unlikely(rrdset_flag_check(st, RRDSET_FLAG_DEBUG)))
debug(D_RRD_STATS, "%s/%s: END "
if(unlikely(pthread_setcancelstate(pthreadoldcancelstate, NULL) != 0))
error("Cannot set pthread cancel state to RESTORE (%d).", pthreadoldcancelstate);
-
- if(unlikely(rrdpush_enabled))
- rrdset_done_push_int(st);
}
-