|
|
/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
vote.c
Abstract:
Routines for sending global updates to the cluster
Author:
Sunita Shrivastava(sunitas) 17-Mar-1998
Revision History:
--*/ #include "gump.h"
/****
@doc EXTERNAL INTERFACES CLUSSVC GUM ****/
/****
@func DWORD | GumSendUpdateOnVote| Allows a the caller to collect votes from all active nodes in the cluster before sending an update.
@parm IN GUM_UPDATE_TYPE | UpdateType | The update type that will be sent if the decision call back function returns true.
@parn IN DWORD | dwContext | This specifies the context related to the Updatetype that will be sent.
@parm IN DWORD | dwInputBufLength | The length of the input buffer passed in via pInputBuffer.
@parm IN PVOID | pInputBuffer | A pointer to the input buffer that is passed to all the active nodes based on which they can vote.
@parm IN DWORD | dwVoteLength | The length of the vote. Depending on this, an appropriately large buffer is allocated to collect all the votes.
@parm IN GUM_VOTE_DECISION_CB | pfnGumDecisionCb | The decision call back function that is invoked once all the votes have been collected.
@rdesc Returns a result code. ERROR_SUCCESS on success.
@comm @xref <f GumpCollectVotes> ****/ DWORD GumSendUpdateOnVote( IN GUM_UPDATE_TYPE UpdateType, IN DWORD dwContext, //vote type
IN DWORD dwInputBufLength, //input data to make judgement upon
IN PVOID pInputBuffer, //size of the input data
IN DWORD dwVoteLength, IN PGUM_VOTE_DECISION_CB pfnGumDecisionCb, IN PVOID pContext ) { DWORD dwVoteBufSize; BOOL bDidAllActiveNodesVote; DWORD dwNumVotes; DWORD dwStatus; GUM_VOTE_DECISION_CONTEXT GumDecisionContext; PBYTE pVoteBuffer=NULL; DWORD dwSequence; DWORD dwDecisionStatus; DWORD dwUpdateBufLength; PBYTE pUpdateBuf=NULL;
ClRtlLogPrint(LOG_NOISE, "[GUM] GumSendUpdateOnVote: Type=%1!u! Context=%2!u!\n", UpdateType, dwContext);
if (dwVoteLength == 0) { dwStatus = ERROR_INVALID_PARAMETER; goto FnExit; }
//SS: We dont have to deal with a join happening between
// the time we allocate the buffer to the time we collect votes
// this is because the buffer we allocate is big enough to
// collect all votes from the maximum number of allowed nodes
// of a cluster.
dwVoteBufSize = (DWORD)(NmMaxNodes * (sizeof(GUM_VOTE_ENTRY) + dwVoteLength)); //allocate a buffer big enough to collect every bodies
pVoteBuffer = (PBYTE)LocalAlloc(LMEM_FIXED, dwVoteBufSize); if (!pVoteBuffer) { dwStatus = GetLastError(); goto FnExit; }
ZeroMemory(pVoteBuffer, dwVoteBufSize);
//setup the decision context structure
GumDecisionContext.UpdateType = UpdateType; GumDecisionContext.dwContext = dwContext; GumDecisionContext.dwInputBufLength = dwInputBufLength; GumDecisionContext.pInputBuf = pInputBuffer; GumDecisionContext.dwVoteLength = dwVoteLength; GumDecisionContext.pContext = pContext;
Retry: //gum get sequence
dwSequence = GumpSequence;
ClRtlLogPrint(LOG_NOISE, "[GUM] GumSendUpdateOnVote: Collect Vote at Sequence=%1!u!\n", dwSequence);
//gets the information from all nodes
//this is done without acquiring the gum lock
//could have been done in parallel if we had the appropriate
//networking constructs
dwStatus = GumpCollectVotes(&GumDecisionContext, dwVoteBufSize, pVoteBuffer, &dwNumVotes, &bDidAllActiveNodesVote);
if (dwStatus != ERROR_SUCCESS) { goto FnExit; }
//Call the callback
dwDecisionStatus = (*pfnGumDecisionCb)(&GumDecisionContext, dwVoteBufSize, pVoteBuffer, dwNumVotes, bDidAllActiveNodesVote, &dwUpdateBufLength, &pUpdateBuf);
ClRtlLogPrint(LOG_NOISE, "[GUM] GumSendUpdateOnVote: Decision Routine returns=%1!u!\n", dwDecisionStatus);
if (dwDecisionStatus == ERROR_SUCCESS) {
//send the update to the locker node
dwStatus = GumAttemptUpdate(dwSequence, UpdateType, dwContext, dwUpdateBufLength, pUpdateBuf);
if (dwStatus == ERROR_CLUSTER_DATABASE_SEQMISMATCH || dwStatus == ERROR_REVISION_MISMATCH ) // for mixed mode
{ //free the update buffer
if (pUpdateBuf) { LocalFree(pUpdateBuf); pUpdateBuf = NULL; } goto Retry;
}
}
FnExit: ClRtlLogPrint(LOG_NOISE, "[GUM] GumSendUpdateOnVote: Returning status=%1!u!\n", dwStatus);
//free the buffer allocated for vote collection
if (pVoteBuffer) { LocalFree(pVoteBuffer); } //free the buffer for update allocated by the decision callback function
if (pUpdateBuf) { LocalFree(pUpdateBuf); }
return(dwStatus); }
/****
@func DWORD | GumCollectVotes| Calls all the nodes in the node to collect their votes.
@parm IN PGUM_VOTE_DECISION_CONTEXT | pVoteContext| A pointer to the vote context structure. This describes the type/context/input data for the vote.
@parn IN DWORD | dwVoteBufSize| The size of the buffer pointed to by pVoteBuf.
@parm OUT PVOID | pVoteBuffer | A pointer to the buffer allocated to collect the votes/data from all the nodes of the cluster.
@parm OUT LPDWORD| pdwNumVotes| The number of nodes whose votes were collected.
@parm IN BOOL| *pbDidAllActiveNodesVote | A pointer to a BOOL. This is set to true if all active nodes at the time the vote was collected vote.
@rdesc Returns a result code. ERROR_SUCCESS on success.
@comm This is called by GumSendUpdateOnVote() to collect votes from all the nodes of the cluster.
@xref <f GumSendUpdateOnVote> <f GumpDispatchVote> ****/ DWORD GumpCollectVotes( IN PGUM_VOTE_DECISION_CONTEXT pVoteContext, IN DWORD dwVoteBufSize, OUT PBYTE pVoteBuffer, OUT LPDWORD pdwNumVotes, OUT BOOL *pbDidAllActiveNodesVote ) { DWORD dwStatus = ERROR_SUCCESS; DWORD dwVoteStatus = ERROR_SUCCESS; DWORD dwCount = 0; DWORD i; PGUM_VOTE_ENTRY pGumVoteEntry; PGUM_INFO GumInfo; DWORD MyNodeId;
*pbDidAllActiveNodesVote = TRUE; GumInfo = &GumTable[pVoteContext->UpdateType]; MyNodeId = NmGetNodeId(NmLocalNode);
for (i=ClusterMinNodeId; i <= NmMaxNodeId; i++) { if (GumInfo->ActiveNode[i]) {
pGumVoteEntry = (PGUM_VOTE_ENTRY)(pVoteBuffer + (dwCount * (sizeof(GUM_VOTE_ENTRY) + pVoteContext->dwVoteLength)));
CL_ASSERT((PBYTE)pGumVoteEntry <= (pVoteBuffer + dwVoteBufSize - sizeof(GUM_VOTE_ENTRY))); //
// Dispatch the vote to the specified node.
//
ClRtlLogPrint(LOG_NOISE, "[GUM] GumVoteUpdate: Dispatching vote type %1!u!\tcontext %2!u! to node %3!d!\n", pVoteContext->UpdateType, pVoteContext->dwContext, i); if (i == MyNodeId) { dwVoteStatus = GumpDispatchVote(pVoteContext->UpdateType, pVoteContext->dwContext, pVoteContext->dwInputBufLength, pVoteContext->pInputBuf, pVoteContext->dwVoteLength, (PBYTE)pGumVoteEntry + sizeof(GUM_VOTE_ENTRY)); } else { GumpStartRpc(i); dwVoteStatus = GumCollectVoteFromNode(GumpRpcBindings[i], pVoteContext->UpdateType, pVoteContext->dwContext, pVoteContext->dwInputBufLength, pVoteContext->pInputBuf, pVoteContext->dwVoteLength, (PBYTE)pGumVoteEntry + sizeof(GUM_VOTE_ENTRY)); GumpEndRpc(i); } if (dwVoteStatus == ERROR_SUCCESS) { pGumVoteEntry->dwFlags = GUM_VOTE_VALID; pGumVoteEntry->dwNodeId = i; pGumVoteEntry->dwNumBytes = pVoteContext->dwVoteLength;
dwCount++; } else pbDidAllActiveNodesVote = FALSE; } } *pdwNumVotes = dwCount; return(dwStatus); }
/****
@func DWORD | GumpDispatchVote| The routine calls the vote routine registered for a given update type to collect vote for the supplied context and the input data.
@parm IN GUM_UPDATE_TYPE | Type | The update type for which this vote is requested.
@parn IN DWORD | dwContext | This specifies the context related to the Updatetype for which a vote is being seeked.
@parm IN DWORD | dwInputBufLength | The length of the input buffer passed in via pInputBuffer.
@parm IN PVOID | pInputBuffer | A pointer to the input buffer via which the input data for the vote is supplied.
@parm IN DWORD | dwVoteLength | The length of the vote. This is also the size of the buffer to which pBuf points to.
@parm OUT PUCHAR | pVoteBuf| A pointer to a buffer in which this node may cast its vote. The length of the vote must not exceed dwVoteLength.
@rdesc Returns a result code. ERROR_SUCCESS on success.
@comm @xref <f GumpCollectVote> <f s_GumCollectVoteFromNode> ****/ DWORD WINAPI GumpDispatchVote( IN GUM_UPDATE_TYPE Type, IN DWORD dwContext, IN DWORD dwInputBufLength, IN PUCHAR pInputBuf, IN DWORD dwVoteLength, OUT PUCHAR pVoteBuf ) { PGUM_INFO GumInfo; PGUM_RECEIVER Receiver; DWORD Status = ERROR_REQUEST_ABORTED;
GumInfo = &GumTable[Type];
if (GumInfo->Joined) { Receiver = GumInfo->Receivers; if (Receiver != NULL) {
try { if (Receiver->VoteRoutine) { Status =(*(Receiver->VoteRoutine))(dwContext, dwInputBufLength, pInputBuf, dwVoteLength, pVoteBuf); } } except (CL_UNEXPECTED_ERROR(GetExceptionCode()), EXCEPTION_EXECUTE_HANDLER ) { Status = GetExceptionCode(); } if (Status != ERROR_SUCCESS) { ClRtlLogPrint(LOG_CRITICAL, "[GUM] Vote routine %1!d! failed with status %2!d!\n", Receiver->VoteRoutine, Status); } } }
return(Status); }
|