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