Added support for large field values (up to 4 GB), async and direct I/O on Linux and Solaris, and performed major code cleanup.
git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@213 0109f412-320b-0410-ab79-c3e0c5ffbbe6
This commit is contained in:
@@ -1,370 +1,382 @@
|
||||
//-------------------------------------------------------------------------
|
||||
// Desc: Insert an element into a 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: fsinselm.cpp 12284 2006-01-19 14:54:14 -0700 (Thu, 19 Jan 2006) dsanders $
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
#include "flaimsys.h"
|
||||
|
||||
FSTATIC RCODE FSBlkInsElm(
|
||||
BTSK_p stk,
|
||||
FLMBYTE * pElm,
|
||||
FLMUINT uiElmLen,
|
||||
FLMUINT uiBlkSize);
|
||||
|
||||
/****************************************************************************
|
||||
Desc: Replace the current element with the input element. Both elements
|
||||
must contain EXACTLY the same key. element[] must contain full key.
|
||||
This gets complex if the input element causes a block split.
|
||||
If so, then call FSBtDelete() and then call FSBtInsert() to split
|
||||
the block.
|
||||
Notes: This is NOT a recursive routine like FSBtInsert() is. Does not work
|
||||
with non-leaf blocks!
|
||||
****************************************************************************/
|
||||
RCODE FSBtReplace(
|
||||
FDB * pDb,
|
||||
LFILE * pLFile,
|
||||
BTSK_p * pStackRV,
|
||||
FLMBYTE * pElement,
|
||||
FLMUINT uiElmLen)
|
||||
{
|
||||
RCODE rc;
|
||||
BTSK_p pStack = *pStackRV;
|
||||
FLMBYTE * pCurElm = CURRENT_ELM( pStack );
|
||||
FLMBYTE * pMovePoint;
|
||||
FLMUINT uiCurRecOfs = (FLMUINT) BBE_REC_OFS( pCurElm);
|
||||
FLMUINT uiCurRecLen = (FLMUINT) BBE_GET_RL( pCurElm);
|
||||
|
||||
FLMUINT uiElmRecOfs = BBE_REC_OFS( pElement);
|
||||
FLMUINT uiElmRecLen = BBE_GET_RL( pElement);
|
||||
FLMUINT uiBytesFree;
|
||||
FLMUINT uiArea;
|
||||
FLMINT iDistance;
|
||||
|
||||
/**
|
||||
*** Set bsBlkEnd because of bug somewhere in the system.
|
||||
*** This MUST be found as soon as possible. April 23, 1992 (SWP)
|
||||
***
|
||||
**/
|
||||
pStack->uiBlkEnd = (FLMUINT) FB2UW( &pStack->pBlk[ BH_ELM_END ] );
|
||||
|
||||
uiBytesFree = pDb->pFile->FileHdr.uiBlockSize -
|
||||
(pStack->uiBlkEnd + BBE_LEM_LEN);
|
||||
|
||||
/* Code around signed compare problems to see if pElement will fit */
|
||||
if( (uiElmRecLen <= uiCurRecLen) || /* pElement len < curElm */
|
||||
(uiBytesFree >= (uiElmRecLen - uiCurRecLen))) /* Enough bytes free */
|
||||
{
|
||||
/* Log the block before modifying it. */
|
||||
if( RC_BAD( rc = FSLogPhysBlk( pDb, pStack)))
|
||||
return( rc);
|
||||
pCurElm = CURRENT_ELM( pStack);
|
||||
|
||||
/* There is room to move things around in the block */
|
||||
iDistance = (FLMINT)(uiElmRecLen - uiCurRecLen); /* Could be positive or negitive*/
|
||||
uiArea = pStack->uiBlkEnd - (pStack->uiCurElm + uiCurRecOfs);
|
||||
pMovePoint = &pCurElm[ uiCurRecOfs ];
|
||||
|
||||
if( uiElmRecLen < uiCurRecLen) /* Move UP <<-- the data in the block*/
|
||||
{
|
||||
uiArea += iDistance; /* iDistance is negitive */
|
||||
pMovePoint -= iDistance; /* Add |distance| to pMovePoint */
|
||||
}
|
||||
if( iDistance)
|
||||
{
|
||||
shiftN( pMovePoint, uiArea, iDistance );
|
||||
pStack->uiBlkEnd += iDistance;
|
||||
UW2FBA( (FLMUINT16)pStack->uiBlkEnd, BLK_ELM_ADDR( pStack, BH_ELM_END ));
|
||||
}
|
||||
/* Change the record length */
|
||||
BBE_SET_RL( pCurElm, BBE_GET_RL( pElement ));
|
||||
|
||||
f_memcpy( &pCurElm[ uiCurRecOfs ], &pElement[ uiElmRecOfs ], uiElmRecLen);
|
||||
}
|
||||
else
|
||||
{
|
||||
/**
|
||||
*** Remove the pElement and reinsert the pElement
|
||||
*** The pElement better contain the entire key! ! !
|
||||
*** Must call FSBtDelete() because cannot just call
|
||||
*** FSBlkDelElm() because SHOULD NOT call FSBtInsert() inserting
|
||||
*** the last item in the block because you don't have a true
|
||||
*** last pElement in the block that reflects the parent.
|
||||
***
|
||||
*** Note: There may not be a FULL_STACK, if adding to the end.
|
||||
*** FSBtDelete() should never get complex if adding to the end.
|
||||
*** FSBtDelete() needs a FULL_STACK when deleting the last pElement
|
||||
*** in the block.
|
||||
**/
|
||||
|
||||
FLMUINT uiKeyLen = (FLMUINT) BBE_GET_KL( pElement);
|
||||
|
||||
if( RC_BAD(rc = FSBtDelete( pDb, pLFile, &pStack )))
|
||||
return( rc );
|
||||
|
||||
/* Setup the pStack and bsKeyBuf[] for the insert */
|
||||
if( RC_BAD(rc = FSBtScanTo( pStack, &pElement[ BBE_KEY ],
|
||||
uiKeyLen, 0)))
|
||||
goto Exit;
|
||||
|
||||
rc = FSBtInsert( pDb, pLFile, &pStack, pElement, uiElmLen );
|
||||
|
||||
*pStackRV = pStack; /* Stack could change on you ! ! ! */
|
||||
}
|
||||
Exit:
|
||||
return( rc );
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
Desc: Insert an pElement/key into a logical b-tree with split support.
|
||||
Supports insertion of a new leaf element in the b-tree structure.
|
||||
This is a complex recursive routine if a block needs to be split.
|
||||
Inserts pElement[] between the previous and current elements.
|
||||
Compress both pElement[] via pStack->uiPrevElmPKC and
|
||||
current element by the difference of the current elements PKC and
|
||||
pStack->wPKC. The PKC value of pElement[] must be ZERO!
|
||||
*****************************************************************************/
|
||||
RCODE FSBtInsert(
|
||||
FDB * pDb,
|
||||
LFILE * pLFile,
|
||||
BTSK_p * pStackRV,
|
||||
FLMBYTE * pElement,
|
||||
FLMUINT uiElmLen)
|
||||
{
|
||||
RCODE rc;
|
||||
BTSK_p pStack = *pStackRV;
|
||||
FLMUINT uiBlkSize = pDb->pFile->FileHdr.uiBlockSize;
|
||||
|
||||
/* Log the block before modifying it. */
|
||||
if( RC_BAD( rc = FSLogPhysBlk( pDb, pStack)))
|
||||
goto Exit;
|
||||
|
||||
/* See if there is enough room for the insertion in the block */
|
||||
|
||||
if( RC_OK( rc = FSBlkInsElm( pStack, pElement, uiElmLen, uiBlkSize)))
|
||||
{
|
||||
// If this is a non-leaf positioning index, update parent counts.
|
||||
if( pLFile->pIxd && (pLFile->pIxd->uiFlags & IXD_POSITIONING))
|
||||
{
|
||||
if( pStack->uiLevel)
|
||||
{
|
||||
rc = FSChangeBlkCounts( pDb, pStack,
|
||||
FB2UD( &pElement[ BNE_CHILD_COUNT]));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if( rc == FERR_BLOCK_FULL)
|
||||
{
|
||||
// No room to insert, split the block and reinsert */
|
||||
// FSBlkSplit() could make a recursive call back to FSBtInsert()
|
||||
|
||||
rc = FSBlkSplit( pDb, pLFile, pStackRV, pElement, uiElmLen );
|
||||
}
|
||||
|
||||
Exit:
|
||||
return( rc);
|
||||
}
|
||||
|
||||
/***************************************************************************
|
||||
Desc: Insert an pElement (any type) into a block & compress the key.
|
||||
Used only by FSBtInsert() and FSBlkSplit().
|
||||
Notes: Variables on the stack are used to save referencing the stack struct.
|
||||
This will insert AFTER the last element in the block. This is
|
||||
very complex code because of having regular and extended elements
|
||||
and coding leaf and non-leaf elements within the same routine.
|
||||
*****************************************************************************/
|
||||
FSTATIC RCODE FSBlkInsElm(
|
||||
BTSK_p pStack, /* Stack holding all state info */
|
||||
FLMBYTE * pElement, /* The input element to insert */
|
||||
FLMUINT uiElmLen, /* Length of the element */
|
||||
FLMUINT uiBlkSize /* Size of the stack block */
|
||||
)
|
||||
{
|
||||
RCODE rc = RC_SET( FERR_BLOCK_FULL); /* Set default for no room */
|
||||
FLMBYTE * pCurElm;
|
||||
FLMUINT uiShiftLen, uiShiftDist; /* Shift length and shift distance */
|
||||
FLMUINT uiNewElmPkc; /* Number of carry btyes for elm */
|
||||
FLMUINT uiNewElmLen = uiElmLen - pStack->uiPrevElmPKC;
|
||||
/* Total length of elm */
|
||||
FLMUINT uiNewElmKeyLen; /* New element's key length */
|
||||
FLMUINT uiCurElmPkc;
|
||||
FLMUINT uiCurElmKeyLen;
|
||||
FLMUINT uiDiff; /* # of bytes to compress on curElm */
|
||||
FLMUINT uiBlkEnd = pStack->uiBlkEnd; /* Value of wBlkEnd */
|
||||
FLMUINT uiElmOvhd = pStack->uiElmOvhd;/* Element overhead */
|
||||
|
||||
uiNewElmPkc = pStack->uiPrevElmPKC;
|
||||
uiNewElmKeyLen = BBE_GET_KL( pElement) - uiNewElmPkc;
|
||||
|
||||
/**
|
||||
*** If there is room, then compress current element and
|
||||
*** insert new element. There must ALWAYS be room for the
|
||||
*** last element marker (LEM).
|
||||
*** "uiDiff" not in computation because of the complexity of
|
||||
*** determining uiDiff before this compare; thus perform a
|
||||
*** split that wasn't needed. This is OK because blocks should
|
||||
*** have some breathing room anyway.
|
||||
**/
|
||||
if( (uiBlkEnd + uiElmOvhd + uiNewElmLen) <= uiBlkSize)
|
||||
{
|
||||
/**
|
||||
*** There is enough space in the block for the element.
|
||||
*** Shift up higher elements compressing more the current element.
|
||||
*** The key in keyBuf must be the curElm key and NOT prevElm!
|
||||
*** pStack->wPKC & pStackPvElmPKC be valid from btScan()
|
||||
**/
|
||||
pCurElm = CURRENT_ELM( pStack );
|
||||
|
||||
if( pStack->uiCurElm < uiBlkEnd )
|
||||
{
|
||||
/**
|
||||
*** uiDiff = additional bytes to compress on the current element.
|
||||
*** There is no way diff can be negative (unless buggy code).
|
||||
**/
|
||||
|
||||
if( uiElmOvhd != BNE_DATA_OVHD)
|
||||
uiCurElmPkc = BBE_GET_PKC( pCurElm );
|
||||
else
|
||||
uiCurElmPkc = 0;
|
||||
|
||||
if( (uiDiff = (FLMUINT) (pStack->uiPKC - uiCurElmPkc)) >= MAX_KEY_SIZ)
|
||||
{
|
||||
return( RC_SET( FERR_BTREE_ERROR) );
|
||||
}
|
||||
if( uiDiff == 0)
|
||||
{
|
||||
/** If there is no "diff" then current element does not
|
||||
*** change. Move element down so many bytes and go on.
|
||||
**/
|
||||
if( uiBlkEnd <= pStack->uiCurElm)
|
||||
return( RC_SET( FERR_BTREE_ERROR) );
|
||||
shiftN( pCurElm, (FLMUINT)(uiBlkEnd - pStack->uiCurElm), uiNewElmLen );
|
||||
}
|
||||
else
|
||||
{
|
||||
/**
|
||||
*** Move from the current element down so many bytes to fit
|
||||
*** the new element.
|
||||
**/
|
||||
uiCurElmKeyLen = (FLMUINT) BBE_GET_KL( pCurElm );
|
||||
uiCurElmPkc += uiDiff; /* Compress more into PKC */
|
||||
/* Check if uiCurElmPkc has overflowed the max. value */
|
||||
if( uiCurElmPkc > BBE_PKC_MAX)
|
||||
{
|
||||
uiDiff -= uiCurElmPkc - BBE_PKC_MAX; /* Could set diff to 0 */
|
||||
uiCurElmPkc = BBE_PKC_MAX;
|
||||
}
|
||||
uiCurElmKeyLen -= uiDiff; /* Remove diff bytes from key */
|
||||
|
||||
/* Shift from the current element's key+diff to end of block */
|
||||
uiShiftLen = (uiBlkEnd - (pStack->uiCurElm + uiElmOvhd + uiDiff));
|
||||
uiShiftDist = (FLMUINT)(uiNewElmLen - uiDiff);
|
||||
|
||||
/* Change block end value to compensate for uiDiff & curElm change*/
|
||||
uiBlkEnd -= uiDiff;
|
||||
|
||||
/* Move up the current element in two statments to re-compress */
|
||||
shiftN( pCurElm + uiElmOvhd + uiDiff, uiShiftLen, uiShiftDist );
|
||||
|
||||
/* Output the new current element overhead */
|
||||
FSSetElmOvhd( pCurElm + uiNewElmLen, uiElmOvhd, uiCurElmPkc,
|
||||
uiCurElmKeyLen, pCurElm );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/**
|
||||
*** Else insert at the end of the block.
|
||||
*** These are special controlled inserts
|
||||
*** "Danger: Don't try this at home"
|
||||
**/
|
||||
; /* BUG: Use to be uiElmLen -= uiNewElmPkc; */
|
||||
|
||||
if( pStack->uiCurElm != uiBlkEnd )
|
||||
{
|
||||
return( RC_SET( FERR_BTREE_ERROR));
|
||||
}
|
||||
}
|
||||
|
||||
/* Create the new elements element overhead portion */
|
||||
FSSetElmOvhd( pCurElm, uiElmOvhd, uiNewElmPkc, uiNewElmKeyLen, pElement );
|
||||
|
||||
/* Move the part of the key and the rest of the record */
|
||||
if( uiElmLen - (uiElmOvhd + uiNewElmPkc))
|
||||
{
|
||||
f_memcpy( pCurElm + uiElmOvhd,
|
||||
&pElement[ uiElmOvhd + uiNewElmPkc ],
|
||||
uiElmLen - (uiElmOvhd + uiNewElmPkc) );
|
||||
}
|
||||
/* Reset the block end */
|
||||
uiBlkEnd += uiNewElmLen;
|
||||
pStack->uiBlkEnd = uiBlkEnd;
|
||||
|
||||
UW2FBA( uiBlkEnd, BLK_ELM_ADDR( pStack, BH_ELM_END ));
|
||||
rc = FERR_OK;
|
||||
}
|
||||
return( rc );
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Desc: Set the element overhead given the needed values
|
||||
****************************************************************************/
|
||||
FLMUINT FSSetElmOvhd(
|
||||
FLMBYTE * pElement,
|
||||
FLMUINT uiElmOvhd,
|
||||
FLMUINT uiPkc,
|
||||
FLMUINT uiKeyLen,
|
||||
FLMBYTE * origElm
|
||||
)
|
||||
{
|
||||
FLMBYTE byFirstByte;
|
||||
|
||||
if( uiElmOvhd == BBE_KEY )
|
||||
{
|
||||
byFirstByte = (FLMBYTE)((*origElm & (BBE_FIRST_FLAG|BBE_LAST_FLAG)) + uiPkc);
|
||||
if( uiKeyLen > 0xFF)
|
||||
{
|
||||
byFirstByte |= (FLMBYTE)(((uiKeyLen) >> BBE_KL_SHIFT_BITS) & BBE_KL_HBITS);
|
||||
}
|
||||
*pElement++ = byFirstByte;
|
||||
*pElement++ = (FLMBYTE) uiKeyLen;
|
||||
*pElement++ = origElm[ BBE_RL ];
|
||||
}
|
||||
else if( uiElmOvhd == BNE_DATA_OVHD)
|
||||
{
|
||||
f_memcpy( pElement, origElm, BNE_DATA_OVHD);
|
||||
}
|
||||
else
|
||||
{
|
||||
byFirstByte = (FLMBYTE)((*origElm & (BBE_FIRST_FLAG|BBE_LAST_FLAG)) + uiPkc);
|
||||
if( uiKeyLen > 0xFF)
|
||||
{
|
||||
byFirstByte |= (FLMBYTE)(((uiKeyLen) >> BBE_KL_SHIFT_BITS) & BBE_KL_HBITS);
|
||||
}
|
||||
*pElement++ = byFirstByte;
|
||||
*pElement++ = (FLMBYTE) uiKeyLen;
|
||||
// Will copy 3 bytes for 2x dbs and 4 bytes ro 3x dbs.
|
||||
f_memcpy( pElement, &origElm[ BNE_CHILD_BLOCK],
|
||||
uiElmOvhd - BNE_CHILD_BLOCK );
|
||||
}
|
||||
|
||||
return( uiElmOvhd );
|
||||
}
|
||||
//-------------------------------------------------------------------------
|
||||
// Desc: Insert an element into a 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: fsinselm.cpp 12284 2006-01-19 14:54:14 -0700 (Thu, 19 Jan 2006) dsanders $
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
#include "flaimsys.h"
|
||||
|
||||
FSTATIC RCODE FSBlkInsElm(
|
||||
BTSK * stk,
|
||||
FLMBYTE * pElm,
|
||||
FLMUINT uiElmLen,
|
||||
FLMUINT uiBlkSize);
|
||||
|
||||
/****************************************************************************
|
||||
Desc: Replace the current element with the input element. Both elements
|
||||
must contain EXACTLY the same key. element[] must contain full key.
|
||||
This gets complex if the input element causes a block split.
|
||||
If so, then call FSBtDelete() and then call FSBtInsert() to split
|
||||
the block.
|
||||
****************************************************************************/
|
||||
RCODE FSBtReplace(
|
||||
FDB * pDb,
|
||||
LFILE * pLFile,
|
||||
BTSK ** pStackRV,
|
||||
FLMBYTE * pElement,
|
||||
FLMUINT uiElmLen)
|
||||
{
|
||||
RCODE rc;
|
||||
BTSK * pStack = *pStackRV;
|
||||
FLMBYTE * pCurElm = CURRENT_ELM( pStack);
|
||||
FLMBYTE * pMovePoint;
|
||||
FLMUINT uiCurRecOfs = (FLMUINT) BBE_REC_OFS( pCurElm);
|
||||
FLMUINT uiCurRecLen = (FLMUINT) BBE_GET_RL( pCurElm);
|
||||
FLMUINT uiElmRecOfs = BBE_REC_OFS( pElement);
|
||||
FLMUINT uiElmRecLen = BBE_GET_RL( pElement);
|
||||
FLMUINT uiBytesFree;
|
||||
FLMUINT uiArea;
|
||||
FLMINT iDistance;
|
||||
|
||||
// Set bsBlkEnd because of bug somewhere in the system. This MUST be
|
||||
// found as soon as possible. April 23, 1992 (SWP)
|
||||
|
||||
pStack->uiBlkEnd = (FLMUINT) FB2UW( &pStack->pBlk[BH_ELM_END]);
|
||||
uiBytesFree = pDb->pFile->FileHdr.uiBlockSize -
|
||||
(pStack->uiBlkEnd + BBE_LEM_LEN);
|
||||
|
||||
// Code around signed compare problems to see if pElement will fit
|
||||
|
||||
if ((uiElmRecLen <= uiCurRecLen) ||
|
||||
(uiBytesFree >= (uiElmRecLen - uiCurRecLen)))
|
||||
{
|
||||
|
||||
// Log the block before modifying it.
|
||||
|
||||
if (RC_BAD( rc = FSLogPhysBlk( pDb, pStack)))
|
||||
{
|
||||
return (rc);
|
||||
}
|
||||
|
||||
pCurElm = CURRENT_ELM( pStack);
|
||||
|
||||
// There is room to move things around in the block
|
||||
|
||||
iDistance = (FLMINT) (uiElmRecLen - uiCurRecLen);
|
||||
uiArea = pStack->uiBlkEnd - (pStack->uiCurElm + uiCurRecOfs);
|
||||
pMovePoint = &pCurElm[uiCurRecOfs];
|
||||
|
||||
if (uiElmRecLen < uiCurRecLen)
|
||||
{
|
||||
uiArea += iDistance; // iDistance is negitive
|
||||
pMovePoint -= iDistance; // Add |distance| to pMovePoint
|
||||
}
|
||||
|
||||
if (iDistance)
|
||||
{
|
||||
shiftN( pMovePoint, uiArea, iDistance);
|
||||
pStack->uiBlkEnd += iDistance;
|
||||
UW2FBA( (FLMUINT16) pStack->uiBlkEnd, BLK_ELM_ADDR( pStack, BH_ELM_END));
|
||||
}
|
||||
|
||||
// Change the record length
|
||||
|
||||
BBE_SET_RL( pCurElm, BBE_GET_RL( pElement));
|
||||
f_memcpy( &pCurElm[uiCurRecOfs], &pElement[uiElmRecOfs], uiElmRecLen);
|
||||
}
|
||||
else
|
||||
{
|
||||
FLMUINT uiKeyLen = (FLMUINT) BBE_GET_KL( pElement);
|
||||
|
||||
if (RC_BAD( rc = FSBtDelete( pDb, pLFile, &pStack)))
|
||||
{
|
||||
return (rc);
|
||||
}
|
||||
|
||||
// Setup the pStack and bsKeyBuf[] for the insert
|
||||
|
||||
if (RC_BAD( rc = FSBtScanTo( pStack, &pElement[BBE_KEY], uiKeyLen, 0)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
rc = FSBtInsert( pDb, pLFile, &pStack, pElement, uiElmLen);
|
||||
*pStackRV = pStack;
|
||||
}
|
||||
|
||||
Exit:
|
||||
|
||||
return (rc);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Desc: Insert an pElement/key into a logical b-tree with split support.
|
||||
Supports insertion of a new leaf element in the b-tree structure.
|
||||
****************************************************************************/
|
||||
RCODE FSBtInsert(
|
||||
FDB * pDb,
|
||||
LFILE * pLFile,
|
||||
BTSK ** pStackRV,
|
||||
FLMBYTE * pElement,
|
||||
FLMUINT uiElmLen)
|
||||
{
|
||||
RCODE rc;
|
||||
BTSK * pStack = *pStackRV;
|
||||
FLMUINT uiBlkSize = pDb->pFile->FileHdr.uiBlockSize;
|
||||
|
||||
// Log the block before modifying it.
|
||||
|
||||
if (RC_BAD( rc = FSLogPhysBlk( pDb, pStack)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// See if there is enough room for the insertion in the block
|
||||
|
||||
if (RC_OK( rc = FSBlkInsElm( pStack, pElement, uiElmLen, uiBlkSize)))
|
||||
{
|
||||
|
||||
// If this is a non-leaf positioning index, update parent counts.
|
||||
|
||||
if (pLFile->pIxd && (pLFile->pIxd->uiFlags & IXD_POSITIONING))
|
||||
{
|
||||
if (pStack->uiLevel)
|
||||
{
|
||||
rc = FSChangeBlkCounts( pDb, pStack,
|
||||
FB2UD( &pElement[BNE_CHILD_COUNT]));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (rc == FERR_BLOCK_FULL)
|
||||
{
|
||||
|
||||
// No room to insert, split the block and reinsert
|
||||
|
||||
rc = FSBlkSplit( pDb, pLFile, pStackRV, pElement, uiElmLen);
|
||||
}
|
||||
|
||||
Exit:
|
||||
|
||||
return (rc);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Desc: Insert an pElement (any type) into a block & compress the key.
|
||||
****************************************************************************/
|
||||
FSTATIC RCODE FSBlkInsElm(
|
||||
BTSK * pStack, // Stack holding all state info
|
||||
FLMBYTE * pElement, // The input element to insert
|
||||
FLMUINT uiElmLen, // Length of the element
|
||||
FLMUINT uiBlkSize) // Size of the stack block
|
||||
{
|
||||
RCODE rc = RC_SET( FERR_BLOCK_FULL);
|
||||
FLMBYTE * pCurElm;
|
||||
FLMUINT uiShiftLen;
|
||||
FLMUINT uiShiftDist;
|
||||
FLMUINT uiNewElmPkc;
|
||||
FLMUINT uiNewElmLen = uiElmLen - pStack->uiPrevElmPKC;
|
||||
FLMUINT uiNewElmKeyLen;
|
||||
FLMUINT uiCurElmPkc;
|
||||
FLMUINT uiCurElmKeyLen;
|
||||
FLMUINT uiDiff;
|
||||
FLMUINT uiBlkEnd = pStack->uiBlkEnd;
|
||||
FLMUINT uiElmOvhd = pStack->uiElmOvhd;
|
||||
|
||||
uiNewElmPkc = pStack->uiPrevElmPKC;
|
||||
uiNewElmKeyLen = BBE_GET_KL( pElement) - uiNewElmPkc;
|
||||
|
||||
// If there is room, then compress current element and insert new
|
||||
// element. There must ALWAYS be room for the last element marker
|
||||
// (LEM). "uiDiff" not in computation because of the complexity of
|
||||
// determining uiDiff before this compare;
|
||||
// thus perform a split that wasn't needed. This is OK because blocks
|
||||
// should have some breathing room anyway.
|
||||
|
||||
if ((uiBlkEnd + uiElmOvhd + uiNewElmLen) <= uiBlkSize)
|
||||
{
|
||||
// There is enough space in the block for the element. Shift up
|
||||
// higher elements compressing more the current element. The key in
|
||||
// keyBuf must be the curElm key and NOT prevElm! pStack->wPKC and
|
||||
// pStackPvElmPKC be valid from btScan()
|
||||
|
||||
pCurElm = CURRENT_ELM( pStack);
|
||||
|
||||
if (pStack->uiCurElm < uiBlkEnd)
|
||||
{
|
||||
|
||||
// uiDiff = additional bytes to compress on the current element.
|
||||
// There is no way diff can be negative (unless buggy code).
|
||||
|
||||
if (uiElmOvhd != BNE_DATA_OVHD)
|
||||
{
|
||||
uiCurElmPkc = BBE_GET_PKC( pCurElm);
|
||||
}
|
||||
else
|
||||
{
|
||||
uiCurElmPkc = 0;
|
||||
}
|
||||
|
||||
if ((uiDiff = (FLMUINT) (pStack->uiPKC - uiCurElmPkc)) >= MAX_KEY_SIZ)
|
||||
{
|
||||
return (RC_SET( FERR_BTREE_ERROR));
|
||||
}
|
||||
|
||||
if (uiDiff == 0)
|
||||
{
|
||||
|
||||
// If there is no "diff" then current element does not change.
|
||||
// Move element down so many bytes and go on.
|
||||
|
||||
if (uiBlkEnd <= pStack->uiCurElm)
|
||||
{
|
||||
return (RC_SET( FERR_BTREE_ERROR));
|
||||
}
|
||||
|
||||
shiftN( pCurElm, (FLMUINT) (uiBlkEnd - pStack->uiCurElm),
|
||||
uiNewElmLen);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// Move from the current element down so many bytes to fit the
|
||||
// new element.
|
||||
|
||||
uiCurElmKeyLen = (FLMUINT) BBE_GET_KL( pCurElm);
|
||||
uiCurElmPkc += uiDiff;
|
||||
|
||||
// Check if uiCurElmPkc has overflowed the max. value
|
||||
|
||||
if (uiCurElmPkc > BBE_PKC_MAX)
|
||||
{
|
||||
uiDiff -= uiCurElmPkc - BBE_PKC_MAX; // Could set diff to 0
|
||||
uiCurElmPkc = BBE_PKC_MAX;
|
||||
}
|
||||
|
||||
uiCurElmKeyLen -= uiDiff; // Remove diff bytes
|
||||
|
||||
// Shift from the current element's key+diff to end of block
|
||||
|
||||
uiShiftLen = (uiBlkEnd - (pStack->uiCurElm + uiElmOvhd + uiDiff));
|
||||
uiShiftDist = (FLMUINT) (uiNewElmLen - uiDiff);
|
||||
|
||||
// Change block end value to compensate for uiDiff and curElm
|
||||
// change
|
||||
|
||||
uiBlkEnd -= uiDiff;
|
||||
|
||||
// Move up the current element in two statments to re-compress
|
||||
|
||||
shiftN( pCurElm + uiElmOvhd + uiDiff, uiShiftLen, uiShiftDist);
|
||||
|
||||
// Output the new current element overhead
|
||||
|
||||
FSSetElmOvhd( pCurElm + uiNewElmLen, uiElmOvhd, uiCurElmPkc,
|
||||
uiCurElmKeyLen, pCurElm);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// Else insert at the end of the block. These are special
|
||||
// controlled inserts
|
||||
|
||||
if (pStack->uiCurElm != uiBlkEnd)
|
||||
{
|
||||
return (RC_SET( FERR_BTREE_ERROR));
|
||||
}
|
||||
}
|
||||
|
||||
// Create the new elements element overhead portion
|
||||
|
||||
FSSetElmOvhd( pCurElm, uiElmOvhd, uiNewElmPkc, uiNewElmKeyLen, pElement);
|
||||
|
||||
// Move the part of the key and the rest of the record
|
||||
|
||||
if (uiElmLen - (uiElmOvhd + uiNewElmPkc))
|
||||
{
|
||||
f_memcpy( pCurElm + uiElmOvhd, &pElement[uiElmOvhd + uiNewElmPkc],
|
||||
uiElmLen - (uiElmOvhd + uiNewElmPkc));
|
||||
}
|
||||
|
||||
// Reset the block end
|
||||
|
||||
uiBlkEnd += uiNewElmLen;
|
||||
pStack->uiBlkEnd = uiBlkEnd;
|
||||
|
||||
UW2FBA( uiBlkEnd, BLK_ELM_ADDR( pStack, BH_ELM_END));
|
||||
rc = FERR_OK;
|
||||
}
|
||||
|
||||
return (rc);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Desc: Set the element overhead given the needed values
|
||||
****************************************************************************/
|
||||
FLMUINT FSSetElmOvhd(
|
||||
FLMBYTE * pElement,
|
||||
FLMUINT uiElmOvhd,
|
||||
FLMUINT uiPkc,
|
||||
FLMUINT uiKeyLen,
|
||||
FLMBYTE * origElm)
|
||||
{
|
||||
FLMBYTE byFirstByte;
|
||||
|
||||
if (uiElmOvhd == BBE_KEY)
|
||||
{
|
||||
byFirstByte = (FLMBYTE) ((*origElm &
|
||||
(BBE_FIRST_FLAG | BBE_LAST_FLAG)) + uiPkc);
|
||||
if (uiKeyLen > 0xFF)
|
||||
{
|
||||
byFirstByte |= (FLMBYTE) (((uiKeyLen) >> BBE_KL_SHIFT_BITS) &
|
||||
BBE_KL_HBITS);
|
||||
}
|
||||
|
||||
*pElement++ = byFirstByte;
|
||||
*pElement++ = (FLMBYTE) uiKeyLen;
|
||||
*pElement++ = origElm[BBE_RL];
|
||||
}
|
||||
else if (uiElmOvhd == BNE_DATA_OVHD)
|
||||
{
|
||||
f_memcpy( pElement, origElm, BNE_DATA_OVHD);
|
||||
}
|
||||
else
|
||||
{
|
||||
byFirstByte = (FLMBYTE) ((*origElm &
|
||||
(BBE_FIRST_FLAG | BBE_LAST_FLAG)) + uiPkc);
|
||||
|
||||
if (uiKeyLen > 0xFF)
|
||||
{
|
||||
byFirstByte |= (FLMBYTE) (((uiKeyLen) >>
|
||||
BBE_KL_SHIFT_BITS) & BBE_KL_HBITS);
|
||||
}
|
||||
|
||||
*pElement++ = byFirstByte;
|
||||
*pElement++ = (FLMBYTE) uiKeyLen;
|
||||
|
||||
// Will copy 3 bytes for 2x dbs and 4 bytes ro 3x dbs.
|
||||
|
||||
f_memcpy( pElement, &origElm[BNE_CHILD_BLOCK],
|
||||
uiElmOvhd - BNE_CHILD_BLOCK);
|
||||
}
|
||||
|
||||
return (uiElmOvhd);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user