=back
+=item B<rrd_scaled_duration (const char * token, unsigned long divisor, unsigned long * valuep)>
+
+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<rrdcreate/"STEP, HEARTBEAT, and Rows As Durations">.
+
+C<token> must be a number with an optional single-character suffix
+encoding the scaling factor:
+
+=over 4
+
+=item C<s>
+
+indicates seconds
+
+=item C<m>
+
+indicates minutes. The value is multipled by 60.
+
+=item C<h>
+
+indicates hours. The value is multipled by 3600 (or C<60m>).
+
+=item C<d>
+
+indicates days. The value is multipled by 86400 (or C<24h>).
+
+=item C<w>
+
+indicates weeks. The value is multipled by 604800 (or C<7d>).
+
+=item C<M>
+
+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<y>
+
+indicates years. The value is multipled by 31622400 (or C<366d>).
+(Note this factor accommodates leap years.)
+
+=back
+
+C<divisor> is a positive value representing the duration in seconds of
+an interval that the desired result counts.
+
+C<valuep> is a pointer to where the decoded value will be stored if
+the conversion is successful.
+
+The initial characters of C<token> must be the base-10 representation
+of a positive integer, or the conversion fails.
+
+If the remainder C<token> is empty (no suffix), it is a count and no
+scaling is performed.
+
+If C<token> 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<divisor> to produce a count of intervals each of
+duration C<divisor> seconds. If division would produce a remainder
+(e.g., C<5m> (300 seconds) divided by C<90s>), the conversion is
+invalid.
+
+If C<token> has unrecognized trailing characters the conversion fails.
+
+The function returns a null pointer if the conversion was successful
+and C<valuep> 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 <rrd-developers@lists.oetiker.ch>
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<s>
-
-indicates seconds
-
-=item C<m>
-
-indicates minutes. The value is multipled by 60.
-
-=item C<h>
-
-indicates hours. The value is multipled by 3600 (or C<60m>).
-
-=item C<d>
-
-indicates days. The value is multipled by 86400 (or C<24h>).
-
-=item C<w>
-
-indicates weeks. The value is multipled by 604800 (or C<7d>).
-
-=item C<M>
-
-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<y>
-
-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<librrd/rrd_scaled_duration>
+for scale factors of the supported suffixes: C<s> (seconds), C<m>
+(minutes), C<h> (hours), C<d> (days), C<w> (weeks), C<M> (months), and
+C<y> (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:
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
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)
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);
}
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:
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;
}
("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){
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[^:]",
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;
+}
+