Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

375 lines
12 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. vote.c
  5. Abstract:
  6. Routines for sending global updates to the cluster
  7. Author:
  8. Sunita Shrivastava(sunitas) 17-Mar-1998
  9. Revision History:
  10. --*/
  11. #include "gump.h"
  12. /****
  13. @doc EXTERNAL INTERFACES CLUSSVC GUM
  14. ****/
  15. /****
  16. @func DWORD | GumSendUpdateOnVote| Allows a the caller to collect votes
  17. from all active nodes in the cluster before sending an update.
  18. @parm IN GUM_UPDATE_TYPE | UpdateType | The update type that will
  19. be sent if the decision call back function returns true.
  20. @parn IN DWORD | dwContext | This specifies the context related to the
  21. Updatetype that will be sent.
  22. @parm IN DWORD | dwInputBufLength | The length of the input buffer
  23. passed in via pInputBuffer.
  24. @parm IN PVOID | pInputBuffer | A pointer to the input buffer that is
  25. passed to all the active nodes based on which they can vote.
  26. @parm IN DWORD | dwVoteLength | The length of the vote. Depending
  27. on this, an appropriately large buffer is allocated to collect
  28. all the votes.
  29. @parm IN GUM_VOTE_DECISION_CB | pfnGumDecisionCb | The decision call
  30. back function that is invoked once all the votes have been collected.
  31. @rdesc Returns a result code. ERROR_SUCCESS on success.
  32. @comm
  33. @xref <f GumpCollectVotes>
  34. ****/
  35. DWORD
  36. GumSendUpdateOnVote(
  37. IN GUM_UPDATE_TYPE UpdateType,
  38. IN DWORD dwContext, //vote type
  39. IN DWORD dwInputBufLength, //input data to make judgement upon
  40. IN PVOID pInputBuffer, //size of the input data
  41. IN DWORD dwVoteLength,
  42. IN PGUM_VOTE_DECISION_CB pfnGumDecisionCb,
  43. IN PVOID pContext
  44. )
  45. {
  46. DWORD dwVoteBufSize;
  47. BOOL bDidAllActiveNodesVote;
  48. DWORD dwNumVotes;
  49. DWORD dwStatus;
  50. GUM_VOTE_DECISION_CONTEXT GumDecisionContext;
  51. PBYTE pVoteBuffer=NULL;
  52. DWORD dwSequence;
  53. DWORD dwDecisionStatus;
  54. DWORD dwUpdateBufLength;
  55. PBYTE pUpdateBuf=NULL;
  56. ClRtlLogPrint(LOG_NOISE,
  57. "[GUM] GumSendUpdateOnVote: Type=%1!u! Context=%2!u!\n",
  58. UpdateType, dwContext);
  59. if (dwVoteLength == 0)
  60. {
  61. dwStatus = ERROR_INVALID_PARAMETER;
  62. goto FnExit;
  63. }
  64. //SS: We dont have to deal with a join happening between
  65. // the time we allocate the buffer to the time we collect votes
  66. // this is because the buffer we allocate is big enough to
  67. // collect all votes from the maximum number of allowed nodes
  68. // of a cluster.
  69. dwVoteBufSize = (DWORD)(NmMaxNodes * (sizeof(GUM_VOTE_ENTRY) + dwVoteLength));
  70. //allocate a buffer big enough to collect every bodies
  71. pVoteBuffer = (PBYTE)LocalAlloc(LMEM_FIXED, dwVoteBufSize);
  72. if (!pVoteBuffer)
  73. {
  74. dwStatus = GetLastError();
  75. goto FnExit;
  76. }
  77. ZeroMemory(pVoteBuffer, dwVoteBufSize);
  78. //setup the decision context structure
  79. GumDecisionContext.UpdateType = UpdateType;
  80. GumDecisionContext.dwContext = dwContext;
  81. GumDecisionContext.dwInputBufLength = dwInputBufLength;
  82. GumDecisionContext.pInputBuf = pInputBuffer;
  83. GumDecisionContext.dwVoteLength = dwVoteLength;
  84. GumDecisionContext.pContext = pContext;
  85. Retry:
  86. //gum get sequence
  87. dwSequence = GumpSequence;
  88. ClRtlLogPrint(LOG_NOISE,
  89. "[GUM] GumSendUpdateOnVote: Collect Vote at Sequence=%1!u!\n",
  90. dwSequence);
  91. //gets the information from all nodes
  92. //this is done without acquiring the gum lock
  93. //could have been done in parallel if we had the appropriate
  94. //networking constructs
  95. dwStatus = GumpCollectVotes(&GumDecisionContext, dwVoteBufSize,
  96. pVoteBuffer, &dwNumVotes, &bDidAllActiveNodesVote);
  97. if (dwStatus != ERROR_SUCCESS)
  98. {
  99. goto FnExit;
  100. }
  101. //Call the callback
  102. dwDecisionStatus = (*pfnGumDecisionCb)(&GumDecisionContext, dwVoteBufSize,
  103. pVoteBuffer, dwNumVotes, bDidAllActiveNodesVote,
  104. &dwUpdateBufLength, &pUpdateBuf);
  105. ClRtlLogPrint(LOG_NOISE,
  106. "[GUM] GumSendUpdateOnVote: Decision Routine returns=%1!u!\n",
  107. dwDecisionStatus);
  108. if (dwDecisionStatus == ERROR_SUCCESS)
  109. {
  110. //send the update to the locker node
  111. dwStatus = GumAttemptUpdate(dwSequence, UpdateType, dwContext,
  112. dwUpdateBufLength, pUpdateBuf);
  113. if (dwStatus == ERROR_CLUSTER_DATABASE_SEQMISMATCH ||
  114. dwStatus == ERROR_REVISION_MISMATCH ) // for mixed mode
  115. {
  116. //free the update buffer
  117. if (pUpdateBuf)
  118. {
  119. LocalFree(pUpdateBuf);
  120. pUpdateBuf = NULL;
  121. }
  122. goto Retry;
  123. }
  124. }
  125. FnExit:
  126. ClRtlLogPrint(LOG_NOISE,
  127. "[GUM] GumSendUpdateOnVote: Returning status=%1!u!\n",
  128. dwStatus);
  129. //free the buffer allocated for vote collection
  130. if (pVoteBuffer)
  131. {
  132. LocalFree(pVoteBuffer);
  133. }
  134. //free the buffer for update allocated by the decision callback function
  135. if (pUpdateBuf)
  136. {
  137. LocalFree(pUpdateBuf);
  138. }
  139. return(dwStatus);
  140. }
  141. /****
  142. @func DWORD | GumCollectVotes| Calls all the nodes in the node
  143. to collect their votes.
  144. @parm IN PGUM_VOTE_DECISION_CONTEXT | pVoteContext| A pointer to
  145. the vote context structure. This describes the type/context/input
  146. data for the vote.
  147. @parn IN DWORD | dwVoteBufSize| The size of the buffer pointed to
  148. by pVoteBuf.
  149. @parm OUT PVOID | pVoteBuffer | A pointer to the buffer allocated to
  150. collect the votes/data from all the nodes of the cluster.
  151. @parm OUT LPDWORD| pdwNumVotes| The number of nodes whose votes
  152. were collected.
  153. @parm IN BOOL| *pbDidAllActiveNodesVote | A pointer to a BOOL. This
  154. is set to true if all active nodes at the time the vote
  155. was collected vote.
  156. @rdesc Returns a result code. ERROR_SUCCESS on success.
  157. @comm This is called by GumSendUpdateOnVote() to collect votes from
  158. all the nodes of the cluster.
  159. @xref <f GumSendUpdateOnVote> <f GumpDispatchVote>
  160. ****/
  161. DWORD GumpCollectVotes(
  162. IN PGUM_VOTE_DECISION_CONTEXT pVoteContext,
  163. IN DWORD dwVoteBufSize,
  164. OUT PBYTE pVoteBuffer,
  165. OUT LPDWORD pdwNumVotes,
  166. OUT BOOL *pbDidAllActiveNodesVote
  167. )
  168. {
  169. DWORD dwStatus = ERROR_SUCCESS;
  170. DWORD dwVoteStatus = ERROR_SUCCESS;
  171. DWORD dwCount = 0;
  172. DWORD i;
  173. PGUM_VOTE_ENTRY pGumVoteEntry;
  174. PGUM_INFO GumInfo;
  175. DWORD MyNodeId;
  176. *pbDidAllActiveNodesVote = TRUE;
  177. GumInfo = &GumTable[pVoteContext->UpdateType];
  178. MyNodeId = NmGetNodeId(NmLocalNode);
  179. for (i=ClusterMinNodeId; i <= NmMaxNodeId; i++)
  180. {
  181. if (GumInfo->ActiveNode[i])
  182. {
  183. pGumVoteEntry = (PGUM_VOTE_ENTRY)(pVoteBuffer +
  184. (dwCount * (sizeof(GUM_VOTE_ENTRY) + pVoteContext->dwVoteLength)));
  185. CL_ASSERT((PBYTE)pGumVoteEntry <= (pVoteBuffer + dwVoteBufSize - sizeof(GUM_VOTE_ENTRY)));
  186. //
  187. // Dispatch the vote to the specified node.
  188. //
  189. ClRtlLogPrint(LOG_NOISE,
  190. "[GUM] GumVoteUpdate: Dispatching vote type %1!u!\tcontext %2!u! to node %3!d!\n",
  191. pVoteContext->UpdateType,
  192. pVoteContext->dwContext,
  193. i);
  194. if (i == MyNodeId)
  195. {
  196. dwVoteStatus = GumpDispatchVote(pVoteContext->UpdateType,
  197. pVoteContext->dwContext,
  198. pVoteContext->dwInputBufLength,
  199. pVoteContext->pInputBuf,
  200. pVoteContext->dwVoteLength,
  201. (PBYTE)pGumVoteEntry + sizeof(GUM_VOTE_ENTRY));
  202. }
  203. else
  204. {
  205. GumpStartRpc(i);
  206. dwVoteStatus = GumCollectVoteFromNode(GumpRpcBindings[i],
  207. pVoteContext->UpdateType,
  208. pVoteContext->dwContext,
  209. pVoteContext->dwInputBufLength,
  210. pVoteContext->pInputBuf,
  211. pVoteContext->dwVoteLength,
  212. (PBYTE)pGumVoteEntry + sizeof(GUM_VOTE_ENTRY));
  213. GumpEndRpc(i);
  214. }
  215. if (dwVoteStatus == ERROR_SUCCESS)
  216. {
  217. pGumVoteEntry->dwFlags = GUM_VOTE_VALID;
  218. pGumVoteEntry->dwNodeId = i;
  219. pGumVoteEntry->dwNumBytes = pVoteContext->dwVoteLength;
  220. dwCount++;
  221. }
  222. else
  223. pbDidAllActiveNodesVote = FALSE;
  224. }
  225. }
  226. *pdwNumVotes = dwCount;
  227. return(dwStatus);
  228. }
  229. /****
  230. @func DWORD | GumpDispatchVote| The routine calls the vote routine
  231. registered for a given update type to collect vote for the
  232. supplied context and the input data.
  233. @parm IN GUM_UPDATE_TYPE | Type | The update type for which this
  234. vote is requested.
  235. @parn IN DWORD | dwContext | This specifies the context related to the
  236. Updatetype for which a vote is being seeked.
  237. @parm IN DWORD | dwInputBufLength | The length of the input buffer
  238. passed in via pInputBuffer.
  239. @parm IN PVOID | pInputBuffer | A pointer to the input buffer via
  240. which the input data for the vote is supplied.
  241. @parm IN DWORD | dwVoteLength | The length of the vote. This is
  242. also the size of the buffer to which pBuf points to.
  243. @parm OUT PUCHAR | pVoteBuf| A pointer to a buffer in which
  244. this node may cast its vote. The length of the vote must
  245. not exceed dwVoteLength.
  246. @rdesc Returns a result code. ERROR_SUCCESS on success.
  247. @comm
  248. @xref <f GumpCollectVote> <f s_GumCollectVoteFromNode>
  249. ****/
  250. DWORD
  251. WINAPI
  252. GumpDispatchVote(
  253. IN GUM_UPDATE_TYPE Type,
  254. IN DWORD dwContext,
  255. IN DWORD dwInputBufLength,
  256. IN PUCHAR pInputBuf,
  257. IN DWORD dwVoteLength,
  258. OUT PUCHAR pVoteBuf
  259. )
  260. {
  261. PGUM_INFO GumInfo;
  262. PGUM_RECEIVER Receiver;
  263. DWORD Status = ERROR_REQUEST_ABORTED;
  264. GumInfo = &GumTable[Type];
  265. if (GumInfo->Joined)
  266. {
  267. Receiver = GumInfo->Receivers;
  268. if (Receiver != NULL)
  269. {
  270. try
  271. {
  272. if (Receiver->VoteRoutine)
  273. {
  274. Status =(*(Receiver->VoteRoutine))(dwContext,
  275. dwInputBufLength,
  276. pInputBuf,
  277. dwVoteLength,
  278. pVoteBuf);
  279. }
  280. } except (CL_UNEXPECTED_ERROR(GetExceptionCode()),
  281. EXCEPTION_EXECUTE_HANDLER
  282. )
  283. {
  284. Status = GetExceptionCode();
  285. }
  286. if (Status != ERROR_SUCCESS)
  287. {
  288. ClRtlLogPrint(LOG_CRITICAL,
  289. "[GUM] Vote routine %1!d! failed with status %2!d!\n",
  290. Receiver->VoteRoutine,
  291. Status);
  292. }
  293. }
  294. }
  295. return(Status);
  296. }