Optimize the DirEntry of RamInode

This commit is contained in:
Shaowei Song 2024-09-14 07:15:28 +00:00 committed by Tate, Hongliang Tian
parent f194514100
commit 22b04ceae4
2 changed files with 57 additions and 17 deletions

View File

@ -8,6 +8,7 @@ use core::{
use aster_block::bio::BioWaiter; use aster_block::bio::BioWaiter;
use aster_rights::Full; use aster_rights::Full;
use aster_util::slot_vec::SlotVec; use aster_util::slot_vec::SlotVec;
use hashbrown::HashMap;
use ostd::{ use ostd::{
mm::{Frame, VmIo}, mm::{Frame, VmIo},
sync::RwMutexWriteGuard, sync::RwMutexWriteGuard,
@ -242,13 +243,13 @@ impl InodeMeta {
pub fn new_dir(mode: InodeMode, uid: Uid, gid: Gid) -> Self { pub fn new_dir(mode: InodeMode, uid: Uid, gid: Gid) -> Self {
let now = now(); let now = now();
Self { Self {
size: 2, size: NUM_SPECIAL_ENTRIES,
blocks: 1, blocks: 1,
atime: now, atime: now,
mtime: now, mtime: now,
ctime: now, ctime: now,
mode, mode,
nlinks: 2, nlinks: NUM_SPECIAL_ENTRIES,
uid, uid,
gid, gid,
} }
@ -316,16 +317,22 @@ impl Inner {
} }
} }
/// Represents a directory entry within a `RamInode`.
struct DirEntry { struct DirEntry {
children: SlotVec<(CStr256, Arc<RamInode>)>, children: SlotVec<(CStr256, Arc<RamInode>)>,
idx_map: HashMap<CStr256, usize>, // Used to accelerate indexing in `children`
this: Weak<RamInode>, this: Weak<RamInode>,
parent: Weak<RamInode>, parent: Weak<RamInode>,
} }
// Every directory has two special entries: "." and "..".
const NUM_SPECIAL_ENTRIES: usize = 2;
impl DirEntry { impl DirEntry {
fn new(this: Weak<RamInode>, parent: Weak<RamInode>) -> Self { fn new(this: Weak<RamInode>, parent: Weak<RamInode>) -> Self {
Self { Self {
children: SlotVec::new(), children: SlotVec::new(),
idx_map: HashMap::new(),
this, this,
parent, parent,
} }
@ -339,9 +346,7 @@ impl DirEntry {
if name == "." || name == ".." { if name == "." || name == ".." {
true true
} else { } else {
self.children self.idx_map.contains_key(name.as_bytes())
.iter()
.any(|(child, _)| child.as_str().unwrap() == name)
} }
} }
@ -351,20 +356,31 @@ impl DirEntry {
} else if name == ".." { } else if name == ".." {
Some((1, self.parent.upgrade().unwrap())) Some((1, self.parent.upgrade().unwrap()))
} else { } else {
self.children let idx = *self.idx_map.get(name.as_bytes())?;
.idxes_and_items() let target_inode = self
.find(|(_, (child, _))| child.as_str().unwrap() == name) .children
.map(|(idx, (_, inode))| (idx + 2, inode.clone())) .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<RamInode>) -> usize { fn append_entry(&mut self, name: &str, inode: Arc<RamInode>) -> 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<RamInode>)> { fn remove_entry(&mut self, idx: usize) -> Option<(CStr256, Arc<RamInode>)> {
assert!(idx >= 2); assert!(idx >= NUM_SPECIAL_ENTRIES);
self.children.remove(idx - 2) let removed = self.children.remove(idx - NUM_SPECIAL_ENTRIES)?;
self.idx_map.remove(&removed.0);
Some(removed)
} }
fn substitute_entry( fn substitute_entry(
@ -372,8 +388,15 @@ impl DirEntry {
idx: usize, idx: usize,
new_entry: (CStr256, Arc<RamInode>), new_entry: (CStr256, Arc<RamInode>),
) -> Option<(CStr256, Arc<RamInode>)> { ) -> Option<(CStr256, Arc<RamInode>)> {
assert!(idx >= 2); assert!(idx >= NUM_SPECIAL_ENTRIES);
self.children.put_at(idx - 2, new_entry) 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<usize> { fn visit_entry(&self, idx: usize, visitor: &mut dyn DirentVisitor) -> Result<usize> {
@ -391,12 +414,12 @@ impl DirEntry {
} }
// Read the normal child entries. // Read the normal child entries.
let start_idx = *idx; let start_idx = *idx;
for (offset, (name, child)) in self for (offset_children, (name, child)) in self
.children .children
.idxes_and_items() .idxes_and_items()
.map(|(offset, (name, child))| (offset + 2, (name, child))) .skip_while(|(offset, _)| offset + NUM_SPECIAL_ENTRIES < start_idx)
.skip_while(|(offset, _)| offset < &start_idx)
{ {
let offset = offset_children + NUM_SPECIAL_ENTRIES;
visitor.visit(name.as_str().unwrap(), child.ino, child.typ, offset)?; visitor.visit(name.as_str().unwrap(), child.ino, child.typ, offset)?;
*idx = offset + 1; *idx = offset + 1;
} }

View File

@ -36,6 +36,11 @@ mod random_test;
mod range_lock; mod range_lock;
mod status_flags; mod status_flags;
use core::{
borrow::Borrow,
hash::{Hash, Hasher},
};
use crate::prelude::*; use crate::prelude::*;
#[derive(Copy, PartialEq, Eq, Clone, Debug)] #[derive(Copy, PartialEq, Eq, Clone, Debug)]
@ -188,6 +193,18 @@ impl<'a, const N: usize> From<&'a str> for FixedStr<N> {
} }
} }
impl<const N: usize> Borrow<[u8]> for FixedCStr<N> {
fn borrow(&self) -> &[u8] {
self.as_bytes()
}
}
impl<const N: usize> Hash for FixedCStr<N> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.as_bytes().hash(state);
}
}
impl<const N: usize> Default for FixedStr<N> { impl<const N: usize> Default for FixedStr<N> {
fn default() -> Self { fn default() -> Self {
Self([0u8; N]) Self([0u8; N])