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

  module      : Log_History.cpp
  special area: Logging
  responsible : UweH
  created     : 2000-11-07
  copyright   : (c) 2000-2004 SAP AG
  description : Implementation for class Log_History.



    ========== 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 "heo55k.h"  // vbegexcl/vendexcl/visexcl
#include "heo56.h"   // vsleep
#include "heo58.h"   // vgetrteinfo
#include "hgg01.h"   // g01maxuser
#include "ggg92.h"   // tgg92_KernelOid for hkb50.h
#include "hkb51.h"   // kb51IsConsistUsedTransId
#include "hkb57_1.h" // k57restartrec
#include "hgg08.h"   // g08history0
#include "hbd91.h"   // bd91ReleaseUnusedObject
#include "SAPDBCommon/Tracing/SAPDBTrace_Usage.hpp"
#include "SAPDBCommon/ErrorsAndMessages/SAPDBErr_Assertions.hpp"
#include "SAPDBCommon/MemoryManagement/SAPDBMem_IRawAllocator.hpp"
#include "RunTime/RTE_Message.hpp"
#include "RunTime/MemoryManagement/RTEMem_Allocator.hpp"
#include "Logging/Log_Types.hpp"
#include "Logging/Log_Exceptions.hpp"
#include "Logging/Log_ActionObject.hpp"
#include "Logging/Log_ActionObjectFile.hpp"
#include "Logging/Log_UndoFile.hpp"
#include "Logging/Log_History.hpp"
#include "GarbageCollector/GC_IGCController.hpp" 
#include "KernelCommon/Kernel_IAdminConfig.hpp"
#include "KernelCommon/Kernel_Migration.hpp"
/*===========================================================================*
 *  DEFINES                                                                  *
 *===========================================================================*/
/*===========================================================================*
 *  LOCALS                                                                   *
 *===========================================================================*/

class DummyGC : public GC_IGarbageCollector // PTS 1114877 UH 2002-03-18 new
{
public:
    virtual SAPDB_UInt1 GetHistOption() const {return 0;}
    virtual void IncHistCreateObjFileCount() {}
    virtual void IncHistDeleteObjCount() {}
    virtual void IncHistDropObjFileCount() {}
    virtual void IncHistEntryReleaseCount() {}
    virtual void IncHistLockObjCount() {}
    virtual void IncHistInsertObjCount() {}
    virtual void IncHistNewObjCount() {}
    virtual void IncHistUpdateObjCount() {}
    virtual void IncObjReleaseCount() {}
    virtual void IncReleaseEmptyPageCount() {} /* PTS 1115760 FF */
    virtual bool IsInterrrupted () const
    {
        return false;
    }
    virtual void SetHistOption(SAPDB_UInt1 option) {}
};

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

Log_History* Log_History::m_Instance = NULL;

/*===========================================================================*
 *  CLASSES, STRUCTURES, TYPES, UNIONS ...                                   *
 *===========================================================================*/
/*===========================================================================*
 *  DEFINITION OF METHODS                                                    *
 *===========================================================================*/
                                         
/* -------------------------------------------------------------------------------- */
void Log_History::HistoryDirectory::ResetInProcess (tsp00_TaskId taskid,
                                                    SAPDB_UInt   fileno)
{
    vbegexcl (taskid, g08history0+(fileno%m_numUKTs));
    m_Directory[fileno].inProcess = false;
    vendexcl (taskid, g08history0+(fileno%m_numUKTs));
}
/* -------------------------------------------------------------------------------- */
void Log_History::HistoryDirectory::Invalidate (tsp00_TaskId taskid,
                                                SAPDB_UInt   fileno)
{
    vbegexcl (taskid, g08history0+(fileno%m_numUKTs));
    m_Directory[fileno].persistent.Invalidate();
    m_Directory[fileno].pagecount = 0;
    m_Directory[fileno].inProcess = false;
    vendexcl (taskid, g08history0+(fileno%m_numUKTs));
}

/* -------------------------------------------------------------------------------- */
void Log_History::HistoryDirectory::RemoveUnusedEntries ()
{
    if ( ! m_Directory.Resize(GetMaxUsedFileCount()) )
        RTE_Crash( SAPDBErr_Exception(__CONTEXT__,SAPDBERR_ASSERT_STATE_FAILED,
                   "m_Directory.Resize() failed") );
}

/* -------------------------------------------------------------------------------- */
bool Log_History::HistoryDirectory::GetNextUnusedFileNo ( tsp00_TaskId  taskid,
                                                          SAPDB_UInt   &fileno )
{
    if ( fileno < GetMaxUsedFileCount()
         ||
         fileno >= GetFileCount() )
        fileno = GetMaxUsedFileCount();
    
    while ( fileno < GetFileCount() )
    {
        vbegexcl (taskid, g08history0+(fileno%m_numUKTs));
        if ( m_Directory[fileno].persistent.IsValid()
             &&
             ! m_Directory[fileno].inProcess )
        {
            m_Directory[fileno].inProcess = true;
            vendexcl (taskid, g08history0+(fileno%m_numUKTs));
            return true;
        }
        vendexcl (taskid, g08history0+(fileno%m_numUKTs));
        ++fileno;
    }
    return false;
}

/* -------------------------------------------------------------------------------- */
void Log_History::HistoryDirectory::SetHistoryFileInfo
    ( tsp00_TaskId           taskid,
      SAPDB_UInt             fileno,
      const HistoryFileInfo& info,
      SAPDB_UInt             pagecount )
{
    vbegexcl (taskid, g08history0+(fileno%m_numUKTs));
    if ( fileno >= m_Directory.GetCapacity() )
    {
        if ( ! m_Directory.Resize(m_Directory.GetCapacity()+10) )
            // PTS 1117126 UH 2002-08-07 if-clause added
            RTE_Crash( SAPDBErr_Exception(__CONTEXT__,SAPDBERR_ASSERT_STATE_FAILED,
                       "m_Directory.Resize() failed") );
    }
    m_Directory[fileno].persistent = info;
    m_Directory[fileno].pagecount = pagecount;
    vendexcl (taskid, g08history0+(fileno%m_numUKTs));
}

/* -------------------------------------------------------------------------------- */
void Log_History::HistoryDirectory::GetHistoryFileInfo
    ( tsp00_TaskId     taskid,
      SAPDB_UInt       fileno,
      HistoryFileInfo &info,
      SAPDB_UInt      &pagecount ) const
{
    vbegexcl (taskid, g08history0+(fileno%m_numUKTs));
    info = m_Directory[fileno].persistent;
    pagecount = m_Directory[fileno].pagecount;
    vendexcl (taskid, g08history0+(fileno%m_numUKTs));
}

/* -------------------------------------------------------------------------------- */
void Log_History::HistoryDirectory::WriteToTrace (tsp00_TaskId      taskid,
                                                  const SAPDB_Char *title) const
{
    Kernel_VTrace trace;
	SAPDB_UInt    ukt;
    
    if ( title != NULL )
        trace << title << NewLine;
    trace << "HistoryDirectory: " << GetFileCount()
          << " entries ("         << GetMaxUsedFileCount()
          << ")"                  << NewLine;

    for ( ukt = 0; ukt < m_numUKTs; ++ukt )
        vbegexcl (taskid, g08history0+ukt);
        
    for ( SAPDB_UInt fileno = 0; fileno < GetFileCount(); ++fileno )
    {
        const HistoryFileInfo &info = m_Directory[fileno].persistent;

        trace << "HistFile "    << fileno
              << ": T"          << info.oldestTransNo.gg90GetInt4()
              << " - T"         << info.youngestTransNo.gg90GetInt4()
              << " page# "      << m_Directory[fileno].pagecount
              << " root: "      << info.root
              << " last: "      << info.last
              << " inProcess: " << m_Directory[fileno].inProcess
              << NewLine;
    }
    
    for ( ukt = 0; ukt < m_numUKTs; ++ukt )
        vendexcl (taskid, g08history0+ukt);
}

/* -------------------------------------------------------------------------------- */
void Log_History::HistoryDirectory::UpdateInfoAfterRegisterNewUndoFile
    ( tsp00_TaskId        taskid,
     SAPDB_UInt           fileno,
     const tgg91_TransNo &newtransno,
     SAPDB_UInt           pagecount,
     Data_PageNo          last )
{
    vbegexcl (taskid, g08history0+(fileno%m_numUKTs));
    SAPDBERR_ASSERT_ARGUMENT (! newtransno.gg90IsNil());
    // PTS 1114970 UH 2002-03-21 begin
    if ( m_Directory[fileno].persistent.youngestTransNo.gg90IsNil()
         ||
         newtransno > m_Directory[fileno].persistent.youngestTransNo )
        m_Directory[fileno].persistent.youngestTransNo = newtransno;
    if ( m_Directory[fileno].persistent.oldestTransNo.gg90IsNil() )
    {
        m_Directory[fileno].persistent.oldestTransNo = newtransno;
        m_Directory[fileno].pagecount                = pagecount;
    }
    else
    {
        if ( m_Directory[fileno].persistent.oldestTransNo > newtransno )
            m_Directory[fileno].persistent.oldestTransNo = newtransno;
        m_Directory[fileno].pagecount += pagecount;
    }
    m_Directory[fileno].persistent.last = last;
    // PTS 1114970 UH 2002-03-21 end
    vendexcl (taskid, g08history0+(fileno%m_numUKTs));
}

/* -------------------------------------------------------------------------------- */
void Log_History::HistoryDirectory::UpdateOldestTransNo
    ( tsp00_TaskId         taskid,
      SAPDB_UInt           fileno,
      const tgg91_TransNo &newOldestTransno,
      Data_PageNo          last,
      SAPDB_UInt           removedPages )
{
    vbegexcl (taskid, g08history0+(fileno%m_numUKTs));

    if ( newOldestTransno.gg90IsNil() )
    {
        m_Directory[fileno].persistent.youngestTransNo.gg90SetNil();
        m_Directory[fileno].persistent.oldestTransNo.gg90SetNil();
        m_Directory[fileno].pagecount = 0;
        vendexcl (taskid, g08history0+(fileno%m_numUKTs));
        return;
    }

    if ( m_Directory[fileno].persistent.oldestTransNo.gg90IsNil()
         ||
         m_Directory[fileno].persistent.oldestTransNo > newOldestTransno )
        m_Directory[fileno].persistent.oldestTransNo = newOldestTransno;
    m_Directory[fileno].persistent.last = last;
    // PTS 1114970 UH 2002-03-21 begin
    if ( m_Directory[fileno].pagecount < removedPages )
        m_Directory[fileno].pagecount = 0;
    else
        m_Directory[fileno].pagecount            -= removedPages;
    // PTS 1114970 UH 2002-03-21 end

    vendexcl (taskid, g08history0+(fileno%m_numUKTs));
}
/* -------------------------------------------------------------------------------- */
void Log_History::DropInstance ()
{
    // PTS 1122361 UH 2003-05-27 new
    SAPDBTRACE_ROUTINE_DEBUG( "Log_History::DropInstance", LogHistory_Trace, 5 );
    if ( m_Instance != 0 )
    {
        GC_IGCController::Instance().ClearAll();  
        m_Instance->m_Directory.Delete();
        m_Instance = 0;
    }
}
/* -------------------------------------------------------------------------------- */
bool Log_History::CreateInstance (tgg00_TransContext &trans)
{
    SAPDBTRACE_ROUTINE_DEBUG( "Log_History::CreateInstance", LogHistory_Trace, 5 );

    if ( m_Instance != 0 )
        return false;
    
    SAPDBMem_IRawAllocator& allocator = RTEMem_Allocator::Instance();

    tsp0058_RTEInfo RTEInfo;
    vgetrteinfo (RTEInfo);

    m_Instance = new(allocator) Log_History ( allocator,
                                              RTEInfo.NumOfUserUKTs,
                                              SAPDB_UInt(g01maxuser()) );
    
    if ( NULL == m_Instance )
        return false;

    if ( ! m_Instance->m_Directory.Initialize() ) 
    {
        destroy (m_Instance, allocator);
        m_Instance = NULL;
        return false;
    }

    m_Instance->m_DirectoryRoot = k57restartrec->rstLastSavept_kb00().svpHistoryRoot_kb00;

    if ( m_Instance->m_DirectoryRoot.IsInvalid() )
    {
        m_Instance->CreateHistoryDirectory(trans);
        k57restartrec->rstLastSavept_kb00().svpHistoryRoot_kb00 = m_Instance->m_DirectoryRoot;
    }
    else
        m_Instance->RestoreHistoryDirectory(trans);
    
    return true;
}

/* -------------------------------------------------------------------------------- */
void Log_History::CreateHistoryDirectory (tgg00_TransContext &trans)
{
    SAPDBTRACE_METHOD_DEBUG( "Log_History::CreateHistoryDirectory", LogHistory_Trace, 5 );

    Log_HistoryDirectory dirfile (trans, Data_PageNo());

    if ( ! dirfile.Create() )
    {
        RTE_Crash( SAPDBErr_Exception(__CONTEXT__,
                   SAPDBERR_ASSERT_STATE_FAILED,
                   "Log_History::CreateHistoryDirectory() dirfile.Create() failed") );
    }
    m_DirectoryRoot = dirfile.GetRootId().PageNo();

    CreateHistoryFiles (trans, dirfile, 0, m_Directory.GetFileCount()-1);

    // PTS 1115706 UH 2002-05-13 begin
    RTE_Message( Log_Exception(__CONTEXT__, LOG_EXISTING_HISTORY_FILES,
                               SAPDB_ToString(GetNumberOfMaxUsedHistoryFiles()),
                               SAPDB_ToString(GetNumberOfHistoryFiles())) );
        
    // Only after registration the garbage collector tasks can work on the history files.
    for ( SAPDB_UInt fileno = 0; fileno < GetNumberOfMaxUsedHistoryFiles(); ++fileno )
        GC_IGCController::Instance().RegisterHistoryFile(trans, fileno);  

    RTE_Message( Log_Exception(__CONTEXT__, LOG_HISTORY_FILE_REGISTERED) );
    // PTS 1115706 UH 2002-05-13 end
}
    
/* -------------------------------------------------------------------------------- */

void Log_History::CreateHistoryFiles (tgg00_TransContext   &trans,
									  Log_HistoryDirectory &dirfile,
									  SAPDB_UInt            firstFileNo,
									  SAPDB_UInt            lastFileNo)
{
    SAPDBTRACE_METHOD_DEBUG( "Log_History::CreateHistoryFiles", LogHistory_Trace, 5 );

    HistoryFileInfo newfileinfo;
    
    for ( SAPDB_UInt historyFileNo = firstFileNo; historyFileNo <= lastFileNo; historyFileNo++)
    {
        Log_HistoryFile file (trans, Data_PageNo(), Data_PageNo() /*, historyFileNo*/ );

        if ( ! file.Create() )
        {
            RTE_Crash( SAPDBErr_Exception(__CONTEXT__,
                       SAPDBERR_ASSERT_STATE_FAILED,
                       "Log_History::CreateHistoryFiles() file.Create() failed") );
        }
        
        newfileinfo.root = file.GetRootId().PageNo();
        newfileinfo.last = newfileinfo.root;
        
        dirfile.AppendHistoryFile(newfileinfo);

        // no bd91RegisterHistoryFile() here

        m_Directory.SetHistoryFileInfo(trans.trTaskId_gg00, historyFileNo, newfileinfo, 0);
    }
}

/* -------------------------------------------------------------------------------- */
void Log_History::RestoreHistoryDirectory (tgg00_TransContext &trans)
{
    SAPDBTRACE_METHOD_DEBUG( "Log_History::RestoreHistoryDirectory", LogHistory_Trace, 5 );

    Log_HistoryDirectory dirfile (trans, m_DirectoryRoot); 
    
    SAPDBERR_ASSERT_STATE ( dirfile.IsCreated() );

    dirfile.MigratePageType(trans); // PTS 1115490 UH 2002-04-29 added
    
    SAPDB_UInt      historyFileNo = 0;
    HistoryFileInfo fileinfo;
    bool            nextFileAvailable = true;
    Data_PageNo     unknownRoot;
    SAPDB_UInt      pagecount;
    
    while ( nextFileAvailable )
    {
        if ( historyFileNo == 0 )
            nextFileAvailable = dirfile.GetFirstHistoryFileInfo (fileinfo);
        else
            nextFileAvailable = dirfile.GetNextHistoryFileInfo (fileinfo);

        if ( LogHistory_Trace.TracesLevel(6) )
            Kernel_VTrace() << "history file #" << historyFileNo << 
                               ": root: "       << fileinfo.root    << 
                               ", last: "       << fileinfo.last    << 
                               ", oldest: "     << fileinfo.oldestTransNo.gg90GetInt4() << 
                               ", youngest: "   << fileinfo.youngestTransNo.gg90GetInt4();

        pagecount = 0;
        
        if ( fileinfo.IsValid() ) // PTS 1122287 UH 2003-05-26
            (void) UpdateHistoryFileInfo (trans, historyFileNo, fileinfo, pagecount);

        m_Directory.SetHistoryFileInfo (trans.trTaskId_gg00, historyFileNo, fileinfo, pagecount);

        // PTS 1114877 UH 2002-03-18 bd91RegisterHistoryFile is now executed at the end.

        ++historyFileNo;
    }
    
    if ( historyFileNo < GetNumberOfMaxUsedHistoryFiles() )
    {
        if ( LogHistory_Trace.TracesLevel(6) )
            Kernel_VTrace() << "MAXUSERTASKS was increased: adding new history files";
        CreateHistoryFiles ( trans, dirfile, historyFileNo,
                             GetNumberOfMaxUsedHistoryFiles()-1 );
    }

    // PTS 1114877 UH 2002-03-18 begin
    RTE_Message( Log_Exception(__CONTEXT__, LOG_EXISTING_HISTORY_FILES,
                               SAPDB_ToString(GetNumberOfMaxUsedHistoryFiles()),
                               SAPDB_ToString(GetNumberOfHistoryFiles())) );
        
    // Only after registration the garbage collector tasks can work on the history files.
    for ( SAPDB_UInt fileno = 0; fileno < GetNumberOfMaxUsedHistoryFiles(); ++fileno )
        GC_IGCController::Instance().RegisterHistoryFile(trans, fileno);  

    RTE_Message( Log_Exception(__CONTEXT__, LOG_HISTORY_FILE_REGISTERED) );
    // PTS 1114877 UH 2002-03-18 end
}

/* -------------------------------------------------------------------------------- */
bool Log_History::UpdateHistoryFileInfo ( tgg00_TransContext &trans,
                                          SAPDB_UInt          historyFileNo,
                                          HistoryFileInfo    &fileinfo,
                                          SAPDB_UInt         &pagecount )
{
    SAPDBTRACE_METHOD_DEBUG( "Log_History::UpdateHistoryFileInfo", LogHistory_Trace, 5 );
    
    if ( ! fileinfo.IsValid() ) // PTS 1122287 UH 2003-05-26 for security
        return false;
        
    Log_HistoryFile            histfile (trans, fileinfo.root, Data_PageNo());
    Log_HistoryFile::Iterator& iter = histfile.GetFirstUndoFileInfo();
    tgg91_TransNo              oldesttransno;
    tgg91_TransNo              youngesttransno;
    SAPDB_UInt                 entryCount = 0;

    oldesttransno.gg90SetNil();
    youngesttransno.gg90SetNil();
    
    while ( iter.IsValid() )
    {
        if ( (*iter).transno.gg90IsNil() ) // find the next valid entry
        {
            ++iter;
            continue;
        }
        
        ++entryCount;
        
        if ( oldesttransno.gg90IsNil() || oldesttransno > (*iter).transno )
            oldesttransno = (*iter).transno;
        
        if ( youngesttransno.gg90IsNil() || (*iter).transno > youngesttransno  )
            youngesttransno =  (*iter).transno;

        if ( (*iter).pagecount == SAPDB_MAX_UINT2 )
        {
            // look into undo file root.
            Log_UndoFile undofile (trans, (*iter).root, (*iter).last);
            pagecount += undofile.GetPageCount();
            undofile.Invalidate(); // prevent Drop() in destructor
        }
        else
            pagecount += (*iter).pagecount;
        ++iter;
    }

    bool fileIsChanged = false;
    
    if ( oldesttransno.gg90IsNil() || youngesttransno.gg90IsNil() )
        // UH 2002-09-02 return if nothing is in the file
        return fileIsChanged;
        
    if ( fileinfo.oldestTransNo != oldesttransno )
    {
        fileinfo.oldestTransNo = oldesttransno;
        fileIsChanged = true;
    }

    if ( fileinfo.youngestTransNo != youngesttransno )
    {
        fileinfo.youngestTransNo = youngesttransno;
        fileIsChanged = true;
    }
    
    if ( fileinfo.last != histfile.LastPageNo() )
    {
        fileinfo.last = histfile.LastPageNo();
        fileIsChanged = true;
    }
    
    if ( fileIsChanged && LogHistory_Trace.TracesLevel(6) )
    {
        Kernel_VTrace() << "updated history file #" << historyFileNo << 
                           ": root: "       << fileinfo.root    << 
                           ", last: "       << fileinfo.last    << 
                           ", oldest: "     << fileinfo.oldestTransNo.gg90GetInt4() << 
                           ", youngest: "   << fileinfo.youngestTransNo.gg90GetInt4()  <<
                           ", pagecount: "  << pagecount;
    }
    return fileIsChanged;
}

/* -------------------------------------------------------------------------------- */
Data_PageNo Log_History::Flush (tgg00_TransContext &trans)
{
    SAPDBTRACE_METHOD_DEBUG ("Log_History::Flush", LogHistory_Trace, 5);

    Log_HistoryDirectory  olddirfile (trans, m_DirectoryRoot);
    Log_HistoryDirectory  newdirfile (trans, Data_PageNo());
    
    if ( LogHistory_Trace.TracesLevel(6) )
        Kernel_VTrace() << "FlushHistory: oldroot: " << m_DirectoryRoot << NewLine;
    
    if ( ! newdirfile.Create() )
    {
        RTE_Crash( SAPDBErr_Exception(__CONTEXT__,
                   SAPDBERR_ASSERT_STATE_FAILED,
                   "Log_History::Flush() newdirfile.Create() failed") );
    }
    
    if ( LogHistory_Trace.TracesLevel(6) )
        Kernel_VTrace() << "FlushHistory: newroot: " << newdirfile.GetRootId().PageNo();
    
    SAPDB_UInt      historyFileCount = GetNumberOfHistoryFiles();
    SAPDB_UInt      fileno;
    SAPDB_UInt      pagecount;
    HistoryFileInfo fileinfo;

    
    if ( GetNumberOfMaxUsedHistoryFiles() < historyFileCount )
    {
        bool removeUnusedHistoryFiles = true;
        for ( fileno = GetNumberOfMaxUsedHistoryFiles();
              fileno < historyFileCount;
              ++fileno )
        {
            if ( ! GetOldestTransNo(fileno).gg90IsNil() )
            {
                if ( LogHistory_Trace.TracesLevel(6) )
                    Kernel_VTrace() << "UNUSED HISTORY: STILL EXISTS";
                removeUnusedHistoryFiles = false;
                break;
            }
        }
        if ( removeUnusedHistoryFiles )
        {
            if ( LogHistory_Trace.TracesLevel(6) )
                Kernel_VTrace() << "UNUSED HISTORY: COMPLETELY REMOVED";
            m_Directory.RemoveUnusedEntries();
            historyFileCount = GetNumberOfMaxUsedHistoryFiles();
            RTE_Message( Log_Exception(__CONTEXT__, LOG_EXISTING_HISTORY_FILES,
                                       SAPDB_ToString(GetNumberOfMaxUsedHistoryFiles()),
                                       SAPDB_ToString(GetNumberOfHistoryFiles())) );
        }
    }

    for ( fileno = 0; fileno < historyFileCount; fileno++)
    {
        m_Directory.GetHistoryFileInfo(trans.trTaskId_gg00, fileno, fileinfo, pagecount);
        newdirfile.AppendHistoryFile(fileinfo);
    }
    olddirfile.Drop();

    m_DirectoryRoot = newdirfile.GetRootId().PageNo();
    
    return m_DirectoryRoot;
}

/* -------------------------------------------------------------------------------- */
bool Log_History::Verify (tgg00_TransContext &trans,
                          bool                isCold)
{
    SAPDBTRACE_METHOD_DEBUG ("Log_History::Verify", LogHistory_Trace, 5);
    Log_HistoryDirectory  dirfile (trans, k57restartrec->rstLastSavept_kb00().svpHistoryRoot_kb00);
    if ( dirfile.IsCreated() )
        return dirfile.Verify(isCold);
    else
        return true;
}

/* -------------------------------------------------------------------------------- */
void Log_History::RegisterUndoFile (tgg00_TransContext &trans,
                                    Log_UndoFile       &file)
{
    SAPDBTRACE_METHOD_DEBUG ("Log_History::RegisterUndoFile", LogHistory_Trace, 5);
    
    SAPDB_Int       fileno = m_Directory.GetFileNo(trans.trTaskId_gg00);
    HistoryFileInfo info;
    SAPDB_UInt      pagecount;
    
    m_Directory.GetHistoryFileInfo(trans.trTaskId_gg00, fileno, info, pagecount);

	// UH 30-07-2002
	// removed vtrace output which was written
	// if a younger transno exists already

	Log_HistoryFile histfile ( trans, info.root, Data_PageNo() );

    trans.trState_gg00.addElement ( tsDbFullNowait_egg00 ); // PTS 1135886 mb 2005-06-01
    histfile.AppendUndoFile (file);
    trans.trState_gg00.delElement ( tsDbFullNowait_egg00 ); // PTS 1135886 mb 2005-06-01
    m_Directory.UpdateInfoAfterRegisterNewUndoFile
                ( trans.trTaskId_gg00,
                  fileno,
                  file.GetTransNo(),
                  file.GetPageCount(),
                  histfile.LastPageNo() );
}
/* -------------------------------------------------------------------------------- */
void Log_History::RemoveHistory (tgg00_TransContext        &trans,
                                 SAPDB_UInt                 fileno,
                                 RemoveOptions              option,
                                 GC_IGarbageCollector      &IGarbColl,                    // PTS xxxxxxx FF 2002-02-12 
                                 bool                      &anythingRemoved)
{
    SAPDBTRACE_METHOD_DEBUG ("Log_History::RemoveHistory", LogHistory_Trace, 5);
    
    if ( fileno >= GetNumberOfHistoryFiles() )
    {
        RTE_Crash( SAPDBErr_Exception(__CONTEXT__,
                   SAPDBERR_ASSERT_ARGUMENT_FAILED,
                   "Log_History::RemoveHistory() fileno is valid") );
    }
    
    anythingRemoved = false;

    HistoryFileInfo fileinfo;
    tgg91_TransNo   minUsedTransNo;
    pasbool         isTransUsed = 0;
    SAPDB_UInt      pagecount;
    bool            currentUndoFileRemoved = false;
    
    m_Directory.GetHistoryFileInfo ( trans.trTaskId_gg00, fileno,
                                     fileinfo, pagecount);
    
    if ( ! fileinfo.IsValid() ) // PTS 1122287 UH 2003-05-26 it may be a continued "remove unused"
    {
        Kernel_VTrace() << "fileinfo " << fileno << " is invalid and ignored" << fileno;
        return;
    }
        
    if ( fileinfo.oldestTransNo.gg90IsNil()
         &&
         fileinfo.youngestTransNo.gg90IsNil() )
    {
        // file is empty
        Log_HistoryFile file (trans, fileinfo.root, Data_PageNo());
        
        if ( option == RemoveUnused && file.IsCreated() )
        {
            if ( LogHistory_Trace.TracesLevel(6) )
                Kernel_VTrace() << "UNUSED HISTORY: DROP EMPTY FILE " << fileno;
            file.Drop();
        }
        return;
    }
    
    if ( option != RemoveUnused )
        CheckAndRemoveUnusedHistory (trans, IGarbColl);

    if ( LogHistory_Trace.TracesLevel(6) )
    {
        Kernel_VTrace trace;
        trace << "RemoveHistory() fileno: " << fileno
              << ", oldest trans: "         << fileinfo.oldestTransNo.gg90GetInt4()
              << ", youngest trans: "       << fileinfo.youngestTransNo.gg90GetInt4()
              << NewLine;
        trace << "RemoveHistory() root: "   << fileinfo.root
              << ", last: "                 << fileinfo.last
              << ", pagecount: "            << pagecount
              << NewLine;
        trace << "RemoveHistory() option: " << ( option==Normal      ? "Normal"
                                              :(option==Truncate    ? "Truncate"
                                              :(option==RemoveUnused? "RemoveUnused"
                                              :                       "Sensitive" ) ) )
              << NewLine;
    }

    kb51IsConsistUsedTransId ( trans.trTaskId_gg00,
                               fileinfo.oldestTransNo,
                               minUsedTransNo,
                               isTransUsed );
                               
    if ( LogHistory_Trace.TracesLevel(6) )
    {
        Kernel_VTrace trace;
        trace << "RemoveHistory() fileno: " << fileno
              << ", oldest trans: "         << fileinfo.oldestTransNo.gg90GetInt4()
              << ", youngest trans: "       << fileinfo.youngestTransNo.gg90GetInt4()
              << NewLine;
        trace << "RemoveHistory() root: "   << fileinfo.root
              << ", last: "                 << fileinfo.last
              << ", pagecount: "            << pagecount
              << NewLine;
        trace << "RemoveHistory() option: " << ( option==Normal      ? "Normal"
                                               :(option==Truncate    ? "Truncate"
                                               :(option==RemoveUnused? "RemoveUnused"
                                               :                       "Sensitive" ) ) )
              << NewLine;
        trace << "RemoveHistory() min used trans: " << minUsedTransNo.gg90GetInt4()
              << ", is used: "      << (isTransUsed==0?"no":"yes")
              << NewLine;
    }
    if ( option == Truncate
         &&
         ! IGarbColl.IsInterrrupted() ) // PTS 1113185 UH 2001-12-18
    {
        TruncateHistory (trans, fileno, fileinfo.root, fileinfo.last,
                         IGarbColl,                 // PTS 1113185 UH 2001-12-18
                         anythingRemoved);
        if ( ! anythingRemoved
             &&
             ! IGarbColl.IsInterrrupted()
             &&
             LogHistory_Check.ChecksLevel(5) )
        {
            // The caller at first scans for the oldest trans.
            // Only if the caller gets an oldest trans it calls RemoveHistory for truncation.
            // So if nothing was done, then the HistoryDirectory is inconsistent with the
            // Historyfile.
            m_Directory.WriteToTrace(trans.trTaskId_gg00, "TruncateHistory() has done nothing");
            RTE_Crash( SAPDBErr_Exception(__CONTEXT__,
                       SAPDBERR_ASSERT_ARGUMENT_FAILED,
                       "TruncateHistory() has done nothing") );
        }
        return;
    }

    if ( isTransUsed == 1 )
    {
        // even the oldest trans in this history file is used
        if ( LogHistory_Trace.TracesLevel(6) )
            Kernel_VTrace() << "RemoveHistory() oldest trans is used => NO ACTION" << NewLine;
        return;
    }
    
    SAPDB_UInt                 loops = 0;
    bool                       removeHistory;
    tgg91_TransNo              transno;
    Data_PageNo                undoRoot;
    Data_PageNo                undoLast;
    Log_HistoryFile            file (trans, fileinfo.root, Data_PageNo() );
    Log_HistoryFile::Iterator &undoFileInfoIter = file.GetFirstUndoFileInfo();

    while ( undoFileInfoIter.IsValid()
            &&
            ! IGarbColl.IsInterrrupted() ) // PTS 1113185 UH 2001-12-18
    {   
        transno   = (*undoFileInfoIter).transno;
        undoRoot  = (*undoFileInfoIter).root;
        undoLast  = (*undoFileInfoIter).last;
        pagecount = (*undoFileInfoIter).pagecount;

        if ( transno.gg90IsNil() ) // find the next valid entry
        {
            ++undoFileInfoIter;
            continue;
        }
        
        if ( LogHistory_Trace.TracesLevel(6) )
            Kernel_VTrace() << "RemoveHistory() transno: " << transno.gg90GetInt4()
                            << ", undoRoot: " << undoRoot
                            << ", undoLast: " << undoLast
                            << ", pagecount: " << pagecount
                            << NewLine;

        if ( transno != (*undoFileInfoIter).transno )
        {
            Kernel_VTrace() << "iter.transno: " << (*undoFileInfoIter).transno.gg90GetInt4()
                            << NewLine;
            undoFileInfoIter.WriteToTrace("transno != iter.transno");
            undoFileInfoIter.Invalidate();
            RTE_Message(SAPDBErr_Exception(__CONTEXT__,SAPDBERR_ASSERT_STATE_FAILED,
                                           "transno == iter.transno, look into vtrace"));
            break;
        }       

        if ( ! minUsedTransNo.gg90IsNil() )
            // simple check if this history is older then the oldest needed
            removeHistory = minUsedTransNo > transno;
        else
        {
            // at the time this run started, no view was open, no history was needed
            if ( fileinfo.youngestTransNo >= transno  )
                removeHistory = true;
            else
            {
                // local youngest transno is reached
                // there may be more entries in the meantime
                // but they are proofed in a later run
                undoFileInfoIter.Invalidate();
                break;
            }
        }
        
        if ( ! removeHistory && option == Sensitive )
        {
            // expensive check if filling state required "Sensitive"
            kb51IsConsistUsedTransId ( trans.trTaskId_gg00,
                                       transno,
                                       minUsedTransNo,
                                       isTransUsed );

            removeHistory = isTransUsed == 0;
        }
        
        if ( LogHistory_Trace.TracesLevel(6) )
            Kernel_VTrace() << "RemoveHistory() transno: " << transno.gg90GetInt4()
                            << (removeHistory?" is removed now":" is not removed now")
                            << NewLine;

        if ( removeHistory )
        {
            anythingRemoved = true;
            currentUndoFileRemoved = RemoveUndoFileWithObjects             // PTS 1113934 UH 2002-02-01
                                      (trans, undoRoot, undoLast,
                                       IGarbColl,                   // PTS 1113185 UH 2001-12-18
                                       file, undoFileInfoIter);     // PTS 1113934 UH 2002-02-01
        }
        else
            ++undoFileInfoIter;

        ++loops;
    }
    
    undoFileInfoIter.Invalidate();

    if ( option == RemoveUnused )
    {
        if ( m_Directory.GetOldestTransNo(fileno).gg90IsNil() )
        {
            if ( LogHistory_Trace.TracesLevel(6) )
                Kernel_VTrace() << "UNUSED HISTORY: DROP FILE " << fileno;
            file.Drop();
        }
    }
    else
    {
        if ( currentUndoFileRemoved )
        {
            // determine new oldest transno
            tgg91_TransNo newOldestTransno = DetermineOldestTransNo(file);
            // The later update only is correct,
            // if the garbage collectors are stopped during savepoint.
            m_Directory.UpdateOldestTransNo ( trans.trTaskId_gg00,
                                              fileno,
                                              newOldestTransno,
                                              file.LastPageNo(),
                                              pagecount );
        }
    }
}

/* -------------------------------------------------------------------------------- */
void Log_History::TruncateHistory (tgg00_TransContext        &trans,
                                   SAPDB_UInt                 fileno,
                                   Data_PageNo                root,
                                   Data_PageNo                last,
                                   GC_IGarbageCollector      &IGarbColl,                    //PTS xxxxxxx FF 2002-02-12 
                                   bool                      &anythingRemoved)
{
    SAPDBTRACE_METHOD_DEBUG ("Log_History::TruncateHistory", LogHistory_Trace, 5);

    Log_HistoryFile            file (trans, root, Data_PageNo() );
    Log_HistoryFile::Iterator& undoFileInfoIter = file.GetFirstUndoFileInfo();

    while ( undoFileInfoIter.IsValid()
            &&
            (*undoFileInfoIter).transno.gg90IsNil() )
        // find the first valid entry
        ++undoFileInfoIter;
        
    if ( ! undoFileInfoIter.IsValid() )
    {
        undoFileInfoIter.Invalidate();
        return;
    }

    if ( LogHistory_Trace.TracesLevel(6) )
        Kernel_VTrace() << "RemoveHistory() transno: " << (*undoFileInfoIter).transno.gg90GetInt4() << " is truncated now"
                        << NewLine;

    Data_PageNo undoRoot  = (*undoFileInfoIter).root;
    Data_PageNo undoLast  = (*undoFileInfoIter).last;
    SAPDB_UInt  pagecount = (*undoFileInfoIter).pagecount;
    

	anythingRemoved = RemoveUndoFileWithObjects (trans, undoRoot, undoLast,
                                                 IGarbColl,                   // PTS 1113185 UH 2001-12-18
                                                 file, undoFileInfoIter);
    if ( anythingRemoved )    // PTS 1113934 UH 2002-02-01
    {
        tgg91_TransNo newOldestTransno;
        
        if ( ! undoFileInfoIter.IsValid() )
            newOldestTransno.gg90SetNil();
        else
            newOldestTransno = DetermineOldestTransNo(file);
         
        // The later update is only correct,
        // if the garbage collectors are stopped during savepoint.
        m_Directory.UpdateOldestTransNo ( trans.trTaskId_gg00,
                                          fileno,
                                          newOldestTransno,
                                          file.LastPageNo(),
                                          pagecount );
    }
    else
        undoFileInfoIter.Invalidate();
}

/* -------------------------------------------------------------------------------- */
tgg91_TransNo Log_History::DetermineOldestTransNo (Log_HistoryFile &file)
{
    tgg91_TransNo oldestTransno;
    Log_HistoryFile::Iterator& undoFileInfoIter = file.GetFirstUndoFileInfo();
    // find the next valid entry
    while ( undoFileInfoIter.IsValid()
            &&
            (*undoFileInfoIter).transno.gg90IsNil() )
        ++undoFileInfoIter;
    if ( ! undoFileInfoIter.IsValid() )
        oldestTransno.gg90SetNil();
    else
    {
        oldestTransno = (*undoFileInfoIter).transno;
        undoFileInfoIter.Invalidate();
    }
    
    return oldestTransno;
}

/* -------------------------------------------------------------------------------- */
bool Log_History::RemoveUndoFileWithObjects (tgg00_TransContext        &trans,
                                             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
{
    SAPDBTRACE_METHOD_DEBUG ("Log_History::RemoveUndoFileWithObjects", LogHistory_Trace, 5);

    undoFileInfoIter.Break(); // PTS 1113934 UH 2002-02-01

    SAPDBMem_IRawAllocator &allocator = *(reinterpret_cast<SAPDBMem_IRawAllocator*>(trans.trAllocator_gg00));
    Log_UndoFile            undofile (trans, root, last);
    Log_BeforeImage         image;
    bool                    isOK = true;
    Data_PageNo             pageno;
    Data_PageOffset         offset = 0; // PTS ? UH 2002-03-15
    bool                    allUndoEntriesDone = false; // PTS ? UH 2002-03-15
    tgg91_PageRef           auxPageref;
    Log_UndoFile::Iterator &iter = undofile.GetIterator(); // PTS ? UH 2002-03-15

    // PTS ? UH 2002-03-15
    // If a previous run was interrupted then start at the last entry which was done at the last time.
    undofile.GetLastGarbageCollectorPosition (pageno, offset);

    if ( pageno.IsValid() && offset > 0 )
        undofile.GetUndoEntry (pageno, offset, Data_ForUpdate, 0, iter);
    else
        undofile.GetLastUndoEntry (Data_ForUpdate, iter);

    if ( trans.trError_gg00 == e_corrupted_datapage_from_io ) // PTS 1117126 UH 2002-08-07
        return false;

    Data_SplitSpaceReader reader (*iter, true); // PTS 1114994 UH 2002-04-17 added releasable

    while ( iter.IsValid()
            &&
            ! IGarbColl.IsInterrrupted() ) // PTS 1113185 UH 2001-12-18
    {
        iter.GetPosition(pageno, offset);

        reader.Reset();
        image.ReadPersistentFormat (reader, isOK);

        allUndoEntriesDone = image.GetSequence() == 0; // UH 2002-05-03
            
        if ( ! isOK )
        {
            Kernel_VTrace() << "current iter position: " << pageno << "." << offset << NewLine;
            RTE_Crash( SAPDBErr_Exception(__CONTEXT__, SAPDBERR_ASSERT_STATE_FAILED,
                       "image.ReadPersistentFormat() failed") );
        }

        if ((( image.GetActionType() == Log_DeleteObject ) || 
            ( image.GetActionType() == Log_DropObjectFile ))  // PTS 1119647 FF 2002-DEC-05
            &&
            ! image.IsDeleted(false) ) // PTS 1113998 UH 2002-02-05
        {
            image.SetDeleted(true);
            
            if ( image.GetActionType() == Log_DeleteObject )
            {
                Log_ActionObject action;
                
                action.ReadPersistentFormat (reader, allocator, isOK);
                if ( ! isOK )
                {
                    Kernel_VTrace() << "current iter position: " << pageno << "." << offset << NewLine;
                    image.WriteToTrace("RemoveUndoFileWithObjects");
                    RTE_Crash( SAPDBErr_Exception(__CONTEXT__,SAPDBERR_ASSERT_STATE_FAILED,
                        "action.ReadPersistentFormat() failed") );
                }
                auxPageref.gg91BuildRef (pageno, offset);
                
                bd91ReleaseUnusedObject ( trans,
                    iter,
                    action.GetOid(),
                    action.GetFileNo(),
                    auxPageref,
                    IGarbColl ); // PTS 1113774 FF 2002-01-29
                tgg00_BasisError auxError = e_ok;
                
                switch (trans.trError_gg00)
                {
                case e_ok:
                    break;
                case e_wrong_object_version:
                case e_wrong_class_id:
                case e_page_in_wrong_tree:
                    auxError           = trans.trError_gg00;
                    trans.trError_gg00 = e_ok;
                    break;
                default:
                    Kernel_VTrace() << "current iter position: " << pageno << "." << offset << NewLine;
                    image.WriteToTrace ("RemoveUndoFileWithObjects");
                    action.WriteToTrace("RemoveUndoFileWithObjects");
                    RTE_Crash( SAPDBErr_Exception(__CONTEXT__,SAPDBERR_ASSERT_STATE_FAILED,
                        "bd91ReleaseUnusedObject failed") );
                }
                
                if ( ! iter.IsValid() )
                {
                    undofile.GetUndoEntry (pageno, offset, Data_ForUpdate, 0, iter); // PTS ? UH 2002-03-15 now ForUpdate
                    if ( trans.trError_gg00 == e_corrupted_datapage_from_io ) // PTS 1117126 UH 2002-08-07
                        return false;
                    *iter; // really assign the space at the given position
                }
                
                if ( auxError != e_ok )
                {
                    // Check if a redo task was a little bit faster then the garbage collector
                    reader.Reset();
                    image.ReadPersistentFormat (reader, isOK);
                    if ( ! isOK )
                    {
                        Kernel_VTrace() << "current iter position: " << pageno << "." << offset << NewLine;
                        RTE_Crash( SAPDBErr_Exception(__CONTEXT__,SAPDBERR_ASSERT_STATE_FAILED,
                            "2. image.ReadPersistentFormat() failed") );
                    }
                    if ( image.GetActionType() != Log_DeleteObject )
                    {
                        Kernel_VTrace() << "current iter position: " << pageno << "." << offset << NewLine;
                        image.WriteToTrace ("RemoveUndoFileWithObjects2");
                        RTE_Crash( SAPDBErr_Exception(__CONTEXT__,SAPDBERR_ASSERT_STATE_FAILED,
                            "no delete entry") );
                    }
                    if ( ! image.IsRollbacked(false) && ! image.IsDeleted(false) )
                    {
                        Kernel_VTrace() << "current iter position: " << pageno << "." << offset << NewLine;
                        image.WriteToTrace ("RemoveUndoFileWithObjects2");
                        action.WriteToTrace("RemoveUndoFileWithObjects2");
                        RTE_Crash( SAPDBErr_Exception(__CONTEXT__,SAPDBERR_ASSERT_STATE_FAILED,
                            "2. bd91ReleaseUnusedObject failed") );
                    }
                }
            }
            else
            {
                // PTS 1119647 FF 2002-DEC-05
                Log_ActionObjectFile actionFile;
                
                actionFile.ReadPersistentFormat (reader, allocator, isOK);
                if ( ! isOK )
                {
                    Kernel_VTrace() << "current iter position: " << pageno << "." << offset << NewLine;
                    image.WriteToTrace("RemoveUndoFileWithObjects");
                    RTE_Crash( SAPDBErr_Exception(__CONTEXT__,SAPDBERR_ASSERT_STATE_FAILED,
                        "actionFile.ReadPersistentFormat() failed") );
                }
                bd91DropObjFile ( trans, actionFile.GetFileNo() );              
                switch (trans.trError_gg00)
                {
                case e_ok:
                    break;
                default:
                    Kernel_VTrace() << "current iter position: " << pageno << "." << offset << NewLine;
                    image.WriteToTrace ("RemoveUndoFileWithObjects");
                    actionFile.WriteToTrace("RemoveUndoFileWithObjects");
                    RTE_Crash( SAPDBErr_Exception(__CONTEXT__,SAPDBERR_ASSERT_STATE_FAILED,
                        "bd91DropObjFile failed") );
                }
            }            
        }
        
        switch ( image.GetActionType() )  // PTS 1114106 FF 13-Feb-2002
        {
        case Log_NewObject:
          IGarbColl.IncHistNewObjCount();
          break;
        case Log_InsertObject:
          IGarbColl.IncHistInsertObjCount();
          break;
        case Log_UpdateObject:
          IGarbColl.IncHistUpdateObjCount();
          break;
        case Log_DeleteObject:
          IGarbColl.IncHistDeleteObjCount();
          break;
        case Log_LockObject:
          IGarbColl.IncHistLockObjCount();
          break;
        case Log_CreateObjectFile:
          IGarbColl.IncHistCreateObjFileCount();
          break;
        case Log_DropObjectFile:
          IGarbColl.IncHistDropObjFileCount();
          break;
        default:
          break;
        }

        --iter;
        *iter; // really assign the space
    }

    iter.Invalidate();

    // PTS 1113934 UH 2002-02-01 begin
    if ( ! allUndoEntriesDone ) // PTS ? UH 2002-03-15
    {
        // Save pageno and offset to start there at the next run.
        undofile.SaveLastGarbageCollectorPosition (pageno, offset); // PTS ? UH 2002-03-15

        undofile.Invalidate(); // prevent Drop() in destructor
        return false;
    }

    if ( ! undoFileInfoIter.Continue() )
    {
        undoFileInfoIter.WriteToTrace ("undoFileInfoIter");
        RTE_Crash( SAPDBErr_Exception(__CONTEXT__, SAPDBERR_ASSERT_STATE_FAILED,
               "iter.Continue() failed") );
    }

    if ( (*undoFileInfoIter).root != root )
    {
        undoFileInfoIter.WriteToTrace ("undoFileInfoIter");
        RTE_Crash( SAPDBErr_Exception(__CONTEXT__, SAPDBERR_ASSERT_STATE_FAILED,
               "iter points to wrong entry") );
    }
               
    historyfile.RemoveUndoFileInfo (undoFileInfoIter);

    const bool breakIterator = iter.IsValid(); // PTS 1135450 UH 10-05-2005

    if ( breakIterator ) // PTS 1135450 UH 10-05-2005
        undoFileInfoIter.Break();

    undofile.Drop();

    if ( breakIterator && ! undoFileInfoIter.Continue() ) // PTS 1135450 UH 10-05-2005
    {
        undoFileInfoIter.WriteToTrace ("undoFileInfoIter");
        RTE_Crash( SAPDBErr_Exception(__CONTEXT__, SAPDBERR_ASSERT_STATE_FAILED,
               "iter.Continue() failed") );
    }
    return true;
    // PTS 1113934 UH 2002-02-01 end
}

/* -------------------------------------------------------------------------------- */
void
Log_History::GetBeforeImage
     (tgg00_TransContext       &Trans,
      const tgg92_KernelOid    &TestOid,
      const tgg91_PageRef      &WantedPageRef,
      SAPDB_UInt4               BodySize,
      SAPDB_Byte               *pBody,
      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)
{
    SAPDBTRACE_ROUTINE_DEBUG ("Log_History::GetBeforeImage", LogHistory_Trace, 5);

    const bool            bWithBody = (BodySize > 0);
    const Data_PageNo     pageno    = WantedPageRef.gg91RefPno();
    const Data_PageOffset offset    = WantedPageRef.gg91RefPos();

    if ( pageno.IsInvalid() )
    {
        if ( LogHistory_Trace.TracesLevel(6) )
        {
            Kernel_VTrace() << "GetBeforeImage() history get: " << pageno << "." << offset
                            << " for oid: " << TestOid.gg92GetPno() << "." << TestOid.gg92GetPos()
                            << " with view: " << Trans.trConsistView_gg00.gg90GetInt4()
                            << NewLine;
            Kernel_VTrace() << "GetBeforeImage() WantedPageRef is NIL" << NewLine;
        }
        Trans.trError_gg00 = e_obj_history_not_found;
        #ifdef SAPDB_QUICK
        RTE_Crash( SAPDBErr_Exception(__CONTEXT__,SAPDBERR_ASSERT_STATE_FAILED,"pageno is invalid") );
        #endif
        return;
    }

    // PTS 1119860 UH 2003-01-08 return with error if offest is not aligned
    if ( offset != Data_PageSplitSpace::AlignRecordSize(offset) )
    {
        Kernel_VTrace() << "GetBeforeImage() history get: " << pageno << "." << offset
                        << " for oid: " << TestOid.gg92GetPno() << "." << TestOid.gg92GetPos()
                        << " with view: " << Trans.trConsistView_gg00.gg90GetInt4()
                        << NewLine;
        Kernel_VTrace() << "GetBeforeImage() WantedPageRef is not aligned" << NewLine;
        Trans.trError_gg00 = e_obj_history_not_found;
        return;
    }

    SAPDBMem_IRawAllocator &allocator = *(reinterpret_cast<SAPDBMem_IRawAllocator*>(Trans.trAllocator_gg00));
    Log_UndoFile            file (Trans, Data_PageNo(), Data_PageNo());
    Log_UndoFile::Iterator  iter (file.PageAccessManager(), allocator);
    
    if ( ! iter.Initialize() )
    {
        Kernel_VTrace() << "GetBeforeImage() history get: " << pageno << "." << offset
                        << " for oid: " << TestOid.gg92GetPno() << "." << TestOid.gg92GetPos()
                        << " with view: " << Trans.trConsistView_gg00.gg90GetInt4()
                        << NewLine;
        RTE_Crash( SAPDBErr_Exception(__CONTEXT__,SAPDBERR_ASSERT_STATE_FAILED,"iter.Initialize()") );
    }

    // PTS 1117126 UH 2002-08-07 maxAllowedEntrySize check added
    
    const Data_SplitRecordLength maxAllowedEntrySize =
                      3 * ( Log_UndoPage::MaxSpaceOffset()
                      -Log_UndoPage::MinSpaceOffset() );

    file.GetUndoEntry ( pageno, offset, Data_ForRead,
                        maxAllowedEntrySize, iter );
                            
    if ( ! iter.IsValid() )
    {
        if ( LogHistory_Trace.TracesLevel(6) )
        {
            Kernel_VTrace() << "GetBeforeImage() history get: " << pageno << "." << offset
                            << " for oid: " << TestOid.gg92GetPno() << "." << TestOid.gg92GetPos()
                            << " with view: " << Trans.trConsistView_gg00.gg90GetInt4()
                            << NewLine;
            Kernel_VTrace() << "GetBeforeImage() entry not found" << NewLine;
        }
        // PTS 1117126 UH 2002-08-07 do not override io error
        if ( Trans.trError_gg00 != e_corrupted_datapage_from_io )
            Trans.trError_gg00 = e_obj_history_not_found;
        iter.Invalidate();
        file.Invalidate();
        return;
    }
    
    Log_UndoFile::EntrySpace &space = *iter;
    
    if ( ! space.CheckAlignment() )
    {
        if ( LogHistory_Trace.TracesLevel(6) )
        {
            Kernel_VTrace() << "GetBeforeImage() history get: " << pageno << "." << offset
                            << " for oid: " << TestOid.gg92GetPno() << "." << TestOid.gg92GetPos()
                            << " with view: " << Trans.trConsistView_gg00.gg90GetInt4()
                            << NewLine;
            Kernel_VTrace() << "GetBeforeImage() could not read image because wrong ALIGNMENT" << NewLine;
        }
        Trans.trError_gg00 = e_obj_history_not_found;
        iter.Invalidate();
        file.Invalidate();
        return;
    }
    
    Data_SplitSpaceReader reader (space);
    Log_BeforeImage       image;
    bool                  isOK = true;
    
    image.ReadPersistentFormat (reader, isOK, true);

    if ( ! isOK )
    {
        Kernel_VTrace() << "GetBeforeImage() history get: " << pageno << "." << offset
                        << " for oid: " << TestOid.gg92GetPno() << "." << TestOid.gg92GetPos()
                        << " with view: " << Trans.trConsistView_gg00.gg90GetInt4()
                        << NewLine;
        Kernel_VTrace() << "GetBeforeImage() could not read image" << NewLine;
        Trans.trError_gg00 = e_obj_history_not_found;
        iter.Invalidate();
        file.Invalidate();
        return;
    }

    ActionType     = image.GetActionType();
    ConsistentView = image.GetConsistentView();
    PrevUpdTrans   = image.GetPreviousUpdateTransNo();
    NextPageRef    = image.GetPreviousImage();
    
    switch ( ActionType )
    {
    case Log_NewObject:
    case Log_InsertObject:
    case Log_UpdateObject:
    case Log_DeleteObject:
    case Log_LockObject:
        {
            Log_ActionObject        action;
            SAPDBMem_IRawAllocator &allocator =
                *(reinterpret_cast<SAPDBMem_IRawAllocator*>(Trans.trAllocator_gg00));
            
            action.ReadPersistentFormat (reader, allocator, isOK);
            
            if ( ! isOK )
            {
                if ( LogHistory_Trace.TracesLevel(6) )
                {
                    Kernel_VTrace() << "GetBeforeImage() history get: " << pageno << "." << offset
                                    << " for oid: " << TestOid.gg92GetPno() << "." << TestOid.gg92GetPos()
                                    << " with view: " << Trans.trConsistView_gg00.gg90GetInt4()
                                    << NewLine;
                    Kernel_VTrace() << "GetBeforeImage() could not read action" << NewLine;
                    image.WriteToTrace("GetBeforeImage()");
                }
                Trans.trError_gg00 = e_obj_history_not_found;
                iter.Invalidate();
                file.Invalidate();
                return;
            }
            
            if ( ! action.GetOid().gg92IsEqIgnoreFrameVers(TestOid) )
            {
                if ( LogHistory_Trace.TracesLevel(6) )
                {
                    Kernel_VTrace() << "GetBeforeImage() history get: " << pageno << "." << offset
                                    << " for oid: " << TestOid.gg92GetPno() << "." << TestOid.gg92GetPos()
                                    << " with view: " << Trans.trConsistView_gg00.gg90GetInt4() << NewLine;
                    image.WriteToTrace("GetBeforeImage()");
                    action.WriteToTrace("GetBeforeImage()");
                    Kernel_VTrace() << "GetBeforeImage() invalid oid" << NewLine;
                }
                Trans.trError_gg00 = e_obj_history_not_found;
                iter.Invalidate();
                file.Invalidate();
                return;
            }

            FrameVers = action.GetOid().gg92GetFrameVers();
            BodyLen   = action.GetBodySize();

            if ( pBody == NULL || ActionType == Log_LockObject )
                break; // no body needed or wanted

            if ( BodyLen > BodySize )
            {
                Kernel_VTrace() << "GetBeforeImage() history get: " << pageno << "." << offset
                                << " for oid: " << TestOid.gg92GetPno() << "." << TestOid.gg92GetPos()
                                << " with view: " << Trans.trConsistView_gg00.gg90GetInt4()
                                << NewLine;
                image.WriteToTrace("GetBeforeImage()");
                action.WriteToTrace("GetBeforeImage()");
                Kernel_VTrace() << "GetBeforeImage() BodySize too small: " << BodySize << " < " << BodyLen
                                << NewLine;
                Trans.trError_gg00 = e_log_error;
                RTE_Crash( SAPDBErr_Exception(__CONTEXT__,SAPDBERR_ASSERT_STATE_FAILED,"bodysize too small") );
                return;
            }

            if ( Log_DeleteObject == ActionType || Log_UpdateObject == ActionType )
                memcpy (pBody, action.GetBody(), BodyLen);
            else if ( Log_NewObject == ActionType || Log_InsertObject == ActionType )
                memset (pBody, 0x00, BodyLen);
        }
        break;
    default:
        if ( LogHistory_Trace.TracesLevel(6) )
        {
            Kernel_VTrace() << "GetBeforeImage() history get: " << pageno << "." << offset
                            << " for oid: " << TestOid.gg92GetPno() << "." << TestOid.gg92GetPos()
                            << " with view: " << Trans.trConsistView_gg00.gg90GetInt4() << NewLine;
            image.WriteToTrace("GetBeforeImage()");
            Kernel_VTrace() << "GetBeforeImage() invalid action type '" << Log_GetActionTypeString(ActionType) // PTS 1134693 UH 2005-04-01
                            << NewLine;
        }
        Trans.trError_gg00 = e_obj_history_not_found;
        iter.Invalidate();
        file.Invalidate();
        return;
    }        

    // PTS 1113253 UH 2001-12-27 activate the if-clause
    if ( image.IsDeleted(false) && bOnlyCheckExistence /* PTS 1113317 UH 2002-01-08 */ )
    {
        if ( LogHistory_Trace.TracesLevel(6) )
        {
            Kernel_VTrace() << "GetBeforeImage() history get: " << pageno << "." << offset
                            << " for oid: " << TestOid.gg92GetPno() << "." << TestOid.gg92GetPos()
                            << " with view: " << Trans.trConsistView_gg00.gg90GetInt4() << NewLine;
            image.WriteToTrace("GetBeforeImage()");
            Kernel_VTrace() << "GetBeforeImage() IsDeleted = true && bOnlyCheckExistence" << NewLine;
        }
        Trans.trError_gg00 = e_obj_history_not_found;
    }

    iter.Invalidate();
    file.Invalidate();
}

/* -------------------------------------------------------------------------------- */
void Log_History::DeleteBeforeImage (tgg00_TransContext    &trans,
                                     const tgg92_KernelOid &oid,
                                     const tgg91_PageRef   &pageref)
{
    SAPDBTRACE_ROUTINE_DEBUG ("Log_History::DeleteBeforeImage", LogHistory_Trace, 5);

    const Data_PageNo     pageno = pageref.gg91RefPno();
    const Data_PageOffset offset = pageref.gg91RefPos();

    // PTS 1113251 UH 2001-12-27
    // removed all RTE_Crash calls and moved the trace output to the error cases
    
    if ( pageno.IsInvalid() )
    {
        if ( LogHistory_Trace.TracesLevel(6) )
        {
            Kernel_VTrace() << "history del: " << pageno << "." << offset << NewLine;
            Kernel_VTrace() << "*** Log_History::DeleteBeforeImage() pageref is NIL" << NewLine;
        }
        trans.trError_gg00 = e_obj_history_not_found;
        return;
    }

    SAPDBMem_IRawAllocator &allocator = *(reinterpret_cast<SAPDBMem_IRawAllocator*>(trans.trAllocator_gg00));
    Log_UndoFile            file (trans, Data_PageNo(), Data_PageNo());
    Log_UndoFile::Iterator  iter (file.PageAccessManager(), allocator);
    
    if ( ! iter.Initialize() )
    {
        RTE_Crash( SAPDBErr_Exception(__CONTEXT__,SAPDBERR_ASSERT_STATE_FAILED,
                   "Log_History::DeleteBeforeImage() iter.Initialize()") );
    }

    file.GetUndoEntry (pageno, offset, Data_ForUpdate, 0, iter);
                            
    if ( ! iter.IsValid() )
    {
        if ( LogHistory_Trace.TracesLevel(6) )
        {
            Kernel_VTrace() << "history del: " << pageno << "." << offset << NewLine;
            Kernel_VTrace() << "*** Log_History::DeleteBeforeImage() entry not found" << NewLine;
        }
        iter.Invalidate();
        file.Invalidate();
        if ( trans.trError_gg00 != e_corrupted_datapage_from_io ) // PTS 1117126 UH 2002-08-07
            trans.trError_gg00 = e_obj_history_not_found;
        return;
    }
    
    Data_SplitSpaceReader reader (*iter);
    Log_BeforeImage       image;
    bool                  isOK = true;
    
    image.ReadPersistentFormat (reader, isOK);

    if ( ! isOK )
    {
        if ( LogHistory_Trace.TracesLevel(6) )
        {
            Kernel_VTrace() << "history del: " << pageno << "." << offset << NewLine;
            Kernel_VTrace() << "*** Log_History::DeleteBeforeImage() error reading image" << NewLine;
        }
        iter.Invalidate();
        file.Invalidate();
        trans.trError_gg00 = e_obj_history_not_found;
        return;
    }

    if ( image.GetActionType() != Log_DeleteObject )
    {
        if ( LogHistory_Trace.TracesLevel(6) )
        {
            Kernel_VTrace() << "history del: " << pageno << "." << offset << NewLine;
            Kernel_VTrace() << "*** Log_History::DeleteBeforeImage(): invalid action type '"
                            << Log_GetActionTypeString(image.GetActionType()) << NewLine;
            image.WriteToTrace("DeleteBeforeImage");
        }
        iter.Invalidate();
        file.Invalidate();
        trans.trError_gg00 = e_obj_history_not_found;
        return;
    }

    Log_ActionObject action;

    action.ReadPersistentFormat (reader, allocator, isOK);

    if ( ! isOK )
    {
        if ( LogHistory_Trace.TracesLevel(6) )
        {
            Kernel_VTrace() << "history del: " << pageno << "." << offset  << NewLine;
            Kernel_VTrace() << "*** Log_History::DeleteBeforeImage() error reading action"  << NewLine;
            image.WriteToTrace("DeleteBeforeImage");
        }
        iter.Invalidate();
        file.Invalidate();
        trans.trError_gg00 = e_obj_history_not_found;
        return;
    }

    if ( ! action.GetOid().gg92IsEqIgnoreFrameVers(oid) )
    {
        if ( LogHistory_Trace.TracesLevel(6) )
        {
            Kernel_VTrace() << "history del: " << pageno << "." << offset  << NewLine;
            Kernel_VTrace() << "*** Log_History::DeleteBeforeImage() invalid oid"  << NewLine;
            image.WriteToTrace("DeleteBeforeImage");
            action.WriteToTrace("DeleteBeforeImage");
        }
        iter.Invalidate();
        file.Invalidate();
        trans.trError_gg00 = e_obj_history_not_found;
        return;
    }

    if ( image.IsDeleted(false) )
    {
        if ( LogHistory_Trace.TracesLevel(6) )
        {
            Kernel_VTrace() << "history del: " << pageno << "." << offset  << NewLine;
            Kernel_VTrace() << "*** Log_History::DeleteBeforeImage() entry already deleted"  << NewLine;
            image.WriteToTrace("DeleteBeforeImage");
            action.WriteToTrace("DeleteBeforeImage");
        }
        iter.Invalidate();
        file.Invalidate();
        trans.trError_gg00 = e_obj_history_not_found;
        return;
    }

    // now invalidate the before image if all checks offer positive results ++++
    image.SetDeleted(true);
    
    iter.Invalidate();
    file.Invalidate();
}

/* -------------------------------------------------------------------------------- */
void Log_History::RemoveCompleteHistory (tgg00_TransContext &trans)
{
    // PTS 1114877 UH 2002-03-18 new
    
    SAPDBTRACE_ROUTINE_DEBUG ("Log_History::RemoveCompleteHistory", LogHistory_Trace, 5);

    bool    anythingRemoved;
    DummyGC dummygc;

    RTE_Message( Log_Exception(__CONTEXT__,LOG_BEGIN_REMOVE_COMPLETE_HISTORY) );

    for ( SAPDB_UInt fileno = 0; fileno < GetNumberOfHistoryFiles(); ++fileno )
    {
        anythingRemoved = false;
        RemoveHistory (trans, fileno, Normal, dummygc, anythingRemoved);
    }

    RTE_Message( Log_Exception(__CONTEXT__,LOG_END_REMOVE_COMPLETE_HISTORY) );
}

/* -------------------------------------------------------------------------------- */
bool Log_History::AnyHistoryExists ()
{
    // PTS 1114877 UH 2002-03-18 new
    SAPDBTRACE_ROUTINE_DEBUG ("Log_History::AnyHistoryExists", LogHistory_Trace, 5);
    for ( SAPDB_UInt fileno = 0; fileno < GetNumberOfHistoryFiles(); ++fileno )
    {
        // outside region => dirty read
        if ( ! GetOldestTransNo(fileno).gg90IsNil() )
            return true;
    }
    return false;
}

/* -------------------------------------------------------------------------------- */
void Log_History::CheckAndRemoveUnusedHistory ( tgg00_TransContext   &trans,
                                                GC_IGarbageCollector &IGarbColl )
{
    // PTS 1115523 UH 2002-05-06 new
    
    SAPDBTRACE_ROUTINE_DEBUG ("Log_History::CheckAndRemoveUnusedHistory", LogHistory_Trace, 5);

    if ( GetNumberOfHistoryFiles() > GetNumberOfMaxUsedHistoryFiles() )
    {
        bool       anythingRemoved;
        SAPDB_UInt fileno = 0;

        while ( m_Directory.GetNextUnusedFileNo(trans.trTaskId_gg00, fileno) )
        {
            if ( LogHistory_Trace.TracesLevel(6) )
                Kernel_VTrace() << "UNUSED HISTORY: REMOVE " << fileno;
            RemoveHistory (trans, fileno, RemoveUnused, IGarbColl, anythingRemoved);
            if ( IGarbColl.IsInterrrupted() )
            {
                m_Directory.ResetInProcess(trans.trTaskId_gg00, fileno);
                break;
            }
            m_Directory.Invalidate(trans.trTaskId_gg00, fileno);
        }
    }
}

/* --------------------------------------------------------------------------- */
bool Log_History::CheckAndStartMigrationIfNeeded (tgg00_TransContext &trans)
{
    SAPDBTRACE_METHOD_DEBUG ("Log_History::CheckAndStartMigrationIfNeeded", LogHistory_Trace, 5);
    // The call of this routine assumes that the caller knows that all history can be removed now.
    // Otherwise it would loop endless here, but the loop can be cancelled by request.

    Kernel_Migration::ChangeInfo &change =
        Kernel_IAdminConfig::Instance().MigrationHandler().SearchForChangeInfo ("historyRootIdCheck");

    /* PTS 1134856 FF */
    Kernel_Migration::ChangeInfo &changeRecreateIndex =
        Kernel_IAdminConfig::Instance().MigrationHandler().SearchForChangeInfo ("RecreateIndexForOmsKeyedObjects");

    if ( change.IsEnabled() || changeRecreateIndex.IsEnabled() )
    {
        pasbool &isCancelled = trans.trRteCommPtr_gg00->to_cancel;
        
        bd91StartOMSGarbageCollection (trans, false);
        if ( trans.trError_gg00 != e_ok )
            return false;
        
        RTE_Message( Log_Exception(__CONTEXT__,LOG_WAIT_FOR_REMOVE_HISTORY) );
    
        while ( AnyHistoryExists() && ! isCancelled )
            vsleep (trans.trTaskId_gg00, 20);
    
        if ( isCancelled )
        {
            RTE_Message( Log_Exception( __CONTEXT__, LOG_WAIT_FOR_REMOVE_HISTORY_CANCELLED,
                                        (AnyHistoryExists()?"exists":"does not exist") ) );
            isCancelled = false;
        }
        change.migrationEnabled = false;
        changeRecreateIndex.migrationEnabled = false;
    }
    return true;
}
