From ec9c7f8d3e12e91ea202b49b3aa03d24925c7115 Mon Sep 17 00:00:00 2001 From: Matthias Seitz Date: Thu, 22 Jan 2026 03:05:50 +0100 Subject: [PATCH] perf(db): use ArrayVec for StoredNibbles key encoding (#21279) --- Cargo.lock | 1 + crates/storage/db-api/Cargo.toml | 1 + crates/storage/db-api/src/models/mod.rs | 7 ++-- crates/storage/db-api/src/table.rs | 32 ++++++++++++++++++- crates/storage/db-api/src/tables/raw.rs | 4 +-- .../db/src/implementation/mdbx/cursor.rs | 10 +++--- .../storage/db/src/implementation/mdbx/tx.rs | 4 +-- 7 files changed, 44 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d3b28b3a92..8e50970e2e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8099,6 +8099,7 @@ dependencies = [ "alloy-genesis", "alloy-primitives", "arbitrary", + "arrayvec", "bytes", "derive_more", "metrics", diff --git a/crates/storage/db-api/Cargo.toml b/crates/storage/db-api/Cargo.toml index 49e4c84f7a..9faf7cb0ab 100644 --- a/crates/storage/db-api/Cargo.toml +++ b/crates/storage/db-api/Cargo.toml @@ -40,6 +40,7 @@ serde = { workspace = true, default-features = false } metrics.workspace = true # misc +arrayvec.workspace = true derive_more.workspace = true bytes.workspace = true diff --git a/crates/storage/db-api/src/models/mod.rs b/crates/storage/db-api/src/models/mod.rs index ebc3625250..8d2e31e875 100644 --- a/crates/storage/db-api/src/models/mod.rs +++ b/crates/storage/db-api/src/models/mod.rs @@ -126,13 +126,10 @@ impl Decode for String { } impl Encode for StoredNibbles { - type Encoded = Vec; + type Encoded = arrayvec::ArrayVec; - // 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>` to reuse the buffer. - self.0.to_vec() + self.0.iter().collect() } } diff --git a/crates/storage/db-api/src/table.rs b/crates/storage/db-api/src/table.rs index 54517908de..d3c43f91be 100644 --- a/crates/storage/db-api/src/table.rs +++ b/crates/storage/db-api/src/table.rs @@ -46,10 +46,40 @@ pub trait Decompress: Send + Sync + Sized + Debug { } } +/// Trait for converting encoded types to `Vec`. +/// +/// This is implemented for all `AsRef<[u8]>` types. For `Vec` 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`. + fn into_vec(self) -> Vec; +} + +impl IntoVec for Vec { + #[inline] + fn into_vec(self) -> Vec { + self + } +} + +impl IntoVec for [u8; N] { + #[inline] + fn into_vec(self) -> Vec { + self.to_vec() + } +} + +impl IntoVec for arrayvec::ArrayVec { + #[inline] + fn into_vec(self) -> Vec { + 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> + Send + Sync + Ord + Debug; + type Encoded: AsRef<[u8]> + IntoVec + Send + Sync + Ord + Debug; /// Encodes data going into the database. fn encode(self) -> Self::Encoded; diff --git a/crates/storage/db-api/src/tables/raw.rs b/crates/storage/db-api/src/tables/raw.rs index 96208a25d5..f183af4fd1 100644 --- a/crates/storage/db-api/src/tables/raw.rs +++ b/crates/storage/db-api/src/tables/raw.rs @@ -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 { impl RawKey { /// 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 diff --git a/crates/storage/db/src/implementation/mdbx/cursor.rs b/crates/storage/db/src/implementation/mdbx/cursor.rs index 61214a857d..90fc5c535c 100644 --- a/crates/storage/db/src/implementation/mdbx/cursor.rs +++ b/crates/storage/db/src/implementation/mdbx/cursor.rs @@ -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 DbCursorRW for Cursor { info: e.into(), operation: DatabaseWriteOperation::CursorUpsert, table_name: T::NAME, - key: key.into(), + key: key.into_vec(), } .into() }) @@ -290,7 +290,7 @@ impl DbCursorRW for Cursor { info: e.into(), operation: DatabaseWriteOperation::CursorInsert, table_name: T::NAME, - key: key.into(), + key: key.into_vec(), } .into() }) @@ -314,7 +314,7 @@ impl DbCursorRW for Cursor { info: e.into(), operation: DatabaseWriteOperation::CursorAppend, table_name: T::NAME, - key: key.into(), + key: key.into_vec(), } .into() }) @@ -350,7 +350,7 @@ impl DbDupCursorRW for Cursor { info: e.into(), operation: DatabaseWriteOperation::CursorAppendDup, table_name: T::NAME, - key: key.into(), + key: key.into_vec(), } .into() }) diff --git a/crates/storage/db/src/implementation/mdbx/tx.rs b/crates/storage/db/src/implementation/mdbx/tx.rs index c0e958ef81..c693c5a80d 100644 --- a/crates/storage/db/src/implementation/mdbx/tx.rs +++ b/crates/storage/db/src/implementation/mdbx/tx.rs @@ -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 { info: e.into(), operation: write_operation, table_name: T::NAME, - key: key.into(), + key: key.into_vec(), } .into() })