mirror of
https://github.com/Cuprate/cuprate.git
synced 2024-12-22 19:49:28 +00:00
database: replace sanakirja
with redb
(#80)
* cargo: replace `sanakirja` with `redb` * database: update docs `sanakirja` -> `redb` * lib: add TODO for `ConcreteEnv` generic replacement * database: split `trait Database` -> `trait Database{Read,Write}` * heed: add `struct HeedTable{Ro,Rw}` to match `redb` behavior * ops: remove imports for now * env: fix `&mut` bound on RwTx * database: impl `redb`, type-checks * fix heed trait impls, `Database{Read,Write}` -> `Database{Ro,Rw}` * redb: impl `From<_>` for `RuntimeError` * update readme * heed: document `HeedTableR{o,w}` types * env: doc `sync()` invariant * database: document data & lock filenames * misc docs, `redb` durability impl, `'db` -> `'env` * redb: fixes * misc docs and fixes * Update database/README.md Co-authored-by: Boog900 <boog900@tutanota.com> --------- Co-authored-by: Boog900 <boog900@tutanota.com>
This commit is contained in:
parent
312e29f0bf
commit
240e579066
33 changed files with 689 additions and 531 deletions
95
Cargo.lock
generated
95
Cargo.lock
generated
|
@ -578,7 +578,7 @@ dependencies = [
|
||||||
"heed",
|
"heed",
|
||||||
"page_size",
|
"page_size",
|
||||||
"paste",
|
"paste",
|
||||||
"sanakirja",
|
"redb",
|
||||||
"serde",
|
"serde",
|
||||||
"tempfile",
|
"tempfile",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
|
@ -838,7 +838,7 @@ checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
"redox_syscall 0.4.1",
|
"redox_syscall",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -903,16 +903,6 @@ dependencies = [
|
||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "fs2"
|
|
||||||
version = "0.4.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9564fc758e15025b46aa6643b1b77d047d1a56a1aea6e01002ac0c7026876213"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "funty"
|
name = "funty"
|
||||||
version = "2.0.0"
|
version = "2.0.0"
|
||||||
|
@ -1371,15 +1361,6 @@ dependencies = [
|
||||||
"generic-array",
|
"generic-array",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "instant"
|
|
||||||
version = "0.1.12"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ipnet"
|
name = "ipnet"
|
||||||
version = "2.9.0"
|
version = "2.9.0"
|
||||||
|
@ -1445,7 +1426,7 @@ checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.4.2",
|
"bitflags 2.4.2",
|
||||||
"libc",
|
"libc",
|
||||||
"redox_syscall 0.4.1",
|
"redox_syscall",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1496,16 +1477,6 @@ version = "2.7.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
|
checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "memmap"
|
|
||||||
version = "0.7.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "6585fd95e7bb50d6cc31e20d4cf9afb4e2ba16c5846fc76793f11218da9c475b"
|
|
||||||
dependencies = [
|
|
||||||
"libc",
|
|
||||||
"winapi",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "merlin"
|
name = "merlin"
|
||||||
version = "3.0.0"
|
version = "3.0.0"
|
||||||
|
@ -1827,17 +1798,6 @@ version = "2.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae"
|
checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "parking_lot"
|
|
||||||
version = "0.11.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99"
|
|
||||||
dependencies = [
|
|
||||||
"instant",
|
|
||||||
"lock_api",
|
|
||||||
"parking_lot_core 0.8.6",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "parking_lot"
|
name = "parking_lot"
|
||||||
version = "0.12.1"
|
version = "0.12.1"
|
||||||
|
@ -1845,21 +1805,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
|
checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"lock_api",
|
"lock_api",
|
||||||
"parking_lot_core 0.9.9",
|
"parking_lot_core",
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "parking_lot_core"
|
|
||||||
version = "0.8.6"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc"
|
|
||||||
dependencies = [
|
|
||||||
"cfg-if",
|
|
||||||
"instant",
|
|
||||||
"libc",
|
|
||||||
"redox_syscall 0.2.16",
|
|
||||||
"smallvec",
|
|
||||||
"winapi",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1870,7 +1816,7 @@ checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"libc",
|
"libc",
|
||||||
"redox_syscall 0.4.1",
|
"redox_syscall",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"windows-targets 0.48.5",
|
"windows-targets 0.48.5",
|
||||||
]
|
]
|
||||||
|
@ -2204,12 +2150,12 @@ dependencies = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redox_syscall"
|
name = "redb"
|
||||||
version = "0.2.16"
|
version = "1.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
|
checksum = "72623e6275cd430215b741f41ebda34db93a13ebde253f908b70871c46afc5ba"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 1.3.2",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -2427,27 +2373,6 @@ version = "1.0.17"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1"
|
checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "sanakirja"
|
|
||||||
version = "1.4.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "7c385eb43079aa7dc6204e473b68b4305ceaea8048dda3a985a339bbb57cde72"
|
|
||||||
dependencies = [
|
|
||||||
"fs2",
|
|
||||||
"log",
|
|
||||||
"memmap",
|
|
||||||
"parking_lot 0.11.2",
|
|
||||||
"sanakirja-core",
|
|
||||||
"serde",
|
|
||||||
"thiserror",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "sanakirja-core"
|
|
||||||
version = "1.4.1"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8376db34ae3eac6e7bd91168bc638450073b708ce9fb46940de676f552238bf5"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "schannel"
|
name = "schannel"
|
||||||
version = "0.1.23"
|
version = "0.1.23"
|
||||||
|
@ -2851,7 +2776,7 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"mio",
|
"mio",
|
||||||
"num_cpus",
|
"num_cpus",
|
||||||
"parking_lot 0.12.1",
|
"parking_lot",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"signal-hook-registry",
|
"signal-hook-registry",
|
||||||
"socket2",
|
"socket2",
|
||||||
|
|
|
@ -10,27 +10,27 @@ keywords = ["cuprate", "database"]
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["heed", "service"]
|
default = ["heed", "service"]
|
||||||
# default = ["sanakirja", "service"] # For testing `sanakirja`.
|
# default = ["redb", "service"] # For testing `redb`.
|
||||||
heed = ["dep:heed"]
|
heed = ["dep:heed"]
|
||||||
sanakirja = ["dep:sanakirja"]
|
redb = ["dep:redb"]
|
||||||
service = ["dep:crossbeam", "dep:tokio", "dep:tower"]
|
service = ["dep:crossbeam", "dep:tokio", "dep:tower"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cfg-if = { workspace = true }
|
cfg-if = { workspace = true }
|
||||||
# FIXME:
|
# FIXME:
|
||||||
# We only need the `thread` feature if `service` is enabled.
|
# We only need the `thread` feature if `service` is enabled.
|
||||||
# Figure out how to enable features of an already pulled in dependency conditionally.
|
# Figure out how to enable features of an already pulled in dependency conditionally.
|
||||||
cuprate-helper = { path = "../helper", features = ["fs", "thread"] }
|
cuprate-helper = { path = "../helper", features = ["fs", "thread"] }
|
||||||
paste = { workspace = true }
|
paste = { workspace = true }
|
||||||
# Needed for database resizes.
|
# Needed for database resizes.
|
||||||
# They must be a multiple of the OS page size.
|
# They must be a multiple of the OS page size.
|
||||||
page_size = { version = "0.6.0" }
|
page_size = { version = "0.6.0" }
|
||||||
thiserror = { workspace = true }
|
thiserror = { workspace = true }
|
||||||
|
|
||||||
# `service` feature.
|
# `service` feature.
|
||||||
crossbeam = { workspace = true, features = ["std"], optional = true }
|
crossbeam = { workspace = true, features = ["std"], optional = true }
|
||||||
tokio = { workspace = true, features = ["full"], optional = true }
|
tokio = { workspace = true, features = ["full"], optional = true }
|
||||||
tower = { workspace = true, features = ["full"], optional = true }
|
tower = { workspace = true, features = ["full"], optional = true }
|
||||||
# SOMEDAY: could be used in `service` as
|
# SOMEDAY: could be used in `service` as
|
||||||
# the database mutual exclusive `RwLock`.
|
# the database mutual exclusive `RwLock`.
|
||||||
#
|
#
|
||||||
|
@ -40,12 +40,12 @@ tower = { workspace = true, features = ["full"], optional = true }
|
||||||
# parking_lot = { workspace = true, optional = true }
|
# parking_lot = { workspace = true, optional = true }
|
||||||
|
|
||||||
# Optional features.
|
# Optional features.
|
||||||
borsh = { workspace = true, optional = true }
|
borsh = { workspace = true, optional = true }
|
||||||
heed = { git = "https://github.com/Cuprate/heed", rev = "5aa75b7", optional = true }
|
heed = { git = "https://github.com/Cuprate/heed", rev = "5aa75b7", optional = true }
|
||||||
sanakirja = { version = "1.4.0", optional = true }
|
redb = { version = "1.5.0", optional = true }
|
||||||
serde = { workspace = true, optional = true }
|
serde = { workspace = true, optional = true }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
cuprate-helper = { path = "../helper", features = ["thread"] }
|
cuprate-helper = { path = "../helper", features = ["thread"] }
|
||||||
page_size = { version = "0.6.0" }
|
page_size = { version = "0.6.0" }
|
||||||
tempfile = { version = "3.10.0" }
|
tempfile = { version = "3.10.0" }
|
|
@ -10,7 +10,9 @@ Cuprate's database implementation.
|
||||||
- [`src/backend/`](#src-backend)
|
- [`src/backend/`](#src-backend)
|
||||||
1. [Backends](#backends)
|
1. [Backends](#backends)
|
||||||
- [`heed`](#heed)
|
- [`heed`](#heed)
|
||||||
|
- [`redb`](#redb)
|
||||||
- [`sanakirja`](#sanakirja)
|
- [`sanakirja`](#sanakirja)
|
||||||
|
- [`MDBX`](#mdbx)
|
||||||
1. [Layers](#layers)
|
1. [Layers](#layers)
|
||||||
- [Database](#database)
|
- [Database](#database)
|
||||||
- [Trait](#trait)
|
- [Trait](#trait)
|
||||||
|
@ -68,7 +70,7 @@ The top-level `src/` files.
|
||||||
|------------------|---------|
|
|------------------|---------|
|
||||||
| `config.rs` | Database `Env` configuration
|
| `config.rs` | Database `Env` configuration
|
||||||
| `constants.rs` | General constants used throughout `cuprate-database`
|
| `constants.rs` | General constants used throughout `cuprate-database`
|
||||||
| `database.rs` | Abstracted database; `trait Database`
|
| `database.rs` | Abstracted database; `trait DatabaseR{o,w}`
|
||||||
| `env.rs` | Abstracted database environment; `trait Env`
|
| `env.rs` | Abstracted database environment; `trait Env`
|
||||||
| `error.rs` | Database error types
|
| `error.rs` | Database error types
|
||||||
| `free.rs` | General free functions (related to the database)
|
| `free.rs` | General free functions (related to the database)
|
||||||
|
@ -76,7 +78,7 @@ The top-level `src/` files.
|
||||||
| `pod.rs` | Data (de)serialization; `trait Pod`
|
| `pod.rs` | Data (de)serialization; `trait Pod`
|
||||||
| `table.rs` | Database table abstraction; `trait Table`
|
| `table.rs` | Database table abstraction; `trait Table`
|
||||||
| `tables.rs` | All the table definitions used by `cuprate-database`
|
| `tables.rs` | All the table definitions used by `cuprate-database`
|
||||||
| `transaction.rs` | Database transaction abstraction; `trait RoTx`, `trait RwTx`
|
| `transaction.rs` | Database transaction abstraction; `trait TxR{o,w}`
|
||||||
|
|
||||||
## `src/ops/`
|
## `src/ops/`
|
||||||
This folder contains the `cupate_database::ops` module.
|
This folder contains the `cupate_database::ops` module.
|
||||||
|
@ -119,10 +121,10 @@ All backends follow the same file structure:
|
||||||
|
|
||||||
| File | Purpose |
|
| File | Purpose |
|
||||||
|------------------|---------|
|
|------------------|---------|
|
||||||
| `database.rs` | Implementation of `trait Database`
|
| `database.rs` | Implementation of `trait DatabaseR{o,w}`
|
||||||
| `env.rs` | Implementation of `trait Env`
|
| `env.rs` | Implementation of `trait Env`
|
||||||
| `error.rs` | Implementation of backend's errors to `cuprate_database`'s error types
|
| `error.rs` | Implementation of backend's errors to `cuprate_database`'s error types
|
||||||
| `transaction.rs` | Implementation of `trait RoTx/RwTx`
|
| `transaction.rs` | Implementation of `trait TxR{o,w}`
|
||||||
| `types.rs` | Type aliases for long backend-specific types
|
| `types.rs` | Type aliases for long backend-specific types
|
||||||
|
|
||||||
# Backends
|
# Backends
|
||||||
|
@ -131,7 +133,7 @@ All backends follow the same file structure:
|
||||||
Each database's implementation is located in its respective file in `src/backend/${DATABASE_NAME}.rs`.
|
Each database's implementation is located in its respective file in `src/backend/${DATABASE_NAME}.rs`.
|
||||||
|
|
||||||
## `heed`
|
## `heed`
|
||||||
The default database used is a modified fork of [`heed`](https://github.com/meilisearch/heed), located at [`Cuprate/heed`](https://github.com/Cuprate/heed).
|
The default database used is a modified fork of [`heed`](https://github.com/meilisearch/heed) (LMDB), located at [`Cuprate/heed`](https://github.com/Cuprate/heed).
|
||||||
|
|
||||||
To generate documentation of the fork for local use:
|
To generate documentation of the fork for local use:
|
||||||
```bash
|
```bash
|
||||||
|
@ -140,10 +142,37 @@ cargo doc
|
||||||
```
|
```
|
||||||
`LMDB` should not need to be installed as `heed` has a build script that pulls it in automatically.
|
`LMDB` should not need to be installed as `heed` has a build script that pulls it in automatically.
|
||||||
|
|
||||||
|
`heed`'s filenames inside Cuprate's database folder (`~/.local/share/cuprate/database/`) are:
|
||||||
|
|
||||||
|
| Filename | Purpose |
|
||||||
|
|------------|---------|
|
||||||
|
| `data.mdb` | Main data file
|
||||||
|
| `lock.mdb` | Database lock file
|
||||||
|
|
||||||
TODO: document max readers limit: https://github.com/monero-project/monero/blob/059028a30a8ae9752338a7897329fe8012a310d5/src/blockchain_db/lmdb/db_lmdb.cpp#L1372. Other potential processes (e.g. `xmrblocks`) that are also reading the `data.mdb` file need to be accounted for.
|
TODO: document max readers limit: https://github.com/monero-project/monero/blob/059028a30a8ae9752338a7897329fe8012a310d5/src/blockchain_db/lmdb/db_lmdb.cpp#L1372. Other potential processes (e.g. `xmrblocks`) that are also reading the `data.mdb` file need to be accounted for.
|
||||||
|
|
||||||
|
## `redb`
|
||||||
|
The 2nd database backend is the 100% Rust [`redb`](https://github.com/cberner/redb).
|
||||||
|
|
||||||
|
The upstream versions from [`crates.io`](https://crates.io/crates/redb) are used.
|
||||||
|
|
||||||
|
`redb`'s filenames inside Cuprate's database folder (`~/.local/share/cuprate/database/`) are:
|
||||||
|
|
||||||
|
| Filename | Purpose |
|
||||||
|
|-------------|---------|
|
||||||
|
| `data.redb` | Main data file
|
||||||
|
|
||||||
## `sanakirja`
|
## `sanakirja`
|
||||||
TODO
|
[`sanakirja`](https://docs.rs/sanakirja) was a candidate as a backend, however there were problems with maximum value sizes.
|
||||||
|
|
||||||
|
The default maximum value size is [1012 bytes](https://docs.rs/sanakirja/1.4.1/sanakirja/trait.Storable.html) which was too small for our requirements. Using [`sanakirja::Slice`](https://docs.rs/sanakirja/1.4.1/sanakirja/union.Slice.html) and [sanakirja::UnsizedStorage](https://docs.rs/sanakirja/1.4.1/sanakirja/trait.UnsizedStorable.html) was attempted, but there were bugs found when inserting a value in-between `512..=4096` bytes.
|
||||||
|
|
||||||
|
As such, it is not implemented.
|
||||||
|
|
||||||
|
## `MDBX`
|
||||||
|
[`MDBX`](https://erthink.github.io/libmdbx) was a candidate as a backend, however MDBX deprecated the custom key/value comparison functions, this makes it a bit trickier to implement dup tables. It is also quite similar to the main backend LMDB (of which it was originally a fork of).
|
||||||
|
|
||||||
|
As such, it is not implemented (yet).
|
||||||
|
|
||||||
# Layers
|
# Layers
|
||||||
TODO: update with accurate information when ready, update image.
|
TODO: update with accurate information when ready, update image.
|
||||||
|
|
|
@ -1,41 +1,97 @@
|
||||||
//! Implementation of `trait Database` for `heed`.
|
//! Implementation of `trait Database` for `heed`.
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Import
|
//---------------------------------------------------------------------------------------------------- Import
|
||||||
use crate::{backend::heed::types::HeedDb, database::Database, error::RuntimeError, table::Table};
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Database Impls
|
use crate::{
|
||||||
impl<T: Table> Database<T> for HeedDb {
|
backend::heed::types::HeedDb,
|
||||||
type RoTx<'db> = heed::RoTxn<'db>;
|
database::{DatabaseRo, DatabaseRw},
|
||||||
type RwTx<'db> = heed::RwTxn<'db>;
|
error::RuntimeError,
|
||||||
|
table::Table,
|
||||||
|
};
|
||||||
|
|
||||||
fn get(&self, ro_tx: &Self::RoTx<'_>, key: &T::Key) -> Result<Option<T::Value>, RuntimeError> {
|
//---------------------------------------------------------------------------------------------------- Heed Database Wrappers
|
||||||
|
// Q. Why does `HeedTableR{o,w}` exist?
|
||||||
|
// A. These wrapper types combine `heed`'s database/table
|
||||||
|
// types with its transaction types. It exists to match
|
||||||
|
// `redb`, which has this behavior built-in.
|
||||||
|
//
|
||||||
|
// `redb` forces us to abstract read/write semantics
|
||||||
|
// at the _opened table_ level, so, we must match that in `heed`,
|
||||||
|
// which abstracts it at the transaction level.
|
||||||
|
//
|
||||||
|
// We must also maintain the ability for
|
||||||
|
// write operations to also read, aka, `Rw`.
|
||||||
|
//
|
||||||
|
// TODO: do we need the `T: Table` phantom bound?
|
||||||
|
// It allows us to reference the `Table` info.
|
||||||
|
|
||||||
|
/// An opened read-only database associated with a transaction.
|
||||||
|
///
|
||||||
|
/// Matches `redb::ReadOnlyTable`.
|
||||||
|
pub(super) struct HeedTableRo<'env, T: Table> {
|
||||||
|
/// An already opened database table.
|
||||||
|
db: HeedDb,
|
||||||
|
/// The associated read-only transaction that opened this table.
|
||||||
|
tx_ro: &'env heed::RoTxn<'env>,
|
||||||
|
/// TODO: do we need this?
|
||||||
|
_table: PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An opened read/write database associated with a transaction.
|
||||||
|
///
|
||||||
|
/// Matches `redb::Table` (read & write).
|
||||||
|
pub(super) struct HeedTableRw<'env, T: Table> {
|
||||||
|
/// TODO
|
||||||
|
db: HeedDb,
|
||||||
|
/// The associated read/write transaction that opened this table.
|
||||||
|
tx_rw: &'env mut heed::RwTxn<'env>,
|
||||||
|
/// TODO: do we need this?
|
||||||
|
_table: PhantomData<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------- DatabaseRo Impl
|
||||||
|
impl<T: Table> DatabaseRo<T> for HeedTableRo<'_, T> {
|
||||||
|
fn get(&self, key: &T::Key) -> Result<Option<T::Value>, RuntimeError> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_range(
|
fn get_range(
|
||||||
&self,
|
&self,
|
||||||
ro_tx: &Self::RoTx<'_>,
|
|
||||||
key: &T::Key,
|
key: &T::Key,
|
||||||
amount: usize,
|
amount: usize,
|
||||||
) -> Result<impl Iterator<Item = T::Value>, RuntimeError> {
|
) -> Result<impl Iterator<Item = T::Value>, RuntimeError> {
|
||||||
let iter: std::vec::Drain<'_, T::Value> = todo!();
|
let iter: std::vec::Drain<'_, T::Value> = todo!();
|
||||||
Ok(iter)
|
Ok(iter)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn put(
|
//---------------------------------------------------------------------------------------------------- DatabaseRw Impl
|
||||||
&mut self,
|
impl<T: Table> DatabaseRo<T> for HeedTableRw<'_, T> {
|
||||||
rw_tx: &mut Self::RwTx<'_>,
|
fn get(&self, key: &T::Key) -> Result<Option<T::Value>, RuntimeError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_range(
|
||||||
|
&self,
|
||||||
key: &T::Key,
|
key: &T::Key,
|
||||||
value: &T::Value,
|
amount: usize,
|
||||||
) -> Result<(), RuntimeError> {
|
) -> Result<impl Iterator<Item = T::Value>, RuntimeError> {
|
||||||
|
let iter: std::vec::Drain<'_, T::Value> = todo!();
|
||||||
|
Ok(iter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Table> DatabaseRw<T> for HeedTableRw<'_, T> {
|
||||||
|
fn put(&mut self, key: &T::Key, value: &T::Value) -> Result<(), RuntimeError> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear(&mut self, rw_tx: &mut Self::RwTx<'_>) -> Result<(), RuntimeError> {
|
fn clear(&mut self) -> Result<(), RuntimeError> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn delete(&mut self, rw_tx: &mut Self::RwTx<'_>, key: &T::Key) -> Result<bool, RuntimeError> {
|
fn delete(&mut self, key: &T::Key) -> Result<bool, RuntimeError> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,9 @@
|
||||||
use std::sync::RwLock;
|
use std::sync::RwLock;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::heed::types::HeedDb,
|
backend::heed::database::{HeedTableRo, HeedTableRw},
|
||||||
config::Config,
|
config::Config,
|
||||||
database::Database,
|
database::{DatabaseRo, DatabaseRw},
|
||||||
env::Env,
|
env::Env,
|
||||||
error::{InitError, RuntimeError},
|
error::{InitError, RuntimeError},
|
||||||
resize::ResizeAlgorithm,
|
resize::ResizeAlgorithm,
|
||||||
|
@ -49,6 +49,14 @@ pub struct ConcreteEnv {
|
||||||
|
|
||||||
impl Drop for ConcreteEnv {
|
impl Drop for ConcreteEnv {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
|
// TODO:
|
||||||
|
// "if the environment has the MDB_NOSYNC flag set the flushes will be omitted,
|
||||||
|
// and with MDB_MAPASYNC they will be asynchronous."
|
||||||
|
// <http://www.lmdb.tech/doc/group__mdb.html#ga85e61f05aa68b520cc6c3b981dba5037>
|
||||||
|
//
|
||||||
|
// We need to do `mdb_env_set_flags(&env, MDB_NOSYNC|MDB_ASYNCMAP, 0)`
|
||||||
|
// to clear the no sync and async flags such that the below `self.sync()`
|
||||||
|
// _actually_ synchronously syncs.
|
||||||
if let Err(e) = self.sync() {
|
if let Err(e) = self.sync() {
|
||||||
// TODO: log error?
|
// TODO: log error?
|
||||||
}
|
}
|
||||||
|
@ -61,8 +69,8 @@ impl Drop for ConcreteEnv {
|
||||||
impl Env for ConcreteEnv {
|
impl Env for ConcreteEnv {
|
||||||
const MANUAL_RESIZE: bool = true;
|
const MANUAL_RESIZE: bool = true;
|
||||||
const SYNCS_PER_TX: bool = false;
|
const SYNCS_PER_TX: bool = false;
|
||||||
type RoTx<'db> = heed::RoTxn<'db>;
|
type TxRo<'env> = heed::RoTxn<'env>;
|
||||||
type RwTx<'db> = heed::RwTxn<'db>;
|
type TxRw<'env> = heed::RwTxn<'env>;
|
||||||
|
|
||||||
#[cold]
|
#[cold]
|
||||||
#[inline(never)] // called once.
|
#[inline(never)] // called once.
|
||||||
|
@ -80,6 +88,12 @@ impl Env for ConcreteEnv {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cold]
|
||||||
|
#[inline(never)] // called once in [`Env::open`]?
|
||||||
|
fn create_tables<T: Table>(&self, tx_rw: &mut Self::TxRw<'_>) -> Result<(), RuntimeError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn config(&self) -> &Config {
|
fn config(&self) -> &Config {
|
||||||
&self.config
|
&self.config
|
||||||
}
|
}
|
||||||
|
@ -116,30 +130,30 @@ impl Env for ConcreteEnv {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn ro_tx(&self) -> Result<Self::RoTx<'_>, RuntimeError> {
|
fn tx_ro(&self) -> Result<Self::TxRo<'_>, RuntimeError> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn rw_tx(&self) -> Result<Self::RwTx<'_>, RuntimeError> {
|
fn tx_rw(&self) -> Result<Self::TxRw<'_>, RuntimeError> {
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cold]
|
|
||||||
#[inline(never)] // called infrequently?.
|
|
||||||
fn create_tables_if_needed<T: Table>(
|
|
||||||
&self,
|
|
||||||
tx_rw: &mut Self::RwTx<'_>,
|
|
||||||
) -> Result<(), RuntimeError> {
|
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn open_database<T: Table>(
|
fn open_db_ro<T: Table>(
|
||||||
&self,
|
&self,
|
||||||
to_rw: &Self::RoTx<'_>,
|
tx_ro: &Self::TxRo<'_>,
|
||||||
) -> Result<impl Database<T>, RuntimeError> {
|
) -> Result<impl DatabaseRo<T>, RuntimeError> {
|
||||||
let tx: HeedDb = todo!();
|
let tx: HeedTableRo<T> = todo!();
|
||||||
|
Ok(tx)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn open_db_rw<T: Table>(
|
||||||
|
&self,
|
||||||
|
tx_rw: &mut Self::TxRw<'_>,
|
||||||
|
) -> Result<impl DatabaseRw<T>, RuntimeError> {
|
||||||
|
let tx: HeedTableRw<T> = todo!();
|
||||||
Ok(tx)
|
Ok(tx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
//! Conversion from `heed::Error` -> `cuprate_database::RuntimeError`.
|
//! Conversion from `heed::Error` -> `cuprate_database`'s errors.
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Use
|
//---------------------------------------------------------------------------------------------------- Use
|
||||||
use crate::constants::DATABASE_CORRUPT_MSG;
|
use crate::constants::DATABASE_CORRUPT_MSG;
|
||||||
|
@ -83,7 +83,7 @@ impl From<heed::Error> for crate::RuntimeError {
|
||||||
//
|
//
|
||||||
// "Requested page not found - this usually indicates corruption."
|
// "Requested page not found - this usually indicates corruption."
|
||||||
// <https://docs.rs/heed/latest/heed/enum.MdbError.html#variant.PageNotFound>
|
// <https://docs.rs/heed/latest/heed/enum.MdbError.html#variant.PageNotFound>
|
||||||
E2::Corrupted | E2::PageNotFound => panic!("{mdb_error:?}\n{DATABASE_CORRUPT_MSG}"),
|
E2::Corrupted | E2::PageNotFound => panic!("{mdb_error:#?}\n{DATABASE_CORRUPT_MSG}"),
|
||||||
|
|
||||||
// These errors should not occur, and if they do,
|
// These errors should not occur, and if they do,
|
||||||
// the best thing `cuprate_database` can do for
|
// the best thing `cuprate_database` can do for
|
||||||
|
@ -98,7 +98,7 @@ impl From<heed::Error> for crate::RuntimeError {
|
||||||
| E2::TxnFull
|
| E2::TxnFull
|
||||||
| E2::BadRslot
|
| E2::BadRslot
|
||||||
| E2::VersionMismatch
|
| E2::VersionMismatch
|
||||||
| E2::BadDbi => panic!("{mdb_error:?}"),
|
| E2::BadDbi => panic!("{mdb_error:#?}"),
|
||||||
|
|
||||||
// These errors are the same as above, but instead
|
// These errors are the same as above, but instead
|
||||||
// of being errors we can't control, these are errors
|
// of being errors we can't control, these are errors
|
||||||
|
@ -135,7 +135,7 @@ impl From<heed::Error> for crate::RuntimeError {
|
||||||
// Don't use a key that is `>511` bytes.
|
// Don't use a key that is `>511` bytes.
|
||||||
// <http://www.lmdb.tech/doc/group__mdb.html#gaaf0be004f33828bf2fb09d77eb3cef94>
|
// <http://www.lmdb.tech/doc/group__mdb.html#gaaf0be004f33828bf2fb09d77eb3cef94>
|
||||||
| E2::BadValSize
|
| E2::BadValSize
|
||||||
=> panic!("fix the database code! {mdb_error:?}"),
|
=> panic!("fix the database code! {mdb_error:#?}"),
|
||||||
},
|
},
|
||||||
|
|
||||||
// Only if we write incorrect code.
|
// Only if we write incorrect code.
|
||||||
|
@ -143,7 +143,7 @@ impl From<heed::Error> for crate::RuntimeError {
|
||||||
| E1::DatabaseClosing
|
| E1::DatabaseClosing
|
||||||
| E1::BadOpenOptions { .. }
|
| E1::BadOpenOptions { .. }
|
||||||
| E1::Encoding(_)
|
| E1::Encoding(_)
|
||||||
| E1::Decoding(_) => panic!("fix the database code! {error:?}"),
|
| E1::Decoding(_) => panic!("fix the database code! {error:#?}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,29 @@
|
||||||
//! Implementation of `trait RoTx/RwTx` for `heed`.
|
//! Implementation of `trait TxRo/TxRw` for `heed`.
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Import
|
//---------------------------------------------------------------------------------------------------- Import
|
||||||
use crate::{
|
use crate::{
|
||||||
error::RuntimeError,
|
error::RuntimeError,
|
||||||
transaction::{RoTx, RwTx},
|
transaction::{TxRo, TxRw},
|
||||||
};
|
};
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- RoTx
|
//---------------------------------------------------------------------------------------------------- TxRo
|
||||||
impl RoTx<'_> for heed::RoTxn<'_> {
|
impl TxRo<'_> for heed::RoTxn<'_> {
|
||||||
fn commit(self) -> Result<(), RuntimeError> {
|
fn commit(self) -> Result<(), RuntimeError> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- RwTx
|
//---------------------------------------------------------------------------------------------------- TxRw
|
||||||
impl RwTx<'_> for heed::RwTxn<'_> {
|
impl TxRo<'_> for heed::RwTxn<'_> {
|
||||||
|
/// TODO
|
||||||
|
/// # Errors
|
||||||
|
/// TODO
|
||||||
|
fn commit(self) -> Result<(), RuntimeError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TxRw<'_> for heed::RwTxn<'_> {
|
||||||
/// TODO
|
/// TODO
|
||||||
/// # Errors
|
/// # Errors
|
||||||
/// TODO
|
/// TODO
|
||||||
|
|
|
@ -4,5 +4,5 @@
|
||||||
use heed::{types::Bytes, Database};
|
use heed::{types::Bytes, Database};
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Types
|
//---------------------------------------------------------------------------------------------------- Types
|
||||||
/// The concrete database type for `heed`.
|
/// The concrete database type for `heed`, usable for reads and writes.
|
||||||
pub(super) type HeedDb = Database<Bytes, Bytes>;
|
pub(super) type HeedDb = Database<Bytes, Bytes>;
|
||||||
|
|
|
@ -12,9 +12,9 @@
|
||||||
cfg_if::cfg_if! {
|
cfg_if::cfg_if! {
|
||||||
// If both backends are enabled, fallback to `heed`.
|
// If both backends are enabled, fallback to `heed`.
|
||||||
// This is useful when using `--all-features`.
|
// This is useful when using `--all-features`.
|
||||||
if #[cfg(all(feature = "sanakirja", not(feature = "heed")))] {
|
if #[cfg(all(feature = "redb", not(feature = "heed")))] {
|
||||||
mod sanakirja;
|
mod redb;
|
||||||
pub use sanakirja::ConcreteEnv;
|
pub use redb::ConcreteEnv;
|
||||||
} else {
|
} else {
|
||||||
mod heed;
|
mod heed;
|
||||||
pub use heed::ConcreteEnv;
|
pub use heed::ConcreteEnv;
|
||||||
|
|
61
database/src/backend/redb/database.rs
Normal file
61
database/src/backend/redb/database.rs
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
//! Implementation of `trait DatabaseR{o,w}` for `redb`.
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------- Import
|
||||||
|
use crate::{
|
||||||
|
backend::redb::types::{RedbTableRo, RedbTableRw},
|
||||||
|
database::{DatabaseRo, DatabaseRw},
|
||||||
|
error::RuntimeError,
|
||||||
|
table::Table,
|
||||||
|
};
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------- DatabaseRo
|
||||||
|
impl<T: Table> DatabaseRo<T> for RedbTableRo<'_> {
|
||||||
|
fn get(&self, key: &T::Key) -> Result<Option<T::Value>, RuntimeError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_range(
|
||||||
|
&self,
|
||||||
|
key: &T::Key,
|
||||||
|
amount: usize,
|
||||||
|
) -> Result<impl Iterator<Item = T::Value>, RuntimeError> {
|
||||||
|
let iter: std::vec::Drain<'_, T::Value> = todo!();
|
||||||
|
Ok(iter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------- DatabaseRw
|
||||||
|
impl<T: Table> DatabaseRo<T> for RedbTableRw<'_, '_> {
|
||||||
|
fn get(&self, key: &T::Key) -> Result<Option<T::Value>, RuntimeError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_range(
|
||||||
|
&self,
|
||||||
|
key: &T::Key,
|
||||||
|
amount: usize,
|
||||||
|
) -> Result<impl Iterator<Item = T::Value>, RuntimeError> {
|
||||||
|
let iter: std::vec::Drain<'_, T::Value> = todo!();
|
||||||
|
Ok(iter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Table> DatabaseRw<T> for RedbTableRw<'_, '_> {
|
||||||
|
fn put(&mut self, key: &T::Key, value: &T::Value) -> Result<(), RuntimeError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear(&mut self) -> Result<(), RuntimeError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn delete(&mut self, key: &T::Key) -> Result<bool, RuntimeError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------- Tests
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
// use super::*;
|
||||||
|
}
|
120
database/src/backend/redb/env.rs
Normal file
120
database/src/backend/redb/env.rs
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
//! Implementation of `trait Env` for `redb`.
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------- Import
|
||||||
|
use std::{path::Path, sync::Arc};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
backend::redb::types::{RedbTableRo, RedbTableRw},
|
||||||
|
config::{Config, SyncMode},
|
||||||
|
database::{DatabaseRo, DatabaseRw},
|
||||||
|
env::Env,
|
||||||
|
error::{InitError, RuntimeError},
|
||||||
|
table::Table,
|
||||||
|
};
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------- ConcreteEnv
|
||||||
|
/// A strongly typed, concrete database environment, backed by `redb`.
|
||||||
|
pub struct ConcreteEnv {
|
||||||
|
/// The actual database environment.
|
||||||
|
env: redb::Database,
|
||||||
|
|
||||||
|
/// The configuration we were opened with
|
||||||
|
/// (and in current use).
|
||||||
|
config: Config,
|
||||||
|
|
||||||
|
/// A cached, redb version of `cuprate_database::config::SyncMode`.
|
||||||
|
/// `redb` needs the sync mode to be set _per_ TX, so we
|
||||||
|
/// will continue to use this value every `Env::tx_rw`.
|
||||||
|
durability: redb::Durability,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for ConcreteEnv {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if let Err(e) = self.sync() {
|
||||||
|
// TODO: log error?
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: log that we are dropping the database.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------- Env Impl
|
||||||
|
impl Env for ConcreteEnv {
|
||||||
|
const MANUAL_RESIZE: bool = false;
|
||||||
|
const SYNCS_PER_TX: bool = false;
|
||||||
|
|
||||||
|
type TxRo<'env> = redb::ReadTransaction<'env>;
|
||||||
|
type TxRw<'env> = redb::WriteTransaction<'env>;
|
||||||
|
|
||||||
|
#[cold]
|
||||||
|
#[inline(never)] // called once.
|
||||||
|
fn open(config: Config) -> Result<Self, InitError> {
|
||||||
|
// TODO: dynamic syncs are not implemented.
|
||||||
|
let durability = match config.sync_mode {
|
||||||
|
// TODO: There's also `redb::Durability::Paranoid`:
|
||||||
|
// <https://docs.rs/redb/1.5.0/redb/enum.Durability.html#variant.Paranoid>
|
||||||
|
// should we use that instead of Immediate?
|
||||||
|
SyncMode::Safe => redb::Durability::Immediate,
|
||||||
|
SyncMode::Async => redb::Durability::Eventual,
|
||||||
|
SyncMode::Fast => redb::Durability::None,
|
||||||
|
// TODO: dynamic syncs are not implemented.
|
||||||
|
SyncMode::FastThenSafe | SyncMode::Threshold(_) => unimplemented!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cold]
|
||||||
|
#[inline(never)] // called once in [`Env::open`]?`
|
||||||
|
fn create_tables<T: Table>(&self, tx_rw: &mut Self::TxRw<'_>) -> Result<(), RuntimeError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn config(&self) -> &Config {
|
||||||
|
&self.config
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sync(&self) -> Result<(), RuntimeError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn tx_ro(&self) -> Result<Self::TxRo<'_>, RuntimeError> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn tx_rw(&self) -> Result<Self::TxRw<'_>, RuntimeError> {
|
||||||
|
// `redb` has sync modes on the TX level, unlike heed,
|
||||||
|
// which sets it at the Environment level.
|
||||||
|
//
|
||||||
|
// So, set the durability here before returning the TX.
|
||||||
|
let mut tx_rw = self.env.begin_write()?;
|
||||||
|
tx_rw.set_durability(self.durability);
|
||||||
|
Ok(tx_rw)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn open_db_ro<T: Table>(
|
||||||
|
&self,
|
||||||
|
tx_ro: &Self::TxRo<'_>,
|
||||||
|
) -> Result<impl DatabaseRo<T>, RuntimeError> {
|
||||||
|
let tx: RedbTableRo = todo!();
|
||||||
|
Ok(tx)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn open_db_rw<T: Table>(
|
||||||
|
&self,
|
||||||
|
tx_rw: &mut Self::TxRw<'_>,
|
||||||
|
) -> Result<impl DatabaseRw<T>, RuntimeError> {
|
||||||
|
let tx: RedbTableRw = todo!();
|
||||||
|
Ok(tx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------- Tests
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
// use super::*;
|
||||||
|
}
|
107
database/src/backend/redb/error.rs
Normal file
107
database/src/backend/redb/error.rs
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
//! Conversion from `redb`'s errors -> `cuprate_database`'s errors.
|
||||||
|
//!
|
||||||
|
//! HACK: There's a lot of `_ =>` usage here because
|
||||||
|
//! `redb`'s errors are `#[non_exhaustive]`...
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------- Import
|
||||||
|
use crate::constants::DATABASE_CORRUPT_MSG;
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------- DatabaseError
|
||||||
|
impl From<redb::DatabaseError> for crate::InitError {
|
||||||
|
/// Created by `redb` in:
|
||||||
|
/// - [`redb::Database::open`](https://docs.rs/redb/1.5.0/redb/struct.Database.html#method.open).
|
||||||
|
fn from(error: redb::DatabaseError) -> Self {
|
||||||
|
use redb::DatabaseError as E;
|
||||||
|
use redb::StorageError as E2;
|
||||||
|
|
||||||
|
// Reference of all possible errors `redb` will return
|
||||||
|
// upon using `redb::Database::open`:
|
||||||
|
// <https://docs.rs/redb/1.5.0/src/redb/db.rs.html#908-923>
|
||||||
|
match error {
|
||||||
|
E::RepairAborted => Self::Corrupt,
|
||||||
|
E::UpgradeRequired(_) => Self::InvalidVersion,
|
||||||
|
E::Storage(s_error) => match s_error {
|
||||||
|
E2::Io(e) => Self::Io(e),
|
||||||
|
E2::Corrupted(_) => Self::Corrupt,
|
||||||
|
|
||||||
|
// HACK: Handle new errors as `redb` adds them.
|
||||||
|
_ => Self::Unknown(Box::new(s_error)),
|
||||||
|
},
|
||||||
|
|
||||||
|
// HACK: Handle new errors as `redb` adds them.
|
||||||
|
_ => Self::Unknown(Box::new(error)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------- TransactionError
|
||||||
|
#[allow(clippy::fallible_impl_from)] // We need to panic sometimes.
|
||||||
|
impl From<redb::TransactionError> for crate::RuntimeError {
|
||||||
|
/// Created by `redb` in:
|
||||||
|
/// - [`redb::Database::begin_write`](https://docs.rs/redb/1.5.0/redb/struct.Database.html#method.begin_write)
|
||||||
|
/// - [`redb::Database::begin_read`](https://docs.rs/redb/1.5.0/redb/struct.Database.html#method.begin_read)
|
||||||
|
fn from(error: redb::TransactionError) -> Self {
|
||||||
|
use redb::StorageError as E;
|
||||||
|
|
||||||
|
match error {
|
||||||
|
redb::TransactionError::Storage(error) => error.into(),
|
||||||
|
|
||||||
|
// HACK: Handle new errors as `redb` adds them.
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------- TableError
|
||||||
|
#[allow(clippy::fallible_impl_from)] // We need to panic sometimes.
|
||||||
|
impl From<redb::TableError> for crate::RuntimeError {
|
||||||
|
/// Created by `redb` in:
|
||||||
|
/// - [`redb::WriteTransaction::open_table`](https://docs.rs/redb/1.5.0/redb/struct.WriteTransaction.html#method.open_table)
|
||||||
|
/// - [`redb::ReadTransaction::open_table`](https://docs.rs/redb/1.5.0/redb/struct.ReadTransaction.html#method.open_table)
|
||||||
|
fn from(error: redb::TableError) -> Self {
|
||||||
|
use redb::StorageError as E2;
|
||||||
|
use redb::TableError as E;
|
||||||
|
|
||||||
|
match error {
|
||||||
|
E::Storage(error) => error.into(),
|
||||||
|
|
||||||
|
// Only if we write incorrect code.
|
||||||
|
E::TableTypeMismatch { .. }
|
||||||
|
| E::TableIsMultimap(_)
|
||||||
|
| E::TableIsNotMultimap(_)
|
||||||
|
| E::TypeDefinitionChanged { .. }
|
||||||
|
| E::TableDoesNotExist(_)
|
||||||
|
| E::TableAlreadyOpen(..) => panic!("fix the database code! {error:#?}"),
|
||||||
|
|
||||||
|
// HACK: Handle new errors as `redb` adds them.
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------- StorageError
|
||||||
|
#[allow(clippy::fallible_impl_from)] // We need to panic sometimes.
|
||||||
|
impl From<redb::StorageError> for crate::RuntimeError {
|
||||||
|
/// Created by `redb` in:
|
||||||
|
/// - [`redb::Table`](https://docs.rs/redb/1.5.0/redb/struct.Table.html) functions
|
||||||
|
/// - [`redb::ReadOnlyTable`](https://docs.rs/redb/1.5.0/redb/struct.ReadOnlyTable.html) functions
|
||||||
|
fn from(error: redb::StorageError) -> Self {
|
||||||
|
use redb::StorageError as E;
|
||||||
|
|
||||||
|
match error {
|
||||||
|
E::Io(e) => Self::Io(e),
|
||||||
|
E::Corrupted(s) => panic!("{s:#?}\n{DATABASE_CORRUPT_MSG}"),
|
||||||
|
E::ValueTooLarge(s) => panic!("fix the database code! {s:#?}"),
|
||||||
|
E::LockPoisoned(s) => panic!("{s:#?}"),
|
||||||
|
|
||||||
|
// HACK: Handle new errors as `redb` adds them.
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------- Tests
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
// use super::*;
|
||||||
|
}
|
|
@ -1,20 +1,22 @@
|
||||||
//! Implementation of `trait RoTx/RwTx` for `sanakirja`.
|
//! Implementation of `trait TxRo/TxRw` for `redb`.
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Import
|
//---------------------------------------------------------------------------------------------------- Import
|
||||||
use crate::{
|
use crate::{
|
||||||
|
config::SyncMode,
|
||||||
|
env::Env,
|
||||||
error::RuntimeError,
|
error::RuntimeError,
|
||||||
transaction::{RoTx, RwTx},
|
transaction::{TxRo, TxRw},
|
||||||
};
|
};
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- RoTx
|
//---------------------------------------------------------------------------------------------------- TxRo
|
||||||
impl RoTx<'_> for sanakirja::Txn<&'_ sanakirja::Env> {
|
impl TxRo<'_> for redb::ReadTransaction<'_> {
|
||||||
fn commit(self) -> Result<(), RuntimeError> {
|
fn commit(self) -> Result<(), RuntimeError> {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- RwTx
|
//---------------------------------------------------------------------------------------------------- TxRw
|
||||||
impl RwTx<'_> for sanakirja::MutTxn<&'_ sanakirja::Env, ()> {
|
impl TxRw<'_> for redb::WriteTransaction<'_> {
|
||||||
/// TODO
|
/// TODO
|
||||||
/// # Errors
|
/// # Errors
|
||||||
/// TODO
|
/// TODO
|
10
database/src/backend/redb/types.rs
Normal file
10
database/src/backend/redb/types.rs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
//! `redb` type aliases.
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------- Types
|
||||||
|
// TODO: replace `()` with a byte container.
|
||||||
|
|
||||||
|
/// The concrete type for readable `redb` tables.
|
||||||
|
pub(super) type RedbTableRo<'env> = redb::ReadOnlyTable<'env, (), ()>;
|
||||||
|
|
||||||
|
/// The concrete type for readable/writable `redb` tables.
|
||||||
|
pub(super) type RedbTableRw<'env, 'tx> = redb::Table<'env, 'tx, (), ()>;
|
|
@ -1,49 +0,0 @@
|
||||||
//! Implementation of `trait Database` for `sanakirja`.
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Import
|
|
||||||
use crate::{
|
|
||||||
backend::sanakirja::types::SanakirjaDb, database::Database, error::RuntimeError, table::Table,
|
|
||||||
};
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Database Impls
|
|
||||||
impl<T: Table> Database<T> for SanakirjaDb {
|
|
||||||
type RoTx<'db> = sanakirja::Txn<&'db sanakirja::Env>;
|
|
||||||
type RwTx<'db> = sanakirja::MutTxn<&'db sanakirja::Env, ()>;
|
|
||||||
|
|
||||||
fn get(&self, ro_tx: &Self::RoTx<'_>, key: &T::Key) -> Result<Option<T::Value>, RuntimeError> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_range(
|
|
||||||
&self,
|
|
||||||
ro_tx: &Self::RoTx<'_>,
|
|
||||||
key: &T::Key,
|
|
||||||
amount: usize,
|
|
||||||
) -> Result<impl Iterator<Item = T::Value>, RuntimeError> {
|
|
||||||
let iter: std::vec::Drain<'_, T::Value> = todo!();
|
|
||||||
Ok(iter)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn put(
|
|
||||||
&mut self,
|
|
||||||
rx_tx: &mut Self::RwTx<'_>,
|
|
||||||
key: &T::Key,
|
|
||||||
value: &T::Value,
|
|
||||||
) -> Result<(), RuntimeError> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clear(&mut self, rx_tx: &mut Self::RwTx<'_>) -> Result<(), RuntimeError> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn delete(&mut self, rx_tx: &mut Self::RwTx<'_>, key: &T::Key) -> Result<bool, RuntimeError> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Tests
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
// use super::*;
|
|
||||||
}
|
|
|
@ -1,93 +0,0 @@
|
||||||
//! Implementation of `trait Env` for `sanakirja`.
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Import
|
|
||||||
use std::{path::Path, sync::Arc};
|
|
||||||
|
|
||||||
use crate::{
|
|
||||||
backend::sanakirja::types::SanakirjaDb,
|
|
||||||
config::Config,
|
|
||||||
database::Database,
|
|
||||||
env::Env,
|
|
||||||
error::{InitError, RuntimeError},
|
|
||||||
table::Table,
|
|
||||||
};
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- ConcreteEnv
|
|
||||||
/// A strongly typed, concrete database environment, backed by `sanakirja`.
|
|
||||||
pub struct ConcreteEnv {
|
|
||||||
/// The actual database environment.
|
|
||||||
env: sanakirja::Env,
|
|
||||||
|
|
||||||
/// The configuration we were opened with
|
|
||||||
/// (and in current use).
|
|
||||||
config: Config,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for ConcreteEnv {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
if let Err(e) = self.sync() {
|
|
||||||
// TODO: log error?
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: log that we are dropping the database.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Env Impl
|
|
||||||
impl Env for ConcreteEnv {
|
|
||||||
const MANUAL_RESIZE: bool = false;
|
|
||||||
const SYNCS_PER_TX: bool = true;
|
|
||||||
/// FIXME:
|
|
||||||
/// We could also implement `Borrow<sanakirja::Env> for ConcreteEnv`
|
|
||||||
/// instead of this reference.
|
|
||||||
type RoTx<'db> = sanakirja::Txn<&'db sanakirja::Env>;
|
|
||||||
type RwTx<'db> = sanakirja::MutTxn<&'db sanakirja::Env, ()>;
|
|
||||||
|
|
||||||
#[cold]
|
|
||||||
#[inline(never)] // called once.
|
|
||||||
fn open(config: Config) -> Result<Self, InitError> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn config(&self) -> &Config {
|
|
||||||
&self.config
|
|
||||||
}
|
|
||||||
|
|
||||||
fn sync(&self) -> Result<(), RuntimeError> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn ro_tx(&self) -> Result<Self::RoTx<'_>, RuntimeError> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn rw_tx(&self) -> Result<Self::RwTx<'_>, RuntimeError> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cold]
|
|
||||||
#[inline(never)] // called infrequently?.
|
|
||||||
fn create_tables_if_needed<T: Table>(
|
|
||||||
&self,
|
|
||||||
tx_rw: &mut Self::RwTx<'_>,
|
|
||||||
) -> Result<(), RuntimeError> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn open_database<T: Table>(
|
|
||||||
&self,
|
|
||||||
to_rw: &Self::RoTx<'_>,
|
|
||||||
) -> Result<impl Database<T>, RuntimeError> {
|
|
||||||
let tx: SanakirjaDb = todo!();
|
|
||||||
Ok(tx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Tests
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
// use super::*;
|
|
||||||
}
|
|
|
@ -1,51 +0,0 @@
|
||||||
//! Conversion from `sanakirja::Error` -> `cuprate_database::RuntimeError`.
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Import
|
|
||||||
use crate::constants::DATABASE_CORRUPT_MSG;
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- InitError
|
|
||||||
impl From<sanakirja::Error> for crate::InitError {
|
|
||||||
fn from(error: sanakirja::Error) -> Self {
|
|
||||||
use sanakirja::Error as E;
|
|
||||||
|
|
||||||
match error {
|
|
||||||
E::IO(io_error) => Self::Io(io_error),
|
|
||||||
E::VersionMismatch => Self::InvalidVersion,
|
|
||||||
|
|
||||||
// A CRC failure essentially means a `sanakirja` page was corrupt.
|
|
||||||
// <https://docs.rs/sanakirja/latest/sanakirja/enum.Error.html#variant.CRC>
|
|
||||||
E::Corrupt(_) | E::CRC(_) => Self::Corrupt,
|
|
||||||
|
|
||||||
// A database lock was poisoned.
|
|
||||||
// <https://docs.rs/sanakirja/latest/sanakirja/enum.Error.html#variant.Poison>
|
|
||||||
E::Poison => Self::Unknown(Box::new(error)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- RuntimeError
|
|
||||||
#[allow(clippy::fallible_impl_from)] // We need to panic sometimes.
|
|
||||||
impl From<sanakirja::Error> for crate::RuntimeError {
|
|
||||||
fn from(error: sanakirja::Error) -> Self {
|
|
||||||
use sanakirja::Error as E;
|
|
||||||
|
|
||||||
match error {
|
|
||||||
E::IO(io_error) => Self::Io(io_error),
|
|
||||||
|
|
||||||
// A CRC failure essentially means a `sanakirja` page was corrupt.
|
|
||||||
// <https://docs.rs/sanakirja/latest/sanakirja/enum.Error.html#variant.CRC>
|
|
||||||
E::Corrupt(_) | E::CRC(_) => panic!("{error:?}\n{DATABASE_CORRUPT_MSG}"),
|
|
||||||
|
|
||||||
// These errors should not occur, and if they do,
|
|
||||||
// the best thing `cuprate_database` can do for
|
|
||||||
// safety is to panic right here.
|
|
||||||
E::Poison | E::VersionMismatch => panic!("{error:?}"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Tests
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test {
|
|
||||||
// use super::*;
|
|
||||||
}
|
|
|
@ -1,6 +0,0 @@
|
||||||
//! `sanakirja` type aliases.
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Types
|
|
||||||
/// The concrete database type for `sanakirja`.
|
|
||||||
pub(super) type SanakirjaDb =
|
|
||||||
sanakirja::btree::Db_<[u8], [u8], sanakirja::btree::page_unsized::Page<[u8], [u8]>>;
|
|
|
@ -17,7 +17,7 @@ use std::{
|
||||||
|
|
||||||
use cuprate_helper::fs::cuprate_database_dir;
|
use cuprate_helper::fs::cuprate_database_dir;
|
||||||
|
|
||||||
use crate::{constants::DATABASE_FILENAME, resize::ResizeAlgorithm};
|
use crate::{constants::DATABASE_DATA_FILENAME, resize::ResizeAlgorithm};
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Config
|
//---------------------------------------------------------------------------------------------------- Config
|
||||||
/// Database [`Env`](crate::Env) configuration.
|
/// Database [`Env`](crate::Env) configuration.
|
||||||
|
@ -72,7 +72,7 @@ impl Config {
|
||||||
|
|
||||||
// Add the database filename to the directory.
|
// Add the database filename to the directory.
|
||||||
let mut db_file = db_directory.to_path_buf();
|
let mut db_file = db_directory.to_path_buf();
|
||||||
db_file.push(DATABASE_FILENAME);
|
db_file.push(DATABASE_DATA_FILENAME);
|
||||||
|
|
||||||
(db_directory, Cow::Owned(db_file))
|
(db_directory, Cow::Owned(db_file))
|
||||||
}
|
}
|
||||||
|
@ -175,15 +175,15 @@ impl Default for Config {
|
||||||
/// will always cause it to fully sync to disk.
|
/// will always cause it to fully sync to disk.
|
||||||
///
|
///
|
||||||
/// # Sync vs Async
|
/// # Sync vs Async
|
||||||
/// All invariants except [`SyncMode::Fast`] are `synchronous`,
|
/// All invariants except [`SyncMode::Async`] & [`SyncMode::Fast`]
|
||||||
/// as in the database will wait until the OS has finished syncing
|
/// are `synchronous`, as in the database will wait until the OS has
|
||||||
/// all the data to disk before continuing.
|
/// finished syncing all the data to disk before continuing.
|
||||||
///
|
///
|
||||||
/// `SyncMode::Fast` is `asynchronous`, meaning the database will _NOT_
|
/// `SyncMode::Async` & `SyncMode::Fast` are `asynchronous`, meaning
|
||||||
/// wait until the data is fully synced to disk before continuing.
|
/// the database will _NOT_ wait until the data is fully synced to disk
|
||||||
/// Note that this doesn't mean the database itself won't be synchronized
|
/// before continuing. Note that this doesn't mean the database itself
|
||||||
/// between readers/writers, but rather that the data _on disk_ may not
|
/// won't be synchronized between readers/writers, but rather that the
|
||||||
/// be immediately synchronized after a write.
|
/// data _on disk_ may not be immediately synchronized after a write.
|
||||||
///
|
///
|
||||||
/// Something like:
|
/// Something like:
|
||||||
/// ```rust,ignore
|
/// ```rust,ignore
|
||||||
|
@ -191,6 +191,17 @@ impl Default for Config {
|
||||||
/// db.get("key");
|
/// db.get("key");
|
||||||
/// ```
|
/// ```
|
||||||
/// will be fine, most likely pulling from memory instead of disk.
|
/// will be fine, most likely pulling from memory instead of disk.
|
||||||
|
///
|
||||||
|
/// # TODO
|
||||||
|
/// Dynamic sync's are not yet supported.
|
||||||
|
///
|
||||||
|
/// Only:
|
||||||
|
///
|
||||||
|
/// - [`SyncMode::Safe`]
|
||||||
|
/// - [`SyncMode::Async`]
|
||||||
|
/// - [`SyncMode::Fast`]
|
||||||
|
///
|
||||||
|
/// are supported, all other variants will panic on [`crate::Env::open`].
|
||||||
#[derive(Copy, Clone, Debug, Default, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
#[derive(Copy, Clone, Debug, Default, PartialEq, PartialOrd, Eq, Ord, Hash)]
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
|
@ -226,11 +237,27 @@ pub enum SyncMode {
|
||||||
///
|
///
|
||||||
/// Every database transaction commit will
|
/// Every database transaction commit will
|
||||||
/// fully sync all data to disk, _synchronously_,
|
/// fully sync all data to disk, _synchronously_,
|
||||||
/// so the database halts until synced.
|
/// so the database (writer) halts until synced.
|
||||||
///
|
///
|
||||||
/// This is expected to be very slow.
|
/// This is expected to be very slow.
|
||||||
|
///
|
||||||
|
/// This matches:
|
||||||
|
/// - LMDB without any special sync flags
|
||||||
|
/// - [`redb::Durability::Immediate`](https://docs.rs/redb/1.5.0/redb/enum.Durability.html#variant.Immediate)
|
||||||
Safe,
|
Safe,
|
||||||
|
|
||||||
|
/// Asynchrously sync to disk per transaction.
|
||||||
|
///
|
||||||
|
/// This is the same as [`SyncMode::Safe`],
|
||||||
|
/// but the syncs will be asynchronous, i.e.
|
||||||
|
/// each transaction commit will sync to disk,
|
||||||
|
/// but only eventually, not necessarily immediately.
|
||||||
|
///
|
||||||
|
/// This matches:
|
||||||
|
/// - [`MDB_MAPASYNC`](http://www.lmdb.tech/doc/group__mdb__env.html#gab034ed0d8e5938090aef5ee0997f7e94)
|
||||||
|
/// - [`redb::Durability::Eventual`](https://docs.rs/redb/1.5.0/redb/enum.Durability.html#variant.Eventual)
|
||||||
|
Async,
|
||||||
|
|
||||||
/// Fully sync to disk after we cross this transaction threshold.
|
/// Fully sync to disk after we cross this transaction threshold.
|
||||||
///
|
///
|
||||||
/// After committing [`usize`] amount of database
|
/// After committing [`usize`] amount of database
|
||||||
|
@ -247,6 +274,12 @@ pub enum SyncMode {
|
||||||
/// It will cause the database to never _actively_ sync,
|
/// It will cause the database to never _actively_ sync,
|
||||||
/// letting the OS decide when to flush data to disk.
|
/// letting the OS decide when to flush data to disk.
|
||||||
///
|
///
|
||||||
|
/// This matches:
|
||||||
|
/// - [`MDB_NOSYNC`](http://www.lmdb.tech/doc/group__mdb__env.html#ga5791dd1adb09123f82dd1f331209e12e) + [`MDB_MAPASYNC`](http://www.lmdb.tech/doc/group__mdb__env.html#gab034ed0d8e5938090aef5ee0997f7e94)
|
||||||
|
/// - [`redb::Durability::None`](https://docs.rs/redb/1.5.0/redb/enum.Durability.html#variant.None)
|
||||||
|
///
|
||||||
|
/// `monerod` reference: <https://github.com/monero-project/monero/blob/7b7958bbd9d76375c47dc418b4adabba0f0b1785/src/blockchain_db/lmdb/db_lmdb.cpp#L1380-L1381>
|
||||||
|
///
|
||||||
/// # Corruption
|
/// # Corruption
|
||||||
/// In the case of a system crash, the database
|
/// In the case of a system crash, the database
|
||||||
/// may become corrupted when using this option.
|
/// may become corrupted when using this option.
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
//! General constants used throughout `cuprate-database`.
|
//! General constants used throughout `cuprate-database`.
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Import
|
//---------------------------------------------------------------------------------------------------- Import
|
||||||
|
use cfg_if::cfg_if;
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Error Messages
|
//---------------------------------------------------------------------------------------------------- Error Messages
|
||||||
/// Corrupt database error message.
|
/// Corrupt database error message.
|
||||||
|
@ -18,27 +19,55 @@ TODO: instructions on:
|
||||||
4. etc";
|
4. etc";
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Misc
|
//---------------------------------------------------------------------------------------------------- Misc
|
||||||
cfg_if::cfg_if! {
|
/// Static string of the `crate` being used as the database backend.
|
||||||
// If both backends are enabled, fallback to `heed`.
|
///
|
||||||
// This is useful when using `--all-features`.
|
/// | Backend | Value |
|
||||||
if #[cfg(all(feature = "sanakirja", not(feature = "heed")))] {
|
/// |---------|-------|
|
||||||
/// Static string of the `crate` being used as the database backend.
|
/// | `heed` | "heed"
|
||||||
pub const DATABASE_BACKEND: &str = "sanakirja";
|
/// | `redb` | "redb"
|
||||||
|
pub const DATABASE_BACKEND: &str = {
|
||||||
/// Cuprate's database filename.
|
cfg_if! {
|
||||||
///
|
if #[cfg(all(feature = "redb", not(feature = "heed")))] {
|
||||||
/// This is the filename for Cuprate's database, used in [`Config::db_file`](crate::config::Config::db_file).
|
"redb"
|
||||||
pub const DATABASE_FILENAME: &str = "data.san"; // TODO: pick a name + extension.
|
} else {
|
||||||
} else {
|
"heed"
|
||||||
/// Static string of the `crate` being used as the database backend.
|
}
|
||||||
pub const DATABASE_BACKEND: &str = "heed";
|
|
||||||
|
|
||||||
/// Cuprate's database filename.
|
|
||||||
///
|
|
||||||
/// This is the filename for Cuprate's database, used in [`Config::db_file`](crate::config::Config::db_file).
|
|
||||||
pub const DATABASE_FILENAME: &str = "data.mdb";
|
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
|
/// Cuprate's database filename.
|
||||||
|
///
|
||||||
|
/// Used in [`Config::db_file`](crate::config::Config::db_file).
|
||||||
|
///
|
||||||
|
/// | Backend | Value |
|
||||||
|
/// |---------|-------|
|
||||||
|
/// | `heed` | "data.mdb"
|
||||||
|
/// | `redb` | "data.redb"
|
||||||
|
pub const DATABASE_DATA_FILENAME: &str = {
|
||||||
|
cfg_if! {
|
||||||
|
if #[cfg(all(feature = "redb", not(feature = "heed")))] {
|
||||||
|
"data.redb"
|
||||||
|
} else {
|
||||||
|
"data.mdb"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Cuprate's database lock filename.
|
||||||
|
///
|
||||||
|
/// | Backend | Value |
|
||||||
|
/// |---------|-------|
|
||||||
|
/// | `heed` | Some("lock.mdb")
|
||||||
|
/// | `redb` | None (redb doesn't use a file lock)
|
||||||
|
pub const DATABASE_LOCK_FILENAME: Option<&str> = {
|
||||||
|
cfg_if! {
|
||||||
|
if #[cfg(all(feature = "redb", not(feature = "heed")))] {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some("lock.mdb")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Tests
|
//---------------------------------------------------------------------------------------------------- Tests
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -1,58 +1,45 @@
|
||||||
//! Abstracted database; `trait Database`.
|
//! Abstracted database; `trait DatabaseRo` & `trait DatabaseRw`.
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Import
|
//---------------------------------------------------------------------------------------------------- Import
|
||||||
use crate::{
|
use crate::{error::RuntimeError, table::Table};
|
||||||
error::RuntimeError,
|
|
||||||
table::Table,
|
|
||||||
transaction::{RoTx, RwTx},
|
|
||||||
};
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Database
|
//---------------------------------------------------------------------------------------------------- DatabaseRo
|
||||||
/// Database (key-value store) abstraction.
|
/// Database (key-value store) read abstraction.
|
||||||
///
|
///
|
||||||
/// TODO
|
/// TODO: document relation between `DatabaseRo` <-> `DatabaseRw`.
|
||||||
pub trait Database<T: Table> {
|
pub trait DatabaseRo<T: Table> {
|
||||||
//------------------------------------------------ Types
|
|
||||||
/// TODO
|
|
||||||
type RoTx<'db>: RoTx<'db>;
|
|
||||||
|
|
||||||
/// TODO
|
|
||||||
type RwTx<'db>: RwTx<'db>;
|
|
||||||
|
|
||||||
//-------------------------------------------------------- Read
|
|
||||||
/// TODO
|
/// TODO
|
||||||
/// # Errors
|
/// # Errors
|
||||||
/// TODO
|
/// TODO
|
||||||
fn get(&self, ro_tx: &Self::RoTx<'_>, key: &T::Key) -> Result<Option<T::Value>, RuntimeError>;
|
fn get(&self, key: &T::Key) -> Result<Option<T::Value>, RuntimeError>;
|
||||||
|
|
||||||
/// TODO
|
/// TODO
|
||||||
/// # Errors
|
/// # Errors
|
||||||
/// TODO
|
/// TODO
|
||||||
fn get_range(
|
fn get_range(
|
||||||
&self,
|
&self,
|
||||||
ro_tx: &Self::RoTx<'_>,
|
|
||||||
key: &T::Key,
|
key: &T::Key,
|
||||||
amount: usize,
|
amount: usize,
|
||||||
) -> Result<impl Iterator<Item = T::Value>, RuntimeError>;
|
) -> Result<impl Iterator<Item = T::Value>, RuntimeError>;
|
||||||
|
}
|
||||||
//-------------------------------------------------------- Write
|
|
||||||
/// TODO
|
//---------------------------------------------------------------------------------------------------- DatabaseRw
|
||||||
/// # Errors
|
/// Database (key-value store) read/write abstraction.
|
||||||
/// TODO
|
///
|
||||||
fn put(
|
/// TODO: document relation between `DatabaseRo` <-> `DatabaseRw`.
|
||||||
&mut self,
|
pub trait DatabaseRw<T: Table>: DatabaseRo<T> {
|
||||||
rw_tx: &mut Self::RwTx<'_>,
|
/// TODO
|
||||||
key: &T::Key,
|
/// # Errors
|
||||||
value: &T::Value,
|
/// TODO
|
||||||
) -> Result<(), RuntimeError>;
|
fn put(&mut self, key: &T::Key, value: &T::Value) -> Result<(), RuntimeError>;
|
||||||
|
|
||||||
/// TODO
|
/// TODO
|
||||||
/// # Errors
|
/// # Errors
|
||||||
/// TODO
|
/// TODO
|
||||||
fn clear(&mut self, rw_tx: &mut Self::RwTx<'_>) -> Result<(), RuntimeError>;
|
fn clear(&mut self) -> Result<(), RuntimeError>;
|
||||||
|
|
||||||
/// TODO
|
/// TODO
|
||||||
/// # Errors
|
/// # Errors
|
||||||
/// TODO
|
/// TODO
|
||||||
fn delete(&mut self, rw_tx: &mut Self::RwTx<'_>, key: &T::Key) -> Result<bool, RuntimeError>;
|
fn delete(&mut self, key: &T::Key) -> Result<bool, RuntimeError>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,11 +3,11 @@
|
||||||
//---------------------------------------------------------------------------------------------------- Import
|
//---------------------------------------------------------------------------------------------------- Import
|
||||||
use crate::{
|
use crate::{
|
||||||
config::Config,
|
config::Config,
|
||||||
database::Database,
|
database::{DatabaseRo, DatabaseRw},
|
||||||
error::{InitError, RuntimeError},
|
error::{InitError, RuntimeError},
|
||||||
resize::ResizeAlgorithm,
|
resize::ResizeAlgorithm,
|
||||||
table::Table,
|
table::Table,
|
||||||
transaction::{RoTx, RwTx},
|
transaction::{TxRo, TxRw},
|
||||||
};
|
};
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Env
|
//---------------------------------------------------------------------------------------------------- Env
|
||||||
|
@ -40,10 +40,10 @@ pub trait Env: Sized {
|
||||||
|
|
||||||
//------------------------------------------------ Types
|
//------------------------------------------------ Types
|
||||||
/// TODO
|
/// TODO
|
||||||
type RoTx<'db>: RoTx<'db>;
|
type TxRo<'env>: TxRo<'env>;
|
||||||
|
|
||||||
/// TODO
|
/// TODO
|
||||||
type RwTx<'db>: RwTx<'db>;
|
type TxRw<'env>: TxRw<'env>;
|
||||||
|
|
||||||
//------------------------------------------------ Required
|
//------------------------------------------------ Required
|
||||||
/// TODO
|
/// TODO
|
||||||
|
@ -51,6 +51,11 @@ pub trait Env: Sized {
|
||||||
/// TODO
|
/// TODO
|
||||||
fn open(config: Config) -> Result<Self, InitError>;
|
fn open(config: Config) -> Result<Self, InitError>;
|
||||||
|
|
||||||
|
/// TODO
|
||||||
|
/// # Errors
|
||||||
|
/// TODO
|
||||||
|
fn create_tables<T: Table>(&self, tx_rw: &mut Self::TxRw<'_>) -> Result<(), RuntimeError>;
|
||||||
|
|
||||||
/// Return the [`Config`] that this database was [`Env::open`]ed with.
|
/// Return the [`Config`] that this database was [`Env::open`]ed with.
|
||||||
fn config(&self) -> &Config;
|
fn config(&self) -> &Config;
|
||||||
|
|
||||||
|
@ -79,6 +84,16 @@ pub trait Env: Sized {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// TODO
|
/// TODO
|
||||||
|
///
|
||||||
|
/// # Invariant
|
||||||
|
/// This must **fully** and **synchronously** flush the database data to disk.
|
||||||
|
///
|
||||||
|
/// I.e., after this function returns, there must be no doubts
|
||||||
|
/// that the data isn't synced yet, it _must_ be synced.
|
||||||
|
///
|
||||||
|
/// TODO: either this invariant or `sync()` itself will most
|
||||||
|
/// likely be removed/changed after `SyncMode` is finalized.
|
||||||
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
/// TODO
|
/// TODO
|
||||||
fn sync(&self) -> Result<(), RuntimeError>;
|
fn sync(&self) -> Result<(), RuntimeError>;
|
||||||
|
@ -110,36 +125,44 @@ pub trait Env: Sized {
|
||||||
/// TODO
|
/// TODO
|
||||||
/// # Errors
|
/// # Errors
|
||||||
/// TODO
|
/// TODO
|
||||||
fn ro_tx(&self) -> Result<Self::RoTx<'_>, RuntimeError>;
|
fn tx_ro(&self) -> Result<Self::TxRo<'_>, RuntimeError>;
|
||||||
|
|
||||||
/// TODO
|
/// TODO
|
||||||
/// # Errors
|
/// # Errors
|
||||||
/// TODO
|
/// TODO
|
||||||
fn rw_tx(&self) -> Result<Self::RwTx<'_>, RuntimeError>;
|
fn tx_rw(&self) -> Result<Self::TxRw<'_>, RuntimeError>;
|
||||||
|
|
||||||
/// TODO
|
|
||||||
/// # Errors
|
|
||||||
/// TODO
|
|
||||||
fn create_tables_if_needed<T: Table>(
|
|
||||||
&self,
|
|
||||||
rw_tx: &mut Self::RwTx<'_>,
|
|
||||||
) -> Result<(), RuntimeError>;
|
|
||||||
|
|
||||||
/// TODO
|
/// TODO
|
||||||
///
|
///
|
||||||
/// # TODO: Invariant
|
/// # TODO: Invariant
|
||||||
/// This should never panic the database because the table doesn't exist.
|
/// This should never panic the database because the table doesn't exist.
|
||||||
///
|
///
|
||||||
/// Opening/using the database env should have an invariant
|
/// Opening/using the database [`Env`] should have an invariant
|
||||||
/// that it creates all the tables we need, such that this
|
/// that it creates all the tables we need, such that this
|
||||||
/// never returns `None`.
|
/// never returns `None`.
|
||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
/// TODO
|
/// TODO
|
||||||
fn open_database<T: Table>(
|
fn open_db_ro<T: Table>(
|
||||||
&self,
|
&self,
|
||||||
ro_tx: &Self::RoTx<'_>,
|
tx_ro: &Self::TxRo<'_>,
|
||||||
) -> Result<impl Database<T>, RuntimeError>;
|
) -> Result<impl DatabaseRo<T>, RuntimeError>;
|
||||||
|
|
||||||
|
/// TODO
|
||||||
|
///
|
||||||
|
/// # TODO: Invariant
|
||||||
|
/// This should never panic the database because the table doesn't exist.
|
||||||
|
///
|
||||||
|
/// Opening/using the database [`Env`] should have an invariant
|
||||||
|
/// that it creates all the tables we need, such that this
|
||||||
|
/// never returns `None`.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
/// TODO
|
||||||
|
fn open_db_rw<T: Table>(
|
||||||
|
&self,
|
||||||
|
tx_rw: &mut Self::TxRw<'_>,
|
||||||
|
) -> Result<impl DatabaseRw<T>, RuntimeError>;
|
||||||
|
|
||||||
//------------------------------------------------ Provided
|
//------------------------------------------------ Provided
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,28 +7,29 @@
|
||||||
//!
|
//!
|
||||||
//! # Purpose
|
//! # Purpose
|
||||||
//! This crate does 3 things:
|
//! This crate does 3 things:
|
||||||
//! 1. Abstracts various databases with the [`Env`], [`Database`], [`Table`], [`Key`], [`RoTx`], and [`RwTx`] traits
|
//! 1. Abstracts various database backends with traits
|
||||||
//! 2. Implements various `Monero` related [functions](ops) & [`tables`]
|
//! 2. Implements various `Monero` related [functions](ops) & [`tables`]
|
||||||
//! 3. Exposes a [`tower::Service`] backed by a thread-pool
|
//! 3. Exposes a [`tower::Service`] backed by a thread-pool
|
||||||
//!
|
//!
|
||||||
//! # Terminology
|
//! # Terminology
|
||||||
//! To be more clear on some terms used in this crate:
|
//! To be more clear on some terms used in this crate:
|
||||||
//!
|
//!
|
||||||
//! | Term | Meaning |
|
//! | Term | Meaning |
|
||||||
//! |------------|--------------------------------------|
|
//! |---------------|--------------------------------------|
|
||||||
//! | `Env` | The 1 database environment, the "whole" thing
|
//! | `Env` | The 1 database environment, the "whole" thing
|
||||||
//! | `Database` | A `key/value` store
|
//! | `DatabaseRo` | A read-only `key/value` store
|
||||||
//! | `Table` | Solely the metadata of a `Database` (the `key` and `value` types, and the name)
|
//! | `DatabaseRw` | A readable/writable `key/value` store
|
||||||
//! | `RoTx` | Read only transaction
|
//! | `Table` | Solely the metadata of a `Database` (the `key` and `value` types, and the name)
|
||||||
//! | `RwTx` | Read/write transaction
|
//! | `TxRo` | Read only transaction
|
||||||
|
//! | `TxRw` | Read/write transaction
|
||||||
//!
|
//!
|
||||||
//! The dataflow is `Env` -> `Tx` -> `Database`
|
//! The dataflow is `Env` -> `Tx` -> `Database`
|
||||||
//!
|
//!
|
||||||
//! Which reads as:
|
//! Which reads as:
|
||||||
//! 1. You have a database `Environment`
|
//! 1. You have a database `Environment`
|
||||||
//! 2. You open up a `Transaction`
|
//! 1. You open up a `Transaction`
|
||||||
//! 2. You get a particular `Database` from that `Environment`
|
//! 1. You get a particular `Database` from that `Environment`
|
||||||
//! 3. You can now read/write data from/to that `Database`
|
//! 1. You can now read/write data from/to that `Database`
|
||||||
//!
|
//!
|
||||||
//! # `ConcreteEnv`
|
//! # `ConcreteEnv`
|
||||||
//! This crate exposes [`ConcreteEnv`], which is a non-generic/non-dynamic,
|
//! This crate exposes [`ConcreteEnv`], which is a non-generic/non-dynamic,
|
||||||
|
@ -60,13 +61,18 @@
|
||||||
//! going to be storing any databases in structs, to lessen
|
//! going to be storing any databases in structs, to lessen
|
||||||
//! the generic `<D: Database>` pain.
|
//! the generic `<D: Database>` pain.
|
||||||
//!
|
//!
|
||||||
|
//! TODO: we could replace `ConcreteEnv` with `fn Env::open() -> impl Env`/
|
||||||
|
//! and use `<E: Env>` everywhere it is stored instead. This would allow
|
||||||
|
//! generic-backed dynamic runtime selection of the database backend, i.e.
|
||||||
|
//! the user can select which database backend they use.
|
||||||
|
//!
|
||||||
//! # Feature flags
|
//! # Feature flags
|
||||||
//! The `service` module requires the `service` feature to be enabled.
|
//! The `service` module requires the `service` feature to be enabled.
|
||||||
//! See the module for more documentation.
|
//! See the module for more documentation.
|
||||||
//!
|
//!
|
||||||
//! Different database backends are enabled by the feature flags:
|
//! Different database backends are enabled by the feature flags:
|
||||||
//! - `heed`
|
//! - `heed` (LMDB)
|
||||||
//! - `sanakirja`
|
//! - `redb`
|
||||||
//!
|
//!
|
||||||
//! The default is `heed`.
|
//! The default is `heed`.
|
||||||
//!
|
//!
|
||||||
|
@ -92,7 +98,7 @@
|
||||||
//! use cuprate_database::{
|
//! use cuprate_database::{
|
||||||
//! config::Config,
|
//! config::Config,
|
||||||
//! ConcreteEnv,
|
//! ConcreteEnv,
|
||||||
//! Env, Key, RoTx, RwTx,
|
//! Env, Key, TxRo, TxRw,
|
||||||
//! service::{ReadRequest, WriteRequest, Response},
|
//! service::{ReadRequest, WriteRequest, Response},
|
||||||
//! };
|
//! };
|
||||||
//!
|
//!
|
||||||
|
@ -166,7 +172,7 @@
|
||||||
unused_comparisons,
|
unused_comparisons,
|
||||||
nonstandard_style
|
nonstandard_style
|
||||||
)]
|
)]
|
||||||
#![allow(unreachable_code, unused_variables, dead_code)] // TODO: remove
|
#![allow(unreachable_code, unused_variables, dead_code, unused_imports)] // TODO: remove
|
||||||
#![allow(
|
#![allow(
|
||||||
// FIXME: this lint affects crates outside of
|
// FIXME: this lint affects crates outside of
|
||||||
// `database/` for some reason, allow for now.
|
// `database/` for some reason, allow for now.
|
||||||
|
@ -289,10 +295,12 @@ pub use backend::ConcreteEnv;
|
||||||
pub mod config;
|
pub mod config;
|
||||||
|
|
||||||
mod constants;
|
mod constants;
|
||||||
pub use constants::{DATABASE_BACKEND, DATABASE_CORRUPT_MSG, DATABASE_FILENAME};
|
pub use constants::{
|
||||||
|
DATABASE_BACKEND, DATABASE_CORRUPT_MSG, DATABASE_DATA_FILENAME, DATABASE_LOCK_FILENAME,
|
||||||
|
};
|
||||||
|
|
||||||
mod database;
|
mod database;
|
||||||
pub use database::Database;
|
pub use database::{DatabaseRo, DatabaseRw};
|
||||||
|
|
||||||
mod env;
|
mod env;
|
||||||
pub use env::Env;
|
pub use env::Env;
|
||||||
|
@ -320,7 +328,7 @@ pub use table::Table;
|
||||||
pub mod tables;
|
pub mod tables;
|
||||||
|
|
||||||
mod transaction;
|
mod transaction;
|
||||||
pub use transaction::{RoTx, RwTx};
|
pub use transaction::{TxRo, TxRw};
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Feature-gated
|
//---------------------------------------------------------------------------------------------------- Feature-gated
|
||||||
#[cfg(feature = "service")]
|
#[cfg(feature = "service")]
|
||||||
|
|
|
@ -1,14 +1,6 @@
|
||||||
//! Alternative blocks.
|
//! Alternative blocks.
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Import
|
//---------------------------------------------------------------------------------------------------- Import
|
||||||
#[allow(unused_imports)] // FIXME: these traits will be eventually in the function impls.
|
|
||||||
use crate::{
|
|
||||||
database::Database,
|
|
||||||
env::Env,
|
|
||||||
table::Table,
|
|
||||||
transaction::{RoTx, RwTx},
|
|
||||||
ConcreteEnv,
|
|
||||||
};
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Free Functions
|
//---------------------------------------------------------------------------------------------------- Free Functions
|
||||||
/// TODO
|
/// TODO
|
||||||
|
|
|
@ -1,14 +1,6 @@
|
||||||
//! Blocks.
|
//! Blocks.
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Import
|
//---------------------------------------------------------------------------------------------------- Import
|
||||||
#[allow(unused_imports)] // FIXME: these traits will be eventually in the function impls.
|
|
||||||
use crate::{
|
|
||||||
database::Database,
|
|
||||||
env::Env,
|
|
||||||
table::Table,
|
|
||||||
transaction::{RoTx, RwTx},
|
|
||||||
ConcreteEnv,
|
|
||||||
};
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Free Functions
|
//---------------------------------------------------------------------------------------------------- Free Functions
|
||||||
/// TODO
|
/// TODO
|
||||||
|
|
|
@ -1,14 +1,6 @@
|
||||||
//! Blockchain.
|
//! Blockchain.
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Import
|
//---------------------------------------------------------------------------------------------------- Import
|
||||||
#[allow(unused_imports)] // FIXME: these traits will be eventually in the function impls.
|
|
||||||
use crate::{
|
|
||||||
database::Database,
|
|
||||||
env::Env,
|
|
||||||
table::Table,
|
|
||||||
transaction::{RoTx, RwTx},
|
|
||||||
ConcreteEnv,
|
|
||||||
};
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Free Functions
|
//---------------------------------------------------------------------------------------------------- Free Functions
|
||||||
/// TODO
|
/// TODO
|
||||||
|
|
|
@ -1,14 +1,6 @@
|
||||||
//! Outputs.
|
//! Outputs.
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Import
|
//---------------------------------------------------------------------------------------------------- Import
|
||||||
#[allow(unused_imports)] // FIXME: these traits will be eventually in the function impls.
|
|
||||||
use crate::{
|
|
||||||
database::Database,
|
|
||||||
env::Env,
|
|
||||||
table::Table,
|
|
||||||
transaction::{RoTx, RwTx},
|
|
||||||
ConcreteEnv,
|
|
||||||
};
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Free Functions
|
//---------------------------------------------------------------------------------------------------- Free Functions
|
||||||
/// TODO
|
/// TODO
|
||||||
|
|
|
@ -1,14 +1,6 @@
|
||||||
//! Properties.
|
//! Properties.
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Import
|
//---------------------------------------------------------------------------------------------------- Import
|
||||||
#[allow(unused_imports)] // FIXME: these traits will be eventually in the function impls.
|
|
||||||
use crate::{
|
|
||||||
database::Database,
|
|
||||||
env::Env,
|
|
||||||
table::Table,
|
|
||||||
transaction::{RoTx, RwTx},
|
|
||||||
ConcreteEnv,
|
|
||||||
};
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Free Functions
|
//---------------------------------------------------------------------------------------------------- Free Functions
|
||||||
/// TODO
|
/// TODO
|
||||||
|
|
|
@ -1,14 +1,6 @@
|
||||||
//! Spent keys.
|
//! Spent keys.
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Import
|
//---------------------------------------------------------------------------------------------------- Import
|
||||||
#[allow(unused_imports)] // FIXME: these traits will be eventually in the function impls.
|
|
||||||
use crate::{
|
|
||||||
database::Database,
|
|
||||||
env::Env,
|
|
||||||
table::Table,
|
|
||||||
transaction::{RoTx, RwTx},
|
|
||||||
ConcreteEnv,
|
|
||||||
};
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Free Functions
|
//---------------------------------------------------------------------------------------------------- Free Functions
|
||||||
/// TODO
|
/// TODO
|
||||||
|
|
|
@ -1,14 +1,6 @@
|
||||||
//! Transactions.
|
//! Transactions.
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Import
|
//---------------------------------------------------------------------------------------------------- Import
|
||||||
#[allow(unused_imports)] // FIXME: these traits will be eventually in the function impls.
|
|
||||||
use crate::{
|
|
||||||
database::Database,
|
|
||||||
env::Env,
|
|
||||||
table::Table,
|
|
||||||
transaction::{RoTx, RwTx},
|
|
||||||
ConcreteEnv,
|
|
||||||
};
|
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Free Functions
|
//---------------------------------------------------------------------------------------------------- Free Functions
|
||||||
/// TODO
|
/// TODO
|
||||||
|
|
|
@ -29,7 +29,7 @@ use std::{num::NonZeroUsize, sync::OnceLock};
|
||||||
///
|
///
|
||||||
/// # TODO
|
/// # TODO
|
||||||
/// We could test around with different algorithms.
|
/// We could test around with different algorithms.
|
||||||
/// Calling [`heed::Env::resize`] is surprisingly fast,
|
/// Calling `heed::Env::resize` is surprisingly fast,
|
||||||
/// around `0.0000082s` on my machine. We could probably
|
/// around `0.0000082s` on my machine. We could probably
|
||||||
/// get away with smaller and more frequent resizes.
|
/// get away with smaller and more frequent resizes.
|
||||||
/// **With the caveat being we are taking a `WriteGuard` to a `RwLock`.**
|
/// **With the caveat being we are taking a `WriteGuard` to a `RwLock`.**
|
||||||
|
|
|
@ -1,24 +1,24 @@
|
||||||
//! Database transaction abstraction; `trait RoTx`, `trait RwTx`.
|
//! Database transaction abstraction; `trait TxRo`, `trait TxRw`.
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- Import
|
//---------------------------------------------------------------------------------------------------- Import
|
||||||
use crate::error::RuntimeError;
|
use crate::{config::SyncMode, env::Env, error::RuntimeError};
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- RoTx
|
//---------------------------------------------------------------------------------------------------- TxRo
|
||||||
/// Read-only database transaction.
|
/// Read-only database transaction.
|
||||||
///
|
///
|
||||||
/// TODO
|
/// TODO
|
||||||
pub trait RoTx<'db> {
|
pub trait TxRo<'env> {
|
||||||
/// TODO
|
/// TODO
|
||||||
/// # Errors
|
/// # Errors
|
||||||
/// TODO
|
/// TODO
|
||||||
fn commit(self) -> Result<(), RuntimeError>;
|
fn commit(self) -> Result<(), RuntimeError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
//---------------------------------------------------------------------------------------------------- RwTx
|
//---------------------------------------------------------------------------------------------------- TxRw
|
||||||
/// Read/write database transaction.
|
/// Read/write database transaction.
|
||||||
///
|
///
|
||||||
/// TODO
|
/// TODO
|
||||||
pub trait RwTx<'db> {
|
pub trait TxRw<'env> {
|
||||||
/// TODO
|
/// TODO
|
||||||
/// # Errors
|
/// # Errors
|
||||||
/// TODO
|
/// TODO
|
||||||
|
|
Loading…
Reference in a new issue