git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@519 0109f412-320b-0410-ab79-c3e0c5ffbbe6
383 lines
10 KiB
C++
383 lines
10 KiB
C++
//-------------------------------------------------------------------------
|
|
// 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( (FLMUINT16)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);
|
|
}
|