Skip to main content

secure_exec_vfs_core/engine/
cache.rs

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