summaryrefslogtreecommitdiff
path: root/src/memory/cached_block.rs
blob: 0c401ff6d857f87766a13fbad4ff4575b398fd1a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
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<T: Block> {
    pub block: T,
    pub index: usize,
    pub dirty: bool,
}

impl<T: Block> CachedBlock<T> {
    fn cast<U: Block>(&self) -> CachedBlock<U> {
        unsafe { std::mem::transmute_copy(&self) }
    }
}

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 }
}

impl AyaFS {
    pub(crate) fn update_block<T: Block>(&mut self, block: CachedBlock<T>) -> bool {
        if self.cached_blocks.contains(&block.index) {
            let data_block = convert::<T, DataBlock>(&block).clone();
            self.cached_blocks.push(block.index, data_block);
            true
        } else {
            false
        }
    }
    pub(crate) fn get_block<T: Block>(&mut self, index: usize) -> Option<&CachedBlock<T>> {
        self.load_block(index)
            .and_then(|| self.cached_blocks.get(&index).map(convert::<DataBlock, T>))
    }

    pub(crate) fn get_block_mut<T: Block>(&mut self, index: usize) -> Option<&mut CachedBlock<T>> {
        self.load_block(index).and_then(|| {
            self.cached_blocks
                .get_mut(&index)
                .map(convert_mut::<DataBlock, T>)
        })
    }

    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
    }
}