You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
474 lines
13 KiB
474 lines
13 KiB
//+---------------------------------------------------------------------------
|
|
//
|
|
// 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
|
|
|