Skip to content

Commit fec4894

Browse files
authored
starknet_committer: add mdbx storage (#8917)
1 parent 386ce2a commit fec4894

File tree

5 files changed

+121
-1
lines changed

5 files changed

+121
-1
lines changed

Cargo.lock

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/starknet_patricia_storage/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ workspace = true
1414

1515
[dependencies]
1616
hex.workspace = true
17+
libmdbx.workspace = true
1718
lru.workspace = true
19+
page_size.workspace = true
1820
serde = { workspace = true, features = ["derive"] }
1921
serde_json.workspace = true
2022
starknet-types-core.workspace = true

crates/starknet_patricia_storage/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,5 @@ pub mod errors;
33
pub mod map_storage;
44
#[cfg(test)]
55
pub mod map_storage_test;
6+
pub mod mdbx_storage;
67
pub mod storage_trait;
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
use std::path::Path;
2+
3+
use libmdbx::{
4+
Database as MdbxDb,
5+
DatabaseFlags,
6+
Geometry,
7+
PageSize,
8+
TableFlags,
9+
WriteFlags,
10+
WriteMap,
11+
};
12+
use page_size;
13+
14+
use crate::storage_trait::{DbHashMap, DbKey, DbValue, PatriciaStorageResult, Storage};
15+
16+
pub struct MdbxStorage {
17+
db: MdbxDb<WriteMap>,
18+
}
19+
20+
// Size in bytes.
21+
const MDBX_MIN_PAGESIZE: usize = 1 << 8; // 256 bytes
22+
const MDBX_MAX_PAGESIZE: usize = 1 << 16; // 64KB
23+
24+
fn get_page_size(os_page_size: usize) -> PageSize {
25+
let mut page_size = os_page_size.clamp(MDBX_MIN_PAGESIZE, MDBX_MAX_PAGESIZE);
26+
27+
// Page size must be power of two.
28+
if !page_size.is_power_of_two() {
29+
page_size = page_size.next_power_of_two() / 2;
30+
}
31+
32+
PageSize::Set(page_size)
33+
}
34+
35+
impl MdbxStorage {
36+
pub fn open(path: &Path) -> PatriciaStorageResult<Self> {
37+
// TODO(tzahi): geometry and related definitions are taken from apollo_storage. Check if
38+
// there are better configurations for the committer and consider moving boh crates mdbx
39+
// code to a common location.
40+
let db = MdbxDb::<WriteMap>::new()
41+
.set_geometry(Geometry {
42+
size: Some(1 << 20..1 << 40),
43+
growth_step: Some(1 << 32),
44+
page_size: Some(get_page_size(page_size::get())),
45+
..Default::default()
46+
})
47+
.set_flags(DatabaseFlags {
48+
// As DbKeys are hashed, there is no locality of pages in the database almost at
49+
// all, so readahead will fill the RAM with garbage.
50+
// See https://libmdbx.dqdkfa.ru/group__c__opening.html#gga9138119a904355d245777c4119534061a16a07f878f8053cc79990063ca9510e7
51+
no_rdahead: true,
52+
// LIFO policy for recycling a Garbage Collection items should be faster when using
53+
// disks with write-back cache.
54+
liforeclaim: true,
55+
..Default::default()
56+
})
57+
.open(path)?;
58+
let txn = db.begin_rw_txn()?;
59+
txn.create_table(None, TableFlags::empty())?;
60+
txn.commit()?;
61+
Ok(Self { db })
62+
}
63+
}
64+
65+
impl Storage for MdbxStorage {
66+
fn get(&mut self, key: &DbKey) -> PatriciaStorageResult<Option<DbValue>> {
67+
let txn = self.db.begin_ro_txn()?;
68+
let table = txn.open_table(None)?;
69+
Ok(txn.get(&table, &key.0)?.map(DbValue))
70+
}
71+
72+
fn set(&mut self, key: DbKey, value: DbValue) -> PatriciaStorageResult<Option<DbValue>> {
73+
let txn = self.db.begin_rw_txn()?;
74+
let table = txn.open_table(None)?;
75+
let prev_val = txn.get(&table, &key.0)?.map(DbValue);
76+
txn.put(&table, key.0, value.0, WriteFlags::UPSERT)?;
77+
txn.commit()?;
78+
Ok(prev_val)
79+
}
80+
81+
fn mget(&mut self, keys: &[&DbKey]) -> PatriciaStorageResult<Vec<Option<DbValue>>> {
82+
let txn = self.db.begin_ro_txn()?;
83+
let table = txn.open_table(None)?;
84+
let mut res = Vec::with_capacity(keys.len());
85+
for key in keys {
86+
res.push(txn.get(&table, &key.0)?.map(DbValue));
87+
}
88+
Ok(res)
89+
}
90+
91+
fn mset(&mut self, key_to_value: DbHashMap) -> PatriciaStorageResult<()> {
92+
let txn = self.db.begin_rw_txn()?;
93+
let table = txn.open_table(None)?;
94+
for (key, value) in key_to_value {
95+
txn.put(&table, key.0, value.0, WriteFlags::UPSERT)?;
96+
}
97+
txn.commit()?;
98+
Ok(())
99+
}
100+
101+
fn delete(&mut self, key: &DbKey) -> PatriciaStorageResult<Option<DbValue>> {
102+
let txn = self.db.begin_rw_txn()?;
103+
let table = txn.open_table(None)?;
104+
let prev_val = txn.get(&table, &key.0)?.map(DbValue);
105+
if prev_val.is_some() {
106+
txn.del(&table, &key.0, None)?;
107+
txn.commit()?;
108+
}
109+
Ok(prev_val)
110+
}
111+
}

crates/starknet_patricia_storage/src/storage_trait.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@ pub type DbHashMap = HashMap<DbKey, DbValue>;
1313

1414
/// An error that can occur when interacting with the database.
1515
#[derive(thiserror::Error, Debug)]
16-
pub enum PatriciaStorageError {}
16+
pub enum PatriciaStorageError {
17+
/// An error that occurred in the database library.
18+
#[error(transparent)]
19+
Mdbx(#[from] libmdbx::Error),
20+
}
1721

1822
pub type PatriciaStorageResult<T> = Result<T, PatriciaStorageError>;
1923

0 commit comments

Comments
 (0)