use crate::sharded_cache::{ShardedCache, UnitWeighter};
use alloc::sync::Arc;
use crate::{GlobalTableId, fs::FsFile};
const TAG_BLOCK: u8 = 0;
const TAG_BLOB: u8 = 1;
type Item = Arc<dyn FsFile>;
#[derive(Clone, Copy, Eq, core::hash::Hash, PartialEq)]
struct CacheKey(u8, u64, u64);
const FD_CACHE_SHARDS: usize = 16;
pub struct DescriptorTable {
inner: ShardedCache<CacheKey, Item, UnitWeighter, rustc_hash::FxBuildHasher>,
table_epoch: portable_atomic::AtomicU64,
}
impl DescriptorTable {
#[must_use]
pub fn new(capacity: usize) -> Self {
let inner = ShardedCache::with_weighter(
capacity as u64,
FD_CACHE_SHARDS,
capacity,
UnitWeighter,
rustc_hash::FxBuildHasher,
);
Self {
inner,
table_epoch: portable_atomic::AtomicU64::new(0),
}
}
pub(crate) fn table_epoch(&self) -> u64 {
self.table_epoch.load(portable_atomic::Ordering::Acquire)
}
fn advance_table_epoch(&self) {
self.table_epoch
.fetch_add(1, portable_atomic::Ordering::Release);
}
pub(crate) fn len(&self) -> usize {
self.inner.len()
}
pub(crate) fn capacity(&self) -> u64 {
self.inner.capacity()
}
pub(crate) fn remove_trees_from(&self, first: crate::tree::inner::TreeId) {
self.inner.remove_where(|key| key.1 >= first);
self.advance_table_epoch();
}
#[must_use]
pub fn access_for_table(&self, id: &GlobalTableId) -> Option<Arc<dyn FsFile>> {
let key = CacheKey(TAG_BLOCK, id.tree_id(), id.table_id());
self.inner.get(&key)
}
#[must_use]
pub(crate) fn peek_for_table(&self, id: &GlobalTableId) -> Option<Arc<dyn FsFile>> {
let key = CacheKey(TAG_BLOCK, id.tree_id(), id.table_id());
self.inner.peek(&key)
}
pub fn insert_for_table(&self, id: GlobalTableId, item: Item) {
let key = CacheKey(TAG_BLOCK, id.tree_id(), id.table_id());
self.inner.insert(key, item);
}
#[must_use]
pub fn access_for_blob_file(&self, id: &GlobalTableId) -> Option<Arc<dyn FsFile>> {
let key = CacheKey(TAG_BLOB, id.tree_id(), id.table_id());
self.inner.get(&key)
}
pub fn insert_for_blob_file(&self, id: GlobalTableId, item: Item) {
let key = CacheKey(TAG_BLOB, id.tree_id(), id.table_id());
self.inner.insert(key, item);
}
pub fn remove_for_table(&self, id: &GlobalTableId) {
let key = CacheKey(TAG_BLOCK, id.tree_id(), id.table_id());
self.inner.remove(&key);
self.advance_table_epoch();
}
pub fn remove_for_blob_file(&self, id: &GlobalTableId) {
let key = CacheKey(TAG_BLOB, id.tree_id(), id.table_id());
self.inner.remove(&key);
}
}