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

438 lines
14 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1998.
//
// File: winsplit.cxx
//
// Contents: Contains the code to do a window split.
//
// Classes: CTableWindowSplit
//
// Functions:
//
// History: 1-08-95 srikants Created
//
//----------------------------------------------------------------------------
#include "pch.cxx"
#pragma hdrstop
#include "winsplit.hxx"
#include "tabledbg.hxx"
//+---------------------------------------------------------------------------
//
// Function: CTableWindowSplit ~ctor
//
// Synopsis: Constructor for the CTableWindowSplit class.
//
// Arguments: [srcWindow] - The source window that needs to be
// split
// [iSplitVisibleRowIndex] - Index in the source window's visible
// row index which is the split index. All rows <=
// iSplitVisibleRowIndex will be in the left hand window and the rest
// in the right hand window after the split.
//
// History: 1-09-95 srikants Created
//
// Notes:
//
//----------------------------------------------------------------------------
CTableWindowSplit::CTableWindowSplit( CTableWindow & srcWindow,
ULONG iSplitQueryRowIndex,
ULONG segIdLeft, ULONG segIdRight,
BOOL fIsLastSegment )
: _srcWindow(srcWindow),
_pLeftWindow(0),
_pRightWindow(0),
_srcQueryRowIndex(srcWindow._GetInvisibleRowIndex()),
_srcClientRowIndex(srcWindow._GetVisibleRowIndex()),
_iSplitQueryRowIndex(iSplitQueryRowIndex),
_iSplitClientRowIndex(-1),
_segIdLeft(segIdLeft), _segIdRight(segIdRight),
_fIsLastSegment(fIsLastSegment)
{
Win4Assert( _srcQueryRowIndex.RowCount() >= 2 );
Win4Assert( iSplitQueryRowIndex < _srcQueryRowIndex.RowCount()-1 );
if ( _srcWindow.IsWatched() )
{
//
// The source window has watch regions. The dynamic rowindex must
// also be split.
//
TBL_OFF oQuerySplitRow = _srcQueryRowIndex.GetRow( iSplitQueryRowIndex );
_iSplitClientRowIndex = _srcClientRowIndex.FindSplitPoint( oQuerySplitRow )-1;
}
}
//+---------------------------------------------------------------------------
//
// Function: ~CTableWindowSplit ~dtor for the CTableWindowSplit class
//
// Synopsis: Frees up the resources
//
// History: 1-09-95 srikants Created
//
// Notes:
//
//----------------------------------------------------------------------------
CTableWindowSplit::~CTableWindowSplit()
{
delete _pLeftWindow;
delete _pRightWindow;
}
//+---------------------------------------------------------------------------
//
// Function: CreateTargetWindows
//
// Synopsis: Creates the target windows and initializes their
// notification region based on the source window notification
// region.
//
// History: 1-09-95 srikants Created
//
// Notes:
//
//----------------------------------------------------------------------------
void CTableWindowSplit::CreateTargetWindows()
{
//
// First create the left and right windows
//
Win4Assert( 0 == _pLeftWindow );
Win4Assert( 0 == _pRightWindow );
_pLeftWindow = new CTableWindow( _srcWindow, _segIdLeft );
_pRightWindow = new CTableWindow( _srcWindow, _segIdRight );
}
//+---------------------------------------------------------------------------
//
// Function: TransferTargetWindows
//
// Synopsis: Transfers the control of the target windows to the caller.
//
// Arguments: [ppLeftWindow] - (output) The pointer to the left window.
// [ppRightWindow] - (output) The pointer to the right window.
//
// History: 1-09-95 srikants Created
//
// Notes:
//
//----------------------------------------------------------------------------
void CTableWindowSplit::TransferTargetWindows( CTableWindow ** ppLeftWindow,
CTableWindow ** ppRightWindow )
{
Win4Assert( 0 != ppLeftWindow && 0 != ppRightWindow );
*ppLeftWindow = _pLeftWindow;
_pLeftWindow = 0;
*ppRightWindow = _pRightWindow;
_pRightWindow = 0;
}
//+---------------------------------------------------------------------------
//
// Function: _CopyWithoutNotifications
//
// Synopsis: Copies rows from the source window to the destination window. Only
// the rows in the "srcRowIndex" will be copied to the
// destination.
//
// Arguments: [destWindow] - Target window to copy to.
// [srcRowIndex] - The source row index.
// [iStartRowIndex] - Starting offset in the row index to start
// copying rows from.
// [iEndRowIndex] - Ending offset in the row index to stop
// copying.
//
// History: 1-09-95 srikants Created
//
// Notes:
//
//----------------------------------------------------------------------------
void CTableWindowSplit::_CopyWithoutNotifications( CTableWindow & destWindow,
CRowIndex & srcRowIndex,
ULONG iStartRowIndex, ULONG iEndRowIndex )
{
Win4Assert( iEndRowIndex < srcRowIndex.RowCount() );
for ( ULONG i = iStartRowIndex; i <= iEndRowIndex; i++ )
{
destWindow._PutRowToVisibleRowIndex( _srcWindow, srcRowIndex.GetRow(i) );
}
}
//+---------------------------------------------------------------------------
//
// Function: _SimpleSplit
//
// Synopsis: Does a simple split in which the first half of the rows from
// the source row index will be copied to the left window and the
// second half to the right window.
//
// History: 1-31-95 srikants Created
//
// Notes: This must be called only when there is no notification region
// in the source window.
//
//----------------------------------------------------------------------------
void CTableWindowSplit::_SimpleSplit()
{
Win4Assert( !_srcWindow.IsWatched() );
//
// The source notifcation region is completely empty. We have to copy from
// the visible row index only.
//
tbDebugOut(( DEB_WINSPLIT, "CTableWindowSplit::Simple Split\n" ));
_CopyWithoutNotifications( *_pLeftWindow, _srcQueryRowIndex,
0, _iSplitQueryRowIndex );
_CopyWithoutNotifications( *_pRightWindow, _srcQueryRowIndex,
_iSplitQueryRowIndex+1,
_srcQueryRowIndex.RowCount()-1 );
}
//+---------------------------------------------------------------------------
//
// Function: DoSplit
//
// Synopsis: Splits the source window into left and right windows.
//
// History: 1-09-95 srikants Created
//
// Notes:
//
//----------------------------------------------------------------------------
void CTableWindowSplit::DoSplit()
{
Win4Assert( 0 != _pLeftWindow && 0 != _pRightWindow );
_pLeftWindow->_SetSplitInProgress();
_pRightWindow->_SetSplitInProgress();
if ( !_srcWindow.IsWatched() )
{
//
// The source notifcation region is completely empty. We have to copy from
// the visible row index only.
//
Win4Assert( -1 == _iSplitClientRowIndex );
_SimpleSplit();
_pLeftWindow->_SetSplitDone();
_pRightWindow->_SetSplitDone();
}
else
{
//
// If notifications are enabled in the target window, then we must copy
// both the client row index and the query row index. O/W, just copy
// the contents of the query row index.
//
//
// Copy the contents to the target left window.
//
tbDebugOut(( DEB_WINSPLIT, "Left Window with Notifications\n" ));
_CopyWithNotifications( *_pLeftWindow, 0, _iSplitQueryRowIndex,
0, _iSplitClientRowIndex );
//
// Copy the contents to the target right window.
//
tbDebugOut(( DEB_WINSPLIT, "Right Window with Notifications\n" ));
_CopyWithNotifications( *_pRightWindow,
_iSplitQueryRowIndex+1, _srcQueryRowIndex.RowCount()-1,
_iSplitClientRowIndex+1, _srcClientRowIndex.RowCount()-1 );
//
// Now apply the watch regions on the new windows.
//
_CopyWatchRegions();
//
// Indicate that the split is done.
//
_pLeftWindow->_SetSplitDone();
_pRightWindow->_SetSplitDone();
//
// If any of the windows doesn't have any watch regions, we have to
// do a state change to delete the dynamic/static split.
//
Win4Assert( _pLeftWindow->IsWatched() || _pRightWindow->IsWatched() );
if ( !_pLeftWindow->IsWatched() )
{
_pLeftWindow->_EndStaticDynamicSplit();
}
if ( !_pRightWindow->IsWatched() )
{
_pRightWindow->_EndStaticDynamicSplit();
}
}
//
// Setup the lowest & highest keys for the left and right windows.
//
_srcWindow.GetSortKey( 0, _pLeftWindow->GetLowestKey() );
_srcWindow.GetSortKey( _iSplitQueryRowIndex+1, _pRightWindow->GetLowestKey() );
_srcWindow.GetSortKey( _iSplitQueryRowIndex, _pLeftWindow->GetHighestKey() );
_srcWindow.GetSortKey( (ULONG) _srcWindow.RowCount()-1, _pRightWindow->GetHighestKey() );
}
//+---------------------------------------------------------------------------
//
// Function: _CopyWithNotifications
//
// Synopsis: Copies contents of both the "visible" and "dynamic" row index
// from the source window to the destination window.
//
// Arguments: [destWindow] - Destination window to copy to.
// [iStartVisRowIndex] - Starting offset in the visible rowindex.
// [iEndVisRowIndex] - Ending offset in the visible rowindex.
// [iStartDynRowIndex] - Starting offset in the dynamic rowindex.
// [iEndDynRowIndex] - Ending offset in the dynamic rowindex.
//
// History: 1-09-95 srikants Created
//
// Notes:
//
//----------------------------------------------------------------------------
void CTableWindowSplit::_CopyWithNotifications( CTableWindow & destWindow,
ULONG iStartQueryRowIndex, ULONG iEndQueryRowIndex,
LONG iStartClientRowIndex, LONG iEndClientRowIndex )
{
Win4Assert( _srcWindow.IsWatched() );
Win4Assert( iStartQueryRowIndex < _srcQueryRowIndex.RowCount() );
Win4Assert( iEndQueryRowIndex >= iStartQueryRowIndex &&
iEndQueryRowIndex < _srcQueryRowIndex.RowCount() );
//
// Copy the rows from the client row index.
//
for ( LONG j = iStartClientRowIndex; j <= iEndClientRowIndex; j++ )
{
destWindow._PutRowToVisibleRowIndex( _srcWindow, _srcClientRowIndex.GetRow(j) );
}
//
// Copy the rows from the query row index.
//
for ( ULONG i = iStartQueryRowIndex; i <= iEndQueryRowIndex; i++ )
{
destWindow._PutRowToDynRowIndex( _srcWindow, _srcQueryRowIndex.GetRow(i) );
}
}
//+---------------------------------------------------------------------------
//
// Member: CTableWindowSplit::_IsOffsetInLeftWindow
//
// Synopsis:
//
// Arguments: [iOffset] -
//
// Returns:
//
// Modifies:
//
// History: 7-27-95 srikants Created
//
// Notes:
//
//----------------------------------------------------------------------------
inline
BOOL CTableWindowSplit::_IsOffsetInLeftWindow( long iOffset )
{
return iOffset <= _iSplitClientRowIndex;
}
//+---------------------------------------------------------------------------
//
// Member: CTableWindowSplit::_CopyWatchRegions
//
// Synopsis:
//
// Modifies:
//
// History: 7-27-95 srikants Created
//
// Notes:
//
//----------------------------------------------------------------------------
void CTableWindowSplit::_CopyWatchRegions()
{
Win4Assert( _srcWindow.IsWatched() );
for ( unsigned i = 0; i < _srcWindow._aWindowWatch.Count(); i++ )
{
CWindowWatch & watch = _srcWindow._aWindowWatch.Get(i);
long cResidual = watch._cRowsLeft;
if ( _IsOffsetInLeftWindow( watch._iRowStart ) )
{
cResidual -= _pLeftWindow->AddWatch( watch._hRegion,
watch._iRowStart,
cResidual,
FALSE );
if ( cResidual > 0 )
{
_pRightWindow->AddWatch( watch._hRegion,
0,
cResidual,
_fIsLastSegment );
}
}
else
{
//
// The offset must be in the right hand side window.
//
Win4Assert( watch._iRowStart > _iSplitClientRowIndex &&
watch._iRowStart < (long) _srcWindow.RowCount() );
Win4Assert( (long) _pLeftWindow->RowCount() == _iSplitClientRowIndex+1 );
_pRightWindow->AddWatch( watch._hRegion,
(LONG) (watch._iRowStart - _pLeftWindow->RowCount()),
cResidual,
_fIsLastSegment );
}
}
}