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

  module      : FBM_SequentialDataVolume.cpp

  -------------------------------------------------------------------------

  responsible : TorstenS

  author      : AlexanderK

  special area: FreeBlockManagement (FBM)
  description : 


  last changed: 2000-03-10  10:00
  see also    : 

  -------------------------------------------------------------------------

  copyright:    (c) 2000-2004 SAP AG



    ========== 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 "FreeBlockManagement/FBM_SequentialDataVolume.hpp"
#include "FreeBlockManagement/FBM_Dump.hpp"
#include "FreeBlockManagement/FBM_Exception.hpp"
#include "FreeBlockManagement/FBM_Messages.hpp"
#include "RunTime/RTE_Crash.hpp"
#include "RunTime/RTE_Message.hpp"


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

/*===========================================================================*
 *  CLASS METHOD DEFINITION                                                  *
 *===========================================================================*/

/*---------------------------------------------------------------------------*
 *  CLASS FBM_SequentialDataVolume                                              *
 *---------------------------------------------------------------------------*/

void
FBM_SequentialDataVolume::InitVolume ()
{
    SAPDBTRACE_ROUTINE_DEBUG  ("FBM_SequentialDataVolume::InitVolume", FBM_Trace, 5);

    SAPDBERR_ASSERT_STATE( 0 < m_NumBlocks );

    /* set members to their start values */
    m_LastUsedBlock                   = FBM_UNDEFINED;
    m_FirstFreeBlock                  = 0;
    m_NumBlocksUsed                   = 0;
    m_DeviceIsInCompressingMode       = false;

    /* check consistency of the device */
#   if COMPILEMODE_MEO00 >= QUICK_MEO00 
    if( FBM_Check.ChecksLevel( 5 ))
        Verify ();
#   endif
}

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

FBM_BlockState
FBM_SequentialDataVolume::GetBlockState(SAPDB_Int4 BlockNo) const
{
    if (FBM_UNDEFINED == m_LastUsedBlock)  // first time
    {
        return BlockState_Free;
    }

    if (BlockNo <= m_LastUsedBlock)
    {
        return BlockState_Occupied;
    }
    else
    {
        return BlockState_Free;
    }
}

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

void
FBM_SequentialDataVolume::SetBlockStateToFree (SAPDB_Int4 BlockNo)
{
    SAPDBERR_ASSERT_STATE (SAPDB_FALSE);

    --m_NumBlocksUsed;
    if (m_FirstFreeBlock > BlockNo) 
        m_FirstFreeBlock = BlockNo;
    
#       if COMPILEMODE_MEO00 >= QUICK_MEO00 
    if( FBM_Check.ChecksLevel( 5 ))
        Verify ();
#       endif
}

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

void
FBM_SequentialDataVolume::SetBlockStateToOccupied (SAPDB_Int4 BlockNo)
{
    ++m_NumBlocksUsed;
    if (m_LastUsedBlock < BlockNo)
        m_LastUsedBlock = BlockNo;
    
#       if COMPILEMODE_MEO00 >= QUICK_MEO00 
    if( FBM_Check.ChecksLevel( 5 ))
        Verify ();
#       endif
}

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

SAPDB_Int4
FBM_SequentialDataVolume::GetNumBlocksUsed() const
{
    return m_NumBlocksUsed;
}

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

SAPDB_Int4
FBM_SequentialDataVolume::GetNumBlocksFree() const
{
    return m_NumBlocks - m_NumBlocksUsed;
}

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

RTE_VolumeAccessMode
FBM_SequentialDataVolume::VolMode() const
{
    return m_VolMode;
}

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


SAPDB_Int4
FBM_SequentialDataVolume::GetMultFreeBlocks  (const SAPDB_Int4  NumBlocksWanted,
                                    SAPDB_Int4       &NumBlocksSupplied)
{
    SAPDBTRACE_ROUTINE_DEBUG  ("FBM_SequentialDataVolume::GetMultFreeBlocks", FBM_Trace, 5);

    SAPDB_Int4 FreeBlockNo;

    /* this routine is called to get  a cluster of free blocks.  */
    /* before the routine is called it is already obvious that   */
    /* there must be at least one free block on this device      */

    if ((NumBlocksWanted + m_LastUsedBlock + 1) >= m_NumBlocks)
    {
        NumBlocksSupplied = m_NumBlocks - 1 - m_LastUsedBlock;
    }
    else
    {
        NumBlocksSupplied = NumBlocksWanted;
    }
        
    FreeBlockNo     =  m_LastUsedBlock + 1;
    m_LastUsedBlock += NumBlocksSupplied;

    /* update counter of used blocks and free blocks in the current section */
    m_NumBlocksUsed += NumBlocksSupplied;

    /* check consistency of the device */
#   if COMPILEMODE_MEO00 >= QUICK_MEO00 
    if( FBM_Check.ChecksLevel( 5 ))
        Verify ();
#   endif

    return ( FreeBlockNo ) ;
}

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

SAPDB_Int4
FBM_SequentialDataVolume::GetFreeBlock  ()
{
    SAPDBTRACE_ROUTINE_DEBUG  ("FBM_SequentialDataVolume::GetFreeBlock", FBM_Trace, 5);

    SAPDB_Int4 FreeBlockNo;

    /* this routine is called to get the adress of a free block. */
    /* before the routine is called it is already obvious that   */
    /* there must be at least one free block on this device      */

    /* find free BlockNo */
    m_LastUsedBlock++;
    FreeBlockNo=m_LastUsedBlock;

    /* write found block no into vtrace */
    SAPDBTRACE_WRITELN( FBM_Trace, 5, "FreeSBlockNo: " << FreeBlockNo);

    /* update counter of used blocks and free blocks in the current section */
    ++m_NumBlocksUsed;

    /* check consistency of the device */
#   if COMPILEMODE_MEO00 >= QUICK_MEO00 
    if( FBM_Check.ChecksLevel( 5 ))
        Verify ();
#   endif

    return ( FreeBlockNo ) ;
}

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


void
FBM_SequentialDataVolume::GetDeviceStatistics (SAPDB_Int4 &NumBlocks,
                                     SAPDB_Int4 &NumBlocksFree,
                                     SAPDB_Int4 &NumBlockFreeAfterSVP) const
{
    NumBlocks            = m_NumBlocks;
    NumBlocksFree        = m_NumBlocks - m_NumBlocksUsed;
    NumBlockFreeAfterSVP = FBM_UNDEFINED;
}

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

void
FBM_SequentialDataVolume::Verify ()
{
    SAPDBTRACE_ROUTINE_DEBUG  ("FBM_SequentialDataVolume::Verify", FBM_Trace, 5);
}

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

void
FBM_SequentialDataVolume::Dump(
    Kernel_Dump  &dump,
    const SAPDB_Int4 devNo) const
{
    struct FBMDataDevice   fbmDev;

    fbmDev.dmpDevNo                           = devNo;
    fbmDev.dmpLastUsedBlock                   = m_LastUsedBlock;
    fbmDev.dmpFirstFreeBlock                  = m_FirstFreeBlock;
    fbmDev.dmpLastFragmentedBlock             = 0;
    fbmDev.dmpFirstFragmentedBlock            = 0;
    fbmDev.dmpNumBlocks                       = m_NumBlocks;
    fbmDev.dmpNumBlocksUsed                   = m_NumBlocksUsed;
    fbmDev.dmpNumBlocksMarkedForBackup        = 0;
    fbmDev.dmpNumBlocksFreeAfterSVP           = 0;
    fbmDev.dmpNumBlocksToAddUntilOptIsReached = 0;
    fbmDev.dmpNumberOfSections                = 0;
    fbmDev.dmpActBlockNoForBackup             = 0;
    fbmDev.dmpStartBlockNoToSearchFreeBlock   = 0;
    fbmDev.dmpDeviceIsInCompressingMode       = m_DeviceIsInCompressingMode;
    fbmDev.dmpFiller1                         = false;
    fbmDev.dmpFiller2                         = 0;

    dump.InsertEntry( Kernel_Dump::DmpFBMDataDevice,
                      Kernel_DumpPage::Entry( &fbmDev, sizeof( fbmDev )));
}
