331 lines
7.4 KiB
C
331 lines
7.4 KiB
C
/*++
|
||
|
||
Copyright (c) 1996 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
join.c
|
||
|
||
Abstract:
|
||
|
||
GUM routines to implement the special join updates.
|
||
|
||
Author:
|
||
|
||
John Vert (jvert) 6/10/1996
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
#include "gump.h"
|
||
|
||
//
|
||
// Define structure used to pass arguments to node enumeration callback
|
||
//
|
||
typedef struct _GUMP_JOIN_INFO {
|
||
GUM_UPDATE_TYPE UpdateType;
|
||
DWORD Status;
|
||
DWORD Sequence;
|
||
DWORD LockerNode;
|
||
} GUMP_JOIN_INFO, *PGUMP_JOIN_INFO;
|
||
|
||
//
|
||
// Local function prototypes
|
||
//
|
||
BOOL
|
||
GumpNodeCallback(
|
||
IN PVOID Context1,
|
||
IN PVOID Context2,
|
||
IN PVOID Object,
|
||
IN LPCWSTR Name
|
||
);
|
||
|
||
|
||
DWORD
|
||
GumBeginJoinUpdate(
|
||
IN GUM_UPDATE_TYPE UpdateType,
|
||
OUT DWORD *Sequence
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Begins the special join update for a joining node. This
|
||
function gets the current GUM sequence number for the
|
||
specified update type from another node in the cluster.
|
||
It also gets the list of nodes currently participating
|
||
in the updates.
|
||
|
||
Arguments:
|
||
|
||
UpdateType - Supplies the GUM_UPDATE_TYPE.
|
||
|
||
Sequence - Returns the sequence number that should be
|
||
passed to GumEndJoinUpdate.
|
||
|
||
Return Value:
|
||
|
||
ERROR_SUCCESS if successful
|
||
|
||
Win32 error code otherwise
|
||
|
||
--*/
|
||
|
||
{
|
||
GUMP_JOIN_INFO JoinInfo;
|
||
|
||
//
|
||
// Enumerate the list of nodes. The callback routine will attempt
|
||
// to obtain the required information from each node that is online.
|
||
//
|
||
JoinInfo.Status = ERROR_GEN_FAILURE;
|
||
JoinInfo.UpdateType = UpdateType;
|
||
OmEnumObjects(ObjectTypeNode,
|
||
GumpNodeCallback,
|
||
&JoinInfo,
|
||
NULL);
|
||
if (JoinInfo.Status == ERROR_SUCCESS) {
|
||
ClRtlLogPrint(LOG_NOISE,
|
||
"[GUM] GumBeginJoinUpdate succeeded with sequence %1!d!\n",
|
||
JoinInfo.Sequence);
|
||
*Sequence = JoinInfo.Sequence;
|
||
}
|
||
|
||
return(JoinInfo.Status);
|
||
}
|
||
|
||
|
||
BOOL
|
||
GumpNodeCallback(
|
||
IN PVOID Context1,
|
||
IN PVOID Context2,
|
||
IN PVOID Object,
|
||
IN LPCWSTR Name
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Node enumeration callback routine for GumBeginJoinUpdate. For each
|
||
node that is currently online, it attempts to connect and obtain
|
||
the current GUM information (sequence and nodelist) for the specified
|
||
update type.
|
||
|
||
Arguments:
|
||
|
||
Context1 - Supplies a pointer to the GUMP_JOIN_INFO structure.
|
||
|
||
Context2 - not used
|
||
|
||
Object - Supplies a pointer to the NM_NODE object
|
||
|
||
Name - Supplies the node's name.
|
||
|
||
Return Value:
|
||
|
||
FALSE - if the information was successfully obtained and enumeration
|
||
should stop.
|
||
|
||
TRUE - If enumeration should continue.
|
||
|
||
--*/
|
||
|
||
{
|
||
DWORD Status;
|
||
DWORD Sequence;
|
||
PGUMP_JOIN_INFO JoinInfo = (PGUMP_JOIN_INFO)Context1;
|
||
PGUM_NODE_LIST NodeList = NULL;
|
||
PNM_NODE Node = (PNM_NODE)Object;
|
||
GUM_UPDATE_TYPE UpdateType;
|
||
DWORD i;
|
||
DWORD LockerNodeId;
|
||
DWORD nodeId;
|
||
|
||
if (NmGetNodeState(Node) != ClusterNodeUp &&
|
||
NmGetNodeState(Node) != ClusterNodePaused){
|
||
//
|
||
// This node is not up, so don't try and get any
|
||
// information from it.
|
||
//
|
||
return(TRUE);
|
||
}
|
||
|
||
//
|
||
// Get the sequence and nodelist information from this node.
|
||
//
|
||
UpdateType = JoinInfo->UpdateType;
|
||
if (UpdateType != GumUpdateTesting) {
|
||
//
|
||
// Our node should not be marked as ClusterNodeUp yet.
|
||
//
|
||
CL_ASSERT(Node != NmLocalNode);
|
||
}
|
||
|
||
nodeId = NmGetNodeId(Node);
|
||
NmStartRpc(nodeId);
|
||
Status = GumGetNodeSequence(GumpRpcBindings[NmGetNodeId(Node)],
|
||
UpdateType,
|
||
&Sequence,
|
||
&LockerNodeId,
|
||
&NodeList);
|
||
NmEndRpc(nodeId);
|
||
|
||
if (Status != ERROR_SUCCESS) {
|
||
ClRtlLogPrint(LOG_UNUSUAL,
|
||
"[GUM] GumGetNodeSequence from %1!ws! failed %2!d!\n",
|
||
OmObjectId(Node),
|
||
Status);
|
||
NmDumpRpcExtErrorInfo(Status);
|
||
return(TRUE);
|
||
}
|
||
|
||
JoinInfo->Status = ERROR_SUCCESS;
|
||
JoinInfo->Sequence = Sequence;
|
||
JoinInfo->LockerNode = LockerNodeId;
|
||
|
||
//
|
||
// Zero out all the nodes in the active node array.
|
||
//
|
||
ZeroMemory(&GumTable[UpdateType].ActiveNode,
|
||
sizeof(GumTable[UpdateType].ActiveNode));
|
||
|
||
//
|
||
// Set all the nodes that are currently active in the
|
||
// active node array.
|
||
//
|
||
for (i=0; i < NodeList->NodeCount; i++) {
|
||
CL_ASSERT(NmIsValidNodeId(NodeList->NodeId[i]));
|
||
ClRtlLogPrint(LOG_NOISE,
|
||
"[GUM] GumpNodeCallback setting node %1!d! active.\n",
|
||
NodeList->NodeId[i]);
|
||
GumTable[UpdateType].ActiveNode[NodeList->NodeId[i]] = TRUE;;
|
||
}
|
||
MIDL_user_free(NodeList);
|
||
|
||
//
|
||
// Add in our own node.
|
||
//
|
||
GumTable[UpdateType].ActiveNode[NmGetNodeId(NmLocalNode)] = TRUE;
|
||
|
||
//
|
||
// Set the current locker node
|
||
//
|
||
GumpLockerNode = LockerNodeId;
|
||
return(FALSE);
|
||
|
||
}
|
||
|
||
|
||
DWORD
|
||
GumCreateRpcBindings(
|
||
PNM_NODE Node
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Creates GUM's private RPC bindings for a joining node.
|
||
Called by the Node Manager.
|
||
|
||
Arguments:
|
||
|
||
Node - A pointer to the node for which to create RPC bindings
|
||
|
||
Return Value:
|
||
|
||
A Win32 status code.
|
||
|
||
--*/
|
||
{
|
||
DWORD Status;
|
||
RPC_BINDING_HANDLE BindingHandle;
|
||
CL_NODE_ID NodeId = NmGetNodeId(Node);
|
||
|
||
|
||
ClRtlLogPrint(LOG_NOISE,
|
||
"[GUM] Creating RPC bindings for node %1!u!.\n",
|
||
NodeId
|
||
);
|
||
|
||
//
|
||
// Main binding
|
||
//
|
||
if (GumpRpcBindings[NodeId] != NULL) {
|
||
//
|
||
// Reuse the old binding.
|
||
//
|
||
Status = ClMsgVerifyRpcBinding(GumpRpcBindings[NodeId]);
|
||
|
||
if (Status != ERROR_SUCCESS) {
|
||
ClRtlLogPrint(LOG_ERROR,
|
||
"[GUM] Failed to verify 1st RPC binding for node %1!u!, status %2!u!.\n",
|
||
NodeId,
|
||
Status
|
||
);
|
||
return(Status);
|
||
}
|
||
}
|
||
else {
|
||
//
|
||
// Create a new binding
|
||
//
|
||
Status = ClMsgCreateRpcBinding(
|
||
Node,
|
||
&(GumpRpcBindings[NodeId]),
|
||
0 );
|
||
|
||
if (Status != ERROR_SUCCESS) {
|
||
ClRtlLogPrint(LOG_ERROR,
|
||
"[GUM] Failed to create 1st RPC binding for node %1!u!, status %2!u!.\n",
|
||
NodeId,
|
||
Status
|
||
);
|
||
return(Status);
|
||
}
|
||
}
|
||
|
||
//
|
||
// Replay binding
|
||
//
|
||
if (GumpReplayRpcBindings[NodeId] != NULL) {
|
||
//
|
||
// Reuse the old binding.
|
||
//
|
||
Status = ClMsgVerifyRpcBinding(GumpReplayRpcBindings[NodeId]);
|
||
|
||
if (Status != ERROR_SUCCESS) {
|
||
ClRtlLogPrint(LOG_ERROR,
|
||
"[GUM] Failed to verify 2nd RPC binding for node %1!u!, status %2!u!.\n",
|
||
NodeId,
|
||
Status
|
||
);
|
||
return(Status);
|
||
}
|
||
}
|
||
else {
|
||
//
|
||
// Create a new binding
|
||
//
|
||
Status = ClMsgCreateRpcBinding(
|
||
Node,
|
||
&(GumpReplayRpcBindings[NodeId]),
|
||
0 );
|
||
|
||
if (Status != ERROR_SUCCESS) {
|
||
ClRtlLogPrint(LOG_ERROR,
|
||
"[GUM] Failed to create 2nd RPC binding for node %1!u!, status %2!u!.\n",
|
||
NodeId,
|
||
Status
|
||
);
|
||
return(Status);
|
||
}
|
||
}
|
||
|
||
return(ERROR_SUCCESS);
|
||
|
||
} // GumCreateRpcBindings
|
||
|
||
|
||
|
||
|