/*!
  @file     FrameCtrl_Manager.cpp
  @author   TorstenS
  @ingroup  FrameControl
  @brief    This class is used to handle i/o capable memory request

\if EMIT_LICENCE
    ========== licence begin  GPL
    Copyright (c) 2001-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
*/



/*===========================================================================*
 *  INCLUDES                                                                 *
 *===========================================================================*/

#include "hbd20_3.h"

#include "FrameControl/FrameCtrl_Manager.hpp"
#include "FrameControl/FrameCtrl_Messages.hpp"
#include "FrameControl/FrameCtrl_Exception.hpp"
#include "KernelCommon/ParameterNames/KernelParam_FrameControl.hpp"
#include "RunTime/RTE_Crash.hpp"
#include "RunTime/MemoryManagement/RTEMem_Allocator.hpp"
#include "RunTime/MemoryManagement/RTEMem_PageAllocator.hpp"
#include "RunTime/MemoryManagement/RTEMem_AWEAllocator.hpp"
#include "RunTime/Configuration/RTEConf_ParameterAccess.hpp"
#include "RunTime/Configuration/RTEConf_ParameterAccessKernelInterface.hpp"
#include "SAPDBCommon/SAPDB_ToString.hpp"

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


/*===========================================================================*
 *  MACROS                                                                   *
 *===========================================================================*/



/*===========================================================================*
 *  LOCAL CLASSES, STRUCTURES, TYPES, UNIONS ...                             *
 *===========================================================================*/



/*===========================================================================*
 *  STATIC/INLINE FUNCTION PROTOTYPES                                        *
 *===========================================================================*/

/* -----------------------------------------------------------------------*/
/*!
    @brief  This method is used to get the configured value for a given 
            integer configuration parameter from the configuration file.
    @return (SAPDB_UInt) configuration value
 */
/* -----------------------------------------------------------------------*/

static SAPDB_UInt
GetConfiguredValue( const RTEConf_Parameter::Name paramName )
{
    RTEConf_Parameter::Integer  paramValue;
    SAPDBErr_MessageList        errMsg;

    if( ! RTEConf_ParameterAccess::Instance()->GetInteger(
                paramName, paramValue, errMsg ))
    {
        RTE_Crash( errMsg );
    }
    return( ( SAPDB_UInt ) paramValue );
}

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

FrameCtrl_Manager*  FrameCtrl_Manager::m_Instance = NULL;

/*===========================================================================*
 *  METHODS                                                                  *
 *===========================================================================*/

FrameCtrl_Manager::FrameCtrl_Manager()
        :
        m_Capacity( 0 ),
        m_PageSize( GetConfiguredValue( UTF8( KERNELPARAM_PAGE_SIZE ))),
        m_CheckedOutByConverter( 0 ),
        m_CheckedOutByDataCache( 0 ),
        m_CheckedOutByLogQueue( 0 ),
        m_CheckedOutByIOManagement( 0 )
{};

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

bool
FrameCtrl_Manager::CreateInstance()
{
    SAPDBTRACE_ROUTINE_DEBUG( "FrameCtrl_Manager::CreateInstance", FrameCtrl_Trace, 5 );

    SAPDBERR_ASSERT_STATE( NULL == m_Instance );

    if ( NULL != m_Instance )
        return( true );

    m_Instance = new( RTEMem_Allocator::Instance() ) FrameCtrl_Manager();

    if( NULL == m_Instance)
        return( false );

    m_Instance->Initialize();

    return( true );
}

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

SAPDB_UInt
FrameCtrl_Manager::GetFreeFrameCount() const
{
    SAPDB_UInt FreePages;

    if ( true == RTEMem_AWEAllocator::Instance().AWEAvailable() )
        FreePages = RTEMem_AWEAllocator::Instance().NumOfFreeMapAreaPages();
    else
        FreePages = ( SAPDB_UInt ) RTEMem_PageAllocator::Instance().GetFreePages();

    return( FreePages );
}

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

void
FrameCtrl_Manager::New(
    const FrameCtrl_RegistrationKey   registrationKey,
    const tsp00_TaskId                taskId,
    Kernel_IPage::PageFrame           &frame,
    SAPDB_UInt4                       &aweBlockNo )
{
    SAPDBTRACE_ROUTINE_DEBUG( "FrameCtrl_Manager::New", FrameCtrl_Trace, 5 );

    void *pFrame = NULL;

    if ( true == RTEMem_AWEAllocator::Instance().AWEAvailable() )
        pFrame = RTEMem_AWEAllocator::Instance().Allocate( &aweBlockNo );
    else
        pFrame = RTEMem_PageAllocator::Instance().Allocate( m_PageSize );

    if( NULL != pFrame )
    {
        SAPDBTRACE_WRITELN( FrameCtrl_Trace, 5,
                            "Provide Memory " << SAPDB_ToString( pFrame, _T_x ) << " From Page Pool" );
    }
    else if( FrameCtrl_DataCacheKey != registrationKey )
    {
        pFrame = bd20ReduceDataCache( taskId );
        if( NULL != pFrame )
        {
            --m_CheckedOutByDataCache;

            SAPDBTRACE_WRITELN( FrameCtrl_Trace, 5,
                                "Provide Memory " << SAPDB_ToString( pFrame, _T_x ) << " From Data Cache" );
        }
    }

    if( NULL == pFrame )
    {
        FrameCtrl_Exception errMsg( __CONTEXT__, FRAME_CTRL_NO_MORE_FRAMES );
        RTE_Crash( errMsg );
    }

    MaintainInternalCounter( registrationKey );

    frame.Assign( pFrame, m_PageSize );
}

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

void
FrameCtrl_Manager::Free(
    const FrameCtrl_RegistrationKey registrationKey,
    const tsp00_TaskId              taskId,
    Kernel_IPage::PageFrame         &frame )
{
    SAPDBTRACE_ROUTINE_DEBUG( "FrameCtrl_Manager::Free", FrameCtrl_Trace, 5 );

    SAPDBERR_ASSERT_STATE( frame.GetLength() == m_PageSize );
    SAPDBERR_ASSERT_STATE( NULL != frame.GetPointer( 0, m_PageSize ));

    if ( true == RTEMem_AWEAllocator::Instance().AWEAvailable())
        RTEMem_AWEAllocator::Instance().Deallocate( frame.GetPointer( 0, m_PageSize ));
    else
        RTEMem_PageAllocator::Instance().Deallocate( frame.GetPointer( 0, m_PageSize ));

    frame.Deassign();

    MaintainInternalCounter( registrationKey, false );
}

/*----------------------------- Private Methods -----------------------------*/

void
FrameCtrl_Manager::MaintainInternalCounter(
    const FrameCtrl_RegistrationKey registrationKey,
    const SAPDB_Bool                bIncrementCounter )
{
    // Note that the counters are modified dirty

    switch( registrationKey )
    {
    case FrameCtrl_ConverterKey:
        if( bIncrementCounter )
            ++m_CheckedOutByConverter;
        else
            --m_CheckedOutByConverter;
        break;
    case FrameCtrl_DataCacheKey:
        if( bIncrementCounter )
            ++m_CheckedOutByDataCache;
        else
            --m_CheckedOutByDataCache;
        break;
    case FrameCtrl_LogKey:
        if( bIncrementCounter )
            ++m_CheckedOutByLogQueue;
        else
            --m_CheckedOutByLogQueue;
        break;
    case FrameCtrl_IOManagementKey:
        if( bIncrementCounter )
            ++m_CheckedOutByIOManagement;
        else
            --m_CheckedOutByIOManagement;
        break;
    case FrameCtrl_FileDirectoryKey:
        if( bIncrementCounter )
            ++m_CheckedOutByFileDirectory;
        else
            --m_CheckedOutByFileDirectory;
        break;
    case FrameCtrl_RestartPageKey:
        if( bIncrementCounter )
            ++m_CheckedOutByRestartRecord;
        else
            --m_CheckedOutByRestartRecord;
    default:;
    };

    SAPDBTRACE_WRITELN( FrameCtrl_Trace, 5, "Statistic: " << NewLine <<
                        "Total Frames: "        << m_Capacity <<
                        " UsedByConverter:    " << m_CheckedOutByConverter     <<
                        " UsedByDataCache:    " << m_CheckedOutByDataCache     <<
                        " UsedByLogQueue:     " << m_CheckedOutByLogQueue      <<
                        " UsedByIOManagement: " << m_CheckedOutByIOManagement  <<
                        " UsedByFDir:         " << m_CheckedOutByFileDirectory <<
                        " UsedByRestart       " << m_CheckedOutByRestartRecord <<
                        " Available: "       << GetFreeFrameCount() );
}

/*---------------------------------------------------------------------------*/
/*-------------- Implementation of Interface Instance methods ---------------*/
/*---------------------------------------------------------------------------*/

FrameCtrl_ICommon&
FrameCtrl_ICommon::GetInstance()
{
    return( FrameCtrl_Manager::GetInstance() );
}

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

FrameCtrl_IConverter&
FrameCtrl_IConverter::GetInstance()
{
    return( FrameCtrl_Manager::GetInstance() );
}

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

FrameCtrl_IDataCache&
FrameCtrl_IDataCache::GetInstance()
{
    return( FrameCtrl_Manager::GetInstance() );
}

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

FrameCtrl_IFileDirectory&
FrameCtrl_IFileDirectory::GetInstance()
{
    return( FrameCtrl_Manager::GetInstance() );
}

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

FrameCtrl_IIOManager&
FrameCtrl_IIOManager::GetInstance()
{
    return( FrameCtrl_Manager::GetInstance() );
}

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

FrameCtrl_ILog&
FrameCtrl_ILog::GetInstance()
{
    return( FrameCtrl_Manager::GetInstance() );
}

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

FrameCtrl_IRestartPage&
FrameCtrl_IRestartPage::GetInstance()
{
    return( FrameCtrl_Manager::GetInstance() );
}


/*===========================================================================*
 *  END OF CODE                                                              *
 *===========================================================================*/
