]> git.itanic.dy.fi Git - rrdd/blobdiff - rrdtool.c
rrdtool: Add support for multi parsers
[rrdd] / rrdtool.c
index d286963c66ea6c04616ad9b5151a9bd2c530eede..d1e85f4c1d398750ed25d81ad7ee15866f68ad85 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
@@ -265,6 +266,68 @@ static int run_post_draw_cmd(struct rrd_database *rrd)
        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;
+
+       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; i++, d++) {
+               time_t then;
+
+               if (!data[d])
+                       break;
+
+               sanitize_rrd_update_data(data[d]);
+
+               then = atoi(data[d]);
+               write_to_logfile(rrd, data[d], then);
+               cmdline[i] = data[d];
+               pr_info("Data: %s\n", data[d]);
+
+               rrd->last_update = then;
+       }
+
+       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 + 12]; /* 12 == "%s:" + NULL termination */
@@ -283,10 +346,12 @@ static int do_rrdtool_update_data(struct rrd_database *rrd)
        bzero(data, sizeof(data));
        l = sprintf(data, "%zd:", now);
 
-       if (rrd->parser && rrd->parser->parse) {
+       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 + 2] = '\0';
+               data[RRD_DATA_MAX_LEN + l] = '\0';
 
                pr_info("Data: %s\n", data);
 
@@ -294,7 +359,9 @@ static int do_rrdtool_update_data(struct rrd_database *rrd)
                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]);
@@ -316,18 +383,14 @@ static int do_rrdtool_update_data(struct rrd_database *rrd)
                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)
 {
-       time_t now = time(0);
-
-       /*
-        * This will put our last update slightly into past, but
-        * ensures our update interval will not drift over time.
-        */
-       rrd->last_update = now - now % rrd->interval;
+       rrd->update_active = 1;
 
        return queue_work(WORK_PRIORITY_HIGH, "rrdtool_update_data",
                        (work_fn_t *)do_rrdtool_update_data, rrd);
@@ -340,10 +403,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];
        }
 
@@ -352,8 +417,7 @@ 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)
 {
@@ -361,7 +425,12 @@ int get_next_update(struct rrd_database **dblist, const char **name)
        time_t now = time(0);
 
        for (i = 0; dblist[i]; i++) {
-               diff = dblist[i]->last_update + dblist[i]->interval - now;
+               diff = ROUND_UP(dblist[i]->last_update, dblist[i]->interval) - now;
+               diff = max(diff, dblist[i]->update_backoff - now);
+
+               if (dblist[i]->update_active)
+                       diff = (now + dblist[i]->interval) % dblist[i]->interval;
+
                if (!sleeptime) {
                        sleeptime = diff;
                        *name = dblist[i]->name;
@@ -370,10 +439,11 @@ int get_next_update(struct rrd_database **dblist, const char **name)
                        sleeptime = diff;
                        *name = dblist[i]->name;
                }
-               if (sleeptime <= 0)
-                       return 0;
        }
 
+       if (sleeptime == 0)
+               sleeptime = -1;
+
        return sleeptime;
 }
 
@@ -411,6 +481,8 @@ static int get_last_update(struct rrd_database *db)
        }
 
        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);
 
        clear_zombie(child);