opendal/services/redb/
backend.rs1use 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::writer::RedbWriter;
26use crate::raw::*;
27use crate::*;
28
29#[doc = include_str!("docs.md")]
31#[derive(Default)]
32pub struct RedbBuilder {
33 pub(super) config: RedbConfig,
34
35 pub(super) database: Option<Arc<redb::Database>>,
36}
37
38impl Debug for RedbBuilder {
39 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
40 f.debug_struct("RedbBuilder")
41 .field("config", &self.config)
42 .finish_non_exhaustive()
43 }
44}
45
46impl RedbBuilder {
47 pub fn database(mut self, db: Arc<redb::Database>) -> Self {
60 self.database = Some(db);
61 self
62 }
63
64 pub fn datadir(mut self, path: &str) -> Self {
78 self.config.datadir = Some(path.into());
79 self
80 }
81
82 pub fn table(mut self, table: &str) -> Self {
84 self.config.table = Some(table.into());
85 self
86 }
87
88 pub fn root(mut self, path: &str) -> Self {
90 self.config.root = Some(path.into());
91 self
92 }
93}
94
95impl Builder for RedbBuilder {
96 type Config = RedbConfig;
97
98 fn build(self) -> Result<impl Access> {
99 let table_name = self.config.table.ok_or_else(|| {
100 Error::new(ErrorKind::ConfigInvalid, "table is required but not set")
101 .with_context("service", REDB_SCHEME)
102 })?;
103
104 let (datadir, db) = if let Some(db) = self.database {
105 (None, db)
106 } else {
107 let datadir = self.config.datadir.ok_or_else(|| {
108 Error::new(ErrorKind::ConfigInvalid, "datadir is required but not set")
109 .with_context("service", REDB_SCHEME)
110 })?;
111
112 let db = redb::Database::create(&datadir)
113 .map_err(parse_database_error)?
114 .into();
115
116 (Some(datadir), db)
117 };
118
119 create_table(&db, &table_name)?;
120
121 let root = normalize_root(&self.config.root.unwrap_or_default());
122
123 Ok(RedbBackend::new(RedbCore {
124 datadir,
125 table: table_name,
126 db,
127 })
128 .with_normalized_root(root))
129 }
130}
131
132#[derive(Clone, Debug)]
134pub struct RedbBackend {
135 core: Arc<RedbCore>,
136 root: String,
137 info: Arc<AccessorInfo>,
138}
139
140impl RedbBackend {
141 pub fn new(core: RedbCore) -> Self {
142 let info = AccessorInfo::default();
143 info.set_scheme(REDB_SCHEME);
144 info.set_name(&core.table);
145 info.set_root("/");
146 info.set_native_capability(Capability {
147 read: true,
148 stat: true,
149 write: true,
150 write_can_empty: true,
151 delete: true,
152 shared: false,
153 ..Default::default()
154 });
155
156 Self {
157 core: Arc::new(core),
158 root: "/".to_string(),
159 info: Arc::new(info),
160 }
161 }
162
163 fn with_normalized_root(mut self, root: String) -> Self {
164 self.info.set_root(&root);
165 self.root = root;
166 self
167 }
168}
169
170impl Access for RedbBackend {
171 type Reader = Buffer;
172 type Writer = RedbWriter;
173 type Lister = ();
174 type Deleter = oio::OneShotDeleter<RedbDeleter>;
175
176 fn info(&self) -> Arc<AccessorInfo> {
177 self.info.clone()
178 }
179
180 async fn stat(&self, path: &str, _: OpStat) -> Result<RpStat> {
181 let p = build_abs_path(&self.root, path);
182
183 if p == build_abs_path(&self.root, "") {
184 Ok(RpStat::new(Metadata::new(EntryMode::DIR)))
185 } else {
186 let bs = self.core.get(&p)?;
187 match bs {
188 Some(bs) => Ok(RpStat::new(
189 Metadata::new(EntryMode::FILE).with_content_length(bs.len() as u64),
190 )),
191 None => Err(Error::new(ErrorKind::NotFound, "kv not found in redb")),
192 }
193 }
194 }
195
196 async fn read(&self, path: &str, args: OpRead) -> Result<(RpRead, Self::Reader)> {
197 let p = build_abs_path(&self.root, path);
198 let bs = match self.core.get(&p)? {
199 Some(bs) => bs,
200 None => {
201 return Err(Error::new(ErrorKind::NotFound, "kv not found in redb"));
202 }
203 };
204 Ok((RpRead::new(), bs.slice(args.range().to_range_as_usize())))
205 }
206
207 async fn write(&self, path: &str, _: OpWrite) -> Result<(RpWrite, Self::Writer)> {
208 let p = build_abs_path(&self.root, path);
209 Ok((RpWrite::new(), RedbWriter::new(self.core.clone(), p)))
210 }
211
212 async fn delete(&self) -> Result<(RpDelete, Self::Deleter)> {
213 Ok((
214 RpDelete::default(),
215 oio::OneShotDeleter::new(RedbDeleter::new(self.core.clone(), self.root.clone())),
216 ))
217 }
218}