pub(super) struct MetadataCaches<S: Storage> {
l2: AsyncLruCache<HostCluster, L2Table, L2CacheBackend<S>>,
rb: AsyncLruCache<HostCluster, RefBlock, RefBlockCacheBackend<S>>,
direction: RwLock<CacheDependency>,
}Expand description
Qcow2 metadata caches with flush-ordering coordination.
When allocating clusters, we need to increment the refcounts (from 0 to 1) before writing the L2 pointers. Therefore, before anything is written from the L2 cache to disk, we need to flush the refblock cache.
When freeing clusters, we need to clear the L2 pointers before decrementing the refcounts (to 0). Therefore before anything is written from the refblock cache to disk, we need to flush the L2 cache.
This structure takes care to heed those dependencies (though the general qcow2 code still needs
to announce them by calling .l2_depends_on_rb() for allocations and .rb_depends_on_l2() for
freeing).
Fields§
§l2: AsyncLruCache<HostCluster, L2Table, L2CacheBackend<S>>L2 table cache
rb: AsyncLruCache<HostCluster, RefBlock, RefBlockCacheBackend<S>>Refblock cache
direction: RwLock<CacheDependency>Current dependency direction
Wrapped methods hold a read guard for their entire execution, preventing the direction from changing mid-operation. Direction switch methods take a write guard.
Implementations§
Source§impl<S: Storage> MetadataCaches<S>
impl<S: Storage> MetadataCaches<S>
Sourcepub fn new(
file: &Arc<S>,
header: &Arc<Header>,
l2_entries: usize,
rb_entries: usize,
) -> Self
pub fn new( file: &Arc<S>, header: &Arc<Header>, l2_entries: usize, rb_entries: usize, ) -> Self
Create metadata caches for the given file, with the given header.
The L2 cache is going to hold l2_entries tables, the refblock cache will have
rb_entries refcount blocks.
Sourcepub async fn l2_depends_on_rb(&self) -> Result<()>
pub async fn l2_depends_on_rb(&self) -> Result<()>
Make sure the refblock cache is flushed before the L2 cache.
Use before allocating new clusters.
Sourcepub async fn rb_depends_on_l2(&self) -> Result<()>
pub async fn rb_depends_on_l2(&self) -> Result<()>
Make sure the L2 cache is flushed before the refblock cache.
Use before freeing clusters.
Sourcepub async fn l2_get_or_insert(
&self,
cluster_index: HostCluster,
) -> Result<Arc<L2Table>>
pub async fn l2_get_or_insert( &self, cluster_index: HostCluster, ) -> Result<Arc<L2Table>>
Retrieve an L2 table from the cache.
See AsyncLruCache::get_or_insert() for details.
Sourcepub async fn l2_insert(
&self,
cluster_index: HostCluster,
table: Arc<L2Table>,
) -> Result<()>
pub async fn l2_insert( &self, cluster_index: HostCluster, table: Arc<L2Table>, ) -> Result<()>
Force-insert an L2 table.
See AsyncLruCache::insert() for details.
Sourcepub async unsafe fn invalidate_l2(&self) -> Result<()>
pub async unsafe fn invalidate_l2(&self) -> Result<()>
Invalidate the L2 cache.
§Safety
May cause image corruption, you must guarantee the on-disk state is consistent.
Sourcepub async fn rb_get_or_insert(
&self,
cluster_index: HostCluster,
) -> Result<Arc<RefBlock>>
pub async fn rb_get_or_insert( &self, cluster_index: HostCluster, ) -> Result<Arc<RefBlock>>
Retrieve a refblock from the cache.
See AsyncLruCache::get_or_insert() for details.
Sourcepub async fn rb_insert(
&self,
cluster_index: HostCluster,
rb: Arc<RefBlock>,
) -> Result<()>
pub async fn rb_insert( &self, cluster_index: HostCluster, rb: Arc<RefBlock>, ) -> Result<()>
Force-insert a refblock.
See AsyncLruCache::insert() for details.
Sourcepub async unsafe fn invalidate_rb(&self) -> Result<()>
pub async unsafe fn invalidate_rb(&self) -> Result<()>
Invalidate the refblock cache.
§Safety
May cause image corruption, you must guarantee the on-disk state is consistent.