opendal/services/moka/
backend.rs1use std::fmt::Debug;
19use std::fmt::Formatter;
20use std::time::Duration;
21
22use log::debug;
23use moka::sync::CacheBuilder;
24use moka::sync::SegmentedCache;
25
26use crate::raw::adapters::typed_kv;
27use crate::raw::*;
28use crate::services::MokaConfig;
29use crate::*;
30
31impl Configurator for MokaConfig {
32 type Builder = MokaBuilder;
33 fn into_builder(self) -> Self::Builder {
34 MokaBuilder { config: self }
35 }
36}
37
38#[doc = include_str!("docs.md")]
40#[derive(Default, Debug)]
41pub struct MokaBuilder {
42 config: MokaConfig,
43}
44
45impl MokaBuilder {
46 pub fn name(mut self, v: &str) -> Self {
48 if !v.is_empty() {
49 self.config.name = Some(v.to_owned());
50 }
51 self
52 }
53
54 pub fn max_capacity(mut self, v: u64) -> Self {
58 if v != 0 {
59 self.config.max_capacity = Some(v);
60 }
61 self
62 }
63
64 pub fn time_to_live(mut self, v: Duration) -> Self {
68 if !v.is_zero() {
69 self.config.time_to_live = Some(v);
70 }
71 self
72 }
73
74 pub fn time_to_idle(mut self, v: Duration) -> Self {
78 if !v.is_zero() {
79 self.config.time_to_idle = Some(v);
80 }
81 self
82 }
83
84 pub fn segments(mut self, v: usize) -> Self {
88 assert!(v != 0);
89 self.config.num_segments = Some(v);
90 self
91 }
92
93 pub fn root(mut self, path: &str) -> Self {
95 self.config.root = if path.is_empty() {
96 None
97 } else {
98 Some(path.to_string())
99 };
100
101 self
102 }
103}
104
105impl Builder for MokaBuilder {
106 const SCHEME: Scheme = Scheme::Moka;
107 type Config = MokaConfig;
108
109 fn build(self) -> Result<impl Access> {
110 debug!("backend build started: {:?}", &self);
111
112 let mut builder: CacheBuilder<String, typed_kv::Value, _> =
113 SegmentedCache::builder(self.config.num_segments.unwrap_or(1));
114 builder = builder.weigher(|k, v| (k.len() + v.size()) as u32);
116 if let Some(v) = &self.config.name {
117 builder = builder.name(v);
118 }
119 if let Some(v) = self.config.max_capacity {
120 builder = builder.max_capacity(v)
121 }
122 if let Some(v) = self.config.time_to_live {
123 builder = builder.time_to_live(v)
124 }
125 if let Some(v) = self.config.time_to_idle {
126 builder = builder.time_to_idle(v)
127 }
128
129 debug!("backend build finished: {:?}", &self);
130
131 let mut backend = MokaBackend::new(Adapter {
132 inner: builder.build(),
133 });
134 if let Some(v) = self.config.root {
135 backend = backend.with_root(&v);
136 }
137
138 Ok(backend)
139 }
140}
141
142pub type MokaBackend = typed_kv::Backend<Adapter>;
144
145#[derive(Clone)]
146pub struct Adapter {
147 inner: SegmentedCache<String, typed_kv::Value>,
148}
149
150impl Debug for Adapter {
151 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
152 f.debug_struct("Adapter")
153 .field("size", &self.inner.weighted_size())
154 .field("count", &self.inner.entry_count())
155 .finish()
156 }
157}
158
159impl typed_kv::Adapter for Adapter {
160 fn info(&self) -> typed_kv::Info {
161 typed_kv::Info::new(
162 Scheme::Moka,
163 self.inner.name().unwrap_or("moka"),
164 typed_kv::Capability {
165 get: true,
166 set: true,
167 delete: true,
168 scan: true,
169 shared: false,
170 },
171 )
172 }
173
174 async fn get(&self, path: &str) -> Result<Option<typed_kv::Value>> {
175 self.blocking_get(path)
176 }
177
178 fn blocking_get(&self, path: &str) -> Result<Option<typed_kv::Value>> {
179 match self.inner.get(path) {
180 None => Ok(None),
181 Some(bs) => Ok(Some(bs)),
182 }
183 }
184
185 async fn set(&self, path: &str, value: typed_kv::Value) -> Result<()> {
186 self.blocking_set(path, value)
187 }
188
189 fn blocking_set(&self, path: &str, value: typed_kv::Value) -> Result<()> {
190 self.inner.insert(path.to_string(), value);
191
192 Ok(())
193 }
194
195 async fn delete(&self, path: &str) -> Result<()> {
196 self.blocking_delete(path)
197 }
198
199 fn blocking_delete(&self, path: &str) -> Result<()> {
200 self.inner.invalidate(path);
201
202 Ok(())
203 }
204
205 async fn scan(&self, path: &str) -> Result<Vec<String>> {
206 self.blocking_scan(path)
207 }
208
209 fn blocking_scan(&self, path: &str) -> Result<Vec<String>> {
210 let keys = self.inner.iter().map(|kv| kv.0.to_string());
211 if path.is_empty() {
212 Ok(keys.collect())
213 } else {
214 Ok(keys.filter(|k| k.starts_with(path)).collect())
215 }
216 }
217}