Merge pull request #17497 from anitazha/randomizeonce

timer: add new feature FixedRandomDelay=
This commit is contained in:
Lennart Poettering 2020-11-10 13:29:04 +01:00 committed by GitHub
commit 394131d5be
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 66 additions and 6 deletions

View File

@ -374,6 +374,7 @@ Most timer unit settings are available to transient units.
✓ RemainAfterElapse=
✓ AccuracySec=
✓ RandomizedDelaySec=
✓ FixedRandomDelay=
Unit=
```

View File

@ -7211,6 +7211,8 @@ node /org/freedesktop/systemd1/unit/systemd_2dtmpfiles_2dclean_2etimer {
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly t RandomizedDelayUSec = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly b FixedRandomDelay = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly b Persistent = ...;
@org.freedesktop.DBus.Property.EmitsChangedSignal("const")
readonly b WakeSystem = ...;
@ -7236,6 +7238,8 @@ node /org/freedesktop/systemd1/unit/systemd_2dtmpfiles_2dclean_2etimer {
<!--property RandomizedDelayUSec is not documented!-->
<!--property FixedRandomDelay is not documented!-->
<!--property Persistent is not documented!-->
<!--property WakeSystem is not documented!-->
@ -7276,6 +7280,8 @@ node /org/freedesktop/systemd1/unit/systemd_2dtmpfiles_2dclean_2etimer {
<variablelist class="dbus-property" generated="True" extra-ref="RandomizedDelayUSec"/>
<variablelist class="dbus-property" generated="True" extra-ref="FixedRandomDelay"/>
<variablelist class="dbus-property" generated="True" extra-ref="Persistent"/>
<variablelist class="dbus-property" generated="True" extra-ref="WakeSystem"/>

View File

@ -268,6 +268,18 @@
<varname>AccuracySec=1us</varname>.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>FixedRandomDelay=</varname></term>
<listitem><para>Takes a boolean argument. If true, some amount of time between 0 and
<varname>RandomizedDelaySec=</varname> is chosen and added as the delay for each timer iteration. As this
delay will not be recalculated on each run, this effectively creates a fixed offset for each iteration.
The distribution between 0 and <varname>RandomizedDelaySec=</varname> is deterministic and based on
a combination of the machine ID, whether the timer is run by the user/system manager, the service manager's
user ID, and the timer's unit name. Has no effect if
<varname>RandomizedDelaySec=</varname> is set to 0. Defaults to <option>false</option>.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>OnClockChange=</varname></term>
<term><varname>OnTimezoneChange=</varname></term>
@ -276,7 +288,7 @@
when the system clock (<constant>CLOCK_REALTIME</constant>) jumps relative to the monotonic clock
(<constant>CLOCK_MONOTONIC</constant>), or when the local system timezone is modified. These options
can be used alone or in combination with other timer expressions (see above) within the same timer
unit. These options default to false.</para></listitem>
unit. These options default to <option>false</option>.</para></listitem>
</varlistentry>
<varlistentry>
@ -301,7 +313,7 @@
is nonetheless subject to the delay imposed by <varname>RandomizedDelaySec=</varname>.
This is useful to catch up on missed runs of the service when the system was powered down. Note that
this setting only has an effect on timers configured with <varname>OnCalendar=</varname>. Defaults to
<varname>false</varname>.</para>
<option>false</option>.</para>
<para>Use <command>systemctl clean --what=state …</command> on the timer unit to remove the timestamp
file maintained by this option from disk. In particular, use this command before uninstalling a timer
@ -317,7 +329,7 @@
from suspend, should it be suspended and if the system supports this. Note that this option will only
make sure the system resumes on the appropriate times, it will not take care of suspending it again
after any work that is to be done is finished. Defaults to
<varname>false</varname>.</para>
<option>false</option>.</para>
<para>Note that this functionality requires privileges and is thus generally only available in the
system service manager.</para>
@ -343,7 +355,7 @@
<varname>RemainAfterElapse=</varname> is on, starting the timer a second time has no effect. However,
if <varname>RemainAfterElapse=</varname> is off and the timer unit was already unloaded, it can be
started again, and thus the service can be triggered multiple times. Defaults to
<varname>yes</varname>.</para></listitem>
<option>true</option>.</para></listitem>
</varlistentry>
</variablelist>
</refsect1>

View File

@ -131,6 +131,7 @@ const sd_bus_vtable bus_timer_vtable[] = {
SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Timer, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
SD_BUS_PROPERTY("AccuracyUSec", "t", bus_property_get_usec, offsetof(Timer, accuracy_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RandomizedDelayUSec", "t", bus_property_get_usec, offsetof(Timer, random_usec), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("FixedRandomDelay", "b", bus_property_get_bool, offsetof(Timer, fixed_random_delay), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Persistent", "b", bus_property_get_bool, offsetof(Timer, persistent), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("WakeSystem", "b", bus_property_get_bool, offsetof(Timer, wake_system), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RemainAfterElapse", "b", bus_property_get_bool, offsetof(Timer, remain_after_elapse), SD_BUS_VTABLE_PROPERTY_CONST),
@ -232,6 +233,9 @@ static int bus_timer_set_transient_property(
if (streq(name, "RandomizedDelayUSec"))
return bus_set_transient_usec(u, name, &t->random_usec, message, flags, error);
if (streq(name, "FixedRandomDelay"))
return bus_set_transient_bool(u, name, &t->fixed_random_delay, message, flags, error);
if (streq(name, "WakeSystem"))
return bus_set_transient_bool(u, name, &t->wake_system, message, flags, error);

View File

@ -481,6 +481,7 @@ Timer.OnTimezoneChange, config_parse_bool,
Timer.Persistent, config_parse_bool, 0, offsetof(Timer, persistent)
Timer.WakeSystem, config_parse_bool, 0, offsetof(Timer, wake_system)
Timer.RemainAfterElapse, config_parse_bool, 0, offsetof(Timer, remain_after_elapse)
Timer.FixedRandomDelay, config_parse_bool, 0, offsetof(Timer, fixed_random_delay)
Timer.AccuracySec, config_parse_sec, 0, offsetof(Timer, accuracy_usec)
Timer.RandomizedDelaySec, config_parse_sec, 0, offsetof(Timer, random_usec)
Timer.Unit, config_parse_trigger_unit, 0, 0

View File

@ -169,6 +169,36 @@ static int timer_setup_persistent(Timer *t) {
return 0;
}
static uint64_t timer_get_fixed_delay_hash(Timer *t) {
static const uint8_t hash_key[] = {
0x51, 0x0a, 0xdb, 0x76, 0x29, 0x51, 0x42, 0xc2,
0x80, 0x35, 0xea, 0xe6, 0x8e, 0x3a, 0x37, 0xbd
};
struct siphash state;
sd_id128_t machine_id;
uid_t uid;
int r;
assert(t);
uid = getuid();
r = sd_id128_get_machine(&machine_id);
if (r < 0) {
log_unit_debug_errno(UNIT(t), r,
"Failed to get machine ID for the fixed delay calculation, proceeding with 0: %m");
machine_id = SD_ID128_NULL;
}
siphash24_init(&state, hash_key);
siphash24_compress(&machine_id, sizeof(sd_id128_t), &state);
siphash24_compress_boolean(MANAGER_IS_SYSTEM(UNIT(t)->manager), &state);
siphash24_compress(&uid, sizeof(uid_t), &state);
siphash24_compress_string(UNIT(t)->id, &state);
return siphash24_finalize(&state);
}
static int timer_load(Unit *u) {
Timer *t = TIMER(u);
int r;
@ -215,6 +245,7 @@ static void timer_dump(Unit *u, FILE *f, const char *prefix) {
"%sWakeSystem: %s\n"
"%sAccuracy: %s\n"
"%sRemainAfterElapse: %s\n"
"%sFixedRandomDelay: %s\n"
"%sOnClockChange: %s\n"
"%sOnTimeZoneChange: %s\n",
prefix, timer_state_to_string(t->state),
@ -224,6 +255,7 @@ static void timer_dump(Unit *u, FILE *f, const char *prefix) {
prefix, yes_no(t->wake_system),
prefix, format_timespan(buf, sizeof(buf), t->accuracy_usec, 1),
prefix, yes_no(t->remain_after_elapse),
prefix, yes_no(t->fixed_random_delay),
prefix, yes_no(t->on_clock_change),
prefix, yes_no(t->on_timezone_change));
@ -332,7 +364,7 @@ static void add_random(Timer *t, usec_t *v) {
if (*v == USEC_INFINITY)
return;
add = random_u64() % t->random_usec;
add = (t->fixed_random_delay ? timer_get_fixed_delay_hash(t) : random_u64()) % t->random_usec;
if (*v + add < *v) /* overflow */
*v = (usec_t) -2; /* Highest possible value, that is not USEC_INFINITY */

View File

@ -59,6 +59,7 @@ struct Timer {
bool remain_after_elapse;
bool on_clock_change;
bool on_timezone_change;
bool fixed_random_delay;
char *stamp_path;
};

View File

@ -2074,7 +2074,8 @@ static int bus_append_timer_property(sd_bus_message *m, const char *field, const
"RemainAfterElapse",
"Persistent",
"OnTimezoneChange",
"OnClockChange"))
"OnClockChange",
"FixedRandomDelay"))
return bus_append_parse_boolean(m, field, eq);
if (STR_IN_SET(field, "AccuracySec",

View File

@ -175,6 +175,7 @@ PipeSize=
Priority=
PropagatesReloadTo=
RandomizedDelaySec=
FixedRandomDelay=
RebootArgument=
ReceiveBuffer=
RefuseManualStart=

View File

@ -32,6 +32,7 @@ OnCalendar=Fri 2012-11-23 11:12:13
Persistent=true
AccuracySec=24h
RandomizedDelaySec=234234234
FixedRandomDelay=true
Persistent=no
Unit=foo.service