1use std::fmt::Debug;
19use std::sync::Arc;
20
21use super::REDB_SCHEME;
22use super::config::RedbConfig;
23use super::core::*;
24use super::deleter::RedbDeleter;
25use super::reader::*;
26use super::writer::RedbWriter;
27use opendal_core::raw::*;
28use opendal_core::*;
29
30#[doc = include_str!("docs.md")]
32#[derive(Default)]
33pub struct RedbBuilder {
34 pub(super) config: RedbConfig,
35
36 pub(super) database: Option<Arc<redb::Database>>,
37}
38
39impl Debug for RedbBuilder {
40 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
41 f.debug_struct("RedbBuilder")
42 .field("config", &self.config)
43 .finish_non_exhaustive()
44 }
45}
46
47impl RedbBuilder {
48 pub fn database(mut self, db: Arc<redb::Database>) -> Self {
61 self.database = Some(db);
62 self
63 }
64
65 pub fn datadir(mut self, path: &str) -> Self {
79 self.config.datadir = Some(path.into());
80 self
81 }
82
83 pub fn table(mut self, table: &str) -> Self {
85 self.config.table = Some(table.into());
86 self
87 }
88
89 pub fn root(mut self, path: &str) -> Self {
91 self.config.root = Some(path.into());
92 self
93 }
94}
95
96impl Builder for RedbBuilder {
97 type Config = RedbConfig;
98
99 fn build(self) -> Result<impl Service> {
100 let table_name = self.config.table.ok_or_else(|| {
101 Error::new(ErrorKind::ConfigInvalid, "table is required but not set")
102 .with_context("service", REDB_SCHEME)
103 })?;
104
105 let (datadir, db) = if let Some(db) = self.database {
106 (None, db)
107 } else {
108 let datadir = self.config.datadir.ok_or_else(|| {
109 Error::new(ErrorKind::ConfigInvalid, "datadir is required but not set")
110 .with_context("service", REDB_SCHEME)
111 })?;
112
113 let db = redb::Database::create(&datadir)
114 .map_err(parse_database_error)?
115 .into();
116
117 (Some(datadir), db)
118 };
119
120 create_table(&db, &table_name)?;
121
122 let root = normalize_root(&self.config.root.unwrap_or_default());
123
124 Ok(RedbBackend::new(RedbCore {
125 datadir,
126 table: table_name,
127 db,
128 })
129 .with_normalized_root(root))
130 }
131}
132
133#[derive(Clone, Debug)]
135pub struct RedbBackend {
136 pub(crate) core: Arc<RedbCore>,
137 pub(crate) root: String,
138 pub(crate) info: ServiceInfo,
139 pub(crate) capability: Capability,
140}
141
142impl RedbBackend {
143 pub fn new(core: RedbCore) -> Self {
144 let info = ServiceInfo::new(REDB_SCHEME, "/", &core.table);
145 let capability = Capability {
146 read: true,
147 stat: true,
148 write: true,
149 write_can_empty: true,
150 delete: true,
151 ..Default::default()
152 };
153
154 Self {
155 core: Arc::new(core),
156 root: "/".to_string(),
157 info,
158 capability,
159 }
160 }
161
162 fn with_normalized_root(mut self, root: String) -> Self {
163 self.info = self.info.with_root(&root);
164 self.root = root;
165 self
166 }
167}
168
169impl Service for RedbBackend {
170 type Reader = oio::StreamReader<RedbReader>;
171 type Writer = RedbWriter;
172 type Lister = ();
173 type Deleter = oio::OneShotDeleter<RedbDeleter>;
174 type Copier = ();
175
176 fn info(&self) -> ServiceInfo {
177 self.info.clone()
178 }
179
180 fn capability(&self) -> Capability {
181 self.capability
182 }
183
184 async fn create_dir(
185 &self,
186 _ctx: &OperationContext,
187 _path: &str,
188 _args: OpCreateDir,
189 ) -> Result<RpCreateDir> {
190 Err(Error::new(
191 ErrorKind::Unsupported,
192 "operation is not supported",
193 ))
194 }
195
196 async fn stat(&self, _ctx: &OperationContext, path: &str, _: OpStat) -> Result<RpStat> {
197 let p = build_abs_path(&self.root, path);
198
199 if p == build_abs_path(&self.root, "") {
200 Ok(RpStat::new(Metadata::new(EntryMode::DIR)))
201 } else {
202 let bs = self.core.get(&p)?;
203 match bs {
204 Some(bs) => Ok(RpStat::new(
205 Metadata::new(EntryMode::FILE).with_content_length(bs.len() as u64),
206 )),
207 None => Err(Error::new(ErrorKind::NotFound, "kv not found in redb")),
208 }
209 }
210 }
211 fn read(&self, _ctx: &OperationContext, path: &str, args: OpRead) -> Result<Self::Reader> {
212 let output: oio::StreamReader<RedbReader> = {
213 Ok(oio::StreamReader::new(RedbReader::new(
214 self.clone(),
215 path,
216 args,
217 )))
218 }?;
219
220 Ok(output)
221 }
222
223 fn write(&self, _ctx: &OperationContext, path: &str, _: OpWrite) -> Result<Self::Writer> {
224 let output: RedbWriter = {
225 let p = build_abs_path(&self.root, path);
226 Ok(RedbWriter::new(self.core.clone(), p))
227 }?;
228
229 Ok(output)
230 }
231
232 fn delete(&self, _ctx: &OperationContext) -> Result<Self::Deleter> {
233 let output: oio::OneShotDeleter<RedbDeleter> = {
234 Ok(oio::OneShotDeleter::new(RedbDeleter::new(
235 self.core.clone(),
236 self.root.clone(),
237 )))
238 }?;
239
240 Ok(output)
241 }
242
243 fn list(&self, _ctx: &OperationContext, _path: &str, _args: OpList) -> Result<Self::Lister> {
244 Err(Error::new(
245 ErrorKind::Unsupported,
246 "operation is not supported",
247 ))
248 }
249
250 fn copy(
251 &self,
252 _ctx: &OperationContext,
253 _from: &str,
254 _to: &str,
255 _args: OpCopy,
256 _opts: OpCopier,
257 ) -> Result<Self::Copier> {
258 Err(Error::new(
259 ErrorKind::Unsupported,
260 "operation is not supported",
261 ))
262 }
263
264 async fn rename(
265 &self,
266 _ctx: &OperationContext,
267 _from: &str,
268 _to: &str,
269 _args: OpRename,
270 ) -> Result<RpRename> {
271 Err(Error::new(
272 ErrorKind::Unsupported,
273 "operation is not supported",
274 ))
275 }
276
277 async fn presign(
278 &self,
279 _ctx: &OperationContext,
280 _path: &str,
281 _args: OpPresign,
282 ) -> Result<RpPresign> {
283 Err(Error::new(
284 ErrorKind::Unsupported,
285 "operation is not supported",
286 ))
287 }
288}