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.

1290 lines
35 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. receive.c
  5. Abstract:
  6. Routines for registering for global updates and dispensing
  7. received global updates to the routines that have registered
  8. for them.
  9. Author:
  10. John Vert (jvert) 17-Apr-1996
  11. Revision History:
  12. --*/
  13. #include "gump.h"
  14. VOID
  15. GumReceiveUpdates(
  16. IN BOOL IsJoining,
  17. IN GUM_UPDATE_TYPE UpdateType,
  18. IN PGUM_UPDATE_ROUTINE UpdateRoutine,
  19. IN PGUM_LOG_ROUTINE LogRoutine,
  20. IN DWORD DispatchCount,
  21. IN OPTIONAL PGUM_DISPATCH_ENTRY DispatchTable,
  22. IN OPTIONAL PGUM_VOTE_ROUTINE VoteRoutine
  23. )
  24. /*++
  25. Routine Description:
  26. Registers a handler for a particular global update type.
  27. Arguments:
  28. IsJoining - TRUE if the current node is joining. If this is true,
  29. updates will not be delivered until GumEndJoinUpdate has
  30. completed successfully. If this is FALSE, updates will be
  31. delivered immediately.
  32. UpdateType - Supplies the update type to register for.
  33. UpdateRoutine - Supplies the routine to be called when a global update
  34. of the specified type occurs.
  35. LogRoutine - If supplied, it specifies the logging routine that must be called to
  36. log transaction to the quorum logs.
  37. DispatchCount - Supplies the number of entries in the dispatch table.
  38. This can be zero.
  39. DispatchTable - Supplies a pointer to the dispatch table. If this is
  40. NULL, no updates of this type will be automatically dispatched.
  41. VoteRoutine - If supplied, this specifies the routine to be called when
  42. a vote for this update type is requested.
  43. Return Value:
  44. None.
  45. --*/
  46. {
  47. PGUM_RECEIVER Receiver;
  48. CL_ASSERT(UpdateType < GumUpdateMaximum);
  49. Receiver = LocalAlloc(LMEM_FIXED, sizeof(GUM_RECEIVER));
  50. if (Receiver == NULL) {
  51. CL_LOGFAILURE(ERROR_NOT_ENOUGH_MEMORY);
  52. return;
  53. }
  54. Receiver->UpdateRoutine = UpdateRoutine;
  55. Receiver->LogRoutine = LogRoutine;
  56. Receiver->DispatchCount = DispatchCount;
  57. Receiver->DispatchTable = DispatchTable;
  58. Receiver->VoteRoutine = VoteRoutine;
  59. //
  60. // John Vert (jvert) 8/2/1996
  61. // remove below debug print if we ever want to support
  62. // multiple GUM handlers.
  63. //
  64. if (GumTable[UpdateType].Receivers != NULL) {
  65. ClRtlLogPrint(LOG_CRITICAL,
  66. "[GUM] Multiple GUM handlers registered for UpdateType %1!d!\n",
  67. UpdateType);
  68. }
  69. EnterCriticalSection(&GumpLock);
  70. Receiver->Next = GumTable[UpdateType].Receivers;
  71. GumTable[UpdateType].Receivers = Receiver;
  72. if (IsJoining) {
  73. GumTable[UpdateType].Joined = FALSE;
  74. } else {
  75. GumTable[UpdateType].Joined = TRUE;
  76. }
  77. LeaveCriticalSection(&GumpLock);
  78. }
  79. VOID
  80. GumIgnoreUpdates(
  81. IN GUM_UPDATE_TYPE UpdateType,
  82. IN PGUM_UPDATE_ROUTINE UpdateRoutine
  83. )
  84. /*++
  85. Routine Description:
  86. Removes an update handler from the GUM table. This is the opposite
  87. of GumReceiveUpdates
  88. Arguments:
  89. UpdateType - Supplies the update type to register for.
  90. UpdateRoutine - Supplies the routine to be called when a global update
  91. of the specified type occurs.
  92. Return Value:
  93. None
  94. --*/
  95. {
  96. PGUM_RECEIVER Receiver;
  97. PGUM_RECEIVER *Last;
  98. //
  99. // We cannot safely de-registr from Gum... ASSERT if anyone calls this
  100. // function.
  101. //
  102. CL_ASSERT(FALSE);
  103. //
  104. // Walk the list of receivers until we find the specified UpdateRoutine
  105. //
  106. Last = &GumTable[UpdateType].Receivers;
  107. EnterCriticalSection(&GumpLock);
  108. while ((Receiver = *Last) != NULL) {
  109. if (Receiver->UpdateRoutine == UpdateRoutine) {
  110. *Last = Receiver->Next;
  111. break;
  112. }
  113. Last = &Receiver->Next;
  114. }
  115. LeaveCriticalSection(&GumpLock);
  116. if (Receiver != NULL) {
  117. LocalFree(Receiver);
  118. }
  119. }
  120. DWORD
  121. WINAPI
  122. GumpDispatchUpdate(
  123. IN GUM_UPDATE_TYPE Type,
  124. IN DWORD Context,
  125. IN BOOL IsLocker,
  126. IN BOOL SourceNode,
  127. IN DWORD BufferLength,
  128. IN PUCHAR Buffer
  129. )
  130. /*++
  131. Routine Description:
  132. Dispatches a GUM update to all the registered handlers on this node
  133. Arguments:
  134. Sequence - Supplies the GUM sequence number for the update
  135. Type - Supplies the GUM_UPDATE_TYPE for the update
  136. Context - Supplies a DWORD of context to be passed to the
  137. GUM update handlers
  138. IsLocker - Specifies if this is a locker node.
  139. SourceNode - Specifies whether the update originated on this node or not.
  140. BufferLength - Supplies the length of the update data
  141. Buffer - Supplies a pointer to the update data
  142. Return Value:
  143. ERROR_SUCCESS if successful
  144. Win32 error otherwise.
  145. --*/
  146. {
  147. PGUM_INFO GumInfo;
  148. PGUM_RECEIVER Receiver;
  149. DWORD Status = ERROR_SUCCESS;
  150. PGUM_DISPATCH_ENTRY Dispatch;
  151. GumInfo = &GumTable[Type];
  152. if (GumInfo->Joined) {
  153. Receiver = GumInfo->Receivers;
  154. while (Receiver != NULL) {
  155. if (Receiver->LogRoutine) {
  156. Status = (*(Receiver->LogRoutine))(PRE_GUM_DISPATCH, GumpSequence,
  157. Context, Buffer, BufferLength);
  158. if (Status != ERROR_SUCCESS)
  159. {
  160. return(Status);
  161. }
  162. }
  163. try {
  164. if ((Receiver->DispatchTable == NULL) ||
  165. (Receiver->DispatchCount < Context) ||
  166. (Receiver->DispatchTable[Context].Dispatch1 == NULL)) {
  167. Status = (Receiver->UpdateRoutine)(Context,
  168. SourceNode,
  169. BufferLength,
  170. Buffer);
  171. } else {
  172. Dispatch = &Receiver->DispatchTable[Context];
  173. //
  174. // This update should be unmarshalled and dispatched to the
  175. // appropriate dispatch routine. The format generated by
  176. // GumpMarshallArgs is an array of offsets into the buffer,
  177. // followed by the actual args. The dispatch table is
  178. // responsible for recording the number of arguments.
  179. //
  180. CL_ASSERT(Dispatch->ArgCount <= GUM_MAX_DISPATCH_ARGS);
  181. CL_ASSERT(Dispatch->ArgCount != 0);
  182. switch (Dispatch->ArgCount) {
  183. case 1:
  184. Status = (Dispatch->Dispatch1)(SourceNode,
  185. GET_ARG(Buffer,0));
  186. break;
  187. case 2:
  188. Status = (Dispatch->Dispatch2)(SourceNode,
  189. GET_ARG(Buffer,0),
  190. GET_ARG(Buffer,1));
  191. break;
  192. case 3:
  193. Status = (Dispatch->Dispatch3)(SourceNode,
  194. GET_ARG(Buffer,0),
  195. GET_ARG(Buffer,1),
  196. GET_ARG(Buffer,2));
  197. break;
  198. case 4:
  199. Status = (Dispatch->Dispatch4)(SourceNode,
  200. GET_ARG(Buffer,0),
  201. GET_ARG(Buffer,1),
  202. GET_ARG(Buffer,2),
  203. GET_ARG(Buffer,3));
  204. break;
  205. case 5:
  206. Status = (Dispatch->Dispatch5)(SourceNode,
  207. GET_ARG(Buffer,0),
  208. GET_ARG(Buffer,1),
  209. GET_ARG(Buffer,2),
  210. GET_ARG(Buffer,3),
  211. GET_ARG(Buffer,4));
  212. break;
  213. default:
  214. CL_ASSERT(FALSE);
  215. }
  216. }
  217. } except (CL_UNEXPECTED_ERROR(GetExceptionCode()),
  218. EXCEPTION_EXECUTE_HANDLER
  219. )
  220. {
  221. Status = GetExceptionCode();
  222. }
  223. if (Status != ERROR_SUCCESS) {
  224. ClRtlLogPrint(LOG_CRITICAL,
  225. "[GUM] Update routine %1!d! failed with status %2!d!\n",
  226. Receiver->UpdateRoutine,
  227. Status);
  228. break;
  229. }
  230. if (Receiver->LogRoutine) {
  231. if (IsLocker && (Status == ERROR_SUCCESS))
  232. (*(Receiver->LogRoutine))(POST_GUM_DISPATCH, GumpSequence,
  233. Context, Buffer, BufferLength);
  234. if (!IsLocker)
  235. (*(Receiver->LogRoutine))(POST_GUM_DISPATCH, GumpSequence,
  236. Context, Buffer, BufferLength);
  237. }
  238. Receiver = Receiver->Next;
  239. }
  240. }
  241. if (Status == ERROR_SUCCESS) {
  242. GumpSequence += 1;
  243. }
  244. return(Status);
  245. }
  246. //rod wants to call this a mandatory update instead of H...word
  247. //some times reupdates get delivered in different views on different
  248. //nodes causing a problem
  249. //For instance, a locker node might see an update and complete it
  250. //successfully in one view but when it replays it in another view
  251. //other nodes may not be able to complete it successfully and may be
  252. //banished.
  253. //in one particular case, the locker node approved of a node join
  254. //because it had finished the node down processing for that node.
  255. //subsequently another node and hence the joiner went down.
  256. //the locker node tried to replay the approval update and banished
  257. //other nodes that were seeing this update after the joiner the joiner
  258. //went down for the second time.
  259. //The correct solution would involve GUM delivering the node down
  260. //message as a gum update and delivering it in the same order with
  261. //respect to other messages on all nodes
  262. //However this will require some restructuring of code which
  263. //cant be done in this time frame(for dtc) hence we are using
  264. //this workaround
  265. //this workaround is safe for gums initiated by the joiner node during
  266. //the join process
  267. void GumpIgnoreSomeUpdatesOnReupdate(
  268. IN DWORD Type,
  269. IN DWORD Context)
  270. {
  271. if ((Type == GumUpdateFailoverManager) &&
  272. (Context == FmUpdateApproveJoin))
  273. GumpLastBufferValid = FALSE;
  274. }
  275. error_status_t
  276. s_GumUpdateNode(
  277. IN handle_t IDL_handle,
  278. IN DWORD Type,
  279. IN DWORD Context,
  280. IN DWORD Sequence,
  281. IN DWORD BufferLength,
  282. IN UCHAR Buffer[]
  283. )
  284. /*++
  285. Routine Description:
  286. Server side routine for GumUpdateNode. This is the side that
  287. receives the update and dispatches it to the appropriate
  288. handlers.
  289. Arguments:
  290. IDL_handle - RPC binding handle, not used
  291. Type - Supplies the GUM_UPDATE_TYPE
  292. Context - Supplies a DWORD of context to be passed to the
  293. GUM update handlers
  294. Sequence - Supplies the GUM sequence number for the specified update type
  295. BufferLength - Supplies the length of the update data
  296. Buffer - Supplies a pointer to the update data.
  297. Return Value:
  298. ERROR_SUCCESS if the update completed successfully
  299. ERROR_CLUSTER_DATABASE_SEQMISMATCH if the GUM sequence number is invalid
  300. --*/
  301. {
  302. DWORD Status;
  303. PGUM_INFO GumInfo;
  304. //
  305. // We need to grap the gumsendupdate lock to serialize send/replay
  306. //
  307. EnterCriticalSection(&GumpSendUpdateLock);
  308. GumInfo = &GumTable[Type];
  309. if (Sequence != GumpSequence) {
  310. MIDL_user_free(Buffer);
  311. if (Sequence+1 == GumpSequence) {
  312. //
  313. // This is a duplicate of a previously seen update, probably due to
  314. // a node failure during GUM. Return success since we have already done
  315. // this.
  316. //
  317. ClRtlLogPrint(LOG_UNUSUAL,
  318. "[GUM] s_GumUpdateNode: Sequence %1!u! is a duplicate of last sequence for Type %2!u!\n",
  319. Sequence,
  320. Type);
  321. LeaveCriticalSection(&GumpSendUpdateLock);
  322. return(ERROR_SUCCESS);
  323. } else {
  324. ClRtlLogPrint(LOG_UNUSUAL,
  325. "[GUM] s_GumUpdateNode: Sequence %1!u! does not match current %2!u! for Type %3!u!\n",
  326. Sequence,
  327. GumpSequence,
  328. Type);
  329. LeaveCriticalSection(&GumpSendUpdateLock);
  330. //
  331. // [GorN] 10/07/1999. The following code will allow the test program
  332. // to recognize this sitiation and to restart clustering service
  333. //
  334. if( NmGetExtendedNodeState( NmLocalNode ) != ClusterNodeUp){
  335. CsInconsistencyHalt(ERROR_CLUSTER_DATABASE_SEQMISMATCH);
  336. }
  337. return(ERROR_CLUSTER_DATABASE_SEQMISMATCH);
  338. }
  339. }
  340. ClRtlLogPrint(LOG_NOISE,
  341. "[GUM] s_GumUpdateNode: dispatching seq %1!u!\ttype %2!u! context %3!u!\n",
  342. Sequence,
  343. Type,
  344. Context);
  345. //SS: set IsLocker to FALSE,
  346. Status = GumpDispatchUpdate(Type,
  347. Context,
  348. FALSE,
  349. FALSE,
  350. BufferLength,
  351. Buffer);
  352. if (Status != ERROR_SUCCESS) {
  353. ClRtlLogPrint(LOG_CRITICAL,
  354. "[GUM] Cluster state inconsistency check\n");
  355. ClRtlLogPrint(LOG_CRITICAL,
  356. "[GUM] s_GumUpdateNode update routine type %1!u! context %2!d! failed with error %3!d! on non-locker node\n",
  357. Type,
  358. Context,
  359. Status);
  360. CL_UNEXPECTED_ERROR( Status );
  361. MIDL_user_free(Buffer);
  362. LeaveCriticalSection(&GumpSendUpdateLock);
  363. return(Status);
  364. }
  365. ClRtlLogPrint(LOG_NOISE,
  366. "[GUM] s_GumUpdateNode: completed update seq %1!u!\ttype %2!u! context %3!u!\n",
  367. Sequence,
  368. Type,
  369. Context);
  370. if (GumpLastBuffer != NULL) {
  371. MIDL_user_free(GumpLastBuffer);
  372. }
  373. GumpLastBuffer = Buffer;
  374. GumpLastContext = Context;
  375. GumpLastBufferLength = BufferLength;
  376. GumpLastUpdateType = Type;
  377. GumpLastBufferValid = TRUE;
  378. GumpIgnoreSomeUpdatesOnReupdate(GumpLastUpdateType, GumpLastContext);
  379. LeaveCriticalSection(&GumpSendUpdateLock);
  380. return(Status);
  381. }
  382. error_status_t
  383. s_GumGetNodeSequence(
  384. IN handle_t IDL_handle,
  385. IN DWORD Type,
  386. OUT LPDWORD Sequence,
  387. OUT LPDWORD LockerNodeId,
  388. OUT PGUM_NODE_LIST *ReturnNodeList
  389. )
  390. /*++
  391. Routine Description:
  392. Returns the node's current GUM sequence number for the specified type
  393. Arguments:
  394. IDL_handle - Supplies the RPC binding handle, not used
  395. Type - Supplies the GUM_UPDATE_TYPE
  396. Sequence - Returns the sequence number for the specified GUM_UPDATE_TYPE
  397. LockerNodeId - Returns the current locker node
  398. ReturnNodeList - Returns the list of active nodes
  399. Return Value:
  400. ERROR_SUCCESS
  401. --*/
  402. {
  403. DWORD i;
  404. DWORD NodeCount;
  405. PGUM_INFO GumInfo;
  406. PGUM_NODE_LIST NodeList;
  407. CL_ASSERT(Type < GumUpdateMaximum);
  408. GumInfo = &GumTable[Type];
  409. NodeCount = 0;
  410. *Sequence = 0; // In case of failure set sequence to 0
  411. EnterCriticalSection(&GumpUpdateLock);
  412. //
  413. // Count up the number of nodes in the list.
  414. //
  415. for (i=ClusterMinNodeId; i <= NmMaxNodeId; i++) {
  416. if (GumInfo->ActiveNode[i] == TRUE) {
  417. ++NodeCount;
  418. }
  419. }
  420. CL_ASSERT(NodeCount > 0); // must be at least us in the list.
  421. //
  422. // Allocate node list
  423. //
  424. NodeList = MIDL_user_allocate(sizeof(GUM_NODE_LIST) + (NodeCount-1)*sizeof(DWORD));
  425. if (NodeList == NULL) {
  426. LeaveCriticalSection(&GumpUpdateLock);
  427. return(ERROR_NOT_ENOUGH_MEMORY);
  428. }
  429. NodeList->NodeCount = NodeCount;
  430. NodeCount = 0;
  431. //
  432. // Fill in the node id array to be returned.
  433. //
  434. for (i=ClusterMinNodeId; i <= NmMaxNodeId; i++) {
  435. if (GumInfo->ActiveNode[i] == TRUE) {
  436. NodeList->NodeId[NodeCount] = i;
  437. ++NodeCount;
  438. }
  439. }
  440. *ReturnNodeList = NodeList;
  441. *Sequence = GumpSequence;
  442. *LockerNodeId = GumpLockerNode;
  443. LeaveCriticalSection(&GumpUpdateLock);
  444. return(ERROR_SUCCESS);
  445. }
  446. error_status_t
  447. s_GumQueueLockingUpdate(
  448. IN handle_t IDL_handle,
  449. IN DWORD NodeId,
  450. IN DWORD Type,
  451. IN DWORD Context,
  452. OUT LPDWORD Sequence,
  453. IN DWORD BufferLength,
  454. IN UCHAR Buffer[]
  455. )
  456. /*++
  457. Routine Description:
  458. Queues a locking update. When the lock can be acquired, the update will
  459. be issued and this routine will return with the lock held.
  460. Arguments:
  461. IDL_handle - Supplies the RPC binding context, not used.
  462. NodeId - Supplies the node id of the issuing node.
  463. Type - Supplies the GUM_UPDATE_TYPE of the update
  464. Context - Supplies the GUM update context
  465. IsLocker - is this is the locker node
  466. Sequence - Returns the sequence that the GUM update must be issued with
  467. BufferLength - Supplies the length of the update.
  468. Buffer - Supplies the update data.
  469. Return Value:
  470. ERROR_SUCCESS if successful
  471. Win32 error otherwise.
  472. --*/
  473. {
  474. DWORD Status;
  475. PGUM_INFO GumInfo;
  476. DWORD dwGennum;
  477. GumInfo = &GumTable[Type];
  478. //
  479. // Get current node generation number
  480. //
  481. dwGennum = GumpGetNodeGenNum(GumInfo, NodeId);
  482. Status = GumpDoLockingUpdate(Type, NodeId, Sequence);
  483. if (Status != ERROR_SUCCESS) {
  484. ClRtlLogPrint(LOG_UNUSUAL,
  485. "[GUM] s_GumQueueLockingUpdate: GumpDoLockingUpdate failed %1!u!\n",
  486. Status);
  487. MIDL_user_free(Buffer);
  488. return(Status);
  489. }
  490. //
  491. // If the node that is granted ownership is no longer a member of the
  492. // cluster or the remote node went down and came back up again, give it up.
  493. //
  494. if (GumpDispatchStart(NodeId, dwGennum) != TRUE)
  495. {
  496. //skip the dispatch and unlock the lock
  497. ClRtlLogPrint(LOG_CRITICAL,
  498. "[GUM] s_GumQueueLockingUpdate: The new locker %1!u! no longer belongs to the cluster\n",
  499. NodeId);
  500. Status = ERROR_CLUSTER_NODE_NOT_READY;
  501. //
  502. // Note we have to use Sequence-1 for the unlock because GumpDispatchUpdate
  503. // failed and did not increment the sequence number.
  504. //
  505. GumpDoUnlockingUpdate(Type, *Sequence - 1);
  506. MIDL_user_free(Buffer);
  507. return(Status);
  508. }
  509. ClRtlLogPrint(LOG_NOISE,
  510. "[GUM] s_GumQueueLockingUpdate: dispatching seq %1!u!\ttype %2!u! context %3!u!\n",
  511. *Sequence,
  512. Type,
  513. Context);
  514. //SS: Set IsLocker to TRUE
  515. Status = GumpDispatchUpdate(Type,
  516. Context,
  517. TRUE,
  518. FALSE,
  519. BufferLength,
  520. Buffer);
  521. if (Status != ERROR_SUCCESS) {
  522. //
  523. // Note we have to use Sequence-1 for the unlock because GumpDispatchUpdate
  524. // failed and did not increment the sequence number.
  525. //
  526. GumpDispatchAbort();
  527. GumpDoUnlockingUpdate(Type, *Sequence - 1);
  528. if (Buffer != NULL)
  529. MIDL_user_free(Buffer);
  530. } else {
  531. if (GumpLastBuffer != NULL) {
  532. MIDL_user_free(GumpLastBuffer);
  533. }
  534. GumpLastBuffer = Buffer;
  535. GumpLastContext = Context;
  536. GumpLastBufferLength = BufferLength;
  537. GumpLastUpdateType = Type;
  538. GumpLastBufferValid = TRUE;
  539. GumpIgnoreSomeUpdatesOnReupdate(GumpLastUpdateType, GumpLastContext);
  540. //
  541. // Just in case our client dies
  542. //
  543. GumpDispatchEnd(NodeId, dwGennum);
  544. }
  545. ClRtlLogPrint(LOG_NOISE,
  546. "[GUM] s_GumQueueLockingUpdate: completed update seq %1!u!\ttype %2!u! context %3!u! result %4!u!\n",
  547. *Sequence,
  548. Type,
  549. Context,
  550. Status);
  551. return(Status);
  552. }
  553. #ifdef GUM_POST_SUPPORT
  554. John Vert (jvert) 11/18/1996
  555. POST is disabled for now since nobody uses it.
  556. N.B. The below code does not handle locker node failures
  557. error_status_t
  558. s_GumQueueLockingPost(
  559. IN handle_t IDL_handle,
  560. IN DWORD NodeId,
  561. IN DWORD Type,
  562. IN DWORD Context,
  563. OUT LPDWORD Sequence,
  564. IN DWORD BufferLength,
  565. IN UCHAR Buffer[],
  566. IN DWORD ActualBuffer
  567. )
  568. /*++
  569. Routine Description:
  570. Queues a post update.
  571. If the GUM lock can be immediately acquired, this routine
  572. behaves exactly like GumQueueLockingUpdate and returns
  573. ERROR_SUCCESS.
  574. If the GUM lock is held, this routine queues an asynchronous
  575. wait block onto the GUM queue and returns ERROR_IO_PENDING.
  576. When the wait block is removed from the GUM queue, the unlocking
  577. thread will call GumpDeliverPostUpdate on the specified node
  578. and supply the passed in context. The calling node can then
  579. deliver the update.
  580. Arguments:
  581. IDL_handle - Supplies the RPC binding context, not used.
  582. NodeId - Supplies the node id of the issuing node.
  583. Type - Supplies the GUM_UPDATE_TYPE of the update
  584. Context - Supplies the GUM update context
  585. Sequence - Returns the sequence that the GUM update must be issued with
  586. BufferLength - Supplies the length of the update.
  587. Buffer - Supplies the update data.
  588. ActualBuffer - Supplies the value of the pointer to the GUM data on the
  589. client side. This will be returned to the callback if this update
  590. is completed asynchronously.
  591. Return Value:
  592. ERROR_SUCCESS if successful
  593. Win32 error otherwise.
  594. --*/
  595. {
  596. DWORD Status;
  597. Status = GumpDoLockingPost(Type, NodeId, Sequence, Context, BufferLength,
  598. ActualBuffer, Buffer);
  599. if (Status != ERROR_SUCCESS) {
  600. if (Status != ERROR_IO_PENDING) {
  601. ClRtlLogPrint(LOG_UNUSUAL,
  602. "[GUM] s_GumQueueLockingPost: GumpDoLockingPost failed %1!u!\n",
  603. Status);
  604. } else {
  605. ClRtlLogPrint(LOG_NOISE,
  606. "[GUM] s_GumQueueLockingPost: GumpDoLockingPost pended update type %1!u! context %2!u!\n",
  607. Type,
  608. Context);
  609. }
  610. return(Status);
  611. }
  612. ClRtlLogPrint(LOG_NOISE,
  613. "[GUM] s_GumQueueLockingPost: dispatching seq %1!u!\ttype %2!u! context %3!u!\n",
  614. *Sequence,
  615. Type,
  616. Context);
  617. //SS: setting IsLocker to FALSE
  618. Status = GumpDispatchUpdate(Type,
  619. Context,
  620. FALSE,
  621. FALSE,
  622. BufferLength,
  623. Buffer);
  624. CL_ASSERT(Status == ERROR_SUCCESS); // posts must never fail
  625. ClRtlLogPrint(LOG_NOISE,
  626. "[GUM] s_GumQueueLockingPost: completed update seq %1!u!\ttype %2!u! context %3!u! result %4!u!\n",
  627. *Sequence,
  628. Type,
  629. Context,
  630. Status);
  631. MIDL_user_free(Buffer);
  632. return(Status);
  633. }
  634. #endif
  635. error_status_t
  636. s_GumAttemptLockingUpdate(
  637. IN handle_t IDL_handle,
  638. IN DWORD NodeId,
  639. IN DWORD Type,
  640. IN DWORD Context,
  641. IN DWORD Sequence,
  642. IN DWORD BufferLength,
  643. IN UCHAR Buffer[]
  644. )
  645. /*++
  646. Routine Description:
  647. Attempts a locking update. If the supplied sequence number
  648. matches and the update lock is not already held, the update
  649. will be issued and this routine will return with the lock held.
  650. Arguments:
  651. IDL_handle - Supplies the RPC binding context, not used.
  652. NodeId - Supplies the node id of the issuing node.
  653. Type - Supplies the GUM_UPDATE_TYPE of the update
  654. Context - Supplies the GUM update context
  655. Sequence - Supplies the sequence that the GUM update must be issued with
  656. BufferLength - Supplies the length of the update.
  657. Buffer - Supplies the update data.
  658. Return Value:
  659. ERROR_SUCCESS if successful
  660. Win32 error otherwise.
  661. --*/
  662. {
  663. DWORD Status;
  664. if (!GumpTryLockingUpdate(Type, NodeId, Sequence)) {
  665. MIDL_user_free(Buffer);
  666. return(ERROR_CLUSTER_DATABASE_SEQMISMATCH);
  667. }
  668. //SS: setting Islocker false
  669. Status = GumpDispatchUpdate(Type,
  670. Context,
  671. FALSE,
  672. FALSE,
  673. BufferLength,
  674. Buffer);
  675. if (Status != ERROR_SUCCESS) {
  676. //
  677. // The update has failed on this node, unlock here
  678. // Note we have to use Sequence-1 for the unlock because GumpDispatchUpdate
  679. // failed and did not increment the sequence number.
  680. //
  681. GumpDoUnlockingUpdate(Type, Sequence-1);
  682. }
  683. MIDL_user_free(Buffer);
  684. return(Status);
  685. }
  686. error_status_t
  687. s_GumUnlockUpdate(
  688. IN handle_t IDL_handle,
  689. IN DWORD Type,
  690. IN DWORD Sequence
  691. )
  692. /*++
  693. Routine Description:
  694. Unlocks a locked update.
  695. Arguments:
  696. IDL_handle - Supplies the RPC binding context, not used.
  697. Type - Supplies the GUM_UPDATE_TYPE of the update
  698. Sequence - Supplies the sequence that the GUM update was issued with
  699. Return Value:
  700. ERROR_SUCCESS if successful
  701. Win32 error code otherwise
  702. --*/
  703. {
  704. GumpDoUnlockingUpdate(Type, Sequence);
  705. return(ERROR_SUCCESS);
  706. }
  707. error_status_t
  708. s_GumJoinUpdateNode(
  709. IN handle_t IDL_handle,
  710. IN DWORD JoiningId,
  711. IN DWORD Type,
  712. IN DWORD Context,
  713. IN DWORD Sequence,
  714. IN DWORD BufferLength,
  715. IN UCHAR Buffer[]
  716. )
  717. /*++
  718. Routine Description:
  719. Server side routine for GumJoinUpdateNode. This is the side that
  720. receives the update, adds the node to the update list, and dispatches
  721. it to the appropriate handlers.
  722. Arguments:
  723. IDL_handle - RPC binding handle, not used
  724. JoiningId - Supplies the nodeid of the joining node.
  725. Type - Supplies the GUM_UPDATE_TYPE
  726. Context - Supplies a DWORD of context to be passed to the
  727. GUM update handlers
  728. Sequence - Supplies the GUM sequence number for the specified update type
  729. BufferLength - Supplies the length of the update data
  730. Buffer - Supplies a pointer to the update data.
  731. Return Value:
  732. ERROR_SUCCESS if the update completed successfully
  733. ERROR_INVALID_HANDLE if the GUM sequence number is invalid
  734. --*/
  735. {
  736. DWORD Status;
  737. PGUM_INFO GumInfo;
  738. GumInfo = &GumTable[Type];
  739. // sync with replay/updates
  740. EnterCriticalSection(&GumpSendUpdateLock);
  741. // [ahm] This is an aborted endjoin, we just resync our seq. with master.
  742. // This should be its own GumUpdateSequence RPC, but for now it ok to
  743. // to this.
  744. if (JoiningId == (DWORD) -1)
  745. {
  746. // we must be off by one at the most
  747. if (Sequence+1 != GumpSequence)
  748. {
  749. CL_ASSERT(Sequence == GumpSequence);
  750. GumpSequence = Sequence+1;
  751. ClRtlLogPrint(LOG_UNUSUAL,
  752. "[GUM] s_GumJoinUpdateNode: pretend we have seen Sequence %1!u!\n",
  753. Sequence);
  754. }
  755. Status = 0;
  756. goto done;
  757. }
  758. if (Sequence != GumpSequence) {
  759. ClRtlLogPrint(LOG_UNUSUAL,
  760. "[GUM] s_GumJoinUpdateNode: Sequence %1!u! does not match current %2!u! for Type %3!u!\n",
  761. Sequence,
  762. GumpSequence,
  763. Type);
  764. LeaveCriticalSection(&GumpSendUpdateLock);
  765. MIDL_user_free(Buffer);
  766. return(ERROR_CLUSTER_DATABASE_SEQMISMATCH);
  767. }
  768. ClRtlLogPrint(LOG_NOISE,
  769. "[GUM] s_GumJoinUpdateNode: dispatching seq %1!u!\ttype %2!u! context %3!u!\n",
  770. Sequence,
  771. Type,
  772. Context);
  773. CL_ASSERT(NmIsValidNodeId(JoiningId));
  774. CL_ASSERT(GumpRpcBindings[JoiningId] != NULL);
  775. CL_ASSERT(GumpReplayRpcBindings[JoiningId] != NULL);
  776. ClRtlLogPrint(LOG_UNUSUAL,
  777. "[GUM] s_GumJoinUpdateNode Adding node %1!d! to update list for GUM type %2!d!\n",
  778. JoiningId,
  779. Type);
  780. //SS: setting IsLocker to FALSE
  781. Status = GumpDispatchUpdate(Type,
  782. Context,
  783. FALSE,
  784. FALSE,
  785. BufferLength,
  786. Buffer);
  787. // [ahm]: We need to make sure the node is still up, otherwise ignore
  788. EnterCriticalSection(&GumpLock);
  789. if (MMIsNodeUp(JoiningId) == TRUE) {
  790. GumTable[Type].ActiveNode[JoiningId] = TRUE;
  791. }
  792. LeaveCriticalSection(&GumpLock);
  793. ClRtlLogPrint(LOG_NOISE,
  794. "[GUM] s_GumJoinUpdateNode: completed update seq %1!u!\ttype %2!u! context %3!u!\n",
  795. Sequence,
  796. Type,
  797. Context);
  798. done:
  799. if (GumpLastBuffer != NULL) {
  800. MIDL_user_free(GumpLastBuffer);
  801. }
  802. GumpLastBuffer = NULL;
  803. GumpLastContext = Context;
  804. GumpLastBufferLength = 0;
  805. GumpLastUpdateType = Type;
  806. GumpLastBufferValid = FALSE;
  807. LeaveCriticalSection(&GumpSendUpdateLock);
  808. MIDL_user_free(Buffer);
  809. return(Status);
  810. }
  811. error_status_t
  812. s_GumAttemptJoinUpdate(
  813. IN handle_t IDL_handle,
  814. IN DWORD JoiningId,
  815. IN DWORD Type,
  816. IN DWORD Context,
  817. IN DWORD Sequence,
  818. IN DWORD BufferLength,
  819. IN UCHAR Buffer[]
  820. )
  821. /*++
  822. Routine Description:
  823. Attempts a locking join update. If the supplied sequence number
  824. matches and the update lock is not already held, the join update
  825. will be issued, the joining node will be added to the update list,
  826. and this routine will return with the lock held.
  827. Arguments:
  828. IDL_handle - Supplies the RPC binding context, not used.
  829. JoiningId - Supplies the nodeid of the joining node.
  830. Type - Supplies the GUM_UPDATE_TYPE of the update
  831. Context - Supplies the GUM update context
  832. Sequence - Supplies the sequence that the GUM update must be issued with
  833. BufferLength - Supplies the length of the update.
  834. Buffer - Supplies the update data.
  835. Return Value:
  836. ERROR_SUCCESS if successful
  837. Win32 error otherwise.
  838. --*/
  839. {
  840. DWORD Status;
  841. PGUM_INFO GumInfo;
  842. GumInfo = &GumTable[Type];
  843. if (!GumpTryLockingUpdate(Type, JoiningId, Sequence)) {
  844. MIDL_user_free(Buffer);
  845. return(ERROR_CLUSTER_DATABASE_SEQMISMATCH);
  846. }
  847. // sync with replay/updates
  848. EnterCriticalSection(&GumpSendUpdateLock);
  849. //SS: set IsLocker to TRUE
  850. Status = GumpDispatchUpdate(Type,
  851. Context,
  852. TRUE,
  853. FALSE,
  854. BufferLength,
  855. Buffer);
  856. if (Status != ERROR_SUCCESS) {
  857. //
  858. // The update has failed on this node, unlock here
  859. // Note we have to use Sequence-1 for the unlock because
  860. // GumpDispatchUpdate failed and did not increment the
  861. // sequence number.
  862. //
  863. GumpDoUnlockingUpdate(Type, Sequence-1);
  864. } else {
  865. CL_ASSERT(NmIsValidNodeId(JoiningId));
  866. CL_ASSERT(GumpRpcBindings[JoiningId] != NULL);
  867. CL_ASSERT(GumpReplayRpcBindings[JoiningId] != NULL);
  868. ClRtlLogPrint(LOG_UNUSUAL,
  869. "[GUM] s_GumAttemptJoinUpdate Adding node %1!d! to update list for GUM type %2!d!\n",
  870. JoiningId,
  871. Type);
  872. // [ahm]: We need to make sure the node is still up, otherwise ignore
  873. EnterCriticalSection(&GumpLock);
  874. if (MMIsNodeUp(JoiningId) == TRUE) {
  875. GumTable[Type].ActiveNode[JoiningId] = TRUE;
  876. }
  877. LeaveCriticalSection(&GumpLock);
  878. if (GumpLastBuffer != NULL) {
  879. MIDL_user_free(GumpLastBuffer);
  880. }
  881. GumpLastBuffer = NULL;
  882. GumpLastContext = Context;
  883. GumpLastBufferLength = 0;
  884. GumpLastUpdateType = Type;
  885. GumpLastBufferValid = FALSE;
  886. }
  887. LeaveCriticalSection(&GumpSendUpdateLock);
  888. MIDL_user_free(Buffer);
  889. return(Status);
  890. }
  891. /****
  892. @func DWORD | s_GumCollectVoteFromNode| The is the server side
  893. routine for GumCollectVoteFromNode.
  894. @parm IN IDL_handle | RPC binding handle, not used.
  895. @parm IN GUM_UPDATE_TYPE | Type | The update type for which this
  896. vote is requested.
  897. @parn IN DWORD | dwContext | This specifies the context related to the
  898. Updatetype for which a vote is being seeked.
  899. @parm IN DWORD | dwInputBufLength | The length of the input buffer
  900. passed in via pInputBuffer.
  901. @parm IN PVOID | pInputBuffer | A pointer to the input buffer via
  902. which the input data for the vote is supplied.
  903. @parm IN DWORD | dwVoteLength | The length of the vote. This is
  904. also the size of the buffer to which pBuf points to.
  905. @parm OUT PUCHAR | pVoteBuf| A pointer to a buffer in which
  906. this node may cast its vote. The length of the vote must
  907. not exceed dwVoteLength.
  908. @rdesc Returns a result code. ERROR_SUCCESS on success.
  909. @comm A node collecting votes invokes this routine to collect a vote
  910. from the remote node. This routine simply invokes GumpDispatchVote().
  911. @xref <f GumpCollectVote> <f GumpDispatchVote>
  912. ****/
  913. DWORD
  914. WINAPI
  915. s_GumCollectVoteFromNode(
  916. IN handle_t IDL_handle,
  917. IN DWORD UpdateType,
  918. IN DWORD dwContext,
  919. IN DWORD dwInputBufLength,
  920. IN PUCHAR pInputBuf,
  921. IN DWORD dwVoteLength,
  922. OUT PUCHAR pVoteBuf
  923. )
  924. {
  925. DWORD dwStatus;
  926. ClRtlLogPrint(LOG_NOISE,
  927. "[GUM] s_GumCollectVote: collecting vote for type %1!u!\tcontext %2!u!\n",
  928. UpdateType,
  929. dwContext);
  930. dwStatus = GumpDispatchVote(UpdateType,
  931. dwContext,
  932. dwInputBufLength,
  933. pInputBuf,
  934. dwVoteLength,
  935. pVoteBuf);
  936. ClRtlLogPrint(LOG_NOISE,
  937. "[GUM] s_GumCollectVote: completed, VoteStatus=%1!u!\n",
  938. dwStatus);
  939. return(dwStatus);
  940. }
  941. #ifdef GUM_POST_SUPPORT
  942. John Vert (jvert) 11/18/1996
  943. POST is disabled for now since nobody uses it.
  944. error_status_t
  945. s_GumDeliverPostCallback(
  946. IN handle_t IDL_handle,
  947. IN DWORD FirstNode,
  948. IN DWORD Type,
  949. IN DWORD Context,
  950. IN DWORD Sequence,
  951. IN DWORD BufferLength,
  952. IN DWORD Buffer
  953. )
  954. /*++
  955. Routine Description:
  956. Callback function used to deliver a posted update that was
  957. queued.
  958. Arguments:
  959. IDL_handle - Supplies the RPC binding context, not used.
  960. FirstNode - Supplies the node ID where the posts should start.
  961. This is generally the LockerNode+1.
  962. Type - Supplies the GUM_UPDATE_TYPE of the update
  963. Context - Supplies the GUM update context
  964. Sequence - Supplies the sequence that the GUM update must be issued with
  965. BufferLength - Supplies the length of the update.
  966. Buffer - Supplies the update data.
  967. Return Value:
  968. ERROR_SUCCESS
  969. --*/
  970. {
  971. GumpDeliverPosts(FirstNode,
  972. Type,
  973. Sequence,
  974. Context,
  975. BufferLength,
  976. (PVOID)Buffer);
  977. return(ERROR_SUCCESS);
  978. }
  979. #endif