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 match self.inner.get(path) {
176 None => Ok(None),
177 Some(bs) => Ok(Some(bs)),
178 }
179 }
180
181 async fn set(&self, path: &str, value: typed_kv::Value) -> Result<()> {
182 self.inner.insert(path.to_string(), value);
183
184 Ok(())
185 }
186
187 async fn delete(&self, path: &str) -> Result<()> {
188 self.inner.invalidate(path);
189
190 Ok(())
191 }
192
193 async fn scan(&self, path: &str) -> Result<Vec<String>> {
194 let keys = self.inner.iter().map(|kv| kv.0.to_string());
195 if path.is_empty() {
196 Ok(keys.collect())
197 } else {
198 Ok(keys.filter(|k| k.starts_with(path)).collect())
199 }
200 }
201}