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
130    fn info(&self) -> ServiceInfo {
131        self.info.clone()
132    }
133
134    fn capability(&self) -> Capability {
135        self.capability
136    }
137
138    async fn create_dir(
139        &self,
140        _ctx: &OperationContext,
141        _path: &str,
142        _args: OpCreateDir,
143    ) -> Result<RpCreateDir> {
144        Err(Error::new(
145            ErrorKind::Unsupported,
146            "operation is not supported",
147        ))
148    }
149
150    async fn stat(&self, _ctx: &OperationContext, path: &str, _: OpStat) -> Result<RpStat> {
151        let p = build_abs_path(&self.root, path);
152
153        if p == build_abs_path(&self.root, "") {
154            Ok(RpStat::new(Metadata::new(EntryMode::DIR)))
155        } else {
156            let bs = self.core.get(&p).await?;
157            match bs {
158                Some(bs) => Ok(RpStat::new(
159                    Metadata::new(EntryMode::FILE).with_content_length(bs.len() as u64),
160                )),
161                None => Err(Error::new(
162                    ErrorKind::NotFound,
163                    "kv not found in foundationdb",
164                )),
165            }
166        }
167    }
168    fn read(&self, _ctx: &OperationContext, path: &str, args: OpRead) -> Result<Self::Reader> {
169        let output: oio::StreamReader<FoundationdbReader> = {
170            Ok(oio::StreamReader::new(FoundationdbReader::new(
171                self.clone(),
172                path,
173                args,
174            )))
175        }?;
176
177        Ok(output)
178    }
179
180    fn write(&self, _ctx: &OperationContext, path: &str, _: OpWrite) -> Result<Self::Writer> {
181        let output: FoundationdbWriter = {
182            let p = build_abs_path(&self.root, path);
183            Ok(FoundationdbWriter::new(self.core.clone(), p))
184        }?;
185
186        Ok(output)
187    }
188
189    fn delete(&self, _ctx: &OperationContext) -> Result<Self::Deleter> {
190        let output: oio::OneShotDeleter<FoundationdbDeleter> = {
191            Ok(oio::OneShotDeleter::new(FoundationdbDeleter::new(
192                self.core.clone(),
193                self.root.clone(),
194            )))
195        }?;
196
197        Ok(output)
198    }
199
200    fn list(&self, _ctx: &OperationContext, _path: &str, _args: OpList) -> Result<Self::Lister> {
201        Err(Error::new(
202            ErrorKind::Unsupported,
203            "operation is not supported",
204        ))
205    }
206
207    fn copy(
208        &self,
209        _ctx: &OperationContext,
210        _from: &str,
211        _to: &str,
212        _args: OpCopy,
213        _opts: OpCopier,
214    ) -> Result<Self::Copier> {
215        Err(Error::new(
216            ErrorKind::Unsupported,
217            "operation is not supported",
218        ))
219    }
220
221    async fn rename(
222        &self,
223        _ctx: &OperationContext,
224        _from: &str,
225        _to: &str,
226        _args: OpRename,
227    ) -> Result<RpRename> {
228        Err(Error::new(
229            ErrorKind::Unsupported,
230            "operation is not supported",
231        ))
232    }
233
234    async fn presign(
235        &self,
236        _ctx: &OperationContext,
237        _path: &str,
238        _args: OpPresign,
239    ) -> Result<RpPresign> {
240        Err(Error::new(
241            ErrorKind::Unsupported,
242            "operation is not supported",
243        ))
244    }
245}