windows-nt/Source/XPSP1/NT/inetsrv/query/ntciutil/propstor.hxx

1169 lines
33 KiB
C++
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
//+---------------------------------------------------------------------------
//
// 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
};