]> git.itanic.dy.fi Git - rrdd/blobdiff - rrdtool.c
onewire_parser.c: Fix compiler warnings about string lengths
[rrdd] / rrdtool.c
index 9fed184cce5e649c6072973b417e3c24da4a594f..f570f5c981d77cbfafac03acdda50eec5c44a206 100644 (file)
--- a/rrdtool.c
+++ b/rrdtool.c
@@ -11,6 +11,7 @@
 #include "parser.h"
 #include "debug.h"
 #include "string.h"
+#include "utils.h"
 
 #define MAX_ARGS       512
 #define ARGSTR_LEN     32768
@@ -34,7 +35,6 @@
 
 int rrdtool_draw_image(struct rrd_image *image)
 {
-       int pid;
        char cmd[] = RRDTOOL_CMD;
 //     char cmd[] = "echo";
        char *args[512], argstr[ARGSTR_LEN];
@@ -48,8 +48,9 @@ int rrdtool_draw_image(struct rrd_image *image)
        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;
@@ -103,7 +104,7 @@ int rrdtool_draw_images(struct rrd_image **image)
        int i;
        for (i = 0; image[i]; i++)
                queue_work(WORK_PRIORITY_LOW, "rrdtool_draw_image",
-                       rrdtool_draw_image, image[i]);
+                       (work_fn_t *)rrdtool_draw_image, image[i]);
 
        return 0;
 }
@@ -195,9 +196,8 @@ static int sanitize_rrd_update_data(char *data)
        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];
@@ -211,7 +211,7 @@ static int write_to_logfile(struct rrd_database *rrd, const char *data)
        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) {
@@ -219,11 +219,15 @@ static int write_to_logfile(struct rrd_database *rrd, const char *data)
                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) {
@@ -251,10 +255,88 @@ static int write_to_logfile(struct rrd_database *rrd, const char *data)
        return ret < 0 ? ret : 0;
 }
 
+static int run_post_draw_cmd(struct rrd_database *rrd)
+{
+       pr_info("Running post draw command for %s\n", rrd->name);
+
+       if (rrd->post_draw_cmd && !strcmp(rrd->post_draw_cmd[0], "shell"))
+               run(rrd->post_draw_cmd[1], &rrd->post_draw_cmd[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)
 {
-       int pid;
-       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[] = {
@@ -265,20 +347,27 @@ static int do_rrdtool_update_data(struct rrd_database *rrd)
                0
        };
        int l;
+       time_t now = time(NULL);
 
-       l = sprintf(data, "N:");
+       bzero(data, sizeof(data));
+       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]);
@@ -287,18 +376,30 @@ static int do_rrdtool_update_data(struct rrd_database *rrd)
        if (rrd->images)
                rrdtool_draw_images(rrd->images);
 
-       if (rrd->post_draw_cmd && !strcmp(rrd->post_draw_cmd[0], "shell"))
-               run(rrd->post_draw_cmd[1], &rrd->post_draw_cmd[1]);
+       /*
+        * We rely on the fact that rrdtool_draw_images queues image
+        * drawings into low priority queue and the post draw queue is
+        * placed on the queue after images. This ensures post draw
+        * command is not started before images are started.
+        *
+        * There is nothing that guarantees post_draw_cmd is executed
+        * after all images are completed though, but it's close..
+        */
+       if (rrd->post_draw_cmd)
+               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",
-                       do_rrdtool_update_data, rrd);
+                       (work_fn_t *)do_rrdtool_update_data, rrd);
 }
 
 /*
@@ -308,10 +409,12 @@ int rrdtool_update_data(struct rrd_database *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];
        }
 
@@ -320,26 +423,24 @@ struct rrd_database *get_outdated_db(struct rrd_database **dblist)
 }
 
 /*
- * 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;
@@ -356,6 +457,38 @@ static int database_exists(struct rrd_database *db)
        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;
@@ -411,6 +544,7 @@ int rrdtool_create_missing_databases(struct rrd_database *dbs[])
        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);