source: mainline/kernel/generic/src/adt/btree.c@ e2ea4ab1

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since e2ea4ab1 was e3ee9b9, checked in by Martin Decky <martin@…>, 15 years ago

remove forward static function declarations and reorder functions
(if not needed for recursion, forward static function declaration only increases source code size and makes it much harder to instantly tell whether a function is actually static or not)

coding style changes
(no change in functionality)

  • Property mode set to 100644
File size: 26.4 KB
Line 
1/*
2 * Copyright (c) 2006 Jakub Jermar
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 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29/** @addtogroup genericadt
30 * @{
31 */
32
33/**
34 * @file
35 * @brief B+tree implementation.
36 *
37 * This file implements B+tree type and operations.
38 *
39 * The B+tree has the following properties:
40 * @li it is a ballanced 3-4-5 tree (i.e. BTREE_M = 5)
41 * @li values (i.e. pointers to values) are stored only in leaves
42 * @li leaves are linked in a list
43 *
44 * Be carefull when using these trees. They need to allocate
45 * and deallocate memory for their index nodes and as such
46 * can sleep.
47 */
48
49#include <adt/btree.h>
50#include <adt/list.h>
51#include <mm/slab.h>
52#include <debug.h>
53#include <panic.h>
54#include <print.h>
55
56static slab_cache_t *btree_node_slab;
57
58#define ROOT_NODE(n) (!(n)->parent)
59#define INDEX_NODE(n) ((n)->subtree[0] != NULL)
60#define LEAF_NODE(n) ((n)->subtree[0] == NULL)
61
62#define FILL_FACTOR ((BTREE_M - 1) / 2)
63
64#define MEDIAN_LOW_INDEX(n) (((n)->keys-1) / 2)
65#define MEDIAN_HIGH_INDEX(n) ((n)->keys / 2)
66#define MEDIAN_LOW(n) ((n)->key[MEDIAN_LOW_INDEX((n))]);
67#define MEDIAN_HIGH(n) ((n)->key[MEDIAN_HIGH_INDEX((n))]);
68
69/** Initialize B-trees. */
70void btree_init(void)
71{
72 btree_node_slab = slab_cache_create("btree_node_slab",
73 sizeof(btree_node_t), 0, NULL, NULL, SLAB_CACHE_MAGDEFERRED);
74}
75
76/** Initialize B-tree node.
77 *
78 * @param node B-tree node.
79 *
80 */
81static void node_initialize(btree_node_t *node)
82{
83 unsigned int i;
84
85 node->keys = 0;
86
87 /* Clean also space for the extra key. */
88 for (i = 0; i < BTREE_MAX_KEYS + 1; i++) {
89 node->key[i] = 0;
90 node->value[i] = NULL;
91 node->subtree[i] = NULL;
92 }
93
94 node->subtree[i] = NULL;
95 node->parent = NULL;
96
97 link_initialize(&node->leaf_link);
98 link_initialize(&node->bfs_link);
99 node->depth = 0;
100}
101
102/** Create empty B-tree.
103 *
104 * @param t B-tree.
105 *
106 */
107void btree_create(btree_t *t)
108{
109 list_initialize(&t->leaf_head);
110 t->root = (btree_node_t *) slab_alloc(btree_node_slab, 0);
111 node_initialize(t->root);
112 list_append(&t->root->leaf_link, &t->leaf_head);
113}
114
115/** Destroy subtree rooted in a node.
116 *
117 * @param root Root of the subtree.
118 *
119 */
120static void btree_destroy_subtree(btree_node_t *root)
121{
122 size_t i;
123
124 if (root->keys) {
125 for (i = 0; i < root->keys + 1; i++) {
126 if (root->subtree[i])
127 btree_destroy_subtree(root->subtree[i]);
128 }
129 }
130
131 slab_free(btree_node_slab, root);
132}
133
134/** Destroy empty B-tree. */
135void btree_destroy(btree_t *t)
136{
137 btree_destroy_subtree(t->root);
138}
139
140/** Insert key-value-rsubtree triplet into B-tree node.
141 *
142 * It is actually possible to have more keys than BTREE_MAX_KEYS.
143 * This feature is used during splitting the node when the
144 * number of keys is BTREE_MAX_KEYS + 1. Insert by left rotation
145 * also makes use of this feature.
146 *
147 * @param node B-tree node into wich the new key is to be inserted.
148 * @param key The key to be inserted.
149 * @param value Pointer to value to be inserted.
150 * @param rsubtree Pointer to the right subtree.
151 *
152 */
153static void node_insert_key_and_rsubtree(btree_node_t *node, btree_key_t key,
154 void *value, btree_node_t *rsubtree)
155{
156 size_t i;
157
158 for (i = 0; i < node->keys; i++) {
159 if (key < node->key[i]) {
160 size_t j;
161
162 for (j = node->keys; j > i; j--) {
163 node->key[j] = node->key[j - 1];
164 node->value[j] = node->value[j - 1];
165 node->subtree[j + 1] = node->subtree[j];
166 }
167
168 break;
169 }
170 }
171
172 node->key[i] = key;
173 node->value[i] = value;
174 node->subtree[i + 1] = rsubtree;
175 node->keys++;
176}
177
178/** Find key by its left or right subtree.
179 *
180 * @param node B-tree node.
181 * @param subtree Left or right subtree of a key found in node.
182 * @param right If true, subtree is a right subtree. If false,
183 * subtree is a left subtree.
184 *
185 * @return Index of the key associated with the subtree.
186 *
187 */
188static size_t find_key_by_subtree(btree_node_t *node, btree_node_t *subtree,
189 bool right)
190{
191 size_t i;
192
193 for (i = 0; i < node->keys + 1; i++) {
194 if (subtree == node->subtree[i])
195 return i - (int) (right != false);
196 }
197
198 panic("Node %p does not contain subtree %p.", node, subtree);
199}
200
201/** Remove key and its left subtree pointer from B-tree node.
202 *
203 * Remove the key and eliminate gaps in node->key array.
204 * Note that the value pointer and the left subtree pointer
205 * is removed from the node as well.
206 *
207 * @param node B-tree node.
208 * @param key Key to be removed.
209 *
210 */
211static void node_remove_key_and_lsubtree(btree_node_t *node, btree_key_t key)
212{
213 size_t i;
214 size_t j;
215
216 for (i = 0; i < node->keys; i++) {
217 if (key == node->key[i]) {
218 for (j = i + 1; j < node->keys; j++) {
219 node->key[j - 1] = node->key[j];
220 node->value[j - 1] = node->value[j];
221 node->subtree[j - 1] = node->subtree[j];
222 }
223
224 node->subtree[j - 1] = node->subtree[j];
225 node->keys--;
226
227 return;
228 }
229 }
230
231 panic("Node %p does not contain key %" PRIu64 ".", node, key);
232}
233
234/** Remove key and its right subtree pointer from B-tree node.
235 *
236 * Remove the key and eliminate gaps in node->key array.
237 * Note that the value pointer and the right subtree pointer
238 * is removed from the node as well.
239 *
240 * @param node B-tree node.
241 * @param key Key to be removed.
242 *
243 */
244static void node_remove_key_and_rsubtree(btree_node_t *node, btree_key_t key)
245{
246 size_t i, j;
247
248 for (i = 0; i < node->keys; i++) {
249 if (key == node->key[i]) {
250 for (j = i + 1; j < node->keys; j++) {
251 node->key[j - 1] = node->key[j];
252 node->value[j - 1] = node->value[j];
253 node->subtree[j] = node->subtree[j + 1];
254 }
255
256 node->keys--;
257 return;
258 }
259 }
260
261 panic("Node %p does not contain key %" PRIu64 ".", node, key);
262}
263
264/** Insert key-value-lsubtree triplet into B-tree node.
265 *
266 * It is actually possible to have more keys than BTREE_MAX_KEYS.
267 * This feature is used during insert by right rotation.
268 *
269 * @param node B-tree node into wich the new key is to be inserted.
270 * @param key The key to be inserted.
271 * @param value Pointer to value to be inserted.
272 * @param lsubtree Pointer to the left subtree.
273 *
274 */
275static void node_insert_key_and_lsubtree(btree_node_t *node, btree_key_t key,
276 void *value, btree_node_t *lsubtree)
277{
278 size_t i;
279
280 for (i = 0; i < node->keys; i++) {
281 if (key < node->key[i]) {
282 size_t j;
283
284 for (j = node->keys; j > i; j--) {
285 node->key[j] = node->key[j - 1];
286 node->value[j] = node->value[j - 1];
287 node->subtree[j + 1] = node->subtree[j];
288 }
289
290 node->subtree[j + 1] = node->subtree[j];
291 break;
292 }
293 }
294
295 node->key[i] = key;
296 node->value[i] = value;
297 node->subtree[i] = lsubtree;
298
299 node->keys++;
300}
301
302/** Rotate one key-value-rsubtree triplet from the left sibling to the right sibling.
303 *
304 * The biggest key and its value and right subtree is rotated
305 * from the left node to the right. If the node is an index node,
306 * than the parent node key belonging to the left node takes part
307 * in the rotation.
308 *
309 * @param lnode Left sibling.
310 * @param rnode Right sibling.
311 * @param idx Index of the parent node key that is taking part
312 * in the rotation.
313 *
314 */
315static void rotate_from_left(btree_node_t *lnode, btree_node_t *rnode, size_t idx)
316{
317 btree_key_t key = lnode->key[lnode->keys - 1];
318
319 if (LEAF_NODE(lnode)) {
320 void *value = lnode->value[lnode->keys - 1];
321
322 node_remove_key_and_rsubtree(lnode, key);
323 node_insert_key_and_lsubtree(rnode, key, value, NULL);
324 lnode->parent->key[idx] = key;
325 } else {
326 btree_node_t *rsubtree = lnode->subtree[lnode->keys];
327
328 node_remove_key_and_rsubtree(lnode, key);
329 node_insert_key_and_lsubtree(rnode, lnode->parent->key[idx], NULL, rsubtree);
330 lnode->parent->key[idx] = key;
331
332 /* Fix parent link of the reconnected right subtree. */
333 rsubtree->parent = rnode;
334 }
335}
336
337/** Rotate one key-value-lsubtree triplet from the right sibling to the left sibling.
338 *
339 * The smallest key and its value and left subtree is rotated
340 * from the right node to the left. If the node is an index node,
341 * than the parent node key belonging to the right node takes part
342 * in the rotation.
343 *
344 * @param lnode Left sibling.
345 * @param rnode Right sibling.
346 * @param idx Index of the parent node key that is taking part
347 * in the rotation.
348 *
349 */
350static void rotate_from_right(btree_node_t *lnode, btree_node_t *rnode, size_t idx)
351{
352 btree_key_t key = rnode->key[0];
353
354 if (LEAF_NODE(rnode)) {
355 void *value = rnode->value[0];
356
357 node_remove_key_and_lsubtree(rnode, key);
358 node_insert_key_and_rsubtree(lnode, key, value, NULL);
359 rnode->parent->key[idx] = rnode->key[0];
360 } else {
361 btree_node_t *lsubtree = rnode->subtree[0];
362
363 node_remove_key_and_lsubtree(rnode, key);
364 node_insert_key_and_rsubtree(lnode, rnode->parent->key[idx], NULL, lsubtree);
365 rnode->parent->key[idx] = key;
366
367 /* Fix parent link of the reconnected left subtree. */
368 lsubtree->parent = lnode;
369 }
370}
371
372/** Insert key-value-rsubtree triplet and rotate the node to the left, if this operation can be done.
373 *
374 * Left sibling of the node (if it exists) is checked for free space.
375 * If there is free space, the key is inserted and the smallest key of
376 * the node is moved there. The index node which is the parent of both
377 * nodes is fixed.
378 *
379 * @param node B-tree node.
380 * @param inskey Key to be inserted.
381 * @param insvalue Value to be inserted.
382 * @param rsubtree Right subtree of inskey.
383 *
384 * @return True if the rotation was performed, false otherwise.
385 *
386 */
387static bool try_insert_by_rotation_to_left(btree_node_t *node,
388 btree_key_t inskey, void *insvalue, btree_node_t *rsubtree)
389{
390 size_t idx;
391 btree_node_t *lnode;
392
393 /*
394 * If this is root node, the rotation can not be done.
395 */
396 if (ROOT_NODE(node))
397 return false;
398
399 idx = find_key_by_subtree(node->parent, node, true);
400 if ((int) idx == -1) {
401 /*
402 * If this node is the leftmost subtree of its parent,
403 * the rotation can not be done.
404 */
405 return false;
406 }
407
408 lnode = node->parent->subtree[idx];
409 if (lnode->keys < BTREE_MAX_KEYS) {
410 /*
411 * The rotaion can be done. The left sibling has free space.
412 */
413 node_insert_key_and_rsubtree(node, inskey, insvalue, rsubtree);
414 rotate_from_right(lnode, node, idx);
415 return true;
416 }
417
418 return false;
419}
420
421/** Insert key-value-rsubtree triplet and rotate the node to the right, if this operation can be done.
422 *
423 * Right sibling of the node (if it exists) is checked for free space.
424 * If there is free space, the key is inserted and the biggest key of
425 * the node is moved there. The index node which is the parent of both
426 * nodes is fixed.
427 *
428 * @param node B-tree node.
429 * @param inskey Key to be inserted.
430 * @param insvalue Value to be inserted.
431 * @param rsubtree Right subtree of inskey.
432 *
433 * @return True if the rotation was performed, false otherwise.
434 *
435 */
436static bool try_insert_by_rotation_to_right(btree_node_t *node,
437 btree_key_t inskey, void *insvalue, btree_node_t *rsubtree)
438{
439 size_t idx;
440 btree_node_t *rnode;
441
442 /*
443 * If this is root node, the rotation can not be done.
444 */
445 if (ROOT_NODE(node))
446 return false;
447
448 idx = find_key_by_subtree(node->parent, node, false);
449 if (idx == node->parent->keys) {
450 /*
451 * If this node is the rightmost subtree of its parent,
452 * the rotation can not be done.
453 */
454 return false;
455 }
456
457 rnode = node->parent->subtree[idx + 1];
458 if (rnode->keys < BTREE_MAX_KEYS) {
459 /*
460 * The rotaion can be done. The right sibling has free space.
461 */
462 node_insert_key_and_rsubtree(node, inskey, insvalue, rsubtree);
463 rotate_from_left(node, rnode, idx);
464 return true;
465 }
466
467 return false;
468}
469
470/** Split full B-tree node and insert new key-value-right-subtree triplet.
471 *
472 * This function will split a node and return a pointer to a newly created
473 * node containing keys greater than or equal to the greater of medians
474 * (or median) of the old keys and the newly added key. It will also write
475 * the median key to a memory address supplied by the caller.
476 *
477 * If the node being split is an index node, the median will not be
478 * included in the new node. If the node is a leaf node,
479 * the median will be copied there.
480 *
481 * @param node B-tree node wich is going to be split.
482 * @param key The key to be inserted.
483 * @param value Pointer to the value to be inserted.
484 * @param rsubtree Pointer to the right subtree of the key being added.
485 * @param median Address in memory, where the median key will be stored.
486 *
487 * @return Newly created right sibling of node.
488 *
489 */
490static btree_node_t *node_split(btree_node_t *node, btree_key_t key,
491 void *value, btree_node_t *rsubtree, btree_key_t *median)
492{
493 btree_node_t *rnode;
494 size_t i;
495 size_t j;
496
497 ASSERT(median);
498 ASSERT(node->keys == BTREE_MAX_KEYS);
499
500 /*
501 * Use the extra space to store the extra node.
502 */
503 node_insert_key_and_rsubtree(node, key, value, rsubtree);
504
505 /*
506 * Compute median of keys.
507 */
508 *median = MEDIAN_HIGH(node);
509
510 /*
511 * Allocate and initialize new right sibling.
512 */
513 rnode = (btree_node_t *) slab_alloc(btree_node_slab, 0);
514 node_initialize(rnode);
515 rnode->parent = node->parent;
516 rnode->depth = node->depth;
517
518 /*
519 * Copy big keys, values and subtree pointers to the new right sibling.
520 * If this is an index node, do not copy the median.
521 */
522 i = (size_t) INDEX_NODE(node);
523 for (i += MEDIAN_HIGH_INDEX(node), j = 0; i < node->keys; i++, j++) {
524 rnode->key[j] = node->key[i];
525 rnode->value[j] = node->value[i];
526 rnode->subtree[j] = node->subtree[i];
527
528 /*
529 * Fix parent links in subtrees.
530 */
531 if (rnode->subtree[j])
532 rnode->subtree[j]->parent = rnode;
533 }
534
535 rnode->subtree[j] = node->subtree[i];
536 if (rnode->subtree[j])
537 rnode->subtree[j]->parent = rnode;
538
539 rnode->keys = j; /* Set number of keys of the new node. */
540 node->keys /= 2; /* Shrink the old node. */
541
542 return rnode;
543}
544
545/** Recursively insert into B-tree.
546 *
547 * @param t B-tree.
548 * @param key Key to be inserted.
549 * @param value Value to be inserted.
550 * @param rsubtree Right subtree of the inserted key.
551 * @param node Start inserting into this node.
552 *
553 */
554static void _btree_insert(btree_t *t, btree_key_t key, void *value,
555 btree_node_t *rsubtree, btree_node_t *node)
556{
557 if (node->keys < BTREE_MAX_KEYS) {
558 /*
559 * Node conatins enough space, the key can be stored immediately.
560 */
561 node_insert_key_and_rsubtree(node, key, value, rsubtree);
562 } else if (try_insert_by_rotation_to_left(node, key, value, rsubtree)) {
563 /*
564 * The key-value-rsubtree triplet has been inserted because
565 * some keys could have been moved to the left sibling.
566 */
567 } else if (try_insert_by_rotation_to_right(node, key, value, rsubtree)) {
568 /*
569 * The key-value-rsubtree triplet has been inserted because
570 * some keys could have been moved to the right sibling.
571 */
572 } else {
573 btree_node_t *rnode;
574 btree_key_t median;
575
576 /*
577 * Node is full and both siblings (if both exist) are full too.
578 * Split the node and insert the smallest key from the node containing
579 * bigger keys (i.e. the new node) into its parent.
580 */
581
582 rnode = node_split(node, key, value, rsubtree, &median);
583
584 if (LEAF_NODE(node)) {
585 list_prepend(&rnode->leaf_link, &node->leaf_link);
586 }
587
588 if (ROOT_NODE(node)) {
589 /*
590 * We split the root node. Create new root.
591 */
592 t->root = (btree_node_t *) slab_alloc(btree_node_slab, 0);
593 node->parent = t->root;
594 rnode->parent = t->root;
595 node_initialize(t->root);
596
597 /*
598 * Left-hand side subtree will be the old root (i.e. node).
599 * Right-hand side subtree will be rnode.
600 */
601 t->root->subtree[0] = node;
602
603 t->root->depth = node->depth + 1;
604 }
605 _btree_insert(t, median, NULL, rnode, node->parent);
606 }
607}
608
609/** Insert key-value pair into B-tree.
610 *
611 * @param t B-tree.
612 * @param key Key to be inserted.
613 * @param value Value to be inserted.
614 * @param leaf_node Leaf node where the insertion should begin.
615 *
616 */
617void btree_insert(btree_t *t, btree_key_t key, void *value,
618 btree_node_t *leaf_node)
619{
620 btree_node_t *lnode;
621
622 ASSERT(value);
623
624 lnode = leaf_node;
625 if (!lnode) {
626 if (btree_search(t, key, &lnode))
627 panic("B-tree %p already contains key %" PRIu64 ".", t, key);
628 }
629
630 _btree_insert(t, key, value, NULL, lnode);
631}
632
633/** Rotate in a key from the left sibling or from the index node, if this operation can be done.
634 *
635 * @param rnode Node into which to add key from its left sibling
636 * or from the index node.
637 *
638 * @return True if the rotation was performed, false otherwise.
639 *
640 */
641static bool try_rotation_from_left(btree_node_t *rnode)
642{
643 size_t idx;
644 btree_node_t *lnode;
645
646 /*
647 * If this is root node, the rotation can not be done.
648 */
649 if (ROOT_NODE(rnode))
650 return false;
651
652 idx = find_key_by_subtree(rnode->parent, rnode, true);
653 if ((int) idx == -1) {
654 /*
655 * If this node is the leftmost subtree of its parent,
656 * the rotation can not be done.
657 */
658 return false;
659 }
660
661 lnode = rnode->parent->subtree[idx];
662 if (lnode->keys > FILL_FACTOR) {
663 rotate_from_left(lnode, rnode, idx);
664 return true;
665 }
666
667 return false;
668}
669
670/** Rotate in a key from the right sibling or from the index node, if this operation can be done.
671 *
672 * @param lnode Node into which to add key from its right sibling
673 * or from the index node.
674 *
675 * @return True if the rotation was performed, false otherwise.
676 *
677 */
678static bool try_rotation_from_right(btree_node_t *lnode)
679{
680 size_t idx;
681 btree_node_t *rnode;
682
683 /*
684 * If this is root node, the rotation can not be done.
685 */
686 if (ROOT_NODE(lnode))
687 return false;
688
689 idx = find_key_by_subtree(lnode->parent, lnode, false);
690 if (idx == lnode->parent->keys) {
691 /*
692 * If this node is the rightmost subtree of its parent,
693 * the rotation can not be done.
694 */
695 return false;
696 }
697
698 rnode = lnode->parent->subtree[idx + 1];
699 if (rnode->keys > FILL_FACTOR) {
700 rotate_from_right(lnode, rnode, idx);
701 return true;
702 }
703
704 return false;
705}
706
707/** Combine node with any of its siblings.
708 *
709 * The siblings are required to be below the fill factor.
710 *
711 * @param node Node to combine with one of its siblings.
712 *
713 * @return Pointer to the rightmost of the two nodes.
714 *
715 */
716static btree_node_t *node_combine(btree_node_t *node)
717{
718 size_t idx;
719 btree_node_t *rnode;
720 size_t i;
721
722 ASSERT(!ROOT_NODE(node));
723
724 idx = find_key_by_subtree(node->parent, node, false);
725 if (idx == node->parent->keys) {
726 /*
727 * Rightmost subtree of its parent, combine with the left sibling.
728 */
729 idx--;
730 rnode = node;
731 node = node->parent->subtree[idx];
732 } else
733 rnode = node->parent->subtree[idx + 1];
734
735 /* Index nodes need to insert parent node key in between left and right node. */
736 if (INDEX_NODE(node))
737 node->key[node->keys++] = node->parent->key[idx];
738
739 /* Copy the key-value-subtree triplets from the right node. */
740 for (i = 0; i < rnode->keys; i++) {
741 node->key[node->keys + i] = rnode->key[i];
742 node->value[node->keys + i] = rnode->value[i];
743
744 if (INDEX_NODE(node)) {
745 node->subtree[node->keys + i] = rnode->subtree[i];
746 rnode->subtree[i]->parent = node;
747 }
748 }
749
750 if (INDEX_NODE(node)) {
751 node->subtree[node->keys + i] = rnode->subtree[i];
752 rnode->subtree[i]->parent = node;
753 }
754
755 node->keys += rnode->keys;
756 return rnode;
757}
758
759/** Recursively remove B-tree node.
760 *
761 * @param t B-tree.
762 * @param key Key to be removed from the B-tree along with its associated value.
763 * @param node Node where the key being removed resides.
764 *
765 */
766static void _btree_remove(btree_t *t, btree_key_t key, btree_node_t *node)
767{
768 if (ROOT_NODE(node)) {
769 if ((node->keys == 1) && (node->subtree[0])) {
770 /*
771 * Free the current root and set new root.
772 */
773 t->root = node->subtree[0];
774 t->root->parent = NULL;
775 slab_free(btree_node_slab, node);
776 } else {
777 /*
778 * Remove the key from the root node.
779 * Note that the right subtree is removed because when
780 * combining two nodes, the left-side sibling is preserved
781 * and the right-side sibling is freed.
782 */
783 node_remove_key_and_rsubtree(node, key);
784 }
785
786 return;
787 }
788
789 if (node->keys <= FILL_FACTOR) {
790 /*
791 * If the node is below the fill factor,
792 * try to borrow keys from left or right sibling.
793 */
794 if (!try_rotation_from_left(node))
795 try_rotation_from_right(node);
796 }
797
798 if (node->keys > FILL_FACTOR) {
799 size_t i;
800
801 /*
802 * The key can be immediatelly removed.
803 *
804 * Note that the right subtree is removed because when
805 * combining two nodes, the left-side sibling is preserved
806 * and the right-side sibling is freed.
807 */
808 node_remove_key_and_rsubtree(node, key);
809
810 for (i = 0; i < node->parent->keys; i++) {
811 if (node->parent->key[i] == key)
812 node->parent->key[i] = node->key[0];
813 }
814 } else {
815 size_t idx;
816 btree_node_t *rnode;
817 btree_node_t *parent;
818
819 /*
820 * The node is below the fill factor as well as its left and right sibling.
821 * Resort to combining the node with one of its siblings.
822 * The node which is on the left is preserved and the node on the right is
823 * freed.
824 */
825 parent = node->parent;
826 node_remove_key_and_rsubtree(node, key);
827 rnode = node_combine(node);
828
829 if (LEAF_NODE(rnode))
830 list_remove(&rnode->leaf_link);
831
832 idx = find_key_by_subtree(parent, rnode, true);
833 ASSERT((int) idx != -1);
834 slab_free(btree_node_slab, rnode);
835 _btree_remove(t, parent->key[idx], parent);
836 }
837}
838
839/** Remove B-tree node.
840 *
841 * @param t B-tree.
842 * @param key Key to be removed from the B-tree along
843 * with its associated value.
844 * @param leaf_node If not NULL, pointer to the leaf node where
845 * the key is found.
846 *
847 */
848void btree_remove(btree_t *t, btree_key_t key, btree_node_t *leaf_node)
849{
850 btree_node_t *lnode;
851
852 lnode = leaf_node;
853 if (!lnode) {
854 if (!btree_search(t, key, &lnode))
855 panic("B-tree %p does not contain key %" PRIu64 ".", t, key);
856 }
857
858 _btree_remove(t, key, lnode);
859}
860
861/** Search key in a B-tree.
862 *
863 * @param t B-tree.
864 * @param key Key to be searched.
865 * @param leaf_node Address where to put pointer to visited leaf node.
866 *
867 * @return Pointer to value or NULL if there is no such key.
868 *
869 */
870void *btree_search(btree_t *t, btree_key_t key, btree_node_t **leaf_node)
871{
872 btree_node_t *cur, *next;
873
874 /*
875 * Iteratively descend to the leaf that can contain the searched key.
876 */
877 for (cur = t->root; cur; cur = next) {
878 /*
879 * Last iteration will set this with proper
880 * leaf node address.
881 */
882 *leaf_node = cur;
883
884 /*
885 * The key can be in the leftmost subtree.
886 * Test it separately.
887 */
888 if (key < cur->key[0]) {
889 next = cur->subtree[0];
890 continue;
891 } else {
892 void *val;
893 size_t i;
894
895 /*
896 * Now if the key is smaller than cur->key[i]
897 * it can only mean that the value is in cur->subtree[i]
898 * or it is not in the tree at all.
899 */
900 for (i = 1; i < cur->keys; i++) {
901 if (key < cur->key[i]) {
902 next = cur->subtree[i];
903 val = cur->value[i - 1];
904
905 if (LEAF_NODE(cur))
906 return key == cur->key[i - 1] ? val : NULL;
907
908 goto descend;
909 }
910 }
911
912 /*
913 * Last possibility is that the key is
914 * in the rightmost subtree.
915 */
916 next = cur->subtree[i];
917 val = cur->value[i - 1];
918
919 if (LEAF_NODE(cur))
920 return key == cur->key[i - 1] ? val : NULL;
921 }
922 descend:
923 ;
924 }
925
926 /*
927 * The key was not found in the *leaf_node and
928 * is smaller than any of its keys.
929 */
930 return NULL;
931}
932
933/** Return pointer to B-tree leaf node's left neighbour.
934 *
935 * @param t B-tree.
936 * @param node Node whose left neighbour will be returned.
937 *
938 * @return Left neighbour of the node or NULL if the node
939 * does not have the left neighbour.
940 *
941 */
942btree_node_t *btree_leaf_node_left_neighbour(btree_t *t, btree_node_t *node)
943{
944 ASSERT(LEAF_NODE(node));
945
946 if (node->leaf_link.prev != &t->leaf_head)
947 return list_get_instance(node->leaf_link.prev, btree_node_t, leaf_link);
948 else
949 return NULL;
950}
951
952/** Return pointer to B-tree leaf node's right neighbour.
953 *
954 * @param t B-tree.
955 * @param node Node whose right neighbour will be returned.
956 *
957 * @return Right neighbour of the node or NULL if the node
958 * does not have the right neighbour.
959 *
960 */
961btree_node_t *btree_leaf_node_right_neighbour(btree_t *t, btree_node_t *node)
962{
963 ASSERT(LEAF_NODE(node));
964
965 if (node->leaf_link.next != &t->leaf_head)
966 return list_get_instance(node->leaf_link.next, btree_node_t, leaf_link);
967 else
968 return NULL;
969}
970
971/** Print B-tree.
972 *
973 * @param t Print out B-tree.
974 *
975 */
976void btree_print(btree_t *t)
977{
978 size_t i;
979 int depth = t->root->depth;
980 link_t head, *cur;
981
982 printf("Printing B-tree:\n");
983 list_initialize(&head);
984 list_append(&t->root->bfs_link, &head);
985
986 /*
987 * Use BFS search to print out the tree.
988 * Levels are distinguished from one another by node->depth.
989 */
990 while (!list_empty(&head)) {
991 link_t *hlp;
992 btree_node_t *node;
993
994 hlp = head.next;
995 ASSERT(hlp != &head);
996 node = list_get_instance(hlp, btree_node_t, bfs_link);
997 list_remove(hlp);
998
999 ASSERT(node);
1000
1001 if (node->depth != depth) {
1002 printf("\n");
1003 depth = node->depth;
1004 }
1005
1006 printf("(");
1007
1008 for (i = 0; i < node->keys; i++) {
1009 printf("%" PRIu64 "%s", node->key[i], i < node->keys - 1 ? "," : "");
1010 if (node->depth && node->subtree[i]) {
1011 list_append(&node->subtree[i]->bfs_link, &head);
1012 }
1013 }
1014
1015 if (node->depth && node->subtree[i])
1016 list_append(&node->subtree[i]->bfs_link, &head);
1017
1018 printf(")");
1019 }
1020
1021 printf("\n");
1022
1023 printf("Printing list of leaves:\n");
1024 for (cur = t->leaf_head.next; cur != &t->leaf_head; cur = cur->next) {
1025 btree_node_t *node;
1026
1027 node = list_get_instance(cur, btree_node_t, leaf_link);
1028
1029 ASSERT(node);
1030
1031 printf("(");
1032
1033 for (i = 0; i < node->keys; i++)
1034 printf("%" PRIu64 "%s", node->key[i], i < node->keys - 1 ? "," : "");
1035
1036 printf(")");
1037 }
1038
1039 printf("\n");
1040}
1041
1042/** @}
1043 */
Note: See TracBrowser for help on using the repository browser.