blob: fb956cdd0a039d50fd2284c6b20d87525f1eef46 [file] [log] [blame]
/**********************************************************************
// @@@ START COPYRIGHT @@@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//
// @@@ END COPYRIGHT @@@
//
**********************************************************************/
/* -*-C++-*-
******************************************************************************
*
* File: RuLogCleanupTaskExecutor.cpp
* Description: Implementation of class CRULogCleanupTaskExecutor.
*
*
* Created: 09/25/2000
* Language: C++
*
*
*
******************************************************************************
*/
#include "dmprepstatement.h"
#include "dsstringlist.h"
#include "uofsIpcMessageTranslator.h"
#include "RuLogCleanupTaskExecutor.h"
#include "RuLogCleanupTask.h"
#include "RuGlobals.h"
#include "RuJournal.h"
#include "RuLogCleanupSQLComposer.h"
//--------------------------------------------------------------------------//
// Constructor
//--------------------------------------------------------------------------//
CRULogCleanupTaskExecutor::CRULogCleanupTaskExecutor(CRUTask *pParentTask) :
inherited(pParentTask),
logCleanupTEDynamicContainer_(NUM_OF_SQL_STMT),
hasRangeLog_(TRUE),
noOfPartitions_(0)
{}
//--------------------------------------------------------------------------//
// CRULogCleanupTaskExecutor::Init()
//
// Initialize data members by analyzing the CleanupTask
//--------------------------------------------------------------------------//
void CRULogCleanupTaskExecutor::Init()
{
inherited::Init();
CRUTbl &tbl = GetLogCleanupTask()->GetTable();
hasRangeLog_ = (CDDObject::eNONE != tbl.GetRangeLogType());
noOfPartitions_ = tbl.getNumberOfPartitions();
ComposeMySql();
}
//--------------------------------------------------------------------------//
// CRULogCleanupTaskExecutor::StoreRequest()
//--------------------------------------------------------------------------//
// LCOV_EXCL_START :cnu
void CRULogCleanupTaskExecutor::
StoreRequest(CUOFsIpcMessageTranslator &translator)
{
inherited::StoreRequest(translator);
logCleanupTEDynamicContainer_.StoreData(translator);
translator.WriteBlock(&hasRangeLog_,sizeof(BOOL));
translator.WriteBlock(&noOfPartitions_,sizeof(Int32));
translator.SetMessageType(
CUOFsIpcMessageTranslator::RU_LOG_CLEANUP_EXECUTOR);
}
// LCOV_EXCL_STOP
//--------------------------------------------------------------------------//
// CRULogCleanupTaskExecutor::LoadRequest()
//--------------------------------------------------------------------------//
// LCOV_EXCL_START :cnu
void CRULogCleanupTaskExecutor::
LoadRequest(CUOFsIpcMessageTranslator &translator)
{
inherited::LoadRequest(translator);
logCleanupTEDynamicContainer_.LoadData(translator);
translator.ReadBlock(&hasRangeLog_,sizeof(BOOL));
translator.ReadBlock(&noOfPartitions_,sizeof(Int32));
}
// LCOV_EXCL_STOP
//--------------------------------------------------------------------------//
// CRULogCleanupTaskExecutor::ComposeMySql()
//--------------------------------------------------------------------------//
void CRULogCleanupTaskExecutor::ComposeMySql()
{
CRULogCleanupSQLComposer myComposer(GetLogCleanupTask());
myComposer.ComposeIUDLogCleanup(CLEAN_IUD_BASIC);
logCleanupTEDynamicContainer_.
SetStatementText(CLEAN_IUD_BASIC, myComposer.GetSQL());
myComposer.ComposeIUDLogCleanup(CLEAN_IUD_FIRSTN);
logCleanupTEDynamicContainer_.
SetStatementText(CLEAN_IUD_FIRSTN, myComposer.GetSQL());
myComposer.ComposeIUDLogCleanup(CLEAN_IUD_MCOMMIT);
logCleanupTEDynamicContainer_.
SetStatementText(CLEAN_IUD_MCOMMIT, myComposer.GetSQL());
if (TRUE == hasRangeLog_)
{
myComposer.ComposeRangeLogCleanup();
logCleanupTEDynamicContainer_.
SetStatementText(CLEAN_RANGE,myComposer.GetSQL());
}
myComposer.composeGetRowCount();
logCleanupTEDynamicContainer_.
SetStatementText(CLEAN_ROWCOUNT, myComposer.GetSQL());
}
//--------------------------------------------------------------------------//
// CRULogCleanupTaskExecutor::Work()
//
// Main finite-state machine switch.
//--------------------------------------------------------------------------//
void CRULogCleanupTaskExecutor::Work()
{
switch(GetState())
{
case EX_START:
{
RUASSERT(FALSE == IsTransactionOpen());
Start();
break;
}
case EX_CLEAN:
{
RUASSERT(FALSE == IsTransactionOpen());
Clean();
break;
}
case EX_EPILOGUE:
{
RUASSERT(FALSE == IsTransactionOpen());
Epilogue();
break;
}
default: RUASSERT(FALSE);
}
}
//--------------------------------------------------------------------------//
// CRULogCleanupTaskExecutor::Start()
//--------------------------------------------------------------------------//
void CRULogCleanupTaskExecutor::Start()
{
CDSString msg;
msg = RefreshDiags[17];
msg += GetLogCleanupTask()->GetTable().GetFullName();
msg += CDSString("...\n");
CRUGlobals::GetInstance()->GetJournal().LogMessage(msg);
SetState(EX_CLEAN);
}
//--------------------------------------------------------------------------//
// CRULogCleanupTaskExecutor::Clean()
//
// Delete the inapplicable data from the log
//--------------------------------------------------------------------------//
void CRULogCleanupTaskExecutor::Clean()
{
SQL_STATEMENT deleteMethod = decideOnDeleteMethod();
switch(deleteMethod)
{
case CLEAN_IUD_BASIC :
CleanLogBasic();
break;
case CLEAN_IUD_MCOMMIT :
CleanLogMultiCommit();
break;
case CLEAN_IUD_FIRSTN :
CleanLogFirstN(CLEAN_IUD_FIRSTN);
break;
}
if (TRUE == hasRangeLog_)
{
CleanLogFirstN(CLEAN_RANGE);
}
SetState(EX_EPILOGUE);
}
//--------------------------------------------------------------------------//
// CRULogCleanupTaskExecutor::decideOnDeleteMethod()
//
// A heuristic decision on which delete method to use.
// First we use this formula to get the average number of rows er partition:
// rowCount * SF
// ---------------
// P * 100
// Where: rowCount is the number of rows in the IUD log (as an upper bound to
// the number of rows to be deleted).
// SF is the safety factor from the defaults table (default is 50%).
// P is the number of partitions.
//
// If the number of rows per partition is smaller than the lock escalation
// limit, we use a simple delete statement.
// Otherwise we use delete with multi commit, unless it is disabled by a CQD.
//--------------------------------------------------------------------------//
CRULogCleanupTaskExecutor::SQL_STATEMENT CRULogCleanupTaskExecutor::decideOnDeleteMethod()
{
SQL_STATEMENT deleteMethod;
BeginTransaction();
CDSString safetyFactorName("MV_LOG_CLEANUP_SAFETY_FACTOR");
TInt32 safetyFactor = 0;
CRUCache::FetchSingleDefault( safetyFactorName, safetyFactor);
CDSString useMultiCommitName("MV_LOG_CLEANUP_USE_MULTI_COMMIT");
TInt32 useMultiCommit = 1;
CRUCache::FetchSingleDefault( useMultiCommitName, useMultiCommit);
if (safetyFactor <= 100)
{
// When the safty factor is set to 100 or less, lock escalation is not an issue,
// so we can use simple delete no matter how many rows are to be deleted.
deleteMethod = CLEAN_IUD_BASIC;
#ifdef _DEBUG
// LCOV_EXCL_START :dpb
CDSString msg("Safety factor set to 100 or less - using simple delete.");
CRUGlobals::GetInstance()->
LogDebugMessage(CRUGlobals::DUMP_COMPILED_DYNAMIC_SQL, "", msg, FALSE);
// LCOV_EXCL_STOP
#endif
}
else
{
Int64 rowCount = getRowCount();
TInt64 rowsPerPartition = rowCount * safetyFactor / (noOfPartitions_ * 100);
if (rowsPerPartition < CRULogCleanupSQLComposer::MAX_ROW_TO_DELETE_IN_SINGLE_TXN)
deleteMethod = CLEAN_IUD_BASIC;
else if (useMultiCommit == 1)
deleteMethod = CLEAN_IUD_MCOMMIT;
else
deleteMethod = CLEAN_IUD_FIRSTN;
#ifdef _DEBUG
CDSString msg;
char buff[200];
sprintf(buff, "IUD log has " PF64 " rows, and %d partitions. Safety factor is %d. Using ",
rowCount, noOfPartitions_, safetyFactor);
msg = buff;
switch(deleteMethod)
{
case CLEAN_IUD_BASIC:
msg += "simple delete.\n";
break;
case CLEAN_IUD_FIRSTN:
msg += "delete First N.\n";
break;
case CLEAN_IUD_MCOMMIT:
msg += "delete with Multi Commit.\n";
break;
}
CRUGlobals::GetInstance()->
LogDebugMessage(CRUGlobals::DUMP_COMPILED_DYNAMIC_SQL, "", msg, FALSE);
#endif
}
CommitTransaction();
return deleteMethod;
}
//--------------------------------------------------------------------------//
// CRULogCleanupTaskExecutor::CleanLogBasic()
//
// No need to loop, but must start a transaction.
//--------------------------------------------------------------------------//
void CRULogCleanupTaskExecutor::CleanLogBasic()
{
// Compilation Stage
CDMPreparedStatement *pStat =
logCleanupTEDynamicContainer_.GetPreparedStatement(CLEAN_IUD_BASIC);
BeginTransaction();
ExecuteStatement(*pStat,
IDS_RU_LOG_CLEANUP_FAILED,
NULL, /* error argument */
TRUE /* Obtain row count */);
CommitTransaction();
TESTPOINT(CRUGlobals::TESTPOINT160);
}
//--------------------------------------------------------------------------//
// CRULogCleanupTaskExecutor::CleanLogFirstN()
//
// Need both the loop and the transactions.
//--------------------------------------------------------------------------//
void CRULogCleanupTaskExecutor::CleanLogFirstN(SQL_STATEMENT statement)
{
// Compilation Stage
CDMPreparedStatement *pStat =
logCleanupTEDynamicContainer_.GetPreparedStatement(statement);
while (TRUE)
{
BeginTransaction();
ExecuteStatement(*pStat,
IDS_RU_LOG_CLEANUP_FAILED,
NULL, /* error argument */
TRUE /* Obtain row count */);
CommitTransaction();
TESTPOINT(CRUGlobals::TESTPOINT160);
if (pStat->GetRowsAffected() <
CRULogCleanupSQLComposer::MAX_ROW_TO_DELETE_IN_SINGLE_TXN)
{
break;
}
}
}
//--------------------------------------------------------------------------//
// CRULogCleanupTaskExecutor::CleanLogMultiCommit()
//
// No need to loop or handle transactions.
//--------------------------------------------------------------------------//
void CRULogCleanupTaskExecutor::CleanLogMultiCommit()
{
// Compilation Stage
CDMPreparedStatement *pStat =
logCleanupTEDynamicContainer_.GetPreparedStatement(CLEAN_IUD_MCOMMIT);
ExecuteStatement(*pStat,
IDS_RU_LOG_CLEANUP_FAILED,
NULL, /* error argument */
TRUE /* Obtain row count */);
TESTPOINT(CRUGlobals::TESTPOINT160);
}
//--------------------------------------------------------------------------//
// CRULogCleanupTaskExecutor::getRowCount()
//
// Find out the number of rows in the IUD log table.
//--------------------------------------------------------------------------//
TInt64 CRULogCleanupTaskExecutor::getRowCount()
{
CDMPreparedStatement *pStat =
logCleanupTEDynamicContainer_.GetPreparedStatement(CLEAN_ROWCOUNT);
ExecuteStatement(*pStat,
IDS_RU_LOG_CLEANUP_FAILED,
NULL, /* error argument */
TRUE, /* Obtain row count */
TRUE /* isQuery */);
CDMResultSet *resultSet = pStat->GetResultSet();
resultSet->Next();
TInt64 rowCount = resultSet->GetLargeInt(1);
pStat->Close();
return rowCount;
}
//--------------------------------------------------------------------------//
// CRULogCleanupTaskExecutor::Epilogue()
//--------------------------------------------------------------------------//
void CRULogCleanupTaskExecutor::Epilogue()
{
CRULogCleanupTask *pTask = GetLogCleanupTask();
RUASSERT(NULL != pTask);
CRUTbl &tbl = pTask->GetTable();
// Update the T.MIN_EPOCH metadata variable
BeginTransaction();
tbl.SetMinLogEpoch(pTask->GetMaxInapplicableEpoch()+1);
tbl.SaveMetadata();
CommitTransaction();
CDSString msg(RefreshDiags[18]);
msg += GetLogCleanupTask()->GetTable().GetFullName();
msg += CDSString(".\n");
CRUGlobals::GetInstance()->GetJournal().LogMessage(msg);
SetState(EX_COMPLETE);
}