mirror of
https://github.com/Cuprate/cuprate.git
synced 2025-04-16 11:11:54 +00:00
parent
d8d1e34266
commit
7e8e62135c
5 changed files with 22 additions and 88 deletions
binaries/cuprated
storage/database/src
|
@ -54,11 +54,11 @@ check_client_pool_interval = { secs = 30, nanos = 0 }
|
|||
## Txpool storage config.
|
||||
[storage.txpool]
|
||||
## The database sync mode for the txpool.
|
||||
sync_mode = "Async"
|
||||
sync_mode = "Fast"
|
||||
## The maximum size of all the txs in the pool (bytes).
|
||||
max_txpool_byte_size = 100_000_000
|
||||
|
||||
## Blockchain storage config.
|
||||
[storage.blockchain]
|
||||
## The database sync mode for the blockchain.
|
||||
sync_mode = "Async"
|
||||
sync_mode = "Fast"
|
||||
|
|
|
@ -29,23 +29,13 @@ impl Default for StorageConfig {
|
|||
}
|
||||
|
||||
/// The blockchain config.
|
||||
#[derive(Debug, Deserialize, Serialize, PartialEq, Eq)]
|
||||
#[derive(Default, Debug, Deserialize, Serialize, PartialEq, Eq)]
|
||||
#[serde(deny_unknown_fields, default)]
|
||||
pub struct BlockchainConfig {
|
||||
#[serde(flatten)]
|
||||
pub shared: SharedStorageConfig,
|
||||
}
|
||||
|
||||
impl Default for BlockchainConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
shared: SharedStorageConfig {
|
||||
sync_mode: SyncMode::Async,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The tx-pool config.
|
||||
#[derive(Debug, Deserialize, Serialize, PartialEq, Eq)]
|
||||
#[serde(deny_unknown_fields, default)]
|
||||
|
@ -60,9 +50,7 @@ pub struct TxpoolConfig {
|
|||
impl Default for TxpoolConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
shared: SharedStorageConfig {
|
||||
sync_mode: SyncMode::Async,
|
||||
},
|
||||
shared: SharedStorageConfig::default(),
|
||||
max_txpool_byte_size: 100_000_000,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -122,10 +122,10 @@ impl Env for ConcreteEnv {
|
|||
// <https://github.com/monero-project/monero/blob/059028a30a8ae9752338a7897329fe8012a310d5/src/blockchain_db/lmdb/db_lmdb.cpp#L1324>
|
||||
let flags = match config.sync_mode {
|
||||
SyncMode::Safe => EnvFlags::empty(),
|
||||
SyncMode::Async => EnvFlags::MAP_ASYNC,
|
||||
SyncMode::Fast => EnvFlags::NO_SYNC | EnvFlags::WRITE_MAP | EnvFlags::MAP_ASYNC,
|
||||
// SOMEDAY: dynamic syncs are not implemented.
|
||||
SyncMode::FastThenSafe | SyncMode::Threshold(_) => unimplemented!(),
|
||||
// TODO: impl `FastThenSafe`
|
||||
SyncMode::FastThenSafe | SyncMode::Fast => {
|
||||
EnvFlags::NO_SYNC | EnvFlags::WRITE_MAP | EnvFlags::MAP_ASYNC
|
||||
}
|
||||
};
|
||||
|
||||
// SAFETY: the flags we're setting are 'unsafe'
|
||||
|
|
|
@ -52,15 +52,9 @@ impl Env for ConcreteEnv {
|
|||
fn open(config: Config) -> Result<Self, InitError> {
|
||||
// SOMEDAY: dynamic syncs are not implemented.
|
||||
let durability = match config.sync_mode {
|
||||
// FIXME: 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,
|
||||
// FIXME: `Fast` maps to `Eventual` instead of `None` because of:
|
||||
// <https://github.com/Cuprate/cuprate/issues/149>
|
||||
SyncMode::Async | SyncMode::Fast => redb::Durability::Eventual,
|
||||
// SOMEDAY: dynamic syncs are not implemented.
|
||||
SyncMode::FastThenSafe | SyncMode::Threshold(_) => unimplemented!(),
|
||||
// TODO: impl `FastThenSafe`
|
||||
SyncMode::FastThenSafe | SyncMode::Fast => redb::Durability::Eventual,
|
||||
};
|
||||
|
||||
let env_builder = redb::Builder::new();
|
||||
|
|
|
@ -19,41 +19,15 @@ use serde::{Deserialize, Serialize};
|
|||
///
|
||||
/// Regardless of the variant chosen, dropping [`Env`](crate::Env)
|
||||
/// will always cause it to fully sync to disk.
|
||||
///
|
||||
/// # Sync vs Async
|
||||
/// All invariants except [`SyncMode::Async`] & [`SyncMode::Fast`]
|
||||
/// are `synchronous`, as in the database will wait until the OS has
|
||||
/// finished syncing all the data to disk before continuing.
|
||||
///
|
||||
/// `SyncMode::Async` & `SyncMode::Fast` are `asynchronous`, meaning
|
||||
/// the database will _NOT_ wait until the data is fully synced to disk
|
||||
/// before continuing. Note that this doesn't mean the database itself
|
||||
/// won't be synchronized between readers/writers, but rather that the
|
||||
/// data _on disk_ may not be immediately synchronized after a write.
|
||||
///
|
||||
/// Something like:
|
||||
/// ```rust,ignore
|
||||
/// db.put("key", value);
|
||||
/// db.get("key");
|
||||
/// ```
|
||||
/// will be fine, most likely pulling from memory instead of disk.
|
||||
///
|
||||
/// # SOMEDAY
|
||||
/// 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)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub enum SyncMode {
|
||||
/// Use [`SyncMode::Fast`] until fully synced,
|
||||
/// then use [`SyncMode::Safe`].
|
||||
///
|
||||
/// # TODO
|
||||
/// This is not implemented internally and has the same behavior as [`SyncMode::Fast`].
|
||||
//
|
||||
// # SOMEDAY: how to implement this?
|
||||
// ref: <https://github.com/monero-project/monero/issues/1463>
|
||||
// monerod-solution: <https://github.com/monero-project/monero/pull/1506>
|
||||
|
@ -74,7 +48,6 @@ pub enum SyncMode {
|
|||
// switch to safe mode, until then, go fast.
|
||||
FastThenSafe,
|
||||
|
||||
#[default]
|
||||
/// Fully sync to disk per transaction.
|
||||
///
|
||||
/// Every database transaction commit will
|
||||
|
@ -88,27 +61,7 @@ pub enum SyncMode {
|
|||
/// - [`redb::Durability::Immediate`](https://docs.rs/redb/1.5.0/redb/enum.Durability.html#variant.Immediate)
|
||||
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 maps to:
|
||||
/// - [`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.
|
||||
///
|
||||
/// After committing [`usize`] amount of database
|
||||
/// transactions, it will be sync to disk.
|
||||
///
|
||||
/// `0` behaves the same as [`SyncMode::Safe`], and a ridiculously large
|
||||
/// number like `usize::MAX` is practically the same as [`SyncMode::Fast`].
|
||||
Threshold(usize),
|
||||
|
||||
#[default]
|
||||
/// Only flush at database shutdown.
|
||||
///
|
||||
/// This is the fastest, yet unsafest option.
|
||||
|
@ -117,26 +70,25 @@ pub enum SyncMode {
|
|||
/// letting the OS decide when to flush data to disk[^1].
|
||||
///
|
||||
/// This maps to:
|
||||
/// - [`MDB_NOSYNC`](http://www.lmdb.tech/doc/group__mdb__env.html#ga5791dd1adb09123f82dd1f331209e12e) + [`MDB_MAPASYNC`](http://www.lmdb.tech/doc/group__mdb__env.html#gab034ed0d8e5938090aef5ee0997f7e94)
|
||||
/// - [`MDB_NOSYNC | MDB_WRITEMAP | MDB_MAPASYNC`](https://github.com/monero-project/monero/blob/90359e31fd657251cb357ecba02c4de2442d1b5c/src/blockchain_db/lmdb/db_lmdb.cpp#L1444)
|
||||
/// - [`redb::Durability::Eventual`](https://docs.rs/redb/1.5.0/redb/enum.Durability.html#variant.Eventual)
|
||||
///
|
||||
/// [`monerod` reference](https://github.com/monero-project/monero/blob/7b7958bbd9d76375c47dc418b4adabba0f0b1785/src/blockchain_db/lmdb/db_lmdb.cpp#L1380-L1381).
|
||||
/// # Default
|
||||
/// This is the default [`SyncMode`].
|
||||
/// ```rust
|
||||
/// use cuprate_database::config::SyncMode;
|
||||
///
|
||||
/// assert_eq!(SyncMode::default(), SyncMode::Fast);
|
||||
/// ```
|
||||
///
|
||||
/// # Corruption
|
||||
/// In the case of a system crash, the database
|
||||
/// may become corrupted when using this option.
|
||||
///
|
||||
///
|
||||
/// [^1]: Semantically, this variant would actually map to
|
||||
/// [`redb::Durability::None`](https://docs.rs/redb/1.5.0/redb/enum.Durability.html#variant.None),
|
||||
/// however due to [`#149`](https://github.com/Cuprate/cuprate/issues/149),
|
||||
/// this is not possible. As such, when using the `redb` backend,
|
||||
/// transaction writes "should be persistent some time after `WriteTransaction::commit` returns."
|
||||
/// Thus, [`SyncMode::Async`] will map to the same `redb::Durability::Eventual` as [`SyncMode::Fast`].
|
||||
//
|
||||
// FIXME: we could call this `unsafe`
|
||||
// and use that terminology in the config file
|
||||
// so users know exactly what they are getting
|
||||
// themselves into.
|
||||
Fast,
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue