windows-nt/Source/XPSP1/NT/inetsrv/query/cindex/mindex.hxx
2020-09-26 16:20:57 +08:00

574 lines
17 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1998.
//
// File: mindex.hxx
//
// Contents: CMasterMergeIndex
//
// Classes: CMasterMergeIndex
//
// Functions:
//
// History: 8-17-94 srikants Created
//
//----------------------------------------------------------------------------
#pragma once
#include <pstore.hxx>
#include <bitoff.hxx>
#include "pindex.hxx"
#include "physidx.hxx"
#include "mmerglog.hxx"
#include "bitstm.hxx"
#include "pcomp.hxx"
#include "pmcomp.hxx"
#include <frmutils.hxx>
class CFreshTest;
class PDirectory;
class CKeyCurStack;
class CRSemiInfinitePage;
class CKeyStack;
class CIndexSnapshot;
class CIndexRecord;
class CWKeyList;
class CTrackSplitKey;
class CMPersDeComp;
class CRWStore;
class CPartition;
//+---------------------------------------------------------------------------
//
// Function: CiPageToCommonPage
//
// Synopsis: Given a "CI Page" number, it computes the COMMON page on which
// the ci page is.
//
// Arguments: [nCiPage] -- The CI page number.
//
// History: 4-20-94 srikants Created
//
// Notes:
//
//----------------------------------------------------------------------------
inline ULONG CiPageToCommonPage( ULONG nCiPage )
{
return(nCiPage/PAGES_PER_COMMON_PAGE);
}
//+---------------------------------------------------------------------------
//
// Class: CSplitKeyInfo
//
// Purpose: A class for storing and retrieving information associated
// with a split key.
//
// History: 4-20-94 srikants Created
//
//----------------------------------------------------------------------------
class CSplitKeyInfo
{
public:
CSplitKeyInfo();
void SetBeginOffset( const BitOffset & bitOff )
{ _start = bitOff; }
const BitOffset & GetBeginOffset () const
{ return _start; }
void SetEndOffset( const BitOffset & bitOff )
{ _end = bitOff; }
const BitOffset & GetEndOffset ( ) const
{ return _end; }
void SetKey( const CKeyBuf & key )
{ _key = key; }
const CKeyBuf & GetKey () const
{ return _key; }
CSplitKeyInfo & operator=( const CSplitKeyInfo & rhs )
{
memcpy( this, &rhs, sizeof(CSplitKeyInfo) );
return *this;
}
void SetMinKey() { _key.FillMin(); }
WORKID GetWidMax() const { return _widMax; }
void SetWidMax( WORKID widMax) { _widMax = widMax; }
#ifdef CIEXTMODE
void CiExtDump(void *ciExtSelf);
#endif
private:
BitOffset _start; // Offset from where this key begins.
BitOffset _end; // Offset where this key ends + 1.
CKeyBuf _key; // The actual key.
WORKID _widMax; // Maximum wid.
};
//+---------------------------------------------------------------------------
//
// Class: CTrackSplitKey
//
// Purpose: Tracks the split key during master merge. At any point
// it can tell the key that can be used as a split key if
// all the pages upto (not including the current one which
// could be partially filled) is flushed to the disk. A key
// qualifies to be a split key if it is on a page which never
// needs to be written to after flushing; it must not be written
// even for patching up the forward links in the bit stream.
//
// History: 4-12-94 srikants Created
//
//
//----------------------------------------------------------------------------
class CTrackSplitKey
{
public:
CTrackSplitKey() : _fNewSplitKeyFound(FALSE) { }
CTrackSplitKey( const CKeyBuf & splitKey,
const BitOffset & bitoffBeginSplit,
const BitOffset & bitoffEndSplit );
void BeginNewKey( const CKeyBuf & currKey,
const BitOffset & beginCurrOff,
WORKID widMax = widInvalid );
const CSplitKeyInfo & GetSplitKey( BitOffset & bitOffFlush )
{
bitOffFlush = _splitKey1.GetEndOffset();
return(_splitKey2);
}
BOOL IsNewKeyFound() { return _fNewSplitKeyFound; }
void ClearNewKeyFound() { _fNewSplitKeyFound = FALSE; }
#ifdef CIEXTMODE
void CiExtDump(void *ciExtSelf);
#endif
private:
CSplitKeyInfo _splitKey2; // The "real" split key. Backpatching of
// forward links is also completed for
// this key.
CSplitKeyInfo _splitKey1; // The key which will be the next split
// key when back patching is completed.
CSplitKeyInfo _prevKey; // The complete key which was looked at
// last.
CSplitKeyInfo _currKey; // The key being currently written by the
// compressor.
BOOL _fNewSplitKeyFound; // Was a splitkey found
};
//+---------------------------------------------------------------------------
//
// Class: STrackSplitKey
//
// Purpose: A smart pointer to a CTrackSplitKey object.
//
// History: 4-12-94 srikants Created
//
//----------------------------------------------------------------------------
class STrackSplitKey
{
public:
STrackSplitKey( CTrackSplitKey * pSplitKey ) : _pSplitKey(pSplitKey)
{
}
~STrackSplitKey() { delete _pSplitKey; }
CTrackSplitKey * operator->() { return _pSplitKey; }
CTrackSplitKey * Acquire()
{
CTrackSplitKey * pTemp = _pSplitKey;
_pSplitKey = 0;
return(_pSplitKey);
}
private:
CTrackSplitKey * _pSplitKey;
};
//+---------------------------------------------------------------------------
//
// Class: CMasterMergeIndex
//
// Purpose: Encapsulates master index operations which span the current
// master index and a new master index during a master merge.
//
// Interface:
//
// History: 30-Mar-94 DwightKr Created.
// 23-Aug-94 SrikantS Modified to use a different model with
// a target index and a target sink.
//
// Notes: CMasterMergeIndex is an encapsulation of the master index
// while a master merge is in progress. A master merge is
// considered to be in progress even when it is "paused".
//
// The _pTargetMasterIndex is the "evolving" target master which
// will become the new master index after the merge is complete.
// It participates in queries. The _pTargetSink is a physical
// "write only" index to which "keys+data" are added. When we
// checkpoint during a merge, all the keys before and including
// the "current split key" are "transferred" to the
// _pTargetMasterIndex from the _pTargetSink. Eventually all the
// data will be transferred to the _pTargetMasterIndex.
//
//----------------------------------------------------------------------------
const LONGLONG eSigMindex = 0x58444e4947524d4di64; // "MMRGINDX"
class CMasterMergeIndex : public CDiskIndex
{
friend class CMPersDeComp;
friend class CResManager;
public:
//
// The target master index MUST exist with both the index
// and directory streams constructed on disk before calling
// this constructor.
//
CMasterMergeIndex(
PStorage & storage,
WORKID widNewMaster,
INDEXID iid,
WORKID widMax,
CPersIndex * pCurrentMaster,
WORKID widMasterLog,
CMMergeLog * pMMergeLog = 0 );
~CMasterMergeIndex();
void SetMMergeIndSnap( CIndexSnapshot * pIndSnap )
{
Win4Assert( 0 == _pIndSnap && 0 != pIndSnap );
_pIndSnap = pIndSnap;
}
BOOL IsMasterMergeIndex() const { return TRUE; }
void Remove();
void Merge( CIndexSnapshot& indSnap,
const CPartition & partn,
CCiFrmPerfCounter & mergeProgress,
BOOL fGetRW ) {}
void Merge( CWKeyList * pNewKeyList,
CFreshTest * pFresh,
const CPartition & partn,
CCiFrmPerfCounter & mergeProgress,
CCiFrameworkParams & frmwrkParams,
BOOL fGetRW );
CKeyCursor * QueryCursor();
CKeyCursor * QueryKeyCursor(const CKey * pKey);
COccCursor * QueryCursor( const CKey * pkey,
BOOL isRange,
ULONG & cMaxNodes );
COccCursor * QueryRangeCursor( const CKey * pkey,
const CKey * pkeyEnd,
ULONG & cMaxNodes );
COccCursor * QuerySynCursor( CKeyArray & keyArr,
BOOL isRange,
ULONG & cMaxNodes );
unsigned Size () const
{ return _ulInitSize; }
WORKID ObjectId() const
{ return _pTargetMasterIndex->ObjectId(); }
void AbortMerge()
{
_fAbortMerge = TRUE;
}
void ClearAbortMerge()
{
_fAbortMerge = FALSE;
}
void FillRecord ( CIndexRecord & record );
WORKID MaxWorkId () const
{
Win4Assert( _widMax == _pTargetMasterIndex->MaxWorkId() );
return _pTargetMasterIndex->MaxWorkId();
}
void SetNewKeyList( CWKeyList * pNewKeyList )
{
_pNewKeyList = pNewKeyList;
}
#ifdef KEYLIST_ENABLED
CRWStore * ComputeRelevantWords(ULONG cRows,ULONG cRW,WORKID *pwid,
CKeyList *pkl);
CRWStore * AcquireRelevantWords();
#endif // KEYLIST_ENABLED
CPersIndex * GetCurrentMasterIndex()
{
return _pCurrentMasterIndex;
}
inline void Reference();
inline void Release();
CIndexSnapshot & LokGetIndSnap() { return *_pIndSnap; }
void AcquireCurrentAndTarget( CPersIndex ** ppCurrentMaster,
CPersIndex ** ppTargetMaster );
#ifdef CIEXTMODE
void CiExtDump(void *ciExtSelf);
#endif
private:
PDirectory & GetTargetDir()
{
return( _pTargetMasterIndex->GetDirectory() );
}
void CreateRange( COccCurStack & curStk,
const CKey * pkey,
const CKey * pkeyEnd,
ULONG & cMaxNodes );
void RestoreIndexDirectory( const CKeyBuf & idxSplitKey,
WORKID widMax,
const BitOffset & idxBitOffRestart);
#if KEYLIST_ENABLED
void RestoreKeyListDirectory( const CKeyBuf & idxSplitKey,
WORKID widMax,
CWKeyList * pNewKeyList,
const CKeyBuf & keylstSplitKey );
#endif // KEYLIST_ENABLED
CKeyCursor * StartMasterMerge( CIndexSnapshot & indSnap,
CMMergeLog & mMergeLog,
CWKeyList * pNewKeyList );
void ReloadMasterMerge( CMMergeLog & mMergeLog );
void CleanupMMergeState();
void SetMaxWorkId ( WORKID widMax )
{
Win4Assert( 0 != _pTargetMasterIndex );
CIndex::SetMaxWorkId( widMax );
_pTargetMasterIndex->SetMaxWorkId( widMax );
}
void ReleaseTargetAndCurrent()
{
_pCurrentMasterIndex = 0;
_pTargetMasterIndex = 0;
}
CPersIndex * GetTargetMaster()
{
return( _pTargetMasterIndex );
}
CKeyCursor * QuerySplitCursor(const CKey * pKey);
void ShrinkFromFront( const CKeyBuf & keyBuf );
const LONGLONG _sigMindex; // Signature
CPersIndex * _pCurrentMasterIndex; // Current master index
CPersIndex * _pTargetMasterIndex; // Target master index
CPhysIndex * _pTargetSink; // Target sink to which we
// are adding keys.
WORKID _widMasterLog; // WORKID of new master index
CPersComp * _pCompr; // Compressor for the new index.
CTrackSplitKey * _pTrackIdxSplitKey; // Split key tracker for index.
#ifdef KEYLIST_ENABLED
CTrackSplitKey * _pTrackKeyLstSplitKey; // Split key tracker for KeyList
#endif // KEYLIST_ENABLED
ULONG _ulInitSize; // Initial guess at index size
CSplitKeyInfo _idxSplitKeyInfo; // SplitKey at checkpoint, used
// for queries
CMutexSem _mutex; // Used to control access to
// dirs during master merge
ULONG _ulFirstPageInUse; // First used page in index
CWKeyList * _pNewKeyList; // The new key list being
BOOL _fAbortMerge; // Flag to indicate if merge
// must be aborted.
PStorage & _storage;
CRWStore * _pRWStore;
CIndexSnapshot * _pIndSnap; // Index Snap Shot for the
// merge.
BOOL _fStateLoaded; // Set to TRUE if the master
// merge state is loaded.
};
//+---------------------------------------------------------------------------
//
// Function: Reference
//
// Synopsis: RefCounts the composite index for QUERY so it will not get
// deleted while in use by an in-progress QUERY.
//
// History: 8-30-94 srikants Created
//
// Assumption: We are under RESMAN LOCK
//
// Notes: It is important to ref-count both the current master and
// target master indexes separately in-addition to refcounting
// this index. Ref-Counting the current master prevents the
// merge snapshot from deleting it while the query is going on.
// Ref-counting the target master protects a long-running query
// from a second merge.
// Consider the following sequence. The refcount is enclosed
// in parenthesis.
//
// 1. Merge M1 is in progress and adding keys to target T1(0).
// 2. Query Q1 starts. T1(0)
// 3. M1 completes. T1(0)
// 4. Merge M2 starts and produces target T2. T1(1)
// 5. M2 completes; T1(0) and is zombie.
// The merge snapshot will then delete T1 because it is a
// zombie and refcount is 0.
//
// To prevent in step 5, we must refcount T1 in step 2 so it
// looks like
// 2. Query Q1 starts. T1(1)
// 3. ... T1(1)
// 4. ... T1(1)
// 5. ... T1(1) and is zombie
// Because T1 is still in use, it will not be deleted.
//
//----------------------------------------------------------------------------
inline void CMasterMergeIndex::Reference()
{
CIndex::Reference();
Win4Assert( 0 != _pTargetMasterIndex );
_pTargetMasterIndex->Reference();
if ( _pCurrentMasterIndex )
_pCurrentMasterIndex->Reference();
}
//+---------------------------------------------------------------------------
//
// Function: Release
//
// Synopsis: Releases the composite index.
//
// History: 8-30-94 srikants Created
//
// Notes: We are under RESMAN lock.
//
//----------------------------------------------------------------------------
inline void CMasterMergeIndex::Release()
{
if ( _pCurrentMasterIndex )
_pCurrentMasterIndex->Release();
Win4Assert( 0 != _pTargetMasterIndex );
_pTargetMasterIndex->Release();
CIndex::Release();
}
//+---------------------------------------------------------------------------
//
// Class: SByteArray
//
// Purpose: Smart pointer to a memory block.
//
// History: 9-29-94 srikants Created
//
// Notes:
//
//----------------------------------------------------------------------------
class SByteArray
{
public:
SByteArray( void * p ) : _pb( (BYTE *) p)
{
}
~SByteArray()
{
delete _pb;
}
void Set( void * p )
{
Win4Assert( 0 == _pb );
_pb = (BYTE *) p;
}
void * Acquire()
{
void * pTemp = _pb;
_pb = 0;
return(pTemp);
}
private:
BYTE * _pb;
};