void GiST::Delete(const GiSTpredicate& pred) { GiSTcursor *c=Search(pred); int condensed; GiSTentry *e; do { if(c==NULL) return; e=c->Next(); GiSTpath path=c->Path(); delete c; if(e==NULL) return; // Read in the node that this belongs to GiSTnode *node=ReadNode(path); node->DeleteEntry(e->Position()); WriteNode(node); condensed=CondenseTree(node); delete node; if(condensed) { ShortenTree(); // because the tree changed, we need to search all over again! // XXX - this is inefficient! users may want to avoid condensing. c=Search(pred); } } while(e!=NULL); }
void GiSTnode::Unpack(const char *page) { const GiSTheader *h = (const GiSTheader *) page; Reset(); SetLevel(h->level); SetSibling(h->sibling); if (!packedNode) packedNode = new char[tree->Store()->PageSize()]; memcpy(packedNode, page, tree->Store()->PageSize()); Expand(h->numEntries); SetNumEntries(h->numEntries); for (int i=0; i<h->numEntries; i++) { GiSTcompressedEntry tmpentry = Entry(i); GiSTentry *e = CreateEntry(); e->SetLevel(Level()); e->SetPosition(i); e->SetNode(this); e->Decompress(tmpentry); // be tidy if (tmpentry.key) delete tmpentry.key; // Append the body with the entry entries[i] = e; } }
void MT::CollectStats () { GiSTpath path; path.MakeRoot (); GiSTnode *node = ReadNode (path); if (!node->IsLeaf()) { int maxLevel = node->Level(); double *radii = new double[maxLevel]; int *pages = new int[maxLevel]; for (int i=0; i<maxLevel; i++) { pages[i] = 0; radii[i] = 0; } TruePredicate truePredicate; GiSTlist<GiSTentry*> list = node->Search(truePredicate); // retrieve all the entries in this node double overlap = ((MTnode *)node)->Overlap(); double totalOverlap = overlap; delete node; while (!list.IsEmpty()) { GiSTentry *entry = list.RemoveFront (); path.MakeChild (entry->Ptr()); node = ReadNode (path); overlap = ((MTnode *)node)->Overlap(); totalOverlap += overlap; pages[node->Level()]++; radii[node->Level()] += ((MTkey *) entry->Key())->MaxRadius(); GiSTlist<GiSTentry*> newlist; if (!node->IsLeaf()) { newlist = node->Search(truePredicate); // recurse to next level } while (!newlist.IsEmpty()) { list.Append (newlist.RemoveFront ()); } path.MakeParent (); delete entry; delete node; } // output the results cout << "Level:\tPages:\tAverage_Radius:"<<endl; int totalPages = 1; // for the root for (int i=maxLevel-1; i>=0; i--) { totalPages += pages[i]; cout << i << ":\t" << pages[i] << "\t" << radii[i]/pages[i] << endl; } cout << "TotalPages:\t" << totalPages << endl; cout << "LeafPages:\t" << pages[0] << endl; cout << "TotalOverlap:\t" << (float)totalOverlap << endl; delete []radii; delete []pages; } else { delete node; } }
GiSTentry* GiSTnode::SearchPtr(GiSTpage ptr) const { for (int i=0; i<numEntries; i++) { GiSTentry *e = (*this)[i]; if (e->Ptr() == ptr) return (GiSTentry*) e->Copy(); } return NULL; }
GiSTlist<GiSTentry*> GiSTnode::Search(const GiSTpredicate &query) const { GiSTlist<GiSTentry*> list; for (int i=0; i<numEntries; i++) { GiSTentry *e = (*this)[i]; if (query.Consistent(*e)) list.Append((GiSTentry*)e->Copy()); } return list; }
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 MTnode::InsertBefore(const GiSTentry& entry, int index) { int n=NumEntries(); BOOL ordered=TRUE; if(index>0) ordered=((*this)[index-1]->Compare(entry)<=0); if(index<n) ordered=ordered&&((*this)[index]->Compare(entry)>=0); if(ordered) { // yes, the position is right for this entry assert(index<=n); GiSTentry *e=(GiSTentry *)entry.Copy(); e->SetLevel(Level()); e->SetPosition(index); e->SetNode(this); // Move everything else over for(int i=n; i>index; i--) { GiSTentry *e=(*this)[i-1]; e->SetPosition(i); (*this)[i]=e; } // Stick the entry in (*this)[index]=e; // Bump up the count SetNumEntries(n+1); } else Insert(entry); // find the right place }
void BTnode::InsertBefore(const GiSTentry& entry, int index) { // Only BTentry's can be inserted into BTnodes. assert(entry.IsA() == BTENTRY_CLASS); BTentry e((const BTentry&) entry); // If this is an internal node, adjust the lower/upper bounds if (!IsLeaf()) { // If not leftmost entry... if (index != 0) { // -inf changes to the upper bound of previous item BTentry *prev = (BTentry*) (*this)[index-1].Ptr(); if (e.LowerBound() == NegInf) e.SetLowerBound(prev->UpperBound()); } // If not rightmost entry... if (index != NumEntries()) { // +inf changes to the lower bound of next item BTentry *next = (BTentry*) (*this)[index].Ptr(); if (e.UpperBound() == PosInf) e.SetUpperBound(next->LowerBound()); } } // Insert it into the node GiSTnode::InsertBefore(e, index); }
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; }
// insert before the original number according to the sequence instead of index void MTnode::InsertBefore (const GiSTentry& newEntry, int index) { int n = NumEntries (); assert (index>=0 && index<=n); BOOL bOrder = TRUE; if (index > 0) { bOrder = (*this)[index-1]->Compare(newEntry) <= 0; } if (index < n) { bOrder = bOrder && (*this)[index]->Compare(newEntry) >= 0; } if (bOrder) { // yes, the position is right for this entry GiSTentry *entry = (GiSTentry *) newEntry.Copy (); entry->SetLevel(Level()); entry->SetPosition(index); entry->SetNode(this); // Move everything else over for (int i=n; i>index; i--) { GiSTentry *e = (*this)[i-1]; e->SetPosition(i); (*this)[i] = e; } // Stick the entry in (*this)[index] = entry; // Bump up the count SetNumEntries (n+1); } else { Insert (newEntry); // find the right place } }
// 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; }
GiSTentry* GiSTcursor::Next() { GiSTpage page; while (first || !stack.IsEmpty()) { if (first) { page = GiSTRootPage; first = 0; } else { assert(lastlevel >= 0); GiSTentry *entry = stack.RemoveFront(); if (entry->IsLeaf()) return entry; // Pop off the stack for (int i=0; i < entry->Level() - lastlevel; i++) path.MakeParent(); page = entry->Ptr(); delete entry; } // Entry was a pointer to another node path.MakeChild(page); GiSTnode *node = gist.ReadNode(path); lastlevel = node->Level(); GiSTlist<GiSTentry*> list = node->Search(*query); while (!list.IsEmpty()) { GiSTentry *entry = list.RemoveRear(); stack.Prepend(entry); } delete node; } // The search is over... return NULL; }
void GiST::DumpNode (ostream& os, GiSTpath path) const { GiSTnode *node = ReadNode(path); node->Print(os); if (!node->IsLeaf()) { TruePredicate truePredicate; GiSTlist<GiSTentry*> list = node->Search(truePredicate); while (!list.IsEmpty()) { GiSTentry *e = list.RemoveFront(); path.MakeChild(e->Ptr()); DumpNode (os, path); path.MakeParent(); delete e; } } delete node; }
void BTnode::Insert(const GiSTentry &entry) { // Only BTentry's can be inserted into BTnode's. assert(entry.IsA() == BTENTRY_CLASS); // This doesn't work for internal nodes. For internal nodes, // the caller must know exactly where to insert. assert(IsLeaf()); GiSTnode::Insert(entry); }
// SearchMinPenalty returns where a new entry should be inserted. GiSTpage GiSTnode::SearchMinPenalty(const GiSTentry &newEntry) const { GiSTentry *minEntry = NULL; GiSTpenalty *minPenalty = NULL; for (int i=0; i<numEntries; i++) { GiSTentry *e = (*this)[i]; assert(e->Node() == this); GiSTpenalty *penalty = e->Penalty(newEntry); if (minEntry == NULL || (*penalty) < (*minPenalty)) { minEntry = e; if (minPenalty) delete minPenalty; minPenalty = penalty; } else delete penalty; } delete minPenalty; return minEntry->Ptr(); }
void CommandSelect(const char *table, const GiSTpredicate& pred) { int i; i = GetTable(table); if (i == NOT_FOUND) { cerr << "Table is not open!\n"; return; } GiST *gist = tables[i].gist; GiSTcursor *c = gist->Search(pred); GiSTentry *e; while ((e = c->Next()) != NULL) { Record* rec = (Record*)e->Ptr(); cout << rec->value << "\n"; delete e; } delete c; }
int RTpredicate::Consistent(const GiSTentry& entry) const { RTentry &rtentry = (RTentry &)entry; if (entry.IsLeaf()) { switch (oper) { case RToverlap: return(rtentry.Key().overlap((RTkey)value)); break; case RTcontains: return(rtentry.Key().contain((RTkey)value)); break; case RTcontained: return(rtentry.Key().contained((RTkey)value)); break; case RTEqual: return(rtentry.Key() == ((RTkey)value)); break; case RTNotDisjoint: return(!rtentry.Key().disjoint((RTkey)value)); break; default: assert(0); return (0); break; } } else { switch (oper) { case RToverlap: case RTcontained: return(rtentry.Key().overlap((RTkey)value)); break; case RTcontains: case RTEqual: return(rtentry.Key().contain(((RTkey)value))); break; case RTNotDisjoint: return(!rtentry.Key().disjoint((RTkey)value)); break; default: assert(0); return (0); break; } } }
void GiSTnode::InsertBefore (const GiSTentry& entry, int index) { assert (index <= NumEntries()); GiSTentry *e = (GiSTentry*)entry.Copy(); e->SetLevel (Level()); e->SetPosition (index); e->SetNode (this); // Move everything else over for (int i=NumEntries(); i>index; i--) { GiSTentry *e = (*this)[i-1]; e->SetPosition (i); (*this)[i] = e; } // Stick the entry in (*this)[index] = e; // Bump up the count numEntries++; }
// 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); }
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(); (*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; } else delete node2; delete e1; delete e2; }
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; } }
int PtrPredicate::Consistent (const GiSTentry& entry) const { return !entry.IsLeaf() || entry.Ptr()==page; }