Subversion Repositories HelenOS-historic

Rev

Rev 1134 | Rev 1140 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 1134 Rev 1136
Line 31... Line 31...
31
 * - it is a ballanced 2-3-4 tree (i.e. BTREE_M = 4)
31
 * - it is a ballanced 2-3-4 tree (i.e. BTREE_M = 4)
32
 * - values (i.e. pointers to values) are stored only in leaves
32
 * - values (i.e. pointers to values) are stored only in leaves
33
 * - leaves are linked in a list
33
 * - leaves are linked in a list
34
 * - technically, it is a B+-tree (because of the previous properties)
34
 * - technically, it is a B+-tree (because of the previous properties)
35
 *
35
 *
36
 * Some of the functions below take pointer to the right-hand
-
 
37
 * side subtree pointer as parameter. Note that this is sufficient
-
 
38
 * because:
-
 
39
 *  - New root node is passed the left-hand side subtree pointer
-
 
40
 *    directly.
-
 
41
 *  - node_split() always creates the right sibling and preserves
-
 
42
 *    the original node (which becomes the left sibling).
-
 
43
 *    There is always pointer to the left-hand side subtree
-
 
44
 *    (i.e. left sibling) in the parent node.
-
 
45
 *
-
 
46
 * Be carefull when using these trees. They need to allocate
36
 * Be carefull when using these trees. They need to allocate
47
 * and deallocate memory for their index nodes and as such
37
 * and deallocate memory for their index nodes and as such
48
 * can sleep.
38
 * can sleep.
49
 */
39
 */
50
 
40
 
Line 56... Line 46...
56
#include <typedefs.h>
46
#include <typedefs.h>
57
#include <print.h>
47
#include <print.h>
58
 
48
 
59
static void _btree_insert(btree_t *t, __native key, void *value, btree_node_t *rsubtree, btree_node_t *node);
49
static void _btree_insert(btree_t *t, __native key, void *value, btree_node_t *rsubtree, btree_node_t *node);
60
static void node_initialize(btree_node_t *node);
50
static void node_initialize(btree_node_t *node);
61
static void node_insert_key(btree_node_t *node, __native key, void *value, btree_node_t *rsubtree);
51
static void node_insert_key_left(btree_node_t *node, __native key, void *value, btree_node_t *rsubtree);
62
void node_remove_key(btree_node_t *node, __native key);
52
static void node_insert_key_right(btree_node_t *node, __native key, void *value, btree_node_t *rsubtree);
63
static btree_node_t *node_split(btree_node_t *node, __native key, void *value, btree_node_t *rsubtree, __native *median);
53
static btree_node_t *node_split(btree_node_t *node, __native key, void *value, btree_node_t *rsubtree, __native *median);
-
 
54
static void node_remove_key_left(btree_node_t *node, __native key);
-
 
55
static void node_remove_key_right(btree_node_t *node, __native key);
-
 
56
static index_t find_key_by_subtree(btree_node_t *node, btree_node_t *subtree, bool right);
-
 
57
static bool try_insert_by_left_rotation(btree_node_t *node, __native key, void *value, btree_node_t *rsubtree);
-
 
58
static bool try_insert_by_right_rotation(btree_node_t *node, __native key, void *value, btree_node_t *rsubtree);
64
 
59
 
65
#define ROOT_NODE(n)        (!(n)->parent)
60
#define ROOT_NODE(n)        (!(n)->parent)
66
#define INDEX_NODE(n)       ((n)->subtree[0] != NULL)
61
#define INDEX_NODE(n)       ((n)->subtree[0] != NULL)
67
#define LEAF_NODE(n)        ((n)->subtree[0] == NULL)
62
#define LEAF_NODE(n)        ((n)->subtree[0] == NULL)
68
 
63
 
Line 125... Line 120...
125
{
120
{
126
    if (node->keys < BTREE_MAX_KEYS) {
121
    if (node->keys < BTREE_MAX_KEYS) {
127
        /*
122
        /*
128
         * Node conatins enough space, the key can be stored immediately.
123
         * Node conatins enough space, the key can be stored immediately.
129
         */
124
         */
130
        node_insert_key(node, key, value, rsubtree);
125
        node_insert_key_right(node, key, value, rsubtree);
-
 
126
    } else if (try_insert_by_left_rotation(node, key, value, rsubtree)) {
-
 
127
        /*
-
 
128
         * The key-value-rsubtree triplet has been inserted because
-
 
129
         * some keys could have been moved to the left sibling.
-
 
130
         */
-
 
131
    } else if (try_insert_by_right_rotation(node, key, value, rsubtree)) {
-
 
132
        /*
-
 
133
         * The key-value-rsubtree triplet has been inserted because
-
 
134
         * some keys could have been moved to the right sibling.
-
 
135
         */
131
    } else {
136
    } else {
132
        btree_node_t *rnode;
137
        btree_node_t *rnode;
133
        __native median;
138
        __native median;
134
       
139
       
135
        /*
140
        /*
136
         * Node is full.
141
         * Node is full and both siblings (if both exist) are full too.
137
         * Split it and insert the smallest key from the node containing
142
         * Split the node and insert the smallest key from the node containing
138
         * bigger keys (i.e. the original node) into its parent.
143
         * bigger keys (i.e. the new node) into its parent.
139
         */
144
         */
140
 
145
 
141
        rnode = node_split(node, key, value, rsubtree, &median);
146
        rnode = node_split(node, key, value, rsubtree, &median);
142
 
147
 
143
        if (LEAF_NODE(node)) {
148
        if (LEAF_NODE(node)) {
Line 146... Line 151...
146
       
151
       
147
        if (ROOT_NODE(node)) {
152
        if (ROOT_NODE(node)) {
148
            /*
153
            /*
149
             * We split the root node. Create new root.
154
             * We split the root node. Create new root.
150
             */
155
             */
151
       
-
 
152
            t->root = (btree_node_t *) malloc(sizeof(btree_node_t), 0);
156
            t->root = (btree_node_t *) malloc(sizeof(btree_node_t), 0);
153
            node->parent = t->root;
157
            node->parent = t->root;
154
            rnode->parent = t->root;
158
            rnode->parent = t->root;
155
            node_initialize(t->root);
159
            node_initialize(t->root);
156
           
160
           
Line 292... Line 296...
292
 
296
 
293
    link_initialize(&node->bfs_link);
297
    link_initialize(&node->bfs_link);
294
    node->depth = 0;
298
    node->depth = 0;
295
}
299
}
296
 
300
 
-
 
301
/** Insert key-value-lsubtree triplet into B-tree node.
-
 
302
 *
-
 
303
 * It is actually possible to have more keys than BTREE_MAX_KEYS.
-
 
304
 * This feature is used during insert by right rotation.
-
 
305
 *
-
 
306
 * @param node B-tree node into wich the new key is to be inserted.
-
 
307
 * @param key The key to be inserted.
-
 
308
 * @param value Pointer to value to be inserted.
-
 
309
 * @param lsubtree Pointer to the left subtree.
-
 
310
 */
-
 
311
void node_insert_key_left(btree_node_t *node, __native key, void *value, btree_node_t *lsubtree)
-
 
312
{
-
 
313
    int i;
-
 
314
 
-
 
315
    for (i = 0; i < node->keys; i++) {
-
 
316
        if (key < node->key[i]) {
-
 
317
            int j;
-
 
318
       
-
 
319
            for (j = node->keys; j > i; j--) {
-
 
320
                node->key[j] = node->key[j - 1];
-
 
321
                node->value[j] = node->value[j - 1];
-
 
322
                node->subtree[j + 1] = node->subtree[j];
-
 
323
            }
-
 
324
            node->subtree[j + 1] = node->subtree[j];
-
 
325
            break; 
-
 
326
        }
-
 
327
    }
-
 
328
    node->key[i] = key;
-
 
329
    node->value[i] = value;
-
 
330
    node->subtree[i] = lsubtree;
-
 
331
           
-
 
332
    node->keys++;
-
 
333
}
-
 
334
 
-
 
335
 
297
/** Insert key-value-right-subtree triplet into B-tree non-full node.
336
/** Insert key-value-rsubtree triplet into B-tree node.
298
 *
337
 *
299
 * It is actually possible to have more keys than BTREE_MAX_KEYS.
338
 * It is actually possible to have more keys than BTREE_MAX_KEYS.
300
 * This feature is used during splitting the node when the
339
 * This feature is used during splitting the node when the
301
 * number of keys is BTREE_MAX_KEYS + 1.
340
 * number of keys is BTREE_MAX_KEYS + 1. Insert by left rotation
-
 
341
 * also makes use of this feature.
302
 *
342
 *
303
 * @param node B-tree node into wich the new key is to be inserted.
343
 * @param node B-tree node into wich the new key is to be inserted.
304
 * @param key The key to be inserted.
344
 * @param key The key to be inserted.
305
 * @param value Pointer to value to be inserted.
345
 * @param value Pointer to value to be inserted.
306
 * @param rsubtree Pointer to the right subtree.
346
 * @param rsubtree Pointer to the right subtree.
307
 */
347
 */
308
void node_insert_key(btree_node_t *node, __native key, void *value, btree_node_t *rsubtree)
348
void node_insert_key_right(btree_node_t *node, __native key, void *value, btree_node_t *rsubtree)
309
{
349
{
310
    int i;
350
    int i;
311
 
351
 
312
    for (i = 0; i < node->keys; i++) {
352
    for (i = 0; i < node->keys; i++) {
313
        if (key < node->key[i]) {
353
        if (key < node->key[i]) {
Line 319... Line 359...
319
                node->subtree[j + 1] = node->subtree[j];
359
                node->subtree[j + 1] = node->subtree[j];
320
            }
360
            }
321
            break; 
361
            break; 
322
        }
362
        }
323
    }
363
    }
324
 
-
 
325
    node->key[i] = key;
364
    node->key[i] = key;
326
    node->value[i] = value;
365
    node->value[i] = value;
327
    node->subtree[i + 1] = rsubtree;
366
    node->subtree[i + 1] = rsubtree;
328
           
367
           
329
    node->keys++;
368
    node->keys++;
Line 353... Line 392...
353
    btree_node_t *rnode;
392
    btree_node_t *rnode;
354
    int i, j;
393
    int i, j;
355
 
394
 
356
    ASSERT(median);
395
    ASSERT(median);
357
    ASSERT(node->keys == BTREE_MAX_KEYS);
396
    ASSERT(node->keys == BTREE_MAX_KEYS);
358
   
397
 
359
    /*
398
    /*
360
     * Use the extra space to store the extra node.
399
     * Use the extra space to store the extra node.
361
     */
400
     */
362
    node_insert_key(node, key, value, rsubtree);
401
    node_insert_key_right(node, key, value, rsubtree);
363
 
402
 
364
    /*
403
    /*
365
     * Compute median of keys.
404
     * Compute median of keys.
366
     */
405
     */
367
    *median = MEDIAN_HIGH(node);
406
    *median = MEDIAN_HIGH(node);
Line 399... Line 438...
399
    node->keys /= 2;    /* Shrink the old node. */
438
    node->keys /= 2;    /* Shrink the old node. */
400
       
439
       
401
    return rnode;
440
    return rnode;
402
}
441
}
403
 
442
 
-
 
443
/** Remove key and its left subtree pointer from B-tree node.
-
 
444
 *
-
 
445
 * Remove the key and eliminate gaps in node->key array.
-
 
446
 * Note that the value pointer and the left subtree pointer
404
/** Remove key from B-tree node.
447
 * is removed from the node as well.
405
 *
448
 *
406
 * @param node B-tree node.
449
 * @param node B-tree node.
407
 * @param key Key to be removed.
450
 * @param key Key to be removed.
408
 */
451
 */
409
void node_remove_key(btree_node_t *node, __native key)
452
void node_remove_key_left(btree_node_t *node, __native key)
-
 
453
{
-
 
454
    int i, j;
-
 
455
   
-
 
456
    for (i = 0; i < node->keys; i++) {
-
 
457
        if (key == node->key[i]) {
-
 
458
            for (j = i + 1; j < node->keys; j++) {
-
 
459
                node->key[j - 1] = node->key[j];
-
 
460
                node->value[j - 1] = node->value[j];
-
 
461
                node->subtree[j - 1] = node->subtree[j];
-
 
462
            }
-
 
463
            node->subtree[j - 1] = node->subtree[j];
-
 
464
            node->keys--;
-
 
465
            return;
-
 
466
        }
-
 
467
    }
-
 
468
    panic("node %P does not contain key %d\n", node, key);
-
 
469
}
-
 
470
 
-
 
471
/** Remove key and its right subtree pointer from B-tree node.
-
 
472
 *
-
 
473
 * Remove the key and eliminate gaps in node->key array.
-
 
474
 * Note that the value pointer and the right subtree pointer
-
 
475
 * is removed from the node as well.
-
 
476
 *
-
 
477
 * @param node B-tree node.
-
 
478
 * @param key Key to be removed.
-
 
479
 */
-
 
480
void node_remove_key_right(btree_node_t *node, __native key)
-
 
481
{
-
 
482
    int i, j;
-
 
483
   
-
 
484
    for (i = 0; i < node->keys; i++) {
-
 
485
        if (key == node->key[i]) {
-
 
486
            for (j = i + 1; j < node->keys; j++) {
-
 
487
                node->key[j - 1] = node->key[j];
-
 
488
                node->value[j - 1] = node->value[j];
-
 
489
                node->subtree[j] = node->subtree[j + 1];
-
 
490
            }
-
 
491
            node->keys--;
-
 
492
            return;
-
 
493
        }
-
 
494
    }
-
 
495
    panic("node %P does not contain key %d\n", node, key);
-
 
496
}
-
 
497
 
-
 
498
/** Find key by its left or right subtree.
-
 
499
 *
-
 
500
 * @param node B-tree node.
-
 
501
 * @param subtree Left or right subtree of a key found in node.
-
 
502
 * @param right If true, subtree is a right subtree. If false, subtree is a left subtree.
-
 
503
 *
-
 
504
 * @return Index of the key associated with the subtree.
-
 
505
 */
-
 
506
index_t find_key_by_subtree(btree_node_t *node, btree_node_t *subtree, bool right)
410
{
507
{
-
 
508
    int i;
-
 
509
   
-
 
510
    for (i = 0; i < node->keys + 1; i++) {
-
 
511
        if (subtree == node->subtree[i])
-
 
512
            return i - (int) (right != false);
-
 
513
    }
-
 
514
    panic("node %P does not contain subtree %P\n", node, subtree);
-
 
515
}
-
 
516
 
-
 
517
/** Insert key-value-rsubtree triplet and rotate the node to the left, if this operation can be done.
-
 
518
 *
-
 
519
 * Left sibling of the node (if it exists) is checked for free space.
-
 
520
 * If there is free space, the key is inserted and the smallest key of
-
 
521
 * the node is moved there. The index node which is the parent of both
-
 
522
 * nodes is fixed.
-
 
523
 *
-
 
524
 * @param node B-tree node.
-
 
525
 * @param inskey Key to be inserted.
-
 
526
 * @param insvalue Value to be inserted.
-
 
527
 * @param rsubtree Right subtree of inskey.
-
 
528
 *
-
 
529
 * @return True if the rotation was performed, false otherwise.
-
 
530
 */
-
 
531
bool try_insert_by_left_rotation(btree_node_t *node, __native inskey, void *insvalue, btree_node_t *rsubtree)
-
 
532
{
-
 
533
    index_t idx;
-
 
534
    btree_node_t *lnode;
-
 
535
 
-
 
536
    /*
-
 
537
     * If this is root node, the rotation can not be done.
-
 
538
     */
-
 
539
    if (ROOT_NODE(node))
-
 
540
        return false;
-
 
541
   
-
 
542
    idx = find_key_by_subtree(node->parent, node, true);
-
 
543
    if ((int) idx == -1) {
-
 
544
        /*
-
 
545
         * If this node is the leftmost subtree of its parent,
-
 
546
         * the rotation can not be done.
-
 
547
         */
-
 
548
        return false;
-
 
549
    }
-
 
550
       
-
 
551
    lnode = node->parent->subtree[idx];
-
 
552
 
-
 
553
    if (lnode->keys < BTREE_MAX_KEYS) {
-
 
554
        __native key;
-
 
555
 
-
 
556
        /*
-
 
557
         * The rotaion can be done. The left sibling has free space.
-
 
558
         */
-
 
559
 
-
 
560
        node_insert_key_right(node, inskey, insvalue, rsubtree);
-
 
561
        key = node->key[0];
-
 
562
       
-
 
563
        if (LEAF_NODE(node)) {
-
 
564
            void *value;
-
 
565
 
-
 
566
            value = node->value[0];
-
 
567
            node_remove_key_left(node, key);
-
 
568
            node_insert_key_right(lnode, key, value, NULL);
-
 
569
            node->parent->key[idx] = node->key[0];
-
 
570
        } else {
-
 
571
            btree_node_t *lsubtree;
-
 
572
 
-
 
573
            lsubtree = node->subtree[0];
-
 
574
            node_remove_key_left(node, key);
-
 
575
            node_insert_key_right(lnode, node->parent->key[idx], NULL, lsubtree);
-
 
576
            node->parent->key[idx] = key;
-
 
577
 
-
 
578
            /* Fix parent link of the reconnected left subtree. */
-
 
579
            lsubtree->parent = lnode;
-
 
580
        }
-
 
581
        return true;
-
 
582
    }
-
 
583
 
-
 
584
    return false;
-
 
585
}
-
 
586
 
-
 
587
/** Insert key-value-rsubtree triplet and rotate the node to the right, if this operation can be done.
-
 
588
 *
-
 
589
 * Right sibling of the node (if it exists) is checked for free space.
-
 
590
 * If there is free space, the key is inserted and the biggest key of
-
 
591
 * the node is moved there. The index node which is the parent of both
-
 
592
 * nodes is fixed.
-
 
593
 *
-
 
594
 * @param node B-tree node.
-
 
595
 * @param inskey Key to be inserted.
-
 
596
 * @param insvalue Value to be inserted.
-
 
597
 * @param rsubtree Right subtree of inskey.
-
 
598
 *
-
 
599
 * @return True if the rotation was performed, false otherwise.
-
 
600
 */
-
 
601
bool try_insert_by_right_rotation(btree_node_t *node, __native inskey, void *insvalue, btree_node_t *rsubtree)
-
 
602
{
-
 
603
    index_t idx;
-
 
604
    btree_node_t *rnode;
-
 
605
 
-
 
606
    /*
-
 
607
     * If this is root node, the rotation can not be done.
-
 
608
     */
-
 
609
    if (ROOT_NODE(node))
-
 
610
        return false;
-
 
611
   
-
 
612
    idx = find_key_by_subtree(node->parent, node, false);
-
 
613
    if (idx == node->parent->keys) {
-
 
614
        /*
-
 
615
         * If this node is the rightmost subtree of its parent,
-
 
616
         * the rotation can not be done.
-
 
617
         */
-
 
618
        return false;
-
 
619
    }
-
 
620
       
-
 
621
    rnode = node->parent->subtree[idx + 1];
-
 
622
 
-
 
623
    if (rnode->keys < BTREE_MAX_KEYS) {
-
 
624
        __native key;
-
 
625
 
-
 
626
        /*
-
 
627
         * The rotaion can be done. The right sibling has free space.
-
 
628
         */
-
 
629
 
-
 
630
        node_insert_key_right(node, inskey, insvalue, rsubtree);
-
 
631
        key = node->key[node->keys - 1];
-
 
632
       
-
 
633
        if (LEAF_NODE(node)) {
-
 
634
            void *value;
-
 
635
 
-
 
636
            value = node->value[node->keys - 1];
-
 
637
            node_remove_key_right(node, key);
-
 
638
            node_insert_key_left(rnode, key, value, NULL);
-
 
639
            node->parent->key[idx] = key;
-
 
640
        } else {
-
 
641
            btree_node_t *rsubt;
-
 
642
 
-
 
643
            rsubt = node->subtree[node->keys];
-
 
644
            node_remove_key_right(node, key);
-
 
645
            node_insert_key_left(rnode, node->parent->key[idx], NULL, rsubt);
-
 
646
            node->parent->key[idx] = key;
-
 
647
 
-
 
648
            /* Fix parent link of the reconnected right subtree. */
-
 
649
            rsubt->parent = rnode;
-
 
650
        }
-
 
651
        return true;
-
 
652
    }
-
 
653
 
-
 
654
    return false;
411
}
655
}
412
 
656
 
413
/** Print B-tree.
657
/** Print B-tree.
414
 *
658
 *
415
 * @param t Print out B-tree.
659
 * @param t Print out B-tree.