windows-nt/Source/XPSP1/NT/base/cluster/service/mm/srgputl.c

795 lines
22 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
#ifdef __TANDEM
#pragma columns 79
#pragma page "srgputl.c - T9050 - utility routines for Regroup Module"
#endif
/* @@@ START COPYRIGHT @@@
** Tandem Confidential: Need to Know only
** Copyright (c) 1995, Tandem Computers Incorporated
** Protected as an unpublished work.
** All Rights Reserved.
**
** The computer program listings, specifications, and documentation
** herein are the property of Tandem Computers Incorporated and shall
** not be reproduced, copied, disclosed, or used in whole or in part
** for any reason without the prior express written permission of
** Tandem Computers Incorporated.
**
** @@@ END COPYRIGHT @@@
**/
/*---------------------------------------------------------------------------
* This file (srgputl.c) contains the cluster_t data type implementation
* and the node pruning algorithm used by Regroup.
*---------------------------------------------------------------------------*/
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#include <wrgp.h>
/************************************************************************
* ClusterInit,
* ClusterUnion,
* ClusterIntersection,
* ClusterDifference,
* ClusterCompare,
* ClusterSubsetOf,
* ClusterComplement,
* ClusterMember,
* ClusterInsert,
* ClusterDelete,
* ClusterCopy,
* ClusterSwap,
* ClusterNumMembers
* =================
*
* Description:
*
* Functions that implement operations on the cluster_t type.
*
* Algorithm:
*
* Operates on the byte array that is the cluster_t type.
*
************************************************************************/
_priv _resident void
ClusterInit(cluster_t c)
{
int i;
for (i = 0; i < BYTES_IN_CLUSTER; i++)
c[i] = 0;
}
_priv _resident void
ClusterUnion(cluster_t dst, cluster_t src1, cluster_t src2)
{
int i;
for (i = 0; i < BYTES_IN_CLUSTER; i++)
dst[i] = src1[i] | src2[i];
}
_priv _resident void
ClusterIntersection(cluster_t dst, cluster_t src1, cluster_t src2)
{
int i;
for (i = 0; i < BYTES_IN_CLUSTER; i++)
dst[i] = src1[i] & src2[i];
}
_priv _resident void
ClusterDifference(cluster_t dst, cluster_t src1, cluster_t src2)
{
int i;
for (i = 0; i < BYTES_IN_CLUSTER; i++)
dst[i] = src1[i] & (~src2[i]);
}
_priv _resident int ClusterCompare(cluster_t c1, cluster_t c2)
{
int identical, i;
identical = 1;
for (i = 0; i < BYTES_IN_CLUSTER; i++)
{
if (c1[i] != c2[i])
{
identical = 0;
break;
}
}
return(identical);
}
_priv _resident int ClusterSubsetOf(cluster_t big, cluster_t small)
/* Returns 1 if set small = set big or small is a subset of big. */
{
int subset, i;
subset = 1;
for (i = 0; i < BYTES_IN_CLUSTER; i++)
{
if ( (big[i] != small[i]) && ((big[i] ^ small[i]) & small[i]) )
{
subset = 0;
break;
}
}
return(subset);
}
_priv _resident void ClusterComplement(cluster_t dst, cluster_t src)
{
int i;
for (i = 0; i < BYTES_IN_CLUSTER; i++)
dst[i] = ~src[i];
}
_priv _resident int ClusterMember(cluster_t c, node_t i)
{
return((BYTE(c,i) >> (BYTEL-1-BIT(i))) & 1);
}
_priv _resident void ClusterInsert(cluster_t c, node_t i)
{
BYTE(c, i) |= (1 << (BYTEL-1-BIT(i)));
}
_priv _resident void ClusterDelete(cluster_t c, node_t i)
{
BYTE(c, i) &= ~(1 << (BYTEL-1-BIT(i)));
}
_priv _resident void ClusterCopy(cluster_t dst, cluster_t src)
{
int i;
for (i = 0; i < BYTES_IN_CLUSTER; i++)
dst[i] = src[i];
}
_priv _resident void ClusterSwap(cluster_t c1, cluster_t c2)
{
int i;
unsigned char temp;
for (i = 0; i < BYTES_IN_CLUSTER; i++)
{
temp = c1[i];
c1[i] = c2[i];
c2[i] = temp;
}
}
_priv _resident int ClusterNumMembers(cluster_t c)
/* Returns the number of nodes in the cluster. */
{
int num_members = 0, i, j;
for (i = 0; i < BYTES_IN_CLUSTER; i++)
{
if (c[i])
{
for (j = 0; j < BYTEL; j++)
if (c[i] & (1 << j))
num_members++;
}
}
return(num_members);
}
/************************************************************************
* ClusterEmpty
* =================
*
* Description:
*
* Checks that a cluster has no members
*
* Parameters:
*
* cluster_t c
* cluster to be examined
*
* Returns:
*
* 0 - cluster contains at least one node
* 1 - cluster is empty
*
* Comment:
*
* The proper place for this function is in srgputl.c
*
************************************************************************/
int ClusterEmpty(cluster_t c)
{
int i;
for (i = 0; i < BYTES_IN_CLUSTER; i++)
{
if (c[i])
{
return 0;
}
}
return 1;
}
/************************************************************************
* rgp_select_tiebreaker
* =====================
*
* Description:
*
* Simple algorithm to select the tie-breaker.
*
* Parameters:
*
* cluster_t cluster -
* cluster from which a tie-breaker is to be selected
*
* Returns:
*
* node_t - the node number of the selected tie-breaker
*
* Algorithm:
*
* The tie-breaker is defined as the lowest numbered node in the
* cluster.
*
************************************************************************/
_priv _resident node_t
rgp_select_tiebreaker(cluster_t cluster)
{
node_t i;
for (i = 0; (i < (node_t) rgp->num_nodes) && !ClusterMember(cluster, i); i++);
/* If the cluster does not have any members, we have a problem! */
if (i >= (node_t) rgp->num_nodes)
RGP_ERROR(RGP_INTERNAL_ERROR);
return(i);
}
/*---------------------------------------------------------------------------
* Node pruning algorithm used by Regroup.
*---------------------------------------------------------------------------
*/
/************************************************************************
* group_exists
* ============
*
* Description:
*
* Check if a specific group already exists or is a subset of a
* group that already exists.
*
* Parameters:
*
* cluster_t groups[] -
* array of groups to examine
*
* int numgroups -
* number of groups discovered so far
*
* cluster_t g -
* specific group to check
*
* Returns:
*
* int - 1 if the specified group exists in the array; 0 therwise.
*
* Algorithm:
*
* Goes through the array and calls ClusterSubsetOf to check if the
* specified group g is a subset of the the array element.
*
************************************************************************/
#if !defined(NT)
_priv _resident static
int
#endif
group_exists(cluster_t groups[], int numgroups, cluster_t g)
{
int exists, i;
exists = 0;
for (i = 0; i < numgroups; i++)
{
if (ClusterSubsetOf(groups[i],g))
{
exists = 1;
break;
}
}
return(exists);
}
/************************************************************************
* prune
* =====
*
* Description:
*
* Algorithm to find all fully connected groups based on # of
* disconnects in the matrix.
*
* Parameters:
*
* disconnect_array disconnects -
* input : array of disconnects
*
* int D -
* input : size of disconnects array
*
* cluster_t live_nodes -
* input : set of all live nodes
*
* cluster_t groups[] -
* output: array of fully-connected groups
*
* Returns:
*
* int - the number of groups made; 0 if no groups or other error
*
* Algorithm:
*
* Start with one group that contains the set of live nodes.
* More groups will be generated as disconnects are examined.
*
* Process each disconnect in the disconnects array by applying
* the disconnect to the current set of fully-connected groups.
*
* The effect of a disconnect on a fully-conncted group depends on
* whether the end points of the disconnect are in the group or not.
*
* If the group contains neither or only one of the endpoints of
* the disconnect, the disconnect has no effect on the group.
*
* If both endpoints of the disconnect are in the group, then the
* group is split into two groups - the original group without
* endpoint 1 and the original group without endpoint 2.
* New groups so generated should be discarded if they already
* exist or are subsets of currently existing groups.
*
* After every disconnect is processed, we end up with the final
* set of fully-connected groups.
*
************************************************************************/
#if !defined(NT)
_priv _resident static
#endif
int
prune(
disconnect_array disconnects,
int D,
cluster_t live_nodes,
cluster_t groups[])
{
int numgroups = 1, i, j;
ClusterCopy(groups[0], live_nodes);
for (i = 0; i < D; i ++)
{
for (j = 0; j < numgroups; j++)
{
/* Split a group that has both ends of the disconnect. */
if (ClusterMember(groups[j],disconnects[i][0]) &&
ClusterMember(groups[j],disconnects[i][1]))
{
/* Correct current group in place.
* Add new group at the end of the array.
*/
numgroups++;
ClusterCopy(groups[numgroups-1], groups[j]);
ClusterDelete(groups[j], disconnects[i][0]);
ClusterDelete(groups[numgroups-1], disconnects[i][1]);
/* Check if the new groups already exist or are subgroups
* of existing groups.
*/
/* First, check the group added at the end of the array. */
if (group_exists(groups, numgroups-1, groups[numgroups-1]))
numgroups--;
/* Next, check the modified group at j.
* To simplify the checking, switch it with the last element
* of the array. If the group already exists, it should be
* removed. Since the group is now the last element of the
* array, removal requires only decrementing the array count.
*/
ClusterSwap(groups[j], groups[numgroups-1]);
if (group_exists(groups, numgroups-1, groups[numgroups-1]))
numgroups--;
j--; /* The j-th entry has been switched with the last entry;
it has to be examined again */
}
}
}
return(numgroups);
}
/************************************************************************
* select_group_with_designated_node
* =================================
*
* Description:
*
* Function to pick an arbitrary fully connected group that
* includes a specified node.
*
* Parameters:
*
* connectivity_matrix_t c -
* input : cluster's connectivity info
*
* node_t selected_node -
* input : just find a fully-connected group that includes this node
*
* cluster_t *group -
* output: group that includes selected_node
*
* Returns:
*
* int - returns 1 if the specified node is alive and 0 if it is not
*
* Algorithm:
*
* Start with a group that includes just the selected node.
* Then, examine nodes starting with node 0 and go up till the
* largest node number. If a node is alive, include it in the group
* if and only if it is connected to all current members of the
* group.
*
* When all nodes are examined, we get a fully-connected group that
* includes the selected node. This is only one of potentially many
* fully-connected groups and is not necessarily the largest
* solution.
*
* This order of examining nodes gives higher priority to lower
* numbered nodes.
*
************************************************************************/
#if !defined(NT)
_priv _resident static
#endif
int
select_group_with_designated_node(
connectivity_matrix_t c,
node_t selected_node,
cluster_t *group)
{
node_t i, j;
if (!node_considered_alive(selected_node))
return(0);
else
{
ClusterInit(*group);
ClusterInsert(*group, selected_node);
for (i = 0; i < (node_t) rgp->num_nodes; i++)
{
if ((i != selected_node) &&
node_considered_alive(i) &&
connected(i, selected_node)
)
{
/* Check if i is connected to all members of the group
* built so far.
*/
for (j = 0; j < i; j++)
{
if (ClusterMember(*group, j) && !connected(j, i))
break;
}
if (j == i) /* i is connected to all current members*/
ClusterInsert(*group, i);
}
}
return(1);
}
}
/************************************************************************
* MatrixInit
* ==========
*
* Description:
*
* Initialize the matrix c to show 0 connectivity.
*
* Parameters:
*
* connectivity_matrix_t c - matrix to be set to 0s.
*
* Returns:
*
* void - no return value
*
* Algorithm:
*
* Calls ClusterInit to initialize the clusters in the matrix.
*
************************************************************************/
_priv _resident void
MatrixInit(connectivity_matrix_t c)
{
int i;
for (i = 0; i < (node_t) rgp->num_nodes; i++)
{
ClusterInit(c[i]);
}
}
/************************************************************************
* MatrixSet
* =========
*
* Description:
*
* Set matrix[row,column] to 1.
*
* Parameters:
*
* connectivity_matrix_t c - matrix to be modified
*
* int row - row number
*
* int column - column number
*
* Returns:
*
* void - no return value
*
* Algorithm:
*
* Calls ClusterInsert to set the appropriate bit (column) in the
* appropriate cluster (row) in the matrix.
*
************************************************************************/
_priv _resident void
MatrixSet(connectivity_matrix_t c, int row, int column)
{
ClusterInsert(c[row], (node_t) column);
}
/************************************************************************
* MatrixOr
* ========
*
* Description:
*
* matrix t := t OR s
*
* Parameters:
*
* connectivity_matrix_t t - target matrix
*
* connectivity_matrix_t s - source matrix to be ORed into target
*
* Returns:
*
* void - no return value
*
* Algorithm:
*
* Calls ClusterUnion to OR the appropriate clusters (rows) in the
* matrices.
*
************************************************************************/
_priv _resident void
MatrixOr(connectivity_matrix_t t, connectivity_matrix_t s)
{
int i;
for (i = 0; i < (node_t) rgp->num_nodes; i++)
ClusterUnion(t[i], s[i], t[i]);
}
/************************************************************************
* connectivity_complete
* =====================
*
* Description:
*
* Boolean function that checks if a given connectivity matrix implies
* full connectivity (all nodes can talk to all others).
*
* Parameters:
*
* connectivity_matrix_t c - connectivity matrix of the cluster
*
* Returns:
*
* int - 0 if there are disconnects in the cluster; 1 if it has full
* connectivity.
*
* Algorithm:
*
* Checks to see if there is any live node in the cluster that cannot
* communicate to another live node in the cluster. Node i is
* considered alive if c[i,i] is set. Nodes i and j are deemed to
* be able to communicate if c[i,j] and c[j,i] are both set.
*
************************************************************************/
_priv _resident int
connectivity_complete(connectivity_matrix_t c)
{
node_t i, j;
for (i = 0; i < (node_t) rgp->num_nodes; i++)
{
if (node_considered_alive(i))
{
for (j = 0; j < i; j++)
{
if (node_considered_alive(j) && !connected(i, j))
{
/* i and j are a pair of live nodes which are not
connected. Thus, there is at least one disconnect.
Return 0. */
return(0);
}
}
}
}
/* No disconnects found; return 1. */
return(1);
}
/************************************************************************
* find_all_fully_connected_groups
* ===============================
*
* Description:
*
* Function to find all fully connected groups in a graph specified
* by a connectivity matrix. An optional "selected_node" can be
* used to simplify the search in case of too large a number of
* possibilities. In that case, a fully-connected group that
* includes selected_node is returned.
*
* Parameters:
*
* connectivity_matrix_t c -
* input : cluster's connectivity info
*
* node_t selected_node -
* input : if there are too many potential groups, just find one
* that includes this node; if all groups can be listed, ignore this.
*
* cluster_t groups[] -
* output: array of potential clusters
*
* Returns:
*
* int - the number of groups made; 0 if no groups or other error
*
* Algorithm:
*
* First the set of live nodes and the set of disconnects in the
* cluster are evaluated. Then, if the number of live nodes and
* disconnects indicates a potentially large number of
* possibilities, select_group_with_designated_node() is called to
* limit the search to a group including the specified node.
* Otherwise, prune() is called to get the list of all possible
* fully-connected groups.
*
************************************************************************/
_priv _resident int
find_all_fully_connected_groups(
connectivity_matrix_t c,
node_t selected_node,
cluster_t groups[])
{
disconnect_array disconnects;
cluster_t live_nodes;
int num_livenodes = 0, num_disconnects = 0;
node_t i, j;
ClusterInit(live_nodes);
for (i = 0; i < (node_t) rgp->num_nodes; i++)
{
if (node_considered_alive(i))
{
ClusterInsert(live_nodes, i);
num_livenodes++;
for (j = 0; j < i; j++)
{
if (node_considered_alive(j) && !connected(i, j))
{
/* i and j are a pair of live nodes which are not
connected. */
disconnects[num_disconnects][0] = i;
disconnects[num_disconnects][1] = j;
num_disconnects++;
}
}
if (too_many_groups(num_livenodes, num_disconnects))
{
RGP_TRACE( "RGP Too many dis",
num_livenodes, /* TRACE */
num_disconnects, /* TRACE */
0, 0 ); /* TRACE */
/* There may be too many choices to consider in reasonable
* time/space. Just return a fully-connected group that
* includes the selected node.
*/
return(select_group_with_designated_node(c,selected_node,groups));
}
}
}
if (num_livenodes == 0)
return(0);
else
return(prune(disconnects, num_disconnects, live_nodes, groups));
}
/*---------------------------------------------------------------------------*/
#ifdef __cplusplus
}
#endif /* __cplusplus */
#if 0
History of changes to this file:
-------------------------------------------------------------------------
1995, December 13 F40:KSK0610 /*F40:KSK06102.2*/
This file is part of the portable Regroup Module used in the NonStop
Kernel (NSK) and Loosely Coupled UNIX (LCU) operating systems. There
are 10 files in the module - jrgp.h, jrgpos.h, wrgp.h, wrgpos.h,
srgpif.c, srgpos.c, srgpsm.c, srgputl.c, srgpcli.c and srgpsvr.c.
The last two are simulation files to test the Regroup Module on a
UNIX workstation in user mode with processes simulating processor nodes
and UDP datagrams used to send unacknowledged datagrams.
This file was first submitted for release into NSK on 12/13/95.
------------------------------------------------------------------------------
This change occurred on 19 Jan 1996 /*F40:MB06458.1*/
Changes for phase IV Sierra message system release. Includes: /*F40:MB06458.2*/
- Some cleanup of the code /*F40:MB06458.3*/
- Increment KCCB counters to count the number of setup messages and /*F40:MB06458.4*/
unsequenced messages sent. /*F40:MB06458.5*/
- Fixed some bugs /*F40:MB06458.6*/
- Disable interrupts before allocating broadcast sibs. /*F40:MB06458.7*/
- Change per-packet-timeout to 5ms /*F40:MB06458.8*/
- Make the regroup and powerfail broadcast use highest priority /*F40:MB06458.9*/
tnet services queue. /*F40:MB06458.10*/
- Call the millicode backdoor to get the processor status from SP /*F40:MB06458.11*/
- Fixed expand bug in msg_listen_ and msg_readctrl_ /*F40:MB06458.12*/
- Added enhancement to msngr_sendmsg_ so that clients do not need /*F40:MB06458.13*/
to be unstoppable before calling this routine. /*F40:MB06458.14*/
- Added new steps in the build file called /*F40:MB06458.15*/
MSGSYS_C - compiles all the message system C files /*F40:MB06458.16*/
MSDRIVER - compiles all the MSDriver files /*F40:MB06458.17*/
REGROUP - compiles all the regroup files /*F40:MB06458.18*/
- remove #pragma env libspace because we set it as a command line /*F40:MB06458.19*/
parameter. /*F40:MB06458.20*/
----------------------------------------------------------------------- /*F40:MB06458.21*/
#endif /* 0 - change descriptions */