opendal_service_rocksdb/
backend.rs1use std::sync::Arc;
19
20use opendal_core::raw::*;
21use opendal_core::*;
22use rocksdb::DB;
23
24use super::ROCKSDB_SCHEME;
25use super::config::RocksdbConfig;
26use super::core::*;
27use super::deleter::RocksdbDeleter;
28use super::lister::RocksdbLister;
29use super::reader::*;
30use super::writer::RocksdbWriter;
31
32#[doc = include_str!("docs.md")]
34#[derive(Debug, Default)]
35pub struct RocksdbBuilder {
36 pub(super) config: RocksdbConfig,
37}
38
39impl RocksdbBuilder {
40 pub fn datadir(mut self, path: &str) -> Self {
42 self.config.datadir = Some(path.into());
43 self
44 }
45
46 pub fn root(mut self, root: &str) -> Self {
50 self.config.root = if root.is_empty() {
51 None
52 } else {
53 Some(root.to_string())
54 };
55
56 self
57 }
58}
59
60impl Builder for RocksdbBuilder {
61 type Config = RocksdbConfig;
62
63 fn build(self) -> Result<impl Service> {
64 let path = self.config.datadir.ok_or_else(|| {
65 Error::new(ErrorKind::ConfigInvalid, "datadir is required but not set")
66 .with_context("service", ROCKSDB_SCHEME)
67 })?;
68 let db = DB::open_default(&path).map_err(|e| {
69 Error::new(ErrorKind::ConfigInvalid, "open default transaction db")
70 .with_context("service", ROCKSDB_SCHEME)
71 .with_context("datadir", path)
72 .set_source(e)
73 })?;
74
75 let root = normalize_root(&self.config.root.unwrap_or_default());
76
77 Ok(RocksdbBackend::new(RocksdbCore { db: Arc::new(db) }).with_normalized_root(root))
78 }
79}
80
81#[derive(Clone, Debug)]
83pub struct RocksdbBackend {
84 pub(crate) core: Arc<RocksdbCore>,
85 pub(crate) root: String,
86 pub(crate) info: ServiceInfo,
87 pub(crate) capability: Capability,
88}
89
90impl RocksdbBackend {
91 pub fn new(core: RocksdbCore) -> Self {
92 let info = ServiceInfo::new(ROCKSDB_SCHEME, "/", core.db.path().to_string_lossy());
93 let capability = Capability {
94 read: true,
95 stat: true,
96 write: true,
97 write_can_empty: true,
98 delete: true,
99 list: true,
100 list_with_recursive: true,
101 ..Default::default()
102 };
103
104 Self {
105 core: Arc::new(core),
106 root: "/".to_string(),
107 info,
108 capability,
109 }
110 }
111
112 fn with_normalized_root(mut self, root: String) -> Self {
113 self.info = self.info.with_root(&root);
114 self.root = root;
115 self
116 }
117}
118
119impl Service for RocksdbBackend {
120 type Reader = oio::StreamReader<RocksdbReader>;
121 type Writer = RocksdbWriter;
122 type Lister = oio::HierarchyLister<RocksdbLister>;
123 type Deleter = oio::OneShotDeleter<RocksdbDeleter>;
124 type Copier = ();
125
126 fn info(&self) -> ServiceInfo {
127 self.info.clone()
128 }
129
130 fn capability(&self) -> Capability {
131 self.capability
132 }
133
134 async fn create_dir(
135 &self,
136 _ctx: &OperationContext,
137 _path: &str,
138 _args: OpCreateDir,
139 ) -> Result<RpCreateDir> {
140 Err(Error::new(
141 ErrorKind::Unsupported,
142 "operation is not supported",
143 ))
144 }
145
146 async fn stat(&self, _ctx: &OperationContext, path: &str, _: OpStat) -> Result<RpStat> {
147 let p = build_abs_path(&self.root, path);
148
149 if p == build_abs_path(&self.root, "") {
150 Ok(RpStat::new(Metadata::new(EntryMode::DIR)))
151 } else {
152 let bs = self.core.get(&p)?;
153 match bs {
154 Some(bs) => Ok(RpStat::new(
155 Metadata::new(EntryMode::FILE).with_content_length(bs.len() as u64),
156 )),
157 None => Err(Error::new(ErrorKind::NotFound, "kv not found in rocksdb")),
158 }
159 }
160 }
161 fn read(&self, _ctx: &OperationContext, path: &str, args: OpRead) -> Result<Self::Reader> {
162 let output: oio::StreamReader<RocksdbReader> = {
163 Ok(oio::StreamReader::new(RocksdbReader::new(
164 self.clone(),
165 path,
166 args,
167 )))
168 }?;
169
170 Ok(output)
171 }
172
173 fn write(&self, _ctx: &OperationContext, path: &str, _: OpWrite) -> Result<Self::Writer> {
174 let output: RocksdbWriter = {
175 let p = build_abs_path(&self.root, path);
176 let writer = RocksdbWriter::new(self.core.clone(), p);
177 Ok(writer)
178 }?;
179
180 Ok(output)
181 }
182
183 fn delete(&self, _ctx: &OperationContext) -> Result<Self::Deleter> {
184 let output: oio::OneShotDeleter<RocksdbDeleter> = {
185 let deleter = RocksdbDeleter::new(self.core.clone(), self.root.clone());
186 Ok(oio::OneShotDeleter::new(deleter))
187 }?;
188
189 Ok(output)
190 }
191
192 fn list(&self, _ctx: &OperationContext, path: &str, args: OpList) -> Result<Self::Lister> {
193 let output: oio::HierarchyLister<RocksdbLister> = {
194 let p = build_abs_path(&self.root, path);
195 let lister = RocksdbLister::new(self.core.clone(), self.root.clone(), p)?;
196 Ok(oio::HierarchyLister::new(lister, path, args.recursive()))
197 }?;
198
199 Ok(output)
200 }
201
202 fn copy(
203 &self,
204 _ctx: &OperationContext,
205 _from: &str,
206 _to: &str,
207 _args: OpCopy,
208 _opts: OpCopier,
209 ) -> Result<Self::Copier> {
210 Err(Error::new(
211 ErrorKind::Unsupported,
212 "operation is not supported",
213 ))
214 }
215
216 async fn rename(
217 &self,
218 _ctx: &OperationContext,
219 _from: &str,
220 _to: &str,
221 _args: OpRename,
222 ) -> Result<RpRename> {
223 Err(Error::new(
224 ErrorKind::Unsupported,
225 "operation is not supported",
226 ))
227 }
228
229 async fn presign(
230 &self,
231 _ctx: &OperationContext,
232 _path: &str,
233 _args: OpPresign,
234 ) -> Result<RpPresign> {
235 Err(Error::new(
236 ErrorKind::Unsupported,
237 "operation is not supported",
238 ))
239 }
240}