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 type Config = FoundationdbConfig;
63
64 fn build(self) -> Result<impl Access> {
65 let _network = Arc::new(unsafe { foundationdb::boot() });
66 let db;
67 if let Some(cfg_path) = &self.config.config_path {
68 db = Database::from_path(cfg_path).map_err(|e| {
69 Error::new(ErrorKind::ConfigInvalid, "open foundation db")
70 .with_context("service", Scheme::Foundationdb)
71 .set_source(e)
72 })?;
73 } else {
74 db = Database::default().map_err(|e| {
75 Error::new(ErrorKind::ConfigInvalid, "open foundation db")
76 .with_context("service", Scheme::Foundationdb)
77 .set_source(e)
78 })?
79 }
80
81 let db = Arc::new(db);
82
83 let root = normalize_root(
84 self.config
85 .root
86 .clone()
87 .unwrap_or_else(|| "/".to_string())
88 .as_str(),
89 );
90
91 Ok(FoundationdbBackend::new(Adapter { db, _network }).with_normalized_root(root))
92 }
93}
94
95pub type FoundationdbBackend = kv::Backend<Adapter>;
97
98#[derive(Clone)]
99pub struct Adapter {
100 db: Arc<Database>,
101 _network: Arc<NetworkAutoStop>,
102}
103
104impl Debug for Adapter {
105 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
106 let mut ds = f.debug_struct("Adapter");
107 ds.finish()
108 }
109}
110
111impl kv::Adapter for Adapter {
112 type Scanner = ();
113
114 fn info(&self) -> kv::Info {
115 kv::Info::new(
116 Scheme::Foundationdb,
117 "foundationdb",
118 Capability {
119 read: true,
120 write: true,
121 delete: true,
122 shared: true,
123 ..Default::default()
124 },
125 )
126 }
127
128 async fn get(&self, path: &str) -> Result<Option<Buffer>> {
129 let transaction = self.db.create_trx().expect("Unable to create transaction");
130
131 match transaction.get(path.as_bytes(), false).await {
132 Ok(slice) => match slice {
133 Some(data) => Ok(Some(Buffer::from(data.to_vec()))),
134 None => Err(Error::new(
135 ErrorKind::NotFound,
136 "foundationdb: key not found",
137 )),
138 },
139 Err(_) => Err(Error::new(
140 ErrorKind::NotFound,
141 "foundationdb: key not found",
142 )),
143 }
144 }
145
146 async fn set(&self, path: &str, value: Buffer) -> Result<()> {
147 let transaction = self.db.create_trx().expect("Unable to create transaction");
148
149 transaction.set(path.as_bytes(), &value.to_vec());
150
151 match transaction.commit().await {
152 Ok(_) => Ok(()),
153 Err(e) => Err(parse_transaction_commit_error(e)),
154 }
155 }
156
157 async fn delete(&self, path: &str) -> Result<()> {
158 let transaction = self.db.create_trx().expect("Unable to create transaction");
159 transaction.clear(path.as_bytes());
160
161 match transaction.commit().await {
162 Ok(_) => Ok(()),
163 Err(e) => Err(parse_transaction_commit_error(e)),
164 }
165 }
166}
167
168fn parse_transaction_commit_error(e: foundationdb::TransactionCommitError) -> Error {
169 Error::new(ErrorKind::Unexpected, e.to_string().as_str())
170 .with_context("service", Scheme::Foundationdb)
171}