opendal/services/foundationdb/
backend.rs1use std::fmt::Debug;
19use std::fmt::Formatter;
20use std::sync::Arc;
21
22use foundationdb::api::NetworkAutoStop;
23use foundationdb::Database;
24
25use crate::raw::adapters::kv;
26use crate::raw::*;
27use crate::services::FoundationdbConfig;
28use crate::Builder;
29use crate::Error;
30use crate::ErrorKind;
31use crate::Scheme;
32use crate::*;
33
34impl Configurator for FoundationdbConfig {
35 type Builder = FoundationdbBuilder;
36 fn into_builder(self) -> Self::Builder {
37 FoundationdbBuilder { config: self }
38 }
39}
40
41#[doc = include_str!("docs.md")]
42#[derive(Default)]
43pub struct FoundationdbBuilder {
44 config: FoundationdbConfig,
45}
46
47impl FoundationdbBuilder {
48 pub fn root(mut self, path: &str) -> Self {
50 self.config.root = Some(path.into());
51 self
52 }
53
54 pub fn config_path(mut self, path: &str) -> Self {
56 self.config.config_path = Some(path.into());
57 self
58 }
59}
60
61impl Builder for FoundationdbBuilder {
62 const SCHEME: Scheme = Scheme::Foundationdb;
63 type Config = FoundationdbConfig;
64
65 fn build(self) -> Result<impl Access> {
66 let _network = Arc::new(unsafe { foundationdb::boot() });
67 let db;
68 if let Some(cfg_path) = &self.config.config_path {
69 db = Database::from_path(cfg_path).map_err(|e| {
70 Error::new(ErrorKind::ConfigInvalid, "open foundation db")
71 .with_context("service", Scheme::Foundationdb)
72 .set_source(e)
73 })?;
74 } else {
75 db = Database::default().map_err(|e| {
76 Error::new(ErrorKind::ConfigInvalid, "open foundation db")
77 .with_context("service", Scheme::Foundationdb)
78 .set_source(e)
79 })?
80 }
81
82 let db = Arc::new(db);
83
84 let root = normalize_root(
85 self.config
86 .root
87 .clone()
88 .unwrap_or_else(|| "/".to_string())
89 .as_str(),
90 );
91
92 Ok(FoundationdbBackend::new(Adapter { db, _network }).with_normalized_root(root))
93 }
94}
95
96pub type FoundationdbBackend = kv::Backend<Adapter>;
98
99#[derive(Clone)]
100pub struct Adapter {
101 db: Arc<Database>,
102 _network: Arc<NetworkAutoStop>,
103}
104
105impl Debug for Adapter {
106 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
107 let mut ds = f.debug_struct("Adapter");
108 ds.finish()
109 }
110}
111
112impl kv::Adapter for Adapter {
113 type Scanner = ();
114
115 fn info(&self) -> kv::Info {
116 kv::Info::new(
117 Scheme::Foundationdb,
118 "foundationdb",
119 Capability {
120 read: true,
121 write: true,
122 delete: true,
123 shared: true,
124 ..Default::default()
125 },
126 )
127 }
128
129 async fn get(&self, path: &str) -> Result<Option<Buffer>> {
130 let transaction = self.db.create_trx().expect("Unable to create transaction");
131
132 match transaction.get(path.as_bytes(), false).await {
133 Ok(slice) => match slice {
134 Some(data) => Ok(Some(Buffer::from(data.to_vec()))),
135 None => Err(Error::new(
136 ErrorKind::NotFound,
137 "foundationdb: key not found",
138 )),
139 },
140 Err(_) => Err(Error::new(
141 ErrorKind::NotFound,
142 "foundationdb: key not found",
143 )),
144 }
145 }
146
147 async fn set(&self, path: &str, value: Buffer) -> Result<()> {
148 let transaction = self.db.create_trx().expect("Unable to create transaction");
149
150 transaction.set(path.as_bytes(), &value.to_vec());
151
152 match transaction.commit().await {
153 Ok(_) => Ok(()),
154 Err(e) => Err(parse_transaction_commit_error(e)),
155 }
156 }
157
158 async fn delete(&self, path: &str) -> Result<()> {
159 let transaction = self.db.create_trx().expect("Unable to create transaction");
160 transaction.clear(path.as_bytes());
161
162 match transaction.commit().await {
163 Ok(_) => Ok(()),
164 Err(e) => Err(parse_transaction_commit_error(e)),
165 }
166 }
167}
168
169fn parse_transaction_commit_error(e: foundationdb::TransactionCommitError) -> Error {
170 Error::new(ErrorKind::Unexpected, e.to_string().as_str())
171 .with_context("service", Scheme::Foundationdb)
172}