Skip to content

Commit

Permalink
core: add a new unit method "catchup()"
Browse files Browse the repository at this point in the history
This is very similar to the existing unit method coldplug() but is
called a bit later. The idea is that that coldplug() restores the unit
state from before any prior reload/restart, i.e. puts the deserialized
state in effect. The catchup() call is then called a bit later, to
catch up with the system state for which we missed notifications while
we were reloading. This is only really useful for mount, swap and device
mount points were we should be careful to generate all missing unit
state change events (i.e. call unit_notify() appropriately) for
everything that happened while we were reloading.
  • Loading branch information
poettering committed Jun 7, 2018
1 parent 62b0cbb commit f0831ed
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 11 deletions.
30 changes: 29 additions & 1 deletion src/core/manager.c
Original file line number Diff line number Diff line change
Expand Up @@ -1350,7 +1350,9 @@ static void manager_coldplug(Manager *m) {

assert(m);

/* Then, let's set up their initial state. */
log_debug("Invoking unit coldplug() handlers…");

/* Let's place the units back into their deserialized state */
HASHMAP_FOREACH_KEY(u, k, m->units, i) {

/* ignore aliases */
Expand All @@ -1363,6 +1365,26 @@ static void manager_coldplug(Manager *m) {
}
}

static void manager_catchup(Manager *m) {
Iterator i;
Unit *u;
char *k;

assert(m);

log_debug("Invoking unit catchup() handlers…");

/* Let's catch up on any state changes that happened while we were reloading/reexecing */
HASHMAP_FOREACH_KEY(u, k, m->units, i) {

/* ignore aliases */
if (u->id != k)
continue;

unit_catchup(u);
}
}

static void manager_build_unit_path_cache(Manager *m) {
char **i;
int r;
Expand Down Expand Up @@ -1602,6 +1624,9 @@ int manager_startup(Manager *m, FILE *serialization, FDSet *fds) {
m->send_reloading_done = true;
}

/* Let's finally catch up with any changes that took place while we were reloading/reexecing */
manager_catchup(m);

return 0;
}

Expand Down Expand Up @@ -3414,6 +3439,9 @@ int manager_reload(Manager *m) {
manager_recheck_journal(m);
manager_recheck_dbus(m);

/* Let's finally catch up with any changes that took place while we were reloading/reexecing */
manager_catchup(m);

/* Sync current state of bus names with our set of listening units */
q = manager_enqueue_sync_bus_names(m);
if (q < 0 && r >= 0)
Expand Down
11 changes: 8 additions & 3 deletions src/core/unit.c
Original file line number Diff line number Diff line change
Expand Up @@ -2298,7 +2298,6 @@ static void unit_update_on_console(Unit *u) {
manager_ref_console(u->manager);
else
manager_unref_console(u->manager);

}

void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, UnitNotifyFlags flags) {
Expand Down Expand Up @@ -3730,8 +3729,7 @@ int unit_coldplug(Unit *u) {

assert(u);

/* Make sure we don't enter a loop, when coldplugging
* recursively. */
/* Make sure we don't enter a loop, when coldplugging recursively. */
if (u->coldplugged)
return 0;

Expand Down Expand Up @@ -3759,6 +3757,13 @@ int unit_coldplug(Unit *u) {
return r;
}

void unit_catchup(Unit *u) {
assert(u);

if (UNIT_VTABLE(u)->catchup)
UNIT_VTABLE(u)->catchup(u);
}

static bool fragment_mtime_newer(const char *path, usec_t mtime, bool path_masked) {
struct stat st;

Expand Down
17 changes: 10 additions & 7 deletions src/core/unit.h
Original file line number Diff line number Diff line change
Expand Up @@ -437,10 +437,14 @@ typedef struct UnitVTable {
* UNIT_STUB if no configuration could be found. */
int (*load)(Unit *u);

/* If a lot of units got created via enumerate(), this is
* where to actually set the state and call unit_notify(). */
/* During deserialization we only record the intended state to return to. With coldplug() we actually put the
* deserialized state in effect. This is where unit_notify() should be called to start things up. */
int (*coldplug)(Unit *u);

/* This is called shortly after all units' coldplug() call was invoked. It's supposed to catch up state changes
* we missed so far (for example because they took place while we were reloading/reexecing) */
void (*catchup)(Unit *u);

void (*dump)(Unit *u, FILE *f, const char *prefix);

int (*start)(Unit *u);
Expand Down Expand Up @@ -531,11 +535,9 @@ typedef struct UnitVTable {
/* Returns true if the unit currently needs access to the console */
bool (*needs_console)(Unit *u);

/* This is called for each unit type and should be used to
* enumerate existing devices and load them. However,
* everything that is loaded here should still stay in
* inactive state. It is the job of the coldplug() call above
* to put the units into the initial state. */
/* This is called for each unit type and should be used to enumerate units already existing in the system
* internally and load them. However, everything that is loaded here should still stay in inactive state. It is
* the job of the coldplug() call above to put the units into the initial state. */
void (*enumerate)(Manager *m);

/* Type specific cleanups. */
Expand Down Expand Up @@ -687,6 +689,7 @@ void unit_serialize_item_format(Unit *u, FILE *f, const char *key, const char *v
int unit_add_node_dependency(Unit *u, const char *what, bool wants, UnitDependency d, UnitDependencyMask mask);

int unit_coldplug(Unit *u);
void unit_catchup(Unit *u);

void unit_status_printf(Unit *u, const char *status, const char *unit_status_msg_format) _printf_(3, 0);
void unit_status_emit_starting_stopping_reloading(Unit *u, JobType t);
Expand Down

0 comments on commit f0831ed

Please sign in to comment.