[rrd-developers] [PATCH] rrdcached ensures time marches forward
kevin brintnall
kbrint at rufus.net
Fri Oct 10 22:11:37 CEST 2008
This patch introduces a feature whereby rrdcached will disallow updates
that do not advance the update time. This prevents the updates from being
discarded later by rrd_update_r.
This patch attempts to make the most of the protocol's limited ability to
return error text when using a -1 return code.
---
diff --git a/doc/rrdcached.pod b/doc/rrdcached.pod
index fd56523..4d079a9 100644
--- a/doc/rrdcached.pod
+++ b/doc/rrdcached.pod
@@ -409,6 +409,10 @@ Adds more data to a filename. This is B<the> operation the daemon was designed
for, so describing the mechanism again is unnecessary. Read L<HOW IT WORKS>
above for a detailed explanation.
+Note that rrdcached only accepts absolute timestamps in the update values.
+Updates strings like "N:1:2:3" are automatically converted to absolute
+time by the RRD client library before sending to rrdcached.
+
=item B<WROTE> I<filename>
This command is written to the journal after a file is successfully
@@ -434,8 +438,8 @@ message itself. The first user command after B<BATCH> is command number one.
client: BATCH
server: 0 Go ahead. End with dot '.' on its own line.
- client: UPDATE x.rrd N:1:2:3 <--- command #1
- client: UPDATE y.rrd N:3:4:5 <--- command #2
+ client: UPDATE x.rrd 1223661439:1:2:3 <--- command #1
+ client: UPDATE y.rrd 1223661440:3:4:5 <--- command #2
client: and so on...
client: .
server: 2 Errors
@@ -469,10 +473,11 @@ daemon was started.
=item B<DataSetsWritten> I<(unsigned 64bit integer)>
-Total number of "data sets" written to disk since the daemon was started. A
-data set is one or more values passed to the B<UPDATE> command. For example:
-C<N:123:456> is one data set with two values. The term "data set" is used to
-prevent confusion whether individual values or groups of values are counted.
+Total number of "data sets" written to disk since the daemon was
+started. A data set is one or more values passed to the B<UPDATE>
+command. For example: C<1223661439:123:456> is one data set with two
+values. The term "data set" is used to prevent confusion whether
+individual values or groups of values are counted.
=item B<TreeNodesNumber> I<(unsigned 64bit integer)>
diff --git a/src/rrd_daemon.c b/src/rrd_daemon.c
index 5e774cb..3e92530 100644
--- a/src/rrd_daemon.c
+++ b/src/rrd_daemon.c
@@ -138,6 +138,7 @@ struct cache_item_s
char **values;
int values_num;
time_t last_flush_time;
+ time_t last_update_stamp;
#define CI_FLAGS_IN_TREE (1<<0)
#define CI_FLAGS_IN_QUEUE (1<<1)
int flags;
@@ -1311,6 +1312,7 @@ static int handle_request_update (listen_socket_t *sock, /* {{{ */
{
char *file;
int values_num = 0;
+ int bad_timestamps = 0;
int status;
char orig_buf[CMD_MAX];
@@ -1401,6 +1403,8 @@ static int handle_request_update (listen_socket_t *sock, /* {{{ */
{
char **temp;
char *value;
+ time_t stamp;
+ char *eostamp;
status = buffer_get_field (&buffer, &buffer_size, &value);
if (status != 0)
@@ -1409,6 +1413,26 @@ static int handle_request_update (listen_socket_t *sock, /* {{{ */
break;
}
+ /* make sure update time is always moving forward */
+ stamp = strtol(value, &eostamp, 10);
+ if (eostamp == value || eostamp == NULL || *eostamp != ':')
+ {
+ ++bad_timestamps;
+ add_response_info(sock, "Cannot find timestamp in '%s'!\n", value);
+ continue;
+ }
+ else if (stamp <= ci->last_update_stamp)
+ {
+ ++bad_timestamps;
+ add_response_info(sock,
+ "illegal attempt to update using time %ld when"
+ " last update time is %ld (minimum one second step)\n",
+ stamp, ci->last_update_stamp);
+ continue;
+ }
+ else
+ ci->last_update_stamp = stamp;
+
temp = (char **) realloc (ci->values,
sizeof (char *) * (ci->values_num + 1));
if (temp == NULL)
@@ -1439,9 +1463,21 @@ static int handle_request_update (listen_socket_t *sock, /* {{{ */
pthread_mutex_unlock (&cache_lock);
if (values_num < 1)
- return send_response(sock, RESP_ERR, "No values updated.\n");
+ {
+ /* if we had only one update attempt, then return the full
+ error message... try to get the most information out
+ of the limited error space allowed by the protocol
+ */
+ if (bad_timestamps == 1)
+ return send_response(sock, RESP_ERR, "%s", sock->wbuf);
+ else
+ return send_response(sock, RESP_ERR,
+ "No values updated (%d bad timestamps).\n",
+ bad_timestamps);
+ }
else
- return send_response(sock, RESP_OK, "Enqueued %i value(s).\n", values_num);
+ return send_response(sock, RESP_OK,
+ "errors, enqueued %i value(s).\n", values_num);
/* NOTREACHED */
assert(1==0);
More information about the rrd-developers
mailing list