mytheclipse_cache/
multilayer.rs1use std::time::Duration;
8
9use async_trait::async_trait;
10
11use crate::traits::{Cache, CacheError};
12
13#[derive(Clone)]
19pub struct MultiLayerCache<L1, L2> {
20 l1: L1,
21 l2: L2,
22 populate_l1: bool,
24}
25
26impl<L1, L2> MultiLayerCache<L1, L2>
27where
28 L1: Cache,
29 L2: Cache,
30{
31 pub fn new(l1: L1, l2: L2) -> Self {
33 Self {
34 l1,
35 l2,
36 populate_l1: true,
37 }
38 }
39
40 pub fn without_l1_backfill(mut self) -> Self {
42 self.populate_l1 = false;
43 self
44 }
45
46 pub fn l1(&self) -> &L1 {
48 &self.l1
49 }
50
51 pub fn l2(&self) -> &L2 {
53 &self.l2
54 }
55}
56
57#[async_trait]
58impl<L1, L2> Cache for MultiLayerCache<L1, L2>
59where
60 L1: Cache,
61 L2: Cache,
62{
63 async fn get(&self, key: &str) -> Result<Option<Vec<u8>>, CacheError> {
64 if let Some(value) = self.l1.get(key).await? {
66 return Ok(Some(value));
67 }
68 if let Some(value) = self.l2.get(key).await? {
70 if self.populate_l1 {
71 self.l1.set(key, value.clone(), None).await?;
72 }
73 return Ok(Some(value));
74 }
75 Ok(None)
76 }
77
78 async fn set(
79 &self,
80 key: &str,
81 value: Vec<u8>,
82 ttl: Option<Duration>,
83 ) -> Result<(), CacheError> {
84 self.l1.set(key, value.clone(), ttl).await?;
85 self.l2.set(key, value, ttl).await
86 }
87
88 async fn invalidate(&self, key: &str) -> Result<(), CacheError> {
89 self.l1.invalidate(key).await?;
90 self.l2.invalidate(key).await
91 }
92
93 async fn clear(&self) -> Result<(), CacheError> {
94 self.l1.clear().await?;
95 self.l2.clear().await
96 }
97}
98
99#[cfg(test)]
100mod tests {
101 use super::*;
102 use crate::memory::MemoryCache;
103
104 #[tokio::test]
105 async fn read_through_populates_l1() {
106 let l2 = MemoryCache::new();
107 l2.set("k", b"l2-value".to_vec(), None).await.unwrap();
108
109 let layered = MultiLayerCache::new(MemoryCache::new(), l2);
110 assert_eq!(layered.l1().get("k").await.unwrap(), None);
111 assert_eq!(layered.get("k").await.unwrap(), Some(b"l2-value".to_vec()));
112 assert_eq!(
114 layered.l1().get("k").await.unwrap(),
115 Some(b"l2-value".to_vec())
116 );
117 }
118
119 #[tokio::test]
120 async fn write_goes_to_both() {
121 let l1 = MemoryCache::new();
122 let l2 = MemoryCache::new();
123 let layered = MultiLayerCache::new(l1, l2.clone());
124 layered.set("k", b"v".to_vec(), None).await.unwrap();
125 assert_eq!(layered.l1().get("k").await.unwrap(), Some(b"v".to_vec()));
126 assert_eq!(l2.get("k").await.unwrap(), Some(b"v".to_vec()));
127 }
128
129 #[tokio::test]
130 async fn invalidate_clears_both() {
131 let l1 = MemoryCache::new();
132 let l2 = MemoryCache::new();
133 let layered = MultiLayerCache::new(l1, l2);
134 layered.set("k", b"v".to_vec(), None).await.unwrap();
135 layered.invalidate("k").await.unwrap();
136 assert_eq!(layered.l1().get("k").await.unwrap(), None);
137 assert_eq!(layered.l2().get("k").await.unwrap(), None);
138 }
139}