Skip to main content

opendal_service_foundationdb/
backend.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18use std::fmt::Debug;
19use std::sync::Arc;
20
21use foundationdb::Database;
22
23use super::FOUNDATIONDB_SCHEME;
24use super::config::FoundationdbConfig;
25use super::core::*;
26use super::deleter::FoundationdbDeleter;
27use super::reader::*;
28use super::writer::FoundationdbWriter;
29use opendal_core::raw::*;
30use opendal_core::*;
31
32#[doc = include_str!("docs.md")]
33#[derive(Debug, Default)]
34pub struct FoundationdbBuilder {
35    pub(super) config: FoundationdbConfig,
36}
37
38impl FoundationdbBuilder {
39    /// Set the root for Foundationdb.
40    pub fn root(mut self, path: &str) -> Self {
41        self.config.root = Some(path.into());
42        self
43    }
44
45    /// Set the config path for Foundationdb. If not set, will fallback to use default
46    pub fn config_path(mut self, path: &str) -> Self {
47        self.config.config_path = Some(path.into());
48        self
49    }
50}
51
52impl Builder for FoundationdbBuilder {
53    type Config = FoundationdbConfig;
54
55    fn build(self) -> Result<impl Service> {
56        let _network = Arc::new(unsafe { foundationdb::boot() });
57        let db;
58        if let Some(cfg_path) = &self.config.config_path {
59            db = Database::from_path(cfg_path).map_err(|e| {
60                Error::new(ErrorKind::ConfigInvalid, "open foundation db")
61                    .with_context("service", FOUNDATIONDB_SCHEME)
62                    .set_source(e)
63            })?;
64        } else {
65            db = Database::default().map_err(|e| {
66                Error::new(ErrorKind::ConfigInvalid, "open foundation db")
67                    .with_context("service", FOUNDATIONDB_SCHEME)
68                    .set_source(e)
69            })?
70        }
71
72        let db = Arc::new(db);
73
74        let root = normalize_root(
75            self.config
76                .root
77                .clone()
78                .unwrap_or_else(|| "/".to_string())
79                .as_str(),
80        );
81
82        Ok(FoundationdbBackend::new(FoundationdbCore { db, _network }).with_normalized_root(root))
83    }
84}
85
86/// Backend for Foundationdb services.
87#[derive(Clone, Debug)]
88pub struct FoundationdbBackend {
89    pub(crate) core: Arc<FoundationdbCore>,
90    pub(crate) root: String,
91    pub(crate) info: ServiceInfo,
92    pub(crate) capability: Capability,
93}
94
95impl FoundationdbBackend {
96    pub fn new(core: FoundationdbCore) -> Self {
97        let info = ServiceInfo::new(FOUNDATIONDB_SCHEME, "/", "foundationdb");
98        let capability = Capability {
99            read: true,
100            stat: true,
101            write: true,
102            write_can_empty: true,
103            delete: true,
104            shared: true,
105            ..Default::default()
106        };
107
108        Self {
109            core: Arc::new(core),
110            root: "/".to_string(),
111            info,
112            capability,
113        }
114    }
115
116    fn with_normalized_root(mut self, root: String) -> Self {
117        self.info = self.info.with_root(&root);
118        self.root = root;
119        self
120    }
121}
122
123impl Service for FoundationdbBackend {
124    type Reader = oio::StreamReader<FoundationdbReader>;
125    type Writer = FoundationdbWriter;
126    type Lister = ();
127    type Deleter = oio::OneShotDeleter<FoundationdbDeleter>;
128    type Copier = ();
129    type Composer = ();
130
131    fn info(&self) -> ServiceInfo {
132        self.info.clone()
133    }
134
135    fn capability(&self) -> Capability {
136        self.capability
137    }
138
139    async fn create_dir(
140        &self,
141        _ctx: &OperationContext,
142        _path: &str,
143        _args: OpCreateDir,
144    ) -> Result<RpCreateDir> {
145        Err(Error::new(
146            ErrorKind::Unsupported,
147            "operation is not supported",
148        ))
149    }
150
151    async fn stat(&self, _ctx: &OperationContext, path: &str, _: OpStat) -> Result<RpStat> {
152        let p = build_abs_path(&self.root, path);
153
154        if p == build_abs_path(&self.root, "") {
155            Ok(RpStat::new(MetadataBuilder::dir().build()))
156        } else {
157            let bs = self.core.get(&p).await?;
158            match bs {
159                Some(bs) => Ok(RpStat::new({
160                    let metadata = MetadataBuilder::file(bs.len() as u64);
161                    metadata.build()
162                })),
163                None => Err(Error::new(
164                    ErrorKind::NotFound,
165                    "kv not found in foundationdb",
166                )),
167            }
168        }
169    }
170    fn read(&self, _ctx: &OperationContext, path: &str, args: OpRead) -> Result<Self::Reader> {
171        let output: oio::StreamReader<FoundationdbReader> = {
172            Ok(oio::StreamReader::new(FoundationdbReader::new(
173                self.clone(),
174                path,
175                args,
176            )))
177        }?;
178
179        Ok(output)
180    }
181
182    fn write(&self, _ctx: &OperationContext, path: &str, _: OpWrite) -> Result<Self::Writer> {
183        let output: FoundationdbWriter = {
184            let p = build_abs_path(&self.root, path);
185            Ok(FoundationdbWriter::new(self.core.clone(), p))
186        }?;
187
188        Ok(output)
189    }
190
191    fn delete(&self, _ctx: &OperationContext) -> Result<Self::Deleter> {
192        let output: oio::OneShotDeleter<FoundationdbDeleter> = {
193            Ok(oio::OneShotDeleter::new(FoundationdbDeleter::new(
194                self.core.clone(),
195                self.root.clone(),
196            )))
197        }?;
198
199        Ok(output)
200    }
201
202    fn list(&self, _ctx: &OperationContext, _path: &str, _args: OpList) -> Result<Self::Lister> {
203        Err(Error::new(
204            ErrorKind::Unsupported,
205            "operation is not supported",
206        ))
207    }
208
209    fn copy(
210        &self,
211        _ctx: &OperationContext,
212        _from: &str,
213        _to: &str,
214        _args: OpCopy,
215    ) -> Result<Self::Copier> {
216        Err(Error::new(
217            ErrorKind::Unsupported,
218            "operation is not supported",
219        ))
220    }
221
222    async fn rename(
223        &self,
224        _ctx: &OperationContext,
225        _from: &str,
226        _to: &str,
227        _args: OpRename,
228    ) -> Result<RpRename> {
229        Err(Error::new(
230            ErrorKind::Unsupported,
231            "operation is not supported",
232        ))
233    }
234
235    async fn presign(
236        &self,
237        _ctx: &OperationContext,
238        _path: &str,
239        _args: OpPresign,
240    ) -> Result<RpPresign> {
241        Err(Error::new(
242            ErrorKind::Unsupported,
243            "operation is not supported",
244        ))
245    }
246}