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.

1158 lines
34 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 2000.
  5. //
  6. // File: scanmgr.cxx
  7. //
  8. // Contents: Scan manager
  9. //
  10. // History: 14-Jul-97 SitaramR Created from dlnotify.cxx
  11. //
  12. // Notes : For lock hierarchy and order of acquiring locks, please see
  13. // cicat.cxx
  14. //
  15. // DISKFULL HANDLING
  16. //
  17. // The disk full situation is either detected in RESMAN and information sent
  18. // up to CICAT or a DISKFULL error is first detected in CICAT and then
  19. // propagated to RESMAN. As part of diskfull processing in the scope table,
  20. // existing scans are aborted in scanmanager and future scans are disabled
  21. // until the diskfull gets cleared up. If DISKFULL is detected at startup
  22. // time, the scope table enters a "incremental scan required" state and doesn't
  23. // schedule any scans/notifications until the situation improves.
  24. //
  25. // If the changelog loses a notification, a DisableUpdates notification is sent
  26. // to the DocStore. The scan is deferred until an EnableUpdates notification
  27. // is sent to DocStore.
  28. //
  29. //----------------------------------------------------------------------------
  30. #include <pch.cxx>
  31. #pragma hdrstop
  32. #include <ciregkey.hxx>
  33. #include <cistore.hxx>
  34. #include <rcstxact.hxx>
  35. #include <imprsnat.hxx>
  36. #include <eventlog.hxx>
  37. #include <docstore.hxx>
  38. #include "cicat.hxx"
  39. #include "update.hxx"
  40. #include "notifmgr.hxx"
  41. #include "scanmgr.hxx"
  42. #include "scopetbl.hxx"
  43. //+---------------------------------------------------------------------------
  44. //
  45. // Member: CCiScanMgr::CCiScanMgr
  46. //
  47. // Synopsis: ~ctor of the scan manager for downlevel CI. It starts a
  48. // background thread for doing the scans.
  49. //
  50. // Arguments: [cicat] -
  51. //
  52. // History: 1-19-96 srikants Created
  53. // 3-03-98 kitmanh Initialized member _fIsReadOnly with
  54. // cicat.IsReadOnly
  55. //
  56. // Notes:
  57. //
  58. //----------------------------------------------------------------------------
  59. CCiScanMgr::CCiScanMgr( CiCat & cicat ) :
  60. _cicat(cicat),
  61. _fAbort(FALSE),
  62. _fSerializeChanges(FALSE),
  63. _state(eStart),
  64. #pragma warning( disable : 4355 ) // this used in base initialization
  65. _thrScan( ScanThread, this, TRUE ), // create suspended
  66. #pragma warning( default : 4355 )
  67. _fBatch(FALSE), // disable batch processing
  68. _fAbortScan(FALSE),
  69. _fScanDisabled(FALSE),
  70. _fIsReadOnly(cicat.IsReadOnly()),
  71. _dwLastShareSynch( 0 )
  72. {
  73. _evtScan.Reset();
  74. _thrScan.SetPriority( THREAD_PRIORITY_BELOW_NORMAL );
  75. }
  76. CCiScanMgr::~CCiScanMgr()
  77. {
  78. InitiateShutdown();
  79. WaitForShutdown();
  80. // delete any in-progress scan info
  81. CLock lock( _mutex );
  82. while ( !_scansInProgress.IsEmpty() )
  83. {
  84. delete _scansInProgress.RemoveLast();
  85. }
  86. }
  87. //+---------------------------------------------------------------------------
  88. //
  89. // Member: CCiScanMgr::StartRecovery
  90. //
  91. // Synopsis: Sets the state to indicate that recovery must be done
  92. // and wakes up the scan thread.
  93. //
  94. // History: 3-06-96 srikants Created
  95. //
  96. //----------------------------------------------------------------------------
  97. void CCiScanMgr::StartRecovery()
  98. {
  99. CLock lock(_mutex);
  100. Win4Assert( eStart == _state );
  101. _state = eDoRecovery;
  102. _evtScan.Set();
  103. }
  104. //+---------------------------------------------------------------------------
  105. //
  106. // Member: CCiScanMgr::StartScansAndNotifies
  107. //
  108. // Synopsis: Initiates scans and notifications in the document store.
  109. //
  110. // History: 12-09-96 srikants Created
  111. //
  112. //----------------------------------------------------------------------------
  113. void CCiScanMgr::StartScansAndNotifies()
  114. {
  115. CLock lock(_mutex);
  116. Win4Assert( eRecovered == _state );
  117. _state = eStartScans;
  118. _evtScan.Set();
  119. }
  120. //+---------------------------------------------------------------------------
  121. //
  122. // Member: CCiScanMgr::_LokIsScanScheduled
  123. //
  124. // Synopsis: Tests if the given scope is already scheduled for a scan.
  125. //
  126. // Arguments: [xScanInfo] - Smart pointer to scaninfo
  127. //
  128. // History: 2-26-96 srikants Created
  129. //
  130. //----------------------------------------------------------------------------
  131. BOOL CCiScanMgr::_LokIsScanScheduled( const XPtr<CCiScanInfo> & xScanInfo )
  132. {
  133. WCHAR const * pwszNewScope = xScanInfo->GetPath();
  134. unsigned lenNewScope = wcslen( pwszNewScope );
  135. for ( CFwdScanInfoIter scanInfoIter(_scansToDo);
  136. !_scansToDo.AtEnd(scanInfoIter);
  137. _scansToDo.Advance(scanInfoIter) )
  138. {
  139. if ( xScanInfo->LokGetWorkType() == scanInfoIter->LokGetWorkType() )
  140. {
  141. WCHAR const * pwszPath = scanInfoIter->GetPath();
  142. CScopeMatch scope( pwszPath, wcslen(pwszPath) );
  143. if (scope.IsInScope( pwszNewScope, lenNewScope ))
  144. {
  145. ciDebugOut(( DEB_ITRACE,"Scan already scheduled for (%ws)\n",
  146. pwszNewScope ));
  147. return TRUE;
  148. }
  149. }
  150. }
  151. return FALSE;
  152. }
  153. //+---------------------------------------------------------------------------
  154. //
  155. // Member: CCiScanMgr::ScanScope
  156. //
  157. // Synopsis: Adds the given scope to the list of scopes to scan.
  158. //
  159. // Arguments: [xScanInfo] - Will be acquired from the safe pointer if
  160. // successfully taken over.
  161. // [fDelayed] - Set to TRUE if the scan must not be done
  162. // immediately.
  163. // [fRefiled] - Set to TRUE if this is a refile or retry scan
  164. //
  165. // History: 1-23-96 srikants Created
  166. //
  167. // Notes:
  168. //
  169. //----------------------------------------------------------------------------
  170. void CCiScanMgr::ScanScope(
  171. XPtr<CCiScanInfo> & xScanInfo,
  172. BOOL fDelayed,
  173. BOOL fRefiled )
  174. {
  175. CLock lock( _mutex );
  176. if ( xScanInfo->GetRetries() <= CCiScanInfo::MAX_RETRIES &&
  177. !_LokIsScanScheduled( xScanInfo ) )
  178. {
  179. Win4Assert( !xScanInfo->LokIsInFinalState() );
  180. Win4Assert( xScanInfo->LokIsInScan()
  181. || xScanInfo->LokIsDelScope()
  182. || xScanInfo->LokIsRenameDir() );
  183. if ( fRefiled )
  184. {
  185. //
  186. // A scan that has been refiled should be done before new scans
  187. // to ensure that all scans are done in FIFO order.
  188. //
  189. _scansToDo.Push( xScanInfo.GetPointer() );
  190. }
  191. else
  192. _scansToDo.Queue( xScanInfo.GetPointer() );
  193. xScanInfo.Acquire();
  194. if ( !fDelayed )
  195. _evtScan.Set();
  196. }
  197. else
  198. {
  199. xScanInfo.Free();
  200. }
  201. }
  202. //+---------------------------------------------------------------------------
  203. //
  204. // Member: CCiScanMgr::DirAddNotification
  205. //
  206. // Synopsis: Schedules the scan of a new directory
  207. //
  208. // Arguments: [pwcsDirName] - Directory added
  209. //
  210. // History: 20-Mar-96 SitaramR Added header
  211. //
  212. //----------------------------------------------------------------------------
  213. void CCiScanMgr::DirAddNotification( WCHAR const *pwcsDirName )
  214. {
  215. //
  216. // Force a full scan of the direcotry, because the directory is new and so
  217. // it cannot have been scanned before
  218. //
  219. XPtr<CCiScanInfo> xScanInfo( _QueryScanInfo( pwcsDirName,
  220. _cicat.GetPartition(),
  221. UPD_FULL,
  222. FALSE ) );
  223. xScanInfo->SetScan();
  224. xScanInfo->SetProcessRoot();
  225. //---------------------------------------------------------
  226. {
  227. CLock lock( _mutex );
  228. _scansToDo.Queue( xScanInfo.GetPointer() );
  229. xScanInfo.Acquire();
  230. _evtScan.Set(); // Wake up the scan thread
  231. }
  232. //---------------------------------------------------------
  233. }
  234. //+---------------------------------------------------------------------------
  235. //
  236. // Member: CCiScanMgr::DirRenameNotification
  237. //
  238. // Synopsis: Schedules the scan of a rename directory notification
  239. //
  240. // Arguments: [pwcsDirOldName] - Previous name of irectory
  241. // [pwcsDirNewName] - New name of directory
  242. //
  243. // History: 20-Mar-96 SitaramR Added header
  244. //
  245. //----------------------------------------------------------------------------
  246. void CCiScanMgr::DirRenameNotification( WCHAR const *pwcsDirOldName,
  247. WCHAR const *pwcsDirNewName )
  248. {
  249. BOOL fRenameScheduled = FALSE;
  250. CLock lock( _mutex );
  251. for ( CFwdScanInfoIter scanInfoIter( _scansToDo );
  252. !_scansToDo.AtEnd( scanInfoIter );
  253. _scansToDo.Advance( scanInfoIter ) )
  254. {
  255. //
  256. // if dirA is renamed to dirB, and then dirB is renamed to dirC, then it is
  257. // the same as dirA being renamed to dirC.
  258. //
  259. // Note: if dirA is renamed to dirB, and then dirB is renamed to dirA, we don't
  260. // cancel the two renames because it may not yield the same original state. For
  261. // example, after the first rename if a file, say file1, below dirB is deleted, and
  262. // then dirB is renamed to dirA, then since the strings table is not aware of the
  263. // file dirB\file1, no action will be taken, ie the file won't be deleted. By
  264. // scheduling the two renames one after another the wid corresponding to dirB\file1
  265. // will be correctly deleted.
  266. //
  267. if ( scanInfoIter->LokIsRenameDir()
  268. && AreIdenticalPaths( scanInfoIter->GetPath(), pwcsDirOldName )
  269. && !AreIdenticalPaths( scanInfoIter->GetDirOldName(), pwcsDirNewName ) ) // See note above
  270. {
  271. //
  272. // By overwriting dirC over dirB (see example above), we have combined the two rename
  273. // operations into one rename operation
  274. //
  275. scanInfoIter->LokSetPath( pwcsDirNewName );
  276. fRenameScheduled = TRUE;
  277. break;
  278. }
  279. }
  280. if ( !fRenameScheduled )
  281. {
  282. XPtr<CCiScanInfo> xScanInfo( _QueryScanInfo( pwcsDirNewName,
  283. _cicat.GetPartition(),
  284. UPD_INCREM,
  285. FALSE ) );
  286. xScanInfo->SetRenameDir();
  287. xScanInfo->SetDirOldName( pwcsDirOldName );
  288. ScanScope( xScanInfo, TRUE, FALSE );
  289. //
  290. // If this rename operation is interrupted in the middle (because of a
  291. // subsequent delete or rename) then files/wids under the old directory may
  292. // still be lying around in the property store. To ensure that all such
  293. // files/wids are removed, schedule a remove operation for the old directory
  294. // name.
  295. //
  296. _LokScheduleRemove( pwcsDirOldName );
  297. }
  298. }
  299. //+---------------------------------------------------------------------------
  300. //
  301. // Member: CCiScanMgr::_QueryScanInfo
  302. //
  303. // Synopsis: Returns a new instance of CCiScanInfo
  304. //
  305. // Arguments: [pwcsScope] -- Scope
  306. // [partId] -- Partition id
  307. // [updFlag] -- Incremental or full update
  308. // [fDoDeletions] -- Shoud deletions be done ?
  309. // [fNewScope] -- TRUE if a new scope
  310. //
  311. // History: 20-Mar-96 SitaramR Added header
  312. //
  313. //----------------------------------------------------------------------------
  314. CCiScanInfo *
  315. CCiScanMgr::_QueryScanInfo( WCHAR const * pwcsScope,
  316. PARTITIONID partId,
  317. ULONG updFlag,
  318. BOOL fDoDeletions,
  319. BOOL fNewScope )
  320. {
  321. Win4Assert( 0 != pwcsScope );
  322. ULONG len = wcslen( pwcsScope );
  323. Win4Assert( pwcsScope[len-1] == L'\\' );
  324. XArray<WCHAR> xPath( len+1 );
  325. RtlCopyMemory( xPath.Get(), pwcsScope, xPath.SizeOf() );
  326. return new CCiScanInfo( xPath,
  327. partId,
  328. updFlag,
  329. fDoDeletions,
  330. CI_VOLID_USN_NOT_ENABLED,
  331. 0,
  332. FALSE,
  333. fNewScope );
  334. }
  335. //+---------------------------------------------------------------------------
  336. //
  337. // Member: CCiScanMgr::ScanScope
  338. //
  339. // Synopsis: Adds the given scope with given characteristics to the list
  340. // of paths to be scanned.
  341. //
  342. // Arguments: [pwcsScope] - path name of scope to be added
  343. // [partId] - partition ID
  344. // [updFlag] -
  345. // [fDoDeletions] -
  346. // [fDelayed] -
  347. // [fNewScope] - TRUE if a new scope
  348. //
  349. // History: 1-19-96 srikants Created
  350. //
  351. //----------------------------------------------------------------------------
  352. void CCiScanMgr::ScanScope( WCHAR const * pwcsScope,
  353. PARTITIONID partId,
  354. ULONG updFlag,
  355. BOOL fDoDeletions,
  356. BOOL fDelayed,
  357. BOOL fNewScope )
  358. {
  359. Win4Assert( wcslen(pwcsScope) < MAX_PATH );
  360. XPtr<CCiScanInfo> xScanInfo( _QueryScanInfo( pwcsScope,
  361. partId,
  362. updFlag,
  363. fDoDeletions,
  364. fNewScope ) );
  365. xScanInfo->SetScan();
  366. xScanInfo->SetProcessRoot();
  367. ScanScope( xScanInfo, fDelayed, FALSE );
  368. }
  369. //+---------------------------------------------------------------------------
  370. //
  371. // Member: CCiScanMgr::ScheduleSerializeChanges
  372. //
  373. // Synopsis: Schedules a serialize-changes task
  374. //
  375. // History: 20-Aug-97 SitaramR Created
  376. //
  377. //----------------------------------------------------------------------------
  378. void CCiScanMgr::ScheduleSerializeChanges()
  379. {
  380. CLock lock(_mutex);
  381. _fSerializeChanges = TRUE;
  382. _evtScan.Set();
  383. }
  384. //+---------------------------------------------------------------------------
  385. //
  386. // Member: CCiScanMgr::InitiateShutdown
  387. //
  388. // Synopsis: Initiates the shutdown process.
  389. //
  390. // History: 2-28-96 srikants Created
  391. //
  392. // Notes:
  393. //
  394. //----------------------------------------------------------------------------
  395. void CCiScanMgr::InitiateShutdown()
  396. {
  397. CLock lock(_mutex);
  398. _fAbort = TRUE;
  399. _fAbortScan = TRUE;
  400. //
  401. // collect all the paths from the to-do stack.
  402. //
  403. while ( _scansToDo.Count() > 0 )
  404. {
  405. //
  406. // delete any pending scans.
  407. //
  408. delete _scansToDo.Pop();
  409. }
  410. _evtScan.Set();
  411. }
  412. //+---------------------------------------------------------------------------
  413. //
  414. // Member: CCiScanMgr::WaitForShutdown
  415. //
  416. // Synopsis: Waits for the shutdown to complete.
  417. //
  418. // History: 2-28-96 srikants Created
  419. //
  420. // Notes:
  421. //
  422. //----------------------------------------------------------------------------
  423. void CCiScanMgr::WaitForShutdown()
  424. {
  425. //
  426. // If we never started running, then just bail out.
  427. //
  428. if ( _thrScan.IsRunning() )
  429. {
  430. ciDebugOut(( DEB_ITRACE, "Waiting for death of scan thread\n" ));
  431. _thrScan.WaitForDeath();
  432. }
  433. }
  434. //+---------------------------------------------------------------------------
  435. //
  436. // Member: CCiScanMgr::SetBatch
  437. //
  438. // Synopsis: Sets the flag that batch processing of scans is in progress.
  439. // Until the flag is turned off, the scan thread will not look
  440. // at the scopes for scanning.
  441. //
  442. // History: 1-23-96 srikants Created
  443. //
  444. // Notes:
  445. //
  446. //----------------------------------------------------------------------------
  447. void CCiScanMgr::SetBatch()
  448. {
  449. CLock lock(_mutex);
  450. _fBatch = TRUE;
  451. }
  452. //+---------------------------------------------------------------------------
  453. //
  454. // Member: CCiScanMgr::ClearBatch
  455. //
  456. // Synopsis: Clears the batch processing flag and wakes up the scan
  457. // thread. All the accumulated scopes for scanning will be
  458. // retrieved by the scan thread and processed.
  459. //
  460. // History: 1-23-96 srikants Created
  461. //
  462. // Notes:
  463. //
  464. //----------------------------------------------------------------------------
  465. void CCiScanMgr::ClearBatch()
  466. {
  467. CLock lock(_mutex);
  468. _fBatch = FALSE;
  469. _evtScan.Set();
  470. }
  471. //+---------------------------------------------------------------------------
  472. //
  473. // Member: CCiScanMgr::WakeUp
  474. //
  475. // Synopsis: Wakes up the scan thread.
  476. //
  477. // History: 1-23-96 srikants Created
  478. //
  479. // Notes:
  480. //
  481. //----------------------------------------------------------------------------
  482. void CCiScanMgr::WakeUp()
  483. {
  484. CLock lock(_mutex);
  485. _evtScan.Set();
  486. }
  487. //+---------------------------------------------------------------------------
  488. //
  489. // Member: CCiScanMgr::ScanThread
  490. //
  491. // Synopsis:
  492. //
  493. // Arguments: [self] -
  494. //
  495. // History: 1-19-96 srikants Created
  496. // 3-03-98 kitmanh Don't _DoScans if catalog is read-only
  497. //
  498. //----------------------------------------------------------------------------
  499. DWORD CCiScanMgr::ScanThread( void * self )
  500. {
  501. SCODE sc = CoInitializeEx( 0, COINIT_MULTITHREADED );
  502. ((CCiScanMgr *) self)->_DoScans();
  503. CoUninitialize();
  504. ciDebugOut(( DEB_ITRACE, "Terminating scan thread\n" ));
  505. //
  506. // This is only necessary if thread is terminated from DLL_PROCESS_DETACH.
  507. //
  508. //TerminateThread( ((CCiScanMgr *) self)->_thrScan.GetHandle(), 0 );
  509. return 0;
  510. }
  511. //+---------------------------------------------------------------------------
  512. //
  513. // Member: CCiScanMgr::SetScanSuccess, public
  514. //
  515. // Synopsis: Called on successful completion of scan.
  516. //
  517. // Arguments: [pScanInfo] -- Scope that was scanned.
  518. //
  519. // History: 13-Apr-1998 KyleP Moved to .cxx and added cicat callback.
  520. //
  521. //----------------------------------------------------------------------------
  522. void CCiScanMgr::SetScanSuccess( CCiScanInfo * pScanInfo )
  523. {
  524. Win4Assert( 0 != pScanInfo );
  525. CLock lock(_mutex);
  526. if ( !_fAbort && !_fAbortScan )
  527. {
  528. pScanInfo->LokSetDone();
  529. _cicat.SetTreeScanComplete( pScanInfo->GetPath() );
  530. }
  531. }
  532. //+---------------------------------------------------------------------------
  533. //
  534. // Member: CCiScanMgr::_DoScans
  535. //
  536. // Synopsis:
  537. //
  538. // History: 1-19-96 srikants Created
  539. // 3-25-98 kitmanh Just set the initialized event and return
  540. // if cat is r/o
  541. //
  542. // Notes:
  543. //
  544. //----------------------------------------------------------------------------
  545. void CCiScanMgr::_DoScans()
  546. {
  547. if ( IsReadOnly() )
  548. {
  549. _cicat.SetEvtInitialized();
  550. _cicat.SetEvtPh2Init();
  551. _cicat.SynchWithRegistryScopes();
  552. return;
  553. }
  554. BOOL fContinue = TRUE;
  555. BOOL fScanned = FALSE; // set to TRUE if a scan is performed
  556. while ( fContinue )
  557. {
  558. BOOL fWait = FALSE; // flag set to TRUE if a wait must be done
  559. EState workType = eStart;
  560. BOOL fShortWait = FALSE;
  561. BOOL fSerializeChanges = FALSE; // No serialize-changes tasks yet
  562. NTSTATUS status = STATUS_SUCCESS;
  563. //
  564. // Don't do any work until the system has booted
  565. //
  566. while ( ( GetTickCount() < _cicat.GetRegParams()->GetStartupDelay() ) &&
  567. ( eStart != _state ) &&
  568. ( eDoRecovery != _state ) )
  569. {
  570. Sleep( 200 );
  571. if ( _fAbort )
  572. break;
  573. }
  574. TRY
  575. {
  576. XPtr<CCiScanInfo> xScanInfo;
  577. // =========================================
  578. {
  579. CLock lock(_mutex);
  580. if ( _fAbort )
  581. break;
  582. if ( !_fBatch && _LokIsOkToScan() )
  583. {
  584. //
  585. // refile any incomplete paths that could not be
  586. // refiled due to low resources.
  587. //
  588. if ( _scansInProgress.Count() > 0 )
  589. {
  590. _LokEmptyInProgressScans();
  591. }
  592. //
  593. // collect all the paths from the to-do stack.
  594. //
  595. while ( _scansToDo.Count() > 0 )
  596. {
  597. // should first save in a safe pointer because the
  598. // push can fail.
  599. xScanInfo.Set( _scansToDo.Pop() );
  600. if ( !_fScanDisabled && !xScanInfo->LokIsInFinalState() )
  601. {
  602. _scansInProgress.Queue( xScanInfo.GetPointer() );
  603. xScanInfo.Acquire();
  604. }
  605. else
  606. {
  607. // this scope is deleted
  608. xScanInfo.Free();
  609. }
  610. }
  611. if ( 0 == _scansInProgress.Count() )
  612. _evtScan.Reset();
  613. if ( 0 == _scansInProgress.Count() && _fSerializeChanges )
  614. {
  615. //
  616. // Make local copy of fSerializeChanges for use outside lock. Also
  617. // reset _fSerializeChanges since a flush task will be scheduled below.
  618. //
  619. fSerializeChanges = TRUE;
  620. _fSerializeChanges = FALSE;
  621. }
  622. }
  623. else if ( _LokIsDoRecovery() )
  624. {
  625. _evtScan.Reset();
  626. workType = eDoRecovery;
  627. }
  628. else if ( _LokIsStartScans() )
  629. {
  630. _evtScan.Reset();
  631. workType = eStartScans;
  632. }
  633. }
  634. // =========================================
  635. //
  636. // Update fixups. We have to do this at regular
  637. // intervals because there is no notification API for
  638. // share changes. Check no more often than every 15
  639. // minutes; this drags in 13 DLLs.
  640. //
  641. DWORD cmsDifference = GetTickCount() - _dwLastShareSynch;
  642. if ( cmsDifference > ( _cicat.GetRegParams()->MaxAutoAliasRefresh() * 1000 * 60 ) )
  643. {
  644. //
  645. // Don't do this in resource-bound situations
  646. //
  647. CI_STATE State;
  648. State.cbStruct = sizeof( State );
  649. SCODE sc = _cicat.CiState( State );
  650. if ( SUCCEEDED( sc ) &&
  651. ( 0 == ( State.eState & ( CI_STATE_HIGH_IO |
  652. CI_STATE_LOW_MEMORY |
  653. CI_STATE_USER_ACTIVE ) ) ) )
  654. {
  655. _cicat.SynchShares();
  656. //
  657. // it is OK to modify this outside the class lock because
  658. // only one thread performs scans for a catalog at any moment
  659. // and there is one CCiScanMgr object per catalog.
  660. //
  661. _dwLastShareSynch = GetTickCount();
  662. }
  663. }
  664. if ( eDoRecovery == workType )
  665. {
  666. //
  667. // Do the long running initialization.
  668. //
  669. Win4Assert( !IsReadOnly() );
  670. // Note: recovery is now synchronous, but this must be
  671. // done asynchronously, since the callback to the docstore
  672. // must be done by a worker thread.
  673. //_cicat.DoRecovery();
  674. //
  675. // Set the state of the scan manager as recovered.
  676. //
  677. // ======================================
  678. {
  679. CLock lock(_mutex);
  680. _state = eRecovered;
  681. }
  682. // ======================================
  683. ciDebugOut(( DEB_WARN, "Setting CiCat recovery done...\n" ));
  684. _cicat.SetRecoveryCompleted();
  685. }
  686. else if ( eStartScans == workType )
  687. {
  688. _cicat.StartScansAndNotifies();
  689. CLock lock(_mutex);
  690. _state = eNormal;
  691. }
  692. else if ( _scansInProgress.Count() > 0 )
  693. {
  694. fScanned = TRUE;
  695. _Scan();
  696. Win4Assert( 0 == _scansInProgress.Count() || _fAbort );
  697. }
  698. else if ( fSerializeChanges )
  699. {
  700. _cicat.SerializeChangesInfo();
  701. fWait = TRUE;
  702. }
  703. else
  704. {
  705. fWait = TRUE;
  706. }
  707. //
  708. // Do scans complete processing if appropriate.
  709. //
  710. if ( fWait &&
  711. eNormal == _state &&
  712. !_fScanDisabled &&
  713. !fSerializeChanges )
  714. {
  715. _cicat.ProcessScansComplete( fScanned, fShortWait );
  716. }
  717. }
  718. CATCH (CException, e)
  719. {
  720. status = e.GetErrorCode();
  721. ciDebugOut(( DEB_ERROR,
  722. "CCiScanMgr::_DoScans. Caught exception 0x%X\n",
  723. status ));
  724. if ( CiCat::IsDiskLowError( status ) ||
  725. STATUS_INSUFFICIENT_RESOURCES == status ||
  726. STATUS_NO_MEMORY == status )
  727. {
  728. // delay the execution of the thread until resources are
  729. // available.
  730. fWait = TRUE;
  731. }
  732. else
  733. {
  734. _cicat.HandleError( status );
  735. fContinue = FALSE;
  736. }
  737. // We did not successfully complete recovery, but we need to signal that
  738. // phase 2 init is complete (albeit unsuccessfully)
  739. // fix for bug 151799
  740. if (_cicat.IsCorrupt() && eDoRecovery == workType)
  741. _cicat.SignalPhase2Completion();
  742. }
  743. END_CATCH
  744. if ( fWait )
  745. {
  746. fScanned = FALSE;
  747. //
  748. // If we are waiting during long initialization, then have a
  749. // shorter wait time to see if the error condition has cleared
  750. // up.
  751. //
  752. DWORD dwWaitTime = ( (eStart != workType) || fShortWait) ?
  753. PREINIT_WAIT : AUTOSCAN_WAIT;
  754. dwWaitTime = min( dwWaitTime,
  755. _cicat.GetRegParams()->GetForcedNetPathScanInterval() * 60 * 1000 );
  756. dwWaitTime = min( dwWaitTime,
  757. _cicat.GetRegParams()->MaxAutoAliasRefresh() * 1000 * 60 );
  758. _evtScan.Wait( dwWaitTime );
  759. }
  760. }
  761. } //_DoScans
  762. //+---------------------------------------------------------------------------
  763. //
  764. // Member: CCiScanMgr::_LokEmptyInProgressScans
  765. //
  766. // Synopsis: Removes all the scans from the "in-progress stack" and either
  767. // deletes them or re-schedules them. If the scan is in its
  768. // "terminal state", the scan is deleted. If there is a retry
  769. // it will be re-scheduled.
  770. //
  771. // History: 1-25-96 srikants Created
  772. //
  773. // Notes:
  774. //
  775. //----------------------------------------------------------------------------
  776. void CCiScanMgr::_LokEmptyInProgressScans()
  777. {
  778. //
  779. // refile any scopes that still need to be worked on.
  780. //
  781. while ( _scansInProgress.Count() > 0 )
  782. {
  783. if ( _fAbort )
  784. break;
  785. XPtr<CCiScanInfo> xScanInfo( _scansInProgress.RemoveLast() );
  786. if ( !_fScanDisabled && !xScanInfo->LokIsInFinalState() )
  787. {
  788. #if CIDBG==1
  789. if ( xScanInfo->LokIsDelScope() )
  790. {
  791. ciDebugOut(( DEB_ITRACE, "Requeing scope (%ws) for removal\n",
  792. xScanInfo->GetPath() ));
  793. }
  794. else if ( xScanInfo->LokIsRenameDir() )
  795. {
  796. ciDebugOut(( DEB_ITRACE, "Requeing scope (%ws) for rename\n",
  797. xScanInfo->GetPath() ));
  798. }
  799. else
  800. {
  801. ciDebugOut(( DEB_ITRACE, "Requeuing scope (%ws) for scan\n",
  802. xScanInfo->GetPath() ));
  803. }
  804. #endif // CIDBG==1
  805. ScanScope( xScanInfo,
  806. xScanInfo->LokIsRetry(), // delay for retry
  807. TRUE ); // It's a refiled scan
  808. }
  809. else
  810. {
  811. xScanInfo.Free();
  812. }
  813. }
  814. }
  815. //+---------------------------------------------------------------------------
  816. //
  817. // Member: CCiScanMgr::_Scan
  818. //
  819. // Synopsis:
  820. //
  821. // Returns:
  822. //
  823. // Modifies:
  824. //
  825. // History: 1-25-96 srikants Created
  826. //
  827. // Notes:
  828. //
  829. //----------------------------------------------------------------------------
  830. void CCiScanMgr::_Scan()
  831. {
  832. // does not THROW
  833. _cicat.DoUpdate( _scansInProgress, *this, _fAbortScan );
  834. // =============================================================
  835. {
  836. CLock lock(_mutex);
  837. _LokEmptyInProgressScans();
  838. _fAbortScan = FALSE;
  839. }
  840. // =============================================================
  841. }
  842. //+---------------------------------------------------------------------------
  843. //
  844. // Member: CCiScanMgr::_LokScheduleRemove
  845. //
  846. // Synopsis: Schedules a path for removal.
  847. //
  848. // Arguments: [pwscScope] - Scope to be removed from CiCat.
  849. //
  850. // History: 1-26-96 srikants Created
  851. //
  852. // Notes:
  853. //
  854. //----------------------------------------------------------------------------
  855. void CCiScanMgr::_LokScheduleRemove( WCHAR const * pwcsScope )
  856. {
  857. CCiScanInfo * pScanInfo = _QueryScanInfo( pwcsScope,
  858. _cicat.GetPartition(),
  859. UPD_INCREM, TRUE );
  860. XPtr<CCiScanInfo> xScanInfo( pScanInfo );
  861. pScanInfo->LokSetDelScope();
  862. ScanScope( xScanInfo, FALSE, FALSE );
  863. }
  864. //+---------------------------------------------------------------------------
  865. //
  866. // Member: CCiScanMgr::RemoveScope
  867. //
  868. // Synopsis: Removes the scope from any active or in-progress scans and
  869. // marks it for "deletions". If there is no active or in-progress
  870. // scan for the scope, a new "deletion scan" will be scheduled.
  871. //
  872. // Arguments: [pwcsScope] - The scope to be removed.
  873. //
  874. // History: 1-25-96 srikants Created
  875. //
  876. // Notes: This method must not only remove the scope from the scheduled
  877. // scans but also from any currently in-progress scans. It is
  878. // possible that the scan thread is currently working on the
  879. // path to be removed. In that case, we set the state of the
  880. // scope to indicate that it must be aborted.
  881. //
  882. //----------------------------------------------------------------------------
  883. void CCiScanMgr::RemoveScope( WCHAR const * pwcsScope )
  884. {
  885. //
  886. // if the given scope is in the list of paths being currently
  887. // scanned, we must mark it deleted.
  888. //
  889. BOOL fRemoved = FALSE;
  890. // ===========================================================
  891. {
  892. CLock lock(_mutex);
  893. if ( _fAbort )
  894. return;
  895. for ( CFwdScanInfoIter scanInfoIter1( _scansToDo );
  896. !_scansToDo.AtEnd( scanInfoIter1 );
  897. _scansToDo.Advance( scanInfoIter1 ) )
  898. {
  899. WCHAR const * pwcsPath = scanInfoIter1->GetPath();
  900. if ( AreIdenticalPaths( pwcsScope, pwcsPath ) )
  901. {
  902. fRemoved = TRUE;
  903. if ( !scanInfoIter1->LokIsDelScope() )
  904. scanInfoIter1->LokSetDelScope();
  905. }
  906. }
  907. //
  908. // Next see in the list of paths being currently scanned.
  909. //
  910. for ( CFwdScanInfoIter scanInfoIter2( _scansInProgress );
  911. !_scansInProgress.AtEnd( scanInfoIter2 );
  912. _scansInProgress.Advance( scanInfoIter2 ) )
  913. {
  914. WCHAR const * pwcsPath = scanInfoIter2->GetPath();
  915. if ( AreIdenticalPaths( pwcsScope, pwcsPath ) )
  916. {
  917. fRemoved = TRUE;
  918. if ( !scanInfoIter2->LokIsDelScope() )
  919. {
  920. _fAbortScan = TRUE;
  921. scanInfoIter2->LokSetDelScope();
  922. }
  923. }
  924. }
  925. if ( !fRemoved )
  926. {
  927. _LokScheduleRemove( pwcsScope );
  928. fRemoved = TRUE;
  929. }
  930. _evtScan.Set(); // wake up the scan thread.
  931. Win4Assert( fRemoved );
  932. }
  933. // ===========================================================
  934. }
  935. //+---------------------------------------------------------------------------
  936. //
  937. // Member: CCiScanMgr::DisableScan
  938. //
  939. // Synopsis: Disables further scans and aborts any in progress.
  940. //
  941. // History: 4-16-96 srikants Created
  942. //
  943. //----------------------------------------------------------------------------
  944. void CCiScanMgr::DisableScan()
  945. {
  946. CLock lock(_mutex);
  947. _fAbortScan = TRUE;
  948. _fScanDisabled = TRUE;
  949. _evtScan.Set();
  950. }
  951. //+---------------------------------------------------------------------------
  952. //
  953. // Member: CCiScanMgr::EnableScan
  954. //
  955. // Synopsis: Re-enables scanning if scanning is currently disabled.
  956. //
  957. // History: 4-16-96 srikants Created
  958. //
  959. //----------------------------------------------------------------------------
  960. void CCiScanMgr::EnableScan()
  961. {
  962. CLock lock(_mutex);
  963. if ( _fScanDisabled )
  964. {
  965. _fScanDisabled = FALSE;
  966. _evtScan.Set();
  967. }
  968. }
  969. //+---------------------------------------------------------------------------
  970. //
  971. // Member: CCiScanMgr::AnyInitialScans
  972. //
  973. // Synopsis: Checks if any scans are the result of a new scope
  974. //
  975. // Returns: TRUE if any scans are for new scopes
  976. //
  977. // History: 3-Aug-98 dlee Created
  978. //
  979. //----------------------------------------------------------------------------
  980. BOOL CCiScanMgr::AnyInitialScans()
  981. {
  982. for ( CFwdScanInfoIter iter1( _scansToDo );
  983. !_scansToDo.AtEnd( iter1 );
  984. _scansToDo.Advance( iter1 ) )
  985. {
  986. if ( iter1->IsNewScope() )
  987. return TRUE;
  988. }
  989. for ( CFwdScanInfoIter iter2( _scansInProgress );
  990. !_scansInProgress.AtEnd( iter2 );
  991. _scansInProgress.Advance( iter2 ) )
  992. {
  993. if ( iter2->IsNewScope() )
  994. return TRUE;
  995. }
  996. return FALSE;
  997. } //AnyInitialScans