void GiST::InsertHelper(const GiSTentry &entry, int level, // level of tree at which to insert int *splitvec) // a vector to trigger Split instead of forced reinsert { GiSTnode *leaf; int overflow=0; leaf=ChooseSubtree(GiSTRootPage, entry, level); leaf->Insert(entry); if (leaf->IsOverFull(*store)) { if(ForcedReinsert()&&!leaf->Path().IsRoot()&&(!splitvec||!splitvec[level])) { int split[GIST_MAX_LEVELS]; // R*-tree-style forced reinsert for(int i=0; i<GIST_MAX_LEVELS; i++) split[i]=0; OverflowTreatment(leaf, entry, split); overflow=1; } else Split(&leaf, entry); if(leaf->IsOverFull(*store)) { // we only should get here if we reinserted, and the node re-filled assert(overflow); leaf->DeleteEntry(entry.Position()); Split(&leaf, entry); } } else WriteNode(leaf); if(!overflow) AdjustKeys(leaf, NULL); delete leaf; }
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::Create(const char *filename) { if (IsOpen()) { return; } store = CreateStore(); store->Create(filename); if (!store->IsOpen()) { return; } store->Allocate(); // reserved for root pointer rootPage = store->Allocate(); assert(rootPage == 1); GiSTnode *node = NewNode(this); node->Path().MakeRoot(); WriteNode(node); delete node; isOpen = 1; }
GiSTnode* GiST::ReadNode (const GiSTpath& path) const { char *buf = new char[store->PageSize()]; GiSTnode *node = NewNode((GiST *)this); store->Read(path.Page(), buf); // do the deed node->Unpack(buf); #ifdef PRINTING_OBJECTS if (debug) { cout << "READ PAGE " << path.Page() << ":\n"; node->Print(cout); } #endif node->Path() = path; delete []buf; return node; }
void GiST::Create (const char *filename) { if (IsOpen()) { return; } store = CreateStore(); store->Create(filename); if (!store->IsOpen()) { // create failed! return; } store->Allocate(); // added by myself, reserved for root store->Allocate(); GiSTnode *node = NewNode(this); node->Path().MakeRoot(); WriteNode (node); delete node; isOpen = 1; }
void GiST::ShortenTree () { GiSTpath path; // Shorten the tree if necessary (This should only be done if root actually changed!) path.MakeRoot (); GiSTnode *root = ReadNode(path); if (!root->IsLeaf() && root->NumEntries()==1) { path.MakeChild ((*root)[0]->Ptr()); GiSTnode *child = ReadNode (path); store->Deallocate(path.Page()); child->SetSibling(0); child->Path().MakeRoot(); WriteNode (child); delete child; } delete root; }
GiSTnode* MXTree::ReadNode(const GiSTpath& path) const { char *firstBuffer = new char[store->PageSize()]; int startPage = (path.IsRoot() ? rootPage : path.Page()); store->Read(startPage, firstBuffer); int pageNum = ceil((float)(((MXTnodeHeader *)firstBuffer)->numEntries*(EntrySize()+sizeof(GiSTpage))+sizeof(MXTnodeHeader))/(float)PAGE_SIZE); GiSTnode *node = new MXTnode(pageNum); node->SetTree((GiST *)this); node->Path() = path; if (pageNum > 1) { char *buffer = new char[store->PageSize()*pageNum]; memset(buffer, 0, store->PageSize()*pageNum); memcpy(buffer, firstBuffer, store->PageSize()); ((MXTfile *)store)->Read(startPage+1, buffer+store->PageSize(), pageNum-1); // do the deed node->Unpack(buffer); delete[] buffer; } else { node->Unpack(firstBuffer); } delete[] firstBuffer; return node; }
// handle underfull leaf nodes int GiST::CondenseTree(GiSTnode *node) { GiSTlist<GiSTentry*> Q; int deleted=0; // Must be condensing a leaf assert(node->IsLeaf()); while(!node->Path().IsRoot()) { GiSTpath parent_path=node->Path(); parent_path.MakeParent(); GiSTnode *P=ReadNode(parent_path); GiSTentry *En=P->SearchPtr(node->Path().Page()); assert(En!=NULL); // Handle under-full node if(node->IsUnderFull(*store)) { if(!IsOrdered()) { TruePredicate truePredicate; GiSTlist<GiSTentry*> list=node->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 // Have to look at left sibling??? GiSTpage neighbor_page=P->SearchNeighbors(node->Path().Page()); GiSTpath neighbor_path=node->Path(); neighbor_path.MakeSibling(neighbor_page); if(neighbor_page!=0) { GiSTnode *neighbor; // If neighbor is RIGHT sibling... if(node->Sibling()==neighbor_page) neighbor=ReadNode(neighbor_path); else { neighbor=node; node=ReadNode(neighbor_path); } GiSTentry *e=P->SearchPtr(node->Path().Page()); node->Coalesce(*neighbor, *e); delete e; // If not overfull, coalesce, kill right node if(!node->IsOverFull(*store)) { node->SetSibling(neighbor->Sibling()); WriteNode(node); // 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; } // If overfull, split (same as borrowing) else { GiSTnode *node2=node->PickSplit(); node2->Path()=neighbor->Path(); node2->SetSibling(neighbor->Sibling()); WriteNode(node); WriteNode(node2); AdjustKeys(node2, &P); delete node2; deleted=1; } delete neighbor; } } } // Adjust covering predicate if(!deleted) AdjustKeys(node, &P); parent_path=node->Path(); parent_path.MakeParent(); delete node; // Propagate deletes if(!deleted) break; node=P; } // Re-insert orphaned entries while(!Q.IsEmpty()) { GiSTentry *e=Q.RemoveFront(); InsertHelper(*e, e->Level()); delete e; } return(deleted); }
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; }