Leaked source code of windows server 2003
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.

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