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.

1814 lines
50 KiB

  1. /*++
  2. Copyright (c) 2000-2001 Microsoft Corporation
  3. Module Name:
  4. initsync.c
  5. Abstract:
  6. Initial Sync Controller Command Server. The initial sync controller command server
  7. controls the sequencing of vvjoins for a new member of the replica set.
  8. This command server is active only during the time the replica set is in seeding state.
  9. During this time the cxtions are paused and unpaused by this command server to make
  10. sure that only 1 vvjoin is in process at any given time. The priority on the cxtion
  11. is used to decide the order of vvjoins.
  12. Following flags are used by this command server.
  13. CXTION_FLAGS_INIT_SYNC : Location = PCXTION->Flags
  14. ^^^^^^^^^^^^^^^^^^^^^^
  15. This flag is set on all inbound connections that are added to a replica set when
  16. it is in the seeding state. This flag is set when the connection is initialized
  17. in OutLogAddNewPartner() and it is reset when the cxtion completes vvjoin in
  18. InitSyncVvJoinDone. While this flag is set and the replica is in seeding state
  19. all decisions to join are made by the initsync command server. Once the cxtion
  20. completes vvjoin and this flag is cleared the cxtion is free to join at any time.
  21. This flag is persistent in the DB,
  22. CXTION_FLAGS_PAUSED : Location = PCXTION->Flags
  23. ^^^^^^^^^^^^^^^^^^^
  24. If a connection has this flag set then it is not allowed to join with its
  25. inbound partner. The command server clears this flag in order. All cxtions
  26. that have the CXTION_FLAGS_INIT_SYNC set start off as paused. They get unpaused
  27. when its their turn to vvjoin.
  28. CXTION_FLAGS_HUNG_INIT_SYNC : Location = PCXTION->Flags
  29. ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  30. This flag is set on a cxtion to indicate that there has been no progress on this
  31. connection for a specified time (timeout) since a NEED_JOIN was sent. If the current
  32. working connection gets in this state the command server may decide to unpause
  33. the next cxtion on list.
  34. CONFIG_FLAG_ONLINE : Location PREPLICA->CnfFlags
  35. ^^^^^^^^^^^^^^^^^^
  36. Presence of this flag on the replica indicates that this member has successfully
  37. completed one pass through the inbound connections and is ready to go online. Until
  38. a member is online it will not join with its outbound partners. For a sysvol replica
  39. set going online also means sysvolready is set to 1. A replica set may be in
  40. online state but it may still be seeding. This depends on the priorities set on
  41. the cxtions.
  42. CONFIG_FLAG_SEEDING : Location PREPLICA->CnfFlags
  43. ^^^^^^^^^^^^^^^^^^^
  44. We don't get here unless the replica set is in seeding state. A new replica
  45. starts up in seeding state unless it is the primary member of the replica set.
  46. ******************************* CXTION OPTIONS **********************************
  47. The options attribute on the "NTDS Connection" object is used to specify the
  48. priority for a given connection. Options is a 32 bit value. The highest bit is
  49. used to indicate if the schedule should be ignored while vvjoining. The next 3
  50. bits are used to spevify a priority from 0-7. The following two masks are used
  51. to get the values.
  52. #define FRSCONN_PRIORITY_MASK 0x70000000
  53. #define NTDSCONN_OPT_IGNORE_SCHEDULE_MASK 0x80000000
  54. The ignore scheduel bit is not checked while the connection is in INIT_SYNC state.
  55. The priorities are interpretted as shown in the table below.
  56. Priority : Behavior
  57. Class
  58. 0 : Volatile connections have this priority.
  59. Highest priority class,
  60. Try every cxtion in this class,
  61. skip to next class on communication errors.
  62. 1-2 : Do not proceed to next class until done with all connections
  63. of this class.
  64. 3-4 : Do not proceed to next class until done with at least one
  65. connection of this class.
  66. 5-7 : Try every cxtion in this class,
  67. Skip to next class on communication errors.
  68. 8 : FRSCONN_MAX_PRIORITY - A priority of '0' in the DS corresponds
  69. to this priority. We need to do this to maintain old
  70. behavior for connections that do not have a priority set.
  71. Do not proceed to next class until done with at least one
  72. connection from this class or any of the other classes.
  73. The command server forms a sorted list of the connections based on their priorities
  74. and then starts vvjoins on these connections one at a time. After every vvjoin
  75. is done it checks if the current class is satisfied based on the table above. If
  76. it is then cxtions from the next class are picked up and so on. When the last
  77. class is satisfied the member goes into Online state and is free to join with its
  78. outbound partners. Remaining connections will continue to vvjoin serially and when
  79. all are done the member goes out of seeding state.
  80. **********************************************************************************
  81. Author:
  82. Sudarshan Chitre - 27th April 2001
  83. Environment
  84. User mode winnt
  85. --*/
  86. #include <ntreppch.h>
  87. #pragma hdrstop
  88. #undef DEBSUB
  89. #undef DEBSUB
  90. #define DEBSUB "INITSYNC:"
  91. #include <frs.h>
  92. #include <tablefcn.h>
  93. #include <perrepsr.h>
  94. #include <ntdsapi.h>
  95. //
  96. // Struct for the Initial Sync Controller Command Server
  97. // Contains info about the queues and the threads
  98. //
  99. COMMAND_SERVER InitSyncCs;
  100. ULONG MaxInitSyncCsThreads;
  101. extern PGEN_TABLE ReplicasByGuid;
  102. //
  103. // Replica Command server functions called from here.
  104. //
  105. VOID
  106. RcsSubmitReplicaCxtionJoin(
  107. IN PREPLICA Replica,
  108. IN PCXTION Cxtion,
  109. IN BOOL Later
  110. );
  111. VOID
  112. RcsUpdateReplicaSetMember(
  113. IN PREPLICA Replica
  114. );
  115. VOID
  116. RcsJoinCxtion(
  117. IN PCOMMAND_PACKET Cmd
  118. );
  119. VOID
  120. RcsEmptyPreExistingDir(
  121. IN PREPLICA Replica
  122. );
  123. BOOL
  124. RcsSetSysvolReady(
  125. IN DWORD NewSysvolReady
  126. );
  127. VOID
  128. RcsReplicaSetRegistry(
  129. IN PREPLICA Replica
  130. );
  131. //
  132. // Send Command server functions called from here.
  133. //
  134. VOID
  135. SndCsSubmitCommPkt2(
  136. IN PREPLICA Replica,
  137. IN PCXTION Cxtion,
  138. IN PCHANGE_ORDER_ENTRY Coe,
  139. IN BOOL SetTimeout,
  140. IN PCOMM_PACKET CommPkt
  141. );
  142. PCOMM_PACKET
  143. CommBuildCommPkt(
  144. IN PREPLICA Replica,
  145. IN PCXTION Cxtion,
  146. IN ULONG Command,
  147. IN PGEN_TABLE VVector,
  148. IN PCOMMAND_PACKET Cmd,
  149. IN PCHANGE_ORDER_COMMAND Coc
  150. );
  151. BOOL
  152. InitSyncPriorityClassSemanticsA(
  153. IN PREPLICA Replica,
  154. IN DWORD PriorityClass
  155. )
  156. /*++
  157. Routine Description:
  158. This function determines if the current state of the cxtions satisfies
  159. Semantics 'A' for priority class 'PriorityClass'
  160. This class is satisfied if all cxtions from this class have completed
  161. the initial sync.
  162. Arguments:
  163. Replica - Replica in question.
  164. PriorityClass - Priority class to evaluate for.
  165. Return Value:
  166. TRUE if ok to move to next class, FALSE otherwise.
  167. --*/
  168. {
  169. #undef DEBSUB
  170. #define DEBSUB "InitSyncPriorityClassSemanticsA:"
  171. PCXTION Cxtion;
  172. PVOID Key;
  173. PGEN_ENTRY Entry;
  174. DWORD NumInClass = 0;
  175. DWORD NumComplete = 0;
  176. DWORD NumCommError = 0;
  177. DWORD NumNotComplete = 0;
  178. DPRINT1(5,":IS: InitSyncPriorityClassSemanticsA called with priority %d\n", PriorityClass);
  179. Key = NULL;
  180. GTabLockTable(Replica->InitSyncCxtionsMasterList);
  181. while (Entry = GTabNextEntryNoLock(Replica->InitSyncCxtionsMasterList, &Key)) {
  182. Cxtion = Entry->Data;
  183. if (Cxtion->Priority > PriorityClass) {
  184. //
  185. // We have done evaluating the class in question.
  186. //
  187. break;
  188. } else if (Cxtion->Priority < PriorityClass) {
  189. continue;
  190. }
  191. do {
  192. Cxtion = Entry->Data;
  193. DPRINT5(5, ":IS: Priority = %d, Penalty = %d, CommPkts = %d : %ws - %ws\n",
  194. Cxtion->Priority,Cxtion->Penalty, Cxtion->CommPkts, Cxtion->Name->Name,
  195. (CxtionFlagIs(Cxtion,CXTION_FLAGS_INIT_SYNC) ? L"Init sync pending" :
  196. L"Init sync done"));
  197. NumInClass++;
  198. if (!CxtionFlagIs(Cxtion,CXTION_FLAGS_INIT_SYNC)) {
  199. NumComplete++;
  200. } else if ((Cxtion->Penalty != 0) ||
  201. (CxtionFlagIs(Cxtion,CXTION_FLAGS_HUNG_INIT_SYNC))){
  202. //
  203. // Either there was some comm error trying to talk to this
  204. // partner or this partner has not sent us packets in a while.
  205. //
  206. NumCommError++;
  207. NumNotComplete++;
  208. } else {
  209. NumNotComplete++;
  210. }
  211. Entry = Entry->Dups;
  212. } while ( Entry != NULL );
  213. }
  214. GTabUnLockTable(Replica->InitSyncCxtionsMasterList);
  215. //
  216. // This class is satisfied if all cxtions from this class have completed
  217. // the initial sync.
  218. //
  219. if (NumInClass == NumComplete) {
  220. return TRUE;
  221. } else {
  222. return FALSE;
  223. }
  224. }
  225. BOOL
  226. InitSyncPriorityClassSemanticsB(
  227. IN PREPLICA Replica,
  228. IN DWORD PriorityClass
  229. )
  230. /*++
  231. Routine Description:
  232. This function determines if the current state of the cxtions satisfies
  233. Semantics 'B' for priority class 'PriorityClass'
  234. This class is satisfied if atleast one cxtion from this class has completed
  235. the initial sync..
  236. Arguments:
  237. Replica - Replica in question.
  238. PriorityClass - Priority class to evaluate for.
  239. Return Value:
  240. TRUE if ok to move to next class, FALSE otherwise.
  241. --*/
  242. {
  243. #undef DEBSUB
  244. #define DEBSUB "InitSyncPriorityClassSemanticsB:"
  245. PCXTION Cxtion;
  246. PVOID Key;
  247. PGEN_ENTRY Entry;
  248. DWORD NumInClass = 0;
  249. DWORD NumComplete = 0;
  250. DWORD NumCommError = 0;
  251. DWORD NumNotComplete = 0;
  252. DPRINT1(5,":IS: InitSyncPriorityClassSemanticsB called with priority %d\n", PriorityClass);
  253. Key = NULL;
  254. GTabLockTable(Replica->InitSyncCxtionsMasterList);
  255. while (Entry = GTabNextEntryNoLock(Replica->InitSyncCxtionsMasterList, &Key)) {
  256. Cxtion = Entry->Data;
  257. if (Cxtion->Priority > PriorityClass) {
  258. //
  259. // We have done evaluating the class in question.
  260. //
  261. break;
  262. } else if (Cxtion->Priority < PriorityClass) {
  263. continue;
  264. }
  265. do {
  266. Cxtion = Entry->Data;
  267. DPRINT5(5, " :IS: Priority = %d, Penalty = %d, CommPkts = %d : %ws - %ws\n",
  268. Cxtion->Priority,Cxtion->Penalty, Cxtion->CommPkts, Cxtion->Name->Name,
  269. (CxtionFlagIs(Cxtion,CXTION_FLAGS_INIT_SYNC) ? L"Init sync pending" :
  270. L"Init sync done"));
  271. NumInClass++;
  272. if (!CxtionFlagIs(Cxtion,CXTION_FLAGS_INIT_SYNC)) {
  273. NumComplete++;
  274. } else if ((Cxtion->Penalty != 0) ||
  275. (CxtionFlagIs(Cxtion,CXTION_FLAGS_HUNG_INIT_SYNC))){
  276. //
  277. // Either there was some comm error trying to talk to this
  278. // partner or this partner has not sent us packets in a while.
  279. //
  280. NumCommError++;
  281. NumNotComplete++;
  282. } else {
  283. NumNotComplete++;
  284. }
  285. Entry = Entry->Dups;
  286. } while ( Entry != NULL );
  287. }
  288. GTabUnLockTable(Replica->InitSyncCxtionsMasterList);
  289. //
  290. // This class is satisfied if atleast one cxtion from this class has completed
  291. // the initial sync..
  292. //
  293. if ((NumInClass == 0) || (NumComplete >= 1)) {
  294. return TRUE;
  295. } else {
  296. return FALSE;
  297. }
  298. }
  299. BOOL
  300. InitSyncPriorityClassSemanticsC(
  301. IN PREPLICA Replica,
  302. IN DWORD PriorityClass
  303. )
  304. /*++
  305. Routine Description:
  306. This function determines if the current state of the cxtions satisfies
  307. Semantics 'C' for priority class 'PriorityClass'
  308. This class is satisfied when all cxtions in this class have been attempted.
  309. Arguments:
  310. Replica - Replica in question.
  311. PriorityClass - Priority class to evaluate for.
  312. Return Value:
  313. TRUE if ok to move to next class, FALSE otherwise.
  314. --*/
  315. {
  316. #undef DEBSUB
  317. #define DEBSUB "InitSyncPriorityClassSemanticsC:"
  318. PCXTION Cxtion;
  319. PVOID Key;
  320. PGEN_ENTRY Entry;
  321. DWORD NumInClass = 0;
  322. DWORD NumComplete = 0;
  323. DWORD NumCommError = 0;
  324. DWORD NumNotComplete = 0;
  325. DPRINT1(5,":IS: InitSyncPriorityClassSemanticsC called with priority %d\n", PriorityClass);
  326. Key = NULL;
  327. GTabLockTable(Replica->InitSyncCxtionsMasterList);
  328. while (Entry = GTabNextEntryNoLock(Replica->InitSyncCxtionsMasterList, &Key)) {
  329. Cxtion = Entry->Data;
  330. if (Cxtion->Priority > PriorityClass) {
  331. //
  332. // We have done evaluating the class in question.
  333. //
  334. break;
  335. } else if (Cxtion->Priority < PriorityClass) {
  336. continue;
  337. }
  338. do {
  339. Cxtion = Entry->Data;
  340. DPRINT5(5, "Priority = %d, Penalty = %d, CommPkts = %d : %ws - %ws\n",
  341. Cxtion->Priority,Cxtion->Penalty, Cxtion->CommPkts, Cxtion->Name->Name,
  342. (CxtionFlagIs(Cxtion,CXTION_FLAGS_INIT_SYNC) ? L"Init sync pending" :
  343. L"Init sync done"));
  344. NumInClass++;
  345. if (!CxtionFlagIs(Cxtion,CXTION_FLAGS_INIT_SYNC)) {
  346. NumComplete++;
  347. } else if ((Cxtion->Penalty != 0) ||
  348. (CxtionFlagIs(Cxtion,CXTION_FLAGS_HUNG_INIT_SYNC))){
  349. //
  350. // Either there was some comm error trying to talk to this
  351. // partner or this partner has not sent us packets in a while.
  352. //
  353. NumCommError++;
  354. NumNotComplete++;
  355. } else {
  356. NumNotComplete++;
  357. }
  358. Entry = Entry->Dups;
  359. } while ( Entry != NULL );
  360. }
  361. GTabUnLockTable(Replica->InitSyncCxtionsMasterList);
  362. //
  363. // This class is satisfied when all cxtions in this class have been attempted.
  364. //
  365. if (NumInClass == (NumComplete + NumCommError)) {
  366. return TRUE;
  367. } else {
  368. return FALSE;
  369. }
  370. }
  371. BOOL
  372. InitSyncPriorityClassSemanticsD(
  373. IN PREPLICA Replica,
  374. IN DWORD PriorityClass
  375. )
  376. /*++
  377. Routine Description:
  378. This function determines if the current state of the cxtions satisfies
  379. Semantics 'D' for priority class 'PriorityClass'
  380. This class is satisfied if atleast one cxtion has completed
  381. the initial sync..
  382. Arguments:
  383. Replica - Replica in question.
  384. PriorityClass - Priority class to evaluate for.
  385. Return Value:
  386. TRUE if ok to move to next class, FALSE otherwise.
  387. --*/
  388. {
  389. #undef DEBSUB
  390. #define DEBSUB "InitSyncPriorityClassSemanticsD:"
  391. PCXTION Cxtion;
  392. PVOID Key;
  393. PGEN_ENTRY Entry;
  394. DWORD NumTotal = 0;
  395. DWORD NumComplete = 0;
  396. DPRINT1(5,":IS: InitSyncPriorityClassSemanticsB called with priority %d\n", PriorityClass);
  397. Key = NULL;
  398. GTabLockTable(Replica->InitSyncCxtionsMasterList);
  399. while (Entry = GTabNextEntryNoLock(Replica->InitSyncCxtionsMasterList, &Key)) {
  400. do {
  401. Cxtion = Entry->Data;
  402. DPRINT5(5, "Priority = %d, Penalty = %d, CommPkts = %d : %ws - %ws\n",
  403. Cxtion->Priority,Cxtion->Penalty, Cxtion->CommPkts, Cxtion->Name->Name,
  404. (CxtionFlagIs(Cxtion,CXTION_FLAGS_INIT_SYNC) ? L"Init sync pending" :
  405. L"Init sync done"));
  406. NumTotal++;
  407. if (!CxtionFlagIs(Cxtion,CXTION_FLAGS_INIT_SYNC)) {
  408. NumComplete++;
  409. }
  410. Entry = Entry->Dups;
  411. } while ( Entry != NULL );
  412. }
  413. GTabUnLockTable(Replica->InitSyncCxtionsMasterList);
  414. //
  415. // This class is satisfied if atleast one cxtion has completed
  416. // the initial sync..
  417. //
  418. if ((NumTotal == 0) || (NumComplete >= 1)) {
  419. return TRUE;
  420. } else {
  421. return FALSE;
  422. }
  423. }
  424. //
  425. // This is a static array of functions that determines what rules are applied to
  426. // what priority class. The rules are in form of functions above that return
  427. // true or false depending on whether the rule is satisfied or not.
  428. //
  429. BOOL (*InitSyncPriorityClassSemantic [])(PREPLICA,DWORD) = {
  430. InitSyncPriorityClassSemanticsC, // Rules for priority class 0
  431. InitSyncPriorityClassSemanticsA, // Rules for priority class 1
  432. InitSyncPriorityClassSemanticsA, // Rules for priority class 2
  433. InitSyncPriorityClassSemanticsB, // Rules for priority class 3
  434. InitSyncPriorityClassSemanticsB, // Rules for priority class 4
  435. InitSyncPriorityClassSemanticsC, // Rules for priority class 5
  436. InitSyncPriorityClassSemanticsC, // Rules for priority class 6
  437. InitSyncPriorityClassSemanticsC, // Rules for priority class 7
  438. InitSyncPriorityClassSemanticsD // Rules for priority class 8
  439. };
  440. BOOL
  441. InitSyncIsPriorityClassSatisfied(
  442. IN PREPLICA Replica,
  443. IN DWORD PriorityClass
  444. )
  445. /*++
  446. Routine Description:
  447. Use the priority class semantics to decide what is the max class we can work on,
  448. Arguments:
  449. Replica - Replica in question.
  450. PriorityClass - Priority class to evaluate for.
  451. Return Value:
  452. TRUE if ok to move to next class, FALSE otherwise.
  453. --*/
  454. {
  455. #undef DEBSUB
  456. #define DEBSUB "InitSyncGetMaxAllowedPriority:"
  457. BOOL (* PrioritySemanticFunction)(PREPLICA,DWORD);
  458. PrioritySemanticFunction = InitSyncPriorityClassSemantic[PriorityClass];
  459. return (*PrioritySemanticFunction)(Replica,PriorityClass);
  460. }
  461. DWORD
  462. InitSyncGetMaxAllowedPriority(
  463. IN PREPLICA Replica
  464. )
  465. /*++
  466. Routine Description:
  467. Use the priority class semantics to decide what is the max class we can work on,
  468. Arguments:
  469. Replica - Replica in question.
  470. Return Value:
  471. Maximum allowed priority class.
  472. --*/
  473. {
  474. #undef DEBSUB
  475. #define DEBSUB "InitSyncGetMaxAllowedPriority:"
  476. DWORD MaxAllowedPriorityClass = 0;
  477. //
  478. // Evaluate if each priority is satisfied or not.
  479. //
  480. while ((MaxAllowedPriorityClass <= FRSCONN_MAX_PRIORITY) &&
  481. InitSyncIsPriorityClassSatisfied(Replica,MaxAllowedPriorityClass)) {
  482. ++MaxAllowedPriorityClass;
  483. }
  484. DPRINT2(4,":IS: Replica %ws - MaxAllowedPriorityClass = %d\n",
  485. Replica->SetName->Name, MaxAllowedPriorityClass);
  486. return MaxAllowedPriorityClass;
  487. }
  488. DWORD
  489. InitSyncGetWorkingPriority(
  490. IN PREPLICA Replica
  491. )
  492. /*++
  493. Routine Description:
  494. Get the current priority class we are working on,
  495. Arguments:
  496. Replica.
  497. Return Value:
  498. None.
  499. --*/
  500. {
  501. #undef DEBSUB
  502. #define DEBSUB "InitSyncGetWorkingPriority:"
  503. DWORD WorkingPriority = 0;
  504. PVOID Key;
  505. PCXTION Cxtion;
  506. Key = NULL;
  507. while (Cxtion = GTabNextDatum(Replica->InitSyncCxtionsWorkingList, &Key)) {
  508. DPRINT5(5, ":IS: Priority = %d, Penalty = %d, CommPkts = %d : %ws - %ws\n",
  509. Cxtion->Priority,Cxtion->Penalty, Cxtion->CommPkts, Cxtion->Name->Name,
  510. (CxtionFlagIs(Cxtion,CXTION_FLAGS_INIT_SYNC) ? L"Init sync pending" :
  511. L"Init sync done"));
  512. if (WorkingPriority < Cxtion->Priority) {
  513. WorkingPriority = Cxtion->Priority;
  514. }
  515. }
  516. DPRINT2(4,":IS: Replica %ws - CurrentWorkingPriorityClass = %d\n",
  517. Replica->SetName->Name, WorkingPriority);
  518. return WorkingPriority;
  519. }
  520. VOID
  521. InitSyncCsSubmitTransfer(
  522. IN PCOMMAND_PACKET Cmd,
  523. IN USHORT Command
  524. )
  525. /*++
  526. Routine Description:
  527. Transfer a request to the initial sync controller command server.
  528. Arguments:
  529. Cmd - Command packet.
  530. Command - Command to convert to.
  531. Return Value:
  532. None.
  533. --*/
  534. {
  535. #undef DEBSUB
  536. #define DEBSUB "InitSyncCsSubmitTransfer:"
  537. //
  538. // Submit a request to allocate staging area
  539. //
  540. Cmd->TargetQueue = RsReplica(Cmd)->InitSyncQueue;
  541. Cmd->Command = Command;
  542. RsTimeout(Cmd) = 0;
  543. DPRINT3(4,":IS: Transfer 0x%08x (0x%08x) to %ws\n",
  544. Command, Cmd, RsReplica(Cmd)->SetName->Name);
  545. FrsSubmitCommandServer(&InitSyncCs, Cmd);
  546. }
  547. VOID
  548. InitSyncCmdPktCompletionRoutine(
  549. IN PCOMMAND_PACKET Cmd,
  550. IN PVOID Arg
  551. )
  552. /*++
  553. Routine Description:
  554. Completion routine for InitSync command packets. Free some specific fields
  555. and send the command on to the generic command packet completion routine
  556. for freeing.
  557. Arguments:
  558. Cmd - Command packet.
  559. Arg - Cmd->CompletionArg
  560. Return Value:
  561. None.
  562. --*/
  563. {
  564. #undef DEBSUB
  565. #define DEBSUB "InitSyncCmdPktCompletionRoutine:"
  566. DPRINT1(4, ":IS: InitSync completion 0x%08x\n", Cmd);
  567. FrsFreeGName(RsCxtion(Cmd));
  568. //
  569. // Send the packet on to the generic completion routine for freeing
  570. //
  571. FrsSetCompletionRoutine(Cmd, FrsFreeCommand, NULL);
  572. FrsCompleteCommand(Cmd, Cmd->ErrorStatus);
  573. }
  574. VOID
  575. InitSyncSubmitToInitSyncCs(
  576. IN PREPLICA Replica,
  577. IN USHORT Command
  578. )
  579. /*++
  580. Routine Description:
  581. Submit a command to a initial sync command server.
  582. Arguments:
  583. Replica - existing replica
  584. Command
  585. Return Value:
  586. None.
  587. --*/
  588. {
  589. #undef DEBSUB
  590. #define DEBSUB "InitSyncSubmitToInitSyncCs:"
  591. PCOMMAND_PACKET Cmd;
  592. //
  593. // Allocate a command packet
  594. //
  595. Cmd = FrsAllocCommand(Replica->InitSyncQueue, Command);
  596. FrsSetCompletionRoutine(Cmd, InitSyncCmdPktCompletionRoutine, NULL);
  597. //
  598. // Address of replica set.
  599. //
  600. RsReplica(Cmd) = Replica;
  601. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, InitSyncSubmitToInitSyncCs cmd");
  602. FrsSubmitCommandServer(&InitSyncCs, Cmd);
  603. }
  604. VOID
  605. InitSyncDelSubmitToInitSyncCs(
  606. IN PREPLICA Replica,
  607. IN PCXTION Cxtion,
  608. IN USHORT Command,
  609. IN DWORD TimeoutInMilliseconds
  610. )
  611. /*++
  612. Routine Description:
  613. Submit a new command to the delayed command server to be submitted to the
  614. initial sync controller command server after "TimeoutInMilliseconds" ms.
  615. Arguments:
  616. Replica - existing replica
  617. Cxtion - existing connection
  618. Command
  619. TimeoutInMilliseconds - This command will be submitted to the Init Sync
  620. Command server after these many ms.
  621. Return Value:
  622. None.
  623. --*/
  624. {
  625. #undef DEBSUB
  626. #define DEBSUB "InitSyncDelSubmitToInitSyncCs:"
  627. PCOMMAND_PACKET Cmd;
  628. //
  629. // Allocate a command packet
  630. //
  631. Cmd = FrsAllocCommand(Replica->InitSyncQueue, Command);
  632. FrsSetCompletionRoutine(Cmd, InitSyncCmdPktCompletionRoutine, NULL);
  633. //
  634. // Address of replica set.
  635. //
  636. RsReplica(Cmd) = Replica;
  637. Cmd->TargetQueue = Replica->InitSyncQueue;
  638. //
  639. // CommPkts are used to detect init sync hangs.
  640. //
  641. if (Cxtion != NULL) {
  642. RsCxtion(Cmd) = FrsDupGName(Cxtion->Name);
  643. RsCommPkts(Cmd) = Cxtion->CommPkts;
  644. }
  645. RsTimeout(Cmd) = TimeoutInMilliseconds;
  646. //
  647. // This command will come back to us in in a little bit.
  648. //
  649. DPRINT2(4,":IS: Submit Cmd (0x%08x), Command 0x%88x\n", Cmd, Cmd->Command);
  650. FrsDelCsSubmitSubmit(&InitSyncCs, Cmd, RsTimeout(Cmd));
  651. }
  652. BOOL
  653. InitSyncCsDelCsSubmit(
  654. IN PCOMMAND_PACKET Cmd,
  655. IN USHORT Command,
  656. IN DWORD TimeoutInMilliseconds
  657. )
  658. /*++
  659. Routine Description:
  660. Submit this command to the delayed command server to be submitted to the
  661. initial sync controller command server after "TimeoutInMilliseconds" ms.
  662. Arguments:
  663. Cmd
  664. Command
  665. TimeoutInMilliseconds - This command will be submitted to the Init Sync
  666. Command server after these many ms.
  667. Return Value:
  668. None.
  669. --*/
  670. {
  671. #undef DEBSUB
  672. #define DEBSUB "InitSyncCsDelCsSubmit:"
  673. //
  674. // Extend the retry time (but not too long)
  675. //
  676. Cmd->Command = Command;
  677. RsTimeout(Cmd) = TimeoutInMilliseconds;
  678. //
  679. // This command will come back to us in in a little bit.
  680. //
  681. DPRINT2(4,":IS: Submit Cmd (0x%08x), Command 0x%08x\n", Cmd, Cmd->Command);
  682. FrsDelCsSubmitSubmit(&InitSyncCs, Cmd, RsTimeout(Cmd));
  683. return (TRUE);
  684. }
  685. VOID
  686. InitSyncBuildMasterList(
  687. IN PREPLICA Replica
  688. )
  689. /*++
  690. Routine Description:
  691. Build the master list from the Replica->Cxtions table.
  692. Arguments:
  693. Replica
  694. Return Value:
  695. None.
  696. --*/
  697. {
  698. #undef DEBSUB
  699. #define DEBSUB "InitSyncBuildMasterList:"
  700. PCXTION Cxtion = NULL;
  701. PVOID Key;
  702. FRS_ASSERT(Replica->InitSyncCxtionsMasterList != NULL);
  703. //
  704. // If we already have a master list then empty it,
  705. //
  706. GTabEmptyTable(Replica->InitSyncCxtionsMasterList,NULL);
  707. LOCK_CXTION_TABLE(Replica);
  708. //
  709. // Take all inbound connections and put them in the master list.
  710. //
  711. Key = NULL;
  712. while (Cxtion = GTabNextDatum(Replica->Cxtions, &Key)) {
  713. //
  714. // Skip the journal conneciton.
  715. //
  716. if (Cxtion->JrnlCxtion) {
  717. continue;
  718. }
  719. //
  720. // We are interested in inbound connections only.
  721. //
  722. if (!Cxtion->Inbound) {
  723. continue;
  724. }
  725. //
  726. // We clear the paused bit on connections that have completed the initial sync.
  727. // These connections are free to join anytime. We still need them in the master
  728. // list as they are needed to verify if the priority class is satisfied.
  729. //
  730. if (!CxtionFlagIs(Cxtion, CXTION_FLAGS_INIT_SYNC)) {
  731. if (CxtionFlagIs(Cxtion,CXTION_FLAGS_PAUSED)) {
  732. ClearCxtionFlag(Cxtion, CXTION_FLAGS_PAUSED); // In case it is still set.
  733. CXTION_STATE_TRACE(3, Cxtion, Replica, 0, "F, INITSYNC Unpaused");
  734. }
  735. } else {
  736. //
  737. // Initially all connections in INIT_SYNC state are paused.
  738. //
  739. SetCxtionFlag(Cxtion, CXTION_FLAGS_PAUSED);
  740. CXTION_STATE_TRACE(3, Cxtion, Replica, 0, "F, INITSYNC Paused");
  741. }
  742. GTabInsertEntry(Replica->InitSyncCxtionsMasterList, Cxtion, &Cxtion->Priority, NULL);
  743. }
  744. UNLOCK_CXTION_TABLE(Replica);
  745. }
  746. VOID
  747. InitSyncBuildWorkingList(
  748. IN PREPLICA Replica,
  749. IN DWORD PriorityClass,
  750. IN BOOL ResetList
  751. )
  752. /*++
  753. Routine Description:
  754. Build the working list from the Replica->InitSyncCxtionsMasterList table.
  755. Arguments:
  756. Replica
  757. PriorityClass - Max Priority Class to pull from master list.
  758. ResetList - Rebuild the working list.
  759. Return Value:
  760. None.
  761. --*/
  762. {
  763. #undef DEBSUB
  764. #define DEBSUB "InitSyncBuildWorkingList:"
  765. PCXTION Cxtion = NULL;
  766. PVOID Key;
  767. PGEN_ENTRY Entry;
  768. LOCK_CXTION_TABLE(Replica);
  769. //
  770. // If we already have a working list then empty it and create a new one,
  771. //
  772. if ((Replica->InitSyncCxtionsWorkingList != NULL) && ResetList) {
  773. GTabEmptyTable(Replica->InitSyncCxtionsWorkingList,NULL);
  774. }
  775. Key = NULL;
  776. GTabLockTable(Replica->InitSyncCxtionsMasterList);
  777. //
  778. // Take all connections from the master list that are <= PriorityClass and
  779. // put them on the current working list.
  780. //
  781. while (Entry = GTabNextEntryNoLock(Replica->InitSyncCxtionsMasterList, &Key)) {
  782. Cxtion = Entry->Data;
  783. if (Cxtion->Priority <= PriorityClass) {
  784. do {
  785. Cxtion = Entry->Data;
  786. GTabInsertEntry(Replica->InitSyncCxtionsWorkingList, Cxtion, Cxtion->Name->Guid, NULL);
  787. Entry = Entry->Dups;
  788. } while ( Entry != NULL );
  789. }
  790. }
  791. GTabUnLockTable(Replica->InitSyncCxtionsMasterList);
  792. DPRINT1(4, ":IS: +++ Printing InitSyncCxtionsMasterList for Replica %ws\n", Replica->SetName->Name);
  793. Key = NULL;
  794. GTabLockTable(Replica->InitSyncCxtionsMasterList);
  795. while (Entry = GTabNextEntryNoLock(Replica->InitSyncCxtionsMasterList, &Key)) {
  796. do {
  797. Cxtion = Entry->Data;
  798. DPRINT5(4, ":IS: Priority = %d, Penalty = %d, CommPkts = %d : %ws - %ws\n",
  799. Cxtion->Priority,Cxtion->Penalty, Cxtion->CommPkts, Cxtion->Name->Name,
  800. (CxtionFlagIs(Cxtion,CXTION_FLAGS_INIT_SYNC) ? L"Init sync pending" :
  801. L"Init sync done"));
  802. Entry = Entry->Dups;
  803. } while ( Entry != NULL );
  804. }
  805. GTabUnLockTable(Replica->InitSyncCxtionsMasterList);
  806. DPRINT1(4, ":IS: +++ Printing InitSyncCxtionsWorkingList for Replica %ws\n", Replica->SetName->Name);
  807. Key = NULL;
  808. while (Cxtion = GTabNextDatum(Replica->InitSyncCxtionsWorkingList, &Key)) {
  809. DPRINT5(4, ":IS: Priority = %d, Penalty = %d, CommPkts = %d : %ws - %ws\n",
  810. Cxtion->Priority,Cxtion->Penalty, Cxtion->CommPkts, Cxtion->Name->Name,
  811. (CxtionFlagIs(Cxtion,CXTION_FLAGS_INIT_SYNC) ? L"Init sync pending" :
  812. L"Init sync done"));
  813. }
  814. UNLOCK_CXTION_TABLE(Replica);
  815. }
  816. VOID
  817. InitSyncStartSync(
  818. IN PCOMMAND_PACKET Cmd
  819. )
  820. /*++
  821. Routine Description:
  822. Start the initial sync on this replica.
  823. Arguments:
  824. Cmd.
  825. Return Value:
  826. None.
  827. --*/
  828. {
  829. #undef DEBSUB
  830. #define DEBSUB "InitSyncStartSync:"
  831. PREPLICA Replica;
  832. PCXTION Cxtion;
  833. PVOID Key;
  834. DWORD CxtionPriority;
  835. PGEN_ENTRY Entry;
  836. DWORD MaxAllowedPriority;
  837. Replica = RsReplica(Cmd);
  838. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, InitSyncStartSync entry");
  839. FRS_PRINT_TYPE(4, Replica);
  840. //
  841. // The replica has to be in SEEDING state to get this command.
  842. //
  843. FRS_ASSERT(BooleanFlagOn(Replica->CnfFlags, CONFIG_FLAG_SEEDING));
  844. //
  845. // If we have already started a initial sync on this replica then
  846. // nothing to do here.
  847. //
  848. if (Replica->InitSyncCxtionsMasterList != NULL) {
  849. return;
  850. }
  851. Replica->InitSyncCxtionsMasterList = GTabAllocNumberTable();
  852. Replica->InitSyncCxtionsWorkingList = GTabAllocTable();
  853. InitSyncBuildMasterList(Replica);
  854. MaxAllowedPriority = InitSyncGetMaxAllowedPriority(Replica);
  855. InitSyncBuildWorkingList(Replica,MaxAllowedPriority,TRUE);
  856. InitSyncCsSubmitTransfer(Cmd, CMD_INITSYNC_JOIN_NEXT);
  857. InitSyncSubmitToInitSyncCs(Replica,CMD_INITSYNC_KEEP_ALIVE);
  858. return;
  859. }
  860. VOID
  861. InitSyncKeepAlive(
  862. IN PCOMMAND_PACKET Cmd
  863. )
  864. /*++
  865. Routine Description:
  866. This command keeps coming back to us until all cxtions have completed the.
  867. initial sync. It is used to detect hangs.
  868. Arguments:
  869. Cmd.
  870. Return Value:
  871. None.
  872. --*/
  873. {
  874. #undef DEBSUB
  875. #define DEBSUB "InitSyncKeepAlive:"
  876. PREPLICA Replica;
  877. PVOID Key;
  878. PCXTION Cxtion;
  879. Replica = RsReplica(Cmd);
  880. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, InitSyncKeepAlive entry");
  881. //
  882. // Stop calling keepalive once we are out of seeding state.
  883. //
  884. if (!BooleanFlagOn(Replica->CnfFlags,CONFIG_FLAG_SEEDING)) {
  885. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  886. return;
  887. }
  888. //
  889. // Do not call JOIN_NEXT as long as there is one cxtion that is not paused and
  890. // not hung,
  891. //
  892. Key = NULL;
  893. while (Cxtion = GTabNextDatum(Replica->InitSyncCxtionsWorkingList, &Key)) {
  894. if (!CxtionFlagIs(Cxtion,CXTION_FLAGS_PAUSED) &&
  895. CxtionFlagIs(Cxtion,CXTION_FLAGS_INIT_SYNC) &&
  896. !CxtionFlagIs(Cxtion,CXTION_FLAGS_HUNG_INIT_SYNC)) {
  897. DPRINT5(5, ":IS: Working on - Priority = %d, Penalty = %d, CommPkts = %d : %ws - %ws\n",
  898. Cxtion->Priority,Cxtion->Penalty, Cxtion->CommPkts, Cxtion->Name->Name,
  899. (CxtionFlagIs(Cxtion,CXTION_FLAGS_INIT_SYNC) ? L"Init sync pending" :
  900. L"Init sync done"));
  901. goto RETURN;
  902. }
  903. }
  904. InitSyncSubmitToInitSyncCs(Replica,CMD_INITSYNC_JOIN_NEXT);
  905. RETURN:
  906. InitSyncCsDelCsSubmit(Cmd, CMD_INITSYNC_KEEP_ALIVE, 240 * 1000);
  907. return;
  908. }
  909. VOID
  910. InitSyncCompletedOnePass(
  911. IN PREPLICA Replica
  912. )
  913. /*++
  914. Routine Description:
  915. Initial sync completed one pass for this replica. Take the appropriate action.
  916. Share out the sysvols here.
  917. Arguments:
  918. Cmd.
  919. Return Value:
  920. None.
  921. --*/
  922. {
  923. #undef DEBSUB
  924. #define DEBSUB "InitSyncCompletedOnePass:"
  925. DPRINT1(4,":IS: Replica %ws has successfully completed one pass of Seeding.\n",Replica->SetName->Name);
  926. SetFlag(Replica->CnfFlags, CONFIG_FLAG_ONLINE);
  927. Replica->NeedsUpdate = TRUE;
  928. RcsUpdateReplicaSetMember(Replica);
  929. //
  930. // Set sysvol ready to 1 if this is the sysvol replica set
  931. // and we haven't shared out the sysvol yet.
  932. //
  933. if (FRS_RSTYPE_IS_SYSVOL(Replica->ReplicaSetType) &&
  934. !Replica->IsSysvolReady) {
  935. RcsReplicaSetRegistry(Replica);
  936. Replica->IsSysvolReady = RcsSetSysvolReady(1);
  937. }
  938. }
  939. VOID
  940. InitSyncCompleted(
  941. IN PREPLICA Replica
  942. )
  943. /*++
  944. Routine Description:
  945. Initial sync completed for this replica. Take the appropriate action.
  946. Get out of seeding state.
  947. Arguments:
  948. Cmd.
  949. Return Value:
  950. None.
  951. --*/
  952. {
  953. #undef DEBSUB
  954. #define DEBSUB "InitSyncCompleted:"
  955. ClearFlag(Replica->CnfFlags, CONFIG_FLAG_SEEDING);
  956. Replica->NeedsUpdate = TRUE;
  957. RcsUpdateReplicaSetMember(Replica);
  958. //
  959. // Half-hearted attempt to delete the empty directories from
  960. // the preexisting directory
  961. //
  962. RcsEmptyPreExistingDir(Replica);
  963. //
  964. // Cleanup the state associated with the InitSync state.
  965. //
  966. DPRINT1(4,":IS: Replica %ws has successfully completed Seeding.\n",Replica->SetName->Name);
  967. Replica->InitSyncCxtionsMasterList = GTabFreeTable(Replica->InitSyncCxtionsMasterList,NULL);
  968. Replica->InitSyncCxtionsWorkingList = GTabFreeTable(Replica->InitSyncCxtionsWorkingList,NULL);
  969. }
  970. VOID
  971. InitSyncJoinNext(
  972. IN PCOMMAND_PACKET Cmd
  973. )
  974. /*++
  975. Routine Description:
  976. Join the next in line.
  977. Arguments:
  978. Cmd.
  979. Return Value:
  980. None.
  981. --*/
  982. {
  983. #undef DEBSUB
  984. #define DEBSUB "InitSyncJoinNext:"
  985. PREPLICA Replica;
  986. PCXTION Cxtion;
  987. // PCXTION NewCxtion;
  988. PVOID Key;
  989. DWORD CxtionPriority;
  990. PGEN_ENTRY Entry;
  991. DWORD NumUnPaused;
  992. DWORD MasterMaxAllowedPriority;
  993. DWORD CurrentWorkingPriority;
  994. Replica = RsReplica(Cmd);
  995. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, InitSyncJoinNext entry");
  996. FRS_PRINT_TYPE(4, Replica);
  997. //
  998. // If the replica has already seeded then we do not have anything to process.
  999. //
  1000. if (!BooleanFlagOn(Replica->CnfFlags, CONFIG_FLAG_SEEDING)) {
  1001. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  1002. return;
  1003. }
  1004. //
  1005. // Get the maximum allowed priority by scanning the master list.
  1006. // We need to do this because new connections might have been added to
  1007. // the master list that have higher priority than the current working priority
  1008. // of the working list.
  1009. //
  1010. MasterMaxAllowedPriority = InitSyncGetMaxAllowedPriority(Replica);
  1011. CurrentWorkingPriority = InitSyncGetWorkingPriority(Replica);
  1012. if (MasterMaxAllowedPriority < CurrentWorkingPriority) {
  1013. //
  1014. // One or more new connections with lower priority might have been added.
  1015. // reset the working list to reflect that.
  1016. //
  1017. InitSyncBuildWorkingList(Replica,MasterMaxAllowedPriority,TRUE);
  1018. } else if (MasterMaxAllowedPriority > CurrentWorkingPriority) {
  1019. //
  1020. // Connections from next priority class can be added to the working list.
  1021. //
  1022. InitSyncBuildWorkingList(Replica,MasterMaxAllowedPriority,FALSE);
  1023. }
  1024. if (MasterMaxAllowedPriority > FRSCONN_MAX_PRIORITY) {
  1025. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, InitSyncJoinNext completed one pass");
  1026. InitSyncCompletedOnePass(Replica);
  1027. }
  1028. LOCK_CXTION_TABLE(Replica);
  1029. Key = NULL;
  1030. NumUnPaused = 0;
  1031. while (Cxtion = GTabNextDatum(Replica->InitSyncCxtionsWorkingList, &Key)) {
  1032. //
  1033. // If the cxtion has already completed the initial sync then skip it.
  1034. //
  1035. if (!CxtionFlagIs(Cxtion,CXTION_FLAGS_INIT_SYNC)) {
  1036. continue;
  1037. }
  1038. ++NumUnPaused;
  1039. if (CxtionFlagIs(Cxtion,CXTION_FLAGS_PAUSED)) {
  1040. ClearCxtionFlag(Cxtion, CXTION_FLAGS_PAUSED);
  1041. CXTION_STATE_TRACE(3, Cxtion, Replica, 0, "F, INITSYNC Unpaused");
  1042. }
  1043. if (CxtionFlagIs(Cxtion,CXTION_FLAGS_HUNG_INIT_SYNC)) {
  1044. ClearCxtionFlag(Cxtion, CXTION_FLAGS_HUNG_INIT_SYNC);
  1045. CXTION_STATE_TRACE(3, Cxtion, Replica, 0, "F, INITSYNC clear hung state");
  1046. }
  1047. CXTION_STATE_TRACE(3, Cxtion, Replica, 0, "F, INITSYNC sending NEED_JOIN");
  1048. //
  1049. // Submit a cmd with the replica command server to send need_join over this
  1050. // cxtion,
  1051. //
  1052. RcsSubmitReplicaCxtionJoin(Replica, Cxtion, FALSE);
  1053. //
  1054. // Submit a cmd with the init sync command server to track the progress of this
  1055. // cxtion. This cmd will look for hung init sync.
  1056. //
  1057. InitSyncDelSubmitToInitSyncCs(Replica,Cxtion,CMD_INITSYNC_CHECK_PROGRESS,300*1000);
  1058. }
  1059. UNLOCK_CXTION_TABLE(Replica);
  1060. //
  1061. // Done synching all connections. Reset seeding state.
  1062. //
  1063. if (NumUnPaused == 0) {
  1064. InitSyncCompleted(Replica);
  1065. RcsSubmitTransferToRcs(Cmd, CMD_VVJOIN_DONE_UNJOIN);
  1066. } else {
  1067. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  1068. }
  1069. }
  1070. VOID
  1071. InitSyncCheckProgress(
  1072. IN PCOMMAND_PACKET Cmd
  1073. )
  1074. /*++
  1075. Routine Description:
  1076. Check the progress of this connectio. Put it in hung state if no packets have
  1077. been received on this connection for some time.
  1078. Arguments:
  1079. Cmd.
  1080. Return Value:
  1081. None.
  1082. --*/
  1083. {
  1084. #undef DEBSUB
  1085. #define DEBSUB "InitSyncCheckProgress:"
  1086. PREPLICA Replica;
  1087. PCXTION InCxtion;
  1088. Replica = RsReplica(Cmd);
  1089. //
  1090. // Retire this command if we are out of seeding state.
  1091. //
  1092. if (!BooleanFlagOn(Replica->CnfFlags,CONFIG_FLAG_SEEDING)) {
  1093. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  1094. return;
  1095. }
  1096. LOCK_CXTION_TABLE(Replica);
  1097. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, InitSyncCheckProgress entry");
  1098. //
  1099. // Find and check the cxtion
  1100. //
  1101. InCxtion = GTabLookupNoLock(Replica->Cxtions, RsCxtion(Cmd)->Guid, NULL);
  1102. if (InCxtion != NULL) {
  1103. DPRINT5(5,":IS: Priority = %d, Penalty = %d, CommPkts = %d : %ws - %ws\n",
  1104. InCxtion->Priority,InCxtion->Penalty, InCxtion->CommPkts, InCxtion->Name->Name,
  1105. (CxtionFlagIs(InCxtion,CXTION_FLAGS_INIT_SYNC) ? L"Init sync pending" :
  1106. L"Init sync done"));
  1107. }
  1108. //
  1109. // Retire this command if the cxtion has been paused or if the connection is
  1110. // out of seeding state.
  1111. //
  1112. if (!InCxtion || CxtionFlagIs(InCxtion,CXTION_FLAGS_PAUSED) ||
  1113. !CxtionFlagIs(InCxtion,CXTION_FLAGS_INIT_SYNC)) {
  1114. if (CxtionFlagIs(InCxtion,CXTION_FLAGS_HUNG_INIT_SYNC)) {
  1115. ClearCxtionFlag(InCxtion,CXTION_FLAGS_HUNG_INIT_SYNC);
  1116. CXTION_STATE_TRACE(3, InCxtion, Replica, 0, "F, INITSYNC clear hung state");
  1117. }
  1118. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  1119. goto RETURN;
  1120. }
  1121. //
  1122. // Do not declare hung if the schedule is off and we are asked to follow schedule.
  1123. //
  1124. if (!NTDSCONN_IGNORE_SCHEDULE(InCxtion->Options) &&
  1125. CxtionFlagIs(InCxtion,CXTION_FLAGS_SCHEDULE_OFF)){
  1126. InitSyncCsDelCsSubmit(Cmd,CMD_INITSYNC_CHECK_PROGRESS,300*1000);
  1127. goto RETURN;
  1128. }
  1129. if (RsCommPkts(Cmd) != InCxtion->CommPkts) {
  1130. RsCommPkts(Cmd) = InCxtion->CommPkts;
  1131. InitSyncCsDelCsSubmit(Cmd,CMD_INITSYNC_CHECK_PROGRESS,300*1000);
  1132. } else {
  1133. SetCxtionFlag(InCxtion,CXTION_FLAGS_HUNG_INIT_SYNC);
  1134. CXTION_STATE_TRACE(3, InCxtion, Replica, 0, "F, INITSYNC Hung");
  1135. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  1136. }
  1137. RETURN:
  1138. UNLOCK_CXTION_TABLE(Replica);
  1139. return;
  1140. }
  1141. VOID
  1142. InitSyncStartJoin(
  1143. IN PCOMMAND_PACKET Cmd
  1144. )
  1145. /*++
  1146. Routine Description:
  1147. We have received start join from a inbound partner. We send need joins to all the
  1148. connections in the current class. When we get start_join from one of the partners
  1149. we pick that one to vvjoin with first and put the remaining connections in the
  1150. paused state.
  1151. Arguments:
  1152. Cmd.
  1153. Return Value:
  1154. None.
  1155. --*/
  1156. {
  1157. #undef DEBSUB
  1158. #define DEBSUB "InitSyncStartJoin:"
  1159. PREPLICA Replica;
  1160. PCXTION InCxtion;
  1161. PCXTION Cxtion;
  1162. PCXTION NewCxtion;
  1163. PVOID Key;
  1164. Replica = RsReplica(Cmd);
  1165. LOCK_CXTION_TABLE(Replica);
  1166. REPLICA_STATE_TRACE(3, Cmd, Replica, 0, "F, InitSyncStartJoin entry");
  1167. FRS_PRINT_TYPE(4, Replica);
  1168. //
  1169. // Find and check the cxtion
  1170. //
  1171. InCxtion = GTabLookupNoLock(Replica->Cxtions, RsCxtion(Cmd)->Guid, NULL);
  1172. if (!InCxtion) {
  1173. return;
  1174. }
  1175. //
  1176. // Ignore the start join if this connection is paused.
  1177. //
  1178. if (CxtionFlagIs(InCxtion,CXTION_FLAGS_PAUSED)) {
  1179. CXTION_STATE_TRACE(3, InCxtion, Replica, 0, "F, Paused - ignore start join");
  1180. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  1181. UNLOCK_CXTION_TABLE(Replica);
  1182. } else {
  1183. //
  1184. // If we were waiting for our partner to respond or think we
  1185. // have already joined then either start the join process or
  1186. // resend our join info.
  1187. //
  1188. if (CxtionStateIs(InCxtion, CxtionStateUnjoined) ||
  1189. CxtionStateIs(InCxtion, CxtionStateJoined)) {
  1190. if (CxtionStateIs(InCxtion, CxtionStateUnjoined)) {
  1191. SetCxtionState(InCxtion, CxtionStateStart);
  1192. }
  1193. //
  1194. // Start the join process or resend the join info
  1195. //
  1196. // This is the first inbound partner that responded to the
  1197. // NEED_JOIN. Start vvjoin with this inbound partner and
  1198. // pause all other cxtions in the working list that are still in
  1199. // INIT_SYNC state.
  1200. //
  1201. Key = NULL;
  1202. while (Cxtion = GTabNextDatum(Replica->InitSyncCxtionsWorkingList, &Key)) {
  1203. DPRINT2(4, "P - %d : %ws\n", Cxtion->Priority, Cxtion->Name->Name);
  1204. FRS_PRINT_TYPE(4, Cxtion);
  1205. NewCxtion = GTabLookup(Replica->Cxtions,Cxtion->Name->Guid,NULL);
  1206. if (NewCxtion != NULL) {
  1207. if (!GUIDS_EQUAL(NewCxtion->Name->Guid,InCxtion->Name->Guid) &&
  1208. CxtionFlagIs(NewCxtion,CXTION_FLAGS_INIT_SYNC)) {
  1209. SetCxtionFlag(NewCxtion,CXTION_FLAGS_PAUSED);
  1210. CXTION_STATE_TRACE(3, NewCxtion, Replica, 0, "F, INITSYNC Paused");
  1211. }
  1212. }
  1213. }
  1214. //
  1215. // Clear the CXTION_FLAGS_HUNG_INIT_SYNC flag if it was set.
  1216. //
  1217. if (CxtionFlagIs(InCxtion,CXTION_FLAGS_HUNG_INIT_SYNC)) {
  1218. ClearCxtionFlag(InCxtion, CXTION_FLAGS_HUNG_INIT_SYNC);
  1219. CXTION_STATE_TRACE(3, InCxtion, Replica, 0, "F, INITSYNC clear hung state");
  1220. }
  1221. UNLOCK_CXTION_TABLE(Replica);
  1222. CXTION_STATE_TRACE(3, InCxtion, Replica, 0, "F, RcsJoinCxtion call");
  1223. RcsJoinCxtion(Cmd);
  1224. } else {
  1225. UNLOCK_CXTION_TABLE(Replica);
  1226. CXTION_STATE_TRACE(3, InCxtion, Replica, 0, "F, Cannot start join");
  1227. FrsCompleteCommand(Cmd, ERROR_SUCCESS);
  1228. }
  1229. }
  1230. }
  1231. VOID
  1232. InitSyncVvJoinDone(
  1233. IN PCOMMAND_PACKET Cmd
  1234. )
  1235. /*++
  1236. Routine Description:
  1237. vvjoin is done join next one.
  1238. Arguments:
  1239. Cmd.
  1240. Return Value:
  1241. None.
  1242. --*/
  1243. {
  1244. #undef DEBSUB
  1245. #define DEBSUB "InitSyncVvJoinDone:"
  1246. PREPLICA Replica;
  1247. PCXTION InCxtion;
  1248. PCOMM_PACKET CPkt;
  1249. Replica = RsReplica(Cmd);
  1250. LOCK_CXTION_TABLE(Replica);
  1251. //
  1252. // Find and check the cxtion
  1253. //
  1254. InCxtion = GTabLookupNoLock(Replica->Cxtions, RsCxtion(Cmd)->Guid, NULL);
  1255. if (!InCxtion) {
  1256. return;
  1257. }
  1258. CXTION_STATE_TRACE(3, InCxtion, Replica, 0, "F, INITSYNC complete");
  1259. //
  1260. // This connection has completed initial sync.
  1261. // It is OK to join this connection at will now.
  1262. //
  1263. if (CxtionFlagIs(InCxtion,CXTION_FLAGS_PAUSED)) {
  1264. ClearCxtionFlag(InCxtion, CXTION_FLAGS_PAUSED);
  1265. CXTION_STATE_TRACE(3, InCxtion, Replica, 0, "F, INITSYNC Unpaused");
  1266. }
  1267. ClearCxtionFlag(InCxtion, CXTION_FLAGS_INIT_SYNC);
  1268. //
  1269. // If this is volatile connection unjoin our upstream partner.
  1270. //
  1271. //
  1272. if (CxtionFlagIs(InCxtion, CXTION_FLAGS_VOLATILE)) {
  1273. CPkt = CommBuildCommPkt(Replica, InCxtion, CMD_UNJOIN_REMOTE, NULL, NULL, NULL);
  1274. SndCsSubmitCommPkt2(Replica, InCxtion, NULL, FALSE, CPkt);
  1275. }
  1276. UNLOCK_CXTION_TABLE(Replica);
  1277. InitSyncCsSubmitTransfer(Cmd,CMD_INITSYNC_JOIN_NEXT);
  1278. }
  1279. DWORD
  1280. MainInitSyncCs(
  1281. PVOID Arg
  1282. )
  1283. /*++
  1284. Routine Description:
  1285. Entry point for a thread serving the initial sync controller command server.
  1286. Arguments:
  1287. Arg - thread
  1288. Return Value:
  1289. None.
  1290. --*/
  1291. {
  1292. #undef DEBSUB
  1293. #define DEBSUB "MainInitSyncCs:"
  1294. DWORD WStatus = ERROR_SUCCESS;
  1295. PCOMMAND_PACKET Cmd;
  1296. PFRS_QUEUE IdledQueue;
  1297. PFRS_THREAD FrsThread = (PFRS_THREAD)Arg;
  1298. //
  1299. // Thread is pointing at the correct command server
  1300. //
  1301. FRS_ASSERT(FrsThread->Data == &InitSyncCs);
  1302. FrsThread->Exit = ThSupExitWithTombstone;
  1303. DPRINT(4, "Initial Sync command server has started.\n");
  1304. //
  1305. // Try-Finally
  1306. //
  1307. try {
  1308. //
  1309. // Capture exception.
  1310. //
  1311. try {
  1312. //
  1313. // Pull entries off the queue and process them
  1314. //
  1315. cant_exit_yet:
  1316. while (Cmd = FrsGetCommandServerIdled(&InitSyncCs, &IdledQueue)) {
  1317. switch (Cmd->Command) {
  1318. case CMD_INITSYNC_START_SYNC:
  1319. DPRINT3(4, "InitSync: Received Cmd 0x%08x Command 0x%08x, TargetQueue 0x%08x\n", Cmd, Cmd->Command, Cmd->TargetQueue);
  1320. InitSyncStartSync(Cmd);
  1321. break;
  1322. case CMD_INITSYNC_JOIN_NEXT:
  1323. DPRINT3(4, "InitSync: Received Cmd 0x%08x Command 0x%08x, TargetQueue 0x%08x\n", Cmd, Cmd->Command, Cmd->TargetQueue);
  1324. InitSyncJoinNext(Cmd);
  1325. break;
  1326. case CMD_INITSYNC_START_JOIN:
  1327. DPRINT3(4, "InitSync: Received Cmd 0x%08x Command 0x%08x, TargetQueue 0x%08x\n", Cmd, Cmd->Command, Cmd->TargetQueue);
  1328. InitSyncStartJoin(Cmd);
  1329. break;
  1330. case CMD_INITSYNC_VVJOIN_DONE:
  1331. DPRINT3(4, "InitSync: Received Cmd 0x%08x Command 0x%08x, TargetQueue 0x%08x\n", Cmd, Cmd->Command, Cmd->TargetQueue);
  1332. InitSyncVvJoinDone(Cmd);
  1333. break;
  1334. case CMD_INITSYNC_KEEP_ALIVE:
  1335. DPRINT3(4, "InitSync: Received Cmd 0x%08x Command 0x%08x, TargetQueue 0x%08x\n", Cmd, Cmd->Command, Cmd->TargetQueue);
  1336. InitSyncKeepAlive(Cmd);
  1337. break;
  1338. case CMD_INITSYNC_CHECK_PROGRESS:
  1339. DPRINT3(4, "InitSync: Received Cmd 0x%08x Command 0x%08x, TargetQueue 0x%08x\n", Cmd, Cmd->Command, Cmd->TargetQueue);
  1340. InitSyncCheckProgress(Cmd);
  1341. break;
  1342. case CMD_INITSYNC_UNJOIN:
  1343. DPRINT3(4, "InitSync: Received Cmd 0x%08x Command 0x%08x, TargetQueue 0x%08x\n", Cmd, Cmd->Command, Cmd->TargetQueue);
  1344. REPLICA_STATE_TRACE(3, Cmd, RsReplica(Cmd), 0, "F, processing");
  1345. InitSyncCsDelCsSubmit(Cmd, CMD_INITSYNC_JOINED,10*1000);
  1346. break;
  1347. case CMD_INITSYNC_JOINED:
  1348. DPRINT3(4, "InitSync: Received Cmd 0x%08x Command 0x%08x, TargetQueue 0x%08x\n", Cmd, Cmd->Command, Cmd->TargetQueue);
  1349. REPLICA_STATE_TRACE(3, Cmd, RsReplica(Cmd), 0, "F, processing");
  1350. InitSyncCsDelCsSubmit(Cmd, CMD_INITSYNC_COMM_TIMEOUT,10*1000);
  1351. break;
  1352. case CMD_INITSYNC_COMM_TIMEOUT:
  1353. DPRINT3(4, "InitSync: Received Cmd 0x%08x Command 0x%08x, TargetQueue 0x%08x\n", Cmd, Cmd->Command, Cmd->TargetQueue);
  1354. REPLICA_STATE_TRACE(3, Cmd, RsReplica(Cmd), 0, "F, processing");
  1355. break;
  1356. default:
  1357. DPRINT3(4, "InitSync: Received Cmd 0x%08x Command 0x%08x, TargetQueue 0x%08x\n", Cmd, Cmd->Command, Cmd->TargetQueue);
  1358. FrsCompleteCommand(Cmd, ERROR_INVALID_FUNCTION);
  1359. break;
  1360. }
  1361. FrsRtlUnIdledQueue(IdledQueue);
  1362. }
  1363. //
  1364. // Exit
  1365. //
  1366. FrsExitCommandServer(&InitSyncCs, FrsThread);
  1367. goto cant_exit_yet;
  1368. //
  1369. // Get exception status.
  1370. //
  1371. } except (EXCEPTION_EXECUTE_HANDLER) {
  1372. GET_EXCEPTION_CODE(WStatus);
  1373. }
  1374. } finally {
  1375. if (WIN_SUCCESS(WStatus)) {
  1376. if (AbnormalTermination()) {
  1377. WStatus = ERROR_OPERATION_ABORTED;
  1378. }
  1379. }
  1380. DPRINT_WS(4, "MainInitSyncCs finally.", WStatus);
  1381. //
  1382. // Trigger FRS shutdown if we terminated abnormally.
  1383. //
  1384. if (!WIN_SUCCESS(WStatus)) {
  1385. DPRINT(4, "MainInitSyncCs terminated abnormally, forcing service shutdown.\n");
  1386. FrsIsShuttingDown = TRUE;
  1387. SetEvent(ShutDownEvent);
  1388. }
  1389. }
  1390. return (WStatus);
  1391. }
  1392. VOID
  1393. InitSyncCsInitialize(
  1394. VOID
  1395. )
  1396. /*++
  1397. Routine Description:
  1398. Initialize the Initial Sync Controller command server.
  1399. Arguments:
  1400. None.
  1401. Return Value:
  1402. None.
  1403. --*/
  1404. {
  1405. #undef DEBSUB
  1406. #define DEBSUB "InitSyncCsInitialize:"
  1407. //
  1408. // Initialize the command server
  1409. //
  1410. CfgRegReadDWord(FKC_MAX_INITSYNCCS_THREADS, NULL, 0, &MaxInitSyncCsThreads);
  1411. FrsInitializeCommandServer(&InitSyncCs, MaxInitSyncCsThreads, L"InitSyncCs", MainInitSyncCs);
  1412. }
  1413. VOID
  1414. ShutDownInitSyncCs(
  1415. VOID
  1416. )
  1417. /*++
  1418. Routine Description:
  1419. Shutdown the Initial Sync Controller command server.
  1420. Arguments:
  1421. None.
  1422. Return Value:
  1423. None.
  1424. --*/
  1425. {
  1426. #undef DEBSUB
  1427. #define DEBSUB "ShutDownInitSyncCs:"
  1428. PVOID Key;
  1429. PREPLICA Replica;
  1430. //
  1431. // Rundown all known queues. New queue entries will bounce.
  1432. //
  1433. Key = NULL;
  1434. while (Replica = GTabNextDatum(ReplicasByGuid, &Key)) {
  1435. REPLICA_STATE_TRACE(3, NULL, Replica, 0, "F, Rundown InitSync cmd srv");
  1436. if (Replica->InitSyncQueue != NULL) {
  1437. FrsRunDownCommandServer(&InitSyncCs, Replica->InitSyncQueue);
  1438. }
  1439. }
  1440. FrsRunDownCommandServer(&InitSyncCs, &InitSyncCs.Queue);
  1441. }