//+--------------------------------------------------------------------------- // // 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 #include #include #include #include #include #include #include #include #include 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 & xObj, DWORD dwStoreLevel ); void Empty(); void FastTransfer( CPropStoreInfo const & psi ); void Accept( XPtr & 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 _xrsoPropStore; // The persistent storage itself BOOL _fOwned; // Set to TRUE if propstore is owned. XArray _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 _xPhysStore; // Main data stream. // // For multi-property changes to metadata // CPropertyStore * _ppsNew; // New metadata stored here BOOL _fNew; // TRUE if something really changed XPtr _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 _xPerThreadReadCounts; XArray _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 _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 _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 &pulPages, CDynArrayInPlace &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 };