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:
449
sql/src/fltrabrt.cpp
Normal file
449
sql/src/fltrabrt.cpp
Normal file
@@ -0,0 +1,449 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// Desc: Contains routines for aborting a transaction.
|
||||
//
|
||||
// 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: fltrabrt.cpp 3114 2006-01-19 13:22:45 -0700 (Thu, 19 Jan 2006) dsanders $
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "flaimsys.h"
|
||||
|
||||
/****************************************************************************
|
||||
Desc: This routine aborts an active transaction for a particular
|
||||
database. If the database is open via a server, a message is
|
||||
sent to the server to abort the transaction. Otherwise, the
|
||||
transaction is rolled back locally.
|
||||
****************************************************************************/
|
||||
RCODE F_Db::abortTrans(
|
||||
FLMBOOL bOkToLogAbort)
|
||||
{
|
||||
RCODE rc = NE_SFLM_OK;
|
||||
eDbTransType eSaveTransType;
|
||||
SFLM_DB_HDR * pLastCommittedDbHdr;
|
||||
SFLM_DB_HDR * pUncommittedDbHdr;
|
||||
FLMBOOL bDumpedCache = FALSE;
|
||||
FLMBOOL bKeepAbortedTrans;
|
||||
FLMUINT64 ui64TransId;
|
||||
F_Rfl * pRfl = m_pDatabase->m_pRfl;
|
||||
RCODE tmpRc;
|
||||
|
||||
// Should never be calling on a temporary database.
|
||||
|
||||
flmAssert( !m_pDatabase->m_bTempDb);
|
||||
|
||||
// Get transaction type
|
||||
|
||||
if (m_eTransType == SFLM_NO_TRANS)
|
||||
{
|
||||
goto Exit; // Will return SUCCESS.
|
||||
}
|
||||
|
||||
// No recovery required if it is a read transaction.
|
||||
|
||||
if (m_eTransType == SFLM_READ_TRANS)
|
||||
{
|
||||
if (m_bKrefSetup)
|
||||
{
|
||||
// krefCntrlFree could be called w/o checking bKrefSetup because
|
||||
// it checks the flag, but it is more optimal to check the
|
||||
// flag before making the call because most of the time it will
|
||||
// be false.
|
||||
|
||||
krefCntrlFree();
|
||||
}
|
||||
|
||||
goto Unlink_From_Trans;
|
||||
}
|
||||
|
||||
#ifdef FLM_DBG_LOG
|
||||
flmDbgLogUpdate( m_pDatabase, m_ui64CurrTransID,
|
||||
0, 0, NE_SFLM_OK, "TAbrt");
|
||||
#endif
|
||||
|
||||
// Disable DB header writes
|
||||
|
||||
pRfl->clearDbHdrs();
|
||||
|
||||
// If the transaction had no update operations, restore it
|
||||
// to its pre-transaction state - make it appear that no
|
||||
// transaction ever happened.
|
||||
|
||||
pLastCommittedDbHdr = &m_pDatabase->m_lastCommittedDbHdr;
|
||||
pUncommittedDbHdr = &m_pDatabase->m_uncommittedDbHdr;
|
||||
ui64TransId = m_ui64CurrTransID;
|
||||
|
||||
// Free up all keys associated with this database. This is done even
|
||||
// if we didn't have any update operations because the KREF may
|
||||
// have been initialized by key generation operations performed
|
||||
// by cursors, etc.
|
||||
|
||||
krefCntrlFree();
|
||||
|
||||
if (m_bHadUpdOper)
|
||||
{
|
||||
|
||||
// Dump any start and stop indexing stubs that should be aborted.
|
||||
|
||||
indexingAfterAbort();
|
||||
|
||||
// Log the abort record to the rfl file, or throw away the logged
|
||||
// records altogether, depending on the LOG_KEEP_ABORTED_TRANS_IN_RFL
|
||||
// flag. If the RFL volume is bad, we will not attempt to keep this
|
||||
// transaction in the RFL.
|
||||
|
||||
if (!pRfl->seeIfRflVolumeOk())
|
||||
{
|
||||
bKeepAbortedTrans = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
bKeepAbortedTrans =
|
||||
(pUncommittedDbHdr->ui8RflKeepAbortedTrans)
|
||||
? TRUE
|
||||
: FALSE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
bKeepAbortedTrans = FALSE;
|
||||
}
|
||||
|
||||
// Log an abort transaction record to the roll-forward log or
|
||||
// throw away the entire transaction, depending on the
|
||||
// bKeepAbortedTrans flag.
|
||||
|
||||
// If the transaction is being "dumped" because of a failed commit,
|
||||
// don't log anything to the RFL.
|
||||
|
||||
if (bOkToLogAbort)
|
||||
{
|
||||
#ifdef FLM_DEBUG
|
||||
if( pRfl->isLoggingEnabled())
|
||||
{
|
||||
flmAssert( m_ui64CurrTransID == pRfl->getCurrTransID());
|
||||
}
|
||||
#endif
|
||||
|
||||
if (RC_BAD( rc = pRfl->logEndTransaction(
|
||||
this, RFL_TRNS_ABORT_PACKET, !bKeepAbortedTrans)))
|
||||
{
|
||||
goto Exit1;
|
||||
}
|
||||
}
|
||||
#ifdef FLM_DEBUG
|
||||
else
|
||||
{
|
||||
// If bOkToLogAbort is FALSE, this always means that either a
|
||||
// commit failed while trying to log an end transaction packet or a
|
||||
// commit packet was logged and the transaction commit subsequently
|
||||
// failed for some other reason. In either case, the RFL should be
|
||||
// in a good state, with its current transaction ID reset to 0. If
|
||||
// not, either bOkToLogAbort is being used incorrectly by the caller
|
||||
// or there is a bug in the RFL logic.
|
||||
|
||||
flmAssert( pRfl->getCurrTransID() == 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
// If there were no operations in the transaction, restore
|
||||
// everything as if the transaction never happened.
|
||||
|
||||
// Even empty transactions can have modified rows to clean up
|
||||
// so we need to call this no matter what.
|
||||
|
||||
m_pDatabase->freeModifiedRows( this, m_ui64CurrTransID - 1);
|
||||
|
||||
if (!m_bHadUpdOper)
|
||||
{
|
||||
|
||||
// Pretend we dumped cache - shouldn't be any to worry about at
|
||||
// this point.
|
||||
|
||||
bDumpedCache = TRUE;
|
||||
goto Exit1;
|
||||
}
|
||||
|
||||
// Dump ALL modified cache blocks associated with the DB.
|
||||
// NOTE: This needs to be done BEFORE the call to flmGetDbHdrInfo
|
||||
// below, because that call will change pDb->m_ui64CurrTransID,
|
||||
// and that value is used by freeModifiedRows.
|
||||
|
||||
m_pDatabase->freeModifiedBlocks( m_ui64CurrTransID);
|
||||
bDumpedCache = TRUE;
|
||||
|
||||
// Reset the Db header from the last committed DB header in pFile.
|
||||
|
||||
getDbHdrInfo( pLastCommittedDbHdr);
|
||||
if (RC_BAD( rc = physRollback( (FLMUINT)pUncommittedDbHdr->ui32RblEOF,
|
||||
m_pDatabase->m_uiFirstLogBlkAddress, FALSE, 0)))
|
||||
{
|
||||
goto Exit1;
|
||||
}
|
||||
|
||||
m_pDatabase->lockMutex();
|
||||
|
||||
// Put the new transaction ID into the log header even though
|
||||
// we are not committing. We want to keep the transaction IDs
|
||||
// incrementing even though we aborted.
|
||||
|
||||
pLastCommittedDbHdr->ui64CurrTransID = ui64TransId;
|
||||
|
||||
// Preserve where we are at in the roll-forward log. Even though
|
||||
// the transaction aborted, we may have kept it in the RFL instead of
|
||||
// throw it away.
|
||||
|
||||
pLastCommittedDbHdr->ui32RflCurrFileNum =
|
||||
pUncommittedDbHdr->ui32RflCurrFileNum;
|
||||
pLastCommittedDbHdr->ui32RflLastTransOffset =
|
||||
pUncommittedDbHdr->ui32RflLastTransOffset;
|
||||
f_memcpy( pLastCommittedDbHdr->ucLastTransRflSerialNum,
|
||||
pUncommittedDbHdr->ucLastTransRflSerialNum,
|
||||
SFLM_SERIAL_NUM_SIZE);
|
||||
f_memcpy( pLastCommittedDbHdr->ucNextRflSerialNum,
|
||||
pUncommittedDbHdr->ucNextRflSerialNum,
|
||||
SFLM_SERIAL_NUM_SIZE);
|
||||
|
||||
// The following items tell us where we are at in the roll-back log.
|
||||
// During a transaction we may log blocks for the checkpoint or for
|
||||
// read transactions. So, even though we are aborting this transaction,
|
||||
// there may be other things in the roll-back log that we don't want
|
||||
// to lose. These items should not be reset until we do a checkpoint,
|
||||
// which is when we know it is safe to throw away the entire roll-back log.
|
||||
|
||||
pLastCommittedDbHdr->ui32RblEOF =
|
||||
pUncommittedDbHdr->ui32RblEOF;
|
||||
pLastCommittedDbHdr->ui32RblFirstCPBlkAddr =
|
||||
pUncommittedDbHdr->ui32RblFirstCPBlkAddr;
|
||||
|
||||
m_pDatabase->unlockMutex();
|
||||
|
||||
pRfl->commitDbHdrs( pLastCommittedDbHdr,
|
||||
&m_pDatabase->m_checkpointDbHdr);
|
||||
|
||||
Exit1:
|
||||
|
||||
// Dump cache, if not done above.
|
||||
|
||||
if (!bDumpedCache)
|
||||
{
|
||||
m_pDatabase->freeModifiedBlocks( m_ui64CurrTransID);
|
||||
m_pDatabase->freeModifiedRows( this, m_ui64CurrTransID - 1);
|
||||
bDumpedCache = TRUE;
|
||||
}
|
||||
|
||||
// Throw away IXD_FIXUPs
|
||||
|
||||
if (m_pIxdFixups)
|
||||
{
|
||||
IXD_FIXUP * pIxdFixup;
|
||||
IXD_FIXUP * pDeleteIxdFixup;
|
||||
|
||||
pIxdFixup = m_pIxdFixups;
|
||||
while (pIxdFixup)
|
||||
{
|
||||
pDeleteIxdFixup = pIxdFixup;
|
||||
pIxdFixup = pIxdFixup->pNext;
|
||||
f_free( &pDeleteIxdFixup);
|
||||
}
|
||||
m_pIxdFixups = NULL;
|
||||
}
|
||||
|
||||
if (m_eTransType == SFLM_UPDATE_TRANS &&
|
||||
gv_SFlmSysData.EventHdrs[ SFLM_EVENT_UPDATES].pEventCBList)
|
||||
{
|
||||
flmTransEventCallback( SFLM_EVENT_ABORT_TRANS, this, rc,
|
||||
ui64TransId);
|
||||
}
|
||||
|
||||
Unlink_From_Trans:
|
||||
|
||||
eSaveTransType = m_eTransType;
|
||||
|
||||
if (m_uiFlags & FDB_HAS_WRITE_LOCK)
|
||||
{
|
||||
if (RC_BAD( tmpRc = pRfl->completeTransWrites( this, FALSE, FALSE)))
|
||||
{
|
||||
if (RC_OK( rc))
|
||||
{
|
||||
rc = tmpRc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (eSaveTransType == SFLM_UPDATE_TRANS)
|
||||
{
|
||||
|
||||
// Before unlocking, restore collection information.
|
||||
|
||||
if (m_uiFlags & FDB_UPDATED_DICTIONARY)
|
||||
{
|
||||
m_pDatabase->lockMutex();
|
||||
flmAssert( m_pDict);
|
||||
unlinkFromDict();
|
||||
if (m_pDatabase->m_pDictList)
|
||||
{
|
||||
|
||||
// Link the F_Db to the right F_Dict object so it will
|
||||
// fixup the correct F_COLLECTION structures.
|
||||
|
||||
linkToDict( m_pDatabase->m_pDictList);
|
||||
}
|
||||
m_pDatabase->unlockMutex();
|
||||
}
|
||||
|
||||
if (m_pDict)
|
||||
{
|
||||
F_TABLE * pTable;
|
||||
FLMUINT uiLfNum;
|
||||
#ifdef FLM_DEBUG
|
||||
F_INDEX * pIndex;
|
||||
FLMUINT uiRootBlk;
|
||||
#endif
|
||||
|
||||
// Only need to do tables. Nothing from the LFH of
|
||||
// an index is stored in memory except for the root block
|
||||
// address, and whenever that is changed, we get a new
|
||||
// dictionary. Since the new dictionary will be discarded
|
||||
// in that case, there is nothing to restore for an index.
|
||||
|
||||
for (uiLfNum = 1, pTable = m_pDict->m_pTableTbl;
|
||||
uiLfNum <= m_pDict->m_uiHighestTableNum;
|
||||
uiLfNum++, pTable++)
|
||||
{
|
||||
if (pTable->uiTableNum)
|
||||
{
|
||||
#ifdef FLM_DEBUG
|
||||
uiRootBlk = pTable->lfInfo.uiRootBlk;
|
||||
#endif
|
||||
if (RC_BAD( tmpRc = m_pDatabase->lFileRead( this, &pTable->lfInfo)))
|
||||
{
|
||||
if (RC_OK( rc))
|
||||
{
|
||||
rc = tmpRc;
|
||||
}
|
||||
}
|
||||
#ifdef FLM_DEBUG
|
||||
else
|
||||
{
|
||||
// Make sure root block did not change - should not
|
||||
// have because root block changes are done by creating
|
||||
// a new dictionary, and we have already discarded
|
||||
// any new dictionary. Hence, root block address should
|
||||
// be the same in memory as it is no disk.
|
||||
|
||||
flmAssert( uiRootBlk == pTable->lfInfo.uiRootBlk);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Do indexes in debug mode to make sure uiRootBlk is correct
|
||||
|
||||
#ifdef FLM_DEBUG
|
||||
for (uiLfNum = 1, pIndex = m_pDict->m_pIndexTbl;
|
||||
uiLfNum <= m_pDict->m_uiHighestIndexNum;
|
||||
uiLfNum++, pIndex++)
|
||||
{
|
||||
if (pIndex->uiIndexNum)
|
||||
{
|
||||
uiRootBlk = pIndex->lfInfo.uiRootBlk;
|
||||
if (RC_BAD( tmpRc = m_pDatabase->lFileRead( this, &pIndex->lfInfo)))
|
||||
{
|
||||
if (RC_OK( rc))
|
||||
{
|
||||
rc = tmpRc;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Make sure root block did not change - should not
|
||||
// have because root block changes are done by creating
|
||||
// a new dictionary, and we have already discarded
|
||||
// any new dictionary. Hence, root block address should
|
||||
// be the same in memory as it is no disk.
|
||||
|
||||
flmAssert( uiRootBlk == pIndex->lfInfo.uiRootBlk);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
// Unlink the database from the transaction list.
|
||||
|
||||
unlinkFromTransList( FALSE);
|
||||
|
||||
if (m_pDbStats)
|
||||
{
|
||||
FLMUINT64 ui64ElapMilli = 0;
|
||||
|
||||
flmAddElapTime( &m_TransStartTime, &ui64ElapMilli);
|
||||
m_pDbStats->bHaveStats = TRUE;
|
||||
if (eSaveTransType == SFLM_READ_TRANS)
|
||||
{
|
||||
m_pDbStats->ReadTransStats.AbortedTrans.ui64Count++;
|
||||
m_pDbStats->ReadTransStats.AbortedTrans.ui64ElapMilli +=
|
||||
ui64ElapMilli;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pDbStats->UpdateTransStats.AbortedTrans.ui64Count++;
|
||||
m_pDbStats->UpdateTransStats.AbortedTrans.ui64ElapMilli +=
|
||||
ui64ElapMilli;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_pStats)
|
||||
{
|
||||
(void)flmStatUpdate( &m_Stats);
|
||||
}
|
||||
|
||||
Exit:
|
||||
|
||||
m_AbortRc = NE_SFLM_OK;
|
||||
return( rc);
|
||||
}
|
||||
|
||||
/*API~***********************************************************************
|
||||
Area : TRANSACTION
|
||||
Desc : Aborts an active transaction.
|
||||
*END************************************************************************/
|
||||
RCODE F_Db::transAbort( void)
|
||||
{
|
||||
RCODE rc = NE_SFLM_OK;
|
||||
|
||||
if (m_eTransType == SFLM_NO_TRANS)
|
||||
{
|
||||
rc = RC_SET( NE_SFLM_NO_TRANS_ACTIVE);
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
rc = abortTrans();
|
||||
|
||||
Exit:
|
||||
|
||||
if (RC_OK( rc))
|
||||
{
|
||||
rc = checkState( __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
return( rc);
|
||||
}
|
||||
Reference in New Issue
Block a user