/* Copyright (C) 2014 InfiniDB, Inc.

   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; version 2 of
   the License.

   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., 51 Franklin Street, Fifth Floor, Boston,
   MA 02110-1301, USA. */

/******************************************************************************************
* $Id: we_indextree.cpp 4450 2013-01-21 14:13:24Z rdempsey $
*
******************************************************************************************/
/** @file */

#include <stdio.h>
#include <string.h>

#define WRITEENGINEINDEXTREE_DLLEXPORT
#include "we_indextree.h"
#undef WRITEENGINEINDEXTREE_DLLEXPORT

namespace WriteEngine
{

/**
 * Constructor
 */
IndexTree::IndexTree()
    : m_useFreeMgr( true ), m_useListMgr( true ), m_useMultiCol( false), m_useMultiRid( false ), m_assignFbo( 0 )
{
    clearBlock( &m_rootBlock );
}

/**
 * Default Destructor
 */
IndexTree::~IndexTree()
{}

/*
   const int IndexTree::getIndexTreeBitTestEntry( uint64_t entry, short* entryType, int* bitTest, int* group, int32_t* treePointer )
   {
      *treePointer = entry & IDX_PTR_MASK;
      entry = entry >> IDX_PTR_SIZE + 2; // skip one spare bit and bit-compare bit

      *group = entry & THREE_BIT_MASK;
      entry = entry >> IDX_GROUP_SIZE;

      *bitTest = entry & TEN_BIT_MASK;
      *entryType = entry >> IDX_BITTEST_SIZE;

      *entryType = entry & THREE_BIT_MASK;

      return NO_ERROR;
   }

   const void IndexTree::setIndexTreeBitTestEntry( uint64_t* entry, short entryType, int bitTest, int group, int32_t treePointer )
   {
      memset( entry, 0, ROW_PER_BYTE );

      *entry = treePointer | group << ( IDX_PTR_SIZE + 2 );
      *entry = *entry | bitTest << ( IDX_PTR_SIZE + 2 + IDX_GROUP_SIZE );
      *entry = *entry | entryType << ( IDX_PTR_SIZE + 2 + IDX_GROUP_SIZE + IDX_TYPE_SIZE );

      return NO_ERROR;
   }
*/
/***********************************************************
 * DESCRIPTION:
 *    Clear the tree
 * PARAMETERS:
 *    myTree - tree pointer
 * RETURN:
 *    none
 ***********************************************************/
void IndexTree::clearTree( IdxTree* myTree )
{
    myTree->width = myTree->key = myTree->rid = myTree->maxLevel = 0;

    for ( int i = 0; i < IDX_MAX_TREE_LEVEL; i++ )
        clearTreeNode( &myTree->node[i] );
}

/***********************************************************
 * DESCRIPTION:
 *    Clear the tree node
 * PARAMETERS:
 *    myNode - node pointer
 * RETURN:
 *    none
 ***********************************************************/
void IndexTree::clearTreeNode( IdxTreeNode* myNode )
{
    myNode->level = 0;
    myNode->allocCount = 0;
    myNode->useCount = 0;
//      myNode->group = 0;
    myNode->used = false;
    setBlankEntry( &myNode->next );
    setBlankEntry( &myNode->current );
}


/***********************************************************
 * DESCRIPTION:
 *    Assign segment from free manager
 * PARAMETERS:
 *    segmentType - group type
 *    assignPtr - the assigned ptr
 *    no - internal debug use flag
 * RETURN:
 *    NO_ERROR if success
 *    error no if fail
 ***********************************************************/
const int IndexTree::assignSegment( int segmentType, IdxEmptyListEntry* assignPtr, int no )
{
    int rc = NO_ERROR;

    m_rootBlock.dirty = true;

    if ( m_useFreeMgr )
    {
        if ( isDebug( DEBUG_3 ))
        {
            printf( "\n++++++ Before Assign");
            printMemSubBlock( &m_rootBlock, 0, true );
        }

        rc = m_freeMgr.assignSegment( /*m_pTreeFile*/m_cbTree, &m_rootBlock, TREE, (IdxTreeGroupType) segmentType, assignPtr /*, TREE */);

        if ( isDebug( DEBUG_3 ))
        {
            printf( "\nAssign the pointer, entry segment=%d fbo=%2d sbid=%2d entry=%2d", segmentType, (int)assignPtr->fbo, (int)assignPtr->sbid, (int)assignPtr->entry );
            printMemSubBlock( &m_rootBlock, 0, true );
        }
    }
    else
    {
        assignPtr->fbo = 1 + m_assignFbo;
        assignPtr->sbid = 3 + no;
        assignPtr->entry = 4 ;
    }

    return rc;
}


/***********************************************************
 * DESCRIPTION:
 *    Build a complete empty tree branch
 * PARAMETERS:
 *    key - key value
 *    width - key width
 *    rid - row id
 *    rootTestbitVal - test bit test value at root level
 * RETURN:
 *    NO_ERROR if success
 *    error no if fail
 ***********************************************************/
const int IndexTree::buildEmptyIndexTreeBranch( const uint64_t key, const int width, const RID rid, const int rootTestbitVal )
{
    int                     rc;
    IdxBitmapPointerEntry   bitmapEntry = {0};

    rc = buildEmptyTreePart( key, width, rid, 1 );

    // set the root level bitmapPointerMap
    bitmapEntry.type = BITMAP_PTR; //BIT_TEST;
    bitmapEntry.fbo = m_tree.node[0].next.fbo;
    bitmapEntry.sbid = m_tree.node[0].next.sbid;
    bitmapEntry.entry = m_tree.node[0].next.entry;

    setSubBlockEntry( m_rootBlock.data, IDX_BITMAP_SUBBLOCK_NO, rootTestbitVal, MAX_COLUMN_BOUNDARY, &bitmapEntry );
    m_rootBlock.dirty = true;

    return rc;
}

/***********************************************************
 * DESCRIPTION:
 *    Build exist index tree branch
 * PARAMETERS:
 *    key - key value
 *    width - key width
 *    rid - row id
 *    rootTestbitVal - test bit at root level
 *    bitmapEntry - current bitmap entry
 * RETURN:
 *    NO_ERROR if success
 *    error no if fail
 ***********************************************************/
const int IndexTree::buildExistIndexTreeBranch( const uint64_t key, const int width, const RID rid, const int rootTestbitVal, IdxBitmapPointerEntry bitmapEntry )
{
    int                     rc = NO_ERROR, loopCount, testbitVal, i, j, allocCount, realCount, matchPos, moveCount, parentLevel = 0, curLevel, curOffset = 0;
    bool                    bSuccess;
    IdxEmptyListEntry       assignPtrEntry, releasePtrEntry;
    IdxBitTestEntry         bittestEntry, matchBitTestEntry, parentBitTestEntry, curEntry;
    DataBlock               curBlock, parentBlock;
    bool                    bAddFlag = false, bDone = false, bFound, bExitOuterLoop, bExitInnerLoop, entryMap[ENTRY_PER_SUBBLOCK];

    bExitOuterLoop = false;
    loopCount = m_tree.maxLevel;

    for ( i = 1; !bExitOuterLoop && i < loopCount; i++ )
    {
        // load the block
        rc = readSubBlockEntry( m_cbTree, &curBlock, m_tree.node[parentLevel].next.fbo, m_tree.node[parentLevel].next.sbid,
                                m_tree.node[parentLevel].next.entry, MAX_COLUMN_BOUNDARY, &bittestEntry );

        if ( rc != NO_ERROR )
            return rc;

        if ( i == 1 && isAddrPtrEmpty( &bittestEntry, BIT_TEST ))
            return ERR_STRUCT_EMPTY;

        rc = getTreeNodeInfo( &curBlock, m_tree.node[parentLevel].next.sbid, m_tree.node[parentLevel].next.entry, width,
                              (IdxTreeGroupType)bittestEntry.group, &allocCount, &realCount, entryMap );

        if ( rc != NO_ERROR )
            return rc;


        matchBitTestEntry = bittestEntry;   // assign to the value of the first entry
        bSuccess = getTestbitValue( key, width, i, &testbitVal );

        setBittestEntry( &curEntry, testbitVal, bittestEntry.group, m_tree.node[parentLevel].next.fbo, m_tree.node[parentLevel].next.sbid, m_tree.node[parentLevel].next.entry );
        setTreeNode( &m_tree.node[i], i, allocCount, realCount, 0, bittestEntry, curEntry );

        matchBitTestEntry.bitTest = testbitVal;
        bFound = getTreeMatchEntry( &curBlock, m_tree.node[parentLevel].next.sbid, m_tree.node[parentLevel].next.entry,
                                    width, allocCount, entryMap, &matchPos, &matchBitTestEntry );

        if ( !bFound )   // this testbit not exist at the current level
        {
            bExitOuterLoop = true;    // tell to exit the outer loop
            bAddFlag = true;

            if ( allocCount < realCount + 1 ) // we have enough space to take care of the extra one
            {
                // we don't have space to take care of the extra one, have to reassign to a big block
                if ( bittestEntry.group >= ENTRY_32 )            // it's impossible this condition holds true
                    return ERR_IDX_TREE_INVALID_GRP;

                m_tree.node[i].current.group++;
                rc = assignSegment( m_tree.node[i].current.group, &assignPtrEntry, i );

                if ( rc != NO_ERROR )
                    return rc;

                m_tree.node[i].allocCount = 0x1 << m_tree.node[i].current.group;

                if ( isDebug( DEBUG_3 ))
                {
                    printf( "\nEntry starting from %d:%d:%d (type %d ) will move to %d:%d:%d (type %d)", (int)m_tree.node[parentLevel].next.fbo, (int)m_tree.node[parentLevel].next.sbid, (int)m_tree.node[parentLevel].next.entry, (int)(m_tree.node[i].current.group - 1),
                            (int)assignPtrEntry.fbo, (int)assignPtrEntry.sbid, (int)assignPtrEntry.entry, (int)m_tree.node[i].current.group );
                    printf( "\nNew space capacity is %d", (int)m_tree.node[i].allocCount );
                    printf( "\nBefore the move" );
                    printSubBlock( m_tree.node[parentLevel].next.fbo, m_tree.node[parentLevel].next.sbid );
                    printSubBlock( assignPtrEntry.fbo, assignPtrEntry.sbid );
                }

                rc = moveEntry( m_tree.node[parentLevel].next.fbo, m_tree.node[parentLevel].next.sbid, m_tree.node[parentLevel].next.entry, width,
                                assignPtrEntry.fbo, assignPtrEntry.sbid, assignPtrEntry.entry, m_tree.node[i].current.group,
                                allocCount, entryMap, &moveCount, m_tree.node[i].allocCount );

                if ( rc != NO_ERROR )
                    return rc;

                if (  isDebug( DEBUG_3 ))
                {
                    printf( "\nAfter the move" );
                    printSubBlock( m_tree.node[parentLevel].next.fbo, m_tree.node[parentLevel].next.sbid );
                    printSubBlock( assignPtrEntry.fbo, assignPtrEntry.sbid );
                }

                if ( moveCount != realCount )
                    return ERR_IDX_TREE_MOVE_ENTRY;

                // set release entry
                setEmptyListEntry( &releasePtrEntry, bittestEntry.group, m_tree.node[parentLevel].next.fbo, m_tree.node[parentLevel].next.sbid, m_tree.node[parentLevel].next.entry );

                if ( i == 1 )   // handle bitmap parent
                {
                    bitmapEntry.fbo = m_tree.node[0].next.fbo = m_tree.node[i].current.fbo = assignPtrEntry.fbo;
                    bitmapEntry.sbid = m_tree.node[0].next.sbid = m_tree.node[i].current.sbid = assignPtrEntry.sbid;
                    bitmapEntry.entry = m_tree.node[0].next.entry = m_tree.node[i].current.entry = assignPtrEntry.entry;
                    setSubBlockEntry( m_rootBlock.data, IDX_BITMAP_SUBBLOCK_NO, rootTestbitVal, MAX_COLUMN_BOUNDARY, &bitmapEntry );
                }
                else   // handle parent for the rest of levels in the tree
                {
                    rc = readSubBlockEntry( m_cbTree, &parentBlock, m_tree.node[parentLevel].current.fbo, m_tree.node[parentLevel].current.sbid,
                                            m_tree.node[parentLevel].current.entry, MAX_COLUMN_BOUNDARY, &parentBitTestEntry );

                    if ( rc != NO_ERROR )
                        return rc;

                    parentBitTestEntry.fbo = m_tree.node[parentLevel].next.fbo = m_tree.node[i].current.fbo = assignPtrEntry.fbo;
                    parentBitTestEntry.sbid = m_tree.node[parentLevel].next.sbid = m_tree.node[i].current.sbid = assignPtrEntry.sbid;
                    parentBitTestEntry.entry = m_tree.node[parentLevel].next.entry = m_tree.node[i].current.entry = assignPtrEntry.entry;

                    rc = writeSubBlockEntry( m_cbTree, &parentBlock, m_tree.node[parentLevel].current.fbo, m_tree.node[parentLevel].current.sbid,
                                             m_tree.node[parentLevel].current.entry, MAX_COLUMN_BOUNDARY, &parentBitTestEntry );

                    if ( rc != NO_ERROR )
                        return rc;
                }

                // here's the work to release the ptr
                rc = releaseSegment( bittestEntry.group, &releasePtrEntry );

                if ( rc != NO_ERROR )
                    return rc;

            } // end of if( allocCount >=

            // take care of rest of empty part
            rc = readSubBlockEntry( m_cbTree, &curBlock, m_tree.node[parentLevel].next.fbo, m_tree.node[parentLevel].next.sbid,
                                    m_tree.node[parentLevel].next.entry, MAX_COLUMN_BOUNDARY, &bittestEntry );

            if ( rc != NO_ERROR )
                return rc;

            m_tree.node[i].current.bitTest = testbitVal;
            matchBitTestEntry.group = m_tree.node[i].current.group;
            m_tree.node[i].allocCount = 0x1 << m_tree.node[i].current.group;

            bExitInnerLoop = false;

            for ( j = 0; !bExitInnerLoop && j < m_tree.node[i].allocCount; j++ )
                if ( !entryMap[j] )          // here's the empty spot
                {

                    if ( m_tree.maxLevel > 2 && i != loopCount - 1 )
                    {
                        rc = buildEmptyTreePart( key, width, rid, i + 1, 0 );

                        if ( rc != NO_ERROR )
                            return rc;

                        bDone = true;
                    }

                    // check out of bound
                    rc = readSubBlockEntry( m_cbTree, &curBlock, m_tree.node[parentLevel].next.fbo, m_tree.node[parentLevel].next.sbid,
                                            m_tree.node[parentLevel].next.entry + j, MAX_COLUMN_BOUNDARY, &bittestEntry );

                    if ( rc != NO_ERROR )
                        return rc;

                    matchBitTestEntry.fbo = m_tree.node[i + 1].current.fbo;
                    matchBitTestEntry.sbid = m_tree.node[i + 1].current.sbid;
                    matchBitTestEntry.entry = m_tree.node[i + 1].current.entry;

                    rc = writeSubBlockEntry( m_cbTree, &curBlock, m_tree.node[parentLevel].next.fbo, m_tree.node[parentLevel].next.sbid,
                                             m_tree.node[parentLevel].next.entry + j, MAX_COLUMN_BOUNDARY, &matchBitTestEntry );

                    if ( rc != NO_ERROR )
                        return rc;

                    m_tree.node[i].useCount++;

                    m_tree.node[i].current.entry += j;
                    entryMap[j] = true;
                    curOffset = j;

                    bExitInnerLoop = true;
                } // end of if( !entryMap[j] )

        } // end of if( !bFound
        else
        {
            m_tree.node[i].current.entry += matchPos;
            m_tree.node[parentLevel].next.entry += matchPos;
        }

        m_tree.node[i].next = matchBitTestEntry;
        parentLevel++;
    } // end of for( i = 1;

    curLevel = m_tree.maxLevel - 1;

    if ( !bDone )
    {
        rc = updateListFile( key, width, rid, curLevel, m_tree.node[curLevel].current.group, m_tree.node[curLevel].allocCount, m_tree.node[curLevel].useCount, curOffset, bAddFlag );
    }

    return rc;
}

/***********************************************************
 * DESCRIPTION:
 *    Build a a part of empty tree branch
 * PARAMETERS:
 *    key - key value
 *    width - key width
 *    rid - row id
 *    startLevel - tree level
 * RETURN:
 *    NO_ERROR if success
 *    error no if fail
 *    retBitTestEntry - return address pointer
 ***********************************************************/
const int IndexTree::buildEmptyTreePart( const uint64_t key, const int width, const RID rid, const int startLevel, const int offset )
{
    int                     rc, loopCount, testbitVal, i, parentLevel;
    bool                    bSuccess;
    IdxEmptyListEntry       assignPtrEntry, childPtrEntry;//, listEntry;
    IdxBitTestEntry         bittestEntry, curEntry;
    DataBlock               curBlock;

    if ( startLevel <= 0 || m_tree.maxLevel < 2 )              // the start level must >= 1 and maxLevel >= 2
        return ERR_IDX_TREE_INVALID_LEVEL;

    loopCount = (m_tree.maxLevel - 1) > 1 ? m_tree.maxLevel - 1 : 0; //( width/5 ) - 1;

    rc = assignSegment( ENTRY_1, &assignPtrEntry, 0 );

    if ( rc != NO_ERROR )
        return rc;

    if ( isAddrPtrEmpty( &assignPtrEntry, EMPTY_LIST ) )
        return ERR_STRUCT_EMPTY;

    parentLevel = startLevel - 1;

    // assuming the parent take care of group, bit test value, and type
    m_tree.node[parentLevel].next.fbo = assignPtrEntry.fbo;
    m_tree.node[parentLevel].next.sbid = assignPtrEntry.sbid;
    m_tree.node[parentLevel].next.entry = assignPtrEntry.entry;

    // assign bit test for rest of levels
    for ( i = startLevel; i < loopCount; i++ )
    {
        // assign another one for child
        rc = assignSegment( ENTRY_1, &childPtrEntry, i );

        if ( rc != NO_ERROR )
            return rc;

        rc = readSubBlockEntry( m_cbTree, &curBlock, m_tree.node[parentLevel].next.fbo, m_tree.node[parentLevel].next.sbid,
                                m_tree.node[parentLevel].next.entry, /*width*/MAX_COLUMN_BOUNDARY, &bittestEntry );

        if ( rc != NO_ERROR )
            return rc;

        bSuccess = getTestbitValue( key, width, i, &testbitVal );

        if ( !bSuccess )
            return ERR_IDX_TREE_INVALID_LEVEL;

        setBittestEntry( &bittestEntry, testbitVal, ENTRY_1, childPtrEntry.fbo, childPtrEntry.sbid, childPtrEntry.entry );
        setSubBlockEntry( &curBlock, m_tree.node[parentLevel].next.sbid, m_tree.node[parentLevel].next.entry, MAX_COLUMN_BOUNDARY, &bittestEntry );

        writeDBFile( m_cbTree, &curBlock, m_tree.node[parentLevel].next.fbo );

        setBittestEntry( &curEntry, testbitVal, ENTRY_1, m_tree.node[parentLevel].next.fbo, m_tree.node[parentLevel].next.sbid, m_tree.node[parentLevel].next.entry );
        setTreeNode( &m_tree.node[i], i, 1, 1, 0, bittestEntry, curEntry );
        parentLevel++;
    }

    // assign the bit test for the last level
    // load the last piece
    rc = updateListFile( key, width, rid, i, ENTRY_1, 1, 1, offset, true );

    return rc;
}


/***********************************************************
 * DESCRIPTION:
 *    Close index files
 * PARAMETERS:
 *    none
 * RETURN:
 *    none
 ***********************************************************/
void IndexTree::closeIndex()
{

    if ( m_rootBlock.dirty )
    {
        uint64_t lbid0 = 0;
#ifdef BROKEN_BY_MULTIPLE_FILES_PER_OID
        BRMWrapper::getInstance()->getBrmInfo( m_cbTree.file.oid, 0, lbid0 );
#endif
        writeDBFile( m_cbTree, m_rootBlock.data, lbid0);
    }

    if ( Cache::getUseCache() )
        flushCache();

    m_fileopTree.closeFile( m_cbTree.file.pFile );
    m_fileopList.closeFile( m_cbList.file.pFile );
    m_cbTree.file.pFile = NULL;
    m_cbList.file.pFile = NULL;
    clear();
}

/***********************************************************
 * DESCRIPTION:
 *    Create index related files
 * PARAMETERS:
 *    treeFid - the index tree file id
 *    listFid - the index list file id
 *    useFreeMgrFlag - internal use flag
 * RETURN:
 *    NO_ERROR if success
 *    error no if fail
 ***********************************************************/
const int IndexTree::createIndex( const FID treeFid, const FID listFid, const bool useFreeMgrFlag )
{
#ifdef BROKEN_BY_MULTIPLE_FILES_PER_OID
    int allocSize;

    // init
//     clear();

    RETURN_ON_ERROR( createFile( treeFid, DEFAULT_TOTAL_BLOCK/* * 10*/, allocSize ) );
    RETURN_ON_ERROR( createFile( listFid, DEFAULT_TOTAL_BLOCK/* * 10*/, allocSize ) );
#endif

    // load index files
//      RETURN_ON_ERROR( openIndex( treeFid, listFid ) );
//      rc = initIndex( treeFid, listFid );
//      closeIndex();

    return initIndex( treeFid, listFid );
}

/***********************************************************
 * DESCRIPTION:
 *    Delete a value from the tree
 * PARAMETERS:
 *    key - key value
 *    width - key width
 *    rid - row id
 * RETURN:
 *    NO_ERROR if success
 *    error no if fail
 ***********************************************************/
const int IndexTree::deleteIndex( const uint64_t key, const int width, const RID rid  )
{
    IdxEmptyListEntry listHdrAddr;

    return processIndex( key, width, rid, listHdrAddr );
}


/***********************************************************
 * DESCRIPTION:
 *    Get test bit values
 * PARAMETERS:
 *    key - index key
 *    width - key width
 *    curTestNo - test bit iteration no
 * RETURN:
 *    True if success, otherwise if out of bound
 *    bittestVal - test bit value
 ***********************************************************/
const bool IndexTree::getTestbitValue( const uint64_t key, const int width, const int curTestNo, int* bittestVal )
{
    int   shiftPos, maskPos = 0;
    bool  bSuccess = true;

    if ( !m_useMultiCol )
    {
        *bittestVal = 0;
        shiftPos = width - ( curTestNo + 1 ) * 5;

        if ( shiftPos > 0 )
            *bittestVal = getBitValue( key, shiftPos, BIT_MASK_ARRAY[5] );
        else
        {
            if ( shiftPos >= -4 )
            {
                maskPos = width - curTestNo  * 5 ;
                *bittestVal = key & BIT_MASK_ARRAY[maskPos];
            }
            else
                bSuccess = false;
        }
    }
    else
        *bittestVal = m_multiColKey.testbitArray[curTestNo];

    return bSuccess;
}


/***********************************************************
 * DESCRIPTION:
 *    Get the matching entry within the current tree node
 * PARAMETERS:
 *    block - block data
 *    fbo, sbid, entry - pointer address
 *    width - key width
 *    allocCount - the total number of allocated entries
 *    entryMap - the entry availablibility map
 *    checkEntry - bittest value
 * RETURN:
 *    True if found, False otherwise
 *    checkEntry - if found the ptr got reset
 ***********************************************************/
const bool IndexTree::getTreeMatchEntry( DataBlock* block, const uint64_t sbid, const uint64_t entry, const int width,
        const int allocCount, const bool* entryMap, int* matchEntry, IdxBitTestEntry* checkEntry )
{
    IdxBitTestEntry   curEntry;
    bool              bFoundFlag = false;

    for ( int i = 0; i < allocCount; i++ )
    {
        getSubBlockEntry( block->data, sbid, entry + i, MAX_COLUMN_BOUNDARY, &curEntry );

        if ( entryMap[i] && ( curEntry.type == checkEntry->type && curEntry.bitTest == checkEntry->bitTest ) )
        {
            *checkEntry = curEntry;
            *matchEntry = i;
            bFoundFlag = true;
            break;
        }
    }

    return bFoundFlag;
}

/***********************************************************
 * DESCRIPTION:
 *    Get tree node summary information
 * PARAMETERS:
 *    block - block data
 *    fbo, sbid, entry - pointer address
 *    width - key width
 *    group - entry group
 *    testbitVal - current bit test value
 * RETURN:
 *    NO_ERROR if success
 *    error no if fail
 *    allocCount - the total number of allocated entries
 *    realCount - the total number of real entries
 *    entryMap - the entry availablibility map
 ***********************************************************/
const int IndexTree::getTreeNodeInfo( DataBlock* block, const uint64_t sbid, const uint64_t entry, const int width,
                                      const IdxTreeGroupType group, int* allocCount, int* realCount, bool* entryMap )
{
    IdxBitTestEntry   curEntry;
    int               rc = NO_ERROR;

    memset( entryMap, false, ENTRY_PER_SUBBLOCK );
    *realCount = 0;
    *allocCount = 0x1 << group;

    for ( int i = 0; i < *allocCount; i++ )
    {
        getSubBlockEntry( block->data, sbid, entry + i, MAX_COLUMN_BOUNDARY, &curEntry );

        if ( curEntry.type == BIT_TEST || curEntry.type == LEAF_LIST )            // every guy here must have the same type
        {
            entryMap[i] = true;
            *realCount = *realCount + 1;
        }
        else if ( curEntry.type == EMPTY_ENTRY )
            entryMap[i] = false;
        else
            rc = ERR_IDX_TREE_INVALID_TYPE;

        if ( rc != NO_ERROR )
            break;
    }

    return rc;
}

/***********************************************************
 * DESCRIPTION:
 *    Check index entry address pointer is empty or not
 * PARAMETERS:
 *    pStruct - index entry pointer
 *    entryType - the entry type
 * RETURN:
 *    True if empty, False otherwise
 ***********************************************************/
const bool IndexTree::isAddrPtrEmpty( void* pStruct, const IdxTreeEntryType entryType ) const
{
    bool                    bStatus;
    IdxBitmapPointerEntry*  pBitmap;
    IdxBitTestEntry*        pBittest;
    IdxEmptyListEntry*      pEmptyList;


    switch ( entryType )
    {
        case BITMAP_PTR/*EMPTY_PTR*/ :  // this is the case for bitmap pointer address
            pBitmap = (IdxBitmapPointerEntry*) pStruct;
            bStatus = /*!pBitmap->oid &&*/ !pBitmap->fbo && !pBitmap->sbid && !pBitmap->entry;
            break;

        case BIT_TEST :   // this is the case for bittest pointer address
            pBittest = (IdxBitTestEntry*) pStruct;
            bStatus = /*!pBittest->oid &&*/ !pBittest->fbo && !pBittest->sbid && !pBittest->entry;
            break;

        case EMPTY_LIST :   // this is the case for bittest pointer address
            pEmptyList = (IdxEmptyListEntry*) pStruct;
            bStatus = !pEmptyList->fbo && !pEmptyList->sbid && !pEmptyList->entry;
            break;

        default  :
            bStatus = true;
    }

    return bStatus;
}

const int IndexTree::initIndex( const FID treeFid, const FID listFid )
{
    int            rc = NO_ERROR;
    long           numOfBlock;
    unsigned char  writeBuf[BYTE_PER_BLOCK];

    bool oldUseVb = BRMWrapper::getUseVb();
    BRMWrapper::setUseVb( false );

    clear();
    RETURN_ON_ERROR( openIndex( treeFid, listFid ) );

    memset( writeBuf, 0, BYTE_PER_BLOCK );
    numOfBlock = getFileSize( m_cbTree.file.pFile ) / BYTE_PER_BLOCK;

    for ( int i = 0; i < numOfBlock; i++ )
        fwrite( writeBuf, sizeof( writeBuf ), 1, m_cbTree.file.pFile );

    numOfBlock = getFileSize( m_cbList.file.pFile ) / BYTE_PER_BLOCK;

    for ( int i = 0; i < numOfBlock; i++ )
        fwrite( writeBuf, sizeof( writeBuf ), 1, m_cbList.file.pFile );

    // very weird, have to close before we can call free mgr init
    closeIndex();
    RETURN_ON_ERROR( openIndex( treeFid, listFid ) );

    rc = m_freeMgr.init( m_cbTree, TREE );

    if ( rc == NO_ERROR )
        rc = m_freeMgr.init( m_cbList, LIST );

    closeIndex();

    BRMWrapper::setUseVb( oldUseVb );

    if ( isDebug( DEBUG_1 ) )
        printf( "\nEnd of the init for oid %d\n", m_cbTree.file.oid );

    return rc;
}

/***********************************************************
 * DESCRIPTION:
 *    Move tree entries
 * PARAMETERS:
 *    fbo, sbid, entry - pointer address
 *    width - key width
 *    allocCount - the total number of allocated entries
 *    entryMap - the entry availablibility map
 * RETURN:
 *    NO_ERROR if success
 *    error no if fail
 ***********************************************************/
const int IndexTree::moveEntry( const uint64_t oldFbo, const uint64_t oldSbid, const uint64_t oldEntry, const int width, const uint64_t newFbo,
                                const uint64_t newSbid, const uint64_t newEntry, const int newGroup, const int allocCount, bool* entryMap, int* moveCount, const int newAllocCount )
{
    int               rc, i;
    DataBlock         oldBlock, newBlock;
    IdxBitTestEntry   curEntry, blankEntry;

    rc = readSubBlockEntry( m_cbTree, &oldBlock, oldFbo, oldSbid, oldEntry, /*width*/MAX_COLUMN_BOUNDARY, &curEntry );

    if ( rc != NO_ERROR )
        return rc;

    rc = readSubBlockEntry( m_cbTree, &newBlock, newFbo, newSbid, newEntry, /*width*/MAX_COLUMN_BOUNDARY, &curEntry );

    if ( rc != NO_ERROR )
        return rc;

    setBlankEntry( &blankEntry );

    for ( i = 0; i < newAllocCount; i++ )
        setSubBlockEntry( newBlock.data, newSbid, newEntry + i, MAX_COLUMN_BOUNDARY, &blankEntry );

    *moveCount = 0;

    for ( i = 0; i < allocCount; i++ )
    {
        getSubBlockEntry( oldBlock.data, oldSbid, oldEntry + i, MAX_COLUMN_BOUNDARY, &curEntry );

        if ( entryMap[i] )
        {
            curEntry.group = newGroup;
            setSubBlockEntry( newBlock.data, newSbid, newEntry + *moveCount, MAX_COLUMN_BOUNDARY, &curEntry );
            *moveCount = *moveCount + 1;

        }

        setBlankEntry( &curEntry );

        if ( newFbo != oldFbo )
            setSubBlockEntry( oldBlock.data, oldSbid, oldEntry + i, MAX_COLUMN_BOUNDARY, &curEntry );
        else
            setSubBlockEntry( newBlock.data, oldSbid, oldEntry + i, MAX_COLUMN_BOUNDARY, &curEntry );
    }

    rc = writeDBFile( m_cbTree, &newBlock, newFbo );

    if ( rc != NO_ERROR )
        return rc;

    if ( newFbo != oldFbo )
        rc = writeDBFile( m_cbTree, &oldBlock, oldFbo );

    // reset map
    memset( entryMap, false, ENTRY_PER_SUBBLOCK );

    for ( i = 0; i < *moveCount; i++ )
        entryMap[i] = true;

    return rc;
}

/***********************************************************
 * DESCRIPTION:
 *    Open index related files
 * PARAMETERS:
 *    treeFid - the index tree file id
 *    listFid - the index list file id
 * RETURN:
 *    NO_ERROR if success
 *    error no if fail
 ***********************************************************/
const int IndexTree::openIndex( const FID treeFid, const FID listFid  )
{
    int rc = NO_ERROR;
    clear();

    // load index files
#ifdef BROKEN_BY_MULTIPLE_FILES_PER_OID
    m_cbTree.file.pFile = m_fileopTree.openFile( treeFid );
#endif

    if ( m_cbTree.file.pFile == NULL )
        return ERR_FILE_OPEN;

#ifdef BROKEN_BY_MULTIPLE_FILES_PER_OID
    m_cbList.file.pFile = m_fileopList.openFile( listFid );
#endif

    if ( m_cbList.file.pFile == NULL )
    {
        m_fileopTree.closeFile( m_cbTree.file.pFile );       // close the one just open
        return ERR_FILE_OPEN;
    }

    m_cbTree.file.oid = treeFid;
    m_cbList.file.oid = listFid;

    uint64_t lbid0 = 0;
#ifdef BROKEN_BY_MULTIPLE_FILES_PER_OID
    rc = BRMWrapper::getInstance()->getBrmInfo( m_cbTree.file.oid, 0, lbid0 );
#endif

    if ( rc != NO_ERROR )
    {
        if ( isDebug( DEBUG_1 ) )
        {
            printf( "\nFor oid : %d block zero is %ld", m_cbTree.file.oid, (long)lbid0 );
            printf( "\nIn open index, have problem in get brmInfo, rc=%d", rc );
        }

        return rc;
    }

    rc = readDBFile( m_cbTree, m_rootBlock.data, lbid0 );

    return rc;
}

/***********************************************************
 * DESCRIPTION:
 *    Process index, including search or delete
 * PARAMETERS:
 *    key - key value
 *    width - key width
 *    rid - row id
 *    listHdrAddr - list header address
 *    bDelete - delete operation flag
 * RETURN:
 *    NO_ERROR if success
 *    error no if fail
 ***********************************************************/
const int IndexTree::processIndex( const uint64_t key, const int width, const RID rid, IdxEmptyListEntry& listHdrAddr, const bool bDelete  )
{
    int                     loopCount, testbitVal, i, allocCount, realCount, matchPos, curFbo, curSbid, curEntry;
    bool                    bSuccess;
    IdxEmptyListEntry       listEntry;
    IdxBitTestEntry         bittestEntry, matchBitTestEntry;
    DataBlock               curBlock;
    bool                    bFound, entryMap[ENTRY_PER_SUBBLOCK];

    int                     rootTestbitVal, rc = NO_ERROR;
    IdxBitmapPointerEntry   bitmapEntry;

    getTestbitValue( key, width, 0, &rootTestbitVal );
    getSubBlockEntry( m_rootBlock.data, 1, rootTestbitVal, MAX_COLUMN_BOUNDARY, &bitmapEntry );

    if ( isAddrPtrEmpty( &bitmapEntry, /*EMPTY_PTR*/BITMAP_PTR ) )
        return bDelete ? ERR_IDX_LIST_INVALID_DELETE : NOT_FOUND ;

    // get the rootbittestEntry level bitmapPointerMap
    curFbo = bitmapEntry.fbo;
    curSbid = bitmapEntry.sbid;
    curEntry = bitmapEntry.entry;

    loopCount = width / 5 + 1;

    for ( i = 1; i < loopCount; i++ )
    {
        // load the block
        rc = readSubBlockEntry( m_cbTree, &curBlock, curFbo, curSbid, curEntry, /*width*/MAX_COLUMN_BOUNDARY, &bittestEntry );

        if ( rc != NO_ERROR )
            return rc;

        if ( isDebug( DEBUG_3 ) )
        {
            printf( "\nIn processIndex, level %d", i );
            printSubBlock( curFbo, curSbid );
        }

        rc = getTreeNodeInfo( &curBlock, curSbid, curEntry, width, (IdxTreeGroupType)bittestEntry.group, &allocCount, &realCount, entryMap );

        if ( rc != NO_ERROR )
            return rc;

        matchBitTestEntry = bittestEntry;   // assign to the value of the first entry
        bSuccess = getTestbitValue( key, width, i, &testbitVal );

        matchBitTestEntry.bitTest = testbitVal;
        bFound = getTreeMatchEntry( &curBlock, curSbid, curEntry, width, allocCount, entryMap, &matchPos, &matchBitTestEntry );

        if ( bFound )   // this test bit exists at the current level
        {
            if ( i == loopCount - 1 )
            {
//               if( loopCount == 2 )   // because of bitmap, it requires a special treatment
                curEntry += matchPos;
                break;
            }
        }
        else
            return NOT_FOUND;

        getSubBlockEntry( &curBlock, curSbid, curEntry + matchPos, MAX_COLUMN_BOUNDARY, &matchBitTestEntry );

        curFbo = matchBitTestEntry.fbo;
        curSbid = matchBitTestEntry.sbid;
        curEntry = matchBitTestEntry.entry;

    } // end of for( i = 0;

    // here's the last level
    // load the last piece
    rc = readSubBlockEntry( m_cbTree, &curBlock, curFbo, curSbid, curEntry /*+ matchPos*/, MAX_COLUMN_BOUNDARY, &bittestEntry );

    if ( rc != NO_ERROR )
        return rc;

    listEntry.fbo = bittestEntry.fbo;
    listEntry.sbid = bittestEntry.sbid;
    listEntry.entry = bittestEntry.entry;

    if ( bDelete )
    {
        rc = m_listMgr.deleteIndexList( m_cbList, rid, key, &listEntry );

        if ( rc != NO_ERROR )
            return rc;

        bSuccess = getTestbitValue( key, width, loopCount - 1, &testbitVal );
        setBittestEntry( &bittestEntry, testbitVal, bittestEntry.group, listEntry.fbo, listEntry.sbid, listEntry.entry, LEAF_LIST );
        setSubBlockEntry( &curBlock, curSbid, curEntry, MAX_COLUMN_BOUNDARY, &bittestEntry );

        rc = writeDBFile( m_cbTree, &curBlock, curFbo );

    }
    else
        listHdrAddr = listEntry;

    return rc;
}


/***********************************************************
 * DESCRIPTION:
 *    Print a sub block
 * PARAMETERS:
 *    fbo - file block offset
 *    sbid - sub block id
 * RETURN:
 *    none
 ***********************************************************/
void IndexTree::printSubBlock( const int fbo, const int sbid, const bool bNoZero )
{
    DataBlock         curBlock;

    readDBFile( m_cbTree, &curBlock, fbo );
    printf( "\n lbid=%2d sbid=%2d", fbo, sbid );
    printMemSubBlock( &curBlock, sbid );
}

void IndexTree::printMemSubBlock( DataBlock* curBlock, const int sbid, const bool bNoZero )
{
    int off;
    unsigned char*    curPos;
    IdxBitTestEntry   curEntry, testZero;

    setBlankEntry( &testZero );
    curPos = curBlock->data + BYTE_PER_SUBBLOCK * sbid;
    printf( "\n========================" );

    for ( int i = 0; i < ENTRY_PER_SUBBLOCK; i++ )
    {
        memcpy( &curEntry, curPos, MAX_COLUMN_BOUNDARY );
        off = memcmp( &testZero, &curEntry, MAX_COLUMN_BOUNDARY );
        printf( "\n Entry %2d : ", i );

        for ( int j = 0; j < MAX_COLUMN_BOUNDARY; j++ )
            printf( " %2X", *(curPos + j) );

        printf( " fbo=%2d sbid=%2d entry=%2d group=%d bit=%2d type=%2d", (int)curEntry.fbo, (int)curEntry.sbid, (int)curEntry.entry, (int)curEntry.group, (int)curEntry.bitTest, (int)curEntry.type );

        curPos += MAX_COLUMN_BOUNDARY;
    }

    printf( "\n" );
}

/***********************************************************
 * DESCRIPTION:
 *    Assign segment from free manager
 * PARAMETERS:
 *    segmentType - group type
 *    assignPtr - the assigned ptr
 *    no - internal debug use flag
 * RETURN:
 *    NO_ERROR if success
 *    error no if fail
 ***********************************************************/
const int IndexTree::releaseSegment( int segmentType, IdxEmptyListEntry* myPtr )
{
    int rc = NO_ERROR;

    m_rootBlock.dirty = true;

    if ( m_useFreeMgr )
    {
        if ( isDebug( DEBUG_3 ) )
            printf( "\n----------Release the pointer, entry segment=%d fbo=%d sbid=%d entry=%d", segmentType, (int)myPtr->fbo, (int)myPtr->sbid, (int)myPtr->entry );

        rc = m_freeMgr.releaseSegment( m_cbTree, &m_rootBlock, TREE, (IdxTreeGroupType) segmentType, myPtr/*, TREE */);

        if ( isDebug( DEBUG_3 ) )
            printf("\nReleased" );
    }

    return rc;
}

const int IndexTree::resetIndexFile( const FID treeFid, const FID listFid )
{
    /*      long numOfBlock;
          unsigned char  writeBuf[BYTE_PER_BLOCK];

          memset( writeBuf, 0, BYTE_PER_BLOCK );
          numOfBlock = getFileSize( m_cbTree.file.pFile )/BYTE_PER_BLOCK;
          for( int i = 0; i < numOfBlock; i++ )
             fwrite( writeBuf, sizeof( writeBuf ), 1, m_cbTree.file.pFile );

          numOfBlock = getFileSize( m_cbList.file.pFile )/BYTE_PER_BLOCK;
          for( int i = 0; i < numOfBlock; i++ )
             fwrite( writeBuf, sizeof( writeBuf ), 1, m_cbList.file.pFile );
    */
    return initIndex( treeFid, listFid );
}

/***********************************************************
 * DESCRIPTION:
 *    Calculate bit test array for multi column index
 * PARAMETERS:
 *    none
 * RETURN:
 *    NO_ERROR if success
 *    error no if fail
 ***********************************************************/
const int IndexTree::calculateBittestArray()
{
    if ( m_multiColKey.totalBit <= 0 )
        return ERR_INVALID_PARAM;

    m_multiColKey.maxLevel = m_multiColKey.totalBit / 5 + 1;

    if ( m_multiColKey.maxLevel > IDX_MAX_MULTI_COL_IDX_LEVEL )
        return ERR_VALUE_OUTOFRANGE;

    for ( int i = 0; i < m_multiColKey.maxLevel - 1; i++ )
    {
        m_multiColKey.curBitset = ( m_multiColKey.bitSet & m_multiColKey.curMask ) >> ( IDX_MAX_MULTI_COL_BIT - ( i + 1 ) * 5 );
        m_multiColKey.testbitArray[i] = m_multiColKey.curBitset.to_ulong();
        m_multiColKey.curMask = m_multiColKey.curMask >> 5;
    }

    m_multiColKey.curBitset = ( m_multiColKey.bitSet & m_multiColKey.curMask ) >> ( IDX_MAX_MULTI_COL_BIT - m_multiColKey.totalBit );
    m_multiColKey.testbitArray[m_multiColKey.maxLevel - 1] = m_multiColKey.curBitset.to_ulong();
    return NO_ERROR;
}

/***********************************************************
 * DESCRIPTION:
 *    Setup bit test array for multi column index
 * PARAMETERS:
 *    keyArray - index key array
 *    totalByte - total byte in the key
 * RETURN:
 *    NO_ERROR if success
 *    error no if fail
 ***********************************************************/
const int IndexTree::setBitsetColumn( void* val, const int pos, const int width, const ColType colType )
{
    int copyLen = width / 8;

    switch ( colType )
    {
        // No body is using float or double for indexing
        /*         case WriteEngine::WR_FLOAT :  m_multiColKey.curBitset = *((float*) val);
                                               break;
                 case WriteEngine::WR_DOUBLE : m_multiColKey.curBitset = *((double*) val);
                                               break;
        */
        case WriteEngine::WR_CHAR :
            m_multiColKey.curBitset.reset();

            for ( int i = 0; i < width / 8; i++ )
            {
                uint64_t curChar = ((char*)val)[i];
                m_multiColKey.curBitset = m_multiColKey.curBitset << 8;
                m_multiColKey.curBitset |= curChar;
            }

            memcpy( m_multiColKey.keyBuf + m_multiColKey.totalBit / 8, (char*) val, copyLen );
            break;

        case WriteEngine::WR_SHORT :
            m_multiColKey.curBitset = *((short*) val);
            memcpy( m_multiColKey.keyBuf + m_multiColKey.totalBit / 8, (short*) val, copyLen );
            break;

        case WriteEngine::WR_BYTE :
            m_multiColKey.curBitset = *((char*) val);
            memcpy( m_multiColKey.keyBuf + m_multiColKey.totalBit / 8, (char*) val, copyLen );
            break;

        case WriteEngine::WR_LONGLONG:
            m_multiColKey.curBitset = *((long long*) val);
            memcpy( m_multiColKey.keyBuf + m_multiColKey.totalBit / 8, (long long*) val, copyLen );
            break;

        case WriteEngine::WR_INT :
        case WriteEngine::WR_MEDINT :
        default  :
            memcpy( m_multiColKey.keyBuf + m_multiColKey.totalBit / 8, (int*) val, copyLen );
            m_multiColKey.curBitset = *((int*) val);
            break;
    }

    m_multiColKey.totalBit += width;
    m_multiColKey.curBitset = m_multiColKey.curBitset << ( IDX_MAX_MULTI_COL_BIT - m_multiColKey.totalBit );
    m_multiColKey.bitSet |= m_multiColKey.curBitset;
    return NO_ERROR;
}

/***********************************************************
 * DESCRIPTION:
 *    Set bit test entry
 * PARAMETERS:
 *    bittestEntry - the bit test entry
 *    testbitVal - current bit test value
 *    group - entry group
 *    fbo, sbid, entry - pointer address
 * RETURN:
 *    none
 ***********************************************************/
void IndexTree::setBittestEntry( IdxBitTestEntry* bittestEntry, const uint64_t testbitVal, const uint64_t group, const uint64_t fbo, const uint64_t sbid, const uint64_t entry, const uint64_t entryType ) const
{
    bittestEntry->type = entryType;
    bittestEntry->bitTest = testbitVal;
    bittestEntry->group = group;
    bittestEntry->bitCompare = BIT_5;
    bittestEntry->spare = 0;

    bittestEntry->fbo = fbo;
    bittestEntry->sbid = sbid;
    bittestEntry->entry = entry;
}

/***********************************************************
 * DESCRIPTION:
 *    Set empty list entry for free manager
 * PARAMETERS:
 *    bittestEntry - the bit test entry
 *    testbitVal - current bit test value
 *    group - entry group
 *    fbo, sbid, entry - pointer address
 * RETURN:
 *    none
 ***********************************************************/
// todo: need test case
void IndexTree::setEmptyListEntry( IdxEmptyListEntry* myEntry, const uint64_t group, const uint64_t fbo, const uint64_t sbid, const uint64_t entry ) const
{
    myEntry->type = EMPTY_PTR;
    myEntry->group = group;
    myEntry->spare = 0;
    myEntry->spare2 = 0;
    myEntry->fbo = fbo;
    myEntry->sbid = sbid;
    myEntry->entry = entry;
}

/***********************************************************
 * DESCRIPTION:
 *    Set the tree header node
 * PARAMETERS:
 *    myTree - tree pointer
 *    key - index key
 *    width - key width
 *    rid - ROW ID
 *    testbitVal - bit test value at root level
 *    bitmapEntry - bitmap entry
 * RETURN:
 *    none
 ***********************************************************/
void IndexTree::setTreeHeader( IdxTree* myTree, const uint64_t key, const RID rid, const int width,
                               const int testbitVal, const IdxBitmapPointerEntry bitmapEntry )
{
    IdxBitTestEntry nextEntry, curEntry;

    myTree->width = width;
    myTree->key = key;
    myTree->rid = rid;
    myTree->maxLevel = (width / 5) + 1;

    setBlankEntry( &nextEntry );
    setBlankEntry( &curEntry );

//      myEntry.bitTest = testbitVal;
    nextEntry.fbo = bitmapEntry.fbo;
    nextEntry.sbid = bitmapEntry.sbid;
    nextEntry.entry = bitmapEntry.entry;
    nextEntry.type = BIT_TEST;

//      nextEntry.group = ENTRY_32;

    curEntry.fbo = 0;
    curEntry.sbid = IDX_BITMAP_SUBBLOCK_NO;
    curEntry.entry = testbitVal;
    curEntry.type = BITMAP_PTR;
    curEntry.group = ENTRY_32;
    curEntry.bitTest = testbitVal;


    // at this point useCount not known
    setTreeNode( &myTree->node[0], 0, ENTRY_PER_SUBBLOCK, 0, testbitVal, nextEntry, curEntry );
}

/***********************************************************
 * DESCRIPTION:
 *    Set the tree node
 * PARAMETERS:
 *    myNode - node pointer
 *    level - current tree level
 *    allocCount - allocated count
 *    useCount - used count
 *    offset - entry offset
 *    nextEntry - next entry
 *    curEntry - current entry
 * RETURN:
 *    none
 ***********************************************************/
void IndexTree::setTreeNode( IdxTreeNode* myNode, const int level, const int allocCount, const int useCount,
                             const int offset, const IdxBitTestEntry nextEntry, const IdxBitTestEntry curEntry )
{
    myNode->level = level;
    myNode->allocCount = allocCount;
    myNode->useCount = useCount;
    myNode->offset = offset;
    myNode->next = nextEntry;
    myNode->current = curEntry;
    myNode->used = true;
}


const bool IndexTree::isTreeEmpty()
{
    bool                    bEmpty = true;
    IdxBitmapPointerEntry   curBitmapPointer, emptyPointer;

    memset( &emptyPointer, 0, MAX_COLUMN_BOUNDARY );

    for ( int i = 0; i < 32; i++ )
    {
        getSubBlockEntry( m_rootBlock.data, IDX_BITMAP_SUBBLOCK_NO, i, MAX_COLUMN_BOUNDARY, &curBitmapPointer );

        if ( memcmp( &curBitmapPointer, &emptyPointer, MAX_COLUMN_BOUNDARY ) )
        {
            bEmpty = false;
            break;
        }
    }

//      printMemSubBlock( &m_rootBlock, IDX_BITMAP_SUBBLOCK_NO );
    return bEmpty;
}

/***********************************************************
 * DESCRIPTION:
 *    Allocate Row ID
 * PARAMETERS:
 *    tableFid - the file id for table bitmap file
 *    totalRow - the total number of rows need to be allocated
 * RETURN:
 *    NO_ERROR if success
 *    rowIdArray - allocation of the row id left here
 ***********************************************************/
const int IndexTree::updateIndex( const uint64_t key, const int width, const RID rid )
{
    int                     rootTestbitVal, rc = NO_ERROR;
    IdxBitmapPointerEntry   curBitmapPointer;

    clearTree( &m_tree );

    getTestbitValue( key, width, 0, &rootTestbitVal );
    getSubBlockEntry( m_rootBlock.data, IDX_BITMAP_SUBBLOCK_NO, rootTestbitVal, MAX_COLUMN_BOUNDARY, &curBitmapPointer );

    setTreeHeader( &m_tree, key, rid, width, rootTestbitVal, curBitmapPointer );

    if ( m_tree.maxLevel > IDX_MAX_TREE_LEVEL )
        return ERR_VALUE_OUTOFRANGE;

    if ( isAddrPtrEmpty( &curBitmapPointer, (IdxTreeEntryType) curBitmapPointer.type ) )
        rc = buildEmptyIndexTreeBranch( key, width, rid, rootTestbitVal );
    else          // at least we have the root level pointer
        rc = buildExistIndexTreeBranch( key, width, rid, rootTestbitVal, curBitmapPointer );

    return rc;
}

/***********************************************************
 * DESCRIPTION:
 *    Dummy list addr generator
 * PARAMETERS:
 *    key - index key
 *    width - key width
 *    rid - ROW ID
 *    myEntry - return entry with addr
 *    no - sequence no
 * RETURN:
 *    NO_ERROR if success
 *    error no if fail
 ***********************************************************/
const int IndexTree::updateIndexList( const uint64_t key, const int width, const RID rid, IdxEmptyListEntry* myEntry, const int no, const bool addFlag )
{
    int rc = NO_ERROR;

    if ( m_useListMgr )
    {
        // doing something here
        if ( !addFlag )  // update list
        {
            if ( m_useMultiRid )
                rc = m_listMgr.updateIndexList( m_cbList, m_multiRid, key, myEntry );
            else
                rc = m_listMgr.updateIndexList( m_cbList, rid, key, myEntry );
        }
        else   // add list
        {
            if ( m_useMultiRid )
                rc = m_listMgr.addIndexListHdr( m_cbList, m_multiRid, key, myEntry );
            else
                rc = m_listMgr.addIndexListHdr( m_cbList, rid, key, myEntry );
        }

    }
    else
    {
        myEntry->fbo = 3;
        myEntry->sbid = 3;
        myEntry->entry = 3 + no;
    }

    return rc;
}

/***********************************************************
 * DESCRIPTION:
 *    Update the entry in index list file
 * PARAMETERS:
 *    key - index key
 *    width - key width
 *    rid - ROW ID
 *    curLevel - current tree level
 *    group - current group
 *    allocCount - allocated count
 *    useCount - used count
 *    offset - entry offset
 * RETURN:
 *    NO_ERROR if success
 *    error no if fail
 ***********************************************************/
const int IndexTree::updateListFile( const uint64_t key, const int width, const RID rid, const int curLevel, const uint64_t group, const int allocCount, const int useCount, const int offset, const bool addFlag )
{
    int                  rc, testbitVal, parentLevel = curLevel - 1;
    IdxEmptyListEntry    listEntry;
    IdxBitTestEntry      bittestEntry, curEntry;
    bool                 bSuccess;
    DataBlock            curBlock;

    rc = readSubBlockEntry( m_cbTree, &curBlock, m_tree.node[parentLevel].next.fbo, m_tree.node[parentLevel].next.sbid,
                            m_tree.node[parentLevel].next.entry + offset, MAX_COLUMN_BOUNDARY, &bittestEntry );

    if ( rc != NO_ERROR )
        return rc;

    if ( !addFlag )
    {
        listEntry.fbo = bittestEntry.fbo;
        listEntry.sbid = bittestEntry.sbid;
        listEntry.entry = bittestEntry.entry;
    }

    rc = updateIndexList( key, width, rid, &listEntry, curLevel, addFlag );

    if ( rc != NO_ERROR )
        return rc;

    bSuccess = getTestbitValue( key, width, curLevel, &testbitVal );
    setBittestEntry( &bittestEntry, testbitVal, group, listEntry.fbo, listEntry.sbid, listEntry.entry, LEAF_LIST );

    rc = writeSubBlockEntry( m_cbTree, &curBlock, m_tree.node[parentLevel].next.fbo, m_tree.node[parentLevel].next.sbid, m_tree.node[parentLevel].next.entry + offset, MAX_COLUMN_BOUNDARY, &bittestEntry );

    setBittestEntry( &curEntry, testbitVal, group, m_tree.node[parentLevel].next.fbo, m_tree.node[parentLevel].next.sbid, m_tree.node[parentLevel].next.entry, LEAF_LIST );
    setTreeNode( &m_tree.node[curLevel], curLevel, allocCount, useCount, offset, bittestEntry, curEntry );

    return rc;
}

} //end of namespace

