1 | /* |
2 | * Copyright 1997-1999, 2001 John-Mark Gurney. |
3 | * All rights reserved. |
4 | * |
5 | * Redistribution and use in source and binary forms, with or without |
6 | * modification, are permitted provided that the following conditions |
7 | * are met: |
8 | * 1. Redistributions of source code must retain the above copyright |
9 | * notice, this list of conditions and the following disclaimer. |
10 | * 2. Redistributions in binary form must reproduce the above copyright |
11 | * notice, this list of conditions and the following disclaimer in the |
12 | * documentation and/or other materials provided with the distribution. |
13 | */ |
14 | |
15 | #include <assert.h> |
16 | #include <limits.h> |
17 | #include <stdlib.h> |
18 | #include <stdio.h> |
19 | #include <string.h> |
20 | #include <strings.h> |
21 | |
22 | #include "bt.h" |
23 | #include "bt_iterator.h" |
24 | #include "stream.h" |
25 | |
26 | #include <citrusleaf/alloc.h> |
27 | |
28 | /* CACHE TODO LIST |
29 | 8.) U128PK/FK CACHE:[EVICT,MISS] support |
30 | |
31 | 11.) DS as stream -\/ |
32 | 7.) DS in rdbSave/Load (dependency on 11) |
33 | |
34 | 12.) slab allocator for ALL btn's |
35 | |
36 | 14.) btFind() in setUniqIndexVal() -> btFindD() + TESTING |
37 | |
38 | 18.) CREATE TABLE () DIRTY |
39 | |
40 | 19.) btreesplitchild dirty math (only set dirty if new split child has dirty) |
41 | */ |
42 | |
43 | // DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG DEBUG |
44 | |
45 | //#define DEBUG_DEL_CASE_STATS |
46 | //#define BT_MEM_PROFILE |
47 | #ifdef BT_MEM_PROFILE |
48 | static ulong tot_bt_data = 0; static ulong tot_bt_data_mem = 0; |
49 | static ulong tot_num_bt_ns = 0; static ulong tnbtnmem = 0; |
50 | static ulong tot_num_bts = 0; static ulong tot_num_bt_mem = 0; |
51 | #define BT_MEM_PROFILE_BT {tot_num_bts++; tot_num_bt_mem += size;} |
52 | #define BT_MEM_PROFILE_NODE {tot_num_bt_ns++; tnbtnmem += size;} |
53 | #else |
54 | #define BT_MEM_PROFILE_BT |
55 | #define BT_MEM_PROFILE_NODE |
56 | #endif |
57 | |
58 | /* PROTOYPES */ |
59 | static void release_dirty_stream(bt *btr, bt_n *x); |
60 | static int real_log2 (unsigned int a, int nbits); |
61 | static bt_data_t findminkey (bt *btr, bt_n *x); |
62 | static bt_data_t findmaxkey (bt *btr, bt_n *x); |
63 | |
64 | // HELPER HELPER HELPER HELPER HELPER HELPER HELPER HELPER HELPER HELPER |
65 | static ulong getNumKey(bt *btr, bt_n *x, int i) { //TODO U128 support |
66 | if (i < 0 || i >= x->n) return 0; |
67 | else { |
68 | ai_obj akey; void *be = KEYS(btr, x, i); |
69 | convertStream2Key(be, &akey, btr); |
70 | return akey.l; |
71 | } |
72 | } |
73 | |
74 | // MEMORY_MANAGEMENT MEMORY_MANAGEMENT MEMORY_MANAGEMENT MEMORY_MANAGEMENT |
75 | /* NOTE used-memory bookkeeping maintained at the Btree level */ |
76 | static void bt_increment_used_memory(bt *btr, size_t size) { //DEBUG_INCR_MEM |
77 | btr->msize += (ull)size; |
78 | } |
79 | static void bt_decrement_used_memory(bt *btr, size_t size) { //DEBUG_DECR_MEM |
80 | btr->msize -= (ull)size; |
81 | } |
82 | // DIRTY_STREAM DIRTY_STREAM DIRTY_STREAM DIRTY_STREAM DIRTY_STREAM |
83 | static uint32 get_dssize(bt *btr, char dirty) { |
84 | assert(dirty > 0); |
85 | uint32 drsize = (dirty == 3) ? sizeof(uint32) : |
86 | (dirty == 2) ? sizeof(ushort16) : sizeof(uchar); // 1 |
87 | //DEBUG_GETDSSIZE |
88 | return (btr->t * 2) * drsize; |
89 | } |
90 | static void alloc_ds(bt *btr, bt_n *x, size_t size, char dirty) { |
91 | assert(dirty != -1); |
92 | void **dsp = (void *)((char *)x + size); |
93 | if (!dirty) { *dsp = NULL; return; } |
94 | size_t dssize = get_dssize(btr, dirty); |
95 | void *ds = cf_malloc(dssize); bzero(ds, dssize); // FREEME 108 |
96 | bt_increment_used_memory(btr, dssize); |
97 | *dsp = ds; //DEBUG_ALLOC_DS |
98 | } |
99 | void incr_ds(bt *btr, bt_n *x) {//USE: when a DR is too big for its DS (incr_ds) |
100 | assert(x->dirty > 0); |
101 | GET_BTN_SIZE(x->leaf) |
102 | void *ods = GET_DS(x, nsize); |
103 | uint32 osize = get_dssize(btr, x->dirty); |
104 | uint32 num = (x->leaf ? (btr->t * 2) : btr->t); //DEBUG_RESIZE_DS_1 |
105 | alloc_ds(btr, x, nsize, x->dirty + 1); |
106 | void *nds = GET_DS(x, nsize); |
107 | if (x->dirty == 1) { |
108 | uchar *s_ds = (uchar *)ods; ushort16 *d_ds = (ushort16 *)nds; |
109 | for (uint32 i = 0; i < num; i++) d_ds[i] = (ushort16)s_ds[i]; |
110 | } else if (x->dirty == 2) { |
111 | ushort16 *s_ds = (ushort16 *)ods; uint32 *d_ds = (uint32 *)nds; |
112 | for (uint32 i = 0; i < num; i++) d_ds[i] = (uint32 )s_ds[i]; |
113 | } else assert(!"incr_ds ERROR" ); |
114 | x->dirty++; //DEBUG_RESIZE_DS_2 |
115 | cf_free(ods); bt_decrement_used_memory(btr, osize); |
116 | } |
117 | |
118 | // BT_ALLOC_BTREE BT_ALLOC_BTREE BT_ALLOC_BTREE BT_ALLOC_BTREE BT_ALLOC_BTREE |
119 | // BT_ALLOC_BTREE BT_ALLOC_BTREE BT_ALLOC_BTREE BT_ALLOC_BTREE BT_ALLOC_BTREE |
120 | static bt_n *allocbtreenode(bt *btr, bool leaf, char dirty) { |
121 | btr->numnodes++; |
122 | GET_BTN_SIZES(leaf, dirty) BT_MEM_PROFILE_NODE //DEBUG_ALLOC_BTN |
123 | bt_n *x = cf_malloc(msize); bzero(x, msize); |
124 | bt_increment_used_memory(btr, msize); |
125 | x->leaf = -1; |
126 | x->dirty = dirty; |
127 | if (dirty != -1) alloc_ds(btr, x, nsize, dirty); |
128 | return x; |
129 | } |
130 | static bt *allocbtree() { |
131 | int size = sizeof(struct btree); |
132 | BT_MEM_PROFILE_BT |
133 | bt *btr = (bt *) cf_malloc(size); bzero(btr, size); // FREE ME 035 |
134 | bt_increment_used_memory(btr, size); //DEBUG_ALLOC_BTREE |
135 | return btr; |
136 | } |
137 | |
138 | static void release_dirty_stream(bt *btr, bt_n *x) { //DEBUG_BTF_BTN_DIRTY |
139 | assert(x->dirty > 0); |
140 | GET_BTN_SIZE(x->leaf) |
141 | bt_decrement_used_memory(btr, get_dssize(btr, x->dirty)); |
142 | void **dsp = GET_DS(x, nsize); cf_free(dsp); // FREED 108 |
143 | x->dirty = 0; |
144 | } |
145 | static void bt_free_btreenode(bt *btr, bt_n *x) { |
146 | GET_BTN_SIZES(x->leaf, x->dirty) bt_decrement_used_memory(btr, msize); |
147 | if (x->dirty > 0) release_dirty_stream(btr, x); |
148 | cf_free(x); // FREED 035 |
149 | } |
150 | static void bt_free_btree(bt *btr) { cf_free(btr); } |
151 | |
152 | // BT_CREATE BT_CREATE BT_CREATE BT_CREATE BT_CREATE BT_CREATE BT_CREATE |
153 | bt *bt_create(bt_cmp_t cmp, bts_t *s, char dirty) { |
154 | int n = BTREE_LONG_TYPE_DEGREE; |
155 | |
156 | if (C_IS_L(s->ktype) || C_IS_G(s->ktype)) { |
157 | n = BTREE_LONG_TYPE_DEGREE; |
158 | } |
159 | else if (C_IS_DG(s->ktype)) { |
160 | n = BTREE_STRING_TYPE_DEGREE; |
161 | } |
162 | |
163 | uchar t = (uchar)((int)(n + 1) / 2); |
164 | int kbyte = sizeof(bt_n) + n * s->ksize; |
165 | int nbyte = kbyte + (n + 1) * VOIDSIZE; |
166 | bt *btr = allocbtree(); |
167 | if (!btr) return NULL; |
168 | memcpy(&btr->s, s, sizeof(bts_t)); /* ktype, btype, ksize, bflag, num */ |
169 | btr->cmp = cmp; |
170 | btr->keyofst = sizeof(bt_n); |
171 | uint32 nodeofst = btr->keyofst + n * s->ksize; |
172 | btr->nodeofst = (ushort16)nodeofst; |
173 | btr->t = t; |
174 | int nbits = real_log2(n, sizeof(int) * 8) + 1; |
175 | nbits = 1 << (real_log2(nbits, sizeof(int) * 8) + 1); |
176 | btr->nbits = (uchar)nbits; |
177 | btr->nbyte = nbyte; |
178 | btr->kbyte = kbyte; |
179 | btr->dirty = dirty; |
180 | btr->root = allocbtreenode(btr, 1, dirty ? 0: -1); |
181 | if (!btr->root) return NULL; |
182 | btr->numnodes = 1; //printf("bt_create\n"); bt_dump_info(printf, btr); |
183 | return btr; |
184 | } |
185 | |
186 | // BINARY_SEARCH BINARY_SEARCH BINARY_SEARCH BINARY_SEARCH BINARY_SEARCH |
187 | /* This is the real log2 function. It is only called when we don't have |
188 | * a value in the table. -> which is basically never */ |
189 | static inline int real_log2(unsigned int a, int nbits) { |
190 | uint32 i = 0; |
191 | uint32 b = (nbits + 1) / 2; /* divide in half rounding up */ |
192 | while (b) { |
193 | i = (i << 1); |
194 | if (a >= (unsigned int)(1 << b)) { // select top half and mark this bit |
195 | a /= (1 << b); |
196 | i = i | 1; |
197 | } else { // select bottom half & dont set bit |
198 | a &= (1 << b) - 1; |
199 | } |
200 | b /= 2; |
201 | } |
202 | return i; |
203 | } |
204 | |
205 | #if 0 |
206 | |
207 | // TODO: global table is pain disabled for avoiding issue |
208 | // open it up later |
209 | /* Implement a lookup table for the log values. This will only allocate |
210 | * memory that we need. This is much faster than calling the log2 routine |
211 | * every time. Doing 1 million insert, searches, and deletes will generate |
212 | * ~58 million calls to log2. Using a lookup table IS NECESSARY! |
213 | -> memory usage of this is trivial, like less than 1KB */ |
214 | static inline int _log2(unsigned int a, int nbits) { |
215 | static char *table = NULL; |
216 | static uint32 alloced = 0; |
217 | uint32 i; |
218 | if (a >= alloced) { |
219 | table = cf_realloc(table, (a + 1) * sizeof *table); |
220 | for (i = alloced; i < a + 1; i++) table[i] = -1; |
221 | alloced = a + 1; |
222 | } |
223 | if (table[a] == -1) table[a] = real_log2(a, nbits); |
224 | return table[a]; |
225 | } |
226 | #endif |
227 | |
228 | static inline int _log2(unsigned int a, int nbits) { |
229 | return real_log2(a, nbits); |
230 | } |
231 | |
232 | static int findkindex(bt *btr, bt_n *x, bt_data_t k, int *r, btIterator *iter) { |
233 | if (x->n == 0) return -1; |
234 | int b, tr; |
235 | int *rr = r ? r : &tr ; /* rr: key is greater than current entry */ |
236 | int i = 0; |
237 | int a = x->n - 1; |
238 | while (a > 0) { |
239 | b = _log2(a, (int)btr->nbits); |
240 | int slot = (1 << b) + i; |
241 | bt_data_t k2 = KEYS(btr, x, slot); |
242 | if ((*rr = btr->cmp(k, k2)) < 0) { |
243 | a = (1 << b) - 1; |
244 | } else { |
245 | a -= (1 << b); |
246 | i |= (1 << b); |
247 | } |
248 | } |
249 | if ((*rr = btr->cmp(k, KEYS(btr, x, i))) < 0) i--; |
250 | if (iter) { iter->bln->in = iter->bln->ik = (i > 0) ? i : 0; } |
251 | return i; |
252 | } |
253 | |
254 | // KEY_SHUFFLING KEY_SHUFFLING KEY_SHUFFLING KEY_SHUFFLING KEY_SHUFFLING |
255 | // NOTE: KEYS are variable sizes: [4,8,12,16,20,24,32 bytes] |
256 | #define ISVOID(btr) (btr->s.ksize == VOIDSIZE) |
257 | |
258 | static inline void **AKEYS(bt *btr, bt_n *x, int i) { |
259 | int ofst = (i * btr->s.ksize); |
260 | char *v = (char *)x + btr->keyofst + ofst; //DEBUG_AKEYS |
261 | return (void **)v; |
262 | } |
263 | #define OKEYS(btr, x) ((void **)((char *)x + btr->keyofst)) |
264 | inline void *KEYS(bt *btr, bt_n *x, int i) { //DEBUG_KEYS |
265 | if ISVOID(btr) return OKEYS(btr, x)[i]; |
266 | else /* OTHER_BT */ return (void *) AKEYS(btr, x, i); |
267 | } |
268 | |
269 | // SCION SCION SCION SCION SCION SCION SCION SCION SCION SCION SCION SCION |
270 | static inline void incr_scion(bt_n *x, int n) { x->scion += n; } |
271 | static inline void decr_scion(bt_n *x, int n) { x->scion -= n; } |
272 | static inline void move_scion(bt *btr, bt_n *y, bt_n *z, int n) { |
273 | for (int i = 0; i < n; i++) { incr_scion(y, NODES(btr, z)[i]->scion); } |
274 | } |
275 | static inline int get_scion_range(bt *btr, bt_n *x, int beg, int end) { |
276 | if (x->dirty <= 0) return end - beg; |
277 | int scion = 0; |
278 | for (int i = beg; i < end; i++) scion += 1 + getDR(btr, x, i); |
279 | return scion; |
280 | } |
281 | |
282 | // DIRTY DIRTY DIRTY DIRTY DIRTY DIRTY DIRTY DIRTY DIRTY DIRTY DIRTY DIRTY |
283 | typedef struct btn_pos { |
284 | bt_n *x; int i; |
285 | } bp_t; |
286 | typedef struct two_bp_gens { |
287 | bp_t p; /* parent */ bp_t c; /* child */ |
288 | } tbg_t; |
289 | static inline void free_bp(void *v) { cf_free(v); } |
290 | |
291 | typedef struct ll_ai_bp_element_s { |
292 | cf_ll_element ele; |
293 | bp_t * value; |
294 | } ll_ai_bp_element; |
295 | |
296 | void |
297 | ll_ai_bp_destroy_fn(cf_ll_element * ele) |
298 | { |
299 | cf_free(((ll_ai_bp_element *)ele)->value); |
300 | cf_free((ll_ai_bp_element *)ele); |
301 | } |
302 | int |
303 | ll_ai_bp_reduce_fn(cf_ll_element *ele, void *udata) |
304 | { |
305 | return CF_LL_REDUCE_DELETE; |
306 | } |
307 | |
308 | //TODO inline |
309 | bt_n *addDStoBTN(bt *btr, bt_n *x, bt_n *p, int pi, char dirty) { |
310 | bt_n *y = allocbtreenode(btr, x->leaf, dirty); |
311 | GET_BTN_SIZE(x->leaf) memcpy(y, x, nsize); |
312 | y->dirty = dirty; btr->dirty = 1; |
313 | if (x == btr->root) btr->root = y; |
314 | else NODES(btr, p)[pi] = y; // update parent NODE bookkeeping |
315 | bt_free_btreenode(btr, x); //DEBUG_ADD_DS_TO_BTN |
316 | return y; |
317 | } |
318 | uint32 getDR(bt *btr, bt_n *x, int i) { |
319 | if (x->dirty <= 0) return 0; |
320 | GET_BTN_SIZE(x->leaf) |
321 | void *dsp = GET_DS(x, nsize);; |
322 | if (x->dirty == 1) { |
323 | uchar *ds = (uchar *)dsp; return (uint32)ds[i]; |
324 | } else if (x->dirty == 2) { |
325 | ushort16 *ds = (ushort16 *)dsp; return (uint32)ds[i]; |
326 | } else if (x->dirty == 3) { |
327 | uint32 *ds = (uint32 *)dsp; return ds[i]; |
328 | } else assert(!"getDR ERROR" ); |
329 | } |
330 | #define INCR_DS_SET_DR \ |
331 | { incr_ds(btr, x); __setDR(btr, x, i, dr); return; } |
332 | |
333 | static void __setDR(bt *btr, bt_n *x, int i, uint32 dr) { |
334 | uint32 odr; GET_BTN_SIZE(x->leaf) |
335 | void *dsp = GET_DS(x, nsize); |
336 | if (x->dirty == 1) { |
337 | uchar *ds = (uchar *)dsp; if (dr > UCHAR_MAX) INCR_DS_SET_DR |
338 | odr = ds[i]; ds[i] = dr; |
339 | } else if (x->dirty == 2) { |
340 | ushort16 *ds = (ushort16 *)dsp; if (dr > USHRT_MAX) INCR_DS_SET_DR |
341 | odr = ds[i]; ds[i] = dr; |
342 | } else if (x->dirty == 3) { |
343 | uint32 *ds = (uint32 *)dsp; |
344 | odr = ds[i]; ds[i] = dr; |
345 | } else assert(!"setDR ERROR" ); |
346 | (void) odr; // silence compiler warnings |
347 | } |
348 | static bt_n *setDR(bt *btr, bt_n *x, int i, uint32 dr, bt_n *p, int pi) { |
349 | if (!dr) return x; |
350 | if (x->dirty <= 0) x = addDStoBTN(btr, x, p, pi, 1); |
351 | __setDR(btr, x, i, dr); return x; |
352 | } |
353 | static bt_n *zeroDR(bt *btr, bt_n *x, int i, bt_n *p, int pi) { |
354 | (void)p; (void) pi; // compiler warnings - these will be used later |
355 | if (x->dirty <= 0) return x; |
356 | __setDR(btr, x, i, 0); return x; |
357 | } |
358 | static bt_n *incrDR(bt *btr, bt_n *x, int i, uint32 dr, bt_n *p, int pi) { |
359 | if (!dr) return x; |
360 | if (x->dirty <= 0) x = addDStoBTN(btr, x, p, pi, 1); |
361 | uint32 odr = getDR(btr, x, i); |
362 | odr += dr; |
363 | return setDR(btr, x, i, odr, p, pi); |
364 | } |
365 | static bt_n *overwriteDR(bt *btr, bt_n *x, int i, uint32 dr, bt_n *p, int pi) { |
366 | if (dr) return setDR (btr, x, i, dr, p, pi); |
367 | else return zeroDR(btr, x, i, p, pi); |
368 | } |
369 | |
370 | // DEL_CASE_DR DEL_CASE_DR DEL_CASE_DR DEL_CASE_DR DEL_CASE_DR DEL_CASE_DR |
371 | static bt_n *incrPrevDR(bt *btr, bt_n *x, int i, uint32 dr, |
372 | bt_n *p, int pi, cf_ll *plist) { |
373 | if (!dr) return x; //DEBUG_INCR_PREV_DR |
374 | if (i > 0) return incrDR(btr, x, i - 1, dr, p, pi); // prev sibling |
375 | else { |
376 | //TODO findminnode() is too inefficient -> needs to be a part of btr |
377 | if (x == findminnode(btr, btr->root)) { // MIN KEY |
378 | btr->dirty_left += dr; btr->dirty = 1; return x; |
379 | } |
380 | cf_ll_element * ele; |
381 | cf_ll_iterator * iter = cf_ll_getIterator(plist, true); |
382 | bt_n *rx = btr->root; int ri = 0; |
383 | |
384 | while ((ele = cf_ll_getNext(iter))) { |
385 | bp_t *bp = ((ll_ai_bp_element *)ele)->value; |
386 | if (bp->i) { rx = bp->x; ri = bp->i - 1; break; } |
387 | } |
388 | bt_n *prx = btr->root; int pri = 0; |
389 | if (rx != btr->root) { // get parent |
390 | ele = cf_ll_getNext(iter); |
391 | bp_t *bp = ((ll_ai_bp_element *)ele)->value; |
392 | prx = bp->x; pri = bp->i; |
393 | } |
394 | cf_ll_releaseIterator(iter); |
395 | //printf("rx: %p ri: %d prx: %p pri: %d\n", rx, ri, prx, pri); |
396 | incrDR(btr, rx, ri, dr, prx, pri); |
397 | return x; // x not modified (only rx) |
398 | } |
399 | } |
400 | static tbg_t get_prev_child_recurse(bt *btr, bt_n *x, int i) { |
401 | bt_n *xp = NODES(btr, x)[i]; //DEBUG_GET_C_REC_1 |
402 | if (!xp->leaf) return get_prev_child_recurse(btr, xp, xp->n); |
403 | tbg_t tbg; |
404 | tbg.p.x = x; tbg.p.i = i; |
405 | tbg.c.x = xp; tbg.c.i = xp->n - 1; //DEBUG_GET_C_REC_2 |
406 | return tbg; |
407 | } |
408 | static bt_n *incrCase2B(bt *btr, bt_n *x, int i, int dr) { //DEBUG_INCR_CASE2B |
409 | tbg_t tbg = get_prev_child_recurse(btr, x, i); //DEBUG_INCR_PREV |
410 | bt_n *nc = incrDR(btr, tbg.c.x, tbg.c.i, dr, tbg.p.x, tbg.p.i); |
411 | incr_scion(nc, dr); |
412 | return x; // x not modified (only tbg.c.x) |
413 | } |
414 | |
415 | // SET_BT_KEY SET_BT_KEY SET_BT_KEY SET_BT_KEY SET_BT_KEY SET_BT_KEY |
416 | static void setBTKeyRaw(bt *btr, bt_n *x, int i, void *src) { //PRIVATE |
417 | void **dest = AKEYS(btr, x, i); |
418 | if ISVOID(btr) *dest = src; |
419 | else memcpy(dest, src, btr->s.ksize); |
420 | //DEBUG_SET_KEY |
421 | } |
422 | static bt_n *setBTKey(bt *btr, bt_n *dx, int di, bt_n *sx, int si, |
423 | bool drt, bt_n *pd, int pdi, bt_n *ps, int psi) { |
424 | if (drt) { |
425 | uint32 dr = getDR (btr, sx, si); //DEBUG_SET_BTKEY |
426 | dx = overwriteDR(btr, dx, di, dr, pd, pdi); |
427 | sx = zeroDR (btr, sx, si, ps, psi); |
428 | } else sx = zeroDR (btr, sx, si, ps, psi); |
429 | setBTKeyRaw(btr, dx, di, KEYS(btr, sx, si)); return dx; |
430 | } |
431 | |
432 | static void mvXKeys(bt *btr, bt_n **dx, int di, |
433 | bt_n **sx, int si, uint32 num, uint32 ks, |
434 | bt_n *pd, int pdi, |
435 | bt_n *ps, int psi) { |
436 | if (!num) return; |
437 | bool x2x = (*dx == *sx); bool forward = (di >= si); |
438 | int i = forward ? (int)num - 1: 0; |
439 | int end = forward ? -1 : (int)num; |
440 | while (i != end) { // DS remove destDR from dx @i, add srcDR to sx @i |
441 | int sii = si + i; int dii = di + i; |
442 | uint32 drs = getDR(btr, *sx, sii), drd = getDR(btr, *dx, dii); |
443 | if (drs) { //DEBUG_MV_X_KEYS_1 |
444 | *dx = setDR (btr, *dx, dii, drs, pd, pdi); |
445 | if (x2x && *dx != *sx) *sx = *dx; |
446 | *sx = zeroDR(btr, *sx, sii, ps, psi); |
447 | if (x2x && *dx != *sx) *dx = *sx; |
448 | } else if (drd) { //DEBUG_MV_X_KEYS_2 |
449 | *dx = zeroDR(btr, *dx, dii, pd, pdi); |
450 | if (x2x && *dx != *sx) *sx = *dx; |
451 | } |
452 | bt_data_t *dest = AKEYS(btr, *dx, di); |
453 | bt_data_t *src = AKEYS(btr, *sx, si); |
454 | void *dk = (char *)dest + (i * ks); |
455 | void *sk = (char *)src + (i * ks); |
456 | memcpy(dk, sk, ks); |
457 | if (forward) i--; else i++; |
458 | } |
459 | } |
460 | static inline void mvXNodes(bt *btr, bt_n *x, int xofst, |
461 | bt_n *z, int zofst, int num) { |
462 | memmove(NODES(btr, x) + xofst, NODES(btr, z) + zofst, (num) * VOIDSIZE); |
463 | } |
464 | |
465 | //NOTE: trimBTN*() do not ever dirty btn's -- TODO they could UN-dirty |
466 | static bt_n *trimBTN(bt *btr, bt_n *x, bool drt, bt_n *p, int pi) { |
467 | //DEBUG_TRIM_BTN |
468 | if (drt) x = zeroDR(btr, x, x->n, p, pi); |
469 | x->n--; return x; |
470 | } |
471 | static bt_n *trimBTN_n(bt *btr, bt_n *x, int n, bool drt, bt_n *p, int pi) { |
472 | if (drt) { |
473 | for (int i = x->n; i >= (x->n - n); i--) x = zeroDR(btr, x, i, p, pi); |
474 | } |
475 | x->n -= n; return x; |
476 | } |
477 | |
478 | // INSERT INSERT INSERT INSERT INSERT INSERT INSERT INSERT INSERT INSERT |
479 | static bool btreesplitchild(bt *btr, bt_n *x, int i, bt_n *y, bt_n *p, int pi) { |
480 | ushort16 t = btr->t; //TODO dirtymath |
481 | bt_n *z = allocbtreenode(btr, y->leaf, y->dirty); if (!z) return 0; |
482 | z->leaf = y->leaf; /* duplicate leaf setting */ |
483 | for (int j = 0; j < t - 1; j++) { |
484 | z = setBTKey(btr, z, j, y, j + t, 1, p, pi, p, pi); |
485 | } |
486 | z->scion = get_scion_range(btr, z, 0, t - 1); decr_scion(y, z->scion); |
487 | z->n = t - 1; y = trimBTN_n(btr, y, t - 1, 0, p, pi); |
488 | if (!y->leaf) { // if it's an internal node, copy the ptr's too |
489 | for (int j = 0; j < t; j++) { |
490 | uint32_t scion = NODES(btr, y)[j + t]->scion; |
491 | decr_scion(y, scion); incr_scion(z, scion); |
492 | NODES(btr, z)[j] = NODES(btr, y)[j + t]; |
493 | } |
494 | } |
495 | for (int j = x->n; j > i; j--) { // move nodes in parent down one |
496 | NODES(btr, x)[j + 1] = NODES(btr, x)[j]; |
497 | } |
498 | NODES(btr, x)[i + 1] = z; // store new node |
499 | for (int j = x->n - 1; j >= i; j--) { // adjust the keys from previous move |
500 | x = setBTKey(btr, x, j + 1, x, j, 1, p, pi, p, pi); |
501 | } |
502 | decr_scion(y, 1 + getDR(btr, y, y->n - 1)); //NEXT LINE: store new key |
503 | x = setBTKey(btr, x, i, y, y->n - 1, 1, p, pi, p, pi); x->n++; |
504 | trimBTN(btr, y, 0, p, pi); |
505 | return 1; |
506 | } |
507 | |
508 | #define GETN(btr) ((2 * btr->t) - 1) |
509 | static bool bt_insertnonfull(bt *btr, bt_n *x, bt_data_t k, bt_n *p, int pi, |
510 | int dr) { |
511 | if (x->leaf) { /* we are a leaf, just add it in */ |
512 | int i = findkindex(btr, x, k, NULL, NULL); |
513 | if (i != x->n - 1) { |
514 | mvXKeys(btr, &x, i + 2, &x, i + 1, (x->n - i - 1), btr->s.ksize, |
515 | p, pi, p, pi); |
516 | } |
517 | x = overwriteDR(btr, x, i + 1, dr, p, pi); |
518 | setBTKeyRaw(btr, x, i + 1, k); x->n++; incr_scion(x, 1); |
519 | } else { /* not leaf */ |
520 | int i = findkindex(btr, x, k, NULL, NULL) + 1; |
521 | if (NODES(btr, x)[i]->n == GETN(btr)) { // if next node is full |
522 | if (!btreesplitchild(btr, x, i, NODES(btr, x)[i], x, i)) return 0; |
523 | if (btr->cmp(k, KEYS(btr, x, i)) > 0) i++; |
524 | } |
525 | bt_insertnonfull(btr, NODES(btr, x)[i], k, x, i, dr); incr_scion(x, 1); |
526 | } |
527 | return 1; |
528 | } |
529 | bool bt_insert(bt *btr, bt_data_t k, uint32 dr) { |
530 | bt_n *r = btr->root; |
531 | bt_n *p = r; |
532 | int pi = 0; |
533 | if (r->n == GETN(btr)) { /* NOTE: tree increase height */ |
534 | bt_n *s = allocbtreenode(btr, 0, r->dirty); if (!s) return 0; |
535 | btr->root = s; |
536 | s->leaf = 0; |
537 | s->n = 0; |
538 | incr_scion(s, r->scion); |
539 | NODES(btr, s)[0] = r; |
540 | if (!btreesplitchild(btr, s, 0, r, p, pi)) return 0; |
541 | p = r = s; |
542 | btr->numnodes++; |
543 | } |
544 | if (!bt_insertnonfull(btr, r, k, p, pi, dr)) return 0; |
545 | btr->numkeys++; |
546 | return 1; |
547 | } |
548 | |
549 | // DELETE DELETE DELETE DELETE DELETE DELETE DELETE DELETE DELETE DELETE |
550 | static bt_n *replaceKeyWithGhost(bt *btr, bt_n *x, int i, bt_data_t k, |
551 | uint32 dr, bt_n *p, int pi) { |
552 | //printf("replaceKeyWithGhost\n"); |
553 | ai_obj akey; convertStream2Key(k, &akey, btr); |
554 | crs_t crs; uint32 ssize; DECLARE_BT_KEY(&akey, x) |
555 | char *stream = createStream(btr, NULL, btkey, ksize, &ssize, &crs);//DEST027 |
556 | x = overwriteDR(btr, x, i, dr, p, pi); |
557 | setBTKeyRaw(btr, x, i, stream); |
558 | return x; |
559 | } |
560 | |
561 | #define ADD_BP(plist, p, pi) /* used to trace path to deleted key */ \ |
562 | if (plist) { \ |
563 | bp_t *bp = (bp_t *) cf_malloc(sizeof(bp_t)); /* FREE ME 109 */ \ |
564 | bp->x = p; bp->i = pi; \ |
565 | ll_ai_bp_element * node = cf_malloc(sizeof(ll_ai_bp_element)); \ |
566 | node->value = bp; \ |
567 | cf_ll_append(plist, (cf_ll_element *)node); \ |
568 | } |
569 | |
570 | #define CREATE_RETURN_DELETED_KEY(btr, kp, dr) \ |
571 | dwd_t dwd; bzero(&dwd, sizeof(dwd_t)); dwd.dr = dr; \ |
572 | if (BIG_BT(btr)) { memcpy(delbuf, kp, btr->s.ksize); } \ |
573 | dwd.k = BIG_BT(btr) ? delbuf : kp; |
574 | |
575 | /* NOTE: ksize > 8 bytes needs buffer for CASE 1 */ |
576 | #define MAX_KEY_SIZE (AS_DIGEST_KEY_SZ *2) |
577 | |
578 | #define DK_NONE 0 |
579 | #define DK_2A 1 |
580 | #define DK_2B 2 |
581 | |
582 | /* remove an existing key from the tree. KEY MUST EXIST |
583 | the s parameter: |
584 | 1.) for normal operation pass it as DK_NONE, |
585 | 2.) delete the max node, pass it as DK_2A, |
586 | 3.) delete the min node, pass it as DK_2B. |
587 | */ |
588 | typedef struct btds_t { |
589 | ulong leaf_del_hits; ulong leaf_del_noop; |
590 | ulong ndel; ulong del_calls; |
591 | ulong case1_del; |
592 | ulong case2A_del; ulong case2B_del; ulong case2C_del; |
593 | ulong case3_del; |
594 | ulong case3A1_del; ulong case3A2_del; ulong case3B1_del; ulong case3B2_del; |
595 | } btds_t; |
596 | |
597 | btds_t *btds = NULL; |
598 | |
599 | static dwd_t deletekey(bt *btr, bt_n *x, bt_data_t k, int s, bool drt, |
600 | bt_n *p, int pi, cf_ll *plist, void **c2Cp, |
601 | bool leafd, char delbuf[]) { btds->del_calls++; |
602 | bt_n *xp, *y, *z; bt_data_t kp; |
603 | int yn, zn, i = 0, r = -1, ks = btr->s.ksize; |
604 | if (s != DK_NONE) { /* min or max node deletion */ |
605 | if (x->leaf) r = 0; |
606 | else { |
607 | if (s == DK_2A) r = 1; // max node |
608 | else if (s == DK_2B) r = -1; // min node |
609 | } |
610 | if (s == DK_2A) i = x->n - 1; // max node/leaf |
611 | else if (s == DK_2B) i = -1; // min node/leaf |
612 | } else i = findkindex(btr, x, k, &r, NULL); //DEBUG_DEL_POST_S |
613 | |
614 | if (!drt) decr_scion(x, 1); // scion reduced by 1 every DELETE |
615 | |
616 | /* Case 1: |
617 | * If the key k is in node x and x is a leaf, delete the key k from x. */ |
618 | if (x->leaf) { btds->case1_del++; |
619 | bool rgst = 0; |
620 | if (s == DK_2B) i++; //DEBUG_DEL_CASE_1 |
621 | kp = KEYS (btr, x, i); |
622 | int dr = getDR(btr, x, i); |
623 | CREATE_RETURN_DELETED_KEY(btr, kp, dr) |
624 | if (drt) { // CASE: EVICT |
625 | if (s == DK_NONE) { //NOTE: only place DR grows |
626 | x = incrPrevDR(btr, x, i, (dr + 1), p, pi, plist); |
627 | } else decr_scion(x, 1 + dr); //NOTE: key FOR Case2A/B |
628 | } else if (s == DK_NONE) { // CASE: DELETE NOT CASE2A/B |
629 | if (dr) { |
630 | if (NBT(btr)) { x = incrPrevDR(btr, x, i, dr, p, pi, plist); } |
631 | else { rgst = 1; // DELETE DataBT KEY w/ DR -> REPLACE w/ GHOST |
632 | x = replaceKeyWithGhost(btr, x, i, kp, dr, p, pi); |
633 | } |
634 | } |
635 | } else if (dr) decr_scion(x, dr); // CASE: DELETE CASE2A/B |
636 | if (!rgst) { // IF NO REPLACE_W_GHOST -> Remove from BTREE |
637 | mvXKeys(btr, &x, i, &x, i + 1, (x->n - i - 1), ks, p, pi, p, pi); |
638 | x = trimBTN(btr, x, drt, p, pi); |
639 | } |
640 | return dwd; |
641 | } |
642 | dwd_t dwde; bzero(&dwde, sizeof(dwd_t)); |
643 | if (r == 0) { /* (r==0) means key found, but in node */ //DEBUG_DEL_CASE_2 |
644 | kp = KEYS(btr, x, i); |
645 | if (!drt) { // ON DELETE |
646 | int dr = getDR(btr, x, i); |
647 | if (dr) { // IF DR -> REPLACE_W_GHOST, no recursive delete |
648 | x = replaceKeyWithGhost(btr, x, i, kp, dr, p, pi); |
649 | CREATE_RETURN_DELETED_KEY(btr, kp, dr) |
650 | return dwd; |
651 | } |
652 | } |
653 | /* Case 2: |
654 | * if the key k is in the node x, and x is an internal node */ |
655 | if ((yn = NODES(btr, x)[i]->n) >= btr->t) { //DEBUG_DEL_CASE_2a |
656 | btds->case2A_del++; |
657 | if (leafd) return dwde; |
658 | /* Case 2a: |
659 | * if the node y that precedes k in node x has at least t keys, |
660 | * then find the previous sequential key (kp) of k. |
661 | * Recursively delete kp, and replace k with kp in x. */ |
662 | xp = NODES(btr, x)[i]; |
663 | ADD_BP(plist, x, i) |
664 | //printf("CASE2A recurse: key: "); printKey(btr, x, i); |
665 | dwd_t dwd = deletekey(btr, xp, NULL, DK_2A, drt, |
666 | x, i, plist, c2Cp, leafd, delbuf); |
667 | //DEBUG_SET_BTKEY_2A |
668 | if (drt) x = incrDR(btr, x, i, ++dwd.dr, p, pi); |
669 | else x = setDR (btr, x, i, dwd.dr, p, pi); |
670 | setBTKeyRaw(btr, x, i, dwd.k); |
671 | dwd.k = kp; // swap back in KPs original value |
672 | return dwd; |
673 | } |
674 | if ((zn = NODES(btr, x)[i + 1]->n) >= btr->t) { //DEBUG_DEL_CASE_2b |
675 | btds->case2B_del++; |
676 | if (leafd) return dwde; |
677 | /* Case 2b: |
678 | * if the node z that follows k in node x has at least t keys, |
679 | * then find the next sequential key (kp) of k. Recursively delete |
680 | * kp, and replace k with kp in x. */ |
681 | xp = NODES(btr, x)[i + 1]; |
682 | ADD_BP(plist, x, i + 1) |
683 | //printf("CASE2B recurse: key: "); printKey(btr, x, i); |
684 | dwd_t dwd = deletekey(btr, xp, NULL, DK_2B, drt, |
685 | x, i + 1, plist, c2Cp, leafd, delbuf); |
686 | //DEBUG_SET_BTKEY_2B |
687 | if (drt) { // prev key inherits DR+1 |
688 | x = incrCase2B (btr, x, i, (getDR(btr, x, i) + 1)); |
689 | } |
690 | x = overwriteDR(btr, x, i, dwd.dr, p, pi); |
691 | setBTKeyRaw(btr, x, i, dwd.k); |
692 | dwd.k = kp; // swap back in KPs original value |
693 | return dwd; |
694 | } |
695 | if (yn == btr->t - 1 && zn == btr->t - 1) { //DEBUG_DEL_CASE_2c |
696 | btds->case2C_del++; |
697 | if (leafd) return dwde; |
698 | /* Case 2c: |
699 | * if both y and z have only t - 1 keys, merge k |
700 | * then all of z into y, so that x loses both k and |
701 | * the pointer to z, and y now contains 2t - 1 keys. */ |
702 | if (!*c2Cp) *c2Cp = KEYS(btr, x, i); //used in remove_key() |
703 | y = NODES(btr, x)[i]; |
704 | z = NODES(btr, x)[i + 1]; |
705 | dwd_t dwd; dwd.k = k; dwd.dr = getDR(btr, x, i); |
706 | incr_scion(y, 1 + dwd.dr); //DEBUG_SET_BTKEY_2C |
707 | y = setDR (btr, y, y->n, dwd.dr, x, i); |
708 | setBTKeyRaw(btr, y, y->n, dwd.k); y->n++; |
709 | incr_scion(y, get_scion_range(btr, z, 0, z->n)); |
710 | mvXKeys(btr, &y, y->n, &z, 0, z->n, ks, x, i, x, i + 1); |
711 | if (!y->leaf) { |
712 | move_scion(btr, y, z, z->n + 1); |
713 | mvXNodes (btr, y, y->n, z, 0, (z->n + 1)); |
714 | } |
715 | y->n += z->n; |
716 | mvXKeys (btr, &x, i, &x, i + 1, (x->n - i - 1), ks, p, pi, p, pi); |
717 | mvXNodes(btr, x, i + 1, x, i + 2, (x->n - i - 1)); |
718 | x = trimBTN(btr, x, drt, p, pi); |
719 | bt_free_btreenode(btr, z); |
720 | ADD_BP(plist, x, i) |
721 | //printf("CASE2C key: "); printKey(btr, x, i); |
722 | return deletekey(btr, y, k, s, drt, x, i, plist, c2Cp, leafd, delbuf); |
723 | } |
724 | } |
725 | /* Case 3: |
726 | * if k is not present in internal node x, determine the root xp of |
727 | * the appropriate subtree that must contain k, if k is in the tree |
728 | * at all. If xp has only t - 1 keys, execute step 3a or 3b as |
729 | * necessary to guarantee that we descend to a node containing at |
730 | * least t keys. Finish by recursing on the appropriate node of x. */ |
731 | i++; |
732 | if ((xp = NODES(btr, x)[i])->n == btr->t - 1) { /* case 3a-c are !x->leaf */ |
733 | /* Case 3a: |
734 | * If xp has only (t-1) keys but has a sibling(y) with at least t keys, |
735 | give xp an extra key by moving a key from x down into xp, |
736 | moving a key from xp's immediate left or right sibling(y) up into x, |
737 | & moving the appropriate node from the sibling(y) into xp. */ |
738 | if (i > 0 && (y = NODES(btr, x)[i - 1])->n >= btr->t) { |
739 | btds->case3A1_del++; |
740 | //printf("CASE3A1 key: "); printKey(btr, x, i); |
741 | if (leafd) return dwde; |
742 | /* left sibling has t keys */ //DEBUG_DEL_CASE_3a1 |
743 | mvXKeys(btr, &xp, 1, &xp, 0, xp->n, ks, x, i, x, i); |
744 | if (!xp->leaf) mvXNodes(btr, xp, 1, xp, 0, (xp->n + 1)); |
745 | incr_scion(xp, 1 + getDR(btr, x, i - 1)); |
746 | xp = setBTKey(btr, xp, 0, x, i - 1, drt, x, i, p, pi); xp->n++; |
747 | decr_scion(y, 1 + getDR(btr, y, y->n - 1)); |
748 | x = setBTKey(btr, x, i - 1, y, y->n - 1, drt, p, pi, x, i - 1); |
749 | if (!xp->leaf) { |
750 | int dscion = NODES(btr, y)[y->n]->scion; |
751 | incr_scion(xp, dscion); decr_scion(y, dscion); |
752 | NODES(btr, xp)[0] = NODES(btr, y)[y->n]; |
753 | } |
754 | y = trimBTN(btr, y, drt, x, i - 1); |
755 | } else if (i < x->n && (y = NODES(btr, x)[i + 1])->n >= btr->t) { |
756 | btds->case3A2_del++; |
757 | //printf("CASE3A2 key: "); printKey(btr, x, i); |
758 | if (leafd) return dwde; |
759 | /* right sibling has t keys */ //DEBUG_DEL_CASE_3a2 |
760 | incr_scion(xp, 1 + getDR(btr, x, i)); |
761 | xp = setBTKey(btr, xp, xp->n++, x, i, drt, x, i, p, pi); |
762 | decr_scion(y, 1 + getDR(btr, y, 0)); |
763 | x = setBTKey(btr, x, i, y, 0, drt, p, pi, x, i + 1); |
764 | if (!xp->leaf) { |
765 | int dscion = NODES(btr, y)[0]->scion; |
766 | incr_scion(xp, dscion); decr_scion(y, dscion); |
767 | NODES(btr, xp)[xp->n] = NODES(btr, y)[0]; |
768 | } |
769 | mvXKeys(btr, &y, 0, &y, 1, y->n - 1, ks, x, i + 1, x, i + 1); |
770 | if (!y->leaf) mvXNodes(btr, y, 0, y, 1, y->n); |
771 | y = trimBTN(btr, y, drt, x, i + 1); |
772 | } |
773 | /* Case 3b: |
774 | * If xp and all of xp's siblings have t - 1 keys, merge xp with |
775 | one sibling, which involves moving a key from x down into the |
776 | new merged node to become the median key for that node. */ |
777 | else if (i > 0 && (y = NODES(btr, x)[i - 1])->n == btr->t - 1) { |
778 | btds->case3B1_del++; |
779 | //printf("CASE3B1 key: "); printKey(btr, x, i); |
780 | if (leafd) return dwde; |
781 | /* merge i with left sibling */ //DEBUG_DEL_CASE_3b1 |
782 | incr_scion(y, 1 + getDR(btr, x, i - 1)); |
783 | y = setBTKey(btr, y, y->n++, x, i - 1, drt, x, i - 1, p, pi); |
784 | incr_scion(y, get_scion_range(btr, xp, 0, xp->n)); |
785 | mvXKeys(btr, &y, y->n, &xp, 0, xp->n, ks, x, i - 1, x, i); |
786 | if (!xp->leaf) { |
787 | move_scion(btr, y, xp, xp->n + 1); |
788 | mvXNodes (btr, y, y->n, xp, 0, (xp->n + 1)); |
789 | } |
790 | y->n += xp->n; |
791 | mvXKeys (btr, &x, i - 1, &x, i, (x->n - i), ks, p, pi, p, pi); |
792 | mvXNodes(btr, x, i, x, i + 1, (x->n - i)); |
793 | x = trimBTN(btr, x, drt, p, pi); |
794 | bt_free_btreenode(btr, xp); |
795 | xp = y; i--; // i-- for parent-arg in recursion (below) |
796 | } else if (i < x->n && (y = NODES(btr, x)[i + 1])->n == btr->t - 1) { |
797 | btds->case3B2_del++; |
798 | //printf("CASE3B2 key: "); printKey(btr, x, i); |
799 | if (leafd) return dwde; |
800 | /* merge i with right sibling */ //DEBUG_DEL_CASE_3b2 |
801 | incr_scion(xp, 1 + getDR(btr, x, i)); |
802 | xp = setBTKey(btr, xp, xp->n++, x, i, drt, x, i, p, pi); |
803 | incr_scion(xp, get_scion_range(btr, y, 0, y->n)); |
804 | mvXKeys(btr, &xp, xp->n, &y, 0, y->n, ks, x, i, x, i + 1); |
805 | if (!xp->leaf) { |
806 | move_scion(btr, xp, y, y->n + 1); |
807 | mvXNodes (btr, xp, xp->n, y, 0, (y->n + 1)); |
808 | } |
809 | xp->n += y->n; |
810 | mvXKeys (btr, &x, i, &x, i + 1, (x->n - i - 1), ks, p, pi, p, pi); |
811 | mvXNodes(btr, x, i + 1, x, i + 2, (x->n - i - 1)); |
812 | x = trimBTN(btr, x, drt, p, pi); |
813 | bt_free_btreenode(btr, y); |
814 | } |
815 | } //printf("RECURSE CASE 3\n"); |
816 | btds->case3_del++; |
817 | ADD_BP(plist, x, i) //DEBUG_DEL_POST_CASE_3 |
818 | dwd_t dwd = deletekey(btr, xp, k, s, drt, x, i, plist, c2Cp, leafd, delbuf); |
819 | // CASE2A/B pull keys up from depths, scion must be decremented |
820 | if (s != DK_NONE) { |
821 | if (drt) decr_scion(x, 1 + dwd.dr); |
822 | else decr_scion(x, dwd.dr); // DELETE already decr_scion()ed 1 |
823 | } |
824 | return dwd; |
825 | } |
826 | |
827 | #ifdef DEBUG_DEL_CASE_STATS |
828 | static void print_del_case_stats(bool leafd, dwd_t dwd, bt *btr) { |
829 | if (leafd) { |
830 | if (!dwd.k) btds->leaf_del_noop++; |
831 | else btds->leaf_del_hits++; |
832 | printf("deletes: %lu noop: %lu ratio: %f numkeys: %d\n" , |
833 | btds->leaf_del_hits, btds->leaf_del_noop, |
834 | (btds->leaf_del_noop && btds->leaf_del_hits) ? |
835 | (double)((double)btds->leaf_del_hits / |
836 | (double)btds->leaf_del_noop) : 0, |
837 | btr->numkeys); |
838 | } else |
839 | printf("ndel: %lu ncalls: %lu C1: %lu(%.2f) C2A: %lu(%.2f) " |
840 | "C2B: %lu(%.2f) C2C: %lu(%.2f) C3: %lu(%.2f) " |
841 | "C3A1: %lu(%.2f) C3A2: %lu(%.2f) C3B1: %lu(%.2f) " |
842 | "C3B2: %lu(%.2f)\n" , |
843 | btds->ndel, btds->del_calls, |
844 | btds->case1_del, |
845 | (double)((double)btds->case1_del / (double)btds->del_calls), |
846 | btds->case2A_del, |
847 | (double)((double)btds->case2A_del / (double)btds->del_calls), |
848 | btds->case2B_del, |
849 | (double)((double)btds->case2B_del / (double)btds->del_calls), |
850 | btds->case2C_del, |
851 | (double)((double)btds->case2C_del / (double)btds->del_calls), |
852 | btds->case3_del, |
853 | (double)((double)btds->case3_del / (double)btds->del_calls), |
854 | btds->case3A1_del, |
855 | (double)((double)btds->case3A1_del / (double)btds->del_calls), |
856 | btds->case3A2_del, |
857 | (double)((double)btds->case3A2_del / (double)btds->del_calls), |
858 | btds->case3B1_del, |
859 | (double)((double)btds->case3B1_del / (double)btds->del_calls), |
860 | btds->case3B2_del, |
861 | (double)((double)btds->case3B2_del / (double)btds->del_calls)); |
862 | fflush(NULL); |
863 | } |
864 | #endif |
865 | |
866 | static dwd_t remove_key(bt *btr, bt_data_t k, bool drt, bool leafd) { |
867 | if (!btds) { btds = cf_malloc(sizeof(btds_t)); bzero(btds, sizeof(btds_t)); } |
868 | btds->ndel++; |
869 | if (!btr->root) { dwd_t dwde; bzero(&dwde, sizeof(dwd_t)); return dwde; } |
870 | void *c2Cp = NULL; /* NOTE: c2Cp gets lost in recursion */ //DEBUG_DEL_START |
871 | bt_n *p = btr->root; int pi = 0; |
872 | cf_ll plist_tmp; |
873 | cf_ll * plist = &plist_tmp; // NOTE: plist stores ancestor line during recursive delete |
874 | if (drt) { |
875 | cf_ll_init(plist, ll_ai_bp_destroy_fn, false); |
876 | ADD_BP(plist, p, pi);//FR110 |
877 | } else plist = NULL; |
878 | char delbuf[MAX_KEY_SIZE]; // NOTE: ksize > 8B needs buffer for CASE 1 |
879 | dwd_t dwd = deletekey(btr, btr->root, k, DK_NONE, drt, |
880 | p, pi, plist, &c2Cp, leafd, delbuf); |
881 | #ifdef DEBUG_DEL_CASE_STATS |
882 | print_del_case_stats(leafd, dwd, btr); |
883 | #endif |
884 | if (!dwd.k) return dwd; // leafd NO-OP |
885 | btr->numkeys--; //DEBUG_DEL_END |
886 | /* remove empty non-leaf node from root, */ |
887 | if (!btr->root->n && !btr->root->leaf) { /* NOTE: tree decrease height */ |
888 | btr->numnodes--; |
889 | bt_n *x = btr->root; |
890 | btr->root = NODES(btr, x)[0]; |
891 | bt_free_btreenode(btr, x); |
892 | } |
893 | if (c2Cp) dwd.k = c2Cp; |
894 | if (plist) { |
895 | cf_ll_reduce(plist, true, ll_ai_bp_reduce_fn, NULL); |
896 | plist = NULL; |
897 | }; // FREED 110 |
898 | return dwd; |
899 | } |
900 | dwd_t bt_delete(bt *btr, bt_data_t k, bool leafd) { |
901 | return remove_key(btr, k, 0, leafd); |
902 | } |
903 | |
904 | // ACCESSORS ACCESSORS ACCESSORS ACCESSORS ACCESSORS ACCESSORS ACCESSORS |
905 | static inline bool key_covers_miss(bt *btr, bt_n *x, int i, ai_obj *akey) { |
906 | if (!(C_IS_NUM(btr->s.ktype))) return 0; |
907 | if (i < 0) i = 0; |
908 | ulong mkey = getNumKey(btr, x, i); |
909 | ulong dr = (ulong)getDR(btr, x, i); |
910 | if (mkey && dr) { |
911 | ulong qkey = akey->l; |
912 | ulong span = mkey + dr; |
913 | //DEBUG_CURRKEY_MISS |
914 | if (qkey >= mkey && qkey <= span) return 1; |
915 | } |
916 | return 0; |
917 | } |
918 | #define SET_DWM_XIP { dwm.x = x; dwm.i = i; dwm.p = p; dwm.pi = pi; } |
919 | dwm_t findnodekey(bt *btr, bt_n *x, bt_data_t k, ai_obj *akey) { |
920 | int r = -1, i = 0; |
921 | bt_n *p = btr->root; int pi = 0; |
922 | dwm_t dwm; bzero(&dwm, sizeof(dwm_t)); SET_DWM_XIP |
923 | while (x) { |
924 | i = findkindex(btr, x, k, &r, NULL); //DEBUG_FIND_NODE_KEY |
925 | if (i >= 0 && !r) { SET_DWM_XIP dwm.k = KEYS(btr, x, i); return dwm; } |
926 | if (key_covers_miss(btr, x, i, akey)) { SET_DWM_XIP dwm.miss = 1; } |
927 | if (x->leaf) { dwm.k = NULL; return dwm; } |
928 | p = x; pi = i + 1; x = NODES(btr, x)[i + 1]; |
929 | } |
930 | return dwm; |
931 | } |
932 | bt_data_t bt_find(bt *btr, bt_data_t k, ai_obj *akey) { //Indexes still use this |
933 | dwm_t dwm = findnodekey(btr, btr->root, k, akey); |
934 | return dwm.k; |
935 | } |
936 | |
937 | static bool check_min_miss(bt *btr, ai_obj *alow) { |
938 | if (!btr->dirty_left) return 0; |
939 | ai_obj amin; convertStream2Key(bt_min(btr), &amin, btr); |
940 | return ai_objEQ(alow, &amin); |
941 | } |
942 | int bt_init_iterator(bt *btr, bt_data_t k, btIterator *iter, ai_obj *alow) { |
943 | if (!btr->root) return II_FAIL; |
944 | int r = -1; |
945 | bool lmiss = check_min_miss(btr, alow); |
946 | bool miss = 0; |
947 | uchar only_right = 1; |
948 | bt_n *x = btr->root; |
949 | while (x) { |
950 | int i = findkindex(btr, x, k, &r, iter); |
951 | if (i >= 0 && r == 0) return lmiss ? II_L_MISS : II_OK; |
952 | if (key_covers_miss(btr, x, i, alow)) miss = 1; //DEBUG_BT_II |
953 | if (miss) return II_MISS; |
954 | if (r < 0 || i != (x->n - 1)) only_right = 0; |
955 | if (x->leaf) { |
956 | if (i != (x->n - 1)) only_right = 0; |
957 | return only_right ? II_ONLY_RIGHT : II_LEAF_EXIT; |
958 | } |
959 | iter->bln->child = get_new_iter_child(iter); |
960 | x = NODES(btr, x)[i + 1]; |
961 | to_child(iter, x); |
962 | } |
963 | return II_FAIL; |
964 | } |
965 | |
966 | bool bt_exist(bt *btr, bt_data_t k, ai_obj *akey) { |
967 | int r = -1; |
968 | bt_n *x = btr->root; |
969 | while (x) { |
970 | int i = findkindex(btr, x, k, &r, NULL); |
971 | if (i >= 0 && r == 0) return 1; |
972 | if (key_covers_miss(btr, x, i, akey)) return 1; |
973 | if (x->leaf) return 0; |
974 | x = NODES(btr, x)[i + 1]; |
975 | } |
976 | return 0; |
977 | } |
978 | |
979 | static bt_data_t findminkey(bt *btr, bt_n *x) { |
980 | if (x->leaf) return KEYS(btr, x, 0); |
981 | else return findminkey(btr, NODES(btr, x)[0]); |
982 | } |
983 | bt_n *findminnode(bt *btr, bt_n *x) { |
984 | if (x->leaf) return x; |
985 | else return findminnode(btr, NODES(btr, x)[0]); |
986 | } |
987 | static bt_data_t findmaxkey(bt *btr, bt_n *x) { |
988 | if (x->leaf) return KEYS(btr, x, x->n - 1); |
989 | else return findmaxkey(btr, NODES(btr, x)[x->n]); |
990 | } |
991 | bt_data_t bt_min(bt *btr) { |
992 | if (!btr->root || !btr->numkeys) return NULL; |
993 | else return findminkey(btr, btr->root); |
994 | } |
995 | bt_data_t bt_max(bt *btr) { |
996 | if (!btr->root || !btr->numkeys) return NULL; |
997 | else return findmaxkey(btr, btr->root); |
998 | } |
999 | |
1000 | // DESTRUCTOR DESTRUCTOR DESTRUCTOR DESTRUCTOR DESTRUCTOR DESTRUCTOR |
1001 | static void destroy_bt_node(bt *btr, bt_n *x) { |
1002 | if (!x->leaf) { |
1003 | for (int i = 0; i <= x->n; i++) { |
1004 | destroy_bt_node(btr, NODES(btr, x)[i]); |
1005 | } |
1006 | } |
1007 | bt_free_btreenode(btr, x); /* memory management in btr */ |
1008 | } |
1009 | void bt_destroy(bt *btr) { |
1010 | if (btr->root) { |
1011 | if (btr->numkeys) destroy_bt_node (btr, btr->root); |
1012 | else bt_free_btreenode(btr, btr->root); |
1013 | btr->root = NULL; |
1014 | } |
1015 | bt_free_btree(btr); |
1016 | } |
1017 | |