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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since a35b458 was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

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