#include "parser.h"
#include "debug.h"
#include "string.h"
+#include "utils.h"
#define MAX_ARGS 512
#define ARGSTR_LEN 32768
pr_info("Drawing image %s\n", image->image_filename);
tmpfile[0] = 0;
- strncat(tmpfile, image->image_filename, sizeof(tmp) - 1);
- strncat(tmpfile, ".tmp", sizeof(tmp) - 1);
+ tmp[0] = 0;
+ strncpy(tmpfile, image->image_filename, sizeof(tmpfile) - 1);
+ _strlcat(tmpfile, ".tmp", sizeof(tmpfile));
if (image->updatestr)
updatestr = image->updatestr;
return entries;
}
-static int write_to_logfile(struct rrd_database *rrd, const char *data)
+static int write_to_logfile(struct rrd_database *rrd, const char *data, time_t now)
{
- time_t t = time(NULL);
int fd, ret;
int spacing, i;
char filename[1024];
if (rrd->logfile_timestamp_fmt)
time_stamp_fmt = rrd->logfile_timestamp_fmt;
- strftime(filename, sizeof(filename), rrd->logfile, localtime(&t));
+ strftime(filename, sizeof(filename), rrd->logfile, localtime(&now));
fd = open(filename, O_RDWR | O_APPEND | O_CREAT | O_CLOEXEC, 0644);
if (fd < 0) {
return -1;
}
- strftime(logstr, sizeof(logstr), time_stamp_fmt, localtime(&t));
+ strftime(logstr, sizeof(logstr), time_stamp_fmt, localtime(&now));
str_ptr = logstr + strlen(logstr);
- data += 2; /* Skip the "N: part */
+ /* Skip the "N: part */
+ while (*data != ':')
+ data++;
+ data++;
+
spacing = 12;
while (*data && str_ptr - logstr < sizeof(logstr) - 1) {
return 0;
}
+static int rrdtool_update_data_multi(struct rrd_database *rrd)
+{
+ char **data = NULL;
+ int ret, i, d;
+ char cmd[] = RRDTOOL_CMD;
+ char *cmdline[512] = {
+ RRDTOOL_CMD,
+ "update",
+ (char *const)rrd->filename,
+ };
+ int old_last_update = rrd->last_update;
+ time_t now = time(NULL);
+
+ ret = rrd->parser->parse_multi(&data, rrd->parser_data,
+ &rrd->parser_state, rrd->last_update);
+ if (ret < 0) {
+ pr_err("Parser failure: %d\n", ret);
+ goto out;
+ }
+
+ for (i = 3, d = 0; i < ARRAY_SIZE(cmdline) - 1; d++) {
+ time_t then;
+
+ if (!data[d])
+ break;
+
+ sanitize_rrd_update_data(data[d]);
+
+ then = atoi(data[d]);
+ if (then > now) {
+ pr_err("Skipping bad data with timestamp in future: %ld > %ld\n",
+ then, now);
+ continue;
+ }
+ write_to_logfile(rrd, data[d], then);
+ cmdline[i] = data[d];
+ pr_info("Data: %s\n", data[d]);
+
+ rrd->last_update = then;
+ i++;
+ }
+
+ cmdline[i] = 0;
+
+ if (ret)
+ run(cmd, cmdline);
+
+out:
+ if (data)
+ for (d = 0; data[d]; d++)
+ free(data[d]);
+ free(data);
+
+ if (old_last_update == rrd->last_update) {
+ rrd->update_backoff = time(NULL) + 10;
+ pr_info("Setting backoff\n");
+ } else
+ rrd->update_backoff = 0;
+
+ /*
+ * Re-schedule job processing in case we are too far behind
+ * with updates on this database and can start parsing more
+ * data immediately.
+ */
+ notify_job_request();
+
+ return 0;
+}
+
static int do_rrdtool_update_data(struct rrd_database *rrd)
{
- char data[RRD_DATA_MAX_LEN + 3]; /* 3 == "N:" + NULL termination */
+ char data[RRD_DATA_MAX_LEN + 12]; /* 12 == "%s:" + NULL termination */
char cmd[] = RRDTOOL_CMD;
// char cmd[] = "echo";
char *const cmdline[] = {
0
};
int l;
+ time_t now = time(NULL);
bzero(data, sizeof(data));
- l = sprintf(data, "N:");
+ l = sprintf(data, "%zd:", now);
- if (rrd->parser && rrd->parser->parse) {
- rrd->parser->parse(data + l, rrd->parser_data);
- data[RRD_DATA_MAX_LEN + 2] = '\0';
+ if (rrd->parser && rrd->parser->parse_multi) {
+ rrdtool_update_data_multi(rrd);
+ } else if (rrd->parser && rrd->parser->parse) {
+ rrd->parser->parse(data + l, rrd->parser_data,
+ &rrd->parser_state);
+ data[RRD_DATA_MAX_LEN + l] = '\0';
pr_info("Data: %s\n", data);
sanitize_rrd_update_data(data + l);
- write_to_logfile(rrd, data);
+ write_to_logfile(rrd, data, now);
run(cmd, cmdline);
- }
+ rrd->last_update = now;
+ } else
+ rrd->last_update = now;
if (rrd->pre_draw_cmd && !strcmp(rrd->pre_draw_cmd[0], "shell")) {
run(rrd->pre_draw_cmd[1], &rrd->pre_draw_cmd[1]);
queue_work(WORK_PRIORITY_LOW, "rrdtool_post_draw_cmd",
(work_fn_t *)run_post_draw_cmd, rrd);
+ rrd->update_active = 0;
+
return 0;
}
int rrdtool_update_data(struct rrd_database *rrd)
{
- rrd->last_update = time(0);
+ rrd->update_active = 1;
return queue_work(WORK_PRIORITY_HIGH, "rrdtool_update_data",
(work_fn_t *)do_rrdtool_update_data, rrd);
struct rrd_database *get_outdated_db(struct rrd_database **dblist)
{
int i;
- time_t now = time(0);
+ time_t now = time(0), last;
for (i = 0; dblist[i]; i++) {
- if ((dblist[i]->last_update + dblist[i]->interval) - now <= 0)
+ last = max(ROUND_UP(dblist[i]->last_update, dblist[i]->interval),
+ dblist[i]->update_backoff);
+ if (!dblist[i]->update_active && last - now <= 0)
return dblist[i];
}
}
/*
- * See how long we may sleep until it is required to run an update
- * again
+ * See how long we may sleep until next update interval window begins
*/
int get_next_update(struct rrd_database **dblist, const char **name)
{
- int i, sleeptime = 0, diff;
+ int i, sleeptime = -1, diff;
time_t now = time(0);
for (i = 0; dblist[i]; i++) {
- diff = dblist[i]->last_update + dblist[i]->interval - now;
- if (!sleeptime) {
- sleeptime = diff;
- *name = dblist[i]->name;
- }
- if (sleeptime > diff) {
+ if (dblist[i]->update_active)
+ continue;
+
+ diff = ROUND_UP(dblist[i]->last_update, dblist[i]->interval) - now;
+ diff = max(diff, dblist[i]->update_backoff - now);
+
+ if (sleeptime == -1 || sleeptime > diff) {
sleeptime = diff;
*name = dblist[i]->name;
}
- if (sleeptime <= 0)
- return 0;
}
return sleeptime;
return 0;
}
+static int get_last_update(struct rrd_database *db)
+{
+ char cmd[] = RRDTOOL_CMD;
+ char *args[10], argstr[ARGSTR_LEN];
+ char buf[16];
+ int idx = 0, argcnt = 0;
+ int ofd, child;
+ int ret;
+
+ add_arg(args, argcnt, argstr, idx, RRDTOOL_CMD);
+ add_arg(args, argcnt, argstr, idx, "last");
+ add_arg(args, argcnt, argstr, idx, db->filename);
+
+ child = run_piped(cmd, args, NULL, &ofd, NULL);
+ ret = read(ofd, buf, sizeof(buf) - 1);
+ if (ret < 0) {
+ pr_err("Error reading: %m\n");
+ buf[0] = 0;
+ } else {
+ buf[ret] = 0;
+ }
+
+ db->last_update = atoi(buf);
+ pr_info("Last update for %s is: %ld, %ld sec ago\n", db->name, db->last_update,
+ time(NULL) - db->last_update);
+
+ close(ofd);
+ clear_zombie(child);
+
+ return 0;
+}
+
static int create_database(struct rrd_database *db)
{
char cmd[] = RRDTOOL_CMD;
for (i = 0, db = dbs[i]; db; i++, db = dbs[i]) {
if (database_exists(db)) {
pr_info("database %s found\n", db->filename);
+ get_last_update(db);
continue;
}
pr_info("Database %s missing, creating\n", db->filename);