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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since df4ed85 was df4ed85, checked in by Jakub Jermar <jakub@…>, 18 years ago

© versus ©

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