git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@697 0109f412-320b-0410-ab79-c3e0c5ffbbe6
303 lines
7.8 KiB
C++
303 lines
7.8 KiB
C++
//------------------------------------------------------------------------------
|
|
// Desc: Routines to handle transaction logging
|
|
//
|
|
// 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$
|
|
//------------------------------------------------------------------------------
|
|
|
|
#include "flaimsys.h"
|
|
|
|
FSTATIC void FLMAPI lgWriteComplete(
|
|
IF_IOBuffer * pIOBuffer,
|
|
void * pvData);
|
|
|
|
#ifdef FLM_DBG_LOG
|
|
/****************************************************************************
|
|
Desc: This routine is used to write out information about logged blocks to
|
|
the log file.
|
|
****************************************************************************/
|
|
void scaLogWrite(
|
|
F_Database * pDatabase,
|
|
FLMUINT uiWriteAddress,
|
|
FLMBYTE * pucBlkBuf,
|
|
FLMUINT uiBufferLen,
|
|
FLMUINT uiBlockSize,
|
|
char * pszEvent
|
|
)
|
|
{
|
|
FLMUINT uiOffset = 0;
|
|
FLMUINT32 ui32BlkAddr;
|
|
FLMUINT64 ui64TransID;
|
|
|
|
while (uiOffset < uiBufferLen)
|
|
{
|
|
ui32BlkAddr = ((F_BLK_HDR *)pucBlkBuf)->ui32BlkAddr;
|
|
ui64TransID = ((F_BLK_HDR *)pucBlkBuf)->ui64TransID;
|
|
|
|
// A uiWriteAddress of zero means we are writing exactly at the
|
|
// block address - i.e., it is the data block, not the log block.
|
|
|
|
flmDbgLogWrite( pDatabase, (FLMUINT)ui32BlkAddr,
|
|
(FLMUINT)((uiWriteAddress)
|
|
? uiWriteAddress + uiOffset
|
|
: (FLMUINT)ui32BlkAddr),
|
|
ui64TransID, pszEvent);
|
|
uiOffset += uiBlockSize;
|
|
pucBlkBuf += uiBlockSize;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
Desc: This is the callback routine that is called when a disk write is
|
|
completed.
|
|
****************************************************************************/
|
|
FSTATIC void FLMAPI lgWriteComplete(
|
|
IF_IOBuffer * pIOBuffer,
|
|
void * pvData)
|
|
{
|
|
F_Database * pDatabase =
|
|
(F_Database *)pIOBuffer->getCallbackData( 0);
|
|
#ifdef FLM_DBG_LOG
|
|
FLMUINT uiBlockSize = pDatabase->getBlockSize();
|
|
FLMUINT uiLength = pIOBuffer->getBufferSize();
|
|
char * pszEvent;
|
|
#endif
|
|
SFLM_DB_STATS * pDbStats = (SFLM_DB_STATS *)pvData;
|
|
|
|
#ifdef FLM_DBG_LOG
|
|
pszEvent = (char *)(RC_OK( pIOBuffer->getCompletionCode())
|
|
? (char *)"LGWRT"
|
|
: (char *)"LGWRT-FAIL");
|
|
scaLogWrite( pDatabase, 0, pIOBuffer->getBuffer(), uiLength,
|
|
uiBlockSize, pszEvent);
|
|
#endif
|
|
|
|
if (pDbStats)
|
|
{
|
|
|
|
// Must lock mutex, because this may be called from async write
|
|
// completion at any time.
|
|
|
|
pDatabase->lockMutex();
|
|
pDbStats->LogBlockWrites.ui64ElapMilli += pIOBuffer->getElapsedTime();
|
|
pDatabase->unlockMutex();
|
|
}
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: This routine flushes a log buffer to the log file.
|
|
****************************************************************************/
|
|
RCODE F_Database::lgFlushLogBuffer(
|
|
SFLM_DB_STATS * pDbStats,
|
|
F_SuperFileHdl * pSFileHdl)
|
|
{
|
|
RCODE rc = NE_SFLM_OK;
|
|
|
|
if (pDbStats)
|
|
{
|
|
pDbStats->bHaveStats = TRUE;
|
|
pDbStats->LogBlockWrites.ui64Count++;
|
|
pDbStats->LogBlockWrites.ui64TotalBytes += m_uiCurrLogWriteOffset;
|
|
}
|
|
|
|
m_pCurrLogBuffer->setCompletionCallback( lgWriteComplete, pDbStats);
|
|
m_pCurrLogBuffer->addCallbackData( (void *)this);
|
|
pSFileHdl->setMaxAutoExtendSize( m_uiMaxFileSize);
|
|
pSFileHdl->setExtendSize( m_uiFileExtendSize);
|
|
|
|
// NOTE: No guarantee that m_pCurrLogBuffer will still be around
|
|
// after the call to writeBlock, unless we are doing
|
|
// non-asynchronous write.
|
|
|
|
if( RC_BAD( rc = pSFileHdl->writeBlock( m_uiCurrLogBlkAddr,
|
|
m_uiCurrLogWriteOffset, m_pCurrLogBuffer)))
|
|
{
|
|
if (pDbStats)
|
|
{
|
|
pDbStats->uiWriteErrors++;
|
|
}
|
|
|
|
goto Exit;
|
|
}
|
|
|
|
Exit:
|
|
|
|
m_uiCurrLogWriteOffset = 0;
|
|
m_pCurrLogBuffer->Release();
|
|
m_pCurrLogBuffer = NULL;
|
|
|
|
return( rc);
|
|
}
|
|
|
|
/****************************************************************************
|
|
Desc: This routine writes a block to the log file.
|
|
****************************************************************************/
|
|
RCODE F_Database::lgOutputBlock(
|
|
SFLM_DB_STATS * pDbStats,
|
|
F_SuperFileHdl * pSFileHdl,
|
|
F_CachedBlock * pLogBlock, // Cached log block.
|
|
F_BLK_HDR * pBlkHdr, // Pointer to the corresponding modified
|
|
// block in cache. This block will be
|
|
// modified to the logged version of
|
|
// the block
|
|
FLMUINT * puiLogEofRV) // Returns log EOF
|
|
{
|
|
RCODE rc = NE_SFLM_OK;
|
|
FLMUINT uiFilePos = *puiLogEofRV;
|
|
FLMBYTE * pucLogBlk;
|
|
F_BLK_HDR * pLogBlkHdr;
|
|
FLMUINT uiBlkAddress;
|
|
FLMUINT uiLogBufferSize;
|
|
|
|
// Time for a new block file?
|
|
|
|
if (FSGetFileOffset( uiFilePos) >= m_uiMaxFileSize)
|
|
{
|
|
FLMUINT uiFileNumber;
|
|
|
|
// Write out the current buffer, if it has anything in it.
|
|
|
|
if (m_uiCurrLogWriteOffset)
|
|
{
|
|
if (RC_BAD( rc = lgFlushLogBuffer( pDbStats, pSFileHdl)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
uiFileNumber = FSGetFileNumber( uiFilePos);
|
|
|
|
if (!uiFileNumber)
|
|
{
|
|
uiFileNumber = FIRST_LOG_BLOCK_FILE_NUMBER;
|
|
}
|
|
else
|
|
{
|
|
uiFileNumber++;
|
|
}
|
|
|
|
if (uiFileNumber > MAX_LOG_BLOCK_FILE_NUMBER)
|
|
{
|
|
rc = RC_SET( NE_SFLM_DB_FULL);
|
|
goto Exit;
|
|
}
|
|
|
|
if (RC_BAD( rc = pSFileHdl->createFile( uiFileNumber )))
|
|
{
|
|
goto Exit;
|
|
}
|
|
uiFilePos = FSBlkAddress( uiFileNumber, 0 );
|
|
}
|
|
|
|
// Copy the log block to the log buffer.
|
|
|
|
if (!m_uiCurrLogWriteOffset)
|
|
{
|
|
m_uiCurrLogBlkAddr = uiFilePos;
|
|
|
|
// Get a buffer for logging.
|
|
// NOTE: Buffers are not kept by the F_Database's buffer manager,
|
|
// so once we are done with this buffer, it will be freed.
|
|
|
|
uiLogBufferSize = MAX_LOG_BUFFER_SIZE;
|
|
|
|
for( ;;)
|
|
{
|
|
if (RC_BAD( rc = m_pBufferMgr->getBuffer(
|
|
uiLogBufferSize, &m_pCurrLogBuffer)))
|
|
{
|
|
// If we failed to get a buffer of the requested size,
|
|
// reduce the buffer size by half and try again.
|
|
|
|
if( rc == NE_SFLM_MEM)
|
|
{
|
|
uiLogBufferSize /= 2;
|
|
if( uiLogBufferSize < m_uiBlockSize)
|
|
{
|
|
goto Exit;
|
|
}
|
|
rc = NE_SFLM_OK;
|
|
continue;
|
|
}
|
|
goto Exit;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Copy data from log block to the log buffer
|
|
|
|
pucLogBlk = m_pCurrLogBuffer->getBufferPtr() + m_uiCurrLogWriteOffset;
|
|
pLogBlkHdr = (F_BLK_HDR *)pucLogBlk;
|
|
f_memcpy( pLogBlkHdr, pLogBlock->m_pBlkHdr, m_uiBlockSize);
|
|
|
|
// If we are logging this block for the current update
|
|
// transaction, set the BEFORE IMAGE (BI) flag in the block header
|
|
// so we will know that this block is a before image block that
|
|
// needs to be restored when aborting the current update
|
|
// transaction.
|
|
|
|
if (pLogBlock->m_ui16Flags & CA_WRITE_TO_LOG)
|
|
{
|
|
pLogBlkHdr->ui8BlkFlags |= BLK_IS_BEFORE_IMAGE;
|
|
}
|
|
uiBlkAddress = (FLMUINT)pLogBlkHdr->ui32BlkAddr;
|
|
|
|
// Encrypt the block if needed
|
|
|
|
if (RC_BAD( rc = encryptBlock( m_pDictList,
|
|
(FLMBYTE *)pLogBlkHdr)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
if (RC_BAD( rc = flmPrepareBlockToWrite( m_uiBlockSize, pLogBlkHdr)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
|
|
// Set up for next log block write
|
|
|
|
m_uiCurrLogWriteOffset += m_uiBlockSize;
|
|
|
|
// If this log buffer is full, write it out.
|
|
|
|
if (m_uiCurrLogWriteOffset == m_pCurrLogBuffer->getBufferSize())
|
|
{
|
|
if (RC_BAD( rc = lgFlushLogBuffer( pDbStats, pSFileHdl)))
|
|
{
|
|
goto Exit;
|
|
}
|
|
}
|
|
|
|
// Save the previous block address into the modified block's
|
|
// block header area. Also save the transaction id.
|
|
|
|
pBlkHdr->ui32PriorBlkImgAddr = (FLMUINT32)uiFilePos;
|
|
|
|
*puiLogEofRV = uiFilePos + m_uiBlockSize;
|
|
|
|
Exit:
|
|
|
|
return( rc);
|
|
}
|