Support inline data in files
This commit is contained in:
+1
-1
@@ -36,7 +36,7 @@ pub use self::header::{Header, HEADER_RING};
|
||||
pub use self::key::{Key, KeySlot, Salt};
|
||||
#[cfg(feature = "std")]
|
||||
pub use self::mount::mount;
|
||||
pub use self::node::{Node, NodeLevel, NodeLevelData};
|
||||
pub use self::node::{Node, NodeFlags, NodeLevel, NodeLevelData};
|
||||
pub use self::record::RecordRaw;
|
||||
pub use self::transaction::Transaction;
|
||||
pub use self::tree::{Tree, TreeData, TreeList, TreePtr};
|
||||
|
||||
+10
-2
@@ -181,8 +181,8 @@ pub struct Node {
|
||||
/// Padding
|
||||
pub padding: [u8; BLOCK_SIZE as usize - 4042],
|
||||
|
||||
/// Level data, kept private so inline data can be supported
|
||||
level_data: NodeLevelData,
|
||||
/// Level data, should not be used directly so inline data can be supported
|
||||
pub(crate) level_data: NodeLevelData,
|
||||
}
|
||||
|
||||
unsafe impl BlockTrait for Node {
|
||||
@@ -253,6 +253,14 @@ impl Node {
|
||||
0
|
||||
}
|
||||
.into(),
|
||||
flags: if mode & Self::MODE_TYPE == Self::MODE_DIR {
|
||||
// Directories must not use inline data (until h-tree supports it)
|
||||
NodeFlags::empty()
|
||||
} else {
|
||||
NodeFlags::INLINE_DATA
|
||||
}
|
||||
.bits()
|
||||
.into(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
+72
-7
@@ -15,17 +15,25 @@ use syscall::error::{
|
||||
use crate::{
|
||||
htree::{self, HTreeHash, HTreeNode, HTreePtr},
|
||||
AllocEntry, AllocList, Allocator, BlockAddr, BlockData, BlockLevel, BlockMeta, BlockPtr,
|
||||
BlockTrait, DirEntry, DirList, Disk, FileSystem, Header, Node, NodeLevel, NodeLevelData,
|
||||
RecordRaw, TreeData, TreePtr, ALLOC_GC_THRESHOLD, ALLOC_LIST_ENTRIES, DIR_ENTRY_MAX_LENGTH,
|
||||
HEADER_RING,
|
||||
BlockTrait, DirEntry, DirList, Disk, FileSystem, Header, Node, NodeFlags, NodeLevel,
|
||||
NodeLevelData, RecordRaw, TreeData, TreePtr, ALLOC_GC_THRESHOLD, ALLOC_LIST_ENTRIES,
|
||||
DIR_ENTRY_MAX_LENGTH, HEADER_RING,
|
||||
};
|
||||
|
||||
pub(crate) fn level_data(node: &TreeData<Node>) -> Result<&NodeLevelData> {
|
||||
node.data().level_data().ok_or(Error::new(EIO))
|
||||
node.data().level_data().ok_or_else(|| {
|
||||
#[cfg(feature = "log")]
|
||||
log::error!("LEVEL_DATA: NODE HAS INLINE DATA");
|
||||
Error::new(EIO)
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn level_data_mut(node: &mut TreeData<Node>) -> Result<&mut NodeLevelData> {
|
||||
node.data_mut().level_data_mut().ok_or(Error::new(EIO))
|
||||
node.data_mut().level_data_mut().ok_or_else(|| {
|
||||
#[cfg(feature = "log")]
|
||||
log::error!("LEVEL_DATA_MUT: NODE HAS INLINE DATA");
|
||||
Error::new(EIO)
|
||||
})
|
||||
}
|
||||
|
||||
pub trait AllocCtx {
|
||||
@@ -1538,6 +1546,20 @@ impl<'a, D: Disk> Transaction<'a, D> {
|
||||
buf: &mut [u8],
|
||||
) -> Result<usize> {
|
||||
let node_size = node.data().size();
|
||||
|
||||
// Try reading from inline data
|
||||
if let Some(inline_data) = node.data().inline_data() {
|
||||
if offset >= node_size {
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
let end = min(node_size, offset + (buf.len() as u64));
|
||||
let len = end - offset;
|
||||
buf[..len as usize].copy_from_slice(&inline_data[offset as usize..end as usize]);
|
||||
offset += len;
|
||||
return Ok(len as usize);
|
||||
}
|
||||
|
||||
let record_level = node.data().record_level();
|
||||
|
||||
let mut bytes_read = 0;
|
||||
@@ -1631,7 +1653,7 @@ impl<'a, D: Disk> Transaction<'a, D> {
|
||||
self.write_node_inner(node, &mut offset, &zeroes[start as usize..end as usize])?;
|
||||
}
|
||||
assert_eq!(offset, size);
|
||||
} else {
|
||||
} else if !node.data().has_inline_data() {
|
||||
// Deallocate records
|
||||
for record in
|
||||
(size.div_ceil(record_level.bytes())..old_size / record_level.bytes()).rev()
|
||||
@@ -1670,7 +1692,7 @@ impl<'a, D: Disk> Transaction<'a, D> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn write_node_inner(
|
||||
fn write_node_inner_records(
|
||||
&mut self,
|
||||
node: &mut TreeData<Node>,
|
||||
offset: &mut u64,
|
||||
@@ -1772,6 +1794,49 @@ impl<'a, D: Disk> Transaction<'a, D> {
|
||||
Ok(node_changed)
|
||||
}
|
||||
|
||||
pub fn write_node_inner(
|
||||
&mut self,
|
||||
node: &mut TreeData<Node>,
|
||||
offset: &mut u64,
|
||||
buf: &[u8],
|
||||
) -> Result<bool> {
|
||||
let mut node_changed = false;
|
||||
|
||||
// Try writing to inline data
|
||||
let node_size = node.data().size();
|
||||
let convert_inline = if let Some(inline_data) = node.data_mut().inline_data_mut() {
|
||||
let end = *offset + (buf.len() as u64);
|
||||
if end < inline_data.len() as u64 {
|
||||
inline_data[*offset as usize..end as usize].copy_from_slice(buf);
|
||||
*offset += buf.len() as u64;
|
||||
if node.data().size() < *offset {
|
||||
node.data_mut().set_size(*offset);
|
||||
}
|
||||
return Ok(true);
|
||||
} else {
|
||||
Some(inline_data[..node_size as usize].to_vec())
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if let Some(inline_data) = convert_inline {
|
||||
// If inline data cannot fit, convert to records
|
||||
let mut flags = node.data().flags();
|
||||
flags.remove(NodeFlags::INLINE_DATA);
|
||||
node.data_mut().set_flags(flags);
|
||||
node.data_mut().level_data = NodeLevelData::default();
|
||||
self.write_node_inner_records(node, &mut 0, &inline_data)?;
|
||||
node_changed = true;
|
||||
}
|
||||
|
||||
if self.write_node_inner_records(node, offset, buf)? {
|
||||
node_changed = true;
|
||||
}
|
||||
|
||||
Ok(node_changed)
|
||||
}
|
||||
|
||||
/// Write the bytes at `buf` to `node` starting at `offset`.
|
||||
pub fn write_node(
|
||||
&mut self,
|
||||
|
||||
Reference in New Issue
Block a user