use and_then_some::BoolExt; use crate::AyaFS; use crate::block_device::BLOCK_SIZE; use crate::disk::data_block::{Block, DataBlock}; #[derive(Clone)] pub struct CachedBlock { pub block: T, pub index: usize, pub dirty: bool, } impl CachedBlock { fn cast(&self) -> CachedBlock { unsafe { std::mem::transmute_copy(&self) } } } 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 } } impl AyaFS { pub(crate) fn update_block(&mut self, block: CachedBlock) -> bool { if self.cached_blocks.contains(&block.index) { let data_block = convert::(&block).clone(); self.cached_blocks.push(block.index, data_block); true } else { false } } pub(crate) fn get_block(&mut self, index: usize) -> Option<&CachedBlock> { self.load_block(index) .and_then(|| self.cached_blocks.get(&index).map(convert::)) } pub(crate) fn get_block_mut(&mut self, index: usize) -> Option<&mut CachedBlock> { self.load_block(index).and_then(|| { self.cached_blocks .get_mut(&index) .map(convert_mut::) }) } pub(crate) fn load_block(&mut self, index: usize) -> bool { // 反正我自己保证所有实现了 Block trait 的数据结构都是 4K bytes 长, 来回 cast 没问题 // 如果 block cache 里没有这个 block if self.cached_blocks.contains(&index) == false { if self.data_bitmap.query(index) == false { return false; } // 先看这个 block 是不是 valid, 不 valid 直接返回 None let block = DataBlock::default(); let buffer = unsafe { std::slice::from_raw_parts_mut(&block as *const DataBlock as *mut u8, BLOCK_SIZE) }; self.device.read(index, buffer); let cached_block = CachedBlock { block, index, dirty: false, }; if let Some((old_index, old_block)) = self.cached_blocks.push(index, cached_block) { assert_ne!(old_index, index); // 只有 block 不在 cache 里的时候才会插入 if old_block.dirty { let old_block_ptr = &old_block.block as *const DataBlock 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); } } // 如果 valid 就放到 block cache 里, 同时将(可能)被驱逐的 block 依据其是否为脏块进行写回 } true } }