Files
mars-flaim/flaim/src/fsdelelm.cpp
dsandersoremutah c55dab446f 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
2006-01-27 21:06:39 +00:00

738 lines
22 KiB
C++

//-------------------------------------------------------------------------
// Desc: Delete element from b-tree block.
// Tabs: 3
//
// Copyright (c) 1991-2001,2003-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: fsdelelm.cpp 12284 2006-01-19 14:54:14 -0700 (Thu, 19 Jan 2006) dsanders $
//-------------------------------------------------------------------------
#include "flaimsys.h"
/***************************************************************************
Desc: Delete the current element from a b-tree block and write block.
The stack must point to the next element after the deleted element.
The next element could be in a different block so be careful.
Notes: The order of the high level if's is VERY important.
The order of changing the blocks is not important because of logging.
*****************************************************************************/
RCODE FSBtDelete(
FDB * pDb,
LFILE * pLFile,
BTSK_p * pStackRV
)
{
RCODE rc;
BTSK_p pStack = *pStackRV;
SCACHE * pTmpSCache;
FLMBYTE * pBlk;
FLMBOOL bReleaseTmpCache = FALSE;
FLMUINT uiNextBlk;
FLMUINT uiPrevBlk;
FLMUINT uiLastElm; /* Offset of last element in a block */
FLMUINT uiElmOvhd = pStack->uiElmOvhd;
FLMBYTE pLEMBuffer[ 12 ]; /* Last element marker buffer */
/* Log block before modifying it */
if( RC_BAD( rc = FSLogPhysBlk( pDb, pStack)))
goto Exit;
// If this is a non-leaf positioning index, update parent counts.
if( pLFile->pIxd && (pLFile->pIxd->uiFlags & IXD_POSITIONING))
{
if( pStack->uiLevel)
{
FLMUINT uiRefCount;
FLMBYTE * pElm = pStack->pBlk + pStack->uiCurElm;
// Reduce the counts from the parent up.
uiRefCount = FB2UD( &pElm[ BNE_CHILD_COUNT]);
if( RC_BAD( rc = FSChangeBlkCounts( pDb, pStack,
(FLMINT) (0 - uiRefCount) )))
{
goto Exit;
}
}
}
if( RC_BAD(rc = FSBlkDelElm( pStack )))
goto Exit;
/**
*** Take care of deletion of the ONLY element in the block.
*** There is NO WAY this could be a root or right end block because
*** of the last element marker (LEM) takes up 2 or 4 bytes
**/
if( pStack->uiBlkEnd == BH_OVHD)
{
/**
*** Free up this empty block and fixup the NEXT/PREV links.
**/
uiNextBlk = FB2UD( &pStack->pBlk[ BH_NEXT_BLK ]);
rc = FSBlockFixLinks( pDb, pLFile, pStack->pSCache);
pStack->pSCache = NULL;
pStack->pBlk = NULL;
if( RC_BAD( rc))
goto Exit;
/**
*** Remove the element that pointed to this block
**/
if( RC_OK( rc = FSDelParentElm( pDb, pLFile, &pStack )))
{
pStack->uiBlkAddr = uiNextBlk;
/* Read the next block and set stack to point to next element */
if( RC_OK(rc = FSGetBlock( pDb, pLFile, uiNextBlk, pStack)))
{
pStack->uiCurElm = BH_OVHD;
/**------------------------------------------------------------
*** Added 07/15/93
*** Need to reset keybuf[] for deletes in a while loop like the
*** data record delete code in fsrecupd.c.
*** This may be cause of some corruptions while deleting
*** lots of records.
***-----------------------------------------------------------*/
FSBlkBuildPKC( pStack, pStack->pKeyBuf, FSBBPKC_AT_CURELM );
}
}
*pStackRV = pStack;
}
/** Deleting a RIGHT MOST B-tree block (along the right side).
*** Check if only the LEM (last element marker) is left in the block.
*** A block CANNOT contain just a LEM. Move the LEM & free the block.
***
*** There are 3 cases to watch for:
*** EMPTY B-TREE - free the root/block save next record in lfArea
*** EMPTY ROOT - free root and goto child & make that root
*** EMPTY BLOCK - cannot contain only a LEM - move to previous block
***
*** Must not move LASST DRN Marker - there is no need to do this.
***
**/
else if( (FB2UD( &pStack->pBlk[ BH_NEXT_BLK ]) == BT_END)
&& ( (pStack->uiBlkEnd == BH_OVHD + uiElmOvhd )
// || ( (pLFile->uiLfType == LF_CONTAINER)
// && (stack->uiBlkEnd == BH_OVHD + DRN_LAST_MARKER_LEN+ uiElmOvhd)
// && (stack->uiBlkType == BHT_LEAF)
) ) //)
{
/**
*** EMPTY B-TREE
*** Level is not in the current LFILE version so check if the root
*** block is the same as this block.
**/
if( (pStack->uiBlkType == BHT_LEAF)
&& (pLFile->uiRootBlk == pStack->uiBlkAddr )) /* Root is leaf */
{
/**
*** Return the empty root block to the system
*** Code (11/26/91) supports empty b-trees. We have gone back
*** and forth on returning empty root blocks to the system.
*** Setup stack for emtpy state and modify the LFILE on disk.
***
*** The data record b-tree can NEVER be empty because of
*** the next record DRN record should always hang around.
***
*** ALL CALLING ROUTINES MUST CHECK for( STACK->uiBlkAddr == BT_END)
**/
pStack->uiBlkAddr = BT_END;
{
/* Get the next DRN and save in the LFD */
FLMBYTE * ptr = &pStack->pBlk[ BH_OVHD ];
ptr += BBE_GETR_KL( ptr ) + BBE_KEY;
pLFile->uiNextDrn = (FLMUINT) FB2UD( ptr);
}
rc = FSBlockFree( pDb, pStack->pSCache);
pStack->pSCache = NULL;
pStack->pBlk = NULL;
if( RC_BAD( rc))
goto Exit;
pLFile->uiRootBlk = BT_END;
rc = flmLFileWrite( pDb, pLFile);
}
/**
*** EMPTY ROOT BLOCK
***
*** Remove root block and set new root block to child.
**/
else if( pLFile->uiRootBlk == pStack->uiBlkAddr)
{
// Obtain child block and set to lfArea to assign new root block
uiNextBlk = FSChildBlkAddr( pStack );
rc = FSBlockFree( pDb, pStack->pSCache);
pStack->pSCache = NULL;
pStack->pBlk = NULL;
if( RC_BAD( rc))
{
goto Exit;
}
pLFile->uiRootBlk = uiNextBlk;
if( RC_BAD( rc = flmLFileWrite( pDb, pLFile)))
{
goto Exit;
}
// Assign the new root block
if( RC_BAD( rc = ScaGetBlock( pDb, pLFile, BHT_LEAF,
uiNextBlk, NULL, &pTmpSCache)))
{
goto Exit;
}
bReleaseTmpCache = TRUE;
if( RC_BAD( rc = ScaLogPhysBlk( pDb, &pTmpSCache)))
{
goto Exit;
}
// Set the root block flag on this block & mark dirty
BH_SET_ROOT_BLK( pTmpSCache->pucBlk );
ScaReleaseCache( pTmpSCache, FALSE);
bReleaseTmpCache = FALSE;
/**
*** Date Added: 8/19/93
*** It is possible to add an element so that a new root block
*** gets created AND THEN Deleted. I saw this on OS2 when they
*** got up to 6 levels in the btree. Because of this the ROOT
*** block in the stack MUST always be pStack[0].
*** The three lines below do this. Tested on Brad Daw's db.
**/
shiftN( (FLMBYTE *) pStack + sizeof(BTSK),
sizeof(BTSK) * pStack->uiLevel, /* think uiLevel + 1 - 1 */
0-(sizeof(BTSK)));
/*
We don't want a pointer to the same shared cache in two different
elements of the pStack. NULL out the one that was moved down.
*/
(pStack + pStack->uiLevel + 1)->pSCache = NULL;
(pStack + pStack->uiLevel + 1)->pBlk = NULL;
pStack--; /* Point 1 element BEFORE stack starts ! */
*pStackRV = pStack;
/* Don't worry about positioning to the next element - root gone */
}
else
{
/**
*** ONLY LAST ELEMENT MARKER (LEM) REMAINS
*** (leaf or (non-leaf but NOT ROOT))
*** A block must NEVER contain only the last element marker (LEM).
*** This may free up a leaf block or a non-leaf block but never
*** a root block (root checks above.)
***
*** This is the most complex case.
*** Move the last element marker (LEM) to the end of the
*** previous block. Be carefull to delete the
*** correct element in the parent block.
*** The algorithm states that there MUST ALWAYS be room to insert
*** the LEM into a block without splitting that block.
***
*** Because of logging the block modifications do not need to be
*** flushed in a specific order to prevent corruption.
*/
uiPrevBlk = FB2UD( &pStack->pBlk[ BH_PREV_BLK ]);
/* Save the last element marker, may be a non-leaf element */
f_memcpy( pLEMBuffer, &pStack->pBlk[ BH_OVHD ], uiElmOvhd );
/* Free the block */
rc = FSBlockFree( pDb, pStack->pSCache);
pStack->pSCache = NULL;
pStack->pBlk = NULL;
if( RC_BAD( rc))
goto Exit;
/* Pop stack - point to parent */
pStack--;
/**
*** Modify the parent blocks last element marker (LEM) to point to
*** the new last block. THEN delete the previous element that
*** also points to the new last block.
**/
/* Read the parent block */
if( RC_BAD( rc = FSGetBlock( pDb, pLFile,
pStack->uiBlkAddr, pStack)))
{
goto Exit;
}
if( RC_BAD( rc = FSLogPhysBlk( pDb, pStack)))
{
goto Exit;
}
/* Change where element points to in the last element marker (LEM) */
FSSetChildBlkAddr( BLK_ELM_ADDR( pStack, pStack->uiCurElm),
uiPrevBlk, pStack->uiElmOvhd );
/* FSBtPrevElm may return -1 which is NOT OK */
if( RC_BAD( rc = FSBtPrevElm( pDb, pLFile, pStack)))
{
rc = (rc == FERR_BT_END_OF_DATA)
? RC_SET( FERR_BTREE_ERROR)
: rc ;
goto Exit;
}
/* Delete the element that points to the new last block */
if( RC_BAD( rc = FSBtDelete( pDb, pLFile, &pStack)))
goto Exit;
pStack++;
/**
*** Read in the new last block
*** Move in the old LEM to the end of the block
*** Position pStack to LEM
**/
if( RC_BAD( rc = FSGetBlock( pDb, pLFile, uiPrevBlk, pStack)))
{
goto Exit;
}
/* Log block before modifying */
if( RC_BAD( rc = FSLogPhysBlk( pDb, pStack)))
goto Exit;
pBlk = pStack->pBlk;
/* Set the pStack elements */
uiLastElm = pStack->uiBlkEnd;
pStack->uiCurElm = uiLastElm;
/* Place the LEM (last element marker) in the block */
f_memcpy( &pBlk[ uiLastElm ], pLEMBuffer, uiElmOvhd );
/* Set next block pointer to BT_END */
UD2FBA( BT_END, &pBlk[ BH_NEXT_BLK ]);
/* Adjust end pointers */
pStack->uiBlkEnd = uiLastElm + uiElmOvhd;
UW2FBA( (FLMUINT16)pStack->uiBlkEnd, &pBlk[ BH_BLK_END ]);
*pStackRV = pStack;
}
}
/**
*** Deleted the LAST (but NOT ONLY) element in the block.
*** The parent block must have its current element changed to reflect
*** the new last element key in this block. The algoritm MUST insert
*** the next last element key and THEN delete the old key or
*** you may have a new root block which is your next block!
*** Comentary: Some b-tree algorithms have key markers that are shorter
*** in the non-leaf blocks. This right-end non-leaf trunctaion is a
*** very good idea, but ALL of the b-tree code has to conform to this
*** rule and it is not a trivial thing to support.
*/
else if( pStack->uiBlkEnd == pStack->uiCurElm)
{
pBlk = pStack->pBlk;
/* Double check in case of corrupt this is not a right most block */
if( FB2UD( &pBlk[ BH_NEXT_BLK ]) != BT_END)
{
rc = FSNewLastBlkElm( pDb, pLFile, &pStack,
FSNLBE_LESS | FSNLBE_POSITION );
*pStackRV = pStack;
}
}
/**
*** Else - normal delete - everything should be correct and the
*** stack is positioned to the next element after the deleted element.
*** The pKeyBuf[] however, is NOT always set to be the current elms key.
*** Check to see if there is room to make a 3/2 combine & do it.
**/
else if( pStack->uiBlkEnd <=
(FFILE_MIN_FILL * pDb->pFile->FileHdr.uiBlockSize / 100))
{
rc = FSCombineBlks( pDb, pLFile, &pStack );
*pStackRV = pStack; /* Stack may have changed */
}
Exit:
if (bReleaseTmpCache)
{
ScaReleaseCache( pTmpSCache, FALSE);
}
return( rc);
}
/****************************************************************************
Desc: Delete the parent element from where you are at in the stack.
Notes: In the future we should either pin down the current block or
reread it in.
****************************************************************************/
RCODE FSDelParentElm(
FDB * pDb,
LFILE * pLFile,
BTSK_p * pStackRV
)
{
RCODE rc;
BTSK_p pStack = *pStackRV; /* Stack pointer */
pStack--;
if( RC_BAD(rc = FSGetBlock( pDb, pLFile, pStack->uiBlkAddr, pStack)))
goto Exit;
/* Ignore status value from FSBtScanTo - just position for delete */
if( RC_BAD(rc = FSBtScanTo( pStack, NULL, 0, (FLMUINT) 0)))
goto Exit;
/* FSBlkBuildPKC( pStack, pStack->pKeyBuf );
but does not build key from current element Much faster than scanTo() */
/* Call will position to the next element which pts to the next blk */
rc = FSBtDelete( pDb, pLFile, &pStack );
Exit:
pStack++; /* Go down the pStack to the original level */
*pStackRV = pStack;
return( rc );
}
/****************************************************************************
Desc: There is a new last block element, store key in parent and
remove current element if( uiFlags & FSNLBE_LESS or GREATER is set
Notes: Take note of the uiFlags - they can change what is done
****************************************************************************/
RCODE FSNewLastBlkElm(
FDB * pDb,
LFILE * pLFile,
BTSK_p * pStackRV,
FLMUINT uiFlags) // FSNLBE_GREATER, *_LESS, CK_COMBINE, POSITION or 0
{
RCODE rc;
BTSK_p pStack = *pStackRV;
FLMBYTE * pBlk = pStack->pBlk;
FLMBYTE * pCurElm; // Points to the current last element
FLMUINT uiOldCurElm = pStack->uiCurElm;
FLMUINT uiNextBlk = 0;
FLMUINT uiDomain = 0; // Domain is index reference range
FLMUINT uiElmLen; // Element length
FLMUINT uiKeyLen;
FLMUINT uiNewElmOvhd;
FLMUINT uiRefCount;
FLMBYTE * pKey;
FLMBYTE pElmBuffer[ MAX_KEY_SIZ + BNE_KEY_COUNTS_START + BNE_DOMAIN_LEN ];
uiNewElmOvhd = (pStack-1)->uiElmOvhd;
uiElmLen = uiNewElmOvhd;
if( uiNewElmOvhd == BNE_DATA_OVHD)
{
pKey = pElmBuffer;
}
else
{
pElmBuffer[ BBE_PKC ] = 0; // Set PKC, DOMAIN to zero
pElmBuffer[ BBE_KL ] = 0;
pKey = pElmBuffer + uiNewElmOvhd;
// Only update the counts if the inserting a key and not replacing.
if( uiNewElmOvhd == BNE_KEY_COUNTS_START)
{
if( RC_BAD( rc = FSBlockCounts( pStack, BH_OVHD,
pStack->uiBlkEnd, NULL, NULL, &uiRefCount)))
{
goto Exit;
}
UD2FBA( uiRefCount, &pElmBuffer[ BNE_CHILD_COUNT]);
}
}
// Build the pElmBuffer[] with the new last key in the block
FSSetChildBlkAddr( pElmBuffer, pStack->uiBlkAddr, uiNewElmOvhd);
if( (uiNextBlk = FB2UD( &pBlk[ BH_NEXT_BLK ])) == BT_END)
{
if( uiNewElmOvhd == BNE_DATA_OVHD)
{
UD2FBA( 0xFFFFFFFF, pElmBuffer);
}
uiKeyLen = 0;
uiElmLen = uiNewElmOvhd;
goto no_domain;
}
// else - fall through
pStack->uiCurElm = pStack->uiBlkEnd;// Position past last element
FSBtPrevElm( pDb, pLFile, pStack ); // Build full key in pKeyBuf[]
uiKeyLen = pStack->uiKeyLen;
// Copy the key
if( uiNewElmOvhd == BNE_DATA_OVHD)
{
flmCopyDrnKey( pElmBuffer, pStack->pKeyBuf);
}
else if( uiKeyLen)
{
f_memcpy( &pElmBuffer[ uiNewElmOvhd ], pStack->pKeyBuf, uiKeyLen );
BBE_SET_KL( pElmBuffer, uiKeyLen );
uiElmLen += uiKeyLen;
}
// If this is a boundqed index reference set then store DOMAIN
pCurElm = CURRENT_ELM( pStack );
uiDomain = ( pLFile->uiLfType == LF_INDEX)
? FSGetDomain( &pCurElm, pStack->uiElmOvhd )
: (FLMUINT) 0;
if( uiDomain)
{
BNE_SET_DOMAIN( pElmBuffer );
pElmBuffer[ uiElmLen++ ] = (FLMBYTE) (uiDomain >> 16 );
pElmBuffer[ uiElmLen++ ] = (FLMBYTE) (uiDomain >> 8 );
pElmBuffer[ uiElmLen++ ] = (FLMBYTE) (uiDomain & 0xFF);
}
no_domain:
/**
*** Go to the parent block, insert new element
*** and delete the old last element in the block.
*** Pinning the current block is not suggested because
*** you could pin number of (levels - 1) blocks.
**/
pStack--;
if( RC_BAD(rc = FSGetBlock( pDb, pLFile, pStack->uiBlkAddr, pStack)))
goto Exit;
/* If greater you should be positioned AFTER the matching element */
if( pStack->uiBlkEnd > BH_OVHD) /* Don't call if NO elements */
{
/* Set up the pStack elements for insert - passing keyLen sets up pStack*/
if( RC_BAD(rc = FSBtScanTo( pStack, pKey, uiKeyLen, uiDomain )))
goto Exit;
}
else
pStack->uiPrevElmPKC = pStack->uiPKC = 0;
/* Insert the element into the parent block - watch for splits! */
if( RC_OK( rc = FSBtInsert( pDb, pLFile, &pStack, pElmBuffer, uiElmLen)))
{
if( uiFlags & FSNLBE_LESS )
{
/* Go to the next element, may read a new block! */
if( RC_OK( rc = FSBtNextElm( pDb, pLFile, pStack )))
{
if( RC_OK( rc = FSBtDelete( pDb, pLFile, &pStack )))
{
/* Now position to the current element - back one */
if( !(uiFlags & FSNLBE_POSITION))
{
rc = FSBtPrevElm( pDb, pLFile, pStack );
rc = (rc == FERR_BT_END_OF_DATA) ? FERR_OK : rc;
}
}
else
{
rc = (rc == FERR_BT_END_OF_DATA) ? FERR_OK : rc;
}
}
}
else if( uiFlags & FSNLBE_GREATER )
{
if( RC_OK( rc = FSBtPrevElm( pDb, pLFile, pStack )))
if( RC_OK(rc = FSBtDelete( pDb, pLFile, &pStack )))
{
/* Position to the next element if flag is set */
if( uiFlags & FSNLBE_POSITION)
{
rc = FSBtNextElm( pDb, pLFile, pStack );
rc = (rc == FERR_BT_END_OF_DATA) ? FERR_OK : rc;
}
}
}
}
Exit:
/**-----------------------------------------------------------
*** Pop the pStack and position to next element
*** in the block that you expect to be positioned to.
*** You should be positioned to the correct parent element.
***----------------------------------------------------------*/
pStack++;
*pStackRV = pStack; /* Update callers pStack */
if( RC_OK(rc))
{
if( ( uiFlags & FSNLBE_POSITION ) && (uiNextBlk != BT_END ))
{
pStack->uiBlkAddr = uiNextBlk;
uiOldCurElm = BH_OVHD;
}
/* Read the next block and set pStack. */
if( RC_OK( rc = FSGetBlock( pDb, pLFile, pStack->uiBlkAddr, pStack)))
{
pStack->uiCurElm = uiOldCurElm; /* Restore original curElm value */
FSBlkBuildPKC( pStack, pStack->pKeyBuf, FSBBPKC_AT_CURELM );
}
}
return( rc );
}
/***************************************************************************
Desc: Delete the current element from a b-tree block without writing block.
The pStack must point to the next element after the deleted element.
Notes: Code handles deletion of an element at any level of the b-tree.
*****************************************************************************/
RCODE FSBlkDelElm(
BTSK_p pStack /* Stack of variables for each level */
)
{
RCODE rc;
FLMBYTE * pDelElm; /* Points to deleted element */
FLMBYTE * pCurElm; /* Points to current elm to move down*/
FLMBYTE * pBlk = pStack->pBlk;/* Points to block for speed */
FLMUINT uiCurElmOfs; /* Current (next) element's offset */
FLMUINT uiDelElmPkc; /* # of carry bytes for deleted elm */
FLMUINT uiCurElmPkc; /* Current element's Prev key count */
FLMUINT uiCurElmKeyLen; /* Current element's key length */
FLMUINT uiOldCurElm = pStack->uiCurElm;
FLMUINT uiElmOvhd = pStack->uiElmOvhd; /* Element overhead for block */
FLMINT iDelElmSize; /* Deleted element's size - signed !!*/
FLMINT iPkcLost; /* Number bytes to expand for next elm*/
/* MUST be a signed word value */
pDelElm = &pBlk[ pStack->uiCurElm ];
if( RC_OK(rc = FSBlkNextElm( pStack )))
{
/**
*** Setup to remove what pDelElm is pointing to
*** This is NOT the last element in the block so move down
*** the rest of the block data.
**/
uiCurElmOfs = pStack->uiCurElm;
iDelElmSize = (FLMINT)(uiCurElmOfs - uiOldCurElm);
pCurElm = &pBlk[ uiCurElmOfs ];
if( pStack->uiBlkType != BHT_NON_LEAF_DATA)
{
uiDelElmPkc = (FLMUINT)(BBE_GET_PKC( pDelElm ));
uiCurElmPkc = (FLMUINT)(BBE_GET_PKC( pCurElm ));
/* If current element uses bytes from the deleted element... */
if( uiCurElmPkc > uiDelElmPkc)
{
iPkcLost = (FLMINT)(uiCurElmPkc - uiDelElmPkc);
/** Create the new deleted element and setup for the shiftN() below
*** moving pCurElm.
**/
uiCurElmPkc -= iPkcLost;
uiCurElmKeyLen = (FLMUINT) (BBE_GET_KL( pCurElm ) + iPkcLost);
BBE_SET_PKC( pDelElm, uiCurElmPkc ); /* Clears all bits */
BBE_SET_KL( pDelElm, uiCurElmKeyLen );
*pDelElm |= (FLMBYTE)(BBE_IS_FIRST_LAST(pCurElm ));
if( pStack->uiBlkType == BHT_LEAF)
{
BBE_SET_RL( pDelElm, BBE_GET_RL( pCurElm ));
}
else
{
f_memcpy( pDelElm + BNE_CHILD_BLOCK,
pCurElm + BNE_CHILD_BLOCK, uiElmOvhd - BNE_CHILD_BLOCK );
}
/* Adjust iDelElmSize & uiCurElmOfs to delete current element overhead */
iDelElmSize -= iPkcLost;
uiCurElmOfs += uiElmOvhd;
/* Move any extra bytes from the deleted element refered in curElm */
f_memcpy( pDelElm + uiElmOvhd, &pStack->pKeyBuf[uiDelElmPkc], iPkcLost);
/* Fall through and copy the rest of the block down */
}
}
/* Shift down - starting at pCurElm */
shiftN( &pBlk[ uiCurElmOfs ], pStack->uiBlkEnd - uiCurElmOfs,
(FLMINT)(0 - iDelElmSize) );
pStack->uiBlkEnd -= iDelElmSize;
}
else if( rc == FERR_BT_END_OF_DATA)
{
rc = FERR_OK;
if( pStack->uiCurElm == pStack->uiBlkEnd) /* Deleted last element in blk */
pStack->uiBlkEnd = uiOldCurElm;
else
{
/* Need to move the last element marker (LEM) down */
/* This should only be used on leaf blocks - suggest using shiftN() */
pBlk[ uiOldCurElm ] = BBE_FIRST_FLAG | BBE_LAST_FLAG;
pBlk[ uiOldCurElm + BBE_KL ] = pBlk[ uiOldCurElm + BBE_RL ] = 0;
pStack->uiBlkEnd = uiOldCurElm + uiElmOvhd;
}
}
else
goto Exit;
/* Modify the element end offset & restore curElm & prevElm on pStack */
UW2FBA( (FLMUINT16) pStack->uiBlkEnd, &pBlk[ BH_BLK_END ]);
pStack->uiCurElm = uiOldCurElm;
Exit:
return( rc );
}
/****************************************************************************
Desc: Sets the parent element's child block value
****************************************************************************/
void FSSetChildBlkAddr(
FLMBYTE * pElement,
FLMUINT uiBlkAddr,
FLMUINT uiBlkOvhd)
{
FLMBYTE * pChildAddr;
if( uiBlkOvhd == BNE_KEY_START || uiBlkOvhd == BNE_KEY_COUNTS_START)
{
pChildAddr = pElement + BNE_CHILD_BLOCK;
UD2FBA( uiBlkAddr, pChildAddr );
}
else if( uiBlkOvhd == BNE_DATA_OVHD)
{
pChildAddr = pElement + BNE_DATA_CHILD_BLOCK;
UD2FBA( uiBlkAddr, pChildAddr );
}
return;
}