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. |