Skip to content

Commit 4cc600c

Browse files
authored
perf(db): do not heap-allocate the stage key per query (paradigmxyz#18284)
1 parent 02ff408 commit 4cc600c

File tree

2 files changed

+34
-1
lines changed

2 files changed

+34
-1
lines changed

‎crates/stages/types/src/id.rs‎

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
use alloc::vec::Vec;
2+
#[cfg(feature = "std")]
3+
use std::{collections::HashMap, sync::OnceLock};
4+
15
/// Stage IDs for all known stages.
26
///
37
/// For custom stages, use [`StageId::Other`]
@@ -27,6 +31,12 @@ pub enum StageId {
2731
Other(&'static str),
2832
}
2933

34+
/// One-time-allocated stage ids encoded as raw Vecs, useful for database
35+
/// clients to reference them for queries instead of encoding anew per query
36+
/// (sad heap allocation required).
37+
#[cfg(feature = "std")]
38+
static ENCODED_STAGE_IDS: OnceLock<HashMap<StageId, Vec<u8>>> = OnceLock::new();
39+
3040
impl StageId {
3141
/// All supported Stages
3242
pub const ALL: [Self; 15] = [
@@ -98,6 +108,25 @@ impl StageId {
98108
pub const fn is_finish(&self) -> bool {
99109
matches!(self, Self::Finish)
100110
}
111+
112+
/// Get a pre-encoded raw Vec, for example, to be used as the DB key for
113+
/// `tables::StageCheckpoints` and `tables::StageCheckpointProgresses`
114+
pub fn get_pre_encoded(&self) -> Option<&Vec<u8>> {
115+
#[cfg(not(feature = "std"))]
116+
{
117+
None
118+
}
119+
#[cfg(feature = "std")]
120+
ENCODED_STAGE_IDS
121+
.get_or_init(|| {
122+
let mut map = HashMap::with_capacity(Self::ALL.len());
123+
for stage_id in Self::ALL {
124+
map.insert(stage_id, stage_id.to_string().into_bytes());
125+
}
126+
map
127+
})
128+
.get(self)
129+
}
101130
}
102131

103132
impl core::fmt::Display for StageId {

‎crates/storage/provider/src/providers/database/provider.rs‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1642,7 +1642,11 @@ impl<TX: DbTx + 'static, N: NodeTypesForProvider> BlockBodyIndicesProvider
16421642

16431643
impl<TX: DbTx, N: NodeTypes> StageCheckpointReader for DatabaseProvider<TX, N> {
16441644
fn get_stage_checkpoint(&self, id: StageId) -> ProviderResult<Option<StageCheckpoint>> {
1645-
Ok(self.tx.get::<tables::StageCheckpoints>(id.to_string())?)
1645+
Ok(if let Some(encoded) = id.get_pre_encoded() {
1646+
self.tx.get_by_encoded_key::<tables::StageCheckpoints>(encoded)?
1647+
} else {
1648+
self.tx.get::<tables::StageCheckpoints>(id.to_string())?
1649+
})
16461650
}
16471651

16481652
/// Get stage checkpoint progress.

0 commit comments

Comments
 (0)