windows-nt/Source/XPSP1/NT/inetsrv/query/cicat/notifmgr.hxx
2020-09-26 16:20:57 +08:00

801 lines
20 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 2000.
//
// File: notifmgr.hxx
//
// Contents: Classes to deal with registry and file system change notifications
//
// Classes: CCiNotify
// CCiNotifyMgr
//
// History: 14-Jul-97 SitaramR Created from dlnotify.hxx
//
//----------------------------------------------------------------------------
#pragma once
#include <refcount.hxx>
#include <regevent.hxx>
#include <fatnot.hxx>
#include <rcstrmhd.hxx>
#include <cimbmgr.hxx>
#include "scaninfo.hxx"
#include "acinotfy.hxx"
#include "usnlist.hxx"
#include "usnmgr.hxx"
class CiCat;
class CCiNotifyMgr;
class CClientDocStore;
const LONGLONG sigCiNotify = 0x594649544F4E4943i64; // "CINOTIFY"
//+---------------------------------------------------------------------------
//
// Class: CCiNotify
//
// Purpose: A single scope to watch for notifications.
//
// History: 1-17-96 srikants Created
//
//----------------------------------------------------------------------------
class CCiNotify : public CGenericNotify
{
public:
CCiNotify( CCiNotifyMgr & notifyMgr,
WCHAR const * wcsScope,
unsigned cwcScope,
VOLUMEID volumeId,
ULONGLONG const & VolumeCreationTime,
ULONG VolumeSerialNumber,
FILETIME const & ftLastScan,
USN usn,
ULONGLONG const & JournalId,
BOOL fUsnTreeScan,
BOOL fDeep = TRUE );
~CCiNotify();
BOOL IsMatch( const WCHAR * wcsPath, ULONG len ) const;
# ifdef CIEXTMODE
void CiExtDump(void *ciExtSelf);
# endif
BOOL IsValidSig()
{
return sigCiNotify == _sigCiNotify;
}
CCiNotifyMgr & GetNotifyMgr() { return _notifyMgr; }
void LokRemove()
{
Unlink();
Close();
Abort();
}
void Abort();
virtual void DoIt();
virtual void ClearNotifyEnabled();
void SetLastScanTime( FILETIME const & ft )
{
_ftLastScan = ft;
}
FILETIME const & GetLastScanTime() const { return _ftLastScan; }
USN Usn() { return _usn; }
void SetUsn( USN usn ) { _usn = usn; }
ULONGLONG const & JournalId() const { return _JournalId; }
void SetJournalId( ULONGLONG const & JournalId ) { _JournalId = JournalId; }
VOLUMEID VolumeId() { return _volumeId; }
ULONGLONG const & VolumeCreationTime() const { return _VolumeCreationTime; }
ULONG VolumeSerialNumber() const { return _VolumeSerialNumber; }
void SetVolumeInfo( ULONGLONG const & VolumeCreationTime, ULONG VolumeSerialNumber )
{
_VolumeCreationTime = VolumeCreationTime;
_VolumeSerialNumber = VolumeSerialNumber;
}
BOOL FUsnTreeScan() { return _fUsnTreeScan; }
void InitUsnTreeScan()
{
_fUsnTreeScan = TRUE;
_usn = 0;
}
void SetUsnTreeScanComplete( USN usnMax )
{
// bogus assert: Win4Assert( _fUsnTreeScan );
_fUsnTreeScan = FALSE;
_usn = usnMax;
}
private:
const LONGLONG _sigCiNotify; // signature for debugging
ULONGLONG _VolumeCreationTime;
union
{
FILETIME _ftLastScan; // Time of the last successful scan
struct
{
ULONGLONG _JournalId; // Usn Journal Id
USN _usn; // Max usn persisted for this volumeId
};
};
ULONG _VolumeSerialNumber;
CCiNotifyMgr & _notifyMgr; // CI Notification manager
VOLUMEID _volumeId; // Volume id
BOOL _fUsnTreeScan; // True if a usn tree traversal is going
// on this scope
};
//+---------------------------------------------------------------------------
//
// Class: CVRootNotify
//
// Purpose: Notification on IIS VRoot changes
//
// History: 1-20-96 KyleP Created
//
//----------------------------------------------------------------------------
class CVRootNotify : public CMetaDataVPathChangeCallBack
{
public:
CVRootNotify( CiCat & cat,
CiVRootTypeEnum eType,
ULONG Instance,
CCiNotifyMgr & notifyMgr );
~CVRootNotify() { DisableNotification(); }
SCODE CallBack( BOOL fCancel );
void DisableNotification();
private:
CiVRootTypeEnum _type;
CiCat & _cat;
CCiNotifyMgr & _notifyMgr;
CMetaDataMgr _mdMgr;
};
//+---------------------------------------------------------------------------
//
// Class: CRegistryScopesNotify
//
// Purpose: Notification on Scopes registry changes
//
// History: 10-16-96 dlee Created
//
//----------------------------------------------------------------------------
class CRegistryScopesNotify : public CRegNotify
{
public:
CRegistryScopesNotify( CiCat & cat, CCiNotifyMgr & notifyMgr );
~CRegistryScopesNotify();
void DoIt();
private:
CiCat & _cat;
CCiNotifyMgr & _notifyMgr;
};
//+---------------------------------------------------------------------------
//
// Class: CCiRegistryNotify
//
// Purpose: A notification class for tracking ContentIndex registry
// changes.
//
// History: 12-12-96 srikants Created
//
//----------------------------------------------------------------------------
class CCiRegistryNotify : public CRegNotify
{
public:
CCiRegistryNotify( CiCat & cat, CCiNotifyMgr & notifyMgr );
~CCiRegistryNotify();
void DoIt();
private:
CiCat & _cat;
CCiNotifyMgr & _notifyMgr;
};
typedef class TDoubleList<CCiNotify> CCiNotifyList;
typedef class TFwdListIter<CCiNotify, CCiNotifyList> CFwdCiNotifyIter;
//+---------------------------------------------------------------------------
//
// Class: CScopeInfo
//
// Purpose: Class that holds a scope and the last scan time.
//
// History: 4-19-96 srikants Created
//
//----------------------------------------------------------------------------
class CScopeInfo
{
public:
CScopeInfo( XArray<WCHAR> & xPath,
ULONGLONG const & VolumeCreationTime,
ULONG VolumeSerialNumber,
FILETIME const & ftLastScan )
: _volumeId(CI_VOLID_USN_NOT_ENABLED),
_VolumeCreationTime( VolumeCreationTime ),
_VolumeSerialNumber( VolumeSerialNumber ),
_ftLastScan( ftLastScan ),
_fUsnTreeScan(FALSE)
{
_pwszScope = xPath.Acquire();
_scanType = eNoScan;
}
CScopeInfo( XArray<WCHAR> & xPath,
ULONGLONG const & VolumeCreationTime,
ULONG VolumeSerialNumber,
VOLUMEID volumeId,
USN usn,
ULONGLONG const & JournalId,
BOOL fScan )
: _volumeId(volumeId),
_VolumeCreationTime( VolumeCreationTime ),
_VolumeSerialNumber( VolumeSerialNumber ),
_fUsnTreeScan( fScan ),
_JournalId( JournalId ),
_usn( usn )
{
_pwszScope = xPath.Acquire();
_scanType = eNoScan;
}
CScopeInfo( WCHAR const * pwszPath,
ULONGLONG const & VolumeCreationTime,
ULONG VolumeSerialNumber,
FILETIME const & ftLastScan )
: _volumeId(CI_VOLID_USN_NOT_ENABLED),
_VolumeCreationTime( VolumeCreationTime ),
_VolumeSerialNumber( VolumeSerialNumber ),
_ftLastScan( ftLastScan ),
_fUsnTreeScan( FALSE )
{
Win4Assert( 0 != pwszPath );
ULONG len = wcslen( pwszPath );
_pwszScope = new WCHAR [len+1];
RtlCopyMemory( _pwszScope, pwszPath, (len+1) * sizeof(WCHAR) );
_scanType = eNoScan;
}
CScopeInfo( WCHAR const * pwszPath,
ULONGLONG const & VolumeCreationTime,
ULONG VolumeSerialNumber,
VOLUMEID volumeId,
USN usn,
ULONGLONG const & JournalId,
BOOL fScan )
: _volumeId(volumeId),
_VolumeCreationTime( VolumeCreationTime ),
_VolumeSerialNumber( VolumeSerialNumber ),
_fUsnTreeScan( fScan ),
_JournalId( JournalId ),
_usn( usn )
{
Win4Assert( 0 != pwszPath );
ULONG len = wcslen( pwszPath );
_pwszScope = new WCHAR [len+1];
RtlCopyMemory( _pwszScope, pwszPath, (len+1) * sizeof(WCHAR) );
_scanType = eNoScan;
}
~CScopeInfo()
{
delete [] _pwszScope;
}
WCHAR const * GetPath() const
{
return _pwszScope;
}
WCHAR * AcquirePath()
{
WCHAR * pwszTemp = _pwszScope;
_pwszScope = 0;
return pwszTemp;
}
void Invalidate()
{
delete [] _pwszScope;
_pwszScope = 0;
}
BOOL IsValid() const { return 0 != _pwszScope; }
FILETIME const & GetLastScanTime() const { return _ftLastScan; }
void SetLastScanTime( FILETIME const & ft )
{
_ftLastScan = ft;
}
VOLUMEID VolumeId() const { return _volumeId; }
USN Usn() const { return _usn; }
void SetUsn( USN usn ) { _usn = usn; }
ULONGLONG const & JournalId() const { return _JournalId; }
void SetJournalId( ULONGLONG const & JournalId ) { _JournalId = JournalId; }
ULONGLONG const & VolumeCreationTime() const { return _VolumeCreationTime; }
ULONG VolumeSerialNumber() const { return _VolumeSerialNumber; }
void SetVolumeInfo( ULONGLONG const & VolumeCreationTime, ULONG VolumeSerialNumber )
{
_VolumeCreationTime = VolumeCreationTime;
_VolumeSerialNumber = VolumeSerialNumber;
}
BOOL IsScanNeeded() const { return eNoScan != _scanType; }
BOOL IsFullScan() const { return eFullScan == _scanType; }
BOOL IsIncrScan() const { return eIncrScan == _scanType; }
void ClearScanNeeded() { _scanType = eNoScan; }
void SetScanNeeded( BOOL fFull )
{
if ( fFull )
{
_scanType = eFullScan;
}
else if ( eNoScan == _scanType )
{
_scanType = eIncrScan;
}
}
BOOL FUsnTreeScan() const { return _fUsnTreeScan; }
void InitUsnTreeScan()
{
_fUsnTreeScan = TRUE;
_usn = 0;
}
void SetUsnTreeScanComplete( USN usnMax )
{
Win4Assert( _fUsnTreeScan );
Win4Assert( _usn == 0 );
_fUsnTreeScan = FALSE;
_usn = usnMax;
}
void ResetForScans()
{
_volumeId = CI_VOLID_USN_NOT_ENABLED;
RtlZeroMemory( &_ftLastScan, sizeof(_ftLastScan) );
_scanType = eFullScan;
}
void ResetForUsns( VOLUMEID volId, USN const & usnStart = 0 )
{
Win4Assert( volId != CI_VOLID_USN_NOT_ENABLED );
_volumeId = volId;
_usn = usnStart;
_fUsnTreeScan = TRUE;
}
private:
CScopeInfo( CScopeInfo const & src ) { Win4Assert( !"Don't call me!" ); }
enum EScanType
{
eNoScan,
eIncrScan,
eFullScan
};
ULONGLONG _VolumeCreationTime;
union
{
struct
{
ULONGLONG _JournalId;
USN _usn;
};
FILETIME _ftLastScan;
};
ULONG _VolumeSerialNumber;
WCHAR * _pwszScope;
VOLUMEID _volumeId;
BOOL _fUsnTreeScan; // True if a usn tree traversal is going
// on this scope
EScanType _scanType;
};
DECL_DYNSTACK( CScopeInfoStack, CScopeInfo );
//+---------------------------------------------------------------------------
//
// Class: CCiNotifyMgr
//
// Purpose: Manages multiple scope notifications for content index. A
// single content index can have multiple scopes and each scope
// needs separate notifications.
//
// History: 1-17-96 srikants Created
//
// Notes:
//
//----------------------------------------------------------------------------
#if CIDBG==1
const LONGLONG eForceNetScanInterval = 2 * 60 * 1000 * 10000; // 2 mins for testing
#endif // CIDBG==1
class CCiNotifyMgr
{
enum EEventType { eNone=0x0,
eKillThread=0x1,
eAddScopes=0x2,
eWatchIISVRoots=0x4,
eWatchRegistryScopes=0x8,
eWatchCiRegistry=0x10,
eUnWatchW3VRoots=0x20,
eUnWatchNNTPVRoots=0x40,
eUnWatchIMAPVRoots=0x80 };
friend class CCiNotifyIter;
public:
CCiNotifyMgr( CiCat & cicat, CCiScanMgr & scanMgr );
~CCiNotifyMgr( );
void Resume() { _thrNotify.Resume(); }
void AddPath( CScopeInfo const & scopeInfo, BOOL & fSubScopesRemoved );
BOOL RemoveScope( const WCHAR * wcsPath );
BOOL IsInScope( WCHAR const * pwcsRoot );
CMutexSem & GetMutex() { return _mutex; }
void AddRef()
{
_refCount.AddRef();
}
void Release()
{
_refCount.Release();
}
void ProcessChanges( XPtr<CCiAsyncProcessNotify> & xWorker );
void ProcessChanges( BYTE const * pbChanges, WCHAR const * pwcsRoot );
CCiAsyncProcessNotify * QueryAsyncWorkItem( BYTE const * pbChanges,
ULONG cbChanges,
WCHAR const * pwcsRoot );
void SetupScan( WCHAR const * pwcsRoot );
unsigned GetUpdateCount()
{
CLock lock(_mutex);
return _nUpdates;
}
void IncrementUpdateCount( ULONG nUpdates )
{
CLock lock(_mutex);
_nUpdates += nUpdates;
}
void ResetUpdateCount()
{
CLock lock(_mutex);
_nUpdates = 0;
}
void InitiateShutdown();
void WaitForShutdown();
void CancelIISVRootNotify( CiVRootTypeEnum eType );
void TrackIISVRoots( BOOL fTrackW3Svc, ULONG W3SvcInstance,
BOOL fTrackNNTPSvc, ULONG NNTPSvcInstance,
BOOL fTrackIMAPSvc, ULONG IMAPSvcInstance );
void TrackScopesInRegistry();
void TrackCiRegistry();
BOOL GetLastScanTime( WCHAR const * pwcsRoot, FILETIME & ft );
void UpdateLastScanTimes( FILETIME const & ft, CUsnFlushInfoList & usnFlushInfoList );
void ForceNetPathScansIf();
CiCat & GetCatalog() { return _cicat; }
BOOL IsRunning() const { return !_fAbort; }
private:
// methods to deal with notifications.
static DWORD WINAPI NotifyThread( void * self );
void _DoNotifications();
void _KillThread();
void _LokTellThreadToAddScope();
void _LokAddScopesNoThrow();
void LokWatchIISVServerNoThrow();
void LokUnWatchIISVServerNoThrow( CVRootNotify * pNotify );
void LokWatchRegistryScopesNoThrow();
void LokWatchCiRegistryNoThrow();
void _LokIncrementUpdateCount()
{
_nUpdates++;
}
void _LokForceScanNetPaths();
CiCat & _cicat;
CCiScanMgr & _scanMgr;
CMutexSem _mutex; // Serialize access to the data.
CCiNotifyList _list; // List of scopes being watched for
// notifications.
CRefCount _refCount;
unsigned _nUpdates; // Count of updates since the last time
// scantime is written.
BOOL _fAbort; // Flag set to TRUE if should abort
LONGLONG _ftLastNetPathScan;
// Time of the last force scan on
// network drives with no notifications
//
// Notification thread management. System executes the APC in the context
// of the thread that makes the notification request.
//
ULONG _evtType;
CEventSem _evt;
CThread _thrNotify;
CScopeInfoStack _stkScopes;
//
// For processing changes to IIS VRoots
//
XPtr<CVRootNotify> _xW3SvcVRootNotify;
XPtr<CVRootNotify> _xNNTPSvcVRootNotify;
XPtr<CVRootNotify> _xIMAPSvcVRootNotify;
BOOL _fTrackW3Svc;
BOOL _fTrackNNTPSvc;
BOOL _fTrackIMAPSvc;
ULONG _W3SvcInstance;
ULONG _NNTPSvcInstance;
ULONG _IMAPSvcInstance;
BOOL _fIISAdminAlive;
CRegistryScopesNotify * _pRegistryScopesNotify;
CCiRegistryNotify * _pCiRegistryNotify;
};
//+---------------------------------------------------------------------------
//
// Class: CCiNotifyIter
//
// Purpose: An iterator to give successive scopes that are being watched
// for notifications.
//
// History: 1-25-96 srikants Created
//
// Notes:
//
//----------------------------------------------------------------------------
class CCiNotifyIter
{
public:
CCiNotifyIter( CCiNotifyMgr & notifyMgr ) :
_notifyMgr(notifyMgr),
_lock(notifyMgr.GetMutex()),
_iNotAdded(0),
_stack(notifyMgr._stkScopes),
_list(notifyMgr._list),
_iter(_list)
{
_UpdateAtEnd();
}
BOOL AtEnd() const { return _fAtEnd; }
WCHAR const * Get()
{
Win4Assert( !AtEnd() );
if ( _iNotAdded < _stack.Count() )
return _stack.Get(_iNotAdded)->GetPath();
else
return _iter->GetScope();
}
void GetLastScanTime( FILETIME & ft )
{
if ( _iNotAdded < _stack.Count() )
RtlZeroMemory( &ft, sizeof(FILETIME) );
else
ft = _iter->GetLastScanTime();
}
VOLUMEID VolumeId()
{
Win4Assert( !AtEnd() );
if ( _iNotAdded < _stack.Count() )
return _stack.Get(_iNotAdded)->VolumeId();
else
return _iter->VolumeId();
}
ULONGLONG const & VolumeCreationTime()
{
Win4Assert( !AtEnd() );
if ( _iNotAdded < _stack.Count() )
return _stack.Get(_iNotAdded)->VolumeCreationTime();
else
return _iter->VolumeCreationTime();
}
ULONG VolumeSerialNumber()
{
Win4Assert( !AtEnd() );
if ( _iNotAdded < _stack.Count() )
return _stack.Get(_iNotAdded)->VolumeSerialNumber();
else
return _iter->VolumeSerialNumber();
}
BOOL IsDownlevelVolume()
{
Win4Assert( !AtEnd() );
if ( _iNotAdded < _stack.Count() )
return ( CI_VOLID_USN_NOT_ENABLED == _stack.Get(_iNotAdded)->VolumeId() );
else
return ( CI_VOLID_USN_NOT_ENABLED == _iter->VolumeId() );
}
USN Usn()
{
Win4Assert( !AtEnd() );
if ( _iNotAdded < _stack.Count() )
return _stack.Get(_iNotAdded)->Usn();
else
return _iter->Usn();
}
ULONGLONG const & JournalId()
{
Win4Assert( !AtEnd() );
if ( _iNotAdded < _stack.Count() )
return _stack.Get(_iNotAdded)->JournalId();
else
return _iter->JournalId();
}
BOOL FUsnTreeScan()
{
Win4Assert( !AtEnd() );
if ( _iNotAdded < _stack.Count() )
return _stack.Get(_iNotAdded)->FUsnTreeScan();
else
return _iter->FUsnTreeScan();
}
void InitUsnTreeScan()
{
Win4Assert( !AtEnd() );
if ( _iNotAdded < _stack.Count() )
_stack.Get(_iNotAdded)->InitUsnTreeScan();
else
_iter->InitUsnTreeScan();
}
void SetTreeScanComplete();
void SetUsnTreeScanComplete( USN usnMax );
void Advance()
{
Win4Assert( !AtEnd() );
if ( _iNotAdded < _stack.Count() )
_iNotAdded++;
else
_list.Advance(_iter);
_UpdateAtEnd();
}
private:
CCiNotifyMgr & _notifyMgr;
CLock _lock;
unsigned _iNotAdded;
BOOL _fAtEnd;
CScopeInfoStack & _stack;
CCiNotifyList & _list;
CFwdCiNotifyIter _iter;
void _UpdateAtEnd()
{
Win4Assert( _iNotAdded <= _stack.Count() );
_fAtEnd = _iNotAdded == _stack.Count() && _list.AtEnd(_iter);
}
};
BOOL AreIdenticalPaths( WCHAR const * pwcsPath1, WCHAR const * pwcsPath2 );