Added .cpp and .h files under the sql/src subdirectory
git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@469 0109f412-320b-0410-ab79-c3e0c5ffbbe6
This commit is contained in:
849
sql/src/flreduce.cpp
Normal file
849
sql/src/flreduce.cpp
Normal file
@@ -0,0 +1,849 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// Desc: Reduce the database size by move 'N' free blocks the the end of
|
||||
// the file and truncating the file.
|
||||
//
|
||||
// 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: flreduce.cpp 3113 2006-01-19 13:20:35 -0700 (Thu, 19 Jan 2006) dsanders $
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "flaimsys.h"
|
||||
|
||||
/****************************************************************************
|
||||
Desc : Reduces the size of a FLAIM database file.
|
||||
Notes: The size of the database file is reduced by freeing a specified
|
||||
number of blocks from the available (unused) block list. The blocks
|
||||
are moved to the end of the file and the file is truncated. If the
|
||||
available block list is empty, FLAIM will attemp to add blocks to
|
||||
the list by freeing log extent blocks.
|
||||
****************************************************************************/
|
||||
RCODE F_Db::reduceSize(
|
||||
FLMUINT uiCount,
|
||||
FLMUINT * puiCount)
|
||||
{
|
||||
RCODE rc = NE_SFLM_OK;
|
||||
F_Rfl * pRfl = m_pDatabase->m_pRfl;
|
||||
FLMUINT uiLogicalEOF;
|
||||
FLMUINT uiBlkAddr;
|
||||
FLMUINT uiNumBlksMoved;
|
||||
FLMUINT uiBlkSize;
|
||||
F_LARGEST_BLK_HDR blkHdr;
|
||||
FLMINT iType;
|
||||
FLMBOOL bFlagSet;
|
||||
FLMBOOL bTransActive = FALSE;
|
||||
FLMBOOL bLockedDb = FALSE;
|
||||
FLMBOOL bEnableLogging = FALSE;
|
||||
|
||||
uiNumBlksMoved = 0;
|
||||
|
||||
if (RC_BAD( rc = checkState( __FILE__, __LINE__)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Make sure we are NOT in a database transaction.
|
||||
|
||||
if (m_eTransType != SFLM_NO_TRANS)
|
||||
{
|
||||
rc = RC_SET( NE_SFLM_TRANS_ACTIVE);
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// There must NOT be a shared lock on the file.
|
||||
|
||||
if (m_uiFlags & FDB_FILE_LOCK_SHARED)
|
||||
{
|
||||
rc = RC_SET( NE_SFLM_SHARED_LOCK);
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Must acquire an exclusive file lock first, if it hasn't been
|
||||
// acquired.
|
||||
|
||||
if (!(m_uiFlags & FDB_HAS_FILE_LOCK))
|
||||
{
|
||||
if (RC_BAD( rc = m_pDatabase->m_pDatabaseLockObj->Lock( this, m_hWaitSem,
|
||||
TRUE, FALSE, TRUE, SFLM_NO_TIMEOUT, 0, m_pDbStats)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
bLockedDb = TRUE;
|
||||
m_uiFlags |= FDB_HAS_FILE_LOCK;
|
||||
}
|
||||
|
||||
// Disable RFL logging - don't want anything logged during reduce
|
||||
// except for the reduce packet.
|
||||
|
||||
bEnableLogging = pRfl->isLoggingEnabled();
|
||||
pRfl->disableLogging();
|
||||
|
||||
// Keep looping to here until the count is satisfied or there
|
||||
// are not any more log extent blocks to turn into avail blks.
|
||||
// The loop does a begin transaction - move blocks - set logical
|
||||
// EOF and commits the transaction. During the commit if there are
|
||||
// not any avail blocks left then a log extent (if any) will be turned
|
||||
// into more avail blocks and we can do this again with more avail
|
||||
// blocks.
|
||||
|
||||
// Start a database transaction
|
||||
|
||||
if( RC_BAD(rc = beginTrans( SFLM_UPDATE_TRANS,
|
||||
SFLM_NO_TIMEOUT, SFLM_DONT_POISON_CACHE)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
bTransActive = TRUE;
|
||||
|
||||
// Make sure that commit does something.
|
||||
|
||||
m_bHadUpdOper = TRUE;
|
||||
|
||||
uiBlkSize = m_pDatabase->m_uiBlockSize;
|
||||
|
||||
// Get the logical end of file and use internally.
|
||||
// Loop until there are not any more free blocks left or the
|
||||
// input count is matched. Switch on each block type found
|
||||
// while backing up through the file.
|
||||
|
||||
uiLogicalEOF = m_uiLogicalEOF;
|
||||
|
||||
while (m_uiFirstAvailBlkAddr &&
|
||||
(!uiCount || uiNumBlksMoved < uiCount))
|
||||
{
|
||||
|
||||
// Read the last block and determine block type.
|
||||
|
||||
if( FSGetFileOffset( uiLogicalEOF) == 0)
|
||||
{
|
||||
IF_FileHdl * pFileHdl;
|
||||
FLMUINT uiFileNumber = FSGetFileNumber( uiLogicalEOF) - 1;
|
||||
FLMUINT64 ui64FileSize;
|
||||
FLMUINT64 ui64Temp;
|
||||
|
||||
if (RC_BAD( rc = m_pSFileHdl->getFileHdl(
|
||||
uiFileNumber, TRUE, &pFileHdl)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if (RC_BAD( rc = pFileHdl->size( &ui64FileSize)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Adjust to a block bounds.
|
||||
|
||||
ui64Temp = (ui64FileSize / uiBlkSize) * uiBlkSize;
|
||||
if( ui64Temp < ui64FileSize)
|
||||
{
|
||||
ui64FileSize = ui64Temp + uiBlkSize;
|
||||
}
|
||||
|
||||
uiLogicalEOF = FSBlkAddress( uiFileNumber, (FLMUINT)ui64FileSize);
|
||||
}
|
||||
|
||||
uiBlkAddr = uiLogicalEOF - uiBlkSize;
|
||||
if (RC_BAD( rc = readBlkHdr( uiBlkAddr,
|
||||
(F_BLK_HDR *)&blkHdr, &iType)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
switch (iType)
|
||||
{
|
||||
case BT_FREE:
|
||||
rc = m_pDatabase->freeAvailBlk( this, uiBlkAddr);
|
||||
break;
|
||||
|
||||
case BT_LEAF:
|
||||
case BT_NON_LEAF:
|
||||
case BT_NON_LEAF_COUNTS:
|
||||
case BT_LEAF_DATA:
|
||||
case BT_DATA_ONLY:
|
||||
rc = m_pDatabase->moveBtreeBlk( this, uiBlkAddr,
|
||||
(FLMUINT)blkHdr.all.BTreeBlkHdr.ui16LogicalFile,
|
||||
getBlkLfType( &blkHdr.all.BTreeBlkHdr));
|
||||
break;
|
||||
|
||||
case BT_LFH_BLK:
|
||||
rc = m_pDatabase->moveLFHBlk( this, uiBlkAddr);
|
||||
break;
|
||||
|
||||
default:
|
||||
rc = RC_SET_AND_ASSERT( NE_SFLM_BTREE_ERROR);
|
||||
break;
|
||||
}
|
||||
|
||||
if (RC_BAD(rc))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
uiNumBlksMoved++;
|
||||
|
||||
// Adjust the logical EOF to the new value.
|
||||
// This is complex when dealing with block files.
|
||||
|
||||
if (FSGetFileOffset( uiLogicalEOF) == 0)
|
||||
{
|
||||
FLMUINT uiFileNumber = FSGetFileNumber( uiLogicalEOF);
|
||||
FLMUINT64 ui64FileOffset;
|
||||
IF_FileHdl * pFileHdl;
|
||||
|
||||
if (uiFileNumber <= 1)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// Leave the current file at zero bytes and move to the
|
||||
// previous store file.
|
||||
|
||||
uiFileNumber--;
|
||||
|
||||
// Compute the end of the previous block file.
|
||||
|
||||
if (RC_BAD( rc = m_pSFileHdl->getFileHdl(
|
||||
uiFileNumber, TRUE, &pFileHdl)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if (RC_BAD( rc = pFileHdl->size( &ui64FileOffset)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
uiLogicalEOF = FSBlkAddress( uiFileNumber, (FLMUINT)ui64FileOffset);
|
||||
}
|
||||
uiLogicalEOF -= uiBlkSize;
|
||||
}
|
||||
|
||||
// Log the reduce packet to the RFL if we are not in the middle of a
|
||||
// restore or recovery. Will need to re-enable logging temporarily
|
||||
// and then turn it back off after logging the packet.
|
||||
|
||||
pRfl->enableLogging();
|
||||
|
||||
// Log the reduce.
|
||||
|
||||
if( RC_BAD( rc = pRfl->logReduce( this, uiCount)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Turn logging back off.
|
||||
|
||||
pRfl->disableLogging();
|
||||
|
||||
if (RC_BAD( rc))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Commit the transaction.
|
||||
|
||||
if (m_uiFlags & FDB_DO_TRUNCATE)
|
||||
{
|
||||
bFlagSet = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
bFlagSet = FALSE;
|
||||
m_uiFlags |= FDB_DO_TRUNCATE;
|
||||
}
|
||||
|
||||
bTransActive = FALSE;
|
||||
rc = commitTrans( uiLogicalEOF, TRUE);
|
||||
|
||||
if (!bFlagSet)
|
||||
{
|
||||
m_uiFlags &= (~(FDB_DO_TRUNCATE));
|
||||
}
|
||||
|
||||
if (RC_BAD( rc))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
Exit:
|
||||
|
||||
if( RC_BAD( rc) && bTransActive)
|
||||
{
|
||||
(void)abortTrans();
|
||||
uiNumBlksMoved = 0;
|
||||
}
|
||||
|
||||
if (puiCount)
|
||||
{
|
||||
// May be more than the count requested.
|
||||
|
||||
*puiCount = uiNumBlksMoved;
|
||||
}
|
||||
|
||||
if (bEnableLogging)
|
||||
{
|
||||
pRfl->enableLogging();
|
||||
}
|
||||
|
||||
if (bLockedDb)
|
||||
{
|
||||
(void)m_pDatabase->m_pDatabaseLockObj->Unlock( TRUE, this);
|
||||
m_uiFlags &= ~FDB_HAS_FILE_LOCK;
|
||||
}
|
||||
|
||||
return( rc);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Desc: Read the block header and return the type of block it is
|
||||
****************************************************************************/
|
||||
RCODE F_Db::readBlkHdr(
|
||||
FLMUINT uiBlkAddress,
|
||||
F_BLK_HDR * pBlkHdr,
|
||||
FLMINT * piType
|
||||
)
|
||||
{
|
||||
RCODE rc = NE_SFLM_OK;
|
||||
FLMUINT uiBytesRead;
|
||||
FLMUINT uiNumLooks;
|
||||
IF_FileHdl * pTmpFileHdl = NULL;
|
||||
F_CachedBlock * pBlkSCache;
|
||||
SFLM_LFILE_STATS * pLFileStats;
|
||||
F_TMSTAMP StartTime;
|
||||
FLMUINT64 ui64ElapMilli = 0;
|
||||
|
||||
// First see if the block is in cache.
|
||||
// Previous writes may not have been forced out to cache.
|
||||
|
||||
if (RC_BAD( rc = m_pDatabase->getBlock( this, NULL, uiBlkAddress,
|
||||
&uiNumLooks, &pBlkSCache)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if (pBlkSCache) // If found in cache ...
|
||||
{
|
||||
f_memcpy( pBlkHdr, pBlkSCache->getBlockPtr(), SIZEOF_LARGEST_BLK_HDR);
|
||||
ScaReleaseCache( pBlkSCache, FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_pDbStats)
|
||||
{
|
||||
ui64ElapMilli = 0;
|
||||
f_timeGetTimeStamp( &StartTime);
|
||||
}
|
||||
|
||||
if (RC_OK( rc = m_pSFileHdl->getFileHdl(
|
||||
FSGetFileNumber( uiBlkAddress), TRUE, &pTmpFileHdl)))
|
||||
{
|
||||
rc = pTmpFileHdl->read( FSGetFileOffset( uiBlkAddress),
|
||||
SIZEOF_LARGEST_BLK_HDR, pBlkHdr, &uiBytesRead);
|
||||
}
|
||||
|
||||
if (m_pDbStats)
|
||||
{
|
||||
flmAddElapTime( &StartTime, &ui64ElapMilli);
|
||||
if (RC_BAD( rc))
|
||||
{
|
||||
m_pDbStats->bHaveStats = TRUE;
|
||||
m_pDbStats->uiReadErrors++;
|
||||
}
|
||||
}
|
||||
|
||||
// Convert the block header if necessary.
|
||||
|
||||
if (blkIsNonNativeFormat( pBlkHdr))
|
||||
{
|
||||
convertBlkHdr( pBlkHdr);
|
||||
}
|
||||
|
||||
if (m_pDbStats && RC_OK( rc))
|
||||
{
|
||||
FLMUINT uiLFileNum;
|
||||
SFLM_BLOCKIO_STATS * pBlockIOStats;
|
||||
|
||||
uiLFileNum = (FLMUINT)((F_BTREE_BLK_HDR *)pBlkHdr)->ui16LogicalFile;
|
||||
if (!uiLFileNum)
|
||||
{
|
||||
pLFileStats = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if( RC_BAD( flmStatGetLFile( m_pDbStats,
|
||||
uiLFileNum,
|
||||
getBlkLfType((F_BTREE_BLK_HDR *)pBlkHdr),
|
||||
0,
|
||||
&pLFileStats, NULL, NULL)))
|
||||
{
|
||||
pLFileStats = NULL;
|
||||
}
|
||||
}
|
||||
if ((pBlockIOStats = flmGetBlockIOStatPtr( m_pDbStats,
|
||||
pLFileStats, (FLMBYTE *)pBlkHdr)) != NULL)
|
||||
{
|
||||
m_pDbStats->bHaveStats = TRUE;
|
||||
if (pLFileStats)
|
||||
{
|
||||
pLFileStats->bHaveStats = TRUE;
|
||||
}
|
||||
pBlockIOStats->BlockReads.ui64ElapMilli += ui64ElapMilli;
|
||||
pBlockIOStats->BlockReads.ui64Count++;
|
||||
pBlockIOStats->BlockReads.ui64TotalBytes += SIZEOF_LARGEST_BLK_HDR;
|
||||
}
|
||||
}
|
||||
|
||||
if (RC_BAD( rc))
|
||||
{
|
||||
if (rc != NE_FLM_IO_END_OF_FILE && rc != NE_SFLM_MEM)
|
||||
{
|
||||
m_pSFileHdl->releaseFile( FSGetFileNumber( uiBlkAddress),
|
||||
TRUE);
|
||||
}
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
|
||||
if (piType)
|
||||
{
|
||||
*piType = (FLMINT)pBlkHdr->ui8BlkType;
|
||||
}
|
||||
|
||||
Exit:
|
||||
|
||||
return( rc );
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Desc: Find where in the b-tree a matching block is located. Move to
|
||||
a free block and change all pointers to the block.
|
||||
Notes: Some of this code could be called in movePcodeLFHBlk but we have
|
||||
to worry about if the block is a root or right most leaf block.
|
||||
****************************************************************************/
|
||||
RCODE F_Database::moveBtreeBlk(
|
||||
F_Db * pDb,
|
||||
FLMUINT uiBlkAddr,
|
||||
FLMUINT uiLfNumber,
|
||||
eLFileType eLfType)
|
||||
{
|
||||
RCODE rc;
|
||||
F_INDEX * pIndex;
|
||||
LFILE * pLFile;
|
||||
F_TABLE * pTable = NULL;
|
||||
F_CachedBlock * pFreeSCache = NULL;
|
||||
FLMBOOL bReleaseCache = FALSE;
|
||||
F_Btree * pbtree = NULL;
|
||||
FLMBOOL bHaveCounts;
|
||||
FLMBOOL bHaveData;
|
||||
IXKeyCompare compareObject;
|
||||
IF_ResultSetCompare * pCompareObject = NULL;
|
||||
|
||||
// Get an F_Btree object
|
||||
|
||||
if (RC_BAD( rc = gv_SFlmSysData.pBtPool->btpReserveBtree( &pbtree)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if (eLfType == SFLM_LF_TABLE)
|
||||
{
|
||||
if ((pTable = pDb->m_pDict->getTable( uiLfNumber)) == NULL)
|
||||
{
|
||||
rc = RC_SET( NE_SFLM_INVALID_TABLE_NUM);
|
||||
goto Exit;
|
||||
}
|
||||
pLFile = &pTable->lfInfo;
|
||||
bHaveCounts = FALSE;
|
||||
bHaveData = TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((pIndex = pDb->m_pDict->getIndex( uiLfNumber)) == NULL)
|
||||
{
|
||||
rc = RC_SET( NE_SFLM_INVALID_INDEX_NUM);
|
||||
goto Exit;
|
||||
}
|
||||
pLFile = &pIndex->lfInfo;
|
||||
bHaveCounts = (pIndex->uiFlags & IXD_ABS_POS) ? TRUE : FALSE;
|
||||
bHaveData = (pIndex->uiNumDataComponents) ? TRUE : FALSE;
|
||||
|
||||
pCompareObject = &compareObject;
|
||||
compareObject.setIxInfo( pDb, pIndex);
|
||||
}
|
||||
|
||||
// Need to make sure that LFILE is up to date.
|
||||
// Force reading it in.
|
||||
|
||||
if (RC_BAD( rc = lFileRead( pDb, pLFile)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// If we are moving the root block, create a new dictionary so
|
||||
// that the LFILE can be modified safely to point to the new
|
||||
// root block.
|
||||
|
||||
if (pLFile->uiRootBlk == uiBlkAddr)
|
||||
{
|
||||
|
||||
// Create a new dictionary
|
||||
|
||||
if (!(pDb->m_uiFlags & FDB_UPDATED_DICTIONARY))
|
||||
{
|
||||
if (RC_BAD( rc = pDb->dictClone()))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Re-get the LFile
|
||||
|
||||
if (eLfType == SFLM_LF_TABLE)
|
||||
{
|
||||
pTable = pDb->m_pDict->getTable( uiLfNumber);
|
||||
flmAssert( pTable);
|
||||
pLFile = &pTable->lfInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
pIndex = pDb->m_pDict->getIndex( uiLfNumber);
|
||||
flmAssert( pIndex);
|
||||
pLFile = &pIndex->lfInfo;
|
||||
pCompareObject = &compareObject;
|
||||
compareObject.setIxInfo( pDb, pIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (RC_BAD( rc = pbtree->btOpen( pDb, pLFile, bHaveCounts, bHaveData,
|
||||
pCompareObject)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Get the next free block.
|
||||
|
||||
if (RC_BAD( rc = blockUseNextAvail( pDb, &pFreeSCache)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
bReleaseCache = TRUE;
|
||||
|
||||
// Move B-tree block to free block.
|
||||
|
||||
if (RC_BAD( rc = pbtree->btMoveBlock( (FLMUINT32)uiBlkAddr,
|
||||
(FLMUINT32)pFreeSCache->m_uiBlkAddress)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
Exit:
|
||||
|
||||
if (bReleaseCache)
|
||||
{
|
||||
ScaReleaseCache( pFreeSCache, FALSE);
|
||||
}
|
||||
|
||||
if (pbtree)
|
||||
{
|
||||
gv_SFlmSysData.pBtPool->btpReturnBtree( &pbtree);
|
||||
}
|
||||
|
||||
if( RC_BAD( rc))
|
||||
{
|
||||
pDb->setMustAbortTrans( rc);
|
||||
}
|
||||
|
||||
return( rc);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Desc: Find where anb LFH input block is located. Move to
|
||||
a free block and change all pointers to the block.
|
||||
****************************************************************************/
|
||||
RCODE F_Database::moveLFHBlk(
|
||||
F_Db * pDb,
|
||||
FLMUINT uiBlkAddr)
|
||||
{
|
||||
RCODE rc;
|
||||
F_CachedBlock * pSCache;
|
||||
FLMBOOL bReleaseCache = FALSE;
|
||||
F_CachedBlock * pFreeSCache = NULL;
|
||||
FLMBOOL bReleaseCache2 = FALSE;
|
||||
F_BLK_HDR * pBlkHdr;
|
||||
F_LF_HDR * pLfHdr;
|
||||
F_BLK_HDR * pFreeBlkHdr;
|
||||
FLMUINT uiLeftBlkAddr;
|
||||
FLMUINT uiRightBlkAddr;
|
||||
FLMUINT uiFreeBlkAddr;
|
||||
FLMUINT uiSavePriorBlkImgAddr;
|
||||
FLMUINT uiPos;
|
||||
FLMUINT uiEndPos;
|
||||
F_TABLE * pTmpTable;
|
||||
F_INDEX * pTmpIndex;
|
||||
LFILE * pTmpLFile;
|
||||
|
||||
if (RC_BAD( rc = getBlock( pDb, NULL, uiBlkAddr, NULL, &pSCache)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
bReleaseCache = TRUE;
|
||||
|
||||
if (RC_BAD( rc = logPhysBlk( pDb, &pSCache)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
pBlkHdr = pSCache->m_pBlkHdr;
|
||||
|
||||
// Get left and rigth block addresses.
|
||||
// Get next avail block and move data over
|
||||
|
||||
uiLeftBlkAddr = (FLMUINT)pBlkHdr->ui32PrevBlkInChain;
|
||||
uiRightBlkAddr = (FLMUINT)pBlkHdr->ui32NextBlkInChain;
|
||||
|
||||
if (RC_BAD( rc = blockUseNextAvail( pDb, &pFreeSCache)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
bReleaseCache2 = TRUE;
|
||||
|
||||
pFreeBlkHdr = pFreeSCache->m_pBlkHdr;
|
||||
uiFreeBlkAddr = (FLMUINT)pFreeBlkHdr->ui32BlkAddr;
|
||||
|
||||
// The free block has been logged and set to dirty in
|
||||
// blockUseNextAvail().
|
||||
// BUT, need to preserve prior image block address - it should
|
||||
// NOT be copied over from the block we are switching with.
|
||||
|
||||
uiSavePriorBlkImgAddr = (FLMUINT)pFreeBlkHdr->ui32PriorBlkImgAddr;
|
||||
|
||||
f_memcpy( pFreeBlkHdr, pBlkHdr, m_uiBlockSize);
|
||||
pFreeBlkHdr->ui32BlkAddr = (FLMUINT32)uiFreeBlkAddr;
|
||||
|
||||
// Restore the saved previous transaction ID and block address.
|
||||
|
||||
pFreeBlkHdr->ui32PriorBlkImgAddr = (FLMUINT32)uiSavePriorBlkImgAddr;
|
||||
|
||||
// Fix up any LFile entries that were pointing to the
|
||||
// original LFH block
|
||||
|
||||
uiPos = SIZEOF_STD_BLK_HDR;
|
||||
uiEndPos = blkGetEnd( m_uiBlockSize, SIZEOF_STD_BLK_HDR, pFreeBlkHdr);
|
||||
|
||||
// Create a new dictionary
|
||||
|
||||
if (!(pDb->m_uiFlags & FDB_UPDATED_DICTIONARY))
|
||||
{
|
||||
if (RC_BAD( rc = pDb->dictClone()))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
|
||||
// Iterate over the set of LFiles in the block and
|
||||
// update their LFH block addresses
|
||||
|
||||
pLfHdr = (F_LF_HDR *)((FLMBYTE *)pFreeBlkHdr + SIZEOF_STD_BLK_HDR);
|
||||
while (uiPos < uiEndPos)
|
||||
{
|
||||
if (pLfHdr->ui32LfType != (FLMUINT32)SFLM_LF_INVALID)
|
||||
{
|
||||
if (pLfHdr->ui32LfType == (FLMUINT32)SFLM_LF_TABLE)
|
||||
{
|
||||
if ((pTmpTable = pDb->m_pDict->getTable(
|
||||
(FLMUINT)pLfHdr->ui32LfNum)) == NULL)
|
||||
{
|
||||
rc = RC_SET_AND_ASSERT( NE_SFLM_DATA_ERROR);
|
||||
goto Exit;
|
||||
}
|
||||
pTmpLFile = &pTmpTable->lfInfo;
|
||||
}
|
||||
else
|
||||
{
|
||||
flmAssert( pLfHdr->ui32LfType == (FLMUINT32)SFLM_LF_INDEX);
|
||||
if ((pTmpIndex = pDb->m_pDict->getIndex(
|
||||
(FLMUINT)pLfHdr->ui32LfNum)) == NULL)
|
||||
{
|
||||
rc = RC_SET_AND_ASSERT( NE_SFLM_DATA_ERROR);
|
||||
goto Exit;
|
||||
}
|
||||
pTmpLFile = &pTmpIndex->lfInfo;
|
||||
}
|
||||
|
||||
pTmpLFile->uiBlkAddress = uiFreeBlkAddr;
|
||||
}
|
||||
uiPos += sizeof( F_LF_HDR);
|
||||
pLfHdr++;
|
||||
}
|
||||
|
||||
// Done with both blocks.
|
||||
|
||||
ScaReleaseCache( pFreeSCache, FALSE);
|
||||
ScaReleaseCache( pSCache, FALSE);
|
||||
bReleaseCache2 = bReleaseCache = FALSE;
|
||||
|
||||
// Read left and right blocks and adjust their
|
||||
// pointers to point to the new block.
|
||||
// This doesn't matter what level of the b-tree
|
||||
// you are on.
|
||||
|
||||
if (uiLeftBlkAddr)
|
||||
{
|
||||
if (RC_BAD( rc = getBlock( pDb, NULL, uiLeftBlkAddr,
|
||||
NULL, &pSCache)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
bReleaseCache = TRUE;
|
||||
if (RC_BAD( rc = logPhysBlk( pDb, &pSCache)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
pSCache->m_pBlkHdr->ui32NextBlkInChain = (FLMUINT32)uiFreeBlkAddr;
|
||||
ScaReleaseCache( pSCache, FALSE);
|
||||
bReleaseCache = FALSE;
|
||||
}
|
||||
|
||||
if (uiRightBlkAddr)
|
||||
{
|
||||
if (RC_BAD( rc = getBlock( pDb, NULL, uiRightBlkAddr,
|
||||
NULL, &pSCache)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
bReleaseCache = TRUE;
|
||||
if (RC_BAD( rc = logPhysBlk( pDb, &pSCache)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
pSCache->m_pBlkHdr->ui32PrevBlkInChain = (FLMUINT32)uiFreeBlkAddr;
|
||||
ScaReleaseCache( pSCache, FALSE);
|
||||
bReleaseCache = FALSE;
|
||||
}
|
||||
|
||||
Exit:
|
||||
|
||||
if (bReleaseCache)
|
||||
{
|
||||
ScaReleaseCache( pSCache, FALSE);
|
||||
}
|
||||
|
||||
if (bReleaseCache2)
|
||||
{
|
||||
ScaReleaseCache( pFreeSCache, FALSE);
|
||||
}
|
||||
|
||||
if( RC_BAD( rc))
|
||||
{
|
||||
pDb->setMustAbortTrans( rc);
|
||||
}
|
||||
|
||||
return( rc);
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
Desc: Free the input avail block. Link the block out of the free list
|
||||
****************************************************************************/
|
||||
RCODE F_Database::freeAvailBlk(
|
||||
F_Db * pDb,
|
||||
FLMUINT uiBlkAddr)
|
||||
{
|
||||
RCODE rc = NE_SFLM_OK;
|
||||
F_LARGEST_BLK_HDR blkHdr;
|
||||
FLMUINT uiPrevBlkAddr;
|
||||
FLMUINT uiNextBlkAddr;
|
||||
F_CachedBlock * pSCache;
|
||||
|
||||
// Check for first avail block condition.
|
||||
|
||||
if (uiBlkAddr == pDb->m_uiFirstAvailBlkAddr)
|
||||
{
|
||||
if (RC_OK( rc = blockUseNextAvail( pDb, &pSCache)))
|
||||
{
|
||||
ScaReleaseCache( pSCache, FALSE);
|
||||
}
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Not first block, unlink from list.
|
||||
|
||||
// Read the block header and get pointers
|
||||
|
||||
if (RC_BAD( rc = pDb->readBlkHdr( uiBlkAddr,
|
||||
(F_BLK_HDR *)&blkHdr, (FLMINT *)0)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
uiPrevBlkAddr = (FLMUINT)blkHdr.all.stdBlkHdr.ui32PrevBlkInChain;
|
||||
uiNextBlkAddr = (FLMUINT)blkHdr.all.stdBlkHdr.ui32NextBlkInChain;
|
||||
|
||||
// Read the previous block, if any
|
||||
|
||||
if (uiPrevBlkAddr)
|
||||
{
|
||||
if (RC_BAD( rc = getBlock( pDb, NULL, uiPrevBlkAddr,
|
||||
NULL, &pSCache)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Log the block before modifying it.
|
||||
|
||||
if (RC_OK( rc = logPhysBlk( pDb, &pSCache)))
|
||||
{
|
||||
pSCache->m_pBlkHdr->ui32NextBlkInChain = (FLMUINT32)uiNextBlkAddr;
|
||||
}
|
||||
ScaReleaseCache( pSCache, FALSE);
|
||||
if (RC_BAD( rc))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
|
||||
// Read the next block, if any.
|
||||
|
||||
if (uiNextBlkAddr)
|
||||
{
|
||||
if (RC_BAD( rc = getBlock( pDb, NULL, uiNextBlkAddr,
|
||||
NULL, &pSCache)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Log the block before modifying it.
|
||||
|
||||
if (RC_OK( rc = logPhysBlk( pDb, &pSCache)))
|
||||
{
|
||||
pSCache->m_pBlkHdr->ui32PrevBlkInChain = (FLMUINT32)uiPrevBlkAddr;
|
||||
}
|
||||
ScaReleaseCache( pSCache, FALSE);
|
||||
if (RC_BAD( rc))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
|
||||
Exit:
|
||||
|
||||
return( rc);
|
||||
}
|
||||
Reference in New Issue
Block a user