Changeset cc27ae48 in mainline


Ignore:
Timestamp:
2006-03-26T19:06:53Z (19 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
50fe620
Parents:
a2c4445
Message:

Try to avoid splitting full B+-tree nodes by trying left or right rotation first.
(This improved memory consumption of this algorithm by some 40% - meassured on 101-item set).

File:
1 edited

Legend:

Unmodified
Added
Removed
  • generic/src/adt/btree.c

    ra2c4445 rcc27ae48  
    3434 * - technically, it is a B+-tree (because of the previous properties)
    3535 *
    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  *
    4636 * Be carefull when using these trees. They need to allocate
    4737 * and deallocate memory for their index nodes and as such
     
    5949static void _btree_insert(btree_t *t, __native key, void *value, btree_node_t *rsubtree, btree_node_t *node);
    6050static 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);
    62 void node_remove_key(btree_node_t *node, __native key);
     51static void node_insert_key_left(btree_node_t *node, __native key, void *value, btree_node_t *rsubtree);
     52static void node_insert_key_right(btree_node_t *node, __native key, void *value, btree_node_t *rsubtree);
    6353static btree_node_t *node_split(btree_node_t *node, __native key, void *value, btree_node_t *rsubtree, __native *median);
     54static void node_remove_key_left(btree_node_t *node, __native key);
     55static void node_remove_key_right(btree_node_t *node, __native key);
     56static index_t find_key_by_subtree(btree_node_t *node, btree_node_t *subtree, bool right);
     57static bool try_insert_by_left_rotation(btree_node_t *node, __native key, void *value, btree_node_t *rsubtree);
     58static bool try_insert_by_right_rotation(btree_node_t *node, __native key, void *value, btree_node_t *rsubtree);
    6459
    6560#define ROOT_NODE(n)            (!(n)->parent)
     
    128123                 * Node conatins enough space, the key can be stored immediately.
    129124                 */
    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                 */
    131136        } else {
    132137                btree_node_t *rnode;
     
    134139               
    135140                /*
    136                  * Node is full.
    137                  * Split it and insert the smallest key from the node containing
    138                  * bigger keys (i.e. the original node) into its parent.
     141                 * Node is full and both siblings (if both exist) are full too.
     142                 * Split the node and insert the smallest key from the node containing
     143                 * bigger keys (i.e. the new node) into its parent.
    139144                 */
    140145
     
    149154                         * We split the root node. Create new root.
    150155                         */
    151                
    152156                        t->root = (btree_node_t *) malloc(sizeof(btree_node_t), 0);
    153157                        node->parent = t->root;
     
    295299}
    296300
    297 /** Insert key-value-right-subtree triplet into B-tree non-full node.
     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 */
     311void 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
     336/** Insert key-value-rsubtree triplet into B-tree node.
    298337 *
    299338 * It is actually possible to have more keys than BTREE_MAX_KEYS.
    300339 * 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.
    302342 *
    303343 * @param node B-tree node into wich the new key is to be inserted.
     
    306346 * @param rsubtree Pointer to the right subtree.
    307347 */
    308 void node_insert_key(btree_node_t *node, __native key, void *value, btree_node_t *rsubtree)
     348void node_insert_key_right(btree_node_t *node, __native key, void *value, btree_node_t *rsubtree)
    309349{
    310350        int i;
     
    322362                }
    323363        }
    324 
    325364        node->key[i] = key;
    326365        node->value[i] = value;
     
    356395        ASSERT(median);
    357396        ASSERT(node->keys == BTREE_MAX_KEYS);
    358        
     397
    359398        /*
    360399         * Use the extra space to store the extra node.
    361400         */
    362         node_insert_key(node, key, value, rsubtree);
     401        node_insert_key_right(node, key, value, rsubtree);
    363402
    364403        /*
     
    402441}
    403442
    404 /** Remove key from B-tree node.
     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
     447 * is removed from the node as well.
    405448 *
    406449 * @param node B-tree node.
    407450 * @param key Key to be removed.
    408451 */
    409 void node_remove_key(btree_node_t *node, __native key)
    410 {
     452void 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 */
     480void 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 */
     506index_t find_key_by_subtree(btree_node_t *node, btree_node_t *subtree, bool right)
     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 */
     531bool 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 */
     601bool 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;
    411655}
    412656
Note: See TracChangeset for help on using the changeset viewer.