Files
mars-flaim/sql/src/fltrbeg.cpp
dsandersoremutah 78bd30e364 Modified to use lock manager in toolkit.
git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@490 0109f412-320b-0410-ab79-c3e0c5ffbbe6
2006-05-31 15:23:25 +00:00

1001 lines
23 KiB
C++

//------------------------------------------------------------------------------
// 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$
//------------------------------------------------------------------------------
#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;
FLMUINT uiRflToken = 0;
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 (eTransType != SFLM_READ_TRANS)
{
pRfl->disableLogging( &uiRflToken);
}
if (RC_BAD( rc = readDictionary()))
{
goto Exit;
}
}
Exit:
if( bMutexLocked)
{
m_pDatabase->unlockMutex();
}
if( uiRflToken)
{
pRfl->enableLogging( &uiRflToken);
}
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(
eLockType eLockType,
FLMINT iPriority,
FLMUINT uiTimeout)
{
RCODE rc = NE_SFLM_OK;
// eLockType better be exclusive or shared
if (eLockType != FLM_LOCK_EXCLUSIVE && eLockType != FLM_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( m_hWaitSem,
(FLMBOOL)((eLockType == FLM_LOCK_EXCLUSIVE)
? (FLMBOOL)TRUE
: (FLMBOOL)FALSE),
uiTimeout, iPriority,
m_pDbStats ? &m_pDbStats->LockStats : NULL)))
{
goto Exit;
}
m_uiFlags |= FDB_HAS_FILE_LOCK;
if (eLockType == FLM_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()))
{
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,
eLockType * 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(
eLockType * peLockType,
FLMBOOL * pbImplicit)
{
RCODE rc = NE_SFLM_OK;
if (peLockType)
{
*peLockType = FLM_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 = FLM_LOCK_SHARED;
}
else
{
*peLockType = FLM_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(
m_hWaitSem, TRUE, uiMaxLockWait, 0,
m_pDbStats ? &m_pDbStats->LockStats : NULL)))
{
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, FLM_NO_TIMEOUT)))
{
m_uiFlags |= FDB_HAS_WRITE_LOCK;
}
Exit:
if (rc == NE_SFLM_DATABASE_LOCK_REQ_TIMEOUT)
{
if (bGotFileLock)
{
(void)m_pDatabase->m_pDatabaseLockObj->unlock();
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();
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_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();
m_uiFlags &= (~(FDB_HAS_FILE_LOCK | FDB_FILE_LOCK_IMPLICIT));
}
}