secure_exec_vfs_core/engine/
cache.rs1use crate::engine::error::VfsResult;
2use crate::engine::metadata::MetadataStore;
3use crate::engine::types::{
4 BlockKey, ChunkEdit, ChunkRange, ChunkRef, CreateInodeAttrs, DentryStat, InodeMeta, InodePatch,
5 SnapshotId,
6};
7use async_trait::async_trait;
8use std::collections::{BTreeMap, VecDeque};
9use std::sync::Mutex;
10
11pub struct CachedMetadataStore<M> {
12 inner: M,
13 cache: Mutex<CacheState>,
14}
15
16#[derive(Debug)]
17struct CacheState {
18 capacity: usize,
19 generation: u64,
20 resolve: BTreeMap<String, Option<InodeMeta>>,
21 lstat: BTreeMap<String, Option<InodeMeta>>,
22 list_dir: BTreeMap<u64, Vec<DentryStat>>,
23 order: VecDeque<CacheKey>,
24}
25
26#[derive(Debug, Clone, PartialEq, Eq)]
27enum CacheKey {
28 Resolve(String),
29 Lstat(String),
30 ListDir(u64),
31}
32
33impl<M> CachedMetadataStore<M> {
34 pub fn new(inner: M, capacity: usize) -> Self {
35 Self {
36 inner,
37 cache: Mutex::new(CacheState {
38 capacity,
39 generation: 0,
40 resolve: BTreeMap::new(),
41 lstat: BTreeMap::new(),
42 list_dir: BTreeMap::new(),
43 order: VecDeque::new(),
44 }),
45 }
46 }
47
48 pub fn into_inner(self) -> M {
49 self.inner
50 }
51
52 fn clear_after_mutation(&self) {
53 let mut cache = self.cache.lock().expect("cache mutex poisoned");
54 cache.generation = cache.generation.wrapping_add(1);
55 cache.resolve.clear();
56 cache.lstat.clear();
57 cache.list_dir.clear();
58 cache.order.clear();
59 }
60}
61
62impl CacheState {
63 fn remember(&mut self, key: CacheKey) {
64 if self.capacity == 0 {
65 self.resolve.clear();
66 self.lstat.clear();
67 self.list_dir.clear();
68 self.order.clear();
69 return;
70 }
71 self.order.push_back(key);
72 while self.order.len() > self.capacity {
73 if let Some(evicted) = self.order.pop_front() {
74 match evicted {
75 CacheKey::Resolve(path) => {
76 self.resolve.remove(&path);
77 }
78 CacheKey::Lstat(path) => {
79 self.lstat.remove(&path);
80 }
81 CacheKey::ListDir(ino) => {
82 self.list_dir.remove(&ino);
83 }
84 }
85 }
86 }
87 }
88}
89
90#[async_trait]
91impl<M: MetadataStore> MetadataStore for CachedMetadataStore<M> {
92 async fn resolve(&self, path: &str) -> VfsResult<InodeMeta> {
93 let generation = {
94 let cache = self.cache.lock().expect("cache mutex poisoned");
95 if let Some(cached) = cache.resolve.get(path).cloned() {
96 return cached.ok_or_else(|| crate::engine::error::VfsError::enoent(path));
97 }
98 cache.generation
99 };
100 let result = self.inner.resolve(path).await;
101 let mut cache = self.cache.lock().expect("cache mutex poisoned");
102 if cache.generation == generation {
103 cache.resolve.insert(path.to_string(), result.clone().ok());
104 cache.remember(CacheKey::Resolve(path.to_string()));
105 }
106 result
107 }
108
109 async fn resolve_parent(&self, path: &str) -> VfsResult<(InodeMeta, String)> {
110 self.inner.resolve_parent(path).await
111 }
112
113 async fn lstat(&self, path: &str) -> VfsResult<InodeMeta> {
114 let generation = {
115 let cache = self.cache.lock().expect("cache mutex poisoned");
116 if let Some(cached) = cache.lstat.get(path).cloned() {
117 return cached.ok_or_else(|| crate::engine::error::VfsError::enoent(path));
118 }
119 cache.generation
120 };
121 let result = self.inner.lstat(path).await;
122 let mut cache = self.cache.lock().expect("cache mutex poisoned");
123 if cache.generation == generation {
124 cache.lstat.insert(path.to_string(), result.clone().ok());
125 cache.remember(CacheKey::Lstat(path.to_string()));
126 }
127 result
128 }
129
130 async fn list_dir(&self, ino: u64) -> VfsResult<Vec<DentryStat>> {
131 let generation = {
132 let cache = self.cache.lock().expect("cache mutex poisoned");
133 if let Some(cached) = cache.list_dir.get(&ino).cloned() {
134 return Ok(cached);
135 }
136 cache.generation
137 };
138 let entries = self.inner.list_dir(ino).await?;
139 let mut cache = self.cache.lock().expect("cache mutex poisoned");
140 if cache.generation == generation {
141 cache.list_dir.insert(ino, entries.clone());
142 cache.remember(CacheKey::ListDir(ino));
143 }
144 Ok(entries)
145 }
146
147 async fn create(
148 &self,
149 parent: u64,
150 name: &str,
151 attrs: CreateInodeAttrs,
152 ) -> VfsResult<InodeMeta> {
153 let result = self.inner.create(parent, name, attrs).await;
154 self.clear_after_mutation();
155 result
156 }
157
158 async fn link(&self, parent: u64, name: &str, target: u64) -> VfsResult<()> {
159 let result = self.inner.link(parent, name, target).await;
160 self.clear_after_mutation();
161 result
162 }
163
164 async fn remove(&self, parent: u64, name: &str) -> VfsResult<Vec<BlockKey>> {
165 let result = self.inner.remove(parent, name).await;
166 self.clear_after_mutation();
167 result
168 }
169
170 async fn rename(
171 &self,
172 src_parent: u64,
173 src: &str,
174 dst_parent: u64,
175 dst: &str,
176 ) -> VfsResult<Vec<BlockKey>> {
177 let result = self.inner.rename(src_parent, src, dst_parent, dst).await;
178 self.clear_after_mutation();
179 result
180 }
181
182 async fn set_attr(&self, ino: u64, patch: InodePatch) -> VfsResult<Vec<BlockKey>> {
183 let result = self.inner.set_attr(ino, patch).await;
184 self.clear_after_mutation();
185 result
186 }
187
188 async fn commit_write(
189 &self,
190 ino: u64,
191 edits: Vec<ChunkEdit>,
192 new_size: u64,
193 ) -> VfsResult<Vec<BlockKey>> {
194 let result = self.inner.commit_write(ino, edits, new_size).await;
195 self.clear_after_mutation();
196 result
197 }
198
199 async fn get_chunks(&self, ino: u64, range: ChunkRange) -> VfsResult<Vec<ChunkRef>> {
200 self.inner.get_chunks(ino, range).await
201 }
202
203 async fn snapshot(&self, root: u64) -> VfsResult<SnapshotId> {
204 self.inner.snapshot(root).await
205 }
206
207 async fn fork(&self, snap: SnapshotId) -> VfsResult<u64> {
208 self.inner.fork(snap).await
209 }
210
211 async fn gc(&self) -> VfsResult<Vec<BlockKey>> {
212 self.inner.gc().await
213 }
214}