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

369 lines
9.3 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1995.
//
// File: PQueue.cxx
//
// Purpose: 'Pending' queue. Queue of pending notifications.
//
// Classes: CPendingQueue
//
// History: 30-Aug-95 KyleP Created
//
//----------------------------------------------------------------------------
#include <pch.cxx>
#pragma hdrstop
#include "pqueue.hxx"
//+---------------------------------------------------------------------------
//
// Member: CPendingQueue::CPendingQueue, public
//
// Synopsis: Constructor
//
// History: 01-Sep-95 KyleP Created
//
//----------------------------------------------------------------------------
CPendingQueue::CPendingQueue()
: _cUnique( 0 ),
_iBottom( 0 ),
_iTop( 0 ),
_cDoc( 16 ),
_aDoc(0)
{
_aDoc = new CPendingQueue::CDocItem[_cDoc];
}
//+---------------------------------------------------------------------------
//
// Member: CPendingQueue::~CPendingQueue, public
//
// Synopsis: Destructor
//
// History: 01-Sep-95 KyleP Created
//
//----------------------------------------------------------------------------
CPendingQueue::~CPendingQueue()
{
Win4Assert( 0 == _iTop );
delete [] _aDoc;
}
//+---------------------------------------------------------------------------
//
// Member: CPendingQueue::LokPrepare, public
//
// Synopsis: Allocate queue entry (to be filled in later).
//
// Arguments: [workid] -- Workid of entry
//
// Returns: Unique identifier for this entry.
//
// History: 01-Sep-95 KyleP Created
//
//----------------------------------------------------------------------------
unsigned CPendingQueue::LokPrepare( WORKID wid )
{
//
// May have to grow the array. This is a very rare operation.
//
if ( _iTop == _cDoc )
{
CPendingQueue::CDocItem * pTemp = _aDoc;
#if CIDBG==1
if ( _iTop >= 128 )
{
ciDebugOut(( DEB_WARN,
"Too many active threads (0x%X) in cleanup\n", _iTop ));
}
#endif // CIDBG==1
_cDoc *= 2;
_aDoc = new CPendingQueue::CDocItem[_cDoc];
RtlCopyMemory( _aDoc, pTemp, _cDoc / 2 * sizeof(_aDoc[0]) );
delete [] pTemp;
}
unsigned iHint = _iTop;
_aDoc[_iTop].wid = wid;
_aDoc[_iTop].hint = _cUnique++;
_aDoc[_iTop].fComplete = FALSE;
_iTop++;
return _aDoc[_iTop-1].hint;
}
//+---------------------------------------------------------------------------
//
// Member: CPendingQueue::LokComplete, public
//
// Synopsis: Fill in pre-reserved queue entry
//
// Arguments: [iHint] -- Unique id of entry.
// [wid] -- Workid of entry.
// [usn] -- USN.
// [volumeId] -- Volume id
// [partid] -- Partition Id
// [action] -- Update/Delete
//
// Returns: TRUE if queue was empty except for this entry. Means this
// entry wasn't added (and can be processed now). FALSE means
// CPendingQueue::Remove must be called directly following return
// from Complete.
//
// History: 01-Sep-95 KyleP Created
//
//----------------------------------------------------------------------------
BOOL CPendingQueue::LokComplete( unsigned iHint,
WORKID wid,
USN usn,
VOLUMEID volumeId,
PARTITIONID partid,
ULONG action )
{
if ( ULONG_MAX == iHint )
{
//
// Special case for scan-update documents. There is no need for
// preserving order of updates.
//
return TRUE;
}
Win4Assert( _iBottom == 0 );
Win4Assert( _iTop > 0 );
//
// Special case: If this is the only pending document then don't bother to fill
// in the struct, only to pull the values out. Remember, this is
// called from Cleanup. Speed counts.
//
if( _iTop == 1 )
{
Win4Assert( _aDoc[0].wid == wid );
Win4Assert( _aDoc[0].hint == iHint );
_iTop--;
return TRUE;
}
//
// The entry may have moved down, but never up the queue.
//
for ( unsigned i = 0; _aDoc[i].hint != iHint; i++ )
{
Win4Assert( i < _iTop );
continue; // NULL body
}
Win4Assert( _aDoc[i].wid == wid );
_aDoc[i].usn = usn;
_aDoc[i].volumeId = volumeId;
_aDoc[i].partid = partid;
_aDoc[i].action = action;
_aDoc[i].fComplete = TRUE;
return FALSE;
}
//+---------------------------------------------------------------------------
//
// Member: CPendingQueue::LokRemove, public
//
// Synopsis: Pop a completed entry from queue.
//
// Arguments: [wid] -- Workid of entry returned here.
// [usn] -- USN returned here.
// [volumeId] -- Volume id
// [partid] -- Partition Id returned here.
// [action] -- Update/Delete returned here.
//
// Returns: TRUE if an entry was available for removal. FALSE is queue
// was empty, or bottom entry was not complete.
//
// History: 01-Sep-95 KyleP Created
//
//----------------------------------------------------------------------------
BOOL CPendingQueue::LokRemove( WORKID & wid,
USN & usn,
VOLUMEID& volumeId,
PARTITIONID & partid,
ULONG & action )
{
//
// All done. Empty queue.
//
if ( _iBottom == _iTop )
{
_iBottom = 0;
_iTop = 0;
return FALSE;
}
//
// Out of completed entries.
//
if ( !_aDoc[_iBottom].fComplete )
{
RtlMoveMemory( _aDoc, &_aDoc[_iBottom], (_iTop - _iBottom) * sizeof(_aDoc[0]) );
_iTop -= _iBottom;
_iBottom = 0;
return FALSE;
}
//
// Got something!
//
wid = _aDoc[_iBottom].wid;
usn = _aDoc[_iBottom].usn;
volumeId = _aDoc[_iBottom].volumeId;
partid = _aDoc[_iBottom].partid;
action = _aDoc[_iBottom].action;
_iBottom++;
return TRUE;
}
//+---------------------------------------------------------------------------
//
// Member: CPendingQueue::LokCountCompleted, public
//
// Returns: Count of completed entries in queue.
//
// History: 01-Sep-95 KyleP Created
//
//----------------------------------------------------------------------------
unsigned CPendingQueue::LokCountCompleted()
{
Win4Assert( _iBottom == 0 );
unsigned cComplete = 0;
for ( unsigned i = 0; i < _iTop; i++ )
{
if ( _aDoc[i].fComplete )
cComplete++;
}
return cComplete;
}
//+---------------------------------------------------------------------------
//
// Member: CPendingQueue::LokGetCompleted, public
//
// Synopsis: Fetch wids of completed entries.
//
// Arguments: [awid] -- Wids returned here.
//
// History: 01-Sep-95 KyleP Created
//
// Notes: Assumes [awid] is big enough to hold CountCompleted() wids.
//
//----------------------------------------------------------------------------
void CPendingQueue::LokGetCompleted( WORKID * awid )
{
Win4Assert( _iBottom == 0 );
for ( unsigned i = 0; i < _iTop; i++ )
{
if ( _aDoc[i].fComplete )
{
*awid = _aDoc[i].wid;
awid++;
}
}
}
//+---------------------------------------------------------------------------
//
// Member: CPendingQueue::LokFlushCompletedEntries
//
// Synopsis: Flushes any completed entries in the pending queue.
//
// History: 9-11-95 srikants Created
//
// Notes: Called as a result of an exception while removing the
// entries.
//
// The "Incomplete" entries will get cleaned up as part of
// the "UpdateDocument" calls from cleanup.
//
//----------------------------------------------------------------------------
void CPendingQueue::LokFlushCompletedEntries()
{
ciDebugOut(( DEB_WARN,
"CPendingQueue::Flushing Entries _iBottom=0x%X _iTop=0x%X\n",
_iBottom, _iTop ));
Win4Assert( 0 == _iBottom || _iBottom <= _iTop );
while ( _iBottom < _iTop && _aDoc[_iBottom].fComplete )
_iBottom++;
if ( _iBottom == _iTop )
{
_iBottom = _iTop = 0;
}
else
{
RtlMoveMemory( _aDoc, &_aDoc[_iBottom], (_iTop - _iBottom) * sizeof(_aDoc[0]) );
_iTop -= _iBottom;
_iBottom = 0;
}
return;
}
//+---------------------------------------------------------------------------
//
// Member: CPendingQueue::LokFlushAllEntries
//
// Synopsis: Flushes all entries in the pending queue.
//
// History: 06-10-95 KyleP Created
//
// Notes: Used during restart, after a call to EnableUsnUpdate.
//
//----------------------------------------------------------------------------
void CPendingQueue::LokFlushAllEntries()
{
ciDebugOut(( DEB_WARN,
"CPendingQueue::Flushing All Entries _iBottom=0x%X _iTop=0x%X\n",
_iBottom, _iTop ));
Win4Assert( 0 == _iBottom || _iBottom < _iTop );
_iBottom = 0;
_iTop = 0;
_cUnique = 0;
return;
}