Windows-Server-2003/inetsrv/query/cursor/orcursor.cxx

338 lines
8.2 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1991 - 2001.
//
// File: ORCURSOR.CXX
//
// Contents: Merge Cursor. Computes union of multiple cursors.
//
// Classes: COrCursor
//
// History: 26-Sep-91 BartoszM Created
//
//----------------------------------------------------------------------------
#include <pch.cxx>
#pragma hdrstop
#include <orcursor.hxx>
#include <curstk.hxx>
//+---------------------------------------------------------------------------
//
// Member: COrCursor::COrCursor, public
//
// Synopsis: Create a sursor that merges a number of cursors.
//
// Arguments: [cCursor] -- count of cursors
// [curStack] -- cursors to be merged
//
// History: 26-Sep-91 BartoszM Created
// 14-Jul-92 KyleP Use max function for Rank
// 22-Feb-93 KyleP Avoid divide-by-zero
//
// Notes: The cursors and the array will be deleted by destructor.
// The cursors have to come from one index
//
//----------------------------------------------------------------------------
COrCursor::COrCursor( int cCursor, CCurStack& curStack )
: _lMaxWeight( 0 ), _iCur( 0 ), _wid( widInvalid )
{
// Two step construction of the heap.
// We have to make sure that all cursors have a valid key
int count = 0;
CCursor** aCursor = curStack.AcqStack();
// remove empty cursors
for ( int i = 0; i < cCursor; i++ )
{
Win4Assert ( aCursor[i] != 0 );
if ( aCursor[i]->WorkId() == widInvalid )
{
delete aCursor[i];
}
else
{
_lMaxWeight = max( _lMaxWeight, aCursor[i]->GetWeight() );
if ( count != i )
aCursor[count++] = aCursor[i];
else
count++;
}
}
//
// Avoid divide-by-zero
//
if ( _lMaxWeight == 0 )
_lMaxWeight = 1;
_widHeap.MakeHeap ( count, aCursor );
if ( !_widHeap.IsEmpty() )
{
CCursor & cursor = * _widHeap.Top();
_wid = cursor.WorkId();
_iid = cursor.IndexId();
_pid = cursor.Pid();
}
}
//+---------------------------------------------------------------------------
//
// Member: COrCursor::WorkId, public
//
// Synopsis: Get current work id.
//
// History: 26-Sep-91 BartoszM Created
//
//----------------------------------------------------------------------------
WORKID COrCursor::WorkId()
{
return _wid;
}
//+---------------------------------------------------------------------------
//
// Member: COrCursor::NextWorkId, public
//
// Synopsis: Move to next work id
//
// Returns: Target work id or widInvalid if no more wid's for current key
//
// History: 26-Sep-91 BartoszM Created
//
//----------------------------------------------------------------------------
WORKID COrCursor::NextWorkId()
{
if ( widInvalid == _wid )
return widInvalid;
WORKID widNew;
do
{
_widHeap.Top()->NextWorkId();
_widHeap.ReheapKey();
widNew = _widHeap.Top()->WorkId();
}
while ( widNew == _wid );
_wid = widNew;
return _wid;
}
//+---------------------------------------------------------------------------
//
// Member: COrCursor::WorkIdCount, public
//
// Synopsis: return wid count
//
// History: 26-Sep-91 BartoszM Created
//
// Notes: 1. Sum up wid count of all cursors in widHeap
//
//----------------------------------------------------------------------------
ULONG COrCursor::WorkIdCount()
{
Win4Assert (( FALSE && "OrCursor::WorkIdCount called" ));
return(0);
}
//+---------------------------------------------------------------------------
//
// Member: COrCursor::HitCount, public
//
// Synopsis: return occurrence count
//
// History: 28-Feb-92 AmyA Created
//
// Notes: returns the occurrence count for the wid on top of _widHeap.
//
//----------------------------------------------------------------------------
ULONG COrCursor::HitCount()
{
if ( widInvalid == _wid )
return 0;
ULONG hitCnt = 0;
CCursor **vector = _widHeap.GetVector();
int count = _widHeap.Count();
for (int i=0; i < count; i++)
{
if ( vector[i]->WorkId() == _wid )
hitCnt += vector[i]->HitCount();
}
return hitCnt;
}
//+---------------------------------------------------------------------------
//
// Member: COrCursor::RatioFinished, public
//
// Synopsis: return approximate ratio of documents processed to total
// documents.
//
// Notes: The ratio, while approximate, should not return 1/1 until
// all cursors are exhausted.
//
//----------------------------------------------------------------------------
void COrCursor::RatioFinished (ULONG& denom, ULONG& num)
{
if ( widInvalid == _wid )
{
denom = num = 1;
return;
}
CCursor **vector = _widHeap.GetVector();
int count = _widHeap.Count();
unsigned cValid = 1;
denom = 0;
num = 0;
for (int i=0; i < count; i++)
{
ULONG d, n;
vector[i]->RatioFinished(d, n);
Win4Assert( n <= d && d > 0 );
num += n;
denom += d;
Win4Assert( d <= denom ); // overflow?
if (n == d)
{
WORKID widCurrent = vector[i]->WorkId();
if (widCurrent != widInvalid && widCurrent != _wid)
cValid++;
}
}
if (num == denom && cValid > 1)
denom++;
}
//+---------------------------------------------------------------------------
//
// Member: COrCursor::Rank, public
//
// Synopsis: returns a rank (turns the OrCursor into a Quorum Cursor)
//
// History: 13-Apr-92 AmyA Created
// 23-Jun-92 MikeHew Added Weighting
// 14-Jul-92 KyleP Use max function for Rank
//
// Notes: See "Automatic Text Processing", G. Salton, 10.4.2 for
// a discussion of the weight formula.
//
//----------------------------------------------------------------------------
LONG COrCursor::Rank()
{
if ( widInvalid == _wid )
return 0;
LONG lRank = 0;
CCursor **vector = _widHeap.GetVector();
int cCur = _widHeap.Count();
for ( int i = 0; i < cCur; i++ )
{
if ( vector[i]->WorkId() == _wid )
{
LONG lNew = vector[i]->Rank() * vector[i]->GetWeight();
lRank = max( lRank, lNew );
}
}
//
// Normalize weight.
//
lRank = lRank / _lMaxWeight;
return ( lRank );
}
//+---------------------------------------------------------------------------
//
// Member: COrCursor::Hit, public
//
// Synopsis: Hits current child (indexed by _iCur)
// Moves onto next child if empty.
//
// History: 07-Sep-92 MikeHew Created
//
// Notes: Hit() should not be called more than once, except by
// NextHit()
//
//----------------------------------------------------------------------------
LONG COrCursor::Hit()
{
int cCur = _widHeap.Count();
CCursor ** aCur = _widHeap.GetVector();
Win4Assert( _iCur < cCur );
LONG rank = aCur[_iCur]->Hit();
// if this cursor is empty, find one that's not
while ( rank == rankInvalid &&
++_iCur < cCur )
{
rank = aCur[_iCur]->Hit();
}
return rank;
}
//+---------------------------------------------------------------------------
//
// Member: COrCursor::NextHit, public
//
// Synopsis: NextHits current child (indexed by _iCur)
// If current child becomes empty, increments _iCur
//
// History: 07-Sep-92 MikeHew Created
//
// Notes: NextHit() should not be called after returning rankInvalid
//
//----------------------------------------------------------------------------
LONG COrCursor::NextHit()
{
int cCur = _widHeap.Count();
CCursor ** aCur = _widHeap.GetVector();
Win4Assert( _iCur < cCur );
LONG rank = aCur[_iCur]->NextHit();
if ( rank == rankInvalid )
{
if ( ++_iCur < cCur )
{
return Hit();
}
}
return rank;
}