Files
mars-flaim/sql/src/translog.cpp
dsandersoremutah 58d6cbdace Sync up with latest common toolkit changes.
git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@612 0109f412-320b-0410-ab79-c3e0c5ffbbe6
2006-06-23 21:26:53 +00:00

323 lines
8.2 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 lgWriteComplete(
IF_IOBuffer * pIOBuffer);
#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 lgWriteComplete(
IF_IOBuffer * pIOBuffer)
{
F_Database * pDatabase =
(F_Database *)pIOBuffer->getCompletionCallbackData( 0);
#ifdef FLM_DBG_LOG
FLMUINT uiBlockSize = pDatabase->getBlockSize();
FLMUINT uiLength = pIOBuffer->getBufferSize();
char * pszEvent;
#endif
SFLM_DB_STATS * pDbStats = (SFLM_DB_STATS *)pIOBuffer->getStats();
#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->getElapTime();
pDatabase->unlockMutex();
}
}
/****************************************************************************
Desc: This routine flushes a log buffer to the log file.
****************************************************************************/
RCODE F_Database::lgFlushLogBuffer(
SFLM_DB_STATS * pDbStats,
F_SuperFileHdl * pSFileHdl,
FLMBOOL bDoAsync)
{
RCODE rc = NE_SFLM_OK;
FLMUINT uiBytesWritten;
IF_IOBuffer * pAsyncBuffer;
if (!bDoAsync)
{
pAsyncBuffer = NULL;
}
else
{
pAsyncBuffer = m_pCurrLogBuffer;
}
if (pDbStats)
{
pDbStats->bHaveStats = TRUE;
pDbStats->LogBlockWrites.ui64Count++;
pDbStats->LogBlockWrites.ui64TotalBytes += m_uiCurrLogWriteOffset;
}
m_pCurrLogBuffer->setCompletionCallback( lgWriteComplete);
m_pCurrLogBuffer->setCompletionCallbackData( 0, (void *)this);
pSFileHdl->setMaxAutoExtendSize( m_uiMaxFileSize);
pSFileHdl->setExtendSize( m_uiFileExtendSize);
m_pCurrLogBuffer->startTimer( pDbStats);
// NOTE: No guarantee that m_pCurrLogBuffer will still be around
// after the call to WriteBlock, unless we are doing
// non-asynchronous write.
rc = pSFileHdl->writeBlock( m_uiCurrLogBlkAddr,
m_uiCurrLogWriteOffset,
m_pCurrLogBuffer->getBuffer(),
pAsyncBuffer, &uiBytesWritten);
if (!pAsyncBuffer)
{
m_pCurrLogBuffer->notifyComplete( rc);
}
m_pCurrLogBuffer = NULL;
if (RC_BAD( rc))
{
if (pDbStats)
{
pDbStats->uiWriteErrors++;
}
goto Exit;
}
Exit:
m_uiCurrLogWriteOffset = 0;
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
FLMBOOL bDoAsync, // Do asynchronous writes?
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,
bDoAsync)))
{
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(
&m_pCurrLogBuffer, uiLogBufferSize, uiLogBufferSize)))
{
// 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->getBuffer() + 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,
bDoAsync)))
{
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);
}