1abbee
From 33ca0f1f0d4b9a91588c84067d2fb30968e41235 Mon Sep 17 00:00:00 2001
a4d3ef
From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Nykr=C3=BDn?= <lnykryn@redhat.com>
a4d3ef
Date: Tue, 14 Jun 2016 14:20:56 +0200
a4d3ef
Subject: [PATCH] manager: reduce complexity of unit_gc_sweep (#3507)
a4d3ef
a4d3ef
When unit is marked as UNSURE, we are trying to find if it state was
a4d3ef
changed over and over again. So lets not go through the UNSURE states
a4d3ef
again. Also when we find a GOOD unit lets propagate the GOOD state to
a4d3ef
all units that this unit reference.
a4d3ef
a4d3ef
This is a problem on machines with a lot of initscripts with different
a4d3ef
starting priority, since those units will reference each other and the
a4d3ef
original algorithm might get to n! complexity.
a4d3ef
a4d3ef
Thanks HATAYAMA Daisuke for the expand_good_state code.
a4d3ef
Cherry-picked from: 4892084f096c19da0e83f28f250ca187b58c22b2
a4d3ef
Resolves: #1344556
a4d3ef
---
a4d3ef
 src/core/manager.c | 16 +++++++++++++++-
a4d3ef
 1 file changed, 15 insertions(+), 1 deletion(-)
a4d3ef
a4d3ef
diff --git a/src/core/manager.c b/src/core/manager.c
1abbee
index 370c8cb..e5226a8 100644
a4d3ef
--- a/src/core/manager.c
a4d3ef
+++ b/src/core/manager.c
1abbee
@@ -838,6 +838,19 @@ enum {
a4d3ef
         _GC_OFFSET_MAX
a4d3ef
 };
a4d3ef
 
a4d3ef
+static void unit_gc_mark_good(Unit *u, unsigned gc_marker)
a4d3ef
+{
a4d3ef
+        Iterator i;
a4d3ef
+        Unit *other;
a4d3ef
+
a4d3ef
+        u->gc_marker = gc_marker + GC_OFFSET_GOOD;
a4d3ef
+
a4d3ef
+        /* Recursively mark referenced units as GOOD as well */
a4d3ef
+        SET_FOREACH(other, u->dependencies[UNIT_REFERENCES], i)
a4d3ef
+                if (other->gc_marker == gc_marker + GC_OFFSET_UNSURE)
a4d3ef
+                        unit_gc_mark_good(other, gc_marker);
a4d3ef
+}
a4d3ef
+
a4d3ef
 static void unit_gc_sweep(Unit *u, unsigned gc_marker) {
a4d3ef
         Iterator i;
a4d3ef
         Unit *other;
1abbee
@@ -847,6 +860,7 @@ static void unit_gc_sweep(Unit *u, unsigned gc_marker) {
a4d3ef
 
a4d3ef
         if (u->gc_marker == gc_marker + GC_OFFSET_GOOD ||
a4d3ef
             u->gc_marker == gc_marker + GC_OFFSET_BAD ||
a4d3ef
+            u->gc_marker == gc_marker + GC_OFFSET_UNSURE ||
a4d3ef
             u->gc_marker == gc_marker + GC_OFFSET_IN_PATH)
a4d3ef
                 return;
a4d3ef
 
1abbee
@@ -887,7 +901,7 @@ bad:
a4d3ef
         return;
a4d3ef
 
a4d3ef
 good:
a4d3ef
-        u->gc_marker = gc_marker + GC_OFFSET_GOOD;
a4d3ef
+        unit_gc_mark_good(u, gc_marker);
a4d3ef
 }
a4d3ef
 
a4d3ef
 static unsigned manager_dispatch_gc_queue(Manager *m) {