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