/*!
  @file    Log_Savepoint.hpp
  @ingroup Logging
  @author  UweH
  @brief   The savepoint manager.

\if EMIT_LICENCE
    ========== 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

\endif
*/
#ifndef LOG_SAVEPOINT_H
#define LOG_SAVEPOINT_H

#include "gsp00.h" // tsp00_TaskId
#include "ggg00.h" // tgg00_TransContext
#include "gkb00.h" // tkb00_SaveptParam
#include "SAPDBCommon/SAPDB_Types.hpp"
#include "KernelCommon/Kernel_DateTime.hpp"
#include "KernelCommon/Kernel_TaskWaitList.hpp"
#include "Logging/Log_Types.hpp"
#include "Converter/Converter_Version.hpp"
#include "IOManager/IOMan_BlockAddress.hpp"
#include "DataAccess/Data_Types.hpp"

class SAPDBMem_IRawAllocator;
/*!
   @class Log_Savepoint
   @brief This is the savepoint manager. It is a Singleton.
 */
class Log_Savepoint
{
public:
    /// default constructor resets all to nil
    Log_Savepoint()
    : m_IsActive         (false),
      m_CurrentWaitList  (0),
      m_WaitingDBmanager (cgg_nil_pid),
      m_DBmanagerReason  (Log_SVPReasonUnknown),
      m_LogWriteEnabled  (false),
      m_SavepointAllowed(true)
    {}
    /*!
        @brief This starts a savepoint if none is running.
        If a savepoint is already running, the caller waits for the next savepoint
        which is executed automatically.
     */
    void StartSavepointAndWait (tgg00_TransContext  &Trans,
                                Log_SavepointReason  Reason);
	/// If somebody is waiting for a savepoint, a savepoint is started, if no savepoint is active.
    void StartSavepoint (tgg00_TransContext  &trans,
                         Log_SavepointReason  reason);
    /*!
        @brief returns true, if the given reason can only be triggered at one time.
        This reasons normally cause special functions during the savepoint.
        Examples are DataBackup or Restart.
     */
    bool IsDBManagerReason (Log_SavepointReason reason);
	/// returns true, if a savepoint is running.
    bool IsActive () const
    {
        // without region
        return m_IsActive;
    }
	/// This is the main servertask method.
    void Coordinator (tgg00_TransContext &Trans);
	/// Verifies opentrans file in restartrecord
    static bool Verify (tgg00_TransContext &trans,
                        bool                isCold);
	/// returns the last used savepoint id
    static Log_EntrySequence GetLastSavepointId();
	/// in online mode this will usually be Log_Savepoint but not during redo.
    static Log_ActionType GetLastSavepointEntryType();
    /// returns the timestamp from the logentry procssed during last savepoint
    static void GetStartEntryTimestamp( Kernel_Date &date,
                                        Kernel_Time &time );
	/// returns the last start entry iosequence
    static Log_IOSequenceNo GetLastSavepointIOSequence();
	/// returns the last start offset
    static Log_RawDeviceOffset GetLastSavepointOffset();
    /// some statistic values are offered
    void GetSavepointStatistics (SAPDB_Int4 &lastDurationSec,
                                 SAPDB_Int4 &lastDurationMicroSec,
                                 SAPDB_Int4 &lastWrittenPages,
                                 SAPDB_Int4 &lastIOcount,
                                 SAPDB_Int4 &avgWrittenPages,
                                 SAPDB_Int4 &avgIOcount)
    {
        // PTS 1119276 UH 2002-12-10 added
        lastWrittenPages     = m_Statistics.last.pagesWritten;
        lastIOcount          = m_Statistics.last.iocount;
        lastDurationSec      = m_Statistics.last.durationSec;
        lastDurationMicroSec = m_Statistics.last.durationMicroSec;
        m_Statistics.GetAvarage(avgWrittenPages,avgIOcount);
    }
    /// This is used for tasks which want to access a page for
    /// structureChange and have to wait for the running savepoint.
    void InsertToWaitForPrepare (tsp00_TaskId       taskid,
                                 tgg00_WaitContext &waitcontext);
    /// This can be used to prevent starting of a new savepoint. If false is returned the call failed.
    bool DenySavepoint (tsp00_TaskId taskid);
    /// This can be used to allow starting savepoints.
    void PermitSavepoint (tsp00_TaskId taskid);
    /// returns true if savepoint is allowed and restartrecord may be written
    bool IsSavepointAllowed() const;
private:
	/// this starts a servertask as a coordinator.
    void StartCoordinator (tgg00_TransContext  &Trans);
    /// used for synchronization to access the restartrecord
    void BeginRegion (tsp00_TaskId taskid);
    /// used for synchronization to access the restartrecord
    void EndRegion (tsp00_TaskId taskid);
    /// During a savepoint the next tasks which want a savepoint are waiting for the next.
    void SwitchWaitList()
    {
        m_CurrentWaitList = (m_CurrentWaitList == 0) ? 1 : 0;
    }
	/// returns current waitlist to use.
    Kernel_TaskWaitList& CurrentWaitList()
    {
        return m_Waitlist [m_CurrentWaitList];
    }
	/// returns current waitlist to use.
    Kernel_TaskWaitList& WaitListForCurrentSavepoint()
    {
        return m_Waitlist [m_CurrentWaitList==0?1:0];
    }
	/// This writes the savepoint entry into all queues if no redo.
    void DetermineRedoStartPositions
            (tgg00_TransContext     &CoordinatorTrans,
             SAPDBMem_IRawAllocator &Allocator,
             tkb00_SaveptParam      &saveptParam);
	/// This creates a chain file, which contains entries for all open transactions.
    void CreateOpenTransFile (tgg00_TransContext &CoordinatorTrans,
                              tkb00_SaveptParam  &saveptParam,
                              bool                bIsRedoSavepoint);
	/// the loginfo pages are updated and restartrecord and loginfo is flushed.
    void FlushRestartRecordAndLogInfoPages  (tgg00_TransContext         &coordinatorTrans,
                                             Log_SavepointReason        reason,
                                             tkb00_SaveptParam          &saveptParam,
                                             Converter_Version          &converterVersion,
                                             IOMan_PackedBlockAddress   &converterRootBlockAddress,
                                             Data_PageNo                &maxDynamicPageNo,
                                             Data_PageNo                &maxStaticPageNo);
	/// FBM blocks being in state free after savepoint.
    void FlushCompleted (tsp00_TaskId            TaskId,
                         const Converter_Version &converterVersion);
	/// This stops all file accesses.
    void ShutdownFilesystem (tgg00_TransContext &coordinatorTrans);
public:
    /// collected statistic data
    struct Statistic // PTS 1119276 UH 2002-12-10 added
    {
        SAPDB_UInt durationSec;
        SAPDB_UInt durationMicroSec;
        SAPDB_UInt pagesWritten;
        SAPDB_UInt iocount;
        Statistic()
        {
            durationSec      = 0;
            durationMicroSec = 0;
            pagesWritten     = 0;
            iocount          = 0;
        }
        Statistic(SAPDB_UInt newDurationSec,
                  SAPDB_UInt newDurationMicroSec,
                  SAPDB_UInt newPagesWritten,
                  SAPDB_UInt newIocount)
        {
            durationSec      = newDurationSec;
            durationMicroSec = newDurationMicroSec;
            pagesWritten     = newPagesWritten;
            iocount          = newIocount;
        }
        Statistic& operator += ( const Statistic &other )
        {
            this->durationSec      += other.durationSec;
            this->durationMicroSec += other.durationMicroSec;
            this->pagesWritten     += other.pagesWritten;
            this->iocount          += other.iocount;
            return *this;
        }
    };
    /// sumarization of statistic data
    struct Statistics // PTS 1119276 UH 2002-12-10 added
    {
        SAPDB_UInt count;
        Statistic  last;
        Statistic  total;
        //-------------------------------------
        //-------------------------------------
        Statistics() { count = 0; }
        void Add(Statistic newValue)
        {
            ++count;
            last  =  newValue;
            total += last;
        }
        void GetAvarage(SAPDB_Int4 &pagesWritten,
                        SAPDB_Int4 &iocount)
        {
            pagesWritten = total.pagesWritten / count;
            iocount      = total.iocount      / count;
        }
    };
private:
	/// It is true, if a savepoint is running or will be running.
    bool                m_IsActive;
	/// Valid values are 0 and 1.
    SAPDB_UInt          m_CurrentWaitList;
    /// This is for tasks waiting for a normal savepoint be finished.
    /// There are two lists. One can be filled with requests and the other one
    /// can be used, if a savepoint is already running to wait for the next savepoint.
    Kernel_TaskWaitList    m_Waitlist [2];
	/// Usually this is the utility task waiting for a backup or shutdown.
    tsp00_TaskId        m_WaitingDBmanager;
	/// This is the reason for the db manager to trigger a savepoint.
    Log_SavepointReason m_DBmanagerReason;
    /*!
        @brief If this is false the next savepoint will be a ReDo-Savepoint
        Which means, that no log is written, but only the restartRecord is changed                   
        This member is initialized with false and can only be set
        to true (only one restart is possible during kernel-lifetime)
     */
    bool         m_LogWriteEnabled; // PTS 1115875 mb 2002-05-28
    /// collection point for statistics
    Statistics   m_Statistics; // PTS 1119276 UH 2002-12-10 added
    /// tasks waiting for end of prepare phase
    Kernel_TaskWaitList    m_WaitingForPrepare;
    /// This flag indicates that no savepoint can be written.
    bool m_SavepointAllowed; // PTS 1121281 UH 2003-03-24
};
/// declaration of singleton access point
extern Log_Savepoint Log_SavepointManager;
#endif  /* LOG_SAVEPOINT_H */