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// Only docs.rs passes `--cfg docsrs`, and only it builds on nightly, so this
66// is inert everywhere else. It is what puts the "available on crate feature X
67// only" badges on gated items. `auto_cfg` is on by default under this gate, so
68// individual items do not need annotating.
69#![cfg_attr(docsrs, feature(doc_cfg))]
70#![warn(clippy::pedantic)]
71#![allow(
72    // Next `cast_*` lints don't give alternatives.
73    clippy::cast_possible_wrap, clippy::cast_possible_truncation, clippy::cast_sign_loss,
74    // Next lints produce too much noise/false positives.
75    clippy::module_name_repetitions, clippy::similar_names, clippy::must_use_candidate,
76    // '... may panic' lints.
77    // Too much work to fix.
78    clippy::missing_errors_doc,
79    clippy::should_panic_without_expect,
80    // False positive: WebSocket
81    clippy::doc_markdown,
82    clippy::missing_safety_doc,
83    clippy::needless_pass_by_value,
84    clippy::ptr_as_ptr,
85    clippy::missing_panics_doc,
86    clippy::from_over_into,
87)]
88
89#[macro_use]
90mod ffi_util;
91
92pub mod backup;
93mod cache;
94pub mod checkpoint;
95mod column_family;
96pub mod compaction;
97pub mod compaction_filter;
98pub mod compaction_filter_factory;
99pub mod compaction_service;
100mod comparator;
101mod db;
102mod db_iterator;
103mod db_options;
104mod db_pinnable_batch;
105mod db_pinnable_slice;
106mod env;
107mod env_options;
108pub mod event_listener;
109pub mod file_checksum;
110mod iter_range;
111pub mod merge_operator;
112pub mod metadata;
113pub mod perf;
114mod prop_name;
115pub mod properties;
116mod slice_transform;
117mod snapshot;
118pub mod sst_file_manager;
119mod sst_file_writer;
120pub mod sst_partitioner;
121pub mod statistics;
122pub mod table_properties;
123pub mod trace;
124mod transactions;
125pub mod wal;
126pub mod wal_filter;
127mod write_batch;
128mod write_batch_with_index;
129mod write_buffer_manager;
130
131pub use crate::{
132    cache::{Cache, HyperClockCacheOptions, MemoryAllocator},
133    column_family::{
134        AsColumnFamilyRef, BoundColumnFamily, ColumnFamily, ColumnFamilyDescriptor,
135        ColumnFamilyRef, ColumnFamilyTtl, DEFAULT_COLUMN_FAMILY_NAME,
136    },
137    compaction::{
138        BlobFileAdditionInfo, BlobFileGarbageInfo, CompactionCancellationToken, CompactionFileInfo,
139        CompactionJobStats, CompactionOptions,
140    },
141    compaction_filter::Decision as CompactionDecision,
142    compaction_service::{
143        CompactionService, CompactionServiceJobInfo, CompactionServiceJobStatus,
144        CompactionServiceOptionsOverride, EnvPriority, OpenAndCompactCancellationToken,
145        OpenAndCompactOptions, ScheduleResponse,
146    },
147    comparator::Comparator,
148    db::{
149        ColumnFamilyMetaData, CompactFilesResult, DB, DBAccess, DBCommon, DBWithThreadMode,
150        ExportImportFilesMetaData, GetIntoBufferResult, LiveFile, MultiThreaded, OwnedPrefixProber,
151        PrefixProber, Range, SingleThreaded, ThreadMode, TimestampedValue,
152    },
153    db_iterator::{
154        DBIterator, DBIteratorWithThreadMode, DBRawIterator, DBRawIteratorWithThreadMode,
155        DBWALIterator, Direction, IteratorMode,
156    },
157    db_options::{
158        BlockBasedIndexType, BlockBasedOptions, BlockBasedPinningTier, BottommostLevelCompaction,
159        ChecksumType, CompactOptions, CuckooTableOptions, DBCompactionPri, DBCompactionStyle,
160        DBCompressionType, DBPath, DBRecoveryMode, DataBlockIndexType, FifoCompactOptions,
161        FlushOptions, FlushWalOptions, ImportColumnFamilyOptions, IndexBlockSearchType, InfoLogger,
162        IngestExternalFileOptions, KeyEncodingType, LogLevel, LruCacheOptions, MemtableFactory,
163        Options, PlainTableFactoryOptions, PrepopulateBlobCache, RateLimiterMode, ReadOptions,
164        ReadTier, SizeApproximationFlags, SizeApproximationOptions, UniversalCompactOptions,
165        UniversalCompactionStopStyle, WaitForCompactOptions, WriteOptions,
166    },
167    db_pinnable_batch::{DBPinnableBatch, DBPinnableBatchIter},
168    db_pinnable_slice::DBPinnableSlice,
169    env::{Env, IoPriority},
170    env_options::EnvOptions,
171    event_listener::OwnedCompactionJobInfo,
172    ffi_util::{CSlice, CStrLike},
173    file_checksum::FileChecksumGenFactory,
174    iter_range::{IterateBounds, PrefixRange},
175    merge_operator::MergeOperands,
176    metadata::{
177        ColumnFamilyMetaDataOptions, FileType, LevelMetaData, LiveFileStorageInfoEntry,
178        LiveFilesStorageInfo, LiveFilesStorageInfoOptions, SstFileMetaData, Temperature,
179    },
180    perf::{PerfContext, PerfMetric, PerfStatsLevel, with_thread_local},
181    slice_transform::SliceTransform,
182    snapshot::{Snapshot, SnapshotReadOptions, SnapshotWithThreadMode},
183    sst_file_manager::SstFileManager,
184    sst_file_writer::SstFileWriter,
185    sst_partitioner::SstPartitionerFactory,
186    table_properties::TableProperties,
187    trace::{
188        BlockCacheTraceOptions, BlockCacheTraceWriterOptions, ReplayOptions, Replayer, TraceFilter,
189        TraceOptions, TraceReader,
190    },
191    transactions::{
192        OccLockBuckets, OccValidationPolicy, OptimisticTransactionDB,
193        OptimisticTransactionDBOptions, OptimisticTransactionOptions, Transaction, TransactionDB,
194        TransactionDBOptions, TransactionOptions, TxnDBWritePolicy,
195    },
196    wal::{OwnedWalFile, WalFile, WalFileType, WalFiles, WalReadOptions},
197    wal_filter::{WalFilter, WalRecordAction},
198    write_batch::{
199        WriteBatch, WriteBatchIterator, WriteBatchIteratorCf, WriteBatchWithTransaction,
200    },
201    write_batch_with_index::WriteBatchWithIndex,
202    write_buffer_manager::WriteBufferManager,
203};
204
205use rust_librocksdb_sys as ffi;
206
207/// The raw `librocksdb` bindings this crate is built against.
208///
209/// [`AsRawPtr`] hands out pointers to types from this crate, such as
210/// `ffi::rocksdb_t`, so callers need a way to name them. Reaching them through
211/// a separate `rust-librocksdb-sys` dependency would mean keeping that
212/// version in lockstep with this crate's by hand, and every sys bump would
213/// break it. Going through this re-export keeps the two tied together.
214///
215/// Everything here is generated by bindgen and is not covered by this crate's
216/// semver guarantee. It changes whenever the vendored RocksDB does.
217#[cfg(feature = "raw-ptr")]
218pub use rust_librocksdb_sys as ffi_raw;
219
220/// Returns `true` if this crate was built with the `coroutines` feature, in
221/// which case librocksdb was compiled with `USE_COROUTINES` and linked
222/// against folly.
223///
224/// When `true`, calling [`ReadOptions::set_async_io(true)`][async-io] on a
225/// `MultiGet` activates the multi-level parallel-read path described in the
226/// RocksDB [Asynchronous IO blog post]. When `false`, `MultiGet` with
227/// `async_io=true` can only parallelize reads within a single LSM level.
228///
229/// Note: this reflects how this crate was configured, not what is in the
230/// linked `librocksdb`. If you used `ROCKSDB_LIB_DIR` to link against an
231/// externally-built `librocksdb.a`, the answer here may not match what that
232/// library was actually compiled with.
233///
234/// [async-io]: ReadOptions::set_async_io
235/// [Asynchronous IO blog post]: https://rocksdb.org/blog/2022/10/07/asynchronous-io-in-rocksdb.html
236#[must_use]
237pub fn built_with_coroutines() -> bool {
238    cfg!(feature = "coroutines")
239}
240
241#[cfg(feature = "raw-ptr")]
242mod raw_ptr;
243
244#[cfg(feature = "raw-ptr")]
245pub use crate::raw_ptr::AsRawPtr;
246
247use std::error;
248use std::fmt;
249
250/// RocksDB error kind.
251#[derive(Debug, Clone, PartialEq, Eq)]
252pub enum ErrorKind {
253    NotFound,
254    Corruption,
255    NotSupported,
256    InvalidArgument,
257    IOError,
258    MergeInProgress,
259    Incomplete,
260    ShutdownInProgress,
261    TimedOut,
262    Aborted,
263    Busy,
264    Expired,
265    TryAgain,
266    CompactionTooLarge,
267    ColumnFamilyDropped,
268    Unknown,
269}
270
271/// A simple wrapper round a string, used for errors reported from
272/// ffi calls.
273#[derive(Debug, Clone, PartialEq, Eq)]
274pub struct Error {
275    message: String,
276}
277
278impl Error {
279    fn new(message: String) -> Error {
280        Error { message }
281    }
282
283    pub fn into_string(self) -> String {
284        self.into()
285    }
286
287    /// Parse corresponding [`ErrorKind`] from error message.
288    pub fn kind(&self) -> ErrorKind {
289        match self.message.split(':').next().unwrap_or("") {
290            "NotFound" => ErrorKind::NotFound,
291            "Corruption" => ErrorKind::Corruption,
292            "Not implemented" => ErrorKind::NotSupported,
293            "Invalid argument" => ErrorKind::InvalidArgument,
294            "IO error" => ErrorKind::IOError,
295            "Merge in progress" => ErrorKind::MergeInProgress,
296            "Result incomplete" => ErrorKind::Incomplete,
297            "Shutdown in progress" => ErrorKind::ShutdownInProgress,
298            "Operation timed out" => ErrorKind::TimedOut,
299            "Operation aborted" => ErrorKind::Aborted,
300            "Resource busy" => ErrorKind::Busy,
301            "Operation expired" => ErrorKind::Expired,
302            "Operation failed. Try again." => ErrorKind::TryAgain,
303            "Compaction too large" => ErrorKind::CompactionTooLarge,
304            "Column family dropped" => ErrorKind::ColumnFamilyDropped,
305            _ => ErrorKind::Unknown,
306        }
307    }
308}
309
310impl AsRef<str> for Error {
311    fn as_ref(&self) -> &str {
312        &self.message
313    }
314}
315
316impl From<Error> for String {
317    fn from(e: Error) -> String {
318        e.message
319    }
320}
321
322impl error::Error for Error {
323    fn description(&self) -> &str {
324        &self.message
325    }
326}
327
328impl fmt::Display for Error {
329    fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
330        self.message.fmt(formatter)
331    }
332}
333
334#[cfg(test)]
335mod test {
336    use crate::{
337        OptimisticTransactionDB, OptimisticTransactionOptions, Transaction, TransactionDB,
338        TransactionDBOptions, TransactionOptions,
339        cache::{Cache, CacheWrapper},
340        write_buffer_manager::{WriteBufferManager, WriteBufferManagerWrapper},
341    };
342
343    use super::{
344        BlockBasedOptions, BoundColumnFamily, ColumnFamily, ColumnFamilyDescriptor, DB, DBIterator,
345        DBRawIterator, IngestExternalFileOptions, Options, PlainTableFactoryOptions, ReadOptions,
346        Snapshot, SstFileWriter, WriteBatch, WriteOptions,
347        column_family::UnboundColumnFamily,
348        env::{Env, EnvWrapper},
349    };
350
351    #[test]
352    fn is_send() {
353        // test (at compile time) that certain types implement the auto-trait Send, either directly for
354        // pointer-wrapping types or transitively for types with all Send fields
355
356        fn is_send<T: Send>() {
357            // dummy function just used for its parameterized type bound
358        }
359
360        is_send::<DB>();
361        is_send::<DBIterator<'_>>();
362        is_send::<DBRawIterator<'_>>();
363        is_send::<Snapshot>();
364        is_send::<Options>();
365        is_send::<ReadOptions>();
366        is_send::<WriteOptions>();
367        is_send::<IngestExternalFileOptions>();
368        is_send::<BlockBasedOptions>();
369        is_send::<PlainTableFactoryOptions>();
370        is_send::<ColumnFamilyDescriptor>();
371        is_send::<ColumnFamily>();
372        is_send::<BoundColumnFamily<'_>>();
373        is_send::<UnboundColumnFamily>();
374        is_send::<SstFileWriter>();
375        is_send::<WriteBatch>();
376        is_send::<Cache>();
377        is_send::<CacheWrapper>();
378        is_send::<Env>();
379        is_send::<EnvWrapper>();
380        is_send::<TransactionDB>();
381        is_send::<OptimisticTransactionDB>();
382        is_send::<Transaction<'_, TransactionDB>>();
383        is_send::<TransactionDBOptions>();
384        is_send::<OptimisticTransactionOptions>();
385        is_send::<TransactionOptions>();
386        is_send::<WriteBufferManager>();
387        is_send::<WriteBufferManagerWrapper>();
388    }
389
390    #[test]
391    fn is_sync() {
392        // test (at compile time) that certain types implement the auto-trait Sync
393
394        fn is_sync<T: Sync>() {
395            // dummy function just used for its parameterized type bound
396        }
397
398        is_sync::<DB>();
399        is_sync::<Snapshot>();
400        is_sync::<Options>();
401        is_sync::<ReadOptions>();
402        is_sync::<WriteOptions>();
403        is_sync::<IngestExternalFileOptions>();
404        is_sync::<BlockBasedOptions>();
405        is_sync::<PlainTableFactoryOptions>();
406        is_sync::<UnboundColumnFamily>();
407        is_sync::<ColumnFamilyDescriptor>();
408        is_sync::<ColumnFamily>();
409        is_sync::<SstFileWriter>();
410        is_sync::<Cache>();
411        is_sync::<CacheWrapper>();
412        is_sync::<Env>();
413        is_sync::<EnvWrapper>();
414        is_sync::<TransactionDB>();
415        is_sync::<OptimisticTransactionDB>();
416        is_sync::<TransactionDBOptions>();
417        is_sync::<OptimisticTransactionOptions>();
418        is_sync::<TransactionOptions>();
419        is_sync::<WriteBufferManager>();
420        is_sync::<WriteBufferManagerWrapper>();
421    }
422}