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:
987
sql/src/fltrbeg.cpp
Normal file
987
sql/src/fltrbeg.cpp
Normal file
@@ -0,0 +1,987 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// Desc: Contains routines for starting a transaction.
|
||||
//
|
||||
// Tabs: 3
|
||||
//
|
||||
// Copyright (c) 1991, 1994-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: fltrbeg.cpp 3114 2006-01-19 13:22:45 -0700 (Thu, 19 Jan 2006) dsanders $
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
#include "flaimsys.h"
|
||||
|
||||
/****************************************************************************
|
||||
Desc: This routine unlinks an F_Db from a transaction's list of F_Dbs.
|
||||
****************************************************************************/
|
||||
void F_Db::unlinkFromTransList(
|
||||
FLMBOOL bCommitting)
|
||||
{
|
||||
flmAssert( m_pIxdFixups == NULL);
|
||||
if( m_eTransType != SFLM_NO_TRANS)
|
||||
{
|
||||
if (m_uiFlags & FDB_HAS_WRITE_LOCK)
|
||||
{
|
||||
|
||||
// If this is a commit operation and we have a commit callback,
|
||||
// call the callback function before unlocking the DIB.
|
||||
|
||||
if (bCommitting && m_pCommitClient)
|
||||
{
|
||||
m_pCommitClient->commit( this);
|
||||
}
|
||||
unlockExclusive();
|
||||
}
|
||||
|
||||
m_pDatabase->lockMutex();
|
||||
if (m_pDict)
|
||||
{
|
||||
unlinkFromDict();
|
||||
}
|
||||
|
||||
// Unlink the transaction from the F_Database if it is a read transaction.
|
||||
|
||||
if (m_eTransType == SFLM_READ_TRANS)
|
||||
{
|
||||
if (m_pNextReadTrans)
|
||||
{
|
||||
m_pNextReadTrans->m_pPrevReadTrans = m_pPrevReadTrans;
|
||||
}
|
||||
else if (!m_uiKilledTime)
|
||||
{
|
||||
m_pDatabase->m_pLastReadTrans = m_pPrevReadTrans;
|
||||
}
|
||||
if (m_pPrevReadTrans)
|
||||
{
|
||||
m_pPrevReadTrans->m_pNextReadTrans = m_pNextReadTrans;
|
||||
}
|
||||
else if (m_uiKilledTime)
|
||||
{
|
||||
m_pDatabase->m_pFirstKilledTrans = m_pNextReadTrans;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pDatabase->m_pFirstReadTrans = m_pNextReadTrans;
|
||||
}
|
||||
|
||||
// Zero out so it will be zero for next transaction begin.
|
||||
|
||||
m_uiKilledTime = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
// Reset to NULL or zero for next update transaction.
|
||||
|
||||
m_pIxStartList = m_pIxStopList = NULL;
|
||||
flmAssert( !m_pIxdFixups);
|
||||
}
|
||||
|
||||
m_pDatabase->unlockMutex();
|
||||
m_eTransType = SFLM_NO_TRANS;
|
||||
m_uiFlags &= (~(FDB_UPDATED_DICTIONARY |
|
||||
FDB_DONT_KILL_TRANS |
|
||||
FDB_DONT_POISON_CACHE |
|
||||
FDB_SWEEP_SCHEDULED));
|
||||
flmAssert( !m_uiDirtyRowCount);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Desc: This routine reads a database's dictionary. This is called only
|
||||
when we did not have a dictionary off of the F_Database object -
|
||||
which will be the first transaction after a database is opened.
|
||||
****************************************************************************/
|
||||
RCODE F_Db::readDictionary( void)
|
||||
{
|
||||
RCODE rc = NE_SFLM_OK;
|
||||
|
||||
if (RC_BAD( rc = dictOpen()))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
m_pDatabase->lockMutex();
|
||||
|
||||
// At this point, we will not yet have opened the database for
|
||||
// general use, so there is no way that any other thread can have
|
||||
// created a dictionary yet.
|
||||
|
||||
flmAssert( !m_pDatabase->m_pDictList);
|
||||
|
||||
// Link the new local dictionary to its file structure.
|
||||
|
||||
m_pDict->linkToDatabase( m_pDatabase);
|
||||
m_pDatabase->unlockMutex();
|
||||
|
||||
Exit:
|
||||
|
||||
return( rc);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Desc: This routine starts a transaction for the specified database. The
|
||||
transaction may be part of an overall larger transaction.
|
||||
****************************************************************************/
|
||||
RCODE F_Db::beginTrans(
|
||||
eDbTransType eTransType,
|
||||
FLMUINT uiMaxLockWait,
|
||||
FLMUINT uiFlags,
|
||||
SFLM_DB_HDR * pDbHdr)
|
||||
{
|
||||
RCODE rc = NE_SFLM_OK;
|
||||
SFLM_DB_HDR * pLastCommittedDbHdr;
|
||||
F_Rfl * pRfl = m_pDatabase->m_pRfl;
|
||||
FLMBOOL bMutexLocked = FALSE;
|
||||
|
||||
// Should not be calling on a temporary database
|
||||
|
||||
flmAssert( !m_pDatabase->m_bTempDb);
|
||||
|
||||
// Check the state of the database engine
|
||||
|
||||
if( RC_BAD( rc = checkState( __FILE__, __LINE__)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Initialize a few things - as few as is necessary to avoid
|
||||
// unnecessary overhead.
|
||||
|
||||
m_AbortRc = NE_SFLM_OK;
|
||||
pLastCommittedDbHdr = &m_pDatabase->m_lastCommittedDbHdr;
|
||||
m_bKrefSetup = FALSE;
|
||||
m_eTransType = eTransType;
|
||||
m_uiThreadId = (FLMUINT)f_threadId();
|
||||
m_uiTransCount++;
|
||||
|
||||
// Link the F_Db to the database's most current F_Dict structure,
|
||||
// if there is one. Also, if it is a read transaction, link the F_Db
|
||||
// into the list of read transactions off of the F_Database object.
|
||||
|
||||
m_pDatabase->lockMutex();
|
||||
bMutexLocked = TRUE;
|
||||
|
||||
if (m_pDatabase->m_pDictList)
|
||||
{
|
||||
// Link the F_Db to the right F_Dict object
|
||||
|
||||
linkToDict( m_pDatabase->m_pDictList);
|
||||
}
|
||||
|
||||
// If it is a read transaction, link into the list of
|
||||
// read transactions off of the F_Database object. Until we
|
||||
// get the DB header transaction ID below, we set ui64CurrTransID
|
||||
// to zero and link this transaction in at the beginning of the
|
||||
// list.
|
||||
|
||||
if (eTransType == SFLM_READ_TRANS)
|
||||
{
|
||||
getDbHdrInfo( pLastCommittedDbHdr);
|
||||
|
||||
// Link in at the end of the transaction list.
|
||||
|
||||
m_pNextReadTrans = NULL;
|
||||
if ((m_pPrevReadTrans = m_pDatabase->m_pLastReadTrans) != NULL)
|
||||
{
|
||||
// Make sure transaction IDs are always in ascending order. They
|
||||
// should be at this point.
|
||||
|
||||
flmAssert( m_pDatabase->m_pLastReadTrans->m_ui64CurrTransID <=
|
||||
m_ui64CurrTransID);
|
||||
m_pDatabase->m_pLastReadTrans->m_pNextReadTrans = this;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pDatabase->m_pFirstReadTrans = this;
|
||||
}
|
||||
m_pDatabase->m_pLastReadTrans = this;
|
||||
m_uiInactiveTime = 0;
|
||||
|
||||
if (uiFlags & SFLM_DONT_KILL_TRANS)
|
||||
{
|
||||
m_uiFlags |= FDB_DONT_KILL_TRANS;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_uiFlags &= ~FDB_DONT_KILL_TRANS;
|
||||
}
|
||||
|
||||
if (pDbHdr)
|
||||
{
|
||||
f_memcpy( pDbHdr, &m_pDatabase->m_lastCommittedDbHdr,
|
||||
sizeof( SFLM_DB_HDR));
|
||||
}
|
||||
}
|
||||
|
||||
m_pDatabase->unlockMutex();
|
||||
bMutexLocked = FALSE;
|
||||
|
||||
if (uiFlags & SFLM_DONT_POISON_CACHE)
|
||||
{
|
||||
m_uiFlags |= FDB_DONT_POISON_CACHE;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_uiFlags &= ~FDB_DONT_POISON_CACHE;
|
||||
}
|
||||
|
||||
// Put an exclusive lock on the database if we are not in a read
|
||||
// transaction. Read transactions require no lock.
|
||||
|
||||
if (eTransType != SFLM_READ_TRANS)
|
||||
{
|
||||
// Set the m_bHadUpdOper to TRUE for all transactions to begin with.
|
||||
// Many calls to beginTrans are internal, and we WANT the
|
||||
// normal behavior at the end of the transaction when it is
|
||||
// committed or aborted. The only time this flag will be set
|
||||
// to FALSE is when the application starts the transaction as
|
||||
// opposed to an internal starting of the transaction.
|
||||
|
||||
m_bHadUpdOper = TRUE;
|
||||
|
||||
// Initialize the count of blocks changed to be 0
|
||||
|
||||
m_uiBlkChangeCnt = 0;
|
||||
|
||||
if (RC_BAD( rc = lockExclusive( uiMaxLockWait)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// If there was a problem with the RFL volume, we must wait
|
||||
// for a checkpoint to be completed before continuing.
|
||||
// The checkpoint thread looks at this same flag and forces
|
||||
// a checkpoint. If it completes one successfully, it will
|
||||
// reset this flag.
|
||||
// Also, if the last forced checkpoint had a problem
|
||||
// (pFile->CheckpointRc != NE_SFLM_OK), we don't want to
|
||||
// start up a new update transaction until it is resolved.
|
||||
|
||||
if( !pRfl->seeIfRflVolumeOk() || RC_BAD( m_pDatabase->m_CheckpointRc))
|
||||
|
||||
{
|
||||
rc = RC_SET( NE_SFLM_MUST_WAIT_CHECKPOINT);
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Set the first log block address to zero.
|
||||
|
||||
m_pDatabase->m_uiFirstLogBlkAddress = 0;
|
||||
|
||||
// Header must be read before opening roll forward log file to make
|
||||
// sure we have the most current log file and log options.
|
||||
|
||||
f_memcpy( &m_pDatabase->m_uncommittedDbHdr, pLastCommittedDbHdr,
|
||||
sizeof( SFLM_DB_HDR));
|
||||
getDbHdrInfo( pLastCommittedDbHdr);
|
||||
|
||||
// Need to increment the current checkpoint for update transactions
|
||||
// so that it will be correct when we go to mark cache blocks.
|
||||
|
||||
if (m_uiFlags & FDB_REPLAYING_RFL)
|
||||
{
|
||||
// During recovery we need to set the transaction ID to the
|
||||
// transaction ID that was logged.
|
||||
|
||||
m_ui64CurrTransID = pRfl->getCurrTransID();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ui64CurrTransID++;
|
||||
}
|
||||
|
||||
// Link F_Db to the most current local dictionary, if there
|
||||
// is one.
|
||||
|
||||
m_pDatabase->lockMutex();
|
||||
if (m_pDatabase->m_pDictList != m_pDict &&
|
||||
m_pDatabase->m_pDictList)
|
||||
{
|
||||
linkToDict( m_pDatabase->m_pDictList);
|
||||
}
|
||||
m_pDatabase->unlockMutex();
|
||||
|
||||
// Set the transaction EOF to the current file EOF
|
||||
|
||||
m_uiTransEOF = m_uiLogicalEOF;
|
||||
|
||||
// Put the transaction ID into the uncommitted log header.
|
||||
|
||||
m_pDatabase->m_uncommittedDbHdr.ui64CurrTransID = m_ui64CurrTransID;
|
||||
|
||||
if (pDbHdr)
|
||||
{
|
||||
f_memcpy( pDbHdr, &m_pDatabase->m_uncommittedDbHdr,
|
||||
sizeof( SFLM_DB_HDR));
|
||||
}
|
||||
}
|
||||
|
||||
// Set up to collect statistics. We only do this at transaction
|
||||
// begin and not on any other type of operation. So this is the
|
||||
// only time when an F_Db will sense that statistics have been
|
||||
// turned on or off.
|
||||
|
||||
if (!gv_SFlmSysData.Stats.bCollectingStats)
|
||||
{
|
||||
m_pStats = NULL;
|
||||
m_pDbStats = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pStats = &m_Stats;
|
||||
|
||||
// Statistics are being collected for the system. Therefore,
|
||||
// if we are not currently collecting statistics in the
|
||||
// session, start. If we were collecting statistics, but the
|
||||
// start time was earlier than the start time in the system
|
||||
// statistics structure, reset the statistics in the session.
|
||||
|
||||
if (!m_Stats.bCollectingStats)
|
||||
{
|
||||
flmStatStart( &m_Stats);
|
||||
}
|
||||
else if (m_Stats.uiStartTime < gv_SFlmSysData.Stats.uiStartTime)
|
||||
{
|
||||
flmStatReset( &m_Stats, FALSE);
|
||||
}
|
||||
(void)flmStatGetDb( &m_Stats, m_pDatabase,
|
||||
0, &m_pDbStats, NULL, NULL);
|
||||
m_pLFileStats = NULL;
|
||||
}
|
||||
|
||||
if (m_pDbStats)
|
||||
{
|
||||
f_timeGetTimeStamp( &m_TransStartTime);
|
||||
}
|
||||
|
||||
// If we do not have a dictionary, read it in from disk.
|
||||
// NOTE: This should only happen when we are first opening
|
||||
// the database.
|
||||
|
||||
if (!m_pDict)
|
||||
{
|
||||
if (RC_BAD( rc = readDictionary()))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
}
|
||||
|
||||
Exit:
|
||||
|
||||
if( bMutexLocked)
|
||||
{
|
||||
m_pDatabase->unlockMutex();
|
||||
}
|
||||
|
||||
if (eTransType != SFLM_READ_TRANS)
|
||||
{
|
||||
if (RC_OK( rc))
|
||||
{
|
||||
rc = pRfl->logBeginTransaction( this);
|
||||
}
|
||||
#ifdef FLM_DBG_LOG
|
||||
flmDbgLogUpdate( m_pDatabase, m_ui64CurrTransID,
|
||||
0, 0, rc, "TBeg");
|
||||
#endif
|
||||
}
|
||||
|
||||
if (eTransType == SFLM_UPDATE_TRANS &&
|
||||
gv_SFlmSysData.EventHdrs [SFLM_EVENT_UPDATES].pEventCBList)
|
||||
{
|
||||
flmTransEventCallback( SFLM_EVENT_BEGIN_TRANS, this, rc,
|
||||
(FLMUINT)(RC_OK( rc)
|
||||
? m_ui64CurrTransID
|
||||
: (FLMUINT64)0));
|
||||
}
|
||||
|
||||
if (RC_BAD( rc))
|
||||
{
|
||||
// If there was an error, unlink the database from the transaction
|
||||
// structure as well as from the FDICT structure. Also dump any nodes
|
||||
// that are already in the cache.
|
||||
|
||||
unlinkFromTransList( FALSE);
|
||||
|
||||
if (m_pStats)
|
||||
{
|
||||
(void)flmStatUpdate( &m_Stats);
|
||||
}
|
||||
}
|
||||
|
||||
return( rc);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Desc: This routine starts a transaction for the specified database. It uses
|
||||
the transaction information in the passed in pDb.
|
||||
****************************************************************************/
|
||||
RCODE F_Db::beginTrans(
|
||||
F_Db * pDb)
|
||||
{
|
||||
RCODE rc = NE_SFLM_OK;
|
||||
FLMBOOL bMutexLocked = FALSE;
|
||||
|
||||
// Should not be calling on a temporary database
|
||||
|
||||
flmAssert( !m_pDatabase->m_bTempDb);
|
||||
|
||||
// pDb better be running a read transaction.
|
||||
|
||||
flmAssert( pDb->m_eTransType == SFLM_READ_TRANS);
|
||||
|
||||
if( RC_BAD( rc = checkState( __FILE__, __LINE__)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Initialize a few things - as few as is necessary to avoid
|
||||
// unnecessary overhead.
|
||||
|
||||
m_AbortRc = NE_SFLM_OK;
|
||||
m_bKrefSetup = FALSE;
|
||||
m_eTransType = SFLM_READ_TRANS;
|
||||
m_uiThreadId = (FLMUINT)f_threadId();
|
||||
m_uiTransCount++;
|
||||
|
||||
// Link the F_Db to the database's most current F_Dict structure,
|
||||
// if there is one. Also, if it is a read transaction, link the F_Db
|
||||
// into the list of read transactions off of the F_Database object.
|
||||
|
||||
m_pDatabase->lockMutex();
|
||||
bMutexLocked = TRUE;
|
||||
|
||||
// Link to the same dictionary as pDb.
|
||||
|
||||
linkToDict( pDb->m_pDict);
|
||||
|
||||
// If it is a read transaction, link into the list of
|
||||
// read transactions off of the F_Database object. Until we
|
||||
// get the DB header transaction ID below, we set ui64CurrTransID
|
||||
// to zero and link this transaction in at the beginning of the
|
||||
// list.
|
||||
|
||||
getDbHdrInfo( pDb);
|
||||
|
||||
// Link into the transaction list right after the point where
|
||||
// pDb is linked in. We need to keep transaction IDs in ascending
|
||||
// order.
|
||||
|
||||
m_pPrevReadTrans = pDb;
|
||||
if ((m_pNextReadTrans = pDb->m_pNextReadTrans) != NULL)
|
||||
{
|
||||
m_pNextReadTrans->m_pPrevReadTrans = this;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pDatabase->m_pLastReadTrans = this;
|
||||
}
|
||||
pDb->m_pNextReadTrans = this;
|
||||
|
||||
m_uiInactiveTime = 0;
|
||||
|
||||
if (pDb->m_uiFlags & FDB_DONT_KILL_TRANS)
|
||||
{
|
||||
m_uiFlags |= FDB_DONT_KILL_TRANS;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_uiFlags &= ~FDB_DONT_KILL_TRANS;
|
||||
}
|
||||
if (pDb->m_uiFlags & FDB_DONT_POISON_CACHE)
|
||||
{
|
||||
m_uiFlags |= FDB_DONT_POISON_CACHE;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_uiFlags &= ~FDB_DONT_POISON_CACHE;
|
||||
}
|
||||
|
||||
m_pDatabase->unlockMutex();
|
||||
bMutexLocked = FALSE;
|
||||
|
||||
// Set up to collect statistics. We only do this at transaction
|
||||
// begin and not on any other type of operation. So this is the
|
||||
// only time when an F_Db will sense that statistics have been
|
||||
// turned on or off.
|
||||
|
||||
if (!gv_SFlmSysData.Stats.bCollectingStats)
|
||||
{
|
||||
m_pStats = NULL;
|
||||
m_pDbStats = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pStats = &m_Stats;
|
||||
|
||||
// Statistics are being collected for the system. Therefore,
|
||||
// if we are not currently collecting statistics in the
|
||||
// session, start. If we were collecting statistics, but the
|
||||
// start time was earlier than the start time in the system
|
||||
// statistics structure, reset the statistics in the session.
|
||||
|
||||
if (!m_Stats.bCollectingStats)
|
||||
{
|
||||
flmStatStart( &m_Stats);
|
||||
}
|
||||
else if (m_Stats.uiStartTime < gv_SFlmSysData.Stats.uiStartTime)
|
||||
{
|
||||
flmStatReset( &m_Stats, FALSE);
|
||||
}
|
||||
(void)flmStatGetDb( &m_Stats, m_pDatabase,
|
||||
0, &m_pDbStats, NULL, NULL);
|
||||
m_pLFileStats = NULL;
|
||||
}
|
||||
|
||||
if (m_pDbStats)
|
||||
{
|
||||
f_timeGetTimeStamp( &m_TransStartTime);
|
||||
}
|
||||
|
||||
Exit:
|
||||
|
||||
if( bMutexLocked)
|
||||
{
|
||||
m_pDatabase->unlockMutex();
|
||||
}
|
||||
|
||||
if (RC_BAD( rc))
|
||||
{
|
||||
// If there was an error, unlink the database from the transaction
|
||||
// structure as well as from the FDICT structure. Also dump any nodes
|
||||
// that are already in the cache.
|
||||
|
||||
unlinkFromTransList( FALSE);
|
||||
|
||||
if (m_pStats)
|
||||
{
|
||||
(void)flmStatUpdate( &m_Stats);
|
||||
}
|
||||
}
|
||||
|
||||
return( rc);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Desc : Starts a transaction.
|
||||
****************************************************************************/
|
||||
RCODE F_Db::transBegin(
|
||||
eDbTransType eTransType,
|
||||
FLMUINT uiMaxLockWait,
|
||||
FLMUINT uiFlags,
|
||||
SFLM_DB_HDR * pDbHdr)
|
||||
{
|
||||
RCODE rc = NE_SFLM_OK;
|
||||
|
||||
// Verify the transaction type.
|
||||
|
||||
if (eTransType != SFLM_UPDATE_TRANS && eTransType != SFLM_READ_TRANS)
|
||||
{
|
||||
rc = RC_SET( NE_SFLM_ILLEGAL_TRANS_TYPE);
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Verify the transaction flags
|
||||
|
||||
if ((uiFlags & SFLM_DONT_KILL_TRANS) && eTransType != SFLM_READ_TRANS)
|
||||
{
|
||||
rc = RC_SET( NE_SFLM_ILLEGAL_TRANS_TYPE);
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Can't start an update transaction on a database that
|
||||
// is locked in shared mode.
|
||||
|
||||
if (eTransType == SFLM_UPDATE_TRANS && (m_uiFlags & FDB_FILE_LOCK_SHARED))
|
||||
{
|
||||
rc = RC_SET( NE_SFLM_SHARED_LOCK);
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// If the database is not running a transaction, start one.
|
||||
|
||||
if (m_eTransType != SFLM_NO_TRANS)
|
||||
{
|
||||
|
||||
// Cannot nest transactions.
|
||||
|
||||
rc = RC_SET( NE_SFLM_TRANS_ACTIVE);
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if (RC_BAD( rc = beginTrans( eTransType,
|
||||
uiMaxLockWait, uiFlags, pDbHdr)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
m_bHadUpdOper = FALSE;
|
||||
|
||||
Exit:
|
||||
|
||||
return( rc);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Desc : Starts a transaction.
|
||||
****************************************************************************/
|
||||
RCODE F_Db::transBegin(
|
||||
F_Db * pDb)
|
||||
{
|
||||
RCODE rc = NE_SFLM_OK;
|
||||
|
||||
// Database cannot already be running a transaction.
|
||||
|
||||
if (m_eTransType != SFLM_NO_TRANS)
|
||||
{
|
||||
|
||||
// Cannot nest transactions.
|
||||
|
||||
rc = RC_SET( NE_SFLM_TRANS_ACTIVE);
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Verify the transaction type.
|
||||
|
||||
if (((F_Db *)pDb)->m_eTransType != SFLM_READ_TRANS)
|
||||
{
|
||||
rc = RC_SET( NE_SFLM_ILLEGAL_TRANS_TYPE);
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if (RC_BAD( rc = beginTrans( (F_Db *)pDb)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
m_bHadUpdOper = FALSE;
|
||||
|
||||
Exit:
|
||||
|
||||
return( rc);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Desc : Obtains a a lock on the database.
|
||||
****************************************************************************/
|
||||
RCODE F_Db::dbLock(
|
||||
eDbLockType eLockType,
|
||||
FLMINT iPriority,
|
||||
FLMUINT uiTimeout)
|
||||
{
|
||||
RCODE rc = NE_SFLM_OK;
|
||||
|
||||
// eLockType better be exclusive or shared
|
||||
|
||||
if (eLockType != SFLM_LOCK_EXCLUSIVE && eLockType != SFLM_LOCK_SHARED)
|
||||
{
|
||||
rc = RC_SET( NE_SFLM_ILLEGAL_OP);
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Nesting of locks is not allowed - this test also keeps this call from
|
||||
// being executed inside an update transaction that implicitly acquired
|
||||
// the lock.
|
||||
|
||||
if (m_uiFlags &
|
||||
(FDB_HAS_FILE_LOCK | FDB_FILE_LOCK_SHARED | FDB_FILE_LOCK_IMPLICIT))
|
||||
{
|
||||
rc = RC_SET( NE_SFLM_ILLEGAL_OP);
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if (RC_BAD( rc = checkState( __FILE__, __LINE__)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Attempt to acquire the lock.
|
||||
|
||||
if (RC_BAD( rc = m_pDatabase->m_pDatabaseLockObj->Lock( this, m_hWaitSem,
|
||||
TRUE, FALSE, (FLMBOOL)((eLockType == SFLM_LOCK_EXCLUSIVE)
|
||||
? (FLMBOOL)TRUE
|
||||
: (FLMBOOL)FALSE),
|
||||
uiTimeout, iPriority, m_pDbStats)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
m_uiFlags |= FDB_HAS_FILE_LOCK;
|
||||
if (eLockType == SFLM_LOCK_SHARED)
|
||||
{
|
||||
m_uiFlags |= FDB_FILE_LOCK_SHARED;
|
||||
}
|
||||
|
||||
Exit:
|
||||
|
||||
return( rc);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Desc : Releases a lock on the database
|
||||
****************************************************************************/
|
||||
RCODE F_Db::dbUnlock( void)
|
||||
{
|
||||
RCODE rc = NE_SFLM_OK;
|
||||
|
||||
// If we don't have an explicit lock, can't do the unlock. It is
|
||||
// also illegal to do the unlock during an update transaction.
|
||||
|
||||
if (!(m_uiFlags & FDB_HAS_FILE_LOCK) ||
|
||||
(m_uiFlags & FDB_FILE_LOCK_IMPLICIT) ||
|
||||
(m_eTransType == SFLM_UPDATE_TRANS))
|
||||
{
|
||||
rc = RC_SET( NE_SFLM_ILLEGAL_OP);
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Unlock the file.
|
||||
|
||||
if (RC_BAD( rc = m_pDatabase->m_pDatabaseLockObj->Unlock( TRUE, this)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Unset the flags that indicated the file was explicitly locked.
|
||||
|
||||
m_uiFlags &= (~(FDB_HAS_FILE_LOCK | FDB_FILE_LOCK_SHARED));
|
||||
|
||||
Exit:
|
||||
|
||||
if (RC_OK( rc))
|
||||
{
|
||||
rc = checkState( __FILE__, __LINE__);
|
||||
}
|
||||
|
||||
return( rc);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Desc : Returns information about current and pending locks on the
|
||||
database.
|
||||
****************************************************************************/
|
||||
RCODE F_Db::getLockInfo(
|
||||
FLMINT iPriority,
|
||||
eDbLockType * peCurrLockType,
|
||||
FLMUINT * puiThreadId,
|
||||
FLMUINT * puiNumExclQueued,
|
||||
FLMUINT * puiNumSharedQueued,
|
||||
FLMUINT * puiPriorityCount)
|
||||
{
|
||||
RCODE rc = NE_SFLM_OK;
|
||||
|
||||
if (RC_BAD( rc = checkState( __FILE__, __LINE__)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
m_pDatabase->m_pDatabaseLockObj->GetLockInfo( iPriority,
|
||||
peCurrLockType, puiThreadId,
|
||||
puiNumExclQueued, puiNumSharedQueued,
|
||||
puiPriorityCount);
|
||||
|
||||
Exit:
|
||||
|
||||
return( rc);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Desc : Returns information about the lock held by the specified database
|
||||
handle.
|
||||
****************************************************************************/
|
||||
RCODE F_Db::getLockType(
|
||||
eDbLockType * peLockType,
|
||||
FLMBOOL * pbImplicit)
|
||||
{
|
||||
RCODE rc = NE_SFLM_OK;
|
||||
|
||||
if (peLockType)
|
||||
{
|
||||
*peLockType = SFLM_LOCK_NONE;
|
||||
}
|
||||
|
||||
if (pbImplicit)
|
||||
{
|
||||
*pbImplicit = FALSE;
|
||||
}
|
||||
|
||||
if (RC_BAD( rc = checkState( __FILE__, __LINE__)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
if (m_uiFlags & FDB_HAS_FILE_LOCK)
|
||||
{
|
||||
if (peLockType)
|
||||
{
|
||||
if (m_uiFlags & FDB_FILE_LOCK_SHARED)
|
||||
{
|
||||
*peLockType = SFLM_LOCK_SHARED;
|
||||
}
|
||||
else
|
||||
{
|
||||
*peLockType = SFLM_LOCK_EXCLUSIVE;
|
||||
}
|
||||
}
|
||||
|
||||
if (pbImplicit)
|
||||
{
|
||||
*pbImplicit = (m_uiFlags & FDB_FILE_LOCK_IMPLICIT)
|
||||
? TRUE
|
||||
: FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
Exit:
|
||||
|
||||
return( rc);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Desc : Forces a checkpoint on the database.
|
||||
****************************************************************************/
|
||||
RCODE F_Db::doCheckpoint(
|
||||
FLMUINT uiTimeout)
|
||||
{
|
||||
RCODE rc = NE_SFLM_OK;
|
||||
|
||||
if (RC_BAD( rc = checkState( __FILE__, __LINE__)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Start an update transaction. Must not already be one going.
|
||||
|
||||
if (m_eTransType != SFLM_NO_TRANS)
|
||||
{
|
||||
rc = RC_SET( NE_SFLM_TRANS_ACTIVE);
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// If we get to this point, we need to start a transaction on the
|
||||
// database.
|
||||
|
||||
if( RC_BAD( rc = beginTrans( SFLM_UPDATE_TRANS, uiTimeout)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Commit the transaction, forcing it to be checkpointed.
|
||||
|
||||
m_bHadUpdOper = FALSE;
|
||||
if (RC_BAD( rc = commitTrans( 0, TRUE)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
Exit:
|
||||
|
||||
return( rc);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Desc: This routine locks a database for exclusive access.
|
||||
****************************************************************************/
|
||||
RCODE F_Db::lockExclusive(
|
||||
FLMUINT uiMaxLockWait)
|
||||
{
|
||||
RCODE rc = NE_SFLM_OK;
|
||||
FLMBOOL bGotFileLock = FALSE;
|
||||
|
||||
flmAssert( !m_pDatabase->m_bTempDb);
|
||||
|
||||
// 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, uiMaxLockWait, 0, m_pDbStats)))
|
||||
{
|
||||
goto Exit;
|
||||
}
|
||||
bGotFileLock = TRUE;
|
||||
m_uiFlags |= (FDB_HAS_FILE_LOCK | FDB_FILE_LOCK_IMPLICIT);
|
||||
}
|
||||
|
||||
if (RC_OK( rc = m_pDatabase->dbWriteLock( m_hWaitSem, m_pDbStats)))
|
||||
{
|
||||
m_uiFlags |= FDB_HAS_WRITE_LOCK;
|
||||
}
|
||||
|
||||
Exit:
|
||||
|
||||
if (rc == NE_SFLM_DATABASE_LOCK_REQ_TIMEOUT)
|
||||
{
|
||||
if (bGotFileLock)
|
||||
{
|
||||
(void)m_pDatabase->m_pDatabaseLockObj->Unlock( TRUE, this);
|
||||
m_uiFlags &= (~(FDB_HAS_FILE_LOCK |
|
||||
FDB_FILE_LOCK_IMPLICIT | FDB_HAS_WRITE_LOCK));
|
||||
}
|
||||
|
||||
if (m_eTransType != SFLM_NO_TRANS)
|
||||
{
|
||||
|
||||
// Unlink the DB from the transaction.
|
||||
|
||||
unlinkFromTransList( FALSE);
|
||||
}
|
||||
}
|
||||
else if (RC_BAD( rc))
|
||||
{
|
||||
if (bGotFileLock)
|
||||
{
|
||||
(void)m_pDatabase->m_pDatabaseLockObj->Unlock( TRUE, this);
|
||||
m_uiFlags &= (~(FDB_HAS_FILE_LOCK |
|
||||
FDB_FILE_LOCK_IMPLICIT | FDB_HAS_WRITE_LOCK));
|
||||
}
|
||||
}
|
||||
|
||||
return( rc);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Desc: This routine unlocks a database that was previously locked
|
||||
using the lockExclusive routine.
|
||||
****************************************************************************/
|
||||
void F_Db::unlockExclusive( void)
|
||||
{
|
||||
flmAssert( !m_pDatabase->m_bTempDb);
|
||||
|
||||
// If we have the write lock, unlock it first.
|
||||
|
||||
flmAssert( m_uiFlags & FDB_HAS_WRITE_LOCK);
|
||||
|
||||
m_pDatabase->dbWriteUnlock( m_pDbStats);
|
||||
m_uiFlags &= ~FDB_HAS_WRITE_LOCK;
|
||||
|
||||
// Give up the file lock, if it was acquired implicitly.
|
||||
|
||||
if (m_uiFlags & FDB_FILE_LOCK_IMPLICIT)
|
||||
{
|
||||
(void)m_pDatabase->m_pDatabaseLockObj->Unlock( TRUE, this);
|
||||
m_uiFlags &= (~(FDB_HAS_FILE_LOCK | FDB_FILE_LOCK_IMPLICIT));
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user