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