sdb_timeseries_t * sdb_timeseries_create(size_t data_names_len, const char * const *data_names, size_t data_len) { sdb_timeseries_t *ts; size_t i; ts = calloc(1, sizeof(*ts)); if (! ts) return NULL; if (stringv_copy(&ts->data_names, &ts->data_names_len, data_names, data_names_len)) { sdb_timeseries_destroy(ts); return NULL; } ts->data = calloc(data_names_len, sizeof(*ts->data)); if (! ts->data) { sdb_timeseries_destroy(ts); return NULL; } for (i = 0; i < data_names_len; ++i) { ts->data[i] = calloc(data_len, sizeof(**ts->data)); if (! ts->data[i]) { sdb_timeseries_destroy(ts); return NULL; } } ts->data_len = data_len; return ts; } /* sdb_timeseries_create */
static sdb_timeseries_t * sdb_rrd_fetch(const char *id, sdb_timeseries_opts_t *opts, sdb_object_t *user_data) { sdb_timeseries_t *ts; time_t start = (time_t)SDB_TIME_TO_SECS(opts->start); time_t end = (time_t)SDB_TIME_TO_SECS(opts->end); unsigned long step = 0; unsigned long ds_cnt = 0; unsigned long val_cnt = 0; char **ds_namv = NULL; rrd_value_t *data = NULL; if (user_data) { /* -> use RRDCacheD */ char *addr = SDB_OBJ_WRAPPER(user_data)->data; if (! rrdcached_connect(addr)) return NULL; #ifdef HAVE_RRD_CLIENT_H if (rrdc_flush(id)) { sdb_log(SDB_LOG_ERR, "Failed to flush '%s' through RRDCacheD: %s", id, rrd_get_error()); return NULL; } #endif } #define FREE_RRD_DATA() \ do { \ size_t i; \ for (i = 0; i < ds_cnt; ++i) \ rrd_freemem(ds_namv[i]); \ rrd_freemem(ds_namv); \ rrd_freemem(data); \ } while (0) /* limit to about 1000 data-points for now * TODO: make this configurable */ step = (end - start) / 1000; if (rrd_fetch_r(id, "AVERAGE", &start, &end, &step, &ds_cnt, &ds_namv, &data)) { char errbuf[1024]; sdb_strerror(errno, errbuf, sizeof(errbuf)); sdb_log(SDB_LOG_ERR, "Failed to fetch data from %s: %s", id, errbuf); return NULL; } val_cnt = (unsigned long)(end - start) / step; /* RRDtool does not support fetching specific data-sources, so we'll have * to filter the requested ones after fetching them all */ if (opts->data_names && opts->data_names_len) ts = sdb_timeseries_create(opts->data_names_len, (const char * const *)opts->data_names, val_cnt); else ts = sdb_timeseries_create(ds_cnt, (const char * const *)ds_namv, val_cnt); if (! ts) { char errbuf[1024]; sdb_strerror(errno, errbuf, sizeof(errbuf)); sdb_log(SDB_LOG_ERR, "Failed to allocate time-series object: %s", errbuf); FREE_RRD_DATA(); return NULL; } ts->start = SECS_TO_SDB_TIME(start + (time_t)step); ts->end = SECS_TO_SDB_TIME(end); if (copy_data(ts, data, (time_t)step, (size_t)ds_cnt, ds_namv) < 0) { FREE_RRD_DATA(); sdb_timeseries_destroy(ts); return NULL; } FREE_RRD_DATA(); return ts; } /* sdb_rrd_fetch */