?? mitab_indfile.cpp
字號:
CPLError(CE_Failure, CPLE_AssertionFailed,
"TABINDNode::Search(): Node has not been initialized yet!");
return -1;
}
/*-----------------------------------------------------------------
* m_nCurIndexEntry is the index of the last item that has been
* returned by FindFirst()/FindNext().
*----------------------------------------------------------------*/
if (m_nSubTreeDepth == 1)
{
/*-------------------------------------------------------------
* Leaf node level... check if the next entry is an exact match
*------------------------------------------------------------*/
m_nCurIndexEntry++;
if (m_nCurIndexEntry >= m_numEntriesInNode && m_nNextNodePtr > 0)
{
// We're at the end of a node ... continue with next node
GotoNodePtr(m_nNextNodePtr);
m_nCurIndexEntry = 0;
}
if (m_nCurIndexEntry < m_numEntriesInNode &&
IndexKeyCmp(pKeyValue, m_nCurIndexEntry) == 0)
{
/* Found it! Return the record number */
return ReadIndexEntry(m_nCurIndexEntry, NULL);
}
else
{
/* No more items with that key... return 0 */
return 0;
}
}
else
{
/*-------------------------------------------------------------
* Index Node: just pass the search to this child node.
*------------------------------------------------------------*/
while(m_nCurIndexEntry < m_numEntriesInNode)
{
if (m_poCurChildNode != NULL)
return m_poCurChildNode->FindNext(pKeyValue);
}
}
// No more nodes were found that contain the key value.
return 0;
}
/**********************************************************************
* TABINDNode::CommitToFile()
*
* For write access, write current block and its children to file.
*
* note: TABRawBinBlock::CommitToFile() does nothing unless the block has
* been modified. (it has an internal bModified flag)
*
* Returns 0 on success, -1 on error.
**********************************************************************/
int TABINDNode::CommitToFile()
{
if ((m_eAccessMode != TABWrite && m_eAccessMode != TABReadWrite) ||
m_poDataBlock == NULL)
return -1;
if (m_poCurChildNode)
{
if (m_poCurChildNode->CommitToFile() != 0)
return -1;
m_nSubTreeDepth = m_poCurChildNode->GetSubTreeDepth() + 1;
}
return m_poDataBlock->CommitToFile();
}
/**********************************************************************
* TABINDNode::AddEntry()
*
* Add an .DAT record entry for pKeyValue in this index
*
* nRecordNo is the .DAT record number, record numbers start at 1.
*
* In order to insert a new value, the root node first does a FindFirst()
* that will load the whole tree branch up to the insertion point.
* Then AddEntry() is recursively called up to the leaf node level for
* the insertion of the actual value.
* If the leaf node is full then it will be split and if necessary the
* split will propagate up in the tree through the pointer that each node
* has on its parent.
*
* If bAddInThisNodeOnly=TRUE, then the entry is added only locally and
* we do not try to update the child node. This is used when the parent
* of a node that is being splitted has to be updated.
*
* bInsertAfterCurChild forces the insertion to happen immediately after
* the m_nCurIndexEntry. This works only when bAddInThisNodeOnly=TRUE.
* The default is to search the node for a an insertion point.
*
* Returns 0 on success, -1 on error
**********************************************************************/
int TABINDNode::AddEntry(GByte *pKeyValue, GInt32 nRecordNo,
GBool bAddInThisNodeOnly /*=FALSE*/,
GBool bInsertAfterCurChild /*=FALSE*/,
GBool bMakeNewEntryCurChild /*=FALSE*/)
{
if ((m_eAccessMode != TABWrite && m_eAccessMode != TABReadWrite) ||
m_poDataBlock == NULL)
return -1;
/*-----------------------------------------------------------------
* If I'm the root node, then do a FindFirst() to init all the nodes
* and to make all of them point ot the insertion point.
*----------------------------------------------------------------*/
if (m_poParentNodeRef == NULL && !bAddInThisNodeOnly)
{
if (FindFirst(pKeyValue) < 0)
return -1; // Error happened and has already been reported.
}
if (m_poCurChildNode && !bAddInThisNodeOnly)
{
CPLAssert(m_nSubTreeDepth > 1);
/*-------------------------------------------------------------
* Propagate the call down to our children
* Note: this recursive call could result in new levels of nodes
* being added under our feet by SplitRootnode() so it is very
* important to return right after this call or we might not be
* able to recognize this node at the end of the call!
*------------------------------------------------------------*/
return m_poCurChildNode->AddEntry(pKeyValue, nRecordNo);
}
else
{
/*-------------------------------------------------------------
* OK, we're a leaf node... this is where the real work happens!!!
*------------------------------------------------------------*/
CPLAssert(m_nSubTreeDepth == 1 || bAddInThisNodeOnly);
/*-------------------------------------------------------------
* First thing to do is make sure that there is room for a new
* entry in this node, and to split it if necessary.
*------------------------------------------------------------*/
if (GetNumEntries() == GetMaxNumEntries())
{
if (m_poParentNodeRef == NULL)
{
/*-----------------------------------------------------
* Splitting the root node adds one level to the tree, so
* after splitting we just redirect the call to our child.
*----------------------------------------------------*/
if (SplitRootNode() != 0)
return -1; // Error happened and has already been reported
CPLAssert(m_poCurChildNode);
CPLAssert(m_nSubTreeDepth > 1);
return m_poCurChildNode->AddEntry(pKeyValue, nRecordNo,
bAddInThisNodeOnly,
bInsertAfterCurChild,
bMakeNewEntryCurChild);
}
else
{
/*-----------------------------------------------------
* Splitting a regular node will leave it 50% full.
*----------------------------------------------------*/
if (SplitNode() != 0)
return -1;
}
}
/*-------------------------------------------------------------
* Insert new key/value at the right position in node.
*------------------------------------------------------------*/
if (InsertEntry(pKeyValue, nRecordNo,
bInsertAfterCurChild, bMakeNewEntryCurChild) != 0)
return -1;
}
return 0;
}
/**********************************************************************
* TABINDNode::InsertEntry()
*
* (private method)
*
* Insert a key/value pair in the current node buffer.
*
* Returns 0 on success, -1 on error
**********************************************************************/
int TABINDNode::InsertEntry(GByte *pKeyValue, GInt32 nRecordNo,
GBool bInsertAfterCurChild /*=FALSE*/,
GBool bMakeNewEntryCurChild /*=FALSE*/)
{
int iInsertAt=0;
if (GetNumEntries() >= GetMaxNumEntries())
{
CPLError(CE_Failure, CPLE_AssertionFailed,
"Node is full! Cannot insert key!");
return -1;
}
/*-----------------------------------------------------------------
* Find the spot where the key belongs
*----------------------------------------------------------------*/
if (bInsertAfterCurChild)
{
iInsertAt = m_nCurIndexEntry+1;
}
else
{
while(iInsertAt < m_numEntriesInNode)
{
int nCmpStatus = IndexKeyCmp(pKeyValue, iInsertAt);
if (nCmpStatus <= 0)
{
break;
}
iInsertAt++;
}
}
m_poDataBlock->GotoByteInBlock(12 + iInsertAt*(m_nKeyLength+4));
/*-----------------------------------------------------------------
* Shift all entries that follow in the array
*----------------------------------------------------------------*/
if (iInsertAt < m_numEntriesInNode)
{
// Since we use memmove() directly, we need to inform
// m_poDataBlock that the upper limit of the buffer will move
m_poDataBlock->GotoByteInBlock(12 + (m_numEntriesInNode+1)*
(m_nKeyLength+4));
m_poDataBlock->GotoByteInBlock(12 + iInsertAt*(m_nKeyLength+4));
memmove(m_poDataBlock->GetCurDataPtr()+(m_nKeyLength+4),
m_poDataBlock->GetCurDataPtr(),
(m_numEntriesInNode-iInsertAt)*(m_nKeyLength+4));
}
/*-----------------------------------------------------------------
* Write new entry
*----------------------------------------------------------------*/
m_poDataBlock->WriteBytes(m_nKeyLength, pKeyValue);
m_poDataBlock->WriteInt32(nRecordNo);
m_numEntriesInNode++;
m_poDataBlock->GotoByteInBlock(0);
m_poDataBlock->WriteInt32(m_numEntriesInNode);
if (bMakeNewEntryCurChild)
m_nCurIndexEntry = iInsertAt;
else if (m_nCurIndexEntry >= iInsertAt)
m_nCurIndexEntry++;
/*-----------------------------------------------------------------
* If we replaced the first entry in the node, then this node's key
* changes and we have to update the reference in the parent node.
*----------------------------------------------------------------*/
if (iInsertAt == 0 && m_poParentNodeRef)
{
if (m_poParentNodeRef->UpdateCurChildEntry(GetNodeKey(),
GetNodeBlockPtr()) != 0)
return -1;
}
return 0;
}
/**********************************************************************
* TABINDNode::UpdateCurChildEntry()
*
* Update the key for the current child node. This method is called by
* the child when its first entry (defining its node key) is changed.
*
* Returns 0 on success, -1 on error
**********************************************************************/
int TABINDNode::UpdateCurChildEntry(GByte *pKeyValue, GInt32 nRecordNo)
{
/*-----------------------------------------------------------------
* Update current child entry with the info for the first node.
*
* For some reason, the key for first entry of the first node of each
* level has to be set to 0 except for the leaf level.
*----------------------------------------------------------------*/
m_poDataBlock->GotoByteInBlock(12 + m_nCurIndexEntry*(m_nKeyLength+4));
if (m_nCurIndexEntry == 0 && m_nSubTreeDepth > 1 && m_nPrevNodePtr == 0)
{
m_poDataBlock->WriteZeros(m_nKeyLength);
}
else
{
m_poDataBlock->WriteBytes(m_nKeyLength, pKeyValue);
}
m_poDataBlock->WriteInt32(nRecordNo);
return 0;
}
/**********************************************************************
* TABINDNode::UpdateSplitChild()
*
* Update the key and/or record ptr information corresponding to the
* current child node.
*
* Returns 0 on success, -1 on error
**********************************************************************/
int TABINDNode::UpdateSplitChild(GByte *pKeyValue1, GInt32 nRecordNo1,
GByte *pKeyValue2, GInt32 nRecordNo2,
int nNewCurChildNo /* 1 or 2 */)
{
/*-----------------------------------------------------------------
* Update current child entry with the info for the first node.
*
* For some reason, the key for first entry of the first node of each
* level has to be set to 0 except for the leaf level.
*----------------------------------------------------------------*/
m_poDataBlock->GotoByteInBlock(12 + m_nCurIndexEntry*(m_nKeyLength+4));
if (m_nCurIndexEntry == 0 && m_nSubTreeDepth > 1 && m_nPrevNodePtr == 0)
{
m_poDataBlock->WriteZeros(m_nKeyLength);
}
else
{
m_poDataBlock->WriteBytes(m_
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -