windows-nt/Source/XPSP1/NT/inetsrv/query/bigtable/tblwindo.hxx
2020-09-26 16:20:57 +08:00

780 lines
22 KiB
C++

//+-------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1994 - 2000.
//
// File: tblwindo.hxx
//
// Contents: Declaration of the CTableWindow class, a component of
// a large table.
//
// Classes: CTableWindow
//
// History: 14 Jun 1994 Alanw Created
// 20 Jun 1995 BartoszM Added watch regions
//
//--------------------------------------------------------------------------
#pragma once
#include <tableseg.hxx>
#include <shardbuf.hxx> // Shared buffer
#include "tblvarnt.hxx" // for CTableVariant
#include "rowcomp.hxx" // for CRowCompareXX
#include "rowindex.hxx" // for CRowIndex
#include "bmkmap.hxx" // for Book Mark Mapping
#include "wnotifmg.hxx" // Watch region notifications manager
class CTableWindowSplit;
class CTableRowKey;
class CPathStore;
class CSingletonCursor;
class CWindowWatch
{
public:
HWATCHREGION _hRegion;
long _iRowStart;
long _cRowsHere; // rows watched in this window
long _cRowsLeft; // rows watched here and in following segments
};
class CChangeScript; // NEWFEATURE - until we give change scripts.
//+-------------------------------------------------------------------------
//
// Class: CTableWindow
//
// Purpose: A segment of a large table which is fully buffered in
// memory.
// It can be directly transferred to the user from the
// cached rowdata.
//
// Interface:
//
//--------------------------------------------------------------------------
class CTableWindow : public CTableSegment
{
INLINE_UNWIND( CTableWindow )
friend CRowCompareVariant;
friend class CTableWindowSplit;
friend class CLargeTable;
friend class CWindowRowIter;
friend class CTableRowLocator;
friend class CBucketizeWindows;
public:
//
// Indicator values for data values.
//
// NOTE: These values need to be translated between these values
// and the standard defines used by OLE DB. We define our
// own values so we can store them in a byte (or smaller)
// field in the row data.
//
enum TableIndicator
{
TBL_DATA_OKAY = 0, // data stored okay
TBL_DATA_OUTOFRANGE, // range error, e.g., long into short
TBL_DATA_CANTCOERCE, // type mismatch
TBL_DATA_USEENTRYID, // entry too big, use entry ID
TBL_DATA_OVERRUN, // value too big for data area
TBL_DATA_EMPTY, // no value for this data point
TBL_DATA_ROWADDED, // row status: added after cursor created
TBL_DATA_BADBOOKMARK, // row status: bookmark for row was invalid
TBL_DATA_PENDING_DELETE, // row status: pending delete
TBL_DATA_HARD_DELETE // row status: hard deleted; not visible
};
CTableWindow(
CSortSet const * pSortSet,
CTableKeyCompare & comparator,
CColumnMasterSet * pMasterColumns,
ULONG segId,
CCategorize *pCategorizer,
CSharedBuffer & sharedBuf,
CQAsyncExecute & QExecute
);
CTableWindow( CTableWindow & src,
ULONG segId
);
~CTableWindow();
// Virtual methods inherited from CTableSink
WORKID PathToWorkID( CRetriever& obj,
CTableSink::ERowType eRowType );
BOOL PutRow( CRetriever & obj, CTableSink::ERowType eRowType )
{
Win4Assert( !"Must not be called" );
return FALSE;
}
BOOL RemoveRow( PROPVARIANT const & varUnique,
WORKID & widNext,
CI_TBL_CHAPT & chapt );
CSortSet const & SortOrder();
// Virtual methods inherited from CTableSegment
BOOL PutRow( CRetriever & obj, CTableRowKey & currKey );
DBCOUNTITEM RowCount()
{
return _visibleRowIndex.RowCount();
}
SCODE GetRows( HWATCHREGION hRegion,
WORKID widStart,
CI_TBL_CHAPT chapt,
ULONG & cRowsToGet,
CTableColumnSet const & rOutColumns,
CGetRowsParams& rGetParams,
WORKID& rwidNextRowToTransfer );
void LokGetOneColumn( WORKID wid,
CTableColumn const & rOutColumn,
BYTE * pbOut,
PVarAllocator & rVarAllocator );
BOOL IsRowInSegment( WORKID wid );
BOOL IsPendingDelete( WORKID wid );
void CompareRange( CRetriever &obj, CCompareResult & rslt );
SCODE GetNotifications( CNotificationParams &rParams );
// Other public methods
BOOL RowOffset(WORKID wid, ULONG & iRow)
{
if ( widInvalid == wid )
return FALSE;
TBL_OFF obRowOffset = 0;
if ( FindBookMark( wid, obRowOffset, iRow ) )
return TRUE;
else return _FindWorkId(wid, obRowOffset, iRow);
}
BOOL FindBookMark( WORKID wid, TBL_OFF &obRow, ULONG & iRow );
WORKID GetBookMarkAt( ULONG iRow );
WORKID GetFirstBookMark();
int CompressData(); // attempt to reduce data storage needs
inline ULONG MemUsed( void ) {
// PERFFIX - also need so sum all non-global, non-shared compressions
return _cbHeapUsed + _DataAllocator.MemUsed();
}
BOOL IsSortedSplit( ULONG & riSplit )
{
return _GetInvisibleRowIndex().FindMidSplitPoint( riSplit );
}
BOOL IsEmptyForQuery();
BOOL IsGettingFull();
unsigned PercentFull();
// Watch region manipulations
long AddWatch (HWATCHREGION hRegion,
LONG iStart,
LONG cRows,
BOOL isLast);
long ModifyWatch (HWATCHREGION hRegion,
LONG iStart,
LONG cRows,
BOOL isLast);
long DeleteWatch (HWATCHREGION hRegion);
long ShrinkWatch (HWATCHREGION hRegion,
CI_TBL_BMK bookmark,
LONG cRows);
long ShrinkWatch (HWATCHREGION hRegion, LONG cRows);
BOOL HasWatch (HWATCHREGION hRegion);
BOOL IsWatched (HWATCHREGION hRegion, CI_TBL_BMK bookmark);
BOOL IsWatched()
{
if ( _aWindowWatch.Count() > 0 )
{
if ( _xDeltaBookMarkMap.IsNull() )
_xDeltaBookMarkMap.Set( new CBookMarkMap( _dynRowIndex ) );
return TRUE;
}
return FALSE;
}
long RowsWatched (HWATCHREGION hRegion);
WORKID RowWorkid(BYTE *pRow)
{ return *(WORKID *) (pRow + _iOffsetWid); }
LONG RowRank(BYTE *pRow)
{
return ( ULONG_MAX == _iOffsetRank ) ?
MAX_QUERY_RANK :
*(LONG *) (pRow + _iOffsetRank);
}
LONG RowHitCount(BYTE *pRow)
{
return ( ULONG_MAX == _iOffsetHitCount ) ?
0 :
*(LONG *) (pRow + _iOffsetHitCount);
}
long GetWatchStart( HWATCHREGION hRegion) const
{
unsigned i = FindRegion(hRegion);
Win4Assert (i < _aWindowWatch.Count());
return _aWindowWatch.Get(i)._iRowStart;
}
BOOL FindNearestDynamicBmk( CI_TBL_CHAPT chapter,
CI_TBL_BMK & bookmark );
BOOL FindFirstNonDeleteDynamicBmk( CI_TBL_BMK & bookmark );
BOOL FindLastNonDeleteDynamicBmk( CI_TBL_BMK & bookmark );
BOOL IsFirstRowFirstOfCategory();
#ifdef CIEXTMODE
void CiExtDump(void *ciExtSelf);
#endif
private:
//
// No Copy consructor allowed for this.
//
CTableWindow( CTableWindow & src );
void _FinishInit( CTableRowAlloc & rowMap, unsigned &maxAlignment );
CSharedBuffer & _GetSharedBuf() const { return _sharedBuf; }
void _InitSortComparators();
void _PopulateRow( CRetriever &obj, BYTE *pThisRow, WORKID wid );
BOOL _FindWorkId( WORKID wid, TBL_OFF & obRow, ULONG & iRow );
WORKID _GetWorkIdAt( ULONG iRow );
WORKID _GetFirstWorkId();
WORKID _GetLastWorkId();
void _AddColumnDesc( CColumnMasterDesc& MasterCol,
CTableRowAlloc& RowMap,
unsigned& maxAlignment);
void _AddColumnDesc( CTableColumn & src,
CTableRowAlloc& RowMap,
unsigned& maxAlignment);
void _AddWatchItem (CWindowWatch& watch);
void _RemoveWatchItem (unsigned i);
CRowIndex & _GetInvisibleRowIndex()
{
return IsWatched() ? _dynRowIndex : _visibleRowIndex;
}
//
// Methods used for window->bucket conversion
//
void GetSortKey( ULONG iRow, CTableRowKey & bktRow );
unsigned FindRegion (HWATCHREGION hRegion) const;
void _StartStaticDynamicSplit();
void _EndStaticDynamicSplit();
void _ReconcileRowIndexes( CRowIndex & dst , CRowIndex & src );
void _CleanupAndReconcileRowIndexes( BOOL fCreatingWatch );
void _Refresh();
//
// Storage for fixed length row data
//
unsigned _cbRowSize; // size in bytes of data for each row
unsigned _iOffsetWid; // offset of WorkID in row data
unsigned _iOffsetRank; // offset of rank in row data
unsigned _iOffsetHitCount; // offset of hitcount in row data
unsigned _iOffsetRowStatus; // offset of row status in row data
unsigned _iOffsetChapter; // offset of chapter number (optional)
CTableColumnSet _Columns; // column descriptions for this window
//
// Shared buffer for the whole table used as temporary memory.
//
CSharedBuffer & _sharedBuf;
XPtr<CSingletonCursor> _xCursor; // singleton cursor used in GetRows
//
// Memory management related methods and variables.
//
BYTE * _RowAlloc( void )
{
_cRowsAllocated++;
// Just get a new row from the allocator
BYTE *pbRetBuf = (BYTE *) _DataAllocator.AllocFixed();
Win4Assert(0 != pbRetBuf);
return pbRetBuf;
}
//
// Additional storage for variable length data which is not
// stored as a compressed column. When first needed after a
// window is created, this will begin at the end of the block of
// data for row data, and grow downward toward it. When these
// grow enough to meet, the row data will be moved out into
// a separate block, allowing the variable data to expand into the
// newly freed area.
//
// At the time this data is moved or grown, it may be a good time to
// convert columns for compressions. All extra data for
// compressed columns will be stored with the column descriptor.
//
CFixedVarTableWindowAllocator _DataAllocator; // Variable data allocator
ULONG _cbHeapUsed; // total heap memory used by structure
CPathStore * _pPathStore; // Store for paths.
//
// Row indirection object. This holds offsets in the heap where each
// row resides. The row index is sorted by the current sort order.
//
CRowIndex _dynRowIndex;
//
// The "static" row index that will be used for giving rows to the
// client (user).
//
CRowIndex _visibleRowIndex;
//
// BookMark mapping object. If there are no notifications, it is
// associated with the _dynRowIndex; o/w it is associated with the
// _visibleRowIndex.
//
CBookMarkMap _BookMarkMap;
//
// BookMark mapping object for the "deltas" or changes pending
// notification to the user. It is always associated with the _dynRowIndex
//
XPtr<CBookMarkMap> _xDeltaBookMarkMap;
//
// Notification processing object
//
CDynArrayInPlace<CWindowWatch> _aWindowWatch;
//
// Row sorting objects.
//
XPtr<CRowCompareVariant> _RowCompare;
XPtr<CRowCompare> _QuickRowCompare;
CSortSet const * _pSortSet;
ULONG _cPendingDeletes; // # of rows with pending deletes. These are
// visible to retrievals.
ULONG _cRowsHardDeleted; // # of rows "hard" deleted - not visible to
// retrievals.
ULONG _cRowsAllocated; // # of rows allocated in the table
BOOL _fSplitInProgress; // Flag set to TRUE when a window split is
// in progress.
CQAsyncExecute & _QueryExecute; // The query object that will be used
// when retrieving the partial deferred cols.
BOOL _IsTableWatched() const;
ULONG _AllocatedRowCount()
{
return _cRowsAllocated;
}
BOOL _fCanPartialDefer ; // Is set in constructor by taking value from the query session
//
// Functions to get at row metadata that always exists
//
void _SetRowWorkid(BYTE *pRow,WORKID wid)
{ *(WORKID *) (pRow + _iOffsetWid) = wid; }
ULONG _RowStatus(BYTE *pRow)
{ return *(BYTE *) (pRow + _iOffsetRowStatus); }
void _SetRowStatus(BYTE *pRow,BYTE status)
{ *(BYTE *) (pRow + _iOffsetRowStatus) = status; }
ULONG _RowChapter(BYTE *pRow)
{ return *(unsigned *) (pRow + _iOffsetChapter); }
void _SetChapter(BYTE *pRow,unsigned Chapter)
{ *(unsigned *) (pRow + _iOffsetChapter) = Chapter; }
//
// Methods to support window splitting. These will be used by the
// CTableWindowSplit class.
//
CRowIndex & _GetVisibleRowIndex()
{
return _visibleRowIndex;
}
CRowIndex & _GetDynamicRowIndex()
{
return _dynRowIndex;
}
BYTE * _GetRow( TBL_OFF oTableRow )
{
return (BYTE *) _DataAllocator.FixedPointer( oTableRow );
}
void _PutRowToVisibleRowIndex( CTableWindow & srcWindow, TBL_OFF oSrcRow );
void _PutRowToDynRowIndex( CTableWindow & srcWindow, TBL_OFF oSrcRow );
TBL_OFF _CopyRow( CTableWindow & srcWindow, TBL_OFF oSrcRow );
WORKID _GetWorkId( TBL_OFF oTableRow )
{
BYTE * pbRow = _GetRow( oTableRow );
return RowWorkid( pbRow );
}
LONG _GetRank( TBL_OFF oTableRow )
{
BYTE * pbRow = _GetRow( oTableRow );
return RowRank( pbRow );
}
LONG _GetHitCount( TBL_OFF oTableRow )
{
BYTE * pbRow = _GetRow( oTableRow );
return RowHitCount( pbRow );
}
BOOL _IsRowDeleted( TBL_OFF oTableRow )
{
BYTE * pbRow = _GetRow( oTableRow );
const ULONG rowStatus = _RowStatus( pbRow );
return TBL_DATA_PENDING_DELETE == rowStatus ||
TBL_DATA_HARD_DELETE == rowStatus ;
}
BOOL _IsWorkIdInVisRowIndex( WORKID wid )
{
return _BookMarkMap.IsBookMarkPresent(wid);
}
BOOL _IsRowInVisRowIndex( TBL_OFF oTableRow )
{
BYTE * pbRow = _GetRow(oTableRow);
Win4Assert( pbRow );
WORKID wid = RowWorkid(pbRow);
TBL_OFF oRowFound;
BOOL fFound = _BookMarkMap.FindBookMark( wid, oRowFound );
return fFound && oRowFound == oTableRow;
}
int _CompareRows( TBL_OFF obRow1, TBL_OFF obRow2 )
{
if ( 0 != _QuickRowCompare.GetPointer() )
return _QuickRowCompare->Compare( obRow1, obRow2 );
else
return _RowCompare->Compare( obRow1, obRow2 );
}
BYTE * _GetRowFromIndex( ULONG iRow, CRowIndex & rowIndex )
{
return _GetRow( rowIndex.GetRow( iRow ) );
}
void _SetSplitInProgress() { _fSplitInProgress = TRUE; }
void _SetSplitDone() { _fSplitInProgress = FALSE; }
void _CopyColumnData( BYTE* pbSrcRow, BYTE* pbOutRow,
CTableColumn **pTableCols, CTableColumnSet const& rOutColumns,
PVarAllocator& rDstPool, CRetriever* obj = NULL );
inline BOOL _CanPartialDeferCol( XPtr<CTableColumn>& xTableCol ) const
{
Win4Assert( xTableCol.GetPointer() );
Win4Assert( _pSortSet );
return ( xTableCol->PropId != pidWorkId &&
xTableCol->PropId != pidRank &&
xTableCol->PropId != pidRankVector &&
xTableCol->PropId != pidHitCount &&
xTableCol->PropId != pidRowStatus &&
xTableCol->PropId != pidChapter &&
xTableCol->PropId != pidSelf &&
!_pSortSet->Exists( xTableCol->PropId ) );
}
};
//+-------------------------------------------------------------------------
//
// Member: CTableWindow::PathToWorkID, inline
//
// Synopsis: Path to WorkID conversion
//
// Arguments: [obj] -- positioned cursor to row
//
// Returns: WORKID - the WorkID assigned
//
// Notes: This method should be called only on CLargeTable.
// CLEANCODE: for now it's convenient to have this as a
// virtual method on CTableSink. It should become
// an ordinary method on CLargeTable once the
// ITable code is removed.
//
//--------------------------------------------------------------------------
inline WORKID CTableWindow::PathToWorkID(
CRetriever& obj,
CTableSink::ERowType eRowType )
{
return 0;
}
//+---------------------------------------------------------------------------
//
// Member: CTableWindow::GetBookMarkAt
//
// Synopsis: Returns a bookmark at the specified offset.
//
// Arguments: [iRow] -
//
// History: 8-04-95 srikants Created
//
// Notes:
//
//----------------------------------------------------------------------------
inline
WORKID CTableWindow::GetBookMarkAt( ULONG iRow )
{
Win4Assert( iRow < _GetVisibleRowIndex().RowCount() );
return RowWorkid( _GetRowFromIndex( iRow, _GetVisibleRowIndex() ) );
}
//+---------------------------------------------------------------------------
//
// Member: CTableWindow::GetFirstBookMark
//
// Synopsis: Returns the first BOOKMARK in the window. A BOOKMARK is one
// which is visible to a client.
//
// History: 8-04-95 srikants Created
//
// Notes:
//
//----------------------------------------------------------------------------
inline
WORKID CTableWindow::GetFirstBookMark()
{
if ( 0 == RowCount() )
return widInvalid;
else
return GetBookMarkAt(0);
}
//+---------------------------------------------------------------------------
//
// Member: CTableWindow::_GetWorkIdAt
//
// Synopsis: Returns the workid at the specified offset in the
// "invisible" row index , ie, query row index.
//
// Arguments: [iRow] -
//
// History: 8-02-95 srikants Created
//
// Notes:
//
//----------------------------------------------------------------------------
inline
WORKID CTableWindow::_GetWorkIdAt( ULONG iRow )
{
Win4Assert( iRow < _GetInvisibleRowIndex().RowCount() );
return RowWorkid( _GetRowFromIndex(iRow , _GetInvisibleRowIndex()) );
}
//+---------------------------------------------------------------------------
//
// Function: _GetFirstWorkId
//
// Synopsis: Returns the first WORKID visible to the QUERY only. Note that
// this can be different from the first bookmark.
//
// History: 8-04-95 srikants Created
//
// Notes:
//
//----------------------------------------------------------------------------
inline
WORKID CTableWindow::_GetFirstWorkId()
{
if ( 0 == RowCount() )
return widInvalid;
else
return _GetWorkIdAt(0);
}
//+---------------------------------------------------------------------------
//
// Function: _GetLastWorkId
//
// Synopsis: Returns the last WORKID visible to the QUERY only. Note that
// this can be different from the first bookmark.
//
// History: 03-12-98 vikasman Created
//
// Notes:
//
//----------------------------------------------------------------------------
inline
WORKID CTableWindow::_GetLastWorkId()
{
if ( 0 == RowCount() )
return widInvalid;
else
return _GetWorkIdAt( (ULONG) RowCount() - 1);
}
//+---------------------------------------------------------------------------
//
// Class: CWindowRowIter ()
//
// Purpose: An iterator to retrieve WORKIDs from the a window.
//
// History: 2-16-95 srikants Created
//
// Notes:
//
//----------------------------------------------------------------------------
class CWindowRowIter
{
public:
CWindowRowIter( CTableWindow & window )
: _window(window), _rowIndex( window._GetInvisibleRowIndex() ),
_curr(0),
_cTotal( _rowIndex.RowCount() )
{
}
BOOL AtEnd() const
{
Win4Assert( _curr <= _cTotal );
return _curr == _cTotal;
}
BOOL AtEnd( ULONG iEnd ) const
{
Win4Assert( _curr <= _cTotal && iEnd <= _cTotal );
return _curr == iEnd;
}
WORKID Get() const
{
Win4Assert( !AtEnd() );
TBL_OFF oTableRow = _rowIndex.GetRow(_curr);
return _window._GetWorkId( oTableRow );
}
LONG Rank() const
{
Win4Assert( !AtEnd() );
TBL_OFF oTableRow = _rowIndex.GetRow(_curr);
return _window._GetRank( oTableRow );
}
LONG HitCount() const
{
Win4Assert( !AtEnd() );
TBL_OFF oTableRow = _rowIndex.GetRow(_curr);
return _window._GetHitCount( oTableRow );
}
BOOL IsDeletedRow() const
{
Win4Assert( !AtEnd() );
TBL_OFF oTableRow = _rowIndex.GetRow(_curr);
return _window._IsRowDeleted( oTableRow );
}
ULONG GetCurrPos() const
{
return _curr;
}
void Next()
{
Win4Assert( !AtEnd() );
_curr++;
}
ULONG TotalRows() const { return _cTotal; }
private:
CTableWindow & _window;
CRowIndex & _rowIndex;
ULONG _curr;
const ULONG _cTotal;
};