From: Peter A. Bigot Date: Fri, 16 May 2014 15:52:49 +0000 (-0500) Subject: rrd_scaled_duration: refactor as utility function X-Git-Tag: v1.5.0-rc1~96^2~2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=c7d54fbd7e1aa87274dba5b01a6271aaa1e4aa64;p=thirdparty%2Frrdtool-1.x.git rrd_scaled_duration: refactor as utility function Move the infrastructure supporting expression of counts and durations by suffixed integers into librrd where it can be used by other programs. Clean up the documentation to remove redundancies. Signed-off-by: Peter A. Bigot --- diff --git a/doc/librrd.pod b/doc/librrd.pod index 0d05f6ee..c443386a 100644 --- a/doc/librrd.pod +++ b/doc/librrd.pod @@ -149,6 +149,81 @@ already exists and is a directory. =back +=item B + +Parse a token in a context where it contains a count (of seconds or +PDP instances), or a duration that can be converted to a count by +representing the duration in seconds and dividing by some scaling +factor. For example, if a user would natively express a 3 day archive +of samples collected every 2 minutes, the sample interval can be +represented by C<2m> instead of C<120>, and the archive duration by +C<3d> (to be divided by 120) instead of C<2160> (3*24*60*60 / 120). +See more examples in L. + +C must be a number with an optional single-character suffix +encoding the scaling factor: + +=over 4 + +=item C + +indicates seconds + +=item C + +indicates minutes. The value is multipled by 60. + +=item C + +indicates hours. The value is multipled by 3600 (or C<60m>). + +=item C + +indicates days. The value is multipled by 86400 (or C<24h>). + +=item C + +indicates weeks. The value is multipled by 604800 (or C<7d>). + +=item C + +indicates months. The value is multipled by 2678400 (or C<31d>). +(Note this factor accommodates the maximum number of days in a month.) + +=item C + +indicates years. The value is multipled by 31622400 (or C<366d>). +(Note this factor accommodates leap years.) + +=back + +C is a positive value representing the duration in seconds of +an interval that the desired result counts. + +C is a pointer to where the decoded value will be stored if +the conversion is successful. + +The initial characters of C must be the base-10 representation +of a positive integer, or the conversion fails. + +If the remainder C is empty (no suffix), it is a count and no +scaling is performed. + +If C has one of the suffixes above, the count is multipled to +convert it to a duration in seconds. The resulting number of seconds +is divided by C to produce a count of intervals each of +duration C seconds. If division would produce a remainder +(e.g., C<5m> (300 seconds) divided by C<90s>), the conversion is +invalid. + +If C has unrecognized trailing characters the conversion fails. + +The function returns a null pointer if the conversion was successful +and C has been updated to the scaled value. On failure, it +returns a text diagnostic suitable for use in user error messages. + += back + =head1 AUTHOR RRD Contributors diff --git a/doc/rrdcreate.pod b/doc/rrdcreate.pod index 43a8c6e3..dc3367a8 100644 --- a/doc/rrdcreate.pod +++ b/doc/rrdcreate.pod @@ -423,47 +423,14 @@ one day averages. Step, heartbeat, and PDP counts and rows may also be specified as durations, which are positive integers with a single-character suffix -that specifies a scaling factor: - -=over - -=item C - -indicates seconds - -=item C - -indicates minutes. The value is multipled by 60. - -=item C - -indicates hours. The value is multipled by 3600 (or C<60m>). - -=item C - -indicates days. The value is multipled by 86400 (or C<24h>). - -=item C - -indicates weeks. The value is multipled by 604800 (or C<7d>). - -=item C - -indicates months. The value is multipled by 2678400 (or C<31d>). -(Note this factor accommodates the maximum number of days in a month.) - -=item C - -indicates years. The value is multipled by 31622400 (or C<366d>). -(Note this factor accommodates leap years.) - -=back +that specifies a scaling factor. See L +for scale factors of the supported suffixes: C (seconds), C +(minutes), C (hours), C (days), C (weeks), C (months), and +C (years). Scaled step and heartbeat values (which are natively durations in seconds) are used directly, while consolidation function row arguments -are divided by their step to produce the number of rows. Note that -the multiplication factors for months and years correspond to the -maximum number of days in a month or year. +are divided by their step to produce the number of rows. With this feature the same specification as above can be written as: diff --git a/src/rrd.h b/src/rrd.h index 0a1319bd..bf6c8895 100644 --- a/src/rrd.h +++ b/src/rrd.h @@ -384,6 +384,10 @@ int rrd_proc_start_end( int rrd_mkdir_p(const char *pathname, mode_t mode); + const char * rrd_scaled_duration (const char * token, + unsigned long divisor, + unsigned long * valuep); + /* * The following functions are _internal_ functions needed to read the raw RRD * files. Since they are _internal_ they may change with the file format and diff --git a/src/rrd_create.c b/src/rrd_create.c index 16f1658c..bfc99380 100644 --- a/src/rrd_create.c +++ b/src/rrd_create.c @@ -28,56 +28,6 @@ void parseGENERIC_DS( const char *def, ds_def_t *ds_def); -static const char * convert_to_count (const char * token, - unsigned long * valuep, - unsigned long divisor) -{ - char * ep = NULL; - unsigned long int value = strtoul(token, &ep, 10); - /* account for -1 => UMAXLONG which is not what we want */ - if (! isdigit(token[0])) - return "value must be (suffixed) positive number"; - /* Catch an internal error before we inhibit scaling */ - if (0 == divisor) - return "INTERNAL ERROR: Zero divisor"; - switch (*ep) { - case 0: /* count only, inhibit scaling */ - divisor = 0; - break; - case 's': /* seconds */ - break; - case 'm': /* minutes */ - value *= 60; - break; - case 'h': /* hours */ - value *= 60 * 60; - break; - case 'd': /* days */ - value *= 24 * 60 * 60; - break; - case 'w': /* weeks */ - value *= 7 * 24 * 60 * 60; - break; - case 'M': /* months */ - value *= 31 * 24 * 60 * 60; - break; - case 'y': /* years */ - value *= 366 * 24 * 60 * 60; - break; - default: /* trailing garbage */ - return "value has trailing garbage"; - } - if (0 == value) - return "value must be positive"; - if ((0 != divisor) && (0 != value)) { - if (0 != (value % divisor)) - return "value would truncate when scaled"; - value /= divisor; - } - *valuep = value; - return NULL; -} - int rrd_create( int argc, char **argv) @@ -142,7 +92,7 @@ int rrd_create( break; case 's': - if ((parsetime_error = convert_to_count(optarg, &pdp_step, 1))) { + if ((parsetime_error = rrd_scaled_duration(optarg, 1, &pdp_step))) { rrd_set_error("step size: %s", parsetime_error); return (-1); } @@ -311,7 +261,7 @@ int parseRRA(const char *def, case CF_SEASONAL: case CF_DEVPREDICT: case CF_FAILURES: - if ((parsetime_error = convert_to_count(token, &rra_def->row_cnt, rrd->stat_head->pdp_step))) + if ((parsetime_error = rrd_scaled_duration(token, rrd->stat_head->pdp_step, &rra_def->row_cnt))) rrd_set_error("Invalid row count %s: %s", token, parsetime_error); break; default: @@ -359,7 +309,7 @@ int parseRRA(const char *def, atoi(token) - 1; break; default: - if ((parsetime_error = convert_to_count(token, &rra_def->pdp_cnt, rrd->stat_head->pdp_step))) + if ((parsetime_error = rrd_scaled_duration(token, rrd->stat_head->pdp_step, &rra_def->pdp_cnt))) rrd_set_error("Invalid step %s: %s", token, parsetime_error); break; } @@ -401,8 +351,9 @@ int parseRRA(const char *def, ("Unexpected extra argument for consolidation function DEVPREDICT"); break; default: - if ((parsetime_error = convert_to_count(token, &rra_def->row_cnt, - rrd->stat_head->pdp_step * rra_def->pdp_cnt))) + if ((parsetime_error = rrd_scaled_duration(token, + rrd->stat_head->pdp_step * rra_def->pdp_cnt, + &rra_def->row_cnt))) rrd_set_error("Invalid row count %s: %s", token, parsetime_error); #if SIZEOF_TIME_T == 4 if ((long long) pdp_step * rra_def->pdp_cnt * row_cnt > 4294967296LL){ @@ -708,7 +659,7 @@ void parseGENERIC_DS( strncpy (numbuf, def, heartbeat_len); numbuf[heartbeat_len] = 0; - if ((parsetime_error = convert_to_count(numbuf, &(ds_def->par[DS_mrhb_cnt].u_cnt), 1))) + if ((parsetime_error = rrd_scaled_duration(numbuf, 1, &(ds_def->par[DS_mrhb_cnt].u_cnt)))) break; if (sscanf(1+colonp, "%18[^:]:%18[^:]", diff --git a/src/rrd_utils.c b/src/rrd_utils.c index bab9ec8f..0ff25f1f 100644 --- a/src/rrd_utils.c +++ b/src/rrd_utils.c @@ -213,3 +213,53 @@ int rrd_mkdir_p(const char *pathname, mode_t mode) return 0; } /* rrd_mkdir_p */ +const char * rrd_scaled_duration (const char * token, + unsigned long divisor, + unsigned long * valuep) +{ + char * ep = NULL; + unsigned long int value = strtoul(token, &ep, 10); + /* account for -1 => UMAXLONG which is not what we want */ + if (! isdigit(token[0])) + return "value must be (suffixed) positive number"; + /* Catch an internal error before we inhibit scaling */ + if (0 == divisor) + return "INTERNAL ERROR: Zero divisor"; + switch (*ep) { + case 0: /* count only, inhibit scaling */ + divisor = 0; + break; + case 's': /* seconds */ + break; + case 'm': /* minutes */ + value *= 60; + break; + case 'h': /* hours */ + value *= 60 * 60; + break; + case 'd': /* days */ + value *= 24 * 60 * 60; + break; + case 'w': /* weeks */ + value *= 7 * 24 * 60 * 60; + break; + case 'M': /* months */ + value *= 31 * 24 * 60 * 60; + break; + case 'y': /* years */ + value *= 366 * 24 * 60 * 60; + break; + default: /* trailing garbage */ + return "value has trailing garbage"; + } + if (0 == value) + return "value must be positive"; + if ((0 != divisor) && (0 != value)) { + if (0 != (value % divisor)) + return "value would truncate when scaled"; + value /= divisor; + } + *valuep = value; + return NULL; +} +