Skip to main content

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, GetIntoBufferResult,
124        LiveFile, 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, InfoLogger, IngestExternalFileOptions,
135        KeyEncodingType, LogLevel, LruCacheOptions, MemtableFactory, Options,
136        PlainTableFactoryOptions, 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/// Returns `true` if this crate was built with the `coroutines` feature, in
163/// which case librocksdb was compiled with `USE_COROUTINES` and linked
164/// against folly.
165///
166/// When `true`, calling [`ReadOptions::set_async_io(true)`][async-io] on a
167/// `MultiGet` activates the multi-level parallel-read path described in the
168/// RocksDB [Asynchronous IO blog post]. When `false`, `MultiGet` with
169/// `async_io=true` can only parallelize reads within a single LSM level.
170///
171/// Note: this reflects how this crate was configured, not what is in the
172/// linked `librocksdb`. If you used `ROCKSDB_LIB_DIR` to link against an
173/// externally-built `librocksdb.a`, the answer here may not match what that
174/// library was actually compiled with.
175///
176/// [async-io]: ReadOptions::set_async_io
177/// [Asynchronous IO blog post]: https://rocksdb.org/blog/2022/10/07/asynchronous-io-in-rocksdb.html
178#[must_use]
179pub fn built_with_coroutines() -> bool {
180    cfg!(feature = "coroutines")
181}
182
183#[cfg(feature = "raw-ptr")]
184mod raw_ptr;
185
186#[cfg(feature = "raw-ptr")]
187pub use crate::raw_ptr::AsRawPtr;
188
189use std::error;
190use std::fmt;
191
192/// RocksDB error kind.
193#[derive(Debug, Clone, PartialEq, Eq)]
194pub enum ErrorKind {
195    NotFound,
196    Corruption,
197    NotSupported,
198    InvalidArgument,
199    IOError,
200    MergeInProgress,
201    Incomplete,
202    ShutdownInProgress,
203    TimedOut,
204    Aborted,
205    Busy,
206    Expired,
207    TryAgain,
208    CompactionTooLarge,
209    ColumnFamilyDropped,
210    Unknown,
211}
212
213/// A simple wrapper round a string, used for errors reported from
214/// ffi calls.
215#[derive(Debug, Clone, PartialEq, Eq)]
216pub struct Error {
217    message: String,
218}
219
220impl Error {
221    fn new(message: String) -> Error {
222        Error { message }
223    }
224
225    pub fn into_string(self) -> String {
226        self.into()
227    }
228
229    /// Parse corresponding [`ErrorKind`] from error message.
230    pub fn kind(&self) -> ErrorKind {
231        match self.message.split(':').next().unwrap_or("") {
232            "NotFound" => ErrorKind::NotFound,
233            "Corruption" => ErrorKind::Corruption,
234            "Not implemented" => ErrorKind::NotSupported,
235            "Invalid argument" => ErrorKind::InvalidArgument,
236            "IO error" => ErrorKind::IOError,
237            "Merge in progress" => ErrorKind::MergeInProgress,
238            "Result incomplete" => ErrorKind::Incomplete,
239            "Shutdown in progress" => ErrorKind::ShutdownInProgress,
240            "Operation timed out" => ErrorKind::TimedOut,
241            "Operation aborted" => ErrorKind::Aborted,
242            "Resource busy" => ErrorKind::Busy,
243            "Operation expired" => ErrorKind::Expired,
244            "Operation failed. Try again." => ErrorKind::TryAgain,
245            "Compaction too large" => ErrorKind::CompactionTooLarge,
246            "Column family dropped" => ErrorKind::ColumnFamilyDropped,
247            _ => ErrorKind::Unknown,
248        }
249    }
250}
251
252impl AsRef<str> for Error {
253    fn as_ref(&self) -> &str {
254        &self.message
255    }
256}
257
258impl From<Error> for String {
259    fn from(e: Error) -> String {
260        e.message
261    }
262}
263
264impl error::Error for Error {
265    fn description(&self) -> &str {
266        &self.message
267    }
268}
269
270impl fmt::Display for Error {
271    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
272        self.message.fmt(formatter)
273    }
274}
275
276#[cfg(test)]
277mod test {
278    use crate::{
279        OptimisticTransactionDB, OptimisticTransactionOptions, Transaction, TransactionDB,
280        TransactionDBOptions, TransactionOptions,
281        cache::{Cache, CacheWrapper},
282        write_buffer_manager::{WriteBufferManager, WriteBufferManagerWrapper},
283    };
284
285    use super::{
286        BlockBasedOptions, BoundColumnFamily, ColumnFamily, ColumnFamilyDescriptor, DB, DBIterator,
287        DBRawIterator, IngestExternalFileOptions, Options, PlainTableFactoryOptions, ReadOptions,
288        Snapshot, SstFileWriter, WriteBatch, WriteOptions,
289        column_family::UnboundColumnFamily,
290        env::{Env, EnvWrapper},
291    };
292
293    #[test]
294    fn is_send() {
295        // test (at compile time) that certain types implement the auto-trait Send, either directly for
296        // pointer-wrapping types or transitively for types with all Send fields
297
298        fn is_send<T: Send>() {
299            // dummy function just used for its parameterized type bound
300        }
301
302        is_send::<DB>();
303        is_send::<DBIterator<'_>>();
304        is_send::<DBRawIterator<'_>>();
305        is_send::<Snapshot>();
306        is_send::<Options>();
307        is_send::<ReadOptions>();
308        is_send::<WriteOptions>();
309        is_send::<IngestExternalFileOptions>();
310        is_send::<BlockBasedOptions>();
311        is_send::<PlainTableFactoryOptions>();
312        is_send::<ColumnFamilyDescriptor>();
313        is_send::<ColumnFamily>();
314        is_send::<BoundColumnFamily<'_>>();
315        is_send::<UnboundColumnFamily>();
316        is_send::<SstFileWriter>();
317        is_send::<WriteBatch>();
318        is_send::<Cache>();
319        is_send::<CacheWrapper>();
320        is_send::<Env>();
321        is_send::<EnvWrapper>();
322        is_send::<TransactionDB>();
323        is_send::<OptimisticTransactionDB>();
324        is_send::<Transaction<'_, TransactionDB>>();
325        is_send::<TransactionDBOptions>();
326        is_send::<OptimisticTransactionOptions>();
327        is_send::<TransactionOptions>();
328        is_send::<WriteBufferManager>();
329        is_send::<WriteBufferManagerWrapper>();
330    }
331
332    #[test]
333    fn is_sync() {
334        // test (at compile time) that certain types implement the auto-trait Sync
335
336        fn is_sync<T: Sync>() {
337            // dummy function just used for its parameterized type bound
338        }
339
340        is_sync::<DB>();
341        is_sync::<Snapshot>();
342        is_sync::<Options>();
343        is_sync::<ReadOptions>();
344        is_sync::<WriteOptions>();
345        is_sync::<IngestExternalFileOptions>();
346        is_sync::<BlockBasedOptions>();
347        is_sync::<PlainTableFactoryOptions>();
348        is_sync::<UnboundColumnFamily>();
349        is_sync::<ColumnFamilyDescriptor>();
350        is_sync::<ColumnFamily>();
351        is_sync::<SstFileWriter>();
352        is_sync::<Cache>();
353        is_sync::<CacheWrapper>();
354        is_sync::<Env>();
355        is_sync::<EnvWrapper>();
356        is_sync::<TransactionDB>();
357        is_sync::<OptimisticTransactionDB>();
358        is_sync::<TransactionDBOptions>();
359        is_sync::<OptimisticTransactionOptions>();
360        is_sync::<TransactionOptions>();
361        is_sync::<WriteBufferManager>();
362        is_sync::<WriteBufferManagerWrapper>();
363    }
364}