1use std::fmt::Debug;
19use std::sync::Arc;
20
21use foyer::HybridCache;
22use log::debug;
23
24use super::FOYER_SCHEME;
25use super::FoyerKey;
26use super::FoyerValue;
27use super::config::FoyerConfig;
28use super::core::FoyerCore;
29use super::deleter::FoyerDeleter;
30use super::reader::*;
31use super::writer::FoyerWriter;
32use opendal_core::raw::*;
33use opendal_core::*;
34
35#[doc = include_str!("docs.md")]
37#[derive(Default)]
38pub struct FoyerBuilder {
39 pub(super) config: FoyerConfig,
40 pub(super) cache: Option<Arc<HybridCache<FoyerKey, FoyerValue>>>,
41}
42
43impl Debug for FoyerBuilder {
44 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
45 f.debug_struct("FoyerBuilder")
46 .field("config", &self.config)
47 .finish_non_exhaustive()
48 }
49}
50
51impl FoyerBuilder {
52 pub fn new() -> Self {
66 Self {
67 ..Default::default()
68 }
69 }
70
71 pub fn name(mut self, name: &str) -> Self {
73 if !name.is_empty() {
74 self.config.name = Some(name.to_owned());
75 }
76 self
77 }
78
79 pub fn cache(mut self, cache: HybridCache<FoyerKey, FoyerValue>) -> Self {
102 self.cache = Some(Arc::new(cache));
103 self
104 }
105
106 pub fn root(mut self, path: &str) -> Self {
110 self.config.root = if path.is_empty() {
111 None
112 } else {
113 Some(path.to_string())
114 };
115 self
116 }
117
118 pub fn memory(mut self, size: usize) -> Self {
125 self.config.memory = Some(size);
126 self
127 }
128
129 pub fn disk_path(mut self, path: &str) -> Self {
134 self.config.disk_path = if path.is_empty() {
135 None
136 } else {
137 Some(path.to_string())
138 };
139 self
140 }
141
142 pub fn disk_capacity(mut self, size: usize) -> Self {
146 self.config.disk_capacity = Some(size);
147 self
148 }
149
150 pub fn disk_file_size(mut self, size: usize) -> Self {
155 self.config.disk_file_size = Some(size);
156 self
157 }
158
159 pub fn recover_mode(mut self, mode: &str) -> Self {
166 if !mode.is_empty() {
167 self.config.recover_mode = Some(mode.to_string());
168 }
169 self
170 }
171
172 pub fn shards(mut self, count: usize) -> Self {
176 self.config.shards = Some(count);
177 self
178 }
179}
180
181impl Builder for FoyerBuilder {
182 type Config = FoyerConfig;
183
184 fn build(self) -> Result<impl Service> {
185 debug!("backend build started: {:?}", self);
186
187 let root = normalize_root(
188 self.config
189 .root
190 .clone()
191 .unwrap_or_else(|| "/".to_string())
192 .as_str(),
193 );
194
195 let mut core = FoyerCore::new(self.config.clone());
196 if let Some(cache) = self.cache {
197 core = core.with_cache(cache.clone());
198 }
199
200 debug!("backend build finished: {:?}", self.config);
201
202 Ok(FoyerBackend::new(core).with_normalized_root(root))
203 }
204}
205
206#[derive(Debug, Clone)]
207pub struct FoyerBackend {
208 pub(crate) core: Arc<FoyerCore>,
209 pub(crate) root: String,
210 pub(crate) info: ServiceInfo,
211 pub(crate) capability: Capability,
212}
213
214impl FoyerBackend {
215 fn new(core: FoyerCore) -> Self {
216 let info = ServiceInfo::new(FOYER_SCHEME, "/", core.name().unwrap_or("foyer"));
217 let capability = Capability {
218 read: true,
219 write: true,
220 write_can_empty: true,
221 delete: true,
222 stat: true,
223 shared: true,
224 ..Default::default()
225 };
226
227 Self {
228 core: Arc::new(core),
229 root: "/".to_string(),
230 info,
231 capability,
232 }
233 }
234
235 fn with_normalized_root(mut self, root: String) -> Self {
236 self.info = self.info.with_root(&root);
237 self.root = root;
238 self
239 }
240}
241
242impl Service for FoyerBackend {
243 type Reader = oio::StreamReader<FoyerReader>;
244 type Writer = FoyerWriter;
245 type Lister = ();
246 type Deleter = oio::OneShotDeleter<FoyerDeleter>;
247 type Copier = ();
248
249 fn info(&self) -> ServiceInfo {
250 self.info.clone()
251 }
252
253 fn capability(&self) -> Capability {
254 self.capability
255 }
256
257 async fn create_dir(
258 &self,
259 _ctx: &OperationContext,
260 _path: &str,
261 _args: OpCreateDir,
262 ) -> Result<RpCreateDir> {
263 Err(Error::new(
264 ErrorKind::Unsupported,
265 "operation is not supported",
266 ))
267 }
268
269 async fn stat(&self, _ctx: &OperationContext, path: &str, _: OpStat) -> Result<RpStat> {
270 let p = build_abs_path(&self.root, path);
271
272 if p == build_abs_path(&self.root, "") {
273 Ok(RpStat::new(Metadata::new(EntryMode::DIR)))
274 } else {
275 match self.core.get(&p).await? {
276 Some(bs) => Ok(RpStat::new(
277 Metadata::new(EntryMode::FILE).with_content_length(bs.len() as u64),
278 )),
279 None => Err(Error::new(ErrorKind::NotFound, "key not found in foyer")),
280 }
281 }
282 }
283 fn read(&self, _ctx: &OperationContext, path: &str, args: OpRead) -> Result<Self::Reader> {
284 let output: oio::StreamReader<FoyerReader> = {
285 Ok(oio::StreamReader::new(FoyerReader::new(
286 self.clone(),
287 path,
288 args,
289 )))
290 }?;
291
292 Ok(output)
293 }
294
295 fn write(&self, _ctx: &OperationContext, path: &str, _: OpWrite) -> Result<Self::Writer> {
296 let output: FoyerWriter = {
297 let p = build_abs_path(&self.root, path);
298 Ok(FoyerWriter::new(self.core.clone(), p))
299 }?;
300
301 Ok(output)
302 }
303
304 fn delete(&self, _ctx: &OperationContext) -> Result<Self::Deleter> {
305 let output: oio::OneShotDeleter<FoyerDeleter> = {
306 Ok(oio::OneShotDeleter::new(FoyerDeleter::new(
307 self.core.clone(),
308 self.root.clone(),
309 )))
310 }?;
311
312 Ok(output)
313 }
314
315 fn list(&self, _ctx: &OperationContext, _path: &str, _args: OpList) -> Result<Self::Lister> {
316 Err(Error::new(
317 ErrorKind::Unsupported,
318 "operation is not supported",
319 ))
320 }
321
322 fn copy(
323 &self,
324 _ctx: &OperationContext,
325 _from: &str,
326 _to: &str,
327 _args: OpCopy,
328 _opts: OpCopier,
329 ) -> Result<Self::Copier> {
330 Err(Error::new(
331 ErrorKind::Unsupported,
332 "operation is not supported",
333 ))
334 }
335
336 async fn rename(
337 &self,
338 _ctx: &OperationContext,
339 _from: &str,
340 _to: &str,
341 _args: OpRename,
342 ) -> Result<RpRename> {
343 Err(Error::new(
344 ErrorKind::Unsupported,
345 "operation is not supported",
346 ))
347 }
348
349 async fn presign(
350 &self,
351 _ctx: &OperationContext,
352 _path: &str,
353 _args: OpPresign,
354 ) -> Result<RpPresign> {
355 Err(Error::new(
356 ErrorKind::Unsupported,
357 "operation is not supported",
358 ))
359 }
360}