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

  module      : vbd490.cpp

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

  author      : TorstenS
  responsible : TorstenS

  special area: CreateIndexCoordinator
  description : 


  last changed: 1999-07-21  14:00
  see also    : 

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

  copyright:    (c) 1999-2004 SAP AG



    ========== licence begin  GPL
    Copyright (c) 1999-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                                                                 *
 *===========================================================================*/

                      // Content of include files
#include "gbd490.h"
/* */
#include "gbd491.h"   // CPP   : CreateIndexParticipant
#include "ggg11.h"    // PASCAL: GG_vtrace_types
#include "hbd01.h"    // PASCAL: filesysteminterface_1
#include "hbd03.h"    // CPP   : filesysteminterface_3
#include "hbd50.h"    // PASCAL: Indexhandling
#include "hkb53.h"    // PASCAL: KB_transaction
#include "hkb90.h"    // PASCAL: KB_sender_receiver
#include "hgg01.h"    // PASCAL: Configuration_Parameter
#include "hgg01_1.h"  // PASCAL: Configuration_Parameter
#include "hgg01_3.h"  // PASCAL: Configuration_Parameter
#include "SAPDB/SAPDBCommon/SAPDB_RangeCode.hpp" // Kernel_move_and_fill
#include "hgg10.h"
#include "heo56.h"    // RTE   : Vsleep

#include "Trace/Trace_Entry.hpp"

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

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

#define IN_REGION_BD490         true

#define MAX_RETRIES_BD490       10

#define CANCEL_MSG_1_BD490      "Index Coordinator Canceled              "
#define SEND_MSG_1_BD490        "All ServerTasks Are Busy                "
#define PROCESS_MSG_1_BD490     "Start Process Keyrange Without Server   "
#define PROCESS_MSG_2_BD490     "Stop Process Keyrange Without Server    "


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



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

struct tbd490_ReceiveDataPart {
    tgg00_IndexCounter rdpIndexCounter;
    tsp00_PageNo       rdpFirstLeafPno;
    tsp00_Bool         rdpEntriesExist;
    tsp00_Bool         rdpErrorOnBaseTable;
};

struct tbd490_SendDataPart {
	tsp00_PageNo	sdpPrimQueuePno;
	tsp00_PageNo    sdpSecQueuePno;
    tsp00_Int4		sdpNumLeavesToScan;
    tsp00_Int4		sdpAvgRecordsPerLeaf;
    tsp00_Int4		sdpStartPrimKeyLen;
    tsp00_Int4		sdpStopPrimKeyLen;
    tgg00_IndexMode sdpIndexMode;
    tsp00_Bool      sdpUseMemorySort;
    tsp00_Int2      sdpFiller1;
    tsp00_Int4      sdpFiller2;
    tsp00_Key		sdpStartPrimKey;
    tsp00_Key		sdpStopPrimKey;
};

struct tbd490_SendQualPart {
    tgg00_FileId    sqpPrimFileId; // pay attention to item sequence in tgg00_QualBuf
    tgg00_StackDesc sqpStackDesc;  // otherwise vtrace output (!) is not good
    tgg00_FileId    sqpInvFileId;
};

/*===========================================================================*
 *  EXTERNAL VARIABLES                                                       *
 *===========================================================================*/



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



/*===========================================================================*
 *  LOCAL VARIABLES                                                          *
 *===========================================================================*/



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

inline void
bd490_AddIndexCounter (tgg00_IndexCounter       &SourceCounter,
                       const tgg00_IndexCounter &AddCounter);

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

inline tsp00_Int4
bd490_GetEstimatedRecordsPerLeaf (tsp00_Int4 NumPrimLeafs,
                                  tsp00_Int4 NumPrimRecords,
                                  tsp00_Int4 AvgRecordsPerLeaf);

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

void
bd490InitIndexCounter (tgg00_IndexCounter  &IndexCounter)
{
    IndexCounter.idc_prim_leafnodes = 0;
    IndexCounter.idc_sec_leafnodes  = 0;
    IndexCounter.idc_prim_keycount  = 0;
    IndexCounter.idc_sec_keycount   = 0;
    IndexCounter.idc_nullcount      = 0;
}

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

inline void
bd490_AddIndexCounter (tgg00_IndexCounter       &SourceCounter,
                       const tgg00_IndexCounter &AddCounter)
{
    bd490Inc (SourceCounter.idc_prim_leafnodes, AddCounter.idc_prim_leafnodes);
    bd490Inc (SourceCounter.idc_sec_leafnodes,  AddCounter.idc_sec_leafnodes);
    bd490Inc (SourceCounter.idc_prim_keycount,  AddCounter.idc_prim_keycount);
    bd490Inc (SourceCounter.idc_sec_keycount,   AddCounter.idc_sec_keycount);
    bd490Inc (SourceCounter.idc_nullcount,      AddCounter.idc_nullcount);
}

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

inline tsp00_Int4
bd490_GetEstimatedRecordsPerLeaf (tsp00_Int4 NumPrimLeafs,
                                  tsp00_Int4 NumPrimRecords,
                                  tsp00_Int4 AvgRecordsPerLeaf)
{
    ROUTINE_DBG_MEO00 ("bd490_GetEstimatedRecordsPerLeaf");
    
    
    if ((0 != NumPrimLeafs) && (0 != NumPrimRecords))
        AvgRecordsPerLeaf = (NumPrimRecords / NumPrimLeafs);
    
    return (AvgRecordsPerLeaf + (AvgRecordsPerLeaf * 3 / 10) + 5); // +30 % security
}

/*===========================================================================*
 *  DEFINITION OF METHODS DECLARED IN gbd490.h (CODE)                        * 
 *===========================================================================*/


cbd490_CreateIndexParallel::cbd490_CreateIndexParallel(
                                                       cbd494_SortableInvTree  &InvTree,
                                                       tbd_current_tree        &PrimCurrent,
                                                       tgg00_StackDesc         &StackDesc,
                                                       tgg00_IndexCounter      &IndexCounter,
                                                       tgg00_IndexMode         IndexMode
                                                       )
                                                       :
m_TrError               (PrimCurrent.curr_trans->trError_gg00),
m_Trans                 (*PrimCurrent.curr_trans),
m_PrimCurrent           (PrimCurrent),
m_IndexCounter          (IndexCounter),
m_IndexMode             (IndexMode),
m_NumUsableServerTasks  (0), // PTS 1104880 TS 1999-12-06 
m_Stack                 (PrimCurrent.curr_trans->trError_gg00, StackDesc),
m_FileList              (*PrimCurrent.curr_trans, InvTree, m_Stack.bd497IsInvUnique())
{
    ROUTINE_DBG_MEO00 ("cbd490_CreateIndexParallel");


	if (e_ok != m_TrError) return;

    bd490InitIndexCounter (m_IndexCounter);

    m_NumUsableServerTasks = bd01UsableServerForParallelExecution (
        PrimCurrent.curr_trans->trTaskId_gg00, 
        tgg00_MessType::fromConst(m_create_index_parallel),! IN_REGION_BD490);
}

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

cbd490_CreateIndexParallel::~cbd490_CreateIndexParallel ()
{
    ROUTINE_DBG_MEO00 ("~cbd490_CreateIndexParallel");
    
   // Call Destructor for FileList
}

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

void 
cbd490_CreateIndexParallel::bd490BuildIndex( tsp00_Bool &bErrorOnBaseTable )
{
    ROUTINE_DBG_MEO00 ("bd490BuildIndex");


    tsp00_Bool    bNoMorePrimData   = false;
    /* */
    tsp00_Int4    CurrFileIndex     = 0;
    tsp00_Int4    AvgRecordsPerLeaf = 0;
    tsp00_Int4    NumLeavesToScan   = 0;
    tsp00_Int4    NumSendOrders     = 0;
    tsp00_Int4    RetryCount        = 0;
    tsp00_Int4    StartPrimKeyLen   = 0;
    tsp00_Int4    StopPrimKeyLen    = 0;
	/* */
	tsp00_PageNo  PrimQueuePno;
	tsp00_PageNo  SecQueuePno;
    /* */
    tgg00_FileId  QueueId;
    /* */
    tsp00_Key     StartPrimKey;
    tsp00_Key	  StopPrimKey;
    /* */
    tsp00_BytePtr pStartPrimKey = REINTERPRET_CAST (tsp00_BytePtr, &StartPrimKey);
    tsp00_BytePtr pStopPrimKey  = REINTERPRET_CAST (tsp00_BytePtr, &StopPrimKey);

    if (0>= m_NumUsableServerTasks) 
	{
		m_TrError = e_no_more_memory; 
		return;
	}

    while 
        (
        ((e_ok == m_TrError) && (! bNoMorePrimData)) || ((e_too_many_net_requests == m_TrError))
        )
	{
        if ((e_ok == m_TrError) && (create_index == m_IndexMode))
        {
            m_FileList.bd496CreateFile (CurrFileIndex, QueueId,	PrimQueuePno, SecQueuePno);
        }

        if (e_ok == m_TrError)
        {
            bd50DetermineKeyRangeForServer (m_PrimCurrent, 
                pStartPrimKey, StartPrimKeyLen, pStopPrimKey, StopPrimKeyLen, 
                NumLeavesToScan, AvgRecordsPerLeaf, bNoMorePrimData);
            
            if( e_ok != m_TrError )
                bErrorOnBaseTable = true;

            AvgRecordsPerLeaf = bd490_GetEstimatedRecordsPerLeaf (
                m_IndexCounter.idc_prim_leafnodes, m_IndexCounter.idc_prim_keycount,
                AvgRecordsPerLeaf);
        }

        if ((e_ok == m_TrError) || (e_too_many_net_requests == m_TrError))
        {
            bd490_SendKeyRangeToServer (CurrFileIndex, NumLeavesToScan, AvgRecordsPerLeaf,
                pStartPrimKey, StartPrimKeyLen, pStopPrimKey, StopPrimKeyLen,
                NumSendOrders, RetryCount, QueueId, PrimQueuePno, SecQueuePno);
        }

        if  (
            ( 
            (e_ok == m_TrError) &&
            ((NumSendOrders == m_NumUsableServerTasks) || (bNoMorePrimData)) 
            )
            ||
            ((e_file_limit == m_TrError) && (NumSendOrders > 0))
            ||
            ((e_too_many_net_requests == m_TrError) && (NumSendOrders > 0))
            )
        {
            bd490_WaitForReply (bNoMorePrimData, NumSendOrders, bErrorOnBaseTable);
        }

        if ((e_too_many_net_requests == m_TrError ) &&
            (0 == NumSendOrders                   ) && 
            (MAX_RETRIES_BD490 <= RetryCount      ))
        {
            bd490_ProcessKeyRangeByCoordinator (CurrFileIndex, NumLeavesToScan, AvgRecordsPerLeaf, 
                pStartPrimKey, StartPrimKeyLen, pStopPrimKey, StopPrimKeyLen, RetryCount, QueueId,
                PrimQueuePno, SecQueuePno, bErrorOnBaseTable);
        }

        if (
            (create_index == m_IndexMode)              &&
            (
            ((e_ok == m_TrError) && (bNoMorePrimData)) || 
            (e_file_limit == m_TrError               )
            )
            )
        {
            m_FileList.bd496MergeFiles (bNoMorePrimData, m_Stack, m_IndexCounter);
        }

        if  (
            (e_ok == m_TrError                   ) && 
            (! bNoMorePrimData                   ) &&
            (m_Trans.trRteCommPtr_gg00->to_cancel)
            )
        {
            m_TrError = e_cancelled;
            g01optextmsg (sp3p_knldiag, sp3m_info, BD490_CANCEL_1_SP03,
                  csp3_n_index, CANCEL_MSG_1_BD490);
        }
    }

    if (e_ok != m_TrError)
    {
        bd490_TaskAbortHandling (NumSendOrders);
        if (create_index == m_IndexMode) m_FileList.bd496DeleteAllFiles();
    }
}

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

void 
cbd490_CreateIndexParallel::bd490_ProcessKeyRangeByCoordinator (
                                                                tsp00_Int4       CurrFileIndex,
                                                                tsp00_Int4       NumLeavesToScan,
                                                                tsp00_Int4       AvgRecordsPerLeaf,
                                                                tsp00_BytePtr    pStartPrimKey,
                                                                tsp00_Int4       StartPrimKeyLen,
                                                                tsp00_BytePtr    pStopPrimKey,
                                                                tsp00_Int4       StopPrimKeyLen,
                                                                tsp00_Int4      &RetryCount,
                                                                tgg00_FileId    &QueueId,
                                                                tsp00_PageNo     PrimQueuePno,
                                                                tsp00_PageNo     SecQueuePno,
                                                                tsp00_Bool      &bErrorOnBaseTable
                                                                )
{
    ROUTINE_DBG_MEO00 ("bd490_ProcessKeyRangeByCoordinator");
    

    if (e_too_many_net_requests == m_TrError) m_TrError = e_ok;
    
    if (e_ok != m_TrError) return;
    
    tsp00_Bool          bEntriesExist;
    tsp00_PageNo        FirstLeafPno = NIL_PAGE_NO_GG00;
    tgg00_IndexCounter  AuxCounter;
    tgg00_StackDesc     AuxStackDesc =  m_Stack.bd497GetStackDesc(); // reduce code check errors
    
    RetryCount = 0;

    g01optextmsg (sp3p_knldiag, sp3m_warning,
        BD490_PROCESS_KEY_RANGE_SP03, csp3_n_index, PROCESS_MSG_1_BD490);
    
    bd03ParticipantCreateIndex (m_Trans, m_PrimCurrent.curr_tree_id, QueueId, 
        AuxStackDesc, pStartPrimKey, pStopPrimKey, StartPrimKeyLen, StopPrimKeyLen, 
        NumLeavesToScan, AvgRecordsPerLeaf, PrimQueuePno, SecQueuePno, 
        (create_index == m_IndexMode), m_IndexMode, AuxCounter, FirstLeafPno, 
        bEntriesExist, bErrorOnBaseTable);

    if (create_index == m_IndexMode)
    {
        if (NIL_PAGE_NO_GG00 != FirstLeafPno)   
            m_FileList.bd496ConvertFile (CurrFileIndex, FirstLeafPno);
        
        if (! bEntriesExist)
            m_FileList.bd496DeleteFile (CurrFileIndex);
        
        if (e_ok == m_TrError) bd490_AddIndexCounter (m_IndexCounter, AuxCounter);
        
        if (g01vtrace.vtrAll_gg00 || g01vtrace.vtrBdIndex_gg00)
        {
            tgg11_BdRootTrace RootTrace;
            
            RootTrace.bdrTrType_gg11.becomes(bdtrRoot_egg11);
            RootTrace.bdrError_gg11  = m_TrError;
            RootTrace.bdrRoot_gg11   = m_IndexCounter.idc_prim_keycount;

            Trace_CommonEntry( m_Trans, tgg00_Debug::fromConst(bd), tgg00_VtraceType::fromConst(b03create), 
                    REINTERPRET_CAST( tsp00_BytePtr, &RootTrace ), sizeof (RootTrace) );
        }
    }
    g01optextmsg (sp3p_knldiag, sp3m_warning,
        BD490_PROCESS_KEY_RANGE_SP03, csp3_n_index, PROCESS_MSG_2_BD490);
}

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

void 
cbd490_CreateIndexParallel::bd490_SendKeyRangeToServer (
                                                        tsp00_Int4       CurrFileIndex,
                                                        tsp00_Int4       NumLeavesToScan,
                                                        tsp00_Int4       AvgRecordsPerLeaf,
                                                        tsp00_BytePtr    pStartPrimKey,
                                                        tsp00_Int4       StartPrimKeyLen,
                                                        tsp00_BytePtr    pStopPrimKey,
                                                        tsp00_Int4       StopPrimKeyLen,
                                                        tsp00_Int4      &NumSendOrders,
                                                        tsp00_Int4      &RetryCount,
                                                        tgg00_FileId    &TempFileId,
                                                        tsp00_PageNo     PrimQueuePno,
                                                        tsp00_PageNo     SecQueuePno
                                                        )                                                        
{
    ROUTINE_DBG_MEO00 ("bd490_SendKeyRangeToServer");


    tgg00_BasisError    AuxError = (e_ok == m_TrError) ? e_ok : m_TrError;
    /* */
    tsp00_Int4          DataPartLen = 0;
    tsp00_Int4          QualPartLen = 0;
    /* */
    tgg00_MessBlock     SendMBlock;
    tgg00_TransChild    SendTrans;
    /* */
    tbd490_SendDataPart SendDataPart;
    tbd490_SendQualPart SendQualPart;


    if (e_ok != m_TrError)
        m_TrError = e_ok; // m_TrError could be only e_too_many_net_requests 
   
    k53child_trans_build (m_create_index_parallel, CurrFileIndex, SendTrans);
    SendTrans.tcdChild_gg00 = CurrFileIndex;

    g01mblock_init (m_Trans, m_create_index_parallel, mm_participant, SendMBlock);
    
    g01stack_init (SendMBlock, 
          m_Stack.bd497GetStackListPtr(), m_Stack.bd497GetStackSize(),
          REINTERPRET_CAST (tgg00_QualBufPtr, &SendQualPart), 
          sizeof (SendQualPart)); 

    g01datapart_init (SendMBlock, REINTERPRET_CAST (tgg00_DataPartPtr ,&SendDataPart), 
        sizeof (SendDataPart));
    
    // Fill DataPart of MessBlock
    // Note that SendMBlock.mb_data is a pointer to SendDataPart
	
	SendDataPart.sdpPrimQueuePno = PrimQueuePno;
    DataPartLen += sizeof (SendDataPart.sdpPrimQueuePno);

	SendDataPart.sdpSecQueuePno = SecQueuePno;
    DataPartLen += sizeof (SendDataPart.sdpSecQueuePno);

    SendDataPart.sdpNumLeavesToScan = NumLeavesToScan; 
    DataPartLen += sizeof (SendDataPart.sdpNumLeavesToScan);

    SendDataPart.sdpAvgRecordsPerLeaf = AvgRecordsPerLeaf; 
    DataPartLen += sizeof (SendDataPart.sdpAvgRecordsPerLeaf);

    SendDataPart.sdpStartPrimKeyLen = StartPrimKeyLen;
    DataPartLen += sizeof (SendDataPart.sdpStartPrimKeyLen);

    SendDataPart.sdpStopPrimKeyLen  = StopPrimKeyLen;
    DataPartLen += sizeof (SendDataPart.sdpStopPrimKeyLen);

    SendDataPart.sdpIndexMode = m_IndexMode;
    DataPartLen += sizeof (SendDataPart.sdpIndexMode);
    
    SendDataPart.sdpUseMemorySort = (create_index == m_IndexMode);
    DataPartLen += sizeof (SendDataPart.sdpUseMemorySort);
    
    SendDataPart.sdpFiller1 = 0;
    DataPartLen += sizeof (SendDataPart.sdpFiller1);
    
    SendDataPart.sdpFiller2 = 0;
    DataPartLen += sizeof (SendDataPart.sdpFiller2);

    g10mv( __FILE__, 1,    
        MAX_KEYLEN_GG00, sizeof (SendDataPart), 
        pStartPrimKey, POS_OFF_DIFF_BD00,
        &SendDataPart, DataPartLen + POS_OFF_DIFF_BD00, 
        StartPrimKeyLen, m_TrError);
    
    if (e_ok != m_TrError) return;
    DataPartLen += StartPrimKeyLen;
    
    g10mv( __FILE__, 2,    
        MAX_KEYLEN_GG00, sizeof (SendDataPart), 
        pStopPrimKey, POS_OFF_DIFF_BD00,
        &SendDataPart, DataPartLen + POS_OFF_DIFF_BD00, 
        StopPrimKeyLen, m_TrError);
    
    if (e_ok != m_TrError) return;
    DataPartLen += StopPrimKeyLen;
    
    SendMBlock.mb_data_len () = DataPartLen;
    
    // Fill QualPart of MessBlock
    // Note that SendMBlock.mb_qual is a pointer to SendQualPart
    
    g10mv( __FILE__, 3,    
        sizeof (m_PrimCurrent.curr_tree_id), sizeof (SendQualPart), 
        &m_PrimCurrent.curr_tree_id, POS_OFF_DIFF_BD00,
        &SendQualPart, QualPartLen + POS_OFF_DIFF_BD00, 
        sizeof (m_PrimCurrent.curr_tree_id), m_TrError);
    
    if (e_ok != m_TrError) return;
    QualPartLen += sizeof (m_PrimCurrent.curr_tree_id);
    
    g10mv( __FILE__, 4,    
        m_Stack.bd497GetStackDescSize(), sizeof (SendQualPart), 
        &m_Stack.bd497GetStackDesc(), POS_OFF_DIFF_BD00,
        &SendQualPart, QualPartLen + POS_OFF_DIFF_BD00, 
        m_Stack.bd497GetStackDescSize(), m_TrError);
    
    if (e_ok != m_TrError) return;
    QualPartLen += m_Stack.bd497GetStackDescSize();
    
    g10mv( __FILE__, 5,    
        sizeof (TempFileId), sizeof (SendQualPart), 
        &TempFileId, POS_OFF_DIFF_BD00,
        &SendQualPart, QualPartLen + POS_OFF_DIFF_BD00, 
        sizeof (TempFileId), m_TrError);
    
    if (e_ok != m_TrError) return;
    QualPartLen += sizeof (TempFileId);

    SendMBlock.mb_qual_len () = QualPartLen;

    if (e_ok == m_TrError)
    {
        k90send (SendMBlock, SendTrans);

        if (e_ok == m_TrError)  ++NumSendOrders;
        else if (e_too_many_net_requests == m_TrError)
        {
            g01optextmsg (sp3p_knldiag, sp3m_warning, BD490_SEND_SP03, 
                csp3_n_index, SEND_MSG_1_BD490);
            ++RetryCount;
            vsleep (m_Trans.trTaskId_gg00, 1);
        }
    }
    
    if ((e_ok == m_TrError) && (e_too_many_net_requests == AuxError))
    {
        RetryCount = 0;
        m_TrError  = e_ok;
    }
}

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

void 
cbd490_CreateIndexParallel::bd490_TaskAbortHandling (
                                                     tsp00_Int4 &NumSendOrders
                                                     )
{
    ROUTINE_DBG_MEO00 ("bd490_TaskAbortHandling");


    tgg00_BasisError    AuxError = m_TrError;
    /* */
    tgg00_MessBlock     ReceiveMBlock;
    tgg00_TransChild    ReceiveTrans;
    /* */
    tbd490_ReceiveDataPart ReceiveDataPart;
   
    m_TrError = e_ok;

    while (0 < NumSendOrders)
    {
        // Read DataPart of MessBlock
        // Note that ReceiveMBlock.mb_data is a pointer to ReceiveDataPart

        g01mblock_init (m_Trans, m_nil, mm_nil, ReceiveMBlock);
        g01datapart_init (ReceiveMBlock, 
            REINTERPRET_CAST (tgg00_DataPartPtr, &ReceiveDataPart), 
            sizeof (ReceiveDataPart));

        k90rcv_child (ReceiveMBlock, ReceiveTrans);
        if (e_ok == m_TrError) --NumSendOrders;
    }
    m_TrError = AuxError;
}

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

void 
cbd490_CreateIndexParallel::bd490_WaitForReply (
                                                tsp00_Bool   bNoMorePrimData,
                                                tsp00_Int4  &NumSendOrders,
                                                tsp00_Bool  &bErrorOnBaseTable
                                                )
{
    ROUTINE_DBG_MEO00 ("bd490_WaitForReply");


    tgg00_BasisError    AuxError = (e_ok == m_TrError) ? e_ok : m_TrError;
     /* */
    tsp00_Int4          DataPartLen = 0;
    tsp00_Int4          QualPartLen = 0;
    tsp00_Int4          OldNumSendOrders = NumSendOrders;
    /* */
    tgg00_MessBlock     ReceiveMBlock;
    tgg00_TransChild    ReceiveTrans;
    /* */
    tbd490_ReceiveDataPart ReceiveDataPart;

    if (e_ok != m_TrError) m_TrError = e_ok; // Real error is stored within AuxError
    
#   if COMPILEMODE_MEO00 >= SLOW_MEO00 
    t01bool (bd_idx_create, "Finish      ", bNoMorePrimData);
    t01int4 (bd_idx_create, "NumSendOrder", NumSendOrders);
#   endif

    while 
        (
        (
        (e_ok == m_TrError) &&
        (
        ((0 < NumSendOrders) && (bNoMorePrimData)                        ) || 
        ((NumSendOrders == m_NumUsableServerTasks) && (! bNoMorePrimData))
        )
        )
        ||
        (
        (e_file_limit == AuxError) && (0 < NumSendOrders)
        )
        ||
        (
        (e_too_many_net_requests == AuxError) && (NumSendOrders == OldNumSendOrders)
        )
        )
    {
        // Read DataPart of MessBlock
        // Note that ReceiveMBlock.mb_data is a pointer to ReceiveDataPart

        g01mblock_init (m_Trans, m_nil, mm_nil, ReceiveMBlock);
        g01datapart_init (ReceiveMBlock, 
            REINTERPRET_CAST (tgg00_DataPartPtr, &ReceiveDataPart), 
            sizeof (ReceiveDataPart));

        k90rcv_child (ReceiveMBlock, ReceiveTrans);

        if (e_ok != m_TrError) return;
        --NumSendOrders;

        if (e_ok != ReceiveTrans.tcdError_gg00) 
        {
            m_TrError = ReceiveTrans.tcdError_gg00;
            return;
        }

        bd490_AddIndexCounter (m_IndexCounter, ReceiveDataPart.rdpIndexCounter);
        bErrorOnBaseTable = ReceiveDataPart.rdpErrorOnBaseTable;

        if (create_index == m_IndexMode)
        {
            if (NIL_PAGE_NO_GG00 != ReceiveDataPart.rdpFirstLeafPno)   
                m_FileList.bd496ConvertFile (ReceiveTrans.tcdChild_gg00, 
                                             ReceiveDataPart.rdpFirstLeafPno);
            
            if (! ReceiveDataPart.rdpEntriesExist)
            {
                // Result file from servertask is empty
                m_FileList.bd496DeleteFile (ReceiveTrans.tcdChild_gg00);
                
                if (e_file_limit == AuxError)
                {
                    // Don't merge if a ServerTask returns an empty file and
                    // the original error says that no empty file is available
                    AuxError = e_ok;
                }
            }
            if (g01vtrace.vtrAll_gg00 || g01vtrace.vtrBdIndex_gg00)
            {
                tgg11_BdRootTrace RootTrace;
                
                RootTrace.bdrTrType_gg11.becomes(bdtrRoot_egg11);
                RootTrace.bdrError_gg11  = m_TrError;
                RootTrace.bdrRoot_gg11   = m_IndexCounter.idc_prim_keycount;
                
                Trace_CommonEntry( m_Trans, tgg00_Debug::fromConst(bd), tgg00_VtraceType::fromConst(b03create), 
                    REINTERPRET_CAST( tsp00_BytePtr, &RootTrace ), sizeof (RootTrace) );
            }
        }
    }
    if ((e_ok == m_TrError) && (e_ok != AuxError))  
        m_TrError = AuxError;

#   if COMPILEMODE_MEO00 >= SLOW_MEO00 
    t01int4 (bd_idx_create, "PrimLeafNode",m_IndexCounter.idc_prim_leafnodes);
    t01bool (bd_idx_create, "BaseTableErr", bErrorOnBaseTable);
#   endif
}


/*---------------------------------------------------------------------------*/
    
cbd490_CreateIndexSequential::cbd490_CreateIndexSequential (
                                                            cbd300_InvCurrent       &InvCurrent,
                                                            tbd_current_tree        &PrimCurrent,
                                                            tgg00_StackDesc         &StackDesc,
                                                            tgg00_IndexCounter      &IndexCounter,
                                                            tgg00_IndexMode			IndexMode
                                                            )
                                                            :
m_TrError		(PrimCurrent.curr_trans->trError_gg00),
m_Trans			(*PrimCurrent.curr_trans),
m_InvCurrent    (InvCurrent),
m_PrimCurrent	(PrimCurrent),
m_IndexCounter	(IndexCounter),
m_IndexMode		(IndexMode),
m_Stack         (PrimCurrent.curr_trans->trError_gg00, StackDesc)
{
    ROUTINE_DBG_MEO00 ("cbd490_CreateIndexSequential");
    
    
    if (e_ok != m_TrError) return;
    
    bd490InitIndexCounter (m_IndexCounter);
}

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

cbd490_CreateIndexSequential::~cbd490_CreateIndexSequential()
{
    ROUTINE_DBG_MEO00 ("~cbd490_CreateIndexSequential");
    
    if (e_ok == m_TrError) 
        m_IndexCounter.idc_sec_leafnodes = m_InvCurrent.bd300GetRootLeafCount();
}

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

void
cbd490_CreateIndexSequential::bd490BuildIndex( tsp00_Bool &bErrorOnBaseTable )
{
     ROUTINE_DBG_MEO00 ("bd490BuildIndex");
     

     tsp00_Bool         bEntriesExist;

     tsp00_Int4         StartPrimKeyLen = 0;;
     tsp00_Int4         StopPrimKeyLen  = MAX_KEYLEN_GG00;

     tsp00_BytePtr      pStartPrimKey = NULL;
     tsp00_BytePtr      pStopPrimKey =  REINTERPRET_CAST (tsp00_BytePtr, &b01fullkey);

     tgg00_StackDesc    StackDesc =  m_Stack.bd497GetStackDesc(); // reduce code check errors
     

     cbd491_CreateIndexParticipant Participant (m_PrimCurrent, StackDesc, m_IndexCounter, false);
     
     Participant.bd491InsertionSort (m_InvCurrent, m_IndexMode, pStartPrimKey, pStopPrimKey, 
         StartPrimKeyLen, StopPrimKeyLen, bEntriesExist, bErrorOnBaseTable);
}

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