git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@643 0109f412-320b-0410-ab79-c3e0c5ffbbe6
366 lines
9.8 KiB
C++
366 lines
9.8 KiB
C++
//-------------------------------------------------------------------------
|
|
// Desc: Database format conversion routines.
|
|
// Tabs: 3
|
|
//
|
|
// Copyright (c) 1999-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: fsconvrt.cpp 12320 2006-01-19 15:53:51 -0700 (Thu, 19 Jan 2006) dsanders $
|
|
//-------------------------------------------------------------------------
|
|
|
|
#include "flaimsys.h"
|
|
|
|
FSTATIC RCODE FSConvertNonLeafTree(
|
|
FDB * pDb,
|
|
LFILE * pLFile,
|
|
BTSK * pOldStack,
|
|
BTSK * pOldStackBase,
|
|
FLMUINT uiNewVersion,
|
|
STATUS_HOOK fnStatusCallback,
|
|
void * UserData,
|
|
DB_UPGRADE_INFO * pDbConvertInfo);
|
|
|
|
FSTATIC void FSBuildNonLeafDataElement(
|
|
BTSK * pStack,
|
|
FLMBYTE * pElement,
|
|
FLMUINT * puiElmLen,
|
|
FLMUINT uiNewElmOvhd,
|
|
FLMBYTE ** ppKey);
|
|
|
|
/***************************************************************************
|
|
Desc: File system conversions from one version to another.
|
|
*****************************************************************************/
|
|
RCODE FSVersionConversion40(
|
|
FDB * pDb,
|
|
FLMUINT uiNewVersion,
|
|
STATUS_HOOK fnStatusCallback,
|
|
void * UserData)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
FFILE * pFile = pDb->pFile;
|
|
LFILE * pLFileTbl;
|
|
FLMUINT uiPos, uiTblSize;
|
|
FLMUINT uiCurrentVersion;
|
|
BTSK * pStack;
|
|
BTSK stackBuf[ BH_MAX_LEVELS ];
|
|
FLMBYTE pKeyBuf[ DIN_KEY_SIZ + 4 ];
|
|
FLMBYTE pDrnKey[ DIN_KEY_SIZ];
|
|
DB_UPGRADE_INFO DbConvertInfo;
|
|
|
|
f_memset( &DbConvertInfo, 0, sizeof( DB_UPGRADE_INFO));
|
|
// Supported conversions...
|
|
uiCurrentVersion = pFile->FileHdr.uiVersionNum;
|
|
|
|
// Loop through all of the data blocks in the lfile.
|
|
|
|
pLFileTbl = pDb->pDict->pLFileTbl;
|
|
uiTblSize = pDb->pDict->uiLFileCnt;
|
|
FSInitStackCache( &stackBuf [0], BH_MAX_LEVELS);
|
|
|
|
for( uiPos = 0; uiPos < uiTblSize; uiPos++)
|
|
{
|
|
LFILE * pLFile;
|
|
|
|
pLFile = &pLFileTbl [uiPos];
|
|
|
|
if( pLFile->uiLfType == LF_CONTAINER)
|
|
{
|
|
if( fnStatusCallback)
|
|
{
|
|
DbConvertInfo.uiLastDrn = 0;
|
|
if( RC_BAD( rc = FSGetNextDrn( pDb, pLFile, FALSE,
|
|
&DbConvertInfo.uiLastDrn)))
|
|
goto Exit;
|
|
}
|
|
// Set up the stack
|
|
FSInitStackCache( &stackBuf [0], BH_MAX_LEVELS);
|
|
pStack = stackBuf;
|
|
pStack->pKeyBuf = pKeyBuf;
|
|
f_UINT32ToBigEndian( 0, pDrnKey);
|
|
if( RC_BAD(rc = FSBtSearch( pDb, pLFile, &pStack,
|
|
pDrnKey, DIN_KEY_SIZ,0)))
|
|
goto Exit;
|
|
|
|
// If pStack isn't at stackBuf[] we have a b-tree of 2 or more levels.
|
|
|
|
// VISIT: the change may not be necessary - may be new version.
|
|
// Look at the root block type.
|
|
|
|
if( pStack != stackBuf)
|
|
{
|
|
DbConvertInfo.uiContainer = pLFile->uiLfNum;
|
|
|
|
if( RC_BAD( rc = FSConvertNonLeafTree( pDb, pLFile, pStack - 1,
|
|
stackBuf, uiNewVersion,
|
|
fnStatusCallback, UserData, &DbConvertInfo)))
|
|
goto Exit;
|
|
}
|
|
FSReleaseStackCache( stackBuf, BH_MAX_LEVELS, FALSE);
|
|
}
|
|
}
|
|
// Loop through all of the data b-trees and look for non-leaf blocks.
|
|
Exit:
|
|
FSReleaseStackCache( stackBuf, BH_MAX_LEVELS, FALSE);
|
|
return( rc);
|
|
}
|
|
|
|
/***************************************************************************
|
|
Desc: Convert the non-leaf data blocks from one version to another version.
|
|
pOldStack points to the level 1 non-leaf data blocks.
|
|
Read all of the elements and build a new non-leaf b-tree
|
|
and make this the new tree while freeing up the old non-leaf blocks.
|
|
*****************************************************************************/
|
|
FSTATIC RCODE FSConvertNonLeafTree(
|
|
FDB * pDb,
|
|
LFILE * pLFile,
|
|
BTSK * pOldStack,
|
|
BTSK * pOldStackBase,
|
|
FLMUINT uiNewVersion,
|
|
STATUS_HOOK fnStatusCallback,
|
|
void * UserData,
|
|
DB_UPGRADE_INFO * pDbConvertInfo)
|
|
{
|
|
RCODE rc = FERR_OK;
|
|
BTSK stackBuf[ BH_MAX_LEVELS ];
|
|
BTSK * pStack;
|
|
FLMBYTE pKeyBuf[ DIN_KEY_SIZ + 4 ];
|
|
FLMBYTE pDrnKey[ DIN_KEY_SIZ];
|
|
FLMBYTE pElement[ DIN_KEY_SIZ + 16]; // Enough bytes for either format
|
|
SCACHE * pTempSCache;
|
|
FLMUINT uiBlkAddr;
|
|
|
|
FSInitStackCache( &stackBuf [0], BH_MAX_LEVELS);
|
|
f_UINT32ToBigEndian( 0, pDrnKey);
|
|
|
|
/*
|
|
Free the b-tree blocks that are above this lowest non-leaf level.
|
|
This will reuse the blocks instead of allocating from the avail list or end
|
|
of file.
|
|
*/
|
|
|
|
pOldStack->uiFlags &= ~FULL_STACK;
|
|
for( ; pOldStackBase != pOldStack; pOldStackBase++ )
|
|
{
|
|
uiBlkAddr = pOldStackBase->uiBlkAddr;
|
|
|
|
// Release block so that caller doesn't release an avail block.
|
|
FSReleaseBlock( pOldStackBase, FALSE);
|
|
|
|
while( uiBlkAddr != BT_END)
|
|
{
|
|
if( RC_BAD( rc = ScaGetBlock( pDb, pLFile, BHT_LEAF,
|
|
uiBlkAddr, NULL, &pTempSCache)))
|
|
goto Exit;
|
|
uiBlkAddr = FB2UD( &pTempSCache->pucBlk[ BH_NEXT_BLK ]);
|
|
|
|
if( RC_BAD( FSBlockFree( pDb, pTempSCache)))
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// Allocate a new root block in the new NON-LEAF format.
|
|
|
|
pStack = stackBuf;
|
|
pStack->pKeyBuf = pKeyBuf;
|
|
pLFile->uiRootBlk = BT_END;
|
|
|
|
if( RC_BAD( flmLFileWrite( pDb, pLFile)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = flmLFileInit( pDb, pLFile)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD(rc = FSGetBlock( pDb, pLFile, pLFile->uiRootBlk, pStack)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = FSLogPhysBlk( pDb, pStack)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Remove both leading elements in the block and setup as a non-leaf block.
|
|
|
|
UW2FBA( BH_OVHD, &pStack->pBlk[ BH_BLK_END]);
|
|
|
|
if( uiNewVersion >= FLM_FILE_FORMAT_VER_4_0)
|
|
{
|
|
pStack->pBlk[ BH_TYPE ] = BHT_NON_LEAF_DATA + BHT_ROOT_BLK;
|
|
}
|
|
else
|
|
{
|
|
pStack->pBlk[ BH_TYPE ] = BHT_NON_LEAF + BHT_ROOT_BLK;
|
|
}
|
|
|
|
pStack->pBlk[ BH_LEVEL ] = 1;
|
|
pStack->uiKeyBufSize = DIN_KEY_SIZ;
|
|
FSBlkToStack( pStack);
|
|
pStack->uiFlags = FULL_STACK;
|
|
|
|
// Build the key for the first element in the old stack.
|
|
|
|
if( RC_BAD( rc = FSBtScanTo( pOldStack, NULL, 0, 0)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Start inserting from pOldStack to pStack until pOldStack is done.
|
|
|
|
for(;;)
|
|
{
|
|
FLMUINT uiElmLen;
|
|
FLMBYTE * pKey;
|
|
|
|
FSBuildNonLeafDataElement( pOldStack, pElement,
|
|
&uiElmLen, pStack->uiElmOvhd, &pKey);
|
|
|
|
if( uiNewVersion <= FLM_FILE_FORMAT_VER_3_02)
|
|
{
|
|
flmAssert( pStack->uiCurElm == pStack->uiBlkEnd);
|
|
if( pStack != stackBuf)
|
|
{
|
|
flmAssert( stackBuf[0].uiCurElm + 6 == stackBuf[0].uiBlkEnd);
|
|
}
|
|
|
|
pStack->uiCurElm = pStack->uiBlkEnd;
|
|
|
|
// Call scanto to place the last element's key in keybuf.
|
|
if( RC_BAD( rc = FSBtScanTo( pStack, NULL, 0, 0)))
|
|
goto Exit;
|
|
if( pStack->uiBlkEnd > BH_OVHD)
|
|
{
|
|
if( uiElmLen > BNE_KEY_START)
|
|
{
|
|
pStack->uiPrevElmPKC =
|
|
FSElmComparePKC( pKeyBuf, DIN_KEY_SIZ, pKey, DIN_KEY_SIZ);
|
|
}
|
|
}
|
|
}
|
|
if( RC_BAD( rc = FSBtInsert( pDb, pLFile, &pStack, pElement, uiElmLen)))
|
|
goto Exit;
|
|
|
|
// Go to next element so we always insert at the end.
|
|
(void) FSBtNextElm( pDb, pLFile, pStack );
|
|
|
|
uiBlkAddr = pOldStack->uiBlkAddr;
|
|
if( RC_BAD( rc = FSBtNextElm( pDb, pLFile, pOldStack )))
|
|
{
|
|
// All done? Free the last block in the old b-tree.
|
|
if( rc == FERR_BT_END_OF_DATA)
|
|
{
|
|
if( RC_BAD( rc = ScaGetBlock( pDb, pLFile, BHT_LEAF,
|
|
uiBlkAddr, NULL, &pTempSCache)))
|
|
goto Exit;
|
|
|
|
// No need to release pTempSCache. FSBlockFree does it.
|
|
if( RC_BAD( FSBlockFree( pDb, pTempSCache)))
|
|
goto Exit;
|
|
rc = FERR_OK;
|
|
break;
|
|
}
|
|
goto Exit;
|
|
}
|
|
|
|
// Did next element position to a new block?
|
|
if( uiBlkAddr != pOldStack->uiBlkAddr)
|
|
{
|
|
// Do callback to report progress.
|
|
if (fnStatusCallback)
|
|
{
|
|
pDbConvertInfo->uiDrn = f_bigEndianToUINT32( pOldStack->pKeyBuf);
|
|
if (RC_BAD( rc = (*fnStatusCallback)( FLM_DB_UPGRADE_STATUS,
|
|
(void *) pDbConvertInfo,
|
|
(void *)0, UserData)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// Free the previous block back into the avail list.
|
|
if( RC_BAD( rc = ScaGetBlock( pDb, pLFile, BHT_LEAF,
|
|
uiBlkAddr, NULL, &pTempSCache)))
|
|
goto Exit;
|
|
if( RC_BAD( FSBlockFree( pDb, pTempSCache)))
|
|
goto Exit;
|
|
// No need to release pTempSCache. FSBlockFree does it.
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
FSReleaseStackCache( stackBuf, BH_MAX_LEVELS, FALSE);
|
|
return( rc);
|
|
}
|
|
|
|
/***************************************************************************
|
|
Desc: Build a non-leaf data element from the current stack position.
|
|
*****************************************************************************/
|
|
FSTATIC void FSBuildNonLeafDataElement(
|
|
BTSK * pStack,
|
|
FLMBYTE * pElement,
|
|
FLMUINT * puiElmLen,
|
|
FLMUINT uiNewElmOvhd,
|
|
FLMBYTE ** ppKey)
|
|
{
|
|
FLMUINT uiElmLen;
|
|
|
|
// Grab the key from the key buffer,
|
|
|
|
if( uiNewElmOvhd == BNE_DATA_OVHD) // New fixed length 4.0 format.
|
|
{
|
|
FLMBYTE * pOldElm = CURRENT_ELM( pStack);
|
|
|
|
uiElmLen = BNE_DATA_OVHD;
|
|
*ppKey = pElement;
|
|
|
|
// Check for last element marker.
|
|
if( pOldElm[ BBE_PKC ] == 0 && pOldElm[ BBE_KL] == 0)
|
|
{
|
|
f_UINT32ToBigEndian( (FLMUINT32)DRN_LAST_MARKER, pElement);
|
|
}
|
|
else
|
|
{
|
|
f_memcpy( pElement, pStack->pKeyBuf, DIN_KEY_SIZ);
|
|
}
|
|
}
|
|
else // Old variable length 3.x format.
|
|
{
|
|
pElement [ BBE_PKC ] = 0; // Set PKC, DOMAIN to zero
|
|
if( FB2UD( pStack->pKeyBuf) == DRN_LAST_MARKER)
|
|
{
|
|
pElement [ BBE_KL ] = 0;
|
|
uiElmLen = BNE_KEY_START;
|
|
}
|
|
else
|
|
{
|
|
pElement [ BBE_PKC ] = 0; // Set PKC, DOMAIN to zero
|
|
pElement [ BBE_KL ] = DIN_KEY_SIZ; // sizeof( FLMUINT32) or 4
|
|
uiElmLen = BNE_KEY_START + DIN_KEY_SIZ;
|
|
f_memcpy( pElement + BNE_KEY_START, pStack->pKeyBuf, DIN_KEY_SIZ);
|
|
}
|
|
*ppKey = pElement + BNE_KEY_START;
|
|
}
|
|
// Set the child block address.
|
|
FSSetChildBlkAddr( pElement, FSChildBlkAddr( pStack), uiNewElmOvhd);
|
|
*puiElmLen = uiElmLen;
|
|
return;
|
|
}
|