From fd125947c9db0b33761414e65e919f73d9bf1815 Mon Sep 17 00:00:00 2001 From: Chuyan Zhang Date: Thu, 30 Nov 2023 12:01:11 -0800 Subject: Refactor workspace --- ayafs-core/src/memory/cached_block.rs | 180 ++++++++++++++++++++++++++++++++++ 1 file changed, 180 insertions(+) create mode 100644 ayafs-core/src/memory/cached_block.rs (limited to 'ayafs-core/src/memory/cached_block.rs') diff --git a/ayafs-core/src/memory/cached_block.rs b/ayafs-core/src/memory/cached_block.rs new file mode 100644 index 0000000..c3d0338 --- /dev/null +++ b/ayafs-core/src/memory/cached_block.rs @@ -0,0 +1,180 @@ +use crate::block_device::{BlockDevice, BLOCK_SIZE}; +use crate::disk::block::Block; +use crate::AyaFS; +use lru::LruCache; +use std::num::NonZeroUsize; +use std::sync::Arc; + +#[derive(Clone)] +pub struct CachedBlock { + pub block: T, + pub index: usize, + pub dirty: bool, +} + +pub fn convert_mut(input_block: &mut CachedBlock) -> &mut CachedBlock { + let ptr = input_block as *const CachedBlock as *mut u8; + let block = ptr.cast::>(); + unsafe { &mut *block } +} + +pub fn convert(input_block: &CachedBlock) -> &CachedBlock { + let ptr = input_block as *const CachedBlock as *mut u8; + let block = ptr.cast::>(); + unsafe { &*block } +} + +pub(crate) struct BlockCache { + device: Arc, + cache: LruCache>, +} + +impl BlockCache { + pub(crate) fn new(device: Arc, cache_size: usize) -> Self { + Self { + device, + cache: LruCache::new(NonZeroUsize::new(cache_size).unwrap()), + } + } + + pub(crate) fn load_block(&mut self, index: usize) -> bool { + if self.cache.contains(&index) == false { + let mut buffer = [0u8; BLOCK_SIZE]; + self.device.read(index, &mut buffer); + let block: T = unsafe { std::mem::transmute_copy(&buffer) }; + let cached_block = CachedBlock { + block, + index, + dirty: false, + }; + if let Some((old_index, old_block)) = self.cache.push(index, cached_block) { + assert_ne!(old_index, index); // 只有 block 不在 cache 里的时候才会插入 + if old_block.dirty { + let old_block_ptr = &old_block.block as *const T as *mut u8; + let old_block_buffer = + unsafe { std::slice::from_raw_parts(old_block_ptr, BLOCK_SIZE) }; + self.device.write(old_index, old_block_buffer); + } + } + } + true + } + + /// 从 LRU cache 里获取一个 block 的引用, 如果没有在 cache 中会加载. + /// 这个函数不应该返回 None + pub(crate) fn get_block(&mut self, index: usize) -> Option<&CachedBlock> { + if !self.cache.contains(&index) { + self.load_block(index); + } + self.cache.get(&index).map(convert::) + } + + /// 从 LRU cache 里获取一个 block 的可变引用, 如果没有在 cache 中会加载. + /// 这个函数不应该返回 None + pub(crate) fn get_block_mut(&mut self, index: usize) -> Option<&mut CachedBlock> { + if !self.cache.contains(&index) { + self.load_block(index); + } + self.cache.get_mut(&index).map(|block| { + block.dirty = true; + convert_mut::(block) + }) + } + + /// 向 LRU cache 中插入一个全新初始化的 block + /// 这个 block 全 0, 而且是 dirty 的, 即使被挤出去也会触发一次落盘 + pub(crate) fn init_block(&mut self, index: usize) { + let allocated_block = CachedBlock { + block: T::default(), + index, + dirty: true, + }; + if let Some((old_index, old_block)) = self.cache.push(index, allocated_block) { + if old_block.dirty { + let old_block_ptr = &old_block.block as *const T as *mut u8; + let old_block_buffer = + unsafe { std::slice::from_raw_parts(old_block_ptr, BLOCK_SIZE) }; + self.device.write(old_index, old_block_buffer); + } + } + } + + #[allow(unused)] + /// 从 LRU cache 中读取一个 block 的引用, *不会* 影响 LRU cache 的结构, 如果没有在 cache 中不会加载. + pub(crate) fn peek_block(&self, index: usize) -> Option<&CachedBlock> { + self.cache.peek(&index).map(convert::) + } + + #[allow(unused)] + /// 从 LRU cache 中读取一个 block 的可变引用, *不会* 影响 LRU cache 的结构, 如果没有在 cache 中不会加载. + pub(crate) fn peek_block_mut(&mut self, index: usize) -> Option<&mut CachedBlock> { + self.cache.peek_mut(&index).map(convert_mut::) + } + + pub(crate) fn update_block(&mut self, block: CachedBlock) -> bool { + if self.cache.contains(&block.index) { + let mut data_block = convert::(&block).clone(); + data_block.dirty = true; // TODO 需要把显式写回的都标记为 dirty 吗 + self.cache.push(block.index, data_block); + true + } else { + false + } + } + + fn pop(&mut self, entry: &usize) -> Option> { + self.cache.pop(entry) + } +} + +impl AyaFS { + pub(crate) fn init_block(&mut self, index: usize) { + self.cached_blocks.init_block(index); + } + + pub(crate) fn get_block(&mut self, index: usize) -> Option<&CachedBlock> { + if self.data_bitmap.query(index) { + Some(self.cached_blocks.get_block::(index).unwrap()) + } else { + self.cached_blocks.pop(&index); + None + } + // self.data_bitmap + // .query(index) + // .then(|| self.cached_blocks.get_block::(index).unwrap()) + // 返回 None 当且仅当 data_bitmap 中这个 block 为 invalid + } + + pub(crate) fn get_block_mut(&mut self, index: usize) -> Option<&mut CachedBlock> { + if self.data_bitmap.query(index) { + Some(self.cached_blocks.get_block_mut::(index).unwrap()) + } else { + self.cached_blocks.pop(&index); + None + } + // self.data_bitmap + // .query(index) + // .then(|| self.cached_blocks.get_block_mut::(index).unwrap()) + // 返回 None 当且仅当 data_bitmap 中这个 block 为 invalid + } + + #[allow(unused)] + pub(crate) fn peek_block(&self, index: usize) -> Option<&CachedBlock> { + self.data_bitmap + .query(index) + .then(|| self.cached_blocks.peek_block::(index).unwrap()) + // 返回 None 当且仅当 data_bitmap 中这个 block 为 invalid + } + + #[allow(unused)] + pub(crate) fn peek_block_mut(&mut self, index: usize) -> Option<&mut CachedBlock> { + self.data_bitmap + .query(index) + .then(|| self.cached_blocks.peek_block_mut::(index).unwrap()) + // 返回 None 当且仅当 data_bitmap 中这个 block 为 invalid + } + + pub(crate) fn update_block(&mut self, block: CachedBlock) -> bool { + self.cached_blocks.update_block(block) + } +} -- cgit v1.2.3-70-g09d2