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 type Config = SledConfig;
83
84 fn build(self) -> Result<impl Access> {
85 let datadir_path = self.config.datadir.ok_or_else(|| {
86 Error::new(ErrorKind::ConfigInvalid, "datadir is required but not set")
87 .with_context("service", Scheme::Sled)
88 })?;
89
90 let db = sled::open(&datadir_path).map_err(|e| {
91 Error::new(ErrorKind::ConfigInvalid, "open db")
92 .with_context("service", Scheme::Sled)
93 .with_context("datadir", datadir_path.clone())
94 .set_source(e)
95 })?;
96
97 let tree_name = self
99 .config
100 .tree
101 .unwrap_or_else(|| DEFAULT_TREE_ID.to_string());
102
103 let tree = db.open_tree(&tree_name).map_err(|e| {
104 Error::new(ErrorKind::ConfigInvalid, "open tree")
105 .with_context("service", Scheme::Sled)
106 .with_context("datadir", datadir_path.clone())
107 .with_context("tree", tree_name.clone())
108 .set_source(e)
109 })?;
110
111 Ok(SledBackend::new(Adapter {
112 datadir: datadir_path,
113 tree,
114 })
115 .with_root(self.config.root.as_deref().unwrap_or("/")))
116 }
117}
118
119pub type SledBackend = kv::Backend<Adapter>;
121
122#[derive(Clone)]
123pub struct Adapter {
124 datadir: String,
125 tree: sled::Tree,
126}
127
128impl Debug for Adapter {
129 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
130 let mut ds = f.debug_struct("Adapter");
131 ds.field("path", &self.datadir);
132 ds.finish()
133 }
134}
135
136impl kv::Adapter for Adapter {
137 type Scanner = kv::Scanner;
138
139 fn info(&self) -> kv::Info {
140 kv::Info::new(
141 Scheme::Sled,
142 &self.datadir,
143 Capability {
144 read: true,
145 write: true,
146 list: true,
147 shared: false,
148 ..Default::default()
149 },
150 )
151 }
152
153 async fn get(&self, path: &str) -> Result<Option<Buffer>> {
154 Ok(self
155 .tree
156 .get(path)
157 .map_err(parse_error)?
158 .map(|v| Buffer::from(v.to_vec())))
159 }
160
161 async fn set(&self, path: &str, value: Buffer) -> Result<()> {
162 self.tree
163 .insert(path, value.to_vec())
164 .map_err(parse_error)?;
165 Ok(())
166 }
167
168 async fn delete(&self, path: &str) -> Result<()> {
169 self.tree.remove(path).map_err(parse_error)?;
170
171 Ok(())
172 }
173
174 async fn scan(&self, path: &str) -> Result<Self::Scanner> {
175 let it = self.tree.scan_prefix(path).keys();
176 let mut res = Vec::default();
177
178 for i in it {
179 let bs = i.map_err(parse_error)?.to_vec();
180 let v = String::from_utf8(bs).map_err(|err| {
181 Error::new(ErrorKind::Unexpected, "store key is not valid utf-8 string")
182 .set_source(err)
183 })?;
184
185 res.push(v);
186 }
187
188 Ok(Box::new(kv::ScanStdIter::new(res.into_iter().map(Ok))))
189 }
190}
191
192fn parse_error(err: sled::Error) -> Error {
193 Error::new(ErrorKind::Unexpected, "error from sled").set_source(err)
194}