diff --git a/Cargo.toml b/Cargo.toml index 9e5db61..fa93882 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ arrayref = "0.3" async-stream = "0.3" async-trait = "0.1" bytes = { package = "lifetimed-bytes", git = "https://github.com/vorot93/lifetimed-bytes" } +const_format = "0.2" ethereum = "0.7" ethereum-interfaces = { git = "https://github.com/rust-ethereum/interfaces", default-features = false, features = ["remotekv"] } ethereum-types = "0.11" @@ -22,6 +23,7 @@ impls = "1" maplit = "1" mdbx = { git = "https://github.com/vorot93/mdbx-rs" } mdbx-sys = { git = "https://github.com/vorot93/mdbx-rs" } +once_cell = "1" rand = "0.8" rlp = "0.5" rlp-derive = "0.1" diff --git a/src/dbutils/table.rs b/src/dbutils/table.rs index 634c270..29f2fd3 100644 --- a/src/dbutils/table.rs +++ b/src/dbutils/table.rs @@ -8,9 +8,15 @@ pub trait Table: 'static { pub trait DupSort: Table {} macro_rules! decl_tables { - ($accum:expr => /* nothing left */) => { pub const COUNT: usize = $accum; }; - ($accum:expr => $name:ident => $db_name:expr, $($tail:tt)*) => { - decl_tables!($accum + 1 => $($tail)*); + (($count:expr, $all_tables:expr) => /* nothing left */) => { + const COUNT: usize = $count; + + fn all_tables() -> impl Iterator { + $all_tables.split(' ') + } + }; + (($count:expr, $all_tables:expr) => $name:ident => $db_name:expr, $($tail:tt)*) => { + decl_tables!(($count, const_format::concatcp!($all_tables, " ", $db_name)) => $($tail)*); #[derive(Clone, Copy, Debug)] pub struct $name; @@ -32,11 +38,17 @@ macro_rules! decl_tables { } }; ($name:ident => $db_name:expr, $($tail:tt)*) => { - decl_tables!(0 => $name => $db_name, $($tail)*); + decl_tables!((0, "") => $name => $db_name, $($tail)*); } } pub mod tables { + use std::collections::HashMap; + + use once_cell::sync::Lazy; + + use crate::Table; + use super::DupSort; decl_tables!( @@ -91,6 +103,26 @@ pub mod tables { impl DupSort for PlainAccountChangeSet {} impl DupSort for PlainStorageChangeSet {} impl DupSort for PlainState {} + + pub const DUPSORT_TABLES: &[&str] = &[ + HashedStorage::DB_NAME, + PlainAccountChangeSet::DB_NAME, + PlainStorageChangeSet::DB_NAME, + PlainState::DB_NAME, + ]; + + pub static TABLE_MAP: Lazy> = Lazy::new(|| { + let mut v = HashMap::with_capacity(COUNT); + for table in all_tables() { + v.insert(table, false); + } + + for table in DUPSORT_TABLES { + v.insert(table, true); + } + + v + }); } #[derive(Clone, Copy, Debug)] diff --git a/src/kv.rs b/src/kv.rs index 97b7136..f303576 100644 --- a/src/kv.rs +++ b/src/kv.rs @@ -6,13 +6,13 @@ use ::mdbx::WriteMap; use async_trait::async_trait; pub struct MemoryKv { - inner: ::mdbx::GenericEnvironment, + inner: mdbx::Environment, _tmpdir: tempfile::TempDir, } #[async_trait(?Send)] impl traits::KV for MemoryKv { - type Tx<'tx> = <::mdbx::GenericEnvironment as traits::KV>::Tx<'tx>; + type Tx<'tx> = as traits::KV>::Tx<'tx>; async fn begin(&self, flags: u8) -> anyhow::Result> { self.inner.begin(flags).await @@ -21,8 +21,7 @@ impl traits::KV for MemoryKv { #[async_trait(?Send)] impl traits::MutableKV for MemoryKv { - type MutableTx<'tx> = - <::mdbx::GenericEnvironment as traits::MutableKV>::MutableTx<'tx>; + type MutableTx<'tx> = as traits::MutableKV>::MutableTx<'tx>; async fn begin_mutable(&self) -> anyhow::Result> { self.inner.begin_mutable().await @@ -32,8 +31,8 @@ impl traits::MutableKV for MemoryKv { pub fn new_mem_database() -> anyhow::Result { let tmpdir = tempfile::tempdir()?; let mut builder = ::mdbx::GenericEnvironment::::new(); - builder.set_max_dbs(crate::tables::COUNT); - let inner = builder.open(tmpdir.path())?; + builder.set_max_dbs(crate::tables::TABLE_MAP.len()); + let inner = mdbx::Environment::open(builder, tmpdir.path(), &crate::tables::TABLE_MAP)?; Ok(MemoryKv { inner, diff --git a/src/kv/mdbx.rs b/src/kv/mdbx.rs index 857a6b7..bb2e660 100644 --- a/src/kv/mdbx.rs +++ b/src/kv/mdbx.rs @@ -1,3 +1,5 @@ +use std::{collections::HashMap, path::Path}; + use crate::{ kv::traits, Cursor, CursorDupSort, DupSort, MutableCursor, MutableCursorDupSort, Table, }; @@ -24,21 +26,50 @@ fn get_both_range<'txn, K: TransactionKind>( Ok(MdbxCursor::get_both_range(c, k, v)?) } -#[async_trait(?Send)] -impl traits::KV for GenericEnvironment { - type Tx<'tx> = MdbxTransaction<'tx, RO, E>; +pub struct Environment { + inner: mdbx::GenericEnvironment, +} - async fn begin(&self, _flags: u8) -> anyhow::Result> { - Ok(self.begin_ro_txn()?) +impl Environment { + pub fn open( + b: mdbx::EnvironmentBuilder, + path: &Path, + chart: &HashMap<&'static str, bool>, + ) -> anyhow::Result { + let env = b.open(path)?; + + let tx = env.begin_rw_txn()?; + for (&db, &is_dup_sort) in chart { + tx.create_db( + Some(db), + if is_dup_sort { + DatabaseFlags::DUP_SORT + } else { + DatabaseFlags::default() + }, + )?; + } + tx.commit()?; + + Ok(Self { inner: env }) } } #[async_trait(?Send)] -impl traits::MutableKV for GenericEnvironment { +impl traits::KV for Environment { + type Tx<'tx> = MdbxTransaction<'tx, RO, E>; + + async fn begin(&self, _flags: u8) -> anyhow::Result> { + Ok(self.inner.begin_ro_txn()?) + } +} + +#[async_trait(?Send)] +impl traits::MutableKV for Environment { type MutableTx<'tx> = MdbxTransaction<'tx, RW, E>; async fn begin_mutable(&self) -> anyhow::Result> { - Ok(self.begin_rw_txn()?) + Ok(self.inner.begin_rw_txn()?) } } diff --git a/src/lib.rs b/src/lib.rs index 2c6f88e..a478a7c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,6 +5,7 @@ trait_alias, min_type_alias_impl_trait )] +#![recursion_limit = "256"] #![allow( incomplete_features, clippy::mutable_key_type,