root/lib/transition/graph.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. update_synapse_ready
  2. update_synapse_confirmed
  3. update_graph
  4. should_fire_synapse
  5. initiate_action
  6. fire_synapse
  7. run_graph

   1 /* 
   2  * Copyright (C) 2004 Andrew Beekhof <andrew@beekhof.net>
   3  * 
   4  * This library is free software; you can redistribute it and/or
   5  * modify it under the terms of the GNU Lesser General Public
   6  * License as published by the Free Software Foundation; either
   7  * version 2.1 of the License, or (at your option) any later version.
   8  * 
   9  * This library is distributed in the hope that it will be useful,
  10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12  * Lesser General Public License for more details.
  13  * 
  14  * You should have received a copy of the GNU Lesser General Public
  15  * License along with this library; if not, write to the Free Software
  16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  17  */
  18 
  19 #include <crm_internal.h>
  20 
  21 #include <crm/crm.h>
  22 #include <crm/msg_xml.h>
  23 #include <crm/common/xml.h>
  24 #include <crm/transition.h>
  25 /* #include <sys/param.h> */
  26 /*  */
  27 
  28 crm_graph_functions_t *graph_fns = NULL;
  29 
  30 static gboolean
  31 update_synapse_ready(synapse_t * synapse, int action_id)
     /* [previous][next][first][last][top][bottom][index][help] */
  32 {
  33     GListPtr lpc = NULL;
  34     gboolean updates = FALSE;
  35 
  36     CRM_CHECK(synapse->executed == FALSE, return FALSE);
  37     CRM_CHECK(synapse->confirmed == FALSE, return FALSE);
  38 
  39     synapse->ready = TRUE;
  40     for (lpc = synapse->inputs; lpc != NULL; lpc = lpc->next) {
  41         crm_action_t *prereq = (crm_action_t *) lpc->data;
  42 
  43         crm_trace("Processing input %d", prereq->id);
  44 
  45         if (prereq->id == action_id) {
  46             crm_trace("Marking input %d of synapse %d confirmed", action_id, synapse->id);
  47             prereq->confirmed = TRUE;
  48             updates = TRUE;
  49 
  50         } else if (prereq->confirmed == FALSE) {
  51             synapse->ready = FALSE;
  52         }
  53 
  54     }
  55 
  56     if (updates) {
  57         crm_trace("Updated synapse %d", synapse->id);
  58     }
  59     return updates;
  60 }
  61 
  62 static gboolean
  63 update_synapse_confirmed(synapse_t * synapse, int action_id)
     /* [previous][next][first][last][top][bottom][index][help] */
  64 {
  65     GListPtr lpc = NULL;
  66     gboolean updates = FALSE;
  67     gboolean is_confirmed = TRUE;
  68 
  69     CRM_CHECK(synapse->executed, return FALSE);
  70     CRM_CHECK(synapse->confirmed == FALSE, return TRUE);
  71 
  72     is_confirmed = TRUE;
  73     for (lpc = synapse->actions; lpc != NULL; lpc = lpc->next) {
  74         crm_action_t *action = (crm_action_t *) lpc->data;
  75 
  76         crm_trace("Processing action %d", action->id);
  77 
  78         if (action->id == action_id) {
  79             crm_trace("Confirmed: Action %d of Synapse %d", action_id, synapse->id);
  80             action->confirmed = TRUE;
  81             updates = TRUE;
  82 
  83         } else if (action->confirmed == FALSE) {
  84             is_confirmed = FALSE;
  85             crm_trace("Synapse %d still not confirmed after action %d", synapse->id, action_id);
  86         }
  87     }
  88 
  89     if (is_confirmed && synapse->confirmed == FALSE) {
  90         crm_trace("Confirmed: Synapse %d", synapse->id);
  91         synapse->confirmed = TRUE;
  92         updates = TRUE;
  93     }
  94 
  95     if (updates) {
  96         crm_trace("Updated synapse %d", synapse->id);
  97     }
  98     return updates;
  99 }
 100 
 101 gboolean
 102 update_graph(crm_graph_t * graph, crm_action_t * action)
     /* [previous][next][first][last][top][bottom][index][help] */
 103 {
 104     gboolean rc = FALSE;
 105     gboolean updates = FALSE;
 106     GListPtr lpc = NULL;
 107 
 108     for (lpc = graph->synapses; lpc != NULL; lpc = lpc->next) {
 109         synapse_t *synapse = (synapse_t *) lpc->data;
 110 
 111         if (synapse->confirmed || synapse->failed) {
 112             crm_trace("Synapse complete");
 113 
 114         } else if (synapse->executed) {
 115             crm_trace("Synapse executed");
 116             rc = update_synapse_confirmed(synapse, action->id);
 117 
 118         } else if (action->failed == FALSE || synapse->priority == INFINITY) {
 119             rc = update_synapse_ready(synapse, action->id);
 120         }
 121         updates = updates || rc;
 122     }
 123 
 124     if (updates) {
 125         crm_trace("Updated graph with completed action %d", action->id);
 126     }
 127     return updates;
 128 }
 129 
 130 static gboolean
 131 should_fire_synapse(crm_graph_t * graph, synapse_t * synapse)
     /* [previous][next][first][last][top][bottom][index][help] */
 132 {
 133     GListPtr lpc = NULL;
 134 
 135     CRM_CHECK(synapse->executed == FALSE, return FALSE);
 136     CRM_CHECK(synapse->confirmed == FALSE, return FALSE);
 137 
 138     crm_trace("Checking pre-reqs for synapse %d", synapse->id);
 139     /* lookup prereqs */
 140     synapse->ready = TRUE;
 141     for (lpc = synapse->inputs; lpc != NULL; lpc = lpc->next) {
 142         crm_action_t *prereq = (crm_action_t *) lpc->data;
 143 
 144         crm_trace("Processing input %d", prereq->id);
 145         if (prereq->confirmed == FALSE) {
 146             crm_trace("Input %d for synapse %d not satisfied: not confirmed", prereq->id, synapse->id);
 147             synapse->ready = FALSE;
 148             break;
 149         } else if(prereq->failed && prereq->can_fail == FALSE) {
 150             crm_trace("Input %d for synapse %d not satisfied: failed", prereq->id, synapse->id);
 151             synapse->ready = FALSE;
 152             break;
 153         }
 154     }
 155 
 156     for (lpc = synapse->actions; synapse->ready && lpc != NULL; lpc = lpc->next) {
 157         crm_action_t *a = (crm_action_t *) lpc->data;
 158 
 159         if (a->type == action_type_pseudo) {
 160             /* None of the below applies to pseudo ops */
 161 
 162         } else if (synapse->priority < graph->abort_priority) {
 163             crm_trace("Skipping synapse %d: abort level %d", synapse->id, graph->abort_priority);
 164             graph->skipped++;
 165             return FALSE;
 166 
 167         } else if(graph_fns->allowed && graph_fns->allowed(graph, a) == FALSE) {
 168             crm_trace("Deferring synapse %d: allowed", synapse->id);
 169             return FALSE;
 170         }
 171     }
 172 
 173     return synapse->ready;
 174 }
 175 
 176 static gboolean
 177 initiate_action(crm_graph_t * graph, crm_action_t * action)
     /* [previous][next][first][last][top][bottom][index][help] */
 178 {
 179     const char *id = NULL;
 180 
 181     CRM_CHECK(action->executed == FALSE, return FALSE);
 182 
 183     id = ID(action->xml);
 184     CRM_CHECK(id != NULL, return FALSE);
 185 
 186     action->executed = TRUE;
 187     if (action->type == action_type_pseudo) {
 188         crm_trace("Executing pseudo-event: %s (%d)", id, action->id);
 189         return graph_fns->pseudo(graph, action);
 190 
 191     } else if (action->type == action_type_rsc) {
 192         crm_trace("Executing rsc-event: %s (%d)", id, action->id);
 193         return graph_fns->rsc(graph, action);
 194 
 195     } else if (action->type == action_type_crm) {
 196         const char *task = NULL;
 197 
 198         task = crm_element_value(action->xml, XML_LRM_ATTR_TASK);
 199         CRM_CHECK(task != NULL, return FALSE);
 200 
 201         if (safe_str_eq(task, CRM_OP_FENCE)) {
 202             crm_trace("Executing STONITH-event: %s (%d)", id, action->id);
 203             return graph_fns->stonith(graph, action);
 204         }
 205 
 206         crm_trace("Executing crm-event: %s (%d)", id, action->id);
 207         return graph_fns->crmd(graph, action);
 208     }
 209 
 210     crm_err("Failed on unsupported command type: %s (id=%s)", crm_element_name(action->xml), id);
 211     return FALSE;
 212 }
 213 
 214 static gboolean
 215 fire_synapse(crm_graph_t * graph, synapse_t * synapse)
     /* [previous][next][first][last][top][bottom][index][help] */
 216 {
 217     GListPtr lpc = NULL;
 218 
 219     CRM_CHECK(synapse != NULL, return FALSE);
 220     CRM_CHECK(synapse->ready, return FALSE);
 221     CRM_CHECK(synapse->confirmed == FALSE, return TRUE);
 222 
 223     crm_trace("Synapse %d fired", synapse->id);
 224     synapse->executed = TRUE;
 225     for (lpc = synapse->actions; lpc != NULL; lpc = lpc->next) {
 226         crm_action_t *action = (crm_action_t *) lpc->data;
 227 
 228         /* allow some leeway */
 229         gboolean passed = FALSE;
 230 
 231         /* Invoke the action and start the timer */
 232         passed = initiate_action(graph, action);
 233         if (passed == FALSE) {
 234             crm_err("Failed initiating <%s id=%d> in synapse %d",
 235                     crm_element_name(action->xml), action->id, synapse->id);
 236             synapse->confirmed = TRUE;
 237             action->confirmed = TRUE;
 238             action->failed = TRUE;
 239             return FALSE;
 240         }
 241     }
 242 
 243     return TRUE;
 244 }
 245 
 246 int
 247 run_graph(crm_graph_t * graph)
     /* [previous][next][first][last][top][bottom][index][help] */
 248 {
 249     GListPtr lpc = NULL;
 250     int stat_log_level = LOG_DEBUG;
 251     int pass_result = transition_active;
 252 
 253     const char *status = "In-progress";
 254 
 255     if (graph_fns == NULL) {
 256         set_default_graph_functions();
 257     }
 258     if (graph == NULL) {
 259         return transition_complete;
 260     }
 261 
 262     graph->fired = 0;
 263     graph->pending = 0;
 264     graph->skipped = 0;
 265     graph->completed = 0;
 266     graph->incomplete = 0;
 267     crm_trace("Entering graph %d callback", graph->id);
 268 
 269     /* Pre-calculate the number of completed and in-flight operations */
 270     for (lpc = graph->synapses; lpc != NULL; lpc = lpc->next) {
 271         synapse_t *synapse = (synapse_t *) lpc->data;
 272 
 273         if (synapse->confirmed) {
 274             crm_trace("Synapse %d complete", synapse->id);
 275             graph->completed++;
 276 
 277         } else if (synapse->failed == FALSE && synapse->executed) {
 278             crm_trace("Synapse %d: confirmation pending", synapse->id);
 279             graph->pending++;
 280         }
 281     }
 282 
 283     /* Now check if there is work to do */
 284     for (lpc = graph->synapses; lpc != NULL; lpc = lpc->next) {
 285         synapse_t *synapse = (synapse_t *) lpc->data;
 286 
 287         if (graph->batch_limit > 0 && graph->pending >= graph->batch_limit) {
 288             crm_debug("Throttling output: batch limit (%d) reached", graph->batch_limit);
 289             break;
 290         } else if (synapse->failed) {
 291             graph->skipped++;
 292             continue;
 293 
 294         } else if (synapse->confirmed || synapse->executed) {
 295             /* Already handled */
 296             continue;
 297         }
 298 
 299         if (should_fire_synapse(graph, synapse)) {
 300             crm_trace("Synapse %d fired", synapse->id);
 301             graph->fired++;
 302             if(fire_synapse(graph, synapse) == FALSE) {
 303                 crm_err("Synapse %d failed to fire", synapse->id);
 304                 stat_log_level = LOG_ERR;
 305                 graph->abort_priority = INFINITY;
 306                 graph->incomplete++;
 307                 graph->fired--;
 308             }
 309 
 310             if (synapse->confirmed == FALSE) {
 311                 graph->pending++;
 312             }
 313 
 314         } else {
 315             crm_trace("Synapse %d cannot fire", synapse->id);
 316             graph->incomplete++;
 317         }
 318     }
 319 
 320     if (graph->pending == 0 && graph->fired == 0) {
 321         graph->complete = TRUE;
 322         stat_log_level = LOG_NOTICE;
 323         pass_result = transition_complete;
 324         status = "Complete";
 325 
 326         if (graph->incomplete != 0 && graph->abort_priority <= 0) {
 327             stat_log_level = LOG_WARNING;
 328             pass_result = transition_terminated;
 329             status = "Terminated";
 330 
 331         } else if (graph->skipped != 0) {
 332             status = "Stopped";
 333         }
 334 
 335     } else if (graph->fired == 0) {
 336         pass_result = transition_pending;
 337     }
 338 
 339     do_crm_log(stat_log_level,
 340                "Transition %d (Complete=%d, Pending=%d,"
 341                " Fired=%d, Skipped=%d, Incomplete=%d, Source=%s): %s",
 342                graph->id, graph->completed, graph->pending, graph->fired,
 343                graph->skipped, graph->incomplete, graph->source, status);
 344 
 345     return pass_result;
 346 }

/* [previous][next][first][last][top][bottom][index][help] */