perf(db): use ArrayVec for StoredNibbles key encoding (#21279)

This commit is contained in:
Matthias Seitz
2026-01-22 03:05:50 +01:00
committed by GitHub
parent dbdaf068f0
commit ec9c7f8d3e
7 changed files with 44 additions and 15 deletions

1
Cargo.lock generated
View File

@@ -8099,6 +8099,7 @@ dependencies = [
"alloy-genesis",
"alloy-primitives",
"arbitrary",
"arrayvec",
"bytes",
"derive_more",
"metrics",

View File

@@ -40,6 +40,7 @@ serde = { workspace = true, default-features = false }
metrics.workspace = true
# misc
arrayvec.workspace = true
derive_more.workspace = true
bytes.workspace = true

View File

@@ -126,13 +126,10 @@ impl Decode for String {
}
impl Encode for StoredNibbles {
type Encoded = Vec<u8>;
type Encoded = arrayvec::ArrayVec<u8, 64>;
// Delegate to the Compact implementation
fn encode(self) -> Self::Encoded {
// NOTE: This used to be `to_compact`, but all it does is append the bytes to the buffer,
// so we can just use the implementation of `Into<Vec<u8>>` to reuse the buffer.
self.0.to_vec()
self.0.iter().collect()
}
}

View File

@@ -46,10 +46,40 @@ pub trait Decompress: Send + Sync + Sized + Debug {
}
}
/// Trait for converting encoded types to `Vec<u8>`.
///
/// This is implemented for all `AsRef<[u8]>` types. For `Vec<u8>` this is a no-op,
/// for other types like `ArrayVec` or fixed arrays it performs a copy.
pub trait IntoVec: AsRef<[u8]> {
/// Convert to a `Vec<u8>`.
fn into_vec(self) -> Vec<u8>;
}
impl IntoVec for Vec<u8> {
#[inline]
fn into_vec(self) -> Vec<u8> {
self
}
}
impl<const N: usize> IntoVec for [u8; N] {
#[inline]
fn into_vec(self) -> Vec<u8> {
self.to_vec()
}
}
impl<const N: usize> IntoVec for arrayvec::ArrayVec<u8, N> {
#[inline]
fn into_vec(self) -> Vec<u8> {
self.to_vec()
}
}
/// Trait that will transform the data to be saved in the DB.
pub trait Encode: Send + Sync + Sized + Debug {
/// Encoded type.
type Encoded: AsRef<[u8]> + Into<Vec<u8>> + Send + Sync + Ord + Debug;
type Encoded: AsRef<[u8]> + IntoVec + Send + Sync + Ord + Debug;
/// Encodes data going into the database.
fn encode(self) -> Self::Encoded;

View File

@@ -1,5 +1,5 @@
use crate::{
table::{Compress, Decode, Decompress, DupSort, Encode, Key, Table, Value},
table::{Compress, Decode, Decompress, DupSort, Encode, IntoVec, Key, Table, Value},
DatabaseError,
};
use serde::{Deserialize, Serialize};
@@ -52,7 +52,7 @@ pub struct RawKey<K: Key> {
impl<K: Key> RawKey<K> {
/// Create new raw key.
pub fn new(key: K) -> Self {
Self { key: K::encode(key).into(), _phantom: std::marker::PhantomData }
Self { key: K::encode(key).into_vec(), _phantom: std::marker::PhantomData }
}
/// Creates a raw key from an existing `Vec`. Useful when we already have the encoded

View File

@@ -11,7 +11,7 @@ use reth_db_api::{
DbCursorRO, DbCursorRW, DbDupCursorRO, DbDupCursorRW, DupWalker, RangeWalker,
ReverseWalker, Walker,
},
table::{Compress, Decode, Decompress, DupSort, Encode, Table},
table::{Compress, Decode, Decompress, DupSort, Encode, IntoVec, Table},
};
use reth_libmdbx::{Error as MDBXError, TransactionKind, WriteFlags, RO, RW};
use reth_storage_errors::db::{DatabaseErrorInfo, DatabaseWriteError, DatabaseWriteOperation};
@@ -268,7 +268,7 @@ impl<T: Table> DbCursorRW<T> for Cursor<RW, T> {
info: e.into(),
operation: DatabaseWriteOperation::CursorUpsert,
table_name: T::NAME,
key: key.into(),
key: key.into_vec(),
}
.into()
})
@@ -290,7 +290,7 @@ impl<T: Table> DbCursorRW<T> for Cursor<RW, T> {
info: e.into(),
operation: DatabaseWriteOperation::CursorInsert,
table_name: T::NAME,
key: key.into(),
key: key.into_vec(),
}
.into()
})
@@ -314,7 +314,7 @@ impl<T: Table> DbCursorRW<T> for Cursor<RW, T> {
info: e.into(),
operation: DatabaseWriteOperation::CursorAppend,
table_name: T::NAME,
key: key.into(),
key: key.into_vec(),
}
.into()
})
@@ -350,7 +350,7 @@ impl<T: DupSort> DbDupCursorRW<T> for Cursor<RW, T> {
info: e.into(),
operation: DatabaseWriteOperation::CursorAppendDup,
table_name: T::NAME,
key: key.into(),
key: key.into_vec(),
}
.into()
})

View File

@@ -6,7 +6,7 @@ use crate::{
DatabaseError,
};
use reth_db_api::{
table::{Compress, DupSort, Encode, Table, TableImporter},
table::{Compress, DupSort, Encode, IntoVec, Table, TableImporter},
transaction::{DbTx, DbTxMut},
};
use reth_libmdbx::{ffi::MDBX_dbi, CommitLatency, Transaction, TransactionKind, WriteFlags, RW};
@@ -387,7 +387,7 @@ impl Tx<RW> {
info: e.into(),
operation: write_operation,
table_name: T::NAME,
key: key.into(),
key: key.into_vec(),
}
.into()
})