ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Tree-M/GiST/GiST.cpp
Revision: 1.1
Committed: Sun May 6 00:45:51 2001 UTC (23 years ago) by root
Branch: MAIN
CVS Tags: HEAD
Log Message:
*** empty log message ***

File Contents

# Content
1 // -*- Mode: C++ -*-
2
3 // GiST.cpp
4 //
5 // Copyright (c) 1996, Regents of the University of California
6 // $Header: /usr/local/devel/GiST/libGiST/libGiST/GiST.cpp,v 1.1.1.1 1996/08/06 23:47:20 jmh Exp $
7
8 #include <stdio.h>
9 #include <string.h>
10
11 #include "GiST.h"
12 #include "GiSTpath.h" // for GiSTRootPage
13
14 GiST::GiST()
15 {
16 isOpen=0;
17 debug=0;
18 store=0;
19 }
20
21 void
22 GiST::Create(const char *filename)
23 {
24 GiSTpage page;
25
26 if(IsOpen()) return;
27 store=CreateStore();
28 store->Create(filename);
29 if(!store->IsOpen()) return;
30 page=store->Allocate();
31
32 GiSTnode *node=NewNode(this);
33 node->Path().MakeRoot();
34 WriteNode(node);
35 delete node;
36 isOpen=1;
37 }
38
39 void
40 GiST::Open(const char *filename)
41 {
42 if(IsOpen()) return;
43 store=CreateStore();
44 store->Open(filename);
45 if(!store->IsOpen()) return;
46 isOpen=1;
47 }
48
49 void
50 GiST::Close()
51 {
52 if(IsOpen()) {
53 store->Close();
54 isOpen=0;
55 }
56 }
57
58 void
59 GiST::Insert(const GiSTentry &entry)
60 {
61 InsertHelper(entry, 0);
62 }
63
64 void
65 GiST::InsertHelper(const GiSTentry &entry,
66 int level, // level of tree at which to insert
67 int *splitvec) // a vector to trigger Split instead of forced reinsert
68 {
69 GiSTnode *leaf;
70 int overflow=0;
71
72 leaf=ChooseSubtree(GiSTRootPage, entry, level);
73 leaf->Insert(entry);
74 if (leaf->IsOverFull(*store)) {
75 if(ForcedReinsert()&&!leaf->Path().IsRoot()&&(!splitvec||!splitvec[level])) {
76 int split[GIST_MAX_LEVELS];
77
78 // R*-tree-style forced reinsert
79 for(int i=0; i<GIST_MAX_LEVELS; i++) split[i]=0;
80 OverflowTreatment(leaf, entry, split);
81 overflow=1;
82 }
83 else Split(&leaf, entry);
84 if(leaf->IsOverFull(*store)) {
85 // we only should get here if we reinserted, and the node re-filled
86 assert(overflow);
87 leaf->DeleteEntry(entry.Position());
88 Split(&leaf, entry);
89 }
90 }
91 else WriteNode(leaf);
92 if(!overflow) AdjustKeys(leaf, NULL);
93 delete leaf;
94 }
95
96 void
97 GiST::OverflowTreatment(GiSTnode *node, const GiSTentry& entry, int *splitvec)
98 {
99 GiSTlist<GiSTentry*> deleted;
100
101 // remove the "top" p entries from the node
102 deleted=RemoveTop(node);
103 WriteNode(node);
104 AdjustKeys(node, NULL);
105 // note that we've seen this level already
106 splitvec[node->Level()]=1;
107 // for each of the deleted entries, call InsertHelper at this level
108 while (!deleted.IsEmpty()) {
109 GiSTentry *tmpentry=deleted.RemoveFront();
110
111 InsertHelper(*tmpentry, node->Level(), splitvec);
112 delete tmpentry;
113 }
114 }
115
116 GiSTlist<GiSTentry*>
117 GiST::RemoveTop(GiSTnode *node)
118 {
119 GiSTlist<GiSTentry*> deleted;
120 int count=node->NumEntries();
121 // default: remove the first ones on the page
122 int num_rem=(int)((count+1)*RemoveRatio()+0.5);
123
124 for(int i=num_rem-1; i>=0; i--) {
125 deleted.Append((GiSTentry *)(*node)[i].Ptr()->Copy());
126 node->DeleteEntry(i);
127 }
128 return(deleted);
129 }
130
131 void
132 GiST::AdjustKeys(GiSTnode *node, GiSTnode **parent)
133 {
134 GiSTnode *P;
135
136 if(node->Path().IsRoot()) return;
137 // Read in node's parent
138 if(parent==NULL) {
139 GiSTpath parent_path=node->Path();
140
141 parent_path.MakeParent();
142 P=ReadNode(parent_path);
143 parent=&P;
144 }
145 else P=*parent;
146
147 // Get the old entry pointing to node
148 GiSTentry *entry=P->SearchPtr(node->Path().Page());
149
150 assert(entry!=NULL);
151
152 // Get union of node
153 GiSTentry *actual=node->Union();
154
155 actual->SetPtr(node->Path().Page());
156 if(!entry->IsEqual(*actual)) {
157 int pos=entry->Position();
158
159 P->DeleteEntry(pos);
160 P->InsertBefore(*actual, pos);
161 // A split may be necessary.
162 // XXX: should we do Forced Reinsert here too?
163 if(P->IsOverFull(*store)) {
164 Split(parent, *actual);
165
166 GiSTpage page=node->Path().Page();
167
168 node->Path()=P->Path();
169 node->Path().MakeChild(page);
170 }
171 else {
172 WriteNode(P);
173 AdjustKeys(P, NULL);
174 }
175 }
176 if(parent==&P) delete P;
177 delete actual;
178 delete entry;
179 }
180
181 void
182 GiST::Sync()
183 {
184 store->Sync();
185 }
186
187 void
188 GiST::Delete(const GiSTpredicate& pred)
189 {
190 GiSTcursor *c=Search(pred);
191 int condensed;
192 GiSTentry *e;
193
194 do {
195 if(c==NULL) return;
196 e=c->Next();
197
198 GiSTpath path=c->Path();
199 delete c;
200 if(e==NULL) return;
201
202 // Read in the node that this belongs to
203 GiSTnode *node=ReadNode(path);
204
205 node->DeleteEntry(e->Position());
206 WriteNode(node);
207 condensed=CondenseTree(node);
208 delete node;
209 if(condensed) {
210 ShortenTree();
211 // because the tree changed, we need to search all over again!
212 // XXX - this is inefficient! users may want to avoid condensing.
213 c=Search(pred);
214 }
215 } while(e!=NULL);
216 }
217
218 void
219 GiST::ShortenTree()
220 {
221 GiSTpath path;
222 // Shorten the tree if necessary (This should only be done if root actually changed!)
223 path.MakeRoot();
224 GiSTnode *root=ReadNode(path);
225
226 if(!root->IsLeaf()&&root->NumEntries()==1) {
227 path.MakeChild((*root)[0]->Ptr());
228 GiSTnode *child=ReadNode(path);
229
230 store->Deallocate(path.Page());
231 child->SetSibling(0);
232 child->Path().MakeRoot();
233 WriteNode(child);
234 delete child;
235 }
236 delete root;
237 }
238
239 // handle underfull leaf nodes
240 int
241 GiST::CondenseTree(GiSTnode *node)
242 {
243 GiSTlist<GiSTentry*> Q;
244 int deleted=0;
245
246 // Must be condensing a leaf
247 assert(node->IsLeaf());
248 while(!node->Path().IsRoot()) {
249 GiSTpath parent_path=node->Path();
250 parent_path.MakeParent();
251 GiSTnode *P=ReadNode(parent_path);
252 GiSTentry *En=P->SearchPtr(node->Path().Page());
253
254 assert(En!=NULL);
255 // Handle under-full node
256 if(node->IsUnderFull(*store)) {
257 if(!IsOrdered()) {
258 TruePredicate truePredicate;
259 GiSTlist<GiSTentry*> list=node->Search(truePredicate);
260
261 while(!list.IsEmpty()) {
262 GiSTentry *e=list.RemoveFront();
263
264 Q.Append(e);
265 }
266 P->DeleteEntry(En->Position());
267 WriteNode(P);
268 deleted=1;
269 AdjustKeys(P, NULL);
270 }
271 else {
272 // Try to borrow entries, else coalesce with a neighbor
273 // Have to look at left sibling???
274 GiSTpage neighbor_page=P->SearchNeighbors(node->Path().Page());
275 GiSTpath neighbor_path=node->Path();
276
277 neighbor_path.MakeSibling(neighbor_page);
278 if(neighbor_page!=0) {
279 GiSTnode *neighbor;
280
281 // If neighbor is RIGHT sibling...
282 if(node->Sibling()==neighbor_page) neighbor=ReadNode(neighbor_path);
283 else {
284 neighbor=node;
285 node=ReadNode(neighbor_path);
286 }
287
288 GiSTentry *e=P->SearchPtr(node->Path().Page());
289
290 node->Coalesce(*neighbor, *e);
291 delete e;
292 // If not overfull, coalesce, kill right node
293 if(!node->IsOverFull(*store)) {
294 node->SetSibling(neighbor->Sibling());
295 WriteNode(node);
296
297 // Delete the neighbor from parent
298 GiSTentry *e=P->SearchPtr(neighbor->Path().Page());
299
300 P->DeleteEntry(e->Position());
301 WriteNode(P);
302 delete e;
303 store->Deallocate(neighbor->Path().Page());
304 deleted=1;
305 }
306 // If overfull, split (same as borrowing)
307 else {
308 GiSTnode *node2=node->PickSplit();
309
310 node2->Path()=neighbor->Path();
311 node2->SetSibling(neighbor->Sibling());
312 WriteNode(node);
313 WriteNode(node2);
314 AdjustKeys(node2, &P);
315 delete node2;
316 deleted=1;
317 }
318 delete neighbor;
319 }
320 }
321 }
322 // Adjust covering predicate
323 if(!deleted) AdjustKeys(node, &P);
324 parent_path=node->Path();
325 parent_path.MakeParent();
326 delete node;
327 // Propagate deletes
328 if(!deleted) break;
329 node=P;
330 }
331 // Re-insert orphaned entries
332 while(!Q.IsEmpty()) {
333 GiSTentry *e=Q.RemoveFront();
334
335 InsertHelper(*e, e->Level());
336 delete e;
337 }
338 return(deleted);
339 }
340
341 GiSTnode*
342 GiST::ChooseSubtree(GiSTpage page, const GiSTentry &entry, int level)
343 {
344 GiSTnode *node;
345 GiSTpath path;
346
347 for(;;) {
348 path.MakeChild(page);
349 node=ReadNode(path);
350 if(level==node->Level()||node->IsLeaf()) break;
351 page=node->SearchMinPenalty(entry);
352 delete node;
353 }
354 return node;
355 }
356
357 void
358 GiST::Split(GiSTnode **node, const GiSTentry& entry)
359 {
360 int went_left=0, new_root=0;
361
362 if((*node)->Path().IsRoot()) {
363 new_root=1;
364 (*node)->Path().MakeChild(store->Allocate());
365 }
366
367 GiSTnode *node2=(*node)->PickSplit();
368 node2->Path().MakeSibling(store->Allocate());
369 GiSTentry *e=(*node)->SearchPtr(entry.Ptr());
370
371 if(e!=NULL) {
372 went_left=1;
373 delete e;
374 }
375 node2->SetSibling((*node)->Sibling());
376 (*node)->SetSibling(node2->Path().Page());
377 WriteNode(*node);
378 WriteNode(node2);
379
380 GiSTentry *e1=(*node)->Union();
381 GiSTentry *e2=node2->Union();
382
383 e1->SetPtr((*node)->Path().Page());
384 e2->SetPtr(node2->Path().Page());
385 // Create new root if root is being split
386 if (new_root) {
387 GiSTnode *root=NewNode(this);
388
389 root->SetLevel((*node)->Level()+1);
390 root->InsertBefore(*e1, 0);
391 root->InsertBefore(*e2, 1);
392 root->Path().MakeRoot();
393 WriteNode(root);
394 delete root;
395 }
396 else {
397 // Insert entry for N' in parent
398 GiSTpath parent_path=(*node)->Path();
399 parent_path.MakeParent();
400 GiSTnode *parent=ReadNode(parent_path);
401 // Find the entry for N in parent
402 GiSTentry *e=parent->SearchPtr((*node)->Path().Page());
403 assert(e!=NULL);
404 // Insert the new entry right after it
405 int pos=e->Position();
406
407 parent->DeleteEntry(pos);
408 parent->InsertBefore(*e1, pos);
409 parent->InsertBefore(*e2, pos+1);
410 delete e;
411 if(!parent->IsOverFull(*store)) WriteNode(parent);
412 else {
413 Split(&parent, went_left? *e1: *e2);
414 GiSTpage page=(*node)->Path().Page();
415
416 (*node)->Path()=parent->Path();
417 (*node)->Path().MakeChild(page);
418 page=node2->Path().Page();
419 node2->Path()=(*node)->Path();
420 node2->Path().MakeSibling(page);
421 }
422 delete parent;
423 }
424 if(!went_left) {
425 delete *node;
426 *node=node2;
427 }
428 else delete node2;
429 delete e1;
430 delete e2;
431 }
432
433 GiSTnode*
434 GiST::ReadNode(const GiSTpath& path) const
435 {
436 char *buf=new char[store->PageSize()];
437 GiSTnode *node=NewNode((GiST *)this);
438
439 store->Read(path.Page(), buf);
440 node->Unpack(buf);
441
442 #ifdef PRINTING_OBJECTS
443 if(debug) {
444 cout << "READ PAGE " << path.Page() << ":\n";
445 node->Print(cout);
446 }
447 #endif
448 node->Path()=path;
449 delete []buf;
450 return node;
451 }
452
453 void
454 GiST::WriteNode(GiSTnode *node)
455 {
456 char *buf=new char[store->PageSize()];
457
458 // make Purify happy
459 memset(buf, 0, store->PageSize());
460 #ifdef PRINTING_OBJECTS
461 if(debug) {
462 cout << "WRITE PAGE " << node->Path().Page() << ":\n";
463 node->Print(cout);
464 }
465 #endif
466 node->Pack(buf);
467 store->Write(node->Path().Page(), buf);
468 delete buf;
469 }
470
471 #ifdef PRINTING_OBJECTS
472
473 void
474 GiST::DumpNode(ostream& os, GiSTpath path) const
475 {
476 GiSTnode *node=ReadNode(path);
477
478 node->Print(os);
479 if(!node->IsLeaf()) {
480 TruePredicate truePredicate;
481 GiSTlist<GiSTentry*> list=node->Search(truePredicate);
482
483 while (!list.IsEmpty()) {
484 GiSTentry *e=list.RemoveFront();
485
486 path.MakeChild(e->Ptr());
487 DumpNode(os, path);
488 path.MakeParent();
489 delete e;
490 }
491 }
492 delete node;
493 }
494
495 void
496 GiST::Print(ostream& os) const
497 {
498 GiSTpath path;
499
500 path.MakeRoot();
501 DumpNode(os, path);
502 }
503
504 #endif
505
506 GiSTcursor*
507 GiST::Search(const GiSTpredicate &query) const
508 {
509 return new GiSTcursor(*this, query);
510 }
511
512 GiST::~GiST()
513 {
514 Close();
515 delete store;
516 }