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.

1508 lines
48 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1991 - 2000.
  5. //
  6. // File: DQUEUE.CXX
  7. //
  8. // Contents: Document queue
  9. //
  10. // Classes: CDocQueue
  11. // CExtractDocs
  12. //
  13. // History: 29-Mar-91 BartoszM Created
  14. // 13-Sep-93 BartoszM Split from changes
  15. // 11-Oct-93 BartoszM Rewrote
  16. // 24-Feb-97 SitaramR Push filtering
  17. //
  18. //----------------------------------------------------------------------------
  19. #include <pch.cxx>
  20. #pragma hdrstop
  21. #include <doclist.hxx>
  22. #include <cifailte.hxx>
  23. #include "dqueue.hxx"
  24. #include "resman.hxx"
  25. //+---------------------------------------------------------------------------
  26. //
  27. // Member: CDocQueue::CheckInvariants
  28. //
  29. // Synopsis: Check that the doc queue is internally self-consistent
  30. //
  31. //----------------------------------------------------------------------------
  32. void CDocQueue::CheckInvariants ( char * pTag ) const
  33. {
  34. #if DBG
  35. Win4Assert( _state == eUseSerializedList ||
  36. _state == eUseUnSerializedList );
  37. Win4Assert( _oAppend <= cDocInChunk &&
  38. _oRetrieve <= cDocInChunk );
  39. if (_cDocuments == 0)
  40. {
  41. Win4Assert( _oAppend == _oRetrieve );
  42. Win4Assert( _unserializedList.IsEmpty() ||
  43. (_pFirstUnFiltered != 0 &&
  44. 0 == _pFirstUnFiltered->GetNext()) );
  45. Win4Assert( _changeLog.IsEmpty() );
  46. Win4Assert( _serializedList.IsEmpty() ||
  47. _pFirstUnFiltered != 0 );
  48. }
  49. else
  50. {
  51. Win4Assert( ! _unserializedList.IsEmpty() ||
  52. ! _serializedList.IsEmpty() ||
  53. ! _changeLog.IsEmpty() );
  54. if ( _pFirstUnFiltered &&
  55. 0 == _pFirstUnFiltered->GetNext() &&
  56. CDocQueue::eUseUnSerializedList == _state )
  57. {
  58. Win4Assert( _cDocuments == (_oAppend - _oRetrieve) );
  59. }
  60. }
  61. if (_oAppend < cDocInChunk)
  62. {
  63. Win4Assert( ! _unserializedList.IsEmpty() );
  64. }
  65. if (_oRetrieve < cDocInChunk)
  66. {
  67. Win4Assert( _pFirstUnFiltered != 0 );
  68. }
  69. #endif // DBG
  70. }
  71. //+---------------------------------------------------------------------------
  72. //
  73. // Class: CExtractDocs
  74. //
  75. // Purpose: A class to "extract" documents from the CDocQueue in a
  76. // transactioned fashion. If there is a failure while extracting
  77. // the documents, the state of the CDocQueue will be left in
  78. // such a way that it will appear no documents have been taken out
  79. // of the CDocQueue.
  80. //
  81. // History: 5-16-94 srikants Created
  82. //
  83. // Notes: When we extract documents out of the CDocQueue, we may have
  84. // to deserialize from the disk if the in-memory queue gets used
  85. // up. There is a possibility that this may fail and in such a
  86. // case an exception will be thrown. If we have already taken out
  87. // some of the documents, these documents may never get filtered
  88. // again. To prevent this situation, we use a "transactioned
  89. // extract" provided by this class.
  90. //
  91. //----------------------------------------------------------------------------
  92. class CExtractDocs
  93. {
  94. public:
  95. inline CExtractDocs( CDocQueue & docQueue, CDocList & docList );
  96. inline ~CExtractDocs();
  97. BOOL IsEmpty() const
  98. {
  99. Win4Assert( _cDocsRetrieved <= _cDocsTotal );
  100. return _cDocsRetrieved == _cDocsTotal;
  101. }
  102. inline void Retrieve( WORKID & wid,
  103. USN & usn,
  104. VOLUMEID& volumeId,
  105. ULONG & action,
  106. ULONG & cRetries,
  107. ULONG & cSecQRetries );
  108. void Commit() { _fCommit = TRUE; }
  109. private:
  110. BOOL IsEndOfCurrentChunk()
  111. {
  112. Win4Assert( _oRetrieve <= cDocInChunk );
  113. return( _oRetrieve == cDocInChunk );
  114. }
  115. CDocQueue & _docQueue;
  116. CDocList & _docList;
  117. BOOL _fCommit;
  118. CDocQueue::ERetrieveState _state; // Current state of retrieval.
  119. ULONG _oRetrieve; // Offset in the first unfiltered
  120. // chunk to retrieve.
  121. CDocChunk* _pFirstUnFiltered; // Ptr to first unfiltered chk
  122. const unsigned &_cDocsTotal; // # of documents left.
  123. unsigned _cDocsRetrieved; // # of documents retrieved.
  124. unsigned _cFilteredChunks; // # of filtered chunks.
  125. };
  126. //+---------------------------------------------------------------------------
  127. //
  128. // Function: CExtractDocs::CExtractDocs
  129. //
  130. // Synopsis: Constructor
  131. //
  132. // History: 5-23-94 srikants Created
  133. //
  134. //----------------------------------------------------------------------------
  135. inline CExtractDocs::CExtractDocs( CDocQueue & docQueue, CDocList & docList )
  136. : _docQueue(docQueue),
  137. _docList(docList),
  138. _fCommit(FALSE),
  139. _state( docQueue._state ),
  140. _oRetrieve( docQueue._oRetrieve),
  141. _pFirstUnFiltered( docQueue._pFirstUnFiltered ),
  142. _cDocsTotal( docQueue._cDocuments ),
  143. _cDocsRetrieved(0),
  144. _cFilteredChunks( docQueue._cFilteredChunks )
  145. {
  146. docQueue.CheckInvariants("CExtractDocs ctor");
  147. }
  148. //+---------------------------------------------------------------------------
  149. //
  150. // Function: CExtractDocs::CExtractDocs
  151. //
  152. // Synopsis: Destructor
  153. //
  154. // History: 5-23-94 srikants Created
  155. //
  156. //----------------------------------------------------------------------------
  157. inline CExtractDocs::~CExtractDocs()
  158. {
  159. _docQueue.CheckInvariants("CExtractDocs pre-dtor");
  160. if ( _fCommit )
  161. {
  162. _docQueue._oRetrieve = _oRetrieve;
  163. _docQueue._pFirstUnFiltered = _pFirstUnFiltered;
  164. _docQueue._cDocuments -= _cDocsRetrieved;
  165. _docQueue._cFilteredChunks = _cFilteredChunks;
  166. _docQueue._state = _state;
  167. //
  168. // Release the memory for filtered chunks that are
  169. // serialized.
  170. //
  171. CDocChunk * pTemp = _state == CDocQueue::eUseSerializedList ?
  172. _pFirstUnFiltered : 0;
  173. _docQueue._serializedList.DestroyUpto( pTemp );
  174. }
  175. else
  176. {
  177. _docList.LokClear();
  178. }
  179. _docQueue.CheckInvariants("CExtractDocs post-dtor");
  180. #if DBG
  181. if ( _pFirstUnFiltered &&
  182. 0 == _pFirstUnFiltered->GetNext() &&
  183. CDocQueue::eUseUnSerializedList == _state )
  184. {
  185. Win4Assert( _docQueue._cDocuments ==
  186. (_docQueue._oAppend - _docQueue._oRetrieve) );
  187. }
  188. #endif // DBG
  189. }
  190. //+---------------------------------------------------------------------------
  191. //
  192. // Member: CExtractDocs::Retrieve
  193. //
  194. // Synopsis: Retrieves a single document from the docqueue. It has been
  195. // assumed that the docQueue is not empty when this method is
  196. // called.
  197. //
  198. // Arguments: [wid] -- Output - Wid of the document
  199. // [usn] -- Output - USN of the document
  200. // [volumeId] -- Output - Volume id of the document
  201. // [action] -- Output - Action performed on the document
  202. // [cRetries] -- Output - Number of filtering retries.
  203. // [cSecQRetries] -- Output - Number of Secondary Q filtering retries.
  204. //
  205. // History: 5-26-94 srikants Created
  206. //
  207. //----------------------------------------------------------------------------
  208. inline void CExtractDocs::Retrieve( WORKID & wid,
  209. USN & usn,
  210. VOLUMEID& volumeId,
  211. ULONG & action,
  212. ULONG & cRetries,
  213. ULONG & cSecQRetries )
  214. {
  215. _docQueue.CheckInvariants("CExtractDocs::Retrieve pre");
  216. Win4Assert( !IsEmpty() );
  217. Win4Assert( 0 != _pFirstUnFiltered );
  218. if ( IsEndOfCurrentChunk() )
  219. {
  220. if ( CDocQueue::eUseSerializedList == _state )
  221. {
  222. //
  223. // We are currently retrieving from the serialized list.
  224. // Check to see if there is another chunk in the serialized
  225. // list that can be used next.
  226. //
  227. if ( 0 != _pFirstUnFiltered->GetNext() )
  228. {
  229. _pFirstUnFiltered = _pFirstUnFiltered->GetNext();
  230. }
  231. else if ( _docQueue._changeLog.IsEmpty() )
  232. {
  233. //
  234. // The change log doesn't have any archived chunks to be
  235. // read. In this case, the unserialized list cannot be
  236. // empty.
  237. //
  238. Win4Assert( !_docQueue._unserializedList.IsEmpty() );
  239. _pFirstUnFiltered = _docQueue._unserializedList.GetFirst();
  240. _state = CDocQueue::eUseUnSerializedList;
  241. }
  242. else
  243. {
  244. //
  245. // DeSerialize from the change log.
  246. //
  247. _docQueue.DeSerialize();
  248. _pFirstUnFiltered = _pFirstUnFiltered->GetNext();
  249. }
  250. }
  251. else
  252. {
  253. //
  254. // The state is UseUnSerializedList.
  255. //
  256. Win4Assert( 0 != _pFirstUnFiltered->GetNext() );
  257. _pFirstUnFiltered = _pFirstUnFiltered->GetNext();
  258. }
  259. _oRetrieve = 0;
  260. Win4Assert( 0 != _pFirstUnFiltered );
  261. }
  262. CDocNotification * pRetrieve = _pFirstUnFiltered->GetDoc( _oRetrieve );
  263. wid = pRetrieve->Wid();
  264. usn = pRetrieve->Usn();
  265. volumeId = pRetrieve->VolumeId();
  266. action = pRetrieve->Action() & ~CI_SCAN_UPDATE;
  267. cRetries = pRetrieve->Retries();
  268. cSecQRetries = pRetrieve->SecQRetries();
  269. _oRetrieve++;
  270. _cDocsRetrieved++;
  271. if ( IsEndOfCurrentChunk() )
  272. {
  273. _cFilteredChunks++;
  274. }
  275. if ( CDocQueue::eUseUnSerializedList == _state &&
  276. 0 == _pFirstUnFiltered->GetNext() )
  277. {
  278. Win4Assert( (_cDocsTotal - _cDocsRetrieved) ==
  279. (_docQueue._oAppend - _oRetrieve) );
  280. }
  281. Win4Assert( _cDocsRetrieved <= _cDocsTotal );
  282. Win4Assert( _oRetrieve <= cDocInChunk );
  283. Win4Assert( _docQueue._changeLog.AvailChunkCount() * cDocInChunk <=
  284. (_cDocsTotal-_cDocsRetrieved) );
  285. _docQueue.CheckInvariants("CExtractDocs::Retrieve post");
  286. } //Retrieve
  287. //+---------------------------------------------------------------------------
  288. //
  289. // Member: CDocQueue::CDocQueue
  290. //
  291. // Synopsis: Initializes queue
  292. //
  293. // Arguments: [widChangeLog] -- Workid of changlog
  294. // [storage] -- Storage
  295. // [type] -- Type of change log -- Primary or Secondary
  296. // [frmwrkParams] -- Framework parameters
  297. //
  298. // History: 11-Oct-93 BartoszM Created
  299. // 10-Feb-94 DwightKr Added code to load from disk
  300. //
  301. //----------------------------------------------------------------------------
  302. CDocQueue::CDocQueue( WORKID widChangeLog,
  303. PStorage & storage,
  304. PStorage::EChangeLogType type,
  305. CCiFrameworkParams & frmwrkParams ) :
  306. _frmwrkParams( frmwrkParams ),
  307. _sigDocQueue(eSigDocQueue),
  308. _changeLog( widChangeLog, storage, type ),
  309. _pResManager(0)
  310. {
  311. LokInit();
  312. }
  313. //+---------------------------------------------------------------------------
  314. //
  315. // Member: CDocQueue::LokInit
  316. //
  317. // Synopsis: Initializes the doc queue members. Also, deserializes chunks
  318. // from the changelog if it is not empty.
  319. //
  320. // History: 27-Dec-94 SrikantS Moved from ~ctor
  321. //
  322. //----------------------------------------------------------------------------
  323. void CDocQueue::LokInit()
  324. {
  325. _state = eUseSerializedList;
  326. _oAppend = _oRetrieve = cDocInChunk;
  327. _pFirstUnFiltered = 0;
  328. _cFilteredChunks = 0;
  329. _cRefiledDocs = 0;
  330. _cDocuments = 0;
  331. if ( !_changeLog.IsEmpty() )
  332. {
  333. _cDocuments = _changeLog.AvailChunkCount() * cDocInChunk;
  334. ULONG nChunksToRead = min( _frmwrkParams.GetMaxQueueChunks() / 2,
  335. _changeLog.AvailChunkCount() );
  336. ULONG nChunksRead = _changeLog.DeSerialize( _serializedList,
  337. nChunksToRead );
  338. Win4Assert( nChunksRead == nChunksToRead );
  339. _pFirstUnFiltered = _serializedList.GetFirst();
  340. Win4Assert( 0 != _pFirstUnFiltered );
  341. _oRetrieve = 0;
  342. }
  343. CheckInvariants("LokInit post");
  344. }
  345. //+---------------------------------------------------------------------------
  346. //
  347. // Member: CDocQueue::~CDocQueue, public
  348. //
  349. // History: 11-Oct-93 BartoszM Created
  350. // 10-Feb-94 DwightKr Added code to save to disk
  351. //
  352. //----------------------------------------------------------------------------
  353. CDocQueue::~CDocQueue()
  354. {
  355. CheckInvariants("CDocQueue dtor");
  356. ciDebugOut (( DEB_ITRACE, "CDocQueue\n" ));
  357. //
  358. // _cRefiledDocs may be non-zero, but that isn't a problem, since
  359. // the updates are still sitting on disk. They are likely here
  360. // because FilterReady got an exception from WorkIdToPath() as CI
  361. // is shutting down, and the docs were refiled.
  362. //
  363. //
  364. // Win4Assert( 0 == _cRefiledDocs );
  365. //
  366. }
  367. //+---------------------------------------------------------------------------
  368. //
  369. // Member: CDocQueue::LokCleanup
  370. //
  371. // Synopsis: Cleans up the private data members.
  372. //
  373. // History: 27-Dec-94 SrikantS Moved from ~ctor
  374. //
  375. //----------------------------------------------------------------------------
  376. void CDocQueue::LokCleanup()
  377. {
  378. CheckInvariants("LokCleanup");
  379. _serializedList.DestroyUpto( 0 );
  380. _unserializedList.DestroyUpto( 0 );
  381. _cDocuments = _cFilteredChunks = 0;
  382. _oAppend = _oRetrieve = cDocInChunk;
  383. _pFirstUnFiltered = 0;
  384. _cRefiledDocs = 0;
  385. }
  386. //+---------------------------------------------------------------------------
  387. //
  388. // Member: CDocQueue::LokEmpty, public
  389. //
  390. // History: 15-Nov-94 DwightKr Created
  391. //
  392. //----------------------------------------------------------------------------
  393. void CDocQueue::LokEmpty()
  394. {
  395. LokCleanup();
  396. _changeLog.LokEmpty();
  397. }
  398. //+---------------------------------------------------------------------------
  399. //
  400. // Function: LokDismount
  401. //
  402. // Synopsis: Prepares for the dismount by serializing the changelog.
  403. //
  404. // History: 6-20-94 srikants Created
  405. //
  406. // Notes: This routine should not throw, since we may be looping
  407. // to dismount multiple partitions on a single volume.
  408. // This avoids an outer TRY/CATCH block, and we really can't
  409. // do anything to correct a failed dismount.
  410. //
  411. //----------------------------------------------------------------------------
  412. NTSTATUS CDocQueue::LokDismount( CChangeTrans & xact )
  413. {
  414. NTSTATUS status = STATUS_SUCCESS;
  415. TRY
  416. {
  417. #ifdef CI_FAILTEST
  418. NTSTATUS failstatus = STATUS_NO_MEMORY ;
  419. ciFAILTEST( failstatus );
  420. #endif // CI_FAILTEST
  421. if ( _changeLog.AreUpdatesEnabled() )
  422. {
  423. if ( 0 != _cRefiledDocs )
  424. LokAppendRefiledDocs( xact );
  425. if ( !_unserializedList.IsEmpty() )
  426. {
  427. Serialize(0);
  428. }
  429. }
  430. }
  431. CATCH( CException, e )
  432. {
  433. ciDebugOut(( DEB_ERROR,
  434. "ChangeLog could not be written out due to error 0x%X\n",
  435. e.GetErrorCode() ));
  436. status = e.GetErrorCode();
  437. }
  438. END_CATCH
  439. //
  440. // Even if the dismount failed, we must clean up our internal
  441. // data structures.
  442. //
  443. LokCleanup();
  444. //
  445. // Should not accept any more update notifications.
  446. //
  447. _changeLog.LokDisableUpdates();
  448. return status;
  449. }
  450. //+---------------------------------------------------------------------------
  451. //
  452. // Member: CDocQueue::Append, public
  453. //
  454. // Synopsis: Appends documents to the queue
  455. //
  456. // Arguments: [wid] -- work id
  457. // [usn] -- update sequence number
  458. // [volumeId] -- volume id
  459. // [action] -- update/delete
  460. // [cRetries] -- number of retries on this item
  461. // [cSecQRetries] -- number of Sec Q retries on this item
  462. //
  463. // History: 11-Oct-93 BartoszM Created
  464. //
  465. // Notes: The RESMAN lock was taken before this method was called.
  466. //
  467. //----------------------------------------------------------------------------
  468. SCODE CDocQueue::Append ( CChangeTrans & xact,
  469. WORKID wid,
  470. USN usn,
  471. VOLUMEID volumeId,
  472. ULONG action,
  473. ULONG cRetries,
  474. ULONG cSecQRetries )
  475. {
  476. CheckInvariants("Append pre");
  477. // The first try is 1. The first retry is 2
  478. Win4Assert( cRetries <= ( _frmwrkParams.GetFilterRetries() + 1 ) );
  479. Win4Assert( 0 != cRetries );
  480. // check for corrupted values, either wid is invalid or action must make sense
  481. Win4Assert( wid == widInvalid ||
  482. (action & CI_UPDATE_OBJ) != 0 ||
  483. (action & CI_UPDATE_PROPS) != 0 ||
  484. (action & CI_DELETE_OBJ) != 0 );
  485. Win4Assert( 0 != wid );
  486. Win4Assert( ((wid & 0x80000000) == 0) || (wid == widInvalid) );
  487. //
  488. // If we have disabled updates, then don't bother saving this
  489. // filter request. If updates are disabled, we will schedule an
  490. // EnableUpdates at a later time to discover all of the lost updates.
  491. // In push filtering, there is no internal refiling and so any appends
  492. // are always from client.
  493. // In pull filtering, the in-memory part of changelog is cleaned up,
  494. // and the in-memory part of changelog is re-initialized on startup.
  495. // Hence appends can be ignored for both push and pull filtering
  496. // when _fUpdatesEnabled is false.
  497. //
  498. if ( !_changeLog.AreUpdatesEnabled() )
  499. return CI_E_UPDATES_DISABLED;
  500. //
  501. // Check if the current append chunk is full.
  502. //
  503. if ( IsAppendChunkFull() )
  504. {
  505. //
  506. // Before allocating a new one, see if we have exceeded the
  507. // threshold of maximum chunks in memory and serialize
  508. // the list appropriately.
  509. //
  510. ULONG cTotal = _serializedList.Count() + _unserializedList.Count();
  511. ULONG MaxQueueChunks = _frmwrkParams.GetMaxQueueChunks();
  512. ciDebugOut(( DEB_ITRACE, "ctotal %d, maxqueuechunks %d\n",
  513. cTotal, MaxQueueChunks ));
  514. if ( cTotal >= MaxQueueChunks )
  515. {
  516. Serialize( MaxQueueChunks / 2 );
  517. }
  518. //
  519. // Allocate a new chunk and append to the unserialized list.
  520. //
  521. CDocChunk * pChunk = new CDocChunk();
  522. _unserializedList.Append( pChunk );
  523. _oAppend = 0;
  524. }
  525. //
  526. // OPTIMIZATION to avoid processing the same wid (eg temp files)
  527. // in the same chunk.
  528. //
  529. // Insert this record so that it overwrites the first entry with the
  530. // same WID within this chunk. This results in the extraction procedure
  531. // to process the WID with the last STATUS received in this chunk.
  532. //
  533. CDocChunk * pLastChunk = _unserializedList.GetLast();
  534. Win4Assert( 0 != pLastChunk );
  535. CDocNotification * pAppend = pLastChunk->GetDoc( _oAppend );
  536. pAppend->Set ( wid, usn, volumeId, action, cRetries, cSecQRetries );
  537. CDocNotification * pRec;
  538. //
  539. // A special case exists if we are have inserted a record into the chunk
  540. // from which we are extracting records. We need to search from the
  541. // current read point forward, rather than from the start of the chunk.
  542. //
  543. if ( _pFirstUnFiltered == pLastChunk )
  544. {
  545. //
  546. // Note that if _oRetrieve is cDocInChunk, then we would have
  547. // created a new chunk and _pFirstUnFiltered would not be same
  548. // as pLastChunk.
  549. //
  550. pRec = pLastChunk->GetDoc(_oRetrieve); // Starting search location
  551. }
  552. else
  553. {
  554. pRec = pLastChunk->GetDoc(0); // Starting search location
  555. }
  556. //
  557. // Since we have added the current wid as a sentinel value, it is
  558. // guaranteed to terminate.
  559. //
  560. while (pRec->Wid() != wid )
  561. pRec++;
  562. if (pRec == pAppend) // This will be true 99% of the time
  563. {
  564. _oAppend++;
  565. _cDocuments++;
  566. }
  567. else // Overwrite the WID found
  568. {
  569. Win4Assert( wid == pRec->Wid() );
  570. pRec->Set ( wid, usn, volumeId, action, cRetries, cSecQRetries );
  571. }
  572. if ( 0 == _pFirstUnFiltered )
  573. {
  574. _pFirstUnFiltered = pLastChunk;
  575. _state = eUseUnSerializedList;
  576. _oRetrieve = 0;
  577. Win4Assert( _cDocuments == 1 && _oAppend == 1 );
  578. }
  579. if ( pLastChunk == _pFirstUnFiltered )
  580. {
  581. Win4Assert( _cDocuments == (_oAppend - _oRetrieve) );
  582. }
  583. Win4Assert( _changeLog.AvailChunkCount() * cDocInChunk <= _cDocuments );
  584. #ifdef CI_FAILTEST
  585. ciFAILTEST( STATUS_DISK_FULL );
  586. #endif // CI_FAILTEST
  587. CheckInvariants("Append post");
  588. return S_OK;
  589. }
  590. //+---------------------------------------------------------------------------
  591. //
  592. // Member: CDocQueue::Get
  593. //
  594. // Synopsis: Get top of the queue. Items are not removed from the queue.
  595. //
  596. // Arguments: [aWid] -- Array of wids
  597. // [cWid] -- Count of wids in array, updated on return
  598. //
  599. // Returns: TRUE if all items in the queue were returned.
  600. //
  601. // History: 23-May-94 SrikantS Created
  602. //
  603. //----------------------------------------------------------------------------
  604. BOOL CDocQueue::Get( WORKID * aWid, unsigned & cWid )
  605. {
  606. CheckInvariants("Get");
  607. //
  608. // We can't refile w/o a transaction, so just return FALSE,
  609. // and if there are too many we won't bother to return any.
  610. //
  611. if ( (0 != _cRefiledDocs) ||
  612. (_cDocuments > cWid) ||
  613. !_changeLog.AreUpdatesEnabled() )
  614. {
  615. cWid = 0;
  616. return( FALSE );
  617. }
  618. //
  619. // Get documents from in-memory list
  620. //
  621. CDocChunk * pChunk = _pFirstUnFiltered;
  622. Win4Assert( 0 != _pFirstUnFiltered || 0 == _cDocuments );
  623. unsigned iDocInChunk = _oRetrieve;
  624. for ( cWid = 0; cWid < _cDocuments; cWid++ )
  625. {
  626. if ( iDocInChunk == cDocInChunk )
  627. {
  628. pChunk = pChunk->GetNext();
  629. iDocInChunk = 0;
  630. if ( 0 == pChunk )
  631. break;
  632. }
  633. aWid[cWid] = pChunk->GetDoc(iDocInChunk)->Wid();
  634. iDocInChunk++;
  635. }
  636. //
  637. // We may not have got all the documents. This occurs when we're using
  638. // the serialized list and don't have all the documents available in
  639. // memory. (We do try to keep a reasonable number of docs in memory)
  640. //
  641. return ( cWid == _cDocuments );
  642. }
  643. //+---------------------------------------------------------------------------
  644. //
  645. // Member: CDocQueue::Extract, public
  646. //
  647. // Synopsis: Extract top of the queue
  648. //
  649. // Arguments: [xact] -- transaction
  650. // [maxDocs] -- size of doclist
  651. // [docList] -- doc list to be filled. It will NOT have any
  652. // duplicate WID entries. The last entry for a wid
  653. // will supercede all other entries before it.
  654. //
  655. // History: 11-Oct-93 BartoszM Created
  656. // 16-May-94 SrikantS Modified to make it a
  657. // transaction.
  658. //
  659. // Notes: This function must be called under resman lock.
  660. //
  661. //----------------------------------------------------------------------------
  662. void CDocQueue::Extract( CChangeTrans & xact,
  663. unsigned maxDocs,
  664. CDocList & docList)
  665. {
  666. CheckInvariants("Extract pre");
  667. //
  668. // If there are any documents that got requeued due to a failure
  669. // after they were extracted, we must append to the list before
  670. // extracting the documents.
  671. //
  672. if ( 0 != _cRefiledDocs )
  673. {
  674. LokAppendRefiledDocs( xact );
  675. }
  676. //
  677. // If we are not saving updates, then don't return any docs to
  678. // filter.
  679. //
  680. if ( !_changeLog.AreUpdatesEnabled() )
  681. {
  682. docList.LokSetCount(0);
  683. return;
  684. }
  685. //
  686. // BeginTransaction
  687. //
  688. CExtractDocs extractDocs( *this, docList );
  689. unsigned i = 0;
  690. while ( (i < maxDocs) && !extractDocs.IsEmpty() )
  691. {
  692. WORKID wid;
  693. USN usn;
  694. VOLUMEID volumeId;
  695. ULONG action;
  696. ULONG cRetries;
  697. ULONG cSecQRetries;
  698. extractDocs.Retrieve( wid, usn, volumeId, action, cRetries, cSecQRetries );
  699. if (widInvalid != wid)
  700. {
  701. //
  702. // If the wid already exists in the doclist, we should overwrite
  703. // that with this one. The last entry in the changelog for the
  704. // same wid always wins.
  705. //
  706. //
  707. // This is currently an N^2 algorithm. See if there
  708. // is a better algorithm if it shows up in profiling. It hasn't
  709. // in the past. Note that there will only be 16 items here
  710. // so the algorithm choice doesn't matter too much.
  711. //
  712. for ( unsigned j = 0; j < i; j++ )
  713. {
  714. if ( docList.Wid(j) == wid )
  715. break;
  716. }
  717. // check for corrupted values
  718. Win4Assert( action == CI_UPDATE_OBJ ||
  719. action == CI_UPDATE_PROPS ||
  720. action == CI_DELETE_OBJ );
  721. docList.Set( j,
  722. wid,
  723. usn,
  724. volumeId,
  725. (action == CI_DELETE_OBJ) ? DELETED : PENDING,
  726. cRetries,
  727. cSecQRetries
  728. );
  729. if ( j == i )
  730. {
  731. // New Wid. Increment the count of entries
  732. i++;
  733. }
  734. else
  735. {
  736. ciDebugOut(( DEB_PENDING | DEB_ITRACE,
  737. "Duplicate wid=0x%X overwritten by action=0x%X\n",
  738. wid, action ));
  739. }
  740. }
  741. }
  742. CheckInvariants("Extract pre-commit");
  743. docList.LokSetCount(i);
  744. extractDocs.Commit(); // EndTransaction
  745. CheckInvariants("Extract post");
  746. } //Extract
  747. //+---------------------------------------------------------------------------
  748. //
  749. // Function: MoveToSerializedList
  750. //
  751. // Synopsis: Skips the chunks in the listToCompact in the change log and
  752. // appends them to the _serializedList, up to the maximum
  753. // permitted by the "nMaxChunksInMem" parameter. This will
  754. // prevent un-necessarily reading the serialized chunks that are
  755. // already in memory.
  756. //
  757. // The rest of the chunks are deleted and will have to be
  758. // de-serialized at a later time because they cannot be held in
  759. // memory now.
  760. //
  761. // Effects: The listToCompact will be emptied when this returns.
  762. //
  763. // Arguments: [listToCompact] -- The list which needs to be compacted.
  764. // [nChunksToMove] -- Maximum number of chunks that must be
  765. // left in memory (suggested).
  766. //
  767. // History: 6-06-94 srikants Created
  768. //
  769. //----------------------------------------------------------------------------
  770. void CDocQueue::MoveToSerializedList( CChunkList & listToCompact,
  771. ULONG nChunksToMove )
  772. {
  773. //
  774. // Until the count in the serializedlist is less than the
  775. // maximum allowed, we transfer from the listToCompact
  776. // to the serialized list.
  777. //
  778. while ( ( nChunksToMove > 0 ) &&
  779. (0 != listToCompact.GetFirst()) )
  780. {
  781. CDocChunk * pChunk = listToCompact.Pop();
  782. Win4Assert( 0 != pChunk );
  783. _serializedList.Append(pChunk);
  784. _changeLog.SkipChunk();
  785. nChunksToMove--;
  786. }
  787. }
  788. //+---------------------------------------------------------------------------
  789. //
  790. // Function: SerializeInLHS
  791. //
  792. // Synopsis: Serializes the unserialized chunks when we are retrieving
  793. // from the "Left Hand Side" of the change log, ie, in the
  794. // "eUseSerializedList" state.
  795. //
  796. // Effects: The unserializedList is emptied and appropriate number of
  797. // chunks appended to the end of the serialized list.
  798. //
  799. // Arguments: [nMaxChunksInMem] -- Suggested maximum number of chunks that
  800. // must be left in memory after doing the
  801. // serialization.
  802. // [aUsnFlushInfo] -- Usn flush info is returned here
  803. //
  804. // History: 6-06-94 srikants Created
  805. //
  806. //----------------------------------------------------------------------------
  807. void CDocQueue::SerializeInLHS( ULONG nMaxChunksInMem,
  808. CCountedDynArray<CUsnFlushInfo> & aUsnFlushInfo )
  809. {
  810. CheckInvariants("SerializeInLHS pre");
  811. Win4Assert( eUseSerializedList == _state );
  812. Win4Assert( _pFirstUnFiltered == _serializedList.GetFirst() );
  813. //
  814. // Delete all the filtered chunks.
  815. //
  816. ULONG cChunkInLogBefore = _changeLog.AvailChunkCount();
  817. _changeLog.Serialize( _unserializedList, aUsnFlushInfo );
  818. ULONG nChunksToMove = 0;
  819. if ( _serializedList.Count() < nMaxChunksInMem )
  820. {
  821. nChunksToMove = nMaxChunksInMem - _serializedList.Count();
  822. }
  823. CChunkList listToCompact;
  824. listToCompact.AcquireAndAppend( _unserializedList );
  825. if ( 0 == cChunkInLogBefore )
  826. {
  827. //
  828. // We can move as much of the listToCompact to the serialized
  829. // list as possible.
  830. //
  831. MoveToSerializedList( listToCompact, nChunksToMove );
  832. }
  833. else
  834. {
  835. //
  836. // Optimization - instead of deleting the unserialized list and
  837. // then reading them, we will see if we can fit the unserialized list
  838. // chunks in memory without having to exceed the memory threshold.
  839. //
  840. if ( cChunkInLogBefore < nChunksToMove )
  841. {
  842. //
  843. // We have to deserialize the change log because chunks
  844. // have to be consumed in the FIFO order strictly.
  845. // Since there can be a failure while doing the deserialization,
  846. // we must not leave the docqueue in an inconsistent
  847. // state - the unSerializedList must be empty.
  848. //
  849. _changeLog.DeSerialize( _serializedList, cChunkInLogBefore );
  850. nChunksToMove -= cChunkInLogBefore;
  851. MoveToSerializedList( listToCompact, nChunksToMove );
  852. }
  853. }
  854. Win4Assert( _unserializedList.IsEmpty() );
  855. //
  856. // After we serialize, we must start using a new chunk for doing
  857. // appends.
  858. //
  859. Win4Assert( _oAppend <= cDocInChunk );
  860. _cDocuments += (cDocInChunk-_oAppend);
  861. _oAppend = cDocInChunk;
  862. Win4Assert( (_oAppend - _oRetrieve) == (_cDocuments % cDocInChunk) ||
  863. ((_oAppend - _oRetrieve) == cDocInChunk &&
  864. (_cDocuments % cDocInChunk) == 0) );
  865. Win4Assert( _changeLog.AvailChunkCount() * cDocInChunk <= _cDocuments );
  866. Win4Assert( 0 != _pFirstUnFiltered || 0 == _cDocuments );
  867. CheckInvariants("SerializeInLHS post");
  868. }
  869. //+---------------------------------------------------------------------------
  870. //
  871. // Function: SerializeInRHS
  872. //
  873. // Synopsis: Serializes the un-serialized list when we are retrieving
  874. // from the "Right Hand Side" of the change-log, ie, we are
  875. // in the "eUseUnSerializedList" state.
  876. //
  877. // Effects: The _unSerializedList will be emptied and appropriate
  878. // number of chunks appended to the _serializedList.
  879. //
  880. // Arguments: [nChunksToMove] -- Maximum number of chunks permitted
  881. // in memory (suggested).
  882. // [aUsnFlushInfo] -- Usn flush info is returned here
  883. //
  884. // History: 6-06-94 srikants Created
  885. //
  886. //----------------------------------------------------------------------------
  887. inline void CDocQueue::SerializeInRHS( ULONG nChunksToMove,
  888. CCountedDynArray<CUsnFlushInfo> & aUsnFlushInfo )
  889. {
  890. CheckInvariants("SerializeInRHS pre");
  891. //
  892. // We are using the unserialized list. The change log must be
  893. // empty and the serialized list must also be empty.
  894. //
  895. Win4Assert( eUseUnSerializedList == _state );
  896. Win4Assert( _changeLog.IsEmpty() );
  897. Win4Assert( _serializedList.IsEmpty() );
  898. //
  899. // Write the unserialized list to disk and keep as much of
  900. // it as possible.
  901. //
  902. _changeLog.Serialize( _unserializedList, aUsnFlushInfo );
  903. //
  904. // Skip up to the _pFirstUnFiltered and delete them.
  905. //
  906. while ( _unserializedList.GetFirst() != _pFirstUnFiltered )
  907. {
  908. CDocChunk * pDelete = _unserializedList.Pop();
  909. delete pDelete;
  910. _changeLog.SkipChunk();
  911. }
  912. //
  913. // Keep as much of the remaining unserialized list in memory
  914. // as possible.
  915. //
  916. CChunkList listToCompact;
  917. listToCompact.AcquireAndAppend( _unserializedList );
  918. BOOL fInLastChunk = FALSE;
  919. if ( 0 != _pFirstUnFiltered )
  920. {
  921. //
  922. // We MUST have at least one chunk (the _pFirstUnFiltered) in memory.
  923. //
  924. Win4Assert( listToCompact.GetFirst() == _pFirstUnFiltered );
  925. nChunksToMove = max(nChunksToMove, 1);
  926. fInLastChunk = _pFirstUnFiltered == listToCompact.GetLast();
  927. }
  928. MoveToSerializedList( listToCompact, nChunksToMove );
  929. _state = eUseSerializedList;
  930. //
  931. // After we serialize, we must start using a new chunk for doing
  932. // appends.
  933. //
  934. Win4Assert( _oAppend <= cDocInChunk );
  935. if ( fInLastChunk && (_oAppend == _oRetrieve) )
  936. {
  937. //
  938. // We have filtered all the documents. After serialization, we will
  939. // start using a new chunk for appending new documents. We should
  940. // consider this chunk fully filtered.
  941. //
  942. Win4Assert( 0 == _cDocuments );
  943. _serializedList.DestroyUpto(0);
  944. if ( cDocInChunk != _oRetrieve )
  945. {
  946. //
  947. // The filtered chunk count should be incremented because we have
  948. // skipped a few documents in the current chunk without filtering
  949. // but have considered them to be filtered.
  950. //
  951. _cFilteredChunks++;
  952. }
  953. _oAppend = _oRetrieve = cDocInChunk;
  954. _pFirstUnFiltered = 0;
  955. }
  956. else
  957. {
  958. _cDocuments += (cDocInChunk-_oAppend);
  959. _oAppend = cDocInChunk;
  960. Win4Assert( _changeLog.AvailChunkCount() * cDocInChunk <= _cDocuments );
  961. }
  962. Win4Assert( (_oAppend - _oRetrieve) == (_cDocuments % cDocInChunk) ||
  963. ((_oAppend - _oRetrieve) == cDocInChunk &&
  964. (_cDocuments % cDocInChunk) == 0) );
  965. Win4Assert( 0 != _pFirstUnFiltered || 0 == _cDocuments );
  966. CheckInvariants("SerializeInRHS post");
  967. }
  968. //+---------------------------------------------------------------------------
  969. //
  970. // Function: Serialize
  971. //
  972. // Synopsis: Serializes the _unSerialized list to disk, moves some of the
  973. // chunks (as permitted nChunksToMove) to the _serializedList
  974. // and frees up the remaining chunks.
  975. //
  976. // Arguments: [nChunksToMove] -- Suggested maximum number of chunks in
  977. // memory.
  978. //
  979. // History: 6-06-94 srikants Created
  980. //
  981. //----------------------------------------------------------------------------
  982. void CDocQueue::Serialize( ULONG nMaxChunksInMem )
  983. {
  984. CheckInvariants("Serialize pre");
  985. //
  986. // Get the current system time which will be used as the flush time
  987. //
  988. FILETIME ftFlush;
  989. GetSystemTimeAsFileTime( &ftFlush );
  990. CCountedDynArray<CUsnFlushInfo> aUsnFlushInfo;
  991. if ( eUseSerializedList == _state )
  992. {
  993. //
  994. // Delete the serialized list up to the first unfiltered chunk.
  995. //
  996. _serializedList.DestroyUpto( _pFirstUnFiltered );
  997. SerializeInLHS( nMaxChunksInMem, aUsnFlushInfo );
  998. }
  999. else
  1000. {
  1001. #if DBG
  1002. if ( _oRetrieve != cDocInChunk )
  1003. {
  1004. Win4Assert( _pFirstUnFiltered != 0 );
  1005. Win4Assert( _pFirstUnFiltered != _serializedList.GetFirst() );
  1006. }
  1007. #endif // DBG
  1008. //
  1009. // We don't need any of the chunks in the serialized list to be
  1010. // in memory.
  1011. //
  1012. _serializedList.DestroyUpto( 0 );
  1013. SerializeInRHS( nMaxChunksInMem, aUsnFlushInfo );
  1014. }
  1015. Win4Assert( _pResManager );
  1016. if ( _changeLog.IsPrimary() )
  1017. _pResManager->NotifyFlush( ftFlush,
  1018. aUsnFlushInfo.Count(),
  1019. (USN_FLUSH_INFO **) aUsnFlushInfo.GetPointer() );
  1020. Win4Assert( _unserializedList.IsEmpty() );
  1021. CheckInvariants("Serialize post");
  1022. }
  1023. //+---------------------------------------------------------------------------
  1024. //
  1025. // Function: DeSerialize
  1026. //
  1027. // Synopsis: Reads the appropriate number of serialized chunks from
  1028. // change log into memory.
  1029. //
  1030. // History: 6-01-94 srikants Redesigned.
  1031. //
  1032. //----------------------------------------------------------------------------
  1033. void CDocQueue::DeSerialize()
  1034. {
  1035. CheckInvariants("DeSerialize pre");
  1036. Win4Assert( eUseSerializedList == _state );
  1037. Win4Assert( !_changeLog.IsEmpty() );
  1038. //
  1039. // Delete all the filtered chunks.
  1040. //
  1041. _serializedList.DestroyUpto( _pFirstUnFiltered );
  1042. //
  1043. // First figure out how many chunks can be deserialized.
  1044. //
  1045. ULONG MaxQueueChunks = _frmwrkParams.GetMaxQueueChunks();
  1046. ULONG nChunksToRead = min( MaxQueueChunks / 2,
  1047. _changeLog.AvailChunkCount() );
  1048. ULONG nChunksInMem = _serializedList.Count() + _unserializedList.Count();
  1049. const ULONG nMaxChunksInMem = MaxQueueChunks / 2;
  1050. if ( nChunksToRead + nChunksInMem > nMaxChunksInMem )
  1051. {
  1052. //
  1053. // If we go ahead and de-serialize nChunksToRead, we will exceed
  1054. // the maximum threshold. We will first serialize the
  1055. // un-serialized documents and free up some memory.
  1056. //
  1057. if ( 0 != _unserializedList.Count() )
  1058. {
  1059. //
  1060. // Get the current system time which will be used as the flush time
  1061. //
  1062. FILETIME ftFlush;
  1063. GetSystemTimeAsFileTime( &ftFlush );
  1064. CCountedDynArray<CUsnFlushInfo> aUsnFlushInfo;
  1065. ULONG nChunksToLeave = nMaxChunksInMem - nChunksToRead;
  1066. SerializeInLHS( nChunksToLeave, aUsnFlushInfo );
  1067. Win4Assert( _pResManager );
  1068. if ( _changeLog.IsPrimary() )
  1069. _pResManager->NotifyFlush( ftFlush,
  1070. aUsnFlushInfo.Count(),
  1071. (USN_FLUSH_INFO **) aUsnFlushInfo.GetPointer() );
  1072. }
  1073. Win4Assert( _unserializedList.Count() == 0 );
  1074. nChunksInMem = _serializedList.Count();
  1075. if ( nChunksInMem >= nMaxChunksInMem )
  1076. {
  1077. //
  1078. // This is the special case where the number of docs in CDocList
  1079. // is > the MaxQueueChunks and this is to allow progress.
  1080. //
  1081. ciDebugOut(( DEB_ITRACE,
  1082. "CDocQueue: Too many chunks in memory: %d\n", nChunksInMem ));
  1083. nChunksToRead = 1;
  1084. }
  1085. else
  1086. {
  1087. nChunksToRead = min( nChunksToRead,
  1088. nMaxChunksInMem-nChunksInMem );
  1089. }
  1090. }
  1091. Win4Assert( nChunksToRead > 0 );
  1092. _changeLog.DeSerialize( _serializedList, nChunksToRead );
  1093. _state = eUseSerializedList;
  1094. CheckInvariants("DeSerialize post");
  1095. }
  1096. //+---------------------------------------------------------------------------
  1097. //
  1098. // Function: LokDeleteWIDsInPersistentIndexes
  1099. //
  1100. // Synopsis: Deletes the workIds that have been filtered and have already
  1101. // made it into a persistent index. This causes the change log
  1102. // to be shrinked from the front.
  1103. //
  1104. // Arguments: [xact] -- Change transaction to use
  1105. // [freshTestLatest] -- Latest freshTest
  1106. // [freshTestAtMerge] -- Fresh test snapshoted at time of shadow
  1107. // merge (can be same as freshTestLatest)
  1108. // [docList] -- Doc list
  1109. // [notifTrans] -- Notification transaction
  1110. //
  1111. // Algorithm: Documents are always processed in the FIFO order in the
  1112. // change log. If a document is not successfully filtered, it
  1113. // is appened as a new entry to the change log. If the order
  1114. // in change log is say A, B, C, D .. then if D has made it into
  1115. // persistent index, we can be sure that either all of A, B
  1116. // and C have made it into persistent index or they have been
  1117. // re-added to the change log. In either case, it is fine to
  1118. // delete up to D.
  1119. //
  1120. // History: 6-01-94 srikants Created
  1121. // 24-Feb-97 SitaramR Push filtering
  1122. //
  1123. //----------------------------------------------------------------------------
  1124. void CDocQueue::LokDeleteWIDsInPersistentIndexes( CChangeTrans & xact,
  1125. CFreshTest & freshTestLatest,
  1126. CFreshTest & freshTestAtMerge,
  1127. CDocList & docList,
  1128. CNotificationTransaction & notifTrans )
  1129. {
  1130. CheckInvariants("LokDeleteWIDsInPersistentIndexes pre");
  1131. //
  1132. // First serialize everything and leave at most MAX_QUEUE_CHUNKS in
  1133. // memory. Serialization is necessary to make sure that the docs which
  1134. // were re-added due to filter failures are persistently recorded in
  1135. // the change log.
  1136. //
  1137. Serialize( _frmwrkParams.GetMaxQueueChunks() );
  1138. ULONG cChunksTruncated =
  1139. _changeLog.LokDeleteWIDsInPersistentIndexes( _cFilteredChunks,
  1140. freshTestLatest,
  1141. freshTestAtMerge,
  1142. docList,
  1143. notifTrans );
  1144. Win4Assert( cChunksTruncated <= _cFilteredChunks );
  1145. _cFilteredChunks -= cChunksTruncated;
  1146. CheckInvariants("LokDeleteWIDsInPersistentIndexes post");
  1147. }
  1148. //+---------------------------------------------------------------------------
  1149. //
  1150. // Function: LokRefileDocs
  1151. //
  1152. // Synopsis: Refiles the documents with the change list. This method
  1153. // is called to add documents that could not be successfully
  1154. // filtered back to the change list.
  1155. //
  1156. // Arguments: [docList] -- Contains the documents to be added back to
  1157. // the change list.
  1158. //
  1159. // Algorithm: All documents with status != WL_IGNORE will be added back
  1160. // to the change list. If the status is DELETED, then it will
  1161. // be considered to be a deleted document. O/W, it will be
  1162. // treated as a "Update".
  1163. //
  1164. // History: 10-24-94 srikants Created
  1165. // 24-Feb-97 SitaramR Push filtering
  1166. //
  1167. // Notes: When this method is called, there must be no outstanding
  1168. // documents to be refiled. DocQueue can deal with at most one
  1169. // outstanding set of refiled documents.
  1170. //
  1171. //----------------------------------------------------------------------------
  1172. void CDocQueue::LokRefileDocs( const CDocList & docList )
  1173. {
  1174. CheckInvariants("LokRefileDocs pre");
  1175. Win4Assert( 0 == _cRefiledDocs );
  1176. Win4Assert( docList.Count() <= CI_MAX_DOCS_IN_WORDLIST );
  1177. for ( unsigned i = 0 ; i < docList.Count(); i++ )
  1178. {
  1179. //
  1180. // If the document has already made into a wordlist, DON'T
  1181. // refile it. The current code has potential for infinite looping
  1182. // behavior. We must NEVER refile a "deleted" document. Consider
  1183. // the following sequence for a document
  1184. //
  1185. // ---------------------------------------------
  1186. // | chunk1 | chunk2 | refiled |
  1187. // ---------------------------------------------
  1188. // | D1 | U2 | ? |
  1189. // ---------------------------------------------
  1190. // The document got deleted and then recreated. If we refile D1
  1191. // as a deletion, the U2 will be superceded by the deletion.
  1192. // Instead, we will just mark the refiled deletion as an update.
  1193. // If the document is not recreated when we go to filter it,
  1194. // the "Wid->Path" will fail and will then be considered (correctly)
  1195. // as a deletion. O/W, we will filter it as an update.
  1196. //
  1197. _aRefiledDocs[_cRefiledDocs].Set( docList.Wid(i),
  1198. 0, // 0 usn for refiled docs
  1199. docList.VolumeId(i),
  1200. CI_UPDATE_OBJ,
  1201. docList.Retries(i),
  1202. docList.SecQRetries(i)
  1203. );
  1204. _cRefiledDocs++;
  1205. }
  1206. }
  1207. //+---------------------------------------------------------------------------
  1208. //
  1209. // Function: LokAppendRefiledDocs
  1210. //
  1211. // Synopsis: Appends the documents in the refiled set to the change list.
  1212. //
  1213. // Arguments: [xact] -- Transaction for this operation
  1214. //
  1215. // History: 10-24-94 srikants Created
  1216. //
  1217. //----------------------------------------------------------------------------
  1218. void CDocQueue::LokAppendRefiledDocs( CChangeTrans & xact )
  1219. {
  1220. CheckInvariants("LokAppendRefiledDocs pre");
  1221. //
  1222. // If the refiled doclist is not empty, we must append those
  1223. // documents.
  1224. //
  1225. const unsigned cDocsToRefile = _cRefiledDocs;
  1226. _cRefiledDocs = 0;
  1227. for ( unsigned i = 0; i < cDocsToRefile ; i++ )
  1228. {
  1229. const CDocNotification & docInfo = _aRefiledDocs[i];
  1230. ciDebugOut(( DEB_ITRACE,
  1231. "CDocQueue: Refiling WID: 0x%X Action: %d\n",
  1232. docInfo.Wid(),
  1233. docInfo.Action() ));
  1234. Win4Assert( docInfo.Usn() == 0 );
  1235. Append( xact,
  1236. docInfo.Wid(),
  1237. docInfo.Usn(),
  1238. docInfo.VolumeId(),
  1239. docInfo.Action(),
  1240. docInfo.Retries(),
  1241. docInfo.SecQRetries() );
  1242. }
  1243. }
  1244. //+---------------------------------------------------------------------------
  1245. //
  1246. // Member: CDocQueue::LokDisableUpdates
  1247. //
  1248. // Synopsis: Disables further updates
  1249. //
  1250. // History: 27-Dec-94 SrikantS Created
  1251. // 24-Feb-97 SitaramR Push filtering
  1252. //
  1253. //----------------------------------------------------------------------------
  1254. void CDocQueue::LokDisableUpdates()
  1255. {
  1256. if ( !_changeLog.FPushFiltering() )
  1257. {
  1258. //
  1259. // In pull (i.e. not push) filtering, clean up the in-memory datastructure
  1260. // because they will be re-notified by the client when updates are
  1261. // enabled
  1262. //
  1263. LokCleanup();
  1264. }
  1265. _changeLog.LokDisableUpdates();
  1266. }
  1267. //+---------------------------------------------------------------------------
  1268. //
  1269. // Member: CDocQueue::LokEnableUpdate
  1270. //
  1271. // Synopsis: Enables updates and change log processing.
  1272. //
  1273. // Arguments: [fFirstTimeUpdatesAreEnabled] -- Is this being called for the
  1274. // first time ?
  1275. //
  1276. // History: 27-Dec-94 SrikantS Created
  1277. // 24-Feb-97 SitaramR Push filtering
  1278. //
  1279. //----------------------------------------------------------------------------
  1280. void CDocQueue::LokEnableUpdates( BOOL fFirstTimeUpdatesAreEnabled )
  1281. {
  1282. _changeLog.LokEnableUpdates( fFirstTimeUpdatesAreEnabled );
  1283. if ( fFirstTimeUpdatesAreEnabled || !_changeLog.FPushFiltering() )
  1284. {
  1285. //
  1286. // In pull (i.e. not push) filtering, re-initialize the in-memory
  1287. // datastructure from the persistent changlog. Also, if EnableUpdates is
  1288. // being called for the first time, then initialize the in-memory
  1289. // datastructure (i.e. do it in the case of push filtering also).
  1290. //
  1291. LokInit();
  1292. }
  1293. }
  1294. //+---------------------------------------------------------------------------
  1295. //
  1296. // Member: CDocQueue::LokFlushUpdates
  1297. //
  1298. // Synopsis: Serializes the changlog
  1299. //
  1300. // History: 27-Jun-97 SitaramR Created
  1301. //
  1302. //----------------------------------------------------------------------------
  1303. void CDocQueue::LokFlushUpdates()
  1304. {
  1305. Serialize( _frmwrkParams.GetMaxQueueChunks() );
  1306. }