mirror of
https://github.com/mariadb-corporation/mariadb-columnstore-engine.git
synced 2025-04-18 21:44:02 +03:00
1521 lines
48 KiB
C++
1521 lines
48 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:
|
|
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;
|
|
}
|
|
|
|
} // namespace WriteEngine
|