Provide context for all allocations and deallocations
This commit is contained in:
+120
-108
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user