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.

856 lines
28 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1991 - 1998.
  5. //
  6. // File: CHANGLOG.CXX
  7. //
  8. // Contents: Methods to make DocQueue persistent
  9. //
  10. // Classes: CDocQueue
  11. //
  12. // History: 08-Feb-91 DwightKr Created
  13. // 24-Feb-97 SitaramR Push filtering
  14. //
  15. //----------------------------------------------------------------------------
  16. #include <pch.cxx>
  17. #pragma hdrstop
  18. #include <rcstxact.hxx>
  19. #include <rcstrmit.hxx>
  20. #include <pstore.hxx>
  21. #include <pfilter.hxx>
  22. #include <cifailte.hxx>
  23. #include <imprsnat.hxx>
  24. #include "changlog.hxx"
  25. #include "fresh.hxx"
  26. #include "resman.hxx"
  27. #include "notxact.hxx"
  28. //+---------------------------------------------------------------------------
  29. //
  30. // Function: CDocChunk::UpdateMaxUsn
  31. //
  32. // Synopsis: Updates the max usn flushed info
  33. //
  34. // Arguments: [aUsnFlushInfo] -- Array of usn info to be updated
  35. //
  36. // History: 05-07-97 SitaramR Created
  37. //
  38. //----------------------------------------------------------------------------
  39. void CDocChunk::UpdateMaxUsn( CCountedDynArray<CUsnFlushInfo> & aUsnFlushInfo )
  40. {
  41. for ( unsigned i=0;
  42. i<cDocInChunk && _aNotify[i].Wid() != widInvalid;
  43. i++ )
  44. {
  45. USN usn = _aNotify[i].Usn();
  46. VOLUMEID volumeId = _aNotify[i].VolumeId();
  47. if ( volumeId != CI_VOLID_USN_NOT_ENABLED && usn != 0 )
  48. {
  49. //
  50. // Usn flush info is needed only for ntfs 5 volumes that have a
  51. // non-default volume id. Also, a usn of 0 indicates a refiled
  52. // document and so it need not be processed.
  53. //
  54. BOOL fFound = FALSE;
  55. for ( unsigned j=0; j<aUsnFlushInfo.Count(); j++ )
  56. {
  57. if ( aUsnFlushInfo[j]->VolumeId() == volumeId )
  58. {
  59. //
  60. // Usn's need not be monotonic because there can be notifications from
  61. // different scopes on same usn volume
  62. //
  63. if ( usn > aUsnFlushInfo[j]->UsnHighest() )
  64. aUsnFlushInfo[j]->SetUsnHighest( usn );
  65. fFound = TRUE;
  66. }
  67. }
  68. if ( !fFound )
  69. {
  70. CUsnFlushInfo *pUsnInfo = new CUsnFlushInfo( volumeId, usn );
  71. XPtr<CUsnFlushInfo> xUsnInfo( pUsnInfo );
  72. aUsnFlushInfo.Add( pUsnInfo, aUsnFlushInfo.Count() );
  73. xUsnInfo.Acquire();
  74. }
  75. }
  76. }
  77. }
  78. //+---------------------------------------------------------------------------
  79. //
  80. // Function: AcquireAndAppend
  81. //
  82. // Synopsis: Acquire the chunks from the given "newList" and append these
  83. // chunks to the current list.
  84. //
  85. // Arguments: [newList] -- List to acquire from.
  86. //
  87. // History: 5-26-94 srikants Created
  88. //
  89. // Notes: The newList will be emptied.
  90. //
  91. //----------------------------------------------------------------------------
  92. void CChunkList::AcquireAndAppend( CChunkList & newList )
  93. {
  94. while ( !newList.IsEmpty() )
  95. {
  96. CDocChunk * pChunk = newList.Pop();
  97. Win4Assert( pChunk );
  98. Append( pChunk );
  99. }
  100. }
  101. //+---------------------------------------------------------------------------
  102. //
  103. // Function: Constructor
  104. //
  105. // Synopsis: Constructs the CChangeLog class by figuring out the number of
  106. // chunks present in the change log.
  107. //
  108. // Arguments: [widChangeLog] -- Workid of changlog
  109. // [storage] -- Storage
  110. // [type] -- Primary or secondary changlog type
  111. //
  112. // History: 5-26-94 srikants Created
  113. // 2-24-97 SitaramR Push filtering
  114. //
  115. //----------------------------------------------------------------------------
  116. CChangeLog::CChangeLog( WORKID widChangeLog,
  117. PStorage & storage,
  118. PStorage::EChangeLogType type )
  119. : _sigChangeLog(eSigChangeLog),
  120. _pResManager( 0 ),
  121. _widChangeLog(widChangeLog),
  122. _storage(storage),
  123. _type(type),
  124. _PersDocQueue(_storage.QueryChangeLog(_widChangeLog,type)),
  125. _oChunkToRead(0),
  126. _cChunksAvail(0),
  127. _cChunksTotal(0),
  128. _fUpdatesEnabled( FALSE ),
  129. _fPushFiltering( FALSE )
  130. {
  131. Win4Assert( IsPrimary() || IsSecondary() );
  132. }
  133. //+---------------------------------------------------------------------------
  134. //
  135. // Function: Destructor
  136. //
  137. // History: 8-Nov-94 DwightKr Created
  138. //
  139. //----------------------------------------------------------------------------
  140. CChangeLog::~CChangeLog()
  141. {
  142. }
  143. //+---------------------------------------------------------------------------
  144. //
  145. // Function: LokVerifyConsistency
  146. //
  147. // History: 12-15-94 srikants Created
  148. //
  149. //----------------------------------------------------------------------------
  150. #if CIDBG==1
  151. void CChangeLog::LokVerifyConsistency()
  152. {
  153. PRcovStorageObj & persDocQueue = *_PersDocQueue;
  154. CRcovStorageHdr & hdr = persDocQueue.GetHeader();
  155. Win4Assert( _cChunksAvail + _oChunkToRead == _cChunksTotal );
  156. ULONG ulDataSize = hdr.GetUserDataSize( hdr.GetPrimary() );
  157. ULONG cTotPrim = ulDataSize / (sizeof(CDocNotification) * cDocInChunk + CRcovStrmIter::SizeofChecksum());
  158. ULONG cPersTotalRec = hdr.GetCount( hdr.GetPrimary() );
  159. Win4Assert( cPersTotalRec == cTotPrim );
  160. Win4Assert( cPersTotalRec * (cDocInChunk * sizeof(CDocNotification) + CRcovStrmIter::SizeofChecksum()) == ulDataSize);
  161. Win4Assert((ulDataSize % (sizeof(CDocNotification) * cDocInChunk + CRcovStrmIter::SizeofChecksum())) == 0);
  162. ULONG cTotBackup = hdr.GetCount( hdr.GetBackup() );
  163. Win4Assert( 0 == _cChunksTotal || _cChunksTotal == cTotPrim );
  164. }
  165. #else
  166. inline void CChangeLog::LokVerifyConsistency(){}
  167. #endif
  168. //+---------------------------------------------------------------------------
  169. //
  170. // Function: LokEmpty, public
  171. //
  172. // Synopsis: Initializes the change log by empting it and setting status
  173. // to eCIDiskFullScan
  174. //
  175. // History: 15-Nov-94 DwightKr Created
  176. //
  177. //----------------------------------------------------------------------------
  178. void CChangeLog::LokEmpty()
  179. {
  180. CImpersonateSystem impersonate;
  181. PRcovStorageObj & persDocQueue = *_PersDocQueue;
  182. CRcovStrmWriteTrans xact( persDocQueue );
  183. persDocQueue.GetHeader().SetCount(persDocQueue.GetHeader().GetBackup(), 0);
  184. xact.Empty();
  185. xact.Commit();
  186. _oChunkToRead = 0;
  187. _cChunksAvail = 0;
  188. _cChunksTotal = 0;
  189. LokVerifyConsistency();
  190. }
  191. //+---------------------------------------------------------------------------
  192. //
  193. // Function: InitSize
  194. //
  195. // Synopsis: Initializes the size of the change log by reading in the
  196. // size information from the change log header.
  197. //
  198. // History: May-26-94 srikants Rewrite and move from CDocQueue
  199. // Nov-08-94 DwightKr Added dirty flag set on startup
  200. //
  201. //----------------------------------------------------------------------------
  202. void CChangeLog::InitSize()
  203. {
  204. ULONG ulDataSize = 0;
  205. //
  206. // Two copies of the content scan data must fit into the recoverable
  207. // stream header in the user-data section. Verify that we haven't
  208. // grown too large.
  209. //
  210. CImpersonateSystem impersonate;
  211. PRcovStorageObj & persDocQueue = *_PersDocQueue;
  212. CRcovStorageHdr & hdr = persDocQueue.GetHeader();
  213. persDocQueue.VerifyConsistency();
  214. //
  215. // Do a read transaction to complete any in-complete transactions.
  216. //
  217. {
  218. CRcovStrmReadTrans xact( persDocQueue );
  219. }
  220. //
  221. // Determine the # of records in the persistent log and do some
  222. // consistency checks.
  223. //
  224. ulDataSize = hdr.GetUserDataSize( hdr.GetPrimary() );
  225. ULONG cRecords = hdr.GetCount( hdr.GetPrimary() );
  226. ULONG cTotRecord = ulDataSize / (sizeof(CDocNotification) * cDocInChunk + CRcovStrmIter::SizeofChecksum());
  227. //
  228. // If the number of records in the file is not the same as the
  229. // number of records in the header, we have an inconsistancy.
  230. //
  231. if ( cRecords != cTotRecord )
  232. {
  233. Win4Assert( !"Corrupt changelog" );
  234. _storage.ReportCorruptComponent( L"ChangeLog2" );
  235. THROW( CException( CI_CORRUPT_DATABASE ) );
  236. }
  237. _oChunkToRead = 0;
  238. _cChunksAvail = cTotRecord;
  239. _cChunksTotal = _cChunksAvail;
  240. }
  241. //+---------------------------------------------------------------------------
  242. //
  243. // Function: DeSerialize
  244. //
  245. // Synopsis: Reads the specified number of chunks from the change log and
  246. // appends them to the list passed.
  247. //
  248. // Arguments: [list] -- List to append to.
  249. // [cChunksToRead] -- Number of chunks to read.
  250. //
  251. // Returns: Number of chunks read.
  252. //
  253. // History: 5-26-94 srikants Created
  254. //
  255. //----------------------------------------------------------------------------
  256. ULONG CChangeLog::DeSerialize( CChunkList & list, ULONG cChunksToRead )
  257. {
  258. CImpersonateSystem impersonate;
  259. CChunkList newChunks;
  260. Win4Assert( cChunksToRead <= _cChunksAvail );
  261. cChunksToRead = min (cChunksToRead, _cChunksAvail);
  262. PRcovStorageObj & persDocQueue = _PersDocQueue.Get();
  263. CRcovStorageHdr & hdr = persDocQueue.GetHeader();
  264. //
  265. // We seem to be losing writes for the header stream. Just check the
  266. // consistency before reading the data from disk.
  267. //
  268. LokVerifyConsistency();
  269. {
  270. // Begin transaction
  271. CRcovStrmReadTrans xact( persDocQueue );
  272. CRcovStrmReadIter iter( xact, cDocInChunk * sizeof(CDocNotification) );
  273. iter.Seek( _oChunkToRead );
  274. for ( unsigned i=0; i < cChunksToRead ; i++ )
  275. {
  276. CDocChunk *pChunk = new CDocChunk;
  277. iter.GetRec( pChunk->GetArray() );
  278. newChunks.Append(pChunk);
  279. }
  280. } // End-Transaction
  281. Win4Assert( newChunks.Count() == cChunksToRead );
  282. //
  283. // Acquire the newly created list and append it to the existing list.
  284. //
  285. list.AcquireAndAppend(newChunks);
  286. //
  287. // Update the internal state.
  288. //
  289. _oChunkToRead += cChunksToRead;
  290. _cChunksAvail -= cChunksToRead;
  291. if ( _cChunksAvail + _oChunkToRead != _cChunksTotal )
  292. {
  293. Win4Assert( ! "Data Corruption && ChangeLog::_cChunksAvail + _oChunktoRead != _cChunksTotal" );
  294. _storage.ReportCorruptComponent( L"ChangeLog3" );
  295. THROW( CException( CI_CORRUPT_DATABASE ) );
  296. }
  297. LokVerifyConsistency();
  298. return(cChunksToRead);
  299. }
  300. //+---------------------------------------------------------------------------
  301. //
  302. // Function: Serialize
  303. //
  304. // Synopsis: Serializes the given list of CDocChunks to the disk.
  305. //
  306. // Arguments: [listToSerialize] -- The list to be serialized
  307. // [aUsnFlushInfo] -- Usn flush info returned here
  308. //
  309. // Returns: Number of chunks serialized.
  310. //
  311. // History: 5-26-94 srikants Created
  312. //
  313. //----------------------------------------------------------------------------
  314. ULONG CChangeLog::Serialize( CChunkList & listToSerialize,
  315. CCountedDynArray<CUsnFlushInfo> & aUsnFlushInfo )
  316. {
  317. CImpersonateSystem impersonate;
  318. unsigned cRecords = 0;
  319. USN updateUSN = 0;
  320. CRcovStorageHdr & hdr = _PersDocQueue.Get().GetHeader();
  321. LokVerifyConsistency();
  322. {
  323. //
  324. // Begin Transaction
  325. //
  326. // STACKSTACK
  327. //
  328. XPtr<CRcovStrmAppendTrans> xTrans( new CRcovStrmAppendTrans( _PersDocQueue.Get() ) );
  329. CRcovStrmAppendIter iter( xTrans.GetReference(), cDocInChunk * sizeof(CDocNotification) );
  330. for ( CDocChunk * pChunk = listToSerialize.GetFirst() ;
  331. 0 != pChunk;
  332. pChunk = pChunk->GetNext() )
  333. {
  334. pChunk->UpdateMaxUsn( aUsnFlushInfo );
  335. iter.AppendRec( pChunk->GetArray() );
  336. cRecords++;
  337. }
  338. xTrans->Commit();
  339. } // EndTransaction
  340. ciDebugOut( (DEB_ITRACE, "SerializeRange: %d records serialized to disk\n", cRecords) );
  341. _cChunksAvail += cRecords;
  342. _cChunksTotal += cRecords;
  343. //
  344. // Extra level of consistency checking for the lengths and record
  345. // counts in the on-disk version vs. in-memory values.
  346. //
  347. ULONG ulDataSize = hdr.GetUserDataSize( hdr.GetPrimary() );
  348. ULONG cTotRecord = ulDataSize / (sizeof(CDocNotification) * cDocInChunk + CRcovStrmIter::SizeofChecksum());
  349. ULONG cRecCount = hdr.GetCount( hdr.GetPrimary() );
  350. if ( (cTotRecord != cRecCount) ||
  351. ((ulDataSize % (sizeof(CDocNotification) * cDocInChunk + CRcovStrmIter::SizeofChecksum())) != 0) ||
  352. (_cChunksTotal != cTotRecord) ||
  353. (_oChunkToRead + _cChunksAvail != cTotRecord) )
  354. {
  355. ciDebugOut(( DEB_ERROR,
  356. "cTotRecord %d, cRecCount %d, ulDataSize %d\n"
  357. "sizeof(CDocNotifications) %d, CRcovStrmIter::SizeofChecksum() %d\n"
  358. "cDocInChunk %d, _cChunksTotal %d, cTotRecord %d\n"
  359. "_oChunkToRead %d, _cChunksAvail %d\n",
  360. cTotRecord, cRecCount, ulDataSize,
  361. sizeof(CDocNotification), CRcovStrmIter::SizeofChecksum(),
  362. cDocInChunk, _cChunksTotal, cTotRecord,
  363. _oChunkToRead, _cChunksAvail ));
  364. Win4Assert( "Data Corruption" && cTotRecord == cRecCount);
  365. Win4Assert( "Data Corruption" && (ulDataSize % (sizeof(CDocNotification) * cDocInChunk + CRcovStrmIter::SizeofChecksum())) == 0);
  366. Win4Assert( "Data Corruption" && _cChunksTotal == cTotRecord );
  367. Win4Assert( "Data Corruption" && _oChunkToRead + _cChunksAvail == _cChunksTotal );
  368. _storage.ReportCorruptComponent( L"ChangeLog5" );
  369. THROW( CException( CI_CORRUPT_DATABASE ) );
  370. }
  371. ciDebugOut(( DEB_ITRACE,
  372. "Serialize: cRecords=%d ulDataSize/sizeof(record)=%d\n",
  373. cRecCount, cTotRecord ));
  374. return cRecords;
  375. } //Serialize
  376. //+---------------------------------------------------------------------------
  377. //
  378. // Function: LokDeleteWIDsInPersistentIndexes
  379. //
  380. // Synopsis: This method computes the number of chunks that can be
  381. // deleted from the front of the changelog and truncates the
  382. // log appropriately.
  383. //
  384. // All documents that have been filtered and successfully made
  385. // into a persistent index need not be filtered after restart.
  386. // This method iterates over the filtered chunks from the front
  387. // of the log and when it detects a document that has not yet
  388. // made it into a persistent index, it stops the iteration and
  389. // truncates the log upto such a chunk ( not including the chunk
  390. // that had a document in a volatile index ).
  391. //
  392. // Arguments: [cFilteredChunks] -- Number of chunks that have been
  393. // filtered.
  394. // [freshTestLatest] -- Latest freshTest
  395. // [freshTestAtMerge] -- Fresh test snapshoted at time of shadow
  396. // merge (can be same as freshTestLatest)
  397. // [docList] -- Resman's Doc list
  398. // [notifTrans] -- Notification transaction
  399. //
  400. // Returns: The number of chunks that have been truncated from the
  401. // front.
  402. //
  403. // History: 5-27-94 SrikantS Created
  404. // 2-24-97 SitaramR Push filtering
  405. //
  406. //----------------------------------------------------------------------------
  407. ULONG CChangeLog::LokDeleteWIDsInPersistentIndexes( ULONG cFilteredChunks,
  408. CFreshTest & freshTestLatest,
  409. CFreshTest & freshTestAtMerge,
  410. CDocList & docList,
  411. CNotificationTransaction & notifTrans )
  412. {
  413. CImpersonateSystem impersonate;
  414. //
  415. // Create the recoverable storage object.
  416. //
  417. PRcovStorageObj & persDocQueue = _PersDocQueue.Get();
  418. CRcovStorageHdr & hdr = persDocQueue.GetHeader();
  419. ULONG ulDataSize = hdr.GetUserDataSize( hdr.GetPrimary() );
  420. ULONG cTotRecord = 0;
  421. LokVerifyConsistency();
  422. #if CIDBG == 1
  423. ULONG cPersTotalRec = hdr.GetCount( hdr.GetPrimary() );
  424. Win4Assert( cPersTotalRec >= cFilteredChunks );
  425. #endif
  426. ULONG cRecord = 0;
  427. BOOL fDocInPersIndex = TRUE;
  428. { // Begin Transaction
  429. CRcovStrmReadTrans xact( persDocQueue );
  430. CRcovStrmReadIter iter( xact, cDocInChunk * sizeof(CDocNotification) );
  431. cTotRecord = iter.UserRecordCount( ulDataSize );
  432. CDocChunk Chunk;
  433. //
  434. // Determine the first chunk in the filtered set which has a document
  435. // that nas not made it to a persistent index.
  436. //
  437. while ( fDocInPersIndex && ( cRecord < cFilteredChunks ) )
  438. {
  439. //
  440. // Read the next chunk from the change log.
  441. //
  442. iter.GetRec( Chunk.GetArray() );
  443. //
  444. // Determine if all the documents in this chunk have made it to
  445. // persistent indexes or not.
  446. //
  447. for ( ULONG oRetrieve = 0; oRetrieve < cDocInChunk; oRetrieve++ )
  448. {
  449. CDocNotification * pRetrieve = Chunk.GetDoc(oRetrieve);
  450. WORKID wid = pRetrieve->Wid();
  451. USN usn = pRetrieve->Usn();
  452. if ( wid == widInvalid
  453. || ( _fPushFiltering && _pResManager->LokIsWidAborted( wid, usn ) ) )
  454. {
  455. //
  456. // An invalid wid means that the changlog did not have enough
  457. // entries to fill Chunk and hence the remaining entries were set
  458. // to widinvalid. AbortedWid means that the wid was
  459. // aborted during filtering and not refiled. Hence we don't
  460. // have to check whether this wid made it to the persistent index
  461. // or not.
  462. //
  463. continue;
  464. }
  465. if ( IsWidInDocList( wid, docList ) )
  466. {
  467. //
  468. // If the wid is in the doclist then it means that it
  469. // did not necessarily make it to the persistent index.
  470. //
  471. fDocInPersIndex = FALSE;
  472. break;
  473. }
  474. if ( pRetrieve->IsDeletion() )
  475. {
  476. //
  477. // For deletions, check if the wid is in iidDeleted using
  478. // freshTestAtMerge. iidDeleted is the index for both deletions
  479. // in wordlists and persistent indexes, and so by using the
  480. // frest test at merge we can be sure that we are doing the
  481. // proper check. Also, check if the wid is in iidInvalid,
  482. // because after a master merge all wids (even deleted ones)
  483. // will be in iidInvalid. Also, check if the wid is in a persistent
  484. // index. This is for the case of delete followed by an add of the
  485. // same wid. Note: since iidDeleted1, iidDeleted2, iidInvalid pass the
  486. // IsPersistent test, all the above tests can be simplified to just
  487. // checking for IsPersistent index.
  488. //
  489. INDEXID iid = freshTestAtMerge.Find( wid );
  490. CIndexId IndexID ( iid );
  491. if ( !IndexID.IsPersistent() )
  492. {
  493. fDocInPersIndex = FALSE;
  494. break;
  495. }
  496. }
  497. else
  498. {
  499. //
  500. // Add or modify case. We use frestTestLatest because if the
  501. // wid is in the wordlist and an earlier version of the same
  502. // wid in a persistent index, then we'll assume that the wid
  503. // has not yet made it to the persistent index. Master index
  504. // is iidinvalid, which is a persistent index.
  505. //
  506. INDEXID iid = freshTestLatest.Find( wid );
  507. if ( iid == iidDeleted1 || iid == iidDeleted2 )
  508. {
  509. //
  510. // An add/modify may actually be a deletion that was requeued as modify. For
  511. // deletions we should use freshTestAtMerge as described above.
  512. //
  513. iid = freshTestAtMerge.Find( wid );
  514. if ( iid != iidDeleted1 && iid != iidDeleted2 )
  515. {
  516. fDocInPersIndex = FALSE;
  517. break;
  518. }
  519. }
  520. else
  521. {
  522. CIndexId IndexID ( iid );
  523. if ( !IndexID.IsPersistent() )
  524. {
  525. //
  526. // Wid is in a wordlist
  527. //
  528. fDocInPersIndex = FALSE;
  529. break;
  530. }
  531. }
  532. } // if/else( pRetrieve->IsDeletion() )
  533. } // for loop
  534. if ( cDocInChunk == oRetrieve )
  535. {
  536. //
  537. // All the documents in this chunk are in persistent
  538. // indexes. These can be deleted from the change log,
  539. // and the documents are added to the commited list
  540. // used in the push/simple filtering model, or they are
  541. // added to the aborted list used in push/simple filtering
  542. // model.
  543. //
  544. Win4Assert( fDocInPersIndex );
  545. if ( _fPushFiltering )
  546. {
  547. for ( ULONG iDoc = 0; iDoc < cDocInChunk; iDoc++ )
  548. {
  549. CDocNotification * pDoc = Chunk.GetDoc(iDoc);
  550. if ( pDoc->Wid() != widInvalid )
  551. {
  552. //
  553. // An invalid wid means that the changlog did not have enough
  554. // entries to fill Chunk and hence the remaining entries were set
  555. // to widinvalid. Hence an invalid wid can be ignored.
  556. //
  557. if ( _pResManager->LokIsWidAborted( pDoc->Wid(), pDoc->Usn() ) )
  558. {
  559. //
  560. // Needs to be removed from the aborted wids list
  561. //
  562. notifTrans.RemoveAbortedWid( pDoc->Wid(), pDoc->Usn() );
  563. }
  564. else
  565. {
  566. //
  567. // Needs to be added to the committed wids list
  568. //
  569. notifTrans.AddCommittedWid( pDoc->Wid() );
  570. }
  571. }
  572. }
  573. }
  574. cRecord++;
  575. }
  576. } // while loop
  577. } // End transaction
  578. ciDebugOut( (DEB_ITRACE, "Truncating %d of %d record(s) from persistent changelog\n", cRecord, cTotRecord) );
  579. if (cRecord > 0)
  580. {
  581. //
  582. // Shrink the change log stream from the front by "cRecord" amount.
  583. //
  584. CRcovStrmMDTrans xact(
  585. persDocQueue,
  586. CRcovStrmMDTrans::mdopFrontShrink,
  587. cRecord * (cDocInChunk * sizeof(CDocNotification) + CRcovStrmIter::SizeofChecksum())
  588. );
  589. cTotRecord -= cRecord;
  590. hdr.SetCount( hdr.GetBackup(), cTotRecord);
  591. xact.Commit();
  592. //
  593. // Commit wids in push filtering model. This needs to be done after the CRcovSTrmMDTrans
  594. // because it should be done only if that transaction is successfully committed
  595. //
  596. notifTrans.Commit();
  597. }
  598. //
  599. // Update the internal state of offset.
  600. //
  601. Win4Assert( cRecord <= _oChunkToRead );
  602. _oChunkToRead -= cRecord;
  603. _cChunksTotal -= cRecord;
  604. LokVerifyConsistency();
  605. return(cRecord);
  606. }
  607. //+---------------------------------------------------------------------------
  608. //
  609. // Function: LokDisableUpdates
  610. //
  611. // Synopsis: Disable further updates to changelog
  612. //
  613. // History: 12-15-94 srikants Created
  614. // 2-24-97 SitaramR Push filtering
  615. //
  616. //----------------------------------------------------------------------------
  617. void CChangeLog::LokDisableUpdates()
  618. {
  619. _fUpdatesEnabled = FALSE;
  620. if ( !_fPushFiltering )
  621. {
  622. //
  623. // In pull (i.e. not push) filtering, reset the in-memory part of
  624. // changlog
  625. //
  626. _cChunksTotal = _cChunksAvail = _oChunkToRead = 0;
  627. LokVerifyConsistency();
  628. }
  629. }
  630. //+---------------------------------------------------------------------------
  631. //
  632. // Function: LokEnableUpdates
  633. //
  634. // Synopsis: Enables updates to changelog
  635. //
  636. // Arguments: [fFirstTimeUpdatesAreEnabled] -- Is this being called for the
  637. // first time ?
  638. //
  639. // History: 12-15-94 srikants Created
  640. // 2-24-97 SitaramR Push filtering
  641. //
  642. //----------------------------------------------------------------------------
  643. void CChangeLog::LokEnableUpdates( BOOL fFirstTimeUpdatesAreEnabled )
  644. {
  645. _fUpdatesEnabled = TRUE;
  646. if ( fFirstTimeUpdatesAreEnabled || !_fPushFiltering )
  647. {
  648. //
  649. // In pull (i.e. not push) filtering, initialize the in-memory part
  650. // of changlog. Also, if EnableUpdates is being called for the first time,
  651. // then initialize the in-memory datastructure (i.e. do the
  652. // initialization in the case of push filtering also).
  653. //
  654. InitSize();
  655. LokVerifyConsistency();
  656. }
  657. }
  658. //+---------------------------------------------------------------------------
  659. //
  660. // Function: SetResman
  661. //
  662. // Synopsis: Initializes ptr to resman
  663. //
  664. // Arguments: [pResManager] -- Resource manager
  665. // [fPushFiltering] -- Using push model of filtering ?
  666. //
  667. // History: 12-15-94 srikants Created
  668. //
  669. //----------------------------------------------------------------------------
  670. void CChangeLog::SetResMan( CResManager * pResManager, BOOL fPushFiltering )
  671. {
  672. _pResManager = pResManager;
  673. _fPushFiltering = fPushFiltering;
  674. if ( fPushFiltering )
  675. {
  676. //
  677. // In push filtering, nuke the changelog because on shutdown all
  678. // client notifications are aborted, and it's the clients
  679. // responsibility to re-notify us after startup
  680. //
  681. CImpersonateSystem impersonate;
  682. PRcovStorageObj & persDocQueue = *_PersDocQueue;
  683. CRcovStrmWriteTrans xact( persDocQueue );
  684. persDocQueue.GetHeader().SetCount(persDocQueue.GetHeader().GetBackup(), 0);
  685. xact.Empty();
  686. xact.Commit();
  687. Win4Assert( _oChunkToRead == 0 );
  688. Win4Assert( _cChunksAvail == 0 );
  689. Win4Assert( _cChunksTotal == 0 );
  690. }
  691. }
  692. //+---------------------------------------------------------------------------
  693. //
  694. // Function: IsWidInDocList
  695. //
  696. // Synopsis: Check if the given wid is in the doc list
  697. //
  698. // Arguments: [wid] -- Workid to check
  699. // [docList] -- Doclist
  700. //
  701. // History: 24-Feb-97 SitaramR Created
  702. //
  703. // Notes: Use simple sequential search because there are atmost 16
  704. // wids in docList
  705. //
  706. //----------------------------------------------------------------------------
  707. BOOL CChangeLog::IsWidInDocList( WORKID wid, CDocList & docList )
  708. {
  709. for ( unsigned i=0; i<docList.Count(); i++ )
  710. {
  711. if ( docList.Wid(i) == wid )
  712. return TRUE;
  713. }
  714. return FALSE;
  715. }