imago/qcow2/
cache.rs

1//! Provides functionality for the L2 and refblock caches.
2
3use super::*;
4use crate::async_lru_cache::AsyncLruCacheBackend;
5use tracing::trace;
6
7/// I/O back-end for the L2 table cache.
8pub(super) struct L2CacheBackend<S: Storage> {
9    /// Qcow2 metadata file.
10    file: Arc<S>,
11
12    /// Qcow2 header.
13    header: Arc<Header>,
14}
15
16/// I/O back-end for the refblock cache.
17pub(super) struct RefBlockCacheBackend<S: Storage> {
18    /// Qcow2 metadata file.
19    file: Arc<S>,
20
21    /// Qcow2 header.
22    header: Arc<Header>,
23}
24
25impl<S: Storage> L2CacheBackend<S> {
26    /// Create a new `L2CacheBackend`.
27    ///
28    /// `file` is the qcow2 metadata (image) file.
29    pub fn new(file: Arc<S>, header: Arc<Header>) -> Self {
30        L2CacheBackend { file, header }
31    }
32}
33
34impl<S: Storage> AsyncLruCacheBackend for L2CacheBackend<S> {
35    type Key = HostCluster;
36    type Value = L2Table;
37
38    async fn load(&self, l2_cluster: HostCluster) -> io::Result<L2Table> {
39        trace!("Loading L2 table");
40
41        L2Table::load(
42            self.file.as_ref(),
43            &self.header,
44            l2_cluster,
45            self.header.l2_entries(),
46        )
47        .await
48    }
49
50    async fn flush(&self, l2_cluster: HostCluster, l2_table: Arc<L2Table>) -> io::Result<()> {
51        trace!("Flushing L2 table");
52        if l2_table.is_modified() {
53            assert!(l2_table.get_cluster().unwrap() == l2_cluster);
54            l2_table.write(self.file.as_ref()).await?;
55        }
56        Ok(())
57    }
58
59    unsafe fn evict(&self, _l2_cluster: HostCluster, l2_table: L2Table) {
60        trace!(
61            "Evicting L2 table {}",
62            l2_table.get_offset().unwrap_or(HostOffset(0))
63        );
64        l2_table.clear_modified();
65    }
66}
67
68impl<S: Storage> RefBlockCacheBackend<S> {
69    /// Create a new `RefBlockCacheBackend`.
70    ///
71    /// `file` is the qcow2 metadata (image) file.
72    pub fn new(file: Arc<S>, header: Arc<Header>) -> Self {
73        RefBlockCacheBackend { file, header }
74    }
75}
76
77impl<S: Storage> AsyncLruCacheBackend for RefBlockCacheBackend<S> {
78    type Key = HostCluster;
79    type Value = RefBlock;
80
81    async fn load(&self, rb_cluster: HostCluster) -> io::Result<RefBlock> {
82        RefBlock::load(self.file.as_ref(), &self.header, rb_cluster).await
83    }
84
85    async fn flush(&self, rb_cluster: HostCluster, refblock: Arc<RefBlock>) -> io::Result<()> {
86        if refblock.is_modified() {
87            assert!(refblock.get_cluster().unwrap() == rb_cluster);
88            refblock.write(self.file.as_ref()).await?;
89        }
90        Ok(())
91    }
92
93    unsafe fn evict(&self, _rb_cluster: HostCluster, refblock: RefBlock) {
94        refblock.clear_modified();
95    }
96}