use std::sync::Arc;
use std::time::Duration;
use async_trait::async_trait;
use crate::cache::{Cache, CacheMode, CacheWrite, Storage};
use crate::compiler::PreprocessorCacheEntry;
use crate::config::PreprocessorCacheModeConfig;
use crate::errors::*;
use bytes::Bytes;
pub struct ReadOnlyStorage(pub Arc<dyn Storage>);
#[async_trait]
impl Storage for ReadOnlyStorage {
async fn get(&self, key: &str) -> Result<Cache> {
self.0.get(key).await
}
async fn put(&self, _key: &str, _entry: CacheWrite) -> Result<Duration> {
Err(anyhow!("Cannot write to read-only storage"))
}
async fn check(&self) -> Result<CacheMode> {
Ok(CacheMode::ReadOnly)
}
fn location(&self) -> String {
self.0.location()
}
fn cache_type_name(&self) -> &'static str {
self.0.cache_type_name()
}
async fn current_size(&self) -> Result<Option<u64>> {
self.0.current_size().await
}
async fn max_size(&self) -> Result<Option<u64>> {
self.0.max_size().await
}
fn preprocessor_cache_mode_config(&self) -> PreprocessorCacheModeConfig {
self.0.preprocessor_cache_mode_config()
}
fn basedirs(&self) -> &[Vec<u8>] {
self.0.basedirs()
}
async fn get_preprocessor_cache_entry(
&self,
key: &str,
) -> Result<Option<Box<dyn crate::lru_disk_cache::ReadSeek>>> {
self.0.get_preprocessor_cache_entry(key).await
}
async fn put_preprocessor_cache_entry(
&self,
_key: &str,
_preprocessor_cache_entry: PreprocessorCacheEntry,
) -> Result<()> {
Err(anyhow!("Cannot write to read-only storage"))
}
async fn get_raw(&self, key: &str) -> Result<Option<Bytes>> {
self.0.get_raw(key).await
}
}
#[cfg(test)]
mod test {
use futures::FutureExt;
use super::*;
use crate::test::mock_storage::MockStorage;
#[test]
fn readonly_storage_is_readonly() {
let storage = ReadOnlyStorage(Arc::new(MockStorage::new(None, false)));
assert_eq!(
storage.check().now_or_never().unwrap().unwrap(),
CacheMode::ReadOnly
);
}
#[test]
fn readonly_storage_forwards_preprocessor_cache_mode_config() {
let storage_no_preprocessor_cache =
ReadOnlyStorage(Arc::new(MockStorage::new(None, false)));
assert!(
!storage_no_preprocessor_cache
.preprocessor_cache_mode_config()
.use_preprocessor_cache_mode
);
let storage_with_preprocessor_cache =
ReadOnlyStorage(Arc::new(MockStorage::new(None, true)));
assert!(
storage_with_preprocessor_cache
.preprocessor_cache_mode_config()
.use_preprocessor_cache_mode
);
}
#[test]
fn readonly_storage_forwards_basedirs() {
let runtime = tokio::runtime::Builder::new_current_thread()
.enable_all()
.worker_threads(1)
.build()
.unwrap();
let tempdir = tempfile::Builder::new()
.prefix("readonly_storage_forwards_basedirs")
.tempdir()
.expect("Failed to create tempdir");
let cache_dir = tempdir.path().join("cache");
std::fs::create_dir(&cache_dir).unwrap();
let basedirs = vec![
b"/home/user/project".to_vec(),
b"/home/user/workspace".to_vec(),
];
let disk_cache = crate::cache::disk::DiskCache::new(
&cache_dir,
1024 * 1024,
runtime.handle(),
super::PreprocessorCacheModeConfig::default(),
super::CacheMode::ReadWrite,
basedirs.clone(),
);
let readonly_storage = ReadOnlyStorage(std::sync::Arc::new(disk_cache));
assert_eq!(readonly_storage.basedirs(), basedirs.as_slice());
}
#[test]
fn readonly_storage_put_err() {
let runtime = tokio::runtime::Builder::new_current_thread()
.enable_all()
.worker_threads(1)
.build()
.unwrap();
let storage = ReadOnlyStorage(Arc::new(MockStorage::new(None, true)));
runtime.block_on(async move {
assert_eq!(
storage
.put("test1", CacheWrite::default())
.await
.unwrap_err()
.to_string(),
"Cannot write to read-only storage"
);
assert_eq!(
storage
.put_preprocessor_cache_entry("test1", PreprocessorCacheEntry::default())
.await
.unwrap_err()
.to_string(),
"Cannot write to read-only storage"
);
});
}
#[test]
fn readonly_storage_forwards_cache_type_name() {
let runtime = tokio::runtime::Builder::new_current_thread()
.enable_all()
.worker_threads(1)
.build()
.unwrap();
let tempdir = tempfile::Builder::new()
.prefix("readonly_cache_type_name")
.tempdir()
.expect("Failed to create tempdir");
let cache_dir = tempdir.path().join("cache");
std::fs::create_dir(&cache_dir).unwrap();
let disk_cache = crate::cache::disk::DiskCache::new(
&cache_dir,
1024 * 1024,
runtime.handle(),
super::PreprocessorCacheModeConfig::default(),
super::CacheMode::ReadWrite,
vec![],
);
let readonly_storage = ReadOnlyStorage(std::sync::Arc::new(disk_cache));
assert_eq!(readonly_storage.cache_type_name(), "disk");
}
}