use std::time::Duration;
use crate::error::CacheError;
use crate::key::KeyRef;
use crate::tier::TierId;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum BackendKind {
InMemory,
InMemoryFallback,
Moka,
Redis,
Sled,
RocksDb,
Postgres,
Neo4j,
Helix,
Oxigraph,
Origin,
Test,
Unavailable,
}
impl BackendKind {
#[must_use]
pub const fn is_implemented(&self) -> bool {
matches!(
self,
Self::InMemory
| Self::InMemoryFallback
| Self::Redis
| Self::Sled
| Self::Oxigraph
| Self::Origin
| Self::Test
)
}
#[must_use]
pub const fn is_persistent_by_design(&self) -> bool {
matches!(self, Self::Sled | Self::RocksDb | Self::Postgres)
}
#[must_use]
pub const fn is_shared_by_design(&self) -> bool {
matches!(
self,
Self::Redis | Self::Postgres | Self::Neo4j | Self::Helix | Self::Origin
)
}
}
impl std::fmt::Display for BackendKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let s = match self {
Self::InMemory => "in-memory",
Self::InMemoryFallback => "in-memory-fallback",
Self::Moka => "moka",
Self::Redis => "redis",
Self::Sled => "sled",
Self::RocksDb => "rocksdb",
Self::Postgres => "postgres",
Self::Neo4j => "neo4j",
Self::Helix => "helix",
Self::Oxigraph => "oxigraph",
Self::Origin => "origin",
Self::Test => "test",
Self::Unavailable => "unavailable",
};
f.write_str(s)
}
}
#[async_trait::async_trait]
pub trait CacheTier<V>: Send + Sync {
fn name(&self) -> String;
fn backend(&self) -> BackendKind;
fn capability(&self) -> crate::capability::TierCapability {
crate::capability::TierCapability::new(
self.backend(),
crate::capability::CapabilityFlags::EMPTY,
crate::capability::OperationalState::Unavailable,
crate::capability::DurabilityClass::Volatile,
)
}
fn eviction_candidate(&self) -> Option<crate::integrity::KeyAddress> {
None
}
fn remove_if_address(&self, address: crate::integrity::KeyAddress) -> Result<bool, CacheError> {
let _ = address;
Ok(false)
}
async fn get(&self, key: &KeyRef<'_>) -> Result<Option<V>, CacheError>;
async fn set(
&self,
key: &KeyRef<'_>,
value: V,
ttl: Option<Duration>,
) -> Result<(), CacheError>;
async fn remove(&self, key: &KeyRef<'_>) -> Result<(), CacheError>;
async fn contains(&self, key: &KeyRef<'_>) -> Result<bool, CacheError>;
fn health(&self) -> TierHealth;
fn tier_id(&self) -> TierId;
}
#[derive(Debug, Clone)]
pub struct TierHealth {
pub consecutive_failures: u64,
pub last_failure_timestamp: Option<std::time::SystemTime>,
pub health_score: f64,
pub availability: f64,
}
impl Default for TierHealth {
fn default() -> Self {
TierHealth {
consecutive_failures: 0,
last_failure_timestamp: None,
health_score: 1.0,
availability: 1.0,
}
}
}
impl TierHealth {
pub fn healthy(&self) -> bool {
self.consecutive_failures == 0
}
pub fn is_circuit_open(&self) -> bool {
self.consecutive_failures >= 5
}
}