1use 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::reader::*;
26use super::writer::SledWriter;
27use opendal_core::raw::*;
28use opendal_core::*;
29
30const DEFAULT_TREE_ID: &str = r#"__sled__default"#;
32
33#[doc = include_str!("docs.md")]
35#[derive(Debug, Default)]
36pub struct SledBuilder {
37 pub(super) config: SledConfig,
38}
39
40impl SledBuilder {
41 pub fn datadir(mut self, path: &str) -> Self {
43 self.config.datadir = Some(path.into());
44 self
45 }
46
47 pub fn tree(mut self, tree: &str) -> Self {
49 self.config.tree = Some(tree.into());
50 self
51 }
52
53 pub fn root(mut self, root: &str) -> Self {
55 self.config.root = if root.is_empty() {
56 None
57 } else {
58 Some(root.to_string())
59 };
60
61 self
62 }
63}
64
65impl Builder for SledBuilder {
66 type Config = SledConfig;
67
68 fn build(self) -> Result<impl Service> {
69 let datadir_path = self.config.datadir.ok_or_else(|| {
70 Error::new(ErrorKind::ConfigInvalid, "datadir is required but not set")
71 .with_context("service", SLED_SCHEME)
72 })?;
73
74 let db = sled::open(&datadir_path).map_err(|e| {
75 Error::new(ErrorKind::ConfigInvalid, "open db")
76 .with_context("service", SLED_SCHEME)
77 .with_context("datadir", datadir_path.clone())
78 .set_source(e)
79 })?;
80
81 let tree_name = self
83 .config
84 .tree
85 .unwrap_or_else(|| DEFAULT_TREE_ID.to_string());
86
87 let tree = db.open_tree(&tree_name).map_err(|e| {
88 Error::new(ErrorKind::ConfigInvalid, "open tree")
89 .with_context("service", SLED_SCHEME)
90 .with_context("datadir", datadir_path.clone())
91 .with_context("tree", tree_name.clone())
92 .set_source(e)
93 })?;
94
95 let root = normalize_root(&self.config.root.unwrap_or_default());
96
97 Ok(SledBackend::new(SledCore {
98 datadir: datadir_path,
99 tree,
100 })
101 .with_normalized_root(root))
102 }
103}
104
105#[derive(Clone, Debug)]
107pub struct SledBackend {
108 pub(crate) core: Arc<SledCore>,
109 pub(crate) root: String,
110 pub(crate) info: ServiceInfo,
111 pub(crate) capability: Capability,
112}
113
114impl SledBackend {
115 pub fn new(core: SledCore) -> Self {
116 let info = ServiceInfo::new(SLED_SCHEME, "/", &core.datadir);
117 let 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 ..Default::default()
126 };
127
128 Self {
129 core: Arc::new(core),
130 root: "/".to_string(),
131 info,
132 capability,
133 }
134 }
135
136 fn with_normalized_root(mut self, root: String) -> Self {
137 self.info = self.info.with_root(&root);
138 self.root = root;
139 self
140 }
141}
142
143impl Service for SledBackend {
144 type Reader = oio::StreamReader<SledReader>;
145 type Writer = SledWriter;
146 type Lister = oio::HierarchyLister<SledLister>;
147 type Deleter = oio::OneShotDeleter<SledDeleter>;
148 type Copier = ();
149
150 fn info(&self) -> ServiceInfo {
151 self.info.clone()
152 }
153
154 fn capability(&self) -> Capability {
155 self.capability
156 }
157
158 async fn create_dir(
159 &self,
160 _ctx: &OperationContext,
161 _path: &str,
162 _args: OpCreateDir,
163 ) -> Result<RpCreateDir> {
164 Err(Error::new(
165 ErrorKind::Unsupported,
166 "operation is not supported",
167 ))
168 }
169
170 async fn stat(&self, _ctx: &OperationContext, path: &str, _: OpStat) -> Result<RpStat> {
171 let p = build_abs_path(&self.root, path);
172
173 if p == build_abs_path(&self.root, "") {
174 Ok(RpStat::new(Metadata::new(EntryMode::DIR)))
175 } else {
176 let bs = self.core.get(&p)?;
177 match bs {
178 Some(bs) => Ok(RpStat::new(
179 Metadata::new(EntryMode::FILE).with_content_length(bs.len() as u64),
180 )),
181 None => Err(Error::new(ErrorKind::NotFound, "kv not found in sled")),
182 }
183 }
184 }
185 fn read(&self, _ctx: &OperationContext, path: &str, args: OpRead) -> Result<Self::Reader> {
186 let output: oio::StreamReader<SledReader> = {
187 Ok(oio::StreamReader::new(SledReader::new(
188 self.clone(),
189 path,
190 args,
191 )))
192 }?;
193
194 Ok(output)
195 }
196
197 fn write(&self, _ctx: &OperationContext, path: &str, _: OpWrite) -> Result<Self::Writer> {
198 let output: SledWriter = {
199 let p = build_abs_path(&self.root, path);
200 let writer = SledWriter::new(self.core.clone(), p);
201 Ok(writer)
202 }?;
203
204 Ok(output)
205 }
206
207 fn delete(&self, _ctx: &OperationContext) -> Result<Self::Deleter> {
208 let output: oio::OneShotDeleter<SledDeleter> = {
209 let deleter = SledDeleter::new(self.core.clone(), self.root.clone());
210 Ok(oio::OneShotDeleter::new(deleter))
211 }?;
212
213 Ok(output)
214 }
215
216 fn list(&self, _ctx: &OperationContext, path: &str, args: OpList) -> Result<Self::Lister> {
217 let output: oio::HierarchyLister<SledLister> = {
218 let p = build_abs_path(&self.root, path);
219 let lister = SledLister::new(self.core.clone(), self.root.clone(), p)?;
220 Ok(oio::HierarchyLister::new(lister, path, args.recursive()))
221 }?;
222
223 Ok(output)
224 }
225
226 fn copy(
227 &self,
228 _ctx: &OperationContext,
229 _from: &str,
230 _to: &str,
231 _args: OpCopy,
232 _opts: OpCopier,
233 ) -> Result<Self::Copier> {
234 Err(Error::new(
235 ErrorKind::Unsupported,
236 "operation is not supported",
237 ))
238 }
239
240 async fn rename(
241 &self,
242 _ctx: &OperationContext,
243 _from: &str,
244 _to: &str,
245 _args: OpRename,
246 ) -> Result<RpRename> {
247 Err(Error::new(
248 ErrorKind::Unsupported,
249 "operation is not supported",
250 ))
251 }
252
253 async fn presign(
254 &self,
255 _ctx: &OperationContext,
256 _path: &str,
257 _args: OpPresign,
258 ) -> Result<RpPresign> {
259 Err(Error::new(
260 ErrorKind::Unsupported,
261 "operation is not supported",
262 ))
263 }
264}