opendal/services/sled/
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::sync::Arc;
19
20use super::config::SledConfig;
21use super::core::*;
22use super::deleter::SledDeleter;
23use super::lister::SledLister;
24use super::writer::SledWriter;
25use crate::raw::*;
26use crate::*;
27
28// https://github.com/spacejam/sled/blob/69294e59c718289ab3cb6bd03ac3b9e1e072a1e7/src/db.rs#L5
29const DEFAULT_TREE_ID: &str = r#"__sled__default"#;
30
31/// Sled services support.
32#[doc = include_str!("docs.md")]
33#[derive(Default)]
34pub struct SledBuilder {
35    pub(super) config: SledConfig,
36}
37
38impl SledBuilder {
39    /// Set the path to the sled data directory. Will create if not exists.
40    pub fn datadir(mut self, path: &str) -> Self {
41        self.config.datadir = Some(path.into());
42        self
43    }
44
45    /// Set the tree for sled.
46    pub fn tree(mut self, tree: &str) -> Self {
47        self.config.tree = Some(tree.into());
48        self
49    }
50
51    /// Set the root for sled.
52    pub fn root(mut self, root: &str) -> Self {
53        self.config.root = if root.is_empty() {
54            None
55        } else {
56            Some(root.to_string())
57        };
58
59        self
60    }
61}
62
63impl Builder for SledBuilder {
64    type Config = SledConfig;
65
66    fn build(self) -> Result<impl Access> {
67        let datadir_path = self.config.datadir.ok_or_else(|| {
68            Error::new(ErrorKind::ConfigInvalid, "datadir is required but not set")
69                .with_context("service", Scheme::Sled)
70        })?;
71
72        let db = sled::open(&datadir_path).map_err(|e| {
73            Error::new(ErrorKind::ConfigInvalid, "open db")
74                .with_context("service", Scheme::Sled)
75                .with_context("datadir", datadir_path.clone())
76                .set_source(e)
77        })?;
78
79        // use "default" tree if not set
80        let tree_name = self
81            .config
82            .tree
83            .unwrap_or_else(|| DEFAULT_TREE_ID.to_string());
84
85        let tree = db.open_tree(&tree_name).map_err(|e| {
86            Error::new(ErrorKind::ConfigInvalid, "open tree")
87                .with_context("service", Scheme::Sled)
88                .with_context("datadir", datadir_path.clone())
89                .with_context("tree", tree_name.clone())
90                .set_source(e)
91        })?;
92
93        let root = normalize_root(&self.config.root.unwrap_or_default());
94
95        Ok(SledBackend::new(SledCore {
96            datadir: datadir_path,
97            tree,
98        })
99        .with_normalized_root(root))
100    }
101}
102
103/// Backend for sled services.
104#[derive(Clone, Debug)]
105pub struct SledBackend {
106    core: Arc<SledCore>,
107    root: String,
108    info: Arc<AccessorInfo>,
109}
110
111impl SledBackend {
112    pub fn new(core: SledCore) -> Self {
113        let info = AccessorInfo::default();
114        info.set_scheme(Scheme::Sled.into_static())
115            .set_name(&core.datadir)
116            .set_root("/")
117            .set_native_capability(Capability {
118                read: true,
119                stat: true,
120                write: true,
121                write_can_empty: true,
122                delete: true,
123                list: true,
124                list_with_recursive: true,
125                shared: false,
126                ..Default::default()
127            });
128
129        Self {
130            core: Arc::new(core),
131            root: "/".to_string(),
132            info: Arc::new(info),
133        }
134    }
135
136    fn with_normalized_root(mut self, root: String) -> Self {
137        self.info.set_root(&root);
138        self.root = root;
139        self
140    }
141}
142
143impl Access for SledBackend {
144    type Reader = Buffer;
145    type Writer = SledWriter;
146    type Lister = oio::HierarchyLister<SledLister>;
147    type Deleter = oio::OneShotDeleter<SledDeleter>;
148
149    fn info(&self) -> Arc<AccessorInfo> {
150        self.info.clone()
151    }
152
153    async fn stat(&self, path: &str, _: OpStat) -> Result<RpStat> {
154        let p = build_abs_path(&self.root, path);
155
156        if p == build_abs_path(&self.root, "") {
157            Ok(RpStat::new(Metadata::new(EntryMode::DIR)))
158        } else {
159            let bs = self.core.get(&p)?;
160            match bs {
161                Some(bs) => Ok(RpStat::new(
162                    Metadata::new(EntryMode::FILE).with_content_length(bs.len() as u64),
163                )),
164                None => Err(Error::new(ErrorKind::NotFound, "kv not found in sled")),
165            }
166        }
167    }
168
169    async fn read(&self, path: &str, args: OpRead) -> Result<(RpRead, Self::Reader)> {
170        let p = build_abs_path(&self.root, path);
171        let bs = match self.core.get(&p)? {
172            Some(bs) => bs,
173            None => {
174                return Err(Error::new(ErrorKind::NotFound, "kv not found in sled"));
175            }
176        };
177        Ok((RpRead::new(), bs.slice(args.range().to_range_as_usize())))
178    }
179
180    async fn write(&self, path: &str, _: OpWrite) -> Result<(RpWrite, Self::Writer)> {
181        let p = build_abs_path(&self.root, path);
182        let writer = SledWriter::new(self.core.clone(), p);
183        Ok((RpWrite::new(), writer))
184    }
185
186    async fn delete(&self) -> Result<(RpDelete, Self::Deleter)> {
187        let deleter = SledDeleter::new(self.core.clone(), self.root.clone());
188        Ok((RpDelete::default(), oio::OneShotDeleter::new(deleter)))
189    }
190
191    async fn list(&self, path: &str, args: OpList) -> Result<(RpList, Self::Lister)> {
192        let p = build_abs_path(&self.root, path);
193        let lister = SledLister::new(self.core.clone(), self.root.clone(), p)?;
194        Ok((
195            RpList::default(),
196            oio::HierarchyLister::new(lister, path, args.recursive()),
197        ))
198    }
199}