1
/* Copyright (C) 2002-2005 MySQL AB & Alexey Botchkov
3
This program is free software; you can redistribute it and/or modify
4
it under the terms of the GNU General Public License as published by
5
the Free Software Foundation; version 2 of the License.
7
This program is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
GNU General Public License for more details.
12
You should have received a copy of the GNU General Public License
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
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;
56
Counts the square of mbr which is a join of a and b
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));
92
Select two nodes to collect group upon
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 -
123
Select next node and group where to add
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);
157
Mark not-in-group entries as n_group
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,
174
int all_size, /* Total key's size */
176
int min_size, /* Minimal group size */
177
int size1, int size2 /* initial group sizes */,
178
double **d_buffer, int n_dim)
183
double *g1 = reserve_coords(d_buffer, n_dim);
184
double *g2 = reserve_coords(d_buffer, n_dim);
188
SplitStruct *end = node + n_entries;
192
LINT_INIT(next_node);
194
if (all_size < min_size * 2)
200
for (; cur<end; ++cur)
202
cur->square = count_square(cur->coords, n_dim);
206
pick_seeds(node, n_entries, &a, &b, n_dim);
211
copy_coords(g1, a->coords, n_dim);
213
copy_coords(g2, b->coords, n_dim);
217
for (i=n_entries - 2; i>0; --i)
219
if (all_size - (size2 + key_size) < min_size) /* Can't write into group 2 */
221
mark_all_entries(node, n_entries, 1);
225
if (all_size - (size1 + key_size) < min_size) /* Can't write into group 1 */
227
mark_all_entries(node, n_entries, 2);
231
pick_next(node, n_entries, g1, g2, &next, &next_node, n_dim);
235
mbr_join(g1, next->coords, n_dim);
240
mbr_join(g2, next->coords, n_dim);
242
next->n_node = next_node;
248
int rtree_split_page(MI_INFO *info, MI_KEYDEF *keyinfo, uchar *page, uchar *key,
249
uint key_length, my_off_t *new_page_offs)
251
int n1, n2; /* Number of items in groups */
260
uchar *source_cur, *cur1, *cur2;
263
uint nod_flag= mi_test_if_nod(page);
264
uint full_length= key_length + (nod_flag ? nod_flag :
265
info->s->base.rec_reflength);
266
int max_keys= (mi_getint(page)-2) / (full_length);
267
DBUG_ENTER("rtree_split_page");
268
DBUG_PRINT("rtree", ("splitting block"));
270
n_dim = keyinfo->keysegs / 2;
272
if (!(coord_buf= (double*) my_alloca(n_dim * 2 * sizeof(double) *
274
sizeof(SplitStruct) * (max_keys + 1))))
275
DBUG_RETURN(-1); /* purecov: inspected */
277
task= (SplitStruct *)(coord_buf + n_dim * 2 * (max_keys + 1 + 4));
279
next_coord = coord_buf;
281
stop = task + max_keys;
282
source_cur = rt_PAGE_FIRST_KEY(page, nod_flag);
284
for (cur = task; cur < stop; ++cur, source_cur = rt_PAGE_NEXT_KEY(source_cur,
285
key_length, nod_flag))
287
cur->coords = reserve_coords(&next_coord, n_dim);
288
cur->key = source_cur;
289
rtree_d_mbr(keyinfo->seg, source_cur, key_length, cur->coords);
292
cur->coords = reserve_coords(&next_coord, n_dim);
293
rtree_d_mbr(keyinfo->seg, key, key_length, cur->coords);
296
old_coord = next_coord;
298
if (split_rtree_node(task, max_keys + 1,
299
mi_getint(page) + full_length + 2, full_length,
300
rt_PAGE_MIN_SIZE(keyinfo->block_length),
301
2, 2, &next_coord, n_dim))
307
if (!(new_page = (uchar*)my_alloca((uint)keyinfo->block_length)))
313
stop = task + (max_keys + 1);
314
cur1 = rt_PAGE_FIRST_KEY(page, nod_flag);
315
cur2 = rt_PAGE_FIRST_KEY(new_page, nod_flag);
318
for (cur = task; cur < stop; ++cur)
321
if (cur->n_node == 1)
324
cur1 = rt_PAGE_NEXT_KEY(cur1, key_length, nod_flag);
330
cur2 = rt_PAGE_NEXT_KEY(cur2, key_length, nod_flag);
334
memcpy(to - nod_flag, cur->key - nod_flag, full_length);
337
mi_putint(page, 2 + n1 * full_length, nod_flag);
338
mi_putint(new_page, 2 + n2 * full_length, nod_flag);
340
if ((*new_page_offs= _mi_new(info, keyinfo, DFLT_INIT_HITS)) ==
344
err_code= _mi_write_keypage(info, keyinfo, *new_page_offs,
345
DFLT_INIT_HITS, new_page);
346
DBUG_PRINT("rtree", ("split new block: %lu", (ulong) *new_page_offs));
348
my_afree((uchar*)new_page);
351
my_afree((uchar*) coord_buf);
352
DBUG_RETURN(err_code);
355
#endif /*HAVE_RTREE_KEYS*/