Skip to content

Commit a470731

Browse files
committed
refactor: expand table, contract dualkeyed
1 parent 3e1a423 commit a470731

6 files changed

Lines changed: 118 additions & 90 deletions

File tree

crates/storage/src/hot/mdbx.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::{
22
hot::{HotKv, HotKvError, HotKvRead, HotKvReadError, HotKvWrite},
33
ser::{DeserError, KeySer, MAX_KEY_SIZE, ValSer},
4-
tables::DualKeyed,
4+
tables::{DualKeyed, Table},
55
};
66
use bytes::{BufMut, BytesMut};
77
use reth_db::{
@@ -84,8 +84,8 @@ where
8484

8585
fn get_dual<T: crate::tables::DualKeyed>(
8686
&self,
87-
key1: &T::K1,
88-
key2: &T::K2,
87+
key1: &T::Key,
88+
key2: &T::Key2,
8989
) -> Result<Option<T::Value>, Self::Error> {
9090
let mut key1_buf = [0u8; MAX_KEY_SIZE];
9191
let key1_bytes = key1.encode_key(&mut key1_buf);
@@ -94,7 +94,7 @@ where
9494
// table has one. This is a bit ugly, and results in an extra
9595
// allocation for fixed-size values. This could be avoided using
9696
// max value size.
97-
let value_bytes = if let Some(size) = T::FIXED_VALUE_SIZE {
97+
let value_bytes = if let Some(size) = <T as Table>::FIXED_VAL_SIZE {
9898
let buf = vec![0u8; size];
9999
let _ = key2.encode_key(&mut buf[..MAX_KEY_SIZE].try_into().unwrap());
100100

@@ -114,9 +114,9 @@ where
114114
return Ok(None);
115115
};
116116
// we need to strip the key2 prefix from the value bytes before decoding
117-
let value_bytes = &value_bytes[<<T as DualKeyed>::K2 as KeySer>::SIZE..];
117+
let value_bytes = &value_bytes[<<T as DualKeyed>::Key2 as KeySer>::SIZE..];
118118

119-
T::Value::decode_value(&value_bytes).map(Some).map_err(Into::into)
119+
T::Value::decode_value(value_bytes).map(Some).map_err(Into::into)
120120
}
121121
}
122122

@@ -140,11 +140,11 @@ impl HotKvWrite for Tx<RW> {
140140
// Specialized put for dual-keyed tables.
141141
fn queue_put_dual<T: crate::tables::DualKeyed>(
142142
&mut self,
143-
key1: &T::K1,
144-
key2: &T::K2,
143+
key1: &T::Key,
144+
key2: &T::Key2,
145145
value: &T::Value,
146146
) -> Result<(), Self::Error> {
147-
let k2_size = <T::K2 as KeySer>::SIZE;
147+
let k2_size = <T::Key2 as KeySer>::SIZE;
148148
let mut scratch = [0u8; MAX_KEY_SIZE];
149149

150150
// This will be the total length of key2 + value, reserved in mdbx

crates/storage/src/hot/revm.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,8 @@ impl<U: HotKvRead> HotKvRead for RevmRead<U> {
6363

6464
fn get_dual<T: DualKeyed>(
6565
&self,
66-
key1: &T::K1,
67-
key2: &T::K2,
66+
key1: &T::Key,
67+
key2: &T::Key2,
6868
) -> Result<Option<T::Value>, Self::Error> {
6969
self.reader.get_dual::<T>(key1, key2)
7070
}
@@ -132,8 +132,8 @@ impl<U: HotKvWrite> HotKvRead for RevmWrite<U> {
132132

133133
fn get_dual<T: DualKeyed>(
134134
&self,
135-
key1: &T::K1,
136-
key2: &T::K2,
135+
key1: &T::Key,
136+
key2: &T::Key2,
137137
) -> Result<Option<T::Value>, Self::Error> {
138138
self.writer.get_dual::<T>(key1, key2)
139139
}
@@ -190,8 +190,8 @@ impl<U: HotKvWrite> HotKvWrite for RevmWrite<U> {
190190

191191
fn queue_put_dual<T: DualKeyed>(
192192
&mut self,
193-
key1: &T::K1,
194-
key2: &T::K2,
193+
key1: &T::Key,
194+
key2: &T::Key2,
195195
value: &T::Value,
196196
) -> Result<(), Self::Error> {
197197
self.writer.queue_put_dual::<T>(key1, key2, value)

crates/storage/src/hot/traits.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,8 @@ pub trait HotKvRead {
102102
/// Get a value from a specific dual-keyed table.
103103
fn get_dual<T: DualKeyed>(
104104
&self,
105-
key1: &T::K1,
106-
key2: &T::K2,
105+
key1: &T::Key,
106+
key2: &T::Key2,
107107
) -> Result<Option<T::Value>, Self::Error> {
108108
let mut key1_buf = [0u8; MAX_KEY_SIZE];
109109
let mut key2_buf = [0u8; MAX_KEY_SIZE];
@@ -205,8 +205,8 @@ pub trait HotKvWrite: HotKvRead {
205205
/// Queue a put operation for a specific dual-keyed table.
206206
fn queue_put_dual<T: DualKeyed>(
207207
&mut self,
208-
key1: &T::K1,
209-
key2: &T::K2,
208+
key1: &T::Key,
209+
key2: &T::Key2,
210210
value: &T::Value,
211211
) -> Result<(), Self::Error> {
212212
let mut key1_buf = [0u8; MAX_KEY_SIZE];
@@ -251,7 +251,7 @@ pub trait HotKvWrite: HotKvRead {
251251
where
252252
T: Table,
253253
{
254-
self.queue_raw_create(T::NAME, T::DUAL_KEY, T::DUAL_FIXED_VAL)
254+
self.queue_raw_create(T::NAME, T::DUAL_KEY, T::IS_FIXED_VAL)
255255
}
256256

257257
/// Queue clearing all entries in a specific table.

crates/storage/src/tables/hot.rs

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,37 +6,49 @@ use reth_db_api::{
66
models::{AccountBeforeTx, ShardedKey, storage_sharded_key::StorageShardedKey},
77
};
88

9-
tables! {
9+
table! {
1010
/// Records recent block Headers, by their number.
11-
Headers<BlockNumber => Header>,
11+
Headers<BlockNumber => Header>
12+
}
1213

14+
table! {
1315
/// Records block numbers by hash.
14-
HeaderNumbers<B256 => BlockNumber>,
16+
HeaderNumbers<B256 => BlockNumber>
17+
}
1518

16-
/// Records the canonical chain header hashes, by height.
17-
CanonicalHeaders<BlockNumber => B256>,
19+
table! {
20+
/// Records the canonical chain header hashes, by height.
21+
CanonicalHeaders<BlockNumber => B256>
22+
}
1823

24+
table! {
1925
/// Records contract Bytecode, by its hash.
20-
Bytecodes<B256 => Bytecode>,
21-
22-
/// Records plain account states, keyed by address.
23-
PlainAccountState<Address => Account>,
24-
26+
Bytecodes<B256 => Bytecode>
27+
}
28+
table! {
29+
/// Records plain account states, keyed by address.
30+
PlainAccountState<Address => Account>
31+
}
32+
table! {
2533
/// Records account state change history, keyed by address.
26-
AccountsHistory<ShardedKey<Address> => BlockNumberList>,
27-
34+
AccountsHistory<ShardedKey<Address> => BlockNumberList>
35+
}
36+
table! {
2837
/// Records storage state change history, keyed by address and storage key.
29-
StorageHistory<StorageShardedKey => BlockNumberList>,
30-
38+
StorageHistory<StorageShardedKey => BlockNumberList>
3139
}
3240

33-
tables! {
41+
table! {
3442
/// Records plain storage states, keyed by address and storage key.
35-
PlainStorageState<Address => B256 => U256> size: Some(32 + 32),
43+
PlainStorageState<Address => B256 => U256> is 32 + 32
44+
}
3645

46+
table! {
3747
/// Records account states before transactions, keyed by (address, block number).
38-
StorageChangeSets<BlockNumberAddress => B256 => StorageEntry> size: Some(32 + 32 + 32),
48+
StorageChangeSets<BlockNumberAddress => B256 => StorageEntry> is 32 + 32 + 32
49+
}
3950

51+
table! {
4052
/// Records account states before transactions, keyed by (address, block number).
41-
AccountChangeSets<BlockNumberAddress => Address => AccountBeforeTx> size: None,
53+
AccountChangeSets<BlockNumberAddress => Address => AccountBeforeTx>
4254
}
Lines changed: 44 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
1-
macro_rules! tables {
1+
macro_rules! table {
22
(
3+
@implement
34
#[doc = $doc:expr]
4-
$name:ident<$key:ty => $value:ty>
5+
$name:ident, $key:ty, $value:ty, $dual:expr, $fixed:expr
56
) => {
67
#[doc = $doc]
78
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
89
pub struct $name;
910

1011
impl crate::tables::Table for $name {
1112
const NAME: &'static str = stringify!($name);
13+
const DUAL_KEY: bool = $dual;
14+
const FIXED_VAL_SIZE: Option<usize> = $fixed;
1215

1316
type Key = $key;
1417
type Value = $value;
@@ -17,33 +20,52 @@ macro_rules! tables {
1720

1821
(
1922
#[doc = $doc:expr]
20-
$name:ident<$key:ty => $subkey:ty => $value:ty> size: $fixed:expr
23+
$name:ident<$key:ty => $value:ty>
2124
) => {
22-
#[doc = $doc]
23-
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
24-
pub struct $name;
25-
26-
impl crate::tables::DualKeyed for $name {
27-
const NAME: &'static str = stringify!($name);
25+
table!(@implement
26+
#[doc = $doc]
27+
$name,
28+
$key,
29+
$value,
30+
false,
31+
None
32+
);
33+
};
2834

29-
const FIXED_VALUE_SIZE: Option<usize> = { $fixed };
3035

31-
type K1 = $key;
32-
type K2 = $subkey;
36+
(
37+
#[doc = $doc:expr]
38+
$name:ident<$key:ty => $subkey:ty => $value:ty>
39+
) => {
40+
table!(@implement
41+
#[doc = $doc]
42+
$name,
43+
$key,
44+
$value,
45+
true,
46+
None
47+
);
3348

34-
type Value = $value;
49+
impl crate::tables::DualKeyed for $name {
50+
type Key2 = $subkey;
3551
}
3652
};
3753

38-
($(#[doc = $doc:expr] $name:ident<$key:ty => $value:ty>),* $(,)?) => {
39-
$(
40-
tables!(#[doc = $doc] $name<$key => $value>);
41-
)*
42-
};
54+
(
55+
#[doc = $doc:expr]
56+
$name:ident<$key:ty => $subkey:ty => $value:ty> is $fixed:expr
57+
) => {
58+
table!(@implement
59+
#[doc = $doc]
60+
$name,
61+
$key,
62+
$value,
63+
true,
64+
Some($fixed)
65+
);
4366

44-
($(#[doc = $doc:expr] $name:ident<$key:ty => $subkey:ty => $value:ty> size: $fixed:expr),* $(,)?) => {
45-
$(
46-
tables!(#[doc = $doc] $name<$key => $subkey => $value> size: $fixed);
47-
)*
67+
impl crate::tables::DualKeyed for $name {
68+
type Key2 = $subkey;
69+
}
4870
};
4971
}

crates/storage/src/tables/mod.rs

Lines changed: 24 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ pub mod hot;
99

1010
use crate::ser::{KeySer, ValSer};
1111

12+
/// The maximum size of a dual key (in bytes).
13+
pub const MAX_FIXED_VAL_SIZE: usize = 96;
14+
1215
/// Trait for table definitions.
1316
pub trait Table {
1417
/// A short, human-readable name for the table.
@@ -17,8 +20,21 @@ pub trait Table {
1720
/// Indicates that this table uses dual keys.
1821
const DUAL_KEY: bool = false;
1922

23+
/// True if the table is guaranteed to have fixed-size values, false
24+
/// otherwise.
25+
const FIXED_VAL_SIZE: Option<usize> = None;
26+
2027
/// Indicates that this table has fixed-size values.
21-
const DUAL_FIXED_VAL: bool = false;
28+
const IS_FIXED_VAL: bool = Self::FIXED_VAL_SIZE.is_some();
29+
30+
/// Compile-time assertions for the table.
31+
#[doc(hidden)]
32+
const ASSERT: () = {
33+
// Ensure that fixed-size values do not exceed the maximum allowed size.
34+
if let Some(size) = Self::FIXED_VAL_SIZE {
35+
assert!(size <= MAX_FIXED_VAL_SIZE, "Fixed value size exceeds maximum allowed size");
36+
}
37+
};
2238

2339
/// The key type.
2440
type Key: KeySer;
@@ -31,35 +47,13 @@ pub trait Table {
3147
/// This trait aims to capture tables that use a composite key made up of two
3248
/// distinct parts. This is useful for representing (e.g.) dupsort or other
3349
/// nested map optimizations.
34-
pub trait DualKeyed {
35-
/// A short, human-readable name for the table.
36-
const NAME: &'static str;
37-
38-
/// If the value size is fixed, `Some(size)`. Otherwise, `None`.
39-
const FIXED_VALUE_SIZE: Option<usize> = None;
40-
41-
/// The first key type.
42-
type K1: KeySer;
43-
50+
pub trait DualKeyed: Table {
4451
/// The second key type.
45-
type K2: KeySer;
46-
47-
/// The value type.
48-
type Value: ValSer;
49-
}
50-
51-
impl<T> Table for T
52-
where
53-
T: DualKeyed,
54-
{
55-
const NAME: &'static str = T::NAME;
56-
57-
/// Indicates that this table uses dual keys.
58-
const DUAL_KEY: bool = true;
59-
60-
/// Indicates that this table has fixed-size values.
61-
const DUAL_FIXED_VAL: bool = T::FIXED_VALUE_SIZE.is_some();
52+
type Key2: KeySer;
6253

63-
type Key = T::K1;
64-
type Value = T::Value;
54+
/// Compile-time assertions for the dual-keyed table.
55+
#[doc(hidden)]
56+
const ASSERT: () = {
57+
assert!(Self::DUAL_KEY, "DualKeyed tables must have DUAL_KEY = true");
58+
};
6559
}

0 commit comments

Comments
 (0)