opendal/services/sled/
backend.rs1use std::fmt::Debug;
19use std::fmt::Formatter;
20use std::str;
21
22use crate::raw::adapters::kv;
23use crate::raw::*;
24use crate::services::SledConfig;
25use crate::Builder;
26use crate::Error;
27use crate::ErrorKind;
28use crate::Scheme;
29use crate::*;
30
31const DEFAULT_TREE_ID: &str = r#"__sled__default"#;
33
34impl Configurator for SledConfig {
35 type Builder = SledBuilder;
36 fn into_builder(self) -> Self::Builder {
37 SledBuilder { config: self }
38 }
39}
40
41#[doc = include_str!("docs.md")]
43#[derive(Default)]
44pub struct SledBuilder {
45 config: SledConfig,
46}
47
48impl Debug for SledBuilder {
49 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
50 f.debug_struct("SledBuilder")
51 .field("config", &self.config)
52 .finish()
53 }
54}
55
56impl SledBuilder {
57 pub fn datadir(mut self, path: &str) -> Self {
59 self.config.datadir = Some(path.into());
60 self
61 }
62
63 pub fn root(mut self, root: &str) -> Self {
65 self.config.root = if root.is_empty() {
66 None
67 } else {
68 Some(root.to_string())
69 };
70
71 self
72 }
73
74 pub fn tree(mut self, tree: &str) -> Self {
76 self.config.tree = Some(tree.into());
77 self
78 }
79}
80
81impl Builder for SledBuilder {
82 const SCHEME: Scheme = Scheme::Sled;
83 type Config = SledConfig;
84
85 fn build(self) -> Result<impl Access> {
86 let datadir_path = self.config.datadir.ok_or_else(|| {
87 Error::new(ErrorKind::ConfigInvalid, "datadir is required but not set")
88 .with_context("service", Scheme::Sled)
89 })?;
90
91 let db = sled::open(&datadir_path).map_err(|e| {
92 Error::new(ErrorKind::ConfigInvalid, "open db")
93 .with_context("service", Scheme::Sled)
94 .with_context("datadir", datadir_path.clone())
95 .set_source(e)
96 })?;
97
98 let tree_name = self
100 .config
101 .tree
102 .unwrap_or_else(|| DEFAULT_TREE_ID.to_string());
103
104 let tree = db.open_tree(&tree_name).map_err(|e| {
105 Error::new(ErrorKind::ConfigInvalid, "open tree")
106 .with_context("service", Scheme::Sled)
107 .with_context("datadir", datadir_path.clone())
108 .with_context("tree", tree_name.clone())
109 .set_source(e)
110 })?;
111
112 Ok(SledBackend::new(Adapter {
113 datadir: datadir_path,
114 tree,
115 })
116 .with_root(self.config.root.as_deref().unwrap_or("/")))
117 }
118}
119
120pub type SledBackend = kv::Backend<Adapter>;
122
123#[derive(Clone)]
124pub struct Adapter {
125 datadir: String,
126 tree: sled::Tree,
127}
128
129impl Debug for Adapter {
130 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
131 let mut ds = f.debug_struct("Adapter");
132 ds.field("path", &self.datadir);
133 ds.finish()
134 }
135}
136
137impl kv::Adapter for Adapter {
138 type Scanner = kv::Scanner;
139
140 fn info(&self) -> kv::Info {
141 kv::Info::new(
142 Scheme::Sled,
143 &self.datadir,
144 Capability {
145 read: true,
146 write: true,
147 list: true,
148 shared: false,
149 ..Default::default()
150 },
151 )
152 }
153
154 async fn get(&self, path: &str) -> Result<Option<Buffer>> {
155 Ok(self
156 .tree
157 .get(path)
158 .map_err(parse_error)?
159 .map(|v| Buffer::from(v.to_vec())))
160 }
161
162 async fn set(&self, path: &str, value: Buffer) -> Result<()> {
163 self.tree
164 .insert(path, value.to_vec())
165 .map_err(parse_error)?;
166 Ok(())
167 }
168
169 async fn delete(&self, path: &str) -> Result<()> {
170 self.tree.remove(path).map_err(parse_error)?;
171
172 Ok(())
173 }
174
175 async fn scan(&self, path: &str) -> Result<Self::Scanner> {
176 let it = self.tree.scan_prefix(path).keys();
177 let mut res = Vec::default();
178
179 for i in it {
180 let bs = i.map_err(parse_error)?.to_vec();
181 let v = String::from_utf8(bs).map_err(|err| {
182 Error::new(ErrorKind::Unexpected, "store key is not valid utf-8 string")
183 .set_source(err)
184 })?;
185
186 res.push(v);
187 }
188
189 Ok(Box::new(kv::ScanStdIter::new(res.into_iter().map(Ok))))
190 }
191}
192
193fn parse_error(err: sled::Error) -> Error {
194 Error::new(ErrorKind::Unexpected, "error from sled").set_source(err)
195}