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.
 
 
 
 
 
 

883 lines
24 KiB

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1991 - 2000.
//
// File: RESMAN.HXX
//
// Contents: Resource Manager
//
// Classes: CResManager
//
// History: 4-Apr-91 BartoszM Created.
// 4-Jan-95 BartoszM Separated Filter Manager
//
//----------------------------------------------------------------------------
#pragma once
//+---------------------------------------------------------------------------
//
// Class: CResManager
//
// Purpose: Manages resources (threads, memory, disk)
//
// Interface: CResManager
//
// History: 4-Apr-91 BartoszM Created
//
//----------------------------------------------------------------------------
#include <pidxtbl.hxx>
#include <lang.hxx>
#include <ciintf.h>
#include <frmutils.hxx>
#include <workman.hxx>
#include <idxnotif.hxx>
#include "cibackup.hxx"
#include "flushnot.hxx"
#include "afwwork.hxx"
#include "abortwid.hxx"
#include "fresh.hxx"
#include "partlst.hxx"
#include "index.hxx"
#include "merge.hxx"
#include "wordlist.hxx"
#include "keylist.hxx"
#include "pqueue.hxx"
#include "rmstate.hxx"
class CContentIndex;
class CPartition;
class CDocList;
class CEntryBuffer;
class CPersIndex;
class CMasterMergeIndex;
class CGetFilterDocsState;
class CFilterAgent;
class PStorage;
class CPidMapper;
class CSimplePidRemapper;
class CResManager;
class PSaveProgressTracker;
BOOL LokCheckIfDiskLow( CResManager & resman,
PStorage & storage,
BOOL fIsCurrentFull,
ICiCAdviseStatus & adviseStatus );
typedef CDynStackInPlace<PARTITIONID> CPartIdStack;
const LONGLONG eSigResman = 0x20204e414d534552i64; // "RESMAN"
//+---------------------------------------------------------------------------
//
// Class: CMergeThreadKiller
//
// Purpose: An object to kill the merge thread should the constructor of
// CResManager fail.
//
// History: 3-06-95 srikants Created
//
// Notes:
//
//----------------------------------------------------------------------------
class CMergeThreadKiller
{
public:
CMergeThreadKiller( CResManager & resman );
~CMergeThreadKiller();
void Defuse()
{
_fKill = FALSE;
}
private:
CResManager & _resman;
BOOL _fKill; // If set to TRUE, the merge thread must be
// killed by this object.
};
class CDeletedIIDTrans;
//+---------------------------------------------------------------------------
//
// Class: CWorkIdToDocName
//
// Purpose: Converts a objectId (workId) to its corresponding docname
//
// History: 20-Oct-94 DwightKr Created
// 22-Jan-97 SrikantS Changed to generating un-interpreted
// BYTES for framework support.
//
//----------------------------------------------------------------------------
class CWorkIdToDocName
{
public:
CWorkIdToDocName( ICiCDocNameToWorkidTranslator * pITranslator,
ICiCDocNameToWorkidTranslatorEx * pITranslator2 )
{
Win4Assert( 0 != pITranslator );
ICiCDocName * pIDocName = 0;
SCODE sc = pITranslator->QueryDocName( &pIDocName );
if ( S_OK != sc )
THROW( CException( sc ) );
_docName.Set( pIDocName );
pITranslator->AddRef();
_translator.Set( pITranslator );
if ( 0 != pITranslator2 )
{
pITranslator2->AddRef();
_translator2.Set( pITranslator2 );
}
}
const BYTE * GetDocName( WORKID objectId, ULONG & cbDocName, BOOL fAccurate )
{
_docName->Clear();
BYTE const * pbBuffer = 0;
cbDocName = 0;
SCODE sc;
if ( fAccurate && !_translator2.IsNull() )
{
sc = _translator2->WorkIdToAccurateDocName( objectId,
_docName.GetPointer() );
}
else
sc = _translator->WorkIdToDocName( objectId,
_docName.GetPointer() );
if ( S_OK == sc )
{
sc = _docName->GetNameBuffer( &pbBuffer, &cbDocName );
Win4Assert( S_OK == sc );
}
return pbBuffer;
}
private:
XInterface<ICiCDocNameToWorkidTranslator> _translator;
XInterface<ICiCDocNameToWorkidTranslatorEx> _translator2;
XInterface<ICiCDocName> _docName;
};
//+---------------------------------------------------------------------------
//
// Class: CResManager
//
// History: 08-Apr-91 BartoszM Created
//
//----------------------------------------------------------------------------
class CResManager
{
friend class CFilterManager;
friend class CFilterAgent;
friend class CMerge;
friend class CMasterMerge;
friend class CIndexSnapshot;
friend class CReleaseMMergeIndex;
friend class CIndexTrans;
friend class CMasterMergeTrans;
friend class CMergeThreadKiller;
friend class CDeletedIIDTrans;
friend class CNotificationTransaction;
friend class CBackupCiPersData;
public:
CResManager( PStorage& storage,
CCiFrameworkParams & params,
ICiCDocStore * pICiCDocStore,
CI_STARTUP_INFO const & startupInfo,
IPropertyMapper * pIPropertyMapper,
CTransaction &xact,
XInterface<CIndexNotificationTable> & xIndexNotifTable );
~CResManager();
void RegisterFilterAgent ( CFilterAgent* pFilterAgent )
{
_pFilterAgent = pFilterAgent;
}
static DWORD WINAPI MergeThread( void* self );
//
// State Changes
//
NTSTATUS Dismount();
void Empty();
NTSTATUS ForceMerge ( PARTITIONID partid, CI_MERGE_TYPE mt );
NTSTATUS StopCurrentMerge();
void DisableUpdates( PARTITIONID partid );
void EnableUpdates( PARTITIONID partid );
//
// Global Resources
//
BOOL IsLowOnDiskSpace() const { return _isLowOnDiskSpace; }
BOOL VerifyIfLowOnDiskSpace()
{
CPriLock lock(_mutex);
return LokCheckLowOnDiskSpace();
}
BOOL LokCheckLowOnDiskSpace ()
{
_isLowOnDiskSpace = LokCheckIfDiskLow(*this,
_storage,
_isLowOnDiskSpace,
_adviseStatus.GetReference() );
return _isLowOnDiskSpace;
}
BOOL LokCheckWordlistQuotas();
NTSTATUS MarkCorruptIndex();
void NoFailFreeResources();
BOOL IsMemoryLow();
BOOL IsIoHigh();
BOOL IsBatteryLow();
BOOL IsOnBatteryPower();
BOOL IsUserActive( BOOL fCheckLongTermActivity );
void SampleUserActivity();
void IndexSize( ULONG & mbIndex );
//
// Statistics and State
//
BOOL IsEmpty() const { return _isBeingEmptied; }
unsigned CountPendingUpdates(unsigned& secCount);
inline unsigned CountPendingUpdates()
{
unsigned temp;
return CountPendingUpdates( temp );
}
void LokUpdateCounters(); // performance meter
void ReferenceQuery();
void DereferenceQuery();
LONG GetQueryCount() const { return _cQuery; }
//
// Updates and queries
//
unsigned ReserveUpdate( WORKID wid );
SCODE UpdateDocument( unsigned iHint,
WORKID wid,
PARTITIONID partid,
USN usn,
VOLUMEID volumeId,
ULONG action);
void FlushUpdates();
void MarkUnReachable( WORKID wid )
{
_docStore->MarkDocUnReachable( wid );
}
CIndex** QueryIndexes ( unsigned cPartitions,
PARTITIONID aPartID[],
CFreshTest** freshTest,
unsigned& cInd,
ULONG cPendingUpdates,
CCurStack * pcurPending,
ULONG* pFlags );
void ReleaseIndexes (
unsigned cInd,
CIndex** apIndex,
CFreshTest* fresh );
SCODE ClearNonStoragePropertiesForWid( WORKID wid );
//
// Backup of Content Index Data.
//
SCODE BackupCIData( PStorage & storage,
BOOL & fFull,
XInterface<ICiEnumWorkids> & xEnumWorkids,
PSaveProgressTracker & progressTracker );
//
// Feedback from downlevel scan
//
inline void MarkOutOfDate();
inline void MarkUpToDate();
//
// Scanning
//
void SetUpdatesLost( PARTITIONID partId );
//
// Notification of ChangeLog flushes support.
//
void NotifyFlush( FILETIME const & ft,
ULONG cEntries,
USN_FLUSH_INFO ** aInfo );
void ProcessFlushNotifies();
// KeyIndex specific Methods
ULONG KeyToId( CKey const * pkey );
void IdToKey( ULONG ulKid, CKey & rkey );
// Relevant Words
CRWStore * ComputeRelevantWords(ULONG cRows,ULONG cRW,
WORKID *pwid,PARTITIONID partid);
CRWStore * RetrieveRelevantWords(BOOL fAcquire,PARTITIONID partid);
NTSTATUS CiState(CIF_STATE & state);
void IncrementFilteredDocumentCount()
{
InterlockedIncrement(&_cFilteredDocuments);
}
ULONG GetFilteredDocumentCount() const { return _cFilteredDocuments; }
CCiFrameworkParams & GetRegParams() { return _frmwrkParams; }
SCODE FPSToPROPID( CFullPropSpec const & fps, PROPID & pid );
BOOL FPushFiltering()
{
Win4Assert( _fPushFiltering == !_xIndexNotifTable.IsNull() );
return _fPushFiltering;
}
void NoFailAbortWidsInDocList();
void NoFailAbortWid( WORKID wid, USN usn );
BOOL LokIsWidAborted( WORKID wid, USN usn )
{
return _aAbortedWids.LokIsWidAborted( wid, usn );
}
void LokRemoveAbortedWid( WORKID wid, USN usn )
{
_aAbortedWids.LokRemoveWid( wid, usn );
}
BOOL IsCiCorrupt() { return _isCorrupt; }
# ifdef CIEXTMODE
void CiExtDump(void *ciExtSelf);
# endif
private:
// Allow Fiter Manager to lock ResManager
CMutexSem& GetMutex () { return _mutex; }
void CompactResources();
unsigned LokGetFreshCount()
{
return _fresh.LokCount();
}
inline void LokCommitFresh ( CFreshTest* freshTest );
CPartition* LokGetPartition ( PARTITIONID partid )
{ return _partList.LokGetPartition(partid); }
// Merges
void DoMerges();
void StopMerges();
void CheckAndDoMerge( MergeType mt, CPartIdStack & partitionIds );
BOOL CheckDeleteMerge( BOOL fForce );
void Merge ( MergeType mt, PARTITIONID partid );
void MasterMerge ( PARTITIONID partid );
void LokClearForceMerge() { _partidToMerge = partidInvalid; }
void LokReleaseIndex ( CIndex* pIndex );
void LokReplaceMasterIndex( CMasterMergeIndex * pMMergeIndex );
#ifdef KEYLIST_ENABLED
CKeyList * _AddRefKeyList();
void _ReleaseKeyList();
#endif // KEYLIST_ENABLED
void RollBackDeletedIIDChange( CDeletedIIDTrans & xact );
// Filter related methods
CDocList & GetDocList() { return _docList; }
BOOL GetFilterDocs ( ULONG cMaxDocs,
ULONG & cDocs,
CGetFilterDocsState & state );
BOOL LokGetFilterDocs( ULONG cMaxDocs,
ULONG & cDocs,
CGetFilterDocsState & state );
void FillDocBuffer ( BYTE * docBuffer,
ULONG & cb,
ULONG & cDocs,
CGetFilterDocsState & state );
BOOL NoFailReFile ( CDocList& docList );
BOOL ReFileCommit ( CDocList& docList );
void NoFailReFileChanges( CDocList& docList );
void LokNoFailReFileChanges( CDocList& docList );
void LokReFileDocument ( PARTITIONID partid,
WORKID wid,
USN usn,
VOLUMEID volumeId,
ULONG retries,
ULONG cSecQRetries );
void LokAddToSecQueue( PARTITIONID partid, WORKID wid, VOLUMEID volumeId, ULONG cSecQRetries );
void LokRefileSecQueueDocs();
BOOL LokTransferWordlist ( PWordList& pWordlist );
void LokNoFailRemoveWordlist( CPartition * pPart );
INDEXID LokMakeWordlistId (PARTITIONID partid);
void ReportFilterFailure (WORKID wid);
SCODE StoreValue( WORKID wid, CFullPropSpec const & ps, CStorageVariant const & var, BOOL & fInSchema );
BOOL StoreSecurity( WORKID wid, PSECURITY_DESCRIPTOR pSD, ULONG cbSD);
void ReportFilteringState( DWORD dwState )
{
CPriLock lock( _mutex );
_dwFilteringState = dwState;
}
//
// Scan and Recovery support
//
void LokCleanupForFullCiScan();
//
// Misc utility methods.
//
static BOOL IsDiskFull( NTSTATUS status )
{
return STATUS_DISK_FULL == status ||
ERROR_DISK_FULL == status ||
HRESULT_FROM_WIN32(ERROR_DISK_FULL) == status ||
CI_E_CONFIG_DISK_FULL == status;
}
static BOOL IsCorrupt( NTSTATUS status )
{
return CI_CORRUPT_DATABASE == status ||
STATUS_INTEGER_DIVIDE_BY_ZERO == status ||
STATUS_ACCESS_VIOLATION == status ||
STATUS_DATATYPE_MISALIGNMENT == status ||
STATUS_IN_PAGE_ERROR == status;
}
static void LogMMergeStartFailure( BOOL fReStart,
PStorage & storage,
DWORD dwError,
ICiCAdviseStatus & adviseStatus );
static void LogMMergePaused( PStorage & storage,
DWORD dwError,
ICiCAdviseStatus & adviseStatus);
//
// Interfacing with the framework client
//
BOOL WorkidToDocName ( WORKID wid, BYTE * pbBuf, unsigned & cb, BOOL fAccurate );
void GetClientState( ULONG & cDocuments );
void LokNotifyCorruptionToClient();
void LokNotifyDisableUpdatesToClient();
void LokNotifyEnableUpdatesToClient();
BOOL LokIsScanNeeded() const { return _isCorrupt
|| _state.LokGetState() == eUpdatesToBeDisabled
|| _state.LokGetState() == eUpdatesDisabled
|| _state.LokGetState() == eUpdatesToBeEnabled; }
void LokWakeupMergeThread()
{
_eventMerge.Set();
}
void LokDeleteFlushWorkItems();
BOOL IsIndexMigrationEnabled() const
{
return _configFlags & CI_CONFIG_ENABLE_INDEX_MIGRATION;
}
BOOL IsIndexingEnabled() const
{
return _configFlags & CI_CONFIG_ENABLE_INDEXING;
}
BOOL IsQueryingEnabled() const
{
return _configFlags & CI_CONFIG_ENABLE_QUERYING;
}
CFresh & GetFresh() { return _fresh; }
PIndexTable & GetIndexTable()
{
return *_idxTab;
}
BOOL LokIsMasterMergeInProgress( PARTITIONID partId = partidDefault )
{
CPartition *pPartition =
_partList.LokGetPartition ( partId );
return pPartition->InMasterMerge();
}
BOOL LokIsMasterIndexPresent( PARTITIONID partId = partidDefault )
{
CPartition *pPartition =
_partList.LokGetPartition ( partId );
return 0 != pPartition->GetCurrentMasterIndex();
}
void BackupContentIndexData();
void LokUpdateBackupMergeProgress();
ULONG GetStorageVersion() { return _storage.GetStorageVersion(); }
//-----------------------------------------------
// This MUST be the first variable in this class.
//-----------------------------------------------
const LONGLONG _sigResman;
PStorage& _storage;
CMutexSem _mutex;
ULONGLONG _mergeTime; // Time to next master merge
XInterface<ICiCResourceMonitor> _xLowRes; // Monitors resource conditions
XInterface<ICiCResourceMonitor> _xLowResDefault; // Monitors resource conditions
//ULONG _ulPagesPerMeg; // System pages per Meg (varies with system page size)
//ULONG _ulPageSize; // System page size
//
// Performance Object
// Note : Must be initialized before CFilterDaemon
// and destroyed after the partition list.
//
CCiFrameworkParams & _frmwrkParams;
XPtr<CKeyList> _sKeyList; // Safe pointer to the keylist object
SIndexTable _idxTab; // index table
CPartList _partList; // list of partitions
CFresh _fresh; // table of fresh indexes
// MUST BE after _partList.
CPartIter _partIter; // partition iterator
CEventSem _eventMerge;
PARTITIONID _partidToMerge; // force merge of this partition
CI_MERGE_TYPE _mtForceMerge; // type of merge
CMerge * _pMerge;
BOOL _fStopMerge;
long _cQuery;
long _cFilteredDocuments; // # filtered documents since boot
CFilterAgent* _pFilterAgent;
//
// Queue used to properly order notifications coming from Cleanup.
//
CPendingQueue _pendQueue;
//
// Documents that are currently being filtered by the daemon.
//
CDocList _docList;
//
// In-progress backup operation.
//
CBackupCiWorkItem * _pBackupWorkItem;
BOOL _isBeingEmptied;
BOOL _isLowOnDiskSpace;
BOOL _isDismounted;
BOOL _isOutOfDate;
BOOL _isCorrupt;
BOOL _fFirstTimeUpdatesAreEnabled; // Is this the first time that
// updates have been enabled after
// startup ? This is used in push
// filtering to initialize in-memory
// part of changelog.
BOOL _fPushFiltering; // Push model of filtering ?
const CI_STARTUP_FLAGS _configFlags; // Content Index flags
CResManState _state;
DWORD _dwFilteringState; // State of the Filter Manager (for ::CiState)
//
// Framework interfacing.
//
XInterface<ICiCDocStore> _docStore;
XInterface<ICiCDocNameToWorkidTranslator> _translator;
XInterface<ICiCDocNameToWorkidTranslatorEx> _translator2;
XInterface<ICiCAdviseStatus> _adviseStatus;
XInterface<ICiCPropertyStorage> _propStore;
XInterface<IPropertyMapper> _mapper;
XInterface<CIndexNotificationTable> _xIndexNotifTable; // Table of notifications
CAbortedWids _aAbortedWids; // List of aborted wids
//
// Mutex to guard the flush notify list and the flush notify list.
//
BOOL _fFlushWorkerActive;
CMutexSem _mtxChangeFlush;
CChangesNotifyFlushList _flushList;
//
// WorkQueue manager for the async work items.
//
CWorkManager _workMan; // Work Queue Manager
//
// This mutex is for the workIdToDocName only. It is too expensive
// to hold resman lock while doing the wid->docname conversion.
//
CMutexSem _workidToDocNameMutex;
XPtr<CWorkIdToDocName> _xWorkidToDocName;
CCiFrmPerfCounter _prfCounter;
//
// Be sure the threads are created *after* any resources they use.
//
CThread _thrMerge;
CMergeThreadKiller _mergeKiller;
CDeletedIndex _activeDeletedIndex;
};
inline void CResManager::NoFailReFileChanges ( CDocList& docList )
{
CPriLock lock(_mutex);
LokNoFailReFileChanges(docList);
}
inline BOOL CResManager::GetFilterDocs ( ULONG cMaxDocs,
ULONG & cDocs,
CGetFilterDocsState & state )
{
CPriLock lock (_mutex);
return LokGetFilterDocs ( cMaxDocs, cDocs, state );
}
inline void CResManager::MarkOutOfDate()
{
CPriLock lock (_mutex);
_isOutOfDate = TRUE;
}
inline void CResManager::MarkUpToDate()
{
CPriLock lock (_mutex);
_isOutOfDate = FALSE;
}
inline void CResManager::ReferenceQuery()
{
InterlockedIncrement(&_cQuery);
}
inline void CResManager::DereferenceQuery()
{
Win4Assert( _cQuery > 0 );
InterlockedDecrement(&_cQuery);
}
//+---------------------------------------------------------------------------
//
// Function: ForceMerge, public
//
// Synopsis: Forces a master merge on the partition specified
//
// Arguments: [partid] -- partition ID to merge
// [mt] -- merge type (master, shadow, etc.)
//
// History: 16-Nov-94 DwightKr Added this header
//
//----------------------------------------------------------------------------
inline NTSTATUS CResManager::ForceMerge ( PARTITIONID partid,
CI_MERGE_TYPE mt )
{
_partidToMerge = partid;
_mtForceMerge = mt;
_eventMerge.Set(); // wake up
return STATUS_SUCCESS;
}
//+---------------------------------------------------------------------------
//
// Member: CResManager::LokCommitFresh, public
//
// Arguments: [pFreshTest] -- fresh test to be committed
//
// History: 08-Oct-91 BartoszM Created
//
// Notes: Commits a new fresh test, All transactions are under resman lock
//
//----------------------------------------------------------------------------
inline void CResManager::LokCommitFresh( CFreshTest* pFreshTest )
{
_fresh.LokCommitMaster(pFreshTest);
}
//+---------------------------------------------------------------------------
//
// Class: CMasterMergePolicy
//
// Purpose: Encapsulates all rules used to determine if it is time to
// automatically trigger a master merge.
//
// History: 03-Aug-94 DwightKr Created
//
//----------------------------------------------------------------------------
class CMasterMergePolicy
{
public :
CMasterMergePolicy( PStorage & storage,
__int64 & shadowIndexSize,
unsigned freshCount,
ULONGLONG & mergeTime,
CCiFrameworkParams & regParams,
ICiCAdviseStatus & adviseStatus) :
_frmwrkParams( regParams ),
_storage(storage),
_shadowIndexSize(shadowIndexSize),
_freshCount(freshCount),
_mergeTime(mergeTime),
_adviseStatus(adviseStatus)
{}
BOOL IsTimeToMasterMerge() const;
BOOL IsMidNightMergeTime();
static ULONGLONG ComputeMidNightMergeTime( LONG mergeTime );
private:
BOOL IsMinDiskFreeForceMerge() const;
BOOL IsMaxShadowIndexSize() const;
BOOL IsMaxFreshListCount() const;
PStorage & _storage;
__int64 & _shadowIndexSize;
unsigned _freshCount;
ULONGLONG & _mergeTime;
CCiFrameworkParams & _frmwrkParams;
ICiCAdviseStatus & _adviseStatus;
};