static int 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) { uchar *k; uchar *last; ulong i; uint nod_flag; uchar *page_buf; int res; DBUG_ENTER("rtree_delete_req"); if (!(page_buf = (uchar*)my_alloca((uint)keyinfo->block_length))) { my_errno = HA_ERR_OUT_OF_MEM; DBUG_RETURN(-1); /* purecov: inspected */ } if (!_mi_fetch_keypage(info, keyinfo, page, DFLT_INIT_HITS, page_buf, 0)) goto err1; nod_flag = mi_test_if_nod(page_buf); DBUG_PRINT("rtree", ("page: %lu level: %d nod_flag: %u", (ulong) page, level, nod_flag)); k = rt_PAGE_FIRST_KEY(page_buf, nod_flag); last = rt_PAGE_END(page_buf); for (i = 0; k < last; k = rt_PAGE_NEXT_KEY(k, key_length, nod_flag), ++i) { if (nod_flag) { /* not leaf */ if (!rtree_key_cmp(keyinfo->seg, key, k, key_length, MBR_WITHIN)) { switch ((res = rtree_delete_req(info, keyinfo, key, key_length, _mi_kpos(nod_flag, k), page_size, ReinsertList, level + 1))) { case 0: /* deleted */ { /* test page filling */ if (*page_size + key_length >= rt_PAGE_MIN_SIZE(keyinfo->block_length)) { /* OK */ /* Calculate a new key value (MBR) for the shrinked block. */ if (rtree_set_key_mbr(info, keyinfo, k, key_length, _mi_kpos(nod_flag, k))) goto err1; if (_mi_write_keypage(info, keyinfo, page, DFLT_INIT_HITS, page_buf)) goto err1; } else { /* Too small: delete key & add it descendant to reinsert list. Store position and level of the block so that it can be accessed later for inserting the remaining keys. */ DBUG_PRINT("rtree", ("too small. move block to reinsert list")); if (rtree_fill_reinsert_list(ReinsertList, _mi_kpos(nod_flag, k), level + 1)) goto err1; /* Delete the key that references the block. This makes the block disappear from the index. Hence we need to insert its remaining keys later. Note: if the block is a branch block, we do not only remove this block, but the whole subtree. So we need to re-insert its keys on the same level later to reintegrate the subtrees. */ rtree_delete_key(info, page_buf, k, key_length, nod_flag); if (_mi_write_keypage(info, keyinfo, page, DFLT_INIT_HITS, page_buf)) goto err1; *page_size = mi_getint(page_buf); } goto ok; } case 1: /* not found - continue searching */ { break; } case 2: /* vacuous case: last key in the leaf */ { rtree_delete_key(info, page_buf, k, key_length, nod_flag); if (_mi_write_keypage(info, keyinfo, page, DFLT_INIT_HITS, page_buf)) goto err1; *page_size = mi_getint(page_buf); res = 0; goto ok; } default: /* error */ case -1: { goto err1; } } } } else { /* leaf */ if (!rtree_key_cmp(keyinfo->seg, key, k, key_length, MBR_EQUAL | MBR_DATA)) { rtree_delete_key(info, page_buf, k, key_length, nod_flag); *page_size = mi_getint(page_buf); if (*page_size == 2) { /* last key in the leaf */ res = 2; if (_mi_dispose(info, keyinfo, page, DFLT_INIT_HITS)) goto err1; } else { res = 0; if (_mi_write_keypage(info, keyinfo, page, DFLT_INIT_HITS, page_buf)) goto err1; } goto ok; } } } res = 1; ok: my_afree((uchar*)page_buf); DBUG_RETURN(res); err1: my_afree((uchar*)page_buf); DBUG_RETURN(-1); /* purecov: inspected */ }
int rtree_split_page(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page, uchar *key, uint key_length, my_off_t *new_page_offs) { int n1, n2; /* Number of items in groups */ SplitStruct *task; SplitStruct *cur; SplitStruct *stop; double *coord_buf; double *next_coord; int n_dim; uchar *source_cur, *cur1, *cur2; uchar *new_page= info->buff; int err_code= 0; uint nod_flag= mi_test_if_nod(page); uint full_length= key_length + (nod_flag ? nod_flag : info->s->base.rec_reflength); int max_keys= (mi_getint(page)-2) / (full_length); DBUG_ENTER("rtree_split_page"); DBUG_PRINT("rtree", ("splitting block")); n_dim = keyinfo->keysegs / 2; if (!(coord_buf= (double*) my_alloca(n_dim * 2 * sizeof(double) * (max_keys + 1 + 4) + sizeof(SplitStruct) * (max_keys + 1)))) DBUG_RETURN(-1); /* purecov: inspected */ task= (SplitStruct *)(coord_buf + n_dim * 2 * (max_keys + 1 + 4)); next_coord = coord_buf; stop = task + max_keys; source_cur = rt_PAGE_FIRST_KEY(page, nod_flag); for (cur = task; cur < stop; ++cur, source_cur = rt_PAGE_NEXT_KEY(source_cur, key_length, nod_flag)) { cur->coords = reserve_coords(&next_coord, n_dim); cur->key = source_cur; rtree_d_mbr(keyinfo->seg, source_cur, key_length, cur->coords); } cur->coords = reserve_coords(&next_coord, n_dim); rtree_d_mbr(keyinfo->seg, key, key_length, cur->coords); cur->key = key; if (split_rtree_node(task, max_keys + 1, mi_getint(page) + full_length + 2, full_length, rt_PAGE_MIN_SIZE(keyinfo->block_length), 2, 2, &next_coord, n_dim)) { err_code = 1; goto split_err; } info->buff_used= 1; stop = task + (max_keys + 1); cur1 = rt_PAGE_FIRST_KEY(page, nod_flag); cur2 = rt_PAGE_FIRST_KEY(new_page, nod_flag); n1= n2 = 0; for (cur = task; cur < stop; ++cur) { uchar *to; if (cur->n_node == 1) { to = cur1; cur1 = rt_PAGE_NEXT_KEY(cur1, key_length, nod_flag); ++n1; } else { to = cur2; cur2 = rt_PAGE_NEXT_KEY(cur2, key_length, nod_flag); ++n2; } if (to != cur->key) memcpy(to - nod_flag, cur->key - nod_flag, full_length); } mi_putint(page, 2 + n1 * full_length, nod_flag); mi_putint(new_page, 2 + n2 * full_length, nod_flag); if ((*new_page_offs= _mi_new(info, keyinfo, DFLT_INIT_HITS)) == HA_OFFSET_ERROR) err_code= -1; else err_code= _mi_write_keypage(info, keyinfo, *new_page_offs, DFLT_INIT_HITS, new_page); DBUG_PRINT("rtree", ("split new block: %lu", (ulong) *new_page_offs)); split_err: my_afree((uchar*) coord_buf); DBUG_RETURN(err_code); }