+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
+
+void rrdset_free(RRDSET *st) {
+ if(unlikely(!st)) return;
+
+ rrdhost_check_wrlock(st->rrdhost); // make sure we have a write lock on the host
+ rrdset_wrlock(st); // lock this RRDSET
+
+ // info("Removing chart '%s' ('%s')", st->id, st->name);
+
+ // ------------------------------------------------------------------------
+ // remove it from the indexes
+
+ if(unlikely(rrdset_index_del(st->rrdhost, st) != st))
+ error("RRDSET: INTERNAL ERROR: attempt to remove from index chart '%s', removed a different chart.", st->id);
+
+ 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
+
+ if(st == st->rrdhost->rrdset_root) {
+ st->rrdhost->rrdset_root = st->next;
+ }
+ else {
+ // find the previous one
+ RRDSET *s;
+ for(s = st->rrdhost->rrdset_root; s && s->next != st ; s = s->next) ;
+
+ // bypass it
+ if(s) s->next = st->next;
+ else error("Request to free RRDSET '%s': cannot find it under host '%s'", st->id, st->rrdhost->hostname);
+ }
+
+ rrdset_unlock(st);
+
+ // ------------------------------------------------------------------------
+ // free it
+
+ netdata_rwlock_destroy(&st->rrdset_rwlock);
+
+ // free directly allocated members
+ freez(st->config_section);
+
+ if(st->rrd_memory_mode == RRD_MEMORY_MODE_SAVE || st->rrd_memory_mode == RRD_MEMORY_MODE_MAP) {
+ debug(D_RRD_CALLS, "Unmapping stats '%s'.", st->name);
+ munmap(st, st->memsize);
+ }
+ else
+ 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);
+ }
+ }
+}
+