1 /* Copyright (c) 2002, 2010, Oracle and/or its affiliates. All rights reserved.
2
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License, version 2.0,
5 as published by the Free Software Foundation.
6
7 This program is also distributed with certain software (including
8 but not limited to OpenSSL) that is licensed under separate terms,
9 as designated in a particular file or component or in included license
10 documentation. The authors of MySQL hereby grant you an additional
11 permission to link the program and your derivative works with the
12 separately licensed software that they have included with MySQL.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License, version 2.0, for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
22
23 #include "myisamdef.h"
24
25 #ifdef HAVE_RTREE_KEYS
26
27 #include "rt_index.h"
28 #include "rt_key.h"
29 #include "rt_mbr.h"
30
31 #define REINSERT_BUFFER_INC 10
32 #define PICK_BY_AREA
33 /*#define PICK_BY_PERIMETER*/
34
35 typedef struct st_page_level
36 {
37 uint level;
38 my_off_t offs;
39 } stPageLevel;
40
41 typedef struct st_page_list
42 {
43 ulong n_pages;
44 ulong m_pages;
45 stPageLevel *pages;
46 } stPageList;
47
48
49 /*
50 Find next key in r-tree according to search_flag recursively
51
52 NOTES
53 Used in rtree_find_first() and rtree_find_next()
54
55 RETURN
56 -1 Error
57 0 Found
58 1 Not found
59 */
60
rtree_find_req(MI_INFO * info,MI_KEYDEF * keyinfo,uint search_flag,uint nod_cmp_flag,my_off_t page,int level)61 static int rtree_find_req(MI_INFO *info, MI_KEYDEF *keyinfo, uint search_flag,
62 uint nod_cmp_flag, my_off_t page, int level)
63 {
64 uchar *k;
65 uchar *last;
66 uint nod_flag;
67 int res;
68 uchar *page_buf;
69 int k_len;
70 uint *saved_key = (uint*) (info->rtree_recursion_state) + level;
71
72 if (!(page_buf = (uchar*)my_alloca((uint)keyinfo->block_length)))
73 {
74 my_errno = HA_ERR_OUT_OF_MEM;
75 return -1;
76 }
77 if (!_mi_fetch_keypage(info, keyinfo, page, DFLT_INIT_HITS, page_buf, 0))
78 goto err1;
79 nod_flag = mi_test_if_nod(page_buf);
80
81 k_len = keyinfo->keylength - info->s->base.rec_reflength;
82
83 if(info->rtree_recursion_depth >= level)
84 {
85 k = page_buf + *saved_key;
86 }
87 else
88 {
89 k = rt_PAGE_FIRST_KEY(page_buf, nod_flag);
90 }
91 last = rt_PAGE_END(page_buf);
92
93 for (; k < last; k = rt_PAGE_NEXT_KEY(k, k_len, nod_flag))
94 {
95 if (nod_flag)
96 {
97 /* this is an internal node in the tree */
98 if (!(res = rtree_key_cmp(keyinfo->seg, info->first_mbr_key, k,
99 info->last_rkey_length, nod_cmp_flag)))
100 {
101 switch ((res = rtree_find_req(info, keyinfo, search_flag, nod_cmp_flag,
102 _mi_kpos(nod_flag, k), level + 1)))
103 {
104 case 0: /* found - exit from recursion */
105 *saved_key = (uint) (k - page_buf);
106 goto ok;
107 case 1: /* not found - continue searching */
108 info->rtree_recursion_depth = level;
109 break;
110 default: /* error */
111 case -1:
112 goto err1;
113 }
114 }
115 }
116 else
117 {
118 /* this is a leaf */
119 if (!rtree_key_cmp(keyinfo->seg, info->first_mbr_key, k,
120 info->last_rkey_length, search_flag))
121 {
122 uchar *after_key = rt_PAGE_NEXT_KEY(k, k_len, nod_flag);
123 info->lastpos = _mi_dpos(info, 0, after_key);
124 info->lastkey_length = k_len + info->s->base.rec_reflength;
125 memcpy(info->lastkey, k, info->lastkey_length);
126 info->rtree_recursion_depth = level;
127 *saved_key = (uint) (last - page_buf);
128
129 if (after_key < last)
130 {
131 info->int_keypos = info->buff;
132 info->int_maxpos = info->buff + (last - after_key);
133 memcpy(info->buff, after_key, last - after_key);
134 info->buff_used = 0;
135 }
136 else
137 {
138 info->buff_used = 1;
139 }
140
141 res = 0;
142 goto ok;
143 }
144 }
145 }
146 info->lastpos = HA_OFFSET_ERROR;
147 my_errno = HA_ERR_KEY_NOT_FOUND;
148 res = 1;
149
150 ok:
151 my_afree((uchar*)page_buf);
152 return res;
153
154 err1:
155 my_afree((uchar*)page_buf);
156 info->lastpos = HA_OFFSET_ERROR;
157 return -1;
158 }
159
160
161 /*
162 Find first key in r-tree according to search_flag condition
163
164 SYNOPSIS
165 rtree_find_first()
166 info Handler to MyISAM file
167 uint keynr Key number to use
168 key Key to search for
169 key_length Length of 'key'
170 search_flag Bitmap of flags how to do the search
171
172 RETURN
173 -1 Error
174 0 Found
175 1 Not found
176 */
177
rtree_find_first(MI_INFO * info,uint keynr,uchar * key,uint key_length,uint search_flag)178 int rtree_find_first(MI_INFO *info, uint keynr, uchar *key, uint key_length,
179 uint search_flag)
180 {
181 my_off_t root;
182 uint nod_cmp_flag;
183 MI_KEYDEF *keyinfo = info->s->keyinfo + keynr;
184
185 if ((root = info->s->state.key_root[keynr]) == HA_OFFSET_ERROR)
186 {
187 my_errno= HA_ERR_END_OF_FILE;
188 return -1;
189 }
190
191 /*
192 Save searched key, include data pointer.
193 The data pointer is required if the search_flag contains MBR_DATA.
194 (minimum bounding rectangle)
195 */
196 memcpy(info->first_mbr_key, key, keyinfo->keylength);
197 info->last_rkey_length = key_length;
198
199 info->rtree_recursion_depth = -1;
200 info->buff_used = 1;
201
202 nod_cmp_flag = ((search_flag & (MBR_EQUAL | MBR_WITHIN)) ?
203 MBR_WITHIN : MBR_INTERSECT);
204 return rtree_find_req(info, keyinfo, search_flag, nod_cmp_flag, root, 0);
205 }
206
207
208 /*
209 Find next key in r-tree according to search_flag condition
210
211 SYNOPSIS
212 rtree_find_next()
213 info Handler to MyISAM file
214 uint keynr Key number to use
215 search_flag Bitmap of flags how to do the search
216
217 RETURN
218 -1 Error
219 0 Found
220 1 Not found
221 */
222
rtree_find_next(MI_INFO * info,uint keynr,uint search_flag)223 int rtree_find_next(MI_INFO *info, uint keynr, uint search_flag)
224 {
225 my_off_t root;
226 uint nod_cmp_flag;
227 MI_KEYDEF *keyinfo = info->s->keyinfo + keynr;
228
229 if (info->update & HA_STATE_DELETED)
230 return rtree_find_first(info, keynr, info->lastkey, info->lastkey_length,
231 search_flag);
232
233 if (!info->buff_used)
234 {
235 uchar *key= info->int_keypos;
236
237 while (key < info->int_maxpos)
238 {
239 if (!rtree_key_cmp(keyinfo->seg, info->first_mbr_key, key,
240 info->last_rkey_length, search_flag))
241 {
242 uchar *after_key = key + keyinfo->keylength;
243
244 info->lastpos= _mi_dpos(info, 0, after_key);
245 memcpy(info->lastkey, key, info->lastkey_length);
246
247 if (after_key < info->int_maxpos)
248 info->int_keypos= after_key;
249 else
250 info->buff_used= 1;
251 return 0;
252 }
253 key+= keyinfo->keylength;
254 }
255 }
256 if ((root = info->s->state.key_root[keynr]) == HA_OFFSET_ERROR)
257 {
258 my_errno= HA_ERR_END_OF_FILE;
259 return -1;
260 }
261
262 nod_cmp_flag = ((search_flag & (MBR_EQUAL | MBR_WITHIN)) ?
263 MBR_WITHIN : MBR_INTERSECT);
264 return rtree_find_req(info, keyinfo, search_flag, nod_cmp_flag, root, 0);
265 }
266
267
268 /*
269 Get next key in r-tree recursively
270
271 NOTES
272 Used in rtree_get_first() and rtree_get_next()
273
274 RETURN
275 -1 Error
276 0 Found
277 1 Not found
278 */
279
rtree_get_req(MI_INFO * info,MI_KEYDEF * keyinfo,uint key_length,my_off_t page,int level)280 static int rtree_get_req(MI_INFO *info, MI_KEYDEF *keyinfo, uint key_length,
281 my_off_t page, int level)
282 {
283 uchar *k;
284 uchar *last;
285 uint nod_flag;
286 int res;
287 uchar *page_buf;
288 uint k_len;
289 uint *saved_key = (uint*) (info->rtree_recursion_state) + level;
290
291 if (!(page_buf = (uchar*)my_alloca((uint)keyinfo->block_length)))
292 return -1;
293 if (!_mi_fetch_keypage(info, keyinfo, page, DFLT_INIT_HITS, page_buf, 0))
294 goto err1;
295 nod_flag = mi_test_if_nod(page_buf);
296
297 k_len = keyinfo->keylength - info->s->base.rec_reflength;
298
299 if(info->rtree_recursion_depth >= level)
300 {
301 k = page_buf + *saved_key;
302 if (!nod_flag)
303 {
304 /* Only leaf pages contain data references. */
305 /* Need to check next key with data reference. */
306 k = rt_PAGE_NEXT_KEY(k, k_len, nod_flag);
307 }
308 }
309 else
310 {
311 k = rt_PAGE_FIRST_KEY(page_buf, nod_flag);
312 }
313 last = rt_PAGE_END(page_buf);
314
315 for (; k < last; k = rt_PAGE_NEXT_KEY(k, k_len, nod_flag))
316 {
317 if (nod_flag)
318 {
319 /* this is an internal node in the tree */
320 switch ((res = rtree_get_req(info, keyinfo, key_length,
321 _mi_kpos(nod_flag, k), level + 1)))
322 {
323 case 0: /* found - exit from recursion */
324 *saved_key = (uint) (k - page_buf);
325 goto ok;
326 case 1: /* not found - continue searching */
327 info->rtree_recursion_depth = level;
328 break;
329 default:
330 case -1: /* error */
331 goto err1;
332 }
333 }
334 else
335 {
336 /* this is a leaf */
337 uchar *after_key = rt_PAGE_NEXT_KEY(k, k_len, nod_flag);
338 info->lastpos = _mi_dpos(info, 0, after_key);
339 info->lastkey_length = k_len + info->s->base.rec_reflength;
340 memcpy(info->lastkey, k, info->lastkey_length);
341
342 info->rtree_recursion_depth = level;
343 *saved_key = (uint) (k - page_buf);
344
345 if (after_key < last)
346 {
347 info->int_keypos = (uchar*)saved_key;
348 memcpy(info->buff, page_buf, keyinfo->block_length);
349 info->int_maxpos = rt_PAGE_END(info->buff);
350 info->buff_used = 0;
351 }
352 else
353 {
354 info->buff_used = 1;
355 }
356
357 res = 0;
358 goto ok;
359 }
360 }
361 info->lastpos = HA_OFFSET_ERROR;
362 my_errno = HA_ERR_KEY_NOT_FOUND;
363 res = 1;
364
365 ok:
366 my_afree((uchar*)page_buf);
367 return res;
368
369 err1:
370 my_afree((uchar*)page_buf);
371 info->lastpos = HA_OFFSET_ERROR;
372 return -1;
373 }
374
375
376 /*
377 Get first key in r-tree
378
379 RETURN
380 -1 Error
381 0 Found
382 1 Not found
383 */
384
rtree_get_first(MI_INFO * info,uint keynr,uint key_length)385 int rtree_get_first(MI_INFO *info, uint keynr, uint key_length)
386 {
387 my_off_t root;
388 MI_KEYDEF *keyinfo = info->s->keyinfo + keynr;
389
390 if ((root = info->s->state.key_root[keynr]) == HA_OFFSET_ERROR)
391 {
392 my_errno= HA_ERR_END_OF_FILE;
393 return -1;
394 }
395
396 info->rtree_recursion_depth = -1;
397 info->buff_used = 1;
398
399 return rtree_get_req(info, keyinfo, key_length, root, 0);
400 }
401
402
403 /*
404 Get next key in r-tree
405
406 RETURN
407 -1 Error
408 0 Found
409 1 Not found
410 */
411
rtree_get_next(MI_INFO * info,uint keynr,uint key_length)412 int rtree_get_next(MI_INFO *info, uint keynr, uint key_length)
413 {
414 my_off_t root= info->s->state.key_root[keynr];
415 MI_KEYDEF *keyinfo = info->s->keyinfo + keynr;
416
417 if (root == HA_OFFSET_ERROR)
418 {
419 my_errno= HA_ERR_END_OF_FILE;
420 return -1;
421 }
422
423 if (!info->buff_used && !info->page_changed)
424 {
425 uint k_len = keyinfo->keylength - info->s->base.rec_reflength;
426 /* rt_PAGE_NEXT_KEY(info->int_keypos) */
427 uchar *key = info->buff + *(int*)info->int_keypos + k_len +
428 info->s->base.rec_reflength;
429 /* rt_PAGE_NEXT_KEY(key) */
430 uchar *after_key = key + k_len + info->s->base.rec_reflength;
431
432 info->lastpos = _mi_dpos(info, 0, after_key);
433 info->lastkey_length = k_len + info->s->base.rec_reflength;
434 memcpy(info->lastkey, key, k_len + info->s->base.rec_reflength);
435
436 *(uint*)info->int_keypos = (uint) (key - info->buff);
437 if (after_key >= info->int_maxpos)
438 {
439 info->buff_used = 1;
440 }
441
442 return 0;
443 }
444
445 return rtree_get_req(info, keyinfo, key_length, root, 0);
446 }
447
448
449 /*
450 Choose non-leaf better key for insertion
451 */
452
453 #ifdef PICK_BY_PERIMETER
rtree_pick_key(MI_INFO * info,MI_KEYDEF * keyinfo,uchar * key,uint key_length,uchar * page_buf,uint nod_flag)454 static uchar *rtree_pick_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *key,
455 uint key_length, uchar *page_buf, uint nod_flag)
456 {
457 double increase;
458 double best_incr = DBL_MAX;
459 double perimeter;
460 double best_perimeter;
461 uchar *best_key;
462 uchar *k = rt_PAGE_FIRST_KEY(page_buf, nod_flag);
463 uchar *last = rt_PAGE_END(page_buf);
464
465 LINT_INIT(best_perimeter);
466 LINT_INIT(best_key);
467
468 for (; k < last; k = rt_PAGE_NEXT_KEY(k, key_length, nod_flag))
469 {
470 if ((increase = rtree_perimeter_increase(keyinfo->seg, k, key, key_length,
471 &perimeter)) == -1)
472 return NULL;
473 if ((increase < best_incr)||
474 (increase == best_incr && perimeter < best_perimeter))
475 {
476 best_key = k;
477 best_perimeter= perimeter;
478 best_incr = increase;
479 }
480 }
481 return best_key;
482 }
483
484 #endif /*PICK_BY_PERIMETER*/
485
486 #ifdef PICK_BY_AREA
rtree_pick_key(MI_INFO * info,MI_KEYDEF * keyinfo,uchar * key,uint key_length,uchar * page_buf,uint nod_flag)487 static uchar *rtree_pick_key(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *key,
488 uint key_length, uchar *page_buf, uint nod_flag)
489 {
490 double increase;
491 double UNINIT_VAR(best_incr);
492 double area;
493 double UNINIT_VAR(best_area);
494 uchar *best_key= NULL;
495 uchar *k = rt_PAGE_FIRST_KEY(page_buf, nod_flag);
496 uchar *last = rt_PAGE_END(page_buf);
497
498 for (; k < last; k = rt_PAGE_NEXT_KEY(k, key_length, nod_flag))
499 {
500 /* The following is safe as -1.0 is an exact number */
501 if ((increase = rtree_area_increase(keyinfo->seg, k, key, key_length,
502 &area)) == -1.0)
503 return NULL;
504 /* The following should be safe, even if we compare doubles */
505 if (!best_key || increase < best_incr ||
506 ((increase == best_incr) && (area < best_area)))
507 {
508 best_key = k;
509 best_area = area;
510 best_incr = increase;
511 }
512 }
513 return best_key;
514 }
515
516 #endif /*PICK_BY_AREA*/
517
518 /*
519 Go down and insert key into tree
520
521 RETURN
522 -1 Error
523 0 Child was not split
524 1 Child was split
525 */
526
rtree_insert_req(MI_INFO * info,MI_KEYDEF * keyinfo,uchar * key,uint key_length,my_off_t page,my_off_t * new_page,int ins_level,int level)527 static int rtree_insert_req(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *key,
528 uint key_length, my_off_t page, my_off_t *new_page,
529 int ins_level, int level)
530 {
531 uchar *k;
532 uint nod_flag;
533 uchar *page_buf;
534 int res;
535 DBUG_ENTER("rtree_insert_req");
536
537 if (!(page_buf = (uchar*)my_alloca((uint)keyinfo->block_length +
538 MI_MAX_KEY_BUFF)))
539 {
540 my_errno = HA_ERR_OUT_OF_MEM;
541 DBUG_RETURN(-1); /* purecov: inspected */
542 }
543 if (!_mi_fetch_keypage(info, keyinfo, page, DFLT_INIT_HITS, page_buf, 0))
544 goto err1;
545 nod_flag = mi_test_if_nod(page_buf);
546 DBUG_PRINT("rtree", ("page: %lu level: %d ins_level: %d nod_flag: %u",
547 (ulong) page, level, ins_level, nod_flag));
548
549 if ((ins_level == -1 && nod_flag) || /* key: go down to leaf */
550 (ins_level > -1 && ins_level > level)) /* branch: go down to ins_level */
551 {
552 if ((k = rtree_pick_key(info, keyinfo, key, key_length, page_buf,
553 nod_flag)) == NULL)
554 goto err1;
555 switch ((res = rtree_insert_req(info, keyinfo, key, key_length,
556 _mi_kpos(nod_flag, k), new_page, ins_level, level + 1)))
557 {
558 case 0: /* child was not split */
559 {
560 rtree_combine_rect(keyinfo->seg, k, key, k, key_length);
561 if (_mi_write_keypage(info, keyinfo, page, DFLT_INIT_HITS, page_buf))
562 goto err1;
563 goto ok;
564 }
565 case 1: /* child was split */
566 {
567 uchar *new_key = page_buf + keyinfo->block_length + nod_flag;
568 /* set proper MBR for key */
569 if (rtree_set_key_mbr(info, keyinfo, k, key_length,
570 _mi_kpos(nod_flag, k)))
571 goto err1;
572 /* add new key for new page */
573 _mi_kpointer(info, new_key - nod_flag, *new_page);
574 if (rtree_set_key_mbr(info, keyinfo, new_key, key_length, *new_page))
575 goto err1;
576 res = rtree_add_key(info, keyinfo, new_key, key_length,
577 page_buf, new_page);
578 if (_mi_write_keypage(info, keyinfo, page, DFLT_INIT_HITS, page_buf))
579 goto err1;
580 goto ok;
581 }
582 default:
583 case -1: /* error */
584 {
585 goto err1;
586 }
587 }
588 }
589 else
590 {
591 res = rtree_add_key(info, keyinfo, key, key_length, page_buf, new_page);
592 if (_mi_write_keypage(info, keyinfo, page, DFLT_INIT_HITS, page_buf))
593 goto err1;
594 goto ok;
595 }
596
597 ok:
598 my_afree((uchar*)page_buf);
599 DBUG_RETURN(res);
600
601 err1:
602 my_afree((uchar*)page_buf);
603 DBUG_RETURN(-1); /* purecov: inspected */
604 }
605
606
607 /*
608 Insert key into the tree
609
610 RETURN
611 -1 Error
612 0 Root was not split
613 1 Root was split
614 */
615
rtree_insert_level(MI_INFO * info,uint keynr,uchar * key,uint key_length,int ins_level)616 static int rtree_insert_level(MI_INFO *info, uint keynr, uchar *key,
617 uint key_length, int ins_level)
618 {
619 my_off_t old_root;
620 MI_KEYDEF *keyinfo = info->s->keyinfo + keynr;
621 int res;
622 my_off_t new_page;
623 DBUG_ENTER("rtree_insert_level");
624
625 if ((old_root = info->s->state.key_root[keynr]) == HA_OFFSET_ERROR)
626 {
627 if ((old_root = _mi_new(info, keyinfo, DFLT_INIT_HITS)) == HA_OFFSET_ERROR)
628 DBUG_RETURN(-1);
629 info->buff_used = 1;
630 mi_putint(info->buff, 2, 0);
631 res = rtree_add_key(info, keyinfo, key, key_length, info->buff, NULL);
632 if (_mi_write_keypage(info, keyinfo, old_root, DFLT_INIT_HITS, info->buff))
633 DBUG_RETURN(1);
634 info->s->state.key_root[keynr] = old_root;
635 DBUG_RETURN(res);
636 }
637
638 switch ((res = rtree_insert_req(info, keyinfo, key, key_length,
639 old_root, &new_page, ins_level, 0)))
640 {
641 case 0: /* root was not split */
642 {
643 break;
644 }
645 case 1: /* root was split, grow a new root */
646 {
647 uchar *new_root_buf= info->buff + info->s->base.max_key_block_length;
648 my_off_t new_root;
649 uchar *new_key;
650 uint nod_flag = info->s->base.key_reflength;
651
652 DBUG_PRINT("rtree", ("root was split, grow a new root"));
653
654 mi_putint(new_root_buf, 2, nod_flag);
655 if ((new_root = _mi_new(info, keyinfo, DFLT_INIT_HITS)) ==
656 HA_OFFSET_ERROR)
657 goto err1;
658
659 new_key = new_root_buf + keyinfo->block_length + nod_flag;
660
661 _mi_kpointer(info, new_key - nod_flag, old_root);
662 if (rtree_set_key_mbr(info, keyinfo, new_key, key_length, old_root))
663 goto err1;
664 if (rtree_add_key(info, keyinfo, new_key, key_length, new_root_buf, NULL)
665 == -1)
666 goto err1;
667 _mi_kpointer(info, new_key - nod_flag, new_page);
668 if (rtree_set_key_mbr(info, keyinfo, new_key, key_length, new_page))
669 goto err1;
670 if (rtree_add_key(info, keyinfo, new_key, key_length, new_root_buf, NULL)
671 == -1)
672 goto err1;
673 if (_mi_write_keypage(info, keyinfo, new_root,
674 DFLT_INIT_HITS, new_root_buf))
675 goto err1;
676 info->s->state.key_root[keynr] = new_root;
677 DBUG_PRINT("rtree", ("new root page: %lu level: %d nod_flag: %u",
678 (ulong) new_root, 0, mi_test_if_nod(new_root_buf)));
679
680 break;
681 err1:
682 DBUG_RETURN(-1); /* purecov: inspected */
683 }
684 default:
685 case -1: /* error */
686 {
687 break;
688 }
689 }
690 DBUG_RETURN(res);
691 }
692
693
694 /*
695 Insert key into the tree - interface function
696
697 RETURN
698 -1 Error
699 0 OK
700 */
701
rtree_insert(MI_INFO * info,uint keynr,uchar * key,uint key_length)702 int rtree_insert(MI_INFO *info, uint keynr, uchar *key, uint key_length)
703 {
704 DBUG_ENTER("rtree_insert");
705 DBUG_RETURN((!key_length ||
706 (rtree_insert_level(info, keynr, key, key_length, -1) == -1)) ?
707 -1 : 0);
708 }
709
710
711 /*
712 Fill reinsert page buffer
713
714 RETURN
715 -1 Error
716 0 OK
717 */
718
rtree_fill_reinsert_list(stPageList * ReinsertList,my_off_t page,int level)719 static int rtree_fill_reinsert_list(stPageList *ReinsertList, my_off_t page,
720 int level)
721 {
722 DBUG_ENTER("rtree_fill_reinsert_list");
723 DBUG_PRINT("rtree", ("page: %lu level: %d", (ulong) page, level));
724 if (ReinsertList->n_pages == ReinsertList->m_pages)
725 {
726 ReinsertList->m_pages += REINSERT_BUFFER_INC;
727 if (!(ReinsertList->pages = (stPageLevel*)my_realloc((uchar*)ReinsertList->pages,
728 ReinsertList->m_pages * sizeof(stPageLevel), MYF(MY_ALLOW_ZERO_PTR))))
729 goto err1;
730 }
731 /* save page to ReinsertList */
732 ReinsertList->pages[ReinsertList->n_pages].offs = page;
733 ReinsertList->pages[ReinsertList->n_pages].level = level;
734 ReinsertList->n_pages++;
735 DBUG_RETURN(0);
736
737 err1:
738 DBUG_RETURN(-1); /* purecov: inspected */
739 }
740
741
742 /*
743 Go down and delete key from the tree
744
745 RETURN
746 -1 Error
747 0 Deleted
748 1 Not found
749 2 Empty leaf
750 */
751
rtree_delete_req(MI_INFO * info,MI_KEYDEF * keyinfo,uchar * key,uint key_length,my_off_t page,uint * page_size,stPageList * ReinsertList,int level)752 static int rtree_delete_req(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *key,
753 uint key_length, my_off_t page, uint *page_size,
754 stPageList *ReinsertList, int level)
755 {
756 uchar *k;
757 uchar *last;
758 ulong i;
759 uint nod_flag;
760 uchar *page_buf;
761 int res;
762 DBUG_ENTER("rtree_delete_req");
763
764 if (!(page_buf = (uchar*)my_alloca((uint)keyinfo->block_length)))
765 {
766 my_errno = HA_ERR_OUT_OF_MEM;
767 DBUG_RETURN(-1); /* purecov: inspected */
768 }
769 if (!_mi_fetch_keypage(info, keyinfo, page, DFLT_INIT_HITS, page_buf, 0))
770 goto err1;
771 nod_flag = mi_test_if_nod(page_buf);
772 DBUG_PRINT("rtree", ("page: %lu level: %d nod_flag: %u",
773 (ulong) page, level, nod_flag));
774
775 k = rt_PAGE_FIRST_KEY(page_buf, nod_flag);
776 last = rt_PAGE_END(page_buf);
777
778 for (i = 0; k < last; k = rt_PAGE_NEXT_KEY(k, key_length, nod_flag), ++i)
779 {
780 if (nod_flag)
781 {
782 /* not leaf */
783 if (!rtree_key_cmp(keyinfo->seg, key, k, key_length, MBR_WITHIN))
784 {
785 switch ((res = rtree_delete_req(info, keyinfo, key, key_length,
786 _mi_kpos(nod_flag, k), page_size, ReinsertList, level + 1)))
787 {
788 case 0: /* deleted */
789 {
790 /* test page filling */
791 if (*page_size + key_length >= rt_PAGE_MIN_SIZE(keyinfo->block_length))
792 {
793 /* OK */
794 /* Calculate a new key value (MBR) for the shrinked block. */
795 if (rtree_set_key_mbr(info, keyinfo, k, key_length,
796 _mi_kpos(nod_flag, k)))
797 goto err1;
798 if (_mi_write_keypage(info, keyinfo, page,
799 DFLT_INIT_HITS, page_buf))
800 goto err1;
801 }
802 else
803 {
804 /*
805 Too small: delete key & add it descendant to reinsert list.
806 Store position and level of the block so that it can be
807 accessed later for inserting the remaining keys.
808 */
809 DBUG_PRINT("rtree", ("too small. move block to reinsert list"));
810 if (rtree_fill_reinsert_list(ReinsertList, _mi_kpos(nod_flag, k),
811 level + 1))
812 goto err1;
813 /*
814 Delete the key that references the block. This makes the
815 block disappear from the index. Hence we need to insert
816 its remaining keys later. Note: if the block is a branch
817 block, we do not only remove this block, but the whole
818 subtree. So we need to re-insert its keys on the same
819 level later to reintegrate the subtrees.
820 */
821 rtree_delete_key(info, page_buf, k, key_length, nod_flag);
822 if (_mi_write_keypage(info, keyinfo, page,
823 DFLT_INIT_HITS, page_buf))
824 goto err1;
825 *page_size = mi_getint(page_buf);
826 }
827
828 goto ok;
829 }
830 case 1: /* not found - continue searching */
831 {
832 break;
833 }
834 case 2: /* vacuous case: last key in the leaf */
835 {
836 rtree_delete_key(info, page_buf, k, key_length, nod_flag);
837 if (_mi_write_keypage(info, keyinfo, page,
838 DFLT_INIT_HITS, page_buf))
839 goto err1;
840 *page_size = mi_getint(page_buf);
841 res = 0;
842 goto ok;
843 }
844 default: /* error */
845 case -1:
846 {
847 goto err1;
848 }
849 }
850 }
851 }
852 else
853 {
854 /* leaf */
855 if (!rtree_key_cmp(keyinfo->seg, key, k, key_length, MBR_EQUAL | MBR_DATA))
856 {
857 rtree_delete_key(info, page_buf, k, key_length, nod_flag);
858 *page_size = mi_getint(page_buf);
859 if (*page_size == 2)
860 {
861 /* last key in the leaf */
862 res = 2;
863 if (_mi_dispose(info, keyinfo, page, DFLT_INIT_HITS))
864 goto err1;
865 }
866 else
867 {
868 res = 0;
869 if (_mi_write_keypage(info, keyinfo, page, DFLT_INIT_HITS, page_buf))
870 goto err1;
871 }
872 goto ok;
873 }
874 }
875 }
876 res = 1;
877
878 ok:
879 my_afree((uchar*)page_buf);
880 DBUG_RETURN(res);
881
882 err1:
883 my_afree((uchar*)page_buf);
884 DBUG_RETURN(-1); /* purecov: inspected */
885 }
886
887
888 /*
889 Delete key - interface function
890
891 RETURN
892 -1 Error
893 0 Deleted
894 */
895
rtree_delete(MI_INFO * info,uint keynr,uchar * key,uint key_length)896 int rtree_delete(MI_INFO *info, uint keynr, uchar *key, uint key_length)
897 {
898 uint page_size;
899 stPageList ReinsertList;
900 my_off_t old_root;
901 MI_KEYDEF *keyinfo = info->s->keyinfo + keynr;
902 DBUG_ENTER("rtree_delete");
903
904 if ((old_root = info->s->state.key_root[keynr]) == HA_OFFSET_ERROR)
905 {
906 my_errno= HA_ERR_END_OF_FILE;
907 DBUG_RETURN(-1); /* purecov: inspected */
908 }
909 DBUG_PRINT("rtree", ("starting deletion at root page: %lu",
910 (ulong) old_root));
911
912 ReinsertList.pages = NULL;
913 ReinsertList.n_pages = 0;
914 ReinsertList.m_pages = 0;
915
916 switch (rtree_delete_req(info, keyinfo, key, key_length, old_root,
917 &page_size, &ReinsertList, 0))
918 {
919 case 2: /* empty */
920 {
921 info->s->state.key_root[keynr] = HA_OFFSET_ERROR;
922 DBUG_RETURN(0);
923 }
924 case 0: /* deleted */
925 {
926 uint nod_flag;
927 ulong i;
928 for (i = 0; i < ReinsertList.n_pages; ++i)
929 {
930 uchar *page_buf;
931 uchar *k;
932 uchar *last;
933
934 if (!(page_buf = (uchar*)my_alloca((uint)keyinfo->block_length)))
935 {
936 my_errno = HA_ERR_OUT_OF_MEM;
937 goto err1;
938 }
939 if (!_mi_fetch_keypage(info, keyinfo, ReinsertList.pages[i].offs,
940 DFLT_INIT_HITS, page_buf, 0))
941 goto err1;
942 nod_flag = mi_test_if_nod(page_buf);
943 DBUG_PRINT("rtree", ("reinserting keys from "
944 "page: %lu level: %d nod_flag: %u",
945 (ulong) ReinsertList.pages[i].offs,
946 ReinsertList.pages[i].level, nod_flag));
947
948 k = rt_PAGE_FIRST_KEY(page_buf, nod_flag);
949 last = rt_PAGE_END(page_buf);
950 for (; k < last; k = rt_PAGE_NEXT_KEY(k, key_length, nod_flag))
951 {
952 int res;
953 if ((res= rtree_insert_level(info, keynr, k, key_length,
954 ReinsertList.pages[i].level)) == -1)
955 {
956 my_afree((uchar*)page_buf);
957 goto err1;
958 }
959 if (res)
960 {
961 ulong j;
962 DBUG_PRINT("rtree", ("root has been split, adjust levels"));
963 for (j= i; j < ReinsertList.n_pages; j++)
964 {
965 ReinsertList.pages[j].level++;
966 DBUG_PRINT("rtree", ("keys from page: %lu now level: %d",
967 (ulong) ReinsertList.pages[i].offs,
968 ReinsertList.pages[i].level));
969 }
970 }
971 }
972 my_afree((uchar*)page_buf);
973 if (_mi_dispose(info, keyinfo, ReinsertList.pages[i].offs,
974 DFLT_INIT_HITS))
975 goto err1;
976 }
977 if (ReinsertList.pages)
978 my_free(ReinsertList.pages);
979
980 /* check for redundant root (not leaf, 1 child) and eliminate */
981 if ((old_root = info->s->state.key_root[keynr]) == HA_OFFSET_ERROR)
982 goto err1;
983 if (!_mi_fetch_keypage(info, keyinfo, old_root, DFLT_INIT_HITS,
984 info->buff, 0))
985 goto err1;
986 nod_flag = mi_test_if_nod(info->buff);
987 page_size = mi_getint(info->buff);
988 if (nod_flag && (page_size == 2 + key_length + nod_flag))
989 {
990 my_off_t new_root = _mi_kpos(nod_flag,
991 rt_PAGE_FIRST_KEY(info->buff, nod_flag));
992 if (_mi_dispose(info, keyinfo, old_root, DFLT_INIT_HITS))
993 goto err1;
994 info->s->state.key_root[keynr] = new_root;
995 }
996 info->update= HA_STATE_DELETED;
997 DBUG_RETURN(0);
998
999 err1:
1000 DBUG_RETURN(-1); /* purecov: inspected */
1001 }
1002 case 1: /* not found */
1003 {
1004 my_errno = HA_ERR_KEY_NOT_FOUND;
1005 DBUG_RETURN(-1); /* purecov: inspected */
1006 }
1007 default:
1008 case -1: /* error */
1009 {
1010 DBUG_RETURN(-1); /* purecov: inspected */
1011 }
1012 }
1013 }
1014
1015
1016 /*
1017 Estimate number of suitable keys in the tree
1018
1019 RETURN
1020 estimated value
1021 */
1022
rtree_estimate(MI_INFO * info,uint keynr,uchar * key,uint key_length,uint flag)1023 ha_rows rtree_estimate(MI_INFO *info, uint keynr, uchar *key,
1024 uint key_length, uint flag)
1025 {
1026 MI_KEYDEF *keyinfo = info->s->keyinfo + keynr;
1027 my_off_t root;
1028 uint i = 0;
1029 uchar *k;
1030 uchar *last;
1031 uint nod_flag;
1032 uchar *page_buf;
1033 uint k_len;
1034 double area = 0;
1035 ha_rows res = 0;
1036
1037 if (flag & MBR_DISJOINT)
1038 return info->state->records;
1039
1040 if ((root = info->s->state.key_root[keynr]) == HA_OFFSET_ERROR)
1041 return HA_POS_ERROR;
1042 if (!(page_buf = (uchar*)my_alloca((uint)keyinfo->block_length)))
1043 return HA_POS_ERROR;
1044 if (!_mi_fetch_keypage(info, keyinfo, root, DFLT_INIT_HITS, page_buf, 0))
1045 goto err1;
1046 nod_flag = mi_test_if_nod(page_buf);
1047
1048 k_len = keyinfo->keylength - info->s->base.rec_reflength;
1049
1050 k = rt_PAGE_FIRST_KEY(page_buf, nod_flag);
1051 last = rt_PAGE_END(page_buf);
1052
1053 for (; k < last; k = rt_PAGE_NEXT_KEY(k, k_len, nod_flag), ++i)
1054 {
1055 if (nod_flag)
1056 {
1057 double k_area = rtree_rect_volume(keyinfo->seg, k, key_length);
1058
1059 /* The following should be safe, even if we compare doubles */
1060 if (k_area == 0)
1061 {
1062 if (flag & (MBR_CONTAIN | MBR_INTERSECT))
1063 {
1064 area += 1;
1065 }
1066 else if (flag & (MBR_WITHIN | MBR_EQUAL))
1067 {
1068 if (!rtree_key_cmp(keyinfo->seg, key, k, key_length, MBR_WITHIN))
1069 area += 1;
1070 }
1071 else
1072 goto err1;
1073 }
1074 else
1075 {
1076 if (flag & (MBR_CONTAIN | MBR_INTERSECT))
1077 {
1078 area += rtree_overlapping_area(keyinfo->seg, key, k, key_length) /
1079 k_area;
1080 }
1081 else if (flag & (MBR_WITHIN | MBR_EQUAL))
1082 {
1083 if (!rtree_key_cmp(keyinfo->seg, key, k, key_length, MBR_WITHIN))
1084 area += rtree_rect_volume(keyinfo->seg, key, key_length) /
1085 k_area;
1086 }
1087 else
1088 goto err1;
1089 }
1090 }
1091 else
1092 {
1093 if (!rtree_key_cmp(keyinfo->seg, key, k, key_length, flag))
1094 ++res;
1095 }
1096 }
1097 if (nod_flag)
1098 {
1099 if (i)
1100 res = (ha_rows) (area / i * info->state->records);
1101 else
1102 res = HA_POS_ERROR;
1103 }
1104
1105 my_afree((uchar*)page_buf);
1106 return res;
1107
1108 err1:
1109 my_afree((uchar*)page_buf);
1110 return HA_POS_ERROR;
1111 }
1112
1113 #endif /*HAVE_RTREE_KEYS*/
1114
1115