16 #include "myisamdef.h"
18 #ifdef HAVE_RTREE_KEYS
32 inline static double *reserve_coords(
double **d_buffer,
int n_dim)
34 double *coords = *d_buffer;
35 (*d_buffer) += n_dim * 2;
39 static void mbr_join(
double *a,
const double *b,
int n_dim)
41 double *end = a + n_dim * 2;
58 static double mbr_join_square(
const double *a,
const double *b,
int n_dim)
60 const double *end = a + n_dim * 2;
65 ((a[1] < b[1]) ? b[1] : a[1]) - ((a[0] > b[0]) ? b[0] : a[0]);
74 static double count_square(
const double *a,
int n_dim)
76 const double *end = a + n_dim * 2;
80 square *= a[1] - a[0];
86 inline static void copy_coords(
double *dst,
const double *src,
int n_dim)
88 memcpy(dst, src,
sizeof(
double) * (n_dim * 2));
94 static void pick_seeds(SplitStruct *node,
int n_entries,
95 SplitStruct **seed_a, SplitStruct **seed_b,
int n_dim)
98 SplitStruct *lim1 = node + (n_entries - 1);
100 SplitStruct *lim2 = node + n_entries;
102 double max_d = -DBL_MAX;
105 for (cur1 = node; cur1 < lim1; ++cur1)
107 for (cur2=cur1 + 1; cur2 < lim2; ++cur2)
110 d = mbr_join_square(cur1->coords, cur2->coords, n_dim) - cur1->square -
125 static void pick_next(SplitStruct *node,
int n_entries,
double *g1,
double *g2,
126 SplitStruct **choice,
int *n_group,
int n_dim)
128 SplitStruct *cur = node;
129 SplitStruct *end = node + n_entries;
131 double max_diff = -DBL_MAX;
133 for (; cur<end; ++cur)
143 diff = mbr_join_square(g1, cur->coords, n_dim) -
144 mbr_join_square(g2, cur->coords, n_dim);
146 abs_diff = fabs(diff);
147 if (abs_diff > max_diff)
150 *n_group = 1 + (diff > 0);
159 static void mark_all_entries(SplitStruct *node,
int n_entries,
int n_group)
161 SplitStruct *cur = node;
162 SplitStruct *end = node + n_entries;
163 for (; cur<end; ++cur)
169 cur->n_node = n_group;
173 static int split_rtree_node(SplitStruct *node,
int n_entries,
177 int size1,
int size2 ,
178 double **d_buffer,
int n_dim)
181 SplitStruct *UNINIT_VAR(a), *UNINIT_VAR(b);
182 double *g1 = reserve_coords(d_buffer, n_dim);
183 double *g2 = reserve_coords(d_buffer, n_dim);
184 SplitStruct *UNINIT_VAR(next);
185 int UNINIT_VAR(next_node);
187 SplitStruct *end = node + n_entries;
189 if (all_size < min_size * 2)
195 for (; cur<end; ++cur)
197 cur->square = count_square(cur->coords, n_dim);
201 pick_seeds(node, n_entries, &a, &b, n_dim);
206 copy_coords(g1, a->coords, n_dim);
208 copy_coords(g2, b->coords, n_dim);
212 for (i=n_entries - 2; i>0; --
i)
214 if (all_size - (size2 + key_size) < min_size)
216 mark_all_entries(node, n_entries, 1);
220 if (all_size - (size1 + key_size) < min_size)
222 mark_all_entries(node, n_entries, 2);
226 pick_next(node, n_entries, g1, g2, &next, &next_node, n_dim);
230 mbr_join(g1, next->coords, n_dim);
235 mbr_join(g2, next->coords, n_dim);
237 next->n_node = next_node;
244 uint key_length, my_off_t *new_page_offs)
254 uchar *source_cur, *cur1, *cur2;
255 uchar *new_page= info->buff;
257 uint nod_flag= mi_test_if_nod(page);
258 uint full_length= key_length + (nod_flag ? nod_flag :
259 info->s->base.rec_reflength);
260 int max_keys= (mi_getint(page)-2) / (full_length);
261 DBUG_ENTER(
"rtree_split_page");
262 DBUG_PRINT(
"rtree", (
"splitting block"));
264 n_dim = keyinfo->keysegs / 2;
266 if (!(coord_buf= (
double*) my_alloca(n_dim * 2 *
sizeof(
double) *
268 sizeof(SplitStruct) * (max_keys + 1))))
271 task= (SplitStruct *)(coord_buf + n_dim * 2 * (max_keys + 1 + 4));
273 next_coord = coord_buf;
275 stop = task + max_keys;
276 source_cur = rt_PAGE_FIRST_KEY(page, nod_flag);
278 for (cur = task; cur < stop; ++cur, source_cur = rt_PAGE_NEXT_KEY(source_cur,
279 key_length, nod_flag))
281 cur->coords = reserve_coords(&next_coord, n_dim);
282 cur->key = source_cur;
283 rtree_d_mbr(keyinfo->seg, source_cur, key_length, cur->coords);
286 cur->coords = reserve_coords(&next_coord, n_dim);
287 rtree_d_mbr(keyinfo->seg, key, key_length, cur->coords);
290 if (split_rtree_node(task, max_keys + 1,
291 mi_getint(page) + full_length + 2, full_length,
292 rt_PAGE_MIN_SIZE(keyinfo->block_length),
293 2, 2, &next_coord, n_dim))
300 stop = task + (max_keys + 1);
301 cur1 = rt_PAGE_FIRST_KEY(page, nod_flag);
302 cur2 = rt_PAGE_FIRST_KEY(new_page, nod_flag);
305 for (cur = task; cur < stop; ++cur)
308 if (cur->n_node == 1)
311 cur1 = rt_PAGE_NEXT_KEY(cur1, key_length, nod_flag);
317 cur2 = rt_PAGE_NEXT_KEY(cur2, key_length, nod_flag);
321 memcpy(to - nod_flag, cur->key - nod_flag, full_length);
324 mi_putint(page, 2 + n1 * full_length, nod_flag);
325 mi_putint(new_page, 2 + n2 * full_length, nod_flag);
327 if ((*new_page_offs= _mi_new(info, keyinfo, DFLT_INIT_HITS)) ==
331 err_code= _mi_write_keypage(info, keyinfo, *new_page_offs,
332 DFLT_INIT_HITS, new_page);
333 DBUG_PRINT(
"rtree", (
"split new block: %lu", (ulong) *new_page_offs));
336 my_afree((uchar*) coord_buf);
337 DBUG_RETURN(err_code);