/*!
  @file           Log_Page.cpp
  @author         UweH
  @author         MartinB
  @ingroup        Logging
  @brief          Handler for log pages
  @see            Kernel_IPage.html
                  Kernel_Page.html
                  Kernel_Page74.html

\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
*/

#include "Logging/Log_Page.hpp"
#include "Logging/Log_Exceptions.hpp"
#include "KernelCommon/Kernel_VTrace.hpp"
#include "SAPDBCommon/SAPDB_ToString.hpp"

//------------------------------------------------------------------------------

Log_Page::~Log_Page()
{
    if ( ! IsAssigned() || m_Frame.GetLength() == 0 )
        return;
        
    if ( LogPage_Check.ChecksLevel(5) )
    {
        if ( ! Verify() )
        {
            WriteToTrace();
            if ( LogPage_Check.ChecksLevel(6) )
                RTE_Crash(Log_Exception(__CONTEXT__, LOG_PAGE_VERIFY,
                                        SAPDB_ToString(ReadLastWriterIOSequenceNo())));
        }
    }
}

//------------------------------------------------------------------------------

SAPDB_Bool Log_Page::Verify() const
{
    if ( ! IsAssigned() )
        return true;
        
    if ( ! Kernel_Page74::Verify() )
        return false;
    
    if ( ReadPageType() != Kernel_LogPageType )
        return false;

    // Check length and alignment of log entries

    const SAPDB_UInt4* pEntrylength;
    OffsetType         firstfreeoffset = MinSpaceOffset();

    for ( OffsetType offset = sizeof(PersistentHeader);
                     offset < firstfreeoffset;
                     offset += CalcNearestAlignedSize(*pEntrylength) ) // PTS 1139685 mb 2005-01-12
    {
        pEntrylength =
        reinterpret_cast<const SAPDB_UInt4*>(m_Frame.GetPointer(offset,sizeof(SAPDB_UInt4)));

        if ( pEntrylength == NULL )
        {
            Kernel_VTrace() << "illegal pointer to length at offset: " << offset;
            return false;
        }
    }
    
    return true;
}

//------------------------------------------------------------------------------

void Log_Page::WriteToTrace() const
{
    Kernel_VTrace trace;
    
    trace << "------------- Log_Page::WriteToTrace() begin -------------------" << NewLine;
    trace << "LastWriteIOSequence: " << ReadLastWriterIOSequenceNo() << NewLine;
    if ( ReadPageType() == Kernel_LogPageType )
        trace << "PageType:         LogPage" << NewLine;
    else
        trace << "PageType:         invalid (" << ReadPageType() << ")" << NewLine;
    trace << "ParityAlgo:       " << ReadParityAlgorithm() << NewLine;
    if ( ReadParityFromHeader() == ReadParityFromTrailer() )
        trace << "ParityBytes:      ok" << NewLine;
    else
        trace << "ParityBytes:      " << ReadParityFromHeader() << "/" << ReadParityFromTrailer() << NewLine;
    // --------------
    trace << "Timestamp:        " << ReadDate() << "/" << ReadTime() << NewLine;
    trace << "QueueInfo:        " << ReadQueueID() << "." << ReadQueueIOSequenceNo() << NewLine;
    trace << "OffsetCount:      " << ReadOffsetCount()
          << " (FirstWriteIOSequence: " << ReadFirstWriterIOSequenceNo() << ")" << NewLine;
    trace << "FirstFreeOffset:  " << ReadFirstFreeOffset() << NewLine;

    OffsetType offset;
    
    trace << "OffsetList:";
    for (offset = LOG_PAGE_FIRST_OFFSET; offset <= ReadOffsetCount(); ++offset)
        trace << "offset (" << offset << "): " << ReadOffsetOnPage(offset) << NewLine;

    if ( LogPage_Trace.TracesLevel (8) )
    {
        const SAPDB_UInt4* entrylength;
        OffsetType         firstfreeoffset = ReadFirstFreeOffset();
        SAPDB_UInt         entryno         = 0;
    
        for ( offset = MinSpaceOffset();
              offset < firstfreeoffset;
              offset += CalcNearestAlignedSize(*entrylength) ) // PTS 1139685 mb 2005-01-12
        {
            entrylength =
            reinterpret_cast<const SAPDB_UInt4*>(m_Frame.GetPointer(offset,sizeof(SAPDB_UInt4)));
            if ( entrylength == NULL )
            {
                trace << "ptr entrylength is NULL offset = " << offset << NewLine;
                break;
            }
            if ( offset + *entrylength <= firstfreeoffset )
                trace << "#" << entryno << " @ " << offset << ", " << *entrylength << NewLine;
            else
                trace << "#" << entryno << " @ " << offset << ", " << *entrylength << "(" << firstfreeoffset-offset << ")" << NewLine;
            ++entryno;
        }
    }
    trace << "------------- Log_Page::WriteToTrace() end -------------------\n";
}

//------------------------------------------------------------------------------
void Log_Page::Truncate(Log_IOSequenceNo newLastIOSeq)
{
    while (!IsEmpty() && (ReadLastWriterIOSequenceNo() != newLastIOSeq))
    {
        if ( ReadOffsetCount() > 1 )
        {
            PersistentHeaderPtr()->m_OffsetCount -= 1;
            WriteWriterIOSequenceNo(ReadLastWriterIOSequenceNo() - 1 );
        }
        else
        {
            Clear();
        }
    }
    UpdateParity();
}


