Subversion Repositories HelenOS-historic

Rev

Rev 1142 | Rev 1147 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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