Skip to main content

redb/
lib.rs

1#![cfg_attr(redb_no_std, no_std)]
2#![deny(clippy::all, clippy::pedantic, clippy::disallowed_methods)]
3#![allow(
4    clippy::if_not_else,
5    clippy::iter_not_returning_iterator,
6    clippy::missing_errors_doc,
7    clippy::missing_panics_doc,
8    clippy::module_name_repetitions,
9    clippy::must_use_candidate,
10    clippy::needless_pass_by_value,
11    clippy::redundant_closure_for_method_calls,
12    clippy::similar_names,
13    clippy::too_many_lines,
14    clippy::unnecessary_wraps,
15    clippy::unreadable_literal
16)]
17
18//! # redb
19//!
20//! A simple, portable, high-performance, ACID, embedded key-value store.
21//!
22//! redb is written in pure Rust and is loosely inspired by [lmdb][lmdb]. Data is stored in a collection
23//! of copy-on-write B+trees. For more details, see the [design doc][design].
24//!
25//! # Features
26//!
27//! - Zero-copy, thread-safe, `BTreeMap` based API
28//! - Fully ACID-compliant transactions
29//! - MVCC support for concurrent readers & writer, without blocking
30//! - Crash-safe by default
31//! - Savepoints and rollbacks
32//!
33//! # Example
34//!
35//! ```
36//! use redb::{Database, Error, ReadableDatabase, ReadableTable, TableDefinition};
37//!
38//! const TABLE: TableDefinition<&str, u64> = TableDefinition::new("my_data");
39//!
40//! fn main() -> Result<(), Error> {
41//!   # #[cfg(not(target_os = "wasi"))]
42//!     let file = tempfile::NamedTempFile::new().unwrap();
43//!   # #[cfg(target_os = "wasi")]
44//!   # let file = tempfile::NamedTempFile::new_in("/tmp").unwrap();
45//!     let db = Database::create(file.path())?;
46//!     let write_txn = db.begin_write()?;
47//!     {
48//!         let mut table = write_txn.open_table(TABLE)?;
49//!         table.insert("my_key", &123)?;
50//!     }
51//!     write_txn.commit()?;
52//!
53//!     let read_txn = db.begin_read()?;
54//!     let table = read_txn.open_table(TABLE)?;
55//!     assert_eq!(table.get_owned("my_key")?.unwrap().value(), 123);
56//!
57//!     Ok(())
58//! }
59//! ```
60//!
61//! # Crate features
62//!
63//! - `std`: enabled by default. With `experimental-api-5` on, disable it to build redb as a
64//!   `no_std` crate; see the README for what that mode requires and leaves out.
65//!
66//! [lmdb]: https://www.lmdb.tech/doc/
67//! [design]: https://github.com/cberner/redb/blob/master/docs/design.md
68
69// Everything redb uses beyond core comes through `alloc`, a subset of std, so this is a no-op for
70// std builds.
71extern crate alloc;
72
73#[cfg(feature = "experimental-multiprocess")]
74pub use db::ConcurrencyMode;
75#[cfg(not(redb_no_std))]
76pub use db::ReadOnlyDatabase;
77pub use db::{
78    Builder, CacheStats, Database, MultimapTableDefinition, MultimapTableHandle, ReadableDatabase,
79    RepairSession, StorageBackend, TableDefinition, TableHandle, UntypedMultimapTableHandle,
80    UntypedTableHandle,
81};
82pub use error::{
83    BackendError, CommitError, CompactionError, DatabaseError, Error, SavepointError,
84    SetDurabilityError, StorageError, TableError, TransactionError,
85};
86#[cfg(feature = "experimental-api-5")]
87pub use key_range::KeyRange;
88#[cfg(feature = "experimental-api-5")]
89pub use multimap_table::MultimapCursor;
90pub use multimap_table::{
91    MultimapRange, MultimapTable, MultimapValue, OwnedMultimapRange, OwnedMultimapValue,
92    ReadOnlyMultimapTable, ReadOnlyUntypedMultimapTable, ReadableMultimapTable,
93};
94#[cfg(feature = "experimental-api-5")]
95pub use table::Cursor;
96#[cfg(feature = "experimental_cursor")]
97pub use table::CursorMut;
98pub use table::{
99    Entry, ExtractIf, OccupiedEntry, OwnedAccessGuard, OwnedRange, Range, ReadOnlyTable,
100    ReadOnlyUntypedTable, ReadableTable, ReadableTableMetadata, Table, TableStats, VacantEntry,
101};
102pub use transactions::{DatabaseStats, Durability, ReadTransaction, WriteTransaction};
103pub use tree_store::{AccessGuard, AccessGuardMut, AccessGuardMutInPlace, Savepoint};
104pub use types::{Key, MutInPlaceValue, TypeName, Value};
105
106pub type Result<T = (), E = StorageError> = core::result::Result<T, E>;
107
108pub mod backends;
109mod complex_types;
110mod db;
111mod error;
112// Public under the redb 5 API preview, so a backend author can name the error type in both
113// modes; with std it is a re-export of `std::io`
114#[cfg(feature = "experimental-api-5")]
115pub mod io;
116#[cfg(not(feature = "experimental-api-5"))]
117mod io;
118#[cfg(feature = "experimental-api-5")]
119mod key_range;
120mod multimap_table;
121mod sealed;
122mod sync;
123mod table;
124mod transaction_tracker;
125mod transactions;
126mod tree_store;
127mod tuple_types;
128mod types;
129
130// core cannot tell whether the current thread is unwinding, and redb's Drop impls consult that in
131// opposite ways, so neither constant is safe to assume. Restricted to panic = "abort" instead,
132// where nothing unwinds and panicking() below is vacuously correct.
133#[cfg(all(redb_no_std, panic = "unwind"))]
134compile_error!(
135    "redb without the standard library requires panic = \"abort\": it cannot detect unwinding, \
136     and its Drop impls depend on being able to. Set panic = \"abort\" in the profile, or enable \
137     the \"std\" feature."
138);
139
140// Rejected here rather than at the AtomicU64 use site, so that the error names the feature
141// responsible instead of an unresolved import.
142#[cfg(all(feature = "cache_metrics", not(target_has_atomic = "64")))]
143compile_error!(
144    "the \"cache_metrics\" feature requires a target with 64-bit atomics: its counters are \
145     AtomicU64. Disable the feature on this target."
146);
147
148#[cfg(not(redb_no_std))]
149pub(crate) fn panicking() -> bool {
150    std::thread::panicking()
151}
152
153#[cfg(redb_no_std)]
154pub(crate) fn panicking() -> bool {
155    false
156}
157
158#[cfg(test)]
159fn create_tempfile() -> tempfile::NamedTempFile {
160    if cfg!(target_os = "wasi") {
161        tempfile::NamedTempFile::new_in("/tmp").unwrap()
162    } else {
163        tempfile::NamedTempFile::new().unwrap()
164    }
165}