summaryrefslogtreecommitdiff
path: root/ayafs-core/src/memory/cached_block.rs
diff options
context:
space:
mode:
authorChuyan Zhang <me@zcy.moe>2023-11-30 12:01:11 -0800
committerChuyan Zhang <me@zcy.moe>2023-11-30 12:01:11 -0800
commitfd125947c9db0b33761414e65e919f73d9bf1815 (patch)
treec4c66d95ba85601427928aa7f23659590055d464 /ayafs-core/src/memory/cached_block.rs
parent1eac97eea4ec0bcef0be061a2cba93a584355283 (diff)
downloadmyfs-fd125947c9db0b33761414e65e919f73d9bf1815.tar.gz
myfs-fd125947c9db0b33761414e65e919f73d9bf1815.zip
Refactor workspace
Diffstat (limited to 'ayafs-core/src/memory/cached_block.rs')
-rw-r--r--ayafs-core/src/memory/cached_block.rs180
1 files changed, 180 insertions, 0 deletions
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<T: Block> {
+ pub block: T,
+ pub index: usize,
+ pub dirty: bool,
+}
+
+pub fn convert_mut<U: Block, T: Block>(input_block: &mut CachedBlock<U>) -> &mut CachedBlock<T> {
+ let ptr = input_block as *const CachedBlock<U> as *mut u8;
+ let block = ptr.cast::<CachedBlock<T>>();
+ unsafe { &mut *block }
+}
+
+pub fn convert<U: Block, T: Block>(input_block: &CachedBlock<U>) -> &CachedBlock<T> {
+ let ptr = input_block as *const CachedBlock<U> as *mut u8;
+ let block = ptr.cast::<CachedBlock<T>>();
+ unsafe { &*block }
+}
+
+pub(crate) struct BlockCache<T: Block> {
+ device: Arc<dyn BlockDevice>,
+ cache: LruCache<usize, CachedBlock<T>>,
+}
+
+impl<T: Block> BlockCache<T> {
+ pub(crate) fn new(device: Arc<dyn BlockDevice>, 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<U: Block>(&mut self, index: usize) -> Option<&CachedBlock<U>> {
+ if !self.cache.contains(&index) {
+ self.load_block(index);
+ }
+ self.cache.get(&index).map(convert::<T, U>)
+ }
+
+ /// 从 LRU cache 里获取一个 block 的可变引用, 如果没有在 cache 中会加载.
+ /// 这个函数不应该返回 None
+ pub(crate) fn get_block_mut<U: Block>(&mut self, index: usize) -> Option<&mut CachedBlock<U>> {
+ if !self.cache.contains(&index) {
+ self.load_block(index);
+ }
+ self.cache.get_mut(&index).map(|block| {
+ block.dirty = true;
+ convert_mut::<T, U>(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<U: Block>(&self, index: usize) -> Option<&CachedBlock<U>> {
+ self.cache.peek(&index).map(convert::<T, U>)
+ }
+
+ #[allow(unused)]
+ /// 从 LRU cache 中读取一个 block 的可变引用, *不会* 影响 LRU cache 的结构, 如果没有在 cache 中不会加载.
+ pub(crate) fn peek_block_mut<U: Block>(&mut self, index: usize) -> Option<&mut CachedBlock<U>> {
+ self.cache.peek_mut(&index).map(convert_mut::<T, U>)
+ }
+
+ pub(crate) fn update_block<U: Block>(&mut self, block: CachedBlock<U>) -> bool {
+ if self.cache.contains(&block.index) {
+ let mut data_block = convert::<U, T>(&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<CachedBlock<T>> {
+ 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<T: Block>(&mut self, index: usize) -> Option<&CachedBlock<T>> {
+ if self.data_bitmap.query(index) {
+ Some(self.cached_blocks.get_block::<T>(index).unwrap())
+ } else {
+ self.cached_blocks.pop(&index);
+ None
+ }
+ // self.data_bitmap
+ // .query(index)
+ // .then(|| self.cached_blocks.get_block::<T>(index).unwrap())
+ // 返回 None 当且仅当 data_bitmap 中这个 block 为 invalid
+ }
+
+ pub(crate) fn get_block_mut<T: Block>(&mut self, index: usize) -> Option<&mut CachedBlock<T>> {
+ if self.data_bitmap.query(index) {
+ Some(self.cached_blocks.get_block_mut::<T>(index).unwrap())
+ } else {
+ self.cached_blocks.pop(&index);
+ None
+ }
+ // self.data_bitmap
+ // .query(index)
+ // .then(|| self.cached_blocks.get_block_mut::<T>(index).unwrap())
+ // 返回 None 当且仅当 data_bitmap 中这个 block 为 invalid
+ }
+
+ #[allow(unused)]
+ pub(crate) fn peek_block<T: Block>(&self, index: usize) -> Option<&CachedBlock<T>> {
+ self.data_bitmap
+ .query(index)
+ .then(|| self.cached_blocks.peek_block::<T>(index).unwrap())
+ // 返回 None 当且仅当 data_bitmap 中这个 block 为 invalid
+ }
+
+ #[allow(unused)]
+ pub(crate) fn peek_block_mut<T: Block>(&mut self, index: usize) -> Option<&mut CachedBlock<T>> {
+ self.data_bitmap
+ .query(index)
+ .then(|| self.cached_blocks.peek_block_mut::<T>(index).unwrap())
+ // 返回 None 当且仅当 data_bitmap 中这个 block 为 invalid
+ }
+
+ pub(crate) fn update_block<T: Block>(&mut self, block: CachedBlock<T>) -> bool {
+ self.cached_blocks.update_block(block)
+ }
+}