fs_core/
caching_device.rs1use crate::block::{BlockDevice, BlockRead};
6use crate::error::Result;
7use std::collections::VecDeque;
8use std::sync::{Arc, Mutex};
9
10pub struct CachingDevice {
12 inner: Arc<dyn BlockDevice>,
13 block_size: u64,
14 state: Mutex<CacheState>,
15}
16
17struct CacheState {
18 entries: VecDeque<(u64, Arc<Vec<u8>>)>,
20 capacity: usize,
21 hits: u64,
22 misses: u64,
23}
24
25impl CachingDevice {
26 pub fn new(inner: Arc<dyn BlockDevice>, block_size: u64, capacity: usize) -> Arc<Self> {
27 Arc::new(Self {
28 inner,
29 block_size,
30 state: Mutex::new(CacheState {
31 entries: VecDeque::with_capacity(capacity),
32 capacity,
33 hits: 0,
34 misses: 0,
35 }),
36 })
37 }
38
39 pub fn stats(&self) -> (u64, u64) {
40 let s = self.state.lock().unwrap();
41 (s.hits, s.misses)
42 }
43
44 pub fn invalidate_all(&self) {
45 let mut s = self.state.lock().unwrap();
46 s.entries.clear();
47 }
48
49 fn invalidate_range(state: &mut CacheState, start: u64, end: u64, block_size: u64) {
50 state.entries.retain(|(off, _)| {
51 let block_end = off.saturating_add(block_size);
52 *off >= end || block_end <= start
53 });
54 }
55}
56
57impl BlockRead for CachingDevice {
58 fn read_at(&self, offset: u64, buf: &mut [u8]) -> Result<()> {
59 let cacheable =
60 buf.len() as u64 == self.block_size && offset.is_multiple_of(self.block_size);
61 if !cacheable {
62 return self.inner.read_at(offset, buf);
63 }
64
65 {
66 let mut s = self.state.lock().unwrap();
67 if let Some(pos) = s.entries.iter().position(|(o, _)| *o == offset) {
68 let entry = s.entries.remove(pos).unwrap();
69 buf.copy_from_slice(&entry.1);
70 s.entries.push_front(entry);
71 s.hits += 1;
72 return Ok(());
73 }
74 s.misses += 1;
75 }
76
77 self.inner.read_at(offset, buf)?;
78 let data = Arc::new(buf.to_vec());
79 let mut s = self.state.lock().unwrap();
80 if s.entries.len() >= s.capacity {
81 s.entries.pop_back();
82 }
83 s.entries.push_front((offset, data));
84 Ok(())
85 }
86
87 fn size_bytes(&self) -> u64 {
88 self.inner.size_bytes()
89 }
90}
91
92impl BlockDevice for CachingDevice {
93 fn write_at(&self, offset: u64, buf: &[u8]) -> Result<()> {
94 let end = offset.saturating_add(buf.len() as u64);
95 {
96 let mut s = self.state.lock().unwrap();
97 let bs = self.block_size;
98 Self::invalidate_range(&mut s, offset, end, bs);
99 }
100 self.inner.write_at(offset, buf)
101 }
102
103 fn flush(&self) -> Result<()> {
104 self.inner.flush()
105 }
106
107 fn is_writable(&self) -> bool {
108 self.inner.is_writable()
109 }
110}