1159 lines
34 KiB
C++
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
|
||
|
|