/*!**************************************************************************

  module      : Log_Savepoint.cpp
  special area: Logging
  responsible : UweH
  created     : 2000-09-25  12:00
  last changed: 2000-10-27  12:00
  copyright:    (c) 2000-2004 SAP AG
  description : The savepoint manager.

    The phases of the savepoint:
    ----------------------------
    
    - Enter all TransRegions, so redo/undo file handling is locked.
    - Get IO-Sequence of all logwriters
    - Flush all logwriter until this savepoint entry and get the entry id.
    - Create the savepoint file with entries for all open transactions.
    - set the datacache to PrepareSavepoint
    - Leave all TransRegion.
    - Flush datacache and converter
    - Flush the restart record and the log info page.
    - increment the converter version


    ========== 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


*****************************************************************************/


/*===========================================================================*
 *  INCLUDES                                                                 *
 *===========================================================================*/

#include "heo52.h"   // vclock
#include "heo55k.h"  // vbegexcl, vendexcl
#include "heo56.h"   // vsuspend
#include "ggg92.h"   // only for hkb51.h
#include "hgg01.h"   // g01mblock_init, g01is_livecache, g01svp_1_conv_flush
#include "hgg08.h"   // g08savepoint
#include "hgg11.h"   // g11kernel_version
#include "hkb38_1.h" // k38is_on_autosave, k38e_autosave_end
#include "hkb50.h"   // k50GetLogTransaction, k50RegisterTransaction
#include "hkb51.h"   // k51enter_all_trans_regions, kb51GetFirstWriteTrans
#include "hkb53.h"   // k53child_trans_build
#include "hkb90.h"   // k90send
#include "hbd01.h"   // b01downfilesystem
#include "hbd20_4.h" // bd20SavepointCompleted
#include "hbd90.h"   // bd90MakeObjCountPersistent
#include "hbd91.h"   // GarbCollController
#include "gkb00.h"   // tkb00_SaveptParam
#include "hkb57.h"   // k57flush_sequences
#include "hkb57_1.h" // k57restartrec

#include "RunTime/RTE_Message.hpp"
#include "SAPDBCommon/Tracing/SAPDBTrace_Usage.hpp"
#include "KernelCommon/Kernel_DateTime.hpp"
#include "KernelCommon/Kernel_IAdminRestartShutdown.hpp"
#include "KernelCommon/Kernel_IAdminHotStandby.hpp"
#include "Converter/Converter_IBackUp.hpp"
#include "Converter/Converter_ICommon.hpp"
#include "Converter/Converter_ISavePoint.hpp"
#include "Logging/Log_Types.hpp"
#include "Logging/Log_AfterImage.hpp"
#include "Logging/Log_ActionSavepoint.hpp"
#include "Logging/Log_Volume.hpp"
#include "Logging/Log_Transaction.hpp"
#include "Logging/Log_OpenTransFile.hpp"
#include "Logging/Log_History.hpp"
#include "Logging/Log_Savepoint.hpp"
#include "Logging/Log_Exceptions.hpp"
#include "Restart/Rst_IRedoReadTask.hpp"
#include "FreeBlockManagement/FBM_IManager.hpp"
#include "SAPDBCommon/ErrorsAndMessages/SAPDBErr_Assertions.hpp"
#include "SAPDBCommon/Tracing/SAPDBTrace_Usage.hpp"
#include "Pager/Pager_ISavepoint.hpp"


/*===========================================================================*
 *  DEFINES                                                                  *
 *===========================================================================*/

#define DISABLE_DATAWRITER  TRUE

/*===========================================================================*
 *  EXTERNAL VARIABLES                                                       *
 *===========================================================================*/

Log_Savepoint Log_SavepointManager;

/*===========================================================================*
 *  LOCAL ROUTINES                                                           *
 *===========================================================================*/

/*---------------------------------------------------------------------------*/
static inline
void PrintReason (tsp00_TaskId        taskid,
                  Log_SavepointReason reason,
                  bool                started)
{
    if ( started )
        RTE_Message( Log_Exception( __CONTEXT__, LOG_SAVEPOINT_REASON,
                                    SAPDB_ToString(taskid,_T_d),
                                    Log_SavepointReasonStrings[reason],
                                    started ? "started" : "not started" ) );
}

/*---------------------------------------------------------------------------*/
static inline bool SystemIsReadyForSavepoint()
{
    return ! b01downfilesystem
           &&
           Log_Volume::IsReadyForWriting()
           &&
           (0 == g01is_livecache() || Log_History::IsInitialized());
}

/*===========================================================================*
 *  CLASSES, STRUCTURES, TYPES, UNIONS ...                                   *
 *===========================================================================*/

/*---------------------------------------------------------------------------*/
void Log_Savepoint::BeginRegion (tsp00_TaskId taskid)
{
    vbegexcl ( taskid, g08savepoint);
}

/*---------------------------------------------------------------------------*/
void Log_Savepoint::EndRegion (tsp00_TaskId taskid)
{
    vendexcl ( taskid, g08savepoint);
}

/*---------------------------------------------------------------------------*/
void Log_Savepoint::StartCoordinator (tgg00_TransContext &Trans)
{
    SAPDBTRACE_METHOD_DEBUG ("Log_Savepoint::StartCoordinator", LogTrans_Trace, 5);

    tgg00_TransChild ChildTrans;
    tgg00_MessBlock  SendMessBlock;

    g01mblock_init (Trans, m_savepoint, mm_nil, SendMessBlock);
    k53child_trans_build (m_savepoint, Converter_ICommon::Instance().Version(), ChildTrans);
    ChildTrans.tcdState_gg00.addElement( tsDbFullNowait_egg00 ); // PTS 1114490 TS 2002-03-05
    SendMessBlock.mb_reply() = false;
    k90send (SendMessBlock, ChildTrans);
    if ( Trans.trError_gg00 != e_ok )
        RTE_Crash( Log_Exception(__CONTEXT__, LOG_START_SAVEPOINT_FAILED, // PTS 1129781 UH 2004-05-24
                                 SAPDB_ToString(Trans.trError_gg00)) );
    SAPDBTRACE_WRITELN (LogTrans_Trace, 6, "end: triggered");
}

/*---------------------------------------------------------------------------*/
bool Log_Savepoint::IsDBManagerReason (Log_SavepointReason reason)
{
    return reason == Log_SVPReasonSaveData
           ||
           reason == Log_SVPReasonSavePages
           ||
           reason == Log_SVPReasonRestart
           ||
           reason == Log_SVPReasonShutdown
		   ||
		   reason == Log_SVPReasonCheckConverterFBM;
}

/*---------------------------------------------------------------------------*/
bool Log_Savepoint::DenySavepoint (tsp00_TaskId taskid)
{
    // PTS 1121281 UH 2003-03-24 new
    SAPDBTRACE_METHOD_DEBUG ("Log_Savepoint::DenySavepoint", LogTrans_Trace, 5);
    BeginRegion (taskid);
    if ( m_IsActive )
    {
        EndRegion (taskid);
        return false;
    }
    m_SavepointAllowed = false;
    EndRegion (taskid);
    return true;
}
/*---------------------------------------------------------------------------*/
void Log_Savepoint::PermitSavepoint (tsp00_TaskId taskid)
{
    SAPDBTRACE_METHOD_DEBUG ("Log_Savepoint::PermitSavepoint", LogTrans_Trace, 5);
    // PTS 1121281 UH 2003-03-24 new
    BeginRegion (taskid);
    m_SavepointAllowed = true;
    EndRegion (taskid);
}
/*---------------------------------------------------------------------------*/
bool Log_Savepoint::IsSavepointAllowed() const
{
    // PTS 1121281 UH 2003-03-24 new
    if ( m_SavepointAllowed )
        return true;
    RTE_Message(Log_Exception(__CONTEXT__,LOG_SAVEPOINT_NOT_ALLOWED));
    return false;
}
/*---------------------------------------------------------------------------*/
void Log_Savepoint::StartSavepointAndWait (tgg00_TransContext  &trans,
                                           Log_SavepointReason  Reason)
{
    SAPDBTRACE_METHOD_DEBUG ("Log_Savepoint::StartSavepointAndWait", LogTrans_Trace, 5);

    if ( ! SystemIsReadyForSavepoint() )
    {
        // PTS 1129993 UH 2004-06-16
        RTE_Message( Log_Exception(__CONTEXT__, LOG_SAVEPOINT_WANTED_BUT_DENIED,
                     Log_SavepointReasonStrings[Reason],
                     "Not SystemIsReadyForSavepoint") );
        return;
    }
    
    tsp00_TaskId        &taskid = trans.trTaskId_gg00;
    Log_SavepointReason  reason = Reason;
    
    if ( ! Log_Volume::Instance().ReserveForEotWillNotBlock() // PTS 1130928 mb 2004-08-10
         &&
         (Log_SVPReasonSaveData  == reason ||
          Log_SVPReasonSavePages == reason) )
    {
        // PTS 1129993 UH 2004-06-16 added if-clause
        RTE_Message( Log_Exception(__CONTEXT__, LOG_SAVEPOINT_WANTED_BUT_DENIED,
                     Log_SavepointReasonStrings[reason],
                     "LOG FULL") );
        trans.trError_gg00 = e_log_full;
        if ( Log_Volume::Instance().GetDeviceState() == Log_DeviceStateHistoryLost )
            RTE_Message( Log_Exception(__CONTEXT__, LOG_BACKUP_AFTER_DATA_BACKUP_NEEDED_IN_ADMIN_MODE) );
        return;
    }

    bool startCoordinator = false;
    
    BeginRegion (taskid);
    
    if ( ! IsSavepointAllowed() )
    {
        // PTS 1121281 UH 2003-03-24
        if ( IsDBManagerReason(Reason) )
            RTE_Crash( SAPDBErr_Exception(__CONTEXT__,SAPDBERR_ASSERT_STATE_FAILED,
                       "Savepoint writing not allowed but needed") );
        EndRegion (taskid);
        return;
    }
    
    if ( ! IsDBManagerReason(Reason) )
        CurrentWaitList().InsertAsFirst(taskid, trans.trWaitContext_gg00);
    else
    {
        if ( m_WaitingDBmanager == cgg_nil_pid )
        {
            m_WaitingDBmanager = taskid;
            m_DBmanagerReason  = Reason;
        }
        else
        {
            Kernel_VTrace() << "waiting task: " << m_WaitingDBmanager
                            << ", old reason: " << Log_SavepointReasonStrings[m_DBmanagerReason]
                            << ", new reason: " << Log_SavepointReasonStrings[Reason]
                            << ", from task " << taskid << NewLine;
                               
            RTE_Crash( SAPDBErr_Exception(__CONTEXT__,SAPDBERR_ASSERT_STATE_FAILED,
                                          "Log_Savepoint::StartSavepointAndWait: (DBM) called twice") );
        }
    }
    if ( ! m_IsActive )
    {
        startCoordinator = true;
        m_IsActive       = true;
    }
    EndRegion (taskid);

    PrintReason (taskid, Reason, startCoordinator);

    if ( startCoordinator )
    {
        StartCoordinator (trans);
        if ( trans.trError_gg00 != e_ok )
            RTE_Crash( Log_Exception(__CONTEXT__,SAPDBERR_ASSERT_STATE_FAILED,
                       "Log_Savepoint::StartSavepointAndWait: StartCoordinator() failed") );
        if ( LogTrans_Trace.TracesLevel(6) )                                          
            Kernel_VTrace() << "*** SAVEPOINT STARTED AND WAIT T" << taskid;
    }
    
    
    SAPDBTRACE_WRITELN (LogTrans_Trace, 6, "suspended TaskId: " << taskid);
    vsuspend (taskid, 243);
}
/*---------------------------------------------------------------------------*/
void Log_Savepoint::StartSavepoint (tgg00_TransContext  &trans,
                                    Log_SavepointReason  reason)
{
    SAPDBTRACE_METHOD_DEBUG ("Log_Savepoint::StartSavepoint", LogTrans_Trace, 5);

    if ( ! SystemIsReadyForSavepoint() )
    {
        // PTS 1129993 UH 2004-06-16
        RTE_Message( Log_Exception(__CONTEXT__, LOG_SAVEPOINT_WANTED_BUT_DENIED,
                     Log_SavepointReasonStrings[reason],
                     "Not SystemIsReadyForSavepoint") );
        return;
    }

    tsp00_TaskId &taskid = trans.trTaskId_gg00;

    if ( ! Log_Volume::Instance().ReserveForEotWillNotBlock() // PTS 1130928 mb 2004-08-10
         &&
         (Log_SVPReasonSaveData  == reason ||
          Log_SVPReasonSavePages == reason) )
    {
        // PTS 1129993 UH 2004-06-16 added if-clause
        RTE_Message( Log_Exception(__CONTEXT__, LOG_SAVEPOINT_WANTED_BUT_DENIED,
                     Log_SavepointReasonStrings[reason],
                     "LOG FULL") );
        trans.trError_gg00 = e_log_full;
        if ( Log_Volume::Instance().GetDeviceState() == Log_DeviceStateHistoryLost )
            RTE_Message( Log_Exception(__CONTEXT__, LOG_BACKUP_AFTER_DATA_BACKUP_NEEDED_IN_ADMIN_MODE) );
        return;
    }

    bool startCoordinator = false;
    
    BeginRegion (taskid);
    if ( ! m_IsActive )
    {
        if ( ! IsSavepointAllowed() ) // PTS 1121281 UH 2003-03-24
        {
            EndRegion (taskid);
            return;
        }
        
        if ( reason != Log_SVPReasonUnknown
             ||
             ! CurrentWaitList().IsEmpty()
             || 
             m_WaitingDBmanager != cgg_nil_pid )
        {
            startCoordinator = true;
            m_IsActive       = true;
        }
    }
    EndRegion (taskid);

    PrintReason (trans.trTaskId_gg00, reason, startCoordinator);
    
    if ( startCoordinator )
    {
        StartCoordinator (trans);
        if ( trans.trError_gg00 != e_ok )
            RTE_Crash( SAPDBErr_Exception(__CONTEXT__,SAPDBERR_ASSERT_STATE_FAILED,
                       "Log_Savepoint::StartSavepoint: StartCoordinator() failed") );
        if ( LogTrans_Trace.TracesLevel(6) )                                          
            Kernel_VTrace() << "*** SAVEPOINT STARTED T" << taskid;
    }
}

/*---------------------------------------------------------------------------*/
void Log_Savepoint::Coordinator (tgg00_TransContext &Trans)
{
    SAPDBTRACE_METHOD_DEBUG ("Log_Savepoint::Coordinator", LogTrans_Trace, 5);

    if ( b01downfilesystem )
    {
        BeginRegion (Trans.trTaskId_gg00);
        m_IsActive = false;
        EndRegion (Trans.trTaskId_gg00);

        Trans.trError_gg00 = e_shutdown;

        return;
    }

    bool                loopAgain;
    tsp00_TaskId        WaitingDBmanager;
    Log_SavepointReason Reason;
    tkb00_SaveptParam   saveptParam;
    teo00_Int4          starttimeSec;      // PTS 1119276 UH 2002-12-10
    teo00_Int4          starttimeMSec;     // PTS 1119276 UH 2002-12-10
    teo00_Int4          endtimeSec;        // PTS 1119276 UH 2002-12-10
    teo00_Int4          endtimeMSec;       // PTS 1119276 UH 2002-12-10
    SAPDB_UInt          numPages;          // PTS 1119276 HH 2002-12-12
    SAPDB_UInt          numPagesTotal = 0; // PTS 1119276 HH 2002-12-12
    SAPDB_UInt          numIO;             // PTS 1119276 HH 2002-12-12
    SAPDB_UInt          numIOTotal    = 0; // PTS 1119276 HH 2002-12-12

    do
    {
        vclock(&starttimeSec,&starttimeMSec); // PTS 1119276 UH 2002-12-10
        loopAgain = false;
        
        BeginRegion (Trans.trTaskId_gg00);
        
        SwitchWaitList();
        WaitingDBmanager   = m_WaitingDBmanager;
        Reason             = m_DBmanagerReason != Log_SVPReasonUnknown ? m_DBmanagerReason
                                                                       : Log_SVPReasonUnknown;
        m_DBmanagerReason  = Log_SVPReasonUnknown;
        m_WaitingDBmanager = cgg_nil_pid;
        saveptParam        = k57restartrec->rstLastSavept_kb00();
        
        EndRegion (Trans.trTaskId_gg00);

		if ( ! Log_Volume::Instance().ReserveForEotWillNotBlock() // PTS 1130928 mb 2004-08-10
			 &&
			 Log_SVPReasonShutdown == Reason )
		{
	        // PTS 1129993 UH 2004-06-16 added if-clause
			Trans.trError_gg00 = e_log_full;
            ShutdownFilesystem (Trans);
			// never come to this line
		}

        if ( LogTrans_Trace.TracesLevel(6) )                                          
            Kernel_VTrace() << "*** SAVEPOINT START T" << Trans.trTaskId_gg00
                            << " (" << Log_SavepointReasonStrings[Reason] << ")" << NewLine;

        /***************************************************************************/
        /***** now, new requests would result in another savepoint loop       ******/
        /***** now, tasks which want to wait for a savepoint wait for the next *****/
        /***************************************************************************/
        
        saveptParam.svpReason_kb00 = Reason;
        ++saveptParam.svpId_kb00;

        SAPDBTRACE_WRITELN (LogTrans_Trace, 6, "SVP: SavepointSequence: " << saveptParam.svpId_kb00);

        /*********************************************************************/
        /***** Prepare data writer for the first flush of data cache and *****/
        /***** converter storage. Make memory structures persistent.     *****/
        /*********************************************************************/

        Pager_ISavepoint::GetInstance().BeginSavepoint( Trans.trTaskId_gg00 );

        if( TRUE == g01is_livecache() )
        {
           bd91StopOMSGarbageCollectionForSpecialOp( Trans.trTaskId_gg00 );

           if( Reason == Log_SVPReasonShutdown )
           {
               bd90MakeObjCountPersistent( Trans );
               
               if( e_ok != Trans.trError_gg00 )
                   RTE_Crash( SAPDBErr_Exception(__CONTEXT__, SAPDBERR_ASSERT_STATE_FAILED,
                              "Log_Savepoint::Coordinator: Can not make liveCache object counters persistent") );
           }
        }

        Pager_ISavepoint::GetInstance().FlushDataCacheBeforePrepare( Trans.trTaskId_gg00, numPages, numIO );
        numPagesTotal += numPages;
        numIOTotal += numIO;

        /*************************************************************************/
        /***** all cached sequences must be flushed now                      *****/
        /*************************************************************************/

        // PTS 1117320 UH 2002-10-28
        // PTS ? UH 2003-05-07 moved k57flush_sequences() after FlushDataCacheBeforePrepare()
        k57flush_sequences (Trans);
  
        if ( Trans.trError_gg00 != e_ok )
            RTE_Crash( SAPDBErr_Exception(__CONTEXT__,SAPDBERR_ASSERT_STATE_FAILED, "k57flush_sequences") );
  
        /*************************************************************************/
        /***** Prevent split operation and wait until last split is finished *****/
        /*************************************************************************/

        bd20SetPreventSplit( Trans.trTaskId_gg00 );

        Pager_ISavepoint::GetInstance().WaitForLastSplit( Trans, numPages, numIO );
        numPagesTotal += numPages;
        numIOTotal += numIO;

        k51enter_all_trans_regions (Trans.trTaskId_gg00);
        SAPDBTRACE_WRITELN (LogTrans_Trace, 6, "SVP: no new write transaction can be started or removed now");

        const bool bIsRedoSavepoint = ! m_LogWriteEnabled;

        DetermineRedoStartPositions ( Trans,
                                      *reinterpret_cast<SAPDBMem_IRawAllocator*>(Trans.trAllocator_gg00),
                                      saveptParam);

        SAPDBTRACE_WRITELN (LogTrans_Trace, 6, "SVP: savepoint logentries were written to the archive logs. ");

        // PTS 1117320 UH 2002-10-28 - re-enable surrogates to be written to the log
        // PTS ? UH 2003-05-07 moved k57end_flush_sequences() directly after DetermineRedoStartPositions()
        k57end_flush_sequences (Trans.trTaskId_gg00);

        CreateOpenTransFile (Trans, saveptParam, bIsRedoSavepoint);
        SAPDBTRACE_WRITELN (LogTrans_Trace, 6, "SVP: open trans file was created.");

        if( TRUE == g01is_livecache() )
        {
            saveptParam.svpHistoryRoot_kb00 = Log_History::GetInstance().Flush(Trans);
            SAPDBTRACE_WRITELN (LogTrans_Trace, 6, "SVP: hisotry directory is flushed.");
            if( e_ok != Trans.trError_gg00 )
                RTE_Crash( SAPDBErr_Exception(__CONTEXT__, SAPDBERR_ASSERT_STATE_FAILED,
                           "liveCache history directory flush") );
        }
           
        /******************************************************************************/
        /*****    mark all svp relevant pages within data cache for final flush    ****/
        /******************************************************************************/

        Converter_Version converterVersion = Converter_ICommon::Instance().Version();
        
        // Set the savepoint state in the component converter to active before the data cache 
        // is prepared to guarantee that no gap exist during the operation "FreeDataPageNo", 
        // which possible cause an inconsistency between data and converter
        Converter_ISavePoint::Instance().BeginSavepoint( Trans.trTaskId_gg00 );

        bd20PrepareSavepoint( Trans.trTaskId_gg00, converterVersion );

        bd20UnSetPreventSplit( Trans.trTaskId_gg00 );

        BeginRegion(Trans.trTaskId_gg00);

        m_WaitingForPrepare.ResumeAll();

        /*********************************************/
        /***** new converter version is used now *****/
        /*********************************************/

		// PTS 1123461 UH 2003-08-28 wake up of waiting tasks is moved down

        EndRegion(Trans.trTaskId_gg00);

        k51leave_all_trans_regions (Trans.trTaskId_gg00);
        SAPDBTRACE_WRITELN (LogTrans_Trace, 6, "SVP: new write transactions can be started or removed again");

        if(( Log_SVPReasonShutdown != Reason ) && ( TRUE == g01is_livecache())) // PTS 1129813 TS 2004-05-25
        {
            bd91StartOMSGarbageCollectionAfterSpecialOp( Trans.trTaskId_gg00 );
            SAPDBTRACE_WRITELN (LogTrans_Trace, 6, "SVP: all waiting tasks were resumed");
        }

        Pager_ISavepoint::GetInstance().FlushDataCacheAfterPrepare( Trans.trTaskId_gg00, numPages, numIO );
        numPagesTotal += numPages;
        numIOTotal += numIO;
       
        // Prepare converter for backup. Note that this will change converter pages
        // and this pages have to be flushed with the current savepoint.
        if( Log_SVPReasonSaveData == Reason  || Log_SVPReasonSavePages == Reason)
        {   
            Converter_ReturnCode retCode = Converter_Ok;
            if( Log_SVPReasonSaveData == Reason ){
                retCode = Converter_IBackUp::Instance().BeginSaveData( Trans.trTaskId_gg00 );
            }
            else{ 
                retCode = Converter_IBackUp::Instance().BeginSavePages( Trans.trTaskId_gg00 );
            }
            if( Converter_Ok != retCode )
            {   // TODO TorstenS/Uwe system shall not crash (KERNEL_DATA_BACKUP_FAILED)
                RTE_Crash( SAPDBErr_Exception(__CONTEXT__,SAPDBERR_ASSERT_STATE_FAILED, 
                    "BeginSaveData/Pages because of exhausted memory"));
            }
        }
		
		if( Log_SVPReasonCheckConverterFBM == Reason)
		{   
			Converter_ReturnCode retCode = Converter_Ok;
			retCode = Converter_IBackUp::Instance().CheckConverterFBM( Trans.trTaskId_gg00 );
		}
		

        IOMan_PackedBlockAddress  packedRootBlockAddr;
        Data_PageNo               maxDynamicPageNo;
        Data_PageNo               maxStaticPageNo;

        Converter_ISavePoint::Instance().FlushParallel( Trans.trTaskId_gg00, converterVersion, 
            maxStaticPageNo, maxDynamicPageNo, packedRootBlockAddr, numPages, numIO );

        numPagesTotal += numPages;
        numIOTotal    += numIO;

        FlushRestartRecordAndLogInfoPages ( Trans,
                                            Reason,
                                            saveptParam,
                                            converterVersion,
                                            packedRootBlockAddr,
                                            maxDynamicPageNo,
                                            maxStaticPageNo );

        FlushCompleted( Trans.trTaskId_gg00, converterVersion );

        if ( Log_SVPReasonShutdown == Reason )
        {
            Pager_ISavepoint::GetInstance().EndSavepoint( Trans.trTaskId_gg00, DISABLE_DATAWRITER );
            ShutdownFilesystem (Trans);
        }
        else
        {
            Pager_ISavepoint::GetInstance().EndSavepoint( Trans.trTaskId_gg00, ! DISABLE_DATAWRITER );
        }

        if ( WaitingDBmanager != cgg_nil_pid )
        {
            vresume (WaitingDBmanager);
            SAPDBTRACE_WRITELN (LogTrans_Trace, 6, "SVP: resumed WaitingDBmanager");
        }
                
        BeginRegion (Trans.trTaskId_gg00);

        // PTS 1123461 UH 2003-08-28 wake up of waiting tasks is now done here after savepoint is valid.
        WaitListForCurrentSavepoint().ResumeAll();

        loopAgain = ( Reason != Log_SVPReasonShutdown )
                    &&
                    ( ! CurrentWaitList().IsEmpty()
                      ||
                      m_WaitingDBmanager != cgg_nil_pid );
        if ( ! loopAgain )
            m_IsActive = false;
        EndRegion (Trans.trTaskId_gg00);
        
        // PTS 1119276 UH 2002-12-10 begin
        vclock(&endtimeSec,&endtimeMSec);
        m_Statistics.Add(Statistic(endtimeSec  - starttimeSec,
                                   endtimeMSec - starttimeMSec,
                                   numPagesTotal, numIOTotal));
        // PTS 1119276 UH 2002-12-10 end
    }
    while ( loopAgain );
    
    /*************************************************/
    /***** the current savepoint is finished now *****/
    /*************************************************/

    if ( LogTrans_Trace.TracesLevel(6) )                                          
        Kernel_VTrace() << "*** SAVEPOINT END T" << Trans.trTaskId_gg00;
}

/*---------------------------------------------------------------------------*/
void Log_Savepoint::DetermineRedoStartPositions
    (tgg00_TransContext     &CoordinatorTrans,
     SAPDBMem_IRawAllocator &Allocator,
     tkb00_SaveptParam      &saveptParam)
{
    SAPDBTRACE_METHOD_DEBUG ("Log_Savepoint::DetermineRedoStartPositions", LogTrans_Trace, 5);

    if (!m_LogWriteEnabled)                     // PTS 1115875 mb 2002-05-28
    {
        if ( Log_SVPReasonRestart == saveptParam.svpReason_kb00 )
            m_LogWriteEnabled = true; // PTS 1126112 UH 2003-12-09 
        else
        {
            Log_EntryInfo entryInfo;
            Kernel_IAdminRestartShutdown::Instance().GetLastEntryRead (entryInfo);
            if ( entryInfo.iosequence.IsInvalid())
            {
                if (Log_SVPReasonDistance == saveptParam.svpReason_kb00)
                // there has been something read from the log, but no iosequence is known
                {
                    RTE_Crash( SAPDBErr_Exception(__CONTEXT__,SAPDBERR_ASSERT_STATE_FAILED, "Savepoint IOSequence must be valid") );
                }
                else
                // do nothing, because nothing has been read, so the savepoint position
                // remains unchanged
                {
                    return;
                }
            }
            else
            {
                saveptParam.svpIOsequence_kb00       = entryInfo.iosequence.RawValue();
                saveptParam.svpStartOffset_kb00      = entryInfo.pageoffset;
                saveptParam.svpStartEntryOffset_kb00 = entryInfo.entryoffset;
                saveptParam.svpStartEntryType_kb00   = entryInfo.entrytype;
                saveptParam.svpStartEntryDate_kb00   = entryInfo.entrydate;
                saveptParam.svpStartEntryTime_kb00   = entryInfo.entrytime;
                return;
            }
        }
    }
    
    Log_AfterImage      AfterImage;
    Log_ActionSavepoint Action (Log_SavepointReason(saveptParam.svpReason_kb00));

    if ( saveptParam.svpReason_kb00 == Log_SVPReasonRestart )
        AfterImage.SetActionType(Log_FinishOpenTrans);
    else
        AfterImage.SetActionType(Log_SavepointEntry);

    AfterImage.SetSequence (saveptParam.svpId_kb00);
    // AfterImage.SetTransNo          ();
    // AfterImage.SetLastUndoSequence ();
    
    Log_AfterImageSpace Space (Allocator);

    if ( ! Space.Initialize() )
        RTE_Crash( SAPDBErr_Exception(__CONTEXT__,SAPDBERR_ASSERT_STATE_FAILED, "Space.Initialize()") );
    
    Log_Queue           *queue = Log_Volume::Instance().GetQueue(CoordinatorTrans.trTaskId_gg00);
    Log_IOSequenceNo     ioSeqNo;
    Log_RawDeviceOffset  devOffset;
    
    if ( 0 == queue )
        RTE_Crash( SAPDBErr_Exception(__CONTEXT__,SAPDBERR_ASSERT_STATE_FAILED, "queue is assigned") );

    ioSeqNo.Invalidate();
    devOffset.Invalidate();
    saveptParam.svpStartEntryOffset_kb00 = 0;

    queue->ReserveForEOT ( CoordinatorTrans.trTaskId_gg00,
                           CoordinatorTrans.trWaitContext_gg00,
                           AfterImage.GetPersistentLength()
                          +
                          Action.GetPersistentLength(),
                          Space,
                          saveptParam.svpStartEntryOffset_kb00 );
                          
    SAPDBERR_ASSERT_STATE ( (AfterImage.GetPersistentLength() \
                             + \
                             Action.GetPersistentLength()) == Space.Length() );

    Data_SplitSpaceWriter Writer (Space);
    bool                  isOK = true;
    
    AfterImage.WritePersistentFormat (Writer, isOK);
    if ( isOK )
        Action.WritePersistentFormat (Writer, isOK);

    queue->UserTaskEOTReady ( CoordinatorTrans.trTaskId_gg00,
                             CoordinatorTrans.trWaitContext_gg00,
                             Space,
                             ioSeqNo,
                             devOffset );
                            
    saveptParam.svpIOsequence_kb00     = ioSeqNo.RawValue(); // PTS 1124724 mb 2003-10-29
    saveptParam.svpStartOffset_kb00    = devOffset;
    saveptParam.svpStartEntryType_kb00 = AfterImage.GetActionType();
    saveptParam.svpStartEntryDate_kb00 = saveptParam.svpDate_kb00;
    saveptParam.svpStartEntryTime_kb00 = saveptParam.svpTime_kb00;
    
    SAPDBTRACE_WRITELN (LogTrans_Trace, 6, "SVP: IOSeqNo: " << saveptParam.svpIOsequence_kb00 << \
                                      ", OffsetOnDevice: " << saveptParam.svpStartOffset_kb00 << \
                                      ", OffsetInPage: "   << saveptParam.svpStartEntryOffset_kb00);
}

/*---------------------------------------------------------------------------*/
void Log_Savepoint::FlushRestartRecordAndLogInfoPages
    (tgg00_TransContext         &coordinatorTrans,
     Log_SavepointReason        reason,
     tkb00_SaveptParam          &saveptParam,
     Converter_Version          &converterVersion,
     IOMan_PackedBlockAddress   &packedRootBlockAddr,
     Data_PageNo                &maxDynamicPageNo,
     Data_PageNo                &maxStaticPageNo)
{
    BeginRegion (coordinatorTrans.trTaskId_gg00);
    
    k57restartrec->rstLastSavept_kb00() = saveptParam;

    g11kernel_version ( k57restartrec->rstReleaseVersion_kb00() );
    
    if ( Log_SVPReasonSaveData == reason )
        k57restartrec->rstLastSaveDataSuccessful_kb00() = false;
        
    k57restartrec->rstPrevConverterVers_kb00() = k57restartrec->rstConverterVersion_kb00();
    k57restartrec->rstConverterVersion_kb00()  = converterVersion;
    k57restartrec->rstSetEndReadOnly_kb00()    = false;
    
    tkb00_ConfigRestartParam &conf = k57restartrec->rstConfigParam_kb00();

    conf.crConvRootBlockAddr_kb00 = packedRootBlockAddr;
    conf.crMaxDynamicPno_kb00     = maxDynamicPageNo;
    conf.crMaxStaticPno_kb00      = maxStaticPageNo;

    k57save_restartrecord (coordinatorTrans.trTaskId_gg00); // now the new savepoint is valid

    if ( coordinatorTrans.trError_gg00 != e_ok )
        RTE_Crash( SAPDBErr_Exception(__CONTEXT__, SAPDBERR_ASSERT_STATE_FAILED,
                   "Log_Savepoint::FlushRestartRecordAndLogInfoPages: k57save_restartrecord failed") );

    if ( Log_SVPReasonSaveData == reason || Log_SVPReasonSavePages == reason )
        *k57frozen_restartrec = *k57restartrec;
    
    Log_Volume &log      = Log_Volume::Instance();
    SAPDB_Byte     *svpValue = reinterpret_cast<SAPDB_Byte*>(&saveptParam);
    
    EndRegion (coordinatorTrans.trTaskId_gg00);

    if ( ! Kernel_IAdminHotStandby::Instance().IsStandby() )
        log.WriteSavepointValuesAndFlushInfoPage
                    (coordinatorTrans.trTaskId_gg00,
                     Log_SVPReasonRestart == saveptParam.svpReason_kb00, // PTS 1137938
                     k57restartrec->rstReleaseVersion_kb00(),
                     SAPDBFields_Field(svpValue, sizeof(saveptParam)));
}

/*---------------------------------------------------------------------------*/
void Log_Savepoint::FlushCompleted (tsp00_TaskId            TaskId,
                                    const Converter_Version &converterVersion)
{
    SAPDBTRACE_METHOD_DEBUG ("Log_Savepoint::FlushCompleted", LogTrans_Trace, 5);

    // Set all blocks from state FreeAfterSavepoint to Free. Note that this
    // has to take place BEFORE the data cache AND the converter are informed 
    // about the savepoint end situation, because: 
    // 
    // First: this guarantees that blocks which are written after the data cache and 
    // converter flush initiated by the savepoint won't be set to FreeAfterSavepoint
    // resp. Free immediately. (PTS 1132143)
    // 
    // Second: this guarantees that the blocks of the pageNo's which are released at 
    // the end of the savepoint won't be set to FreeAfterSavepoint resp. Free 
    // immediately. (PTS 1137294)

    FBM_IManager::Instance().SetAllBlocksMarkedAsFreeAfterSVPToFree( TaskId );

    // Increment converter version. At this time all savepoint relevant data
    // pages and the converter pages are written to the data area.
    // The data pages written next, will get the incremented converter version!
    // At this point the converter is not in savepoint mode, which means that there
    // is no special handling for pageNo's and the corresponding blocks to be released!

    Converter_Version newConverterVersion;
    Converter_ISavePoint::Instance().EndSavepoint( TaskId, newConverterVersion );

    // Reset savepoint state and enable data cache to write non 
    // savepoint relevant data pages to the data area

    bd20SavepointCompleted( TaskId, converterVersion );

    // Free pnos removed during prepare phase 
    Converter_ISavePoint::Instance().FreePageNosAfterSavepoint( TaskId );
}

/*---------------------------------------------------------------------------*/
void Log_Savepoint::CreateOpenTransFile (tgg00_TransContext &CoordinatorTrans,
                                         tkb00_SaveptParam  &saveptParam,
                                         bool                bIsRedoSavepoint)
{
    SAPDBTRACE_METHOD_DEBUG ("Log_Savepoint::CreateOpenTransFile", LogTrans_Trace, 5);

    Log_OpenTransFile File             (CoordinatorTrans, saveptParam.svpId_kb00, bIsRedoSavepoint);
    Log_OpenTransFile OldOpenTransFile (CoordinatorTrans, saveptParam.svpOpenTransRoot_kb00);
    tgg00_TransIndex  WriteTransIndex = cgg_nil_transindex;
    Log_Transaction  *pLogTrans       = NULL;
    Log_IOSequenceNo  oldestKnownIOSequence; // PTS 1124684 UH 2003-10-16
    Log_IOSequenceNo  oldestOpenTransIOSequence; // PTS 1124684 UH 2003-10-16
    
    if ( saveptParam.svpOpenTransRoot_kb00 == NIL_PAGE_NO_GG00 )  // PTS 1124684 UH 2003-10-16
		oldestKnownIOSequence = 0;
	else
        oldestKnownIOSequence = OldOpenTransFile.GetOldestKnownIOSequence();
    
    SAPDBTRACE_WRITELN (LogTrans_Trace, 6, "SVP: oldestKnownIOSequence: " << oldestKnownIOSequence);

    if ( ! File.Create () ) // PTS 1121659 UH 2003-04-30
        RTE_Crash( SAPDBErr_Exception(__CONTEXT__, SAPDBERR_ASSERT_STATE_FAILED, "OpenTransFile.Create()") );
                  
    if ( ! File.IsCreated() )
        RTE_Crash( SAPDBErr_Exception(__CONTEXT__,SAPDBERR_ASSERT_STATE_FAILED,"OpenTransFile.IsCreated()") );
    
    saveptParam.svpOpenTransCnt_kb00 = 0;
    
    for ( kb51GetFirstWriteTrans (WriteTransIndex);
          WriteTransIndex != cgg_nil_transindex;
          kb51GetNextWriteTrans  (WriteTransIndex) )
    {
        SAPDBTRACE_WRITELN (LogTrans_Trace, 6, "SVP: OpenTransNo: "<<saveptParam.svpOpenTransCnt_kb00<<\
                                          ", WriteTransIndex: "<<WriteTransIndex);
        
        pLogTrans = REINTERPRET_CAST(Log_Transaction*,k50GetLogTransaction (WriteTransIndex));
        
        if ( NULL == pLogTrans )
            RTE_Crash( SAPDBErr_Exception(__CONTEXT__,SAPDBERR_ASSERT_STATE_FAILED,
                       "Log_Savepoint::CreateOpenTransFile: pLogTrans=NULL") );
        
        if ( saveptParam.svpReason_kb00 == Log_SVPReasonRestart )
        {
            // PTS 1124684 UH 2003-10-16 inserted check
            pLogTrans->WriteToTrace("open trans not allowed");
            RTE_Crash( SAPDBErr_Exception(__CONTEXT__, SAPDBERR_ASSERT_STATE_FAILED,
                       "Log_Savepoint::CreateOpenTransFile: open redo trans found") );
        }

        if ( pLogTrans->IsSavepointRelevant() )
        {
            ++saveptParam.svpOpenTransCnt_kb00;
            File.WriteOpenTrans (*pLogTrans);
            if ( oldestOpenTransIOSequence.IsInvalid()  // PTS 1124684 UH 2003-10-16
                 ||
                 Log_IOSequenceNo::LeftIsOlder(pLogTrans->GetOldestKnownIOSequence(), // PTS 1127009 UH 2004-01-09
                                               oldestOpenTransIOSequence,
                                               oldestKnownIOSequence) )
            {
                oldestOpenTransIOSequence = pLogTrans->GetOldestKnownIOSequence(); // PTS 1127009 UH 2004-01-09
            }
        }
    }
    
    SAPDBTRACE_WRITELN (LogTrans_Trace, 6, "SVP: new oldestEOTsequence: " << oldestOpenTransIOSequence);
    File.SetOldestKnownIOSequence(oldestOpenTransIOSequence);  // PTS 1124684 UH 2003-10-16

    if ( saveptParam.svpOpenTransRoot_kb00 != NIL_PAGE_NO_GG00 )
    {
        OldOpenTransFile.Drop();
        SAPDBTRACE_WRITELN (LogTrans_Trace, 6, "SVP: old OpenTransRoot: " << saveptParam.svpOpenTransRoot_kb00);
    }
    saveptParam.svpOpenTransRoot_kb00 = File.GetRootId().PageNo();
    SAPDBTRACE_WRITELN (LogTrans_Trace, 6, "SVP: new OpenTransRoot: " << saveptParam.svpOpenTransRoot_kb00);

    Kernel_DateTime dateTime;

    dateTime.DetermineTime();
    saveptParam.svpDate_kb00 = dateTime.GetDate();
    saveptParam.svpTime_kb00 = dateTime.GetTime();
}

/*---------------------------------------------------------------------------*/

void Log_Savepoint::ShutdownFilesystem (tgg00_TransContext &coordinatorTrans)
{
    SAPDBTRACE_ROUTINE_DEBUG ("Log_Savepoint::ShutdownFilesystem", LogTrans_Trace, 5);

    if ( k38is_on_autosave (coordinatorTrans, false) )
        k38e_autosave_end (coordinatorTrans, false);

    Kernel_VTrace() << "\n"
                    << "\n"
                    << "############################################\n"
                    << "############### SHUTDOWN ###################\n";
    Kernel_VTrace() << "############################################\n"
                    << "\n"
                    << "\n";

    Kernel_IAdminRestartShutdown::Instance().Offline(coordinatorTrans.trError_gg00);

    RTE_Crash( SAPDBErr_Exception(__CONTEXT__,SAPDBERR_ASSERT_STATE_FAILED,
               "Log_Savepoint::Shutdown: kernel must not run at this moment.") );
}

/*---------------------------------------------------------------------------*/
bool Log_Savepoint::Verify (tgg00_TransContext &trans,
                            bool                isCold)
{
    Log_OpenTransFile file (trans, k57restartrec->rstLastSavept_kb00().svpOpenTransRoot_kb00);
    if ( file.IsCreated() )
        return file.Verify(isCold);
    else
        return true;
}

/*---------------------------------------------------------------------------*/
Log_EntrySequence Log_Savepoint::GetLastSavepointId ()
{
    return 0 == k57restartrec
           ? Log_EntrySequence()
           : Log_EntrySequence(k57restartrec->rstLastSavept_kb00().svpId_kb00);
}

/*---------------------------------------------------------------------------*/
Log_ActionType Log_Savepoint::GetLastSavepointEntryType()
{
    return 0 == k57restartrec
           ? Log_NoOp : Log_ActionType(k57restartrec->rstLastSavept_kb00().svpStartEntryType_kb00);
}

/*---------------------------------------------------------------------------*/
Log_IOSequenceNo Log_Savepoint::GetLastSavepointIOSequence()
{
    return 0 == k57restartrec
           ? Log_IOSequenceNo()
           : Log_IOSequenceNo(k57restartrec->rstLastSavept_kb00().svpIOsequence_kb00);
}

/*---------------------------------------------------------------------------*/
Log_RawDeviceOffset Log_Savepoint::GetLastSavepointOffset()
{
    return k57restartrec->rstLastSavept_kb00().svpStartOffset_kb00;
}

/*---------------------------------------------------------------------------*/
void Log_Savepoint::GetStartEntryTimestamp( Kernel_Date &date,
                                            Kernel_Time &time )
{
    date.Invalidate();
    time.Invalidate();
    
    if ( k57restartrec != 0 ) return;
    
    date = k57restartrec->rstLastSavept_kb00().svpStartEntryDate_kb00;
    time = k57restartrec->rstLastSavept_kb00().svpStartEntryTime_kb00;
}
/*---------------------------------------------------------------------------*/
void Log_Savepoint::InsertToWaitForPrepare (tsp00_TaskId       taskid,
                                            tgg00_WaitContext &waitcontext)
{
    BeginRegion(taskid);
    m_WaitingForPrepare.InsertAsLast(taskid, waitcontext);
    EndRegion(taskid);
}
