New feature: "?" for time specifications, means a single time selected at
random from within the range at file read time. Very useful if you want to avoid having a fleet of machines melt a server by all trying to contact it at a precise time every morning. See docs for details. Reviewed by: christos, apb, vixie, others. XXX apb suggests, quite reasonably, that ?10-16/2 should mean something like 10,12,14,16 or 11,13,15. I'm too lazy to do it right now, but it should be done. XXX vixie suggests, quite reasonably, that if you're using "?" one should delay randomly by 0-59 seconds. In the modern NTP world, you could imagine that with a million well synchronized machines the second just at the minute would be hit quite hard. I'm too lazy to do it right now, but it should be done. XXX cron needs to be updated to Vixie's cron 4.1 code.
This commit is contained in:
parent
0c046062f0
commit
4cfab35c9c
|
@ -1,4 +1,4 @@
|
|||
.\" $NetBSD: crontab.5,v 1.11 2004/09/02 11:41:27 jmmv Exp $
|
||||
.\" $NetBSD: crontab.5,v 1.12 2009/04/04 16:05:10 perry Exp $
|
||||
.\"
|
||||
.\"/* Copyright 1988,1990,1993,1994 by Paul Vixie
|
||||
.\" * All rights reserved
|
||||
|
@ -135,6 +135,20 @@ with a hyphen. The specified range is inclusive. For example,
|
|||
8-11 for an ``hours'' entry specifies execution at hours 8, 9, 10
|
||||
and 11.
|
||||
.PP
|
||||
A field may begin with a question mark (?), which indicates a
|
||||
single value randomly selected when the crontab file is read.
|
||||
If the field contains only a question mark, the value is randomly
|
||||
selected from the range of all possible values for the field.
|
||||
If the question mark precedes a range, the value is randomly selected
|
||||
from the range.
|
||||
For example, ``? ?2-5 * * *'' specifies that a task will be performed
|
||||
daily between 2:00am and and 5:59am at a time randomly selected when
|
||||
the crontab file is first read.
|
||||
As just one example, this feature can be used to prevent a large
|
||||
number of hosts from contacting a server simultaneously and
|
||||
overloading it by staggering the time at which a download script is
|
||||
executed.
|
||||
.PP
|
||||
Lists are allowed. A list is a set of numbers (or ranges)
|
||||
separated by commas. Examples: ``1,2,5,9'', ``0-4,8-12''.
|
||||
.PP
|
||||
|
@ -211,6 +225,7 @@ MAILTO=paul
|
|||
0 22 * * 1-5 mail -s "It's 10pm" joe%Joe,%%Where are your kids?%
|
||||
23 0-23/2 * * * echo "run 23 minutes after midn, 2am, 4am ..., everyday"
|
||||
5 4 * * sun echo "run at 5 after 4 every sunday"
|
||||
? ?2-4 1,15 * * echo "random between 2am-4:59am on the 1st and 15th"
|
||||
.fi
|
||||
.SH SEE ALSO
|
||||
cron(8), crontab(1)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* $NetBSD: entry.c,v 1.9 2008/02/16 07:26:00 matt Exp $ */
|
||||
/* $NetBSD: entry.c,v 1.10 2009/04/04 16:05:10 perry Exp $ */
|
||||
|
||||
/* Copyright 1988,1990,1993,1994 by Paul Vixie
|
||||
* All rights reserved
|
||||
|
@ -22,7 +22,7 @@
|
|||
#if 0
|
||||
static char rcsid[] = "Id: entry.c,v 2.12 1994/01/17 03:20:37 vixie Exp";
|
||||
#else
|
||||
__RCSID("$NetBSD: entry.c,v 1.9 2008/02/16 07:26:00 matt Exp $");
|
||||
__RCSID("$NetBSD: entry.c,v 1.10 2009/04/04 16:05:10 perry Exp $");
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@ -358,6 +358,18 @@ get_list(bitstr_t *bits, /* one bit per flag, default=FALSE */
|
|||
}
|
||||
|
||||
|
||||
static int
|
||||
random_with_range(int low, int high)
|
||||
{
|
||||
/* Kind of crappy error detection, but...
|
||||
*/
|
||||
if (low >= high)
|
||||
return low;
|
||||
else
|
||||
return arc4random() % (high - low + 1) + low;
|
||||
}
|
||||
|
||||
|
||||
static char
|
||||
get_range(bitstr_t *bits, /* one bit per flag, default=FALSE */
|
||||
int low, /* bounds, impl. offset for bitstr */
|
||||
|
@ -371,24 +383,44 @@ get_range(bitstr_t *bits, /* one bit per flag, default=FALSE */
|
|||
|
||||
int i;
|
||||
int num1, num2, num3;
|
||||
int qmark, star;
|
||||
|
||||
qmark = star = FALSE;
|
||||
|
||||
Debug(DPARS|DEXT, ("get_range()...entering, exit won't show\n"))
|
||||
|
||||
if (ch == '*') {
|
||||
/* '*' means "first-last" but can still be modified by /step
|
||||
*/
|
||||
star = TRUE;
|
||||
num1 = low;
|
||||
num2 = high;
|
||||
ch = get_char(file);
|
||||
if (ch == EOF)
|
||||
return EOF;
|
||||
} else {
|
||||
} else if (ch == '?') {
|
||||
qmark = TRUE;
|
||||
ch = get_char(file);
|
||||
if (ch == EOF)
|
||||
return EOF;
|
||||
if (!isdigit(ch)) {
|
||||
num1 = random_with_range(low, high);
|
||||
if (EOF == set_element(bits, low, high, num1))
|
||||
return EOF;
|
||||
return ch;
|
||||
}
|
||||
}
|
||||
|
||||
if (!star) {
|
||||
if (EOF == (ch = get_number(&num1, low, names, ch, file)))
|
||||
return EOF;
|
||||
|
||||
if (ch != '-') {
|
||||
/* not a range, it's a single number.
|
||||
* a single number after '?' is bogus.
|
||||
*/
|
||||
if (qmark)
|
||||
return EOF;
|
||||
if (EOF == set_element(bits, low, high, num1))
|
||||
return EOF;
|
||||
return ch;
|
||||
|
@ -404,12 +436,28 @@ get_range(bitstr_t *bits, /* one bit per flag, default=FALSE */
|
|||
ch = get_number(&num2, low, names, ch, file);
|
||||
if (ch == EOF)
|
||||
return EOF;
|
||||
|
||||
/* if we have a random range, it is really
|
||||
* like having a single number.
|
||||
*/
|
||||
if (qmark) {
|
||||
if (num1 > num2)
|
||||
return EOF;
|
||||
num1 = random_with_range(num1, num2);
|
||||
if (EOF == set_element(bits, low, high, num1))
|
||||
return EOF;
|
||||
return ch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* check for step size
|
||||
*/
|
||||
if (ch == '/') {
|
||||
/* '?' is incompatible with '/'
|
||||
*/
|
||||
if (qmark)
|
||||
return EOF;
|
||||
/* eat the slash
|
||||
*/
|
||||
ch = get_char(file);
|
||||
|
|
Loading…
Reference in New Issue