1
0
mirror of https://github.com/mariadb-corporation/mariadb-columnstore-engine.git synced 2025-04-18 21:44:02 +03:00
2017-10-26 17:18:17 +01:00

1473 lines
50 KiB
C++

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