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.

5107 lines
150 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1991 - 2000.
  5. //
  6. // File: RESMAN.CXX
  7. //
  8. // Contents: Resource Manager
  9. //
  10. // Classes: CResManager
  11. //
  12. // History: 08-Apr-91 BartoszM Created
  13. // 4-Jan-95 BartoszM Separated Filter Manager
  14. // Jan-08-97 mohamedn CFwEventItem and CDmFwEventItem
  15. // 24-Feb-97 SitaramR Push filtering
  16. //
  17. //----------------------------------------------------------------------------
  18. #include <pch.cxx>
  19. #pragma hdrstop
  20. #include <cci.hxx>
  21. #include <xact.hxx>
  22. #include <pstore.hxx>
  23. #include <cifailte.hxx>
  24. #include <ciole.hxx>
  25. #include <regevent.hxx>
  26. #include <ciregkey.hxx>
  27. #include <eventlog.hxx>
  28. #include <cievtmsg.h>
  29. #include <cifrmcom.hxx>
  30. #include <fwevent.hxx>
  31. #include <pidmap.hxx>
  32. #include <identran.hxx>
  33. #include <psavtrak.hxx>
  34. #include "resman.hxx"
  35. #include "ci.hxx"
  36. #include "partn.hxx"
  37. #include "pindex.hxx"
  38. #include "mindex.hxx"
  39. #include "idxids.hxx"
  40. #include "indxact.hxx"
  41. #include "merge.hxx"
  42. #include "mmerglog.hxx"
  43. #include "pendcur.hxx"
  44. #include "fltstate.hxx"
  45. #include "idle.hxx"
  46. #include "notxact.hxx"
  47. #include "lowres.hxx"
  48. const ULONG lowDiskWaterMark = 3 * 512 * 1024; // 1.5 MB
  49. const ULONG highDiskWaterMark = lowDiskWaterMark + 512 * 1024; // 2.0 MB
  50. const ULONG minDiskFreeForMerge = lowDiskWaterMark;
  51. class CRevertBoolValue {
  52. public:
  53. CRevertBoolValue( BOOL & rfValue, BOOL fValue ) :
  54. _rfVal( rfValue ),
  55. _fRevert( TRUE )
  56. {
  57. Win4Assert( rfValue != fValue );
  58. _fPrevVal = _rfVal;
  59. _rfVal = fValue;
  60. }
  61. ~CRevertBoolValue()
  62. {
  63. if (_fRevert)
  64. _rfVal = _fPrevVal;
  65. }
  66. void Revert()
  67. {
  68. _rfVal = _fPrevVal;
  69. _fRevert = FALSE;
  70. }
  71. private:
  72. BOOL & _rfVal;
  73. BOOL _fPrevVal;
  74. BOOL _fRevert;
  75. };
  76. CMergeThreadKiller::CMergeThreadKiller( CResManager & resman )
  77. : _resman(resman), _fKill(TRUE)
  78. {
  79. }
  80. CMergeThreadKiller::~CMergeThreadKiller()
  81. {
  82. if ( _fKill )
  83. {
  84. _resman._fStopMerge = TRUE;
  85. _resman._thrMerge.Resume();
  86. _resman.StopMerges();
  87. }
  88. }
  89. //+---------------------------------------------------------------------------
  90. //
  91. // Class: CPendQueueTrans
  92. //
  93. // Purpose: Transaction for flushing the pending queue if there is a
  94. // failure while extracting entries out of the pending queue
  95. // and adding them to the changelog.
  96. //
  97. // History: 9-11-95 srikants Created
  98. //
  99. //----------------------------------------------------------------------------
  100. class CPendQueueTrans : public CTransaction
  101. {
  102. public:
  103. CPendQueueTrans( CPendingQueue & pendQueue ) : _pendQueue( pendQueue )
  104. {
  105. }
  106. ~CPendQueueTrans()
  107. {
  108. if ( CTransaction::XActAbort == _status )
  109. {
  110. CLock lock( _pendQueue.GetMutex() );
  111. _pendQueue.LokFlushCompletedEntries();
  112. }
  113. }
  114. private:
  115. CPendingQueue & _pendQueue;
  116. };
  117. //+---------------------------------------------------------------------------
  118. //
  119. // Member: CResManager::CResManager, public
  120. //
  121. // Arguments: [cat] -- catalog
  122. // [xact] -- transaction
  123. //
  124. // History: 08-Apr-91 BartoszM Created
  125. // Jan-07-96 mohamedn CFwEventItem
  126. //
  127. //----------------------------------------------------------------------------
  128. CResManager::CResManager(
  129. PStorage &storage,
  130. CCiFrameworkParams & params,
  131. ICiCDocStore * pDocStore,
  132. CI_STARTUP_INFO const & startupInfo,
  133. IPropertyMapper * pPropMapper,
  134. CTransaction& xact,
  135. XInterface<CIndexNotificationTable> & xIndexNotifTable )
  136. : _sigResman(eSigResman),
  137. _frmwrkParams( params ),
  138. _mergeTime(0),
  139. _storage ( storage ),
  140. _sKeyList(0),
  141. _idxTab( _storage.QueryIndexTable( xact ) ),
  142. _partList ( storage, *_idxTab, _sKeyList, xact, params ),
  143. _fresh ( storage, xact, _partList ),
  144. _partidToMerge ( partidInvalid ),
  145. _fStopMerge(FALSE),
  146. _pMerge(0),
  147. #pragma warning( disable : 4355 ) // this used in base initialization
  148. _thrMerge ( MergeThread, this, TRUE ), // create suspended
  149. _mergeKiller( *this ),
  150. #pragma warning( default : 4355 )
  151. _activeDeletedIndex( _idxTab->GetDeletedIndex() ),
  152. _cQuery(0),
  153. _cFilteredDocuments(0),
  154. _pBackupWorkItem(0),
  155. _isBeingEmptied(FALSE),
  156. _isLowOnDiskSpace(FALSE),
  157. _isDismounted(FALSE),
  158. _isOutOfDate(FALSE),
  159. _isCorrupt(FALSE),
  160. _fFirstTimeUpdatesAreEnabled( TRUE ),
  161. _fPushFiltering( FALSE ),
  162. _fFlushWorkerActive( FALSE ),
  163. _configFlags( startupInfo.startupFlags ),
  164. _xIndexNotifTable( xIndexNotifTable.Acquire() ),
  165. _dwFilteringState( 0 ),
  166. _pFilterAgent( 0 )
  167. {
  168. Win4Assert( 0 != pDocStore );
  169. //
  170. // Look for a resource monitor. If none exists, use the default.
  171. //
  172. _xLowResDefault.Set( new CLowRes(_frmwrkParams) );
  173. SCODE sc = pDocStore->QueryInterface( IID_ICiCResourceMonitor,
  174. _xLowRes.GetQIPointer() );
  175. if ( FAILED(sc) )
  176. {
  177. _xLowResDefault->AddRef();
  178. _xLowRes.Set( _xLowResDefault.GetPointer() );
  179. }
  180. //
  181. //
  182. // The presence or absence of an actual pointer in _xIndexNotifTable,
  183. // indicates whether the client has specified pull filtering or push
  184. // filtering.
  185. //
  186. _fPushFiltering = !_xIndexNotifTable.IsNull();
  187. //
  188. // Initialize the resman in all the partitions.
  189. //
  190. CPartIter iter;
  191. for ( iter.LokInit(_partList); !iter.LokAtEnd(); iter.LokAdvance(_partList))
  192. {
  193. CPartition * pPart = iter.LokGet();
  194. pPart->SetResMan( this, FPushFiltering() );
  195. }
  196. if ( _fPushFiltering )
  197. {
  198. //
  199. // In push filtering, an identity translator is used
  200. //
  201. CIdentityNameTranslator *pIdentityTrans = new CIdentityNameTranslator();
  202. sc = pIdentityTrans->QueryInterface( IID_ICiCDocNameToWorkidTranslator,
  203. _translator.GetQIPointer() );
  204. Win4Assert( SUCCEEDED( sc ) );
  205. _translator->Release(); // QI does an AddRef
  206. }
  207. else
  208. {
  209. //
  210. // In pull filtering, the client provides the translator, which may
  211. // be the Ex version.
  212. //
  213. sc = pDocStore->QueryInterface( IID_ICiCDocNameToWorkidTranslatorEx,
  214. _translator2.GetQIPointer() );
  215. if ( SUCCEEDED(sc) )
  216. sc = _translator2->QueryInterface( IID_ICiCDocNameToWorkidTranslator,
  217. _translator.GetQIPointer() );
  218. else
  219. sc = pDocStore->QueryInterface( IID_ICiCDocNameToWorkidTranslator,
  220. _translator.GetQIPointer() );
  221. }
  222. if ( S_OK != sc )
  223. THROW( CException(sc) );
  224. //
  225. // Create a workIdToDocName converter object.
  226. //
  227. _xWorkidToDocName.Set( new CWorkIdToDocName( _translator.GetPointer(), _translator2.GetPointer() ) );
  228. ICiCAdviseStatus * pAdviseStatus;
  229. sc = pDocStore->QueryInterface( IID_ICiCAdviseStatus,
  230. (void **) & pAdviseStatus );
  231. if ( S_OK != sc )
  232. THROW( CException(sc) );
  233. _adviseStatus.Set( pAdviseStatus );
  234. _prfCounter.SetAdviseStatus( pAdviseStatus );
  235. ICiCPropertyStorage * pPropStore;
  236. sc = pDocStore->QueryInterface( IID_ICiCPropertyStorage,
  237. (void **) & pPropStore );
  238. if ( S_OK != sc )
  239. THROW( CException(sc) );
  240. _propStore.Set( pPropStore );
  241. pDocStore->AddRef();
  242. _docStore.Set( pDocStore );
  243. pPropMapper->AddRef();
  244. _mapper.Set( pPropMapper );
  245. ULONG mergeTime = _frmwrkParams.GetMasterMergeTime();
  246. _mergeTime = CMasterMergePolicy::ComputeMidNightMergeTime(mergeTime);
  247. if ( -1 == _mergeTime )
  248. {
  249. CFwEventItem item(EVENTLOG_ERROR_TYPE,
  250. MSG_CI_BAD_SYSTEM_TIME,
  251. 0);
  252. item.ReportEvent( _adviseStatus.GetReference() );
  253. THROW( CException( STATUS_INVALID_PARAMETER ) );
  254. }
  255. //
  256. // Restore the information associated with any master merge that
  257. // was stopped when the drive was dismounted.
  258. //
  259. _partList.RestoreMMergeState(*this, _storage);
  260. _partIter.LokInit( _partList );
  261. _isLowOnDiskSpace = LokCheckIfDiskLow( *this,
  262. _storage,
  263. _isLowOnDiskSpace,
  264. _adviseStatus.GetReference() );
  265. _thrMerge.SetPriority ( _frmwrkParams.GetThreadPriorityMerge() );
  266. _mergeKiller.Defuse();
  267. _thrMerge.Resume();
  268. //
  269. // Set the merge progress indicator to 0, and refresh other counters
  270. //
  271. _prfCounter.Update( CI_PERF_MERGE_PROGRESS, 0 );
  272. LokUpdateCounters();
  273. //
  274. // Enable or disables updates/notifications based on disk space available
  275. // and whether the catalog is readonly
  276. //
  277. if ( _isLowOnDiskSpace || _storage.IsReadOnly() )
  278. {
  279. DisableUpdates( partidDefault );
  280. _state.LokSetState( eUpdatesDisabled );
  281. }
  282. else
  283. {
  284. EnableUpdates( partidDefault );
  285. SCODE sc = _docStore->EnableUpdates();
  286. if ( SUCCEEDED( sc ) )
  287. _state.LokSetState( eSteady );
  288. else
  289. _state.LokSetState( eUpdatesToBeEnabled );
  290. }
  291. }
  292. //+-------------------------------------------------------------------------
  293. //
  294. // Member: CResManager::~CResManager, public
  295. //
  296. // Synopsis: Shuts down merge(s)
  297. //
  298. // History: 13-Aug-93 KyleP Created
  299. //
  300. //--------------------------------------------------------------------------
  301. CResManager::~CResManager()
  302. {
  303. _workMan.AbortWorkItems();
  304. LokDeleteFlushWorkItems();
  305. _workMan.WaitForDeath();
  306. StopMerges();
  307. #if CIDBG==1
  308. // ======================================
  309. {
  310. CPriLock lock(_mutex);
  311. Win4Assert( 0 == _pBackupWorkItem );
  312. }
  313. // ======================================
  314. #endif // CIDBG==1
  315. }
  316. //+---------------------------------------------------------------------------
  317. //
  318. // Member: CResManager::MergeThread, public
  319. //
  320. // Synopsis: Entry point for the thread responsible
  321. // for asynchronous merges
  322. //
  323. // History: 05-Mar-92 BartoszM Created
  324. //
  325. //----------------------------------------------------------------------------
  326. DWORD WINAPI CResManager::MergeThread( void* self )
  327. {
  328. if ( !((CResManager*)self)->_fStopMerge )
  329. ((CResManager*)self)->DoMerges();
  330. return 0;
  331. }
  332. //==============
  333. // STATE CHANGES
  334. //==============
  335. //+---------------------------------------------------------------------------
  336. //
  337. // Function: Dismount
  338. //
  339. // Synopsis: Dismounts the catalog by stopping any in-progress merge
  340. // and also finishing off any pending writes ( eg. ChangeLog).
  341. //
  342. // History: 6-20-94 srikants Created
  343. //
  344. //----------------------------------------------------------------------------
  345. NTSTATUS CResManager::Dismount()
  346. {
  347. ciDebugOut(( DEB_ITRACE, "*** CI: Initiating DisMount ***\n" ));
  348. NTSTATUS status = STATUS_SUCCESS;
  349. TRY
  350. {
  351. //
  352. // Inform all the partitions to cleanup. We have to abort any
  353. // in-progress merges without having to take a lock. There could
  354. // be another thread (like the filter thread) with the lock doing
  355. // a long operation. In one case we had it trying to create a new
  356. // fresh test and the memory writer could not make any progress
  357. // because the merge was continuing to dirty the pages.
  358. //
  359. // There is no need to take a lock because the partitions are not
  360. // going away and the operation we are about to do is just turning
  361. // on a one-way flag.
  362. //
  363. {
  364. PARTITIONID partid = 1;
  365. CPartition* pPart = _partList.LokGetPartition ( partid );
  366. pPart->PrepareForCleanup();
  367. }
  368. //
  369. // Stop in progress merges.
  370. //
  371. StopMerges();
  372. //
  373. // Dismount each of the partitions.
  374. //
  375. // ================================================
  376. {
  377. CPriLock lock( _mutex );
  378. Win4Assert( !_isDismounted );
  379. _isDismounted = TRUE;
  380. CKeyList * pKeyList = _sKeyList.Acquire();
  381. delete pKeyList;
  382. CPartIter iter;
  383. for ( iter.LokInit(_partList); !iter.LokAtEnd(); iter.LokAdvance(_partList))
  384. {
  385. CPartition * pPart = iter.LokGet();
  386. // =======================================================
  387. CChangeTrans xact( *this, pPart );
  388. if ( STATUS_SUCCESS == pPart->LokDismount( xact ) )
  389. {
  390. xact.LokCommit();
  391. }
  392. //=========================================================
  393. }
  394. if ( _pBackupWorkItem )
  395. _pBackupWorkItem->GetSaveProgressTracker().SetAbort();
  396. }
  397. // ================================================
  398. _workMan.WaitForDeath();
  399. }
  400. CATCH( CException, e )
  401. {
  402. status = e.GetErrorCode();
  403. ciDebugOut(( DEB_ERROR,
  404. "ContentIndex Dismount Failed. Error Code 0x%X\n", status ));
  405. }
  406. END_CATCH
  407. ciDebugOut(( DEB_ITRACE, "*** CI: Completed DisMount ***\n" ));
  408. return status;
  409. }
  410. //+---------------------------------------------------------------------------
  411. //
  412. // Function: CResManager::Empty, public
  413. //
  414. // Synopsis: Releases resources associated with the resman object. This
  415. // includes all indexes, the persistent freshlog, the persistant
  416. // changelog, the freshtest, and the master merge log.
  417. //
  418. // History: 15-Aug-94 DwightKr Created
  419. //
  420. //----------------------------------------------------------------------------
  421. void CResManager::Empty()
  422. {
  423. CPriLock lock( _mutex );
  424. _isBeingEmptied = TRUE;
  425. //
  426. // Cancel any connections to the CI Filter service.
  427. //
  428. _pFilterAgent->LokCancel();
  429. //
  430. // Delete everything from the index table here first.
  431. //
  432. _idxTab->LokEmpty();
  433. //
  434. // If anything fails after this point, chkdsk /f or autochk will
  435. // release the disk storage associated with the leaked objects
  436. // since they are no longer part of the persistent index list.
  437. //
  438. //
  439. // For each partition, zombify all indexes.
  440. //
  441. CPartIter iter;
  442. for ( iter.LokInit(_partList); !iter.LokAtEnd(); iter.LokAdvance(_partList))
  443. {
  444. CPartition* pPart = iter.LokGet();
  445. //
  446. // Zombify all indexes in this partition, and delete them if their
  447. // ref-count is 0.
  448. //
  449. CIndex ** aIndex = 0;
  450. TRY
  451. {
  452. unsigned cIndex;
  453. aIndex = pPart->LokZombify( cIndex );
  454. ReleaseIndexes( cIndex, aIndex, NULL );
  455. }
  456. CATCH ( CException, e )
  457. {
  458. }
  459. END_CATCH
  460. delete [] aIndex;
  461. //
  462. // Delete the change log associated with this partition. These
  463. // routines do not throw exceptions.
  464. //
  465. WORKID widChangeLog = _partList.GetChangeLogObjectId( pPart->GetId() );
  466. if ( widChangeLog != widInvalid)
  467. _storage.RemoveObject( widChangeLog );
  468. WORKID widMMergeLog;
  469. WORKID widDummy;
  470. pPart->GetMMergeObjectIds( widMMergeLog, widDummy, widDummy );
  471. if ( widMMergeLog != widInvalid)
  472. _storage.RemoveObject( widMMergeLog );
  473. }
  474. _fresh.LokEmpty(); // Release storage associated with fresh test
  475. WORKID widFreshLog = _storage.GetSpecialItObjectId( itFreshLog );
  476. #ifdef KEYLIST_ENABLED
  477. WORKID widKeyList = _storage.GetSpecialItObjectId( itMMKeyList );
  478. #else
  479. WORKID widKeyList = widInvalid;
  480. #endif //
  481. WORKID widPhrLat = _storage.GetSpecialItObjectId( itPhraseLat );
  482. if ( widFreshLog != widInvalid)
  483. _storage.RemoveObject( widFreshLog );
  484. if ( widKeyList != widInvalid)
  485. _storage.RemoveObject( widKeyList );
  486. if ( widPhrLat != widInvalid)
  487. _storage.RemoveObject( widPhrLat );
  488. }
  489. //+---------------------------------------------------------------------------
  490. //
  491. // Function: StopCurrentMerge
  492. //
  493. // Synopsis: Aborts any in-progress merge.
  494. //
  495. // History: 5-04-94 srikants Created
  496. //
  497. //----------------------------------------------------------------------------
  498. NTSTATUS CResManager::StopCurrentMerge()
  499. {
  500. {
  501. CPriLock lock( _mutex );
  502. //
  503. // If we're doing a merge right now then kill it off.
  504. //
  505. if ( 0 != _pMerge )
  506. _pMerge->LokAbort();
  507. }
  508. return STATUS_SUCCESS;
  509. }
  510. //+---------------------------------------------------------------------------
  511. //
  512. // Member: CResManager::DisableUpdates, public
  513. //
  514. // Arguments: [partid] -- partition id
  515. //
  516. // History: 24-Dec-94 Anonymous Created
  517. //
  518. //----------------------------------------------------------------------------
  519. void CResManager::DisableUpdates( PARTITIONID partid )
  520. {
  521. CPriLock lock( _mutex );
  522. CPartition * pPart = _partList.LokGetPartition( partid );
  523. Win4Assert( 0 != pPart );
  524. pPart->LokDisableUpdates();
  525. }
  526. //+---------------------------------------------------------------------------
  527. //
  528. // Member: CResManager::EnableUpdates, public
  529. //
  530. // Arguments: [partid] -- partition id
  531. //
  532. // History: 24-Dec-94 Anonymous Created
  533. //
  534. //----------------------------------------------------------------------------
  535. void CResManager::EnableUpdates( PARTITIONID partid )
  536. {
  537. CPriLock lock( _mutex );
  538. CPartition * pPart = _partList.LokGetPartition( partid );
  539. Win4Assert( 0 != pPart );
  540. pPart->LokEnableUpdates( _fFirstTimeUpdatesAreEnabled );
  541. _fFirstTimeUpdatesAreEnabled = FALSE;
  542. }
  543. //+---------------------------------------------------------------------------
  544. //
  545. // Function: LokCheckIfDiskLow
  546. //
  547. // Synopsis: Checks if we are running low on free disk space. It has
  548. // a "LowWaterMark" and a "HighWaterMark".
  549. //
  550. // If current state is "not full", then it will check to
  551. // see if the free disk space is < the LowWaterMark.
  552. //
  553. // if current state is "full", then it will check to see if
  554. // the free disk space is < the HighWaterMark.
  555. //
  556. // The HighWaterMark is > the LowWaterMark to prevent hysterisis.
  557. //
  558. // Arguments: [resman] -- Resource manager
  559. // [storage] -- Storage object.
  560. // [fCurrent] -- Current state.
  561. // [adviseStatus] -- reference to ICiCAdviseStatus
  562. //
  563. // Returns: TRUE if we are running low on disk space.
  564. // FALSE otherwise.
  565. //
  566. // History: 10-11-94 srikants Created
  567. // Jan-07-96 mohamedn CFwEventItem
  568. //
  569. //----------------------------------------------------------------------------
  570. BOOL LokCheckIfDiskLow( CResManager & resman,
  571. PStorage & storage,
  572. BOOL fIsCurrentFull,
  573. ICiCAdviseStatus & adviseStatus )
  574. {
  575. BOOL fLowOnDisk = fIsCurrentFull;
  576. TRY
  577. {
  578. __int64 diskTotal, diskRemaining;
  579. storage.GetDiskSpace( diskTotal, diskRemaining );
  580. if ( !fIsCurrentFull )
  581. fLowOnDisk = diskRemaining < lowDiskWaterMark;
  582. else
  583. fLowOnDisk = diskRemaining < highDiskWaterMark;
  584. //
  585. // It is okay to read it without mutex as it is only a heuristic.
  586. //
  587. if ( fLowOnDisk && !fIsCurrentFull && !storage.IsReadOnly() )
  588. {
  589. ciDebugOut(( DEB_WARN, "****YOU ARE RUNNING LOW ON DISK SPACE****\n"));
  590. ciDebugOut(( DEB_WARN, "****PLEASE FREE UP SOME SPACE ****\n"));
  591. ULONG mbToFree = highDiskWaterMark/(1024*1024);
  592. ULONG mbIndex;
  593. resman.IndexSize( mbIndex );
  594. mbToFree = max( mbToFree, mbIndex );
  595. mbToFree = min( mbToFree, 50 ); // don't ask for more than 50 MB
  596. CFwEventItem item( EVENTLOG_AUDIT_FAILURE,
  597. MSG_CI_LOW_DISK_SPACE,
  598. 2);
  599. item.AddArg(storage.GetVolumeName() );
  600. item.AddArg(mbToFree);
  601. item.ReportEvent(adviseStatus);
  602. }
  603. else if ( fIsCurrentFull && !fLowOnDisk )
  604. {
  605. ciDebugOut(( DEB_WARN, "****DISK SPACE FREED UP ****\n"));
  606. }
  607. }
  608. CATCH( CException,e )
  609. {
  610. ciDebugOut(( DEB_ERROR,
  611. "Error 0x%X while getting disk space info\n",
  612. e.GetErrorCode() ));
  613. }
  614. END_CATCH
  615. return ( fLowOnDisk );
  616. }
  617. //+---------------------------------------------------------------------------
  618. //
  619. // Function: NoFailFreeResources
  620. //
  621. // Synopsis: deletes a big wordlist and schedules refiltering
  622. //
  623. // History: 6-Jan-95 BartoszM Created
  624. //
  625. //----------------------------------------------------------------------------
  626. void CResManager::NoFailFreeResources()
  627. {
  628. ciDebugOut(( DEB_WARN, "Running out of resources. " ));
  629. TRY
  630. {
  631. PARTITIONID partId = 1;
  632. CPriLock lock(_mutex);
  633. CPartition * pPart = LokGetPartition( partId );
  634. //
  635. // Before calling remove word list, we must append any refiled
  636. // documents to the doc queue. This is because, the docqueue
  637. // can handle only one set of refiled documents.
  638. //
  639. {
  640. // =========================================
  641. CChangeTrans xact( *this, pPart );
  642. pPart->LokAppendRefiledDocs( xact );
  643. xact.LokCommit();
  644. // =========================================
  645. }
  646. LokNoFailRemoveWordlist( pPart );
  647. }
  648. CATCH( CException, e )
  649. {
  650. }
  651. END_CATCH
  652. }
  653. //+-------------------------------------------------------------------------
  654. //
  655. // Member: CResManager::IsMemoryLow, private
  656. //
  657. // Returns: TRUE if we're in a low memory situation
  658. //
  659. // History: 10-May-93 AmyA Created from old DoUpdates
  660. // 3-May-96 dlee #if 0'ed it out because the memory
  661. // load # isn't reliable, and we've
  662. // got LOTS of other allocations anyway.
  663. // 05-Nov-97 KyleP New approach
  664. //
  665. //--------------------------------------------------------------------------
  666. BOOL CResManager::IsMemoryLow()
  667. {
  668. SCODE sc = _xLowRes->IsMemoryLow();
  669. if ( E_NOTIMPL == sc )
  670. sc = _xLowResDefault->IsMemoryLow();
  671. return ( S_OK == sc );
  672. }
  673. //+-------------------------------------------------------------------------
  674. //
  675. // Member: CResManager::IsIoHigh, private
  676. //
  677. // Returns: TRUE if the system is performing a 'lot' of I/O
  678. //
  679. // History: 10-Dec-97 KyleP Created
  680. //
  681. // Notes: This call takes time (~ 5 sec) to complete.
  682. //
  683. //--------------------------------------------------------------------------
  684. BOOL CResManager::IsIoHigh()
  685. {
  686. SCODE sc = _xLowRes->IsIoHigh( &_fStopMerge );
  687. if ( E_NOTIMPL == sc )
  688. sc = _xLowResDefault->IsIoHigh( &_fStopMerge );
  689. return ( S_OK == sc );
  690. }
  691. //+-------------------------------------------------------------------------
  692. //
  693. // Member: CResManager::IsBatteryLow, private
  694. //
  695. // Returns: TRUE if the system is running low on battery power.
  696. //
  697. // History: 16-Jul-98 KyleP Created
  698. //
  699. // Notes: By default, even 100% battery (as opposed to A/C) may be
  700. // considered low.
  701. //
  702. //--------------------------------------------------------------------------
  703. BOOL CResManager::IsBatteryLow()
  704. {
  705. SCODE sc = _xLowRes->IsBatteryLow();
  706. if ( E_NOTIMPL == sc )
  707. sc = _xLowResDefault->IsBatteryLow();
  708. return ( S_OK == sc );
  709. }
  710. //+-------------------------------------------------------------------------
  711. //
  712. // Member: CResManager::IsOnBatteryPower, private
  713. //
  714. // Returns: TRUE if the system is running on battery power.
  715. //
  716. // History: 01-Oct-00 dlee Created
  717. //
  718. //--------------------------------------------------------------------------
  719. BOOL CResManager::IsOnBatteryPower()
  720. {
  721. SCODE sc = _xLowRes->IsOnBatteryPower();
  722. if ( E_NOTIMPL == sc )
  723. sc = _xLowResDefault->IsOnBatteryPower();
  724. return ( S_OK == sc );
  725. } //IsOnBatteryPower
  726. //+-------------------------------------------------------------------------
  727. //
  728. // Member: CResManager::SampleUserActivity, private
  729. //
  730. // Returns: - nothing -
  731. //
  732. // History: 31 Jul 98 AlanW Created
  733. //
  734. //--------------------------------------------------------------------------
  735. void CResManager::SampleUserActivity()
  736. {
  737. SCODE sc = _xLowRes->SampleUserActivity();
  738. if ( E_NOTIMPL == sc )
  739. _xLowResDefault->SampleUserActivity();
  740. return;
  741. }
  742. //+-------------------------------------------------------------------------
  743. //
  744. // Member: CResManager::IsUserActive, private
  745. //
  746. // Arguments: [fCheckLongTerm] - TRUE if long-term activity should be checked.
  747. //
  748. // Returns: TRUE if the interactive user is using the keyboard or mouse
  749. //
  750. // History: 28 Jul 98 AlanW Created
  751. //
  752. //--------------------------------------------------------------------------
  753. BOOL CResManager::IsUserActive(BOOL fCheckLongTerm)
  754. {
  755. SCODE sc = _xLowRes->IsUserActive(fCheckLongTerm);
  756. if ( E_NOTIMPL == sc )
  757. sc = _xLowResDefault->IsUserActive(fCheckLongTerm);
  758. return ( S_OK == sc );
  759. }
  760. //======================
  761. // STATE AND STATISTICS
  762. //======================
  763. //+-------------------------------------------------------------------------
  764. //
  765. // Member: CResManager::CountPendingUpdates, public
  766. //
  767. // Arguments: [secCount (output)] -- Count of secondary Q Updates
  768. //
  769. // Returns: Count of pending updates.
  770. //
  771. // History: 14-Dec-92 KyleP Created
  772. //
  773. // Notes: If wordlists are being constructed the count may be low.
  774. //
  775. //--------------------------------------------------------------------------
  776. unsigned CResManager::CountPendingUpdates(unsigned& secCount)
  777. {
  778. CPriLock lock( _mutex );
  779. unsigned count = 0;
  780. CPartIter iter;
  781. secCount = 0;
  782. for ( iter.LokInit(_partList); !iter.LokAtEnd(); iter.LokAdvance(_partList))
  783. {
  784. count += iter.LokGet()->LokCountUpdates();
  785. secCount += iter.LokGet()->LokCountSecUpdates();
  786. }
  787. return(count + secCount);
  788. }
  789. //+-------------------------------------------------------------------------
  790. //
  791. // Member: CResManager::UpdateCounters, public
  792. //
  793. // Returns: Updates performance counters.
  794. //
  795. // History: 05-Jan-95 BartoszM Created
  796. //
  797. //--------------------------------------------------------------------------
  798. void CResManager::LokUpdateCounters()
  799. {
  800. if ( !_isDismounted )
  801. {
  802. _prfCounter.Update( CI_PERF_NUM_WORDLIST, _partList.LokWlCount() );
  803. unsigned cSecQDocuments;
  804. unsigned cUnfilteredDocs = CountPendingUpdates( cSecQDocuments );
  805. _prfCounter.Update( CI_PERF_FILES_TO_BE_FILTERED, cUnfilteredDocs );
  806. _prfCounter.Update( CI_PERF_DEFERRED_FILTER_FILES, cSecQDocuments );
  807. _prfCounter.Update( CI_PERF_NUM_UNIQUE_KEY, _sKeyList->MaxKeyIdInUse() );
  808. _prfCounter.Update( CI_PERF_DOCUMENTS_FILTERED, _cFilteredDocuments );
  809. ULONG cDocuments;
  810. GetClientState( cDocuments );
  811. _prfCounter.Update( CI_PERF_NUM_DOCUMENTS, cDocuments );
  812. }
  813. }
  814. //====================
  815. // UPDATES AND QUERIES
  816. //====================
  817. //+---------------------------------------------------------------------------
  818. //
  819. // Member: CResManager::ReserveUpdate, public
  820. //
  821. // Arguments: [wid] -- Used to confirm hint.
  822. //
  823. // Returns: Hint to position of reserved slot.
  824. //
  825. // History: 30-Aug-95 KyleP Created
  826. //
  827. //----------------------------------------------------------------------------
  828. unsigned CResManager::ReserveUpdate( WORKID wid )
  829. {
  830. CPriLock lock ( _pendQueue.GetMutex() );
  831. return _pendQueue.LokPrepare( wid );
  832. }
  833. //+---------------------------------------------------------------------------
  834. //
  835. // Member: CResManager::UpdateDocument, public
  836. //
  837. // Arguments: [iHint] -- Positional hint
  838. // [wid] -- wid to add/delete
  839. // [partid] -- partition containing this wid
  840. // [usn] -- USN associated with change
  841. // [volumeId] -- Volume Id
  842. // [action] -- addition / deletion
  843. //
  844. // History: 08-Apr-91 BartoszM Created
  845. // 08-Oct-93 BartoszM Rewrote to accept single document
  846. // 30-Aug-95 KyleP Use reserved slots
  847. //
  848. //----------------------------------------------------------------------------
  849. SCODE CResManager::UpdateDocument( unsigned iHint,
  850. WORKID wid,
  851. PARTITIONID partid,
  852. USN usn,
  853. VOLUMEID volumeId,
  854. ULONG action )
  855. {
  856. if ( !IsIndexingEnabled() )
  857. return CI_E_FILTERING_DISABLED;
  858. Win4Assert ( partid == 1 );
  859. //
  860. // Try to avoid lock contention
  861. // with filter agent
  862. //
  863. _pFilterAgent->SlowDown();
  864. CPriLock lock ( _mutex );
  865. BOOL fComplete;
  866. {
  867. CPriLock lock2( _pendQueue.GetMutex() );
  868. if ( _isBeingEmptied ) // The content index is empty
  869. {
  870. //
  871. // Just get rid of any pending entries in the queue.
  872. //
  873. if ( !_pendQueue.LokComplete( iHint, wid, usn, volumeId, partid, action ) )
  874. {
  875. while ( _pendQueue.LokRemove( wid, usn, volumeId, partid, action ) )
  876. ;
  877. }
  878. return CI_E_SHUTDOWN;
  879. }
  880. //
  881. // The if clause triggers when this document is the only one
  882. // on the queue.
  883. //
  884. fComplete = _pendQueue.LokComplete( iHint, wid, usn, volumeId, partid, action );
  885. }
  886. SCODE sc = S_OK;
  887. if ( fComplete )
  888. {
  889. CPartition* pPart = _partList.LokGetPartition ( partid );
  890. CChangeTrans xact( *this, pPart );
  891. sc = pPart->LokUpdateDocument ( xact, wid, usn, volumeId, action, 1, 0 );
  892. xact.LokCommit();
  893. _pFilterAgent->LokWakeUp();
  894. }
  895. else
  896. {
  897. BOOL fGotOne = FALSE;
  898. CPendQueueTrans pendQueueTrans( _pendQueue );
  899. while ( TRUE )
  900. {
  901. BOOL fGotAnother;
  902. {
  903. CLock lock2( _pendQueue.GetMutex() );
  904. fGotAnother = _pendQueue.LokRemove( wid, usn, volumeId, partid, action );
  905. }
  906. if ( fGotAnother )
  907. {
  908. fGotOne = TRUE;
  909. CPartition* pPart = _partList.LokGetPartition ( partid );
  910. CChangeTrans xact( *this, pPart );
  911. sc = pPart->LokUpdateDocument ( xact, wid, usn, volumeId, action, 1, 0 );
  912. xact.LokCommit();
  913. }
  914. else
  915. break;
  916. }
  917. pendQueueTrans.Commit();
  918. if ( fGotOne )
  919. _pFilterAgent->LokWakeUp();
  920. }
  921. return sc;
  922. }
  923. //+---------------------------------------------------------------------------
  924. //
  925. // Member: CResManager::FlushUpdates
  926. //
  927. // Synopsis: Flushes all update notifications to disk
  928. //
  929. // History: 27-Jun-97 SitaramR Created
  930. //
  931. //----------------------------------------------------------------------------
  932. void CResManager::FlushUpdates()
  933. {
  934. CPriLock lock( _mutex );
  935. CPartition * pPart = _partList.LokGetPartition( partidDefault );
  936. Win4Assert( 0 != pPart );
  937. pPart->LokFlushUpdates();
  938. }
  939. //+---------------------------------------------------------------------------
  940. //
  941. // Member: CResManager::QueryIndexes, public
  942. //
  943. // Arguments: [cPartitions] -- count of partitions
  944. // [aPartID] -- array of partition id's
  945. // [freshTest] -- return arg.: fresh test
  946. // [cInd] -- return arg: count of indexes
  947. // [cPendingUpdates] -- Pending update 'threshold'. If fewer
  948. // pending updates, the pending wids are
  949. // returned in *pcurPending.
  950. // [pcurPending] -- Pending cursors stored here.
  951. // [pFlags] -- return arg: status of indexes
  952. //
  953. // Returns: Array of pointers to indexes
  954. //
  955. // History: 08-Oct-91 BartoszM Created
  956. //
  957. // Notes: Called by Query
  958. // Indexes and fresh test have ref count increased
  959. // Flags may change to indicate status of indexes
  960. //
  961. //----------------------------------------------------------------------------
  962. CIndex** CResManager::QueryIndexes (
  963. unsigned cPartitions,
  964. PARTITIONID aPartID[],
  965. CFreshTest** freshTest,
  966. unsigned& cInd,
  967. ULONG cPendingUpdates,
  968. CCurStack * pcurPending,
  969. ULONG* pFlags )
  970. {
  971. unsigned count = 0;
  972. CPartition* pPart;
  973. CPriLock lock ( _mutex );
  974. if ( _isCorrupt )
  975. THROW( CException( CI_CORRUPT_DATABASE ) );
  976. if ( _isBeingEmptied ) // Content index is empty or corrupt
  977. {
  978. cInd = 0;
  979. cPartitions = 0;
  980. return 0;
  981. }
  982. for ( unsigned i = 0; i < cPartitions; i++ )
  983. {
  984. pPart = _partList.LokGetPartition( aPartID [i] );
  985. count += pPart->LokIndexCount();
  986. }
  987. XArray<CIndex *> apIndex( count );
  988. #if CIDBG || DBG
  989. unsigned j = 0;
  990. #endif
  991. for ( i = 0; i < cPartitions; i++ )
  992. {
  993. pPart = _partList.LokGetPartition(aPartID [i]);
  994. #if CIDBG || DBG
  995. j +=
  996. #endif // CIDBG || DBG
  997. pPart->LokGetIndexes ( &apIndex[i] );
  998. if ( LokIsScanNeeded() && !_storage.IsReadOnly() )
  999. *pFlags |= CI_NOT_UP_TO_DATE;
  1000. //
  1001. // If we're looking for pending updates, get them. Otherwise just
  1002. // set the out-of-date flag.
  1003. //
  1004. unsigned cPending = pPart->LokCountUpdates();
  1005. cPending += pPart->LokCountSecUpdates();
  1006. if ( cPending != 0 )
  1007. {
  1008. ULONG fFlags = CI_NOT_UP_TO_DATE; // assume non-success
  1009. if ( cPendingUpdates > 0 )
  1010. {
  1011. Win4Assert( 0 != pcurPending );
  1012. if ( cPending <= cPendingUpdates )
  1013. {
  1014. XArray<WORKID> pWid( cPending );
  1015. BOOL fSucceeded = pPart->LokGetPendingUpdates(
  1016. pWid.GetPointer(),
  1017. cPending );
  1018. if ( fSucceeded )
  1019. {
  1020. Win4Assert( cPending > 0 );
  1021. XPtr<CPendingCursor> xCursor( new CPendingCursor( pWid, cPending ) );
  1022. pcurPending->Push( xCursor.GetPointer() );
  1023. xCursor.Acquire();
  1024. fFlags = 0;
  1025. }
  1026. }
  1027. }
  1028. *pFlags |= fFlags;
  1029. }
  1030. }
  1031. //
  1032. // Also check to see if we are actually in the process of filtering some
  1033. // documents.
  1034. //
  1035. if ( _docList.Count() > 0 )
  1036. {
  1037. if ( _docList.Count() <= cPendingUpdates )
  1038. {
  1039. Win4Assert( 0 != pcurPending );
  1040. XArray<WORKID> pWid( _docList.Count() );
  1041. ciDebugOut((DEB_FILTERWIDS,
  1042. "CResManager::QueryIndexes - pending documents: %d %x\n",
  1043. _docList.Count(), pWid.GetPointer()));
  1044. _docList.LokGetWids( pWid );
  1045. XPtr<CPendingCursor> xCursor( new CPendingCursor( pWid, _docList.Count() ) );
  1046. pcurPending->Push( xCursor.GetPointer() );
  1047. xCursor.Acquire();
  1048. }
  1049. else
  1050. *pFlags |= CI_NOT_UP_TO_DATE;
  1051. }
  1052. //
  1053. // Also check documents pending notifcation that may be complete but
  1054. // out-of-order.
  1055. //
  1056. {
  1057. CPriLock lock( _pendQueue.GetMutex() );
  1058. unsigned cwidPending = _pendQueue.LokCountCompleted();
  1059. if ( cwidPending > 0 )
  1060. {
  1061. if ( cwidPending <= cPendingUpdates )
  1062. {
  1063. Win4Assert( 0 != pcurPending );
  1064. XArray<WORKID> pWid( cwidPending );
  1065. _pendQueue.LokGetCompleted( pWid.GetPointer() );
  1066. XPtr<CPendingCursor> xCursor( new CPendingCursor( pWid, cwidPending ) );
  1067. pcurPending->Push( xCursor.GetPointer() );
  1068. xCursor.Acquire();
  1069. }
  1070. else
  1071. *pFlags |= CI_NOT_UP_TO_DATE;
  1072. }
  1073. }
  1074. //
  1075. // Finally, check for pending scans.
  1076. //
  1077. if ( _isOutOfDate )
  1078. *pFlags |= CI_NOT_UP_TO_DATE;
  1079. Win4Assert ( j == count );
  1080. *freshTest = _fresh.LokGetFreshTest();
  1081. cInd = count;
  1082. return apIndex.Acquire();
  1083. }
  1084. //+---------------------------------------------------------------------------
  1085. //
  1086. // Member: CResManager::ReleaseIndexes, public
  1087. //
  1088. // Synopsis: Decrements ref counts, deletes if indexes
  1089. // marked to be deleted.
  1090. //
  1091. // Arguments: [cInd] -- count of indexes
  1092. // [apIndex] -- array of indexes
  1093. // [freshTest] -- fresh test
  1094. //
  1095. // History: 08-Oct-91 BartoszM Created
  1096. //
  1097. // Notes: Takes ResMan lock
  1098. //
  1099. //----------------------------------------------------------------------------
  1100. void CResManager::ReleaseIndexes ( unsigned cInd, CIndex** apIndex,
  1101. CFreshTest* pFreshTest )
  1102. {
  1103. ciDebugOut (( DEB_ITRACE, "Release Indexes\n" ));
  1104. CPriLock lock ( _mutex );
  1105. for ( unsigned i = 0; i < cInd; i++ )
  1106. {
  1107. if ( apIndex[i] != 0 )
  1108. LokReleaseIndex ( apIndex[i] );
  1109. }
  1110. if ( pFreshTest)
  1111. _fresh.LokReleaseFreshTest (pFreshTest);
  1112. }
  1113. //+---------------------------------------------------------------------------
  1114. //
  1115. // Member: CResManager::BackupContentIndexData
  1116. //
  1117. // Synopsis: Private method called by the merge thread to backup the
  1118. // content index data. If successful, it sets the status of
  1119. // the backup work item to indicate success. Otherwise, it
  1120. // must be considered to have failed.
  1121. //
  1122. // History: 3-18-97 srikants Created
  1123. //
  1124. //----------------------------------------------------------------------------
  1125. void CResManager::BackupContentIndexData()
  1126. {
  1127. Win4Assert( 0 != _pBackupWorkItem );
  1128. ciDebugOut(( DEB_WARN, "Starting Backup of Ci Data\n" ));
  1129. //
  1130. // Create the backup object.
  1131. //
  1132. CPartition *pPartition =_partList.LokGetPartition ( partidDefault );
  1133. CBackupCiPersData backup( *_pBackupWorkItem,
  1134. *this,
  1135. *pPartition );
  1136. // =========================================
  1137. {
  1138. CPriLock lock(_mutex);
  1139. backup.LokGrabResources();
  1140. }
  1141. // =========================================
  1142. backup.BackupIndexes();
  1143. // =========================================
  1144. {
  1145. CPriLock lock(_mutex);
  1146. backup.LokBackupMetaInfo();
  1147. ciDebugOut(( DEB_WARN, "Completed Backup of Ci Data\n" ));
  1148. _pBackupWorkItem->LokSetStatus( STATUS_SUCCESS );
  1149. }
  1150. // =========================================
  1151. }
  1152. //+---------------------------------------------------------------------------
  1153. //
  1154. // Member: CResManager::LokUpdateBackupMergeProgress
  1155. //
  1156. // Synopsis: Updates the backup progress during the merge.
  1157. //
  1158. // History: 3-20-97 srikants Created
  1159. //
  1160. //----------------------------------------------------------------------------
  1161. void CResManager::LokUpdateBackupMergeProgress()
  1162. {
  1163. Win4Assert( 0 != _pBackupWorkItem );
  1164. CCiFrmPerfCounter counter( _adviseStatus.GetPointer(),
  1165. CI_PERF_MERGE_PROGRESS );
  1166. DWORD dwMergeProgress = counter.GetCurrValue();
  1167. //
  1168. // Assuming Merge is half of the work, we will assume half
  1169. // progress. So make the denominator 200 instead of 100.
  1170. //
  1171. if ( _pMerge )
  1172. {
  1173. const cShadowMergePart = 5;
  1174. if ( _pBackupWorkItem->IsFullSave() )
  1175. {
  1176. if ( _pMerge->GetMergeType() != mtMaster )
  1177. {
  1178. //
  1179. // The shadow merge preceding a master is approx. 5%
  1180. // say.
  1181. //
  1182. dwMergeProgress = cShadowMergePart;
  1183. }
  1184. else
  1185. {
  1186. dwMergeProgress = min(dwMergeProgress + cShadowMergePart, 100);
  1187. }
  1188. }
  1189. _pBackupWorkItem->LokUpdateMergeProgress( (ULONG) dwMergeProgress, 100 );
  1190. }
  1191. }
  1192. //+---------------------------------------------------------------------------
  1193. //
  1194. // Member: CResManager::BackupCIData
  1195. //
  1196. // Synopsis: External method to backup content index data. It creates
  1197. // a backup work item and waits for the backup to complete.
  1198. //
  1199. // Arguments: [storage] - Destination storage
  1200. // [fFull] - [in/out] Set to TRUE if a full merge is
  1201. // needed on input; On output will be set to TRUE if a full
  1202. // merge was done.
  1203. // [progressTracker] - Progress tracker.
  1204. //
  1205. // History: 3-18-97 srikants Created
  1206. //
  1207. //----------------------------------------------------------------------------
  1208. SCODE CResManager::BackupCIData( PStorage & storage,
  1209. BOOL & fFull,
  1210. XInterface<ICiEnumWorkids> & xEnumWorkids,
  1211. PSaveProgressTracker & progressTracker )
  1212. {
  1213. if ( !IsIndexMigrationEnabled() || !IsIndexingEnabled() )
  1214. return CI_E_INVALID_STATE;
  1215. SCODE sc = S_OK;
  1216. Win4Assert( fFull );
  1217. TRY
  1218. {
  1219. // ===================================================
  1220. {
  1221. CLock lock(_mutex);
  1222. if ( _isDismounted )
  1223. THROW( CException( CI_E_SHUTDOWN ) );
  1224. // There can be only one operation going on at a time.
  1225. if ( 0 != _pBackupWorkItem )
  1226. THROW( CException( CI_E_INVALID_STATE ) );
  1227. _pBackupWorkItem = new CBackupCiWorkItem( storage,
  1228. fFull,
  1229. progressTracker );
  1230. _eventMerge.Set();
  1231. }
  1232. // ===================================================
  1233. ciDebugOut(( DEB_WARN, "Waiting for backup to complete\n" )) ;
  1234. //
  1235. // Wait for the work-item to be completed.
  1236. //
  1237. while ( TRUE )
  1238. {
  1239. DWORD const dwWaitTime = 1 * 60 * 1000; // 1 minute in millisecs
  1240. _pBackupWorkItem->WaitForCompletion( dwWaitTime );
  1241. //============================================================
  1242. {
  1243. CPriLock lock(_mutex);
  1244. if ( _pBackupWorkItem->LokIsDone() )
  1245. break;
  1246. //
  1247. // If there is a merge going on, we must update the progress.
  1248. //
  1249. if ( _pBackupWorkItem->LokIsDoingMerge() )
  1250. LokUpdateBackupMergeProgress();
  1251. _pBackupWorkItem->LokReset();
  1252. }
  1253. //============================================================
  1254. } // of while
  1255. sc= _pBackupWorkItem->GetStatus();
  1256. ciDebugOut(( DEB_WARN, "Backup completed with code 0x%X\n", sc ));
  1257. if ( S_OK == sc )
  1258. {
  1259. fFull = _pBackupWorkItem->IsFullSave();
  1260. xEnumWorkids.Set( _pBackupWorkItem->AcquireWorkIdEnum() );
  1261. }
  1262. // ====================================
  1263. {
  1264. CLock lock(_mutex);
  1265. delete _pBackupWorkItem;
  1266. _pBackupWorkItem = 0;
  1267. }
  1268. // ====================================
  1269. }
  1270. CATCH( CException,e )
  1271. {
  1272. sc = HRESULT_FROM_WIN32( e.GetErrorCode() );
  1273. Win4Assert( !"How Did we Come Here" );
  1274. }
  1275. END_CATCH
  1276. return sc;
  1277. }
  1278. //+---------------------------------------------------------------------------
  1279. //
  1280. // Member: CResManager::CiState, public
  1281. //
  1282. // Arguments: [state] -- internal state of the CI
  1283. //
  1284. // History: 01-Nov-95 DwightKr Created
  1285. //
  1286. //
  1287. //----------------------------------------------------------------------------
  1288. #define setState( field, value ) \
  1289. if ( state.cbStruct >= ( offsetof( CIF_STATE, field) + \
  1290. sizeof( state.field ) ) ) \
  1291. { \
  1292. state.field = ( value ); \
  1293. }
  1294. #define roundup(a, b) ((a%b) ? (a/b + 1) : (a/b))
  1295. NTSTATUS CResManager::CiState(CIF_STATE & state)
  1296. {
  1297. CPriLock lock( _mutex );
  1298. if ( _isDismounted )
  1299. return CI_E_SHUTDOWN;
  1300. if ( _isCorrupt )
  1301. return CI_CORRUPT_DATABASE;
  1302. setState( cWordList, _partList.LokWlCount() );
  1303. setState( cPersistentIndex, _partList.LokIndexCount() - state.cWordList );
  1304. // Get the perf counter for the # of queries executed
  1305. Win4Assert( !_adviseStatus.IsNull() );
  1306. long cQ;
  1307. _adviseStatus->GetPerfCounterValue( CI_PERF_TOTAL_QUERIES, &cQ );
  1308. setState( cQueries, cQ );
  1309. unsigned cSecQDocuments;
  1310. ULONG cUnfilteredDocs = CountPendingUpdates(cSecQDocuments) + _docList.Count();
  1311. setState( cDocuments, cUnfilteredDocs );
  1312. setState( cSecQDocuments, cSecQDocuments );
  1313. setState( cFreshTest, LokGetFreshCount() );
  1314. CCiFrmPerfCounter counter( _adviseStatus.GetPointer(),
  1315. CI_PERF_MERGE_PROGRESS );
  1316. setState( dwMergeProgress, (ULONG) counter.GetCurrValue() );
  1317. setState( cFilteredDocuments, _cFilteredDocuments );
  1318. unsigned size = roundup(_partList.LokIndexSize(), ((1024*1024)/CI_PAGE_SIZE));
  1319. setState( dwIndexSize, size);
  1320. setState( cUniqueKeys, _sKeyList->MaxKeyIdInUse() );
  1321. state.cbStruct = min( state.cbStruct, sizeof(state) );
  1322. DWORD eCiState = _dwFilteringState;
  1323. //
  1324. // Set each of the state bits independently.
  1325. //
  1326. //
  1327. // Are we in a shadow or master merge?
  1328. //
  1329. if ( 0 != _pMerge )
  1330. {
  1331. switch (_pMerge->GetMergeType() )
  1332. {
  1333. case mtShadow:
  1334. eCiState |= CIF_STATE_SHADOW_MERGE;
  1335. break;
  1336. case mtAnnealing:
  1337. eCiState |= CIF_STATE_ANNEALING_MERGE;
  1338. break;
  1339. case mtIncrBackup:
  1340. eCiState |= CIF_STATE_INDEX_MIGRATION_MERGE;
  1341. break;
  1342. default:
  1343. eCiState |= CIF_STATE_MASTER_MERGE;
  1344. break;
  1345. }
  1346. }
  1347. else
  1348. {
  1349. CPartition *pPartition = _partList.LokGetPartition ( partidDefault );
  1350. if ( pPartition->InMasterMerge() )
  1351. eCiState |= CIF_STATE_MASTER_MERGE_PAUSED;
  1352. }
  1353. if ( LokIsScanNeeded() )
  1354. eCiState |= CIF_STATE_CONTENT_SCAN_REQUIRED;
  1355. setState( eState, (CIF_STATE_FLAGS) eCiState );
  1356. return STATUS_SUCCESS;
  1357. }
  1358. //+---------------------------------------------------------------------------
  1359. //
  1360. // Member: CResManager::IndexSize
  1361. //
  1362. // Synopsis: Computes the size of the indexes in all partitions
  1363. //
  1364. // Arguments: [mbIndex] - On output, will have the size of all indexes
  1365. // in MBs.
  1366. //
  1367. // History: 4-15-96 srikants Created
  1368. //
  1369. //----------------------------------------------------------------------------
  1370. void CResManager::IndexSize( ULONG & mbIndex )
  1371. {
  1372. CLock lock(_mutex);
  1373. mbIndex = _partList.LokIndexSize() / ((1024*1024)/CI_PAGE_SIZE);
  1374. }
  1375. //+---------------------------------------------------------------------------
  1376. //
  1377. // Member: CResManager::LokCheckWordlistQuotas, public
  1378. //
  1379. // Synopsis: Determine if we've reached wordlist capacity.
  1380. //
  1381. // Returns: TRUE if we have as much wordlist data in memory as
  1382. // parameters allow.
  1383. //
  1384. // History: 14-Jan-1999 KyleP Created
  1385. //
  1386. //----------------------------------------------------------------------------
  1387. BOOL CResManager::LokCheckWordlistQuotas()
  1388. {
  1389. CPartIter iter;
  1390. for ( iter.LokInit(_partList); !iter.LokAtEnd(); iter.LokAdvance(_partList) )
  1391. {
  1392. CPartition* pPart = iter.LokGet();
  1393. if ( pPart->LokCheckWordlistMerge() )
  1394. return TRUE;
  1395. }
  1396. return FALSE;
  1397. }
  1398. //+---------------------------------------------------------------------------
  1399. //
  1400. // Member: CResManager::MarkCorruptIndex
  1401. //
  1402. // Synopsis: Marks the index as corrupt, disables updates in all partitions
  1403. // and wakes up the merge thread to notify the framework client
  1404. // about the corruption.
  1405. //
  1406. // History: 1-30-97 srikants Created
  1407. //
  1408. //----------------------------------------------------------------------------
  1409. NTSTATUS CResManager::MarkCorruptIndex()
  1410. {
  1411. CPriLock lock(_mutex);
  1412. //
  1413. // Disable updates in all partitions
  1414. //
  1415. CPartIter iter;
  1416. for ( iter.LokInit(_partList); !iter.LokAtEnd(); iter.LokAdvance(_partList))
  1417. {
  1418. CPartition * pPart = iter.LokGet();
  1419. pPart->LokDisableUpdates();
  1420. }
  1421. if ( _state.FLokCorruptionNotified() )
  1422. return S_OK;
  1423. _isCorrupt = TRUE;
  1424. StopCurrentMerge();
  1425. _eventMerge.Set();
  1426. return S_OK;
  1427. }
  1428. //=====================
  1429. // KEYINDEX
  1430. //=====================
  1431. #ifdef KEYLIST_ENABLED
  1432. //+---------------------------------------------------------------------------
  1433. //
  1434. // Member: CResManager::_AddRefKeyList, private
  1435. //
  1436. // Synopsis: Adds to refcount on the keylist
  1437. //
  1438. // History: 07-Jul-94 dlee Created
  1439. //
  1440. //----------------------------------------------------------------------------
  1441. CKeyList * CResManager::_AddRefKeyList()
  1442. {
  1443. CPriLock lock( _mutex );
  1444. _sKeyList->Reference();
  1445. return _sKeyList.GetPointer();
  1446. }
  1447. //+---------------------------------------------------------------------------
  1448. //
  1449. // Member: CResManager::_ReleaseKeyList, private
  1450. //
  1451. // Synopsis: Release a refcount on the keylist
  1452. //
  1453. // History: 07-Jul-94 dlee Created
  1454. //
  1455. //----------------------------------------------------------------------------
  1456. void CResManager::_ReleaseKeyList()
  1457. {
  1458. CPriLock lock( _mutex );
  1459. _sKeyList->Release();
  1460. if ( !_sKeyList->InUse() && _sKeyList->IsZombie() )
  1461. {
  1462. ciDebugOut(( DEB_ITRACE,
  1463. "Keylist %x unreferenced zombie. Deleting\n",
  1464. _sKeyList->GetId() ));
  1465. CKeyList * pKeyList = _sKeyList.Acquire();
  1466. pKeyList->Remove();
  1467. delete pKeyList;
  1468. }
  1469. }
  1470. #endif // KEYLIST_ENABLED
  1471. //+---------------------------------------------------------------------------
  1472. //
  1473. // Member: CResManager::KeyToId, public
  1474. //
  1475. // Synopsis: Maps from a key to an id.
  1476. //
  1477. // Arguments: [pkey] -- pointer to the key to be mapped to ULONG
  1478. //
  1479. // Returns: key id - a ULONG
  1480. //
  1481. // History: 03-Nov-93 w-Patg Created.
  1482. // 17-Feb-94 KyleP Initial version
  1483. //
  1484. //----------------------------------------------------------------------------
  1485. ULONG CResManager::KeyToId( CKey const * pkey )
  1486. {
  1487. #ifdef KEYLIST_ENABLED
  1488. CKeyList * pKeyList = _AddRefKeyList();
  1489. ULONG kid = pKeyList->KeyToId( pkey );
  1490. _ReleaseKeyList();
  1491. return( kid );
  1492. #else
  1493. return widInvalid;
  1494. #endif // KEYLIST_ENABLED
  1495. }
  1496. //+---------------------------------------------------------------------------
  1497. //
  1498. // Member: CResManager::IdToKey, public
  1499. //
  1500. // Synopsis: Maps from an id to a key.
  1501. //
  1502. // Arguments: [ulKid] -- key id to be mapped to a key
  1503. // [rkey] -- reference to the returned key
  1504. //
  1505. // Returns: void
  1506. //
  1507. // History: 03-Nov-93 w-Patg Created.
  1508. // 17-Feb-94 KyleP Initial version
  1509. //
  1510. //----------------------------------------------------------------------------
  1511. void CResManager::IdToKey( ULONG ulKid, CKey & rkey )
  1512. {
  1513. #ifdef KEYLIST_ENABLED
  1514. CKeyList * pKeyList = _AddRefKeyList();
  1515. pKeyList->IdToKey( ulKid, rkey );
  1516. _ReleaseKeyList();
  1517. #else
  1518. rkey.FillMin();
  1519. #endif // KEYLIST_ENABLED
  1520. }
  1521. //+-------------------------------------------------------------------------
  1522. //
  1523. // Member: CResManager::ComputeRelevantWords, public
  1524. //
  1525. // Synopsis: Computes and returns relevant words for a set of wids
  1526. //
  1527. // Arguments: [cRows] -- # of rows to compute and in pwid array
  1528. // [cRW] -- # of rw per wid
  1529. // [pwid] -- array of wids to work over
  1530. // [partid] -- partition
  1531. //
  1532. // History: 10-May-94 v-dlee Created
  1533. //
  1534. //--------------------------------------------------------------------------
  1535. CRWStore * CResManager::ComputeRelevantWords(ULONG cRows,ULONG cRW,
  1536. WORKID *pwids,
  1537. PARTITIONID partid)
  1538. {
  1539. CRWStore *prws = 0;
  1540. #ifdef KEYLIST_ENABLED
  1541. CPriLock lock( _mutex );
  1542. CPartition *pPart = LokGetPartition(partid);
  1543. if (pPart != 0)
  1544. {
  1545. CPersIndex *pIndex= pPart->GetCurrentMasterIndex();
  1546. if (pIndex != 0)
  1547. {
  1548. prws = pIndex->ComputeRelevantWords(cRows,cRW,pwids,
  1549. _sKeyList.GetPointer() );
  1550. }
  1551. }
  1552. #endif // KEYLIST_ENABLED
  1553. return prws;
  1554. } //ComputeRelevantWords
  1555. //+-------------------------------------------------------------------------
  1556. //
  1557. // Member: CRWStore::RetrieveRelevantWords, public
  1558. //
  1559. // Synopsis: Retrieves relevant words already computed
  1560. //
  1561. // Arguments: [fAcquire] -- TRUE if ownership is transferred.
  1562. // [partid] -- partition
  1563. //
  1564. // History: 10-May-94 v-dlee Created
  1565. //
  1566. //--------------------------------------------------------------------------
  1567. CRWStore * CResManager::RetrieveRelevantWords(BOOL fAcquire,
  1568. PARTITIONID partid)
  1569. {
  1570. CRWStore *prws = 0;
  1571. #ifdef KEYLIST_ENABLED
  1572. CPriLock lock( _mutex );
  1573. CPartition *pPart = LokGetPartition(partid);
  1574. if (pPart != 0)
  1575. {
  1576. prws = pPart->RetrieveRelevantWords(fAcquire);
  1577. }
  1578. #endif // KEYLIST_ENABLED
  1579. return prws;
  1580. } //RetrieveRelevantWords
  1581. //================
  1582. // PRIVATE METHODS
  1583. //================
  1584. //+-------------------------------------------------------------------------
  1585. //
  1586. // Member: CResManager::CompactResources
  1587. //
  1588. // History: 05-Jan-95 BartoszM Created
  1589. //
  1590. //--------------------------------------------------------------------------
  1591. void CResManager::CompactResources()
  1592. {
  1593. CPriLock lock( _mutex );
  1594. CPartIter iter;
  1595. for ( iter.LokInit(_partList); !iter.LokAtEnd(); iter.LokAdvance(_partList))
  1596. {
  1597. iter.LokGet()->LokCompact();
  1598. }
  1599. }
  1600. //=================================//
  1601. // MERGES //
  1602. //=================================//
  1603. //+---------------------------------------------------------------------------
  1604. //
  1605. // Member: CResManager::DoMerges, private
  1606. //
  1607. // History: 08-Apr-91 BartoszM Created
  1608. // 25-Feb-92 BartoszM Rewrote to use thread
  1609. // 30-Jun-97 KrishnaN Calling docstore.FlushPropertyStore
  1610. // before a shadow merge.
  1611. // 03-Mar-98 KitmanH Don't merge if _storage is read-only
  1612. //
  1613. // Notes: Entry point for captive threads
  1614. //
  1615. //----------------------------------------------------------------------------
  1616. void CResManager::DoMerges()
  1617. {
  1618. if ( _storage.IsReadOnly() )
  1619. return;
  1620. CCiFrmPerfCounter pPerIndexCounter( _adviseStatus.GetPointer(), CI_PERF_NUM_PERSISTENT_INDEXES );
  1621. CCiFrmPerfCounter pIndexSizeCounter( _adviseStatus.GetPointer(), CI_PERF_INDEX_SIZE );
  1622. CCiFrmPerfCounter pPendingCounter( _adviseStatus.GetPointer(), CI_PERF_FILES_TO_BE_FILTERED );
  1623. CCiFrmPerfCounter pNumKeysCounter( _adviseStatus.GetPointer(), CI_PERF_NUM_UNIQUE_KEY);
  1624. CCiFrmPerfCounter pWordListCounter(_adviseStatus.GetPointer(), CI_PERF_NUM_WORDLIST);
  1625. CCiFrmPerfCounter pDeferredFilesCounter( _adviseStatus.GetPointer(), CI_PERF_DEFERRED_FILTER_FILES );
  1626. XPtr<CIdleTime> xIdle( new CIdleTime() );
  1627. //
  1628. // Allow mount to complete before checking for merges. O/W we will
  1629. // start a merge before the mount/startup is complete and it might
  1630. // prevent a system from coming up.
  1631. //
  1632. const lowDiskPollTime = 1; // 1 minute
  1633. DWORD dwWaitTime = _isLowOnDiskSpace ? lowDiskPollTime : _frmwrkParams.GetMaxMergeInterval();
  1634. _eventMerge.Wait( dwWaitTime * 1000 * 60 );
  1635. BOOL fAnnealing = FALSE;
  1636. while ( !_fStopMerge )
  1637. {
  1638. BOOL fCorrupt = FALSE;
  1639. ciDebugOut (( DEB_ITRACE, "\t|Merge Wakeup!\n" ));
  1640. //
  1641. // Book keeping chores.
  1642. //
  1643. BOOL fBackupCiData = FALSE;
  1644. BOOL fBackupStarted = FALSE;
  1645. TRY
  1646. {
  1647. // ===============================================
  1648. CPriLock lock(_mutex);
  1649. if ( _isCorrupt )
  1650. {
  1651. if ( !_state.FLokCorruptionNotified() )
  1652. LokNotifyCorruptionToClient();
  1653. }
  1654. else
  1655. {
  1656. //
  1657. // Use low disk condition plus the current state to decide if
  1658. // updates should be enabled or not
  1659. //
  1660. _isLowOnDiskSpace = LokCheckIfDiskLow( *this,
  1661. _storage,
  1662. _isLowOnDiskSpace,
  1663. _adviseStatus.GetReference() );
  1664. if ( _isLowOnDiskSpace )
  1665. {
  1666. if ( _state.LokGetState() != eUpdatesToBeDisabled
  1667. && _state.LokGetState() != eUpdatesDisabled )
  1668. {
  1669. _state.LokSetState( eUpdatesToBeDisabled );
  1670. _state.LokSetUpdateType( eIncremental );
  1671. }
  1672. }
  1673. else
  1674. {
  1675. if ( _state.LokGetState() == eUpdatesDisabled )
  1676. _state.LokSetState( eUpdatesToBeEnabled );
  1677. }
  1678. if ( _state.LokGetState() == eUpdatesToBeDisabled )
  1679. LokNotifyDisableUpdatesToClient();
  1680. else if ( _state.LokGetState() == eUpdatesToBeEnabled )
  1681. LokNotifyEnableUpdatesToClient();
  1682. }
  1683. fBackupCiData = 0 != _pBackupWorkItem;
  1684. // ===============================================
  1685. }
  1686. CATCH( CException, e )
  1687. {
  1688. // ignore and try again the next time through the loop.
  1689. }
  1690. END_CATCH
  1691. TRY
  1692. {
  1693. if ( !_isCorrupt && _partidToMerge != partidInvalid )
  1694. {
  1695. ciDebugOut (( DEB_ITRACE, "Forced merge in %ld\n",
  1696. _partidToMerge ));
  1697. switch ( _mtForceMerge )
  1698. {
  1699. case CI_MASTER_MERGE:
  1700. MasterMerge ( _partidToMerge );
  1701. break;
  1702. case CI_SHADOW_MERGE:
  1703. Merge( mtShadow, _partidToMerge );
  1704. break;
  1705. case CI_ANNEALING_MERGE:
  1706. Merge( mtAnnealing, _partidToMerge );
  1707. break;
  1708. case CI_ANY_MERGE:
  1709. break; // Do nothing. Let normal mechanism work it out.
  1710. default:
  1711. Win4Assert( !"Invalid ForceMerge type" );
  1712. }
  1713. }
  1714. if ( !_isLowOnDiskSpace && !_isCorrupt )
  1715. {
  1716. //
  1717. // Refile the documents from the secondary queue to the primary
  1718. // queue in pull filtering.
  1719. //
  1720. // ======================= lock ======================
  1721. if ( !_fPushFiltering )
  1722. {
  1723. CLock lock(_mutex);
  1724. LokRefileSecQueueDocs();
  1725. }
  1726. // ======================= unlock ======================
  1727. if ( fBackupCiData )
  1728. {
  1729. BOOL fIsMasterPresent = FALSE;
  1730. BOOL fIsMMergeInProgress = FALSE;
  1731. //================================
  1732. {
  1733. CPriLock lock(_mutex);
  1734. _pBackupWorkItem->LokSetDoingMerge();
  1735. fIsMasterPresent = LokIsMasterIndexPresent( partidDefault );
  1736. fIsMMergeInProgress = LokIsMasterMergeInProgress( partidDefault );
  1737. }
  1738. //================================
  1739. if ( _pBackupWorkItem->IsFullSave() ||
  1740. fIsMMergeInProgress ||
  1741. !fIsMasterPresent )
  1742. {
  1743. _pBackupWorkItem->SetDoingFullSave();
  1744. MasterMerge( partidDefault );
  1745. }
  1746. else
  1747. {
  1748. Merge( mtIncrBackup, partidDefault );
  1749. }
  1750. fBackupStarted = TRUE;
  1751. BackupContentIndexData();
  1752. }
  1753. else
  1754. {
  1755. if ( fAnnealing )
  1756. {
  1757. fAnnealing = FALSE;
  1758. CPartIdStack partitionIds;
  1759. CheckAndDoMerge( mtAnnealing, partitionIds );
  1760. while ( partitionIds.Count() > 0 )
  1761. Merge( mtAnnealing, partitionIds.Pop() );
  1762. }
  1763. {
  1764. CPartIdStack partitionIds;
  1765. CheckAndDoMerge( mtShadow, partitionIds );
  1766. while ( partitionIds.Count() > 0 )
  1767. {
  1768. // Call FlushPropertyStore on DocStore to give it
  1769. // a chance to persist changes before a shadow merge.
  1770. _docStore->FlushPropertyStore();
  1771. Merge( mtShadow, partitionIds.Pop() );
  1772. }
  1773. }
  1774. {
  1775. if ( CheckDeleteMerge( _partidToMerge != partidInvalid ) )
  1776. {
  1777. // Call FlushPropertyStore on DocStore to give it
  1778. // a chance to persist changes before a shadow merge.
  1779. _docStore->FlushPropertyStore();
  1780. Merge( mtDeletes, 1 );
  1781. }
  1782. }
  1783. BOOL fIsMasterPresent = FALSE;
  1784. BOOL fIsMMergeInProgress = FALSE;
  1785. //================================
  1786. {
  1787. CPriLock lock(_mutex);
  1788. fIsMasterPresent = LokIsMasterIndexPresent( partidDefault );
  1789. fIsMMergeInProgress = LokIsMasterMergeInProgress( partidDefault );
  1790. }
  1791. //================================
  1792. {
  1793. CPartIdStack partitionIds;
  1794. CheckAndDoMerge( mtMaster, partitionIds );
  1795. while ( partitionIds.Count() > 0 )
  1796. MasterMerge( partitionIds.Pop() );
  1797. }
  1798. }
  1799. }
  1800. }
  1801. CATCH ( CException, e )
  1802. {
  1803. ciDebugOut (( DEB_ERROR,
  1804. "ResMan::DoMerges -- merge failed with 0x%x\n",
  1805. e.GetErrorCode() ));
  1806. if ( IsDiskFull(e.GetErrorCode()) )
  1807. {
  1808. ciDebugOut(( DEB_ERROR, "***** DISK IS FULL *****\n" ));
  1809. CPriLock lock(_mutex);
  1810. _isLowOnDiskSpace = LokCheckIfDiskLow( *this,
  1811. _storage,
  1812. _isLowOnDiskSpace,
  1813. _adviseStatus.GetReference() );
  1814. }
  1815. else if ( IsCorrupt( e.GetErrorCode() ) )
  1816. {
  1817. Win4Assert( "!Merge failed, but not for low disk. Why?" );
  1818. fCorrupt = TRUE;
  1819. }
  1820. //
  1821. // We have to prevent a master merge from being restarted
  1822. // immediately. The reason for failure could be something like
  1823. // out of disk space (typical reason) or log full. In either
  1824. // case we will only be exacerbating the situation if we
  1825. // restart immediately.
  1826. //
  1827. _eventMerge.Reset();
  1828. }
  1829. END_CATCH
  1830. // ==========================================================
  1831. {
  1832. CPriLock lock( _mutex );
  1833. Win4Assert( _partList.LokIndexCount() >= _partList.LokWlCount() );
  1834. pPerIndexCounter.Update(_partList.LokIndexCount()-_partList.LokWlCount());
  1835. pIndexSizeCounter.Update(_partList.LokIndexSize() / ((1024*1024)/CI_PAGE_SIZE) );
  1836. pNumKeysCounter.Update(_sKeyList->MaxKeyIdInUse());
  1837. pWordListCounter.Update(_partList.LokWlCount());
  1838. _partidToMerge = partidInvalid;
  1839. if ( _fStopMerge )
  1840. {
  1841. ciDebugOut(( DEB_ITRACE, "Stopping Merge\n" ));
  1842. break;
  1843. }
  1844. if ( !_isCorrupt && ( _state.LokGetState() == eSteady ) && ( 0 != _pFilterAgent ) )
  1845. _pFilterAgent->LokWakeUp();
  1846. _eventMerge.Reset(); // sleep
  1847. if ( fBackupStarted || _isCorrupt )
  1848. {
  1849. //
  1850. // Set that backup to be complete even if it failed. Once
  1851. // Backup starts, it either succeeds or fails but in either
  1852. // case the operation is considered done.
  1853. //
  1854. if ( 0 != _pBackupWorkItem )
  1855. {
  1856. if ( _isCorrupt )
  1857. _pBackupWorkItem->LokSetStatus( CI_CORRUPT_DATABASE );
  1858. _pBackupWorkItem->LokSetDone();
  1859. }
  1860. }
  1861. }
  1862. // ==========================================================
  1863. BOOL fSteadyState = TRUE;
  1864. if ( fCorrupt )
  1865. {
  1866. CPriLock lock(_mutex);
  1867. _isCorrupt = TRUE;
  1868. fSteadyState = _state.LokGetState() == eSteady;
  1869. }
  1870. unsigned cSecQCount;
  1871. unsigned cPending = CountPendingUpdates( cSecQCount );
  1872. //
  1873. // Wait for either the merge event to be signaled or the deadman timeout.
  1874. //
  1875. dwWaitTime = ( ( _isLowOnDiskSpace ) ||
  1876. ( !fSteadyState ) ||
  1877. ( 0 != cPending ) ) ?
  1878. lowDiskPollTime : _frmwrkParams.GetMaxMergeInterval();
  1879. NTSTATUS Status = _eventMerge.Wait( dwWaitTime * 60 * 1000 );
  1880. if ( !_isCorrupt )
  1881. {
  1882. unsigned PercentIdle = xIdle->PercentIdle();
  1883. //
  1884. // Are we idle enough to consider an annealing merge?
  1885. //
  1886. if ( STATUS_TIMEOUT == Status && PercentIdle >= _frmwrkParams.GetMinMergeIdleTime() )
  1887. {
  1888. ciDebugOut(( DEB_ITRACE, "Idle time for period: %u percent\n", PercentIdle ));
  1889. fAnnealing = TRUE;
  1890. }
  1891. }
  1892. if ( _fStopMerge )
  1893. {
  1894. ciDebugOut(( DEB_ITRACE, "Stopping Merge\n" ));
  1895. break;
  1896. }
  1897. cPending = CountPendingUpdates( cSecQCount );
  1898. pPendingCounter.Update(cPending);
  1899. pDeferredFilesCounter.Update(cSecQCount);
  1900. ciDebugOut (( DEB_ITRACE | DEB_PENDING,
  1901. "%d updates pending\n", cPending ));
  1902. }
  1903. // ===========================================
  1904. {
  1905. CPriLock lock2(_mutex);
  1906. if ( _pBackupWorkItem )
  1907. {
  1908. ciDebugOut(( DEB_WARN, "Forcing the backup to be done\n" ));
  1909. _pBackupWorkItem->LokSetDone();
  1910. }
  1911. }
  1912. // ===========================================
  1913. }
  1914. //+-------------------------------------------------------------------------
  1915. //
  1916. // Member: CResManager::StopMerges, private
  1917. //
  1918. // Synopsis: Aborts merge-in-progress (if any) and sets merge flag.
  1919. //
  1920. // History: 13-Aug-93 KyleP Created
  1921. //
  1922. //--------------------------------------------------------------------------
  1923. void CResManager::StopMerges()
  1924. {
  1925. {
  1926. CPriLock lock( _mutex );
  1927. _fStopMerge = TRUE;
  1928. _eventMerge.Set(); // wake up
  1929. //
  1930. // If we're doing a merge right now then kill it off.
  1931. //
  1932. if ( 0 != _pMerge )
  1933. {
  1934. _pMerge->LokAbort();
  1935. }
  1936. }
  1937. //
  1938. // Wait for merge thread to die.
  1939. //
  1940. _thrMerge.WaitForDeath();
  1941. }
  1942. //+---------------------------------------------------------------------------
  1943. //
  1944. // Member: CResManager::CheckAndDoMerge, private
  1945. //
  1946. // History: 08-Apr-91 BartoszM Created
  1947. //
  1948. // Notes: Called by captive thread.
  1949. //
  1950. //----------------------------------------------------------------------------
  1951. void CResManager::CheckAndDoMerge( MergeType mt, CPartIdStack & partitionIds)
  1952. {
  1953. if ( !IsBatteryLow() )
  1954. {
  1955. CPriLock lock( _mutex );
  1956. ciDebugOut (( DEB_ITRACE, "check merge\n" ));
  1957. CPartIter iter;
  1958. for ( iter.LokInit(_partList); !iter.LokAtEnd(); iter.LokAdvance(_partList))
  1959. {
  1960. CPartition* pPart = iter.LokGet();
  1961. if ( mt == mtMaster )
  1962. {
  1963. __int64 shadowIndexSize = pPart->LokIndexSize();
  1964. CPersIndex * pMasterIndex = pPart->GetCurrentMasterIndex();
  1965. if ( pMasterIndex )
  1966. shadowIndexSize -= pMasterIndex->Size();
  1967. shadowIndexSize *= CI_PAGE_SIZE;
  1968. CMasterMergePolicy mergePolicy( _storage, shadowIndexSize,
  1969. LokGetFreshCount(),
  1970. _mergeTime,
  1971. _frmwrkParams,
  1972. _adviseStatus.GetReference() );
  1973. if ( mergePolicy.IsTimeToMasterMerge() ||
  1974. ( mergePolicy.IsMidNightMergeTime() &&
  1975. !IsOnBatteryPower() ) )
  1976. partitionIds.Push( pPart->GetId() );
  1977. }
  1978. else
  1979. {
  1980. if ( pPart->LokCheckMerge(mt) ||
  1981. ( IsMemoryLow() && pPart->LokCheckLowMemoryMerge() ) )
  1982. {
  1983. #if CIDBG == 1
  1984. if ( !pPart->LokCheckMerge(mt) )
  1985. {
  1986. ciDebugOut(( DEB_WARN, "Merge due to low memory. %u wordlists, %u shadow.\n",
  1987. pPart->WordListCount(), pPart->LokIndexCount() ));
  1988. }
  1989. #endif
  1990. partitionIds.Push( pPart->GetId() );
  1991. }
  1992. }
  1993. }
  1994. }
  1995. }
  1996. //+---------------------------------------------------------------------------
  1997. //
  1998. // Member: CResManager::CheckDeleteMerge, private
  1999. //
  2000. // Synopsis: Merge check for delete merge
  2001. //
  2002. // Arguments: [fForce] -- If TRUE, even 1 pending delete will force merge.
  2003. //
  2004. // Returns: TRUE if merge should be performed.
  2005. //
  2006. // History: 12-Jun-97 KyleP Created
  2007. //
  2008. // Notes: Called by captive thread.
  2009. //
  2010. //----------------------------------------------------------------------------
  2011. BOOL CResManager::CheckDeleteMerge( BOOL fForce )
  2012. {
  2013. CPriLock lock( _mutex );
  2014. ciDebugOut (( DEB_ITRACE, "check delete merge\n" ));
  2015. //
  2016. // A 'delete merge' occurs when enough documents have been deleted, and no
  2017. // documents have been added or modified (which would cause a shadow merge).
  2018. //
  2019. return ( ( _fresh.LokDeleteCount() > _frmwrkParams.GetMaxFreshDeletes() ) ||
  2020. ( fForce && _fresh.LokDeleteCount() > 0 ) );
  2021. }
  2022. //+---------------------------------------------------------------------------
  2023. //
  2024. // Member: CResManager::Merge, private
  2025. //
  2026. // Synopsis: Perform a merge in partition
  2027. //
  2028. // Arguments: [partid] -- partition id
  2029. // [mt] -- Merge type
  2030. //
  2031. // Signals: CExcetpion
  2032. //
  2033. // History: 08-Apr-91 BartoszM Created
  2034. // 13-Nov-91 BartoszM Rewrote using CMerge
  2035. //
  2036. //----------------------------------------------------------------------------
  2037. void CResManager::Merge( MergeType mt, PARTITIONID partid )
  2038. {
  2039. ciDebugOut (( DEB_ITRACE, "%s", (mtDeletes == mt) ? "Delete merging: Have a quick stretch" :
  2040. "Shadow merging: Get a cup of coffee\n" ));
  2041. CMerge Merge( *this, partid, mt );
  2042. //
  2043. // Perform resource acquisition under storage transaction. If
  2044. // aborted all persistent storage will be deleted by the storage
  2045. // transaction.
  2046. //
  2047. {
  2048. CPriLock lock ( _mutex );
  2049. Win4Assert( _pMerge == 0 );
  2050. if (_fStopMerge)
  2051. {
  2052. ciDebugOut(( DEB_ITRACE, "Stopping Merge\n" ));
  2053. return;
  2054. }
  2055. Merge.LokGrabResources(); // may throw an exception
  2056. //
  2057. // Optimization: Don't merge zero indexes.
  2058. //
  2059. if ( 0 != Merge.LokCountOld() )
  2060. {
  2061. _pMerge = &Merge;
  2062. }
  2063. else if ( mtDeletes != mt )
  2064. {
  2065. ciDebugOut(( DEB_ITRACE, "Shadow merge of zero indexes. Cancelled.\n" ));
  2066. return;
  2067. }
  2068. }
  2069. XPtr<CNotificationTransaction> xNotifyTrans;
  2070. // Perform the merge under simple transaction
  2071. // No lock held.
  2072. {
  2073. TRY
  2074. {
  2075. //
  2076. // Perform merge, if necessary.
  2077. //
  2078. if ( 0 != Merge.LokCountOld() )
  2079. {
  2080. CCiFrmPerfCounter counter( _adviseStatus.GetPointer(), CI_PERF_MERGE_PROGRESS );
  2081. Merge.Do( counter );
  2082. }
  2083. //
  2084. // NotifTrans should be outside resman lock and the resman lock
  2085. // is acquired in notifTran's destructor
  2086. //
  2087. xNotifyTrans.Set( new CNotificationTransaction( this,
  2088. _xIndexNotifTable.GetPointer() ) );
  2089. }
  2090. CATCH ( CException, e )
  2091. {
  2092. CPriLock lock ( _mutex );
  2093. Merge.LokRollBack();
  2094. _pMerge = 0;
  2095. // Really bad errors indicate the index is corrupt.
  2096. SCODE scE = e.GetErrorCode();
  2097. if ( STATUS_INTEGER_DIVIDE_BY_ZERO == scE ||
  2098. STATUS_ACCESS_VIOLATION == scE ||
  2099. STATUS_IN_PAGE_ERROR == scE )
  2100. {
  2101. ciDebugOut(( DEB_ERROR,
  2102. "Corrupt index, caught 0x%x\n", scE ));
  2103. _storage.ReportCorruptComponent( L"ShadowMerge" );
  2104. THROW( CException( CI_CORRUPT_DATABASE ) );
  2105. }
  2106. RETHROW();
  2107. }
  2108. END_CATCH
  2109. }
  2110. // nb: no failures allowed until CMergeTrans is constructed!
  2111. CDiskIndex* pIndexNew = 0;
  2112. { //=================== begin notification transaction =========================
  2113. {
  2114. CLock lock( _mutex );
  2115. XPtr<CFreshTest> xFreshTestAtMerge;
  2116. {
  2117. _pMerge = 0;
  2118. CMergeTrans Xact( *this, _storage, Merge );
  2119. unsigned cIndOld = Merge.LokCountOld();
  2120. INDEXID* aIidOld = Merge.LokGetIidList();
  2121. pIndexNew = Merge.LokGetNewIndex();
  2122. //
  2123. // Write the new fresh test persistently to disk.
  2124. //
  2125. CPersFresh newFreshLog( _storage, _partList );
  2126. CShadowMergeSwapInfo swapInfo;
  2127. swapInfo._widNewFreshLog = _fresh.LokUpdate( Merge,
  2128. Xact,
  2129. newFreshLog,
  2130. pIndexNew ? pIndexNew->GetId() : iidInvalid,
  2131. cIndOld,
  2132. aIidOld,
  2133. xFreshTestAtMerge );
  2134. swapInfo._widOldFreshLog =
  2135. _storage.GetSpecialItObjectId( itFreshLog );
  2136. swapInfo._cIndexOld = cIndOld;
  2137. swapInfo._aIidOld = aIidOld;
  2138. _partList.LokSwapIndexes( Xact,
  2139. partid,
  2140. pIndexNew,
  2141. swapInfo );
  2142. //
  2143. // No failures allowed after this point on until the transaction
  2144. // is committed.
  2145. //
  2146. Merge.ReleaseNewIndex();
  2147. ciDebugOut (( DEB_ITRACE, "done merging\n" ));
  2148. Xact.LokCommit();
  2149. #if CIDBG == 1
  2150. if ( pIndexNew )
  2151. pIndexNew->Reference();
  2152. #endif
  2153. //==========================================
  2154. }
  2155. ciFAILTEST( STATUS_NO_MEMORY );
  2156. CPartition *pPartition =_partList.LokGetPartition ( partid );
  2157. //
  2158. // Delete the wids in the change log that have made it to
  2159. // the new shadow index created in this merge. The algorithm
  2160. // needs the latest fresh test, fresh test snapshoted at the
  2161. // start of shadow merge and the doc list. If the latest fresh
  2162. // test is the same as the fresh test at merge, then as an
  2163. // optimization, the fresh test at merge is null. So, in the
  2164. // optimized case, we use the latest fresh test as the fresh
  2165. // test at merge.
  2166. //
  2167. CFreshTest *pFreshTestLatest = _fresh.LokGetFreshTest();
  2168. CFreshTestLock freshTestLock( pFreshTestLatest );
  2169. CFreshTest *pFreshTestAtMerge;
  2170. if ( xFreshTestAtMerge.IsNull() )
  2171. pFreshTestAtMerge = pFreshTestLatest;
  2172. else
  2173. pFreshTestAtMerge = xFreshTestAtMerge.GetPointer();
  2174. //==========================================
  2175. CChangeTrans xact( *this, pPartition );
  2176. pPartition->LokDeleteWIDsInPersistentIndexes( xact,
  2177. *pFreshTestLatest,
  2178. *pFreshTestAtMerge,
  2179. _docList,
  2180. xNotifyTrans.GetReference() );
  2181. xact.Commit();
  2182. }
  2183. xNotifyTrans.Free();
  2184. } //=================== end notification transaction =========================
  2185. #if CIDBG == 1
  2186. if ( pIndexNew )
  2187. {
  2188. pIndexNew->VerifyContents();
  2189. {
  2190. CPriLock lock ( _mutex );
  2191. LokReleaseIndex( pIndexNew );
  2192. }
  2193. }
  2194. #endif
  2195. _storage.CheckPoint();
  2196. } //Merge
  2197. //+---------------------------------------------------------------------------
  2198. //
  2199. // Member: CResManager::LogMMergeStartFailure
  2200. //
  2201. // Synopsis: Writes an eventlog message to indicate a MasterMerge could
  2202. // not be started.
  2203. //
  2204. // Arguments: [fRestart] - Indicates if this is a restarted master merge.
  2205. // [storage] - Storage reference
  2206. // [error] - Error code.
  2207. // [adviseStatus] - reference to ICiCAdviseStatus
  2208. //
  2209. // History: 5-27-96 srikants Created
  2210. // Jan-07-96 mohamedn CDmFwEventItem
  2211. //
  2212. //----------------------------------------------------------------------------
  2213. void CResManager::LogMMergeStartFailure( BOOL fRestart,
  2214. PStorage & storage,
  2215. ULONG error,
  2216. ICiCAdviseStatus & adviseStatus)
  2217. {
  2218. TRY
  2219. {
  2220. DWORD dwMsgCode = fRestart ?
  2221. MSG_CI_MASTER_MERGE_CANT_RESTART :
  2222. MSG_CI_MASTER_MERGE_CANT_START;
  2223. CDmFwEventItem Item( EVENTLOG_AUDIT_FAILURE,
  2224. dwMsgCode,
  2225. 2,
  2226. sizeof(error),
  2227. (void *)&error );
  2228. Item.AddArg( storage.GetVolumeName() );
  2229. Item.AddArg( error );
  2230. Item.ReportEvent( adviseStatus );
  2231. }
  2232. CATCH( CException, e )
  2233. {
  2234. ciDebugOut(( DEB_ERROR, "Error 0x%X in LogMMergeStartFailure\n",
  2235. e.GetErrorCode() ));
  2236. }
  2237. END_CATCH
  2238. }
  2239. //+---------------------------------------------------------------------------
  2240. //
  2241. // Member: CResManager::LogMMergePaused
  2242. //
  2243. // Synopsis: Writes an eventlog message that master merge was paused.
  2244. //
  2245. // Arguments: [storage] - Storage
  2246. // [error] - Error which caused the merge to be paused.
  2247. // [adviseStatus] - Advise status to use for notifying about the
  2248. // event.
  2249. //
  2250. // History: 1-24-97 srikants Added header
  2251. //
  2252. //----------------------------------------------------------------------------
  2253. void CResManager::LogMMergePaused( PStorage & storage,
  2254. ULONG error,
  2255. ICiCAdviseStatus &adviseStatus)
  2256. {
  2257. if ( IsCorrupt( error ) )
  2258. {
  2259. // don't log "paused" when there is corruption
  2260. return;
  2261. }
  2262. TRY
  2263. {
  2264. CDmFwEventItem Item( EVENTLOG_INFORMATION_TYPE,
  2265. MSG_CI_MASTER_MERGE_ABORTED,
  2266. 2,
  2267. sizeof(error),
  2268. (void *)&error );
  2269. Item.AddArg( storage.GetVolumeName() );
  2270. Item.AddArg( error );
  2271. Item.ReportEvent( adviseStatus );
  2272. }
  2273. CATCH( CException, e )
  2274. {
  2275. ciDebugOut(( DEB_ERROR, "Error 0x%X in LogMMergePaused\n",
  2276. e.GetErrorCode() ));
  2277. }
  2278. END_CATCH
  2279. }
  2280. //+---------------------------------------------------------------------------
  2281. //
  2282. // Member: CResManager::MasterMerge, private
  2283. //
  2284. // Synopsis: Perform a MasterMerge in partition
  2285. //
  2286. // Arguments: [partid] -- partition id
  2287. //
  2288. // Signals: CException
  2289. //
  2290. // History: 08-Apr-91 BartoszM Created
  2291. // 13-Nov-91 BartoszM Rewrote using CMerge
  2292. // 17-Feb-94 KyleP Added keylist merge
  2293. // Jan-07-96 mohamedn CDmFwEventItem
  2294. //
  2295. //----------------------------------------------------------------------------
  2296. void CResManager::MasterMerge ( PARTITIONID partid )
  2297. {
  2298. ciDebugOut (( DEB_ITRACE, "\n===MASTER MERGE===\n" ));
  2299. //
  2300. // Force a shadow merge if we are not restarting a master merge. This
  2301. // will force all word lists into persistent indexes.
  2302. //
  2303. BOOL fMasterMergePaused = FALSE;
  2304. //
  2305. // Before starting the master merge, we have to swap the deleted index
  2306. // iid. However, if there is a failure before we commit the beginning
  2307. // of the master merge, we have to roll back this change. The
  2308. // CDeletedIIDTrans object does this.
  2309. //
  2310. CDeletedIIDTrans delIIDTrans( *this );
  2311. INDEXID iidDelPreMerge = iidInvalid;
  2312. {
  2313. CPriLock lock ( _mutex );
  2314. CPartition *pPartition = _partList.LokGetPartition ( partid );
  2315. fMasterMergePaused = pPartition->InMasterMerge();
  2316. if ( !fMasterMergePaused )
  2317. {
  2318. if ( 0 == LokGetFreshCount() )
  2319. {
  2320. //
  2321. // There is no benefit in doing a master merge. Just return
  2322. //
  2323. return;
  2324. }
  2325. iidDelPreMerge = _activeDeletedIndex.GetIndex();
  2326. delIIDTrans.LokLogNewDeletedIid( iidDelPreMerge,
  2327. _activeDeletedIndex.GetNewIndex() );
  2328. _activeDeletedIndex.SwapIndex();
  2329. }
  2330. }
  2331. if ( !fMasterMergePaused )
  2332. {
  2333. //
  2334. // First do a delete merge to finish merging all outstanding
  2335. // word-lists into a persistent index.
  2336. //
  2337. // A delete merge will force an optimized null merge if there are
  2338. // outstanding deletes in the fresh test which need to be logged.
  2339. // This is an important case for Push filtering. Since it doesn't
  2340. // hurt in the other model, just keep the code identical.
  2341. //
  2342. Merge( mtDeletes, partid );
  2343. }
  2344. else
  2345. {
  2346. //
  2347. // This is a restarted master merge. The _activeDeletedIndex contains
  2348. // the "Post" master merge deleted index. The "New" one will be same
  2349. // as the "Prev" one.
  2350. //
  2351. iidDelPreMerge = _activeDeletedIndex.GetNewIndex();
  2352. CDmFwEventItem Item( EVENTLOG_INFORMATION_TYPE,
  2353. MSG_CI_MASTER_MERGE_RESTARTED,
  2354. 1 );
  2355. Item.AddArg( _storage.GetVolumeName() );
  2356. Item.ReportEvent( _adviseStatus.GetReference() );
  2357. }
  2358. CMasterMerge Merge( *this, partid );
  2359. TRY
  2360. {
  2361. CPriLock lock ( _mutex );
  2362. Win4Assert( _pMerge == 0 );
  2363. if ( _fStopMerge )
  2364. {
  2365. ciDebugOut(( DEB_ITRACE, "Stopping Merge\n" ));
  2366. return;
  2367. }
  2368. ciFAILTEST( STATUS_NO_MEMORY );
  2369. CPartition *pPartition =_partList.LokGetPartition ( partid );
  2370. if ( !pPartition->InMasterMerge() )
  2371. {
  2372. Win4Assert( delIIDTrans.IsTransLogged() );
  2373. Merge.LokGrabResources( delIIDTrans ); // may throw an exception
  2374. if ( 0 == Merge.LokCountOld() )
  2375. {
  2376. ciDebugOut(( DEB_ITRACE, "Master merge of 0 indexes cancelled\n"));
  2377. return;
  2378. }
  2379. }
  2380. else
  2381. {
  2382. Merge.LokLoadRestartResources();
  2383. }
  2384. //
  2385. // The deletionIIDTrans must be either committed or not logged at
  2386. // all.
  2387. //
  2388. Win4Assert( !delIIDTrans.IsRollBackTrans() );
  2389. _pMerge = &Merge;
  2390. }
  2391. CATCH( CException, e )
  2392. {
  2393. ciDebugOut(( DEB_ERROR, "Error 0x%X while starting a MasterMerge\n",
  2394. e.GetErrorCode() ));
  2395. LogMMergeStartFailure( fMasterMergePaused,
  2396. _storage,
  2397. e.GetErrorCode(),
  2398. _adviseStatus.GetReference() );
  2399. RETHROW();
  2400. }
  2401. END_CATCH
  2402. // Perform the merge under simple transaction
  2403. // No lock held.
  2404. {
  2405. TRY
  2406. {
  2407. // Perform merge
  2408. CCiFrmPerfCounter counter( _adviseStatus.GetPointer(), CI_PERF_MERGE_PROGRESS );
  2409. Merge.Do( counter );
  2410. }
  2411. CATCH ( CException, e )
  2412. {
  2413. CPriLock lock ( _mutex );
  2414. Merge.LokRollBack();
  2415. _pMerge = 0;
  2416. LogMMergePaused( _storage,
  2417. e.GetErrorCode(),
  2418. _adviseStatus.GetReference() );
  2419. RETHROW();
  2420. }
  2421. END_CATCH
  2422. }
  2423. CMasterMergeIndex* pMMergeIndex = 0;
  2424. {
  2425. CPriLock lock ( _mutex );
  2426. {
  2427. _pMerge = 0;
  2428. unsigned cIndOld = Merge.LokCountOld();
  2429. INDEXID* aIidOld = Merge.LokGetIidList();
  2430. pMMergeIndex = Merge.LokGetMasterMergeIndex();
  2431. CMergeTrans MergeTrans( *this, _storage, Merge );
  2432. ciFAILTEST( STATUS_NO_MEMORY );
  2433. //==========================================
  2434. CMasterMergeTrans xact( *this,
  2435. _storage,
  2436. MergeTrans,
  2437. pMMergeIndex,
  2438. Merge );
  2439. CPartition *pPart = LokGetPartition(partid);
  2440. #ifdef KEYLIST_ENABLED
  2441. pPart->SetRelevantWords(pMMergeIndex->AcquireRelevantWords());
  2442. #endif // KEYLIST_ENABLED
  2443. //
  2444. // Remove old indexes from fresh list after master merge
  2445. //
  2446. CPersFresh newFreshLog( _storage, _partList );
  2447. CMasterMergeSwapInfo SwapInfo;
  2448. SwapInfo._widNewFreshLog = _fresh.LokRemoveIndexes (
  2449. MergeTrans,
  2450. newFreshLog,
  2451. cIndOld, aIidOld, iidDelPreMerge );
  2452. SwapInfo._widOldFreshLog = _storage.GetSpecialItObjectId( itFreshLog );
  2453. SwapInfo._cIndexOld = cIndOld;
  2454. SwapInfo._aIidOld = aIidOld;
  2455. SwapInfo._partid = partid;
  2456. CKeyList const * pOldKeyList = _sKeyList.GetPointer();
  2457. CKeyList const * pNewKeyList = Merge.LokGetNewKeyList();
  2458. _partList.LokSwapIndexes( MergeTrans,
  2459. partid,
  2460. pMMergeIndex,
  2461. SwapInfo,
  2462. pOldKeyList,
  2463. pNewKeyList );
  2464. //
  2465. // After this point, we must not resume the master merge even
  2466. // if there is a soft failure.
  2467. //
  2468. Merge.ReleaseNewIndex();
  2469. #ifdef KEYLIST_ENABLED
  2470. //
  2471. // Get rid of the current KeyList and replace it with the
  2472. // new KeyList
  2473. //
  2474. _storage.SetSpecialItObjectId( itMMKeyList, widInvalid );
  2475. CKeyList * pKeyList = _sKeyList.Acquire();
  2476. Win4Assert( 0 != pKeyList );
  2477. _sKeyList.Set( Merge.LokGetNewKeyList() );
  2478. Merge.LokReleaseNewKeyList();
  2479. pKeyList->Zombify();
  2480. if ( !pKeyList->InUse() )
  2481. {
  2482. pKeyList->Remove();
  2483. delete pKeyList;
  2484. }
  2485. #else
  2486. CKeyList * pKeyList = _sKeyList.Acquire();
  2487. Win4Assert( 0 != pKeyList );
  2488. _sKeyList.Set( Merge.LokGetNewKeyList() );
  2489. Merge.LokReleaseNewKeyList();
  2490. delete pKeyList;
  2491. #endif // KEYLIST_ENABLED
  2492. #if CIDBG == 1
  2493. pMMergeIndex->Reference();
  2494. #endif
  2495. xact.LokCommit();
  2496. //==========================================
  2497. ciDebugOut (( DEB_ITRACE, "done merging\n" ));
  2498. }
  2499. //
  2500. // There is no need to compact the change log here because the
  2501. // participants in the master merge are persistent indexes and
  2502. // there will be no wids to be deleted from the change log when
  2503. // persistent indexes are merged into another persistent index.
  2504. //
  2505. }
  2506. #if CIDBG == 1
  2507. pMMergeIndex->VerifyContents();
  2508. {
  2509. CPriLock lock ( _mutex );
  2510. LokReleaseIndex( pMMergeIndex );
  2511. }
  2512. #endif
  2513. _storage.CheckPoint();
  2514. CDmFwEventItem Item( EVENTLOG_INFORMATION_TYPE,
  2515. MSG_CI_MASTER_MERGE_COMPLETED,
  2516. 1 );
  2517. Item.AddArg( _storage.GetVolumeName() );
  2518. Item.ReportEvent( _adviseStatus.GetReference() );
  2519. }
  2520. //+---------------------------------------------------------------------------
  2521. //
  2522. // Class: CReleaseMMergeIndex
  2523. //
  2524. // Purpose: Class to acquire the ownernship of the target and current
  2525. // master indexes during the destruction of a mastermerge index
  2526. // and release the target and current indexes.
  2527. //
  2528. // History: 9-29-94 srikants Created
  2529. //
  2530. //----------------------------------------------------------------------------
  2531. class CReleaseMMergeIndex
  2532. {
  2533. public:
  2534. CReleaseMMergeIndex( CResManager & resman, CMasterMergeIndex * mmIndex );
  2535. ~CReleaseMMergeIndex();
  2536. private:
  2537. CResManager & _resman;
  2538. CMasterMergeIndex * _pmmIndex;
  2539. CPersIndex * _pTargetMaster;
  2540. CPersIndex * _pCurrentMaster;
  2541. };
  2542. CReleaseMMergeIndex::CReleaseMMergeIndex( CResManager & resman,
  2543. CMasterMergeIndex * mmIndex ) :
  2544. _resman(resman),
  2545. _pmmIndex(mmIndex),
  2546. _pTargetMaster(0),
  2547. _pCurrentMaster(0)
  2548. {
  2549. Win4Assert( _pmmIndex );
  2550. Win4Assert( _pmmIndex->IsZombie() && !_pmmIndex->InUse() );
  2551. _pmmIndex->AcquireCurrentAndTarget( &_pCurrentMaster, &_pTargetMaster );
  2552. Win4Assert( 0 == _pCurrentMaster || _pCurrentMaster->IsZombie() );
  2553. if ( 0 != _pCurrentMaster )
  2554. {
  2555. _pCurrentMaster->Reference();
  2556. }
  2557. Win4Assert( 0 != _pTargetMaster );
  2558. _pTargetMaster->Reference();
  2559. }
  2560. CReleaseMMergeIndex::~CReleaseMMergeIndex()
  2561. {
  2562. delete _pmmIndex;
  2563. if ( 0 != _pCurrentMaster )
  2564. _resman.LokReleaseIndex( _pCurrentMaster );
  2565. _resman.LokReleaseIndex( _pTargetMaster );
  2566. }
  2567. //+---------------------------------------------------------------------------
  2568. //
  2569. // Member: CResManager::LokReleaseIndex, private
  2570. //
  2571. // Synopsis: Decrements ref counts, deletes if index
  2572. // marked to be deleted.
  2573. //
  2574. // Arguments: [pIndex] -- index to be released
  2575. //
  2576. // History: 08-Oct-91 BartoszM Created
  2577. //
  2578. // Notes: ResMan LOCKED
  2579. //
  2580. //----------------------------------------------------------------------------
  2581. void CResManager::LokReleaseIndex ( CIndex* pIndex )
  2582. {
  2583. pIndex->Release();
  2584. if ( pIndex->IsZombie() && !pIndex->InUse() )
  2585. {
  2586. CIndexId iid = pIndex->GetId();
  2587. //
  2588. // If it is not a master index, it has to be removed from the
  2589. // Partition object. A master index would have been already removed
  2590. // when merge completed.
  2591. //
  2592. // If we are in the Empty path, then we want to force all indexes
  2593. // to be deleted if their ref-count is 0.
  2594. //
  2595. if ( !pIndex->IsMaster() || _isBeingEmptied )
  2596. {
  2597. if ( !_isDismounted )
  2598. {
  2599. TRY
  2600. {
  2601. _partList.LokRemoveIndex ( iid );
  2602. }
  2603. CATCH( CException, e )
  2604. {
  2605. ciDebugOut(( DEB_ERROR,
  2606. "Index 0x%08x could not be deleted from index table\n",
  2607. iid ));
  2608. }
  2609. END_CATCH
  2610. TRY
  2611. {
  2612. // Must impersonate as system since query threads
  2613. // impersonating as a query user can't delete the
  2614. // files sometimes deleted when an index is released
  2615. // after a merge. Impersonation can fail, which will
  2616. // leak the file on disk.
  2617. CImpersonateSystem impersonate;
  2618. if ( iid.IsPersistent() )
  2619. pIndex->Remove();
  2620. }
  2621. CATCH( CException, e )
  2622. {
  2623. ciDebugOut(( DEB_ERROR,
  2624. "Index 0x%08x could not be deleted from disk, %#x\n",
  2625. iid, e.GetErrorCode() ));
  2626. }
  2627. END_CATCH
  2628. }
  2629. else
  2630. {
  2631. //
  2632. // Zombie indexes are cleaned up after reboot.
  2633. //
  2634. //
  2635. // After a dismount, we should not have any dirty streams
  2636. // and releasing a persistent zombie index will update the
  2637. // index table on disk. That is not allowed. This situation
  2638. // happens only when queries have not been released and
  2639. // shutdown is happening.
  2640. //
  2641. //
  2642. ciDebugOut(( DEB_WARN,
  2643. "Index with iid 0x%X being released AFTER CI dismount\n",
  2644. iid ));
  2645. }
  2646. delete pIndex;
  2647. }
  2648. else
  2649. {
  2650. //
  2651. // This must be a master merge index as no other master index
  2652. // can be a zombie.
  2653. //
  2654. Win4Assert( pIndex->IsMasterMergeIndex() );
  2655. CReleaseMMergeIndex mmIndexRel( *this,
  2656. (CMasterMergeIndex *)pIndex );
  2657. }
  2658. }
  2659. }
  2660. //+---------------------------------------------------------------------------
  2661. //
  2662. // Function: LokReplaceMasterIndex
  2663. //
  2664. // Synopsis: Replaces the CMasterMergeIndex with the CPersIndex incarnation
  2665. // of the target master index in the index list. Also prepares
  2666. // the CMasterMergeIndex for removal from the in-memory index
  2667. // list by zombifying it.
  2668. //
  2669. // Arguments: [pMMergeIndex] -- The target index in the CMasterMergeIndex
  2670. // form.
  2671. // [pNewMaster] -- The CPersIndex form of the target index.
  2672. //
  2673. // History: 6-30-94 srikants Created
  2674. //
  2675. //----------------------------------------------------------------------------
  2676. void CResManager::LokReplaceMasterIndex ( CMasterMergeIndex* pMMergeIndex )
  2677. {
  2678. Win4Assert( pMMergeIndex->IsMaster() && pMMergeIndex->IsZombie() );
  2679. CPersIndex * pNewMaster = pMMergeIndex->GetTargetMaster();
  2680. Win4Assert( pNewMaster->IsMaster() && !pNewMaster->IsZombie() );
  2681. //
  2682. // Delete the master merge index from the partition.
  2683. //
  2684. CIndexId iid = pMMergeIndex->GetId();
  2685. CPartition * pPart = _partList.LokGetPartition( iid.PartId() );
  2686. pPart->LokRemoveIndex ( iid );
  2687. //
  2688. // Check if there is a query in progress. If not, we can
  2689. // go ahead and delete it. If a query is in progress, the
  2690. // indexsnapshot of the query will delete it.
  2691. //
  2692. if ( !pMMergeIndex->InUse() )
  2693. {
  2694. Win4Assert( !pNewMaster->InUse() );
  2695. pMMergeIndex->ReleaseTargetAndCurrent();
  2696. delete pMMergeIndex;
  2697. }
  2698. //
  2699. // Add the new master index to the partition object. This will
  2700. // now be the only master accessible to new queries.
  2701. //
  2702. pPart->AddIndex( pNewMaster );
  2703. }
  2704. //
  2705. //+---------------------------------------------------------------------------
  2706. //
  2707. // Function: RollBackDeletedIIDChange
  2708. //
  2709. // Synopsis: Rolls back the changed made to the deleted iid during the
  2710. // beginning of a master merge.
  2711. //
  2712. // Arguments: [xact] - The transaction object which is rolling back the
  2713. // change to the deleted iid.
  2714. //
  2715. // History: 7-17-95 srikants Created
  2716. //
  2717. // Notes: Consider the following sequence of events:
  2718. //
  2719. // 1. Pre-MasterMerge preparations : Change Deleleted IID to iidDeleted2 from
  2720. // iidDeleted1.
  2721. //
  2722. // 2. Start a shadow merge.
  2723. //
  2724. // 3. Commit the beginning of a new MasterMerge
  2725. //
  2726. // 4. Complete the master merge .....
  2727. //
  2728. // If there is a failure between steps 2 and 3, we just revert the deleted
  2729. // IID back to iidDeleted2. Even if some entries were created in the fresh
  2730. // list between steps 2 & 3 of the form, WID->iidDeleted2, it is okay. They
  2731. // will get deleted from the fresh list on the second MasterMerge.
  2732. //
  2733. //----------------------------------------------------------------------------
  2734. void CResManager::RollBackDeletedIIDChange( CDeletedIIDTrans & xact )
  2735. {
  2736. CPriLock lock(_mutex);
  2737. Win4Assert( _activeDeletedIndex.GetIndex() == xact.GetNewDelIID() );
  2738. Win4Assert( _activeDeletedIndex.GetNewIndex() == xact.GetOldDelIID() );
  2739. _activeDeletedIndex.SwapIndex();
  2740. }
  2741. //========================
  2742. // FILTER RELATED METHODS
  2743. //========================
  2744. //+---------------------------------------------------------------------------
  2745. //
  2746. // Function: LokGetFilterDocs
  2747. //
  2748. // Synopsis: Gets documents from the change log for filtering. _docList
  2749. // will be filled with the documents.
  2750. //
  2751. // Arguments: [cMaxDocs] -- [in] Maximum number of docs to retrieve
  2752. // [cDocs] -- [out] Number of documents retrieved
  2753. // [state] -- [in/out] State of the document retrieval
  2754. // progress.
  2755. //
  2756. // Returns: Number of documents in the docBuffer.
  2757. //
  2758. // History: 6-16-94 srikants Separated for making kernel mode call
  2759. // Asynchronous.
  2760. //
  2761. // Notes: This function has two goals:
  2762. //
  2763. // 1. Select documents from different partitions in a round
  2764. // robin fashion.
  2765. //
  2766. //----------------------------------------------------------------------------
  2767. BOOL CResManager::LokGetFilterDocs ( ULONG cMaxDocs,
  2768. ULONG & cDocs,
  2769. CGetFilterDocsState & state )
  2770. {
  2771. ciDebugOut(( DEB_ITRACE, "# CResManager::LokGetFilterDocs.\n" ));
  2772. Win4Assert( state.GetTriesLeft() > 0 && state.GetTriesLeft() <=2 );
  2773. cDocs = 0;
  2774. Win4Assert ( !_isBeingEmptied );
  2775. unsigned maxDocs = min( cMaxDocs, CI_MAX_DOCS_IN_WORDLIST);
  2776. if ( _partIter.LokAtEnd() )
  2777. return FALSE; // There are no valid partitions
  2778. // we are sure that the partition is valid
  2779. CPartition* pPart = _partIter.LokGet();
  2780. Win4Assert ( pPart != 0 );
  2781. //
  2782. // Don't bother looking for more documents to filter if there
  2783. // are too many wordlists in memory -- wait until they are
  2784. // merged.
  2785. //
  2786. if ( pPart->WordListCount() < _frmwrkParams.GetMaxWordlists() )
  2787. {
  2788. CChangeTrans xact( *this, pPart );
  2789. pPart->LokQueryPendingUpdates ( xact, maxDocs, _docList );
  2790. xact.LokCommit();
  2791. }
  2792. else
  2793. {
  2794. ciDebugOut(( DEB_ITRACE,
  2795. "Too many wordlists. Waking merge\n" ));
  2796. _eventMerge.Set();
  2797. }
  2798. _docList.SetPartId ( pPart->GetId() );
  2799. //==================================
  2800. //
  2801. // If there is a failure after this point, we have to re-add
  2802. // the documents to the change log.
  2803. //
  2804. cDocs = _docList.Count();
  2805. for (unsigned i = 0; i < cDocs; i++)
  2806. {
  2807. if (_docList.Status(i) != DELETED && _docList.Status(i) != WL_NULL)
  2808. break;
  2809. }
  2810. BOOL fRetry = FALSE;
  2811. if ( i == cDocs && i != 0 )
  2812. {
  2813. CIndexTrans xact( *this );
  2814. _fresh.LokDeleteDocuments ( xact, _docList, _activeDeletedIndex.GetIndex() );
  2815. xact.LokCommit();
  2816. cDocs = 0;
  2817. _docList.LokClear();
  2818. state.Reset();
  2819. //
  2820. // If we are doing a bunch of deletions in a "delnode" case,
  2821. // we should see if the number of changed documents has exceeded
  2822. // the max fresh test count and wake up the merge thread. Note
  2823. // that we are not starting a merge here - the merge thread will
  2824. // deal with the policy issues.
  2825. //
  2826. if ( LokGetFreshCount() > _frmwrkParams.GetMaxFreshCount() ||
  2827. CheckDeleteMerge( FALSE ) )
  2828. {
  2829. _eventMerge.Set();
  2830. }
  2831. LokUpdateCounters();
  2832. }
  2833. _partIter.LokAdvance( _partList );
  2834. if ( _partIter.LokAtEnd() )
  2835. {
  2836. _partIter.LokInit( _partList );
  2837. state.DecrementTries();
  2838. fRetry = (0 == cDocs) && (state.GetTriesLeft() > 0);
  2839. }
  2840. else
  2841. {
  2842. fRetry = ( 0 != cDocs );
  2843. }
  2844. Win4Assert( cDocs == _docList.Count() );
  2845. return fRetry;
  2846. }
  2847. //+---------------------------------------------------------------------------
  2848. //
  2849. // Member: CResManager::FillDocBuffer, public
  2850. //
  2851. // Synopsis: Fills buffer with strings for paths and properties of docs
  2852. // to be filtered
  2853. //
  2854. // Arguments: [docBuffer] -- (in, out) buffer to be filled with document
  2855. // names.
  2856. // [cb] -- (in, out) count of bytes in docBuffer
  2857. // [cDocs] -- (out) count of # documents to filter
  2858. // [state] -- [in/out] State of the document retrieval
  2859. // progress.
  2860. //
  2861. // History: 08-Apr-1991 BartoszM Created
  2862. // 24-Nov-1992 KyleP Retry pending documents
  2863. // 22-Mar-1993 AmyA Split into several functions
  2864. // 22-Jan-1997 SrikantS Changed doc. names to bytes for frame
  2865. // work.
  2866. // 18-May-2000 KitmanH Changed to push retried docs to filter
  2867. // one by one
  2868. //
  2869. //----------------------------------------------------------------------------
  2870. void CResManager::FillDocBuffer( BYTE * docBuffer,
  2871. ULONG & cb, ULONG & cDocs,
  2872. CGetFilterDocsState & state )
  2873. {
  2874. Win4Assert( docBuffer != 0 );
  2875. // =========================================
  2876. {
  2877. CPriLock lock(_mutex);
  2878. _docList.LokSortOnWid();
  2879. }
  2880. // ==========================================
  2881. unsigned cDocuments = _docList.Count();
  2882. //
  2883. // Format of the data
  2884. // 4 Bytes remaining files count, 2 Bytes number of files. Following
  2885. // that is (2 Bytes of Name Length in bytes, Name)*
  2886. //
  2887. if ( _fPushFiltering )
  2888. {
  2889. //
  2890. // We can't take an exception while growing the aborted wids
  2891. // array while doing exception processing in the filter manager.
  2892. // So, pre-allocate the array now to insure we won't run out of
  2893. // room later. Now is a good time to die; later isn't.
  2894. //
  2895. CPriLock lock( _mutex );
  2896. _aAbortedWids.LokReserve( cDocuments );
  2897. //
  2898. // In push filtering there are no refiles, and hence the buffer
  2899. // cannot overflow. Check that the buffer can fit 16 documents.
  2900. // A document name is the serialized form of the wid, i.e. it's
  2901. // 4 bytes long. The buffer size is 4K.
  2902. //
  2903. Win4Assert( cb > 4 + 2 + 16 * (2 + 4) );
  2904. }
  2905. const cbLenField = sizeof(ULONG);
  2906. Win4Assert( cb >= cbLenField );
  2907. Win4Assert( sizeof(ULONG) == 4 );
  2908. if ( cb < cbLenField )
  2909. THROW( CException( STATUS_INVALID_PARAMETER ) );
  2910. //
  2911. // Fill the number of documents left in the changelog in the first
  2912. // 4 bytes of the buffer.
  2913. //
  2914. // =========================================================
  2915. {
  2916. CPriLock lock( _mutex );
  2917. ULONG partid = 1;
  2918. CPartition * pPart = _partList.LokGetPartition( partid );
  2919. ULONG cDocsLeft = pPart->LokCountUpdates();
  2920. RtlCopyMemory( docBuffer, &cDocsLeft, sizeof(ULONG) );
  2921. }
  2922. // =========================================================
  2923. RtlZeroMemory( docBuffer + cbLenField, sizeof USHORT );
  2924. const cbUSHORT = sizeof USHORT;
  2925. BYTE * pCount = docBuffer + cbLenField;
  2926. *pCount = 0;
  2927. BYTE * pBuf = pCount + cbUSHORT;
  2928. BYTE * pEnd = docBuffer + cb;
  2929. cDocs = 0;
  2930. // copy path/property pairs into buffer until we run out of either
  2931. // buffer space or pairs. We stop filling the buffer if we encounter a
  2932. // document that has a retry count > 1, we will fill the docBuffer with
  2933. // these docs one at a time
  2934. ciDebugOut((DEB_FILTERWIDS | DEB_ITRACE,
  2935. "CResManager::FillDocBuffer..."));
  2936. unsigned cbExtraSpaceNeeded = 0;
  2937. for (unsigned cSrcDocs = 0; cSrcDocs < cDocuments; cSrcDocs++)
  2938. {
  2939. //
  2940. // Leave the first 2 bytes for the length field
  2941. //
  2942. unsigned cbPath = (unsigned)(pEnd - pBuf);
  2943. if ( cbPath <= cbUSHORT )
  2944. {
  2945. // We would definitely need more space than a USHORT, but
  2946. // we don't know how much right now. But since the filter
  2947. // increases space by a PAGE, I guess we should do fine.
  2948. cbExtraSpaceNeeded = cbUSHORT - cbPath + 1;
  2949. break;
  2950. }
  2951. if (_docList.Status(cSrcDocs) == DELETED)
  2952. {
  2953. cbPath = 0;
  2954. ciDebugOut(( DEB_FILTERWIDS | DEB_NOCOMPNAME, " %dX",
  2955. _docList.Wid(cSrcDocs) ));
  2956. }
  2957. else
  2958. {
  2959. if ( _docList.Retries(cSrcDocs) > 1 )
  2960. {
  2961. ciDebugOut(( DEB_FILTERWIDS | DEB_NOCOMPNAME,
  2962. "************FillDocBuffer: Retry count is %d. Wid is %d\n",
  2963. _docList.Retries(cSrcDocs),
  2964. _docList.Wid(cSrcDocs) ));
  2965. ciDebugOut(( DEB_FILTERWIDS | DEB_NOCOMPNAME, "cDocs is %d\n", cDocs ));
  2966. if ( cDocs > 0 )
  2967. {
  2968. //
  2969. // There is at least one document in the docBuffer. Stop
  2970. // now so we can file the doc(s) being retried one by one.
  2971. //
  2972. break;
  2973. }
  2974. else
  2975. {
  2976. //
  2977. // Add the currenct doc. Stop if the current add is successful
  2978. //
  2979. //
  2980. // Make room for the length field at the beginning.
  2981. //
  2982. cbPath -= cbUSHORT;
  2983. ciDebugOut(( DEB_FILTERWIDS | DEB_NOCOMPNAME, " %d",
  2984. _docList.Wid(cSrcDocs) ));
  2985. unsigned cbPathIn = cbPath;
  2986. //
  2987. // If this is not the first try, then attempt to get a more
  2988. // accurate path. We may be suffering from NTBUG: 270566
  2989. //
  2990. // changes cbPath.
  2991. if ( !WorkidToDocName( _docList.Wid(cSrcDocs),
  2992. pBuf+cbUSHORT,
  2993. cbPath,
  2994. TRUE ) )
  2995. {
  2996. if ( cbPathIn < cbPath)
  2997. {
  2998. cbExtraSpaceNeeded = cbPath - cbPathIn;
  2999. }
  3000. break;
  3001. }
  3002. // cbPath = 0 if object has been deleted (not added to docBuffer)
  3003. if ( cbPath == 0 )
  3004. {
  3005. _docList.SetStatus( cSrcDocs, DELETED );
  3006. ciDebugOut(( DEB_FILTERWIDS | DEB_NOCOMPNAME, "X" ));
  3007. }
  3008. else
  3009. {
  3010. ClearNonStoragePropertiesForWid( _docList.Wid(cSrcDocs) );
  3011. cSrcDocs++;
  3012. cDocs++;
  3013. USHORT uscb = (USHORT) cbPath;
  3014. RtlCopyMemory( pBuf, &uscb, cbUSHORT );
  3015. pBuf += (cbPath+cbUSHORT);
  3016. break;
  3017. }
  3018. }
  3019. }
  3020. else // not retries
  3021. {
  3022. ciDebugOut(( DEB_FILTERWIDS | DEB_NOCOMPNAME,
  3023. "FillDocBuffer: Not retry for wid %d\n",
  3024. _docList.Wid(cSrcDocs) ));
  3025. //
  3026. // Make room for the length field at the beginning.
  3027. //
  3028. cbPath -= cbUSHORT;
  3029. ciDebugOut(( DEB_FILTERWIDS | DEB_NOCOMPNAME, " %d",
  3030. _docList.Wid(cSrcDocs) ));
  3031. unsigned cbPathIn = cbPath;
  3032. // changes cbPath.
  3033. if ( !WorkidToDocName( _docList.Wid(cSrcDocs),
  3034. pBuf+cbUSHORT,
  3035. cbPath,
  3036. FALSE ) )
  3037. {
  3038. if ( cbPathIn < cbPath)
  3039. {
  3040. cbExtraSpaceNeeded = cbPath - cbPathIn;
  3041. }
  3042. break;
  3043. }
  3044. // cbPath = 0 if object has been deleted
  3045. if ( cbPath == 0 )
  3046. {
  3047. _docList.SetStatus( cSrcDocs, DELETED );
  3048. ciDebugOut(( DEB_FILTERWIDS | DEB_NOCOMPNAME, "X" ));
  3049. }
  3050. else
  3051. {
  3052. cDocs++;
  3053. ClearNonStoragePropertiesForWid( _docList.Wid(cSrcDocs) );
  3054. }
  3055. }
  3056. }
  3057. USHORT uscb = (USHORT) cbPath;
  3058. RtlCopyMemory( pBuf, &uscb, cbUSHORT );
  3059. pBuf += (cbPath+cbUSHORT);
  3060. }
  3061. ciDebugOut (( DEB_FILTERWIDS | DEB_NOCOMPNAME, "\n" ));
  3062. //
  3063. // Fill in the count of the number of documents.
  3064. //
  3065. USHORT usFileCount = (USHORT) cSrcDocs;
  3066. RtlCopyMemory( pCount, &usFileCount, cbUSHORT );
  3067. if ( cSrcDocs < cDocuments )
  3068. {
  3069. if ( 0 == cSrcDocs && cbExtraSpaceNeeded > 0 )
  3070. {
  3071. // We need a larger buffer
  3072. cb += cbExtraSpaceNeeded;
  3073. }
  3074. //
  3075. // No refiling in push filtering
  3076. //
  3077. Win4Assert( !_fPushFiltering );
  3078. ciDebugOut (( DEB_ITRACE, "Putting back documents\n" ));
  3079. CDocList docListExtra;
  3080. docListExtra.SetPartId( _docList.PartId() );
  3081. for ( unsigned i = 0, j = cSrcDocs; j < cDocuments; i++, j++ )
  3082. {
  3083. ciDebugOut(( DEB_ITRACE | DEB_NOCOMPNAME, " %d", _docList.Wid(j) ));
  3084. ciDebugOut(( DEB_FILTERWIDS | DEB_NOCOMPNAME, "Refiling Wid %d\n", _docList.Wid(j) ));
  3085. docListExtra.Set( i,
  3086. _docList.Wid(j),
  3087. _docList.Usn(j),
  3088. _docList.VolumeId(j) );
  3089. }
  3090. ciDebugOut (( DEB_ITRACE | DEB_NOCOMPNAME, "\n" ));
  3091. CPriLock lock2(_mutex);
  3092. docListExtra.LokSetCount(i);
  3093. _docList.LokSetCount( cSrcDocs );
  3094. ReFileCommit ( docListExtra );
  3095. }
  3096. //
  3097. // If we were unable to convert any of the wids to paths, then all of
  3098. // them have been deleted.
  3099. //
  3100. if ( 0 == cDocs )
  3101. {
  3102. ciDebugOut (( DEB_ITRACE, "All docs were deleted\n" ));
  3103. CPriLock lock3(_mutex);
  3104. _docList.LokClear();
  3105. state.Reset();
  3106. }
  3107. else
  3108. {
  3109. cb = (ULONG)(pBuf - docBuffer);
  3110. }
  3111. }
  3112. //+---------------------------------------------------------------------------
  3113. //
  3114. // Function: NoFailReFile
  3115. //
  3116. // Synopsis: re-adds the documents to the change log witout committing
  3117. //
  3118. // History: 6-16-94 srikants Separated from FilterReady for making
  3119. // kernel mode call Asynchronous.
  3120. //
  3121. //----------------------------------------------------------------------------
  3122. BOOL CResManager::NoFailReFile ( CDocList& docList )
  3123. {
  3124. //
  3125. // No refiling in push filtering
  3126. //
  3127. Win4Assert( !_fPushFiltering );
  3128. CPriLock lock ( _mutex );
  3129. if ( _isBeingEmptied )
  3130. return FALSE;
  3131. LokNoFailReFileChanges( docList );
  3132. docList.LokClear();
  3133. return TRUE;
  3134. }
  3135. //+---------------------------------------------------------------------------
  3136. //
  3137. // Function: ReFileCommit
  3138. //
  3139. // Synopsis: re-adds the documents to the change log and commits
  3140. // them to the change list.
  3141. //
  3142. // History: 6-16-94 srikants Separated from FilterReady for making
  3143. // kernel mode call Asynchronous.
  3144. //
  3145. //----------------------------------------------------------------------------
  3146. BOOL CResManager::ReFileCommit ( CDocList& docList )
  3147. {
  3148. //
  3149. // No refiling in push filtering
  3150. //
  3151. Win4Assert( !_fPushFiltering );
  3152. CPriLock lock ( _mutex );
  3153. if ( _isBeingEmptied )
  3154. return FALSE;
  3155. LokNoFailReFileChanges( docList );
  3156. docList.LokClear();
  3157. //
  3158. // The docqueue can handle only one set of refiled documents.
  3159. // we MUST complete processing of the
  3160. // refiled documents.
  3161. //
  3162. PARTITIONID partId = 1;
  3163. CPartition * pPart = LokGetPartition( partId );
  3164. {
  3165. // =========================================
  3166. CChangeTrans xact( *this, pPart );
  3167. pPart->LokAppendRefiledDocs( xact );
  3168. xact.LokCommit();
  3169. // =========================================
  3170. }
  3171. return TRUE;
  3172. }
  3173. //+---------------------------------------------------------------------------
  3174. //
  3175. // Function: LokNoFailReFileChanges
  3176. //
  3177. // Synopsis: Refiles the updates with the change log.
  3178. //
  3179. // Arguments: [docList] -- contains the documents to be added back to the
  3180. // change log.
  3181. //
  3182. // History: 5-16-94 srikants Modified to deal with failures during
  3183. // append of docs to change log.
  3184. //
  3185. // Notes: This CANNOT throw
  3186. //
  3187. //----------------------------------------------------------------------------
  3188. void CResManager::LokNoFailReFileChanges( CDocList& docList )
  3189. {
  3190. //
  3191. // No refiling in push filtering
  3192. //
  3193. Win4Assert( !_fPushFiltering );
  3194. Win4Assert ( docList.PartId() == 1 );
  3195. CPartition* pPart = _partList.LokGetPartition ( docList.PartId() );
  3196. pPart->LokRefileDocs( docList );
  3197. _pFilterAgent->LokWakeUp ();
  3198. }
  3199. //+-------------------------------------------------------------------------
  3200. //
  3201. // Member: CResManager::LokReFileDocument, public
  3202. //
  3203. // Returns: Put a document back on the quueue to be refiltered
  3204. //
  3205. // History: 05-Jan-95 BartoszM Created
  3206. //
  3207. //--------------------------------------------------------------------------
  3208. void CResManager::LokReFileDocument ( PARTITIONID partid,
  3209. WORKID wid,
  3210. USN usn,
  3211. VOLUMEID volumeId,
  3212. ULONG retries,
  3213. ULONG secQRetries )
  3214. {
  3215. //
  3216. // No refiling in push filtering
  3217. //
  3218. Win4Assert( !_fPushFiltering );
  3219. CPartition* pPart = _partList.LokGetPartition(partid);
  3220. //==========================================
  3221. CChangeTrans xact( *this, pPart );
  3222. //
  3223. // A usn of 0 is used for all refiled documents
  3224. //
  3225. pPart->LokUpdateDocument (xact, wid, 0, volumeId, CI_UPDATE_OBJ, retries, secQRetries);
  3226. xact.LokCommit();
  3227. //==========================================
  3228. }
  3229. //+---------------------------------------------------------------------------
  3230. //
  3231. // Member: CResManager::LokAddToSecQueue
  3232. //
  3233. // Synopsis: Adds the given document to the secondary change log of the
  3234. // partition.
  3235. //
  3236. // Arguments: [partid] - PartitionId
  3237. // [wid] - WorkId of the document
  3238. // [volumeId] - Volume id
  3239. // [cSecQRetries] - Sec Q Retry Count
  3240. //
  3241. // History: 5-09-96 srikants Created
  3242. //
  3243. //----------------------------------------------------------------------------
  3244. void CResManager::LokAddToSecQueue( PARTITIONID partid,
  3245. WORKID wid,
  3246. VOLUMEID volumeId,
  3247. ULONG cSecQRetries )
  3248. {
  3249. //
  3250. // No refiling in push filtering
  3251. //
  3252. Win4Assert( !_fPushFiltering );
  3253. CPartition* pPart = _partList.LokGetPartition(partid);
  3254. //==========================================
  3255. CChangeTrans xact( *this, pPart );
  3256. pPart->LokAddToSecQueue (xact, wid, volumeId, cSecQRetries);
  3257. xact.LokCommit();
  3258. //==========================================
  3259. }
  3260. //+---------------------------------------------------------------------------
  3261. //
  3262. // Member: CResManager::LokRefileSecQueueDocs
  3263. //
  3264. // Synopsis: Transfers the documents from the secondary queue to the primary
  3265. // change queue.
  3266. //
  3267. // History: 5-09-96 srikants Created
  3268. //
  3269. //----------------------------------------------------------------------------
  3270. void CResManager::LokRefileSecQueueDocs()
  3271. {
  3272. //
  3273. // No refiling in push filtering
  3274. //
  3275. Win4Assert( !_fPushFiltering );
  3276. CPartIter iter;
  3277. for ( iter.LokInit(_partList); !iter.LokAtEnd(); iter.LokAdvance(_partList))
  3278. {
  3279. CPartition * pPart = iter.LokGet();
  3280. //==========================================
  3281. CChangeTrans xact( *this, pPart );
  3282. pPart->LokRefileSecQueue( xact );
  3283. xact.LokCommit();
  3284. //==========================================
  3285. }
  3286. }
  3287. //+-------------------------------------------------------------------------
  3288. //
  3289. // Member: CResManager::LokTransferWordlist, public
  3290. //
  3291. // Returns: Transfer a wordlist from the filter manager
  3292. // to the content index
  3293. //
  3294. // History: 05-Jan-95 BartoszM Created
  3295. //
  3296. //--------------------------------------------------------------------------
  3297. BOOL CResManager::LokTransferWordlist ( PWordList& pWordList )
  3298. {
  3299. BOOL fSuccess = TRUE;
  3300. PARTITIONID partid = _docList.PartId();
  3301. CPartition* pPart = _partList.LokGetPartition(partid);
  3302. INDEXID iid = pWordList->GetId();
  3303. TRY
  3304. {
  3305. //==========================================
  3306. CIndexTrans xact( *this );
  3307. //
  3308. // LokDone can fail while trying to add unfinished docs to the
  3309. // change log. In that case we must disable further USN updates.
  3310. // We should commit the change transaction immediately after the
  3311. // LokDone succeeds.
  3312. //
  3313. CChangeTrans changeXact( *this, pPart );
  3314. pPart->LokDone ( changeXact, iid, _docList );
  3315. ciFAILTEST( STATUS_NO_MEMORY );
  3316. changeXact.LokCommit();
  3317. _fresh.LokAddIndex ( xact, iid, _activeDeletedIndex.GetIndex(),
  3318. _docList, *pWordList );
  3319. ciDebugOut (( DEB_ITRACE, "CFilterManager::FilterDone "
  3320. "Success: transfering wordlist\n" ));
  3321. pWordList->Done();
  3322. //
  3323. // This may be an empty wordlist: all documents were deleted or in error.
  3324. // If so, just get rid of the wordlist.
  3325. //
  3326. if ( pWordList->IsEmpty() )
  3327. {
  3328. #if CIDBG == 1
  3329. unsigned cShouldHaveData = 0;
  3330. unsigned cDocuments = _docList.Count();
  3331. for ( unsigned iDoc = 0; iDoc < cDocuments; iDoc++ )
  3332. {
  3333. switch ( _docList.Status(iDoc) )
  3334. {
  3335. case TOO_MANY_RETRIES:
  3336. case SUCCESS:
  3337. case TOO_MANY_BLOCKS_TO_FILTER:
  3338. cShouldHaveData++;
  3339. break;
  3340. default:
  3341. break;
  3342. }
  3343. }
  3344. if ( cShouldHaveData != 0 )
  3345. {
  3346. for ( unsigned iDoc = 0; iDoc < cDocuments; iDoc++ )
  3347. {
  3348. ciDebugOut(( DEB_ERROR, "WID: 0x%x STATUS: %d\n",
  3349. _docList.Wid(iDoc), _docList.Status(iDoc) ));
  3350. }
  3351. }
  3352. Win4Assert( cShouldHaveData == 0 );
  3353. #endif
  3354. pWordList.Delete();
  3355. }
  3356. else
  3357. pWordList.Transfer ( pPart );
  3358. xact.LokCommit();
  3359. }
  3360. CATCH ( CException, e )
  3361. {
  3362. ciDebugOut(( DEB_ERROR,
  3363. "Exception 0x%x caught commiting wordlist.\n"
  3364. "delete wordlist and clear doclist\n",
  3365. e.GetErrorCode() ));
  3366. fSuccess = FALSE;
  3367. }
  3368. END_CATCH
  3369. _eventMerge.Set(); // wake up
  3370. return fSuccess;
  3371. }
  3372. //+---------------------------------------------------------------------------
  3373. //
  3374. // Function: LokNoFailRemoveWordlist
  3375. //
  3376. // Synopsis: Removes the biggest wordlist from memory and adds the
  3377. // documents back to the change log.
  3378. //
  3379. // Requires: _docList.Count() == 0 when this method is called. This
  3380. // relies on the fact that there are no other outstanding
  3381. // wordlists being constructed.
  3382. //
  3383. // History: 10-20-94 srikants Added the header section and modified
  3384. // to deal with the change in refiling
  3385. // documents.
  3386. //
  3387. //----------------------------------------------------------------------------
  3388. void CResManager::LokNoFailRemoveWordlist( CPartition * pPart )
  3389. {
  3390. //
  3391. // In push filtering, we don't delete completed wordlist to simplify
  3392. // the logic of aborting the notification transaction on the client
  3393. //
  3394. if ( _isBeingEmptied || _fPushFiltering )
  3395. return;
  3396. //
  3397. // Look for biggest wordlist
  3398. //
  3399. unsigned cInd;
  3400. CIndex ** apIndex = pPart->LokQueryMergeIndexes( cInd, mtWordlist );
  3401. XPtrST<CIndex *> xIndex( apIndex );
  3402. unsigned size = 0;
  3403. CWordList * pWordList = 0;
  3404. for ( unsigned i = 0; i < cInd; i++ )
  3405. {
  3406. apIndex[i]->Release();
  3407. if ( apIndex[i]->Size() > size )
  3408. {
  3409. Win4Assert( apIndex[i]->IsWordlist() );
  3410. pWordList = (CWordList *)apIndex[i];
  3411. size = pWordList->Size();
  3412. }
  3413. }
  3414. if ( pWordList )
  3415. {
  3416. //
  3417. // Reschedule contents for later filtering.
  3418. //
  3419. INDEXID iid = pWordList->GetId();
  3420. ciDebugOut(( DEB_ITRACE,
  3421. "Removing wordlist %x to reduce resource consumption.\n",
  3422. iid ));
  3423. CDocList _docList;
  3424. _docList.SetPartId ( pPart->GetId() );
  3425. pWordList->GetDocuments( _docList );
  3426. #if CIDBG == 1
  3427. for ( unsigned cWid = 0; cWid < _docList.Count(); cWid++ )
  3428. {
  3429. ciDebugOut(( DEB_ITRACE, "Reschedule filtering of wid %d\n",
  3430. _docList.Wid( cWid ) ));
  3431. }
  3432. #endif // CIDBG == 1
  3433. LokNoFailReFileChanges ( _docList );
  3434. //
  3435. // Remove it
  3436. //
  3437. ciDebugOut(( DEB_WARN, "Deleting wordlist with USN (%x, %x).\n",
  3438. lltoHighPart(pWordList->Usn()), (ULONG) pWordList->Usn() ));
  3439. pPart->LokRemoveIndex( iid );
  3440. if ( !pWordList->InUse() )
  3441. {
  3442. _partList.LokRemoveIndex ( iid );
  3443. delete pWordList;
  3444. }
  3445. else
  3446. {
  3447. pWordList->Zombify();
  3448. }
  3449. }
  3450. }
  3451. //+-------------------------------------------------------------------------
  3452. //
  3453. // Member: CResManager::LokMakeWordlistId, public
  3454. //
  3455. // Returns: Makes unique wordlist id
  3456. //
  3457. // History: 05-Jan-95 BartoszM Created
  3458. //
  3459. //--------------------------------------------------------------------------
  3460. INDEXID CResManager::LokMakeWordlistId (PARTITIONID partid)
  3461. {
  3462. CPartition* pPart = _partList.LokGetPartition(partid);
  3463. if ( pPart == 0 )
  3464. return iidInvalid;
  3465. // Get unique index id
  3466. INDEXID iid = pPart->LokMakeWlstId ();
  3467. ciDebugOut((DEB_FILTERWIDS,
  3468. "CResManager::LokMakeWorkListId - new wordlist iid: %x\n", iid));
  3469. return iid;
  3470. }
  3471. //+-------------------------------------------------------------------------
  3472. //
  3473. // Member: CResManager::ReportFilterFailure, public
  3474. //
  3475. // Synopsis: Write to event log about unsuccessful filtering
  3476. //
  3477. // Arguments: [wid] -- workid of the file that couldn't be filtered
  3478. //
  3479. // History: 05-Jan-95 BartoszM Created
  3480. //
  3481. //--------------------------------------------------------------------------
  3482. void CResManager::ReportFilterFailure (WORKID wid)
  3483. {
  3484. PROPVARIANT var;
  3485. var.vt = VT_UI4;
  3486. var.ulVal = wid;
  3487. _adviseStatus->NotifyStatus( CI_NOTIFY_FILTERING_FAILURE,
  3488. 1,
  3489. &var );
  3490. }
  3491. //=========
  3492. // SCANNING
  3493. //=========
  3494. //+---------------------------------------------------------------------------
  3495. //
  3496. // Member: CResManager::SetUpdateLost
  3497. //
  3498. // Synopsis: Sets that an update got lost and wakes up the merge thread
  3499. // to notify the client about it.
  3500. //
  3501. // Arguments: [partId] - Partition id
  3502. //
  3503. // History: 1-24-97 srikants Created
  3504. //
  3505. //----------------------------------------------------------------------------
  3506. void CResManager::SetUpdatesLost( PARTITIONID partId )
  3507. {
  3508. CPriLock lock(_mutex);
  3509. if ( _state.LokGetState() != eUpdatesToBeDisabled )
  3510. {
  3511. _state.LokSetState( eUpdatesToBeDisabled );
  3512. _state.LokSetUpdateType( eIncremental );
  3513. StopCurrentMerge();
  3514. _eventMerge.Set();
  3515. }
  3516. }
  3517. //+---------------------------------------------------------------------------
  3518. //
  3519. // Member: CResManager::LokCleanupForFullCiScan, public
  3520. //
  3521. // History: 10-Nov-94 DwightKr Created
  3522. //
  3523. // Notes: This routine performs the disk I/O and other operations
  3524. // which does the cleanup after a corruption is detected.
  3525. //
  3526. // This routine is similar to the Empty() method, except
  3527. // that we do not delete the change log object or the
  3528. // freshlog object, and the index list must contain
  3529. // the change log and fresh log after the cleanup is complete.
  3530. //
  3531. //----------------------------------------------------------------------------
  3532. void CResManager::LokCleanupForFullCiScan()
  3533. {
  3534. if ( 0 != _pMerge ) // Stop in progress merges.
  3535. _pMerge->LokAbort();
  3536. //
  3537. // Delete everything from the index table here first.
  3538. //
  3539. _idxTab->LokEmpty();
  3540. //
  3541. // If anything fails after this point, chkdsk /f or autochk will
  3542. // release the disk storage associated with the leaked objects
  3543. // since they are no longer part of the persistent index list.
  3544. //
  3545. //
  3546. // For each partition, zombify all indexes, and re-add the change
  3547. // log to the index table on disk.
  3548. //
  3549. CPartIter iter;
  3550. for ( iter.LokInit(_partList);
  3551. !iter.LokAtEnd();
  3552. iter.LokAdvance(_partList))
  3553. {
  3554. CPartition* pPart = iter.LokGet();
  3555. Win4Assert( pPart != NULL );
  3556. pPart->LokDisableUpdates();
  3557. //
  3558. // Zombify all indexes in this partition, and delete them if
  3559. // their ref-count is 0.
  3560. //
  3561. unsigned cIndex;
  3562. CIndex ** aIndex = pPart->LokZombify( cIndex );
  3563. ReleaseIndexes( cIndex, aIndex, NULL );
  3564. delete [] aIndex;
  3565. WORKID widMMergeLog;
  3566. WORKID widDummy;
  3567. pPart->GetMMergeObjectIds( widMMergeLog, widDummy, widDummy );
  3568. if ( widMMergeLog != widInvalid)
  3569. _storage.RemoveObject( widMMergeLog );
  3570. //
  3571. // Empty the fresh test and the fresh log, and add it to the
  3572. // index table on disk.
  3573. //
  3574. pPart->LokEmpty(); // Release change list/log storage
  3575. WORKID oidChangeLog = pPart->GetChangeLogObjectId();
  3576. Win4Assert( oidChangeLog != widInvalid );
  3577. _partList.LokAddIt( oidChangeLog, itChangeLog, pPart->GetId() );
  3578. }
  3579. //
  3580. // Empty the fresh test, fresh log, and add the fresh log to
  3581. // the index table on disk.
  3582. //
  3583. _fresh.LokInit(); // Release fresh test/log storage
  3584. WORKID oidFreshLog = _storage.GetSpecialItObjectId(itFreshLog);
  3585. Win4Assert( oidFreshLog != widInvalid );
  3586. _partList.LokAddIt( oidFreshLog, itFreshLog, partidFresh1 );
  3587. #ifdef KEYLIST_ENABLED
  3588. WORKID widKeyList = _storage.GetSpecialItObjectId( itMMKeyList );
  3589. #else
  3590. WORKID widKeyList = widInvalid;
  3591. #endif // KEYLIST_ENABLED
  3592. WORKID widPhrLat = _storage.GetSpecialItObjectId( itPhraseLat );
  3593. if ( widKeyList != widInvalid)
  3594. {
  3595. _storage.RemoveObject( widKeyList );
  3596. _storage.SetSpecialItObjectId( itMMKeyList, widInvalid );
  3597. }
  3598. if ( widPhrLat != widInvalid)
  3599. {
  3600. _storage.RemoveObject( widPhrLat );
  3601. _storage.SetSpecialItObjectId( itPhraseLat, widInvalid );
  3602. }
  3603. _isBeingEmptied = FALSE; // Allow new queries
  3604. }
  3605. // ===========================================================
  3606. // Content Index Frame Work Interfacing.
  3607. // ===========================================================
  3608. //+---------------------------------------------------------------------------
  3609. //
  3610. // Member: CResManager::WorkidToDocName
  3611. //
  3612. // Synopsis: Converts the given workid to path and fill it in the buffer
  3613. // given.
  3614. //
  3615. // Arguments: [wid] -- Workid to convert.
  3616. // [pbBuf] -- Destination buffer;
  3617. // [cb] -- On input the total number of bytes that can be
  3618. // put. On output, the actual number of bytes copied.
  3619. // For a deleted file, the cb will be 0.
  3620. // [fAccurate] -- TRUE --> Attempt to get a more accurate
  3621. // workid-to-path translation.
  3622. //
  3623. // Returns: TRUE if successfully converted; FALSE means the buffer was
  3624. // not big enough.
  3625. //
  3626. // History: 12-04-96 srikants Created
  3627. //
  3628. // Notes: WorkidToDocName is called outside the resman lock. It is a
  3629. // potentially long operation and taking resman lock is not
  3630. // advisable. Also, creation of a CWorkidToDocName object once
  3631. // for each wid->docName conversion is expensive. So, we create
  3632. // one in resman constructor and protect it with a separate
  3633. // lock.
  3634. //
  3635. //----------------------------------------------------------------------------
  3636. BOOL CResManager::WorkidToDocName( WORKID wid,
  3637. BYTE * pbBuf,
  3638. unsigned & cb,
  3639. BOOL fAccurate )
  3640. {
  3641. CLock lock(_workidToDocNameMutex);
  3642. ULONG cbDocName;
  3643. BYTE const * pbDocName = _xWorkidToDocName->GetDocName( wid, cbDocName, fAccurate );
  3644. BOOL fStatus = TRUE;
  3645. if ( pbDocName )
  3646. {
  3647. ciDebugOut(( DEB_FILTERWIDS | DEB_NOCOMPNAME,
  3648. "WorkidToDocName: wid is %d and DocName is %ws\n",
  3649. wid,
  3650. pbDocName ));
  3651. if ( cbDocName > cb )
  3652. fStatus = FALSE;
  3653. else
  3654. RtlCopyMemory( pbBuf, pbDocName, cbDocName );
  3655. cb = cbDocName;
  3656. }
  3657. else
  3658. {
  3659. cb = 0;
  3660. }
  3661. return fStatus;
  3662. } // WorkidToDocName
  3663. //+---------------------------------------------------------------------------
  3664. //
  3665. // Member: CResManager::GetClientState
  3666. //
  3667. // Synopsis: Gets the client specific status information like total
  3668. // number of documents.
  3669. //
  3670. // Arguments: [cDocuments] - [out] Total # of documents
  3671. //
  3672. // History: 12-04-96 srikants Created
  3673. //
  3674. //----------------------------------------------------------------------------
  3675. void CResManager::GetClientState( ULONG & cDocuments )
  3676. {
  3677. CI_CLIENT_STATUS status;
  3678. SCODE sc = _docStore->GetClientStatus( &status );
  3679. if ( S_OK == sc )
  3680. {
  3681. cDocuments = status.cDocuments;
  3682. }
  3683. else
  3684. {
  3685. cDocuments = 0;
  3686. }
  3687. }
  3688. //+---------------------------------------------------------------------------
  3689. //
  3690. // Member: CResManager::LokNotifyCorruptionToClient
  3691. //
  3692. // Synopsis: Informs the client that the catalog is corrupt
  3693. //
  3694. // History: 12-04-96 srikants Created
  3695. //
  3696. //----------------------------------------------------------------------------
  3697. void CResManager::LokNotifyCorruptionToClient()
  3698. {
  3699. Win4Assert( _isCorrupt );
  3700. DisableUpdates( partidDefault );
  3701. SCODE sc = _docStore->DisableUpdates( FALSE, CI_CORRUPT_INDEX );
  3702. if ( SUCCEEDED( sc ) )
  3703. _state.LokSetCorruptionNotified();
  3704. //
  3705. // Disabled following assert so that the general NT 5 user is not
  3706. // bothered by this assert.
  3707. //
  3708. //Win4Assert( ! "We must empty the Content Index" );
  3709. // Empty();
  3710. }
  3711. //+---------------------------------------------------------------------------
  3712. //
  3713. // Member: CResManager::LokNotifyDisableUpdatesToClient
  3714. //
  3715. // Synopsis: Informs the client that updates should be disabled
  3716. //
  3717. // History: 07-05-97 SitaramR Created
  3718. //
  3719. //----------------------------------------------------------------------------
  3720. void CResManager::LokNotifyDisableUpdatesToClient()
  3721. {
  3722. Win4Assert( _state.LokGetState() == eUpdatesToBeDisabled );
  3723. DisableUpdates( partidDefault );
  3724. BOOL fIncremental = _state.LokGetUpdateType() == eIncremental;
  3725. SCODE sc = _docStore->DisableUpdates( fIncremental, CI_LOST_UPDATE );
  3726. if ( SUCCEEDED(sc) )
  3727. {
  3728. ciDebugOut(( DEB_WARN, "Notified disabled updates to DocStore\n" ));
  3729. _state.LokSetState( eUpdatesDisabled );
  3730. }
  3731. }
  3732. //+---------------------------------------------------------------------------
  3733. //
  3734. // Member: CResManager::LokNotifyEnableUpdatesToClient
  3735. //
  3736. // Synopsis: Informs the client that updates should be enabled
  3737. //
  3738. // History: 07-05-97 SitaramR Created
  3739. //
  3740. //----------------------------------------------------------------------------
  3741. void CResManager::LokNotifyEnableUpdatesToClient()
  3742. {
  3743. Win4Assert( _state.LokGetState() == eUpdatesToBeEnabled );
  3744. EnableUpdates( partidDefault );
  3745. SCODE sc = _docStore->EnableUpdates();
  3746. if ( SUCCEEDED(sc) )
  3747. {
  3748. ciDebugOut(( DEB_WARN, "Notified enable updates to DocStore\n" ));
  3749. _state.LokSetState( eSteady );
  3750. }
  3751. }
  3752. //+---------------------------------------------------------------------------
  3753. //
  3754. // Member: CResManager::StoreValue
  3755. //
  3756. // Synopsis: Stores the given value in the document store
  3757. //
  3758. // Arguments: [wid] - WorkId of the document
  3759. // [ps] - The FULLPROPSPEC of the property
  3760. // [var] - Value of the property
  3761. // [fInSchema] - Returns TRUE if the property is in the schema
  3762. //
  3763. // Returns: SCODE result
  3764. //
  3765. // History: 12-18-96 srikants Created
  3766. //
  3767. //----------------------------------------------------------------------------
  3768. SCODE CResManager::StoreValue( WORKID wid,
  3769. CFullPropSpec const & ps,
  3770. CStorageVariant const & var,
  3771. BOOL & fInSchema )
  3772. {
  3773. FULLPROPSPEC const * fps = ps.CastToStruct();
  3774. PROPVARIANT const * pVar = ConvertToPropVariant( &var );
  3775. // Default to TRUE since the return code isn't checked!
  3776. fInSchema = TRUE;
  3777. SCODE sc = _propStore->StoreProperty( wid, fps, pVar );
  3778. if ( CI_E_PROPERTY_NOT_CACHED == sc )
  3779. fInSchema = FALSE;
  3780. else if ( FAILED( sc ) )
  3781. return sc;
  3782. return S_OK;
  3783. }
  3784. BOOL CResManager::StoreSecurity( WORKID wid,
  3785. PSECURITY_DESCRIPTOR pSD,
  3786. ULONG cbSD )
  3787. {
  3788. return S_OK == _docStore->StoreSecurity( wid, (BYTE *) pSD, cbSD );
  3789. }
  3790. //+---------------------------------------------------------------------------
  3791. //
  3792. // Member: CResManager::FPSToPROPID, public
  3793. //
  3794. // Synopsis: Converts FULLPROPSPEC property to PROPID
  3795. //
  3796. // Arguments: [fps] -- FULLPROPSPEC representation of property
  3797. // [pid] -- PROPID written here on success
  3798. //
  3799. // Returns: S_OK on success
  3800. //
  3801. // History: 29-Dec-1997 KyleP Created.
  3802. //
  3803. //----------------------------------------------------------------------------
  3804. SCODE CResManager::FPSToPROPID( CFullPropSpec const & fps, PROPID & pid )
  3805. {
  3806. return _mapper->PropertyToPropid( fps.CastToStruct(), TRUE, &pid );
  3807. }
  3808. //
  3809. // Flush notify support
  3810. //
  3811. //+---------------------------------------------------------------------------
  3812. //
  3813. // Member: CResManager::NotifyFlush
  3814. //
  3815. // Synopsis: Notifies the client that changes got flushed and gives the
  3816. // flush information.
  3817. //
  3818. // Arguments: [ft] - FileTime of the last successful flush.
  3819. // [cEntries] - Number of entries in the aInfo
  3820. // [aInfo] - Array of USN information for the flush.
  3821. //
  3822. // History: 1-27-97 srikants Created
  3823. //
  3824. // Note: We should not call directly into framework client because
  3825. // it violates resman->client lock hierarchy. We should not call
  3826. // into client with resman lock held.
  3827. //
  3828. //----------------------------------------------------------------------------
  3829. void CResManager::NotifyFlush( FILETIME const & ft,
  3830. ULONG cEntries,
  3831. USN_FLUSH_INFO ** ppInfo )
  3832. {
  3833. if ( !_fPushFiltering )
  3834. {
  3835. //
  3836. // Notification of flushes are sent in pull filtering only.
  3837. // For push filtering, the ICiCIndexNotificationStatus
  3838. // interface is used to notify clients.
  3839. //
  3840. CPriLock lock(_mutex);
  3841. CChangesFlushNotifyItem * pItem =
  3842. new CChangesFlushNotifyItem( ft, cEntries, ppInfo );
  3843. _flushList.Queue( pItem );
  3844. if (! _fFlushWorkerActive)
  3845. {
  3846. CFwFlushNotify * pWorkItem = new CFwFlushNotify( _workMan, *this );
  3847. _workMan.AddToWorkList( pWorkItem );
  3848. pWorkItem->AddToWorkQueue();
  3849. pWorkItem->Release();
  3850. }
  3851. }
  3852. } //NotifyFlush
  3853. //+---------------------------------------------------------------------------
  3854. //
  3855. // Member: CResManager::ProcessFlushNotifies
  3856. //
  3857. // Synopsis: Processes the queued flush notifies in a FIFO order. This
  3858. // method is called only by the asynchronous worker thread
  3859. // responsible for notifying the client about flushes.
  3860. //
  3861. // History: 1-27-97 srikants Created
  3862. //
  3863. //----------------------------------------------------------------------------
  3864. void CResManager::ProcessFlushNotifies()
  3865. {
  3866. //
  3867. // Only one worker thread allowed to operate on the list at a time.
  3868. //
  3869. CLock lock (_mtxChangeFlush );
  3870. CRevertBoolValue RevertFlushActive( _fFlushWorkerActive, TRUE );
  3871. while ( TRUE )
  3872. {
  3873. CChangesFlushNotifyItem * pItem = 0;
  3874. //
  3875. // Remove the first flush item from the list under resman lock.
  3876. //
  3877. //===========================================
  3878. {
  3879. CPriLock lock(_mutex);
  3880. pItem = _flushList.GetFirst();
  3881. if ( pItem )
  3882. _flushList.Pop();
  3883. if (_flushList.IsEmpty())
  3884. RevertFlushActive.Revert();
  3885. }
  3886. //===========================================
  3887. if ( pItem )
  3888. {
  3889. SCODE sc = _docStore->CheckPointChangesFlushed(
  3890. pItem->GetFlushTime(),
  3891. pItem->GetCount(),
  3892. pItem->GetFlushInfo() );
  3893. if ( FAILED(sc) )
  3894. {
  3895. //
  3896. // We don't have to requeue this item. The client's restart
  3897. // work will just increase.
  3898. //
  3899. ciDebugOut(( DEB_ERROR,
  3900. "CheckPointChangesFlushed failed. Error (0x%X)\n",
  3901. sc ));
  3902. }
  3903. pItem->Close();
  3904. delete pItem;
  3905. }
  3906. else
  3907. {
  3908. break;
  3909. }
  3910. } // While (TRUE)
  3911. } //ProcessFlushNotifies
  3912. //+---------------------------------------------------------------------------
  3913. //
  3914. // Member: CResManager::_LokDeleteFlushWorkItems
  3915. //
  3916. // Synopsis: Deletes the flush notifies in the queue. This is called
  3917. // during shutdown (dismount) to clean up any asynchronous
  3918. // worker threads referring to resman.
  3919. //
  3920. // History: 1-27-97 srikants Created
  3921. //
  3922. //----------------------------------------------------------------------------
  3923. void CResManager::LokDeleteFlushWorkItems()
  3924. {
  3925. for ( CChangesFlushNotifyItem * pItem = _flushList.Pop();
  3926. 0 != pItem;
  3927. pItem = _flushList.Pop() )
  3928. {
  3929. pItem->Close();
  3930. delete pItem;
  3931. }
  3932. } //LokDeleteFlushWorkItems
  3933. //+---------------------------------------------------------------------------
  3934. //
  3935. // Member: CResManager::NoFailAbortWidsInDocList
  3936. //
  3937. // Synopsis: Used in push filtering to abort all wids in the current
  3938. // doclist
  3939. //
  3940. // History: 24-Feb-97 SitaramR Created
  3941. //
  3942. //----------------------------------------------------------------------------
  3943. void CResManager::NoFailAbortWidsInDocList()
  3944. {
  3945. CPriLock lock ( _mutex );
  3946. if ( _isBeingEmptied )
  3947. return ;
  3948. for ( unsigned i=0; i<_docList.Count(); i++ )
  3949. {
  3950. WORKID wid = _docList.Wid(i);
  3951. USN usn = _docList.Usn(i);
  3952. //
  3953. // Abort the client transaction
  3954. //
  3955. _xIndexNotifTable->AbortWid( wid, usn );
  3956. //
  3957. // Keep track of aborted wids for use during
  3958. // changlog shrink from front.
  3959. //
  3960. _aAbortedWids.NoFailLokAddWid( wid, usn );
  3961. }
  3962. _docList.LokClear();
  3963. } //NoFailAbortWidsInDocList
  3964. //+---------------------------------------------------------------------------
  3965. //
  3966. // Member: CResManager::NoFailAbortWid
  3967. //
  3968. // Synopsis: Used in push filtering to abort a wid
  3969. //
  3970. // Arguments: [wid] -- Workid
  3971. // [usn] -- Usn
  3972. //
  3973. // History: 24-Feb-97 SitaramR Created
  3974. //
  3975. //----------------------------------------------------------------------------
  3976. void CResManager::NoFailAbortWid( WORKID wid, USN usn )
  3977. {
  3978. CPriLock lock ( _mutex );
  3979. if ( _isBeingEmptied )
  3980. return ;
  3981. //
  3982. // Abort the client transaction
  3983. //
  3984. _xIndexNotifTable->AbortWid( wid, usn );
  3985. //
  3986. // Keep track of aborted wid for use during
  3987. // changlog shrink from front.
  3988. //
  3989. _aAbortedWids.NoFailLokAddWid( wid, usn );
  3990. } //NoFailAbortWid
  3991. //+---------------------------------------------------------------------------
  3992. //
  3993. // Member: CResManager::ClearNonStoragePropertiesForWid
  3994. //
  3995. // Synopsis: Clear non-storage properties from the property storage for wid
  3996. //
  3997. // Arguments: [wid] -- Workid
  3998. //
  3999. // History: 10-Oct-2000 KitmanH Created
  4000. //
  4001. //----------------------------------------------------------------------------
  4002. SCODE CResManager::ClearNonStoragePropertiesForWid( WORKID wid )
  4003. {
  4004. return _propStore->ClearNonStoragePropertiesForWid( wid );
  4005. }
  4006. //====================
  4007. // MASTER MERGE POLICY
  4008. //====================
  4009. //+---------------------------------------------------------------------------
  4010. //
  4011. // Member: CMasterMergePolicy::IsTimeToMasterMerge, public
  4012. //
  4013. // Synopsis: Determines if the system should start a master merge
  4014. // immediately, and not wait until the master merge time.
  4015. //
  4016. // History: 4-Aug-94 DwightKr Created
  4017. //
  4018. // Notes: If new tests are added simply add them here.
  4019. //
  4020. //----------------------------------------------------------------------------
  4021. BOOL CMasterMergePolicy::IsTimeToMasterMerge() const
  4022. {
  4023. return IsMaxShadowIndexSize() ||
  4024. IsMaxFreshListCount() ||
  4025. IsMinDiskFreeForceMerge();
  4026. }
  4027. //+---------------------------------------------------------------------------
  4028. //
  4029. // Member: CMasterMergePolicy::IsMinDiskFreeForceMerge, private
  4030. //
  4031. // Synopsis: If the amount of free disk space is lower than a threshold,
  4032. // then we should master merge, since it is likely that disk
  4033. // space will be released.
  4034. //
  4035. // History: 4-Aug-94 DwightKr Created
  4036. // Jan-07-96 mohamedn CDmFwEventItem
  4037. //
  4038. //----------------------------------------------------------------------------
  4039. BOOL CMasterMergePolicy::IsMinDiskFreeForceMerge() const
  4040. {
  4041. //
  4042. // If we've exceeded the MIN_DISKFREE_FORCE_MERGE space used on
  4043. // the system, and a master merge has the potential to make some
  4044. // useful progress, then it's time to force a master merge. The
  4045. // values of MIN_DISKFREE_FORCE_MERGE and MAX_SHADOW_FREESPACE
  4046. // are expressed as a percentage.
  4047. //
  4048. __int64 diskTotal, diskRemaining;
  4049. _storage.GetDiskSpace( diskTotal, diskRemaining );
  4050. if ( diskRemaining < minDiskFreeForMerge )
  4051. return FALSE;
  4052. if (diskRemaining*100/diskTotal < _frmwrkParams.GetMinDiskFreeForceMerge() &&
  4053. _shadowIndexSize*100/diskRemaining > _frmwrkParams.GetMaxShadowFreeForceMerge() )
  4054. {
  4055. CDmFwEventItem item( EVENTLOG_INFORMATION_TYPE,
  4056. MSG_CI_MASTER_MERGE_STARTED_TOTAL_DISK_SPACE_USED,
  4057. 2);
  4058. item.AddArg( _storage.GetVolumeName() );
  4059. item.AddArg( _frmwrkParams.GetMinDiskFreeForceMerge() );
  4060. item.ReportEvent(_adviseStatus);
  4061. ciDebugOut(( DEB_ITRACE | DEB_PENDING,
  4062. "Master merge, reason: Low on disk space\n" ));
  4063. return TRUE;
  4064. }
  4065. return FALSE;
  4066. }
  4067. //+---------------------------------------------------------------------------
  4068. //
  4069. // Member: CMasterMergePolicy::IsMaxFreshListCount, private
  4070. //
  4071. // Synopsis: If the number of entries in the fresh list is great than
  4072. // a threshold, we should master merge, and free up memory
  4073. // occupied by the fresh hash.
  4074. //
  4075. // History: 4-Aug-94 DwightKr Created
  4076. // Jan-07-96 mohamedn CDmFwEventItem
  4077. //
  4078. //----------------------------------------------------------------------------
  4079. BOOL CMasterMergePolicy::IsMaxFreshListCount() const
  4080. {
  4081. if ( _freshCount > _frmwrkParams.GetMaxFreshCount() )
  4082. {
  4083. CDmFwEventItem item( EVENTLOG_INFORMATION_TYPE,
  4084. MSG_CI_MASTER_MERGE_STARTED_FRESH_LIST_COUNT,
  4085. 2);
  4086. item.AddArg( _storage.GetVolumeName() );
  4087. item.AddArg( _frmwrkParams.GetMaxFreshCount() );
  4088. item.ReportEvent(_adviseStatus);
  4089. ciDebugOut(( DEB_ITRACE | DEB_PENDING,
  4090. "Master merge, reason: More than %d entries in freshhash\n",
  4091. _frmwrkParams.GetMaxFreshCount() ));
  4092. return TRUE;
  4093. }
  4094. return FALSE;
  4095. }
  4096. //+---------------------------------------------------------------------------
  4097. //
  4098. // Member: CMasterMergePolicy::IsMaxShadowIndexSize, private
  4099. //
  4100. // Synopsis: If the combined size of all shadow indexes is greater than
  4101. // a threahold, we should master merge, and free up disk space.
  4102. // The content index should not take up more than a given
  4103. // percentage of disk space.
  4104. //
  4105. // History: 4-Aug-94 DwightKr Created
  4106. // Jan-07-96 mohamedn CDmFwEventItem
  4107. //
  4108. //----------------------------------------------------------------------------
  4109. BOOL CMasterMergePolicy::IsMaxShadowIndexSize() const
  4110. {
  4111. __int64 diskTotal, diskRemaining;
  4112. _storage.GetDiskSpace( diskTotal, diskRemaining );
  4113. if ( diskRemaining < minDiskFreeForMerge )
  4114. return FALSE;
  4115. if ( _shadowIndexSize*100/diskTotal > _frmwrkParams.GetMaxShadowIndexSize() )
  4116. {
  4117. CDmFwEventItem item( EVENTLOG_INFORMATION_TYPE,
  4118. MSG_CI_MASTER_MERGE_STARTED_SHADOW_INDEX_SIZE,
  4119. 2);
  4120. item.AddArg( _storage.GetVolumeName() );
  4121. item.AddArg( _frmwrkParams.GetMaxShadowIndexSize() );
  4122. item.ReportEvent(_adviseStatus);
  4123. ciDebugOut(( DEB_ITRACE | DEB_PENDING,
  4124. "Master merge, reason: Combined shadow indexes > %d%% of disk\n",
  4125. _frmwrkParams.GetMaxShadowIndexSize() ));
  4126. return TRUE;
  4127. }
  4128. return FALSE;
  4129. }
  4130. //+---------------------------------------------------------------------------
  4131. //
  4132. // Method: CMasterMergePolicy::ComputeMidNightMergeTime
  4133. //
  4134. // Synopsis: Function to compute the time (in hundreds of nanoseconds
  4135. // from midnight Dec 31, 1969) for the next master merge based on
  4136. // the value given from registry.
  4137. //
  4138. // Arguments: [mergeTime] - The time read from the registry control params.
  4139. // It's an offset in minutes after midnight.
  4140. //
  4141. // Returns: LONG - time for next merge
  4142. //
  4143. // History: 19-Feb-1996 srikants Moved the code from svcfilt.cxx
  4144. // 17-Nov-1999 KyleP Stop using CRT
  4145. //
  4146. // Notes: If the time is before January 1, 1970 it will return -1.
  4147. //
  4148. //----------------------------------------------------------------------------
  4149. ULONGLONG CMasterMergePolicy::ComputeMidNightMergeTime( LONG mergeTime )
  4150. {
  4151. Win4Assert( mergeTime < 24 * 60 );
  4152. mergeTime *= 60;
  4153. //
  4154. // What time is it here?
  4155. //
  4156. SYSTEMTIME stLocal;
  4157. GetLocalTime( &stLocal );
  4158. LONG lNow = stLocal.wHour*60*60 + stLocal.wMinute*60 + stLocal.wSecond;
  4159. //
  4160. // Have we passed the daily merge time?
  4161. //
  4162. LONGLONG llHNSTilMerge; // Hundred-Nano-Second-Til-Merge
  4163. LONGLONG const llHNSOneDay = 24*60*60*10000000i64;
  4164. if ( lNow < mergeTime )
  4165. llHNSTilMerge = mergeTime * 10000000i64;
  4166. else
  4167. llHNSTilMerge = mergeTime * 10000000i64 + llHNSOneDay;
  4168. //
  4169. // Create the *local* filetime for the next merge
  4170. //
  4171. stLocal.wHour = 0;
  4172. stLocal.wMinute = 0;
  4173. stLocal.wSecond = 0;
  4174. stLocal.wMilliseconds = 1;
  4175. FILETIME ftLocal;
  4176. if ( !SystemTimeToFileTime( &stLocal, &ftLocal ) )
  4177. return -1;
  4178. ((ULARGE_INTEGER *)&ftLocal)->QuadPart += llHNSTilMerge;
  4179. //
  4180. // Now, adjust to UTC and return
  4181. //
  4182. FILETIME ft;
  4183. if ( !LocalFileTimeToFileTime( &ftLocal, &ft ) )
  4184. return -1;
  4185. #if CIDBG == 1
  4186. FILETIME ft2;
  4187. GetSystemTimeAsFileTime( &ft2 );
  4188. Win4Assert( ((ULARGE_INTEGER *)&ft2)->QuadPart < ((ULARGE_INTEGER *)&ft)->QuadPart );
  4189. #endif // CIDBG
  4190. return ((ULARGE_INTEGER *)&ft)->QuadPart;
  4191. } //ComputeMidNightMergeTime
  4192. //+---------------------------------------------------------------------------
  4193. //
  4194. // Member: CMasterMergePolicy::IsMidNightMergeTime, public
  4195. //
  4196. // Synopsis: Determines if it's been 24 hours since the last merge time
  4197. //
  4198. // History: 4-Aug-1994 DwightKr Created
  4199. // 17-Nov-1999 KyleP Stop using CRT
  4200. //
  4201. //----------------------------------------------------------------------------
  4202. BOOL CMasterMergePolicy::IsMidNightMergeTime()
  4203. {
  4204. FILETIME ft;
  4205. GetSystemTimeAsFileTime( &ft );
  4206. if ( ((ULARGE_INTEGER *)&ft)->QuadPart > _mergeTime )
  4207. {
  4208. ULONG mergeTime = _frmwrkParams.GetMasterMergeTime();
  4209. ULONGLONG oldMergeTime = _mergeTime;
  4210. _mergeTime = ComputeMidNightMergeTime( mergeTime );
  4211. //
  4212. // If it's been more than 30 minutes since the master merge time, don't
  4213. // do it. This can happen if we were doing a master merge as part of
  4214. // indexing documents or if you turn on a machine in the morning and it
  4215. // was off at the master merge time.
  4216. //
  4217. LONGLONG const llHNSHalfHour = 30*60*10000000i64;
  4218. if ( ((ULARGE_INTEGER *)&ft)->QuadPart > ( oldMergeTime + llHNSHalfHour ) )
  4219. return FALSE;
  4220. return TRUE;
  4221. }
  4222. return FALSE;
  4223. } //IsMidNightMergeTime