/*!
    @ingroup        Restart
    @file           Rst_RedoManager.cpp
    @author         UweH
    @author         MartinB
    @author         JuergenA
    @brief          parallel undo/redo of transactions in order to restart the database
*/
/*

    ========== licence begin  GPL
    Copyright (c) 2000-2005 SAP AG

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.

    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, write to the Free Software
    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
    ========== licence end



 */
#include "RunTime/RTE_Message.hpp"
#include "Restart/Rst_Exceptions.hpp"
#include "Restart/Rst_RedoManager.hpp"
#include "Restart/Rst_RedoTaskLifeCycle.hpp"
#include "Restart/Rst_RedoTrafficControl.hpp"
#include "Restart/Rst_RedoReadTask.hpp"
#include "Logging/Log_Volume.hpp"
#include "Logging/Log_Savepoint.hpp"
#include "KernelCommon/Kernel_Trace.hpp"
#include "ggg00.h"
// --------------------------------------------------------------------------
void Rst_RedoManager::CheckForClearLog(       tsp00_TaskId          taskid,
                                        const Rst_LogEntryIterator &iter,
                                              bool                 &lastPageCleared)
{
    SAPDBTRACE_METHOD_DEBUG ("Rst_RedoManager::CheckForClearLog", LogTrans_Trace, 5);
    Log_Volume         &log = Log_Volume::Instance();
    Log_IOSequenceNo    lastIOSequenceOnLog = iter.GetLastProcessedIOSeq();
    
    lastPageCleared = false;
    if (!log.LogIsEmpty())
    // also for an emtpy log the DB has to be restartable
    {
        if (Log_VolumeIterator::Iter_untilReached == iter.GetState())
        {
            if (iter.GetLastReadOffset().IsValid())                    // PTS 1111525 mb 2002-01-24 restore log until
            // some or all pages from the log_device had been read
            {
                Log_IOSequenceNo         firstIOSeqOfLogVolume;
                Log_RawDeviceOffset      firstKnownOffset;
                
                log.GetFirstKnownBeforeRestoreLog(firstKnownOffset, firstIOSeqOfLogVolume);
                Log_RawDeviceOffset firstToBeCleared = iter.GetLastReadOffset();
                Log_RawDeviceIterator lastToBeCleared = 
                        --(Log_RawDeviceIterator( log.LogicalLogBeginOffset(),
                                                  firstKnownOffset,
                                                  log.LogicalLogEndOffset()));
                log.ClearLogPartially ( taskid,
                                        firstToBeCleared,
                                        lastToBeCleared.GetPosition(),
                                        lastIOSequenceOnLog,
                                        lastPageCleared);
            }
            else
            // no pages of the log_device had been read => clear them all
            {
                log.ClearLogComplete (taskid,
                                      lastIOSequenceOnLog+1);
                lastPageCleared = true;
            }
        }
    }
}
// --------------------------------------------------------------------------
void Rst_RedoManager::RedoLog (
                    tgg00_TransContext &TransContext,
                    Log_RawDeviceOffset lastRedoOffset,
			  const Kernel_Date         untilDate,
              const Kernel_Time         untilTime,
              const Log_IOSequenceNo    untilIOSeq,
                    Rst_RedoKind        redokind)
{
    SAPDBTRACE_METHOD_DEBUG ("Rst_RedoManager::RedoLog", LogTrans_Trace, 5);
    
    KERNEL_TRACE_BASIS_ERROR (TransContext.trError_gg00, LogTrans_Trace, 5);
    
    m_redoIsAborted = false;
    m_untilDate = untilDate;
    m_untilTime = untilTime;
    if (untilIOSeq.IsValid())				// PTS 1124727 mb 2003-10-20
    {
        m_untilIOSequence = untilIOSeq;
        ++m_untilIOSequence;
    }
    SAPDBMem_IRawAllocator         &allocator = *reinterpret_cast<SAPDBMem_IRawAllocator*>(TransContext.trAllocator_gg00);
    Rst_LogEntryIterator            logIter (m_untilDate, m_untilTime, m_untilIOSequence, lastRedoOffset, redokind, allocator);
    Rst_RedoReadTask                redoReader (logIter, m_redoIsAborted);
    Rst_RedoAllocateTrafficControl  RedoTrafficControl;
    bool                            isOk = true;

    RedoTrafficControl.Allocate (allocator,m_redoIsAborted,m_transread,m_transredone,isOk);
    if ( ! isOk )
    {
        TransContext.trError_gg00 = e_no_more_memory;
        return;
    }
    
    m_pRedoReadIterator = &logIter;
    m_pRedoReader       = &redoReader;
    
    {   // inside this block log reader tasks are running
        Rst_RedoReadTaskLifeCycle ReadTaskLifeCycle (TransContext);

        {   // inside this block redo execute tasks are running
            Rst_RedoExecuteTaskLifeCycle ExecuteTaskLifeCycle (TransContext);
        }
    }
    
    logIter.GetReadPosition(m_LastEntryRead); // PTS 1123675 UH 2003-08-20
    
    m_pRedoReader       = 0;
    m_pRedoReadIterator = 0;

    if ( TransContext.trRteCommPtr_gg00->to_cancel ) // UH 2002-05-21 added
        m_redoIsAborted = true;                      // UH 2002-05-21 added

    if ( e_ok == TransContext.trError_gg00
         &&
         m_redoIsAborted )
    {
         TransContext.trError_gg00 = m_abortReason;
    }
    
    if (e_ok == TransContext.trError_gg00)     // PTS 1123675 UH 2003-08-20
    {
        bool lastReadPageCleared;
        CheckForClearLog(TransContext.trTaskId_gg00, logIter, lastReadPageCleared);
    
        Log_Volume       &log            = Log_Volume::Instance();
        Log_IOSequenceNo  nextIOSeqOnLog = logIter.GetLastProcessedIOSeq();
        
        if (redokind == Rst_RedoKindRestoreLog || !log.LogIsEmpty())
        {
            ++nextIOSeqOnLog;
        }
    
        Log_RawDeviceIterator nextWritePosition;
        if (logIter.GetLastReadOffset().IsValid() &&  !log.LogIsEmpty())
        // there had been something read from the log and it had not been cleared by CheckForClearLog()
        {
            if (!lastReadPageCleared)
            {
                nextWritePosition = ++(Log_RawDeviceIterator (log.LogicalLogBeginOffset(),
                                                              logIter.GetLastReadOffset(), 
                                                              log.LogicalLogEndOffset()));
            }
            else
            {
                nextWritePosition = Log_RawDeviceIterator (log.LogicalLogBeginOffset(),
                                                           logIter.GetLastReadOffset(), 
                                                           log.LogicalLogEndOffset());
            }
        }
        else
        {
            nextWritePosition = Log_RawDeviceIterator (log.LogicalLogBeginOffset(),
                                                       log.LogicalLogBeginOffset(),
                                                       log.LogicalLogEndOffset());
        }
        
        log.UpdateIOSequenceAndOffset (TransContext.trTaskId_gg00, nextIOSeqOnLog, nextWritePosition);

        // PTS 1126112 UH 2003-12-09 moved to Log_Savepoint::Coordinator()
        // Log_SavepointManager.EnableSavepointWriteOnLog ();
        if ( redokind == Rst_RedoKindRestoreLog )
            // PTS ? UH 2004-01-21 call only if restore log in case of hot standby config
            Log_SavepointManager.StartSavepointAndWait (TransContext, Log_SVPReasonRestart);
        return;
    }
    
    if ( redokind == Rst_RedoKindRestoreLog
         &&
         e_cancelled == TransContext.trError_gg00 )
    {
        Log_EntryInfo entryInfo;
        GetLastEntryRead (entryInfo);
        if ( entryInfo.iosequence.IsValid() )
            // PTS 1127077 2004-01-12 the reason must not be "Restart"
            Log_SavepointManager.StartSavepointAndWait (TransContext, Log_SVPReasonDistance);
        TransContext.trError_gg00 = e_cancelled;
    }
}
// --------------------------------------------------------------------------
void Rst_RedoManager::AbortRedo(const tgg00_BasisError abortReason)
{
    SAPDBTRACE_METHOD_DEBUG ("Rst_RedoManager::AbortRedo", LogTrans_Trace, 5);
    m_redoIsAborted = true;
    m_abortReason = abortReason;
}
// --------------------------------------------------------------------------
void Rst_RedoManager::GetProgressInfo( SAPDB_UInt &transread,
                                       SAPDB_UInt &transredone )
{
    SAPDBTRACE_METHOD_DEBUG ("Rst_RedoManager::GetProgressInfo", LogTrans_Trace, 5);
    transread   = m_transread;
    transredone = m_transredone;
    RTE_Message( Restart_Exception(__CONTEXT__, RST_REDO_PROGRESS,
                               SAPDB_ToString(transread),
                               SAPDB_ToString(transredone)) );
}
// --------------------------------------------------------------------------
Log_RawDeviceOffset Rst_RedoManager::GetLastRedoReadOffset()
{
    SAPDBTRACE_METHOD_DEBUG ("Rst_RedoManager::GetLastRedoReadOffset", LogTrans_Trace, 5);
    if ( 0 == m_pRedoReadIterator )
        return Log_RawDeviceOffset(); 
    return  m_pRedoReadIterator->GetCurrentReadOffset();
}
// --------------------------------------------------------------------------
void Rst_RedoManager::SetLastRedoReadOffset( Log_RawDeviceOffset lastRedoOffset, tsp00_TaskId taskId  )
{
    SAPDBTRACE_METHOD_DEBUG ("Rst_RedoManager::SetLastRedoReadOffset", LogTrans_Trace, 5);
    if ( 0 != m_pRedoReadIterator )
    {
        Log_Volume     &log = Log_Volume::Instance();
        if (   lastRedoOffset >= log.LogicalLogBeginOffset()
            && lastRedoOffset <= log.LogicalLogEndOffset())
        {
            m_pRedoReadIterator->SetLastRedoReadOffset(lastRedoOffset, taskId);
        }
        else
        {
            RTE_Message(Restart_Exception(__CONTEXT__, RST_INVALID_REDO_OFFSET,
                  SAPDB_ToString(lastRedoOffset,_T_d)));
        }
    }
}
// --------------------------------------------------------------------------
void Rst_RedoManager::SuspendRedoReader(tsp00_TaskId          taskid)
{
    SAPDBTRACE_METHOD_DEBUG ("Rst_RedoManager::SuspendRedoReader", LogTrans_Trace, 5);
    if ( m_pRedoReadIterator != 0 )
    {
        m_pRedoReadIterator->SuspendRedoReader(taskid);
    }
}
// --------------------------------------------------------------------------
void Rst_RedoManager::ResumeRedoReader(const Kernel_Date         untilDate,
                                       const Kernel_Time         untilTime)
{
    SAPDBTRACE_METHOD_DEBUG ("Rst_RedoManager::ResumeRedoReader", LogTrans_Trace, 5);
    if ( m_pRedoReadIterator != 0 )
    {
        m_untilDate = untilDate;
        m_untilTime = untilTime;
        m_pRedoReadIterator->ResumeReaderForRestart();
    }
}
// --------------------------------------------------------------------------
void Rst_RedoManager::GetLastEntryRead(Log_EntryInfo &entryInfo)
{
    // PTS 1123675 UH 2003-08-20 new
    SAPDBTRACE_METHOD_DEBUG ("Rst_RedoManager::GetLastEntryRead", LogTrans_Trace, 5);
    if ( m_pRedoReader != 0 )
        m_pRedoReader->GetReadPosition(m_LastEntryRead); 
    entryInfo = m_LastEntryRead;
}
// --------------------------------------------------------------------------
void Rst_RedoManager::ReadLogAndCreateRedoFiles(tgg00_TransContext &readerTrans)
{
    // PTS 1123675 UH 2003-08-20 new
    SAPDBTRACE_METHOD_DEBUG ("Rst_RedoManager::ReadLogAndCreateRedoFiles", LogTrans_Trace, 5);
    if ( 0 == m_pRedoReader )
    {
        readerTrans.trError_gg00 = e_not_implemented;
        return;
    }
    m_pRedoReader->ReadLogAndCreateRedoFiles(readerTrans);
}
/*===========================================================================*
*  END OF CODE                                                               *
*============================================================================*/
