From: oetiker Date: Sat, 11 Oct 2008 09:37:53 +0000 (+0000) Subject: This patch introduces a feature whereby rrdcached will disallow updates X-Git-Url: https://git.octo.it/?p=rrdtool.git;a=commitdiff_plain;h=22129bb15a8ad204cf8a5e88e8834ec0b51908c0 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. -- kevin brintnall git-svn-id: svn://svn.oetiker.ch/rrdtool/trunk/program@1596 a5681a0c-68f1-0310-ab6d-d61299d08faa --- 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 operation the daemon was designed for, so describing the mechanism again is unnecessary. Read L 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 I This command is written to the journal after a file is successfully @@ -434,8 +438,8 @@ message itself. The first user command after B 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 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 command. For example: -C 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 +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 I<(unsigned 64bit integer)> diff --git a/src/rrd_daemon.c b/src/rrd_daemon.c index 36d418b..b2cee95 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);