// adjust the keys of node, which is used during the final phase of the BulkLoad algorithm void MT::AdjKeys (GiSTnode *node) { if (node->Path().IsRoot()) { return; } GiSTpath parentPath = node->Path(); parentPath.MakeParent (); GiSTnode *parentNode = ReadNode (parentPath); GiSTentry *parentEntry = parentNode->SearchPtr(node->Path().Page()); // parent entry assert (parentEntry != NULL); GiSTentry *unionEntry = node->Union(); unionEntry->SetPtr(node->Path().Page()); ((MTkey *) unionEntry->Key())->distance = ((MTkey *) parentEntry->Key())->distance; // necessary to keep track of the distance from the parent if (!parentEntry->IsEqual(*unionEntry)) { // replace this entry parentNode->DeleteEntry(parentEntry->Position()); parentNode->Insert(*unionEntry); WriteNode (parentNode); AdjKeys (parentNode); } delete unionEntry; delete parentEntry; delete parentNode; }
void GiST::AdjustKeys (GiSTnode *node, GiSTnode **parent) { if (node->Path().IsRoot()) { return; } GiSTnode *P; // Read in node's parent if (parent == NULL) { GiSTpath parent_path = node->Path(); parent_path.MakeParent (); P = ReadNode (parent_path); parent = &P; } else { P = *parent; } // Get the old entry pointing to node GiSTentry *entry = P->SearchPtr(node->Path().Page()); assert (entry != NULL); // Get union of node GiSTentry *actual = node->Union(); WriteNode(node); // added by myself for the splitted = false; actual->SetPtr(node->Path().Page()); if (!entry->IsEqual(*actual)) { int pos = entry->Position(); P->DeleteEntry(pos); P->InsertBefore(*actual, pos); // A split may be necessary. // XXX: should we do Forced Reinsert here too? if (P->IsOverFull(*store)) { Split (parent, *actual); GiSTpage page = node->Path().Page(); node->Path() = P->Path(); node->Path().MakeChild(page); } else { WriteNode (P); AdjustKeys (P, NULL); } } if (parent == &P) { delete P; } delete actual; delete entry; }
void MXTree::Split(GiSTnode **node, const GiSTentry& entry) { double radii[2], dist, *dists = new double[(*node)->NumEntries()*2]; int pageNums[2], cands[2]; vector<vector<int>> vec(2); ((MXTnode *)(*node))->TestPromotion(radii, &dist, pageNums, cands, dists, vec); if (Trade((*node)->Path().IsRoot(), radii, dist, pageNums, ((MXTnode *)(*node))->GetPageNum()+1, (*node)->NumEntries())) { // don't split now delete[] dists; GiSTpath oldPath = (*node)->Path(); int startPage = ((*node)->Path().IsRoot() ? rootPage : (*node)->Path().Page()); int pageNum = ((MXTnode *)(*node))->GetPageNum(); ((MXTfile *)store)->Deallocate(startPage, pageNum); startPage = ((MXTfile *)store)->Allocate(++pageNum); (*node)->Path().MakeSibling(startPage); rootPage = ((*node)->Path().IsRoot() ? startPage : rootPage); ((MXTnode *)(*node))->SetPageNum(pageNum); WriteNode(*node); if (!(*node)->Path().IsRoot() && startPage != oldPath.Page()) { GiSTpath parentPath = oldPath; parentPath.MakeParent(); GiSTnode *parentNode = ReadNode(parentPath); GiSTentry *e = parentNode->SearchPtr(oldPath.Page()); assert(e != NULL); int pos = e->Position(); e->SetPtr(startPage); parentNode->DeleteEntry(pos); parentNode->InsertBefore(*e, pos); WriteNode(parentNode); delete parentNode; delete e; } } else { // split now bool bLeft = false, bNewRoot = false; if ((*node)->Path().IsRoot()) { bNewRoot = true; (*node)->Path().MakeChild(rootPage); rootPage = store->Allocate(); } int oldPageNum = ((MXTnode *)(*node))->GetPageNum(); GiSTnode *node2 = ((MXTnode *)(*node))->PickSplit(cands, dists, vec); delete[] dists; int curPageNum = ((MXTnode *)(*node))->GetPageNum(); assert(oldPageNum >= curPageNum); if (oldPageNum > curPageNum) { ((MXTfile *)store)->Deallocate((*node)->Path().Page()+curPageNum, oldPageNum-curPageNum); } node2->Path().MakeSibling(((MXTfile *)store)->Allocate(((MXTnode *)node2)->GetPageNum())); WriteNode(*node); WriteNode(node2); GiSTentry *e = (*node)->SearchPtr(entry.Ptr()); if (e != NULL) { bLeft = true; delete e; } GiSTentry *e1 = (*node)->Union(); GiSTentry *e2 = node2->Union(); e1->SetPtr((*node)->Path().Page()); e2->SetPtr(node2->Path().Page()); // Create new root if root is being split if (bNewRoot) { GiSTnode *root = NewNode(this); root->SetLevel((*node)->Level() + 1); root->InsertBefore(*e1, 0); root->InsertBefore(*e2, 1); root->Path().MakeRoot(); WriteNode(root); delete root; } else { // Insert entry for N' in parent GiSTpath parentPath = (*node)->Path(); parentPath.MakeParent(); GiSTnode *parent = ReadNode(parentPath); // Find the entry for N in parent GiSTentry *e = parent->SearchPtr((*node)->Path().Page()); assert(e != NULL); // Insert the new entry right after it int pos = e->Position(); parent->DeleteEntry(pos); parent->InsertBefore(*e1, pos); parent->InsertBefore(*e2, pos+1); delete e; if (!parent->IsOverFull(*store)) { WriteNode(parent); } else { Split(&parent, bLeft? *e1: *e2); // parent is the node which contains the entry inserted GiSTpage page = (*node)->Path().Page(); (*node)->Path() = parent->Path(); // parent's path may change (*node)->Path().MakeChild(page); page = node2->Path().Page(); node2->Path() = (*node)->Path(); node2->Path().MakeSibling(page); } delete parent; } if (!bLeft) { delete *node; *node = node2; // return it } else { delete node2; } delete e1; delete e2; } }
void GiST::Split (GiSTnode **node, const GiSTentry& entry) { int went_left = 0, new_root = 0; if ((*node)->Path().IsRoot()) { new_root = 1; (*node)->Path().MakeChild(store->Allocate()); } GiSTnode *node2 = (*node)->PickSplit(); node2->Path().MakeSibling(store->Allocate()); GiSTentry *e = (*node)->SearchPtr(entry.Ptr()); if (e != NULL) { went_left = 1; delete e; } node2->SetSibling((*node)->Sibling()); (*node)->SetSibling(node2->Path().Page()); WriteNode (*node); WriteNode (node2); GiSTentry *e1 = (*node)->Union(); GiSTentry *e2 = node2->Union(); e1->SetPtr((*node)->Path().Page()); e2->SetPtr(node2->Path().Page()); // Create new root if root is being split if (new_root) { GiSTnode *root = NewNode (this); root->SetLevel((*node)->Level() + 1); root->InsertBefore(*e1, 0); root->InsertBefore(*e2, 1); root->Path().MakeRoot(); WriteNode (root); delete root; } else { // Insert entry for N' in parent GiSTpath parent_path = (*node)->Path(); parent_path.MakeParent (); GiSTnode *parent = ReadNode (parent_path); // Find the entry for N in parent GiSTentry *e = parent->SearchPtr((*node)->Path().Page()); assert (e != NULL); // Insert the new entry right after it int pos = e->Position(); parent->DeleteEntry(pos); parent->InsertBefore(*e1, pos); parent->InsertBefore(*e2, pos+1); delete e; if (!parent->IsOverFull(*store)) { WriteNode (parent); } else { Split (&parent, went_left? *e1: *e2); GiSTpage page = (*node)->Path().Page(); (*node)->Path() = parent->Path(); // parent's path may changed (*node)->Path().MakeChild (page); page = node2->Path().Page(); node2->Path() = (*node)->Path(); node2->Path().MakeSibling (page); } delete parent; } if (!went_left) { delete *node; *node = node2; // return it } else { delete node2; } delete e1; delete e2; }
// handle underfull leaf nodes int GiST::CondenseTree (GiSTnode *leaf) { GiSTlist<GiSTentry*> Q; int deleted = 0; // Must be condensing a leaf assert (leaf->IsLeaf()); while (!leaf->Path().IsRoot()) { GiSTpath parent_path = leaf->Path(); parent_path.MakeParent (); GiSTnode *P = ReadNode (parent_path); GiSTentry *En = P->SearchPtr(leaf->Path().Page()); assert (En != NULL); // Handle under-full node if (leaf->IsUnderFull(*store)) { if (!IsOrdered()) { TruePredicate truePredicate; GiSTlist<GiSTentry*> list = leaf->Search(truePredicate); while (!list.IsEmpty()) { GiSTentry *e = list.RemoveFront(); Q.Append (e); } P->DeleteEntry(En->Position()); WriteNode (P); deleted = 1; AdjustKeys (P, NULL); } else { // Try to borrow entries, else coalesce with a neighbor GiSTpage neighbor_page = P->SearchNeighbors(leaf->Path().Page()); // right and then left if (neighbor_page != 0) { GiSTpath neighbor_path = leaf->Path(); neighbor_path.MakeSibling (neighbor_page); GiSTnode *neighbor; if (leaf->Sibling() == neighbor_page) { // RIGHT sibling... neighbor = ReadNode (neighbor_path); } else { // LEFT sibling neighbor = leaf; leaf = ReadNode (neighbor_path); } leaf->Coalesce(*neighbor); // If not overfull, coalesce, kill right node if (!leaf->IsOverFull(*store)) { leaf->SetSibling(neighbor->Sibling()); WriteNode (leaf); // Delete the neighbor from parent GiSTentry *e = P->SearchPtr(neighbor->Path().Page()); P->DeleteEntry(e->Position()); WriteNode (P); delete e; store->Deallocate(neighbor->Path().Page()); deleted = 1; } else { // If overfull, split (same as borrowing) GiSTnode *node2 = leaf->PickSplit(); node2->Path() = neighbor->Path(); node2->SetSibling(neighbor->Sibling()); WriteNode (leaf); WriteNode (node2); AdjustKeys (node2, &P); delete node2; deleted = 1; } delete neighbor; } } } // Adjust covering predicate if (!deleted) { AdjustKeys (leaf, &P); } parent_path = leaf->Path(); parent_path.MakeParent (); delete leaf; // Propagate deletes if (!deleted) { break; } leaf = P; } // Re-insert orphaned entries while (!Q.IsEmpty()) { GiSTentry *e = Q.RemoveFront (); InsertHelper (*e, e->Level()); delete e; } return (deleted); }