mirror_corosync/exec/amfsg.c
Lon Hohberger f983d37a2f Patch contains:
A mechanism to defer and recall simultaneous
events in the state machines for amf_cluster,
amf_application and amf_sg.

The implication of this defer and recall mechanism is
that it's now possible to to recover from e.g. several
simultaneous SU failures in an ordered serialized manner.

The events that could be deferred/recalled so far is
SG_FAILOVER_NODE_EV,SG_START_EV,SG_FAILOVER_SU_EV,
CLUSTER_SYNC_READY_EV,APPLICATION_START_EV and
APPLICATION_ASSIGN_WORKLOAD_EV.

Files involved:

Index: exec/amfnode.c
Index: exec/amfsg.c
Index: exec/amfutil.c
Index: exec/amfapp.c
Index: exec/amfcomp.c
Index: exec/amfcluster.c
Index: exec/amf.h



git-svn-id: http://svn.fedorahosted.org/svn/corosync/trunk@1266 fd59a12c-fef9-0310-b244-a6a79926bd2f
2006-10-13 10:18:04 +00:00

1834 lines
50 KiB
C

/** @file amfsg.c
*
* Copyright (c) 2002-2006 MontaVista Software, Inc.
* Author: Steven Dake (sdake@mvista.com)
*
* Copyright (c) 2006 Ericsson AB.
* Author: Hans Feldt, Anders Eriksson, Lars Holm
* - Introduced AMF B.02 information model
* - Use DN in API and multicast messages
* - (Re-)Introduction of event based multicast messages
* - Refactoring of code into several AMF files
* - Component/SU restart, SU failover
* - Constructors/destructors
* - Serializers/deserializers
*
* All rights reserved.
*
*
* This software licensed under BSD license, the text of which follows:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the MontaVista Software, Inc. nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*
* AMF Service Group Class Implementation
*
* This file contains functions for handling AMF-service groups(SGs). It can be
* viewed as the implementation of the AMF Service Group class (called SG)
* as described in SAI-Overview-B.02.01. The SA Forum specification
* SAI-AIS-AMF-B.02.01 has been used as specification of the behaviour
* and is referred to as 'the spec' below.
*
* The functions in this file are responsible for:
* -on request start the service group by instantiating the contained SUs
* -on request assign the service instances it protects to the in-service
* service units it contains respecting as many as possible of the configured
* requirements for the group
* -create and delete an SI-assignment object for each relation between
* an SI and an SU
* -order each contained SU to create and delete CSI-assignments
* -request the Service Instance class (SI) to execute the transfer of the
* HA-state set/remove requests to each component involved
* -fully control the execution of component failover and SU failover
* -on request control the execution of the initial steps of node switchover
* and node failover
* -fully handle the auto adjust procedure
*
* Currently only the 'n+m' redundancy model is implemented. It is the
* ambition to identify n+m specific variables and functions and add the suffix
* '_nplusm' to them so that they can be easily recognized.
*
* When SG is requested to assign workload to all SUs or all SUs hosted on
* a specific node, a procedure containing several steps is executed:
* <1> An algorithm is executed which assigns SIs to SUs respecting the rules
* that has been configured for SG. The algorithm also has to consider
* if assignments between som SIs and SUs already exist. The scope of this
* algorithm is to create SI-assignments and set up requested HA-state for
* each assignment but not to transfer those HA-states to the components.
* <2> All SI-assignments with a requested HA state == ACTIVE are transferred
* to the components concerned before any STANDBY assignments are
* transferred. All components have to acknowledge the setting of the
* ACTIVE HA state before the transfer of any STANDBY assignment is
* initiated.
* <3> All active assignments can not be transferred at the same time to the
* different components because the rules for dependencies between SI and
* SI application wide and CSI and CSI within one SI, has to be respected.
*
* SG is fully responsible for step <1> but not fully responsible for handling
* step <2> and <3>. However, SG uses an attribute called 'dependency level'
* when requsted to assign workload. This parameter refers to an integer that
* has been calculated initially for each SI. The 'dependency level' indicates
* to which extent an SI depends on other SIs such that an SI that depends on
* no other SI is on dependecy_level == 1, an SI that depends only on an SI on
* dependency_level == 1 is on dependency-level == 2.
* An SI that depends on several SIs gets a
* dependency_level that is one unit higher than the SI with the highest
* dependency_level it depends on. When SG is requested to assign the workload
* on a certain dependency level, it requests all SI objects on that level to
* activate (all) SI-assignments that during step <1> has been requested to
* assume the active HA state.
*
* SG contains the following state machines:
* - administrative state machine (ADSM) (NOT IN THIS RELEASE)
* - availability control state machine (ACSM)
*
* The availability control state machine contains two states and one of them
* is composite. Being a composite state means that it contains substates.
* The states are:
* - IDLE (non composite state)
* - MANAGING_SG (composite state)
* MANAGING_SG is entered at several different events which has in common
* the need to set up or change the assignment of SIs to SUs. Only one such
* event can be handled at the time. If new events occur while one event is
* being handled then the new event is saved and will be handled after the
* handling of the first event is ready (return to IDLE state has been done).
* MANAGING_SG handles the following events:
* - start (requests SG to order SU to instantiate all SUs in SG and waits
* for SU to indicate presence state change reports from the SUs and
* finally responds 'started' to the requester)
* - assign (requests SG to assign SIs to SUs according to pre-configured
* rules (if not already done) and transfer the HA state of
* the SIs on the requested SI dependency level. Then SG waits for
* confirmation that the HA state has been succesfully set and
* finally responds 'assigned' to the reqeuster)
* - auto_adjust (this event indicates that the auto-adjust probation timer has
* expired and that SG should evaluate current assignments of
* SIs to SUs and if needed remove current assignments and
* create new according to what is specified in paragraph
* 3.7.1.2)
* - failover_comp (requests SG to failover a specific component according to
* the procedure described in paragraph 3.12.1.3)
* - failover_su (requests SG to failover a specific SU according to the
* procedure described in paragraph 3.12.1.3 and 3.12.1.4)
* - switchover_node (requests SG to execute the recovery actions described
* in 3.12.1.3 and respond to the requester when recovery
* is completed)
* - failover_node (requests SG to execute the recovery actions described
* in 3.12.1.3 and respond to the requester when recovery is
* completed)
*
*/
#include <stdlib.h>
#include <errno.h>
#include "amf.h"
#include "print.h"
#include "main.h"
#include "util.h"
static void acsm_enter_activating_standby (struct amf_sg *sg);
static void delete_si_assignments_in_scope (struct amf_sg *sg);
static void acsm_enter_repairing_su (struct amf_sg *sg);
static void standby_su_activated_cbfn (
struct amf_si_assignment *si_assignment, int result);
static void dependent_si_deactivated_cbfn (
struct amf_si_assignment *si_assignment, int result);
static const char *sg_event_type_text[] = {
"Unknown",
"Failover su",
"Failover node",
"Failover comp",
"Switchover node",
"Start",
"Autoadjust",
"Assign si"
};
typedef struct sg_event {
amf_sg_event_type_t event_type;
amf_sg_t *sg;
amf_su_t *su;
amf_comp_t *comp;
amf_node_t *node;
} sg_event_t;
static void sg_set_event (amf_sg_event_type_t sg_event_type,
amf_sg_t *sg, amf_su_t *su, amf_comp_t *comp, amf_node_t * node,
sg_event_t *sg_event)
{
sg_event->event_type = sg_event_type;
sg_event->node = node;
sg_event->su = su;
sg_event->comp = comp;
sg_event->sg = sg;
}
static void sg_defer_event (amf_sg_event_type_t event_type,
sg_event_t *sg_event)
{
amf_fifo_put (event_type, &sg_event->sg->deferred_events,
sizeof (sg_event_t),
sg_event);
}
static void sg_recall_deferred_events (amf_sg_t *sg)
{
sg_event_t sg_event;
ENTER ("");
if (amf_fifo_get (&sg->deferred_events, &sg_event)) {
switch (sg_event.event_type) {
case SG_FAILOVER_SU_EV:
amf_sg_failover_su_req (sg_event.sg,
sg_event.su, sg_event.node);
break;
case SG_FAILOVER_NODE_EV:
amf_sg_failover_node_req (sg_event.sg,
sg_event.node);
break;
case SG_FAILOVER_COMP_EV:
case SG_SWITCH_OVER_NODE_EV:
case SG_START_EV:
case SG_AUTO_ADJUST_EV:
default:
break;
}
}
}
static void timer_function_sg_recall_deferred_events (void *data)
{
amf_sg_t *sg = (amf_sg_t*)data;
ENTER ("");
sg_recall_deferred_events (sg);
}
static void sg_enter_idle (amf_sg_t *sg)
{
SaNameT dn;
ENTER ("sg: %s state: %d", sg->name.value, sg->avail_state);
sg->avail_state = SG_AC_Idle;
if (sg->recovery_scope.event_type != 0) {
switch (sg->recovery_scope.event_type) {
case SG_FAILOVER_SU_EV:
assert (sg->recovery_scope.sus[0] != NULL);
amf_su_dn_make (sg->recovery_scope.sus[0], &dn);
log_printf (
LOG_NOTICE,
"'%s' %s recovery action finished",
dn.value,
sg_event_type_text[sg->recovery_scope.event_type]);
break;
case SG_FAILOVER_NODE_EV:
amf_node_sg_failed_over (
sg->recovery_scope.node, sg);
log_printf (
LOG_NOTICE,
"'%s for %s' recovery action finished",
sg_event_type_text[sg->recovery_scope.event_type],
sg->name.value);
break;
case SG_START_EV:
amf_application_sg_started (sg->application,
sg, this_amf_node);
break;
default:
log_printf (
LOG_NOTICE,
"'%s' recovery action finished",
sg_event_type_text[0]);
break;
}
}
if (sg->recovery_scope.sus != NULL) {
free ((void *)sg->recovery_scope.sus);
}
if (sg->recovery_scope.sis != NULL) {
free ((void *)sg->recovery_scope.sis);
}
memset (&sg->recovery_scope, 0, sizeof (struct sg_recovery_scope));
sg->node_to_start = NULL;
amf_call_function_asynchronous (
timer_function_sg_recall_deferred_events, sg);
}
static int su_instantiated_count (struct amf_sg *sg)
{
int cnt = 0;
struct amf_su *su;
for (su = sg->su_head; su != NULL; su = su->next) {
if (su->saAmfSUPresenceState == SA_AMF_PRESENCE_INSTANTIATED)
cnt++;
}
return cnt;
}
static int has_any_su_in_scope_active_workload (struct amf_sg *sg)
{
struct amf_su **sus= sg->recovery_scope.sus;
struct amf_si_assignment *si_assignment;
while (*sus != NULL) {
si_assignment = amf_su_get_next_si_assignment (*sus, NULL);
while (si_assignment != NULL) {
if (si_assignment->saAmfSISUHAState !=
SA_AMF_HA_ACTIVE) {
break;
}
si_assignment = amf_su_get_next_si_assignment (
*sus, si_assignment);
}
if (si_assignment != NULL) {
break;
}
sus++;
}
return(*sus == NULL);
}
static int is_standby_for_non_active_si_in_scope (struct amf_sg *sg)
{
struct amf_si **sis= sg->recovery_scope.sis;
struct amf_si_assignment *si_assignment;
/*
* Check if there is any si in the scope which has no active assignment
* and at least one standby assignment.
*/
while (*sis != NULL) {
si_assignment = (*sis)->assigned_sis;
while (si_assignment != NULL) {
if (si_assignment->saAmfSISUHAState ==
SA_AMF_HA_ACTIVE) {
break;
}
si_assignment = si_assignment->next;
}
if (si_assignment == NULL) {
/* There is no ACTIVE assignment ..*/
si_assignment = (*sis)->assigned_sis;
while (si_assignment != NULL) {
if (si_assignment->saAmfSISUHAState ==
SA_AMF_HA_STANDBY) {
break;
}
si_assignment = si_assignment->next;
}
if (si_assignment != NULL) {
/* .. and one STANDBY assignment*/
break;
}
}
sis++;
}
return(*sis != NULL);
}
static void acsm_enter_terminating_suspected (struct amf_sg *sg)
{
struct amf_su **sus= sg->recovery_scope.sus;
sg->avail_state = SG_AC_TerminatingSuspected;
/*
* Terminate suspected SU(s)
*/
while (*sus != 0) {
amf_su_terminate (*sus);
sus++;
}
}
static inline int su_presense_state_is_ored (amf_su_t *su,
SaAmfPresenceStateT state1,SaAmfPresenceStateT state2,
SaAmfPresenceStateT state3)
{
return(su->saAmfSUPresenceState == state1 || su->saAmfSUPresenceState ==
state2 || su->saAmfSUPresenceState == state3) ? 1 : 0;
}
static inline int su_presense_state_is_not (amf_su_t *su,
SaAmfPresenceStateT state1,SaAmfPresenceStateT state2,
SaAmfPresenceStateT state3)
{
return(su->saAmfSUPresenceState != state1 && su->saAmfSUPresenceState !=
state2 && su->saAmfSUPresenceState != state3) ? 1 : 0;
}
/**
* Callback function used by SI when there is no dependent SI to
* deactivate.
* @param sg
*/
static void dependent_si_deactivated_cbfn2 (struct amf_sg *sg)
{
struct amf_su **sus = sg->recovery_scope.sus;
ENTER("'%s'", sg->name.value);
/*
* Select next state depending on if some
* SU in the scope is needs to be terminated.
*/
while (*sus != NULL) {
amf_su_t *su = *sus;
ENTER("SU %s pr_state='%d'",su->name.value,
su->saAmfSUPresenceState);
if (su_presense_state_is_ored (su,
SA_AMF_PRESENCE_UNINSTANTIATED,
SA_AMF_PRESENCE_TERMINATION_FAILED,
SA_AMF_PRESENCE_INSTANTIATION_FAILED)) {
sus++;
continue;
}
break;
}
if (*sus != NULL) {
acsm_enter_terminating_suspected (sg);
} else {
delete_si_assignments_in_scope(sg);
acsm_enter_activating_standby (sg);
}
}
static void timer_function_dependent_si_deactivated2 (void *data)
{
ENTER ("");
amf_sg_t *sg = (amf_sg_t *)data;
dependent_si_deactivated_cbfn2 (sg);
}
static struct amf_si *si_get_dependent (struct amf_si *si)
{
struct amf_si *tmp_si = NULL;
ENTER("'%p'",si->depends_on);
if (si->depends_on != NULL) {
if (si->depends_on->name.length < SA_MAX_NAME_LENGTH) {
si->depends_on->name.value[si->depends_on->name.length] = '\0';
}
SaNameT res_arr[2];
int is_match;
is_match = sa_amf_grep ((char*)si->depends_on->name.value,
"safDepend=.*,safSi=(.*),safApp=.*",
2, res_arr);
if (is_match) {
tmp_si = amf_si_find (si->application,
(char*)res_arr[1].value);
} else {
log_printf (LOG_LEVEL_ERROR, "distinguished name for "
"amf_si_depedency failed\n");
openais_exit_error (AIS_DONE_FATAL_ERR);
}
}
return tmp_si;
}
static struct amf_si *amf_dependent_get_next (struct amf_si *si,
struct amf_si *si_iter)
{
struct amf_si *tmp_si;
struct amf_application *application;
ENTER("");
if (si_iter == NULL) {
assert(amf_cluster != NULL);
application = amf_cluster->application_head;
assert(application != NULL);
tmp_si = application->si_head;
} else {
tmp_si = si_iter->next;
if (tmp_si == NULL) {
application = si->application->next;
if (application == NULL) {
goto out;
}
}
}
for (; tmp_si != NULL; tmp_si = tmp_si->next) {
struct amf_si *depends_on_si = si_get_dependent (tmp_si);
while (depends_on_si != NULL) {
if (depends_on_si == si) {
goto out;
}
depends_on_si = depends_on_si->next;
}
}
out:
return tmp_si;
}
static void acsm_enter_deactivating_dependent_workload (amf_sg_t *sg)
{
struct amf_si **sis= sg->recovery_scope.sis;
struct amf_si_assignment *si_assignment;
int callback_pending = 0;
sg->avail_state = SG_AC_DeactivatingDependantWorkload;
ENTER("'%s'",sg->name.value);
/*
* For each SI in the recovery scope, find all active assignments
* and request them to be deactivated.
*/
while (*sis != NULL) {
struct amf_si *dependent_si;
struct amf_si *si = *sis;
si_assignment = si->assigned_sis;
dependent_si = amf_dependent_get_next (si, NULL);
while (dependent_si != NULL) {
si_assignment = dependent_si->assigned_sis;
while (si_assignment != NULL) {
if (si_assignment->saAmfSISUHAState ==
SA_AMF_HA_ACTIVE) {
si_assignment->requested_ha_state =
SA_AMF_HA_QUIESCED;
callback_pending = 1;
amf_si_ha_state_assume (
si_assignment,
dependent_si_deactivated_cbfn);
}
si_assignment = si_assignment->next;
}
dependent_si = amf_dependent_get_next (si, dependent_si);
}
sis++;
}
if (callback_pending == 0) {
static poll_timer_handle dependent_si_deactivated_handle;
ENTER("");
poll_timer_add (aisexec_poll_handle, 0, sg,
timer_function_dependent_si_deactivated2,
&dependent_si_deactivated_handle);
}
}
/**
* Enter function for state SG_AC_ActivatingStandby. It activates
* one STANDBY assignment for each SI in the recovery scope.
* @param sg
*/
static void acsm_enter_activating_standby (struct amf_sg *sg)
{
struct amf_si **sis= sg->recovery_scope.sis;
struct amf_si_assignment *si_assignment;
int is_no_standby_activated = 1;
ENTER("'%s'",sg->name.value);
sg->avail_state = SG_AC_ActivatingStandby;
/*
* For each SI in the recovery scope, find one standby
* SI assignment and activate it.
*/
while (*sis != NULL) {
si_assignment = (*sis)->assigned_sis;
while (si_assignment != NULL) {
if (si_assignment->saAmfSISUHAState ==
SA_AMF_HA_STANDBY) {
si_assignment->requested_ha_state =
SA_AMF_HA_ACTIVE;
amf_si_ha_state_assume (
si_assignment, standby_su_activated_cbfn);
is_no_standby_activated = 0;
break;
}
si_assignment = si_assignment->next;
}
sis++;
}
if (is_no_standby_activated) {
sg->avail_state = SG_AC_AssigningStandbyToSpare;
acsm_enter_repairing_su (sg);
}
}
static void acsm_enter_repairing_su (struct amf_sg *sg)
{
struct amf_su **sus= sg->recovery_scope.sus;
ENTER("'%s'",sg->name.value);
sg->avail_state = SG_AC_ReparingSu;
int is_any_su_instantiated = 0;
/*
* Instantiate SUs in current recovery scope until the configured
* preference is fulfiled.
*/
while (*sus != NULL) {
if (su_instantiated_count ((*sus)->sg) <
(*sus)->sg->saAmfSGNumPrefInserviceSUs) {
struct amf_node *node =
amf_node_find(&((*sus)->saAmfSUHostedByNode));
if (node == NULL) {
log_printf (LOG_LEVEL_ERROR,
"no node to hosted on su found"
"amf_si_depedency failed\n");
openais_exit_error (AIS_DONE_FATAL_ERR);
}
if (node->saAmfNodeOperState ==
SA_AMF_OPERATIONAL_ENABLED) {
/* node is synchronized */
is_any_su_instantiated = 1;
amf_su_instantiate ((*sus));
}
}
sus++;
}
if (is_any_su_instantiated == 0) {
sg_enter_idle (sg);
}
}
/**
* Checks if the si pointed out is already in the scope.
* @param sg
* @param si
*/
static int is_si_in_scope(struct amf_sg *sg, struct amf_si *si)
{
struct amf_si **tmp_sis= sg->recovery_scope.sis;
while (*tmp_sis != NULL) {
if (*tmp_sis == si) {
break;
}
tmp_sis++;
}
return(*tmp_sis == si);
}
/**
* Adds the si pointed out to the scope.
* @param sg
* @param si
*/
static void add_si_to_scope ( struct amf_sg *sg, struct amf_si *si)
{
int number_of_si = 2; /* It shall be at least two */
struct amf_si **tmp_sis= sg->recovery_scope.sis;
ENTER ("'%s'", si->name.value);
while (*tmp_sis != NULL) {
number_of_si++;
tmp_sis++;
}
sg->recovery_scope.sis = (struct amf_si **)
realloc((void *)sg->recovery_scope.sis,
sizeof (struct amf_si *)*number_of_si);
assert (sg->recovery_scope.sis != NULL);
tmp_sis= sg->recovery_scope.sis;
while (*tmp_sis != NULL) {
tmp_sis++;
}
*tmp_sis = si;
*(++tmp_sis) = NULL;
}
/**
* Adds the ssu pointed out to the scope.
* @param sg
* @param su
*/
static void add_su_to_scope (struct amf_sg *sg, struct amf_su *su)
{
int number_of_su = 2; /* It shall be at least two */
struct amf_su **tmp_sus= sg->recovery_scope.sus;
ENTER ("'%s'", su->name.value);
while (*tmp_sus != NULL) {
number_of_su++;
tmp_sus++;
}
sg->recovery_scope.sus = (struct amf_su **)
realloc((void *)sg->recovery_scope.sus,
sizeof (struct amf_su *)*number_of_su);
assert (sg->recovery_scope.sus != NULL);
tmp_sus= sg->recovery_scope.sus;
while (*tmp_sus != NULL) {
tmp_sus++;
}
*tmp_sus = su;
*(++tmp_sus) = NULL;
}
/**
* Set recovery scope for failover SU.
* @param sg
* @param su
*/
static void set_scope_for_failover_su (struct amf_sg *sg, struct amf_su *su)
{
struct amf_si_assignment *si_assignment;
struct amf_si **sis;
struct amf_su **sus;
SaNameT dn;
sg->recovery_scope.event_type = SG_FAILOVER_SU_EV;
sg->recovery_scope.node = NULL;
sg->recovery_scope.comp = NULL;
sg->recovery_scope.sus = (struct amf_su **)
calloc (2, sizeof (struct amf_su *));
sg->recovery_scope.sis = (struct amf_si **)
calloc (1, sizeof (struct amf_si *));
assert ((sg->recovery_scope.sus != NULL) &&
(sg->recovery_scope.sis != NULL));
sg->recovery_scope.sus[0] = su;
amf_su_dn_make (sg->recovery_scope.sus[0], &dn);
log_printf (
LOG_NOTICE, "'%s' for %s recovery action started",
sg_event_type_text[sg->recovery_scope.event_type],
dn.value);
si_assignment = amf_su_get_next_si_assignment (su, NULL);
while (si_assignment != NULL) {
if (is_si_in_scope(sg, si_assignment->si) == 0) {
add_si_to_scope(sg,si_assignment->si );
}
si_assignment = amf_su_get_next_si_assignment (su, si_assignment);
}
sus = sg->recovery_scope.sus;
dprintf("The following sus are within the scope:\n");
while (*sus != NULL) {
dprintf("%s\n", (*sus)->name.value);
sus++;
}
sis= sg->recovery_scope.sis;
dprintf("The following sis are within the scope:\n");
while (*sis != NULL) {
dprintf("%s\n", (*sis)->name.value);
sis++;
}
}
static void set_scope_for_failover_node (struct amf_sg *sg, struct amf_node *node)
{
struct amf_si_assignment *si_assignment;
struct amf_si **sis;
struct amf_su **sus;
struct amf_su *su;
ENTER ("'%s'", node->name.value);
sg->recovery_scope.event_type = SG_FAILOVER_NODE_EV;
sg->recovery_scope.node = node;
sg->recovery_scope.comp = NULL;
sg->recovery_scope.sus = (struct amf_su **)
calloc (1, sizeof (struct amf_su *));
sg->recovery_scope.sis = (struct amf_si **)
calloc (1, sizeof (struct amf_si *));
log_printf (
LOG_NOTICE, "'%s' for node %s recovery action started",
sg_event_type_text[sg->recovery_scope.event_type],
node->name.value);
assert ((sg->recovery_scope.sus != NULL) &&
(sg->recovery_scope.sis != NULL));
for (su = sg->su_head; su != NULL; su = su->next) {
if (name_match (&node->name, &su->saAmfSUHostedByNode)) {
add_su_to_scope (sg, su);
}
}
sus = sg->recovery_scope.sus;
while (*sus != 0) {
su = *sus;
si_assignment = amf_su_get_next_si_assignment (su, NULL);
while (si_assignment != NULL) {
if (is_si_in_scope(sg, si_assignment->si) == 0) {
add_si_to_scope(sg, si_assignment->si );
}
si_assignment = amf_su_get_next_si_assignment (
su, si_assignment);
}
sus++;
}
sus = sg->recovery_scope.sus;
dprintf("The following sus are within the scope:\n");
while (*sus != NULL) {
dprintf("%s\n", (*sus)->name.value);
sus++;
}
sis = sg->recovery_scope.sis;
dprintf("The following sis are within the scope:\n");
while (*sis != NULL) {
dprintf("%s\n", (*sis)->name.value);
sis++;
}
}
/**
* Delete all SI assignments and all CSI assignments
* by requesting all contained components.
* @param su
*/
static void delete_si_assignments (struct amf_su *su)
{
struct amf_csi *csi;
struct amf_si *si;
struct amf_si_assignment *si_assignment;
struct amf_si_assignment **prev;
ENTER ("'%s'", su->name.value);
for (si = su->sg->application->si_head; si != NULL; si = si->next) {
prev = &si->assigned_sis;
if (!name_match (&si->saAmfSIProtectedbySG, &su->sg->name)) {
continue;
}
for (csi = si->csi_head; csi != NULL; csi = csi->next) {
amf_csi_delete_assignments (csi, su);
}
for (si_assignment = si->assigned_sis; si_assignment != NULL;
si_assignment = si_assignment->next) {
if (si_assignment->su == su) {
struct amf_si_assignment *tmp = si_assignment;
*prev = si_assignment->next;
dprintf ("SI assignment %s unlinked",
tmp->name.value);
free (tmp);
} else {
prev = &si_assignment->next;
}
}
}
}
/**
* Delete all SI assignments and all CSI assignments in current
* recovery scope.
* @param sg
*/
static void delete_si_assignments_in_scope (struct amf_sg *sg)
{
struct amf_su **sus= sg->recovery_scope.sus;
while (*sus != NULL) {
delete_si_assignments (*sus);
sus++;
}
}
/**
* Callback function used by SI when an SI has been deactivated.
* @param si_assignment
* @param result
*/
static void dependent_si_deactivated_cbfn (
struct amf_si_assignment *si_assignment, int result)
{
struct amf_sg *sg = si_assignment->su->sg;
struct amf_su **sus = sg->recovery_scope.sus;
struct amf_su *su;
ENTER ("'%s', %d", si_assignment->si->name.value, result);
/*
* If all SI assignments for all SUs in the SG are not pending,
* goto next state (TerminatingSuspected).
*/
for (su = sg->su_head ; su != NULL; su = su->next) {
struct amf_si_assignment *si_assignment;
si_assignment = amf_su_get_next_si_assignment(su, NULL);
while (si_assignment != NULL) {
if (si_assignment->saAmfSISUHAState !=
si_assignment->requested_ha_state) {
goto still_wating;
}
si_assignment = amf_su_get_next_si_assignment(su,
si_assignment);
}
}
still_wating:
if (su == NULL) {
sus = si_assignment->su->sg->recovery_scope.sus;
/*
* Select next state depending on if some
* SU in the scope is needs to be terminated.
*/
while (*sus != NULL) {
if (su_presense_state_is_not (*sus,
SA_AMF_PRESENCE_UNINSTANTIATED,
SA_AMF_PRESENCE_TERMINATION_FAILED,
SA_AMF_PRESENCE_INSTANTIATION_FAILED)) {
break;
}
sus++;
}
if (*sus != NULL) {
acsm_enter_terminating_suspected (sg);
} else {
delete_si_assignments_in_scope(sg);
acsm_enter_activating_standby (sg);
}
}
LEAVE("");
}
static void standby_su_activated_cbfn (
struct amf_si_assignment *si_assignment, int result)
{
struct amf_su **sus= si_assignment->su->sg->recovery_scope.sus;
struct amf_si **sis= si_assignment->su->sg->recovery_scope.sis;
ENTER ("'%s', %d", si_assignment->si->name.value, result);
/*
* If all SI assignments for all SIs in the scope are activated, goto next
* state.
*/
while (*sis != NULL) {
if ((*sis)->assigned_sis != NULL &&
(*sis)->assigned_sis->saAmfSISUHAState != SA_AMF_HA_ACTIVE) {
break;
}
sis++;
}
if (*sis == NULL) {
/*
* TODO: create SI assignment to spare and assign them
*/
(*sus)->sg->avail_state = SG_AC_AssigningStandbyToSpare;
acsm_enter_repairing_su ((*sus)->sg);
}
}
static void assign_si_assumed_cbfn (
struct amf_si_assignment *si_assignment, int result)
{
struct amf_si_assignment *tmp_si_assignment;
struct amf_si *si;
struct amf_sg *sg = si_assignment->su->sg;
int si_assignment_cnt = 0;
int confirmed_assignments = 0;
ENTER ("'%s', %d", si_assignment->si->name.value, result);
/*
* Report to application when all SIs that this SG protects
* has been assigned or go back to idle state if not cluster
* start.
*/
for (si = sg->application->si_head; si != NULL; si = si->next) {
if (name_match (&si->saAmfSIProtectedbySG, &sg->name)) {
for (tmp_si_assignment = si->assigned_sis;
tmp_si_assignment != NULL;
tmp_si_assignment = tmp_si_assignment->next) {
si_assignment_cnt++;
if (tmp_si_assignment->requested_ha_state ==
tmp_si_assignment->saAmfSISUHAState) {
confirmed_assignments++;
}
}
}
}
assert (confirmed_assignments != 0);
switch (sg->avail_state) {
case SG_AC_AssigningOnRequest:
if (si_assignment_cnt == confirmed_assignments) {
sg_enter_idle (sg);
amf_application_sg_assigned (sg->application, sg);
} else {
dprintf ("%d, %d", si_assignment_cnt, confirmed_assignments);
}
break;
case SG_AC_AssigningStandBy:
{
if (si_assignment_cnt == confirmed_assignments) {
sg_enter_idle (sg);
}
break;
}
default:
dprintf ("%d, %d, %d", sg->avail_state, si_assignment_cnt,
confirmed_assignments);
amf_runtime_attributes_print (amf_cluster);
assert (0);
break;
}
}
static inline int div_round (int a, int b)
{
int res;
assert (b != 0);
res = a / b;
if ((a % b) != 0)
res++;
return res;
}
static int no_su_has_presence_state (
struct amf_sg *sg, struct amf_node *node_to_start,
SaAmfPresenceStateT state)
{
struct amf_su *su;
int no_su_has_presence_state = 1;
for (su = sg->su_head; su != NULL; su = su->next) {
if (su->saAmfSUPresenceState == state) {
if (node_to_start == NULL) {
no_su_has_presence_state = 0;
break;
} else {
if (name_match(&node_to_start->name,
&su->saAmfSUHostedByNode)) {
no_su_has_presence_state = 0;
break;
}
}
}
}
return no_su_has_presence_state;
}
static int all_su_in_scope_has_presence_state (
struct amf_sg *sg, SaAmfPresenceStateT state)
{
struct amf_su **sus= sg->recovery_scope.sus;
while (*sus != NULL) {
if ((*sus)->saAmfSUPresenceState != state) {
break;
}
sus++;
}
return(*sus == NULL);
}
/**
* Get number of SIs protected by the specified SG.
* @param sg
*
* @return int
*/
static int sg_si_count_get (struct amf_sg *sg)
{
struct amf_si *si;
int cnt = 0;
for (si = sg->application->si_head; si != NULL; si = si->next) {
if (name_match (&si->saAmfSIProtectedbySG, &sg->name)) {
cnt += 1;
}
}
return(cnt);
}
static int amf_si_get_saAmfSINumReqActiveAssignments(struct amf_si *si)
{
struct amf_si_assignment *si_assignment = si->assigned_sis;
int number_of_req_active_assignments = 0;
for (; si_assignment != NULL; si_assignment = si_assignment->next) {
if (si_assignment->requested_ha_state == SA_AMF_HA_ACTIVE) {
number_of_req_active_assignments++;
}
}
return number_of_req_active_assignments;
}
static int amf_si_get_saAmfSINumReqStandbyAssignments(struct amf_si *si)
{
struct amf_si_assignment *si_assignment = si->assigned_sis;
int number_of_req_active_assignments = 0;
for (; si_assignment != NULL; si_assignment = si_assignment->next) {
if (si_assignment->requested_ha_state == SA_AMF_HA_STANDBY) {
number_of_req_active_assignments++;
}
}
return number_of_req_active_assignments;
}
static int sg_assign_nm_active (struct amf_sg *sg, int su_active_assign)
{
struct amf_su *su;
struct amf_si *si;
int assigned = 0;
int assign_to_su = 0;
int total_assigned = 0;
int si_left;
int si_total;
int su_left_to_assign = su_active_assign;
si_total = sg_si_count_get (sg);
si_left = si_total;
assign_to_su = div_round (si_left, su_active_assign);
if (assign_to_su > sg->saAmfSGMaxActiveSIsperSUs) {
assign_to_su = sg->saAmfSGMaxActiveSIsperSUs;
}
su = sg->su_head;
while (su != NULL && su_left_to_assign > 0) {
if (amf_su_get_saAmfSUReadinessState (su) !=
SA_AMF_READINESS_IN_SERVICE ||
amf_su_get_saAmfSUNumCurrActiveSIs (su) ==
assign_to_su ||
amf_su_get_saAmfSUNumCurrStandbySIs (su) > 0) {
su = su->next;
continue; /* Not in service */
}
si = sg->application->si_head;
assigned = 0;
assign_to_su = div_round (si_left, su_left_to_assign);
if (assign_to_su > sg->saAmfSGMaxActiveSIsperSUs) {
assign_to_su = sg->saAmfSGMaxActiveSIsperSUs;
}
while (si != NULL) {
if (name_match (&si->saAmfSIProtectedbySG, &sg->name) &&
assigned < assign_to_su &&
amf_si_get_saAmfSINumReqActiveAssignments(si) == 0) {
assigned += 1;
total_assigned += 1;
amf_su_assign_si (su, si, SA_AMF_HA_ACTIVE);
}
si = si->next;
}
su = su->next;
su_left_to_assign -= 1;
si_left -= assigned;
dprintf (" su_left_to_assign =%d, si_left=%d\n",
su_left_to_assign, si_left);
}
assert (total_assigned <= si_total);
if (total_assigned == 0) {
dprintf ("Info: No SIs assigned");
}
LEAVE();
return total_assigned;
}
static int sg_assign_nm_standby (struct amf_sg *sg, int su_standby_assign)
{
struct amf_su *su;
struct amf_si *si;
int assigned = 0;
int assign_to_su = 0;
int total_assigned = 0;
int si_left;
int si_total;
int su_left_to_assign = su_standby_assign;
ENTER ("'%s'", sg->name.value);
if (su_standby_assign == 0) {
return 0;
}
si_total = sg_si_count_get (sg);
si_left = si_total;
assign_to_su = div_round (si_left, su_standby_assign);
if (assign_to_su > sg->saAmfSGMaxStandbySIsperSUs) {
assign_to_su = sg->saAmfSGMaxStandbySIsperSUs;
}
su = sg->su_head;
while (su != NULL && su_left_to_assign > 0) {
if (amf_su_get_saAmfSUReadinessState (su) !=
SA_AMF_READINESS_IN_SERVICE ||
amf_su_get_saAmfSUNumCurrActiveSIs (su) > 0 ||
amf_su_get_saAmfSUNumCurrStandbySIs (su) ==
assign_to_su) {
su = su->next;
continue; /* Not available for assignment */
}
si = sg->application->si_head;
assigned = 0;
assign_to_su = div_round (si_left, su_left_to_assign);
if (assign_to_su > sg->saAmfSGMaxStandbySIsperSUs) {
assign_to_su = sg->saAmfSGMaxStandbySIsperSUs;
}
while (si != NULL) {
if (name_match (&si->saAmfSIProtectedbySG, &sg->name) &&
assigned < assign_to_su &&
amf_si_get_saAmfSINumReqStandbyAssignments (si) == 0) {
assigned += 1;
total_assigned += 1;
amf_su_assign_si (su, si, SA_AMF_HA_STANDBY);
}
si = si->next;
}
su_left_to_assign -= 1;
si_left -= assigned;
dprintf (" su_left_to_assign =%d, si_left=%d\n",
su_left_to_assign, si_left);
su = su->next;
}
assert (total_assigned <= si_total);
if (total_assigned == 0) {
dprintf ("Info: No SIs assigned!");
}
return total_assigned;
}
static int su_inservice_count_get (struct amf_sg *sg)
{
struct amf_su *su;
int answer = 0;
for (su = sg->su_head; su != NULL; su = su->next) {
if (amf_su_get_saAmfSUReadinessState (su) ==
SA_AMF_READINESS_IN_SERVICE) {
answer += 1;
}
}
return(answer);
}
/**
* TODO: dependency_level not used, hard coded
* @param sg
* @param dependency_level
*/
static int assign_si (struct amf_sg *sg, int dependency_level)
{
int active_sus_needed = 0;
int standby_sus_needed = 0;
int inservice_count;
int su_active_assign;
int su_standby_assign;
int su_spare_assign;
int assigned = 0;
ENTER ("'%s'", sg->name.value);
/**
* Phase 1: Calculate assignments and create all runtime objects in
* information model. Do not do the actual assignment, done in
* phase 2.
*/
/**
* Calculate number of SUs to assign to active or standby state
*/
inservice_count = su_inservice_count_get (sg);
if (sg->saAmfSGNumPrefActiveSUs > 0) {
dprintf("LHL sg_si_count_get (sg) %d ,sg->saAmfSGMaxActiveSIsperSUs %d, ",
sg_si_count_get (sg),
sg->saAmfSGMaxActiveSIsperSUs);
active_sus_needed = div_round (
sg_si_count_get (sg),
sg->saAmfSGMaxActiveSIsperSUs);
} else {
log_printf (LOG_LEVEL_ERROR, "ERROR: saAmfSGNumPrefActiveSUs == 0 !!");
openais_exit_error (AIS_DONE_FATAL_ERR);
}
if (sg->saAmfSGNumPrefStandbySUs > 0) {
standby_sus_needed = div_round (
sg_si_count_get (sg),
sg->saAmfSGMaxStandbySIsperSUs);
} else {
log_printf (LOG_LEVEL_ERROR, "ERROR: saAmfSGNumPrefStandbySUs == 0 !!");
openais_exit_error (AIS_DONE_FATAL_ERR);
}
dprintf ("(inservice=%d) (active_sus_needed=%d) (standby_sus_needed=%d)"
"\n",
inservice_count, active_sus_needed, standby_sus_needed);
/* Determine number of active and standby service units
* to assign based upon reduction procedure
*/
if ((inservice_count < active_sus_needed)) {
dprintf ("assignment VI - partial assignment with SIs drop outs\n");
su_active_assign = inservice_count;
su_standby_assign = 0;
su_spare_assign = 0;
} else
if ((inservice_count < active_sus_needed + standby_sus_needed)) {
dprintf ("assignment V - partial assignment with reduction of"
" standby units\n");
su_active_assign = active_sus_needed;
su_standby_assign = inservice_count - active_sus_needed;
su_spare_assign = 0;
} else
if ((inservice_count < sg->saAmfSGNumPrefActiveSUs + standby_sus_needed)) {
dprintf ("IV: full assignment with reduction of active service"
" units\n");
su_active_assign = inservice_count - standby_sus_needed;
su_standby_assign = standby_sus_needed;
su_spare_assign = 0;
} else
if ((inservice_count <
sg->saAmfSGNumPrefActiveSUs + sg->saAmfSGNumPrefStandbySUs)) {
dprintf ("III: full assignment with reduction of standby service"
" units\n");
su_active_assign = sg->saAmfSGNumPrefActiveSUs;
su_standby_assign = inservice_count - sg->saAmfSGNumPrefActiveSUs;
su_spare_assign = 0;
} else
if ((inservice_count ==
sg->saAmfSGNumPrefActiveSUs + sg->saAmfSGNumPrefStandbySUs)) {
if (sg->saAmfSGNumPrefInserviceSUs > inservice_count) {
dprintf ("II: full assignment with spare reduction\n");
} else {
dprintf ("II: full assignment without spares\n");
}
su_active_assign = sg->saAmfSGNumPrefActiveSUs;
su_standby_assign = sg->saAmfSGNumPrefStandbySUs;
su_spare_assign = 0;
} else {
dprintf ("I: full assignment with spares\n");
su_active_assign = sg->saAmfSGNumPrefActiveSUs;
su_standby_assign = sg->saAmfSGNumPrefStandbySUs;
su_spare_assign = inservice_count -
sg->saAmfSGNumPrefActiveSUs - sg->saAmfSGNumPrefStandbySUs;
}
dprintf ("(inservice=%d) (assigning active=%d) (assigning standby=%d)"
" (assigning spares=%d)\n",
inservice_count, su_active_assign, su_standby_assign, su_spare_assign);
if (inservice_count > 0) {
assigned = sg_assign_nm_active (sg, su_active_assign);
assigned += sg_assign_nm_standby (sg, su_standby_assign);
sg->saAmfSGNumCurrAssignedSUs = inservice_count;
/**
* Phase 2: do the actual assignment to the component
* TODO: first do active, then standby
*/
{
struct amf_si *si;
struct amf_si_assignment *si_assignment;
for (si = sg->application->si_head; si != NULL; si = si->next) {
if (name_match (&si->saAmfSIProtectedbySG, &sg->name)) {
for (si_assignment = si->assigned_sis;
si_assignment != NULL;
si_assignment = si_assignment->next) {
if (si_assignment->requested_ha_state !=
si_assignment->saAmfSISUHAState) {
amf_si_ha_state_assume (
si_assignment, assign_si_assumed_cbfn);
}
}
}
}
}
}
LEAVE ("'%s'", sg->name.value);
return assigned;
}
int amf_sg_assign_si_req (struct amf_sg *sg, int dependency_level)
{
int posible_to_assign_si;
sg->recovery_scope.event_type = SG_ASSIGN_SI_EV;
sg->avail_state = SG_AC_AssigningOnRequest;
if ((posible_to_assign_si = assign_si (sg, dependency_level)) == 0) {
sg_enter_idle (sg);
}
return posible_to_assign_si;
}
void amf_sg_failover_node_req (struct amf_sg *sg, struct amf_node *node)
{
ENTER("'%s, %s'",node->name.value, sg->name.value);
sg_event_t sg_event;
switch (sg->avail_state) {
case SG_AC_Idle:
set_scope_for_failover_node(sg, node);
if (has_any_su_in_scope_active_workload (sg)) {
acsm_enter_deactivating_dependent_workload (sg);
} else {
amf_su_t **sus = sg->recovery_scope.sus;
/*
* Select next state depending on if some
* SU in the scope needs to be terminated.
*/
while (*sus != NULL) {
amf_su_t *su = *sus;
ENTER("SU %s pr_state='%d'",su->name.value,
su->saAmfSUPresenceState);
if (su_presense_state_is_ored (su,
SA_AMF_PRESENCE_UNINSTANTIATED,
SA_AMF_PRESENCE_TERMINATION_FAILED,
SA_AMF_PRESENCE_INSTANTIATION_FAILED)) {
sus++;
continue;
}
break;
}
if (*sus != NULL) {
acsm_enter_terminating_suspected (sg);
} else {
delete_si_assignments_in_scope (sg);
sg_enter_idle (sg);
}
}
break;
case SG_AC_DeactivatingDependantWorkload:
case SG_AC_TerminatingSuspected:
case SG_AC_ActivatingStandby:
case SG_AC_AssigningStandbyToSpare:
case SG_AC_ReparingComponent:
case SG_AC_ReparingSu:
case SG_AC_AssigningOnRequest:
case SG_AC_InstantiatingServiceUnits:
case SG_AC_RemovingAssignment:
case SG_AC_AssigningActiveworkload:
case SG_AC_AssigningAutoAdjust:
case SG_AC_AssigningStandBy:
case SG_AC_WaitingAfterOperationFailed:
sg_set_event (SG_FAILOVER_NODE_EV, sg, 0, 0, node, &sg_event);
sg_defer_event (SG_FAILOVER_NODE_EV, &sg_event);
break;
default:
assert (0);
break;
}
}
void amf_sg_start (struct amf_sg *sg, struct amf_node *node)
{
sg_event_t sg_event;
sg->recovery_scope.event_type = SG_START_EV;
switch (sg->avail_state) {
case SG_AC_Idle: {
amf_su_t *su;
sg_avail_control_state_t old_avail_state = sg->avail_state;
int instantiated_sus = 0;
ENTER ("'%s'", sg->name.value);
sg->node_to_start = node;
sg->avail_state = SG_AC_InstantiatingServiceUnits;
for (su = sg->su_head;
(su != NULL) &&
(instantiated_sus < sg->saAmfSGNumPrefInserviceSUs);
su = su->next) {
if (node == NULL) {
/*
* Cluster start
*/
amf_su_instantiate (su);
instantiated_sus++;
} else {
/*
* Node start, match if SU is hosted on the
* specified node
*/
if (name_match (&node->name,
&su->saAmfSUHostedByNode)) {
amf_su_instantiate (su);
instantiated_sus++;
}
}
}
if (instantiated_sus == 0) {
sg->avail_state = old_avail_state;
}
break;
}
case SG_AC_InstantiatingServiceUnits:
sg_set_event (SG_START_EV, sg, 0, 0, node, &sg_event);
sg_defer_event (SG_START_EV, &sg_event);
break;
case SG_AC_DeactivatingDependantWorkload:
case SG_AC_TerminatingSuspected:
case SG_AC_ActivatingStandby:
case SG_AC_AssigningStandbyToSpare:
case SG_AC_ReparingComponent:
case SG_AC_ReparingSu:
case SG_AC_AssigningOnRequest:
case SG_AC_RemovingAssignment:
case SG_AC_AssigningActiveworkload:
case SG_AC_AssigningAutoAdjust:
case SG_AC_AssigningStandBy:
case SG_AC_WaitingAfterOperationFailed:
default:
assert (0);
break;
}
}
void amf_sg_su_state_changed (struct amf_sg *sg,
struct amf_su *su, SaAmfStateT type, int state)
{
ENTER ("'%s' SU '%s' state %s",
sg->name.value, su->name.value, amf_presence_state(state));
if (type == SA_AMF_PRESENCE_STATE) {
if (state == SA_AMF_PRESENCE_INSTANTIATED) {
if (sg->avail_state == SG_AC_InstantiatingServiceUnits) {
if (no_su_has_presence_state(sg, sg->node_to_start,
SA_AMF_PRESENCE_INSTANTIATING)) {
sg_enter_idle (sg);
}
} else if (sg->avail_state == SG_AC_ReparingSu) {
if (all_su_in_scope_has_presence_state(su->sg,
SA_AMF_PRESENCE_INSTANTIATED)) {
su->sg->avail_state = SG_AC_AssigningStandBy;
if (assign_si (sg, 0) == 0) {
sg_enter_idle (sg);
}
} else {
dprintf ("avail-state: %u", sg->avail_state);
assert (0);
}
} else {
dprintf ("avail-state: %u", sg->avail_state);
assert (0);
}
} else if (state == SA_AMF_PRESENCE_UNINSTANTIATED) {
if (sg->avail_state == SG_AC_TerminatingSuspected) {
if (all_su_in_scope_has_presence_state (sg, state)) {
delete_si_assignments_in_scope (sg);
if (is_standby_for_non_active_si_in_scope (sg)) {
acsm_enter_activating_standby (sg);
} else {
/*
* TODO: create SI assignment to spare and assign them
*/
sg->avail_state = SG_AC_AssigningStandbyToSpare;
acsm_enter_repairing_su (sg);
}
}
} else {
assert (0);
}
} else if (state == SA_AMF_PRESENCE_INSTANTIATING) {
; /* nop */
} else if (state == SA_AMF_PRESENCE_INSTANTIATION_FAILED) {
if (sg->avail_state == SG_AC_InstantiatingServiceUnits) {
if (no_su_has_presence_state(sg, sg->node_to_start,
SA_AMF_PRESENCE_INSTANTIATING)) {
sg_enter_idle (sg);
}
}
} else {
assert (0);
}
} else {
assert (0);
}
}
void amf_sg_init (void)
{
log_init ("AMF");
}
void amf_sg_failover_su_req (struct amf_sg *sg, struct amf_su *su,
struct amf_node *node)
{
ENTER ("");
sg_event_t sg_event;
switch (sg->avail_state) {
case SG_AC_Idle:
set_scope_for_failover_su (sg, su);
if (has_any_su_in_scope_active_workload (sg)) {
acsm_enter_deactivating_dependent_workload (sg);
} else {
acsm_enter_terminating_suspected (sg);
}
break;
case SG_AC_DeactivatingDependantWorkload:
case SG_AC_TerminatingSuspected:
case SG_AC_ActivatingStandby:
case SG_AC_AssigningStandbyToSpare:
case SG_AC_ReparingComponent:
case SG_AC_ReparingSu:
case SG_AC_AssigningOnRequest:
case SG_AC_InstantiatingServiceUnits:
case SG_AC_RemovingAssignment:
case SG_AC_AssigningActiveworkload:
case SG_AC_AssigningAutoAdjust:
case SG_AC_AssigningStandBy:
case SG_AC_WaitingAfterOperationFailed:
sg_set_event (SG_FAILOVER_SU_EV, sg, su, 0, 0, &sg_event);
sg_defer_event (SG_FAILOVER_SU_EV, &sg_event);
break;
default:
assert (0);
break;
}
}
/**
* Constructor for SG objects. Adds SG to the list owned by
* the specified application. Always returns a valid SG
* object, out-of-memory problems are handled here. Default
* values are initialized.
* @param sg
* @param name
*
* @return struct amf_sg*
*/
struct amf_sg *amf_sg_new (struct amf_application *app, char *name)
{
struct amf_sg *sg = amf_calloc (1, sizeof (struct amf_sg));
setSaNameT (&sg->name, name);
sg->saAmfSGAdminState = SA_AMF_ADMIN_UNLOCKED;
sg->saAmfSGNumPrefActiveSUs = 1;
sg->saAmfSGNumPrefStandbySUs = 1;
sg->saAmfSGNumPrefInserviceSUs = ~0;
sg->saAmfSGNumPrefAssignedSUs = ~0;
sg->saAmfSGCompRestartProb = -1;
sg->saAmfSGCompRestartMax = ~0;
sg->saAmfSGSuRestartProb = -1;
sg->saAmfSGSuRestartMax = ~0;
sg->saAmfSGAutoAdjustProb = -1;
sg->saAmfSGAutoRepair = SA_TRUE;
sg->application = app;
sg->next = app->sg_head;
app->sg_head = sg;
sg->deferred_events = NULL;
return sg;
}
void amf_sg_delete (struct amf_sg *sg)
{
struct amf_su *su;
for (su = sg->su_head; su != NULL;) {
struct amf_su *tmp = su;
su = su->next;
amf_su_delete (tmp);
}
free (sg);
}
void *amf_sg_serialize (struct amf_sg *sg, int *len)
{
char *buf = NULL;
int offset = 0, size = 0;
TRACE8 ("%s", sg->name.value);
buf = amf_serialize_SaNameT (buf, &size, &offset, &sg->name);
buf = amf_serialize_SaUint32T (buf, &size, &offset, sg->saAmfSGRedundancyModel);
buf = amf_serialize_SaUint32T (
buf, &size, &offset, sg->saAmfSGAutoAdjust);
buf = amf_serialize_SaUint32T (
buf, &size, &offset, sg->saAmfSGNumPrefActiveSUs);
buf = amf_serialize_SaUint32T (
buf, &size, &offset, sg->saAmfSGNumPrefStandbySUs);
buf = amf_serialize_SaUint32T (
buf, &size, &offset, sg->saAmfSGNumPrefInserviceSUs);
buf = amf_serialize_SaUint32T (
buf, &size, &offset, sg->saAmfSGNumPrefAssignedSUs);
buf = amf_serialize_SaUint32T (
buf, &size, &offset, sg->saAmfSGMaxActiveSIsperSUs);
buf = amf_serialize_SaUint32T (
buf, &size, &offset, sg->saAmfSGMaxStandbySIsperSUs);
buf = amf_serialize_SaUint32T (
buf, &size, &offset, sg->saAmfSGCompRestartProb);
buf = amf_serialize_SaUint32T (
buf, &size, &offset, sg->saAmfSGCompRestartMax);
buf = amf_serialize_SaUint32T (
buf, &size, &offset, sg->saAmfSGSuRestartProb);
buf = amf_serialize_SaUint32T (
buf, &size, &offset, sg->saAmfSGSuRestartMax);
buf = amf_serialize_SaUint32T (
buf, &size, &offset, sg->saAmfSGAutoAdjustProb);
buf = amf_serialize_SaUint32T (
buf, &size, &offset, sg->saAmfSGAutoRepair);
buf = amf_serialize_SaUint32T (
buf, &size, &offset, sg->saAmfSGAdminState);
buf = amf_serialize_SaUint32T (
buf, &size, &offset, sg->saAmfSGNumCurrAssignedSUs);
buf = amf_serialize_SaUint32T (
buf, &size, &offset, sg->saAmfSGNumCurrNonInstantiatedSpareSUs);
buf = amf_serialize_SaUint32T (
buf, &size, &offset, sg->saAmfSGNumCurrInstantiatedSpareSUs);
buf = amf_serialize_SaStringT (
buf, &size, &offset, sg->clccli_path);
buf = amf_serialize_SaUint32T (
buf, &size, &offset, sg->avail_state);
*len = offset;
return buf;
}
struct amf_sg *amf_sg_deserialize (struct amf_application *app, char *buf)
{
char *tmp = buf;
struct amf_sg *sg = amf_sg_new (app, "");
tmp = amf_deserialize_SaNameT (tmp, &sg->name);
tmp = amf_deserialize_SaUint32T (tmp, &sg->saAmfSGRedundancyModel);
tmp = amf_deserialize_SaUint32T (tmp, &sg->saAmfSGAutoAdjust);
tmp = amf_deserialize_SaUint32T (tmp, &sg->saAmfSGNumPrefActiveSUs);
tmp = amf_deserialize_SaUint32T (tmp, &sg->saAmfSGNumPrefStandbySUs);
tmp = amf_deserialize_SaUint32T (tmp, &sg->saAmfSGNumPrefInserviceSUs);
tmp = amf_deserialize_SaUint32T (tmp, &sg->saAmfSGNumPrefAssignedSUs);
tmp = amf_deserialize_SaUint32T (tmp, &sg->saAmfSGMaxActiveSIsperSUs);
tmp = amf_deserialize_SaUint32T (tmp, &sg->saAmfSGMaxStandbySIsperSUs);
tmp = amf_deserialize_SaUint32T (tmp, &sg->saAmfSGCompRestartProb);
tmp = amf_deserialize_SaUint32T (tmp, &sg->saAmfSGCompRestartMax);
tmp = amf_deserialize_SaUint32T (tmp, &sg->saAmfSGSuRestartProb);
tmp = amf_deserialize_SaUint32T (tmp, &sg->saAmfSGSuRestartMax);
tmp = amf_deserialize_SaUint32T (tmp, &sg->saAmfSGAutoAdjustProb);
tmp = amf_deserialize_SaUint32T (tmp, &sg->saAmfSGAutoRepair);
tmp = amf_deserialize_SaUint32T (tmp, &sg->saAmfSGAdminState);
tmp = amf_deserialize_SaUint32T (tmp, &sg->saAmfSGNumCurrAssignedSUs);
tmp = amf_deserialize_SaUint32T (tmp, &sg->saAmfSGNumCurrNonInstantiatedSpareSUs);
tmp = amf_deserialize_SaUint32T (tmp, &sg->saAmfSGNumCurrInstantiatedSpareSUs);
tmp = amf_deserialize_SaStringT (tmp, &sg->clccli_path);
tmp = amf_deserialize_SaUint32T (tmp, &sg->avail_state);
return sg;
}
struct amf_sg *amf_sg_find (struct amf_application *app, char *name)
{
struct amf_sg *sg;
for (sg = app->sg_head; sg != NULL; sg = sg->next) {
if (sg->name.length == strlen(name) &&
strncmp (name, (char*)sg->name.value, sg->name.length) == 0) {
break;
}
}
return sg;
}