electrs_rocksdb/
lib.rs

1// Copyright 2020 Tyler Neely
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14//
15
16//! Rust wrapper for RocksDB.
17//!
18//! # Examples
19//!
20//! ```
21//! use rocksdb::{DB, Options};
22//! // NB: db is automatically closed at end of lifetime
23//! let path = "_path_for_rocksdb_storage";
24//! {
25//!    let db = DB::open_default(path).unwrap();
26//!    db.put(b"my key", b"my value").unwrap();
27//!    match db.get(b"my key") {
28//!        Ok(Some(value)) => println!("retrieved value {}", String::from_utf8(value).unwrap()),
29//!        Ok(None) => println!("value not found"),
30//!        Err(e) => println!("operational problem encountered: {}", e),
31//!    }
32//!    db.delete(b"my key").unwrap();
33//! }
34//! let _ = DB::destroy(&Options::default(), path);
35//! ```
36//!
37//! Opening a database and a single column family with custom options:
38//!
39//! ```
40//! use rocksdb::{DB, ColumnFamilyDescriptor, Options};
41//!
42//! let path = "_path_for_rocksdb_storage_with_cfs";
43//! let mut cf_opts = Options::default();
44//! cf_opts.set_max_write_buffer_number(16);
45//! let cf = ColumnFamilyDescriptor::new("cf1", cf_opts);
46//!
47//! let mut db_opts = Options::default();
48//! db_opts.create_missing_column_families(true);
49//! db_opts.create_if_missing(true);
50//! {
51//!     let db = DB::open_cf_descriptors(&db_opts, path, vec![cf]).unwrap();
52//! }
53//! let _ = DB::destroy(&db_opts, path);
54//! ```
55//!
56
57#![warn(clippy::pedantic)]
58#![allow(
59    // Next `cast_*` lints don't give alternatives.
60    clippy::cast_possible_wrap, clippy::cast_possible_truncation, clippy::cast_sign_loss,
61    // Next lints produce too much noise/false positives.
62    clippy::module_name_repetitions, clippy::similar_names, clippy::must_use_candidate,
63    // '... may panic' lints.
64    // Too much work to fix.
65    clippy::missing_errors_doc,
66    // False positive: WebSocket
67    clippy::doc_markdown,
68    clippy::missing_safety_doc,
69    clippy::needless_pass_by_value,
70    clippy::ptr_as_ptr,
71    clippy::missing_panics_doc,
72    clippy::from_over_into,
73)]
74
75#[macro_use]
76mod ffi_util;
77
78pub mod backup;
79pub mod checkpoint;
80mod column_family;
81pub mod compaction_filter;
82pub mod compaction_filter_factory;
83mod comparator;
84mod db;
85mod db_iterator;
86mod db_options;
87mod db_pinnable_slice;
88mod iter_range;
89pub mod merge_operator;
90pub mod perf;
91pub mod properties;
92mod slice_transform;
93mod snapshot;
94mod sst_file_writer;
95mod transactions;
96mod write_batch;
97
98pub use crate::{
99    column_family::{
100        AsColumnFamilyRef, BoundColumnFamily, ColumnFamily, ColumnFamilyDescriptor,
101        ColumnFamilyRef, DEFAULT_COLUMN_FAMILY_NAME,
102    },
103    compaction_filter::Decision as CompactionDecision,
104    db::{
105        DBAccess, DBCommon, DBWithThreadMode, LiveFile, MultiThreaded, SingleThreaded, ThreadMode,
106        DB,
107    },
108    db_iterator::{
109        DBIterator, DBIteratorWithThreadMode, DBRawIterator, DBRawIteratorWithThreadMode,
110        DBWALIterator, Direction, IteratorMode,
111    },
112    db_options::{
113        BlockBasedIndexType, BlockBasedOptions, BottommostLevelCompaction, Cache, ChecksumType,
114        CompactOptions, CuckooTableOptions, DBCompactionStyle, DBCompressionType, DBPath,
115        DBRecoveryMode, DataBlockIndexType, Env, FifoCompactOptions, FlushOptions,
116        IngestExternalFileOptions, LogLevel, MemtableFactory, Options, PlainTableFactoryOptions,
117        ReadOptions, UniversalCompactOptions, UniversalCompactionStopStyle, WriteOptions,
118    },
119    db_pinnable_slice::DBPinnableSlice,
120    ffi_util::CStrLike,
121    iter_range::{IterateBounds, PrefixRange},
122    merge_operator::MergeOperands,
123    perf::{PerfContext, PerfMetric, PerfStatsLevel},
124    slice_transform::SliceTransform,
125    snapshot::{Snapshot, SnapshotWithThreadMode},
126    sst_file_writer::SstFileWriter,
127    transactions::{
128        OptimisticTransactionDB, OptimisticTransactionOptions, Transaction, TransactionDB,
129        TransactionDBOptions, TransactionOptions,
130    },
131    write_batch::{WriteBatch, WriteBatchIterator, WriteBatchWithTransaction},
132};
133
134use electrs_librocksdb_sys as ffi;
135
136use std::error;
137use std::fmt;
138
139/// RocksDB error kind.
140#[derive(Debug, Clone, PartialEq, Eq)]
141pub enum ErrorKind {
142    NotFound,
143    Corruption,
144    NotSupported,
145    InvalidArgument,
146    IOError,
147    MergeInProgress,
148    Incomplete,
149    ShutdownInProgress,
150    TimedOut,
151    Aborted,
152    Busy,
153    Expired,
154    TryAgain,
155    CompactionTooLarge,
156    ColumnFamilyDropped,
157    Unknown,
158}
159
160/// A simple wrapper round a string, used for errors reported from
161/// ffi calls.
162#[derive(Debug, Clone, PartialEq, Eq)]
163pub struct Error {
164    message: String,
165}
166
167impl Error {
168    fn new(message: String) -> Error {
169        Error { message }
170    }
171
172    pub fn into_string(self) -> String {
173        self.into()
174    }
175
176    /// Parse corresponding [`ErrorKind`] from error message.
177    pub fn kind(&self) -> ErrorKind {
178        match self.message.split(':').next().unwrap_or("") {
179            "NotFound" => ErrorKind::NotFound,
180            "Corruption" => ErrorKind::Corruption,
181            "Not implemented" => ErrorKind::NotSupported,
182            "Invalid argument" => ErrorKind::InvalidArgument,
183            "IO error" => ErrorKind::IOError,
184            "Merge in progress" => ErrorKind::MergeInProgress,
185            "Result incomplete" => ErrorKind::Incomplete,
186            "Shutdown in progress" => ErrorKind::ShutdownInProgress,
187            "Operation timed out" => ErrorKind::TimedOut,
188            "Operation aborted" => ErrorKind::Aborted,
189            "Resource busy" => ErrorKind::Busy,
190            "Operation expired" => ErrorKind::Expired,
191            "Operation failed. Try again." => ErrorKind::TryAgain,
192            "Compaction too large" => ErrorKind::CompactionTooLarge,
193            "Column family dropped" => ErrorKind::ColumnFamilyDropped,
194            _ => ErrorKind::Unknown,
195        }
196    }
197}
198
199impl AsRef<str> for Error {
200    fn as_ref(&self) -> &str {
201        &self.message
202    }
203}
204
205impl From<Error> for String {
206    fn from(e: Error) -> String {
207        e.message
208    }
209}
210
211impl error::Error for Error {
212    fn description(&self) -> &str {
213        &self.message
214    }
215}
216
217impl fmt::Display for Error {
218    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
219        self.message.fmt(formatter)
220    }
221}
222
223#[cfg(test)]
224mod test {
225    use crate::{
226        OptimisticTransactionDB, OptimisticTransactionOptions, Transaction, TransactionDB,
227        TransactionDBOptions, TransactionOptions,
228    };
229
230    use super::{
231        column_family::UnboundColumnFamily,
232        db_options::{CacheWrapper, EnvWrapper},
233        BlockBasedOptions, BoundColumnFamily, Cache, ColumnFamily, ColumnFamilyDescriptor,
234        DBIterator, DBRawIterator, Env, IngestExternalFileOptions, Options,
235        PlainTableFactoryOptions, ReadOptions, Snapshot, SstFileWriter, WriteBatch, WriteOptions,
236        DB,
237    };
238
239    #[test]
240    fn is_send() {
241        // test (at compile time) that certain types implement the auto-trait Send, either directly for
242        // pointer-wrapping types or transitively for types with all Send fields
243
244        fn is_send<T: Send>() {
245            // dummy function just used for its parameterized type bound
246        }
247
248        is_send::<DB>();
249        is_send::<DBIterator<'_>>();
250        is_send::<DBRawIterator<'_>>();
251        is_send::<Snapshot>();
252        is_send::<Options>();
253        is_send::<ReadOptions>();
254        is_send::<WriteOptions>();
255        is_send::<IngestExternalFileOptions>();
256        is_send::<BlockBasedOptions>();
257        is_send::<PlainTableFactoryOptions>();
258        is_send::<ColumnFamilyDescriptor>();
259        is_send::<ColumnFamily>();
260        is_send::<BoundColumnFamily<'_>>();
261        is_send::<UnboundColumnFamily>();
262        is_send::<SstFileWriter>();
263        is_send::<WriteBatch>();
264        is_send::<Cache>();
265        is_send::<CacheWrapper>();
266        is_send::<Env>();
267        is_send::<EnvWrapper>();
268        is_send::<TransactionDB>();
269        is_send::<OptimisticTransactionDB>();
270        is_send::<Transaction<'_, TransactionDB>>();
271        is_send::<TransactionDBOptions>();
272        is_send::<OptimisticTransactionOptions>();
273        is_send::<TransactionOptions>();
274    }
275
276    #[test]
277    fn is_sync() {
278        // test (at compile time) that certain types implement the auto-trait Sync
279
280        fn is_sync<T: Sync>() {
281            // dummy function just used for its parameterized type bound
282        }
283
284        is_sync::<DB>();
285        is_sync::<Snapshot>();
286        is_sync::<Options>();
287        is_sync::<ReadOptions>();
288        is_sync::<WriteOptions>();
289        is_sync::<IngestExternalFileOptions>();
290        is_sync::<BlockBasedOptions>();
291        is_sync::<PlainTableFactoryOptions>();
292        is_sync::<UnboundColumnFamily>();
293        is_sync::<ColumnFamilyDescriptor>();
294        is_sync::<SstFileWriter>();
295        is_sync::<Cache>();
296        is_sync::<CacheWrapper>();
297        is_sync::<Env>();
298        is_sync::<EnvWrapper>();
299        is_sync::<TransactionDB>();
300        is_sync::<OptimisticTransactionDB>();
301        is_sync::<TransactionDBOptions>();
302        is_sync::<OptimisticTransactionOptions>();
303        is_sync::<TransactionOptions>();
304    }
305}