rust_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 rust_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 rust_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    clippy::should_panic_without_expect,
75    // False positive: WebSocket
76    clippy::doc_markdown,
77    clippy::missing_safety_doc,
78    clippy::needless_pass_by_value,
79    clippy::ptr_as_ptr,
80    clippy::missing_panics_doc,
81    clippy::from_over_into,
82)]
83
84#[macro_use]
85mod ffi_util;
86
87pub mod backup;
88pub mod checkpoint;
89mod column_family;
90pub mod compaction_filter;
91pub mod compaction_filter_factory;
92mod comparator;
93mod db;
94mod db_iterator;
95mod db_options;
96mod db_pinnable_slice;
97mod env;
98mod iter_range;
99pub mod merge_operator;
100pub mod perf;
101mod prop_name;
102pub mod properties;
103mod slice_transform;
104mod snapshot;
105mod sst_file_writer;
106pub mod statistics;
107mod transactions;
108mod write_batch;
109
110pub use crate::{
111    column_family::{
112        AsColumnFamilyRef, BoundColumnFamily, ColumnFamily, ColumnFamilyDescriptor,
113        ColumnFamilyRef, ColumnFamilyTtl, DEFAULT_COLUMN_FAMILY_NAME,
114    },
115    compaction_filter::Decision as CompactionDecision,
116    db::{
117        DBAccess, DBCommon, DBWithThreadMode, LiveFile, MultiThreaded, SingleThreaded, ThreadMode,
118        DB,
119    },
120    db_iterator::{
121        DBIterator, DBIteratorWithThreadMode, DBRawIterator, DBRawIteratorWithThreadMode,
122        DBWALIterator, Direction, IteratorMode,
123    },
124    db_options::{
125        BlockBasedIndexType, BlockBasedOptions, BlockBasedPinningTier, BottommostLevelCompaction,
126        Cache, ChecksumType, CompactOptions, CuckooTableOptions, DBCompactionPri,
127        DBCompactionStyle, DBCompressionType, DBPath, DBRecoveryMode, DataBlockIndexType,
128        FifoCompactOptions, FlushOptions, IngestExternalFileOptions, KeyEncodingType, LogLevel,
129        LruCacheOptions, MemtableFactory, Options, PlainTableFactoryOptions, RateLimiterMode,
130        ReadOptions, ReadTier, UniversalCompactOptions, UniversalCompactionStopStyle,
131        WaitForCompactOptions, WriteBufferManager, WriteOptions,
132    },
133    db_pinnable_slice::DBPinnableSlice,
134    env::Env,
135    ffi_util::CStrLike,
136    iter_range::{IterateBounds, PrefixRange},
137    merge_operator::MergeOperands,
138    perf::{PerfContext, PerfMetric, PerfStatsLevel},
139    slice_transform::SliceTransform,
140    snapshot::{Snapshot, SnapshotWithThreadMode},
141    sst_file_writer::SstFileWriter,
142    transactions::{
143        OptimisticTransactionDB, OptimisticTransactionOptions, Transaction, TransactionDB,
144        TransactionDBOptions, TransactionOptions,
145    },
146    write_batch::{WriteBatch, WriteBatchIterator, WriteBatchWithTransaction},
147};
148
149use rust_librocksdb_sys as ffi;
150
151use std::error;
152use std::fmt;
153
154/// RocksDB error kind.
155#[derive(Debug, Clone, PartialEq, Eq)]
156pub enum ErrorKind {
157    NotFound,
158    Corruption,
159    NotSupported,
160    InvalidArgument,
161    IOError,
162    MergeInProgress,
163    Incomplete,
164    ShutdownInProgress,
165    TimedOut,
166    Aborted,
167    Busy,
168    Expired,
169    TryAgain,
170    CompactionTooLarge,
171    ColumnFamilyDropped,
172    Unknown,
173}
174
175/// A simple wrapper round a string, used for errors reported from
176/// ffi calls.
177#[derive(Debug, Clone, PartialEq, Eq)]
178pub struct Error {
179    message: String,
180}
181
182impl Error {
183    fn new(message: String) -> Error {
184        Error { message }
185    }
186
187    pub fn into_string(self) -> String {
188        self.into()
189    }
190
191    /// Parse corresponding [`ErrorKind`] from error message.
192    pub fn kind(&self) -> ErrorKind {
193        match self.message.split(':').next().unwrap_or("") {
194            "NotFound" => ErrorKind::NotFound,
195            "Corruption" => ErrorKind::Corruption,
196            "Not implemented" => ErrorKind::NotSupported,
197            "Invalid argument" => ErrorKind::InvalidArgument,
198            "IO error" => ErrorKind::IOError,
199            "Merge in progress" => ErrorKind::MergeInProgress,
200            "Result incomplete" => ErrorKind::Incomplete,
201            "Shutdown in progress" => ErrorKind::ShutdownInProgress,
202            "Operation timed out" => ErrorKind::TimedOut,
203            "Operation aborted" => ErrorKind::Aborted,
204            "Resource busy" => ErrorKind::Busy,
205            "Operation expired" => ErrorKind::Expired,
206            "Operation failed. Try again." => ErrorKind::TryAgain,
207            "Compaction too large" => ErrorKind::CompactionTooLarge,
208            "Column family dropped" => ErrorKind::ColumnFamilyDropped,
209            _ => ErrorKind::Unknown,
210        }
211    }
212}
213
214impl AsRef<str> for Error {
215    fn as_ref(&self) -> &str {
216        &self.message
217    }
218}
219
220impl From<Error> for String {
221    fn from(e: Error) -> String {
222        e.message
223    }
224}
225
226impl error::Error for Error {
227    fn description(&self) -> &str {
228        &self.message
229    }
230}
231
232impl fmt::Display for Error {
233    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
234        self.message.fmt(formatter)
235    }
236}
237
238#[cfg(test)]
239mod test {
240    use crate::{
241        OptimisticTransactionDB, OptimisticTransactionOptions, Transaction, TransactionDB,
242        TransactionDBOptions, TransactionOptions,
243    };
244
245    use super::{
246        column_family::UnboundColumnFamily,
247        db_options::{CacheWrapper, WriteBufferManagerWrapper},
248        env::{Env, EnvWrapper},
249        BlockBasedOptions, BoundColumnFamily, Cache, ColumnFamily, ColumnFamilyDescriptor,
250        DBIterator, DBRawIterator, IngestExternalFileOptions, Options, PlainTableFactoryOptions,
251        ReadOptions, Snapshot, SstFileWriter, WriteBatch, WriteBufferManager, WriteOptions, DB,
252    };
253
254    #[test]
255    fn is_send() {
256        // test (at compile time) that certain types implement the auto-trait Send, either directly for
257        // pointer-wrapping types or transitively for types with all Send fields
258
259        fn is_send<T: Send>() {
260            // dummy function just used for its parameterized type bound
261        }
262
263        is_send::<DB>();
264        is_send::<DBIterator<'_>>();
265        is_send::<DBRawIterator<'_>>();
266        is_send::<Snapshot>();
267        is_send::<Options>();
268        is_send::<ReadOptions>();
269        is_send::<WriteOptions>();
270        is_send::<IngestExternalFileOptions>();
271        is_send::<BlockBasedOptions>();
272        is_send::<PlainTableFactoryOptions>();
273        is_send::<ColumnFamilyDescriptor>();
274        is_send::<ColumnFamily>();
275        is_send::<BoundColumnFamily<'_>>();
276        is_send::<UnboundColumnFamily>();
277        is_send::<SstFileWriter>();
278        is_send::<WriteBatch>();
279        is_send::<Cache>();
280        is_send::<CacheWrapper>();
281        is_send::<Env>();
282        is_send::<EnvWrapper>();
283        is_send::<TransactionDB>();
284        is_send::<OptimisticTransactionDB>();
285        is_send::<Transaction<'_, TransactionDB>>();
286        is_send::<TransactionDBOptions>();
287        is_send::<OptimisticTransactionOptions>();
288        is_send::<TransactionOptions>();
289        is_send::<WriteBufferManager>();
290        is_send::<WriteBufferManagerWrapper>();
291    }
292
293    #[test]
294    fn is_sync() {
295        // test (at compile time) that certain types implement the auto-trait Sync
296
297        fn is_sync<T: Sync>() {
298            // dummy function just used for its parameterized type bound
299        }
300
301        is_sync::<DB>();
302        is_sync::<Snapshot>();
303        is_sync::<Options>();
304        is_sync::<ReadOptions>();
305        is_sync::<WriteOptions>();
306        is_sync::<IngestExternalFileOptions>();
307        is_sync::<BlockBasedOptions>();
308        is_sync::<PlainTableFactoryOptions>();
309        is_sync::<UnboundColumnFamily>();
310        is_sync::<ColumnFamilyDescriptor>();
311        is_sync::<ColumnFamily>();
312        is_sync::<SstFileWriter>();
313        is_sync::<Cache>();
314        is_sync::<CacheWrapper>();
315        is_sync::<Env>();
316        is_sync::<EnvWrapper>();
317        is_sync::<TransactionDB>();
318        is_sync::<OptimisticTransactionDB>();
319        is_sync::<TransactionDBOptions>();
320        is_sync::<OptimisticTransactionOptions>();
321        is_sync::<TransactionOptions>();
322        is_sync::<WriteBufferManager>();
323        is_sync::<WriteBufferManagerWrapper>();
324    }
325}