377 lines
10 KiB
C++
377 lines
10 KiB
C++
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// 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 <pstore.hxx>
|
||
|
#include <pmmstrm.hxx>
|
||
|
|
||
|
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<BYTE> _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<CPhysBuffer *> _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<PMmStream> _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<CMutexSem> _xMutex;
|
||
|
XPtr<CReadWriteAccess> _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 );
|
||
|
}
|
||
|
|