summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
authorLukáš Nykrýn <lnykryn@redhat.com>2016-06-14 14:20:56 +0200
committerLennart Poettering <lennart@poettering.net>2016-06-14 14:20:56 +0200
commit4892084f096c19da0e83f28f250ca187b58c22b2 (patch)
treed719664eb002fb77c29ed4d3944d0b3ebc4a9e32 /src/core
parentbbc85a16e12083fdf13215c07a57ad7a5fb56ef8 (diff)
manager: reduce complexity of unit_gc_sweep (#3507)
When unit is marked as UNSURE, we are trying to find if it state was changed over and over again. So lets not go through the UNSURE states again. Also when we find a GOOD unit lets propagate the GOOD state to all units that this unit reference. This is a problem on machines with a lot of initscripts with different starting priority, since those units will reference each other and the original algorithm might get to n! complexity. Thanks HATAYAMA Daisuke for the expand_good_state code.
Diffstat (limited to 'src/core')
-rw-r--r--src/core/manager.c16
1 files changed, 15 insertions, 1 deletions
diff --git a/src/core/manager.c b/src/core/manager.c
index ec8acdff5b..5c0fee935d 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -877,6 +877,19 @@ enum {
_GC_OFFSET_MAX
};
+static void unit_gc_mark_good(Unit *u, unsigned gc_marker)
+{
+ Iterator i;
+ Unit *other;
+
+ u->gc_marker = gc_marker + GC_OFFSET_GOOD;
+
+ /* Recursively mark referenced units as GOOD as well */
+ SET_FOREACH(other, u->dependencies[UNIT_REFERENCES], i)
+ if (other->gc_marker == gc_marker + GC_OFFSET_UNSURE)
+ unit_gc_mark_good(other, gc_marker);
+}
+
static void unit_gc_sweep(Unit *u, unsigned gc_marker) {
Iterator i;
Unit *other;
@@ -886,6 +899,7 @@ static void unit_gc_sweep(Unit *u, unsigned gc_marker) {
if (u->gc_marker == gc_marker + GC_OFFSET_GOOD ||
u->gc_marker == gc_marker + GC_OFFSET_BAD ||
+ u->gc_marker == gc_marker + GC_OFFSET_UNSURE ||
u->gc_marker == gc_marker + GC_OFFSET_IN_PATH)
return;
@@ -926,7 +940,7 @@ bad:
return;
good:
- u->gc_marker = gc_marker + GC_OFFSET_GOOD;
+ unit_gc_mark_good(u, gc_marker);
}
static unsigned manager_dispatch_gc_queue(Manager *m) {