git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@7 0109f412-320b-0410-ab79-c3e0c5ffbbe6
649 lines
14 KiB
C++
649 lines
14 KiB
C++
//------------------------------------------------------------------------------
|
|
// Desc: Routines for reading and writing logical file headers.
|
|
//
|
|
// Tabs: 3
|
|
//
|
|
// Copyright (c) 1991-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: fslfile.cpp 3114 2006-01-19 13:22:45 -0700 (Thu, 19 Jan 2006) dsanders $
|
|
//------------------------------------------------------------------------------
|
|
|
|
#include "flaimsys.h"
|
|
|
|
FSTATIC FLMUINT FSLFileFindEmpty(
|
|
FLMUINT uiBlockSize,
|
|
F_BLK_HDR * pBlkHdr);
|
|
|
|
/***************************************************************************
|
|
Desc: Searches a block for an empty LFH slot. This is called whenever
|
|
a new logical file is create so we re-use the slots.
|
|
Ret: 0-Empty slot not found
|
|
non-zero - offset in the block of the empty slot
|
|
***************************************************************************/
|
|
FSTATIC FLMUINT FSLFileFindEmpty(
|
|
FLMUINT uiBlockSize,
|
|
F_BLK_HDR * pBlkHdr)
|
|
{
|
|
FLMUINT uiPos = SIZEOF_STD_BLK_HDR;
|
|
FLMUINT uiEndPos = blkGetEnd( uiBlockSize, SIZEOF_STD_BLK_HDR,
|
|
pBlkHdr);
|
|
F_LF_HDR * pLfHdr = (F_LF_HDR *)((FLMBYTE *)pBlkHdr + SIZEOF_STD_BLK_HDR);
|
|
|
|
while (uiPos < uiEndPos)
|
|
{
|
|
if (pLfHdr->ui32LfType == XFLM_LF_INVALID)
|
|
{
|
|
break;
|
|
}
|
|
|
|
uiPos += sizeof( F_LF_HDR);
|
|
pLfHdr++;
|
|
}
|
|
return( (uiPos < uiEndPos) ? uiPos : 0);
|
|
}
|
|
|
|
/***************************************************************************
|
|
Desc: Retrieves the logical file header record from disk & updates LFILE.
|
|
Called when it is discovered that the LFH for a
|
|
particular logical file is out of date.
|
|
*****************************************************************************/
|
|
RCODE F_Database::lFileRead(
|
|
F_Db * pDb,
|
|
LFILE * pLFile,
|
|
F_COLLECTION * pCollection
|
|
)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_CachedBlock * pSCache;
|
|
FLMBOOL bReleaseCache = FALSE;
|
|
|
|
// Read in the block containing the logical file header
|
|
|
|
if (RC_BAD( rc = getBlock( pDb, NULL,
|
|
pLFile->uiBlkAddress, NULL, &pSCache)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
bReleaseCache = TRUE;
|
|
|
|
// Copy the LFH from the block to the LFILE
|
|
|
|
FSLFileIn( (FLMBYTE *)(pSCache->m_pBlkHdr) + pLFile->uiOffsetInBlk,
|
|
pLFile, pCollection, pLFile->uiBlkAddress, pLFile->uiOffsetInBlk);
|
|
|
|
Exit:
|
|
|
|
if (bReleaseCache)
|
|
{
|
|
ScaReleaseCache( pSCache, FALSE);
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/***************************************************************************
|
|
Desc: Update the LFH data on disk.
|
|
*****************************************************************************/
|
|
RCODE F_Database::lFileWrite(
|
|
F_Db * pDb,
|
|
F_COLLECTION * pCollection,
|
|
LFILE * pLFile)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_CachedBlock * pSCache;
|
|
FLMBOOL bReleaseCache = FALSE;
|
|
F_LF_HDR * pLfHdr;
|
|
#ifdef DEBUG
|
|
F_CachedBlock * pTmpSCache = NULL;
|
|
#endif
|
|
|
|
flmAssert( !pDb->m_pDatabase->m_pRfl ||
|
|
!pDb->m_pDatabase->m_pRfl->isLoggingEnabled());
|
|
|
|
// Read in the block containing the logical file header
|
|
|
|
if (RC_BAD( rc = getBlock( pDb, NULL,
|
|
pLFile->uiBlkAddress, NULL, &pSCache)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
bReleaseCache = TRUE;
|
|
|
|
// Log the block before modifying it
|
|
|
|
if (RC_BAD( rc = logPhysBlk( pDb, &pSCache)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Now modify the block and set its status to dirty
|
|
|
|
pLfHdr = (F_LF_HDR *)((FLMBYTE *)(pSCache->m_pBlkHdr) +
|
|
pLFile->uiOffsetInBlk);
|
|
|
|
// If deleted, fill with 0, except for type - it is set below
|
|
|
|
if (pLFile->eLfType == XFLM_LF_INVALID)
|
|
{
|
|
f_memset( pLfHdr, 0, sizeof( F_LF_HDR));
|
|
pLfHdr->ui32LfType = XFLM_LF_INVALID;
|
|
}
|
|
else
|
|
{
|
|
|
|
pLfHdr->ui32LfNumber = (FLMUINT32)pLFile->uiLfNum;
|
|
pLfHdr->ui32LfType = (FLMUINT32)pLFile->eLfType;
|
|
pLfHdr->ui32EncId = (FLMUINT32)pLFile->uiEncId;
|
|
|
|
#ifdef DEBUG
|
|
if (RC_BAD( rc = getBlock( pDb, NULL,
|
|
pLFile->uiRootBlk, NULL, &pTmpSCache)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if (!isRootBlk( (F_BTREE_BLK_HDR *)pTmpSCache->m_pBlkHdr))
|
|
{
|
|
rc = RC_SET_AND_ASSERT( NE_XFLM_DATA_ERROR);
|
|
}
|
|
#endif
|
|
|
|
pLfHdr->ui32RootBlkAddr = (FLMUINT32)pLFile->uiRootBlk;
|
|
|
|
if (pCollection)
|
|
{
|
|
flmAssert( pLFile == &pCollection->lfInfo);
|
|
flmAssert( pLFile->eLfType == XFLM_LF_COLLECTION);
|
|
pLfHdr->ui64NextNodeId = pCollection->ui64NextNodeId;
|
|
pLfHdr->ui64FirstDocId = pCollection->ui64FirstDocId;
|
|
pLfHdr->ui64LastDocId = pCollection->ui64LastDocId;
|
|
pCollection->bNeedToUpdateNodes = FALSE;
|
|
}
|
|
else
|
|
{
|
|
flmAssert( pLFile->eLfType == XFLM_LF_INDEX);
|
|
pLfHdr->ui64NextNodeId = 0;
|
|
pLfHdr->ui64FirstDocId = 0;
|
|
pLfHdr->ui64LastDocId = 0;
|
|
}
|
|
}
|
|
|
|
// If the LFILE was deleted, we need to set pLFile->uiLfNum to zero.
|
|
// This should happen only AFTER the LFILE update is logged, because
|
|
// logLFileUpdate relies on pLFile->uiLfNum being non-zero.
|
|
|
|
if (pLFile->eLfType == XFLM_LF_INVALID)
|
|
{
|
|
pLFile->uiLfNum = 0;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if (bReleaseCache)
|
|
{
|
|
ScaReleaseCache( pSCache, FALSE);
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
if (pTmpSCache)
|
|
{
|
|
ScaReleaseCache( pTmpSCache, FALSE);
|
|
}
|
|
#endif
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/***************************************************************************
|
|
Desc: Creates and initializes a LFILE structure on disk and in memory.
|
|
*****************************************************************************/
|
|
RCODE F_Database::lFileCreate(
|
|
F_Db * pDb,
|
|
LFILE * pLFile,
|
|
F_COLLECTION * pCollection,
|
|
FLMUINT uiLfNum,
|
|
eLFileType eLfType,
|
|
FLMBOOL bCounts,
|
|
FLMBOOL bHaveData,
|
|
FLMUINT uiEncId)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_CachedBlock * pNewSCache;
|
|
F_CachedBlock * pSCache = NULL;
|
|
F_BLK_HDR * pBlkHdr;
|
|
FLMUINT uiBlkAddress;
|
|
FLMUINT uiNextBlkAddress;
|
|
FLMUINT uiEndPos;
|
|
FLMUINT uiPos;
|
|
FLMBOOL bReleaseCache2 = FALSE;
|
|
FLMBOOL bReleaseCache = FALSE;
|
|
F_Btree * pbTree = NULL;
|
|
|
|
flmAssert( !pDb->m_pDatabase->m_pRfl ||
|
|
!pDb->m_pDatabase->m_pRfl->isLoggingEnabled());
|
|
|
|
if (eLfType == XFLM_LF_COLLECTION)
|
|
{
|
|
if( bCounts)
|
|
{
|
|
// Force bCounts to be FALSE in this case
|
|
flmAssert( 0);
|
|
bCounts = FALSE;
|
|
}
|
|
|
|
if( !bHaveData)
|
|
{
|
|
// Force bHaveData to be TRUE in this case
|
|
flmAssert( 0);
|
|
bHaveData = TRUE;
|
|
}
|
|
}
|
|
|
|
// Find an available slot to create the LFH -- follow the linked list
|
|
// of LFH blocks to find one.
|
|
|
|
uiNextBlkAddress = (FLMUINT)m_uncommittedDbHdr.ui32FirstLFBlkAddr;
|
|
|
|
// Better be at least one LFH block.
|
|
|
|
if (uiNextBlkAddress == 0)
|
|
{
|
|
rc = RC_SET( NE_XFLM_DATA_ERROR);
|
|
goto Exit;
|
|
}
|
|
|
|
while (uiNextBlkAddress != 0)
|
|
{
|
|
if (bReleaseCache)
|
|
{
|
|
ScaReleaseCache( pSCache, FALSE);
|
|
bReleaseCache = FALSE;
|
|
}
|
|
uiBlkAddress = uiNextBlkAddress;
|
|
|
|
if (RC_BAD( rc = getBlock( pDb, NULL,
|
|
uiBlkAddress, NULL, &pSCache)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
bReleaseCache = TRUE;
|
|
|
|
pBlkHdr = pSCache->m_pBlkHdr;
|
|
uiNextBlkAddress = (FLMUINT)pBlkHdr->ui32NextBlkInChain;
|
|
uiEndPos = blkGetEnd( m_uiBlockSize, SIZEOF_STD_BLK_HDR, pBlkHdr);
|
|
if ((uiPos = FSLFileFindEmpty( m_uiBlockSize, pBlkHdr)) != 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
// If we did not find a deleted slot we can use, see if there
|
|
// is room for a new logical file in the last block
|
|
// in the chain. If not, allocate a new block.
|
|
|
|
if (uiPos == 0)
|
|
{
|
|
uiEndPos = blkGetEnd( m_uiBlockSize, SIZEOF_STD_BLK_HDR, pBlkHdr);
|
|
|
|
// Allocate new block?
|
|
|
|
if (uiEndPos + sizeof( F_LF_HDR) >= m_uiBlockSize)
|
|
{
|
|
if (RC_BAD( rc = createBlock( pDb, &pNewSCache)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
bReleaseCache2 = TRUE;
|
|
|
|
pBlkHdr = pNewSCache->m_pBlkHdr;
|
|
uiNextBlkAddress = (FLMUINT)pBlkHdr->ui32BlkAddr;
|
|
|
|
// Modify the new block's next pointer and other fields.
|
|
|
|
pBlkHdr->ui32NextBlkInChain = 0;
|
|
pBlkHdr->ui32PrevBlkInChain = (FLMUINT32)uiBlkAddress;
|
|
pBlkHdr->ui8BlkType = BT_LFH_BLK;
|
|
pBlkHdr->ui16BlkBytesAvail = (FLMUINT16)(m_uiBlockSize -
|
|
SIZEOF_STD_BLK_HDR);
|
|
|
|
if (RC_BAD( rc = logPhysBlk( pDb, &pSCache)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
pSCache->m_pBlkHdr->ui32NextBlkInChain = (FLMUINT32)uiNextBlkAddress;
|
|
|
|
// Set everything up so we are pointing to the new block.
|
|
|
|
ScaReleaseCache( pSCache, FALSE);
|
|
pSCache = pNewSCache;
|
|
bReleaseCache2 = FALSE;
|
|
uiEndPos = blkGetEnd( m_uiBlockSize, SIZEOF_STD_BLK_HDR,
|
|
pSCache->m_pBlkHdr);
|
|
uiBlkAddress = uiNextBlkAddress;
|
|
}
|
|
|
|
// Modify the end of block pointer -- log block before modifying.
|
|
|
|
uiPos = uiEndPos;
|
|
uiEndPos += sizeof( F_LF_HDR);
|
|
}
|
|
|
|
// Call memset to ensure unused bytes are zero.
|
|
// pBlkHdr, uiPos and uiEndPos should ALL be set.
|
|
|
|
if (RC_BAD( rc = logPhysBlk( pDb, &pSCache)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
pBlkHdr = pSCache->m_pBlkHdr;
|
|
f_memset( (FLMBYTE *)(pBlkHdr) + uiPos, 0, sizeof( F_LF_HDR));
|
|
flmAssert( uiEndPos >= SIZEOF_STD_BLK_HDR &&
|
|
uiEndPos <= m_uiBlockSize);
|
|
pBlkHdr->ui16BlkBytesAvail = (FLMUINT16)(m_uiBlockSize - uiEndPos);
|
|
|
|
// Done with block in this routine
|
|
|
|
ScaReleaseCache( pSCache, FALSE);
|
|
bReleaseCache = FALSE;
|
|
|
|
// Set the variables in the LFILE structure to later save to disk
|
|
|
|
pLFile->uiLfNum = uiLfNum;
|
|
pLFile->eLfType = eLfType;
|
|
pLFile->uiBlkAddress = uiBlkAddress;
|
|
pLFile->uiOffsetInBlk = uiPos;
|
|
pLFile->uiEncId = uiEncId;
|
|
if (pCollection)
|
|
{
|
|
pCollection->ui64NextNodeId = 1;
|
|
pCollection->ui64FirstDocId = 0;
|
|
pCollection->ui64LastDocId = 0;
|
|
pCollection->bNeedToUpdateNodes = TRUE;
|
|
}
|
|
|
|
// Get the btree...
|
|
if (RC_BAD( rc = gv_XFlmSysData.pBtPool->btpReserveBtree( &pbTree)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if (RC_BAD( rc = pbTree->btCreate( pDb, pLFile, bCounts, bHaveData)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if (RC_BAD( rc = lFileWrite( pDb, pCollection, pLFile)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if (bReleaseCache)
|
|
{
|
|
ScaReleaseCache( pSCache, FALSE);
|
|
}
|
|
if (bReleaseCache2)
|
|
{
|
|
ScaReleaseCache( pNewSCache, FALSE);
|
|
}
|
|
if (pbTree)
|
|
{
|
|
gv_XFlmSysData.pBtPool->btpReturnBtree( &pbTree);
|
|
}
|
|
return( rc);
|
|
}
|
|
|
|
/***************************************************************************
|
|
Desc: Delete a logical file.
|
|
*****************************************************************************/
|
|
RCODE F_Database::lFileDelete(
|
|
F_Db * pDb,
|
|
F_COLLECTION * pCollection,
|
|
LFILE * pLFile,
|
|
FLMBOOL bCounts,
|
|
FLMBOOL bHaveData)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_Btree * pbTree = NULL;
|
|
F_DOMNode * pDoc = NULL;
|
|
F_DOMNode * pChainNode = NULL;
|
|
F_DOMNode * pAddrNode = NULL;
|
|
FLMUINT uiLoop;
|
|
|
|
flmAssert( pDb->m_uiFlags & FDB_UPDATED_DICTIONARY);
|
|
|
|
// Get a btree
|
|
|
|
if (RC_BAD( rc = gv_XFlmSysData.pBtPool->btpReserveBtree( &pbTree)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Delete the logical file's B-Tree blocks.
|
|
// If there is no root block, no need to do anything.
|
|
|
|
flmAssert( pLFile->uiRootBlk);
|
|
|
|
if (pLFile->eLfType == XFLM_LF_COLLECTION)
|
|
{
|
|
flmAssert( pCollection);
|
|
flmAssert( !bCounts && bHaveData);
|
|
bCounts = FALSE;
|
|
bHaveData = TRUE;
|
|
|
|
if( RC_BAD( rc = pbTree->btOpen( pDb, pLFile, bCounts, bHaveData)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Delete the B-Tree
|
|
|
|
if (RC_BAD( rc = pbTree->btDeleteTree( pDb->m_pDeleteStatus)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FLMUINT puiBlkChains[ BH_MAX_LEVELS];
|
|
FLMUINT uiChainCount;
|
|
|
|
flmAssert( !pCollection);
|
|
flmAssert( pLFile->eLfType == XFLM_LF_INDEX);
|
|
|
|
if( RC_BAD( rc = pbTree->btOpen( pDb, pLFile, bCounts, bHaveData)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pbTree->btGetBlockChains(
|
|
puiBlkChains, &uiChainCount)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Indexes are always deleted in the background.
|
|
// Set up a maintenance document to free the blocks of
|
|
// the B-Tree.
|
|
|
|
if( RC_BAD( rc = pDb->createRootNode( XFLM_MAINT_COLLECTION,
|
|
ELM_DELETE_TAG, ELEMENT_NODE, &pDoc)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
for( uiLoop = 0; uiLoop < uiChainCount; uiLoop++)
|
|
{
|
|
if( RC_BAD( rc = pDoc->createNode( pDb,
|
|
ELEMENT_NODE, ELM_BLOCK_CHAIN_TAG, XFLM_LAST_CHILD,
|
|
(IF_DOMNode **)&pChainNode)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pChainNode->createAttribute(
|
|
pDb, ATTR_ADDRESS_TAG, (IF_DOMNode **)&pAddrNode)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pAddrNode->setUINT(
|
|
pDb, puiBlkChains[ uiLoop])))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pAddrNode->addModeFlags(
|
|
pDb, FDOM_READ_ONLY | FDOM_CANNOT_DELETE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pChainNode->addModeFlags(
|
|
pDb, FDOM_READ_ONLY | FDOM_CANNOT_DELETE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
if( RC_BAD( rc = pDoc->addModeFlags(
|
|
pDb, FDOM_READ_ONLY | FDOM_CANNOT_DELETE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if( RC_BAD( rc = pDb->documentDone( pDoc)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Signal the maintenance thread that it has work to do
|
|
|
|
f_semSignal( m_hMaintSem);
|
|
}
|
|
|
|
// Delete the LFILE entry.
|
|
|
|
pLFile->uiRootBlk = 0;
|
|
pLFile->eLfType = XFLM_LF_INVALID;
|
|
|
|
if( RC_BAD( rc = lFileWrite( pDb, pCollection, pLFile)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( pChainNode)
|
|
{
|
|
pChainNode->Release();
|
|
}
|
|
|
|
if( pAddrNode)
|
|
{
|
|
pAddrNode->Release();
|
|
}
|
|
|
|
if( pDoc)
|
|
{
|
|
pDoc->Release();
|
|
}
|
|
|
|
if( pbTree)
|
|
{
|
|
gv_XFlmSysData.pBtPool->btpReturnBtree( &pbTree);
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/***************************************************************************
|
|
Desc: Set the next node ID for a collection. Must be inside an update
|
|
transaction.
|
|
*****************************************************************************/
|
|
RCODE F_Db::setNextNodeId(
|
|
FLMUINT uiCollection,
|
|
FLMUINT64 ui64NextNodeId)
|
|
{
|
|
RCODE rc = NE_XFLM_OK;
|
|
F_COLLECTION * pCollection;
|
|
F_Rfl * pRfl = m_pDatabase->m_pRfl;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
FLMUINT uiRflToken = 0;
|
|
|
|
if( RC_BAD( rc = checkTransaction( XFLM_UPDATE_TRANS, &bStartedTrans)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Disable RFL logging
|
|
|
|
pRfl->disableLogging( &uiRflToken);
|
|
|
|
// Get a pointer to the collection
|
|
|
|
if (RC_BAD( rc = m_pDict->getCollection( uiCollection, &pCollection)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Set the next NODE ID for the collection
|
|
|
|
if (ui64NextNodeId > pCollection->ui64NextNodeId)
|
|
{
|
|
pCollection->ui64NextNodeId = ui64NextNodeId;
|
|
pCollection->bNeedToUpdateNodes = TRUE;
|
|
}
|
|
|
|
// Log the operation
|
|
|
|
pRfl->enableLogging( &uiRflToken);
|
|
|
|
if( RC_BAD( rc = pRfl->logSetNextNodeId( this, uiCollection, ui64NextNodeId)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if( RC_BAD( rc))
|
|
{
|
|
setMustAbortTrans( rc);
|
|
}
|
|
|
|
if( uiRflToken)
|
|
{
|
|
pRfl->enableLogging( &uiRflToken);
|
|
}
|
|
|
|
if( bStartedTrans)
|
|
{
|
|
if( RC_BAD( rc))
|
|
{
|
|
transAbort();
|
|
}
|
|
else
|
|
{
|
|
rc = transCommit();
|
|
}
|
|
}
|
|
|
|
return( rc);
|
|
}
|