Renamed version4 to flaim and version5 to xflaim
git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@7 0109f412-320b-0410-ab79-c3e0c5ffbbe6
This commit is contained in:
641
flaim/src/fscomblk.cpp
Normal file
641
flaim/src/fscomblk.cpp
Normal file
@@ -0,0 +1,641 @@
|
||||
//-------------------------------------------------------------------------
|
||||
// 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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user