You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

99 lines
2.7 KiB

//! Inserting into the persistant cache.
use super::*;
use ::bytes::BytesMut;
use std::path::Path;
use tokio::fs::{self, File};
use std::io;
use tokio::io::AsyncWrite;
use cryptohelpers::sha2::{Sha256, Digest};
use mem::MemoryMut;
/// The write rule used for cache insertion operations.
/// This ensures the number of bytes returned corresponds to the number written into memory.
///
/// This is because we care more about the integrity of memcached data, because we can dump that to disk later if the integrity of the disk copy is incorrect.
#[derive(Debug)]
enum CacheWriteRule{}
impl plex::WriteRule for CacheWriteRule
{
#[inline(always)] fn compare_byte_sizes(a: usize, b: usize) -> Result<usize, Self::CompareFailedError> {
Ok(std::cmp::max(a,b))
}
}
/// A partially formed cache entry that can be mutated.
/// It has not yet been inserted into a persistant `ByteCache` cache, and is write-only.
pub struct PartialCacheEntry<K>
{
cfg: Arc<Config>,
id: Uuid,
key: K,
/// Written to with each write to any instance created by `writer()`.
/// Finalised only when freezing this to a completed entry.
hasher: Sha256,
file: Option<File>,
memory: MemoryMut,
}
/// The writer type for writing to a `PartialCacheEntry`.
pub type PartialCacheEntrySink<'a> = plex::MultiplexWrite<Box<dyn AsyncWrite + Send + Sync + Unpin + 'a>, Sha256Sink<&'a mut Sha256>>;
impl<K: Key> PartialCacheEntry<K>
{
#[inline(always)] pub(super) fn new_uninit(owner: &ByteCache<K>, key: K) -> Self
{
Self {
cfg: Arc::clone(&owner.cfg),
id: Uuid::new_v4(),
file: None,
memory: MemoryMut::new(),
hasher: Sha256::new(),
key,
}
}
#[inline(always)] pub(super) async fn init(&mut self) -> io::Result<()>
{
//self.memory.reserve(PAGE_SIZE);
if let Some(root) = &self.cfg.disk_location {
self.file = Some(fs::OpenOptions::new()
.write(true)
.open(gen_temp_path(root, &self.id)).await?);
}
Ok(())
}
/// Create a writer for this entry
pub fn writer(&mut self) -> PartialCacheEntrySink<'_>
{
let bx: Box<dyn AsyncWrite + Send + Sync + Unpin + '_> = if let Some(file) = self.file.as_mut()
{
Box::new((&mut self.memory).multiplex_ruled::<_, CacheWriteRule>(file))
} else {
Box::new(&mut self.memory)
};
bx.multiplex(Sha256Sink::new(&mut self.hasher))
}
}
/// Create a path for a **non-completed** entry
pub(super) fn gen_temp_path(root: impl AsRef<Path>, from: &Uuid) -> PathBuf
{
root.as_ref().join(format!("{}.open", from))
}
/// Create a path for a **completed** entry
pub(super) fn gen_path(root: impl AsRef<Path>, from: &Uuid) -> PathBuf
{
root.as_ref().join(format!("{}.entry", from))
}