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

344 lines
8.5 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1991 - 2000.
//
// File: ANDCUR.CXX
//
// Contents: And Cursor. Computes intersection of multiple cursors.
//
// Classes: CAndCursor
//
// History: 24-May-91 BartoszM Created.
//
//----------------------------------------------------------------------------
#include <pch.cxx>
#pragma hdrstop
#include "andcur.hxx"
#pragma optimize( "t", on )
//+---------------------------------------------------------------------------
//
// Member: CAndCursor::CAndCursor, public
//
// Synopsis: Create a cursor that merges a number of cursors.
//
// Arguments: [cCursor] -- count of cursors
// [curStack] -- cursors to merge
//
// Notes: All cursors must come from the same index
// and the same property
//
// History: 24-May-91 BartoszM Created
// 22-Feb-93 KyleP Avoid divide-by-zero
//
//----------------------------------------------------------------------------
CAndCursor::CAndCursor( unsigned cCursor, CCurStack& curStack )
: _aCur ( curStack.AcqStack() ),
_cCur ( cCursor ),
_iCur ( 0 ),
_lMaxWeight( 0 )
{
Win4Assert ( _aCur[0] != 0 );
_iid = _aCur[0]->IndexId();
_pid = _aCur[0]->Pid();
//
// Calculate maximum weight of any child.
//
for ( UINT i = 0; i < _cCur; i++ )
{
_lMaxWeight = max( _lMaxWeight, _aCur[i]->GetWeight() );
}
//
// Avoid divide-by-zero
//
if ( _lMaxWeight == 0 )
_lMaxWeight = 1;
// NTRAID#DB-NTBUG9-84004-2000/07/31-dlee Indexing Service internal cursors aren't optimized to use shortest cursors first
_wid = _aCur[0]->WorkId();
FindConjunction();
}
//+---------------------------------------------------------------------------
//
// Member: CAndCursor::~CAndCursor, public
//
// Synopsis: Delete the cursor together with children
//
// History: 24-May-91 BartoszM Created
//
//----------------------------------------------------------------------------
CAndCursor::~CAndCursor( )
{
for ( unsigned i = 0; i < _cCur; i++ )
delete _aCur[i];
delete (void*) _aCur;
}
//+---------------------------------------------------------------------------
//
// Member: CAndCursor::WorkId, public
//
// Synopsis: Get current work id.
//
// History: 24-May-91 BartoszM Created
//
//----------------------------------------------------------------------------
WORKID CAndCursor::WorkId()
{
return _wid;
}
//+---------------------------------------------------------------------------
//
// Member: CAndCursor::NexWorkID, public
//
// Synopsis: Move to next work id
//
// Returns: Target work id or widInvalid if no more wid's for current key
//
// History: 24-May-91 BartoszM Created
//
//----------------------------------------------------------------------------
WORKID CAndCursor::NextWorkId()
{
// NTRAID#DB-NTBUG9-84004-2000/07/31-dlee Indexing Service internal cursors aren't optimized to use shortest cursors first
_wid = _aCur[0]->NextWorkId();
FindConjunction();
return _wid;
}
//+---------------------------------------------------------------------------
//
// Member: CAndCursor::HitCount, public
//
// Synopsis: Returns smallest HitCount of all keys in current wid.
//
// Requires: _wid set to any of the current wid's
//
// Returns: smallest occurrence count of all keys in wid.
//
// History: 28-Feb-92 AmyA Created
//
// Notes: If there is no conjunction in current wid, returns 0.
//
//----------------------------------------------------------------------------
ULONG CAndCursor::HitCount()
{
ULONG count = _aCur[0]->HitCount();
for ( unsigned i = 1; i < _cCur; i++ )
{
ULONG newcount = _aCur[i]->HitCount();
if ( newcount < count )
count = newcount;
}
return count;
}
void CAndCursor::RatioFinished (ULONG& denom, ULONG& num)
{
denom = 1;
num = 0;
for (unsigned i=0; i < _cCur; i++)
{
ULONG d, n;
_aCur[i]->RatioFinished(d, n);
if (d == n)
{
// done if any cursor is done.
denom = d;
num = n;
Win4Assert( denom > 0 );
break;
}
else if (d > denom)
{
// the one with largest denom
// is the most meaningful
denom = d;
num = n;
}
else if (d == denom && n < num )
{
num = n; // be pessimistic
}
}
}
//+---------------------------------------------------------------------------
//
// Member: CAndCursor::Rank, public
//
// Synopsis: Returns smallest rank of all keys in current wid.
//
// Requires: _wid set to any of the current wid's
//
// Returns: smallest rank of all keys in wid.
//
// History: 14-Apr-92 AmyA Created
// 27-Jul-92 KyleP Use min function for weight
//
// Notes: If there is no conjunction in current wid, returns 0.
//
// See "Automatic Text Processing", G. Salton, 10.4.2 for
// a discussion of the weight formula.
//
//----------------------------------------------------------------------------
LONG CAndCursor::Rank()
{
LONG lRank = (MAX_QUERY_RANK - _aCur[0]->Rank()) * _aCur[0]->GetWeight();
for ( UINT i = 1; i < _cCur; i++ )
{
LONG lNew = (MAX_QUERY_RANK - _aCur[i]->Rank()) * _aCur[i]->GetWeight();
lRank = max( lRank, lNew );
}
//
// Normalize weight.
//
lRank = MAX_QUERY_RANK - (lRank / _lMaxWeight);
return( lRank );
}
//+---------------------------------------------------------------------------
//
// Member: CAndCursor::FindConjunction, private
//
// Synopsis: Find nearest conjunction of all the same work id's
//
// Requires: _wid set to any of the current wid's
//
// Returns: TRUE when found, FALSE otherwise
//
// Modifies: [_wid] to point to conjunction or to widInvalid
//
// History: 24-May-91 BartoszM Created
//
// Notes: If cursors are in conjunction, no change results
//
//----------------------------------------------------------------------------
BOOL CAndCursor::FindConjunction()
{
BOOL fChange;
do
{
fChange = FALSE;
// NTRAID#DB-NTBUG9-84004-2000/07/31-dlee Indexing Service internal cursors aren't optimized to use shortest cursors first
// for all cursors in turn
for ( unsigned i = 0; i < _cCur; i++ )
{
// Seek _wid increment cursor to or past current _wid
// or exit when exhausted
WORKID widTmp = _aCur[i]->WorkId();
while ( widTmp < _wid )
{
widTmp = _aCur[i]->NextWorkId();
if ( widInvalid == widTmp )
{
_wid = widInvalid;
return FALSE;
}
}
// if overshot, try again with new _wid
if ( widTmp > _wid )
{
_wid = widTmp;
fChange = TRUE;
break;
}
}
} while ( fChange );
return TRUE;
}
//+---------------------------------------------------------------------------
//
// Member: CAndCursor::Hit, public
//
// Synopsis: Hits current child (indexed by _iCur)
//
// History: 07-Sep-92 MikeHew Created
//
// Notes: Hit() should not be called more than once, except by
// NextHit()
//
//----------------------------------------------------------------------------
LONG CAndCursor::Hit()
{
Win4Assert( _iCur < _cCur );
if ( WorkId() == widInvalid )
{
return rankInvalid;
}
else
{
return _aCur[_iCur]->Hit();
}
}
//+---------------------------------------------------------------------------
//
// Member: CAndCursor::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 CAndCursor::NextHit()
{
Win4Assert( _iCur < _cCur );
LONG rank = _aCur[_iCur]->NextHit();
if ( rank == rankInvalid )
{
if ( ++_iCur < _cCur )
{
return Hit();
}
}
return rank;
}