/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
void ONDXPage::QueryDelete()
{ // Store in GarbageCollector if (IsModified() && rIndex.m_pFileStream)
WriteONDXPage( *rIndex.m_pFileStream, *this );
bModified = false; if (rIndex.UseCollector())
{ if (aChild.Is())
aChild->Release(false);
for (sal_uInt16 i = 0; i < rIndex.getHeader().db_maxkeys;i++)
{ if (ppNodes[i].GetChild().Is())
ppNodes[i].GetChild()->Release(false);
ppNodes[i] = ONDXNode();
}
bNoDelete = 1;
nCount = 0;
aParent.Clear();
rIndex.Collect(this);
} else
{ // I'm not sure about the original purpose of this line, but right now // it serves the purpose that anything that attempts to do an AddFirstRef() // after an object is deleted will trip an assert.
nRefCount = 1 << 30; deletethis;
}
}
sal_uInt16 ONDXPage::FindPos(const ONDXKey& rKey) const
{ // searches the position for the given key in a page
sal_uInt16 i = 0; while (i < nCount && rKey > ((*this)[i]).GetKey())
i++;
return i;
}
bool ONDXPage::Find(const ONDXKey& rKey)
{ // searches the given key // Speciality: At the end of the method // the actual page and the position of the node, fulfilling the '<=' condition, are saved // This is considered at insert.
sal_uInt16 i = 0; while (i < nCount && rKey > ((*this)[i]).GetKey())
i++;
bool ONDXPage::Insert(ONDXNode& rNode, sal_uInt32 nRowsLeft)
{ // When creating an index there can be multiple nodes added, // these are sorted ascending bool bAppend = nRowsLeft > 0; if (IsFull())
{
ONDXNode aSplitNode; if (bAppend)
aSplitNode = rNode; else
{ // Save the last node
aSplitNode = (*this)[nCount-1]; if(rNode.GetKey() <= aSplitNode.GetKey())
{ bool bResult = true; // this practically reduces the number of nodes by 1 if (IsLeaf() && this == rIndex.m_aCurLeaf)
{ // assumes, that the node, for which the condition (<=) holds, is stored in m_nCurNode
--nCount; // (otherwise we might get Assertions and GPFs - 60593)
bResult = Insert(rIndex.m_nCurNode + 1, rNode);
} else// position unknown
{
sal_uInt16 nPos = 0; while (nPos < nCount)
{ if (rNode.GetKey() <= ((*this)[nPos]).GetKey()) break;
++nPos;
}
--nCount; // (otherwise we might get Assertions and GPFs - 60593)
bResult = Insert(nPos, rNode);
}
// can the new node be inserted if (!bResult)
{
nCount++;
aSplitNode = rNode;
}
} else
aSplitNode = rNode;
}
// insert extracted node into parent node if (!HasParent())
{ // No parent, then new root
ONDXPagePtr aNewRoot = rIndex.CreatePage(nNewPagePos + 1);
aNewRoot->SetChild(this);
// create new leaf and divide page
ONDXPagePtr aNewPage = rIndex.CreatePage(nNewPagePos,aParent);
rIndex.SetPageCount(nNewPageCount);
// How many nodes are being inserted? // Enough, then we can fill the page to the brim
ONDXNode aInnerNode; if (!IsLeaf() || nRowsLeft < o3tl::make_unsigned(rIndex.GetMaxNodes() / 2))
aInnerNode = Split(*aNewPage); else
{
aInnerNode = (*this)[nCount - 1];
// Node points to the new page
aInnerNode.SetChild(aNewPage);
// Inner nodes have no record number if (rIndex.isUnique())
aInnerNode.GetKey().ResetRecord();
// new page points to the page of the extracted node if (!IsLeaf())
aNewPage->SetChild(aInnerNode.GetChild());
}
if (nCount)
{
++nCount; // shift right for (sal_uInt16 i = std::min(static_cast<sal_uInt16>(nMaxCount-1), static_cast<sal_uInt16>(nCount-1)); nPos < i; --i)
(*this)[i] = (*this)[i-1];
} else if (nCount < nMaxCount)
nCount++;
// insert at the position
ONDXNode& rInsertNode = (*this)[nPos];
rInsertNode = rNode; if (rInsertNode.GetChild().Is())
{
rInsertNode.GetChild()->SetParent(this);
rNode.GetChild()->SetParent(this);
}
if (aTempParent.Is())
{ // Free pages not needed, there will be no reference anymore to the pages // afterwards 'this' can't be valid anymore!!!
sal_uInt16 nParentPos = aTempParent->Search(this); if (nParentPos != NODE_NOTFOUND)
(*aTempParent)[nParentPos].GetChild().Clear(); else
aTempParent->GetChild().Clear();
}
}
void ONDXPage::Delete(sal_uInt16 nNodePos)
{ if (IsLeaf())
{ // The last element will not be deleted if (nNodePos == (nCount - 1))
{
ONDXNode aNode = (*this)[nNodePos];
// parent's KeyValue has to be replaced if (HasParent())
aParent->SearchAndReplace(aNode.GetKey(),
(*this)[nNodePos-1].GetKey());
}
}
// Delete the node
Remove(nNodePos);
// Underflow if (HasParent() && nCount < (rIndex.GetMaxNodes() / 2))
{ // determine, which node points to the page
sal_uInt16 nParentNodePos = aParent->Search(this); // last element on parent-page -> merge with secondlast page if (nParentNodePos == (aParent->Count() - 1))
{ if (!nParentNodePos) // merge with left neighbour
Merge(nParentNodePos,aParent->GetChild(&rIndex)); else
Merge(nParentNodePos,(*aParent)[nParentNodePos-1].GetChild(&rIndex,aParent));
} // otherwise merge page with next page else
{ // merge with right neighbour
nParentNodePos = o3tl::sanitizing_inc(nParentNodePos);
Merge(nParentNodePos,((*aParent)[nParentNodePos].GetChild(&rIndex,aParent)));
} if (HasParent() && !(*aParent)[nParentNodePos].HasChild())
aParent->Delete(nParentNodePos);
} elseif (IsRoot()) // make sure that the position of the root is kept
rIndex.SetRootPos(nPagePos);
}
ONDXNode ONDXPage::Split(ONDXPage& rPage)
{
DBG_ASSERT(IsFull(), "Incorrect Splitting"); /* divide one page into two leaf: Page 1 is (n - (n/2)) Page 2 is (n/2) Node n/2 will be duplicated inner node: Page 1 is (n+1)/2 Page 2 is (n/2-1) Node ((n+1)/2 + 1) : will be taken out
*/
ONDXNode aResultNode; if (IsLeaf())
{ for (sal_uInt16 i = nCount - (nCount / 2), j = 0 ; i < nCount; i++)
rPage.Insert(j++,(*this)[i]);
// this node contains a key that already exists in the tree and must be replaced
ONDXNode aLastNode = (*this)[nCount - 1];
nCount = nCount - (nCount / 2);
aResultNode = (*this)[nCount - 1];
if (HasParent())
aParent->SearchAndReplace(aLastNode.GetKey(),
aResultNode.GetKey());
} else
{ for (sal_uInt16 i = (nCount + 1) / 2 + 1, j = 0 ; i < nCount; i++)
rPage.Insert(j++,(*this)[i]);
// Determine if page is right or left neighbour bool bRight = ((*xPage)[0].GetKey() > (*this)[0].GetKey()); // true when xPage is at the right side
sal_uInt16 nNewCount = (*xPage).Count() + Count();
if (IsLeaf())
{ // Condition for merge if (nNewCount < (nMaxNodes_2 * 2))
{
sal_uInt16 nLastNode = bRight ? Count() - 1 : xPage->Count() - 1; if (bRight)
{
DBG_ASSERT(xPage != this,"xPage and THIS must not be the same: infinite loop"); // shift all nodes from xPage to the left node (append) while (xPage->Count())
{
Append((*xPage)[0]);
xPage->Remove(0);
}
} else
{
DBG_ASSERT(xPage != this,"xPage and THIS must not be the same: infinite loop"); // xPage is the left page and THIS the right one while (xPage->Count())
{
Insert(0,(*xPage)[xPage->Count()-1]);
xPage->Remove(xPage->Count()-1);
} // replace old position of xPage in parent with this if (nParentNodePos)
(*aParent)[nParentNodePos-1].SetChild(this,aParent); else// or set as right node
aParent->SetChild(this);
aParent->SetModified(true);
}
// cancel Child-relationship at parent node
(*aParent)[nParentNodePos].SetChild(); // replace the Node-value, only if changed page is the left one, otherwise become if(aParent->IsRoot() && aParent->Count() == 1)
{
(*aParent)[0].SetChild();
aParent->ReleaseFull();
aParent.Clear();
rIndex.SetRootPos(nPagePos);
rIndex.m_aRoot = this;
SetModified(true);
} else
aParent->SearchAndReplace((*this)[nLastNode].GetKey(),(*this)[nCount-1].GetKey());
xPage->SetModified(false);
xPage->ReleaseFull(); // is not needed anymore
} // balance the elements nNewCount >= (nMaxNodes_2 * 2) else
{ if (bRight)
{ // shift all nodes from xPage to the left node (append)
ONDXNode aReplaceNode = (*this)[nCount - 1]; while (nCount < nMaxNodes_2)
{
Append((*xPage)[0]);
xPage->Remove(0);
} // Replace the node values: replace old last value by the last of xPage
aParent->SearchAndReplace(aReplaceNode.GetKey(),(*this)[nCount-1].GetKey());
} else
{ // insert all nodes from this in front of the xPage nodes
ONDXNode aReplaceNode = (*this)[nCount - 1]; while (xPage->Count() < nMaxNodes_2)
{
xPage->Insert(0,(*this)[nCount-1]);
Remove(nCount-1);
} // Replace the node value
aParent->SearchAndReplace(aReplaceNode.GetKey(),(*this)[Count()-1].GetKey());
}
}
} else// !IsLeaf()
{ // Condition for merge if (nNewCount < nMaxNodes_2 * 2)
{ if (bRight)
{
DBG_ASSERT(xPage != this,"xPage and THIS must not be the same: infinite loop"); // Parent node will be integrated; is initialized with Child from xPage
(*aParent)[nParentNodePos].SetChild(xPage->GetChild(),aParent);
Append((*aParent)[nParentNodePos]); for (sal_uInt16 i = 0 ; i < xPage->Count(); i++)
Append((*xPage)[i]);
} else
{
DBG_ASSERT(xPage != this,"xPage and THIS must not be the same: infinite loop"); // Parent-node will be integrated; is initialized with child
(*aParent)[nParentNodePos].SetChild(GetChild(),aParent); // Parent memorizes my child
Insert(0,(*aParent)[nParentNodePos]); // insert parent node into myself while (xPage->Count())
{
Insert(0,(*xPage)[xPage->Count()-1]);
xPage->Remove(xPage->Count()-1);
}
SetChild(xPage->GetChild());
if (nParentNodePos)
(*aParent)[nParentNodePos-1].SetChild(this,aParent); else
aParent->SetChild(this);
}
// afterwards parent node will be reset
(*aParent)[nParentNodePos].SetChild();
aParent->SetModified(true);
if(aParent->IsRoot() && aParent->Count() == 1)
{
(*aParent).SetChild();
aParent->ReleaseFull();
aParent.Clear();
rIndex.SetRootPos(nPagePos);
rIndex.m_aRoot = this;
SetModified(true);
} elseif(nParentNodePos) // replace the node value // for Append the range will be enlarged, for Insert the old node from xPage will reference to this // that's why the node must be updated here
aParent->SearchAndReplace((*aParent)[nParentNodePos-1].GetKey(),(*aParent)[nParentNodePos].GetKey());
xPage->SetModified(false);
xPage->ReleaseFull();
} // balance the elements else
{ if (bRight)
{ while (nCount < nMaxNodes_2)
{
(*aParent)[nParentNodePos].SetChild(xPage->GetChild(),aParent);
Append((*aParent)[nParentNodePos]);
(*aParent)[nParentNodePos] = (*xPage)[0];
xPage->Remove(0);
}
xPage->SetChild((*aParent)[nParentNodePos].GetChild());
(*aParent)[nParentNodePos].SetChild(xPage,aParent);
} else
{ while (nCount < nMaxNodes_2)
{
(*aParent)[nParentNodePos].SetChild(GetChild(),aParent);
Insert(0,(*aParent)[nParentNodePos]);
(*aParent)[nParentNodePos] = (*xPage)[xPage->Count()-1];
xPage->Remove(xPage->Count()-1);
}
SetChild((*aParent)[nParentNodePos].GetChild());
(*aParent)[nParentNodePos].SetChild(this,aParent);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.