Provide context for all allocations and deallocations

This commit is contained in:
Jeremy Soller
2025-08-01 21:32:16 -06:00
parent 0a14166c2f
commit 5828e12e85
+120 -108
View File
@@ -19,6 +19,34 @@ use crate::{
TreePtr, ALLOC_GC_THRESHOLD, ALLOC_LIST_ENTRIES, DIR_ENTRY_MAX_LENGTH, HEADER_RING,
};
trait AllocCtx {
fn allocate(&mut self, _addr: BlockAddr) {}
fn deallocate(&mut self, _addr: BlockAddr) {}
}
pub struct FsCtx;
impl AllocCtx for FsCtx {}
impl AllocCtx for TreeData<Node> {
fn allocate(&mut self, addr: BlockAddr) {
let blocks = self.data().blocks();
self.data_mut().set_blocks(
blocks
.checked_add(addr.level().blocks::<u64>())
.expect("node block count overflow"),
);
}
fn deallocate(&mut self, addr: BlockAddr) {
let blocks = self.data().blocks();
self.data_mut().set_blocks(
blocks
.checked_sub(addr.level().blocks::<u64>())
.expect("node block count underflow"),
);
}
}
pub struct Transaction<'a, D: Disk> {
fs: &'a mut FileSystem<D>,
//TODO: make private
@@ -60,10 +88,15 @@ impl<'a, D: Disk> Transaction<'a, D> {
/// Allocate a new block of size defined by `meta`, returning its address.
/// - returns `Err(ENOSPC)` if a block of this size could not be alloated.
/// - unsafe because order must be done carefully and changes must be flushed to disk
pub(crate) unsafe fn allocate(&mut self, meta: BlockMeta) -> Result<BlockAddr> {
pub(crate) unsafe fn allocate(
&mut self,
ctx: &mut dyn AllocCtx,
meta: BlockMeta,
) -> Result<BlockAddr> {
match self.allocator.allocate(meta) {
Some(addr) => {
self.allocator_log.push_back(AllocEntry::allocate(addr));
ctx.allocate(addr);
Ok(addr)
}
None => Err(Error::new(ENOSPC)),
@@ -72,7 +105,7 @@ impl<'a, D: Disk> Transaction<'a, D> {
/// Deallocate the given block.
/// - unsafe because order must be done carefully and changes must be flushed to disk
pub(crate) unsafe fn deallocate(&mut self, addr: BlockAddr) {
pub(crate) unsafe fn deallocate(&mut self, ctx: &mut dyn AllocCtx, addr: BlockAddr) {
//TODO: should we use some sort of not-null abstraction?
assert!(!addr.is_null());
@@ -98,46 +131,22 @@ impl<'a, D: Disk> Transaction<'a, D> {
// Deallocate later when syncing filesystem, to avoid re-use
self.deallocate.push(addr);
}
ctx.deallocate(addr);
}
unsafe fn node_allocate(
unsafe fn deallocate_block<T: BlockTrait>(
&mut self,
node: &mut TreeData<Node>,
meta: BlockMeta,
) -> Result<BlockAddr> {
let addr = self.allocate(meta)?;
let blocks = node.data().blocks();
node.data_mut().set_blocks(
blocks
.checked_add(addr.level().blocks())
.expect("node allocated too many blocks"),
);
Ok(addr)
}
unsafe fn node_deallocate(&mut self, node: &mut TreeData<Node>, addr: BlockAddr) -> bool {
if !addr.is_null() {
self.deallocate(addr);
let blocks = node.data().blocks();
node.data_mut().set_blocks(
blocks
.checked_sub(addr.level().blocks())
.expect("node deallocated too many blocks"),
);
ctx: &mut dyn AllocCtx,
ptr: BlockPtr<T>,
) -> bool {
if !ptr.is_null() {
self.deallocate(ctx, ptr.addr());
true
} else {
false
}
}
unsafe fn node_deallocate_block<T: BlockTrait>(
&mut self,
node: &mut TreeData<Node>,
ptr: BlockPtr<T>,
) -> bool {
self.node_deallocate(node, ptr.addr())
}
/// Drain `self.allocator_log` and `self.deallocate`,
/// updating the [`AllocList`] with the resulting state.
///
@@ -210,7 +219,7 @@ impl<'a, D: Disk> Transaction<'a, D> {
while new_blocks.len() * ALLOC_LIST_ENTRIES
<= self.allocator_log.len() + self.deallocate.len()
{
new_blocks.push(unsafe { self.allocate(BlockMeta::default())? });
new_blocks.push(unsafe { self.allocate(&mut FsCtx, BlockMeta::default())? });
}
// De-allocate old blocks (after allocation to prevent re-use)
@@ -426,16 +435,17 @@ impl<'a, D: Disk> Transaction<'a, D> {
/// Write block data to a new address, returning new address
pub fn sync_block<T: BlockTrait + Deref<Target = [u8]>>(
&mut self,
ctx: &mut dyn AllocCtx,
mut block: BlockData<T>,
) -> Result<BlockPtr<T>> {
// Swap block to new address
let meta = block.addr().meta();
let old_addr = block.swap_addr(unsafe { self.allocate(meta)? });
let old_addr = block.swap_addr(unsafe { self.allocate(ctx, meta)? });
// Deallocate old address (will only take effect after sync_allocator, which helps to
// prevent re-use before a new header is written
if !old_addr.is_null() {
unsafe {
self.deallocate(old_addr);
self.deallocate(ctx, old_addr);
}
}
// Write new block
@@ -559,14 +569,14 @@ impl<'a, D: Disk> Transaction<'a, D> {
l0.data_mut().ptrs[i0] = block_ptr.cast();
l1.data_mut()
.set_branch_full(i1, l0.data().tree_list_is_full());
l1.data_mut().ptrs[i1] = self.sync_block(l0)?;
l1.data_mut().ptrs[i1] = self.sync_block(&mut FsCtx, l0)?;
l2.data_mut()
.set_branch_full(i2, l1.data().tree_list_is_full());
l2.data_mut().ptrs[i2] = self.sync_block(l1)?;
l2.data_mut().ptrs[i2] = self.sync_block(&mut FsCtx, l1)?;
l3.data_mut()
.set_branch_full(i3, l2.data().tree_list_is_full());
l3.data_mut().ptrs[i3] = self.sync_block(l2)?;
self.header.tree = self.sync_block(l3)?;
l3.data_mut().ptrs[i3] = self.sync_block(&mut FsCtx, l2)?;
self.header.tree = self.sync_block(&mut FsCtx, l3)?;
self.header_changed = true;
return Ok(tree_ptr);
@@ -603,37 +613,37 @@ impl<'a, D: Disk> Transaction<'a, D> {
l0.data_mut().set_branch_full(i0, false);
l0.data_mut().ptrs[i0] = BlockPtr::default();
let l0_ptr = if l0.data().tree_list_is_empty() {
unsafe { self.deallocate(l0.addr()) };
unsafe { self.deallocate(&mut FsCtx, l0.addr()) };
BlockPtr::default()
} else {
self.sync_block(l0)?
self.sync_block(&mut FsCtx, l0)?
};
l1.data_mut().set_branch_full(i1, false);
l1.data_mut().ptrs[i1] = l0_ptr;
let l1_ptr = if l1.data().tree_list_is_empty() {
unsafe { self.deallocate(l1.addr()) };
unsafe { self.deallocate(&mut FsCtx, l1.addr()) };
BlockPtr::default()
} else {
self.sync_block(l1)?
self.sync_block(&mut FsCtx, l1)?
};
l2.data_mut().set_branch_full(i2, false);
l2.data_mut().ptrs[i2] = l1_ptr;
let l2_ptr = if l2.data().tree_list_is_empty() {
unsafe { self.deallocate(l2.addr()) };
unsafe { self.deallocate(&mut FsCtx, l2.addr()) };
BlockPtr::default()
} else {
self.sync_block(l2)?
self.sync_block(&mut FsCtx, l2)?
};
l3.data_mut().set_branch_full(i3, false);
l3.data_mut().ptrs[i3] = l2_ptr;
let l3_ptr = if l3.data().tree_list_is_empty() {
unsafe { self.deallocate(l3.addr()) };
unsafe { self.deallocate(&mut FsCtx, l3.addr()) };
BlockPtr::default()
} else {
self.sync_block(l3)?
self.sync_block(&mut FsCtx, l3)?
};
self.header.tree = l3_ptr;
@@ -669,11 +679,11 @@ impl<'a, D: Disk> Transaction<'a, D> {
raw.data_mut().copy_from_slice(node.data());
// Write updates to newly allocated blocks
l0.data_mut().ptrs[i0] = self.sync_block(raw)?;
l1.data_mut().ptrs[i1] = self.sync_block(l0)?;
l2.data_mut().ptrs[i2] = self.sync_block(l1)?;
l3.data_mut().ptrs[i3] = self.sync_block(l2)?;
self.header.tree = self.sync_block(l3)?;
l0.data_mut().ptrs[i0] = self.sync_block(&mut FsCtx, raw)?;
l1.data_mut().ptrs[i1] = self.sync_block(&mut FsCtx, l0)?;
l2.data_mut().ptrs[i2] = self.sync_block(&mut FsCtx, l1)?;
l3.data_mut().ptrs[i3] = self.sync_block(&mut FsCtx, l2)?;
self.header.tree = self.sync_block(&mut FsCtx, l3)?;
self.header_changed = true;
}
@@ -834,7 +844,7 @@ impl<'a, D: Disk> Transaction<'a, D> {
unsafe {
let parent = self.read_tree(parent_ptr)?;
let node_block_data = BlockData::new(
self.allocate(BlockMeta::default())?,
self.allocate(&mut FsCtx, BlockMeta::default())?,
Node::new(
mode,
parent.data().uid(),
@@ -880,7 +890,7 @@ impl<'a, D: Disk> Transaction<'a, D> {
// Create the first DirList block
let dir = BlockData::<DirList>::empty(BlockAddr::default()).unwrap();
let dir_ptr = self.sync_block(dir)?;
let dir_ptr = self.sync_block(&mut parent, dir)?;
// Add the DirList directly to the parent directory
parent.data_mut().level0[1] = unsafe { dir_ptr.cast() };
@@ -929,7 +939,7 @@ impl<'a, D: Disk> Transaction<'a, D> {
let mut sibling =
BlockData::<HTreeNode<RecordRaw>>::empty(BlockAddr::default()).unwrap();
let _ = mem::replace(sibling.data_mut(), unallocated_sibling);
let sibling_block_ptr = self.sync_block(sibling)?;
let sibling_block_ptr = self.sync_block(&mut parent, sibling)?;
let sibling_htree_ptr = HTreePtr::new(sibling_htree_hash, sibling_block_ptr);
let sibling_record_ptr: HTreePtr<RecordRaw> = unsafe { sibling_htree_ptr.cast() };
@@ -938,7 +948,7 @@ impl<'a, D: Disk> Transaction<'a, D> {
.data()
.find_max_htree_hash()
.ok_or(Error::new(EIO))?;
let root_block_ptr = self.sync_block(htree_root)?;
let root_block_ptr = self.sync_block(&mut parent, htree_root)?;
let root_htree_ptr = HTreePtr::new(root_htree_hash, root_block_ptr);
let root_record_ptr: HTreePtr<RecordRaw> = unsafe { root_htree_ptr.cast() };
@@ -948,7 +958,7 @@ impl<'a, D: Disk> Transaction<'a, D> {
new_root.data_mut().ptrs[0] = sibling_record_ptr;
let unexpected_sibling = htree::add_inner_node(new_root.data_mut(), root_record_ptr)?;
assert!(unexpected_sibling.is_none());
let new_root_ptr = self.sync_block(new_root)?;
let new_root_ptr = self.sync_block(&mut parent, new_root)?;
// Add the parent node pointer, increase the level, and increase one block size per allocated block
parent.data_mut().level0[0] = BlockPtr::marker(htree_levels as u8 + 1);
@@ -957,7 +967,7 @@ impl<'a, D: Disk> Transaction<'a, D> {
parent.data_mut().set_size(size);
} else if htree_levels > 0 {
// Update the parent node with the new root pointer
let root_block_ptr = self.sync_block(htree_root)?;
let root_block_ptr = self.sync_block(&mut parent, htree_root)?;
parent.data_mut().level0[1] = unsafe { root_block_ptr.cast() };
} else {
// Update the parent with the DirList block, ignoring the fake htree_root
@@ -999,7 +1009,7 @@ impl<'a, D: Disk> Transaction<'a, D> {
let mut dir = self.read_block(dir_ptr)?;
let unallocated_sibling =
htree::add_dir_entry(dir.data_mut(), &mut htree_ptr.htree_hash, dir_entry)?;
let dir_record_ptr = unsafe { self.sync_block(dir)?.cast() };
let dir_record_ptr = unsafe { self.sync_block(parent_dir_node, dir)?.cast() };
parent_htree_node.ptrs[htree_ptr_idx] =
HTreePtr::new(htree_ptr.htree_hash, dir_record_ptr);
@@ -1007,7 +1017,7 @@ impl<'a, D: Disk> Transaction<'a, D> {
// The DirList block was split, so we need to add it to the h-tree
let mut dir = BlockData::<DirList>::empty(BlockAddr::default()).unwrap();
let _ = mem::replace(dir.data_mut(), new_unallocated_dir);
let dir_ptr = self.sync_block(dir)?;
let dir_ptr = self.sync_block(parent_dir_node, dir)?;
let dir_htree_ptr = HTreePtr::new(new_hash, dir_ptr);
let dir_record_ptr: HTreePtr<RecordRaw> = unsafe { dir_htree_ptr.cast() };
let size = parent_dir_node.data().size() + record_byte_size;
@@ -1032,7 +1042,7 @@ impl<'a, D: Disk> Transaction<'a, D> {
// Write the muteated H-tree block back to disk and update the parent node's pointer
let htree_hash = htree_block.data().find_max_htree_hash().unwrap();
let htree_block_ptr = self.sync_block(htree_block)?;
let htree_block_ptr = self.sync_block(parent_dir_node, htree_block)?;
let htree_record_ptr: BlockPtr<RecordRaw> = unsafe { htree_block_ptr.cast() };
parent_htree_node.ptrs[htree_ptr_idx] = HTreePtr::new(htree_hash, htree_record_ptr);
@@ -1041,7 +1051,7 @@ impl<'a, D: Disk> Transaction<'a, D> {
let mut sibling =
BlockData::<HTreeNode<RecordRaw>>::empty(BlockAddr::default()).unwrap();
let _ = mem::replace(sibling.data_mut(), new_unallocated_sibling);
let sibling_ptr = self.sync_block(sibling)?;
let sibling_ptr = self.sync_block(parent_dir_node, sibling)?;
let sibling_htree_ptr = HTreePtr::new(new_hash, sibling_ptr);
let sibling_record_ptr: HTreePtr<RecordRaw> = unsafe { sibling_htree_ptr.cast() };
let size = parent_dir_node.data().size() + record_byte_size;
@@ -1145,7 +1155,7 @@ impl<'a, D: Disk> Transaction<'a, D> {
// Dealocate the htree_root only if it was a real root node in the H-tree
if htree_levels > 0 {
unsafe {
self.deallocate(htree_root.addr());
self.deallocate(&mut parent, htree_root.addr());
}
let record_byte_size = parent.data().record_level().bytes();
let size = parent.data().size() - record_byte_size;
@@ -1155,7 +1165,7 @@ impl<'a, D: Disk> Transaction<'a, D> {
parent.data_mut().level0[1] = BlockPtr::default();
} else if htree_levels > 0 {
// Update the real htree_root and update the ptr in the parent
let htree_root_block_ptr = self.sync_block(htree_root)?;
let htree_root_block_ptr = self.sync_block(&mut parent, htree_root)?;
parent.data_mut().level0[1] = unsafe { htree_root_block_ptr.cast() };
} else {
// The htree_root is fake, so update the parent with the ptr to the one and only directory list
@@ -1167,7 +1177,7 @@ impl<'a, D: Disk> Transaction<'a, D> {
self.sync_tree(parent)?;
self.remove_tree(node.ptr())?;
unsafe {
self.deallocate(node_addr);
self.deallocate(&mut FsCtx, node_addr);
}
Ok(Some(node_id))
@@ -1216,14 +1226,14 @@ impl<'a, D: Disk> Transaction<'a, D> {
if let Some(new_tree_hash) = new_htree_hash {
// The entry_ptr needs to be updated in the parent_htree_node
let dir_block_ptr = self.sync_block(dir_list)?;
let dir_block_ptr = self.sync_block(parent_dir_node, dir_list)?;
let dir_record_ptr: BlockPtr<RecordRaw> = unsafe { dir_block_ptr.cast() };
parent_htree_node.ptrs[entry_idx] =
HTreePtr::new(new_tree_hash, dir_record_ptr);
} else {
// The entry needs to be removed from the parent_htree_noce
parent_htree_node.ptrs[entry_idx] = HTreePtr::default();
unsafe { self.deallocate(dir_list.addr()) };
unsafe { self.deallocate(parent_dir_node, dir_list.addr()) };
let size = parent_dir_node.data().size() - record_byte_size;
parent_dir_node.data_mut().set_size(size);
}
@@ -1256,14 +1266,14 @@ impl<'a, D: Disk> Transaction<'a, D> {
if let Some(new_htree_hash) = htree_node.data().find_max_htree_hash() {
// The entry_ptr needs to be updated in the parent_htree_node
let htree_block_ptr = self.sync_block(htree_node)?;
let htree_block_ptr = self.sync_block(parent_dir_node, htree_node)?;
let htree_record_ptr: BlockPtr<RecordRaw> = unsafe { htree_block_ptr.cast() };
parent_htree_node.ptrs[entry_idx] =
HTreePtr::new(new_htree_hash, htree_record_ptr);
} else {
// The htree_node is now empty, so remove it
parent_htree_node.ptrs[entry_idx] = HTreePtr::default();
unsafe { self.deallocate(htree_node.addr()) };
unsafe { self.deallocate(parent_dir_node, htree_node.addr()) };
let size = parent_dir_node.data().size() - record_byte_size;
parent_dir_node.data_mut().set_size(size);
}
@@ -1374,54 +1384,54 @@ impl<'a, D: Disk> Transaction<'a, D> {
match NodeLevel::new(record_offset).ok_or(Error::new(ERANGE))? {
NodeLevel::L0(i0) => {
let ptr = node.data_mut().level0[i0].clear();
self.node_deallocate_block(node, ptr);
self.deallocate_block(node, ptr);
}
NodeLevel::L1(i1, i0) => {
let mut l0 = self.read_block_or_empty(node.data().level1[i1])?;
self.node_deallocate_block(node, l0.data_mut().ptrs[i0].clear());
self.deallocate_block(node, l0.data_mut().ptrs[i0].clear());
if l0.data().is_empty() {
let ptr = node.data_mut().level1[i1].clear();
self.node_deallocate_block(node, ptr);
self.deallocate_block(node, ptr);
} else {
node.data_mut().level1[i1] = self.sync_block(l0)?;
node.data_mut().level1[i1] = self.sync_block(node, l0)?;
}
}
NodeLevel::L2(i2, i1, i0) => {
let mut l1 = self.read_block_or_empty(node.data().level2[i2])?;
let mut l0 = self.read_block_or_empty(l1.data().ptrs[i1])?;
self.node_deallocate_block(node, l0.data_mut().ptrs[i0].clear());
self.deallocate_block(node, l0.data_mut().ptrs[i0].clear());
if l0.data().is_empty() {
self.node_deallocate_block(node, l1.data_mut().ptrs[i1].clear());
self.deallocate_block(node, l1.data_mut().ptrs[i1].clear());
} else {
l1.data_mut().ptrs[i1] = self.sync_block(l0)?;
l1.data_mut().ptrs[i1] = self.sync_block(node, l0)?;
}
if l1.data().is_empty() {
let ptr = node.data_mut().level2[i2].clear();
self.node_deallocate_block(node, ptr);
self.deallocate_block(node, ptr);
} else {
node.data_mut().level2[i2] = self.sync_block(l1)?;
node.data_mut().level2[i2] = self.sync_block(node, l1)?;
}
}
NodeLevel::L3(i3, i2, i1, i0) => {
let mut l2 = self.read_block_or_empty(node.data().level3[i3])?;
let mut l1 = self.read_block_or_empty(l2.data().ptrs[i2])?;
let mut l0 = self.read_block_or_empty(l1.data().ptrs[i1])?;
self.node_deallocate_block(node, l0.data_mut().ptrs[i0].clear());
self.deallocate_block(node, l0.data_mut().ptrs[i0].clear());
if l0.data().is_empty() {
self.node_deallocate_block(node, l1.data_mut().ptrs[i1].clear());
self.deallocate_block(node, l1.data_mut().ptrs[i1].clear());
} else {
l1.data_mut().ptrs[i1] = self.sync_block(l0)?;
l1.data_mut().ptrs[i1] = self.sync_block(node, l0)?;
}
if l1.data().is_empty() {
self.node_deallocate_block(node, l2.data_mut().ptrs[i2].clear());
self.deallocate_block(node, l2.data_mut().ptrs[i2].clear());
} else {
l2.data_mut().ptrs[i2] = self.sync_block(l1)?;
l2.data_mut().ptrs[i2] = self.sync_block(node, l1)?;
}
if l2.data().is_empty() {
let ptr = node.data_mut().level3[i3].clear();
self.node_deallocate_block(node, ptr);
self.deallocate_block(node, ptr);
} else {
node.data_mut().level3[i3] = self.sync_block(l2)?;
node.data_mut().level3[i3] = self.sync_block(node, l2)?;
}
}
NodeLevel::L4(i4, i3, i2, i1, i0) => {
@@ -1429,27 +1439,27 @@ impl<'a, D: Disk> Transaction<'a, D> {
let mut l2 = self.read_block_or_empty(l3.data().ptrs[i3])?;
let mut l1 = self.read_block_or_empty(l2.data().ptrs[i2])?;
let mut l0 = self.read_block_or_empty(l1.data().ptrs[i1])?;
self.node_deallocate_block(node, l0.data_mut().ptrs[i0].clear());
self.deallocate_block(node, l0.data_mut().ptrs[i0].clear());
if l0.data().is_empty() {
self.node_deallocate_block(node, l1.data_mut().ptrs[i1].clear());
self.deallocate_block(node, l1.data_mut().ptrs[i1].clear());
} else {
l1.data_mut().ptrs[i1] = self.sync_block(l0)?;
l1.data_mut().ptrs[i1] = self.sync_block(node, l0)?;
}
if l1.data().is_empty() {
self.node_deallocate_block(node, l2.data_mut().ptrs[i2].clear());
self.deallocate_block(node, l2.data_mut().ptrs[i2].clear());
} else {
l2.data_mut().ptrs[i2] = self.sync_block(l1)?;
l2.data_mut().ptrs[i2] = self.sync_block(node, l1)?;
}
if l2.data().is_empty() {
self.node_deallocate_block(node, l3.data_mut().ptrs[i3].clear());
self.deallocate_block(node, l3.data_mut().ptrs[i3].clear());
} else {
l3.data_mut().ptrs[i3] = self.sync_block(l2)?;
l3.data_mut().ptrs[i3] = self.sync_block(node, l2)?;
}
if l3.data().is_empty() {
let ptr = node.data_mut().level4[i4].clear();
self.node_deallocate_block(node, ptr);
self.deallocate_block(node, ptr);
} else {
node.data_mut().level4[i4] = self.sync_block(l3)?;
node.data_mut().level4[i4] = self.sync_block(node, l3)?;
}
}
}
@@ -1474,15 +1484,15 @@ impl<'a, D: Disk> Transaction<'a, D> {
let mut l0 = self.read_block_or_empty(node.data().level1[i1])?;
l0.data_mut().ptrs[i0] = ptr;
node.data_mut().level1[i1] = self.sync_block(l0)?;
node.data_mut().level1[i1] = self.sync_block(node, l0)?;
}
NodeLevel::L2(i2, i1, i0) => {
let mut l1 = self.read_block_or_empty(node.data().level2[i2])?;
let mut l0 = self.read_block_or_empty(l1.data().ptrs[i1])?;
l0.data_mut().ptrs[i0] = ptr;
l1.data_mut().ptrs[i1] = self.sync_block(l0)?;
node.data_mut().level2[i2] = self.sync_block(l1)?;
l1.data_mut().ptrs[i1] = self.sync_block(node, l0)?;
node.data_mut().level2[i2] = self.sync_block(node, l1)?;
}
NodeLevel::L3(i3, i2, i1, i0) => {
let mut l2 = self.read_block_or_empty(node.data().level3[i3])?;
@@ -1490,9 +1500,9 @@ impl<'a, D: Disk> Transaction<'a, D> {
let mut l0 = self.read_block_or_empty(l1.data().ptrs[i1])?;
l0.data_mut().ptrs[i0] = ptr;
l1.data_mut().ptrs[i1] = self.sync_block(l0)?;
l2.data_mut().ptrs[i2] = self.sync_block(l1)?;
node.data_mut().level3[i3] = self.sync_block(l2)?;
l1.data_mut().ptrs[i1] = self.sync_block(node, l0)?;
l2.data_mut().ptrs[i2] = self.sync_block(node, l1)?;
node.data_mut().level3[i3] = self.sync_block(node, l2)?;
}
NodeLevel::L4(i4, i3, i2, i1, i0) => {
let mut l3 = self.read_block_or_empty(node.data().level4[i4])?;
@@ -1501,10 +1511,10 @@ impl<'a, D: Disk> Transaction<'a, D> {
let mut l0 = self.read_block_or_empty(l1.data().ptrs[i1])?;
l0.data_mut().ptrs[i0] = ptr;
l1.data_mut().ptrs[i1] = self.sync_block(l0)?;
l2.data_mut().ptrs[i2] = self.sync_block(l1)?;
l3.data_mut().ptrs[i3] = self.sync_block(l2)?;
node.data_mut().level4[i4] = self.sync_block(l3)?;
l1.data_mut().ptrs[i1] = self.sync_block(node, l0)?;
l2.data_mut().ptrs[i2] = self.sync_block(node, l1)?;
l3.data_mut().ptrs[i3] = self.sync_block(node, l2)?;
node.data_mut().level4[i4] = self.sync_block(node, l3)?;
}
}
}
@@ -1717,7 +1727,7 @@ impl<'a, D: Disk> Transaction<'a, D> {
}
// CoW record using its current level
let new_addr = unsafe { self.node_allocate(node, record.addr().meta())? };
let new_addr = unsafe { self.allocate(node, record.addr().meta())? };
let mut old_addr = record.swap_addr(new_addr);
// If the record was resized we need to dealloc the original ptr
@@ -1734,8 +1744,10 @@ impl<'a, D: Disk> Transaction<'a, D> {
node_changed = true;
// Deallocate old record
unsafe {
self.node_deallocate(node, old_addr);
if !old_addr.is_null() {
unsafe {
self.deallocate(node, old_addr);
}
}
}