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

475 lines
12 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1991 - 2000.
//
// File: MCURSOR.CXX
//
// Contents: Merge Cursor
//
// Classes: CMergeCursor
//
// History: 06-May-91 BartoszM Created
//
// widHeap keyHeap
//
//----------------------------------------------------------------------------
#include <pch.cxx>
#pragma hdrstop
#include <curstk.hxx>
#include "mcursor.hxx"
//+---------------------------------------------------------------------------
//
// Member: CMergeCursor::CMergeCursor, public
//
// Synopsis: Create a cursor that merges a number of cursors.
//
// Arguments: [cCursor] -- count of cursors
// [aCursor] -- array of pointers to cursors
//
// History: 06-May-91 BartoszM Created
// 24-Jan-92 AmyA Modified to take CKeyCurArray as a
// parameter.
//
// Notes: The cursors and the array will be deleted by destructor.
// Leaves widHeap empty.
//
//----------------------------------------------------------------------------
CMergeCursor::CMergeCursor( CKeyCurStack & stkCursor )
: _keyHeap (),
_widHeap ( stkCursor.Count() )
{
_widMax = 0; // not valid
// Two step construction of the heap.
// We have to make sure that all cursors have a valid key
int cCursor = stkCursor.Count();
int count = 0;
// remove empty cursors. GetKey() can fail; don't leak cursors.
for ( int i = 0; i < cCursor; i++ )
{
CKeyCursor *pCur = stkCursor.Get( i );
Win4Assert( 0 != pCur );
if ( 0 == pCur->GetKey() )
stkCursor.Free( i );
else
count++;
}
XArray<CKeyCursor *> aCursor( count );
for ( count = 0, i = 0; i < cCursor; i++ )
{
CKeyCursor *pCur = stkCursor.Get( i );
if ( 0 != pCur )
aCursor[ count++ ] = pCur;
}
delete [] stkCursor.AcqStack();
_keyHeap.MakeHeap ( count, aCursor.Acquire() );
if ( !_keyHeap.IsEmpty() )
{
_iid = _keyHeap.Top()->IndexId();
_pid = _keyHeap.Top()->Pid();
}
ciDebugOut(( DEB_ITRACE, "merge cursor has %d cursors\n", count ));
} //CMergeCursor
//+---------------------------------------------------------------------------
//
// Member: CMergeCursor::GetKey, public
//
// Synopsis: Get current key.
//
// History: 06-May-91 BartoszM Created
//
// Notes: Does not replenish widHeap
// Current key is defined as:
// 1. cur key of all cursors in widHeap, or,
// 2. if widHeap empty, cur key of Top of key heap
// (and cur key of all cursors in keyHeap with
// the same cur key).
//
//----------------------------------------------------------------------------
const CKeyBuf * CMergeCursor::GetKey()
{
if ( _widHeap.IsEmpty() )
{
if ( _keyHeap.IsEmpty() )
return 0;
return _keyHeap.Top()->GetKey();
}
return _widHeap.Top()->GetKey();
}
//+---------------------------------------------------------------------------
//
// Member: CMergeCursor::WorkId, public
//
// Synopsis: Get current work id.
//
// History: 06-May-91 BartoszM Created
//
// Notes: Current wid is defined as:
// 1. Cur wid of Top of widHeap (and cur wid of all
// cursors in widHeap with the same wid-- however,
// NextWid should not increment the others, since
// they correspond to different index id's), or,
// 2. if widHeap empty: replenish it
//
//----------------------------------------------------------------------------
WORKID CMergeCursor::WorkId()
{
if ( _widHeap.IsEmpty() && !ReplenishWid() )
return widInvalid;
return _widHeap.Top()->WorkId();
}
//+---------------------------------------------------------------------------
//
// Member: CMergeCursor::Occurrence, public
//
// Synopsis: Get current occurrence.
//
// History: 06-May-91 BartoszM Created
//
// Notes: Current occurrence is defined as:
// 1. cur occ of Top of widHeap, or,
// 2. if widHeap empty, replenish it.
//
//----------------------------------------------------------------------------
OCCURRENCE CMergeCursor::Occurrence()
{
if ( _widHeap.IsEmpty() && !ReplenishWid() )
return OCC_INVALID;
return _widHeap.Top()->Occurrence();
}
//+---------------------------------------------------------------------------
//
// Member: CMergeCursor::GetNextKey, public
//
// Synopsis: Move to next key
//
// Returns: Target key or NULL if no more keys
//
// History: 06-May-91 BartoszM Created
//
// Effects: Updates _iid _pid to the ones of the keyHeap top
//
// Notes: 1. Increment and move to keyHeap all cursors
// from widHeap, or,
// 2. if widHeap empty, increment and reheap all
// cursors in keyHeap with the same cur key
// as the Top.
//
//----------------------------------------------------------------------------
const CKeyBuf * CMergeCursor::GetNextKey()
{
if ( ! _widHeap.IsEmpty() )
{
// move widHeap to keyHeap advancing all cursors
CKeyCursor * cur;
while ( ( cur = _widHeap.RemoveBottom() ) != 0 )
{
if ( cur->GetNextKey() == 0 )
{
delete cur;
}
else
{
_keyHeap.Add ( cur );
}
}
}
else if ( !_keyHeap.IsEmpty() )
{
// widHeap was empty. Advance all cursors
// with the lowest key.
CKeyBuf key = *_keyHeap.Top()->GetKey();
do
{
if ( _keyHeap.Top()->GetNextKey() == 0 )
{
delete _keyHeap.RemoveTop();
if ( _keyHeap.IsEmpty () )
return 0;
}
else
{
_keyHeap.Reheap();
}
} while ( AreEqual(&key, _keyHeap.Top()->GetKey()) );
}
else
return 0;
if ( _keyHeap.IsEmpty() )
return 0;
CKeyCursor* cur = _keyHeap.Top();
_pid = cur->Pid();
_iid = cur->IndexId();
return cur->GetKey();
}
//+---------------------------------------------------------------------------
//
// Member: CMergeCursor::NextWorkId, public
//
// Synopsis: Move to next work id
//
// Returns: Target work id or widInvalid if no more wid's for current key
//
// Effects: Updates _iid to the one of the widHeap top
//
//
// History: 06-May-91 BartoszM Created
//
// Notes: The same work id may be returned multiple times,
// corresponding to multiple indexes.
// 1. Increment Top of widHeap and reheap, or,
// 2. if widHeap empty, replenish it
//
//----------------------------------------------------------------------------
WORKID CMergeCursor::NextWorkId()
{
if ( _widHeap.IsEmpty() && !ReplenishWid() )
return widInvalid;
_widHeap.Top()->NextWorkId();
_widHeap.Reheap();
CKeyCursor* cur = _widHeap.Top();
_iid = cur->IndexId();
return cur->WorkId();
}
//+---------------------------------------------------------------------------
//
// Member: CMergeCursor::NextOccurrence, public
//
// Synopsis: Move to next occurrence
//
// Returns: Target occurrence or OCC_INVALID if no more occurrences
// for current (wid, index id) combination.
//
// History: 06-May-91 BartoszM Created
//
// Notes: 1. Increment Top of widHeap (do not reheap!), or,
// 2. if widHeap empty, replenish it
//
//----------------------------------------------------------------------------
OCCURRENCE CMergeCursor::NextOccurrence()
{
if ( _widHeap.IsEmpty() && !ReplenishWid() )
return OCC_INVALID;
return _widHeap.Top()->NextOccurrence();
}
//+---------------------------------------------------------------------------
//
// Member: CMergeCursor::MaxOccurrence
//
// Synopsis: Returns max occurrence of current wid
//
// History: 20-Jun-96 SitaramR Created
//
//----------------------------------------------------------------------------
OCCURRENCE CMergeCursor::MaxOccurrence()
{
if ( _widHeap.IsEmpty() )
return OCC_INVALID;
return _widHeap.Top()->MaxOccurrence();
}
//+---------------------------------------------------------------------------
//
// Member: CMergeCursor::WorkIdCount, public
//
// Synopsis: return wid count
//
// History: 21-Jun-91 BartoszM Created
//
// Notes: 1. Sum up wid count of all cursors in widHeap, or,
// 2. if widHeap empty, replenish it
//
//----------------------------------------------------------------------------
ULONG CMergeCursor::WorkIdCount()
{
// Sum up all wid counts for the same key.
// move all cursors with the same key to wid heap
if (_widHeap.IsEmpty() && !ReplenishWid())
{
return 0;
}
int count = _widHeap.Count();
ULONG widCount = 0;
CKeyCursor **curVec = _widHeap.GetVector();
while ( --count >= 0 )
widCount += curVec[count]->WorkIdCount();
// ciDebugOut (( DEB_ITRACE, "merge : wid count %ld\n", widCount ));
return widCount;
}
//+---------------------------------------------------------------------------
//
// Member: CMergeCursor::OccurrenceCount, public
//
// Synopsis: return occurrence count
//
// History: 21-Jun-91 BartoszM Created
//
// Notes: 1. Return occ count of Top of widHeap
// Occ counts of other cursors with the
// same wid do not count! They will
// be returned after NextWorkId is called
// 2. if widHeap empty, replenish it
//
//----------------------------------------------------------------------------
ULONG CMergeCursor::OccurrenceCount()
{
if ( _widHeap.IsEmpty() && !ReplenishWid() )
{
return 0;
}
return _widHeap.Top()->OccurrenceCount();
}
//+---------------------------------------------------------------------------
//
// Member: CMergeCursor::HitCount, public
//
// Synopsis: return occurrence count
//
// History: 27-Feb-92 AmyA Created
//
// Notes: see notes for OccurrenceCount().
//
//----------------------------------------------------------------------------
ULONG CMergeCursor::HitCount()
{
return OccurrenceCount();
}
//+---------------------------------------------------------------------------
//
// Member: CMergeCursor::ReplenishWid, protected
//
// Synopsis: Replenish the wid heap
//
// Returns: TRUE if successful, FALSE if key heap exhausted
//
// Effects: Updates _iid to the ones of the widHeap top
//
// History: 06-May-91 BartoszM Created
//
//----------------------------------------------------------------------------
BOOL CMergeCursor::ReplenishWid()
{
if ( _keyHeap.IsEmpty() )
{
return FALSE;
}
// Move all cursors with the lowest key
// to widHeap
CKeyBuf key = *(_keyHeap.Top()->GetKey());
do {
CKeyCursor* cur = _keyHeap.RemoveTop();
_widHeap.Add ( cur );
} while ( !_keyHeap.IsEmpty()
&& AreEqual( &key, _keyHeap.Top()->GetKey()) );
_iid = _widHeap.Top()->IndexId();
return TRUE;
}
//
// Remove RefillStream() and FreeStream() once NTFS supports
// sparse file operations on parts of a file when other parts
// of the file are mapped. This won't happen any time soon.
//
void CMergeCursor::FreeStream()
{
ULONG cCursors = _keyHeap.Count();
CKeyCursor **aCursors = _keyHeap.GetVector();
ciDebugOut(( DEB_ITRACE, "free key heap has %d cursors\n", cCursors ));
for ( ULONG i = 0; i < cCursors; i++ )
aCursors[ i ]->FreeStream();
cCursors = _widHeap.Count();
aCursors = _widHeap.GetVector();
ciDebugOut(( DEB_ITRACE, "free wid heap has %d cursors\n", cCursors ));
for ( i = 0; i < cCursors; i++ )
aCursors[ i ]->FreeStream();
} //FreeStream
void CMergeCursor::RefillStream()
{
ULONG cCursors = _keyHeap.Count();
CKeyCursor **aCursors = _keyHeap.GetVector();
ciDebugOut(( DEB_ITRACE, "refill key heap has %d cursors\n", cCursors ));
for ( ULONG i = 0; i < cCursors; i++ )
aCursors[ i ]->RefillStream();
cCursors = _widHeap.Count();
aCursors = _widHeap.GetVector();
ciDebugOut(( DEB_ITRACE, "refill wid heap has %d cursors\n", cCursors ));
for ( i = 0; i < cCursors; i++ )
aCursors[ i ]->RefillStream();
} //FreeStream