/*!
    @file       IOMan_DataArea.hpp
    @author     TorstenS
    @ingroup    IOManagement
    @brief      This module is used to manage the data area.

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


#ifndef IOMAN_DATACONTROL_HPP
#define IOMAN_DATACONTROL_HPP



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

#include "gsp00.h"

#include "Container/Container_Vector.hpp"
#include "IOManager/IOMan_BlockAddress.hpp"
#include "IOManager/IOMan_DataVolume.hpp"
#include "IOManager/IOMan_PageFrameAllocator.hpp"
#include "IOManager/IOMan_Types.hpp"
#include "KernelCommon/Kernel_Common.hpp"
#include "SAPDBCommon/MemoryManagement/SAPDBMem_IRawAllocator.hpp"


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


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


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

/* -----------------------------------------------------------------------*/
/*!
    @class  IOMan_DataArea
    @brief  This class is used to manage the data area. The data area the
            the collectio of all data volumes and used to store data pages.
 */
/* -----------------------------------------------------------------------*/

class IOMan_DataArea
{
public:

    /* -----------------------------------------------------------------------*/
    /*!
       @brief   Defines abbreviation for a data volume collection
     */
    /* -----------------------------------------------------------------------*/

    typedef Container_Vector<IOMan_DataVolume>  DataVolumes;

    /* -----------------------------------------------------------------------*/
    /*!
       @brief   Defines abbreviation for a data volume collection iterator
     */
    /* -----------------------------------------------------------------------*/

    typedef DataVolumes::Iterator               Iterator;

    /* -----------------------------------------------------------------------*/
    /*!
      @brief   Defines abbreviation for a const data volume collection iterator
     */
    /* -----------------------------------------------------------------------*/

    typedef DataVolumes::ConstIterator          ConstIterator;

    /* -----------------------------------------------------------------------*/
    /*! @name Constructors and initialization */
    /*@{*/
    /* -----------------------------------------------------------------------*/

    /* -----------------------------------------------------------------------*/
    /*!
        @brief  Constructor
        @param  pageAllocator [in] Allocator for page frames
        @param  allocator     [in] Allocator
        @return none
     */
    /* -----------------------------------------------------------------------*/

    IOMan_DataArea(
        IOMan_PageFrameAllocator    &pageAllocator,
        SAPDBMem_IRawAllocator      &allocator )
    :
    m_PageAllocator( pageAllocator ),
    m_UsedVolumes( 0 ),
    m_ConfiguredVolumes( 0 ),
    m_TotalDataPages( 0 ),
    m_Volumes( allocator )
    {}

    /* -----------------------------------------------------------------------*/
    /*!
        @brief  This method is used to initialize the data control structures,
                i.e. to get the memory via the allocator.
        @param  taskId [in] Identification of the calling task
        @param  maxDataVolumes [in] Maximun number of data volumes.
        @return true if the initialization is succesful; else false
     */
    /* -----------------------------------------------------------------------*/

    SAPDB_Bool Initialize(
        const tsp00_TaskId  taskId,
        const SAPDB_Int     maxDataVolumes );

    /* -----------------------------------------------------------------------*/
    /*@}*/
    /* -----------------------------------------------------------------------*/

    /* -----------------------------------------------------------------------*/
    /*! @name Volume administration */
    /*@{*/
    /* -----------------------------------------------------------------------*/

    /* -----------------------------------------------------------------------*/
    /*!
        @brief  This method is used close all data volumes which are still
                in mode open.
        @param  taskId [in] Identification of the calling task
        @return none
     */
    /* -----------------------------------------------------------------------*/

    void CloseAll( const tsp00_TaskId taskId );

    /* -----------------------------------------------------------------------*/
    /*!
        @brief  This method is used to create, format and open all data 
                volumes being defined within the data base configuration file.
        @param  taskId [in] Identification of the calling task
        @param  pDBIdentifier [in] Unique data base identifier
        @return true means successful execution
     */
    /* -----------------------------------------------------------------------*/

    SAPDB_Bool CreateAll(
        const tsp00_TaskId  taskId,
        const SAPDB_Byte    *pDBIdentifier );

    /* -----------------------------------------------------------------------*/
    /*!
       @brief   This method is used to open all data volumes being configued
                in the data base configuration file.
       @param   taskId [in] Identification of the calling task
       @return  true means successful execution
     */
    /* -----------------------------------------------------------------------*/


    SAPDB_Bool OpenAll( const tsp00_TaskId taskId );

    /* -----------------------------------------------------------------------*/
    /*!
       @brief   This method is used to add a new data volume to the data
                base volume set in warm as in cold mode too.
       @param   taskId [in] Identification of the calling task.
       @param   bIsCold [in] Is data base state db_cold (opposite db_warm)
       @param   devName [in] Name of the new volume
       @param   devSize [in] Size of the new devsppace in pages
       @param   devNo [in] Logical indentifier of the volume
       @return  true means that add data volume was successful
     */
    /* -----------------------------------------------------------------------*/

    SAPDB_Bool AddVolume(
        const tsp00_TaskId      taskId,
        const SAPDB_Bool        bIsCold,
        tsp00_VFilename         &devName,
        const IOMan_BlockCount  devSize,
        const IOMan_DeviceNo    devNo );

    /* -----------------------------------------------------------------------*/
    /*@}*/
    /* -----------------------------------------------------------------------*/

    /* -----------------------------------------------------------------------*/
    /*! @name Volume access */
    /*@{*/
    /* -----------------------------------------------------------------------*/

    /* -----------------------------------------------------------------------*/
    /*!
        @brief  This method returns a volume handler for the given logical
                identifier. There is not check whether the given logical
                is valid.
        @param  devNo [in] Logical volume identifier
        @return (IOMan_DataVolume)
     */
    /* -----------------------------------------------------------------------*/

    IOMan_DataVolume & Get( const IOMan_DeviceNo devNo )
    {
        return( m_Volumes[ devNo - IOMan_DataArea::GetFirstDataVolumeNo() ] );
    }

    const IOMan_DataVolume & Get( const IOMan_DeviceNo devNo ) const
    {
        return( m_Volumes[ devNo - IOMan_DataArea::GetFirstDataVolumeNo() ] );
    }

    /* -----------------------------------------------------------------------*/
    /*@}*/
    /* -----------------------------------------------------------------------*/
    /* -----------------------------------------------------------------------*/
    /*! @name Iterator access */
    /*@{*/
    /* -----------------------------------------------------------------------*/

    /* -----------------------------------------------------------------------*/
    /*!
       @brief   This method is used to set an iterator to the first data
                volume. There is no check whether the first volume is valid.
       @return  Iterator/ConstIterator
     */
    /* -----------------------------------------------------------------------*/

    Iterator Begin()
    {
        return( m_Volumes.Begin() );
    }

    ConstIterator Begin() const
    {
        return( m_Volumes.Begin() );
    }

    /* -----------------------------------------------------------------------*/
    /*!
       @brief   This method is used to get an iterator pointing behind the 
                last valid data volume. Crazy isnt't it?
       @return  Iterator/ConstIterator
     */
    /* -----------------------------------------------------------------------*/

    Iterator End()
    {
        return( m_Volumes.End() );
    }

    ConstIterator End() const
    {
        return( m_Volumes.End() );
    }

    /* -----------------------------------------------------------------------*/
    /*!
       @brief   This method returns the identifier of the first data volume.
                It's not guaranteed that the returned volume identifier 
                specifies a volume which is online.
       @return  IOMan_DeviceNo
     */
    /* -----------------------------------------------------------------------*/

    static IOMan_DeviceNo GetFirstDataVolumeNo()
    {
        return( 1 ); // Volume counting starts with one
    }

    /* -----------------------------------------------------------------------*/
    /*!
       @brief   This method returns the next identifier of the data volume
                following the given data volume. It's not guaranteed that
                the returned volume identifier specifies a volume which
                is online.
       @param   devNo [in] Logical volume identifier
       @return  IOMan_DeviceNo
     */
    /* -----------------------------------------------------------------------*/

    IOMan_DeviceNo GetNextDataVolumeNo( const IOMan_DeviceNo devNo ) const
    {
        return( devNo + 1 );
    }

    /* -----------------------------------------------------------------------*/
    /*@}*/
    /* -----------------------------------------------------------------------*/

    /* -----------------------------------------------------------------------*/
    /*! @name Configuration and statistic information */
    /*@{*/
    /* -----------------------------------------------------------------------*/

    /* -----------------------------------------------------------------------*/
    /*!
       @brief   This method returns the number of data volumes configured 
                within the data base configuration file, i.e the number of 
                data volumes corresponding to a entry within the configuration 
                file. This number is also available if not all data volumes 
                are in mode open.
       @return  (SAPDB_Int)
     */
    /* -----------------------------------------------------------------------*/

    SAPDB_Int ConfiguredVolumes() const
    {
        return( m_ConfiguredVolumes );
    }

    /* -----------------------------------------------------------------------*/
    /*!
       @brief   This method is used to determine the logical identifier for
                a given data volume name. It is not needed that the data 
                volumes are in mode open.
       @param   devName [in] Name of the searched volume
       @param   devNo [out] Logical identifier of the volume
       @return  true means volume was found; else false
     */
    /* -----------------------------------------------------------------------*/


    SAPDB_Bool GetVolumeNo(
        tsp00_VFilename   &devName,
        IOMan_DeviceNo    &devNo ) const;

    /* -----------------------------------------------------------------------*/
    /*!
       @brief   This method returns the maximun number of configurable data 
                volumes. This value is stored within the data base configuration
                file.
       @return  (SAPDB_Int) Maximun number of configurable data volumes.
     */
    /* -----------------------------------------------------------------------*/

    SAPDB_Int MaxVolumes() const
    {
        return( m_Volumes.GetCapacity() );
    }

    /* -----------------------------------------------------------------------*/
    /*!
       @brief   This method returns the sum of all pages storable within all 
                configured data volumes. This value doesn't include the pages
                needed for administrativ purpose, i.e IOMan_InfoPage.
                This value is only available if all
                data volumes are in mode open.
       @return  IOMan_BlockCount
     */
    /* -----------------------------------------------------------------------*/

    IOMan_BlockCount  TotalUsableDataPages() const
    {
        return( m_TotalDataPages );
    }

    /* -----------------------------------------------------------------------*/
    /*!
       @brief   This method returns the sum of all pages storable within all 
                configured data volumes. This value includes all pages of
                all data volumes without taking amount of pages reserved 
                for administrative purposes. This value is only available if 
                all data volumes are in mode open.
       @return  SAPDB_Int4
     */
    /* -----------------------------------------------------------------------*/

    SAPDB_Int4 TotalDataPages() const
    {
        return( TotalUsableDataPages() + UsedVolumes() );
    }

    /* -----------------------------------------------------------------------*/
    /*!
       @brief   This method returns the number of data volumes which are 
                currently in mode open. Usualy all configured data volumes 
                are still in mode open.
       @return  (SAPDB_Int)
     */
    /* -----------------------------------------------------------------------*/


    SAPDB_Int UsedVolumes() const
    {
        return( m_UsedVolumes );
    }

    /* -----------------------------------------------------------------------*/
    /*!
       @brief   This method checks the validity of the given data volume id.
       @param   devNo [in] Logical volume identifier
       @return  SAPDB_Bool
     */
    /* -----------------------------------------------------------------------*/

    SAPDB_Bool IsDataVolumeNoValid( const IOMan_DeviceNo devNo ) const
    {
        if(( IOMan_DataArea::GetFirstDataVolumeNo() > devNo ) || ( devNo > MaxVolumes()))
            return( SAPDB_FALSE );
        else
            return( SAPDB_TRUE );
    }

    /* -----------------------------------------------------------------------*/
    /*!
       @brief   This method returns whether the given data volume is in
                state online.
       @param   devNo [in] Logical volume identifier
       @return  SAPDB_Bool
     */
    /* -----------------------------------------------------------------------*/

    SAPDB_Bool IsDataVolumeOnline( const IOMan_DeviceNo devNo ) const
    {
        if( ! IsDataVolumeNoValid( devNo ) )
            return( SAPDB_FALSE );

        return( Get( devNo ).IsOnline() );
    }

    /* -----------------------------------------------------------------------*/
    /*@}*/
    /* -----------------------------------------------------------------------*/

private:

    /* -----------------------------------------------------------------------*/
    /*!
       @brief   This method is used to check the previous and next linkage
                of the given volume. If the logical linkage is corrupted the
                data base will crash.
                state online.
       @param   taskId     [in] Identification of the calling task
       @param   prevVolume [in] previous volume 
       @param   volume     [in] current volume 
       @return  void
     */
    /* -----------------------------------------------------------------------*/

    void CreateLinkage(
        const tsp00_TaskId  taskId,
        IOMan_DataVolume  &prevVolume,
        IOMan_DataVolume  &volume );

    /* -----------------------------------------------------------------------*/
    /*!
       @brief   This method is used to the access to the predecessor and 
                successor of the given volume. If a no successor or predecessor
                is available NULL ist returned; else a pointer to the dbIdentifier 
                is returned.
       @param   volume      [in] current volume 
       @param   pPrevVolume [out] previous volume 
       @param   pNextVolume [out] next volume 
       @return  (SAPDB_Byte*) dbIdentifier
     */
    /* -----------------------------------------------------------------------*/

    const SAPDB_Byte *DetermineLinkage(
        const IOMan_DataVolume    &volume,
        IOMan_DataVolume          **pPrevVolume,
        IOMan_DataVolume          **pNextVolume );


    /// Copy and assignment operator are not supported

    /* -----------------------------------------------------------------------*/
    /*!
       @brief   The assignment operator is not supported to avoid not allowed
                duplicates.
       @param   dataControl [in] dataControl 
       @return  dataControl&
     */
    /* -----------------------------------------------------------------------*/

    IOMan_DataArea& operator=( const IOMan_DataArea &dataControl );

    /* -----------------------------------------------------------------------*/
    /*!
       @brief   The copy operator is not supported to avoid not allowed
                duplicates.
       @param   dataControl [in] dataControl 
       @return  dataControl&
     */
    /* -----------------------------------------------------------------------*/

    IOMan_DataArea( const IOMan_DataArea &dataControl );

private:

    /* -----------------------------------------------------------------------*/
    /*!
        @brief  Allocator for page frames. The page frame size is defined by
                the data base configuration file.
     */
    /* -----------------------------------------------------------------------*/

    IOMan_PageFrameAllocator    &m_PageAllocator;

    /* -----------------------------------------------------------------------*/
    /*!
        @brief  The number of data volumes which are currently in mode
                open. Usualy all configured data volumes are still in
                mode open.
     */
    /* -----------------------------------------------------------------------*/

    SAPDB_Int   m_UsedVolumes;

    /* -----------------------------------------------------------------------*/
    /*!
        @brief  The number of data volumes configured within the data
                base configuration file, i.e the number of data volumes
                corresponding to a entry within the configuration file.
                This number is also available if not all data volumes are
                in mode open.
     */
    /* -----------------------------------------------------------------------*/

    SAPDB_Int4  m_ConfiguredVolumes;

    /* -----------------------------------------------------------------------*/
    /*!
        @brief  The sum of all pages storable within all configured
                data volumes. This value is only available if all
                data volumes are in mode open.
     */
    /* -----------------------------------------------------------------------*/

    IOMan_BlockCount  m_TotalDataPages;

    /* -----------------------------------------------------------------------*/
    /*!
        @brief  Collection of data volumes. 
     */
    /* -----------------------------------------------------------------------*/

    DataVolumes   m_Volumes;
};




#endif  /* IOMAN_DATACONTROL_HPP */
