opendal/services/sled/
backend.rs1use 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
28const DEFAULT_TREE_ID: &str = r#"__sled__default"#;
30
31#[doc = include_str!("docs.md")]
33#[derive(Default)]
34pub struct SledBuilder {
35 pub(super) config: SledConfig,
36}
37
38impl SledBuilder {
39 pub fn datadir(mut self, path: &str) -> Self {
41 self.config.datadir = Some(path.into());
42 self
43 }
44
45 pub fn tree(mut self, tree: &str) -> Self {
47 self.config.tree = Some(tree.into());
48 self
49 }
50
51 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 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#[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}