use std::path::Path;
use std::sync::Arc;
use std::sync::atomic::{AtomicU64, Ordering};
use super::{MemoryStorage, ReadableFile, Storage, StorageLock, WritableFile};
use crate::Result;
#[derive(Debug, Default)]
pub(crate) struct Reads {
pub(crate) inline: AtomicU64,
pub(crate) blocking: AtomicU64,
pub(crate) open: AtomicU64,
}
#[derive(Debug, Clone)]
pub(crate) struct CountedStorage {
inner: MemoryStorage,
inline: bool,
pub(crate) reads: Arc<Reads>,
}
impl CountedStorage {
pub(crate) fn new(inline: bool) -> Self {
Self {
inner: MemoryStorage::new(),
inline,
reads: Arc::default(),
}
}
}
struct CountedFile {
inner: Arc<dyn ReadableFile>,
inline: bool,
reads: Arc<Reads>,
}
impl ReadableFile for CountedFile {
fn read_at(&self, offset: u64, buf: &mut [u8]) -> Result<()> {
self.reads.blocking.fetch_add(1, Ordering::Relaxed);
self.inner.read_at(offset, buf)
}
fn try_read_at(&self, offset: u64, buf: &mut [u8]) -> Result<bool> {
if !self.inline {
return Ok(false);
}
let made = self.inner.try_read_at(offset, buf)?;
if made {
self.reads.inline.fetch_add(1, Ordering::Relaxed);
}
Ok(made)
}
fn len(&self) -> Result<u64> {
self.inner.len()
}
}
impl Drop for CountedFile {
fn drop(&mut self) {
self.reads.open.fetch_sub(1, Ordering::Relaxed);
}
}
impl Storage for CountedStorage {
fn create(&self, path: &Path) -> Result<Box<dyn WritableFile>> {
self.inner.create(path)
}
fn open(&self, path: &Path) -> Result<Arc<dyn ReadableFile>> {
let inner = self.inner.open(path)?;
self.reads.open.fetch_add(1, Ordering::Relaxed);
Ok(Arc::new(CountedFile {
inner,
inline: self.inline,
reads: Arc::clone(&self.reads),
}))
}
fn exists(&self, path: &Path) -> Result<bool> {
self.inner.exists(path)
}
fn remove(&self, path: &Path) -> Result<()> {
self.inner.remove(path)
}
fn rename(&self, from: &Path, to: &Path) -> Result<()> {
self.inner.rename(from, to)
}
fn list(&self, dir: &Path) -> Result<Vec<String>> {
self.inner.list(dir)
}
fn create_dir_all(&self, dir: &Path) -> Result<()> {
self.inner.create_dir_all(dir)
}
fn sync_dir(&self, dir: &Path) -> Result<()> {
self.inner.sync_dir(dir)
}
fn lock(&self, path: &Path) -> Result<Box<dyn StorageLock>> {
self.inner.lock(path)
}
}