Skip to content

Commit 795c122

Browse files
yoavGrsTzahiTaub
authored andcommitted
starknet_committer: add mdbx storage
1 parent 386ce2a commit 795c122

File tree

5 files changed

+124
-1
lines changed

5 files changed

+124
-1
lines changed

Cargo.lock

Lines changed: 3 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: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,11 @@ testing = []
1313
workspace = true
1414

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

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)