use super::{CacheKey, CacheMeta};
use crate::key::CompactCacheKey;
use crate::trace::SpanHandle;
use async_trait::async_trait;
use pingora_error::Result;
use std::any::Any;
#[derive(Debug, Clone, Copy)]
pub enum PurgeType {
Eviction,
Invalidation,
}
#[async_trait]
pub trait Storage {
async fn lookup(
&'static self,
key: &CacheKey,
trace: &SpanHandle,
) -> Result<Option<(CacheMeta, HitHandler)>>;
async fn lookup_streaming_write(
&'static self,
key: &CacheKey,
_streaming_write_tag: Option<&[u8]>,
trace: &SpanHandle,
) -> Result<Option<(CacheMeta, HitHandler)>> {
self.lookup(key, trace).await
}
async fn get_miss_handler(
&'static self,
key: &CacheKey,
meta: &CacheMeta,
trace: &SpanHandle,
) -> Result<MissHandler>;
async fn purge(
&'static self,
key: &CompactCacheKey,
purge_type: PurgeType,
trace: &SpanHandle,
) -> Result<bool>;
async fn update_meta(
&'static self,
key: &CacheKey,
meta: &CacheMeta,
trace: &SpanHandle,
) -> Result<bool>;
fn support_streaming_partial_write(&self) -> bool {
false
}
fn as_any(&self) -> &(dyn Any + Send + Sync + 'static);
}
#[async_trait]
pub trait HandleHit {
async fn read_body(&mut self) -> Result<Option<bytes::Bytes>>;
async fn finish(
self: Box<Self>, storage: &'static (dyn Storage + Sync),
key: &CacheKey,
trace: &SpanHandle,
) -> Result<()>;
fn can_seek(&self) -> bool {
false
}
fn can_seek_multipart(&self) -> bool {
self.can_seek()
}
fn seek(&mut self, _start: usize, _end: Option<usize>) -> Result<()> {
todo!("seek() needs to be implemented")
}
fn seek_multipart(&mut self, start: usize, end: Option<usize>) -> Result<()> {
self.seek(start, end)
}
fn should_count_access(&self) -> bool {
true
}
fn get_eviction_weight(&self) -> usize {
0
}
fn as_any(&self) -> &(dyn Any + Send + Sync);
fn as_any_mut(&mut self) -> &mut (dyn Any + Send + Sync);
}
pub type HitHandler = Box<dyn HandleHit + Sync + Send>;
pub enum MissFinishType {
Created(usize),
Appended(usize, Option<usize>),
}
#[async_trait]
pub trait HandleMiss {
async fn write_body(&mut self, data: bytes::Bytes, eof: bool) -> Result<()>;
async fn finish(
self: Box<Self>, ) -> Result<MissFinishType>;
fn streaming_write_tag(&self) -> Option<&[u8]> {
None
}
}
pub type MissHandler = Box<dyn HandleMiss + Sync + Send>;
pub mod streaming_write {
#[derive(Debug, Clone, Copy)]
pub struct U64WriteId([u8; 8]);
impl U64WriteId {
pub fn as_bytes(&self) -> &[u8] {
&self.0[..]
}
}
impl From<u64> for U64WriteId {
fn from(value: u64) -> U64WriteId {
U64WriteId(value.to_be_bytes())
}
}
impl From<U64WriteId> for u64 {
fn from(value: U64WriteId) -> u64 {
u64::from_be_bytes(value.0)
}
}
impl TryFrom<&[u8]> for U64WriteId {
type Error = std::array::TryFromSliceError;
fn try_from(value: &[u8]) -> std::result::Result<Self, Self::Error> {
Ok(U64WriteId(value.try_into()?))
}
}
#[derive(Debug, Clone, Copy)]
pub struct U32WriteId([u8; 4]);
impl U32WriteId {
pub fn as_bytes(&self) -> &[u8] {
&self.0[..]
}
}
impl From<u32> for U32WriteId {
fn from(value: u32) -> U32WriteId {
U32WriteId(value.to_be_bytes())
}
}
impl From<U32WriteId> for u32 {
fn from(value: U32WriteId) -> u32 {
u32::from_be_bytes(value.0)
}
}
impl TryFrom<&[u8]> for U32WriteId {
type Error = std::array::TryFromSliceError;
fn try_from(value: &[u8]) -> std::result::Result<Self, Self::Error> {
Ok(U32WriteId(value.try_into()?))
}
}
}