Skip to content

Commit c4e3901

Browse files
committed
refactor: Hide Db/Tx lifetimes via Deref/Generics
1 parent e207624 commit c4e3901

File tree

2 files changed

+67
-38
lines changed

2 files changed

+67
-38
lines changed

src/database.rs

Lines changed: 55 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use parking_lot::Mutex;
1111
use std::{
1212
fs::File,
1313
io,
14+
ops::Deref,
1415
path::{Path, PathBuf},
1516
};
1617

@@ -194,21 +195,6 @@ impl Database {
194195
Ok(())
195196
}
196197

197-
pub fn begin_rw(&self) -> Result<Transaction<'_, RW>, TransactionError> {
198-
let context = self.storage_engine.write_context();
199-
let min_snapshot_id = self.transaction_manager.lock().begin_rw(context.snapshot_id)?;
200-
if min_snapshot_id > 0 {
201-
self.storage_engine.unlock(min_snapshot_id - 1);
202-
}
203-
Ok(Transaction::new(context, self))
204-
}
205-
206-
pub fn begin_ro(&self) -> Result<Transaction<'_, RO>, TransactionError> {
207-
let context = self.storage_engine.read_context();
208-
self.transaction_manager.lock().begin_ro(context.snapshot_id);
209-
Ok(Transaction::new(context, self))
210-
}
211-
212198
pub fn state_root(&self) -> B256 {
213199
self.storage_engine.read_context().root_node_hash
214200
}
@@ -244,13 +230,32 @@ impl Database {
244230
}
245231
}
246232

233+
pub fn begin_ro<DB: Deref<Target = Database>>(
234+
db: DB,
235+
) -> Result<Transaction<DB, RO>, TransactionError> {
236+
let context = db.storage_engine.read_context();
237+
db.transaction_manager.lock().begin_ro(context.snapshot_id);
238+
Ok(Transaction::new(context, db))
239+
}
240+
241+
pub fn begin_rw<DB: Deref<Target = Database>>(
242+
db: DB,
243+
) -> Result<Transaction<DB, RW>, TransactionError> {
244+
let context = db.storage_engine.write_context();
245+
let min_snapshot_id = db.transaction_manager.lock().begin_rw(context.snapshot_id)?;
246+
if min_snapshot_id > 0 {
247+
db.storage_engine.unlock(min_snapshot_id - 1);
248+
}
249+
Ok(Transaction::new(context, db))
250+
}
251+
247252
#[cfg(test)]
248253
mod tests {
249254
use super::*;
250255
use crate::{account::Account, path::AddressPath};
251256
use alloy_primitives::{address, Address, U256};
252257
use alloy_trie::{EMPTY_ROOT_HASH, KECCAK_EMPTY};
253-
use std::fs;
258+
use std::{fs, sync::Arc};
254259
use tempdir::TempDir;
255260

256261
#[test]
@@ -315,16 +320,16 @@ mod tests {
315320
let address = address!("0xd8da6bf26964af9d7eed9e03e53415d37aa96045");
316321

317322
let account1 = Account::new(1, U256::from(100), EMPTY_ROOT_HASH, KECCAK_EMPTY);
318-
let mut tx = db.begin_rw().unwrap();
323+
let mut tx = begin_rw(&db).unwrap();
319324
tx.set_account(AddressPath::for_address(address), Some(account1.clone())).unwrap();
320325

321326
tx.commit().unwrap();
322327

323328
let account2 = Account::new(456, U256::from(123), EMPTY_ROOT_HASH, KECCAK_EMPTY);
324-
let mut tx = db.begin_rw().unwrap();
329+
let mut tx = begin_rw(&db).unwrap();
325330
tx.set_account(AddressPath::for_address(address), Some(account2.clone())).unwrap();
326331

327-
let mut ro_tx = db.begin_ro().unwrap();
332+
let mut ro_tx = begin_ro(&db).unwrap();
328333
tx.commit().unwrap();
329334

330335
// The read transaction was created before the write was committed, so it should not see the
@@ -334,7 +339,7 @@ mod tests {
334339
assert_eq!(account1, read_account.unwrap());
335340

336341
// The writer transaction is committed, so the read transaction should see the changes.
337-
let mut ro_tx = db.begin_ro().unwrap();
342+
let mut ro_tx = begin_ro(&db).unwrap();
338343

339344
let read_account = ro_tx.get_account(AddressPath::for_address(address)).unwrap();
340345

@@ -372,29 +377,29 @@ mod tests {
372377
let address1 = address!("0xd8da6bf26964af9d7eed9e03e53415d37aa96045");
373378
let account1 = Account::new(1, U256::from(100), EMPTY_ROOT_HASH, KECCAK_EMPTY);
374379

375-
let mut tx = db.begin_rw().unwrap();
380+
let mut tx = begin_rw(&db).unwrap();
376381
tx.set_account(AddressPath::for_address(address1), Some(account1.clone())).unwrap();
377382

378383
tx.commit().unwrap();
379384
db.close().unwrap();
380385

381386
let db = Database::open(&file_path).unwrap();
382-
let mut tx = db.begin_ro().unwrap();
387+
let mut tx = begin_ro(&db).unwrap();
383388
let account = tx.get_account(AddressPath::for_address(address1)).unwrap().unwrap();
384389
assert_eq!(account, account1);
385390

386391
tx.commit().unwrap();
387392

388393
let address2 = address!("0x1234567890abcdef1234567890abcdef12345678");
389394
let account2 = Account::new(2, U256::from(200), EMPTY_ROOT_HASH, KECCAK_EMPTY);
390-
let mut tx = db.begin_rw().unwrap();
395+
let mut tx = begin_rw(&db).unwrap();
391396
tx.set_account(AddressPath::for_address(address2), Some(account2.clone())).unwrap();
392397

393398
tx.commit().unwrap();
394399
db.close().unwrap();
395400

396401
let db = Database::open(&file_path).unwrap();
397-
let mut tx = db.begin_ro().unwrap();
402+
let mut tx = begin_ro(&db).unwrap();
398403

399404
let account = tx.get_account(AddressPath::for_address(address1)).unwrap().unwrap();
400405
assert_eq!(account, account1);
@@ -434,7 +439,7 @@ mod tests {
434439
assert_eq!(db.storage_engine.page_manager.size(), 0);
435440

436441
// Add 1000 accounts
437-
let mut tx = db.begin_rw().expect("rw transaction creation failed");
442+
let mut tx = begin_rw(&db).expect("rw transaction creation failed");
438443
let initial_accounts = random_accounts(1000).collect::<Vec<_>>();
439444
for (address, account) in &initial_accounts {
440445
tx.set_account(address.clone(), account.clone()).expect("adding account failed");
@@ -456,7 +461,7 @@ mod tests {
456461
}
457462

458463
// Add 1000 more accounts
459-
let mut tx = db.begin_rw().expect("rw transaction creation failed");
464+
let mut tx = begin_rw(&db).expect("rw transaction creation failed");
460465
let more_accounts = random_accounts(1000).collect::<Vec<_>>();
461466
for (address, account) in &more_accounts {
462467
tx.set_account(address.clone(), account.clone()).expect("adding account failed");
@@ -487,7 +492,7 @@ mod tests {
487492
}
488493

489494
// Obtain a read transaction, and verify that it can access all the initial accounts
490-
let mut read_tx = db.begin_ro().expect("ro transaction creation failed");
495+
let mut read_tx = begin_ro(&db).expect("ro transaction creation failed");
491496
for (address, account) in &initial_accounts {
492497
assert_eq!(
493498
read_tx.get_account(address.clone()).expect("error while reading account"),
@@ -496,7 +501,7 @@ mod tests {
496501
}
497502

498503
// Delete the initial accounts
499-
let mut tx = db.begin_rw().expect("rw transaction creation failed");
504+
let mut tx = begin_rw(&db).expect("rw transaction creation failed");
500505
for (address, _) in &initial_accounts {
501506
tx.set_account(address.clone(), None).expect("deleting account failed");
502507
}
@@ -512,4 +517,26 @@ mod tests {
512517
);
513518
}
514519
}
520+
521+
#[test]
522+
fn test_db_arc_tx() {
523+
let tmp_dir = TempDir::new("test_db").unwrap();
524+
let file_path = tmp_dir.path().join("test.db");
525+
let db = Database::create_new(&file_path).unwrap();
526+
527+
let db_arc = Arc::new(db);
528+
529+
let address = address!("0xd8da6bf26964af9d7eed9e03e53415d37aa96045");
530+
let mut tx = begin_rw(db_arc.clone()).unwrap();
531+
tx.set_account(
532+
AddressPath::for_address(address),
533+
Some(Account::new(1, U256::from(100), EMPTY_ROOT_HASH, KECCAK_EMPTY)),
534+
)
535+
.unwrap();
536+
tx.commit().unwrap();
537+
538+
let mut tx = begin_ro(db_arc).unwrap();
539+
let account = tx.get_account(AddressPath::for_address(address)).unwrap().unwrap();
540+
assert_eq!(account, Account::new(1, U256::from(100), EMPTY_ROOT_HASH, KECCAK_EMPTY));
541+
}
515542
}

src/transaction.rs

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use alloy_trie::Nibbles;
1414
pub use error::TransactionError;
1515
pub use manager::TransactionManager;
1616
use sealed::sealed;
17-
use std::{collections::HashMap, fmt::Debug};
17+
use std::{collections::HashMap, fmt::Debug, ops::Deref, sync::Arc};
1818

1919
#[sealed]
2020
pub trait TransactionKind: Debug {}
@@ -34,21 +34,23 @@ impl TransactionKind for RO {}
3434
// Compile-time assertion to ensure that `Transaction` is `Send`
3535
const _: fn() = || {
3636
fn consumer<T: Send>() {}
37-
consumer::<Transaction<'_, RO>>();
38-
consumer::<Transaction<'_, RW>>();
37+
consumer::<Transaction<&Database, RO>>();
38+
consumer::<Transaction<&Database, RW>>();
39+
consumer::<Transaction<Arc<Database>, RO>>();
40+
consumer::<Transaction<Arc<Database>, RW>>();
3941
};
4042

4143
#[derive(Debug)]
42-
pub struct Transaction<'tx, K: TransactionKind> {
44+
pub struct Transaction<DB, K: TransactionKind> {
4345
committed: bool,
4446
context: TransactionContext,
45-
database: &'tx Database,
47+
database: DB,
4648
pending_changes: HashMap<Nibbles, Option<TrieValue>>,
4749
_marker: std::marker::PhantomData<K>,
4850
}
4951

50-
impl<'tx, K: TransactionKind> Transaction<'tx, K> {
51-
pub(crate) fn new(context: TransactionContext, database: &'tx Database) -> Self {
52+
impl<DB: Deref<Target = Database>, K: TransactionKind> Transaction<DB, K> {
53+
pub(crate) fn new(context: TransactionContext, database: DB) -> Self {
5254
Self {
5355
committed: false,
5456
context,
@@ -137,7 +139,7 @@ impl<'tx, K: TransactionKind> Transaction<'tx, K> {
137139
}
138140
}
139141

140-
impl Transaction<'_, RW> {
142+
impl<DB: Deref<Target = Database>> Transaction<DB, RW> {
141143
pub fn set_account(
142144
&mut self,
143145
address_path: AddressPath,
@@ -186,7 +188,7 @@ impl Transaction<'_, RW> {
186188
}
187189
}
188190

189-
impl Transaction<'_, RO> {
191+
impl<DB: Deref<Target = Database>> Transaction<DB, RO> {
190192
pub fn commit(mut self) -> Result<(), TransactionError> {
191193
let mut transaction_manager = self.database.transaction_manager.lock();
192194
transaction_manager.remove_tx(self.context.snapshot_id, false);
@@ -196,7 +198,7 @@ impl Transaction<'_, RO> {
196198
}
197199
}
198200

199-
impl<K: TransactionKind> Drop for Transaction<'_, K> {
201+
impl<DB, K: TransactionKind> Drop for Transaction<DB, K> {
200202
fn drop(&mut self) {
201203
// TODO: panic if the transaction is not committed
202204
}

0 commit comments

Comments
 (0)