1020 lines
38 KiB
C
1020 lines
38 KiB
C
//
|
|
// Copyright (c) 2014 Wind River Systems, Inc.
|
|
//
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
//
|
|
#include "sm_service_domain_filter.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
|
|
#include "sm_limits.h"
|
|
#include "sm_types.h"
|
|
#include "sm_debug.h"
|
|
#include "sm_time.h"
|
|
#include "sm_db.h"
|
|
#include "sm_db_foreach.h"
|
|
#include "sm_db_nodes.h"
|
|
#include "sm_service_domain_member_table.h"
|
|
#include "sm_service_domain_neighbor_table.h"
|
|
#include "sm_service_domain_assignment_table.h"
|
|
#include "sm_node_api.h"
|
|
#include "sm_node_swact_monitor.h"
|
|
#include "sm_node_utils.h"
|
|
#include "sm_failover_utils.h"
|
|
|
|
static SmDbHandleT* _sm_db_handle = NULL;
|
|
|
|
// ****************************************************************************
|
|
// Service Domain Filter - Cleanup
|
|
// ===============================
|
|
static void sm_service_domain_filter_cleanup( void* user_data[],
|
|
SmServiceDomainAssignmentT* assignment )
|
|
{
|
|
assignment->sched_list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLED;
|
|
}
|
|
// ****************************************************************************
|
|
|
|
// ****************************************************************************
|
|
// Service Domain Filter - By Node Ready
|
|
// =====================================
|
|
static void sm_service_domain_filter_by_node_ready( void* user_data[],
|
|
SmServiceDomainAssignmentT* assignment )
|
|
{
|
|
SmServiceDomainFilterCountsT* counts;
|
|
SmDbNodeT node;
|
|
SmServiceDomainSchedulingListT list;
|
|
SmErrorT error;
|
|
|
|
counts = (SmServiceDomainFilterCountsT*) user_data[0];
|
|
|
|
list = assignment->sched_list;
|
|
|
|
error = sm_db_nodes_read( _sm_db_handle, assignment->node_name, &node );
|
|
if( SM_OKAY == error )
|
|
{
|
|
|
|
if( SM_NODE_READY_STATE_ENABLED != node.ready_state )
|
|
{
|
|
list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_UNAVAILABLE;
|
|
++(counts->unavailable_members);
|
|
}
|
|
} else if( SM_NOT_FOUND == error ) {
|
|
list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_UNAVAILABLE;
|
|
++(counts->unavailable_members);
|
|
|
|
} else {
|
|
DPRINTFE( "Failed to read node (%s) info, error = %s.",
|
|
assignment->node_name, sm_error_str(error) );
|
|
return;
|
|
}
|
|
|
|
if( list != assignment->sched_list )
|
|
{
|
|
assignment->sched_list = list;
|
|
}
|
|
}
|
|
// ****************************************************************************
|
|
|
|
// ****************************************************************************
|
|
// Service Domain Filter - By Node Administrative State
|
|
// ====================================================
|
|
static void sm_service_domain_filter_by_node_admin_state( void* user_data[],
|
|
SmServiceDomainAssignmentT* assignment )
|
|
{
|
|
SmServiceDomainFilterCountsT* counts;
|
|
SmDbNodeT node;
|
|
SmServiceDomainSchedulingListT list;
|
|
SmErrorT error;
|
|
|
|
counts = (SmServiceDomainFilterCountsT*) user_data[0];
|
|
|
|
list = assignment->sched_list;
|
|
|
|
error = sm_db_nodes_read( _sm_db_handle, assignment->node_name, &node );
|
|
if( SM_OKAY == error )
|
|
{
|
|
if( SM_NODE_ADMIN_STATE_LOCKED == node.admin_state )
|
|
{
|
|
#ifdef SM_CONFIG_OPTION_STANDBY_ALL_SERVICES_ON_A_LOCKED_NODE
|
|
switch( list )
|
|
{
|
|
case SM_SERVICE_DOMAIN_SCHEDULING_LIST_ACTIVE:
|
|
--(counts->active_members);
|
|
list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_STANDBY;
|
|
++(counts->go_standby_members);
|
|
break;
|
|
case SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_ACTIVE:
|
|
--(counts->go_active_members);
|
|
list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_STANDBY;
|
|
++(counts->go_standby_members);
|
|
break;
|
|
default:
|
|
//Ignore.
|
|
break;
|
|
}
|
|
#else
|
|
// Adjust counts.
|
|
switch( list )
|
|
{
|
|
case SM_SERVICE_DOMAIN_SCHEDULING_LIST_ACTIVE:
|
|
--(counts->active_members);
|
|
break;
|
|
case SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_ACTIVE:
|
|
--(counts->go_active_members);
|
|
break;
|
|
case SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_STANDBY:
|
|
--(counts->go_standby_members);
|
|
break;
|
|
case SM_SERVICE_DOMAIN_SCHEDULING_LIST_STANDBY:
|
|
--(counts->standby_members);
|
|
break;
|
|
case SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLING:
|
|
--(counts->disabling_members);
|
|
break;
|
|
case SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLED:
|
|
--(counts->disabled_members);
|
|
break;
|
|
case SM_SERVICE_DOMAIN_SCHEDULING_LIST_FAILED:
|
|
--(counts->failed_members);
|
|
break;
|
|
case SM_SERVICE_DOMAIN_SCHEDULING_LIST_FATAL:
|
|
case SM_SERVICE_DOMAIN_SCHEDULING_LIST_UNAVAILABLE:
|
|
default:
|
|
//Ignore.
|
|
break;
|
|
}
|
|
|
|
if(( SM_SERVICE_DOMAIN_SCHEDULING_LIST_FATAL != list )&&
|
|
( SM_SERVICE_DOMAIN_SCHEDULING_LIST_UNAVAILABLE != list ))
|
|
{
|
|
list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_UNAVAILABLE;
|
|
++(counts->unavailable_members);
|
|
}
|
|
#endif // SM_CONFIG_OPTION_STANDBY_ALL_SERVICES_ON_A_LOCKED_NODE
|
|
}
|
|
} else if( SM_NOT_FOUND != error ) {
|
|
DPRINTFE( "Failed to read node (%s) info, error = %s.",
|
|
assignment->node_name, sm_error_str(error) );
|
|
return;
|
|
}
|
|
|
|
if( list != assignment->sched_list )
|
|
{
|
|
assignment->sched_list = list;
|
|
}
|
|
}
|
|
// ****************************************************************************
|
|
|
|
// ****************************************************************************
|
|
// Service Domain Filter - By Neighbor
|
|
// ===================================
|
|
static void sm_service_domain_filter_by_neighbor( void* user_data[],
|
|
SmServiceDomainAssignmentT* assignment )
|
|
{
|
|
SmServiceDomainFilterCountsT* counts;
|
|
SmServiceDomainSchedulingListT list;
|
|
SmServiceDomainNeighborT* neighbor;
|
|
SmErrorT error;
|
|
|
|
counts = (SmServiceDomainFilterCountsT*) user_data[0];
|
|
|
|
list = assignment->sched_list;
|
|
|
|
neighbor = sm_service_domain_neighbor_table_read( assignment->node_name,
|
|
assignment->name );
|
|
if( NULL != neighbor )
|
|
{
|
|
if( SM_SERVICE_DOMAIN_NEIGHBOR_STATE_FULL != neighbor->state )
|
|
{
|
|
list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_UNAVAILABLE;
|
|
++(counts->unavailable_members);
|
|
|
|
} else {
|
|
if( SM_SERVICE_DOMAIN_SCHEDULING_LIST_UNAVAILABLE == list )
|
|
{
|
|
list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLED;
|
|
// Don't increment here as the counts will be
|
|
// thrown off later, assignment filter will do
|
|
// the increment.
|
|
}
|
|
}
|
|
} else {
|
|
char hostname[SM_NODE_NAME_MAX_CHAR];
|
|
|
|
error = sm_node_api_get_hostname( hostname );
|
|
if( SM_OKAY != error )
|
|
{
|
|
DPRINTFE( "Failed to get hostname, error=%s.",
|
|
sm_error_str( error ) );
|
|
return;
|
|
}
|
|
|
|
if( 0 != strcmp( hostname, assignment->node_name ) )
|
|
{
|
|
list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_UNAVAILABLE;
|
|
++(counts->unavailable_members);
|
|
}
|
|
}
|
|
|
|
if( list != assignment->sched_list )
|
|
{
|
|
assignment->sched_list = list;
|
|
}
|
|
}
|
|
// ****************************************************************************
|
|
|
|
// ****************************************************************************
|
|
// Service Domain Filter - By Assignment
|
|
// =====================================
|
|
static void sm_service_domain_filter_by_assignment( void* user_data[],
|
|
SmServiceDomainAssignmentT* assignment )
|
|
{
|
|
SmServiceDomainFilterCountsT* counts;
|
|
SmServiceDomainSchedulingListT list;
|
|
|
|
counts = (SmServiceDomainFilterCountsT*) user_data[0];
|
|
|
|
list = assignment->sched_list;
|
|
|
|
++(counts->total_members);
|
|
|
|
// Previous filter might have already decided that this assignment
|
|
// needs to be put on the unavailable or disabled list (node checks).
|
|
if( SM_SERVICE_DOMAIN_SCHEDULING_LIST_UNAVAILABLE == assignment->sched_list )
|
|
{
|
|
DPRINTFD( "Member assignment (%s) for service domain (%s) node (%s) "
|
|
"is unavailable.", assignment->service_group_name,
|
|
assignment->name, assignment->node_name );
|
|
return;
|
|
}
|
|
|
|
// The scheduler decided that this assignment needs to be disabled.
|
|
if( SM_SERVICE_DOMAIN_SCHEDULING_STATE_DISABLE == assignment->sched_state )
|
|
{
|
|
// Assignment is failed, move to the failed scheduling list.
|
|
if( SM_SERVICE_GROUP_STATUS_FAILED == assignment->status )
|
|
{
|
|
// Fatal condition is looked at later when the health of all
|
|
// assignments is compared.
|
|
list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_FAILED;
|
|
++(counts->failed_members);
|
|
} else {
|
|
// Put it on the unavailable list, so that it can't be chosen.
|
|
list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_UNAVAILABLE;
|
|
++(counts->unavailable_members);
|
|
}
|
|
goto UPDATE;
|
|
}
|
|
|
|
// Request to swact from this assignment has been indicated.
|
|
if(( SM_SERVICE_DOMAIN_SCHEDULING_STATE_SWACT == assignment->sched_state )||
|
|
( SM_SERVICE_DOMAIN_SCHEDULING_STATE_SWACT_FORCE == assignment->sched_state ))
|
|
{
|
|
if(( SM_SERVICE_GROUP_STATE_ACTIVE == assignment->state )||
|
|
( SM_SERVICE_GROUP_STATE_GO_ACTIVE == assignment->state ))
|
|
{
|
|
SmServiceDomainMemberT* member;
|
|
|
|
member = sm_service_domain_member_table_read( assignment->name,
|
|
assignment->service_group_name );
|
|
if( NULL == member )
|
|
{
|
|
list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_STANDBY;
|
|
++(counts->go_standby_members);
|
|
|
|
DPRINTFE( "Failed to read service domain (%s) member (%s), "
|
|
"error=%s.", assignment->name,
|
|
assignment->service_group_name,
|
|
sm_error_str(SM_NOT_FOUND) );
|
|
goto UPDATE;
|
|
}
|
|
|
|
if( 0 < member->m_standby )
|
|
{
|
|
list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_STANDBY;
|
|
++(counts->go_standby_members);
|
|
} else {
|
|
list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLED;
|
|
++(counts->disabled_members);
|
|
}
|
|
} else if( SM_SERVICE_GROUP_STATE_STANDBY == assignment->state ) {
|
|
list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_STANDBY;
|
|
++(counts->standby_members);
|
|
|
|
} else {
|
|
list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLED;
|
|
++(counts->disabled_members);
|
|
}
|
|
goto UPDATE;
|
|
}
|
|
|
|
// Assignment is failed, move to the failed scheduling list.
|
|
if( SM_SERVICE_GROUP_STATUS_FAILED == assignment->status )
|
|
{
|
|
// Fatal condition is looked at later when the health of all
|
|
// assignments is compared.
|
|
char hostname[SM_NODE_NAME_MAX_CHAR];
|
|
SmErrorT error = sm_node_utils_get_hostname( hostname );
|
|
if( SM_OKAY != error )
|
|
{
|
|
DPRINTFE( "Failed to get hostname, error=%s.",
|
|
sm_error_str( error ) );
|
|
hostname[0] = '\0';
|
|
goto UPDATE;
|
|
}
|
|
SmNodeScheduleStateT current_schedule_state = sm_get_controller_state( hostname );
|
|
SmNodeScheduleStateT to_schedule_state;
|
|
if(0 == strcmp(hostname, assignment->node_name))
|
|
{
|
|
to_schedule_state = SM_NODE_STATE_STANDBY;
|
|
}else
|
|
{
|
|
to_schedule_state = SM_NODE_STATE_ACTIVE;
|
|
}
|
|
if(current_schedule_state != to_schedule_state)
|
|
{
|
|
DPRINTFI("Uncontrolled swact start");
|
|
SmNodeSwactMonitor::SwactStart(to_schedule_state);
|
|
}
|
|
|
|
list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_FAILED;
|
|
++(counts->failed_members);
|
|
goto UPDATE;
|
|
}
|
|
|
|
// Select scheduling list based on desired-state and operational state.
|
|
if( SM_SERVICE_GROUP_STATE_ACTIVE == assignment->desired_state )
|
|
{
|
|
if( SM_SERVICE_GROUP_STATE_ACTIVE == assignment->state )
|
|
{
|
|
list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_ACTIVE;
|
|
++(counts->active_members);
|
|
} else {
|
|
list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_ACTIVE;
|
|
++(counts->go_active_members);
|
|
}
|
|
}
|
|
else if( SM_SERVICE_GROUP_STATE_STANDBY == assignment->desired_state )
|
|
{
|
|
if( SM_SERVICE_GROUP_STATE_STANDBY == assignment->state )
|
|
{
|
|
list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_STANDBY;
|
|
++(counts->standby_members);
|
|
} else {
|
|
list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_STANDBY;
|
|
++(counts->go_standby_members);
|
|
}
|
|
}
|
|
else if( SM_SERVICE_GROUP_STATE_DISABLED == assignment->desired_state )
|
|
{
|
|
if( SM_SERVICE_GROUP_STATE_DISABLED == assignment->state )
|
|
{
|
|
list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLED;
|
|
++(counts->disabled_members);
|
|
} else {
|
|
list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLING;
|
|
++(counts->disabling_members);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLED;
|
|
++(counts->disabled_members);
|
|
}
|
|
|
|
UPDATE:
|
|
if( list != assignment->sched_list )
|
|
{
|
|
assignment->sched_list = list;
|
|
}
|
|
}
|
|
// ****************************************************************************
|
|
|
|
// ****************************************************************************
|
|
// Service Domain Filter - Count Healthier Assignments
|
|
// ===================================================
|
|
static void sm_service_domain_filter_count_healthier_assignments(
|
|
void* user_data[], SmServiceDomainAssignmentT* assignment )
|
|
{
|
|
int* count;
|
|
SmDbNodeT node;
|
|
SmServiceDomainAssignmentT* target_assignment;
|
|
|
|
count = (int*) user_data[0];
|
|
target_assignment = (SmServiceDomainAssignmentT*) user_data[1];
|
|
SmErrorT error;
|
|
|
|
error = sm_db_nodes_read( _sm_db_handle, assignment->node_name, &node );
|
|
if( SM_OKAY == error )
|
|
{
|
|
if( SM_NODE_ADMIN_STATE_LOCKED == node.admin_state )
|
|
{
|
|
DPRINTFD( "Node (%s) is locked.", assignment->node_name );
|
|
return;
|
|
}
|
|
} else if( SM_NOT_FOUND == error ) {
|
|
DPRINTFD( "Node (%s) not found.", assignment->node_name );
|
|
return;
|
|
} else {
|
|
DPRINTFE( "Failed to read node (%s) info, error = %s.",
|
|
assignment->node_name, sm_error_str(error) );
|
|
return;
|
|
}
|
|
|
|
if(( 0 == strcmp( assignment->name, target_assignment->name ) )&&
|
|
( 0 != strcmp( assignment->node_name, target_assignment->node_name ) )&&
|
|
( 0 == strcmp( assignment->service_group_name,
|
|
target_assignment->service_group_name ) )&&
|
|
( SM_SERVICE_DOMAIN_SCHEDULING_LIST_FAILED != assignment->sched_list )&&
|
|
( SM_SERVICE_DOMAIN_SCHEDULING_LIST_FATAL != assignment->sched_list )&&
|
|
( SM_SERVICE_DOMAIN_SCHEDULING_LIST_UNAVAILABLE != assignment->sched_list )&&
|
|
( assignment->health > target_assignment->health ))
|
|
{
|
|
++(*count);
|
|
}
|
|
}
|
|
// ****************************************************************************
|
|
|
|
// ****************************************************************************
|
|
// Service Domain Filter - By Assignment Health
|
|
// ============================================
|
|
static void sm_service_domain_filter_by_assignment_health( void* user_data[],
|
|
SmServiceDomainAssignmentT* assignment )
|
|
{
|
|
int count = 0;
|
|
char* service_domain_name = (char*) user_data[1];
|
|
SmServiceDomainFilterCountsT* counts;
|
|
SmServiceDomainMemberT* member;
|
|
void* user_data2[] = {&count, assignment };
|
|
|
|
counts = (SmServiceDomainFilterCountsT*) user_data[0];
|
|
|
|
if( SM_SERVICE_DOMAIN_SCHEDULING_LIST_FAILED != assignment->sched_list )
|
|
{
|
|
// Only looking at the failed list.
|
|
return;
|
|
}
|
|
|
|
member = sm_service_domain_member_table_read( assignment->name,
|
|
assignment->service_group_name );
|
|
if( NULL == member )
|
|
{
|
|
DPRINTFE( "Failed to read service domain (%s) member (%s), error=%s.",
|
|
assignment->name, assignment->service_group_name,
|
|
sm_error_str(SM_NOT_FOUND) );
|
|
return;
|
|
}
|
|
|
|
sm_service_domain_assignment_table_foreach( service_domain_name,
|
|
user_data2, sm_service_domain_filter_count_healthier_assignments );
|
|
|
|
if( member->n_active <= count )
|
|
{
|
|
// Healthier assignment available.
|
|
switch( assignment->condition )
|
|
{
|
|
case SM_SERVICE_GROUP_CONDITION_ACTION_FAILURE:
|
|
// Already on the failed scheduling list.
|
|
break;
|
|
|
|
case SM_SERVICE_GROUP_CONDITION_FATAL_FAILURE:
|
|
assignment->sched_list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_FATAL;
|
|
--(counts->failed_members);
|
|
++(counts->fatal_members);
|
|
break;
|
|
|
|
default:
|
|
assignment->sched_state = SM_SERVICE_DOMAIN_SCHEDULING_STATE_DISABLE;
|
|
assignment->sched_list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_UNAVAILABLE;
|
|
--(counts->failed_members);
|
|
++(counts->unavailable_members);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
// ****************************************************************************
|
|
|
|
// ****************************************************************************
|
|
// Service Domain Filter - Service Group Aggregate Recover
|
|
// =======================================================
|
|
static SmErrorT sm_service_domain_filter_service_group_aggregate_recover(
|
|
bool* recover, SmServiceDomainAssignmentT* assignment )
|
|
{
|
|
if(( SM_SERVICE_DOMAIN_SCHEDULING_STATE_SWACT == assignment->sched_state )&&
|
|
( SM_SERVICE_GROUP_CONDITION_ACTION_FAILURE == assignment->condition ))
|
|
{
|
|
if((( SM_SERVICE_GROUP_STATE_STANDBY == assignment->desired_state )&&
|
|
( SM_SERVICE_GROUP_STATE_GO_STANDBY == assignment->state ))||
|
|
(( SM_SERVICE_GROUP_STATE_DISABLED == assignment->desired_state )&&
|
|
( SM_SERVICE_GROUP_STATE_DISABLING == assignment->state )))
|
|
{
|
|
// Fail back to from-side back.
|
|
*recover = true;
|
|
DPRINTFE( "Failback service domain (%s) member (%s).",
|
|
assignment->name, assignment->service_group_name );
|
|
}
|
|
}
|
|
|
|
return( SM_OKAY );
|
|
}
|
|
// ****************************************************************************
|
|
|
|
// ****************************************************************************
|
|
// Service Domain Filter - Service Group Aggregate Recover Apply
|
|
// =============================================================
|
|
static SmErrorT sm_service_domain_filter_service_group_aggregate_recover_apply(
|
|
SmServiceDomainFilterCountsT* counts,
|
|
SmServiceDomainAssignmentT* assignment )
|
|
{
|
|
assignment->sched_state = SM_SERVICE_DOMAIN_SCHEDULING_STATE_NONE;
|
|
|
|
switch( assignment->sched_list )
|
|
{
|
|
case SM_SERVICE_DOMAIN_SCHEDULING_LIST_ACTIVE:
|
|
case SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_ACTIVE:
|
|
case SM_SERVICE_DOMAIN_SCHEDULING_LIST_UNAVAILABLE:
|
|
// Nothing to recover.
|
|
break;
|
|
case SM_SERVICE_DOMAIN_SCHEDULING_LIST_STANDBY:
|
|
--(counts->standby_members);
|
|
++(counts->go_active_members);
|
|
assignment->sched_list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_ACTIVE;
|
|
break;
|
|
case SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_STANDBY:
|
|
--(counts->go_standby_members);
|
|
++(counts->go_active_members);
|
|
assignment->sched_list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_ACTIVE;
|
|
break;
|
|
case SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLED:
|
|
--(counts->disabled_members);
|
|
++(counts->go_active_members);
|
|
assignment->sched_list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_ACTIVE;
|
|
break;
|
|
case SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLING:
|
|
--(counts->disabling_members);
|
|
++(counts->go_active_members);
|
|
assignment->sched_list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_ACTIVE;
|
|
break;
|
|
case SM_SERVICE_DOMAIN_SCHEDULING_LIST_FAILED:
|
|
--(counts->failed_members);
|
|
++(counts->go_active_members);
|
|
assignment->sched_list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_ACTIVE;
|
|
break;
|
|
default:
|
|
//Ignore.
|
|
break;
|
|
}
|
|
|
|
return( SM_OKAY );
|
|
}
|
|
// ****************************************************************************
|
|
|
|
// ****************************************************************************
|
|
// Service Domain Filter - Get Service Group Aggregate List
|
|
// ========================================================
|
|
static SmErrorT sm_service_domain_filter_get_service_group_aggregate_list(
|
|
SmServiceDomainSchedulingListT* list,
|
|
SmServiceDomainAssignmentT* assignment )
|
|
{
|
|
// Failed and Fatal scheduling list is not checked below. This is to
|
|
// allow partial service scenarios, otherwise we would pull down all
|
|
// co-located assignments.
|
|
|
|
if( SM_SERVICE_DOMAIN_SCHEDULING_LIST_ACTIVE == *list )
|
|
{
|
|
if(( SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_ACTIVE == assignment->sched_list )||
|
|
( SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_STANDBY == assignment->sched_list )||
|
|
( SM_SERVICE_DOMAIN_SCHEDULING_LIST_STANDBY == assignment->sched_list )||
|
|
( SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLING == assignment->sched_list )||
|
|
( SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLED == assignment->sched_list )||
|
|
( SM_SERVICE_DOMAIN_SCHEDULING_LIST_UNAVAILABLE == assignment->sched_list ))
|
|
{
|
|
*list = assignment->sched_list;
|
|
}
|
|
} else if( SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_ACTIVE == *list )
|
|
{
|
|
if(( SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_STANDBY == assignment->sched_list )||
|
|
( SM_SERVICE_DOMAIN_SCHEDULING_LIST_STANDBY == assignment->sched_list )||
|
|
( SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLING == assignment->sched_list )||
|
|
( SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLED == assignment->sched_list )||
|
|
( SM_SERVICE_DOMAIN_SCHEDULING_LIST_UNAVAILABLE == assignment->sched_list ))
|
|
{
|
|
*list = assignment->sched_list;
|
|
}
|
|
} else if( SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_STANDBY == *list )
|
|
{
|
|
if(( SM_SERVICE_DOMAIN_SCHEDULING_LIST_STANDBY == assignment->sched_list )||
|
|
( SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLING == assignment->sched_list )||
|
|
( SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLED == assignment->sched_list )||
|
|
( SM_SERVICE_DOMAIN_SCHEDULING_LIST_UNAVAILABLE == assignment->sched_list ))
|
|
{
|
|
*list = assignment->sched_list;
|
|
}
|
|
} else if( SM_SERVICE_DOMAIN_SCHEDULING_LIST_STANDBY == *list )
|
|
{
|
|
if(( SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLING == assignment->sched_list )||
|
|
( SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLED == assignment->sched_list )||
|
|
( SM_SERVICE_DOMAIN_SCHEDULING_LIST_UNAVAILABLE == assignment->sched_list ))
|
|
{
|
|
*list = assignment->sched_list;
|
|
}
|
|
} else if( SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLING == *list )
|
|
{
|
|
if(( SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLED == assignment->sched_list )||
|
|
( SM_SERVICE_DOMAIN_SCHEDULING_LIST_UNAVAILABLE == assignment->sched_list ))
|
|
{
|
|
*list = assignment->sched_list;
|
|
}
|
|
} else if( SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLED == *list )
|
|
{
|
|
if( SM_SERVICE_DOMAIN_SCHEDULING_LIST_UNAVAILABLE == assignment->sched_list )
|
|
{
|
|
*list = assignment->sched_list;
|
|
}
|
|
}
|
|
|
|
return( SM_OKAY );
|
|
}
|
|
// ****************************************************************************
|
|
|
|
// ****************************************************************************
|
|
// Service Domain Filter - Apply Service Group Aggregate List
|
|
// ==========================================================
|
|
static SmErrorT sm_service_domain_filter_apply_service_group_aggregate_list(
|
|
SmServiceDomainFilterCountsT* counts, SmServiceDomainSchedulingListT* list,
|
|
SmServiceDomainAssignmentT* assignment )
|
|
{
|
|
if(( *list != assignment->sched_list )&&
|
|
( SM_SERVICE_DOMAIN_SCHEDULING_LIST_FAILED != assignment->sched_list )&&
|
|
( SM_SERVICE_DOMAIN_SCHEDULING_LIST_FATAL != assignment->sched_list ))
|
|
{
|
|
// Adjust counts.
|
|
switch( assignment->sched_list )
|
|
{
|
|
case SM_SERVICE_DOMAIN_SCHEDULING_LIST_ACTIVE:
|
|
--(counts->active_members);
|
|
break;
|
|
case SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_ACTIVE:
|
|
--(counts->go_active_members);
|
|
break;
|
|
case SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_STANDBY:
|
|
--(counts->go_standby_members);
|
|
break;
|
|
case SM_SERVICE_DOMAIN_SCHEDULING_LIST_STANDBY:
|
|
--(counts->standby_members);
|
|
break;
|
|
case SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLING:
|
|
--(counts->disabling_members);
|
|
break;
|
|
case SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLED:
|
|
--(counts->disabled_members);
|
|
break;
|
|
case SM_SERVICE_DOMAIN_SCHEDULING_LIST_UNAVAILABLE:
|
|
--(counts->unavailable_members);
|
|
break;
|
|
default:
|
|
//Ignore.
|
|
break;
|
|
}
|
|
|
|
switch( *list )
|
|
{
|
|
case SM_SERVICE_DOMAIN_SCHEDULING_LIST_ACTIVE:
|
|
++(counts->active_members);
|
|
break;
|
|
case SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_ACTIVE:
|
|
++(counts->go_active_members);
|
|
break;
|
|
case SM_SERVICE_DOMAIN_SCHEDULING_LIST_GO_STANDBY:
|
|
++(counts->go_standby_members);
|
|
break;
|
|
case SM_SERVICE_DOMAIN_SCHEDULING_LIST_STANDBY:
|
|
++(counts->standby_members);
|
|
break;
|
|
case SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLING:
|
|
++(counts->disabling_members);
|
|
break;
|
|
case SM_SERVICE_DOMAIN_SCHEDULING_LIST_DISABLED:
|
|
++(counts->disabled_members);
|
|
break;
|
|
case SM_SERVICE_DOMAIN_SCHEDULING_LIST_UNAVAILABLE:
|
|
++(counts->unavailable_members);
|
|
break;
|
|
default:
|
|
//Ignore.
|
|
break;
|
|
}
|
|
|
|
assignment->sched_list = *list;
|
|
}
|
|
|
|
return( SM_OKAY );
|
|
}
|
|
// ****************************************************************************
|
|
|
|
// ****************************************************************************
|
|
// Service Domain Filter - Service Group Aggregate Member
|
|
// ======================================================
|
|
void sm_service_domain_filter_service_group_aggregate_member( void* user_data[],
|
|
SmServiceDomainMemberT* member )
|
|
{
|
|
bool apply;
|
|
bool* recover;
|
|
SmDbNodeT* node;
|
|
char* service_domain_name;
|
|
SmServiceDomainFilterCountsT* counts;
|
|
SmServiceDomainSchedulingListT* list;
|
|
SmServiceDomainAssignmentT* assignment;
|
|
SmErrorT error;
|
|
|
|
counts = (SmServiceDomainFilterCountsT*) user_data[0];
|
|
service_domain_name = (char*) user_data[1];
|
|
node = (SmDbNodeT*) user_data[2];
|
|
list = (SmServiceDomainSchedulingListT*) user_data[3];
|
|
apply = *(bool*) user_data[4];
|
|
recover = (bool*) user_data[5];
|
|
|
|
assignment = sm_service_domain_assignment_table_read( service_domain_name,
|
|
node->name, member->service_group_name );
|
|
if( NULL == assignment )
|
|
{
|
|
// Possible that the node has been provisioned, but not configured yet.
|
|
// This is possible during initial commissioning of the second
|
|
// controller.
|
|
DPRINTFD( "Failed to query service domain (%s) assignment (%s) for "
|
|
"node (%s), error=%s.", member->name,
|
|
member->service_group_name, node->name,
|
|
sm_error_str(SM_NOT_FOUND) );
|
|
return;
|
|
}
|
|
|
|
if( apply )
|
|
{
|
|
if( *recover )
|
|
{
|
|
error = sm_service_domain_filter_service_group_aggregate_recover_apply(
|
|
counts, assignment );
|
|
if( SM_OKAY != error )
|
|
{
|
|
DPRINTFE( "Failed to apply service domain (%s) assignment (%s) "
|
|
"recovery for node (%s), error=%s.", member->name,
|
|
member->service_group_name, node->name,
|
|
sm_error_str( error ) );
|
|
return;
|
|
}
|
|
} else {
|
|
error = sm_service_domain_filter_apply_service_group_aggregate_list(
|
|
counts, list, assignment );
|
|
if( SM_OKAY != error )
|
|
{
|
|
DPRINTFE( "Failed to apply service domain (%s) assignment (%s) "
|
|
"list for node (%s), error=%s.", member->name,
|
|
member->service_group_name, node->name,
|
|
sm_error_str( error ) );
|
|
return;
|
|
}
|
|
}
|
|
} else {
|
|
// First determine if recovery is needed.
|
|
error = sm_service_domain_filter_service_group_aggregate_recover(
|
|
recover, assignment );
|
|
if( SM_OKAY != error )
|
|
{
|
|
DPRINTFE( "Failed to determine if recovery of service domain (%s) "
|
|
"assignment (%s) is needed for node (%s), error=%s.",
|
|
member->name, member->service_group_name, node->name,
|
|
sm_error_str( error ) );
|
|
return;
|
|
}
|
|
|
|
if( false == *recover )
|
|
{
|
|
// Recovery not needed, get the common list among the service
|
|
// group aggregate.
|
|
error = sm_service_domain_filter_get_service_group_aggregate_list(
|
|
list, assignment );
|
|
if( SM_OKAY != error )
|
|
{
|
|
DPRINTFE( "Failed to get service domain (%s) assignment (%s) "
|
|
"list for node (%s), error=%s.", member->name,
|
|
member->service_group_name, node->name,
|
|
sm_error_str( error ) );
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// ****************************************************************************
|
|
|
|
// ****************************************************************************
|
|
// Service Domain Filter - Service Group Aggregates
|
|
// ================================================
|
|
void sm_service_domain_filter_service_group_aggregates( void* user_data[],
|
|
SmServiceDomainMemberT* member )
|
|
{
|
|
bool apply = false;
|
|
bool recover = false;
|
|
char* service_domain_name = (char*) user_data[1];
|
|
SmServiceDomainSchedulingListT list;
|
|
void* user_data2[] = { user_data[0], user_data[1], user_data[2],
|
|
&list, &apply, &recover };
|
|
|
|
if( '\0' == member->service_group_aggregate[0] )
|
|
{
|
|
DPRINTFD( "Not aggregated with other service groups." );
|
|
return;
|
|
}
|
|
|
|
list = SM_SERVICE_DOMAIN_SCHEDULING_LIST_ACTIVE;
|
|
|
|
sm_service_domain_member_table_foreach_service_group_aggregate(
|
|
service_domain_name, member->service_group_aggregate, user_data2,
|
|
sm_service_domain_filter_service_group_aggregate_member );
|
|
|
|
apply = true;
|
|
|
|
sm_service_domain_member_table_foreach_service_group_aggregate(
|
|
service_domain_name, member->service_group_aggregate, user_data2,
|
|
sm_service_domain_filter_service_group_aggregate_member );
|
|
}
|
|
// ****************************************************************************
|
|
|
|
// ****************************************************************************
|
|
// Service Domain Filter - By Service Group Aggregate
|
|
// ==================================================
|
|
SmErrorT sm_service_domain_filter_by_service_group_aggregate( void* user_data[],
|
|
void* record )
|
|
{
|
|
char* service_domain_name = (char*) user_data[1];
|
|
SmDbNodeT* node = (SmDbNodeT*) record;
|
|
void* user_data2[] = { user_data[0], user_data[1], node };
|
|
|
|
sm_service_domain_member_table_foreach( service_domain_name, user_data2,
|
|
sm_service_domain_filter_service_group_aggregates );
|
|
|
|
return( SM_OKAY );
|
|
}
|
|
// ****************************************************************************
|
|
|
|
// ****************************************************************************
|
|
// Service Domain Filter - Preselect Apply
|
|
// =======================================
|
|
SmErrorT sm_service_domain_filter_preselect_apply( char service_domain_name[],
|
|
SmServiceDomainFilterCountsT* counts )
|
|
{
|
|
long ms_expired;
|
|
SmTimeT time_prev, time_now;
|
|
void* user_data[] = {counts, service_domain_name};
|
|
SmDbNodeT node;
|
|
SmErrorT error;
|
|
|
|
memset( counts, 0, sizeof(SmServiceDomainFilterCountsT) );
|
|
|
|
// Filter - Cleanup
|
|
sm_time_get( &time_prev );
|
|
|
|
sm_service_domain_assignment_table_foreach( service_domain_name,
|
|
user_data, sm_service_domain_filter_cleanup );
|
|
|
|
sm_time_get( &time_now );
|
|
ms_expired = sm_time_delta_in_ms( &time_now, &time_prev );
|
|
DPRINTFD( "Scheduler execute - apply filter - cleanup, "
|
|
"took %li ms.", ms_expired );
|
|
|
|
// Filter - By Node Ready.
|
|
sm_time_get( &time_prev );
|
|
|
|
sm_service_domain_assignment_table_foreach( service_domain_name,
|
|
user_data, sm_service_domain_filter_by_node_ready );
|
|
|
|
sm_time_get( &time_now );
|
|
ms_expired = sm_time_delta_in_ms( &time_now, &time_prev );
|
|
DPRINTFD( "Scheduler execute - apply filter - node enabled, "
|
|
"took %li ms.", ms_expired );
|
|
|
|
// Filter - By Neighbor.
|
|
sm_time_get( &time_prev );
|
|
|
|
sm_service_domain_assignment_table_foreach( service_domain_name,
|
|
user_data, sm_service_domain_filter_by_neighbor );
|
|
|
|
sm_time_get( &time_now );
|
|
ms_expired = sm_time_delta_in_ms( &time_now, &time_prev );
|
|
DPRINTFD( "Scheduler execute - apply filter - neighbor, "
|
|
"took %li ms.", ms_expired );
|
|
|
|
// Filter - By Assignments.
|
|
sm_time_get( &time_prev );
|
|
|
|
sm_service_domain_assignment_table_foreach( service_domain_name,
|
|
user_data, sm_service_domain_filter_by_assignment );
|
|
|
|
sm_time_get( &time_now );
|
|
ms_expired = sm_time_delta_in_ms( &time_now, &time_prev );
|
|
DPRINTFD( "Scheduler execute - apply filter - assignments, "
|
|
"took %li ms.", ms_expired );
|
|
|
|
// Filter - By Assignment Health.
|
|
sm_time_get( &time_prev );
|
|
|
|
sm_service_domain_assignment_table_foreach( service_domain_name,
|
|
user_data, sm_service_domain_filter_by_assignment_health );
|
|
|
|
sm_time_get( &time_now );
|
|
ms_expired = sm_time_delta_in_ms( &time_now, &time_prev );
|
|
DPRINTFD( "Scheduler execute - apply filter - assignment health, "
|
|
"took %li ms.", ms_expired );
|
|
|
|
// Filter - By Node Administrative State.
|
|
sm_time_get( &time_prev );
|
|
|
|
sm_service_domain_assignment_table_foreach( service_domain_name,
|
|
user_data, sm_service_domain_filter_by_node_admin_state );
|
|
|
|
sm_time_get( &time_now );
|
|
ms_expired = sm_time_delta_in_ms( &time_now, &time_prev );
|
|
DPRINTFD( "Scheduler execute - apply filter - node admin state, "
|
|
"took %li ms.", ms_expired );
|
|
|
|
// Filter - By Service Group Aggregate.
|
|
sm_time_get( &time_prev );
|
|
|
|
error = sm_db_foreach( SM_DATABASE_NAME, SM_NODES_TABLE_NAME,
|
|
NULL, &node, &sm_db_nodes_convert,
|
|
sm_service_domain_filter_by_service_group_aggregate,
|
|
user_data );
|
|
if( SM_OKAY != error )
|
|
{
|
|
DPRINTFE( "Failed to loop over nodes, error=%s.",
|
|
sm_error_str( error ) );
|
|
return( error );
|
|
}
|
|
|
|
sm_time_get( &time_now );
|
|
ms_expired = sm_time_delta_in_ms( &time_now, &time_prev );
|
|
DPRINTFD( "Scheduler execute - apply filter - service group "
|
|
"aggregate, took %li ms.", ms_expired );
|
|
|
|
return( SM_OKAY );
|
|
}
|
|
// ****************************************************************************
|
|
|
|
// ****************************************************************************
|
|
// Service Domain Filter - Post Select Apply
|
|
// =========================================
|
|
SmErrorT sm_service_domain_filter_post_select_apply( char service_domain_name[],
|
|
SmServiceDomainFilterCountsT* counts )
|
|
{
|
|
long ms_expired;
|
|
SmTimeT time_prev, time_now;
|
|
void* user_data[] = {counts, service_domain_name};
|
|
SmDbNodeT node;
|
|
SmErrorT error;
|
|
|
|
// Filter - By Service Group Aggregate.
|
|
sm_time_get( &time_prev );
|
|
|
|
error = sm_db_foreach( SM_DATABASE_NAME, SM_NODES_TABLE_NAME,
|
|
NULL, &node, &sm_db_nodes_convert,
|
|
sm_service_domain_filter_by_service_group_aggregate,
|
|
user_data );
|
|
if( SM_OKAY != error )
|
|
{
|
|
DPRINTFE( "Failed to loop over nodes, error=%s.",
|
|
sm_error_str( error ) );
|
|
return( error );
|
|
}
|
|
|
|
sm_time_get( &time_now );
|
|
ms_expired = sm_time_delta_in_ms( &time_now, &time_prev );
|
|
DPRINTFD( "Scheduler execute - post select apply filter - service group "
|
|
"aggregate, took %li ms.", ms_expired );
|
|
|
|
return( SM_OKAY );
|
|
}
|
|
// ****************************************************************************
|
|
|
|
// ****************************************************************************
|
|
// Service Domain Filter - Initialize
|
|
// ==================================
|
|
SmErrorT sm_service_domain_filter_initialize( SmDbHandleT* sm_db_handle )
|
|
{
|
|
_sm_db_handle = sm_db_handle;
|
|
|
|
return( SM_OKAY );
|
|
}
|
|
// ****************************************************************************
|
|
|
|
// ****************************************************************************
|
|
// Service Domain Filter - Finalize
|
|
// ================================
|
|
SmErrorT sm_service_domain_filter_finalize( void )
|
|
{
|
|
_sm_db_handle = NULL;
|
|
|
|
return( SM_OKAY );
|
|
}
|
|
// ****************************************************************************
|