WindowsXP/Source/XPSP1/NT/inetsrv/query/cicat/scanmgr.cxx
2024-08-03 16:30:48 +02:00

1159 lines
34 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 2000.
//
// File: scanmgr.cxx
//
// Contents: Scan manager
//
// History: 14-Jul-97 SitaramR Created from dlnotify.cxx
//
// Notes : For lock hierarchy and order of acquiring locks, please see
// cicat.cxx
//
// DISKFULL HANDLING
//
// The disk full situation is either detected in RESMAN and information sent
// up to CICAT or a DISKFULL error is first detected in CICAT and then
// propagated to RESMAN. As part of diskfull processing in the scope table,
// existing scans are aborted in scanmanager and future scans are disabled
// until the diskfull gets cleared up. If DISKFULL is detected at startup
// time, the scope table enters a "incremental scan required" state and doesn't
// schedule any scans/notifications until the situation improves.
//
// If the changelog loses a notification, a DisableUpdates notification is sent
// to the DocStore. The scan is deferred until an EnableUpdates notification
// is sent to DocStore.
//
//----------------------------------------------------------------------------
#include <pch.cxx>
#pragma hdrstop
#include <ciregkey.hxx>
#include <cistore.hxx>
#include <rcstxact.hxx>
#include <imprsnat.hxx>
#include <eventlog.hxx>
#include <docstore.hxx>
#include "cicat.hxx"
#include "update.hxx"
#include "notifmgr.hxx"
#include "scanmgr.hxx"
#include "scopetbl.hxx"
//+---------------------------------------------------------------------------
//
// Member: CCiScanMgr::CCiScanMgr
//
// Synopsis: ~ctor of the scan manager for downlevel CI. It starts a
// background thread for doing the scans.
//
// Arguments: [cicat] -
//
// History: 1-19-96 srikants Created
// 3-03-98 kitmanh Initialized member _fIsReadOnly with
// cicat.IsReadOnly
//
// Notes:
//
//----------------------------------------------------------------------------
CCiScanMgr::CCiScanMgr( CiCat & cicat ) :
_cicat(cicat),
_fAbort(FALSE),
_fSerializeChanges(FALSE),
_state(eStart),
#pragma warning( disable : 4355 ) // this used in base initialization
_thrScan( ScanThread, this, TRUE ), // create suspended
#pragma warning( default : 4355 )
_fBatch(FALSE), // disable batch processing
_fAbortScan(FALSE),
_fScanDisabled(FALSE),
_fIsReadOnly(cicat.IsReadOnly()),
_dwLastShareSynch( 0 )
{
_evtScan.Reset();
_thrScan.SetPriority( THREAD_PRIORITY_BELOW_NORMAL );
}
CCiScanMgr::~CCiScanMgr()
{
InitiateShutdown();
WaitForShutdown();
// delete any in-progress scan info
CLock lock( _mutex );
while ( !_scansInProgress.IsEmpty() )
{
delete _scansInProgress.RemoveLast();
}
}
//+---------------------------------------------------------------------------
//
// Member: CCiScanMgr::StartRecovery
//
// Synopsis: Sets the state to indicate that recovery must be done
// and wakes up the scan thread.
//
// History: 3-06-96 srikants Created
//
//----------------------------------------------------------------------------
void CCiScanMgr::StartRecovery()
{
CLock lock(_mutex);
Win4Assert( eStart == _state );
_state = eDoRecovery;
_evtScan.Set();
}
//+---------------------------------------------------------------------------
//
// Member: CCiScanMgr::StartScansAndNotifies
//
// Synopsis: Initiates scans and notifications in the document store.
//
// History: 12-09-96 srikants Created
//
//----------------------------------------------------------------------------
void CCiScanMgr::StartScansAndNotifies()
{
CLock lock(_mutex);
Win4Assert( eRecovered == _state );
_state = eStartScans;
_evtScan.Set();
}
//+---------------------------------------------------------------------------
//
// Member: CCiScanMgr::_LokIsScanScheduled
//
// Synopsis: Tests if the given scope is already scheduled for a scan.
//
// Arguments: [xScanInfo] - Smart pointer to scaninfo
//
// History: 2-26-96 srikants Created
//
//----------------------------------------------------------------------------
BOOL CCiScanMgr::_LokIsScanScheduled( const XPtr<CCiScanInfo> & xScanInfo )
{
WCHAR const * pwszNewScope = xScanInfo->GetPath();
unsigned lenNewScope = wcslen( pwszNewScope );
for ( CFwdScanInfoIter scanInfoIter(_scansToDo);
!_scansToDo.AtEnd(scanInfoIter);
_scansToDo.Advance(scanInfoIter) )
{
if ( xScanInfo->LokGetWorkType() == scanInfoIter->LokGetWorkType() )
{
WCHAR const * pwszPath = scanInfoIter->GetPath();
CScopeMatch scope( pwszPath, wcslen(pwszPath) );
if (scope.IsInScope( pwszNewScope, lenNewScope ))
{
ciDebugOut(( DEB_ITRACE,"Scan already scheduled for (%ws)\n",
pwszNewScope ));
return TRUE;
}
}
}
return FALSE;
}
//+---------------------------------------------------------------------------
//
// Member: CCiScanMgr::ScanScope
//
// Synopsis: Adds the given scope to the list of scopes to scan.
//
// Arguments: [xScanInfo] - Will be acquired from the safe pointer if
// successfully taken over.
// [fDelayed] - Set to TRUE if the scan must not be done
// immediately.
// [fRefiled] - Set to TRUE if this is a refile or retry scan
//
// History: 1-23-96 srikants Created
//
// Notes:
//
//----------------------------------------------------------------------------
void CCiScanMgr::ScanScope(
XPtr<CCiScanInfo> & xScanInfo,
BOOL fDelayed,
BOOL fRefiled )
{
CLock lock( _mutex );
if ( xScanInfo->GetRetries() <= CCiScanInfo::MAX_RETRIES &&
!_LokIsScanScheduled( xScanInfo ) )
{
Win4Assert( !xScanInfo->LokIsInFinalState() );
Win4Assert( xScanInfo->LokIsInScan()
|| xScanInfo->LokIsDelScope()
|| xScanInfo->LokIsRenameDir() );
if ( fRefiled )
{
//
// A scan that has been refiled should be done before new scans
// to ensure that all scans are done in FIFO order.
//
_scansToDo.Push( xScanInfo.GetPointer() );
}
else
_scansToDo.Queue( xScanInfo.GetPointer() );
xScanInfo.Acquire();
if ( !fDelayed )
_evtScan.Set();
}
else
{
xScanInfo.Free();
}
}
//+---------------------------------------------------------------------------
//
// Member: CCiScanMgr::DirAddNotification
//
// Synopsis: Schedules the scan of a new directory
//
// Arguments: [pwcsDirName] - Directory added
//
// History: 20-Mar-96 SitaramR Added header
//
//----------------------------------------------------------------------------
void CCiScanMgr::DirAddNotification( WCHAR const *pwcsDirName )
{
//
// Force a full scan of the direcotry, because the directory is new and so
// it cannot have been scanned before
//
XPtr<CCiScanInfo> xScanInfo( _QueryScanInfo( pwcsDirName,
_cicat.GetPartition(),
UPD_FULL,
FALSE ) );
xScanInfo->SetScan();
xScanInfo->SetProcessRoot();
//---------------------------------------------------------
{
CLock lock( _mutex );
_scansToDo.Queue( xScanInfo.GetPointer() );
xScanInfo.Acquire();
_evtScan.Set(); // Wake up the scan thread
}
//---------------------------------------------------------
}
//+---------------------------------------------------------------------------
//
// Member: CCiScanMgr::DirRenameNotification
//
// Synopsis: Schedules the scan of a rename directory notification
//
// Arguments: [pwcsDirOldName] - Previous name of irectory
// [pwcsDirNewName] - New name of directory
//
// History: 20-Mar-96 SitaramR Added header
//
//----------------------------------------------------------------------------
void CCiScanMgr::DirRenameNotification( WCHAR const *pwcsDirOldName,
WCHAR const *pwcsDirNewName )
{
BOOL fRenameScheduled = FALSE;
CLock lock( _mutex );
for ( CFwdScanInfoIter scanInfoIter( _scansToDo );
!_scansToDo.AtEnd( scanInfoIter );
_scansToDo.Advance( scanInfoIter ) )
{
//
// if dirA is renamed to dirB, and then dirB is renamed to dirC, then it is
// the same as dirA being renamed to dirC.
//
// Note: if dirA is renamed to dirB, and then dirB is renamed to dirA, we don't
// cancel the two renames because it may not yield the same original state. For
// example, after the first rename if a file, say file1, below dirB is deleted, and
// then dirB is renamed to dirA, then since the strings table is not aware of the
// file dirB\file1, no action will be taken, ie the file won't be deleted. By
// scheduling the two renames one after another the wid corresponding to dirB\file1
// will be correctly deleted.
//
if ( scanInfoIter->LokIsRenameDir()
&& AreIdenticalPaths( scanInfoIter->GetPath(), pwcsDirOldName )
&& !AreIdenticalPaths( scanInfoIter->GetDirOldName(), pwcsDirNewName ) ) // See note above
{
//
// By overwriting dirC over dirB (see example above), we have combined the two rename
// operations into one rename operation
//
scanInfoIter->LokSetPath( pwcsDirNewName );
fRenameScheduled = TRUE;
break;
}
}
if ( !fRenameScheduled )
{
XPtr<CCiScanInfo> xScanInfo( _QueryScanInfo( pwcsDirNewName,
_cicat.GetPartition(),
UPD_INCREM,
FALSE ) );
xScanInfo->SetRenameDir();
xScanInfo->SetDirOldName( pwcsDirOldName );
ScanScope( xScanInfo, TRUE, FALSE );
//
// If this rename operation is interrupted in the middle (because of a
// subsequent delete or rename) then files/wids under the old directory may
// still be lying around in the property store. To ensure that all such
// files/wids are removed, schedule a remove operation for the old directory
// name.
//
_LokScheduleRemove( pwcsDirOldName );
}
}
//+---------------------------------------------------------------------------
//
// Member: CCiScanMgr::_QueryScanInfo
//
// Synopsis: Returns a new instance of CCiScanInfo
//
// Arguments: [pwcsScope] -- Scope
// [partId] -- Partition id
// [updFlag] -- Incremental or full update
// [fDoDeletions] -- Shoud deletions be done ?
// [fNewScope] -- TRUE if a new scope
//
// History: 20-Mar-96 SitaramR Added header
//
//----------------------------------------------------------------------------
CCiScanInfo *
CCiScanMgr::_QueryScanInfo( WCHAR const * pwcsScope,
PARTITIONID partId,
ULONG updFlag,
BOOL fDoDeletions,
BOOL fNewScope )
{
Win4Assert( 0 != pwcsScope );
ULONG len = wcslen( pwcsScope );
Win4Assert( pwcsScope[len-1] == L'\\' );
XArray<WCHAR> xPath( len+1 );
RtlCopyMemory( xPath.Get(), pwcsScope, xPath.SizeOf() );
return new CCiScanInfo( xPath,
partId,
updFlag,
fDoDeletions,
CI_VOLID_USN_NOT_ENABLED,
0,
FALSE,
fNewScope );
}
//+---------------------------------------------------------------------------
//
// Member: CCiScanMgr::ScanScope
//
// Synopsis: Adds the given scope with given characteristics to the list
// of paths to be scanned.
//
// Arguments: [pwcsScope] - path name of scope to be added
// [partId] - partition ID
// [updFlag] -
// [fDoDeletions] -
// [fDelayed] -
// [fNewScope] - TRUE if a new scope
//
// History: 1-19-96 srikants Created
//
//----------------------------------------------------------------------------
void CCiScanMgr::ScanScope( WCHAR const * pwcsScope,
PARTITIONID partId,
ULONG updFlag,
BOOL fDoDeletions,
BOOL fDelayed,
BOOL fNewScope )
{
Win4Assert( wcslen(pwcsScope) < MAX_PATH );
XPtr<CCiScanInfo> xScanInfo( _QueryScanInfo( pwcsScope,
partId,
updFlag,
fDoDeletions,
fNewScope ) );
xScanInfo->SetScan();
xScanInfo->SetProcessRoot();
ScanScope( xScanInfo, fDelayed, FALSE );
}
//+---------------------------------------------------------------------------
//
// Member: CCiScanMgr::ScheduleSerializeChanges
//
// Synopsis: Schedules a serialize-changes task
//
// History: 20-Aug-97 SitaramR Created
//
//----------------------------------------------------------------------------
void CCiScanMgr::ScheduleSerializeChanges()
{
CLock lock(_mutex);
_fSerializeChanges = TRUE;
_evtScan.Set();
}
//+---------------------------------------------------------------------------
//
// Member: CCiScanMgr::InitiateShutdown
//
// Synopsis: Initiates the shutdown process.
//
// History: 2-28-96 srikants Created
//
// Notes:
//
//----------------------------------------------------------------------------
void CCiScanMgr::InitiateShutdown()
{
CLock lock(_mutex);
_fAbort = TRUE;
_fAbortScan = TRUE;
//
// collect all the paths from the to-do stack.
//
while ( _scansToDo.Count() > 0 )
{
//
// delete any pending scans.
//
delete _scansToDo.Pop();
}
_evtScan.Set();
}
//+---------------------------------------------------------------------------
//
// Member: CCiScanMgr::WaitForShutdown
//
// Synopsis: Waits for the shutdown to complete.
//
// History: 2-28-96 srikants Created
//
// Notes:
//
//----------------------------------------------------------------------------
void CCiScanMgr::WaitForShutdown()
{
//
// If we never started running, then just bail out.
//
if ( _thrScan.IsRunning() )
{
ciDebugOut(( DEB_ITRACE, "Waiting for death of scan thread\n" ));
_thrScan.WaitForDeath();
}
}
//+---------------------------------------------------------------------------
//
// Member: CCiScanMgr::SetBatch
//
// Synopsis: Sets the flag that batch processing of scans is in progress.
// Until the flag is turned off, the scan thread will not look
// at the scopes for scanning.
//
// History: 1-23-96 srikants Created
//
// Notes:
//
//----------------------------------------------------------------------------
void CCiScanMgr::SetBatch()
{
CLock lock(_mutex);
_fBatch = TRUE;
}
//+---------------------------------------------------------------------------
//
// Member: CCiScanMgr::ClearBatch
//
// Synopsis: Clears the batch processing flag and wakes up the scan
// thread. All the accumulated scopes for scanning will be
// retrieved by the scan thread and processed.
//
// History: 1-23-96 srikants Created
//
// Notes:
//
//----------------------------------------------------------------------------
void CCiScanMgr::ClearBatch()
{
CLock lock(_mutex);
_fBatch = FALSE;
_evtScan.Set();
}
//+---------------------------------------------------------------------------
//
// Member: CCiScanMgr::WakeUp
//
// Synopsis: Wakes up the scan thread.
//
// History: 1-23-96 srikants Created
//
// Notes:
//
//----------------------------------------------------------------------------
void CCiScanMgr::WakeUp()
{
CLock lock(_mutex);
_evtScan.Set();
}
//+---------------------------------------------------------------------------
//
// Member: CCiScanMgr::ScanThread
//
// Synopsis:
//
// Arguments: [self] -
//
// History: 1-19-96 srikants Created
// 3-03-98 kitmanh Don't _DoScans if catalog is read-only
//
//----------------------------------------------------------------------------
DWORD CCiScanMgr::ScanThread( void * self )
{
SCODE sc = CoInitializeEx( 0, COINIT_MULTITHREADED );
((CCiScanMgr *) self)->_DoScans();
CoUninitialize();
ciDebugOut(( DEB_ITRACE, "Terminating scan thread\n" ));
//
// This is only necessary if thread is terminated from DLL_PROCESS_DETACH.
//
//TerminateThread( ((CCiScanMgr *) self)->_thrScan.GetHandle(), 0 );
return 0;
}
//+---------------------------------------------------------------------------
//
// Member: CCiScanMgr::SetScanSuccess, public
//
// Synopsis: Called on successful completion of scan.
//
// Arguments: [pScanInfo] -- Scope that was scanned.
//
// History: 13-Apr-1998 KyleP Moved to .cxx and added cicat callback.
//
//----------------------------------------------------------------------------
void CCiScanMgr::SetScanSuccess( CCiScanInfo * pScanInfo )
{
Win4Assert( 0 != pScanInfo );
CLock lock(_mutex);
if ( !_fAbort && !_fAbortScan )
{
pScanInfo->LokSetDone();
_cicat.SetTreeScanComplete( pScanInfo->GetPath() );
}
}
//+---------------------------------------------------------------------------
//
// Member: CCiScanMgr::_DoScans
//
// Synopsis:
//
// History: 1-19-96 srikants Created
// 3-25-98 kitmanh Just set the initialized event and return
// if cat is r/o
//
// Notes:
//
//----------------------------------------------------------------------------
void CCiScanMgr::_DoScans()
{
if ( IsReadOnly() )
{
_cicat.SetEvtInitialized();
_cicat.SetEvtPh2Init();
_cicat.SynchWithRegistryScopes();
return;
}
BOOL fContinue = TRUE;
BOOL fScanned = FALSE; // set to TRUE if a scan is performed
while ( fContinue )
{
BOOL fWait = FALSE; // flag set to TRUE if a wait must be done
EState workType = eStart;
BOOL fShortWait = FALSE;
BOOL fSerializeChanges = FALSE; // No serialize-changes tasks yet
NTSTATUS status = STATUS_SUCCESS;
//
// Don't do any work until the system has booted
//
while ( ( GetTickCount() < _cicat.GetRegParams()->GetStartupDelay() ) &&
( eStart != _state ) &&
( eDoRecovery != _state ) )
{
Sleep( 200 );
if ( _fAbort )
break;
}
TRY
{
XPtr<CCiScanInfo> xScanInfo;
// =========================================
{
CLock lock(_mutex);
if ( _fAbort )
break;
if ( !_fBatch && _LokIsOkToScan() )
{
//
// refile any incomplete paths that could not be
// refiled due to low resources.
//
if ( _scansInProgress.Count() > 0 )
{
_LokEmptyInProgressScans();
}
//
// collect all the paths from the to-do stack.
//
while ( _scansToDo.Count() > 0 )
{
// should first save in a safe pointer because the
// push can fail.
xScanInfo.Set( _scansToDo.Pop() );
if ( !_fScanDisabled && !xScanInfo->LokIsInFinalState() )
{
_scansInProgress.Queue( xScanInfo.GetPointer() );
xScanInfo.Acquire();
}
else
{
// this scope is deleted
xScanInfo.Free();
}
}
if ( 0 == _scansInProgress.Count() )
_evtScan.Reset();
if ( 0 == _scansInProgress.Count() && _fSerializeChanges )
{
//
// Make local copy of fSerializeChanges for use outside lock. Also
// reset _fSerializeChanges since a flush task will be scheduled below.
//
fSerializeChanges = TRUE;
_fSerializeChanges = FALSE;
}
}
else if ( _LokIsDoRecovery() )
{
_evtScan.Reset();
workType = eDoRecovery;
}
else if ( _LokIsStartScans() )
{
_evtScan.Reset();
workType = eStartScans;
}
}
// =========================================
//
// Update fixups. We have to do this at regular
// intervals because there is no notification API for
// share changes. Check no more often than every 15
// minutes; this drags in 13 DLLs.
//
DWORD cmsDifference = GetTickCount() - _dwLastShareSynch;
if ( cmsDifference > ( _cicat.GetRegParams()->MaxAutoAliasRefresh() * 1000 * 60 ) )
{
//
// Don't do this in resource-bound situations
//
CI_STATE State;
State.cbStruct = sizeof( State );
SCODE sc = _cicat.CiState( State );
if ( SUCCEEDED( sc ) &&
( 0 == ( State.eState & ( CI_STATE_HIGH_IO |
CI_STATE_LOW_MEMORY |
CI_STATE_USER_ACTIVE ) ) ) )
{
_cicat.SynchShares();
//
// it is OK to modify this outside the class lock because
// only one thread performs scans for a catalog at any moment
// and there is one CCiScanMgr object per catalog.
//
_dwLastShareSynch = GetTickCount();
}
}
if ( eDoRecovery == workType )
{
//
// Do the long running initialization.
//
Win4Assert( !IsReadOnly() );
// Note: recovery is now synchronous, but this must be
// done asynchronously, since the callback to the docstore
// must be done by a worker thread.
//_cicat.DoRecovery();
//
// Set the state of the scan manager as recovered.
//
// ======================================
{
CLock lock(_mutex);
_state = eRecovered;
}
// ======================================
ciDebugOut(( DEB_WARN, "Setting CiCat recovery done...\n" ));
_cicat.SetRecoveryCompleted();
}
else if ( eStartScans == workType )
{
_cicat.StartScansAndNotifies();
CLock lock(_mutex);
_state = eNormal;
}
else if ( _scansInProgress.Count() > 0 )
{
fScanned = TRUE;
_Scan();
Win4Assert( 0 == _scansInProgress.Count() || _fAbort );
}
else if ( fSerializeChanges )
{
_cicat.SerializeChangesInfo();
fWait = TRUE;
}
else
{
fWait = TRUE;
}
//
// Do scans complete processing if appropriate.
//
if ( fWait &&
eNormal == _state &&
!_fScanDisabled &&
!fSerializeChanges )
{
_cicat.ProcessScansComplete( fScanned, fShortWait );
}
}
CATCH (CException, e)
{
status = e.GetErrorCode();
ciDebugOut(( DEB_ERROR,
"CCiScanMgr::_DoScans. Caught exception 0x%X\n",
status ));
if ( CiCat::IsDiskLowError( status ) ||
STATUS_INSUFFICIENT_RESOURCES == status ||
STATUS_NO_MEMORY == status )
{
// delay the execution of the thread until resources are
// available.
fWait = TRUE;
}
else
{
_cicat.HandleError( status );
fContinue = FALSE;
}
// We did not successfully complete recovery, but we need to signal that
// phase 2 init is complete (albeit unsuccessfully)
// fix for bug 151799
if (_cicat.IsCorrupt() && eDoRecovery == workType)
_cicat.SignalPhase2Completion();
}
END_CATCH
if ( fWait )
{
fScanned = FALSE;
//
// If we are waiting during long initialization, then have a
// shorter wait time to see if the error condition has cleared
// up.
//
DWORD dwWaitTime = ( (eStart != workType) || fShortWait) ?
PREINIT_WAIT : AUTOSCAN_WAIT;
dwWaitTime = min( dwWaitTime,
_cicat.GetRegParams()->GetForcedNetPathScanInterval() * 60 * 1000 );
dwWaitTime = min( dwWaitTime,
_cicat.GetRegParams()->MaxAutoAliasRefresh() * 1000 * 60 );
_evtScan.Wait( dwWaitTime );
}
}
} //_DoScans
//+---------------------------------------------------------------------------
//
// Member: CCiScanMgr::_LokEmptyInProgressScans
//
// Synopsis: Removes all the scans from the "in-progress stack" and either
// deletes them or re-schedules them. If the scan is in its
// "terminal state", the scan is deleted. If there is a retry
// it will be re-scheduled.
//
// History: 1-25-96 srikants Created
//
// Notes:
//
//----------------------------------------------------------------------------
void CCiScanMgr::_LokEmptyInProgressScans()
{
//
// refile any scopes that still need to be worked on.
//
while ( _scansInProgress.Count() > 0 )
{
if ( _fAbort )
break;
XPtr<CCiScanInfo> xScanInfo( _scansInProgress.RemoveLast() );
if ( !_fScanDisabled && !xScanInfo->LokIsInFinalState() )
{
#if CIDBG==1
if ( xScanInfo->LokIsDelScope() )
{
ciDebugOut(( DEB_ITRACE, "Requeing scope (%ws) for removal\n",
xScanInfo->GetPath() ));
}
else if ( xScanInfo->LokIsRenameDir() )
{
ciDebugOut(( DEB_ITRACE, "Requeing scope (%ws) for rename\n",
xScanInfo->GetPath() ));
}
else
{
ciDebugOut(( DEB_ITRACE, "Requeuing scope (%ws) for scan\n",
xScanInfo->GetPath() ));
}
#endif // CIDBG==1
ScanScope( xScanInfo,
xScanInfo->LokIsRetry(), // delay for retry
TRUE ); // It's a refiled scan
}
else
{
xScanInfo.Free();
}
}
}
//+---------------------------------------------------------------------------
//
// Member: CCiScanMgr::_Scan
//
// Synopsis:
//
// Returns:
//
// Modifies:
//
// History: 1-25-96 srikants Created
//
// Notes:
//
//----------------------------------------------------------------------------
void CCiScanMgr::_Scan()
{
// does not THROW
_cicat.DoUpdate( _scansInProgress, *this, _fAbortScan );
// =============================================================
{
CLock lock(_mutex);
_LokEmptyInProgressScans();
_fAbortScan = FALSE;
}
// =============================================================
}
//+---------------------------------------------------------------------------
//
// Member: CCiScanMgr::_LokScheduleRemove
//
// Synopsis: Schedules a path for removal.
//
// Arguments: [pwscScope] - Scope to be removed from CiCat.
//
// History: 1-26-96 srikants Created
//
// Notes:
//
//----------------------------------------------------------------------------
void CCiScanMgr::_LokScheduleRemove( WCHAR const * pwcsScope )
{
CCiScanInfo * pScanInfo = _QueryScanInfo( pwcsScope,
_cicat.GetPartition(),
UPD_INCREM, TRUE );
XPtr<CCiScanInfo> xScanInfo( pScanInfo );
pScanInfo->LokSetDelScope();
ScanScope( xScanInfo, FALSE, FALSE );
}
//+---------------------------------------------------------------------------
//
// Member: CCiScanMgr::RemoveScope
//
// Synopsis: Removes the scope from any active or in-progress scans and
// marks it for "deletions". If there is no active or in-progress
// scan for the scope, a new "deletion scan" will be scheduled.
//
// Arguments: [pwcsScope] - The scope to be removed.
//
// History: 1-25-96 srikants Created
//
// Notes: This method must not only remove the scope from the scheduled
// scans but also from any currently in-progress scans. It is
// possible that the scan thread is currently working on the
// path to be removed. In that case, we set the state of the
// scope to indicate that it must be aborted.
//
//----------------------------------------------------------------------------
void CCiScanMgr::RemoveScope( WCHAR const * pwcsScope )
{
//
// if the given scope is in the list of paths being currently
// scanned, we must mark it deleted.
//
BOOL fRemoved = FALSE;
// ===========================================================
{
CLock lock(_mutex);
if ( _fAbort )
return;
for ( CFwdScanInfoIter scanInfoIter1( _scansToDo );
!_scansToDo.AtEnd( scanInfoIter1 );
_scansToDo.Advance( scanInfoIter1 ) )
{
WCHAR const * pwcsPath = scanInfoIter1->GetPath();
if ( AreIdenticalPaths( pwcsScope, pwcsPath ) )
{
fRemoved = TRUE;
if ( !scanInfoIter1->LokIsDelScope() )
scanInfoIter1->LokSetDelScope();
}
}
//
// Next see in the list of paths being currently scanned.
//
for ( CFwdScanInfoIter scanInfoIter2( _scansInProgress );
!_scansInProgress.AtEnd( scanInfoIter2 );
_scansInProgress.Advance( scanInfoIter2 ) )
{
WCHAR const * pwcsPath = scanInfoIter2->GetPath();
if ( AreIdenticalPaths( pwcsScope, pwcsPath ) )
{
fRemoved = TRUE;
if ( !scanInfoIter2->LokIsDelScope() )
{
_fAbortScan = TRUE;
scanInfoIter2->LokSetDelScope();
}
}
}
if ( !fRemoved )
{
_LokScheduleRemove( pwcsScope );
fRemoved = TRUE;
}
_evtScan.Set(); // wake up the scan thread.
Win4Assert( fRemoved );
}
// ===========================================================
}
//+---------------------------------------------------------------------------
//
// Member: CCiScanMgr::DisableScan
//
// Synopsis: Disables further scans and aborts any in progress.
//
// History: 4-16-96 srikants Created
//
//----------------------------------------------------------------------------
void CCiScanMgr::DisableScan()
{
CLock lock(_mutex);
_fAbortScan = TRUE;
_fScanDisabled = TRUE;
_evtScan.Set();
}
//+---------------------------------------------------------------------------
//
// Member: CCiScanMgr::EnableScan
//
// Synopsis: Re-enables scanning if scanning is currently disabled.
//
// History: 4-16-96 srikants Created
//
//----------------------------------------------------------------------------
void CCiScanMgr::EnableScan()
{
CLock lock(_mutex);
if ( _fScanDisabled )
{
_fScanDisabled = FALSE;
_evtScan.Set();
}
}
//+---------------------------------------------------------------------------
//
// Member: CCiScanMgr::AnyInitialScans
//
// Synopsis: Checks if any scans are the result of a new scope
//
// Returns: TRUE if any scans are for new scopes
//
// History: 3-Aug-98 dlee Created
//
//----------------------------------------------------------------------------
BOOL CCiScanMgr::AnyInitialScans()
{
for ( CFwdScanInfoIter iter1( _scansToDo );
!_scansToDo.AtEnd( iter1 );
_scansToDo.Advance( iter1 ) )
{
if ( iter1->IsNewScope() )
return TRUE;
}
for ( CFwdScanInfoIter iter2( _scansInProgress );
!_scansInProgress.AtEnd( iter2 );
_scansInProgress.Advance( iter2 ) )
{
if ( iter2->IsNewScope() )
return TRUE;
}
return FALSE;
} //AnyInitialScans