Nothing to see here, move along
at main 889 lines 27 kB view raw
1use crate::block_io::BlockIo; 2use crate::cache::BlockCache; 3use crate::error::FsError; 4use crate::pool::{NodeIdx, NodePool, is_pool_ref, pool_idx_to_addr}; 5use lancer_core::fs::{ 6 BLOCK_SIZE_MIN_LOG2, BTREE_MAX_ENTRIES, BTREE_MIN_ENTRIES, BTreeNode, BlockRef, BlockType, 7 Compression, 8}; 9 10const MAX_DEPTH: usize = 5; 11 12enum WalkDone { 13 Leaf(NodeIdx), 14 Err(FsError), 15} 16 17impl From<FsError> for WalkDone { 18 fn from(e: FsError) -> Self { 19 WalkDone::Err(e) 20 } 21} 22 23fn load_node( 24 pool: &mut NodePool, 25 cache: &mut BlockCache, 26 bio: &mut BlockIo, 27 block_ref: &BlockRef, 28) -> Result<NodeIdx, FsError> { 29 let addr = block_ref.physical_block_addr(); 30 match is_pool_ref(addr) { 31 true => Ok(crate::pool::addr_to_pool_idx(addr)), 32 false => { 33 let block_num = crate::blockref_block_num(block_ref); 34 pool.pool_load(cache, bio, block_num) 35 } 36 } 37} 38 39fn load_and_validate( 40 pool: &mut NodePool, 41 cache: &mut BlockCache, 42 bio: &mut BlockIo, 43 block_ref: &BlockRef, 44) -> Result<NodeIdx, FsError> { 45 let idx = load_node(pool, cache, bio, block_ref)?; 46 match pool.get(idx).is_valid() { 47 true => Ok(idx), 48 false => { 49 pool.pool_free(idx); 50 Err(FsError::CorruptNode) 51 } 52 } 53} 54 55fn node_insert_entry(node: &mut BTreeNode, pos: usize, entry: BlockRef) -> bool { 56 let count = node.entry_count(); 57 match count < BTREE_MAX_ENTRIES { 58 true => { 59 node.entries.copy_within(pos..count, pos + 1); 60 node.entries[pos] = entry; 61 node.header.entry_count += 1; 62 false 63 } 64 false => true, 65 } 66} 67 68fn node_remove_entry(node: &mut BTreeNode, pos: usize) -> BlockRef { 69 let count = node.entry_count(); 70 let removed = node.entries[pos]; 71 node.entries.copy_within(pos + 1..count, pos); 72 node.entries[count - 1] = BlockRef::ZERO; 73 node.header.entry_count -= 1; 74 removed 75} 76 77fn node_merge( 78 pool: &mut NodePool, 79 left_idx: NodeIdx, 80 right_idx: NodeIdx, 81) -> Result<NodeIdx, FsError> { 82 let merged_idx = pool.pool_alloc()?; 83 84 let left = pool.get(left_idx); 85 let left_count = left.entry_count(); 86 let level = left.header.level; 87 let left_entries: [BlockRef; BTREE_MAX_ENTRIES] = { 88 let mut arr = [BlockRef::ZERO; BTREE_MAX_ENTRIES]; 89 (0..left_count).for_each(|i| { 90 arr[i] = left.entries[i]; 91 }); 92 arr 93 }; 94 95 let right = pool.get(right_idx); 96 let right_count = right.entry_count(); 97 let right_entries: [BlockRef; BTREE_MAX_ENTRIES] = { 98 let mut arr = [BlockRef::ZERO; BTREE_MAX_ENTRIES]; 99 (0..right_count).for_each(|i| { 100 arr[i] = right.entries[i]; 101 }); 102 arr 103 }; 104 105 let merged = pool.get_mut(merged_idx); 106 merged.header = lancer_core::fs::BTreeNodeHeader::new(level); 107 (0..left_count).for_each(|i| { 108 merged.entries[i] = left_entries[i]; 109 }); 110 (0..right_count).for_each(|i| { 111 merged.entries[left_count + i] = right_entries[i]; 112 }); 113 merged.header.entry_count = (left_count + right_count) as u16; 114 115 pool.pool_free(left_idx); 116 pool.pool_free(right_idx); 117 118 Ok(merged_idx) 119} 120 121pub fn btree_lookup( 122 pool: &mut NodePool, 123 cache: &mut BlockCache, 124 bio: &mut BlockIo, 125 root: &BlockRef, 126 key: u64, 127 txn_filter: Option<u64>, 128) -> Result<Option<BlockRef>, FsError> { 129 if root.is_null() { 130 return Ok(None); 131 } 132 133 let mut loaded: [NodeIdx; MAX_DEPTH + 1] = [0; { MAX_DEPTH + 1 }]; 134 let mut loaded_count = 0usize; 135 let mut result: Option<BlockRef> = None; 136 137 let walk_err = (0..MAX_DEPTH + 1).try_fold(*root, |current_ref, _| { 138 let idx = load_and_validate(pool, cache, bio, &current_ref)?; 139 loaded[loaded_count] = idx; 140 loaded_count += 1; 141 142 let node = pool.get(idx); 143 match node.is_leaf() { 144 true => { 145 result = node 146 .search_by_key(key) 147 .ok() 148 .map(|i| node.entries[i]) 149 .filter(|entry| match txn_filter { 150 Some(max_txn) => entry.transaction_id <= max_txn, 151 None => true, 152 }); 153 Err(WalkDone::Leaf(idx)) 154 } 155 false => { 156 let child_idx = node.find_child_index(key); 157 match child_idx < node.entry_count() { 158 true => Ok(node.entries[child_idx]), 159 false => { 160 result = None; 161 Err(WalkDone::Leaf(idx)) 162 } 163 } 164 } 165 } 166 }); 167 168 (0..loaded_count).for_each(|i| { 169 let idx = loaded[i]; 170 if !pool.is_dirty(idx) { 171 pool.pool_free(idx); 172 } 173 }); 174 175 match walk_err { 176 Err(WalkDone::Leaf(_)) => Ok(result), 177 Err(WalkDone::Err(e)) => Err(e), 178 Ok(_) => Err(FsError::CorruptNode), 179 } 180} 181 182struct PathEntry { 183 pool_idx: NodeIdx, 184 child_index: usize, 185} 186 187pub fn btree_insert( 188 pool: &mut NodePool, 189 cache: &mut BlockCache, 190 bio: &mut BlockIo, 191 root: &BlockRef, 192 key: u64, 193 value: BlockRef, 194 txn: u64, 195) -> Result<BlockRef, FsError> { 196 if root.is_null() { 197 let leaf_idx = pool.pool_alloc()?; 198 let leaf = pool.get_mut(leaf_idx); 199 *leaf = BTreeNode::new(0); 200 let mut entry = value; 201 entry.key = key; 202 entry.transaction_id = txn; 203 leaf.entries[0] = entry; 204 leaf.header.entry_count = 1; 205 return Ok(make_pool_blockref(leaf_idx)); 206 } 207 208 let mut path: [PathEntry; MAX_DEPTH] = core::array::from_fn(|_| PathEntry { 209 pool_idx: 0, 210 child_index: 0, 211 }); 212 let mut depth = 0usize; 213 let mut leaf_idx: NodeIdx = 0; 214 215 let walk_err = (0..MAX_DEPTH + 1).try_fold(*root, |current_ref, _| { 216 let idx = load_and_validate(pool, cache, bio, &current_ref)?; 217 let node = pool.get(idx); 218 219 match node.is_leaf() { 220 true => { 221 leaf_idx = idx; 222 Err(WalkDone::Leaf(idx)) 223 } 224 false => { 225 let child_idx = node.find_child_index(key); 226 match depth < MAX_DEPTH { 227 true => { 228 path[depth] = PathEntry { 229 pool_idx: idx, 230 child_index: child_idx, 231 }; 232 depth += 1; 233 } 234 false => return Err(FsError::TreeFull.into()), 235 } 236 match child_idx < node.entry_count() { 237 true => Ok(node.entries[child_idx]), 238 false => Err(FsError::CorruptNode.into()), 239 } 240 } 241 } 242 }); 243 244 match walk_err { 245 Err(WalkDone::Leaf(_)) => {} 246 Err(WalkDone::Err(e)) => return Err(e), 247 Ok(_) => return Err(FsError::CorruptNode), 248 } 249 250 if pool.get(leaf_idx).search_by_key(key).is_ok() { 251 return Err(FsError::DuplicateKey); 252 } 253 254 let new_leaf_idx = cow_node(pool, leaf_idx)?; 255 let new_leaf = pool.get_mut(new_leaf_idx); 256 let insert_pos = match new_leaf.search_by_key(key) { 257 Ok(_) => return Err(FsError::DuplicateKey), 258 Err(pos) => pos, 259 }; 260 261 match new_leaf.entry_count() < BTREE_MAX_ENTRIES { 262 true => { 263 let mut entry = value; 264 entry.key = key; 265 entry.transaction_id = txn; 266 node_insert_entry(new_leaf, insert_pos, entry); 267 propagate_up(pool, &path, depth, new_leaf_idx, None, root, txn) 268 } 269 false => { 270 let mut entry = value; 271 entry.key = key; 272 entry.transaction_id = txn; 273 let split = split_with_insert(pool, new_leaf_idx, insert_pos, entry)?; 274 propagate_up(pool, &path, depth, 0, Some(split), root, txn) 275 } 276 } 277} 278 279fn split_with_insert( 280 pool: &mut NodePool, 281 full_idx: NodeIdx, 282 insert_pos: usize, 283 entry: BlockRef, 284) -> Result<(NodeIdx, NodeIdx), FsError> { 285 let left_idx = pool.pool_alloc()?; 286 let right_idx = pool.pool_alloc()?; 287 288 let full_node = pool.get(full_idx); 289 let level = full_node.header.level; 290 let count = full_node.entry_count(); 291 292 let total = count + 1; 293 let mid = total / 2; 294 295 let mut combined = [BlockRef::ZERO; BTREE_MAX_ENTRIES + 1]; 296 (0..insert_pos).for_each(|i| { 297 combined[i] = full_node.entries[i]; 298 }); 299 combined[insert_pos] = entry; 300 (insert_pos..count).for_each(|i| { 301 combined[i + 1] = full_node.entries[i]; 302 }); 303 304 { 305 let left = pool.get_mut(left_idx); 306 left.header = lancer_core::fs::BTreeNodeHeader::new(level); 307 left.header.entry_count = mid as u16; 308 (0..mid).for_each(|i| { 309 left.entries[i] = combined[i]; 310 }); 311 } 312 313 let right_count = total - mid; 314 { 315 let right = pool.get_mut(right_idx); 316 right.header = lancer_core::fs::BTreeNodeHeader::new(level); 317 right.header.entry_count = right_count as u16; 318 (0..right_count).for_each(|i| { 319 right.entries[i] = combined[mid + i]; 320 }); 321 } 322 323 pool.pool_free(full_idx); 324 325 Ok((left_idx, right_idx)) 326} 327 328fn free_if_clean(pool: &mut NodePool, idx: NodeIdx) { 329 match pool.is_dirty(idx) { 330 true => {} 331 false => pool.pool_free(idx), 332 } 333} 334 335fn cow_node(pool: &mut NodePool, src_idx: NodeIdx) -> Result<NodeIdx, FsError> { 336 match pool.is_dirty(src_idx) { 337 true => Ok(src_idx), 338 false => { 339 let src = pool.get(src_idx).clone(); 340 let new_idx = pool.pool_alloc()?; 341 *pool.get_mut(new_idx) = src; 342 [src_idx] 343 .iter() 344 .filter(|&&idx| new_idx != idx) 345 .for_each(|&idx| pool.pool_free(idx)); 346 Ok(new_idx) 347 } 348 } 349} 350 351fn make_pool_blockref(idx: NodeIdx) -> BlockRef { 352 let addr = pool_idx_to_addr(idx); 353 BlockRef::new( 354 addr & !0xF, 355 BLOCK_SIZE_MIN_LOG2, 356 0, 357 0, 358 0u128, 359 0u32, 360 BlockType::Indirect, 361 Compression::None, 362 0, 363 0, 364 ) 365} 366 367fn make_child_ref(pool_idx: NodeIdx, key: u64, txn: u64) -> BlockRef { 368 let mut r = make_pool_blockref(pool_idx); 369 r.key = key; 370 r.transaction_id = txn; 371 r 372} 373 374fn max_key_in_node(pool: &NodePool, idx: NodeIdx) -> u64 { 375 let node = pool.get(idx); 376 let count = node.entry_count(); 377 match count { 378 0 => 0, 379 _ => node.entries[count - 1].key, 380 } 381} 382 383fn propagate_up( 384 pool: &mut NodePool, 385 path: &[PathEntry; MAX_DEPTH], 386 depth: usize, 387 child_idx: NodeIdx, 388 pending_split: Option<(NodeIdx, NodeIdx)>, 389 root: &BlockRef, 390 txn: u64, 391) -> Result<BlockRef, FsError> { 392 let mut split: Option<(NodeIdx, NodeIdx)> = pending_split; 393 394 let top_result: Result<u16, FsError> = 395 (0..depth) 396 .rev() 397 .try_fold(child_idx, |current_child, level| { 398 let parent_entry = &path[level]; 399 let new_parent_idx = cow_node(pool, parent_entry.pool_idx)?; 400 401 match split.take() { 402 Some((left_idx, right_idx)) => { 403 let left_max = max_key_in_node(pool, left_idx); 404 let right_max = max_key_in_node(pool, right_idx); 405 406 let left_ref = make_child_ref(left_idx, left_max, txn); 407 let right_ref = make_child_ref(right_idx, right_max, txn); 408 409 let parent = pool.get_mut(new_parent_idx); 410 let ci = parent_entry.child_index; 411 parent.entries[ci] = left_ref; 412 413 let overflow = node_insert_entry(parent, ci + 1, right_ref); 414 match overflow { 415 true => { 416 let new_split = split_with_parent_insert( 417 pool, 418 new_parent_idx, 419 ci + 1, 420 right_ref, 421 )?; 422 split = Some(new_split); 423 Ok(new_split.0) 424 } 425 false => { 426 split = None; 427 Ok(new_parent_idx) 428 } 429 } 430 } 431 None => { 432 let child_max = max_key_in_node(pool, current_child); 433 let parent = pool.get_mut(new_parent_idx); 434 let child_ref = &mut parent.entries[parent_entry.child_index]; 435 child_ref.physical_addr = 436 pool_idx_to_addr(current_child) | (child_ref.physical_addr & 0xF); 437 child_ref.key = child_max; 438 child_ref.transaction_id = txn; 439 Ok(new_parent_idx) 440 } 441 } 442 }); 443 444 let top_idx = top_result?; 445 446 match split { 447 Some((left_idx, right_idx)) => { 448 let new_root_idx = pool.pool_alloc()?; 449 let top_level = pool.get(left_idx).header.level; 450 451 let left_max = max_key_in_node(pool, left_idx); 452 let right_max = max_key_in_node(pool, right_idx); 453 454 let left_ref = make_child_ref(left_idx, left_max, txn); 455 let right_ref = make_child_ref(right_idx, right_max, txn); 456 457 let new_root = pool.get_mut(new_root_idx); 458 *new_root = BTreeNode::new(top_level + 1); 459 new_root.entries[0] = left_ref; 460 new_root.entries[1] = right_ref; 461 new_root.header.entry_count = 2; 462 463 Ok(make_pool_blockref(new_root_idx)) 464 } 465 None => { 466 let mut r = make_pool_blockref(top_idx); 467 r.key = root.key; 468 r.transaction_id = root.transaction_id; 469 Ok(r) 470 } 471 } 472} 473 474fn split_with_parent_insert( 475 pool: &mut NodePool, 476 full_idx: NodeIdx, 477 insert_pos: usize, 478 entry: BlockRef, 479) -> Result<(NodeIdx, NodeIdx), FsError> { 480 split_with_insert(pool, full_idx, insert_pos, entry) 481} 482 483pub fn btree_delete( 484 pool: &mut NodePool, 485 cache: &mut BlockCache, 486 bio: &mut BlockIo, 487 root: &BlockRef, 488 key: u64, 489 txn: u64, 490) -> Result<Option<BlockRef>, FsError> { 491 if root.is_null() { 492 return Ok(None); 493 } 494 495 let mut path: [PathEntry; MAX_DEPTH] = core::array::from_fn(|_| PathEntry { 496 pool_idx: 0, 497 child_index: 0, 498 }); 499 let mut depth = 0usize; 500 let mut leaf_idx: NodeIdx = 0; 501 502 let walk_err = (0..MAX_DEPTH + 1).try_fold(*root, |current_ref, _| { 503 let idx = load_and_validate(pool, cache, bio, &current_ref)?; 504 let node = pool.get(idx); 505 506 match node.is_leaf() { 507 true => { 508 leaf_idx = idx; 509 Err(WalkDone::Leaf(idx)) 510 } 511 false => { 512 let child_idx = node.find_child_index(key); 513 match depth < MAX_DEPTH { 514 true => { 515 path[depth] = PathEntry { 516 pool_idx: idx, 517 child_index: child_idx, 518 }; 519 depth += 1; 520 } 521 false => return Err(FsError::TreeFull.into()), 522 } 523 match child_idx < node.entry_count() { 524 true => Ok(node.entries[child_idx]), 525 false => Err(FsError::CorruptNode.into()), 526 } 527 } 528 } 529 }); 530 531 match walk_err { 532 Err(WalkDone::Leaf(_)) => {} 533 Err(WalkDone::Err(e)) => return Err(e), 534 Ok(_) => return Err(FsError::CorruptNode), 535 } 536 537 let key_pos = match pool.get(leaf_idx).search_by_key(key) { 538 Ok(pos) => pos, 539 Err(_) => return Ok(None), 540 }; 541 542 let new_leaf_idx = cow_node(pool, leaf_idx)?; 543 node_remove_entry(pool.get_mut(new_leaf_idx), key_pos); 544 545 match depth { 546 0 => Ok(Some(make_pool_blockref(new_leaf_idx))), 547 _ => propagate_delete_up(pool, cache, bio, &path, depth, new_leaf_idx, txn), 548 } 549} 550 551#[allow(clippy::too_many_arguments)] 552fn propagate_delete_up( 553 pool: &mut NodePool, 554 cache: &mut BlockCache, 555 bio: &mut BlockIo, 556 path: &[PathEntry; MAX_DEPTH], 557 depth: usize, 558 child_idx: NodeIdx, 559 txn: u64, 560) -> Result<Option<BlockRef>, FsError> { 561 let mut needs_rebalance = pool.get(child_idx).entry_count() < BTREE_MIN_ENTRIES; 562 563 let top_idx = (0..depth) 564 .rev() 565 .try_fold(child_idx, |current_child, level| { 566 let parent_entry = &path[level]; 567 let new_parent_idx = cow_node(pool, parent_entry.pool_idx)?; 568 569 match needs_rebalance { 570 true => { 571 let rebalanced = rebalance( 572 pool, 573 cache, 574 bio, 575 new_parent_idx, 576 parent_entry.child_index, 577 current_child, 578 txn, 579 )?; 580 needs_rebalance = match level > 0 { 581 true => pool.get(rebalanced).entry_count() < BTREE_MIN_ENTRIES, 582 false => false, 583 }; 584 Ok::<NodeIdx, FsError>(rebalanced) 585 } 586 false => { 587 let child_max = max_key_in_node(pool, current_child); 588 let parent = pool.get_mut(new_parent_idx); 589 let child_ref = &mut parent.entries[parent_entry.child_index]; 590 child_ref.physical_addr = 591 pool_idx_to_addr(current_child) | (child_ref.physical_addr & 0xF); 592 child_ref.key = child_max; 593 child_ref.transaction_id = txn; 594 needs_rebalance = false; 595 Ok(new_parent_idx) 596 } 597 } 598 })?; 599 600 let top_node = pool.get(top_idx); 601 match top_node.entry_count() == 1 && top_node.header.level > 0 { 602 true => { 603 let only_child_ref = top_node.entries[0]; 604 match is_pool_ref(only_child_ref.physical_block_addr()) { 605 true => { 606 let child_pool_idx = 607 crate::pool::addr_to_pool_idx(only_child_ref.physical_block_addr()); 608 pool.pool_free(top_idx); 609 Ok(Some(make_pool_blockref(child_pool_idx))) 610 } 611 false => { 612 pool.pool_free(top_idx); 613 Ok(Some(only_child_ref)) 614 } 615 } 616 } 617 false => Ok(Some(make_pool_blockref(top_idx))), 618 } 619} 620 621#[allow(clippy::too_many_arguments)] 622fn rebalance( 623 pool: &mut NodePool, 624 cache: &mut BlockCache, 625 bio: &mut BlockIo, 626 parent_idx: NodeIdx, 627 child_pos: usize, 628 child_idx: NodeIdx, 629 txn: u64, 630) -> Result<NodeIdx, FsError> { 631 let parent_count = pool.get(parent_idx).entry_count(); 632 633 let right_sib_ref = match child_pos + 1 < parent_count { 634 true => Some(pool.get(parent_idx).entries[child_pos + 1]), 635 false => None, 636 }; 637 let left_sib_ref = match child_pos > 0 { 638 true => Some(pool.get(parent_idx).entries[child_pos - 1]), 639 false => None, 640 }; 641 642 let right_sibling = match right_sib_ref { 643 Some(ref sib_ref) => Some(load_and_validate(pool, cache, bio, sib_ref)?), 644 None => None, 645 }; 646 647 match right_sibling { 648 Some(sib_idx) if pool.get(sib_idx).entry_count() > BTREE_MIN_ENTRIES => { 649 return redistribute_from_right(pool, parent_idx, child_pos, child_idx, sib_idx, txn); 650 } 651 _ => {} 652 } 653 654 let left_sibling = match left_sib_ref { 655 Some(ref sib_ref) => Some(load_and_validate(pool, cache, bio, sib_ref)?), 656 None => None, 657 }; 658 659 match left_sibling { 660 Some(sib_idx) if pool.get(sib_idx).entry_count() > BTREE_MIN_ENTRIES => { 661 if let Some(right_idx) = right_sibling { 662 free_if_clean(pool, right_idx); 663 } 664 return redistribute_from_left(pool, parent_idx, child_pos, child_idx, sib_idx, txn); 665 } 666 _ => {} 667 } 668 669 if let Some(sib_idx) = right_sibling { 670 if let Some(left_idx) = left_sibling { 671 free_if_clean(pool, left_idx); 672 } 673 let merged_idx = node_merge(pool, child_idx, sib_idx)?; 674 let merged_max = max_key_in_node(pool, merged_idx); 675 let parent = pool.get_mut(parent_idx); 676 parent.entries[child_pos] = make_child_ref(merged_idx, merged_max, txn); 677 node_remove_entry(parent, child_pos + 1); 678 return Ok(parent_idx); 679 } 680 681 if let Some(sib_idx) = left_sibling { 682 let merged_idx = node_merge(pool, sib_idx, child_idx)?; 683 let merged_max = max_key_in_node(pool, merged_idx); 684 let parent = pool.get_mut(parent_idx); 685 parent.entries[child_pos - 1] = make_child_ref(merged_idx, merged_max, txn); 686 node_remove_entry(parent, child_pos); 687 return Ok(parent_idx); 688 } 689 690 let child_max = max_key_in_node(pool, child_idx); 691 let parent = pool.get_mut(parent_idx); 692 let child_ref = &mut parent.entries[child_pos]; 693 child_ref.physical_addr = pool_idx_to_addr(child_idx) | (child_ref.physical_addr & 0xF); 694 child_ref.key = child_max; 695 child_ref.transaction_id = txn; 696 Ok(parent_idx) 697} 698 699fn redistribute_from_right( 700 pool: &mut NodePool, 701 parent_idx: NodeIdx, 702 child_pos: usize, 703 child_idx: NodeIdx, 704 sib_idx: NodeIdx, 705 txn: u64, 706) -> Result<NodeIdx, FsError> { 707 let new_child_idx = cow_node(pool, child_idx)?; 708 let new_sib_idx = cow_node(pool, sib_idx)?; 709 710 let first_from_sib = node_remove_entry(pool.get_mut(new_sib_idx), 0); 711 712 let child = pool.get_mut(new_child_idx); 713 node_insert_entry(child, child.entry_count(), first_from_sib); 714 715 let child_max = max_key_in_node(pool, new_child_idx); 716 let sib_max = max_key_in_node(pool, new_sib_idx); 717 718 let parent = pool.get_mut(parent_idx); 719 parent.entries[child_pos] = make_child_ref(new_child_idx, child_max, txn); 720 parent.entries[child_pos + 1] = make_child_ref(new_sib_idx, sib_max, txn); 721 722 Ok(parent_idx) 723} 724 725fn redistribute_from_left( 726 pool: &mut NodePool, 727 parent_idx: NodeIdx, 728 child_pos: usize, 729 child_idx: NodeIdx, 730 sib_idx: NodeIdx, 731 txn: u64, 732) -> Result<NodeIdx, FsError> { 733 let new_child_idx = cow_node(pool, child_idx)?; 734 let new_sib_idx = cow_node(pool, sib_idx)?; 735 736 let sib = pool.get_mut(new_sib_idx); 737 let last_pos = sib.entry_count() - 1; 738 let last_from_sib = node_remove_entry(sib, last_pos); 739 740 let child = pool.get_mut(new_child_idx); 741 node_insert_entry(child, 0, last_from_sib); 742 743 let child_max = max_key_in_node(pool, new_child_idx); 744 let sib_max = max_key_in_node(pool, new_sib_idx); 745 746 let parent = pool.get_mut(parent_idx); 747 parent.entries[child_pos] = make_child_ref(new_child_idx, child_max, txn); 748 parent.entries[child_pos - 1] = make_child_ref(new_sib_idx, sib_max, txn); 749 750 Ok(parent_idx) 751} 752 753pub struct BTreeIter { 754 root: BlockRef, 755 start_key: u64, 756 end_key: u64, 757 txn_filter: Option<u64>, 758 last_key: Option<u64>, 759 exhausted: bool, 760} 761 762pub fn btree_range( 763 root: &BlockRef, 764 start_key: u64, 765 end_key: u64, 766 txn_filter: Option<u64>, 767) -> BTreeIter { 768 BTreeIter { 769 root: *root, 770 start_key, 771 end_key, 772 txn_filter, 773 last_key: None, 774 exhausted: false, 775 } 776} 777 778impl BTreeIter { 779 pub fn next( 780 &mut self, 781 pool: &mut NodePool, 782 cache: &mut BlockCache, 783 bio: &mut BlockIo, 784 ) -> Result<Option<BlockRef>, FsError> { 785 if self.exhausted { 786 return Ok(None); 787 } 788 789 let search_key = self 790 .last_key 791 .map(|k| k.saturating_add(1)) 792 .unwrap_or(self.start_key); 793 794 if search_key > self.end_key { 795 self.exhausted = true; 796 return Ok(None); 797 } 798 799 if self.root.is_null() { 800 self.exhausted = true; 801 return Ok(None); 802 } 803 804 let leaf_idx = walk_to_leaf_pool(pool, cache, bio, &self.root, search_key)?; 805 let node = pool.get(leaf_idx); 806 let count = node.entry_count(); 807 808 let txn_filter = self.txn_filter; 809 let end_key = self.end_key; 810 let found = (0..count) 811 .map(|i| node.entries[i]) 812 .filter(|e| e.key >= search_key && e.key <= end_key) 813 .find(|e| match txn_filter { 814 Some(max_txn) => e.transaction_id <= max_txn, 815 None => true, 816 }); 817 818 let max_key = (0..count).map(|i| node.entries[i].key).max(); 819 820 if !pool.is_dirty(leaf_idx) { 821 pool.pool_free(leaf_idx); 822 } 823 824 match found { 825 Some(entry) => { 826 self.last_key = Some(entry.key); 827 Ok(Some(entry)) 828 } 829 None => match max_key { 830 Some(mk) if mk >= search_key && mk < self.end_key => { 831 self.last_key = Some(mk); 832 self.next(pool, cache, bio) 833 } 834 _ => { 835 self.exhausted = true; 836 Ok(None) 837 } 838 }, 839 } 840 } 841} 842 843fn walk_to_leaf_pool( 844 pool: &mut NodePool, 845 cache: &mut BlockCache, 846 bio: &mut BlockIo, 847 root: &BlockRef, 848 target_key: u64, 849) -> Result<NodeIdx, FsError> { 850 let mut intermediates: [NodeIdx; MAX_DEPTH] = [0; MAX_DEPTH]; 851 let mut intermediate_count = 0usize; 852 let mut leaf_result: Option<NodeIdx> = None; 853 854 let walk_err = (0..MAX_DEPTH + 1).try_fold(*root, |current_ref, _| { 855 let idx = load_and_validate(pool, cache, bio, &current_ref).map_err(WalkDone::Err)?; 856 let node = pool.get(idx); 857 858 match node.is_leaf() { 859 true => { 860 leaf_result = Some(idx); 861 Err(WalkDone::Leaf(idx)) 862 } 863 false => { 864 intermediates[intermediate_count] = idx; 865 intermediate_count += 1; 866 let child_idx = node.find_child_index(target_key); 867 match child_idx < node.entry_count() { 868 true => Ok(node.entries[child_idx]), 869 false => { 870 let last = node.entry_count().saturating_sub(1); 871 Ok(node.entries[last]) 872 } 873 } 874 } 875 } 876 }); 877 878 (0..intermediate_count).for_each(|i| { 879 free_if_clean(pool, intermediates[i]); 880 }); 881 882 match leaf_result { 883 Some(idx) => Ok(idx), 884 None => match walk_err { 885 Err(WalkDone::Err(e)) => Err(e), 886 _ => Err(FsError::CorruptNode), 887 }, 888 } 889}