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 type Composer = ();
176
177 fn info(&self) -> ServiceInfo {
178 self.info.clone()
179 }
180
181 fn capability(&self) -> Capability {
182 self.capability
183 }
184
185 async fn create_dir(
186 &self,
187 _ctx: &OperationContext,
188 _path: &str,
189 _args: OpCreateDir,
190 ) -> Result<RpCreateDir> {
191 Err(Error::new(
192 ErrorKind::Unsupported,
193 "operation is not supported",
194 ))
195 }
196
197 async fn stat(&self, _ctx: &OperationContext, path: &str, _: OpStat) -> Result<RpStat> {
198 let p = build_abs_path(&self.root, path);
199
200 if p == build_abs_path(&self.root, "") {
201 Ok(RpStat::new(MetadataBuilder::dir().build()))
202 } else {
203 let bs = self.core.get(&p)?;
204 match bs {
205 Some(bs) => Ok(RpStat::new({
206 let metadata = MetadataBuilder::file(bs.len() as u64);
207 metadata.build()
208 })),
209 None => Err(Error::new(ErrorKind::NotFound, "kv not found in redb")),
210 }
211 }
212 }
213 fn read(&self, _ctx: &OperationContext, path: &str, args: OpRead) -> Result<Self::Reader> {
214 let output: oio::StreamReader<RedbReader> = {
215 Ok(oio::StreamReader::new(RedbReader::new(
216 self.clone(),
217 path,
218 args,
219 )))
220 }?;
221
222 Ok(output)
223 }
224
225 fn write(&self, _ctx: &OperationContext, path: &str, _: OpWrite) -> Result<Self::Writer> {
226 let output: RedbWriter = {
227 let p = build_abs_path(&self.root, path);
228 Ok(RedbWriter::new(self.core.clone(), p))
229 }?;
230
231 Ok(output)
232 }
233
234 fn delete(&self, _ctx: &OperationContext) -> Result<Self::Deleter> {
235 let output: oio::OneShotDeleter<RedbDeleter> = {
236 Ok(oio::OneShotDeleter::new(RedbDeleter::new(
237 self.core.clone(),
238 self.root.clone(),
239 )))
240 }?;
241
242 Ok(output)
243 }
244
245 fn list(&self, _ctx: &OperationContext, _path: &str, _args: OpList) -> Result<Self::Lister> {
246 Err(Error::new(
247 ErrorKind::Unsupported,
248 "operation is not supported",
249 ))
250 }
251
252 fn copy(
253 &self,
254 _ctx: &OperationContext,
255 _from: &str,
256 _to: &str,
257 _args: OpCopy,
258 ) -> Result<Self::Copier> {
259 Err(Error::new(
260 ErrorKind::Unsupported,
261 "operation is not supported",
262 ))
263 }
264
265 async fn rename(
266 &self,
267 _ctx: &OperationContext,
268 _from: &str,
269 _to: &str,
270 _args: OpRename,
271 ) -> Result<RpRename> {
272 Err(Error::new(
273 ErrorKind::Unsupported,
274 "operation is not supported",
275 ))
276 }
277
278 async fn presign(
279 &self,
280 _ctx: &OperationContext,
281 _path: &str,
282 _args: OpPresign,
283 ) -> Result<RpPresign> {
284 Err(Error::new(
285 ErrorKind::Unsupported,
286 "operation is not supported",
287 ))
288 }
289}