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