<p dir="ltr"><br>
On 2 Dec 2014 22:19, "Ken Sedgwick" <<a href="mailto:ksedgwic@bonsai.com">ksedgwic@bonsai.com</a>> wrote:<br>
><br>
> Systems with many units (~10K) take many seconds to perform a<br>
> daemon-reload. The process of load-balancing these systems requires<br>
> multiple daemon-reloads, many issued concurrently.</p>
<p dir="ltr">Out of curiosity, how does this work? Is there code we can look at?</p>
<p dir="ltr">> Currently many of<br>
> these redundant daemon-reloads timeout and fail.<br>
><br>
> This patch adds a new systemd method ReloadTimestamped which contains<br>
> the monotonic timestamp of the daemon-reload issuance. When a<br>
> ReloadTimestamped message is handled it's timestamp is compared to<br>
> the timestamp of the most recent successful daemon reload. If the<br>
> message is redundant it is returns with success immediately.<br>
><br>
> The original Reload method is preserved to support compatibility with<br>
> older systemctl versions.<br>
><br>
> If a new systemctl receives a SD_BUS_ERROR_UNKNOWN_METHOD error in<br>
> response to ReloadTimestamped it retries with the original Reload<br>
> method.<br>
> ---<br>
> src/core/dbus-manager.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++<br>
> src/core/manager.c | 8 ++++++++<br>
> src/core/manager.h | 3 +++<br>
> src/systemctl/systemctl.c | 19 ++++++++++++++++++-<br>
> 4 files changed, 76 insertions(+), 1 deletion(-)<br>
><br>
> diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c<br>
> index 0994d7b..6a42456 100644<br>
> --- a/src/core/dbus-manager.c<br>
> +++ b/src/core/dbus-manager.c<br>
> @@ -1100,6 +1100,52 @@ static int method_reload(sd_bus *bus, sd_bus_message *message, void *userdata, s<br>
> return 1;<br>
> }<br>
><br>
> +static int method_reload_timestamped(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {<br>
> + Manager *m = userdata;<br>
> + int r;<br>
> + usec_t requested_time;<br>
> +<br>
> + assert(bus);<br>
> + assert(message);<br>
> + assert(m);<br>
> +<br>
> + r = bus_verify_reload_daemon_async(m, message, error);<br>
> + if (r < 0)<br>
> + return r;<br>
> + if (r == 0)<br>
> + return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */<br>
> +<br>
> + r = mac_selinux_access_check(message, "reload", error);<br>
> + if (r < 0)<br>
> + return r;<br>
> +<br>
> + r = sd_bus_message_read(message, "t", &requested_time);<br>
> + if (r < 0)<br>
> + return r;<br>
> +<br>
> + /* Is this reload needed? If a completed reload was started<br>
> + * after this reload was requested we can coalesce it and<br>
> + * return immediate success. */<br>
> +<br>
> + if (requested_time < m->last_reload_time)<br>
> + return sd_bus_reply_method_return(message, NULL);<br>
> +<br>
> + /* Instead of sending the reply back right away, we just<br>
> + * remember that we need to and then send it after the reload<br>
> + * is finished. That way the caller knows when the reload<br>
> + * finished. */<br>
> +<br>
> + assert(!m->queued_message);<br>
> + r = sd_bus_message_new_method_return(message, &m->queued_message);<br>
> + if (r < 0)<br>
> + return r;<br>
> +<br>
> + m->queued_message_bus = sd_bus_ref(bus);<br>
> + m->exit_code = MANAGER_RELOAD;<br>
> +<br>
> + return 1;<br>
> +}<br>
> +<br>
> static int method_reexecute(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {<br>
> Manager *m = userdata;<br>
> int r;<br>
> @@ -1917,6 +1963,7 @@ const sd_bus_vtable bus_manager_vtable[] = {<br>
> SD_BUS_METHOD("CreateSnapshot", "sb", "o", method_create_snapshot, 0),<br>
> SD_BUS_METHOD("RemoveSnapshot", "s", NULL, method_remove_snapshot, 0),<br>
> SD_BUS_METHOD("Reload", NULL, NULL, method_reload, SD_BUS_VTABLE_UNPRIVILEGED),<br>
> + SD_BUS_METHOD("ReloadTimestamped", "t", NULL, method_reload_timestamped, SD_BUS_VTABLE_UNPRIVILEGED),<br>
> SD_BUS_METHOD("Reexecute", NULL, NULL, method_reexecute, SD_BUS_VTABLE_UNPRIVILEGED),<br>
> SD_BUS_METHOD("Exit", NULL, NULL, method_exit, 0),<br>
> SD_BUS_METHOD("Reboot", NULL, NULL, method_reboot, SD_BUS_VTABLE_CAPABILITY(CAP_SYS_BOOT)),<br>
> diff --git a/src/core/manager.c b/src/core/manager.c<br>
> index cff24fa..4619ce3 100644<br>
> --- a/src/core/manager.c<br>
> +++ b/src/core/manager.c<br>
> @@ -616,6 +616,8 @@ int manager_new(SystemdRunningAs running_as, bool test_run, Manager **_m) {<br>
><br>
> m->taint_usr = dir_is_empty("/usr") > 0;<br>
><br>
> + m->last_reload_time = 0ULL;<br>
> +<br>
> *_m = m;<br>
> return 0;<br>
><br>
> @@ -2444,9 +2446,12 @@ int manager_reload(Manager *m) {<br>
> int r, q;<br>
> _cleanup_fclose_ FILE *f = NULL;<br>
> _cleanup_fdset_free_ FDSet *fds = NULL;<br>
> + usec_t this_reload_time;<br>
><br>
> assert(m);<br>
><br>
> + this_reload_time = now(CLOCK_MONOTONIC);<br>
> +<br>
> r = manager_open_serialization(m, &f);<br>
> if (r < 0)<br>
> return r;<br>
> @@ -2518,6 +2523,9 @@ int manager_reload(Manager *m) {<br>
><br>
> m->send_reloading_done = true;<br>
><br>
> + if (r >= 0)<br>
> + m->last_reload_time = this_reload_time;<br>
> +<br>
> return r;<br>
> }<br>
><br>
> diff --git a/src/core/manager.h b/src/core/manager.h<br>
> index ab75f90..7790127 100644<br>
> --- a/src/core/manager.h<br>
> +++ b/src/core/manager.h<br>
> @@ -295,6 +295,9 @@ struct Manager {<br>
><br>
> /* Used for processing polkit authorization responses */<br>
> Hashmap *polkit_registry;<br>
> +<br>
> + /* Used to coalesce redundant reloads */<br>
> + usec_t last_reload_time;<br>
> };<br>
><br>
> int manager_new(SystemdRunningAs running_as, bool test_run, Manager **m);<br>
> diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c<br>
> index 74af772..3a50c75 100644<br>
> --- a/src/systemctl/systemctl.c<br>
> +++ b/src/systemctl/systemctl.c<br>
> @@ -142,6 +142,8 @@ static bool arg_plain = false;<br>
><br>
> static bool original_stdout_is_tty;<br>
><br>
> +static bool legacy_daemon_reload = false;<br>
> +<br>
> static int daemon_reload(sd_bus *bus, char **args);<br>
> static int halt_now(enum action a);<br>
> static int check_one_unit(sd_bus *bus, const char *name, const char *good_states, bool quiet);<br>
> @@ -4860,6 +4862,9 @@ static int daemon_reload(sd_bus *bus, char **args) {<br>
> /* "daemon-reload" */ "Reload";<br>
> }<br>
><br>
> + if (streq(method, "Reload") && !legacy_daemon_reload)<br>
> + method = "ReloadTimestamped";<br>
> +<br>
> r = sd_bus_message_new_method_call(<br>
> bus,<br>
> &m,<br>
> @@ -4870,12 +4875,24 @@ static int daemon_reload(sd_bus *bus, char **args) {<br>
> if (r < 0)<br>
> return bus_log_create_error(r);<br>
><br>
> + if (streq(method, "ReloadTimestamped")) {<br>
> + r = sd_bus_message_append(m, "t", now(CLOCK_MONOTONIC));<br>
> + if (r < 0)<br>
> + return bus_log_create_error(r);<br>
> + }<br>
> +<br>
> r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);<br>
> if (r < 0)<br>
> return bus_log_create_error(r);<br>
><br>
> r = sd_bus_call(bus, m, 0, &error, NULL);<br>
> - if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL)<br>
> + if (r == -EBADR && streq(method, "ReloadTimestamped") && streq(<a href="http://error.name">error.name</a>, SD_BUS_ERROR_UNKNOWN_METHOD)) {<br>
> + /* The ReloadTimestamped method wasn't available, retry<br>
> + * with legacy Reload instead. */<br>
> + legacy_daemon_reload = true;<br>
> + return daemon_reload(bus, args);<br>
> + }<br>
> + else if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL)<br>
> /* There's always a fallback possible for<br>
> * legacy actions. */<br>
> r = -EADDRNOTAVAIL;<br>
> --<br>
> 1.9.3<br>
><br>
> _______________________________________________<br>
> systemd-devel mailing list<br>
> <a href="mailto:systemd-devel@lists.freedesktop.org">systemd-devel@lists.freedesktop.org</a><br>
> <a href="http://lists.freedesktop.org/mailman/listinfo/systemd-devel">http://lists.freedesktop.org/mailman/listinfo/systemd-devel</a><br>
</p>