1 //-< RTREE.CPP >-----------------------------------------------------*--------*
2 // GigaBASE Version 1.0 (c) 1999 GARRET * ? *
3 // (Post Relational Database Management System) * /\| *
4 // * / \ *
5 // Created: 22-Nov-2001 K.A. Knizhnik * / [] \ *
6 // Last update: 22-Nov-2001 K.A. Knizhnik * GARRET *
7 //-------------------------------------------------------------------*--------*
8 // R-tree class implementation
9 //-------------------------------------------------------------------*--------*
10
11 #define INSIDE_GIGABASE
12
13 #include "gigabase.h"
14 #include "rtree.h"
15
16 BEGIN_GIGABASE_NAMESPACE
17
insert(dbDatabase * db,oid_t treeId,oid_t recordId,int offs)18 void dbRtree::insert(dbDatabase* db, oid_t treeId, oid_t recordId, int offs)
19 {
20 dbGetTie treeTie;
21 dbRtree* tree = (dbRtree*)db->getRow(treeTie, treeId);
22 dbGetTie tie;
23 byte* record = (byte*)db->getRow(tie, recordId);
24 rectangle& r = *(rectangle*)(record + offs);
25 if (tree->root == 0) {
26 dbPutTie tie;
27 dbRtree* t = (dbRtree*)db->putRow(tie, treeId);
28 t->root = dbRtreePage::allocate(db, recordId, r);
29 t->height = 1;
30 } else {
31 oid_t p = dbRtreePage::insert(db, r, tree->root, recordId, tree->height);
32 if (p != 0) {
33 dbPutTie tie;
34 dbRtree* t = (dbRtree*)db->putRow(tie, treeId);
35 // root splitted
36 t->root = dbRtreePage::allocate(db, tree->root, p);
37 t->height += 1;
38 }
39 }
40 }
41
42
insert(dbDatabase * db,oid_t treeId,oid_t recordId,rectangle const & r)43 void dbRtree::insert(dbDatabase* db, oid_t treeId, oid_t recordId, rectangle const& r)
44 {
45 dbGetTie treeTie;
46 dbRtree* tree = (dbRtree*)db->getRow(treeTie, treeId);
47 if (tree->root == 0) {
48 dbPutTie tie;
49 dbRtree* t = (dbRtree*)db->putRow(tie, treeId);
50 t->root = dbRtreePage::allocate(db, recordId, r);
51 t->height = 1;
52 } else {
53 oid_t p = dbRtreePage::insert(db, r, tree->root, recordId, tree->height);
54 if (p != 0) {
55 dbPutTie tie;
56 dbRtree* t = (dbRtree*)db->putRow(tie, treeId);
57 // root splitted
58 t->root = dbRtreePage::allocate(db, tree->root, p);
59 t->height += 1;
60 }
61 }
62 }
63
64
remove(dbDatabase * db,oid_t treeId,oid_t recordId,int offs)65 void dbRtree::remove(dbDatabase* db, oid_t treeId, oid_t recordId, int offs)
66 {
67 dbGetTie treeTie;
68 dbRtree* tree = (dbRtree*)db->getRow(treeTie, treeId);
69 assert(tree->height != 0);
70
71 dbGetTie getTie;
72 byte* record = (byte*)db->getRow(getTie, recordId);
73 rectangle& r = *(rectangle*)(record + offs);
74
75 dbRtreePage::reinsert_list rlist;
76 bool found = dbRtreePage::remove(db, r, tree->root, recordId, tree->height, rlist);
77 assert(found);
78
79 dbPutTie putTie;
80 oid_t p = rlist.chain;
81 int level = rlist.level;
82 bool rootSplitted = false;
83
84 while (p != 0) {
85 dbRtreePage* pg = (dbRtreePage*)db->get(p);
86 for (int i = 0, n = pg->n; i < n; i++) {
87 oid_t q = dbRtreePage::insert(db, pg->b[i].rect, tree->root,
88 pg->b[i].p, tree->height-level);
89 if (q != 0) {
90 // root splitted
91 oid_t oldRoot = tree->root;
92 if (!rootSplitted) {
93 tree = (dbRtree*)db->putRow(putTie, treeId);
94 rootSplitted = true;
95 }
96 tree->root = dbRtreePage::allocate(db, oldRoot, q);
97 tree->height += 1;
98 }
99 }
100 level -= 1;
101 oid_t next = pg->next_reinsert_page();
102 db->pool.unfix(pg);
103 db->freePage(p);
104 p = next;
105 }
106 dbRtreePage* pg = (dbRtreePage*)db->get(tree->root);
107 if (pg->n == 1 && tree->height > 1) {
108 oid_t newRoot = (tree->height > 1) ? pg->b[0].p : 0;
109 db->freePage(tree->root);
110 if (!rootSplitted) {
111 tree = (dbRtree*)db->putRow(putTie, treeId);
112 }
113 tree->root = newRoot;
114 tree->height -= 1;
115 }
116 db->pool.unfix(pg);
117 }
118
find(dbDatabase * db,oid_t treeId,dbSearchContext & sc)119 bool dbRtree::find(dbDatabase* db, oid_t treeId, dbSearchContext& sc)
120 {
121 dbGetTie treeTie;
122 dbRtree* tree = (dbRtree*)db->getRow(treeTie, treeId);
123 if (tree->height > 0) {
124 return dbRtreePage::find(db, tree->root, sc, tree->height);
125 }
126 return true;
127 }
128
purge(dbDatabase * db,oid_t treeId)129 void dbRtree::purge(dbDatabase* db, oid_t treeId)
130 {
131 dbPutTie treeTie;
132 dbRtree* tree = (dbRtree*)db->putRow(treeTie, treeId);
133 if (tree->height > 0) {
134 dbRtreePage::purge(db, tree->root, tree->height);
135 }
136 tree->root = 0;
137 tree->height = 0;
138 }
139
drop(dbDatabase * db,oid_t treeId)140 void dbRtree::drop(dbDatabase* db, oid_t treeId)
141 {
142 purge(db, treeId);
143 db->free(db->getPos(treeId) & ~dbFlagsMask, sizeof(dbRtree));
144 db->freeId(treeId);
145 }
146
allocate(dbDatabase * db)147 oid_t dbRtree::allocate(dbDatabase* db)
148 {
149 oid_t oid = db->allocateId();
150 offs_t pos = db->allocate(sizeof(dbRtree));
151 db->setPos(oid, pos | dbModifiedFlag);
152 dbPutTie tie;
153 tie.set(db->pool, oid, pos, sizeof(dbRtree));
154 dbRtree* tree = (dbRtree*)tie.get();
155 tree->size = sizeof(dbRtree);
156 tree->root = 0;
157 tree->height = 0;
158 return oid;
159 }
160
161 //-------------------------------------------------------------------------
162 // R-tree page methods
163 //-------------------------------------------------------------------------
164
165 //
166 // Search for objects overlapped with specified rectangle and call
167 // callback method for all such objects.
168 //
169
find(dbDatabase * db,oid_t pageId,dbSearchContext & sc,int level)170 bool dbRtreePage::find(dbDatabase* db, oid_t pageId, dbSearchContext& sc, int level)
171 {
172 dbRtreePage* pg = (dbRtreePage*)db->get(pageId);
173 bool rc = pg->find(db, sc, level);
174 db->pool.unfix(pg);
175 return rc;
176 }
177
178 static rectangle::comparator comparators[] =
179 {
180 &rectangle::operator ==,
181 &rectangle::operator &,
182 &rectangle::operator >,
183 &rectangle::operator >=,
184 &rectangle::operator <,
185 &rectangle::operator <=
186 };
187
find(dbDatabase * db,dbSearchContext & sc,int level) const188 bool dbRtreePage::find(dbDatabase* db, dbSearchContext& sc, int level) const
189 {
190 assert(level >= 0);
191 rectangle& r = *(rectangle*)sc.firstKey;
192 sc.probes += 1;
193 if (--level != 0) { /* this is an internal node in the tree */
194 for (int i = 0; i < n; i++) {
195 if (b[i].rect & r) {
196 if (!find(db, b[i].p, sc, level)) {
197 return false;
198 }
199 }
200 }
201 } else { /* this is a leaf node */
202 rectangle::comparator cmp = comparators[sc.firstKeyInclusion];
203 for (int i = 0; i < n; i++) {
204 if ((b[i].rect.*cmp)(r)) {
205 if (sc.condition == NULL
206 || db->evaluateBoolean(sc.condition, b[i].p, sc.cursor->table, sc.cursor))
207 {
208 if (!sc.cursor->add(b[i].p)) {
209 return false;
210 }
211 }
212 }
213 }
214 }
215 // printf("Level %d, nodes %d, intersects %d\n", level, n, nIntersects);
216 return true;
217 }
218
219 //
220 // Create root page
221 //
allocate(dbDatabase * db,oid_t recordId,rectangle const & r)222 oid_t dbRtreePage::allocate(dbDatabase* db, oid_t recordId, rectangle const& r)
223 {
224 oid_t pageId = db->allocatePage();
225 dbRtreePage* pg = (dbRtreePage*)db->put(pageId);
226 pg->n = 1;
227 pg->b[0].rect = r;
228 pg->b[0].p = recordId;
229 db->pool.unfix(pg);
230 return pageId;
231 }
232
233 //
234 // Create new root page (root splitting)
235 //
allocate(dbDatabase * db,oid_t oldRootId,oid_t newPageId)236 oid_t dbRtreePage::allocate(dbDatabase* db, oid_t oldRootId, oid_t newPageId)
237 {
238 oid_t pageId = db->allocatePage();
239 dbRtreePage* pg = (dbRtreePage*)db->put(pageId);
240 pg->n = 2;
241 cover(db, oldRootId, pg->b[0].rect);
242 pg->b[0].p = oldRootId;
243 cover(db, newPageId, pg->b[1].rect);
244 pg->b[1].p = newPageId;
245 db->pool.unfix(pg);
246 return pageId;
247 }
248
249 //
250 // Calculate cover of all rectangles at page
251 //
cover(dbDatabase * db,oid_t pageId,rectangle & r)252 void dbRtreePage::cover(dbDatabase* db, oid_t pageId, rectangle& r)
253 {
254 dbRtreePage* pg = (dbRtreePage*)db->get(pageId);
255 pg->cover(r);
256 db->pool.unfix(pg);
257 }
258
cover(rectangle & r) const259 void dbRtreePage::cover(rectangle& r) const
260 {
261 r = b[0].rect;
262 for (int i = 1; i < n; i++) {
263 r += b[i].rect;
264 }
265 }
266
267 #define INFINITY (area_t)1000000000*1000000000
268
split_page(dbDatabase * db,branch const & br)269 oid_t dbRtreePage::split_page(dbDatabase* db, branch const& br)
270 {
271 int i, j, seed[2];
272 area_t rect_area[card+1], waste, worst_waste = -INFINITY;
273 //
274 // As the seeds for the two groups, find two rectangles which waste
275 // the most area if covered by a single rectangle.
276 //
277 rect_area[0] = area(br.rect);
278 for (i = 0; i < card; i++) {
279 rect_area[i+1] = area(b[i].rect);
280 }
281 branch const* bp = &br;
282 for (i = 0; i < card; i++) {
283 for (j = i+1; j <= card; j++) {
284 waste = area(bp->rect + b[j-1].rect) - rect_area[i] - rect_area[j];
285 if (waste > worst_waste) {
286 worst_waste = waste;
287 seed[0] = i;
288 seed[1] = j;
289 }
290 }
291 bp = &b[i];
292 }
293 char taken[card];
294 rectangle group[2];
295 area_t group_area[2];
296 int group_card[2];
297 oid_t pid;
298
299 memset(taken, 0, sizeof taken);
300 taken[seed[1]-1] = 2;
301 group[1] = b[seed[1]-1].rect;
302
303 if (seed[0] == 0) {
304 group[0] = br.rect;
305 pid = allocate(db, br.p, br.rect);
306 } else {
307 group[0] = b[seed[0]-1].rect;
308 pid = allocate(db, b[seed[0]-1].p, group[0]);
309 b[seed[0]-1] = br;
310 }
311 dbPutTie tie;
312 dbRtreePage* p = (dbRtreePage*)db->put(tie, pid);
313
314 group_card[0] = group_card[1] = 1;
315 group_area[0] = rect_area[seed[0]];
316 group_area[1] = rect_area[seed[1]];
317 //
318 // Split remaining rectangles between two groups.
319 // The one chosen is the one with the greatest difference in area
320 // expansion depending on which group - the rect most strongly
321 // attracted to one group and repelled from the other.
322 //
323 while (group_card[0] + group_card[1] < card + 1
324 && group_card[0] < card + 1 - min_fill
325 && group_card[1] < card + 1 - min_fill)
326 {
327 int better_group = -1, chosen = -1;
328 area_t biggest_diff = -1;
329 for (i = 0; i < card; i++) {
330 if (!taken[i]) {
331 area_t diff = (area(group[0] + b[i].rect) - group_area[0])
332 - (area(group[1] + b[i].rect) - group_area[1]);
333 if (diff > biggest_diff || -diff > biggest_diff) {
334 chosen = i;
335 if (diff < 0) {
336 better_group = 0;
337 biggest_diff = -diff;
338 } else {
339 better_group = 1;
340 biggest_diff = diff;
341 }
342 }
343 }
344 }
345 assert(chosen >= 0);
346 group_card[better_group] += 1;
347 group[better_group] += b[chosen].rect;
348 group_area[better_group] = area(group[better_group]);
349 taken[chosen] = better_group+1;
350 if (better_group == 0) {
351 p->b[group_card[0]-1] = b[chosen];
352 }
353 }
354 //
355 // If one group gets too full, then remaining rectangle are
356 // split between two groups in such way to balance cards of two groups.
357 //
358 if (group_card[0] + group_card[1] < card + 1) {
359 for (i = 0; i < card; i++) {
360 if (!taken[i]) {
361 if (group_card[0] >= group_card[1]) {
362 taken[i] = 2;
363 group_card[1] += 1;
364 } else {
365 taken[i] = 1;
366 p->b[group_card[0]++] = b[i];
367 }
368 }
369 }
370 }
371 p->n = group_card[0];
372 n = group_card[1];
373 for (i = 0, j = 0; i < n; j++) {
374 if (taken[j] == 2) {
375 b[i++] = b[j];
376 }
377 }
378 return pid;
379 }
380
remove_branch(int i)381 void dbRtreePage::remove_branch(int i)
382 {
383 n -= 1;
384 memmove(&b[i], &b[i+1], (n-i)*sizeof(branch));
385 }
386
insert(dbDatabase * db,rectangle const & r,oid_t pageId,oid_t recordId,int level)387 oid_t dbRtreePage::insert(dbDatabase* db, rectangle const& r, oid_t pageId, oid_t recordId, int level)
388 {
389 dbPutTie tie;
390 dbRtreePage* pg = (dbRtreePage*)db->put(tie, pageId);
391 oid_t oid = pg->insert(db, r, recordId, level);
392 return oid;
393 }
394
insert(dbDatabase * db,rectangle const & r,oid_t recordId,int level)395 oid_t dbRtreePage::insert(dbDatabase* db, rectangle const& r, oid_t recordId, int level)
396 {
397 branch br;
398 if (--level != 0) {
399 // not leaf page
400 int i, mini = 0;
401 area_t min_incr = INFINITY;
402 area_t best_area = INFINITY;
403 for (i = 0; i < n; i++) {
404 area_t r_area = area(b[i].rect);
405 area_t incr = area(b[i].rect + r) - r_area;
406 if (incr < min_incr) {
407 best_area = r_area;
408 min_incr = incr;
409 mini = i;
410 } else if (incr == min_incr && r_area < best_area) {
411 best_area = r_area;
412 mini = i;
413 }
414 }
415 oid_t q = insert(db, r, b[mini].p, recordId, level);
416 if (q == 0) {
417 // child was not split
418 b[mini].rect += r;
419 return 0;
420 } else {
421 // child was split
422 cover(db, b[mini].p, b[mini].rect);
423 br.p = q;
424 cover(db, q, br.rect);
425 return add_branch(db, br);
426 }
427 } else {
428 br.p = recordId;
429 br.rect = r;
430 return add_branch(db, br);
431 }
432 }
433
remove(dbDatabase * db,rectangle const & r,oid_t pageId,oid_t recordId,int level,reinsert_list & rlist)434 bool dbRtreePage::remove(dbDatabase* db, rectangle const& r, oid_t pageId, oid_t recordId,
435 int level, reinsert_list& rlist)
436 {
437 dbPutTie tie;
438 dbRtreePage* pg = (dbRtreePage*)db->put(tie, pageId);
439 bool rc = pg->remove(db, r, recordId, level, rlist);
440 return rc;
441 }
442
remove(dbDatabase * db,rectangle const & r,oid_t recordId,int level,reinsert_list & rlist)443 bool dbRtreePage::remove(dbDatabase* db, rectangle const& r, oid_t recordId, int level,
444 reinsert_list& rlist)
445 {
446 if (--level != 0) {
447 for (int i = 0; i < n; i++) {
448 if (b[i].rect & r) {
449 if (remove(db, r, b[i].p, recordId, level, rlist)) {
450 dbRtreePage* p = (dbRtreePage*)db->get(b[i].p);
451 if (p->n >= min_fill) {
452 p->cover(b[i].rect);
453 db->pool.unfix(p);
454 } else {
455 dbPutTie tie;
456 // not enough entries in child
457 db->pool.unfix(p);
458 p = (dbRtreePage*)db->put(tie, b[i].p);
459 p->b[card-1].p = rlist.chain;
460 rlist.chain = b[i].p;
461 rlist.level = level - 1;
462 remove_branch(i);
463 }
464 return true;
465 }
466 }
467 }
468 } else {
469 for (int i = 0; i < n; i++) {
470 if (b[i].p == recordId) {
471 remove_branch(i);
472 return true;
473 }
474 }
475 }
476 return false;
477 }
478
purge(dbDatabase * db,oid_t pageId,int level)479 void dbRtreePage::purge(dbDatabase* db, oid_t pageId, int level)
480 {
481 if (--level != 0) { /* this is an internal node in the tree */
482 dbRtreePage* pg = (dbRtreePage*)db->get(pageId);
483 for (int i = 0; i < pg->n; i++) {
484 purge(db, pg->b[i].p, level);
485 }
486 db->pool.unfix(pg);
487 }
488 db->freePage(pageId);
489 }
490
init(dbDatabase * db,oid_t treeId,dbSearchContext & sc)491 void dbRtreeIterator::init(dbDatabase* db, oid_t treeId, dbSearchContext& sc)
492 {
493 this->db = db;
494 this->sc = sc;
495 this->treeId = treeId;
496 }
497
first()498 oid_t dbRtreeIterator::first()
499 {
500 dbGetTie tie;
501 dbRtree* tree = (dbRtree*)db->getRow(tie, treeId);
502 height = tree->height;
503
504 if (height == 0) {
505 return 0;
506 }
507 return gotoFirstItem(0, tree->root);
508 }
509
last()510 oid_t dbRtreeIterator::last()
511 {
512 dbGetTie tie;
513 dbRtree* tree = (dbRtree*)db->getRow(tie, treeId);
514 height = tree->height;
515
516 if (height == 0) {
517 return 0;
518 }
519 return gotoLastItem(0, tree->root);
520 }
521
522
next()523 oid_t dbRtreeIterator::next()
524 {
525 rectangle& r = *(rectangle*)sc.firstKey;
526 int sp = height;
527 while (--sp >= 0) {
528 dbRtreePage* pg = (dbRtreePage*)db->get(pageStack[sp]);
529 for (int i = posStack[sp], n = pg->n; ++i < n;) {
530 if (r & pg->b[i].rect) {
531 oid_t curr = pg->b[i].p;
532 if (sp+1 == height) {
533 if (sc.condition != NULL && !db->evaluateBoolean(sc.condition, curr, sc.cursor->table, sc.cursor)) {
534 continue;
535 }
536 } else if ((curr = gotoFirstItem(sp+1, curr)) == 0) {
537 continue;
538 }
539 pageStack[sp] = pageStack[sp];
540 posStack[sp] = i;
541 db->pool.unfix(pg);
542 return curr;
543 }
544 }
545 db->pool.unfix(pg);
546 }
547 return 0;
548 }
549
prev()550 oid_t dbRtreeIterator::prev()
551 {
552 rectangle& r = *(rectangle*)sc.firstKey;
553 int sp = height;
554 while (--sp >= 0) {
555 dbRtreePage* pg = (dbRtreePage*)db->get(pageStack[sp]);
556 for (int i = posStack[sp]; --i >= 0;) {
557 if (r & pg->b[i].rect) {
558 oid_t curr = pg->b[i].p;
559 if (sp+1 == height) {
560 if (sc.condition != NULL && !db->evaluateBoolean(sc.condition, curr, sc.cursor->table, sc.cursor)) {
561 continue;
562 }
563 } else if ((curr = gotoLastItem(sp+1, curr)) == 0) {
564 continue;
565 }
566 pageStack[sp] = pageStack[sp];
567 posStack[sp] = i;
568 db->pool.unfix(pg);
569 return curr;
570 }
571 }
572 db->pool.unfix(pg);
573 }
574 return 0;
575 }
576
gotoFirstItem(int sp,oid_t pageId)577 oid_t dbRtreeIterator::gotoFirstItem(int sp, oid_t pageId)
578 {
579 dbRtreePage* pg = (dbRtreePage*)db->get(pageId);
580 rectangle& r = *(rectangle*)sc.firstKey;
581
582 for (int i = 0, n = pg->n; i < n; i++) {
583 if (r & pg->b[i].rect) {
584 oid_t curr = pg->b[i].p;
585 if (sp+1 == height) {
586 if (sc.condition != NULL && !db->evaluateBoolean(sc.condition, curr, sc.cursor->table, sc.cursor)) {
587 continue;
588 }
589 } else if ((curr = gotoFirstItem(sp+1, curr)) == 0) {
590 continue;
591 }
592 pageStack[sp] = pageId;
593 posStack[sp] = i;
594 db->pool.unfix(pg);
595 return curr;
596 }
597 }
598 db->pool.unfix(pg);
599 return 0;
600 }
601
gotoLastItem(int sp,oid_t pageId)602 oid_t dbRtreeIterator::gotoLastItem(int sp, oid_t pageId)
603 {
604 dbRtreePage* pg = (dbRtreePage*)db->get(pageId);
605 rectangle& r = *(rectangle*)sc.firstKey;
606
607 for (int i = pg->n; --i >= 0;) {
608 if (r & pg->b[i].rect) {
609 oid_t curr = pg->b[i].p;
610 if (sp+1 == height) {
611 if (sc.condition != NULL && !db->evaluateBoolean(sc.condition, curr, sc.cursor->table, sc.cursor)) {
612 continue;
613 }
614 } else if ((curr = gotoLastItem(sp+1, curr)) == 0) {
615 continue;
616 }
617 pageStack[sp] = pageId;
618 posStack[sp] = i;
619 db->pool.unfix(pg);
620 return curr;
621 }
622 }
623 db->pool.unfix(pg);
624 return 0;
625 }
626
627
628
629 END_GIGABASE_NAMESPACE
630