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 type Composer = ();
249
250 fn info(&self) -> ServiceInfo {
251 self.info.clone()
252 }
253
254 fn capability(&self) -> Capability {
255 self.capability
256 }
257
258 async fn create_dir(
259 &self,
260 _ctx: &OperationContext,
261 _path: &str,
262 _args: OpCreateDir,
263 ) -> Result<RpCreateDir> {
264 Err(Error::new(
265 ErrorKind::Unsupported,
266 "operation is not supported",
267 ))
268 }
269
270 async fn stat(&self, _ctx: &OperationContext, path: &str, _: OpStat) -> Result<RpStat> {
271 let p = build_abs_path(&self.root, path);
272
273 if p == build_abs_path(&self.root, "") {
274 Ok(RpStat::new(MetadataBuilder::dir().build()))
275 } else {
276 match self.core.get(&p).await? {
277 Some(bs) => Ok(RpStat::new({
278 let metadata = MetadataBuilder::file(bs.len() as u64);
279 metadata.build()
280 })),
281 None => Err(Error::new(ErrorKind::NotFound, "key not found in foyer")),
282 }
283 }
284 }
285 fn read(&self, _ctx: &OperationContext, path: &str, args: OpRead) -> Result<Self::Reader> {
286 let output: oio::StreamReader<FoyerReader> = {
287 Ok(oio::StreamReader::new(FoyerReader::new(
288 self.clone(),
289 path,
290 args,
291 )))
292 }?;
293
294 Ok(output)
295 }
296
297 fn write(&self, _ctx: &OperationContext, path: &str, _: OpWrite) -> Result<Self::Writer> {
298 let output: FoyerWriter = {
299 let p = build_abs_path(&self.root, path);
300 Ok(FoyerWriter::new(self.core.clone(), p))
301 }?;
302
303 Ok(output)
304 }
305
306 fn delete(&self, _ctx: &OperationContext) -> Result<Self::Deleter> {
307 let output: oio::OneShotDeleter<FoyerDeleter> = {
308 Ok(oio::OneShotDeleter::new(FoyerDeleter::new(
309 self.core.clone(),
310 self.root.clone(),
311 )))
312 }?;
313
314 Ok(output)
315 }
316
317 fn list(&self, _ctx: &OperationContext, _path: &str, _args: OpList) -> Result<Self::Lister> {
318 Err(Error::new(
319 ErrorKind::Unsupported,
320 "operation is not supported",
321 ))
322 }
323
324 fn copy(
325 &self,
326 _ctx: &OperationContext,
327 _from: &str,
328 _to: &str,
329 _args: OpCopy,
330 ) -> Result<Self::Copier> {
331 Err(Error::new(
332 ErrorKind::Unsupported,
333 "operation is not supported",
334 ))
335 }
336
337 async fn rename(
338 &self,
339 _ctx: &OperationContext,
340 _from: &str,
341 _to: &str,
342 _args: OpRename,
343 ) -> Result<RpRename> {
344 Err(Error::new(
345 ErrorKind::Unsupported,
346 "operation is not supported",
347 ))
348 }
349
350 async fn presign(
351 &self,
352 _ctx: &OperationContext,
353 _path: &str,
354 _args: OpPresign,
355 ) -> Result<RpPresign> {
356 Err(Error::new(
357 ErrorKind::Unsupported,
358 "operation is not supported",
359 ))
360 }
361}