//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1998 // // File: PhyStr.hxx // // Contents: Buffer/Index package // // Classes: // // History: 09-Jan-96 KyleP Lifted from CIndex directory // //---------------------------------------------------------------------------- #pragma once #include #include class PStorageObject; class PStorage; class PSaveProgressTracker; //+------------------------------------------------------------------------- // // Class: CPhysBuffer // // Purpose: Encapsulates a reference counted 'buffer'. // // History: 07-Mar-92 KyleP Created // 21-Apr-93 BartoszM Rewrote to use memory mapped files // // Notes: Physical buffers are managed objects. They are created // by physical indexes and property caches. // //-------------------------------------------------------------------------- class CPhysBuffer { public: CPhysBuffer( PMmStream& stream, ULONG PageNo, BOOL fWrite, BOOL fIntentToWrite, BOOL fMap ); ~CPhysBuffer(); CPhysBuffer *Next() { return _pphysNext; } void Link( CPhysBuffer * pphysbuf ) { _pphysNext = pphysbuf; } void SetIntentToWrite() { Win4Assert( _fWrite ); _fNeedToFlush = TRUE; } BOOL RequiresFlush() const { return _fNeedToFlush; } void Reference() { InterlockedIncrement( &_cRef ); } void DeReference( unsigned usn ) { Win4Assert( 0 != _cRef ); InterlockedDecrement( &_cRef ); _usn = usn; } BOOL IsReferenced() { return ( 0 != InterlockedCompareExchange( &_cRef, 0, 0 ) ); } BOOL IsRefCountOne() { return ( 1 == _cRef ); } ULONG PageNumber() { return _PageNo; } unsigned GetUSN() { return _usn; } ULONG * GetPage( ULONG nPage ) { ULONG cpageIntoBuf = nPage & ( PAGES_PER_COMMON_PAGE - 1 ); Win4Assert( ( nPage % PAGES_PER_COMMON_PAGE ) == ( nPage & ( PAGES_PER_COMMON_PAGE - 1 ) ) ); BYTE * pbBase = (BYTE *) ( _fMap ? _strmBuf.Get() : _xBuffer.Get() ); return (ULONG*)( pbBase + CI_PAGE_SIZE * cpageIntoBuf ); } void Flush( BOOL fFailFlush ); BOOL IsWritable() { return _fWrite; } #ifdef CIEXTMODE void CiExtDump(void *ciExtSelf); #endif private: ULONG _PageNo; CMmStreamBuf _strmBuf; PMmStream & _stream; long _cRef; unsigned _usn; CPhysBuffer * _pphysNext; BOOL _fNeedToFlush; // Is flush required for writable buffers? BOOL _fWrite; BOOL _fMap; // TRUE if mapped, FALSE if Read/WriteFile XArrayVirtual _xBuffer; // buffer to use if not mapped }; //+------------------------------------------------------------------------- // // Class: CBufferCache // // Purpose: A cache of buffers // // History: 17-Mar-93 BartoszM Created // //-------------------------------------------------------------------------- class CBufferCache { friend class CBufferCacheIter; public: CBufferCache( unsigned cHash ); ~CBufferCache(); void Free( BOOL fFailFlush = TRUE ); void Add( CPhysBuffer * pphysBuf, ULONG hash ); CPhysBuffer * Search( ULONG hash, ULONG commonPage ); void Destroy ( ULONG ulPage, BOOL fFailFlush = TRUE ); void Flush( ULONG nHighPage, BOOL fLeaveFlushFlagAlone = FALSE ); void TryToRemoveBuffers( unsigned cLimit ); BOOL MinPageInUse( ULONG & minPage ); unsigned Count() { return _cBuffers; } #ifdef CIEXTMODE void CiExtDump(void *ciExtSelf); #endif ULONG hash(ULONG nPage) { return (nPage/PAGES_PER_COMMON_PAGE) % _cHash; } private: unsigned _cBuffers; unsigned _cHash; XArray _aPhysBuf; #if CIDBG == 1 unsigned _cCacheHits; unsigned _cCacheMisses; #endif // DBG==1 || CIDBG==1 }; //+------------------------------------------------------------------------- // // Class: CBufferCacheIterator // // Purpose: Iterates over the cache of buffers // // History: 17-Mar-93 BartoszM Created // //-------------------------------------------------------------------------- class CBufferCacheIter { public: CBufferCacheIter ( CBufferCache& cache ); BOOL AtEnd() { return _pBuf == 0; } void operator++(); CPhysBuffer* Get() { return _pBuf; } private: CPhysBuffer** _pPhysBuf; unsigned _idx; CPhysBuffer* _pBuf; unsigned _cHash; }; //+------------------------------------------------------------------------- // // Class: CPhysStorage // // Purpose: Provides physical access to index pages // // History: 07-Mar-92 KyleP Created // 21-Apr-93 BartoszM Rewrote to use memory mapped files // 17-Feb-94 KyleP Subclass for PhysIndex / PhysHash // 10-Apr-94 SrikantS Added the ability to reopen for write // from read and also to provide support // for restarting a master merge. // //-------------------------------------------------------------------------- const LONGLONG eSigPhysStorage = 0x45524f5453594850i64; // "PHYSTORE" class CPhysStorage { public: virtual ~CPhysStorage(); void Close(); void Reopen( BOOL fWritable = FALSE ); ULONG * BorrowNewBuffer(ULONG nPage); ULONG * BorrowBuffer( ULONG nPage, BOOL fWritable=FALSE, BOOL fWriteIntent = FALSE ); void ReturnBuffer( ULONG nPage, BOOL fFlush = FALSE, BOOL fFailFlush = TRUE ); BOOL RequiresFlush( ULONG nPage ); inline ULONG * BorrowNewLargeBuffer( ULONG nLargePage ); inline ULONG * BorrowLargeBuffer( ULONG nLargePage, BOOL fWritable = TRUE, BOOL fWriteIntent = TRUE ); inline void ReturnLargeBuffer( ULONG nLargePage ); ULONG PageSize() const { return _cpageFileSize; } ULONG PagesInUse() const { return _cpageUsedFileSize; } WORKID ObjectId() const { return _objectId; } void Flush( BOOL fLeaveFlushFlagAlone = FALSE ); void SetUsedPagesCount(ULONG cPage) { Win4Assert( cPage <= _cpageFileSize ); _cpageUsedFileSize = cPage; } BOOL MinPageInUse( ULONG &minPage ); ULONG ShrinkFromFront( ULONG ulFirstPage, ULONG ulNumPages ); void ShrinkToFit(); void UpdatePageCount( CPhysStorage & storage ) { _cpageFileSize = storage._cpageFileSize; _cpageUsedFileSize = storage._cpageUsedFileSize; } void SetPageGrowth( ULONG cpageGrowth ) { Win4Assert( cpageGrowth > 0 ); _cpageGrowth = cpageGrowth; } void * GetLargePagePointer( ULONG nLargePage ); BOOL WouldLargePageGrowMapping( ULONG nLargePage ); void MakeBackupCopy( CPhysStorage & dst, PSaveProgressTracker & progressTracker ); WCHAR const * GetPath() { return _stream->GetPath(); } BOOL IsWritable() const { return _fWritable; } PStorage & GetStorage() { return _storage; } #ifdef CIEXTMODE void CiExtDump(void *ciExtSelf); #endif protected: CPhysStorage( PStorage & storage, PStorageObject& obj, WORKID objectId, unsigned cpageReqSize, PMmStream * stream, BOOL fThrowCorruptErrorOnFailures, unsigned cCachedItems = 0, BOOL fAllowReadAhead = TRUE ); CPhysStorage( PStorage & storage, PStorageObject& obj, WORKID objectId, PMmStream * stream, PStorage::EOpenMode mode, BOOL fThrowCorruptErrorOnFailures, unsigned cCachedItems = 0, BOOL fAllowReadAhead = FALSE ); virtual void ReOpenStream() = 0; const LONGLONG _sigPhysStorage; PStorage& _storage; PStorageObject& _obj; XPtr _stream; BOOL _fWritable; private: ULONG * LokBorrowOrAddBuffer( ULONG hash, ULONG commonPage, ULONG nPage, BOOL fAdd, BOOL fWritable, BOOL fIntentToWrite ); ULONG * LokBorrowNewBuffer( ULONG hash, ULONG commonPage, ULONG nPage ); void _GrowFile( ULONG cpageSize ); unsigned _usnGen; // usns for pages unsigned _cMaxCachedBuffers; // # pages to cache ULONG _cpageFileSize; // File size on disk ULONG _cpageUsedFileSize; // # pages in use in file ULONG _cpageGrowth; // # pages to grow file size ULONG _iFirstNonShrunkPage; // first page not shrunk BOOL _fAllowReadAhead; // TRUE if non-mapped IO ok WORKID _objectId; BOOL _fThrowCorruptErrorOnFailures; // Should errors during opening // be marked as catalog corruption ? XPtr _xMutex; XPtr _xRWAccess; CBufferCache _cache; }; inline ULONG * CPhysStorage::BorrowNewLargeBuffer( ULONG nLargePage ) { ULONG *pBuffer = BorrowNewBuffer( nLargePage * PAGES_PER_COMMON_PAGE ); RtlZeroMemory( pBuffer, COMMON_PAGE_SIZE ); return pBuffer; } inline ULONG * CPhysStorage::BorrowLargeBuffer( ULONG nLargePage, BOOL fWritable, BOOL fWriteIntent ) { return BorrowBuffer( nLargePage * PAGES_PER_COMMON_PAGE, fWritable, fWriteIntent ); } inline void CPhysStorage::ReturnLargeBuffer( ULONG nLargePage ) { ReturnBuffer( nLargePage * PAGES_PER_COMMON_PAGE ); }