From 22b04ceae47cd7939acd162d48c8d970f40f211a Mon Sep 17 00:00:00 2001 From: Shaowei Song Date: Sat, 14 Sep 2024 07:15:28 +0000 Subject: [PATCH] Optimize the `DirEntry` of `RamInode` --- kernel/src/fs/ramfs/fs.rs | 57 ++++++++++++++++++++++++++------------ kernel/src/fs/utils/mod.rs | 17 ++++++++++++ 2 files changed, 57 insertions(+), 17 deletions(-) diff --git a/kernel/src/fs/ramfs/fs.rs b/kernel/src/fs/ramfs/fs.rs index 6e04e0d84..841506624 100644 --- a/kernel/src/fs/ramfs/fs.rs +++ b/kernel/src/fs/ramfs/fs.rs @@ -8,6 +8,7 @@ use core::{ use aster_block::bio::BioWaiter; use aster_rights::Full; use aster_util::slot_vec::SlotVec; +use hashbrown::HashMap; use ostd::{ mm::{Frame, VmIo}, sync::RwMutexWriteGuard, @@ -242,13 +243,13 @@ impl InodeMeta { pub fn new_dir(mode: InodeMode, uid: Uid, gid: Gid) -> Self { let now = now(); Self { - size: 2, + size: NUM_SPECIAL_ENTRIES, blocks: 1, atime: now, mtime: now, ctime: now, mode, - nlinks: 2, + nlinks: NUM_SPECIAL_ENTRIES, uid, gid, } @@ -316,16 +317,22 @@ impl Inner { } } +/// Represents a directory entry within a `RamInode`. struct DirEntry { children: SlotVec<(CStr256, Arc)>, + idx_map: HashMap, // Used to accelerate indexing in `children` this: Weak, parent: Weak, } +// Every directory has two special entries: "." and "..". +const NUM_SPECIAL_ENTRIES: usize = 2; + impl DirEntry { fn new(this: Weak, parent: Weak) -> Self { Self { children: SlotVec::new(), + idx_map: HashMap::new(), this, parent, } @@ -339,9 +346,7 @@ impl DirEntry { if name == "." || name == ".." { true } else { - self.children - .iter() - .any(|(child, _)| child.as_str().unwrap() == name) + self.idx_map.contains_key(name.as_bytes()) } } @@ -351,20 +356,31 @@ impl DirEntry { } else if name == ".." { Some((1, self.parent.upgrade().unwrap())) } else { - self.children - .idxes_and_items() - .find(|(_, (child, _))| child.as_str().unwrap() == name) - .map(|(idx, (_, inode))| (idx + 2, inode.clone())) + let idx = *self.idx_map.get(name.as_bytes())?; + let target_inode = self + .children + .get(idx) + .map(|(name_cstr256, inode)| { + debug_assert_eq!(name, name_cstr256.as_str().unwrap()); + inode.clone() + }) + .unwrap(); + Some((idx + NUM_SPECIAL_ENTRIES, target_inode)) } } fn append_entry(&mut self, name: &str, inode: Arc) -> usize { - self.children.put((CStr256::from(name), inode)) + let name = CStr256::from(name); + let idx = self.children.put((name, inode)); + self.idx_map.insert(name, idx); + idx } fn remove_entry(&mut self, idx: usize) -> Option<(CStr256, Arc)> { - assert!(idx >= 2); - self.children.remove(idx - 2) + assert!(idx >= NUM_SPECIAL_ENTRIES); + let removed = self.children.remove(idx - NUM_SPECIAL_ENTRIES)?; + self.idx_map.remove(&removed.0); + Some(removed) } fn substitute_entry( @@ -372,8 +388,15 @@ impl DirEntry { idx: usize, new_entry: (CStr256, Arc), ) -> Option<(CStr256, Arc)> { - assert!(idx >= 2); - self.children.put_at(idx - 2, new_entry) + assert!(idx >= NUM_SPECIAL_ENTRIES); + let new_name = new_entry.0; + let idx_children = idx - NUM_SPECIAL_ENTRIES; + + let substitute = self.children.put_at(idx_children, new_entry)?; + let removed = self.idx_map.remove(&substitute.0); + debug_assert_eq!(removed.unwrap(), idx_children); + self.idx_map.insert(new_name, idx_children); + Some(substitute) } fn visit_entry(&self, idx: usize, visitor: &mut dyn DirentVisitor) -> Result { @@ -391,12 +414,12 @@ impl DirEntry { } // Read the normal child entries. let start_idx = *idx; - for (offset, (name, child)) in self + for (offset_children, (name, child)) in self .children .idxes_and_items() - .map(|(offset, (name, child))| (offset + 2, (name, child))) - .skip_while(|(offset, _)| offset < &start_idx) + .skip_while(|(offset, _)| offset + NUM_SPECIAL_ENTRIES < start_idx) { + let offset = offset_children + NUM_SPECIAL_ENTRIES; visitor.visit(name.as_str().unwrap(), child.ino, child.typ, offset)?; *idx = offset + 1; } diff --git a/kernel/src/fs/utils/mod.rs b/kernel/src/fs/utils/mod.rs index 86a72eaf5..0c961edbc 100644 --- a/kernel/src/fs/utils/mod.rs +++ b/kernel/src/fs/utils/mod.rs @@ -36,6 +36,11 @@ mod random_test; mod range_lock; mod status_flags; +use core::{ + borrow::Borrow, + hash::{Hash, Hasher}, +}; + use crate::prelude::*; #[derive(Copy, PartialEq, Eq, Clone, Debug)] @@ -188,6 +193,18 @@ impl<'a, const N: usize> From<&'a str> for FixedStr { } } +impl Borrow<[u8]> for FixedCStr { + fn borrow(&self) -> &[u8] { + self.as_bytes() + } +} + +impl Hash for FixedCStr { + fn hash(&self, state: &mut H) { + self.as_bytes().hash(state); + } +} + impl Default for FixedStr { fn default() -> Self { Self([0u8; N])