[systemd-devel] [PATCH] daemon-reload timestamped: coalesce redundant daemon-reloads

Ken Sedgwick ksedgwic at bonsai.com
Tue Dec 2 13:19:22 PST 2014


Systems with many units (~10K) take many seconds to perform a
daemon-reload.  The process of load-balancing these systems requires
multiple daemon-reloads, many issued concurrently.  Currently many of
these redundant daemon-reloads timeout and fail.

This patch adds a new systemd method ReloadTimestamped which contains
the monotonic timestamp of the daemon-reload issuance.  When a
ReloadTimestamped message is handled it's timestamp is compared to
the timestamp of the most recent successful daemon reload.  If the
message is redundant it is returns with success immediately.

The original Reload method is preserved to support compatibility with
older systemctl versions.

If a new systemctl receives a SD_BUS_ERROR_UNKNOWN_METHOD error in
response to ReloadTimestamped it retries with the original Reload
method.
---
 src/core/dbus-manager.c   | 47 +++++++++++++++++++++++++++++++++++++++++++++++
 src/core/manager.c        |  8 ++++++++
 src/core/manager.h        |  3 +++
 src/systemctl/systemctl.c | 19 ++++++++++++++++++-
 4 files changed, 76 insertions(+), 1 deletion(-)

diff --git a/src/core/dbus-manager.c b/src/core/dbus-manager.c
index 0994d7b..6a42456 100644
--- a/src/core/dbus-manager.c
+++ b/src/core/dbus-manager.c
@@ -1100,6 +1100,52 @@ static int method_reload(sd_bus *bus, sd_bus_message *message, void *userdata, s
         return 1;
 }
 
+static int method_reload_timestamped(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        Manager *m = userdata;
+        int r;
+        usec_t requested_time;
+
+        assert(bus);
+        assert(message);
+        assert(m);
+
+        r = bus_verify_reload_daemon_async(m, message, error);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
+
+        r = mac_selinux_access_check(message, "reload", error);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_read(message, "t", &requested_time);
+        if (r < 0)
+                return r;
+
+        /* Is this reload needed?  If a completed reload was started
+         * after this reload was requested we can coalesce it and
+         * return immediate success. */
+
+        if (requested_time < m->last_reload_time)
+                return sd_bus_reply_method_return(message, NULL);
+
+        /* Instead of sending the reply back right away, we just
+         * remember that we need to and then send it after the reload
+         * is finished. That way the caller knows when the reload
+         * finished. */
+
+        assert(!m->queued_message);
+        r = sd_bus_message_new_method_return(message, &m->queued_message);
+        if (r < 0)
+                return r;
+
+        m->queued_message_bus = sd_bus_ref(bus);
+        m->exit_code = MANAGER_RELOAD;
+
+        return 1;
+}
+
 static int method_reexecute(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
         Manager *m = userdata;
         int r;
@@ -1917,6 +1963,7 @@ const sd_bus_vtable bus_manager_vtable[] = {
         SD_BUS_METHOD("CreateSnapshot", "sb", "o", method_create_snapshot, 0),
         SD_BUS_METHOD("RemoveSnapshot", "s", NULL, method_remove_snapshot, 0),
         SD_BUS_METHOD("Reload", NULL, NULL, method_reload, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("ReloadTimestamped", "t", NULL, method_reload_timestamped, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("Reexecute", NULL, NULL, method_reexecute, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("Exit", NULL, NULL, method_exit, 0),
         SD_BUS_METHOD("Reboot", NULL, NULL, method_reboot, SD_BUS_VTABLE_CAPABILITY(CAP_SYS_BOOT)),
diff --git a/src/core/manager.c b/src/core/manager.c
index cff24fa..4619ce3 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -616,6 +616,8 @@ int manager_new(SystemdRunningAs running_as, bool test_run, Manager **_m) {
 
         m->taint_usr = dir_is_empty("/usr") > 0;
 
+        m->last_reload_time = 0ULL;
+
         *_m = m;
         return 0;
 
@@ -2444,9 +2446,12 @@ int manager_reload(Manager *m) {
         int r, q;
         _cleanup_fclose_ FILE *f = NULL;
         _cleanup_fdset_free_ FDSet *fds = NULL;
+        usec_t this_reload_time;
 
         assert(m);
 
+        this_reload_time = now(CLOCK_MONOTONIC);
+
         r = manager_open_serialization(m, &f);
         if (r < 0)
                 return r;
@@ -2518,6 +2523,9 @@ int manager_reload(Manager *m) {
 
         m->send_reloading_done = true;
 
+        if (r >= 0)
+                m->last_reload_time = this_reload_time;
+
         return r;
 }
 
diff --git a/src/core/manager.h b/src/core/manager.h
index ab75f90..7790127 100644
--- a/src/core/manager.h
+++ b/src/core/manager.h
@@ -295,6 +295,9 @@ struct Manager {
 
         /* Used for processing polkit authorization responses */
         Hashmap *polkit_registry;
+
+        /* Used to coalesce redundant reloads */
+        usec_t last_reload_time;
 };
 
 int manager_new(SystemdRunningAs running_as, bool test_run, Manager **m);
diff --git a/src/systemctl/systemctl.c b/src/systemctl/systemctl.c
index 74af772..3a50c75 100644
--- a/src/systemctl/systemctl.c
+++ b/src/systemctl/systemctl.c
@@ -142,6 +142,8 @@ static bool arg_plain = false;
 
 static bool original_stdout_is_tty;
 
+static bool legacy_daemon_reload = false;
+
 static int daemon_reload(sd_bus *bus, char **args);
 static int halt_now(enum action a);
 static int check_one_unit(sd_bus *bus, const char *name, const char *good_states, bool quiet);
@@ -4860,6 +4862,9 @@ static int daemon_reload(sd_bus *bus, char **args) {
                                     /* "daemon-reload" */ "Reload";
         }
 
+        if (streq(method, "Reload") && !legacy_daemon_reload)
+                method = "ReloadTimestamped";
+
         r = sd_bus_message_new_method_call(
                         bus,
                         &m,
@@ -4870,12 +4875,24 @@ static int daemon_reload(sd_bus *bus, char **args) {
         if (r < 0)
                 return bus_log_create_error(r);
 
+        if (streq(method, "ReloadTimestamped")) {
+                r = sd_bus_message_append(m, "t", now(CLOCK_MONOTONIC));
+                if (r < 0)
+                        return bus_log_create_error(r);
+        }
+
         r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
         if (r < 0)
                 return bus_log_create_error(r);
 
         r = sd_bus_call(bus, m, 0, &error, NULL);
-        if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL)
+        if (r == -EBADR && streq(method, "ReloadTimestamped") && streq(error.name, SD_BUS_ERROR_UNKNOWN_METHOD)) {
+                /* The ReloadTimestamped method wasn't available, retry
+                 * with legacy Reload instead. */
+                legacy_daemon_reload = true;
+                return daemon_reload(bus, args);
+        }
+        else if (r == -ENOENT && arg_action != ACTION_SYSTEMCTL)
                 /* There's always a fallback possible for
                  * legacy actions. */
                 r = -EADDRNOTAVAIL;
-- 
1.9.3



More information about the systemd-devel mailing list