/****************************************************************************

  module      : vbd13.cpp

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

  responsible : TorstenS

  special area: nodehandling
  description : Implements the node handling inclusive waiting conditions

  last changed: 2000-10-05  9:03
  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 "gsp00.h"    // All Types
#include "gsp03_3.h"

#include "Converter/Converter_IPageNoManager.hpp"
#include "Converter/Converter_ICommon.hpp"
#include "Converter/Converter_Version.hpp"
#include "DataAccess/Data_BasePage.hpp"
#include "DataAccess/Data_Exceptions.hpp"
#include "DataAccess/Data_Messages.hpp"
#include "DataAccess/Data_Types.hpp"
#include "IOManager/IOMan_Types.hpp"
#include "IOManager/IOMan_BlockAddress.hpp"
#include "IOManager/IOMan_IDataIO.hpp"
#include "KernelCommon/Kernel_Common.hpp"
#include "KernelCommon/Kernel_FileIO.hpp"
#include "SAPDBCommon/SAPDB_ToString.hpp"
#include "RunTime/RTE_Message.hpp"
#include "Trace/Trace_PageNoEntry.hpp"

#include "ggg00.h"    // Kernel Types
#include "ggg01.h"    // OMS errors
#include "gbd00.h"    // BD Types
#include "gbd02.h"    // Datacache Types
#include "gbd499.h"   // IndexMemoryManagementUnit
#include "ggg91.h"    // Fileversion

#include "hbd01.h"
#include "hbd01_1.h"
#include "hbd06.h"
#include "hbd13.h" 
#include "hbd17.h"
#include "hbd20.h"
#include "hbd30.h"
#include "hbd73.h"
#include "hgg01_1.h" 
#include "hgg01_3.h" 
#include "hgg04.h" 
#include "hgg17.h"
#include "ggg92.h"    // used by hgg06.h
#include "hgg06.h"
#include "SAPDB/SAPDBCommon/SAPDB_RangeCode.hpp" // Kernel_move_and_fill
#include "hgg10.h"
#include "hsp30.h"
#include "heo55k.h"   // excl
#include "heo56.h"    // vsuspend
#include "heo670.h"   // eo670_CTraceStack

#if COMPILEMODE_MEO00 >= SLOW_MEO00
#include "hta99.h"
#endif

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


#ifdef SAPDB_SLOW
#define SUSP_RES  true
#endif

#define IS_READ           true
#define IS_VIRTUAL        true
#define NEW_NODE          true

#define WAIT_FOR_SVP_PREP   "B13WAIT FOR SVP PREPARE "
#define WAIT_FOR_READ       "B13WAIT FOR READ        "
#define WAIT_FOR_WRITE      "B13WAIT FOR WRITE       "
#define WAIT_FOR_BD_LOCK    "B13WAIT FOR BD LOCK     "
#define WAIT_FOR_SVP_END    "B13WAIT FOR SVP END     "

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



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


#ifdef SAPDB_SLOW
class cbd13_CheckNodeTrace
{
public:
    cbd13_CheckNodeTrace (tgg00_BasisError &TrError,
                          tsp00_PageNo      CurrRoot,
                          tsp00_PageNo      NodeRoot);

    ~cbd13_CheckNodeTrace();

private:
    tgg00_BasisError    &m_TrError;
};
#endif

/*===========================================================================*
 *  STATIC/INLINE FUNCTIONS (PROTOTYPES)                                     *
 *===========================================================================*/


#ifdef SAPDB_SLOW

inline
cbd13_CheckNodeTrace::cbd13_CheckNodeTrace (tgg00_BasisError &TrError,
        tsp00_PageNo      CurrRoot,
        tsp00_PageNo      NodeRoot):
        m_TrError (TrError)
{
    t01p2int4 (bd_io, "NodeRoot    ",NodeRoot, "CurrRoot    ", CurrRoot);
};

#endif

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

#ifdef SAPDB_SLOW

inline
cbd13_CheckNodeTrace::~cbd13_CheckNodeTrace ()
{
    t01basis_error (bi, "bd13chk Node", m_TrError);
};

#endif

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

inline
tbd02_RecoveryMode
bd13_GetRecoveryMode( const tgg00_FileId    &fileId )
{
    if( gg04IsPermStaticTfn( fileId.fileTfn_gg00()))
    {
        SAPDBERR_ASSERT_STATE( fileId.fileType_gg00().includes( ftsObject_egg00 ));

        return( tbd02_RecoveryMode::fromConst( rmPermStatic_ebd02 ));
    }
    else if( fileId.fileType_gg00().includes( ftsTemp_egg00 )) // PTS 1123689 TS 2003-08-20
    {
        return( tbd02_RecoveryMode::fromConst( rmTemp_ebd02 ));
    }
    else
    {
        SAPDBERR_ASSERT_STATE( fileId.fileType_gg00().includes( ftsPerm_egg00 ) ||
                               fileId.fileType_gg00().includes( ftsByteStr_egg00 ));

        return( tbd02_RecoveryMode::fromConst( rmPermDynamic_ebd02 ));
    }
}

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

void
bd13_BadDataPageHandling(
    tgg00_TransContext  &trans,
    const tgg00_FileId  &fileId,
    const tsp00_PageNo  pageNo );

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

void
bd13_IllegalPageNoHandling(
    tgg00_TransContext          &trans,
    const tgg00_FileId          &fileId,
    const tsp00_PageNo          pageNo,
    const tbd02_RecoveryMode    recMode );

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

inline void
bd13_MsgAndSuspend(
    tgg00_TransContext              &trans,
    const tsp00_PageNo              pageNo,
    const tgg00_VtraceType_Param    traceType,
    const char                      *msgText, // tsp00_C24
    const tsp00_Int4                suspendReason );

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

inline void
bd13_MsgAndSuspendForPageLockReq(
    tgg00_TransContext              &trans,
    tgg00_FileId                    &fileId,
    const tsp00_PageNo              pageNo,
    const tbd_node_request_Param    nodeReq,
    const SAPDB_Bool                bIsRoot );

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

inline void
bd13_InitPageState(
    tbd02_CachePageState            &nodeState,
    const tbd00_PageLockMode_Param  pageLockMode,
    bool                            &bIsFirstInit );

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

inline void
bd13_OverflowReaction (
    const tsp00_TaskId          TaskId,
    const tsp00_PageNo          PageNo,
    const tgg00_MessType        actionType,
    const tsp00_Int4            SuspendReason,
    tgg00_BasisError            &TrError,
    tsp00_Int                   &RetryCount );

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

#ifdef SAPDB_SLOW
inline void
bd13_GetNodeTraceInfo(
    const tsp00_PageNo              pageNo,
    const tbd02_RecoveryMode        recMode,
    const SAPDB_Bool                bIsRoot,
    const tbd_node_request_Param    nodeRequest );
#endif

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

/*===========================================================================*
 *  LOCAL FUNCTIONS (PROTOTYPES)                                             *
 *===========================================================================*/

void
bd13_CheckNodeHeader(
    const tgg00_FileId    &FileId,
    tsp00_PageNo          PageNo,
    const tbd_nodeptr     Nptr,
    tgg00_BasisError      &TrError );

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

void
bd13_CheckRootNodeHeader(
    const tgg00_FileId  &FileId,
    const tbd_nodeptr    Nptr,
    tgg00_BasisError    &TrError );

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

void
bd13_CheckNodeErrorHandling(
    const tsp00_TaskId          taskId,
    const tgg00_BasisError      trError,
    const tbd_nodeptr           &pNode,
    const tbd02_RecoveryMode    recMode,
    const tsp00_Int4            value );

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

void
bd13_FrameForNewNode(
    const tsp00_Int2          LevelNo,
    tsp00_PageNo              NewPageNo,
    const tbd02_RecoveryMode  recMode,
    tbd_node_ptrs             &Nptrs,
    tbd_current_tree          &Current);

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

void
bd13_FreeNode(
    tbd_current_tree            &current,
    const tsp00_PageNo          pageNo,
    const tbd02_RecoveryMode    recMode,
    const Converter_Version     &pageConverterVersion );

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

void
bd13_WriteOldOccupant(
    tgg00_TransContext         &Trans,
    tbd_nodeptr                 pNode,
    tbd_nodeptr                 pCblock,
    tsp00_PageNo                PageNo,
    const tbd02_RecoveryMode    recMode,
    tbd02_CachePageState       &NodeState,
    tsp00_Bool                  NewNode );

/*===========================================================================*
 *  GLOBAL FUNCTIONS (CODE)                                                  * 
 *===========================================================================*/

externC void
bd13GetNode (tbd_current_tree         &Current,
             tsp00_PageNo              PageNo,
             tbd00_PageLockMode_Param  PageLockMode,
             tbd_node_request_Param    NodeReq,
             tbd_node_ptrs            &Nptrs)

{
    ROUTINE_DBG_MEO00 ("bd13GetNode");


    bool                        IsRoot       = (PageNo == Current.curr_tree_id.fileRoot_gg00());
    bool                        bPageRead    = false;
    bool                        UnlockDone   = false;
    bool                        bIsFirstInit = true;
    tsp00_Int                   RetryCount   = 0;
    tbd02_CachePageState        NodeState;
    tgg00_BasisError            &TrError     = Current.curr_trans->trError_gg00;
    tgg00_TransContext          &CurrTrans   = *Current.curr_trans;
    tgg00_FileId                &CurrFileId  = Current.curr_tree_id;
    const tsp00_TaskId          &TaskId      = CurrTrans.trTaskId_gg00;
    const tbd02_RecoveryMode    recMode      = bd13_GetRecoveryMode( CurrFileId );

    if  ((IsRoot) && (NULL != Current.currRootNptrs_bd00.np_ptr()))
    {
        Nptrs = Current.currRootNptrs_bd00;
        bd20CheckRootNptrs( TaskId, TrError, PageNo, Nptrs.np_ptr(), Nptrs.np_cbptr() );
        return;
    }

    if( NULL != Current.currIndexNptrs_bd00.np_ptr() &&
            PageNo == Current.currIndexNptrs_bd00.np_ptr()->nd_id())
    {
        Nptrs = Current.currIndexNptrs_bd00;
        return;
    }

    Nptrs.np_cbptr() = NULL;
    Nptrs.np_ptr()   = NULL;

#   ifdef SAPDB_SLOW
    bd13_GetNodeTraceInfo( PageNo, recMode, IsRoot, NodeReq );
    t01int4( bd_io, "CurrCounter ", Current.currCounter_bd00 );
#   endif

    if ( plmLockForSplit_ebd00 == PageLockMode || plmLockForSplitNoWait_ebd00 == PageLockMode) /* PTS 1108703 UH 2000-12-12 */
        NodeState.cpsSynchSvpAndTreeSplits_bd02.becomes(synchCheckPreventSplit_ebd02);
    else
        NodeState.cpsSynchSvpAndTreeSplits_bd02.becomes(synchNone_ebd02);

    while (e_ok == TrError)
    {
        bd13_InitPageState (NodeState, PageLockMode, bIsFirstInit);

        bd20GetPage( TaskId, CurrTrans.trWaitContext_gg00, // UH 2003-02-26
                     TrError, CurrTrans.trBdExclFileLocks_gg00, CurrFileId, PageNo,
                     recMode, NodeReq, Nptrs.np_ptr(), Nptrs.np_cbptr(), NodeState );

        if  (e_ok != TrError)
        {
            // data cache overflow handling
            if ((e_sysbuffer_overflow == TrError) || (e_no_more_temp_space == TrError))
            {
                bd13_OverflowReaction( TaskId, PageNo, Current.curr_action, 43, TrError, RetryCount );
                continue;
            }
            break; // fatal error has occured
        }

        // data cache synchronisation with savepoint prepare phase
        if (synchWait_ebd02 == NodeState.cpsSynchSvpAndTreeSplits_bd02)
        {
            bd13_MsgAndSuspend (CurrTrans, PageNo, b_await_r, WAIT_FOR_SVP_PREP, 230);
            NodeState.cpsSynchSvpAndTreeSplits_bd02.becomes(synchCheckPreventSplit_ebd02);
            continue;
        }

        // data cache contains requested page
        if  (NodeState.cpsFound_bd02)
        {
            // requested page is still in read IO by another task
            if  (NodeState.cpsDirty_bd02)
            {
                bd13_MsgAndSuspend (CurrTrans, PageNo, b_await_r, WAIT_FOR_READ, 41);
                continue;
            }

            // requested page is locked by another task
            if  (NodeState.cpsHaveToWaitForLock_bd02)
            {
                bd13_MsgAndSuspendForPageLockReq( CurrTrans, CurrFileId, PageNo, NodeReq, IsRoot );
                continue;
            }

            // requested page is available
            if  (CurrTrans.trRteCommPtr_gg00->virt_reads < MAX_INT2_SP00)
            {
                ++CurrTrans.trRteCommPtr_gg00->virt_reads;
            }
            if (Nptrs.np_ptr() != NULL)
            {
                bd73DataIOStatistic (Nptrs.np_ptr()->nd_level(), CurrFileId.fileTfn_gg00(), IS_VIRTUAL, IS_READ);
            }
            break;
        }

        // data cache doesn't contains requested page

        // requested page is still in write IO by another task
        if  (NodeState.cpsWaitForWrite_bd02)
        {
            bd13_MsgAndSuspend (CurrTrans, PageNo, b_await_w, WAIT_FOR_WRITE, 42);
            continue;
        }

        // in special cases release bd lock on requested page during page will be read by own task

        if
        (
            ( Current.currUnlockAllowed_bd00                                ) &&
            ( nr_for_read == NodeReq                                        ) &&
            ( NULL != Current.currIndexNptrs_bd00.np_ptr()                  ) && // for leaves only
            ( bd20IsPageShareLocked( Current.currIndexNptrs_bd00.np_cbptr())) && //  ----- " ------
            (
                (tfnTable_egg00     == CurrFileId.fileTfn_gg00()) ||
                (tfnShortScol_egg00 == CurrFileId.fileTfn_gg00())
            )
        )
        {
            UnlockDone = true; // indicate that the bd lock is released
            bd30ReleaseTree( Current );
        }

        // before reading the request page into the data cache the assigned
        // data cache frame has to be written onto disk, because the page on
        // the frame is changed.
        if  (NodeState.cpsDirty_bd02)
        {
            bd13_WriteOldOccupant( CurrTrans, Nptrs.np_ptr(), Nptrs.np_cbptr(),
                                   PageNo, recMode, NodeState, !NEW_NODE );
        }
        {
            // perform the read IO for the requested page
            bPageRead = true; // needed to handle the assigned data cache frame
            Data_BasePage Page( Nptrs.np_ptr(), rmPermStatic_ebd02 != recMode,
                                rmTemp_ebd02 == recMode, Nptrs.np_cbptr() );

            const IOMan_ReturnCode retCode =
                IOMan_IDataIO::GetInstance().ReadDataPage( TaskId, Page, PageNo );

            switch( retCode )  // PTS 1127038 TS 2004-02-06
            {
            case IOMan_NoConverterEntry:
                {
                    TrError = e_no_converter_entry;
                    break;
                }
            case IOMan_PageNoOutOfRange:
                {
                    bd13_IllegalPageNoHandling( CurrTrans, CurrFileId, PageNo, recMode );
                    break; // could be a fatal error
                }
            case IOMan_BadDataPage:
                {
                    bd13_BadDataPageHandling( CurrTrans, CurrFileId, PageNo );
                    break; // fatal error has occured
                }
            default:
                ;
            }
        }

        if( e_ok == TrError )
            bd73DataIOStatistic (Nptrs.np_ptr()->nd_level(), CurrFileId.fileTfn_gg00(), !IS_VIRTUAL, IS_READ);

        break;
    };
    // end data cache overflow loop

    if  (
        (NULL != Nptrs.np_ptr()              ) &&
        (e_ok == TrError                     ) &&
        (NodeReq != nr_for_upd_ret_if_blocked)
    )
        bd13_CheckNodeHeader( CurrFileId, PageNo, Nptrs.np_ptr(), TrError );

    // handle assigned data cache frame in case of user triggered read IO
    if( bPageRead )
    {
        if( e_ok == TrError )
        {
            if( UnlockDone )
                TrError = e_bd_leaf_unlocked;

            bd20UsePage( TaskId, TrError, PageNo, recMode,  Nptrs.np_cbptr(), NodeReq, Nptrs.np_ptr() );
        }
        else
        {
            tgg00_BasisError AuxError = TrError;
            TrError                   = e_ok;

            bd20FreePage( TaskId, PageNo, recMode, TrError, CurrTrans.trBdExclFileLocks_gg00 );

            if( e_ok == TrError )
                TrError = AuxError;

            if  (
                ((e_no_converter_entry == TrError) || (e_page_in_wrong_tree == TrError))
                &&
                (!CurrFileId.fileType_gg00().includes (ftsTemp_egg00 ))
                &&
                (!CurrFileId.fileType_gg00().includes (ftsObject_egg00))
                &&
                (IsRoot)
            )
            {
                TrError = e_old_fileversion;
            }
            Nptrs.np_ptr()   = NULL;
            Nptrs.np_cbptr() = NULL;
        }
    }
    ++CurrTrans.trIoCount_gg00;

    if( Nptrs.np_ptr() != NULL )
        ++Current.currCounter_bd00;
};

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

externC void
bd13GetNewSpecifiedNode (
    tgg00_TransContext         &Trans,
    tgg00_FileId               &FileId,
    tsp00_PageNo               WantedPageNo,
    tbd_node_ptrs              &Nptrs,
    tsp00_Bool                 &bPageGenerated)
{
    ROUTINE_DBG_MEO00( "bd13GetNewSpecifiedNode" );


#   ifdef SAPDB_SLOW
    t01int4( bd_io, "GetStaticPno", WantedPageNo );
#   endif

    SAPDBERR_ASSERT_STATE( rmPermStatic_ebd02 == bd13_GetRecoveryMode( FileId ));

    bool                        bPageRead    = false;
    bool                        bIsFirstInit = true;
    tsp00_Int                   RetryCount   = 0;
    tbd02_CachePageState        NodeState;
    tgg00_BasisError            &TrError     = Trans.trError_gg00;
    const tsp00_TaskId          &TaskId      = Trans.trTaskId_gg00;
    const tbd02_RecoveryMode    recMode      = tbd02_RecoveryMode::fromConst( rmPermStatic_ebd02 );

    Nptrs.np_cbptr() = NULL;
    Nptrs.np_ptr()   = NULL;
    bPageGenerated   = false;
    NodeState.cpsSynchSvpAndTreeSplits_bd02.becomes(synchCheckPreventSplit_ebd02);


    while( e_ok == TrError )
    {
        bd13_InitPageState( NodeState, plmLockForSplit_ebd00, bIsFirstInit );

        bd20GetPage( TaskId, Trans.trWaitContext_gg00, // UH 2003-02-26
                     TrError, Trans.trBdExclFileLocks_gg00, FileId, WantedPageNo,
                     rmPermStatic_ebd02, nr_for_update, Nptrs.np_ptr(), Nptrs.np_cbptr(),
                     NodeState );

        if( e_ok != TrError )
        {
            // data cache overflow handling
            if(( e_sysbuffer_overflow == TrError ) || ( e_no_more_temp_space == TrError ))
            {
                bd13_OverflowReaction( TaskId, WantedPageNo,  tgg00_MessType::fromConst( m_nil ),
                                       43, TrError, RetryCount );
                continue;
            }
            break; // fatal error has occured
        }

        // data cache synchronisation with savepoint prepare phase
        if( synchWait_ebd02 == NodeState.cpsSynchSvpAndTreeSplits_bd02 )
        {
            bd13_MsgAndSuspend( Trans, WantedPageNo, b_await_r, WAIT_FOR_SVP_PREP, 230 );
            NodeState.cpsSynchSvpAndTreeSplits_bd02.becomes( synchCheckPreventSplit_ebd02 );
            continue;
        }
        // ==================================
        // data cache contains requested page
        // ==================================
        if( NodeState.cpsFound_bd02 )
        {
            // requested page is still in read IO by another task
            if( NodeState.cpsDirty_bd02 )
            {
                bd13_MsgAndSuspend( Trans, WantedPageNo, b_await_r, WAIT_FOR_READ, 41 );
                continue;
            }

            // requested page is locked by another task
            if( NodeState.cpsHaveToWaitForLock_bd02 )
            {
                bd13_MsgAndSuspendForPageLockReq( Trans, FileId, WantedPageNo, nr_for_update, false );
                continue;
            }

            // requested page is available
            if( Trans.trRteCommPtr_gg00->virt_reads < MAX_INT2_SP00 )
            {
                ++Trans.trRteCommPtr_gg00->virt_reads;
            }
            if( Nptrs.np_ptr() != NULL )
            {
                bd73DataIOStatistic( LEAF_LEVEL_BD00, FileId.fileTfn_gg00(), IS_VIRTUAL, IS_READ);
            }
            break;
        }
        // ==========================================
        // data cache doesn't contains requested page
        // ==========================================

        // requested page is still in write IO by another task
        if( NodeState.cpsWaitForWrite_bd02 )
        {
            bd13_MsgAndSuspend( Trans, WantedPageNo, b_await_w, WAIT_FOR_WRITE, 42 );
            continue;
        }

        // before reading the request page into the data cache the assigned
        // data cache frame has to be written onto disk, because the page on
        // the frame is changed.
        if( NodeState.cpsDirty_bd02 )
        {
            bd13_WriteOldOccupant( Trans, Nptrs.np_ptr(), Nptrs.np_cbptr(), WantedPageNo,
                                   recMode, NodeState, !NEW_NODE );
        }
        {
            // perform the read IO for the requested page
            bPageRead = true; // needed to handle the assigned data cache frame
            Data_BasePage Page( Nptrs.np_ptr(), rmPermStatic_ebd02 != recMode,
                                rmTemp_ebd02 == recMode, Nptrs.np_cbptr() );

            const IOMan_ReturnCode retCode =
                IOMan_IDataIO::GetInstance().ReadDataPage( TaskId, Page, WantedPageNo );

            switch( retCode )  // PTS 1127038 TS 2004-02-06
            {
            case IOMan_BadDataPage:
                {
                    TrError = e_bad_datapage;
                    break;
                }
            case IOMan_NoConverterEntry:
                {
                    // The page is neither in the data cache nor on a data volume
                    // and therefore is has to be generated with the given page no!
                    
                    TrError        = e_ok;
                    bPageGenerated = true; // Mark corresponding converter entry as used
                    
                    if( ! Converter_IPageNoManager::Instance().RequestSpecificiedNewStaticPageNo(
                                TaskId, WantedPageNo ))
                        TrError = e_page_no_in_use;
                    break;
                }
            case IOMan_PageNoOutOfRange:
                {
                    TrError = e_invalid_oid;
                    break; 
                }
            default:
                ;
            }
        }

        if( e_ok != TrError )
            break; // fatal error has occured

        bd73DataIOStatistic( LEAF_LEVEL_BD00, FileId.fileTfn_gg00(), !IS_VIRTUAL, IS_READ);

        if( bPageGenerated )
            b13init_default_data_page( FileId, LEAF_LEVEL_BD00, WantedPageNo, Nptrs );

        break;
    };
    // end data cache overflow loop

    // Make only same primitive checks, because of the interaction with the garbage
    // collector it is possible that requested page is still in another object file.
    // It is only warranted that this file is an object file.
    if(( NULL != Nptrs.np_ptr()) && ( e_ok == TrError ))
    {
        if( WantedPageNo != Nptrs.np_ptr()->nd_id() )
            TrError = e_illegal_page_no;
        else
            if(
                ( pt2Object_egg00    != Nptrs.np_ptr()->nd_pt2() ) &&
                ( pt2VarObject_egg00 != Nptrs.np_ptr()->nd_pt2() )
            )
                TrError = e_inconsistent_nodetype;
    }
    // handle assigned data cache frame in case of user triggered read IO
    if( bPageRead )
    {
        if( e_ok == TrError )
            bd20UsePage( TaskId, TrError, WantedPageNo, rmPermStatic_ebd02, Nptrs.np_cbptr(),
                         nr_for_update, Nptrs.np_ptr() );
        else
        {
            tgg00_BasisError AuxError = TrError;
            TrError                   = e_ok;

            bd20FreePage( TaskId, WantedPageNo, rmPermStatic_ebd02, TrError, Trans.trBdExclFileLocks_gg00 );

            if( e_ok == TrError)
                TrError = AuxError;

            Nptrs.np_ptr()   = NULL;
            Nptrs.np_cbptr() = NULL;
        }
    }
}

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

externC void
b13new_node(
    tsp00_Int2         LevelNo,
    tbd_node_ptrs     &Nptrs,
    tbd_current_tree  &Current)

{
    ROUTINE_DBG_MEO00 ("b13new_node");

    Data_PageNo                 newPageNo;
    tgg00_FileId                &fileId = Current.curr_tree_id;
    tgg00_TransContext          &trans  = *Current.curr_trans;
    const tbd02_RecoveryMode    recMode = bd13_GetRecoveryMode( fileId );

    SAPDBERR_ASSERT_STATE( rmPermStatic_ebd02 != recMode );

    if (fileId.fileType_gg00().includes(ftsTemp_egg00))
    {
        if( Converter_IPageNoManager::Instance().RequestNewTempPageNo(
                    trans.trTaskId_gg00, newPageNo ))
        {
            if( ! fileId.fileType_gg00().includes( ftsShared_egg00 )){
                ++trans.trTempCount_gg00;
                ++trans.trRteCommPtr_gg00->temp_page_cnt;
            }
        }
        else
        {
            trans.trError_gg00 = e_no_more_temp_space;
            return;
        }
    }
    else
    {
        if( ! Converter_IPageNoManager::Instance().RequestNewPermDynamicPageNo(
                    trans.trTaskId_gg00, newPageNo ))
        {
            trans.trError_gg00 = e_no_more_perm_space;
            return;
        }
    };
    bd13_FrameForNewNode( LevelNo, newPageNo, recMode, Nptrs, Current );
}

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

externC void
b13new_object_node(
    tbd_node_ptrs     &Nptrs,
    tbd_current_tree  &Current)
{
    ROUTINE_DBG_MEO00 ("b13new_object_node");

    Data_PageNo                 newPageNo;
    tgg00_FileId                &fileId = Current.curr_tree_id;
    tgg00_TransContext          &trans  = *Current.curr_trans;
    const tbd02_RecoveryMode    recMode = bd13_GetRecoveryMode( fileId );

    switch(  fileId.fileTfn_gg00() )
    {
    case tfnObj_egg00:
        {
            SAPDBERR_ASSERT_STATE( rmPermStatic_ebd02 == recMode );

            if( ! Converter_IPageNoManager::Instance().RequestNewStaticPageNo(
                        trans.trTaskId_gg00, newPageNo ))
            {
                trans.trError_gg00 = e_no_more_perm_space;
                return;
            }
            bd13_FrameForNewNode(LEAF_LEVEL_BD00, newPageNo, recMode, Nptrs, Current);
            break;
        }
    case tfnContObj_egg00:
        {
            SAPDBERR_ASSERT_STATE( rmPermDynamic_ebd02 == recMode );

            if( ! Converter_IPageNoManager::Instance().RequestNewPermDynamicPageNo(
                        trans.trTaskId_gg00, newPageNo))
            {
                trans.trError_gg00 = e_no_more_perm_space;
                return;
            }
            bd13_FrameForNewNode (LEAF_LEVEL_BD00, newPageNo, recMode, Nptrs, Current);
            break;
        }
    default:
        {
            trans.trError_gg00 = e_invalid_filetype;
            g01opmsg (sp3p_knldiag, sp3m_error, csp03_b13_illegal_obj_file_type,
                      csp3_n_obj, "Illegal type for objfile", fileId.fileTfn_gg00());
            return;
        }
    }
    if( e_ok != trans.trError_gg00 )
    {
        tgg00_BasisError AuxError = trans.trError_gg00;
        trans.trError_gg00        = e_ok;

        b13free_node( Nptrs, Current );
        if( e_ok == trans.trError_gg00 )
        {
            trans.trError_gg00 = AuxError;
        }
    }
}

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

externC void
b13new_root(
    tbd_node_ptrs     &Nptrs,
    tbd_current_tree  &Current)

{
    ROUTINE_DBG_MEO00 ("b13new_root");

    b13new_node (LEAF_LEVEL_BD00, Nptrs, Current );

#   ifdef SAPDB_SLOW
    if( e_ok == Current.curr_trans->trError_gg00 )
    {
        t01int4 (bd_io, "new root pno", Nptrs.np_ptr()->nd_id());
    }
#   endif

};

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

externC void
b13init_default_data_page (
    tgg00_FileId         &FileId,
    tsp00_Int2            Level,
    tsp00_PageNo          NewPno,
    tbd_node_ptrs        &Nptrs)

{
    ROUTINE_DBG_MEO00 ("b13init_default_data_page");

    const tbd02_RecoveryMode recMode = bd13_GetRecoveryMode( FileId );
    const SAPDB_Bool bIsRoot = (NIL_PAGE_NO_GG00 == FileId.fileRoot_gg00()) && (LEAF_LEVEL_BD00 == Level);

    Nptrs.np_ptr()->nd_id()               = NewPno;
    Nptrs.np_ptr()->nd_pt().becomes (ptData_egg00);
    Nptrs.np_ptr()->nd_checktype().becomes (chckChecksumData_egg00);
    Nptrs.np_ptr()->nd_pmode().clear();
    /* */
    Nptrs.np_ptr()->nd_bottom()           = BODY_BEG_BD00;
    Nptrs.np_ptr()->nd_record_cnt()       = 0;
    /* */
    Nptrs.np_ptr()->nd_level()            = Level;
    Nptrs.np_ptr()->nd_file_state().clear();
    Nptrs.np_ptr()->nd_sorted()           = false;
    /* */
    Nptrs.np_ptr()->nd_right()            = NIL_PAGE_NO_GG00;
    Nptrs.np_ptr()->nd_left()             = NIL_PAGE_NO_GG00;
    /* */
    Nptrs.np_ptr()->nd_last()             = NIL_PAGE_NO_GG00;
    Nptrs.np_ptr()->nd_leaf_no()          = NIL_PAGE_NO_GG00;
    /* */
    Nptrs.np_ptr()->nd_conv_version()     = Converter_Version::GetNilVersion();
    Nptrs.np_ptr()->nd_str_version()      = NIL_STR_VERSION_GG00;
    /* */
    Nptrs.np_ptr()->nd_filler2()          = 0;
    Nptrs.np_ptr()->ndInvUsageCnt_bd00()  = cgg_nil_transindex;
    /* */
    if  ((! FileId.fileType_gg00().includes (ftsByteStr_egg00)) &&
            (LEAF_LEVEL_BD00 == Level))
    {
        Nptrs.np_ptr()->ndLeafCount_bd00() = 1;
    }
    else
    {
        Nptrs.np_ptr()->ndLeafCount_bd00() = 0; // == ndStrFileSize_bd00
    }
    Nptrs.np_ptr()->ndTreeLeaves_bd00()   = cgg_nil_leafnodes;
    /* */
    Nptrs.np_ptr()->nd_trans_id().gg90SetNil();
    Nptrs.np_ptr()->nd_filler4()          = 0;
    /* */
    Nptrs.np_ptr()->ndInvRoot_bd00()      = NIL_PAGE_NO_GG00; // PTS 1120695 UH 2003-10-27

    Nptrs.np_ptr()->nd_write_cnt()        = 0;
    /* */
    if( bIsRoot )
    {
        Nptrs.np_ptr()->nd_root()         = NewPno;
        Nptrs.np_ptr()->nd_file_version() = FileId.fileVersion_gg00();
    }
    else
    {
        Nptrs.np_ptr()->nd_root() = FileId.fileRoot_gg00();
        Nptrs.np_ptr()->nd_file_version().gg90SetNil();
    }
    /* */
    /* */
    /* */
    switch (FileId.fileTfn_gg00())
    {
    case tfnOmsInv_egg00 :
    case tfnMulti_egg00 :
    case tfnTempInv_egg00 :
        Nptrs.np_ptr()->nd_pt2().becomes(pt2Inv_egg00);
        break;
    case tfnInvSubtree_egg00 :
        Nptrs.np_ptr()->nd_pt2().becomes(pt2InvSubtree_egg00);
        break;
    case tfnLog_egg00 :
    case tfnObjBefore_egg00 :
        Nptrs.np_ptr()->nd_pt2().becomes(pt2Log_egg00);
        if  (tfnLog_egg00 == FileId.fileTfn_gg00())
        {
            Nptrs.np_ptr()->nd_trans_id() = FileId.fileTransId_gg00();
        }
        else
        {
            // pos of last checked and unused history entry in the page
            Nptrs.np_ptr()->nd_left() = sizeof(Nptrs.np_ptr()->nd_full_header()) + 1;
        }

        Nptrs.np_ptr()->nd_file_version().gg90SetNil();

        if  (NIL_PAGE_NO_GG00 == FileId.fileRoot_gg00())
        {
            Nptrs.np_ptr()->nd_root() = NewPno;
            Nptrs.np_ptr()->nd_last() = NewPno;
        }
        else
        {
            Nptrs.np_ptr()->nd_root() = FileId.fileRoot_gg00();
            Nptrs.np_ptr()->nd_last() = NIL_PAGE_NO_GG00;
        }
        break;
    case tfnObj_egg00 :
        Nptrs.np_ptr()->nd_pt2().becomes(pt2Object_egg00);
        break;
    case tfnContObj_egg00 :
        Nptrs.np_ptr()->nd_pt2().becomes(pt2ContObject_egg00);
        break;
    case tfnUndoLog_egg00 :
        Nptrs.np_ptr()->nd_pt2().becomes(pt2UndoLog_egg00);
        break;
    case tfnRedoLog_egg00 :
        Nptrs.np_ptr()->nd_pt2().becomes(pt2RedoLog_egg00);
        break;
    case tfnHistory_egg00 :
        Nptrs.np_ptr()->nd_pt2().becomes(pt2History_egg00);
        break;
    case tfnHistoryDirectory_egg00 :
        Nptrs.np_ptr()->nd_pt2().becomes(pt2HistoryDirectory_egg00);
        break;
    case tfnOpenTrans_egg00 :
        Nptrs.np_ptr()->nd_pt2().becomes(pt2OpenTrans_egg00);
        break;
    default :
        if (FileId.fileType_gg00().includes (ftsByteStr_egg00))
        {
            Nptrs.np_ptr()->nd_pt2().becomes(pt2String_egg00);
        }
        else
        {
            const tsp00_PageNo pageRoot = Nptrs.np_ptr()->nd_root();
            Nptrs.np_ptr()->nd_pt2().becomes (pt2Tab_egg00);

            if(
                ( pageRoot == g01tabid.sys1_cat.fileRoot_gg00() && (recMode == rmPermDynamic_ebd02 )) ||
                ( pageRoot == g01tabid.sys2_cat.fileRoot_gg00() && (recMode == rmPermDynamic_ebd02 ))
            )
            {
                Nptrs.np_ptr()->nd_pmode().addElement(pmCatalog_egg00);
            }
            else
            {
                if  (
                    ( pageRoot == bd17GetTempFdirRoot() && (recMode == rmTemp_ebd02        )) ||
                    ( pageRoot == bd17GetFdirRoot()     && (recMode == rmPermDynamic_ebd02 )) ||
                    ( pageRoot == bd17GetLongFdirRoot() && (recMode == rmPermDynamic_ebd02 ))
                )
                {
                    Nptrs.np_ptr()->nd_pmode().addElement(pmFdir_egg00);
                }
                else
                    if( ! bIsRoot && FileId.fileType_gg00().includes( ftsArchive_egg00 ))
                    {
                        Nptrs.np_ptr()->nd_pmode().addElement( pmArchive_egg00 );
                    }
            }
        }
    }
    /* */
    if  (FileId.fileType_gg00().includes (ftsTemp_egg00))
    {
        Nptrs.np_ptr()->nd_pmode().addElement(pmTemp_egg00);
    }
    Nptrs.np_ptr()->nd_checksum() = 0;
    Nptrs.np_ptr()->nd_trailer()  = Nptrs.np_ptr()->nd_header();
};

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

externC void
b13r_release_node(
    tbd_node_ptrs         &Nptrs,
    tbd_current_tree      &Current,
    tbd_lru_info_Param     LruInfo)

{
    ROUTINE_DBG_MEO00 ("b13r_release_node");


    tgg00_TransContext          &CurrTrans  = *Current.curr_trans;
    tgg00_FileId                &CurrFileId = Current.curr_tree_id;
    const tbd02_RecoveryMode    recMode     = bd13_GetRecoveryMode( CurrFileId );
    const tsp00_PageNo          pageNo      = Nptrs.np_ptr()->nd_id();
    const tbd_nodeptr           pRoot       = Current.currRootNptrs_bd00.np_ptr();
    const tbd_nodeptr           pIndex      = Current.currIndexNptrs_bd00.np_ptr();

#   ifdef SAPDB_SLOW
    switch( recMode )
    {
    case rmTemp_ebd02:
        t01int4 (bd_io, "Rrel tmp pno", pageNo);
        break;
    case rmPermDynamic_ebd02:
        t01int4 (bd_io, "Rrel dyn pno", pageNo);
        break;
    case rmPermStatic_ebd02:
        t01int4 (bd_io, "Rrel sta pno", pageNo);

        break;
    default:
        ;
    }
#   endif

    // if currNptrs_bd00 is set, then tree-locks are realized by
    // holding the node within current. It is forbidden to release
    // the node until the tree-lock is already necessary.

    const bool bKeepPage = ((NULL != pRoot)  && (pageNo == pRoot->nd_id())) ||
                           ((NULL != pIndex) && (pageNo == pIndex->nd_id()));

    if( ! bKeepPage )
    {
        bd20RReleasePage (CurrTrans.trTaskId_gg00, CurrTrans.trBdExclFileLocks_gg00,
                          CurrFileId, Nptrs.np_ptr(), REFCAST_MEO00 (tbd02_pDataCBlock) &Nptrs.np_cbptr(),
                          recMode, LruInfo);

        --Current.currCounter_bd00;

#       ifdef SAPDB_SLOW
        t01int4( bd_io, "CurrCounter ", Current.currCounter_bd00 );
#       endif
    }
    else
    {
        Nptrs.np_ptr()   = NULL;
        Nptrs.np_cbptr() = NULL;
    }

};

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

externC void
b13w_release_node(
    tbd_node_ptrs         &Nptrs,
    tbd_current_tree      &Current)

{
    ROUTINE_DBG_MEO00 ("b13w_release_node");


    tgg00_BasisError            AuxError    = Current.curr_trans->trError_gg00;
    tgg00_BasisError            &TrError    = Current.curr_trans->trError_gg00;
    tgg00_TransContext          &CurrTrans  = *Current.curr_trans;
    tgg00_FileId                &CurrFileId = Current.curr_tree_id;;
    tbd02_SwapState             IoState;
    const tsp00_Int             level       = Nptrs.np_ptr()->nd_level();
    const tbd02_RecoveryMode    recMode     = bd13_GetRecoveryMode( CurrFileId );
    const tsp00_TaskId          &TaskId     = CurrTrans.trTaskId_gg00;
    const tsp00_PageNo          pageNo      = Nptrs.np_ptr()->nd_id();
    const tbd_nodeptr           pRoot       = Current.currRootNptrs_bd00.np_ptr();
    const tbd_nodeptr           pIndex      = Current.currIndexNptrs_bd00.np_ptr();

#   ifdef SAPDB_SLOW
    switch( recMode )
    {
    case rmTemp_ebd02:
        t01int4 (bd_io, "Wrel tmp pno", pageNo);
        break;
    case rmPermDynamic_ebd02:
        t01int4 (bd_io, "Wrel dyn pno", pageNo);
        break;
    case rmPermStatic_ebd02:
        t01int4 (bd_io, "Wrel sta pno", pageNo);

        break;
    default:
        ;
    }
#   endif

    TrError = e_ok;

    if(
        ( g01glob.treecheck ) && ( rmTemp_ebd02 != recMode ) &&
        (
            ( tfnSys_egg00       == CurrFileId.fileTfn_gg00()) ||
            ( tfnTable_egg00     == CurrFileId.fileTfn_gg00()) ||
            ( tfnShortScol_egg00 == CurrFileId.fileTfn_gg00())
        )
    )
    {
        bd13CheckNode( TaskId, TrError, Nptrs, CurrFileId, true );
        if( e_ok != TrError )
        {
            b06write_filename_and_root( CurrFileId );
            g01abort( csp3_bd_msg, csp3_n_btree, "bd13CheckNode           ", 0);
        };
    }

    // if currNptrs_bd00 is set, then tree-locks are realized by
    // holding the node within current. It is forbidden to release
    // the node until the tree-lock is already necessary.

    const bool bKeepPage = ((NULL != pRoot)  && (pageNo == pRoot->nd_id())) ||
                           ((NULL != pIndex) && (pageNo == pIndex->nd_id()));
    if( bKeepPage )
    {
        if( pageNo == CurrFileId.fileRoot_gg00() )
            Current.currRootUpdated_bd00 = true;
        else
            Current.currIndexUpdated_bd00 = true;
    }
    else
    {
        IoState.becomes (swsTestIo_ebd02);
        bd20WReleasePage( TaskId, CurrFileId, CurrTrans.trBdExclFileLocks_gg00, Nptrs.np_ptr(),
                          REFCAST_MEO00 (tbd02_pDataCBlock) &Nptrs.np_cbptr(), IoState, recMode );

        if( swsDoIo_ebd02 == IoState )
        {
            bd73DataIOStatistic( Nptrs.np_ptr()->nd_level(), CurrFileId.fileTfn_gg00(),
                                 !IS_VIRTUAL, !IS_READ );

            if( e_ok == TrError )
            {
                Data_BasePage   Page( Nptrs.np_ptr(), rmPermStatic_ebd02 != recMode,
                                      rmTemp_ebd02 == recMode, Nptrs.np_cbptr() );

                IOMan_IDataIO::GetInstance().WriteDataPage( TaskId, Page );
            }
            if( e_ok != TrError )
                g01abort (csp3_bd_msg, csp3_n_btree, "b13w_rel: write error   ", TrError);

            bd20ForcedIODone( Nptrs.np_cbptr(), TaskId );
            IoState.becomes( swsIoDone_ebd02 );

            bd20WReleasePage( TaskId, CurrFileId, CurrTrans.trBdExclFileLocks_gg00, Nptrs.np_ptr(),
                              REFCAST_MEO00 (tbd02_pDataCBlock) &Nptrs.np_cbptr(), IoState, recMode );
        }

        bd73DataIOStatistic (level, CurrFileId.fileTfn_gg00(), IS_VIRTUAL, !IS_READ);

        --Current.currCounter_bd00;
        // monitoring of physical writes must be done in VBD20 when
        // clearing pages or executing savepoints
#       ifdef SAPDB_SLOW
        t01int4( bd_io, "CurrCounter ", Current.currCounter_bd00 );
#       endif

    }
    TrError          = AuxError;
    Nptrs.np_ptr()   = NULL;
    Nptrs.np_cbptr() = NULL;
};

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

externC void
bd13FreePageNo(
    tsp00_PageNo      pageNo,
    tsp00_Int4        pageConverterVersion,
    tbd_current_tree  &current )

{
    ROUTINE_DBG_MEO00 ("bd13FreePageNo");

    tgg00_FileId    &currFileId = current.curr_tree_id;
    tbd00_FreeQueue &freeQueue   = current.currFreeQueue_bd00;

    if(
        ( pageNo == currFileId.fileRoot_gg00()       ) &&
        ( NULL != current.currRootNptrs_bd00.np_ptr())
    )
    {
        current.currRootNptrs_bd00.np_ptr() = NULL;
    }

    if(
        ( NULL != current.currRootNptrs_bd00.np_ptr()                       ) &&
        ( bd20IsPageExclusiveLocked( current.currRootNptrs_bd00.np_cbptr( ))) &&
        ( freeQueue.fqTop_bd00 <= MAX_FREE_QUEUE_BD00                       ) &&
        ( ! currFileId.fileBdUse_gg00().includes( bd_release_acc )          )
    )
    {
        const tsp00_Int4 queuePos = freeQueue.fqTop_bd00 - POS_OFF_DIFF_BD00;

        freeQueue.fqPnos_bd00[ queuePos ]        = pageNo;
        freeQueue.fqPageVersion_bd00[ queuePos ] = pageConverterVersion;

        ++freeQueue.fqTop_bd00;
    }
    else
    {
        const tbd02_RecoveryMode recMode = bd13_GetRecoveryMode( currFileId );

        bd13_FreeNode( current, pageNo, recMode, pageConverterVersion );
    }
};

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

externC void
bd13FreeJustCreatedPageNo(
    tsp00_PageNo      pageNo,
    tbd_current_tree  &current )
{
    Converter_Version   pageConverterVersion;

    bd13FreePageNo( pageNo, pageConverterVersion, current );
};

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

externC void
bd13FreeTempPageNo(
    tsp00_PageNo      pageNo,
    tbd_current_tree  &current )
{
    SAPDBERR_ASSERT_STATE( current.curr_tree_id.fileType_gg00().includes( ftsTemp_egg00 ));

    Converter_Version   pageConverterVersion;

    bd13FreePageNo( pageNo, pageConverterVersion, current );
};

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

externC void
b13free_node (tbd_node_ptrs    &Nptrs,
              tbd_current_tree &Current)

{
    const tsp00_PageNo      pageNo = Nptrs.np_ptr()->nd_id();
    const Converter_Version pageConverterVersion = Nptrs.np_ptr()->nd_conv_version();

    if(
        ( pageNo == Current.curr_tree_id.fileRoot_gg00()                ) &&
        ( Current.curr_tree_id.fileType_gg00().includes( ftsTemp_egg00 ))
    )
    {
        Nptrs.np_ptr()->nd_root() = NIL_PAGE_NO_GG00;
    }

    bd13FreePageNo( pageNo, pageConverterVersion, Current );

    if(( e_ok != Current.curr_trans->trError_gg00) && (NULL != Nptrs.np_ptr() ))
    {
        b13r_release_node( Nptrs, Current, lru_normal );
    }

    Nptrs.np_ptr()   = NULL;
    Nptrs.np_cbptr() = NULL;
};

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

externC void
bd13FreePnosAfterUnlock( tbd_current_tree &Current )

{
    ROUTINE_DBG_MEO00 ("bd13FreePnosAfterUnlock");

    if( e_shutdown == Current.curr_trans->trError_gg00 ) // PTS 1123793 TS 2003-08-26
        return;

    const tgg00_BasisError auxError  = Current.curr_trans->trError_gg00; // PTS 1123793 TS 2003-08-26
    Current.curr_trans->trError_gg00 = e_ok;

    const tbd02_RecoveryMode recMode    = bd13_GetRecoveryMode( Current.curr_tree_id );
    tbd00_FreeQueue          &freeQueue = Current.currFreeQueue_bd00;

    while ((e_ok == Current.curr_trans->trError_gg00) && (1 < freeQueue.fqTop_bd00))
    {
        --freeQueue.fqTop_bd00;

        const tsp00_Int4        queuePos    = freeQueue.fqTop_bd00 - POS_OFF_DIFF_BD00;
        const tsp00_PageNo      pageNo      = freeQueue.fqPnos_bd00[ queuePos ];
        const Converter_Version pageVersion = freeQueue.fqPageVersion_bd00[ queuePos ];

        bd13_FreeNode( Current, pageNo, recMode, pageVersion );
    }
    Current.curr_trans->trError_gg00 = auxError;
};

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

externC void
bd13WriteExclusiveLockedRoot( tbd_current_tree &current )
{
    ROUTINE_DBG_MEO00( "bd13WriteExclusiveLockedRoot" );

    tgg00_TransContext          &trans   = *current.curr_trans;
    tgg00_FileId                &fileId  = current.curr_tree_id;
    const tbd_nodeptr           &pNode   = current.currRootNptrs_bd00.np_ptr();
    const tbd_nodeptr           &pCblock = current.currRootNptrs_bd00.np_cbptr();
    const tsp00_PageNo          pageNo   = pNode->nd_id();
    const tbd02_RecoveryMode    recMode  = bd13_GetRecoveryMode( fileId );

    tbd02_CachePageState    nodeState;
    SAPDB_Bool              bIsFirstInit = true;
    SAPDB_Bool1             bWritePage   = false;

    bd13_InitPageState( nodeState, plmLock_ebd00, bIsFirstInit );
    nodeState.cpsSynchSvpAndTreeSplits_bd02.becomes( synchNone_ebd02 );

    while( e_ok == trans.trError_gg00 )
    {
        bd20CheckExclusiveLockedPageForIO( trans.trTaskId_gg00, fileId,
                                           pageNo, recMode, pCblock, bWritePage, nodeState );

        if( nodeState.cpsWaitForWrite_bd02 )
        {
            // at this time the data cache contains more than one image of the current
            // root page and therefore we have to wait with the i/o until the older
            // images of the root page are written to to the data area.

            bd13_MsgAndSuspend( trans, pageNo, b_await_w, WAIT_FOR_WRITE, 40 );
            nodeState.cpsWaitForWrite_bd02 = false;
            continue;
        }

        if( nodeState.cpsWaitForSvpEnd_bd02 )
        {
            // the root page is changed but not relevant for the running savepoint
            // therefore we have to wait with the i/o until the savepoint is finished.
            // otherwise the converter version materialized with the running savepoint
            // will be inconsistent

            bd13_MsgAndSuspend (trans, pageNo, b_await_w, WAIT_FOR_SVP_END, 28 );
            nodeState.cpsWaitForSvpEnd_bd02 = false;
            continue;
        }

        if( bWritePage )
        {
            // the root page has to be written into the data area. Note that the
            // state of the control block is blocked and not userIo! Synchronization
            // of i/o with a concurrent running (pager) task will be done by the
            // usageCounter and the blocked state of the control block.

            nodeState.cpsFound_bd02 = true; // guarantee that subsequent proc will not call bd20ReplaceOldOccupant
            bd13_WriteOldOccupant( trans, pNode, pCblock, pageNo, recMode, nodeState, !NEW_NODE);
        }
        break; // normal termination condition
    }
};
/*---------------------------------------------------------------------------*/

externC void
bd13CheckNode(
    tsp00_TaskId          taskId,
    tgg00_BasisError      &trError,
    tbd_node_ptrs         &pNodes,
    tgg00_FileId          &fileId,
    tsp00_Bool            bExtendedCheck )
{
    ROUTINE_DBG_MEO00 ("bd13CheckNode");

    const tbd_nodeptr           &pNode  = pNodes.np_ptr();
    const tbd02_RecoveryMode    recMode = bd13_GetRecoveryMode( fileId );


    if(( pNode->nd_bottom() < BODY_BEG_BD00 ) || ( pNode->nd_bottom() > MAX_BOTTOM_BD00 )){
        trError = e_data_page_corrupted; // invalid bottom
        bd13_CheckNodeErrorHandling( taskId, trError, pNode, recMode, pNode->nd_bottom());
        return;
    }

    const Data_PageNo maxPageNo = ( ! bExtendedCheck ) ? (Data_PageNo) NIL_PAGE_NO_GG00 :
                                  (( rmTemp_ebd02 == recMode ) ?
                                   Converter_ICommon::Instance().MaxTempPageNo() :
                                   Converter_ICommon::Instance().MaxPermDynamicPageNo());

    const tsp00_Int4 maxRecIndex    = pNode->nd_record_cnt()-1;
    tsp00_Int4       totalRecLength = 0;
    tsp00_Int4       prevKeyLength  = 0;
    tgg00_RecPtr     pPrevRec       = NULL;

    for( tsp00_Int4 recIndex = FIRST_REC_INDEX_BD00; recIndex <= maxRecIndex; ++recIndex )
    {
        const tsp00_Int4 recPos =
            pNode->nd_pointer_list()[MAX_POINTERINDEX_BD00 - recIndex - POS_OFF_DIFF_BD00];

        if(( recPos < BODY_BEG_BD00) || ( recPos >= pNode->nd_bottom()))
        {
            trError = e_illegal_entrypos; // invalid record position
            bd13_CheckNodeErrorHandling( taskId, trError, pNode, recMode, recPos );
            return;
        }

        const tgg00_RecPtr pRec =
            reinterpret_cast<tgg00_RecPtr>( &pNode->nd_body()[recPos - POS_OFF_DIFF_BD00 - NODE_HEADER_MXBD00]);

        const tsp00_Int4   recLength = pRec->recLen_gg00();

        totalRecLength = totalRecLength + b01rec_align( recLength );

        if(
            ( recLength  < MIN_RECORD_LEN_BD00 ) ||
            ( recPos + b01rec_align( recLength ) > pNode->nd_bottom())
        )
        {
            trError = e_illegal_entrylength;  // invalid record length
            bd13_CheckNodeErrorHandling( taskId, trError, pNode, recMode, recPos );
            return;
        }

        const tsp00_Int4   keyLength = pRec->recKeyLen_gg00();

        if (
            (( pNode->nd_level() == LEAF_LEVEL_BD00 ) && ( keyLength < 1 )) ||
            ( keyLength > MAX_KEYLEN_GG00 ) ||
            ( keyLength > recLength )       ||
            (
                ( pNode->nd_level() > LEAF_LEVEL_BD00 ) &&
                ( keyLength + cgg_rec_key_offset + sizeof ( tbd00_SepLeafCount ) != recLength )
            )
        )
        {
            trError = e_illegal_keylength; // invalid key length
            bd13_CheckNodeErrorHandling( taskId, trError, pNode, recMode, recPos );
            return;
        }

        // ADDITIONAL CHECKS ONLY EXECUTED IF REQUESTED

        if( ! bExtendedCheck )
            continue;

        if( NULL != pPrevRec )
        {
            tsp00_LcompResult compResult;

            s30cmp (pRec->recKey_gg00().keyVal_gg00(), POS_OFF_DIFF_BD00, keyLength,
                    pPrevRec->recKey_gg00().keyVal_gg00(), POS_OFF_DIFF_BD00, prevKeyLength,
                    compResult );

            if( l_greater != compResult )
            {
                trError = e_illegal_key; // invalid key order
                bd13_CheckNodeErrorHandling( taskId, trError, pNode, recMode, recPos );
                return;
            }
        }
        prevKeyLength = keyLength;
        pPrevRec      = pRec;

        if( pNode->nd_level() > LEAF_LEVEL_BD00 )
        {
            const tsp00_PageNo pageNo = gg06PnoGet( pRec->recPno_gg00());

            if(( pageNo < 0) || ( pageNo > maxPageNo ))
            {
                trError = e_illegal_page_no; // invalid separator pageNo
                bd13_CheckNodeErrorHandling( taskId, trError, pNode, recMode, recPos );
                return;
            }

            for( tsp00_Int4 auxRecIndex = FIRST_REC_INDEX_BD00; auxRecIndex < recIndex; ++auxRecIndex )
            {
                const tsp00_Int4   auxRecPos =
                    pNode->nd_pointer_list()[MAX_POINTERINDEX_BD00 - auxRecIndex - POS_OFF_DIFF_BD00];

                const tgg00_RecPtr pAuxRec   =
                    reinterpret_cast<tgg00_RecPtr> (&pNode->nd_body()[ auxRecPos - POS_OFF_DIFF_BD00
                                                    - NODE_HEADER_MXBD00]);

                if( pageNo == gg06PnoGet( pAuxRec->recPno_gg00()))
                {
                    trError = e_illegal_page_no; // duplicate separator pageNo
                    bd13_CheckNodeErrorHandling( taskId, trError, pNode, recMode, recPos );
                    return;
                }
            }
        }
    }

    if( totalRecLength != pNode->nd_bottom() - BODY_BEG_BD00 )
    {
        trError = e_illegal_record; // invalid record length
        bd13_CheckNodeErrorHandling( taskId, trError, pNode, recMode, totalRecLength );
        return;
    }
}

/*===========================================================================*
 *  LOCAL FUNCTIONS (CODE)                                                   *
 *===========================================================================*/

inline void
bd13_MsgAndSuspend(
    tgg00_TransContext           &trans,
    const  tsp00_PageNo          pageNo,
    const tgg00_VtraceType_Param traceType,
    const char                   *msgText, //tsp00_C24
    const tsp00_Int4             suspendReason )
{
    if( g01vtrace.vtrAll_gg00 || g01vtrace.vtrIoTrace_gg00 )
    {
        Trace_PageNoEntry( trans, pageNo, traceType );
    }
# ifdef SUSP_RES
    g01opmsg( sp3p_nil, sp3m_info, csp3_bd_msg, csp3_n_datacache, msgText, pageNo );
# endif

    vsuspend( trans.trTaskId_gg00, suspendReason );
}

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

inline void
bd13_MsgAndSuspendForPageLockReq(
    tgg00_TransContext              &trans,
    tgg00_FileId                    &fileId,
    const tsp00_PageNo              pageNo,
    const tbd_node_request_Param    nodeReq,
    const SAPDB_Bool                bIsRoot )
{
    const SAPDB_Bool bForUpdate = ( nr_for_update == nodeReq );
    tsp00_Int4 suspendReason;

    if( fileId.fileType_gg00().includes( ftsTemp_egg00 ))
    {   // TempRootExcl, TempRootShare, TempNodeExcl, TempNodeShare
        suspendReason = bIsRoot ? (( bForUpdate ) ? 20 : 21 ) : (( bForUpdate ) ? 22 : 23 );
    }
    else if( g04inv_tfn( fileId.fileTfn_gg00() ))
    {
        // InvRootExcl, InvRootShare, InvNodeExcl, InvNodeShare
        suspendReason = bIsRoot ? (( bForUpdate ) ? 16 : 17 ) : (( bForUpdate ) ? 18 : 19 );
    }
    else if( fileId.fileType_gg00().includes( ftsObject_egg00 ))
    {
        // ObjRootExcl, ObjRootShare, ObjNodeExcl, ObjNodeShare
        suspendReason = bIsRoot ? (( bForUpdate ) ? 24 : 25 ) : (( bForUpdate ) ? 26 : 27 );
    }
    else if( tfnUndoLog_egg00 == fileId.fileTfn_gg00() )
    {
        // UndoRootExcl, UndoRootShare, UndoNodeExcl, UndoNodeShare
        suspendReason = bIsRoot ? (( bForUpdate ) ? 29 : 30 ) : (( bForUpdate ) ? 31 : 32 );
    }
    else if( tfnHistory_egg00 == fileId.fileTfn_gg00() )
    {
        // HistRootExcl, HistRootShare, HistNodeExcl, HistNodeShare
        suspendReason = bIsRoot ? (( bForUpdate ) ? 33 : 34 ) : (( bForUpdate ) ? 35 : 36 );
    }
    else
    {   // TableRootExcl, TableRootShare, TableNodeExcl, TableNodeShare
        suspendReason = bIsRoot ? (( bForUpdate ) ? 10 : 11 ) : (( bForUpdate ) ? 12 : 13 );
    }

    if( g01vtrace.vtrAll_gg00 || g01vtrace.vtrIoTrace_gg00 )
    {
        const tgg00_VtraceType_Param traceType = bForUpdate ? b13exclusive_wait : b13share_wait;

        Trace_PageNoEntry( trans, pageNo, traceType );
    }

# ifdef SUSP_RES
    g01opmsg( sp3p_nil, sp3m_info, csp3_bd_msg, csp3_n_datacache, WAIT_FOR_BD_LOCK, pageNo );
# endif

    vSuspendForPageLock( trans.trTaskId_gg00, suspendReason, pageNo );
}

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

inline void
bd13_InitPageState( tbd02_CachePageState            &nodeState,
                    const tbd00_PageLockMode_Param  pageLockMode,
                    bool                            &bIsFirstInit )
{
    nodeState.cpsFound_bd02             = false;
    nodeState.cpsDirty_bd02             = false;
    nodeState.cpsWaitForWrite_bd02      = false;
    nodeState.cpsWaitForSvpEnd_bd02     = false;
    nodeState.cpsIoDone_bd02            = false;
    nodeState.cpsHaveToWaitForLock_bd02 = false;

    if( plmLockForSplitNoWait_ebd00 == pageLockMode )
        nodeState.cpsIntendToWaitForLock_bd02 = false;
    else
        nodeState.cpsIntendToWaitForLock_bd02 = true;

    if( bIsFirstInit )
    {
        if( plmLockWithoutReschedule_ebd00 == pageLockMode ) // PTS 1115176 TS 2002-04-09
            nodeState.cpsTaskRescheduled_bd02 = true; // do not reschedule
        else
            nodeState.cpsTaskRescheduled_bd02 = false;
        bIsFirstInit = false;
    }
}

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

void
bd13_CheckNodeHeader (const tgg00_FileId    &FileId,
                      tsp00_PageNo          PageNo,
                      const tbd_nodeptr     Nptr,
                      tgg00_BasisError      &TrError)
{
    ROUTINE_DBG_MEO00 ("bd13_CheckNodeHeader");


#   ifdef SAPDB_SLOW
    cbd13_CheckNodeTrace (TrError, FileId.fileRoot_gg00(), Nptr->nd_root());
#   endif

    if( PageNo != Nptr->nd_id() )
    {
        TrError = e_illegal_page_no;
        return;
    }

    if  ((NIL_PAGE_NO_GG00 != FileId.fileRoot_gg00()) &&
            ( Nptr->nd_root()  != FileId.fileRoot_gg00()))
    {
        if  (NIL_PAGE_NO_GG00 != Nptr->nd_root())
        {
            if ( FileId.fileTfn_gg00() == tfnMulti_egg00 )
                TrError = e_old_fileversion; // PTS 1128771 UH 2004-03-26
            else
                TrError = e_page_in_wrong_tree;
        }
        else
            TrError = e_invalid_root;
        return;
    }

    switch( FileId.fileTfn_gg00() )
    {
    case tfnObjBefore_egg00 :
        if  ((ptData_egg00 != Nptr->nd_pt()) ||
                ( pt2Log_egg00 != Nptr->nd_pt2()))
        {
            TrError = e_inconsistent_nodetype;
            return;
        }
        break;
    case tfnObj_egg00 :
        SAPDBERR_ASSERT_STATE(FileId.fileContObjFileNo_gg00() == 0);

        if  (oftFixLenObjFile_egg00 == FileId.fileObjFileType_gg00())
        {
            if  (pt2Object_egg00 != Nptr->nd_pt2())
            {
                TrError = e_inconsistent_nodetype;
                return;
            }
        }
        else if  (oftVarLenObjFile_egg00 == FileId.fileObjFileType_gg00())
        {
            if  (pt2VarObject_egg00 != Nptr->nd_pt2())
            {
                TrError = e_inconsistent_nodetype;
                return;
            }
        }
        else if
        (
            ( pt2Object_egg00     != Nptr->nd_pt2() ) &&
            ( pt2VarObject_egg00  != Nptr->nd_pt2() )
        )
        {
            TrError = e_inconsistent_nodetype;
            return;
        }
        break;
    case tfnContObj_egg00 :
        SAPDBERR_ASSERT_STATE(FileId.fileContObjFileNo_gg00() > 0);
        if  (pt2ContObject_egg00 != Nptr->nd_pt2())
        {
            TrError = e_inconsistent_nodetype;
            return;
        }
        break;
    case tfnUndoLog_egg00 :
        if  ((ptData_egg00 != Nptr->nd_pt()) ||
                ( pt2UndoLog_egg00 != Nptr->nd_pt2()))
        {
            TrError = e_inconsistent_nodetype;
            return;
        }
        break;
    case tfnRedoLog_egg00 :
        if  ((ptData_egg00 != Nptr->nd_pt()) ||
                ( pt2RedoLog_egg00 != Nptr->nd_pt2()))
        {
            TrError = e_inconsistent_nodetype;
            return;
        }
        break;
    case tfnHistory_egg00 :
        if  ((ptData_egg00 != Nptr->nd_pt()) ||
                ( pt2History_egg00 != Nptr->nd_pt2()))
        {
            TrError = e_inconsistent_nodetype;
            return;
        }
        break;
    case tfnHistoryDirectory_egg00 :
        if  ((ptData_egg00 != Nptr->nd_pt()) ||
                ( pt2HistoryDirectory_egg00 != Nptr->nd_pt2()))
        {
            TrError = e_inconsistent_nodetype;
            return;
        }
        break;
    case tfnOpenTrans_egg00 :
        if  ((ptData_egg00 != Nptr->nd_pt()) ||
                ( pt2OpenTrans_egg00 != Nptr->nd_pt2()))
        {
            TrError = e_inconsistent_nodetype;
            return;
        }
        break;
    };

    if( Nptr->nd_id() == FileId.fileRoot_gg00() )
        bd13_CheckRootNodeHeader( FileId, Nptr, TrError );
};

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

void
bd13_CheckRootNodeHeader (const tgg00_FileId  &FileId,
                          const tbd_nodeptr    Nptr,
                          tgg00_BasisError    &TrError)

{
    ROUTINE_DBG_MEO00 ("bd13_CheckRootNodeHeader");


    switch( FileId.fileTfn_gg00() )
    {
    case tfnInvSubtree_egg00 :
        if  (pt2InvSubtree_egg00 != Nptr->nd_pt2())
        {
            TrError = e_inconsistent_nodetype;
            return;
        }
        break;
    case tfnOmsInv_egg00 :
    case tfnMulti_egg00 :
        if  (pt2Inv_egg00 != Nptr->nd_pt2())
        {
            TrError = e_inconsistent_nodetype;
            return;
        }
        break;
    case tfnTempInv_egg00 :
        if  (
            (
                (pt2InvSubtree_egg00 != Nptr->nd_pt2()) &&
                (pt2Inv_egg00        != Nptr->nd_pt2())
            )
            ||
            (!Nptr->nd_pmode().includes (pmTemp_egg00))
        )
        {
            TrError = e_inconsistent_nodetype;
            return;
        }
        break;
    case tfnColumn_egg00 :
        if  (pt2String_egg00 != Nptr->nd_pt2())
        {
            TrError = e_inconsistent_nodetype;
            return;
        }
        break;
    case tfnAux_egg00 :
        if  (g04inv_tfn (FileId.fileOldTfn_gg00()))
        {
            if  ((pt2InvSubtree_egg00 != Nptr->nd_pt2()) &&
                    ( pt2Inv_egg00        != Nptr->nd_pt2()))
            {
                TrError = e_inconsistent_nodetype;
                return;
            }
        }
        else
            TrError = e_ok;
        break;
    case tfnUndoLog_egg00 :
        if  (pt2UndoLog_egg00 != Nptr->nd_pt2())
        {
            TrError = e_inconsistent_nodetype;
            return;
        }
        break;
    case tfnRedoLog_egg00 :
        if  (pt2RedoLog_egg00 != Nptr->nd_pt2())
        {
            TrError = e_inconsistent_nodetype;
            return;
        }
        break;
    case tfnOpenTrans_egg00 :
        if  (pt2OpenTrans_egg00 != Nptr->nd_pt2())
        {
            TrError = e_inconsistent_nodetype;
            return;
        }
        break;
    case tfnHistory_egg00 :
        if  (pt2History_egg00 != Nptr->nd_pt2())
        {
            TrError = e_inconsistent_nodetype;
            return;
        }
        break;
    case tfnHistoryDirectory_egg00 :
        if  (pt2HistoryDirectory_egg00 != Nptr->nd_pt2())
        {
            TrError = e_inconsistent_nodetype;
            return;
        }
        break;
    default :
        if  ((pt2InvSubtree_egg00 == Nptr->nd_pt2()) ||
                ( pt2Inv_egg00        == Nptr->nd_pt2()) ||
                ( pt2String_egg00     == Nptr->nd_pt2()) )
        {
            TrError = e_inconsistent_nodetype;
            return;
        }
    };

    if  (FileId.fileType_gg00().includes(ftsTemp_egg00))
    {
        if  (!Nptr->nd_pmode().includes (pmTemp_egg00))
        {
            TrError = e_inconsistent_nodetype;
        }
        return;
    }

    // no ftsTemp_egg00 included
    if  (Nptr->nd_pmode().includes (pmTemp_egg00))
    {
        TrError = e_inconsistent_nodetype;
        return;
    }

    if  ((Nptr->nd_file_version() != FileId.fileVersion_gg00()) &&
            (!FileId.fileVersion_gg00().gg91IsDummyVers())          &&
            (tfnAux_egg00 != FileId.fileTfn_gg00()))
    {
        TrError = e_old_fileversion;
        return;
    }
    else
    {
        if  ((Nptr->nd_file_state().includes(f_not_accessible)     )    &&
                (!FileId.fileBdUse_gg00().includes(bd_release_acc)))
        {
            // PTS 1118737 UH 2002-12-10 added messages
            tgg00_FileId auxFileId = FileId;
            b06write_filename_and_root(auxFileId);
            g01opmsg (sp3p_knldiag, sp3m_error, csp3_bd_msg, csp3_n_btree,
                      "File not accessable, pt2", Nptr->nd_pt2());
            TrError = e_file_not_accessible;
            return;
        }
    }

    if (FileId.fileBdUse_gg00().includes(bd_write_acc))
    {
        if  (Nptr->nd_file_state().includes(f_bad))
        {
            TrError = e_bad_file;
            Data_Exception errMsg( __CONTEXT__, DATA_WRN_BAD_FILE,
                                   SAPDB_ToString( FileId.fileRoot_gg00(), _T_d ));
            RTE_Message( errMsg );
            return;
        }
        if
        (
            (Nptr->nd_file_state().includes(f_read_only))       &&
            (!FileId.fileBdUse_gg00().includes(bd_load_nolog))  &&
            (!FileId.fileHandling_gg00().includes(hsNoLog_egg00))
        )
        {
            TrError = e_file_read_only;
            return;
        }
        if  (
            (FileId.fileHandling_gg00().includes(hsNoLog_egg00 )) &&
            (! FileId.fileType_gg00().includes( ftsTemp_egg00  )) &&
            (! Nptr->nd_file_state().includes( f_read_only     )) &&
            (pt2Inv_egg00        != Nptr->nd_pt2()              ) &&
            (pt2InvSubtree_egg00 != Nptr->nd_pt2()              )
        )
        {
            TrError = e_file_must_be_read_only;
            return;
        }
    };

    if  ((tfnTable_egg00 == FileId.fileTfn_gg00()                     ) &&
            (cgg_nil_leafnodes != FileId.fileLeafNodes_gg00()         ) &&
            (Nptr->ndTreeLeaves_bd00() != FileId.fileLeafNodes_gg00()))
    {
#   ifdef SAPDB_SLOW
        t01int4 (bd, "bd13che tree", FileId.fileLeafNodes_gg00());
        t01int4 (bd, "bd13che root", Nptr->ndTreeLeaves_bd00());
#   endif
        TrError = e_old_leafnodes_number;
    }
};

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

void
bd13_CheckNodeErrorHandling(
    const tsp00_TaskId          taskId,
    const tgg00_BasisError      trError,
    const tbd_nodeptr           &pNode,
    const tbd02_RecoveryMode    recMode,
    const tsp00_Int4            value )
{
    switch( trError )
    {
    case e_data_page_corrupted:
        g01opmsg( sp3p_knldiag, sp3m_error, bd13x1IllegalBottom_csp03,
                  csp3_n_btree, "Invalid bottom          ", value);
        break;
    case e_illegal_entrypos:
        g01opmsg( sp3p_knldiag, sp3m_error, bd13x1IllegalEntry_csp03,
                  csp3_n_btree, "Illegal entry position  ", value );
        break;
    case e_illegal_entrylength:
        g01opmsg( sp3p_knldiag, sp3m_error, bd13x1IllegalEntry_csp03,
                  csp3_n_btree, "Illegal record length   ", value );
        break;
    case e_illegal_keylength:
        g01opmsg( sp3p_knldiag, sp3m_error, bd13x1IllegalEntry_csp03,
                  csp3_n_btree, "Illegal key len length  ", value );
        break;
    case e_illegal_key:
        g01opmsg( sp3p_knldiag, sp3m_error, bd13x1IllegalEntry_csp03,
                  csp3_n_btree, "Wrong key order         ", value );
        break;
    case e_illegal_record:
        g01opmsg( sp3p_knldiag, sp3m_error, bd13x1IllegalEntry_csp03,
                  csp3_n_btree, "Sum record len <> bottom", value );
        break;
    case e_illegal_page_no:
        g01opmsg( sp3p_knldiag, sp3m_error, bd13x1IllegalPageNo_csp03,
                  csp3_n_btree, "Illegal separator pageNo", value );
        break;
    default :
        g01opmsg( sp3p_knldiag, sp3m_error, bd13x1IllegalEntry_csp03,
                  csp3_n_btree, "unexpected base error   ", trError );
    }

    const tsp00_PageNo  pageNo = pNode->nd_id();

    g01opmsg( sp3p_knldiag, sp3m_error, bd13x1IllegalEntry_csp03,
              csp3_n_btree, "Corrupted data page     ", pageNo );

    Data_BasePage   page( pNode, rmPermStatic_ebd02 != recMode, rmTemp_ebd02 == recMode );
    Kernel_FileIO   dumpFile( KERNEL_DATA_FILE, KERNEL_COR_FILE_EXTENSION, SAPDB_ToString( pageNo, _T_d ));
    dumpFile.Write( page );
    dumpFile.Close();
};

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

void
bd13_BadDataPageHandling(
    tgg00_TransContext  &trans,
    const tgg00_FileId  &fileId,
    const tsp00_PageNo  pageNo)
{

    tsp00_Line tfnText;
    tsp00_Int4 len = 0;
    g17tfntype_to_line( fileId.fileTfn_gg00(), len, tfnText );
    tfnText [len] = '\0';

    switch( fileId.fileTfn_gg00() )
    {
    case tfnUndoLog_egg00:
    case tfnRedoLog_egg00:
    case tfnHistory_egg00:
    case tfnOpenTrans_egg00:
    case tfnHistoryDirectory_egg00:
    case tfnObj_egg00:
    case tfnContObj_egg00:
        {
            // ReSet error code. The new error code yields to an emergency shutdown,
            // because no 'online recovery' with SQL technics is possible

            trans.trError_gg00 = e_corrupted_datapage_from_io;

            Data_Exception errMsg( __CONTEXT__, DATA_ERR_CORRUPTED_PAGE,
                                   SAPDB_ToString( pageNo, _T_d ), 
                                   SAPDB_ToString( fileId.fileRoot_gg00(), _T_d ), tfnText );
            RTE_Message( errMsg );
        }
        break;
    default:
        {
            // e_bad_datapage is handled by bd30ReleaseTree or bd300SetFileNotAccessible

            trans.trError_gg00 = e_bad_datapage;

            Data_Exception errMsg( __CONTEXT__, DATA_ERR_BAD_PAGE,
                                   SAPDB_ToString( pageNo, _T_d ),
                                   SAPDB_ToString( fileId.fileRoot_gg00(), _T_d ), tfnText );
            RTE_Message( errMsg );
        }
    }
}

/*---------------------------------------------------------------------------*/
// PTS 1127038 TS 2004-02-06
void
bd13_IllegalPageNoHandling(
    tgg00_TransContext          &trans,
    const tgg00_FileId          &fileId,
    const tsp00_PageNo          pageNo,
    const tbd02_RecoveryMode    recMode )
{
    ROUTINE_DBG_MEO00 ("bd13_IllegalPageNoHandling");

    if( rmPermStatic_ebd02 == recMode )
    {
        trans.trError_gg00 = e_invalid_oid;
        return;
    }

    // In case of a non liveCache instance this is a FATAL error
    // Kernel should be stopped by the calling task, after appending
    // some additional informations.

    trans.trError_gg00 = e_illegal_page_no;

    const Data_PageNo maxPageNo = ( rmPermDynamic_ebd02 == recMode ) ?
                                  Converter_ICommon::Instance().MaxPermDynamicPageNo() :
                                  Converter_ICommon::Instance().MaxTempPageNo();

    const SAPDB_Char *recModeString = ( rmPermDynamic_ebd02 == recMode ) ?
                                      "permanent" : "temporary";

    Data_Exception errMsg( __CONTEXT__, DATA_ERR_PAGENO_OUT_OF_RANGE,
                           recModeString, SAPDB_ToString( pageNo, _T_d ),
                           SAPDB_ToString( fileId.fileRoot_gg00(), _T_d ),
                           SAPDB_ToString( maxPageNo, _T_d ));
    RTE_Message( errMsg );

    eo670_CTraceStack();
}

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

void
bd13_WriteOldOccupant (tgg00_TransContext         &Trans,
                       tbd_nodeptr                 pNode,
                       tbd_nodeptr                 pCblock,
                       tsp00_PageNo                PageNo,
                       const tbd02_RecoveryMode    recMode, // recovery mode of the new page
                       tbd02_CachePageState       &NodeState,
                       tsp00_Bool                  NewNode)

{
    ROUTINE_DBG_MEO00 ("bd13_WriteOldOccupant");

    tgg00_BasisError    &TrError = Trans.trError_gg00;
    const tsp00_TaskId  &TaskId  = Trans.trTaskId_gg00;

    bd73DataIOStatistic( pNode->nd_level(), bd20GetFileTfn( pCblock ), !IS_VIRTUAL, !IS_READ );

    {
        Data_BasePage   Page( pNode, !gg04IsStaticPage( pNode->nd_pt2()),
                              pNode->nd_pmode().includes( pmTemp_egg00 ), pCblock );

        IOMan_IDataIO::GetInstance().WriteDataPage( TaskId, Page );
    }
    if( e_ok == TrError )
    {
        if( NodeState.cpsFound_bd02 )
        {
            bd20ForcedIODone( pCblock, TaskId );
            NodeState.cpsIoDone_bd02 = true;
        }
        else
            bd20ReplaceOldOccupant( TaskId, TrError, PageNo, recMode, pCblock, NewNode );
    }
    if( e_ok != TrError )
        g01abort (csp3_bd_msg, csp3_n_btree, "bd13_WriteOldOcc error  ", TrError);
}

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

inline void
bd13_OverflowReaction (
    const tsp00_TaskId      TaskId,
    const tsp00_PageNo      PageNo,
    const tgg00_MessType    actionType,
    const tsp00_Int4        SuspendReason,
    tgg00_BasisError        &TrError,
    tsp00_Int               &RetryCount )
{
    const tsp00_Int4 defaultRetries = 11;
    const tsp00_Int4 maxRetries     = 61;

    if( e_sysbuffer_overflow == TrError )
    {
        vsleep (TaskId, 1);
        ++RetryCount;

        if( 0 == ( RetryCount % 10 ))
        {
            g01opmsg (sp3p_knldiag, sp3m_warning, csp3_b20_lru_overflow_1,
                      csp3_n_datacache, "DATA CACHE OVERFLOW     ", TaskId);
        }

        if( RetryCount <= defaultRetries )
        {
            TrError = e_ok;
            return;
        }
        // be more soft, if parallel index creation is active
        // and calling task is not the index builder
        if(
            ( cbd499_IndexMemoryManagementUnit::bd499IsInUse()) &&
            ( actionType != m_create_index_parallel )
        )
        {
            if( RetryCount <= maxRetries )
            {
                TrError = e_ok;
                return;
            }
        }
        //  page acces will fail with e_sysbuffer_overflow
        g01opmsg (sp3p_knldiag, sp3m_warning, csp3_b20_lru_overflow_2,
                  csp3_n_datacache, "DATA CACHE OVERFLOW     ", TaskId);
        return;
    }

    if( e_no_more_temp_space == TrError )
    {
# ifdef SUSP_RES
        switch (SuspendReason)
        {
        case 43 :
            g01opmsg (sp3p_nil, sp3m_info, csp3_bd_msg,
                      csp3_n_datacache, "B13GET NODE: OFLW       ", PageNo);
            break;
        case 46 :
            g01opmsg (sp3p_nil, sp3m_info, csp3_bd_msg,
                      csp3_n_datacache, "B13NEW NODE: OFLW       ", PageNo);
            break;
        case 59 :
            g01opmsg (sp3p_nil, sp3m_info, csp3_bd_msg,
                      csp3_n_datacache, "B13GET NODE ADDR: OFLW  ", PageNo);
            break;
        case 240 :
            g01opmsg (sp3p_nil, sp3m_info, csp3_bd_msg,
                      csp3_n_datacache, "B13FREE NODE: OFLW      ", PageNo);
            break;
        default :
            break;
        }
# endif
        vsuspend (TaskId, SuspendReason);
        TrError = e_ok;
    }
}

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

void
bd13_FrameForNewNode (const tsp00_Int2          LevelNo,
                      tsp00_PageNo              NewPagePno,
                      const tbd02_RecoveryMode  recMode,
                      tbd_node_ptrs             &Nptrs,
                      tbd_current_tree          &Current)

{
    ROUTINE_DBG_MEO00 ("bd13_FrameForNewNode");


    bool                 bIsFirstCall = true;
    bool                 bIsFirstInit = true;
    tsp00_Int            RetryCount   = 0;
    tbd02_CachePageState NodeState;
    tgg00_BasisError     &TrError     = Current.curr_trans->trError_gg00;
    tgg00_TransContext   &CurrTrans   = *Current.curr_trans;
    tgg00_FileId         &CurrFileId  = Current.curr_tree_id;

#   ifdef SAPDB_SLOW
    t01int4 (bd_io, "CurrCounter   ", Current.currCounter_bd00);
#   endif

    TrError          = e_ok;
    Nptrs.np_cbptr() = NULL;

    bd13_InitPageState (NodeState, plmLock_ebd00, bIsFirstInit);
    NodeState.cpsSynchSvpAndTreeSplits_bd02.becomes(synchNone_ebd02);

    while (e_ok == TrError)
    {
        bd20NewPage (CurrTrans.trTaskId_gg00, TrError, CurrFileId, NewPagePno, recMode,
                     Nptrs.np_ptr(), REFCAST_MEO00 (tbd02_pDataCBlock) &Nptrs.np_cbptr(), NodeState);

        if  (e_ok != TrError)
        {
            // data cache overflow handling
            if ((e_sysbuffer_overflow == TrError) || (e_no_more_temp_space == TrError))
            {
                bd13_OverflowReaction( CurrTrans.trTaskId_gg00, NewPagePno,
                                       Current.curr_action, 46, TrError, RetryCount );
                continue;
            }
            break; // fatal error has occured
        }

        // caused by the synchronization between data cache and converter it
        // is possible that a new pageno is temporary in the data cache, although
        // the corresponding converter slot indicates that the pageno is free!
        if  (NodeState.cpsWaitForWrite_bd02)
        {
            bd13_MsgAndSuspend (CurrTrans, NewPagePno, b_await_w, WAIT_FOR_WRITE, 56);
            NodeState.cpsWaitForWrite_bd02 = false;
            continue;
        }

        // before reading the request page into the data cache the assigned
        // data cache frame has to be written onto disk, because the page on
        // the frame is changed.
        if  (NodeState.cpsDirty_bd02)
        {
            bd13_WriteOldOccupant (CurrTrans, Nptrs.np_ptr(), Nptrs.np_cbptr(),
                                   NewPagePno, recMode, NodeState, NEW_NODE);
        }
        b13init_default_data_page( CurrFileId, LevelNo, NewPagePno, Nptrs );
        break;
    }
    ++CurrTrans.trIoCount_gg00;

    if( Nptrs.np_ptr() != NULL )
        ++Current.currCounter_bd00;

#   ifdef SAPDB_SLOW
    if  (e_ok == TrError)
    {
        t01int4 (bd_io, "new pno     ", Nptrs.np_ptr()->nd_id());
    }
#   endif
};

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

void
bd13_FreeNode (
    tbd_current_tree            &current,
    const tsp00_PageNo          pageNo,
    const tbd02_RecoveryMode    recMode,
    const Converter_Version     &pageConverterVersion )
{
    ROUTINE_DBG_MEO00 ("bd13_FreeNode");

    bool                 bIsFirstInit      = true;
    tsp00_Bool           bFirstCall        = true;
    tsp00_Bool           bPageLockedToFree = false;
    tsp00_Int            retryCount        = 0;
    tbd02_CachePageState nodeState;
    tbd_node_ptrs        pNodes;

    tgg00_TransContext   &trans   = *current.curr_trans;
    tgg00_FileId         &fileId  = current.curr_tree_id;
    tgg00_BasisError     &trError = trans.trError_gg00;
    const tsp00_TaskId   &taskId  = trans.trTaskId_gg00;

#   ifdef SAPDB_SLOW
    switch( recMode )
    {
    case rmTemp_ebd02:
        t01int4( bd_io, "free tmp pno", pageNo );
        break;
    case rmPermDynamic_ebd02:
        t01int4( bd_io, "free dyn pno", pageNo );
        break;
    case rmPermStatic_ebd02:
        t01int4( bd_io, "free sta pno", pageNo );
        break;
    default:
        ;
    }
#   endif

    bd13_InitPageState (nodeState, plmLock_ebd00, bIsFirstInit);
    nodeState.cpsSynchSvpAndTreeSplits_bd02.becomes( synchNone_ebd02 );

    while(( e_ok == trError ) && ( !bPageLockedToFree ))
    {
        bd20LockPageForFree( taskId, trError, fileId, pageNo, recMode,
                             bFirstCall, bPageLockedToFree, nodeState, pNodes.np_ptr(),
                             REFCAST_MEO00 (tbd02_pDataCBlock) &pNodes.np_cbptr() );

        if( e_ok != trError )
        {
            if(( e_sysbuffer_overflow == trError ) || ( e_no_more_temp_space == trError ))
            {
                bd13_OverflowReaction( taskId, pageNo, current.curr_action, 240, 
                    trError, retryCount );
                continue;
            }
            break; //fatal error has occured
        }

        bFirstCall = false;
        if( nodeState.cpsWaitForWrite_bd02 )
        {
            bd13_MsgAndSuspend( trans, pageNo, b_await_w, WAIT_FOR_WRITE, 44 );
            nodeState.cpsWaitForWrite_bd02 = false;
            continue;
        }
        if( nodeState.cpsDirty_bd02 )
        {
            bd13_WriteOldOccupant( trans, pNodes.np_ptr(), pNodes.np_cbptr(),
                                   pageNo, recMode, nodeState, !NEW_NODE );
            continue;
        }
    }

    if( e_ok != trError )
        return;

    // pNodes.np_cbptr() is available but pNodes.np_ptr() do not have to point to the valid page

    switch( recMode )
    {
    case rmTemp_ebd02:
        {
            SAPDBERR_ASSERT_STATE( fileId.fileType_gg00().includes( ftsTemp_egg00 ));

            Converter_IPageNoManager::Instance().FreeTempPageNo( taskId, pageNo );

            if( ! fileId.fileType_gg00().includes( ftsShared_egg00 )){
                --trans.trTempCount_gg00;
                --trans.trRteCommPtr_gg00->temp_page_cnt;
            }
        }
        break;
    case rmPermDynamic_ebd02:
        Converter_IPageNoManager::Instance().FreePermDynamicPageNo( taskId, pageNo, pageConverterVersion );
        break;
    case rmPermStatic_ebd02:
        Converter_IPageNoManager::Instance().FreePermStaticPageNo( taskId, pageNo, pageConverterVersion );
        break;
    default:
        ;
    }

    if( 0 < bd20GetPageUsageCount( pNodes.np_cbptr() ))
    {
        // Caused by the different possibilities to free a page it's difficult to decide
        // whether the page reference count should be decremented or not. For example:
        // bd13GetNode -> bd13RRelease -> bd13FreePageNo(bd13_FreeNode) => no decrement
        // bd13GetNode -> bd13FreePageNo(bd13_FreeNode) => decrement
        // bd13FreePageNo(bd13_FreeNode) without reading the temporary page before => no decrement

        --current.currCounter_bd00;
    }

    bd20FreePage( taskId, pageNo, recMode, trError, trans.trBdExclFileLocks_gg00 );

#   ifdef SAPDB_SLOW
    t01int4( bd_io, "CurrCounter ", current.currCounter_bd00 );
#   endif

};

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

#ifdef SAPDB_SLOW
inline void
bd13_GetNodeTraceInfo(
    const tsp00_PageNo              pageNo,
    const tbd02_RecoveryMode        recMode,
    const SAPDB_Bool                bIsRoot,
    const tbd_node_request_Param    nodeRequest )
{
    switch( recMode )
    {
    case rmTemp_ebd02 :
        if( bIsRoot ){
            t01int4( bd_io, "GetTempRoot ", pageNo );
        }
        else
            t01int4( bd_io, "GetTempPno  ", pageNo );
        break;
    case rmPermDynamic_ebd02:
        if( bIsRoot ){
            t01int4( bd_io, "GetPermRoot ", pageNo );
        }
        else
            t01int4( bd_io, "GetPermPno  ", pageNo );
        break;
    case rmPermStatic_ebd02:
        t01int4( bd_io, "GetStaticPno", pageNo );
        break;
    default:
        ;
    }

    switch( nodeRequest )
    {
    case nr_for_read:
        t01sname( bd_io, "Read Request" );
        break;
    case nr_for_update:
        t01sname( bd_io, "Upd Request " );
        break;
    default:
        t01sname( bd_io, "NoOp Request" );
    }
};
#endif


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