| /********************************************************************** |
| // @@@ 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); |
| } |