/*! @defgroup     History History Manager */
/*!
  @file           Log_History.hpp
  @ingroup        History
  @author         UweH
  @brief          The HistoryManager is a singleton.

\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_HISTORY_H
#define Log_HISTORY_H

#include "gsp00.h" // tsp00_TaskId
#include "ggg00.h"
#include "SAPDBCommon/SAPDB_Types.hpp"
#include "Container/Container_Vector.hpp"
#include "DataAccess/Data_Types.hpp"
#include "Logging/Log_HistoryFile.hpp"
#include "Logging/Log_HistoryDirectory.hpp"
#include "GarbageCollector/GC_IGarbageCollector.hpp" // PTS xxxxxxx FF 2002-02-12

class Log_UndoFile;
class tgg92_KernelOid;
class SAPDBMem_IRawAllocator;

/*!
	@class  Log_History
    @brief  This is the history manager.
*/

class Log_History
{

public:
    /// This defines the information of one history file within the history directory
    typedef Log_HistoryDirectory::HistoryFileInfo HistoryFileInfo;

    /// Gives the granularity of history to be deleted.
    enum  RemoveOptions
    {
        Normal,        ///< "phase green"  Only easy to remove history is removed.
        Sensitive,     ///< "phase yellow" All history which can be is removed, this is more expensive.
        Truncate,      ///< "phase red"    The oldest history is removed, even if it is needed by views.
        RemoveUnused   ///< for internal use only
    };

public:

	/// This method creates the singleton. Ona any error false is returned.
    static bool CreateInstance (tgg00_TransContext &trans);

    /// This deallocates all allocated resources.
    static void DropInstance();

    /// this calls Delete()
    ~Log_History()
    {
        DropInstance();
    }

    /*!
        @returns new history directory root
        @brief          All data is flushed to disk. This is used by the savepoint.
    */
    Data_PageNo Flush (tgg00_TransContext &trans);

    /// returns true, if all files.Verify() return true.
    bool Verify (tgg00_TransContext &trans,
                 bool                isCold);

	/// A transaction calls this, if it produced before images needed by other transactions
    /// to view data consistent.
    void RegisterUndoFile ( tgg00_TransContext &trans,
                            Log_UndoFile       &file );

	/// this offers a before image mathing the given consistent view.
    static void GetBeforeImage (tgg00_TransContext       &Trans,
                                const tgg92_KernelOid    &Oid,
                                const tgg91_PageRef      &WantedPageRef,
                                SAPDB_UInt4               BodySize,
                                SAPDB_Byte               *pObjBody,
                                bool                      bOnlyCheckExistence, // PTS 1113317 UH 2002-01-08
                                SAPDB_UInt4              &BodyLen,
                                tgg00_ObjFrameVers       &FrameVers,
                                Log_ActionType           &ActionType,
                                tgg91_TransNo            &ConsistentView,
                                tgg91_TransNo            &PrevUpdTrans,
                                tgg91_PageRef            &NextPageRef);

	/// returns true, if the given Id references a valid before image.
    static bool BeforeImageExists (tgg00_TransContext    &Trans,
                                   const tgg92_KernelOid &testoid,
                                   const tgg91_PageRef   &wanted)
    {
        SAPDB_UInt4        BodyLen;
        tgg00_ObjFrameVers FrameVers;
        Log_ActionType     ActionType = Log_NoOp;
        tgg91_TransNo      ConsistentView;
        tgg91_TransNo      PrevUpdTrans;
        tgg91_PageRef      NextPageRef;

        GetBeforeImage ( Trans, testoid, wanted, 0, NULL, true, // PTS 1113317 UH 2002-01-08
                         BodyLen, FrameVers, ActionType,
                         ConsistentView, PrevUpdTrans, NextPageRef );

        if ( e_ok != Trans.trError_gg00 ) 
        {
            if ( e_illegal_page_no != Trans.trError_gg00 )
                Trans.trError_gg00 = e_ok;
            return false;
        }
        
        return true;
    }

	/// returns true, if is used.
    static bool IsHistoryUsed (tsp00_TaskId        taskid,
                               tgg92_KernelOid    &oid,
                               tgg00_ObjTransInfo &info);

    /// A before image is marked as deleted
    static void DeleteBeforeImage (tgg00_TransContext    &trans,
                                   const tgg92_KernelOid &oid,
                                   const tgg91_PageRef   &pageref);

	/// The history manager singleton is returned.
	/// It is assumed, that the component is initialized.
    //  +++ THIS IS PUBLIC UNTIL THERE ARE EXISTING DIFFERENT INTERFACES +++
    static Log_History& GetInstance()
    {
        SAPDBERR_ASSERT_STATE (m_Instance != NULL);
        return( *m_Instance );
    }

    /// returns true, if GetInstance() can be used.
    static bool IsInitialized()
    {
        return m_Instance != NULL;
    }

    /// accessor
    SAPDB_UInt GetNumberOfHistoryFiles () const
    {
        return m_Directory.GetFileCount();
    }
                   
    /// accessor
    SAPDB_UInt GetNumberOfMaxUsedHistoryFiles () const
    {
        return m_Directory.GetMaxUsedFileCount();
    }
                   
    /// returns the oldest transo of the given history file
    const tgg91_TransNo & GetOldestTransNo (SAPDB_UInt fileno) const
    {
        return m_Directory.GetOldestTransNo (fileno);
    }
                   
    /// returns the oldest transo of the given history file
	/// The range is between 0 and (GetNumberOfHistoryFiles() - 1)
    void GetInfo ( tsp00_TaskId     taskid,
                   SAPDB_UInt       fileno,
                   HistoryFileInfo &info,
                   SAPDB_UInt      &pagecount ) const
    {
        m_Directory.GetHistoryFileInfo( taskid, fileno, info, pagecount );
    }
                   
	/// This call removes history depending on the given options.
    void RemoveHistory (tgg00_TransContext        &trans,
                        SAPDB_UInt                 fileno,
                        RemoveOptions              option,
                        GC_IGarbageCollector      &IGarbColl,                    //PTS xxxxxxx FF 2002-02-12 
                        bool                      &anythingRemoved);

    /*!
        @brief This method removes the complete history including the history directory.
       
        The anchor in the restartrecord is deleted, even the memory is deallocated.
        After this method returns the history management must be created new.
        This can be used for migration prupose.
     */
    void RemoveCompleteHistory (tgg00_TransContext &trans);

    /*!
        @brief This method removes history files which are not used if there are any existing.
        History files can be unused if MAXUSERTASKS has been decreased.
     */

    void CheckAndRemoveUnusedHistory ( tgg00_TransContext   &trans,
                                       GC_IGarbageCollector &IGarbColl );

	/// this is used by garbage collector dump bd930DumpHistoryFileDir()
    const void* GetDumpInfo (SAPDB_UInt fileno)
    {
        return m_Directory.GetDumpInfo(fileno);
    }

	/// returns true, if any history directory entry has a valid transno. Dirty Read / Outside region !
    bool AnyHistoryExists (); // PTS 1114877 UH 2002-03-18 new

    /// This is used for migration to get rid of really all history informations
    /// On any error false is returned.
    bool CheckAndStartMigrationIfNeeded (tgg00_TransContext &trans);
    
#ifdef CONSTRUCTOR_MAY_NOT_BE_PRIVATE_AND_NO_FRIEND_DEFINED
protected:
#else
private:
#endif
    /// forbidden to use, because this is a singleton
    Log_History (const Log_History& other);
    /// forbidden to use, because this is a singleton
    Log_History& operator= (const Log_History &Manager);
                     
#ifdef CONSTRUCTOR_MAY_NOT_BE_PRIVATE_AND_NO_FRIEND_DEFINED
private:
#endif

	/// the constructor for the singleton
    Log_History (SAPDBMem_IRawAllocator &allocator,
                 SAPDB_UInt              numUKTs,
                 SAPDB_UInt              maxFiles)
    : m_Directory (allocator, numUKTs, maxFiles)
    {}

	/// This creates Historyfiles and initializes the directory.
    void CreateHistoryDirectory (tgg00_TransContext &trans);

	/// This creates Historyfiles.
	void CreateHistoryFiles (tgg00_TransContext   &trans,
							 Log_HistoryDirectory &dirfile,
							 SAPDB_UInt            firstFileNo,
							 SAPDB_UInt            lastFileNo);
    
	/// This restores the directory.
    void RestoreHistoryDirectory (tgg00_TransContext &trans);

	/// returns true, if fileinfo has changed
    bool UpdateHistoryFileInfo ( tgg00_TransContext &trans,
                                 SAPDB_UInt          historyFileNo,
                                 HistoryFileInfo    &fileinfo,
                                 SAPDB_UInt         &pagecount );
                                 
    /*!
        @return true, if UndoFile was really removed.
    	@brief  this removes an undo file an all objects which are deleted in it.
        isInterrupted can becomes true, if the garbage collection should be aborted.
    */
    // PTS 1113934 UH 2002-02-01
    bool RemoveUndoFileWithObjects (tgg00_TransContext        &trans,                      // PTS 1113934 UH 2002-02-01
                                    Data_PageNo                root,
                                    Data_PageNo                last,
                                    GC_IGarbageCollector      &IGarbColl,                  // PTS xxxxxxx FF 2002-02-12 
                                    Log_HistoryFile           &historyfile,                // PTS 1113934 UH 2002-02-01
                                    Log_HistoryFile::Iterator &undoFileInfoIter);          // PTS 1113934 UH 2002-02-01

    /// removal of the oldest transo
    void TruncateHistory (tgg00_TransContext        &trans,
                          SAPDB_UInt                 fileno,
                          Data_PageNo                root,
                          Data_PageNo                last,
                          GC_IGarbageCollector      &IGarbColl,                            // PTS xxxxxxx FF 2002-02-12 
                          bool                      &anythingRemoved);
                          
    /// the oldest transno is determines
    tgg91_TransNo DetermineOldestTransNo (Log_HistoryFile &file);

public:

	/// This defines the directory in main memory.
    class HistoryDirectory
    {
    public:
        HistoryDirectory ( SAPDBMem_IRawAllocator& allocator,
                           SAPDB_UInt              numUKTs,
                           SAPDB_UInt              maxFiles )
        : m_Directory (allocator),
          m_numUKTs   (numUKTs),
          m_maxFiles  (maxFiles)
        {}
        
        bool Initialize()
        {
            return m_Directory.Initialize (GetMaxUsedFileCount());
        }
        
        void Delete()
        {
            m_Directory.Delete();
        }
        
        ~HistoryDirectory()
        {
            Delete();
        }
        
        SAPDB_UInt GetFileCount() const
        {
            return m_Directory.GetSize();
        }

        SAPDB_UInt GetMaxUsedFileCount() const
        {
            return m_maxFiles;
        }

        SAPDB_Int GetFileNo(tsp00_TaskId taskid) const
        {
            return taskid % GetMaxUsedFileCount();
        }

        const tgg91_TransNo & GetOldestTransNo (SAPDB_UInt fileno) const
        {
            return m_Directory[fileno].persistent.oldestTransNo;
        }

        void SetHistoryFileInfo ( tsp00_TaskId           taskid,
                                  SAPDB_UInt             fileno,
                                  const HistoryFileInfo& info,
                                  SAPDB_UInt             pagecount );

        void GetHistoryFileInfo ( tsp00_TaskId     taskid,
                                  SAPDB_UInt       fileno,
                                  HistoryFileInfo &info,
                                  SAPDB_UInt      &pagecount ) const;

        void UpdateInfoAfterRegisterNewUndoFile ( tsp00_TaskId         taskid,
                                                  SAPDB_UInt           fileno,
                                                  const tgg91_TransNo &newtransno,
                                                  SAPDB_UInt           pagecount,
                                                  Data_PageNo          last );

        void UpdateOldestTransNo ( tsp00_TaskId         taskid,
                                   SAPDB_UInt           fileno,
                                   const tgg91_TransNo &newOldestTransno,
                                   Data_PageNo          last,
                                   SAPDB_UInt           removedPages );
    
        const void* GetDumpInfo (SAPDB_UInt fileno)
        {
            return &(m_Directory[fileno]);
        }
        

        /*!
            The next fileno of an unused history file is given.
            The history directory entry is marked as used so no other
            requestor will ever get this entry again.
            Usually fileno is set to 0 at the beginning.
            If false is returned there exists no file which is unused.
        */
        bool GetNextUnusedFileNo ( tsp00_TaskId  taskid,
                                   SAPDB_UInt   &fileno );
    
        void RemoveUnusedEntries ();

        void ResetInProcess (tsp00_TaskId taskid,
                             SAPDB_UInt   fileno);

        void Invalidate (tsp00_TaskId taskid,
                         SAPDB_UInt   fileno);

        void WriteToTrace (tsp00_TaskId      taskid,
                           const SAPDB_Char *title = NULL) const;

    public:

        struct ExtendedHistoryFileInfo
        {
            HistoryFileInfo persistent;
            SAPDB_UInt4     pagecount;
            SAPDB_Bool1     inProcess;
            SAPDB_Bool1     filler1;
            SAPDB_UInt2     filler2;
            ExtendedHistoryFileInfo()
            :pagecount(0),
             inProcess(false),
             filler1(0),
             filler2(0)
            {}
        };

    private:
    
        typedef Container_Vector<ExtendedHistoryFileInfo> Directory;
        Directory        m_Directory;
        const SAPDB_UInt m_numUKTs;
        const SAPDB_UInt m_maxFiles;
    };
    
    typedef HistoryDirectory::ExtendedHistoryFileInfo ExtendedHistoryFileInfo;

    HistoryDirectory m_Directory;
    Data_PageNo      m_DirectoryRoot;
    
private:

    static Log_History* m_Instance;
};
#endif  /* Log_HISTORY_H */
