windows-nt/Source/XPSP1/NT/inetsrv/query/bigtable/sglookup.cxx
2020-09-26 16:20:57 +08:00

466 lines
12 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 2000.
//
// File: sglookup.cxx
//
// Contents: A class for doing a quick lookup of a segment based on the
// key. It will do a binary search and locate the segment.
// This is useful for doing row insertions into a large table
// when keys are not coming in any specific order.
//
// Classes: CSegmentArrray
//
// History: 10-20-95 srikants Created
//
//----------------------------------------------------------------------------
#include "pch.cxx"
#pragma hdrstop
#include <sglookup.hxx>
#include <seglist.hxx>
#include "tabledbg.hxx"
//+---------------------------------------------------------------------------
//
// Member: CSegmentArray consructor
//
// Synopsis: Initializes the segment array
//
// History: 10-20-95 srikants Created
//
//----------------------------------------------------------------------------
CSegmentArray::CSegmentArray()
: CDynArrayInPlace<CTableSegment *>(eMinSegments),
_pComparator(0),
_iHint(0)
{
}
//+---------------------------------------------------------------------------
//
// Member: CSegmentArray::_FindSegment
//
// Synopsis: Given a segment pointer, it searches for the segment in the
// array and returns the index in the array.
//
// Arguments: [pSeg] - Segment to look for.
//
// Returns: Index in the array if the segment is located.
// -1 otherwise.
//
// History: 10-25-95 srikants Created
//
//----------------------------------------------------------------------------
int CSegmentArray::_FindSegment( const CTableSegment * pSeg )
{
Win4Assert( 0 != pSeg );
//
// Optimization - use the last returned segment index as a hint
//
if ( _iHint < Count() && Get(_iHint) == pSeg )
return (int) _iHint;
for ( unsigned i = 0; i < Count(); i++ )
{
if ( Get(i) == pSeg )
{
_iHint = i;
return (int) i;
}
}
//
// The segment could not be located.
//
_iHint = 0;
return -1;
}
//+---------------------------------------------------------------------------
//
// Member: CSegmentArray::LookUp
//
// Synopsis: Looks up the segment which is likely to contain the given
// key or is a candidate to insert the given key.
//
// Arguments: [key] - Key to look up.
//
// Returns: The segment pointer where to look for/insert the given key.
// 0 if there are no segments
//
// History: 10-20-95 srikants Created
//
// Notes: Please note that each segment has only the "smallest" key in
// that segment. We don't know anything about the highest key in
// that segment. if we two adjacent segments with lowest keys
// k1 and k3 and a new key if k1 < k2 < k3,
// k2 will end up in segment 1
//
//----------------------------------------------------------------------------
CTableSegment * CSegmentArray::LookUp( CTableRowKey & key )
{
Win4Assert( 0 != _pComparator );
int cSegs = (int) Count();
if ( 0 == cSegs )
return 0;
int iLow = 0;
int iHigh = cSegs - 1;
int iMid = iHigh/2;
int iComp = 0;
while ( iLow <= iHigh )
{
iMid = (iLow + iHigh)/2;
CTableSegment * pCurrSeg = Get( (unsigned) iMid );
iComp = _pComparator->Compare( key, pCurrSeg->GetLowestKey() );
if ( 0 == iComp )
return pCurrSeg;
if ( iComp > 0 ) // key is bigger than the smallest key in the seg
iLow = iMid+1;
else // key is < the smallest key in the seg
iHigh = iMid-1;
}
Win4Assert( iLow > iHigh );
int iGet = 0;
if ( iMid > iHigh )
{
Win4Assert( iLow == iMid );
Win4Assert( iComp < 0 );
iGet = iHigh >= 0 ? iHigh : 0;
}
else
{
Win4Assert( iMid == iHigh );
Win4Assert( iMid < iLow && iMid < cSegs );
iGet = iMid;
}
return Get( (unsigned) iGet );
}
//+---------------------------------------------------------------------------
//
// Member: CSegmentArray::Append
//
// Synopsis: Adds the given segment to the end of the array.
//
// Arguments: [pSeg] - Segment to be appended.
//
// History: 10-20-95 srikants Created
//
//----------------------------------------------------------------------------
void CSegmentArray::Append( CTableSegment * pSeg )
{
Win4Assert( 0 != pSeg );
Win4Assert( !IsFound(pSeg) );
Add( pSeg, Count() );
}
//+---------------------------------------------------------------------------
//
// Member: CSegmentArray::InsertAfter
//
// Synopsis: Inserts the given segment after the marker segment
//
// Arguments: [pMarker] - Segment already present in the array.
// [pSeg] - New segment to be inserted.
//
// History: 10-20-95 srikants Created
//
//----------------------------------------------------------------------------
void CSegmentArray::InsertAfter( const CTableSegment * pMarker,
CTableSegment * pSeg )
{
Win4Assert( 0 != pSeg );
Win4Assert( !IsFound(pSeg) );
Win4Assert( 0 != pMarker );
int iMarker = _FindSegment( pMarker );
Win4Assert( iMarker >= 0 );
Insert( pSeg, (unsigned)iMarker+1 );
}
//+---------------------------------------------------------------------------
//
// Member: CSegmentArray::InsertBefore
//
// Synopsis: Inserts the given segment "before" the marker segment
//
// Arguments: [pMarker] - The segment before which the new segment must
// be inserted. If NULL, the given segment will be added as
// the first segment in the array.
//
// [pSeg] - The new segment
//
// History: 10-20-95 srikants Created
//
//----------------------------------------------------------------------------
void CSegmentArray::InsertBefore( const CTableSegment * pMarker,
CTableSegment * pSeg )
{
Win4Assert( 0 != pSeg );
Win4Assert( !IsFound(pSeg) );
if ( 0 != pMarker )
{
int iPos = _FindSegment( pMarker );
Win4Assert( iPos >= 0 );
Insert( pSeg, (unsigned) iPos );
}
else
{
Insert( pSeg, 0 ); // make this the first in the array
}
}
//+---------------------------------------------------------------------------
//
// Member: CSegmentArray::Replace
//
// Synopsis: Replaces the old segment with the new segment
//
// Arguments: [pOld] -
// [pNew] -
//
// History: 10-20-95 srikants Created
//
//----------------------------------------------------------------------------
void CSegmentArray::Replace( const CTableSegment * pOld, CTableSegment * pNew )
{
Win4Assert( 0 != pOld && 0 != pNew );
int iPos = _FindSegment( pOld );
Win4Assert( iPos >= 0 );
Win4Assert( !IsFound( pNew ) );
Add( pNew, (unsigned) iPos );
}
//+---------------------------------------------------------------------------
//
// Member: CSegmentArray::_MoveEntries
//
// Synopsis: Moves entries from the specified offset by the given number
// of entries..
//
// Arguments: [iStart] - Starting offset to move
// [cEntries] - Number of entries to move by.
//
// History: 10-20-95 srikants Created
//
//----------------------------------------------------------------------------
void CSegmentArray::_MoveEntries( unsigned iStart, unsigned cEntries )
{
Win4Assert( iStart < _count );
if ( 0 == cEntries )
return;
Win4Assert( cEntries + _count <= Size() );
unsigned iNewPos = iStart + cEntries;
memmove( _aItem + iNewPos, _aItem + iStart,
(_count - iStart) * sizeof(CTableSegment *) );
_count += cEntries;
#if CIDBG==1
//
// The caller can asser that the moved entries are all NULL.
//
for ( unsigned i = iStart; i < iNewPos; i++ )
{
_aItem[i] = 0;
}
#endif // CIDBG==1
}
//+---------------------------------------------------------------------------
//
// Member: CSegmentArray::Replace
//
// Synopsis: Removes "pOld" from the list and inserts the new list of
// segments in its place.
//
// Arguments: [pOld] -
// [segList] -
//
// History: 10-20-95 srikants Created
//
//----------------------------------------------------------------------------
void CSegmentArray::Replace( const CTableSegment * pOld,
CTableSegList & segList )
{
unsigned cSegsToInsert = segList.GetSegmentsCount();
if ( cSegsToInsert == 0 )
{
RemoveEntry( pOld );
return;
}
int iSeg = _FindSegment( pOld );
Win4Assert( iSeg >= 0 );
unsigned iInsert = (unsigned) iSeg;
//
// Replace the current segment with the first one in the list
//
CFwdTableSegIter iter( segList );
Win4Assert ( !segList.AtEnd(iter) );
_aItem[iInsert++] = iter.GetSegment();
segList.Advance(iter);
cSegsToInsert--;
if ( !segList.AtEnd(iter) )
{
Win4Assert( cSegsToInsert > 0 );
//
// There is more than one segment to replace with. We should
// iterate and move them.
//
unsigned cTotalSegs = _count + cSegsToInsert;
//
// Grow the array if necessary.
//
if ( (cTotalSegs-1) >= _size )
_GrowToSize( cTotalSegs-1 );
if ( iInsert != _count )
{
Win4Assert( iInsert < _count );
_MoveEntries( iInsert, cSegsToInsert );
}
else
{
//
// We are just appending at the end. No need to move anything
//
#if CIDBG==1
for ( unsigned i = _count; i < cTotalSegs; i++ )
{
_aItem[i] = 0;
}
#endif // CIDBG==1
_count +=cSegsToInsert;
Win4Assert( _count == cTotalSegs );
}
for ( ; !segList.AtEnd(iter); segList.Advance(iter) )
{
#if CIDBG==1
//
// We are either appending to the end or the entries got moved
// and nullified.
//
Win4Assert( 0 == _aItem[iInsert] );
#endif // CIDBG==1
Win4Assert( !IsFound(iter.GetSegment()) );
_aItem[iInsert++] = iter.GetSegment();
}
}
}
//+---------------------------------------------------------------------------
//
// Member: CSegmentArray::RemoveEntry
//
// Synopsis: Removes the specified segment from the array.
//
// Arguments: [pSeg] -
//
// History: 10-20-95 srikants Created
//
//----------------------------------------------------------------------------
void CSegmentArray::RemoveEntry( const CTableSegment * pSeg )
{
int iSeg = _FindSegment( pSeg );
Win4Assert( iSeg >= 0 );
Remove( (unsigned) iSeg );
}
#if CIDBG==1
//+---------------------------------------------------------------------------
//
// Member: CSegmentArray::TestInSync
//
// Synopsis: Tests that the list and the array are fully in sync.
//
// Arguments: [list] - The global list of segments
//
// History: 10-25-95 srikants Created
//
//----------------------------------------------------------------------------
void CSegmentArray::TestInSync( CTableSegList & list )
{
if ( Count() != list.GetSegmentsCount() )
{
tbDebugOut(( DEB_ERROR, "Array Count = 0x%X ListCount = 0x%X \n",
Count(), list.GetSegmentsCount() ));
Win4Assert( !"Array Count and List Count Not In Sync" );
return;
}
unsigned i = 0;
for ( CFwdTableSegIter iter(list); !list.AtEnd(iter); list.Advance(iter) )
{
if ( iter.GetSegment() != Get(i) )
{
tbDebugOut(( DEB_ERROR, "iter.GetSegment() = 0x%X : i = 0x%X : Array[i] = 0x%X\n",
iter.GetSegment(), i, Get(i) ));
Win4Assert( !"List and Array are not in sync" );
}
i++;
}
}
#endif // CIDBG==1