1use std::error::Error;
10use std::fmt::{Display, Formatter};
11
12use miette::{Diagnostic, Severity};
13
14use crate::StatusSeverity;
15
16pub(crate) mod db;
17pub(crate) mod iter;
18pub(crate) mod tx;
19
20#[cxx::bridge]
21pub(crate) mod ffi {
22 #[derive(Debug, Clone)]
23 struct DbOpts {
24 pub db_path: Vec<u8>,
25 pub options_path: Vec<u8>,
26 pub prepare_for_bulk_load: bool,
27 pub increase_parallelism: usize,
28 pub optimize_level_style_compaction: bool,
29 pub create_if_missing: bool,
30 pub paranoid_checks: bool,
31 pub enable_blob_files: bool,
32 pub min_blob_size: usize,
33 pub blob_file_size: usize,
34 pub enable_blob_garbage_collection: bool,
35 pub use_bloom_filter: bool,
36 pub bloom_filter_bits_per_key: f64,
37 pub bloom_filter_whole_key_filtering: bool,
38 pub use_capped_prefix_extractor: bool,
39 pub capped_prefix_extractor_len: usize,
40 pub use_fixed_prefix_extractor: bool,
41 pub fixed_prefix_extractor_len: usize,
42 pub destroy_on_exit: bool,
43 pub block_cache_size: usize,
44 }
45
46 #[derive(Clone, Debug, Eq, PartialEq)]
47 pub struct RocksDbStatus {
48 pub code: StatusCode,
49 pub subcode: StatusSubCode,
50 pub severity: StatusSeverity,
51 pub message: String,
52 }
53
54 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
55 pub enum StatusCode {
56 kOk = 0,
57 kNotFound = 1,
58 kCorruption = 2,
59 kNotSupported = 3,
60 kInvalidArgument = 4,
61 kIOError = 5,
62 kMergeInProgress = 6,
63 kIncomplete = 7,
64 kShutdownInProgress = 8,
65 kTimedOut = 9,
66 kAborted = 10,
67 kBusy = 11,
68 kExpired = 12,
69 kTryAgain = 13,
70 kCompactionTooLarge = 14,
71 kColumnFamilyDropped = 15,
72 kMaxCode,
73 }
74
75 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
76 pub enum StatusSubCode {
77 kNone = 0,
78 kMutexTimeout = 1,
79 kLockTimeout = 2,
80 kLockLimit = 3,
81 kNoSpace = 4,
82 kDeadlock = 5,
83 kStaleFile = 6,
84 kMemoryLimit = 7,
85 kSpaceLimit = 8,
86 kPathNotFound = 9,
87 KMergeOperandsInsufficientCapacity = 10,
88 kManualCompactionPaused = 11,
89 kOverwritten = 12,
90 kTxnNotPrepared = 13,
91 kIOFenced = 14,
92 kMergeOperatorFailed = 15,
93 kMergeOperandThresholdExceeded = 16,
94 kMaxSubCode,
95 }
96
97 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
98 pub enum StatusSeverity {
99 kNoError = 0,
100 kSoftError = 1,
101 kHardError = 2,
102 kFatalError = 3,
103 kUnrecoverableError = 4,
104 kMaxSeverity,
105 }
106
107 unsafe extern "C++" {
108 include!("bridge.h");
109
110 type StatusCode;
111 type StatusSubCode;
112 type StatusSeverity;
113 type WriteOptions;
114 type PinnableSlice;
115 fn convert_pinnable_slice_back(s: &PinnableSlice) -> &[u8];
116
117 fn set_w_opts_sync(o: Pin<&mut WriteOptions>, val: bool);
118 fn set_w_opts_disable_wal(o: Pin<&mut WriteOptions>, val: bool);
119 fn set_w_opts_no_slowdown(o: Pin<&mut WriteOptions>, val: bool);
120
121 pub type SnapshotBridge;
124
125 type RocksDbBridge;
126 fn get_db_path(self: &RocksDbBridge) -> &CxxString;
127 fn open_db(builder: &DbOpts, status: &mut RocksDbStatus) -> SharedPtr<RocksDbBridge>;
128 fn transact(self: &RocksDbBridge) -> UniquePtr<TxBridge>;
129 fn del_range(self: &RocksDbBridge, lower: &[u8], upper: &[u8], status: &mut RocksDbStatus);
130 fn put(self: &RocksDbBridge, key: &[u8], val: &[u8], status: &mut RocksDbStatus);
131 fn compact_range(
132 self: &RocksDbBridge,
133 lower: &[u8],
134 upper: &[u8],
135 status: &mut RocksDbStatus,
136 );
137 fn get_sst_writer(
138 self: &RocksDbBridge,
139 path: &str,
140 status: &mut RocksDbStatus,
141 ) -> UniquePtr<SstFileWriterBridge>;
142 fn ingest_sst(self: &RocksDbBridge, path: &str, status: &mut RocksDbStatus);
143
144 type SstFileWriterBridge;
145 fn put(
146 self: Pin<&mut SstFileWriterBridge>,
147 key: &[u8],
148 val: &[u8],
149 status: &mut RocksDbStatus,
150 );
151 fn finish(self: Pin<&mut SstFileWriterBridge>, status: &mut RocksDbStatus);
152
153 type TxBridge;
154 fn verify_checksums(self: Pin<&mut TxBridge>, val: bool);
156 fn fill_cache(self: Pin<&mut TxBridge>, val: bool);
157 fn get_w_opts(self: Pin<&mut TxBridge>) -> Pin<&mut WriteOptions>;
158 fn start(self: Pin<&mut TxBridge>);
159 fn set_snapshot(self: Pin<&mut TxBridge>, val: bool);
160 fn clear_snapshot(self: Pin<&mut TxBridge>);
161 fn get(
162 self: &TxBridge,
163 key: &[u8],
164 for_update: bool,
165 status: &mut RocksDbStatus,
166 ) -> UniquePtr<PinnableSlice>;
167 fn exists(self: &TxBridge, key: &[u8], for_update: bool, status: &mut RocksDbStatus);
168 fn put(self: &TxBridge, key: &[u8], val: &[u8], status: &mut RocksDbStatus);
169 fn del(self: &TxBridge, key: &[u8], status: &mut RocksDbStatus);
170 fn commit(self: Pin<&mut TxBridge>, status: &mut RocksDbStatus);
171 fn rollback(self: Pin<&mut TxBridge>, status: &mut RocksDbStatus);
172 fn rollback_to_savepoint(self: Pin<&mut TxBridge>, status: &mut RocksDbStatus);
173 fn pop_savepoint(self: Pin<&mut TxBridge>, status: &mut RocksDbStatus);
174 fn set_savepoint(self: Pin<&mut TxBridge>);
175 fn iterator(self: &TxBridge) -> UniquePtr<IterBridge>;
176
177 type IterBridge;
178 fn start(self: Pin<&mut IterBridge>);
179 fn reset(self: Pin<&mut IterBridge>);
180 fn clear_bounds(self: Pin<&mut IterBridge>);
182 fn set_lower_bound(self: Pin<&mut IterBridge>, bound: &[u8]);
183 fn set_upper_bound(self: Pin<&mut IterBridge>, bound: &[u8]);
184 fn verify_checksums(self: Pin<&mut IterBridge>, val: bool);
185 fn fill_cache(self: Pin<&mut IterBridge>, val: bool);
186 fn tailing(self: Pin<&mut IterBridge>, val: bool);
187 fn total_order_seek(self: Pin<&mut IterBridge>, val: bool);
188 fn auto_prefix_mode(self: Pin<&mut IterBridge>, val: bool);
189 fn prefix_same_as_start(self: Pin<&mut IterBridge>, val: bool);
190 fn pin_data(self: Pin<&mut IterBridge>, val: bool);
191
192 fn to_start(self: Pin<&mut IterBridge>);
193 fn to_end(self: Pin<&mut IterBridge>);
194 fn seek(self: Pin<&mut IterBridge>, key: &[u8]);
195 fn seek_backward(self: Pin<&mut IterBridge>, key: &[u8]);
196 fn is_valid(self: &IterBridge) -> bool;
197 fn next(self: Pin<&mut IterBridge>);
198 fn prev(self: Pin<&mut IterBridge>);
199 fn status(self: &IterBridge, status: &mut RocksDbStatus);
200 fn key(self: &IterBridge) -> &[u8];
201 fn val(self: &IterBridge) -> &[u8];
202 }
203}
204
205impl Default for ffi::RocksDbStatus {
206 #[inline]
207 fn default() -> Self {
208 ffi::RocksDbStatus {
209 code: ffi::StatusCode::kOk,
210 subcode: ffi::StatusSubCode::kNone,
211 severity: ffi::StatusSeverity::kNoError,
212 message: "".to_string(),
213 }
214 }
215}
216
217impl Error for ffi::RocksDbStatus {}
218
219impl Display for ffi::RocksDbStatus {
220 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
221 if self.message.is_empty() {
222 write!(f, "RocksDB error: {self:?}")
223 } else {
224 write!(f, "RocksDB error: {}", self.message)
225 }
226 }
227}
228
229impl Diagnostic for ffi::RocksDbStatus {
230 fn code<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
231 if self.is_ok() {
232 None
233 } else {
234 Some(Box::new(format!(
235 "rocksdb::{:?}::{:?}",
236 self.code, self.subcode
237 )))
238 }
239 }
240 fn severity(&self) -> Option<Severity> {
241 match self.severity {
242 StatusSeverity::kNoError => None,
243 _ => Some(Severity::Error),
244 }
245 }
246 fn help<'a>(&'a self) -> Option<Box<dyn Display + 'a>> {
247 Some(Box::new("This error is usually outside Retia's control"))
248 }
249}
250
251impl ffi::RocksDbStatus {
252 #[inline(always)]
253 pub fn is_ok(&self) -> bool {
254 self.code == ffi::StatusCode::kOk
255 }
256 #[inline(always)]
257 pub fn is_not_found(&self) -> bool {
258 self.code == ffi::StatusCode::kNotFound
259 }
260 #[inline(always)]
261 pub fn is_ok_or_not_found(&self) -> bool {
262 self.is_ok() || self.is_not_found()
263 }
264}