core: clear dependency graph before freeing all units

When the manager tears down every unit during reload or shutdown,
unit_free() removes each dependency from both endpoints. This work is
redundant because every dependency map is about to disappear, and it
scales poorly with thousands of synthesized mount units.

Clear all unit dependency maps in one manager-wide pass before invoking
the existing unit_free() cleanup.

With 10,000 bind mounts, this reduced the mean daemon-reload time from
63.558s to 14.708s.
This commit is contained in:
Chris Ayoub
2026-08-22 04:21:35 +09:00
committed by Yu Watanabe
parent 3bbf9351dc
commit 0b87becb0a
+25
View File
@@ -1670,11 +1670,36 @@ static unsigned manager_dispatch_stop_notify_queue(Manager *m) {
return n;
}
static void manager_clear_unit_dependencies(Manager *m) {
Unit *u;
const char *name;
assert(m);
HASHMAP_FOREACH_KEY(u, name, m->units) {
/* ignore aliases */
if (u->id != name)
continue;
for (Hashmap *dependencies; (dependencies = hashmap_steal_first(u->dependencies));)
hashmap_free(dependencies);
u->dependencies = hashmap_free(u->dependencies);
u->dependency_generation++;
}
}
static void manager_clear_jobs_and_units(Manager *m) {
Unit *u;
assert(m);
/* All units are going away, hence discard the full dependency graph in one pass. Otherwise
* unit_free() removes every edge from both endpoints separately, which becomes very costly with
* large numbers of synthesized mount units. */
manager_clear_unit_dependencies(m);
while ((u = hashmap_first(m->units)))
unit_free(u);