git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@612 0109f412-320b-0410-ab79-c3e0c5ffbbe6
1308 lines
28 KiB
C++
1308 lines
28 KiB
C++
//------------------------------------------------------------------------------
|
|
// Desc: Database config get/set functions
|
|
//
|
|
// Tabs: 3
|
|
//
|
|
// Copyright (c) 1996-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: Set the RFL keep files flag.
|
|
****************************************************************************/
|
|
RCODE F_Db::setRflKeepFilesFlag(
|
|
FLMBOOL bKeepFiles)
|
|
{
|
|
RCODE rc = NE_SFLM_OK;
|
|
FLMBOOL bDbLocked = FALSE;
|
|
|
|
// See if the database is being forced to close
|
|
|
|
if (RC_BAD( rc = checkState( __FILE__, __LINE__)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Make sure we don't have a transaction going
|
|
|
|
if (m_eTransType != SFLM_NO_TRANS)
|
|
{
|
|
rc = RC_SET( NE_SFLM_TRANS_ACTIVE);
|
|
goto Exit;
|
|
}
|
|
|
|
// Make sure there is no active backup running
|
|
|
|
m_pDatabase->lockMutex();
|
|
if (m_pDatabase->m_bBackupActive)
|
|
{
|
|
m_pDatabase->unlockMutex();
|
|
rc = RC_SET( NE_SFLM_BACKUP_ACTIVE);
|
|
goto Exit;
|
|
}
|
|
m_pDatabase->unlockMutex();
|
|
|
|
// Need to lock the database but not start a transaction yet.
|
|
|
|
if (!(m_uiFlags & (FDB_HAS_FILE_LOCK | FDB_FILE_LOCK_SHARED)))
|
|
{
|
|
if (RC_BAD( rc = dbLock( FLM_LOCK_EXCLUSIVE, 0,
|
|
FLM_NO_TIMEOUT)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
bDbLocked = TRUE;
|
|
}
|
|
|
|
// If we aren't changing the keep flag, jump to exit without doing
|
|
// anything.
|
|
|
|
if ((bKeepFiles &&
|
|
m_pDatabase->m_lastCommittedDbHdr.ui8RflKeepFiles) ||
|
|
(!bKeepFiles &&
|
|
!m_pDatabase->m_lastCommittedDbHdr.ui8RflKeepFiles))
|
|
{
|
|
goto Exit; // Will return NE_SFLM_OK;
|
|
}
|
|
|
|
// Force a checkpoint and roll to the next RFL file numbers.
|
|
// When changing from keep to no-keep or vice versa, we need to
|
|
// go to a new RFL file so that the new RFL file gets new
|
|
// serial numbers and a new keep or no-keep flag.
|
|
|
|
if (RC_BAD( rc = doCheckpoint( FLM_NO_TIMEOUT)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
f_memcpy( &m_pDatabase->m_uncommittedDbHdr,
|
|
&m_pDatabase->m_lastCommittedDbHdr,
|
|
sizeof( SFLM_DB_HDR));
|
|
m_pDatabase->m_uncommittedDbHdr.ui8RflKeepFiles =
|
|
(FLMUINT8)(bKeepFiles
|
|
? (FLMUINT8)1
|
|
: (FLMUINT8)0);
|
|
|
|
// Force a new RFL file - this will also write out the entire
|
|
// log header - including the changes we made above.
|
|
|
|
if (RC_BAD( rc = m_pDatabase->m_pRfl->finishCurrFile( this, TRUE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if (bDbLocked)
|
|
{
|
|
dbUnlock();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Set the RFL directory for a database.
|
|
****************************************************************************/
|
|
RCODE F_Db::setRflDir(
|
|
const char * pszNewRflDir)
|
|
{
|
|
RCODE rc = NE_SFLM_OK;
|
|
FLMBOOL bDbLocked = FALSE;
|
|
|
|
// See if the database is being forced to close
|
|
|
|
if (RC_BAD( rc = checkState( __FILE__, __LINE__)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Make sure we don't have a transaction going
|
|
|
|
if (m_eTransType != SFLM_NO_TRANS)
|
|
{
|
|
rc = RC_SET( NE_SFLM_TRANS_ACTIVE);
|
|
goto Exit;
|
|
}
|
|
|
|
// Make sure there is no active backup running
|
|
|
|
m_pDatabase->lockMutex();
|
|
if (m_pDatabase->m_bBackupActive)
|
|
{
|
|
m_pDatabase->unlockMutex();
|
|
rc = RC_SET( NE_SFLM_BACKUP_ACTIVE);
|
|
goto Exit;
|
|
}
|
|
m_pDatabase->unlockMutex();
|
|
|
|
// Make sure the path exists and that it is a directory
|
|
// rather than a file.
|
|
|
|
if (pszNewRflDir && *pszNewRflDir)
|
|
{
|
|
if (!gv_SFlmSysData.pFileSystem->isDir( pszNewRflDir))
|
|
{
|
|
rc = RC_SET( NE_FLM_IO_INVALID_FILENAME);
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// Need to lock the database because we can't change the RFL
|
|
// directory until after the checkpoint has completed. The
|
|
// checkpoint code will unlock the transaction, but not the
|
|
// file if we have an explicit lock. We need to do this to
|
|
// prevent another transaction from beginning before we have
|
|
// changed the RFL directory.
|
|
|
|
if (!(m_uiFlags & (FDB_HAS_FILE_LOCK | FDB_FILE_LOCK_SHARED)))
|
|
{
|
|
if( RC_BAD( rc = dbLock( FLM_LOCK_EXCLUSIVE, 0,
|
|
FLM_NO_TIMEOUT)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
bDbLocked = TRUE;
|
|
}
|
|
|
|
// Force a checkpoint and roll to the next RFL file numbers. Both
|
|
// of these steps are necessary to ensure that we won't have to do
|
|
// any recovery using the current RFL file - because we do not
|
|
// move the current RFL file to the new directory. Forcing the
|
|
// checkpoint ensures that we have no transactions that will need
|
|
// to be recovered if we were to crash. Rolling the RFL file number
|
|
// ensures that no more transactions will be logged to the current
|
|
// RFL file.
|
|
|
|
if (RC_BAD( rc = doCheckpoint( FLM_NO_TIMEOUT)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Force a new RFL file.
|
|
|
|
if (RC_BAD( rc = m_pDatabase->m_pRfl->finishCurrFile( this, FALSE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Set the RFL directory to the new value now that we have
|
|
// finished the checkpoint and rolled to the next RFL file.
|
|
|
|
m_pDatabase->lockMutex();
|
|
rc = m_pDatabase->m_pRfl->setRflDir( pszNewRflDir);
|
|
m_pDatabase->unlockMutex();
|
|
|
|
Exit:
|
|
|
|
if (bDbLocked)
|
|
{
|
|
dbUnlock();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Set the RFL file size limits for a database.
|
|
****************************************************************************/
|
|
RCODE F_Db::setRflFileSizeLimits(
|
|
FLMUINT uiMinRflSize,
|
|
FLMUINT uiMaxRflSize)
|
|
{
|
|
RCODE rc = NE_SFLM_OK;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
// See if the database is being forced to close
|
|
|
|
if (RC_BAD( rc = checkState( __FILE__, __LINE__)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Make sure the limits are valid.
|
|
|
|
// Maximum must be enough to hold at least one packet plus
|
|
// the RFL header. Minimum must not be greater than the
|
|
// maximum. NOTE: Minimum and maximum are allowed to be
|
|
// equal, but in all cases, maximum takes precedence over
|
|
// minimum. We will first NOT exceed the maximum. Then,
|
|
// if possible, we will go above the minimum.
|
|
|
|
if (uiMaxRflSize < RFL_MAX_PACKET_SIZE + 512)
|
|
{
|
|
uiMaxRflSize = RFL_MAX_PACKET_SIZE + 512;
|
|
}
|
|
if (uiMaxRflSize > gv_SFlmSysData.uiMaxFileSize)
|
|
{
|
|
uiMaxRflSize = gv_SFlmSysData.uiMaxFileSize;
|
|
}
|
|
if (uiMinRflSize > uiMaxRflSize)
|
|
{
|
|
uiMinRflSize = uiMaxRflSize;
|
|
}
|
|
|
|
// 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 (RC_BAD( rc = beginTrans( SFLM_UPDATE_TRANS)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
bStartedTrans = TRUE;
|
|
|
|
// Commit the transaction.
|
|
|
|
m_pDatabase->m_uncommittedDbHdr.ui32RflMinFileSize =
|
|
(FLMUINT32)uiMinRflSize;
|
|
m_pDatabase->m_uncommittedDbHdr.ui32RflMaxFileSize =
|
|
(FLMUINT32)uiMaxRflSize;
|
|
|
|
bStartedTrans = FALSE;
|
|
if (RC_BAD( rc = commitTrans( 0, FALSE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if (bStartedTrans)
|
|
{
|
|
abortTrans();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Roll to the next RFL file for this database
|
|
****************************************************************************/
|
|
RCODE F_Db::rflRollToNextFile( void)
|
|
{
|
|
RCODE rc = NE_SFLM_OK;
|
|
|
|
// See if the database is being forced to close
|
|
|
|
if (RC_BAD( rc = checkState( __FILE__, __LINE__)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// NOTE: finishCurrFile will not roll to the next file if the current
|
|
// file has not been created.
|
|
|
|
if (RC_BAD( rc = m_pDatabase->m_pRfl->finishCurrFile( this, FALSE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Set keep aborted transactions in RFL flag.
|
|
****************************************************************************/
|
|
RCODE F_Db::setKeepAbortedTransInRflFlag(
|
|
FLMBOOL bKeep
|
|
)
|
|
{
|
|
RCODE rc = NE_SFLM_OK;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
// See if the database is being forced to close
|
|
|
|
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 (RC_BAD( rc = beginTrans( SFLM_UPDATE_TRANS)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
bStartedTrans = TRUE;
|
|
|
|
// Change the uncommitted log header
|
|
|
|
m_pDatabase->m_uncommittedDbHdr.ui8RflKeepAbortedTrans =
|
|
(FLMUINT8)(bKeep
|
|
? (FLMUINT8)1
|
|
: (FLMUINT8)0);
|
|
|
|
// Commit the transaction.
|
|
|
|
bStartedTrans = FALSE;
|
|
if (RC_BAD( rc = commitTrans( 0, FALSE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if (bStartedTrans)
|
|
{
|
|
abortTrans();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Set auto turn off keep RFL flag.
|
|
****************************************************************************/
|
|
RCODE F_Db::setAutoTurnOffKeepRflFlag(
|
|
FLMBOOL bAutoTurnOff
|
|
)
|
|
{
|
|
RCODE rc = NE_SFLM_OK;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
// See if the database is being forced to close
|
|
|
|
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 (RC_BAD( rc = beginTrans( SFLM_UPDATE_TRANS)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
bStartedTrans = TRUE;
|
|
|
|
// Change the uncommitted log header
|
|
|
|
m_pDatabase->m_uncommittedDbHdr.ui8RflAutoTurnOffKeep =
|
|
(FLMUINT8)(bAutoTurnOff
|
|
? (FLMUINT8)1
|
|
: (FLMUINT8)0);
|
|
|
|
// Commit the transaction.
|
|
|
|
bStartedTrans = FALSE;
|
|
if (RC_BAD( rc = commitTrans( 0, FALSE)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if (bStartedTrans)
|
|
{
|
|
abortTrans();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Retrieves the Checkpoint info for the database passed in. This assumes
|
|
global mutex has already been locked.
|
|
*****************************************************************************/
|
|
void F_Database::getCPInfo(
|
|
SFLM_CHECKPOINT_INFO * pCheckpointInfo)
|
|
{
|
|
FLMUINT uiElapTime;
|
|
FLMUINT uiCurrTime;
|
|
|
|
flmAssert( pCheckpointInfo);
|
|
|
|
f_memset( pCheckpointInfo, 0, sizeof( SFLM_CHECKPOINT_INFO));
|
|
if (m_pCPInfo)
|
|
{
|
|
pCheckpointInfo->bRunning = m_pCPInfo->bDoingCheckpoint;
|
|
if (pCheckpointInfo->bRunning)
|
|
{
|
|
if (m_pCPInfo->uiStartTime)
|
|
{
|
|
uiCurrTime = FLM_GET_TIMER();
|
|
|
|
uiElapTime = FLM_ELAPSED_TIME( uiCurrTime,
|
|
m_pCPInfo->uiStartTime);
|
|
pCheckpointInfo->uiRunningTime = FLM_TIMER_UNITS_TO_MILLI( uiElapTime);
|
|
}
|
|
else
|
|
{
|
|
pCheckpointInfo->uiRunningTime = 0;
|
|
}
|
|
pCheckpointInfo->bForcingCheckpoint =
|
|
m_pCPInfo->bForcingCheckpoint;
|
|
if (m_pCPInfo->uiForceCheckpointStartTime)
|
|
{
|
|
uiCurrTime = FLM_GET_TIMER();
|
|
uiElapTime = FLM_ELAPSED_TIME( uiCurrTime,
|
|
m_pCPInfo->uiForceCheckpointStartTime);
|
|
pCheckpointInfo->uiForceCheckpointRunningTime =
|
|
FLM_TIMER_UNITS_TO_MILLI( uiElapTime);
|
|
}
|
|
else
|
|
{
|
|
pCheckpointInfo->uiForceCheckpointRunningTime = 0;
|
|
}
|
|
pCheckpointInfo->eForceCheckpointReason =
|
|
m_pCPInfo->eForceCheckpointReason;
|
|
pCheckpointInfo->bWritingDataBlocks =
|
|
m_pCPInfo->bWritingDataBlocks;
|
|
pCheckpointInfo->uiLogBlocksWritten =
|
|
m_pCPInfo->uiLogBlocksWritten;
|
|
pCheckpointInfo->uiDataBlocksWritten =
|
|
m_pCPInfo->uiDataBlocksWritten;
|
|
}
|
|
pCheckpointInfo->uiBlockSize = m_uiBlockSize;
|
|
pCheckpointInfo->uiDirtyCacheBytes =
|
|
m_uiDirtyCacheCount * m_uiBlockSize;
|
|
if (m_pCPInfo->uiStartWaitTruncateTime)
|
|
{
|
|
uiCurrTime = FLM_GET_TIMER();
|
|
|
|
uiElapTime = FLM_ELAPSED_TIME( uiCurrTime,
|
|
m_pCPInfo->uiStartWaitTruncateTime);
|
|
pCheckpointInfo->uiWaitTruncateTime =
|
|
FLM_TIMER_UNITS_TO_MILLI( uiElapTime);
|
|
}
|
|
else
|
|
{
|
|
pCheckpointInfo->uiWaitTruncateTime = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Retrieves the Checkpoint info for the database.
|
|
*****************************************************************************/
|
|
void F_Db::getCheckpointInfo(
|
|
SFLM_CHECKPOINT_INFO * pCheckpointInfo)
|
|
{
|
|
m_pDatabase->lockMutex();
|
|
m_pDatabase->getCPInfo( pCheckpointInfo);
|
|
m_pDatabase->unlockMutex();
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Returns current RFL file number
|
|
****************************************************************************/
|
|
RCODE F_Db::getRflFileNum(
|
|
FLMUINT * puiRflFileNum
|
|
)
|
|
{
|
|
RCODE rc = NE_SFLM_OK;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
FLMUINT uiLastCPFile;
|
|
FLMUINT uiLastTransFile;
|
|
|
|
if (m_eTransType == SFLM_READ_TRANS)
|
|
{
|
|
rc = RC_SET( NE_SFLM_ILLEGAL_TRANS_OP);
|
|
goto Exit;
|
|
}
|
|
else if (m_eTransType != SFLM_NO_TRANS)
|
|
{
|
|
if (!okToCommitTrans())
|
|
{
|
|
rc = RC_SET( NE_SFLM_ABORT_TRANS);
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (RC_BAD( rc = beginTrans( SFLM_UPDATE_TRANS)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
bStartedTrans = TRUE;
|
|
}
|
|
|
|
// Get the CP and last trans RFL file numbers. Need to
|
|
// return the higher of the two. No need to lock the
|
|
// mutex because we are in an update transaction.
|
|
|
|
uiLastCPFile =
|
|
(FLMUINT)m_pDatabase->m_uncommittedDbHdr.ui32RflLastCPFileNum;
|
|
|
|
uiLastTransFile =
|
|
(FLMUINT)m_pDatabase->m_uncommittedDbHdr.ui32RflCurrFileNum;
|
|
|
|
*puiRflFileNum = uiLastCPFile > uiLastTransFile
|
|
? uiLastCPFile
|
|
: uiLastTransFile;
|
|
|
|
Exit:
|
|
|
|
if (bStartedTrans)
|
|
{
|
|
abortTrans();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Returns highest not used RFL file number
|
|
****************************************************************************/
|
|
RCODE F_Db::getHighestNotUsedRflFileNum(
|
|
FLMUINT * puiHighestNotUsedRflFileNum
|
|
)
|
|
{
|
|
RCODE rc = NE_SFLM_OK;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
FLMUINT uiLastCPFile;
|
|
FLMUINT uiLastTransFile;
|
|
|
|
if (m_eTransType == SFLM_READ_TRANS)
|
|
{
|
|
rc = RC_SET( NE_SFLM_ILLEGAL_TRANS_OP);
|
|
goto Exit;
|
|
}
|
|
else if (m_eTransType != SFLM_NO_TRANS)
|
|
{
|
|
if (!okToCommitTrans())
|
|
{
|
|
rc = RC_SET( NE_SFLM_ABORT_TRANS);
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (RC_BAD( rc = beginTrans( SFLM_UPDATE_TRANS)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
bStartedTrans = TRUE;
|
|
}
|
|
|
|
// Get the CP and last trans RFL file numbers. Need to
|
|
// return the lower of the two minus 1.
|
|
|
|
uiLastCPFile =
|
|
(FLMUINT)m_pDatabase->m_uncommittedDbHdr.ui32RflLastCPFileNum;
|
|
|
|
uiLastTransFile =
|
|
(FLMUINT)m_pDatabase->m_uncommittedDbHdr.ui32RflCurrFileNum;
|
|
|
|
*puiHighestNotUsedRflFileNum =
|
|
(FLMUINT)((uiLastCPFile < uiLastTransFile
|
|
? uiLastCPFile
|
|
: uiLastTransFile) - 1);
|
|
Exit:
|
|
|
|
if (bStartedTrans)
|
|
{
|
|
abortTrans();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Returns RFL file size limits for the database
|
|
****************************************************************************/
|
|
RCODE F_Db::getRflFileSizeLimits(
|
|
FLMUINT * puiRflMinFileSize,
|
|
FLMUINT * puiRflMaxFileSize
|
|
)
|
|
{
|
|
RCODE rc = NE_SFLM_OK;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if (m_eTransType == SFLM_READ_TRANS)
|
|
{
|
|
rc = RC_SET( NE_SFLM_ILLEGAL_TRANS_OP);
|
|
goto Exit;
|
|
}
|
|
else if (m_eTransType != SFLM_NO_TRANS)
|
|
{
|
|
if (!okToCommitTrans())
|
|
{
|
|
rc = RC_SET( NE_SFLM_ABORT_TRANS);
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (RC_BAD( rc = beginTrans( SFLM_UPDATE_TRANS)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
bStartedTrans = TRUE;
|
|
}
|
|
|
|
if (puiRflMinFileSize)
|
|
{
|
|
*puiRflMinFileSize =
|
|
(FLMUINT)m_pDatabase->m_uncommittedDbHdr.ui32RflMinFileSize;
|
|
}
|
|
if (puiRflMaxFileSize)
|
|
{
|
|
*puiRflMaxFileSize =
|
|
(FLMUINT)m_pDatabase->m_uncommittedDbHdr.ui32RflMaxFileSize;
|
|
}
|
|
|
|
Exit:
|
|
|
|
if (bStartedTrans)
|
|
{
|
|
abortTrans();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Returns RFL keep flag for the database
|
|
****************************************************************************/
|
|
RCODE F_Db::getRflKeepFlag(
|
|
FLMBOOL * pbKeep
|
|
)
|
|
{
|
|
RCODE rc = NE_SFLM_OK;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if (m_eTransType == SFLM_READ_TRANS)
|
|
{
|
|
rc = RC_SET( NE_SFLM_ILLEGAL_TRANS_OP);
|
|
goto Exit;
|
|
}
|
|
else if (m_eTransType != SFLM_NO_TRANS)
|
|
{
|
|
if (!okToCommitTrans())
|
|
{
|
|
rc = RC_SET( NE_SFLM_ABORT_TRANS);
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (RC_BAD( rc = beginTrans( SFLM_UPDATE_TRANS)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
bStartedTrans = TRUE;
|
|
}
|
|
|
|
*pbKeep = m_pDatabase->m_uncommittedDbHdr.ui8RflKeepFiles
|
|
? TRUE
|
|
: FALSE;
|
|
|
|
Exit:
|
|
|
|
if (bStartedTrans)
|
|
{
|
|
abortTrans();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Returns last backup transaction ID for the database
|
|
****************************************************************************/
|
|
RCODE F_Db::getLastBackupTransID(
|
|
FLMUINT64 * pui64LastBackupTransID
|
|
)
|
|
{
|
|
RCODE rc = NE_SFLM_OK;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if (m_eTransType == SFLM_READ_TRANS)
|
|
{
|
|
rc = RC_SET( NE_SFLM_ILLEGAL_TRANS_OP);
|
|
goto Exit;
|
|
}
|
|
else if (m_eTransType != SFLM_NO_TRANS)
|
|
{
|
|
if (!okToCommitTrans())
|
|
{
|
|
rc = RC_SET( NE_SFLM_ABORT_TRANS);
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (RC_BAD( rc = beginTrans( SFLM_UPDATE_TRANS)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
bStartedTrans = TRUE;
|
|
}
|
|
|
|
*pui64LastBackupTransID =
|
|
m_pDatabase->m_uncommittedDbHdr.ui64LastBackupTransID;
|
|
|
|
Exit:
|
|
|
|
if (bStartedTrans)
|
|
{
|
|
abortTrans();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Returns blocks changed since the last backup for the database
|
|
****************************************************************************/
|
|
RCODE F_Db::getBlocksChangedSinceBackup(
|
|
FLMUINT * puiBlocksChangedSinceBackup
|
|
)
|
|
{
|
|
RCODE rc = NE_SFLM_OK;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if (m_eTransType == SFLM_READ_TRANS)
|
|
{
|
|
rc = RC_SET( NE_SFLM_ILLEGAL_TRANS_OP);
|
|
goto Exit;
|
|
}
|
|
else if (m_eTransType != SFLM_NO_TRANS)
|
|
{
|
|
if (!okToCommitTrans())
|
|
{
|
|
rc = RC_SET( NE_SFLM_ABORT_TRANS);
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (RC_BAD( rc = beginTrans( SFLM_UPDATE_TRANS)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
bStartedTrans = TRUE;
|
|
}
|
|
|
|
*puiBlocksChangedSinceBackup =
|
|
(FLMUINT)m_pDatabase->m_uncommittedDbHdr.ui32BlksChangedSinceBackup;
|
|
|
|
Exit:
|
|
|
|
if (bStartedTrans)
|
|
{
|
|
abortTrans();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Returns the auto-turn-off-keep-RFL flag for the database
|
|
****************************************************************************/
|
|
RCODE F_Db::getAutoTurnOffKeepRflFlag(
|
|
FLMBOOL * pbAutoTurnOff
|
|
)
|
|
{
|
|
RCODE rc = NE_SFLM_OK;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if (m_eTransType == SFLM_READ_TRANS)
|
|
{
|
|
rc = RC_SET( NE_SFLM_ILLEGAL_TRANS_OP);
|
|
goto Exit;
|
|
}
|
|
else if (m_eTransType != SFLM_NO_TRANS)
|
|
{
|
|
if (!okToCommitTrans())
|
|
{
|
|
rc = RC_SET( NE_SFLM_ABORT_TRANS);
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (RC_BAD( rc = beginTrans( SFLM_UPDATE_TRANS)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
bStartedTrans = TRUE;
|
|
}
|
|
|
|
*pbAutoTurnOff = m_pDatabase->m_uncommittedDbHdr.ui8RflAutoTurnOffKeep
|
|
? TRUE
|
|
: FALSE;
|
|
|
|
Exit:
|
|
|
|
if (bStartedTrans)
|
|
{
|
|
abortTrans();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Returns the keep aborted transactions in RFL flag for the database
|
|
****************************************************************************/
|
|
RCODE F_Db::getKeepAbortedTransInRflFlag(
|
|
FLMBOOL * pbKeep
|
|
)
|
|
{
|
|
RCODE rc = NE_SFLM_OK;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if (m_eTransType == SFLM_READ_TRANS)
|
|
{
|
|
rc = RC_SET( NE_SFLM_ILLEGAL_TRANS_OP);
|
|
goto Exit;
|
|
}
|
|
else if (m_eTransType != SFLM_NO_TRANS)
|
|
{
|
|
if (!okToCommitTrans())
|
|
{
|
|
rc = RC_SET( NE_SFLM_ABORT_TRANS);
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (RC_BAD( rc = beginTrans( SFLM_UPDATE_TRANS)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
bStartedTrans = TRUE;
|
|
}
|
|
|
|
*pbKeep = m_pDatabase->m_uncommittedDbHdr.ui8RflKeepAbortedTrans
|
|
? TRUE
|
|
: FALSE;
|
|
|
|
Exit:
|
|
|
|
if (bStartedTrans)
|
|
{
|
|
abortTrans();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Returns disk space usage for the database
|
|
****************************************************************************/
|
|
RCODE F_Db::getDiskSpaceUsage(
|
|
FLMUINT64 * pui64DataSize,
|
|
FLMUINT64 * pui64RollbackSize,
|
|
FLMUINT64 * pui64RflSize)
|
|
{
|
|
RCODE rc = NE_SFLM_OK;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
FLMUINT uiEndAddress;
|
|
FLMUINT uiLastFileNumber;
|
|
FLMUINT64 ui64LastFileSize;
|
|
char szTmpName [F_PATH_MAX_SIZE];
|
|
char szRflDir [F_PATH_MAX_SIZE];
|
|
IF_FileHdl * pFileHdl = NULL;
|
|
IF_DirHdl * pDirHdl = NULL;
|
|
|
|
if (m_eTransType == SFLM_READ_TRANS)
|
|
{
|
|
rc = RC_SET( NE_SFLM_ILLEGAL_TRANS_OP);
|
|
goto Exit;
|
|
}
|
|
else if (m_eTransType != SFLM_NO_TRANS)
|
|
{
|
|
if (!okToCommitTrans())
|
|
{
|
|
rc = RC_SET( NE_SFLM_ABORT_TRANS);
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (RC_BAD( rc = beginTrans( SFLM_UPDATE_TRANS)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
bStartedTrans = TRUE;
|
|
}
|
|
|
|
// See if they want the database files sizes.
|
|
|
|
if (pui64DataSize)
|
|
{
|
|
uiEndAddress = m_uiLogicalEOF;
|
|
uiLastFileNumber = FSGetFileNumber( uiEndAddress);
|
|
|
|
// Last file number better be in the proper range.
|
|
|
|
flmAssert( uiLastFileNumber >= 1 &&
|
|
uiLastFileNumber <= MAX_DATA_BLOCK_FILE_NUMBER);
|
|
|
|
// Get the actual size of the last file.
|
|
|
|
if (RC_BAD( rc = m_pSFileHdl->getFileSize( uiLastFileNumber,
|
|
&ui64LastFileSize)))
|
|
{
|
|
if (rc == NE_FLM_IO_PATH_NOT_FOUND ||
|
|
rc == NE_FLM_IO_INVALID_FILENAME)
|
|
{
|
|
if (uiLastFileNumber > 1)
|
|
{
|
|
rc = NE_SFLM_OK;
|
|
ui64LastFileSize = 0;
|
|
}
|
|
else
|
|
{
|
|
|
|
// Should always be a data file #1
|
|
|
|
RC_UNEXPECTED_ASSERT( rc);
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// One of two situations exists with respect to the last
|
|
// file: 1) it has not been fully written out yet (blocks
|
|
// are still cached, or 2) it has been written out and
|
|
// extended beyond what the logical EOF shows. We want
|
|
// the larger of these two possibilities.
|
|
|
|
if (FSGetFileOffset( uiEndAddress) > ui64LastFileSize)
|
|
{
|
|
ui64LastFileSize = FSGetFileOffset( uiEndAddress);
|
|
}
|
|
|
|
if (uiLastFileNumber == 1)
|
|
{
|
|
|
|
// Only one file - use last file's size.
|
|
|
|
*pui64DataSize = ui64LastFileSize;
|
|
}
|
|
else
|
|
{
|
|
|
|
// Size is the sum of full size for all files except the last one,
|
|
// plus the calculated (or actual) size of the last one.
|
|
|
|
(*pui64DataSize) = (FLMUINT64)(uiLastFileNumber - 1) *
|
|
(FLMUINT64)m_pDatabase->m_uiMaxFileSize +
|
|
ui64LastFileSize;
|
|
}
|
|
}
|
|
|
|
// See if they want the rollback files sizes.
|
|
|
|
if (pui64RollbackSize)
|
|
{
|
|
uiEndAddress = (FLMUINT)m_pDatabase->m_uncommittedDbHdr.ui32RblEOF;
|
|
uiLastFileNumber = FSGetFileNumber( uiEndAddress);
|
|
|
|
// Last file number better be in the proper range.
|
|
|
|
flmAssert( !uiLastFileNumber ||
|
|
(uiLastFileNumber >=
|
|
FIRST_LOG_BLOCK_FILE_NUMBER &&
|
|
uiLastFileNumber <=
|
|
MAX_LOG_BLOCK_FILE_NUMBER));
|
|
|
|
// Get the size of the last file number.
|
|
|
|
if (RC_BAD( rc = m_pSFileHdl->getFileSize( uiLastFileNumber,
|
|
&ui64LastFileSize)))
|
|
{
|
|
if (rc == NE_FLM_IO_PATH_NOT_FOUND ||
|
|
rc == NE_FLM_IO_INVALID_FILENAME)
|
|
{
|
|
if (uiLastFileNumber)
|
|
{
|
|
rc = NE_SFLM_OK;
|
|
ui64LastFileSize = 0;
|
|
}
|
|
else
|
|
{
|
|
|
|
// Should always have rollback file #0
|
|
|
|
RC_UNEXPECTED_ASSERT( rc);
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// If the EOF offset for the last file is greater than the
|
|
// actual file size, use it instead of the actual file size.
|
|
|
|
if (FSGetFileOffset( uiEndAddress) > ui64LastFileSize)
|
|
{
|
|
ui64LastFileSize = FSGetFileOffset( uiEndAddress);
|
|
}
|
|
|
|
// Special case handling here because rollback file numbers start with
|
|
// zero and then skip to a file number that is one beyond the
|
|
// highest data file number - so the calculation for file size needs
|
|
// to account for this.
|
|
|
|
if (!uiLastFileNumber)
|
|
{
|
|
*pui64RollbackSize = ui64LastFileSize;
|
|
}
|
|
else
|
|
{
|
|
FLMUINT uiFirstLogFileNum = FIRST_LOG_BLOCK_FILE_NUMBER;
|
|
|
|
// Add full size of file zero plus a full size for every file
|
|
// except the last one.
|
|
|
|
(*pui64RollbackSize) = (FLMUINT64)(uiLastFileNumber -
|
|
uiFirstLogFileNum + 1) *
|
|
(FLMUINT64)m_pDatabase->m_uiMaxFileSize +
|
|
ui64LastFileSize;
|
|
}
|
|
}
|
|
|
|
// See if they want the roll-forward log file sizes.
|
|
|
|
if (pui64RflSize)
|
|
{
|
|
char * pszDbFileName = m_pDatabase->m_pszDbPath;
|
|
|
|
*pui64RflSize = 0;
|
|
|
|
// Scan the RFL directory for
|
|
// RFL files. The call below to rflGetDirAndPrefix is done
|
|
// to get the prefix. It will not return the correct
|
|
// RFL directory name, because we are passing in a NULL
|
|
// RFL directory path (which may or may not be correct).
|
|
// That's OK, because we get the RFL directory directly
|
|
// from the F_Rfl object anyway.
|
|
|
|
if (RC_BAD( rc = rflGetDirAndPrefix( pszDbFileName,
|
|
NULL, szRflDir)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// We need to get the RFL directory from the F_Rfl object.
|
|
|
|
m_pDatabase->lockMutex();
|
|
f_strcpy( szRflDir, m_pDatabase->m_pRfl->getRflDirPtr());
|
|
m_pDatabase->unlockMutex();
|
|
|
|
// See if the directory exists. If not, we are done.
|
|
|
|
if (gv_SFlmSysData.pFileSystem->isDir( szRflDir))
|
|
{
|
|
|
|
// Open the directory and scan for RFL files.
|
|
|
|
if (RC_BAD( rc = gv_SFlmSysData.pFileSystem->openDir( szRflDir,
|
|
"*", &pDirHdl)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
for (;;)
|
|
{
|
|
if (RC_BAD( rc = pDirHdl->next()))
|
|
{
|
|
if (rc == NE_FLM_IO_NO_MORE_FILES)
|
|
{
|
|
rc = NE_SFLM_OK;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
pDirHdl->currentItemPath( szTmpName);
|
|
|
|
// If the item looks like an RFL file name, get
|
|
// its size.
|
|
|
|
if (!pDirHdl->currentItemIsDir() &&
|
|
rflGetFileNum( szTmpName, &uiLastFileNumber))
|
|
{
|
|
|
|
// Open the file and get its size.
|
|
|
|
if (RC_BAD( rc = gv_SFlmSysData.pFileSystem->openFile(
|
|
szTmpName, FLM_IO_RDWR | FLM_IO_SH_DENYNONE | FLM_IO_DIRECT,
|
|
&pFileHdl)))
|
|
{
|
|
if (rc == NE_FLM_IO_PATH_NOT_FOUND ||
|
|
rc == NE_FLM_IO_INVALID_FILENAME)
|
|
{
|
|
rc = NE_SFLM_OK;
|
|
ui64LastFileSize = 0;
|
|
}
|
|
else
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (RC_BAD( rc = pFileHdl->size( &ui64LastFileSize)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
if (pFileHdl)
|
|
{
|
|
pFileHdl->Release();
|
|
pFileHdl = NULL;
|
|
}
|
|
(*pui64RflSize) += ui64LastFileSize;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
|
|
if (pFileHdl)
|
|
{
|
|
pFileHdl->Release();
|
|
}
|
|
|
|
if (pDirHdl)
|
|
{
|
|
pDirHdl->Release();
|
|
}
|
|
|
|
if (bStartedTrans)
|
|
{
|
|
abortTrans();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Returns the next incremental backup sequence number for the database
|
|
****************************************************************************/
|
|
RCODE F_Db::getNextIncBackupSequenceNum(
|
|
FLMUINT * puiNextIncBackupSequenceNum
|
|
)
|
|
{
|
|
RCODE rc = NE_SFLM_OK;
|
|
FLMBOOL bStartedTrans = FALSE;
|
|
|
|
if (m_eTransType == SFLM_READ_TRANS)
|
|
{
|
|
rc = RC_SET( NE_SFLM_ILLEGAL_TRANS_OP);
|
|
goto Exit;
|
|
}
|
|
else if (m_eTransType != SFLM_NO_TRANS)
|
|
{
|
|
if (!okToCommitTrans())
|
|
{
|
|
rc = RC_SET( NE_SFLM_ABORT_TRANS);
|
|
goto Exit;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (RC_BAD( rc = beginTrans( SFLM_UPDATE_TRANS)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
bStartedTrans = TRUE;
|
|
}
|
|
|
|
*puiNextIncBackupSequenceNum =
|
|
(FLMUINT)m_pDatabase->m_uncommittedDbHdr.ui32IncBackupSeqNum;
|
|
|
|
Exit:
|
|
|
|
if (bStartedTrans)
|
|
{
|
|
abortTrans();
|
|
}
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Returns list of lock waiters in an object that allows caller to
|
|
iterate through the list.
|
|
****************************************************************************/
|
|
RCODE F_Db::getLockWaiters(
|
|
IF_LockInfoClient * pLockInfo
|
|
)
|
|
{
|
|
RCODE rc = NE_SFLM_OK;
|
|
|
|
if (m_pDatabase->m_pDatabaseLockObj)
|
|
{
|
|
rc = m_pDatabase->m_pDatabaseLockObj->getLockInfo( pLockInfo);
|
|
}
|
|
else
|
|
{
|
|
pLockInfo->setLockCount( 0);
|
|
}
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Returns RFL directory for the database
|
|
****************************************************************************/
|
|
void F_Db::getRflDir(
|
|
char * pszRflDir
|
|
)
|
|
{
|
|
m_pDatabase->lockMutex();
|
|
f_strcpy( pszRflDir, m_pDatabase->m_pRfl->getRflDirPtr());
|
|
m_pDatabase->unlockMutex();
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: Returns database serial number
|
|
****************************************************************************/
|
|
void F_Db::getSerialNumber(
|
|
char * pucSerialNumber)
|
|
{
|
|
m_pDatabase->lockMutex();
|
|
f_memcpy( pucSerialNumber, m_pDatabase->m_lastCommittedDbHdr.ucDbSerialNum,
|
|
SFLM_SERIAL_NUM_SIZE);
|
|
m_pDatabase->unlockMutex();
|
|
}
|