Hi,

the dependency checking in monit-4.6 falsely assumes that the inter-service 
dependencies constitute a TREE.

With a simple configuration like this

snip

check file A with path /tmp/A

check file B with path /tmp/B
   depends on A

check file C with path /tmp/C
   depends on A

check file D with path /tmp/D
   depends on B, C

snap

this leads monit to believe there was a dependency loop:

$ monit -t
monit: Error: Found a depend loop in the control file involving the service 
'B'

Instead, the dependency structure forms a directed acyclic graph (dag).

In the attached patch I have replaced check_depend(), validate_depend() and 
order_depend() by an implementation that does a topological sort of the 
dependency dag, thereby finding any (real) cycles and putting the services in 
the required order.

Regards,
Philipp Berndt
diff -pur monit-4.6/p.y monit-4.6.toposort/p.y
--- monit-4.6/p.y	2005-09-13 00:08:40.000000000 +0200
+++ monit-4.6.toposort/p.y	2005-12-08 22:17:52.000000000 +0100
@@ -3100,43 +3100,63 @@ static void check_hostname(char *hostnam
  
 }
 
-
 /*
- * Check the dependency graph for errors and if dependencies are
- * present reshuffle the service list in a depending order.
+ * Check the dependency graph for errors
+ * by doing a topological sort, thereby finding any cycles.
+ * Assures that graph is a Directed Acyclic Graph (DAG).
  */
 static void check_depend() {
-
-  Service_T s;
-  int has_depend= FALSE;
-  
-  for(s= servicelist; s; s= s->next) {
-    if(s->visited)
-	continue;
-    validate_depend(s, &has_depend);
-    reset_depend();
-  }
-  
-  if(has_depend) {
-    
-    Service_T d;
-    
+  Service_T s, depends_on;
+  depend_list = NULL;            /* depend_list will be the topological sorted servicelist */
+  Service_T* dlt = &depend_list; /* the current tail of it                                 */
+  int done;                      /* no unvisited nodes left?                               */
+  int found_some;                /* last iteration found anything new ?                    */
+
+  do { 
+    done = TRUE;
+    found_some = FALSE; 
     for(s= servicelist; s; s= s->next) {
+        Dependant_T d;
       if(s->visited)
 	  continue;
-      order_depend(s);
+      done = FALSE; // still unvisited nodes
+      depends_on = NULL;
+      for(d= s->dependantlist; d; d= d->next) {
+        Service_T dp = Util_getService(d->dependant);
+        if(!dp) {
+          log("%s: Error: Depend service '%s' is not defined in the "
+              "control file\n", prog, d->dependant);
+          exit(1);
+        }
+        if (!dp->visited) {
+          depends_on = dp;
+        }
+      }
+
+      if (!depends_on) {
+        s->visited = TRUE;
+        found_some = TRUE;
+        *dlt = s;
+        dlt = &s->next_depend;
+      }
     }
+  } while(found_some && !done);
+	
+  if (!done)
+   {
+        ASSERT(depends_on);
+	log("%s: Error: Found a depend loop in the control file "
+	    "involving the service '%s'\n", prog, depends_on->name);
+	exit(1);
+   } 
 
-    ASSERT(depend_list);
-    servicelist= depend_list;
+  ASSERT(depend_list);
+  servicelist= depend_list;
     
-    for(d= depend_list; d; d= d->next_depend)
-	d->next= d->next_depend;
+  for(s= depend_list; s; s= s->next_depend)
+    s->next= s->next_depend;
     
-  }
-
   reset_depend();
-  
 }
 
 
@@ -3183,77 +3203,3 @@ static int cleanup_hash_string(char *has
  
 }
 
-
-/*
- * Search for any errors in the service dependency graph
- */
-static void validate_depend(Service_T s, int *has_depend) {
-
-  ASSERT(s);
-
-  if(s->visited)
-      return;
-  
-  if(s->dependantlist) {
-    
-    Dependant_T d;
-    
-    for(d= s->dependantlist; d; d= d->next) {
-      
-      Service_T dp= Util_getService(d->dependant);
-      
-      if(!dp) {
-	log("%s: Error: Depend service '%s' is not defined in the "
-	    "control file\n", prog, d->dependant);
-	exit(1);
-      }
-      
-      if(dp->depend_visited) {
-	log("%s: Error: Found a depend loop in the control file "
-	    "involving the service '%s'\n", prog, s->name);
-	exit(1);
-      }
-      
-      *has_depend= TRUE;
-      dp->depend_visited= TRUE;
-      validate_depend(dp, has_depend);
-      
-    }
-  }
-  
-  s->visited= TRUE;
-
-}
-
-
-/*
- * Order the service list with the most "depending" service last and
- * the least first.
- */
-static void order_depend(Service_T s) {
-
-  ASSERT(s);
-  
-  if(s->visited)
-      return;
-
-  s->visited= TRUE;
-
-  if(s->dependantlist) {
-    
-    Dependant_T d;
-    
-    for(d= s->dependantlist; d; d= d->next) {
-      
-      Service_T dp= Util_getService(d->dependant);
-      
-      order_depend(dp);
-      
-    }
-  }
-
-  s->next_depend= depend_list;
-  depend_list= s;
-
-}
- 
--
To unsubscribe:
http://lists.nongnu.org/mailman/listinfo/monit-general

Reply via email to