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

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

huge type system cleanup
remove cyclical type dependencies across multiple header files
many minor coding style fixes

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