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