|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1991 - 2000.
//
// File: PropStor.hxx
//
// Contents: Persistent property store (external to docfile)
//
// Classes: CPropertyStore
//
// History: 27-Dec-19 KyleP Created
//
//----------------------------------------------------------------------------
#pragma once
#include <prcstob.hxx>
#include <phystr.hxx>
#include <rcstxact.hxx>
#include <propdesc.hxx>
#include <proplock.hxx>
#include <cistore.hxx>
#include <propbkp.hxx>
#include <fsciexps.hxx>
#include <enumstr.hxx>
#include <imprsnat.hxx>
class COnDiskPropertyRecord; class CBorrowed; class CPropRecordNoLock; class CPropRecord; class CPropRecordForWrites; class CEnumString; class CPropStoreBackupStream; class CPropStoreManager; class CCompositePropRecordForWrites;
enum ERecordFormat { eNormal = 0, eLean = 1 };
//+-------------------------------------------------------------------------
//
// Class: CPropStoreInfo
//
// Purpose: Global persistent state for property store
//
// History: 27-Dec-95 KyleP Created
//
//--------------------------------------------------------------------------
class CPropStoreInfo { public:
enum { fDirtyPropStore = 1, fNotBackedUp = 2, };
//
// Constructors and destructor
//
CPropStoreInfo(DWORD dwStoreLevel);
CPropStoreInfo( CPropStoreInfo const & psi );
~CPropStoreInfo() { Shutdown( FALSE ); }
void Init( XPtr<PRcovStorageObj> & xObj, DWORD dwStoreLevel );
void Empty();
void FastTransfer( CPropStoreInfo const & psi );
void Accept( XPtr<PRcovStorageObj> & xObj ) { Win4Assert( _xrsoPropStore.IsNull() ); _xrsoPropStore.Set( xObj.Acquire() ); _fOwned = TRUE; }
void Shutdown( BOOL fMarkClean = TRUE ) { if ( _fOwned && !_xrsoPropStore.IsNull() ) { if ( fMarkClean ) MarkClean();
_xrsoPropStore.Free(); } else { _xrsoPropStore.Acquire(); } }
//
// Global metadata
//
WORKID WorkId() { return _info.widStream; } WORKID NextWorkId(CiStorage & storage); WORKID InitWorkId(CiStorage & storage);
WORKID MaxWorkId() const { return _info.widMax; } WORKID FreeListHead() const { return _info.widFreeHead; } WORKID FreeListTail() const { return _info.widFreeTail; } ULONG RecordSize() const { return _info.culRecord; } ULONG RecordsPerPage() const { return _cRecPerPage; } ULONG FixedRecordSize() const { return _info.culFixed; } ULONG CountProps() const { return _info.cTotal; } ULONG CountFixedProps() const { return _info.cFixed; } BOOL IsDirty() const { return ( 0 != ( _info.fDirty & fDirtyPropStore ) ); } BOOL IsBackedUp() const { return ( 0 == ( _info.fDirty & fNotBackedUp ) ); }
ULONG OSPageSize() const { return _ulOSPageSize; } ULONG OSPagesPerPage() const { return _cOSPagesPerLargePage; }
inline void MarkDirty(); inline void MarkClean(); inline void MarkNotBackedUp(); inline void MarkBackedUp();
void SetMaxWorkId( WORKID wid ) { _info.widMax = wid; MarkDirty(); } void SetFreeListHead( WORKID wid ) { _info.widFreeHead = wid; MarkDirty(); } void SetFreeListTail( WORKID wid ) { _info.widFreeTail = wid; MarkDirty(); }
ULONG CountRecordsInUse() const { return _info.cTopLevel; } void IncRecordsInUse() { _info.cTopLevel++; } void DecRecordsInUse() { _info.cTopLevel--; } void SetRecordsInUse( ULONG count ) { _info.cTopLevel = count; } void SetStoreLevel(DWORD dwLevel) { _info.dwStoreLevel = dwLevel; } DWORD GetStoreLevel() { return _info.dwStoreLevel; }
//
// Lean record support
//
ERecordFormat GetRecordFormat() const { return _info.eRecordFormat; } void SetRecordFormat(ERecordFormat type) { _info.eRecordFormat = type; }
//
// Per-property metadata
//
inline BOOL CanStore( PROPID pid );
inline unsigned Size( PROPID pid );
inline ULONG Type( PROPID pid );
inline BOOL CanBeModified( PROPID pid );
inline CPropDesc const * GetDescription( PROPID pid );
inline CPropDesc const * GetDescriptionByOrdinal( ULONG ordinal );
BOOL Add( PROPID pid, ULONG vt, unsigned cbMaxLen, BOOL fCanBeModified, CiStorage & storage );
BOOL Delete( PROPID pid, CiStorage & storage );
void Commit( CPropStoreInfo & psi, CRcovStrmWriteTrans & xact );
PRcovStorageObj * GetRcovObj() { return _xrsoPropStore.GetPointer(); }
void DetectFormat();
private:
friend class CPropertyStore;
void ChangeDirty( int fDirty ); unsigned Lookup( PROPID pid ); unsigned LookupNew( PROPID pid );
inline CPropDesc const * GetDescription( unsigned i ); ULONG CountDescription() { return _aProp.Count(); }
struct SPropInfo { ULONG Version; ULONG culRecord; ULONG culFixed; int fDirty; ULONG cTotal; ULONG cFixed; ULONG cHash; WORKID widStream; WORKID widMax; WORKID widFreeHead; ULONG cTopLevel; WORKID widFreeTail; DWORD dwStoreLevel; ERecordFormat eRecordFormat; };
ULONG _cRecPerPage; // # records per 64K page
SPropInfo _info; // Non-repeated info, stored in header
XPtr<PRcovStorageObj> _xrsoPropStore; // The persistent storage itself
BOOL _fOwned; // Set to TRUE if propstore is owned.
XArray<CPropDesc> _aProp;
ULONG _ulOSPageSize; // GetSystemInfo returns this
ULONG _cOSPagesPerLargePage;// number of OS pages per COMMON_PAGE_SIZE sized large page
};
//+-------------------------------------------------------------------------
//
// Class: CPhysPropertyStore
//
// Purpose: Persistent property store
//
// History: 27-Dec-95 KyleP Created
//
//--------------------------------------------------------------------------
class CPhysPropertyStore : public CPhysStorage { public:
inline CPhysPropertyStore( PStorage & storage, PStorageObject& obj, WORKID objectId, PMmStream * stream, PStorage::EOpenMode mode, unsigned cMappedItems ); private:
virtual void ReOpenStream();
};
// Backup support
enum EField { eFieldNone = 0, eTopLevelField = 1};
//+-------------------------------------------------------------------------
//
// Class: CPropertyStore
//
// Purpose: Persistent property store
//
// History: 27-Dec-95 KyleP Created
//
//--------------------------------------------------------------------------
class CPropertyStore { public:
CPropertyStore(CPropStoreManager& propStoreMgr, DWORD dwLevel); ~CPropertyStore();
//
// Two phase construction (to accomadate late-bound storage)
//
void FastInit( CiStorage * pStorage); void LongInit( BOOL & fWasDirty, ULONG & cInconsistencies, T_UpdateDoc pfnUpdateCallback, void const *pUserData ); BOOL IsDirty() const { return _PropStoreInfo.IsDirty(); }
void Empty();
//
// Schema manipulation
//
inline BOOL CanStore( PROPID pid );
inline unsigned Size( PROPID pid );
inline ULONG Type( PROPID pid );
inline BOOL CanBeModified( PROPID pid );
ULONG_PTR BeginTransaction();
void Setup( PROPID pid, ULONG vt, DWORD cbMaxLen, ULONG_PTR ulToken, BOOL fModifiable = TRUE );
void EndTransaction( ULONG_PTR ulToken, BOOL fCommit, PROPID pidFixed );
//
// Backup/Load
//
void MakeBackupCopy( IProgressNotify * pIProgressNotify, BOOL & fAbort, CiStorage & dstStorage, ICiEnumWorkids * pIWorkIds, IEnumString **ppFileList); //
// Property storage/retrieval.
//
SCODE WriteProperty( WORKID wid, PROPID pid, CStorageVariant const & var, BOOL fBackup = TRUE); SCODE WriteProperty( CPropRecordForWrites &PropRecord, PROPID pid, CStorageVariant const & var, BOOL fBackup);
inline WORKID WritePropertyInNewRecord( PROPID pid, CStorageVariant const & var, BOOL fBackup = TRUE);
BOOL ReadProperty( WORKID wid, PROPID pid, PROPVARIANT & var ); BOOL ReadProperty( WORKID wid, PROPID pid, PROPVARIANT & var, BYTE * pbExtra, unsigned * pcbExtra ); BOOL ReadProperty( CPropRecordNoLock & PropRecord, PROPID pid, PROPVARIANT * pbData, unsigned * pcb); BOOL ReadProperty( COnDiskPropertyRecord *prec, PROPID pid, PROPVARIANT & var, BYTE * pbExtra, unsigned * pcbExtra ); BOOL ReadProperty( CPropRecordNoLock & PropRecord, PROPID pid, PROPVARIANT & var, BYTE * pbExtra, unsigned * pcbExtra );
//
// Special path/wid support
//
inline WORKID MaxWorkId(); inline ULONG RecordsPerPage() const { return _PropStoreInfo.RecordsPerPage(); }
void DeleteRecord( WORKID wid, BOOL fBackup = TRUE );
inline ULONG CountRecordsInUse() const;
void Shutdown() { _fAbort = TRUE; _PropStoreInfo.Shutdown(); }
BOOL Flush();
PStorage & GetStorage() { Win4Assert ( 0 != _pStorage );
return *_pStorage; }
CiStorage & GetCiStorage() { Win4Assert ( 0 != _pStorage );
return *_pStorage; }
//
// Some info from CPropertyStoreInfo
//
inline ULONG OSPagesPerPage() const { return _PropStoreInfo.OSPagesPerPage(); }
inline ULONG OSPageSize() const { return _PropStoreInfo.OSPageSize(); }
inline ULONG RecordSize() const { return _PropStoreInfo.RecordSize(); }
inline CPropStoreBackupStream * BackupStream() { return _xPSBkpStrm.GetPointer(); }
inline CPhysPropertyStore * PhysStore() { return _xPhysStore.GetPointer(); }
inline WORKID MaxWorkId() const { return _PropStoreInfo.MaxWorkId(); }
inline void IncRecordsInUse() { _PropStoreInfo.IncRecordsInUse(); }
//
// get and set parameters
//
void SetBackupSize(ULONG ulBackupSizeInPages) { // range will be enforced when it is actually
// used.
_ulBackupSizeInPages = ulBackupSizeInPages; }
ULONG GetDesiredBackupSize() { return _ulBackupSizeInPages; }
ULONG GetActualBackupSize() { Win4Assert(!_xPSBkpStrm.IsNull()); return _xPSBkpStrm->MaxPages(); }
void SetMappedCacheSize(ULONG ulPSMappedCache) { // Enforce ranges
C_ASSERT(CI_PROPERTY_STORE_MAPPED_CACHE_MIN == 0); if (ulPSMappedCache > CI_PROPERTY_STORE_MAPPED_CACHE_MAX) _ulPSMappedCache = CI_PROPERTY_STORE_MAPPED_CACHE_MAX; else _ulPSMappedCache = ulPSMappedCache; }
ULONG GetMappedCacheSize() { return _ulPSMappedCache; }; ULONG GetTotalSizeInKB();
inline DWORD GetStoreLevel() { return _PropStoreInfo.GetStoreLevel(); }
//
// Lean record support
//
ERecordFormat GetRecordFormat() const { return _PropStoreInfo.GetRecordFormat(); } void SetRecordFormat(ERecordFormat type) { _PropStoreInfo.SetRecordFormat( type ); }
void MarkBackedUpMode() { _PropStoreInfo.MarkBackedUp(); }
void MarkNotBackedUpMode() { _PropStoreInfo.MarkNotBackedUp(); }
BOOL IsBackedUpMode() { return _PropStoreInfo.IsBackedUp(); }
//
// Clean Up
//
void ClearNonStorageProperties( CCompositePropRecordForWrites & rec );
private:
friend class CPropertyStoreWids; friend class CPropRecordNoLock; friend class CPropRecord; friend class CPropRecordForWrites; friend class CPropertyStoreRecovery; friend class CPropStoreManager; friend class CLockRecordForRead; friend class CLockRecordForWrite; friend class CLockAllRecordsForWrite; friend class CBackupWid;
CPropertyStore( CPropertyStore & psi, CiStorage * pStorage );
WORKID CreateStorage( WORKID wid = widInvalid );
void InitNewRecord( WORKID wid, ULONG cWid, COnDiskPropertyRecord * prec, BOOL fTopLevel, BOOL fBackup);
void InitFreeList( );
void RecycleFreeList( WORKID wid );
void LokFreeRecord( WORKID wid, ULONG cFree, COnDiskPropertyRecord * prec, BOOL fBackup );
WORKID LokAllocRecord( ULONG cFree );
void WritePropertyInSpecificNewRecord( WORKID wid, PROPID pid, CStorageVariant const & var, BOOL fBackup = TRUE );
WORKID NewWorkId( ULONG cWid, BOOL fBackup ) { return LokNewWorkId( cWid, TRUE, fBackup ); }
WORKID LokNewWorkId( ULONG cWid, BOOL fTopLevel, BOOL fBackup );
//
// Record locking.
//
void AcquireRead( CReadWriteLockRecord & record ); void SyncRead( CReadWriteLockRecord & record ); void SyncReadDecrement( CReadWriteLockRecord & record ); void ReleaseRead( CReadWriteLockRecord & record );
void AcquireWrite( CReadWriteLockRecord & record ); void ReleaseWrite( CReadWriteLockRecord & record );
void AcquireWrite2( CReadWriteLockRecord & record ); void ReleaseWrite2( CReadWriteLockRecord & record );
void AcquireWriteOnAllRecords(); void ReleaseWriteOnAllRecords();
CPropertyLockMgr & LockMgr() { return _lockMgr; }
CReadWriteAccess & GetReadWriteAccess() { return _rwAccess; }
void Transfer( CPropertyStore & Target, PROPID pidFixed, BOOL & fAbort, IProgressNotify * pProgress = 0 );
void FastTransfer( CPropertyStore & Target, BOOL & fAbort, IProgressNotify * pProgress = 0 );
CiStorage * _pStorage; // Persistent storage object.
CPropStoreInfo _PropStoreInfo; // Global persistent state for property store.
WORKID * _aFreeBlocks; // Pointers into free list by rec. size
BOOL _fAbort; // Set to TRUE when aborting
BOOL _fIsConsistent; // Set to TRUE as long as the data is
// consistent
//
// Record locking
//
CMutexSem _mtxWrite; // Taken to add/remove/modify records
CMutexSem _mtxRW; // Sometimes used during per-record locking
CEventSem _evtRead; // Sometimes used during per-record locking
CEventSem _evtWrite; // Sometimes used during per-record locking
CPropertyLockMgr _lockMgr; // arbitrates record-level locking
CReadWriteAccess _rwAccess; // Controls access to resources
XPtr<CPhysPropertyStore> _xPhysStore; // Main data stream.
//
// For multi-property changes to metadata
//
CPropertyStore * _ppsNew; // New metadata stored here
BOOL _fNew; // TRUE if something really changed
XPtr<CPropStoreBackupStream> _xPSBkpStrm; // prop store backup stream
ULONG _ulBackupSizeInPages; // backup size in pages
ULONG _ulPSMappedCache; // size of the mapped cache
DWORD _dwStoreLevel; // primary or secondary?
CPropStoreManager& _propStoreMgr; // Manager controlling this.
#if CIDBG==1
_int64 _sigPSDebug;
DWORD _tidReadSet; DWORD _tidReadReset; DWORD _tidWriteSet; DWORD _tidWriteReset; BYTE * _pbRecordLockTracker; // tracks write locking for en masse record lockup
void _SetReadTid() { _tidReadSet = GetCurrentThreadId(); }
void _ReSetReadTid() { _tidReadReset = GetCurrentThreadId(); }
void _SetWriteTid() { _tidWriteSet = GetCurrentThreadId(); }
void _ReSetWriteTid() { _tidWriteReset = GetCurrentThreadId(); }
//
// Deadlock detection for the first 256 threads.
//
enum { cTrackThreads = 2048 };
XArray<long> _xPerThreadReadCounts; XArray<long> _xPerThreadWriteCounts;
#else
void _SetReadTid() { } void _ReSetReadTid() { } void _SetWriteTid() { } void _ReSetWriteTid() { }
#endif // CIDBG==1
};
//+---------------------------------------------------------------------------
//
// Member: CPropStoreInfo::CanStore, public
//
// Arguments: [pid] -- Propid to check.
//
// Returns: TRUE if [pid] can exist in property store (e.g. has been
// registered).
//
// History: 27-Dec-95 KyleP Created.
//
//----------------------------------------------------------------------------
inline BOOL CPropStoreInfo::CanStore( PROPID pid ) { return (0 != _info.cHash) && _aProp[Lookup(pid)].IsInUse(); }
//+---------------------------------------------------------------------------
//
// Member: CPropStoreInfo::Size, public
//
// Synopsis: Returns size in cache for this property.
//
// Arguments: [pid] -- Propid to check.
//
// Returns: TRUE if [pid] can exist in property store (e.g. has been
// registered).
//
// History: 27-Dec-95 KyleP Created.
//
//----------------------------------------------------------------------------
inline unsigned CPropStoreInfo::Size( PROPID pid ) { if (0 == _info.cHash) return 0;
unsigned hash = Lookup(pid);
if ( _aProp[hash].IsInUse() ) return _aProp[hash].Size(); else return 0; }
inline BOOL CPropStoreInfo::CanBeModified( PROPID pid ) { if (0 == _info.cHash) return TRUE;
unsigned hash = Lookup(pid);
if ( _aProp[hash].IsInUse() ) return _aProp[hash].Modifiable(); else { // if it not in the store, it doesn't matter what the
// reply is. But we will return TRUE so clients like Admin know that
// they can allow the property metadata to be modified.
return TRUE; }
}
//+---------------------------------------------------------------------------
//
// Member: CPropStoreInfo::Type, public
//
// Synopsis: Returns type in cache for this property.
//
// Arguments: [pid] -- Propid to check.
//
// Returns: TRUE if [pid] can exist in property store (e.g. has been
// registered).
//
// History: 27-Dec-95 KyleP Created.
//
//----------------------------------------------------------------------------
inline ULONG CPropStoreInfo::Type( PROPID pid ) { if (0 == _info.cHash) return VT_EMPTY;
unsigned hash = Lookup(pid);
if ( _aProp[hash].IsInUse() ) return _aProp[hash].Type(); else return VT_EMPTY; }
void CPropStoreInfo::MarkDirty() { #if 0 // there are too many clients who get this wrong...
CImpersonateSystem impersonate(FALSE); // FALSE = don't impersonate
Win4Assert(!impersonate.IsImpersonated()); #endif // cidbg == 1
if ( 0 == ( _info.fDirty & fDirtyPropStore ) ) { CImpersonateSystem impersonate; ChangeDirty( _info.fDirty | fDirtyPropStore ); } }
void CPropStoreInfo::MarkClean() { if ( 0 != ( _info.fDirty & fDirtyPropStore ) ) { CImpersonateSystem impersonate; ChangeDirty( _info.fDirty & ~fDirtyPropStore ); } }
void CPropStoreInfo::MarkNotBackedUp() { if ( 0 == ( _info.fDirty & fNotBackedUp ) ) ChangeDirty( _info.fDirty | fNotBackedUp ); }
void CPropStoreInfo::MarkBackedUp() { if ( 0 != ( _info.fDirty & fNotBackedUp ) ) ChangeDirty( _info.fDirty & ~fNotBackedUp ); }
inline CPhysPropertyStore::CPhysPropertyStore( PStorage & storage, PStorageObject& obj, WORKID objectId, PMmStream * stream, PStorage::EOpenMode mode, unsigned cMappedItems ) : CPhysStorage( storage, obj, objectId, stream, mode, TRUE, cMappedItems ) { }
//+---------------------------------------------------------------------------
//
// Member: CPropertyStore::CanStore, public
//
// Arguments: [pid] -- Propid to check.
//
// Returns: TRUE if [pid] can exist in property store (e.g. has been
// registered).
//
// History: 27-Dec-95 KyleP Created.
//
//----------------------------------------------------------------------------
inline BOOL CPropertyStore::CanStore( PROPID pid ) { return _PropStoreInfo.CanStore( pid ); }
//+---------------------------------------------------------------------------
//
// Member: CPropertyStore::Size, public
//
// Arguments: [pid] -- Propid to check.
//
// Returns: Size of property in store, or 0 if it isn't in store.
//
// History: 27-Dec-95 KyleP Created.
//
//----------------------------------------------------------------------------
inline unsigned CPropertyStore::Size( PROPID pid ) { return _PropStoreInfo.Size( pid ); }
//+---------------------------------------------------------------------------
//
// Member: CPropertyStore::Type, public
//
// Arguments: [pid] -- Propid to check.
//
// Returns: Type of property in store, or VT_EMPTY if it isn't in store.
//
// History: 27-Dec-95 KyleP Created.
//
//----------------------------------------------------------------------------
inline ULONG CPropertyStore::Type( PROPID pid ) { return _PropStoreInfo.Type( pid ); }
//+---------------------------------------------------------------------------
//
// Member: CPropertyStore::WritePropertyInNewRecord, public
//
// Synopsis: Like WriteProperty, but also allocates record.
//
// Arguments: [pid] -- Propid to write.
// [var] -- Property value
//
// Returns: Workid of new record.
//
// History: 27-Dec-95 KyleP Created.
//
//----------------------------------------------------------------------------
inline WORKID CPropertyStore::WritePropertyInNewRecord( PROPID pid, CStorageVariant const & var, BOOL fBackup ) { WORKID wid = NewWorkId( 1, fBackup );
ciDebugOut(( DEB_PROPSTORE, "New short record at %d\n", wid ));
WriteProperty( wid, pid, var, fBackup );
_PropStoreInfo.IncRecordsInUse();
return wid; }
//+---------------------------------------------------------------------------
//
// Member: CPropertyStore::CountRecordsInUse, public
//
// Returns: Count of 'top level' records (correspond to user wids)
//
// History: 15-Feb-96 KyleP Created.
//
//----------------------------------------------------------------------------
inline ULONG CPropertyStore::CountRecordsInUse() const { return _PropStoreInfo.CountRecordsInUse(); }
//+---------------------------------------------------------------------------
//
// Member: CPropertyStore::MaxWorkId, public
//
// Returns: Maximum workid which has been allocated.
//
// History: 28-Dec-95 KyleP Created.
//
//----------------------------------------------------------------------------
inline WORKID CPropertyStore::MaxWorkId() { return _PropStoreInfo.MaxWorkId(); }
//+---------------------------------------------------------------------------
//
// Member: CPropertyStore::CanBeModified, public
//
// Returns: Can the property info be modifed for the given property?
//
// History: 28-Dec-95 KyleP Created.
//
//----------------------------------------------------------------------------
inline BOOL CPropertyStore::CanBeModified( PROPID pid ) { return _PropStoreInfo.CanBeModified( pid ); }
//+---------------------------------------------------------------------------
//
// Member: CPropertyStoreInfo::GetDescription, public
//
// Arguments: [pid] -- Propid to check.
//
// Returns: Metadata descriptor for specified property.
//
// History: 28-Dec-95 KyleP Created.
//
//----------------------------------------------------------------------------
inline CPropDesc const * CPropStoreInfo::GetDescription( PROPID pid ) { if (0 == _info.cHash) return 0;
unsigned hash = Lookup( pid );
if ( _aProp[hash].IsInUse() ) return &_aProp[hash]; else return 0; }
//+---------------------------------------------------------------------------
//
// Member: CPropertyStoreInfo::GetDescription, public
//
// Arguments: [i] -- the index position in the array.
//
// Returns: Metadata descriptor for the i-th property in the schema.
//
// History: 17-Oct-2000 KitmanH Created.
//
//----------------------------------------------------------------------------
inline CPropDesc const * CPropStoreInfo::GetDescription( unsigned i ) { if (0 == _info.cHash) return 0;
if ( i < _aProp.Count() ) { if ( pidInvalid != _aProp[i].Pid() ) return &_aProp[i]; }
return 0; }
//+---------------------------------------------------------------------------
//
// Member: CPropertyStoreInfo::GetDescriptionByOrdinal, public
//
// Arguments: [ordinal] -- Ordinal
//
// Returns: Metadata descriptor for specified property.
//
// History: 16-Jan-96 KyleP Created.
//
//----------------------------------------------------------------------------
inline CPropDesc const * CPropStoreInfo::GetDescriptionByOrdinal( ULONG ordinal ) { Win4Assert( 0 != _info.cHash );
for ( unsigned i = 0; i < _aProp.Count(); i++ ) { if ( _aProp[i].Pid() != pidInvalid && _aProp[i].Ordinal() == ordinal ) return &_aProp[i]; }
return 0; }
//+---------------------------------------------------------------------------
//
// Class: CPropertyStoreRecovery
//
// Purpose: Recovers the property store from a dirty shutdown
//
// History: 4-10-96 srikants Created
//
// Notes:
//
//----------------------------------------------------------------------------
class CPropertyStoreRecovery { public:
CPropertyStoreRecovery( CPropertyStore & propStore, T_UpdateDoc pfnUpdateCallback, void const *pUserData ); ~CPropertyStoreRecovery( );
void DoRecovery(); ULONG GetInconsistencyCount() const { return _cInconsistencies; }
private:
void Pass0(); void Pass1(); void Pass2();
void Complete(); void SetFree();
BOOL CheckOverflowChain(); void FreeChain();
WORKID AddToFreeList( WORKID widFree, ULONG cFree, COnDiskPropertyRecord * precFree, WORKID widListHead );
CPropertyStore & _propStore; CPropStoreInfo & _PropStoreInfo;
CPhysPropertyStore * _pPhysStore;
WORKID _wid; // Wid being processed currently
COnDiskPropertyRecord * _pRec; // Pointer to _wid's on disk rec
WORKID _cRec; // Count of records for this wid
XPtr<CPropStoreBackupStream> _xPSBkpStrm; // prop store backup stream
//
// Cumulative values during recovery.
//
WORKID * _aFreeBlocks; // Array of free lists by size
WORKID _widMax; // Current wid max
ULONG _cTopLevel; // Total top level records
ULONG _cRecPerPage; // Records per long page
ULONG _cInconsistencies; // Number of inconsistencies.
ULONG _cForceFreed; // Number of records forecefully
// freed.
THashTable<ULONG> _pageTable; // Table of pages in backup.
T_UpdateDoc _fnUpdateCallback; // callback to update the wid
void const * _pUserData; // user data echoed back along with callback
class CGraftPage { public: ~CGraftPage() { _pPhysStore->ReturnLargeBuffer(_ulPageInPS / _cPagesPerLargePage); }
CGraftPage(ULONG ulPageInBkp, ULONG ulPageInPS, ULONG cPageSize, ULONG cCustomPagesPerLargePage, CPhysPropertyStore *pPhysStore, CPropStoreBackupStream *pPSBkpStrm): _cPagesPerLargePage( cCustomPagesPerLargePage ), _ulPageInPS( ulPageInPS ), _pPhysStore( pPhysStore ) { PBYTE pLargePage = (PBYTE)pPhysStore->BorrowLargeBuffer( ulPageInPS/cCustomPagesPerLargePage, TRUE); BYTE *pbPageLoc = (pLargePage + cPageSize*(ulPageInPS%cCustomPagesPerLargePage));
// Zap the page from backup file to property store
pPSBkpStrm->ReadPage(ulPageInBkp, &ulPageInPS, pbPageLoc); ciDebugOut((DEB_PROPSTORE, "Successfully grafted backup page %d to %d in PS at location 0x%8x.\n", ulPageInBkp, ulPageInPS, pbPageLoc)); }
private:
ULONG _cPagesPerLargePage; ULONG _ulPageInPS; CPhysPropertyStore *_pPhysStore; }; };
//+---------------------------------------------------------------------------
//
// Class: CBackupWid
//
// Purpose: Backs up a wid to the backup
//
// History: 6-20-97 KrishnaN Created
//
// Notes:
//
//----------------------------------------------------------------------------
class CBackupWid { public:
CBackupWid(CPropertyStore *pPropStor, WORKID wid, ULONG cRecsInWid): _pPropStor( pPropStor ), _nLargePage( 0xFFFFFFFF ), _ulFirstPage( 0xFFFFFFFF ), _ulLastPage( 0xFFFFFFFF ), _pbFirstPage( 0 ) { BackupWid(wid, cRecsInWid); }
CBackupWid(CPropertyStore *pPropStor, WORKID wid, ULONG cRecsInWid, EField FieldToCommit, ULONG ulValue, COnDiskPropertyRecord const *pRec): _pPropStor( pPropStor ), _nLargePage( 0xFFFFFFFF ), _ulFirstPage( 0xFFFFFFFF ), _ulLastPage( 0xFFFFFFFF ), _pbFirstPage( 0 ) { BackupWid(wid, cRecsInWid, FieldToCommit, ulValue, pRec); }
~CBackupWid() { _pPropStor->PhysStore()->ReturnLargeBuffer(_nLargePage); }
private:
//
// TryDescribeWidInAPage should be called first even when you
// know that you may not be able to describe the wid in a single
// page. This figures out the large page and borrows it. It also
// figures out how many pages you might need, so you can allocate
// the size and pass it to DescribeWid
//
inline ULONG TryDescribeWidInAPage(WORKID wid, ULONG cRecsInWid); inline void DescribeWid( WORKID wid, ULONG cRecsInWid, CDynArrayInPlace<ULONG> &pulPages, CDynArrayInPlace<void *> &ppvPages);
void BackupWid(WORKID wid, ULONG cRecsInWid, EField FieldToCommit = eFieldNone, ULONG ulValue = 0, COnDiskPropertyRecord const *pRec = 0);
BOOL BackupPages(ULONG cPages, ULONG const *pSlots, void const * const * ppvPages);
ULONG DescribeField( EField FieldToCommit, COnDiskPropertyRecord const *pRec, ULONG cPages, void const * const* ppvPages, ULONG &pulOffset);
inline void ComputeOSPageLocations(WORKID wid, ULONG cRecsInWid, ULONG *pFirstPage, ULONG *pLastPage); inline BYTE * GetOSPagePointer(ULONG ulPage);
CPropertyStore * _pPropStor; ULONG _nLargePage; // large page containing this wid
ULONG _ulFirstPage, _ulLastPage; // OS pages spanned by this wid
BYTE * _pbFirstPage; // address of the first page
};
|