use async_trait::async_trait;
use hitbox_core::{BoxContext, CacheKey, CacheValue, Offload};
use std::future::Future;
use super::{CompositionReadPolicy, ReadResult};
use crate::composition::CompositionLayer;
#[derive(Debug, Clone, Copy, Default)]
pub struct SequentialReadPolicy;
impl SequentialReadPolicy {
pub fn new() -> Self {
Self
}
}
#[async_trait]
impl CompositionReadPolicy for SequentialReadPolicy {
#[tracing::instrument(skip(self, key, read_l1, read_l2, _offload), level = "trace")]
async fn execute_with<T, E, F1, F2, Fut1, Fut2, O>(
&self,
key: CacheKey,
read_l1: F1,
read_l2: F2,
_offload: &O,
) -> Result<ReadResult<T>, E>
where
T: Send + 'static,
E: Send + std::fmt::Debug + 'static,
F1: FnOnce(CacheKey) -> Fut1 + Send,
F2: FnOnce(CacheKey) -> Fut2 + Send,
Fut1: Future<Output = (Result<Option<CacheValue<T>>, E>, BoxContext)> + Send + 'static,
Fut2: Future<Output = (Result<Option<CacheValue<T>>, E>, BoxContext)> + Send + 'static,
O: Offload<'static>,
{
let (l1_result, l1_ctx) = read_l1(key.clone()).await;
match l1_result {
Ok(Some(value)) => {
tracing::trace!("L1 hit");
return Ok(ReadResult {
value: Some(value),
source: CompositionLayer::L1,
context: l1_ctx,
});
}
Ok(None) => {
tracing::trace!("L1 miss");
}
Err(e) => {
tracing::warn!(error = ?e, "L1 read failed");
}
}
let (l2_result, l2_ctx) = read_l2(key).await;
match l2_result {
Ok(Some(value)) => {
tracing::trace!("L2 hit");
Ok(ReadResult {
value: Some(value),
source: CompositionLayer::L2,
context: l2_ctx,
})
}
Ok(None) => {
tracing::trace!("L2 miss");
Ok(ReadResult {
value: None,
source: CompositionLayer::L2,
context: l2_ctx,
})
}
Err(e) => {
tracing::error!(error = ?e, "L2 read failed");
Err(e)
}
}
}
}