git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@7 0109f412-320b-0410-ab79-c3e0c5ffbbe6
642 lines
21 KiB
C++
642 lines
21 KiB
C++
//-------------------------------------------------------------------------
|
|
// Desc: B-tree block combining
|
|
// Tabs: 3
|
|
//
|
|
// Copyright (c) 1992-2006 Novell, Inc. All Rights Reserved.
|
|
//
|
|
// This program is free software; you can redistribute it and/or
|
|
// modify it under the terms of version 2 of the GNU General Public
|
|
// License as published by the Free Software Foundation.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program; if not, contact Novell, Inc.
|
|
//
|
|
// To contact Novell about this file by physical or electronic mail,
|
|
// you may find current contact information at www.novell.com
|
|
//
|
|
// $Id: fscomblk.cpp 12283 2006-01-19 14:53:15 -0700 (Thu, 19 Jan 2006) dsanders $
|
|
//-------------------------------------------------------------------------
|
|
|
|
#include "flaimsys.h"
|
|
|
|
FSTATIC FLMINT FSBlkCompressPKC(
|
|
BTSK_p pStack,
|
|
FLMBYTE * pTempPKCBuf);
|
|
|
|
|
|
/*
|
|
Desc: Build a PKC buffer for a single element
|
|
Return: Length used within the PKC buffer
|
|
*/
|
|
FINLINE FLMUINT FSElmBuildPKC(
|
|
FLMBYTE * pPkcBuf,
|
|
FLMBYTE * pElement,
|
|
FLMBYTE * pElmPkcBuf,
|
|
FLMUINT uiElmOvhd)
|
|
{
|
|
FLMUINT uiPkc;
|
|
FLMUINT uiKeyLen;
|
|
|
|
if( uiElmOvhd == BNE_DATA_OVHD)
|
|
return 0;
|
|
|
|
uiKeyLen = (FLMUINT)(BBE_GET_KL( pElement ));
|
|
|
|
if( (uiPkc = (FLMUINT)(BBE_GET_PKC( pElement))) != 0)
|
|
{
|
|
f_memmove( pPkcBuf, pElmPkcBuf, uiPkc );
|
|
}
|
|
if( uiPkc + uiKeyLen > BBE_PKC_MAX)
|
|
uiKeyLen = (FLMUINT)(BBE_PKC_MAX - uiPkc);
|
|
|
|
f_memmove( &pPkcBuf[ uiPkc ], &pElement[ uiElmOvhd ], uiKeyLen );
|
|
|
|
return( uiPkc + uiKeyLen);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
Desc: Try to combine two blocks into a single block. The algorithm will
|
|
alternate tring the block to the right or uiLeft of the 'target' block.
|
|
The bsCurElm MUST be positioned to the current element. The bsCurElm
|
|
may be at the very end of the block not pointing to an element. If
|
|
so then if blocks are combine bsCurElm should then be valid.
|
|
Notes: Remember that this can be called on any level of the btree.
|
|
****************************************************************************/
|
|
RCODE FSCombineBlks(
|
|
FDB * pDb,
|
|
LFILE * pLFile,
|
|
BTSK_p * pStackRV /* Stack may change on you */
|
|
)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
BTSK_p pStack = *pStackRV;
|
|
SCACHE * pLeftCache;
|
|
SCACHE * pRightCache;
|
|
FLMBYTE * pLeftBlk;
|
|
FLMBYTE * pRightBlk;
|
|
FLMBYTE * pBlk = pStack->pBlk;
|
|
FLMBOOL bReleaseLeft = FALSE;
|
|
FLMBOOL bReleaseRight = FALSE;
|
|
FLMUINT uiLeftBlkAddr;
|
|
FLMUINT uiRightBlkAddr;
|
|
FLMUINT uiLeftBlkEnd;
|
|
FLMUINT uiRightBlkEnd;
|
|
FLMUINT uiBlkAddr = pStack->uiBlkAddr;
|
|
FLMUINT uiBlkEnd = pStack->uiBlkEnd;
|
|
FLMUINT uiCurElm = pStack->uiCurElm;
|
|
FLMUINT uiElmOvhd = pStack->uiElmOvhd;
|
|
FLMUINT uiBlkSize;
|
|
FLMUINT uiPosToElm = 0;
|
|
FLMUINT uiPosToBlk = 0;
|
|
FLMUINT uiSplitPoint;
|
|
FLMUINT uiTargetSplitPoint;
|
|
FLMINT iTemp;
|
|
FLMINT iDelta;
|
|
BTSK tempStack;
|
|
FLMBYTE pPkcBuf[ BBE_PKC_MAX ];
|
|
DB_STATS * pDbStats;
|
|
|
|
f_yieldCPU(); /* NLM - release cpu */
|
|
|
|
/* Return if either block is leftmost or rightmost block */
|
|
uiLeftBlkAddr = (FLMUINT) FB2UD( &pBlk[ BH_PREV_BLK ]);
|
|
uiRightBlkAddr = (FLMUINT) FB2UD( &pBlk[ BH_NEXT_BLK ]);
|
|
if( ( uiLeftBlkAddr == BT_END) || ( uiRightBlkAddr == BT_END))
|
|
{
|
|
goto Exit; // Should return SUCCESS
|
|
}
|
|
|
|
uiBlkSize = pDb->pFile->FileHdr.uiBlockSize - uiElmOvhd;
|
|
|
|
/* Read in left and right blocks - make sure all cache ptrs are valid */
|
|
|
|
if( RC_BAD( rc = ScaGetBlock( pDb, pLFile, BHT_LEAF, uiLeftBlkAddr, NULL,
|
|
&pLeftCache)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
bReleaseLeft = TRUE;
|
|
|
|
if( RC_BAD( rc = ScaGetBlock( pDb, pLFile, BHT_LEAF, uiRightBlkAddr, NULL,
|
|
&pRightCache)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
bReleaseRight = TRUE;
|
|
|
|
/* Determine if there is room without compressing first elm in current blk*/
|
|
pLeftBlk = pLeftCache->pucBlk;
|
|
uiLeftBlkEnd = (FLMUINT) FB2UW( &pLeftBlk[ BH_BLK_END ]);
|
|
pRightBlk = pRightCache->pucBlk;
|
|
uiRightBlkEnd = (FLMUINT) FB2UW( &pRightBlk[ BH_BLK_END ]);
|
|
|
|
/* Don't want to fill too tight - so don't subtract BH_OVHD from sum */
|
|
if( uiLeftBlkEnd + uiBlkEnd + uiRightBlkEnd > uiBlkSize + uiBlkSize)
|
|
{
|
|
FSCB_Unpin:
|
|
if( bReleaseRight)
|
|
{
|
|
ScaReleaseCache( pRightCache, FALSE);
|
|
bReleaseRight = FALSE;
|
|
}
|
|
if( bReleaseLeft)
|
|
{
|
|
ScaReleaseCache( pLeftCache, FALSE);
|
|
bReleaseLeft = FALSE;
|
|
}
|
|
|
|
if( RC_OK( rc = FSGetBlock( pDb, pLFile, uiBlkAddr, pStack)))
|
|
{
|
|
pStack->uiCurElm = uiCurElm;
|
|
/* bsKeyBuf[] could have been wiped out in a scanTo call! */
|
|
FSBlkBuildPKC( pStack, pStack->pKeyBuf, FSBBPKC_AT_CURELM);
|
|
}
|
|
goto Exit;
|
|
}
|
|
|
|
/**---------------------------------------------------------------------
|
|
*** This is a very good yet extreamly tricky algorithm!
|
|
*** If the delta (difference in size) of the left and right blocks
|
|
*** is more than the size of the middle block the entire middle will
|
|
*** will be moved to the left or right block that is not very full.
|
|
*** Otherwise, uiTargetSplitPoint will be computed to be around the
|
|
*** point that will place elements in both blocks to fill the left
|
|
*** and right blocks to about the same point.
|
|
*** NOTE: Read the comments if all is fuzzy.
|
|
***--------------------------------------------------------------------*/
|
|
|
|
iTemp = uiBlkEnd - BH_OVHD + BBE_PKC_MAX; /* temp is max. bytes to move */
|
|
uiTargetSplitPoint = 0;
|
|
|
|
if( uiLeftBlkEnd < uiRightBlkEnd ) /* Put most in the left block */
|
|
{
|
|
iDelta = uiRightBlkEnd - uiLeftBlkEnd;
|
|
if( iTemp <= iDelta)
|
|
pStack->uiCurElm = uiBlkEnd; /* Put all in the left block */
|
|
else
|
|
uiTargetSplitPoint = BH_OVHD + iDelta + ((iTemp - iDelta) >> 1);
|
|
}
|
|
else /* Put most in the right block */
|
|
{
|
|
iDelta = uiLeftBlkEnd - uiRightBlkEnd;
|
|
if( iTemp <= iDelta )
|
|
pStack->uiCurElm = BH_OVHD; /* Put all in right block */
|
|
else
|
|
uiTargetSplitPoint = BH_OVHD + ((iTemp - iDelta) >> 1);
|
|
}
|
|
|
|
if( uiTargetSplitPoint) /* If try to divide into both blocks */
|
|
{
|
|
pStack->uiCurElm = uiTargetSplitPoint;
|
|
|
|
/* Scan AFTER targetSplitPoint */
|
|
if( RC_BAD(rc = FSBtScanTo( pStack, NULL, 0, 0)))
|
|
goto Exit;
|
|
|
|
/**-----------------------------------------------------------------
|
|
*** Last check to see if elements will fit in both blocks.
|
|
*** This is still a chance that all elements will go to one block
|
|
***----------------------------------------------------------------*/
|
|
if( ( uiLeftBlkEnd + (pStack->uiCurElm - BH_OVHD) > uiBlkSize ) ||
|
|
( uiRightBlkEnd + (uiBlkEnd - pStack->uiCurElm) + BBE_PKC_MAX > uiBlkSize ))
|
|
goto FSCB_Unpin;
|
|
}
|
|
|
|
/* We are now guarenteed to fit!!! - log blocks and start moving */
|
|
|
|
if( (pDbStats = pDb->pDbStats) != NULL)
|
|
{
|
|
LFILE_STATS * pLFileStats;
|
|
|
|
if( (pLFileStats = fdbGetLFileStatPtr( pDb, pLFile)) != NULL)
|
|
{
|
|
pLFileStats->bHaveStats =
|
|
pDbStats->bHaveStats = TRUE;
|
|
pLFileStats->ui64BlockCombines++;
|
|
}
|
|
}
|
|
|
|
if( RC_BAD( rc = ScaLogPhysBlk( pDb, &pLeftCache )))
|
|
goto Exit;
|
|
pLeftBlk = pLeftCache->pucBlk;
|
|
|
|
uiSplitPoint = pStack->uiCurElm;
|
|
if( uiSplitPoint != BH_OVHD ) /* Elements to move into LEFT block? */
|
|
{
|
|
FLMUINT uiCompressBytes;
|
|
FLMUINT uiBytesAdded = uiSplitPoint - BH_OVHD;
|
|
|
|
tempStack.pSCache = pLeftCache;
|
|
tempStack.pBlk = pLeftCache->pucBlk;
|
|
FSBlkToStack( &tempStack );
|
|
tempStack.uiKeyBufSize = MAX_KEY_SIZ;
|
|
|
|
/* Algorithm could call the move routine if it wasn't for uiCompressBytes */
|
|
f_memmove( &pLeftBlk[ uiLeftBlkEnd ], &pBlk[ BH_OVHD ], uiBytesAdded );
|
|
tempStack.uiCurElm = uiLeftBlkEnd;
|
|
|
|
uiLeftBlkEnd += uiBytesAdded;
|
|
tempStack.uiBlkEnd = uiLeftBlkEnd;
|
|
UW2FBA( uiLeftBlkEnd, &pLeftBlk[ BH_BLK_END ]);
|
|
|
|
uiCompressBytes = FSBlkCompressPKC( &tempStack, pPkcBuf );
|
|
if( uiCompressBytes == 0xFFFF) /* Special case that shouldn't happen. */
|
|
{
|
|
rc = RC_SET( FERR_DATA_ERROR);
|
|
goto Exit;
|
|
}
|
|
if( uiCurElm < uiSplitPoint )
|
|
{
|
|
uiPosToBlk = uiLeftBlkAddr;
|
|
uiPosToElm = (FLMUINT)((uiLeftBlkEnd - uiBytesAdded) + uiCurElm - BH_OVHD);
|
|
|
|
// NOTE: uiCompressBytes should be zero for fixed element blocks - see
|
|
// FSBlkCompressPKC
|
|
|
|
if( uiCurElm != BH_OVHD )
|
|
uiPosToElm -= uiCompressBytes;
|
|
}
|
|
}
|
|
UD2FBA( uiRightBlkAddr, &pLeftBlk[ BH_NEXT_BLK ] );
|
|
ScaReleaseCache( pLeftCache, FALSE);
|
|
bReleaseLeft = FALSE;
|
|
|
|
/**-------------------------------------------------------------------
|
|
*** WOW - done with the left block. Move the rest of the data
|
|
*** into the right block. Be carefull to compress the first
|
|
*** element of the right block and decompress the element that
|
|
*** is at the split point in the middle (deleted) block.
|
|
***------------------------------------------------------------------*/
|
|
|
|
if( RC_BAD( rc = ScaLogPhysBlk( pDb, &pRightCache )))
|
|
goto Exit;
|
|
pRightBlk = pRightCache->pucBlk;
|
|
|
|
if( uiSplitPoint != uiBlkEnd ) /* Elements to move into RIGHT block? */
|
|
{
|
|
FLMBYTE * pSplitPoint = &pBlk[ uiSplitPoint ];
|
|
tempStack.pSCache = pRightCache;
|
|
tempStack.pBlk = pRightCache->pucBlk;
|
|
FSBlkToStack( &tempStack );
|
|
tempStack.uiKeyBufSize = MAX_KEY_SIZ;
|
|
|
|
/* Setup to position to current block and element at end of routine */
|
|
if( uiCurElm >= uiSplitPoint )
|
|
{
|
|
uiPosToBlk = uiRightBlkAddr;
|
|
uiPosToElm = (FLMUINT)((uiCurElm - uiSplitPoint) + BH_OVHD);
|
|
|
|
// No PKC in fixed element blocks.
|
|
|
|
if( uiCurElm != uiSplitPoint && tempStack.uiElmOvhd != BNE_DATA_OVHD)
|
|
{
|
|
uiPosToElm += BBE_GET_PKC( pSplitPoint );
|
|
}
|
|
}
|
|
/**---------------------------------------------------------------
|
|
*** If ScanTo() doesn't match uiCurElm exact then current element
|
|
*** does not have the proper stuff in the pkc buffer or bsKeyBuf
|
|
***--------------------------------------------------------------*/
|
|
/* pStack->uiCurElm is uiSplitPoint */
|
|
FSBlkBuildPKC( pStack, pPkcBuf, FSBBPKC_AT_CURELM );
|
|
if( RC_BAD( rc = FSBlkMoveElms( &tempStack, pSplitPoint,
|
|
(FLMUINT)(uiBlkEnd - uiSplitPoint), pPkcBuf )))
|
|
goto Exit;
|
|
}
|
|
|
|
UD2FBA( uiLeftBlkAddr, &pRightBlk[ BH_PREV_BLK ] );
|
|
ScaReleaseCache( pRightCache, FALSE);
|
|
bReleaseRight = FALSE;
|
|
|
|
/* Now we can free the current block - blkFixLinks may work instead */
|
|
|
|
rc = FSBlockFree( pDb, pStack->pSCache);
|
|
pStack->pSCache = NULL;
|
|
pStack->pBlk = NULL;
|
|
if( RC_BAD( rc))
|
|
return( rc );
|
|
|
|
/**----------------------------------------------------------------------
|
|
*** Now the hard part. Go to the parent & delete the current element.
|
|
*** Go to the previous element and modify to reflect the new last
|
|
*** element in the left block.
|
|
***---------------------------------------------------------------------*/
|
|
|
|
if( RC_BAD( rc = FSDelParentElm( pDb, pLFile, &pStack )))
|
|
return( rc );
|
|
|
|
if( uiSplitPoint != BH_OVHD ) /* Is there is new stuff in left blk?*/
|
|
{
|
|
/* Position and fixup the parent elements */
|
|
if( RC_OK(rc = FSGetBlock( pDb, pLFile, uiLeftBlkAddr, pStack)))
|
|
{
|
|
rc = FSNewLastBlkElm( pDb, pLFile, &pStack,
|
|
FSNLBE_GREATER | FSNLBE_POSITION );
|
|
}
|
|
}
|
|
|
|
/**------------------------------------------------------
|
|
*** Position the pStack to where you should be.
|
|
*** The parent element is pointing to the right block.
|
|
***-----------------------------------------------------*/
|
|
if( RC_OK( rc ))
|
|
{
|
|
/* Read in position block and position to current element */
|
|
if( RC_OK(rc = FSGetBlock( pDb, pLFile, uiPosToBlk, pStack)))
|
|
{
|
|
pStack->uiCurElm = uiPosToElm;
|
|
if( uiPosToBlk == uiLeftBlkAddr )
|
|
{
|
|
rc = FSAdjustStack( pDb, pLFile, pStack, FALSE);
|
|
}
|
|
/**--------------------------------------------
|
|
*** This line must be explained!
|
|
*** We should really be replacing the original
|
|
*** PKC buffer into what was there before this
|
|
*** routine was called. This works because
|
|
*** delete/insert pairs call scanTo before the
|
|
*** insert.
|
|
***--------------------------------------------*/
|
|
FSBlkBuildPKC( pStack, pStack->pKeyBuf, FSBBPKC_AT_CURELM );
|
|
}
|
|
}
|
|
*pStackRV = pStack;
|
|
Exit:
|
|
if( bReleaseLeft)
|
|
{
|
|
ScaReleaseCache( pLeftCache, FALSE);
|
|
}
|
|
if( bReleaseRight)
|
|
{
|
|
ScaReleaseCache( pRightCache, FALSE);
|
|
}
|
|
return( rc );
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Move 1 or more elements into the bsCurElm location within a block.
|
|
Everything MUST fit. Will compress the element coming in as well
|
|
as the element at bsCurElm. This will also work if you are moving
|
|
data down within the same block.
|
|
****************************************************************************/
|
|
RCODE FSBlkMoveElms(
|
|
BTSK_p pStack, /* Stack containing block to accept data*/
|
|
FLMBYTE * pInsertElm, /* Element(s) to insert into block */
|
|
FLMUINT uiInsElmLen, /* Length of the Element(s) */
|
|
FLMBYTE * pElmPkcBuf /* PKC buffer for element if elm has PKC*/
|
|
)
|
|
{
|
|
FLMBYTE * pBlk = pStack->pBlk;
|
|
FLMUINT uiCurElm = pStack->uiCurElm;
|
|
FLMUINT uiElmOvhd = pStack->uiElmOvhd;
|
|
FLMUINT uiBytesInPkc;
|
|
|
|
FLMBYTE pInsertElmPckBuf[ BBE_PKC_MAX ];
|
|
FLMUINT uiMovedKeyLen, uiMovedPkc;
|
|
FLMUINT uiTemp;
|
|
FLMUINT uiNewBlkEnd;
|
|
FLMUINT uiInsertElmKeyLen;
|
|
FLMINT iDistanceToShiftDown;
|
|
FLMUINT uiAreaToShiftDown;
|
|
FLMBYTE pPkcBuf[ BBE_PKC_MAX ];
|
|
FLMUINT uiInsertElmPkc;
|
|
FLMUINT uiInsertElmPkcLen;
|
|
|
|
if( uiElmOvhd == BNE_DATA_OVHD)
|
|
{
|
|
if( (uiAreaToShiftDown = (pStack->uiBlkEnd - uiCurElm)) > 0)
|
|
{
|
|
shiftN( &pBlk[ uiCurElm ], uiAreaToShiftDown, uiInsElmLen);
|
|
}
|
|
f_memmove( &pBlk[ uiCurElm], pInsertElm, uiInsElmLen);
|
|
pStack->uiBlkEnd += uiInsElmLen;
|
|
UW2FBA( pStack->uiBlkEnd, &pBlk[ BH_BLK_END ]);
|
|
goto Exit;
|
|
}
|
|
|
|
// ELSE Normal complex move with previos key count (PKC)
|
|
|
|
/* Puts up to BBE_PKC_MAX bytes in pPkcBuf[] only */
|
|
uiBytesInPkc = FSBlkBuildPKC( pStack, pPkcBuf, FSBBPKC_BEFORE_CURELM );
|
|
|
|
/* Compute real pkc for element */
|
|
uiInsertElmPkcLen = FSElmBuildPKC( pInsertElmPckBuf, pInsertElm, pElmPkcBuf, uiElmOvhd );
|
|
|
|
uiMovedPkc = FSElmComparePKC( pPkcBuf, uiBytesInPkc, pInsertElmPckBuf, uiInsertElmPkcLen );
|
|
|
|
/**----------------------------------------------------------------
|
|
*** Compute how much area pInsertElm[] will take when moved,
|
|
*** compute uiBlkEnd and move most of the element except the key
|
|
***---------------------------------------------------------------*/
|
|
uiInsertElmKeyLen = (FLMUINT)(BBE_GET_KL( pInsertElm ));
|
|
uiInsertElmPkc = (FLMUINT)(BBE_GET_PKC( pInsertElm ));
|
|
uiMovedKeyLen = (FLMUINT)(uiInsertElmKeyLen + uiInsertElmPkc - uiMovedPkc);
|
|
iDistanceToShiftDown = (FLMINT)(uiInsElmLen + uiMovedKeyLen - uiInsertElmKeyLen);
|
|
if( (uiAreaToShiftDown = (FLMUINT)(pStack->uiBlkEnd - uiCurElm)) > 0)
|
|
{
|
|
shiftN( &pBlk[ uiCurElm ], uiAreaToShiftDown, iDistanceToShiftDown );
|
|
}
|
|
|
|
uiNewBlkEnd = (FLMUINT)(pStack->uiBlkEnd + iDistanceToShiftDown);
|
|
UW2FBA( uiNewBlkEnd, &pBlk[ BH_BLK_END ]);
|
|
pStack->uiBlkEnd = uiNewBlkEnd;
|
|
|
|
/* Move the first pInsertElm[] overhead values and key to where to be inserted*/
|
|
FSSetElmOvhd( &pBlk[uiCurElm], uiElmOvhd, uiMovedPkc, uiMovedKeyLen, pInsertElm);
|
|
|
|
/**--------------------------------------------------------------
|
|
*** The tricky part is to move the key!
|
|
*** The key could move in 2 parts pInsertElmPckBuf and pInsertElm[]
|
|
***-------------------------------------------------------------*/
|
|
|
|
if( uiMovedKeyLen + uiMovedPkc > BBE_PKC_MAX ) /* Key not entirely in pPkcBuf[] */
|
|
{
|
|
/* Move all that is in the pPkcBuf[] */
|
|
f_memcpy( &pBlk[ uiCurElm + uiElmOvhd ],
|
|
&pInsertElmPckBuf[ uiMovedPkc ],
|
|
uiTemp = (FLMUINT)(BBE_PKC_MAX - uiMovedPkc) );
|
|
|
|
/* Move the rest that is in the element */
|
|
f_memmove( &pBlk[ uiCurElm + uiElmOvhd + uiTemp ],
|
|
&pInsertElm[ uiElmOvhd + uiInsertElmKeyLen - (uiMovedKeyLen - uiTemp) ],
|
|
uiMovedKeyLen - uiTemp );
|
|
}
|
|
else if( uiMovedKeyLen)
|
|
{
|
|
/* Entire key fits within the pPkcBuf[] */
|
|
f_memcpy( &pBlk[ uiCurElm + uiElmOvhd ],
|
|
&pInsertElmPckBuf[ uiMovedPkc ], uiMovedKeyLen );
|
|
}
|
|
/* Move the rest of the element(s) over to the block */
|
|
uiTemp = uiElmOvhd + uiInsertElmKeyLen;
|
|
f_memmove( &pBlk[ uiCurElm + uiElmOvhd + uiMovedKeyLen ], /* Better move HIGH-LOW */
|
|
&pInsertElm[ uiTemp ], uiInsElmLen - uiTemp );
|
|
|
|
/**---------------------------------------------------------------
|
|
*** Now - if uiAreaToShiftDown has a value then position to the
|
|
*** old uiCurElm and try to compress more out of the element
|
|
***--------------------------------------------------------------*/
|
|
|
|
if( uiAreaToShiftDown)
|
|
{
|
|
pStack->uiCurElm = uiCurElm + iDistanceToShiftDown;
|
|
/* Could change pStack->wBlkEnd */
|
|
FSBlkCompressPKC( pStack, pPkcBuf );
|
|
}
|
|
pStack->uiCurElm = uiCurElm; /* Points to start of inserted element(s) */
|
|
|
|
Exit:
|
|
return( FERR_OK );
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Build the PKC portion scanning in a block to but not
|
|
including pStack->uiCurElm
|
|
Notes: General routine for split and combine code.
|
|
More setup needed if you are calling FSBtInsert() or FSBlkInsElm().
|
|
This routine is fastest known way to build PKC from any element.
|
|
****************************************************************************/
|
|
FLMUINT FSBlkBuildPKC(
|
|
BTSK_p pStack,
|
|
FLMBYTE * pPkcBuf,
|
|
FLMUINT uiFlags
|
|
)
|
|
{
|
|
FLMUINT uiMoveArea;
|
|
FLMUINT uiPkc;
|
|
FLMUINT uiTargetCurElm;
|
|
FLMUINT uiElmOvhd = pStack->uiElmOvhd;
|
|
FLMUINT uiCurElm;
|
|
FLMUINT uiElmKeyLen;
|
|
FLMBYTE * pCurElm;
|
|
|
|
if( uiElmOvhd == BNE_DATA_OVHD)
|
|
{
|
|
return 0;
|
|
}
|
|
/* Code below is fastest way to position to bsCurElm */
|
|
uiTargetCurElm = pStack->uiCurElm;
|
|
uiMoveArea = uiPkc = 0;
|
|
uiCurElm = BH_OVHD;
|
|
while( uiCurElm < uiTargetCurElm)
|
|
{
|
|
FSBB_one_more_time:
|
|
|
|
pCurElm = &pStack->pBlk[ uiCurElm ];
|
|
uiElmKeyLen = (FLMUINT)(BBE_GET_KL( pCurElm));
|
|
if( uiElmKeyLen )
|
|
{
|
|
/* Move minimum data over to the pPkcBuf[] */
|
|
uiPkc = (FLMUINT)(BBE_GET_PKC( pCurElm ));
|
|
uiMoveArea = ((uiPkc + uiElmKeyLen) > BBE_PKC_MAX)
|
|
? (BBE_PKC_MAX - uiPkc)
|
|
: uiElmKeyLen;
|
|
|
|
/* Most common uiMoveArea value for data records & numeric keys */
|
|
if( uiMoveArea == 1)
|
|
pPkcBuf[ uiPkc ] = pCurElm[ uiElmOvhd ];
|
|
else if( uiMoveArea )
|
|
{
|
|
f_memmove( &pPkcBuf[ uiPkc ], &pCurElm[ uiElmOvhd ], uiMoveArea);
|
|
}
|
|
}
|
|
|
|
if( pStack->uiBlkType == BHT_LEAF)
|
|
{
|
|
/* Goto the next element in the block */
|
|
uiCurElm += BBE_GET_RL( pCurElm);
|
|
}
|
|
else if( BNE_IS_DOMAIN( pCurElm)) /* Non-leaf block */
|
|
{
|
|
uiCurElm += BNE_DOMAIN_LEN;
|
|
}
|
|
uiCurElm += uiElmOvhd + uiElmKeyLen;
|
|
}
|
|
|
|
/* Hit the target current element */
|
|
if( uiFlags == FSBBPKC_AT_CURELM)
|
|
{
|
|
/* Copy the current element into the pPkcBuf[] */
|
|
uiFlags = FSBBPKC_BEFORE_CURELM;
|
|
goto FSBB_one_more_time;
|
|
}
|
|
|
|
return( uiPkc + uiMoveArea);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Compress out (or in) the PKC bytes in the current element
|
|
Notes: pTempPkcBuf passed in only to save pStack space.
|
|
****************************************************************************/
|
|
FSTATIC FLMINT FSBlkCompressPKC(
|
|
BTSK_p pStack,
|
|
FLMBYTE * pTempPkcBuf
|
|
)
|
|
{
|
|
FLMUINT uiTempPkcLen;
|
|
FLMUINT uiPkcBufLen;
|
|
FLMUINT uiCurPkc, uiTruePkc;
|
|
FLMINT iCompressBytes = 0;
|
|
FLMBYTE * pCurElm;
|
|
FLMBYTE pPkcBuf[ BBE_PKC_MAX ];
|
|
|
|
if( pStack->uiElmOvhd == BNE_DATA_OVHD)
|
|
goto Exit;
|
|
|
|
/* Build the PKC buffer from the block */
|
|
uiTempPkcLen = FSBlkBuildPKC( pStack, pTempPkcBuf, FSBBPKC_BEFORE_CURELM);
|
|
|
|
/**-------------------------------------------------------
|
|
*** Position to the current element and build its own
|
|
*** pkc buffer. Compare and see if equals the current
|
|
*** element's pkc value. If not compress/decompress
|
|
***------------------------------------------------------*/
|
|
|
|
pCurElm = &pStack->pBlk[ pStack->uiCurElm ];
|
|
uiCurPkc = (FLMUINT)(BBE_GET_PKC( pCurElm));
|
|
uiPkcBufLen = FSElmBuildPKC( pPkcBuf, pCurElm, pTempPkcBuf, pStack->uiElmOvhd);
|
|
|
|
uiTruePkc = FSElmComparePKC( pTempPkcBuf, uiTempPkcLen, pPkcBuf, uiPkcBufLen);
|
|
|
|
if( uiTruePkc != uiCurPkc)
|
|
{
|
|
FLMBYTE * pBlk = pStack->pBlk;
|
|
FLMUINT uiCurElm = pStack->uiCurElm;
|
|
FLMUINT uiBlkEnd = pStack->uiBlkEnd;
|
|
FLMUINT uiElmOvhd = pStack->uiElmOvhd;
|
|
FLMUINT keyLen = (FLMUINT)(BBE_GET_KL(pCurElm));
|
|
FLMUINT uiTemp;
|
|
|
|
if( uiTruePkc > uiCurPkc)
|
|
{
|
|
/* Need to compress out some more bytes */
|
|
iCompressBytes = uiTruePkc - uiCurPkc;
|
|
uiTemp = uiCurElm + uiElmOvhd + iCompressBytes;
|
|
shiftN( &pBlk[ uiTemp ], (FLMUINT)(uiBlkEnd - uiTemp),
|
|
(FLMINT)(-iCompressBytes));
|
|
|
|
/* Reassign the element overhead */
|
|
FSSetElmOvhd( pCurElm, uiElmOvhd,
|
|
(FLMUINT)(uiCurPkc + iCompressBytes),
|
|
(FLMUINT)(keyLen - iCompressBytes),
|
|
pCurElm);
|
|
uiBlkEnd -= iCompressBytes;
|
|
}
|
|
else /* uiTruePkc < uiCurPkc */
|
|
{
|
|
return( 0xFFFF); /* FERR_BTREE_ERROR Cannot ever happen right now */
|
|
}
|
|
UW2FBA( uiBlkEnd, &pBlk[ BH_BLK_END ]);
|
|
pStack->uiBlkEnd = uiBlkEnd;
|
|
}
|
|
Exit:
|
|
return( iCompressBytes);
|
|
}
|
|
|