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