Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: get rid of lifetime GATs #5478

Merged
merged 7 commits into from
Nov 19, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 19 additions & 7 deletions crates/storage/db/src/abstraction/common.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
pub(crate) use sealed::Sealed;

use crate::{abstraction::table::*, DatabaseError};

/// A key-value pair for table `T`.
pub type KeyValue<T> = (<T as Table>::Key, <T as Table>::Value);

Expand All @@ -16,13 +20,21 @@ pub type IterPairResult<T> = Option<Result<KeyValue<T>, DatabaseError>>;
/// A value only result for table `T`.
pub type ValueOnlyResult<T> = Result<Option<<T as Table>::Value>, DatabaseError>;

use crate::{abstraction::table::*, DatabaseError};

// Sealed trait helper to prevent misuse of the API.
// Sealed trait helper to prevent misuse of the Database API.
mod sealed {
use std::sync::Arc;
use crate::database::Database;
use crate::DatabaseEnv;
use crate::mock::DatabaseMock;

/// Sealed trait to limit the implementors of the Database trait.
pub trait Sealed: Sized {}
#[allow(missing_debug_implementations)]
pub struct Bounds<T>(T);
impl<T> Sealed for Bounds<T> {}

impl<DB: Database> Sealed for &DB { }
impl<DB: Database> Sealed for Arc<DB> { }
impl Sealed for DatabaseEnv{ }
impl Sealed for DatabaseMock{ }

#[cfg(any(test, feature = "test-utils"))]
impl<DB: Database> Sealed for crate::test_utils::TempDatabase<DB>{ }
}
pub(crate) use sealed::{Bounds, Sealed};
37 changes: 18 additions & 19 deletions crates/storage/db/src/abstraction/database.rs
Original file line number Diff line number Diff line change
@@ -1,35 +1,34 @@
use crate::{
common::{Bounds, Sealed},
common::{Sealed},
table::TableImporter,
transaction::{DbTx, DbTxMut},
DatabaseError,
};
use std::{fmt::Debug, sync::Arc};

/// Implements the GAT method from:
/// <https://sabrinajewson.org/blog/the-better-alternative-to-lifetime-gats#the-better-gats>.
/// Trait that provides the different transaction types.
///
/// Sealed trait which cannot be implemented by 3rd parties, exposed only for implementers
pub trait DatabaseGAT<'a, __ImplicitBounds: Sealed = Bounds<&'a Self>>: Send + Sync {
pub trait DatabaseGAT: Sealed + Send + Sync {
mattsse marked this conversation as resolved.
Show resolved Hide resolved
/// RO database transaction
type TX: DbTx + Send + Sync + Debug;
/// RW database transaction
type TXMut: DbTxMut + DbTx + TableImporter + Send + Sync + Debug;
}

/// Main Database trait that spawns transactions to be executed.
pub trait Database: for<'a> DatabaseGAT<'a> {
pub trait Database: DatabaseGAT {
/// Create read only transaction.
fn tx(&self) -> Result<<Self as DatabaseGAT<'_>>::TX, DatabaseError>;
fn tx(&self) -> Result<<Self as DatabaseGAT>::TX, DatabaseError>;

/// Create read write transaction only possible if database is open with write access.
fn tx_mut(&self) -> Result<<Self as DatabaseGAT<'_>>::TXMut, DatabaseError>;
fn tx_mut(&self) -> Result<<Self as DatabaseGAT>::TXMut, DatabaseError>;

/// Takes a function and passes a read-only transaction into it, making sure it's closed in the
/// end of the execution.
fn view<T, F>(&self, f: F) -> Result<T, DatabaseError>
where
F: FnOnce(&<Self as DatabaseGAT<'_>>::TX) -> T,
F: FnOnce(&<Self as DatabaseGAT>::TX) -> T,
{
let tx = self.tx()?;

Expand All @@ -43,7 +42,7 @@ pub trait Database: for<'a> DatabaseGAT<'a> {
/// the end of the execution.
fn update<T, F>(&self, f: F) -> Result<T, DatabaseError>
where
F: FnOnce(&<Self as DatabaseGAT<'_>>::TXMut) -> T,
F: FnOnce(&<Self as DatabaseGAT>::TXMut) -> T,
{
let tx = self.tx_mut()?;

Expand All @@ -55,33 +54,33 @@ pub trait Database: for<'a> DatabaseGAT<'a> {
}

// Generic over Arc
impl<'a, DB: Database> DatabaseGAT<'a> for Arc<DB> {
type TX = <DB as DatabaseGAT<'a>>::TX;
type TXMut = <DB as DatabaseGAT<'a>>::TXMut;
impl<DB: Database> DatabaseGAT for Arc<DB> {
type TX = <DB as DatabaseGAT>::TX;
type TXMut = <DB as DatabaseGAT>::TXMut;
}

impl<DB: Database> Database for Arc<DB> {
fn tx(&self) -> Result<<Self as DatabaseGAT<'_>>::TX, DatabaseError> {
fn tx(&self) -> Result<<Self as DatabaseGAT>::TX, DatabaseError> {
<DB as Database>::tx(self)
}

fn tx_mut(&self) -> Result<<Self as DatabaseGAT<'_>>::TXMut, DatabaseError> {
fn tx_mut(&self) -> Result<<Self as DatabaseGAT>::TXMut, DatabaseError> {
<DB as Database>::tx_mut(self)
}
}

// Generic over reference
impl<'a, DB: Database> DatabaseGAT<'a> for &DB {
type TX = <DB as DatabaseGAT<'a>>::TX;
type TXMut = <DB as DatabaseGAT<'a>>::TXMut;
impl<DB: Database> DatabaseGAT for &DB {
type TX = <DB as DatabaseGAT>::TX;
type TXMut = <DB as DatabaseGAT>::TXMut;
}

impl<DB: Database> Database for &DB {
fn tx(&self) -> Result<<Self as DatabaseGAT<'_>>::TX, DatabaseError> {
fn tx(&self) -> Result<<Self as DatabaseGAT>::TX, DatabaseError> {
<DB as Database>::tx(self)
}

fn tx_mut(&self) -> Result<<Self as DatabaseGAT<'_>>::TXMut, DatabaseError> {
fn tx_mut(&self) -> Result<<Self as DatabaseGAT>::TXMut, DatabaseError> {
<DB as Database>::tx_mut(self)
}
}
19 changes: 9 additions & 10 deletions crates/storage/db/src/abstraction/mock.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
//! Mock database
use std::{collections::BTreeMap, ops::RangeBounds};

use crate::{
common::{PairResult, ValueOnlyResult},
cursor::{
Expand All @@ -22,16 +21,16 @@ pub struct DatabaseMock {
}

impl Database for DatabaseMock {
fn tx(&self) -> Result<<Self as DatabaseGAT<'_>>::TX, DatabaseError> {
fn tx(&self) -> Result<<Self as DatabaseGAT>::TX, DatabaseError> {
Ok(TxMock::default())
}

fn tx_mut(&self) -> Result<<Self as DatabaseGAT<'_>>::TXMut, DatabaseError> {
fn tx_mut(&self) -> Result<<Self as DatabaseGAT>::TXMut, DatabaseError> {
Ok(TxMock::default())
}
}

impl<'a> DatabaseGAT<'a> for DatabaseMock {
impl DatabaseGAT for DatabaseMock {
type TX = TxMock;

type TXMut = TxMock;
Expand All @@ -44,12 +43,12 @@ pub struct TxMock {
_table: BTreeMap<Vec<u8>, Vec<u8>>,
}

impl<'a> DbTxGAT<'a> for TxMock {
impl DbTxGAT for TxMock {
type Cursor<T: Table> = CursorMock;
type DupCursor<T: DupSort> = CursorMock;
}

impl<'a> DbTxMutGAT<'a> for TxMock {
impl DbTxMutGAT for TxMock {
type CursorMut<T: Table> = CursorMock;
type DupCursorMut<T: DupSort> = CursorMock;
}
Expand All @@ -65,13 +64,13 @@ impl DbTx for TxMock {

fn abort(self) {}

fn cursor_read<T: Table>(&self) -> Result<<Self as DbTxGAT<'_>>::Cursor<T>, DatabaseError> {
fn cursor_read<T: Table>(&self) -> Result<<Self as DbTxGAT>::Cursor<T>, DatabaseError> {
Ok(CursorMock { _cursor: 0 })
}

fn cursor_dup_read<T: DupSort>(
&self,
) -> Result<<Self as DbTxGAT<'_>>::DupCursor<T>, DatabaseError> {
) -> Result<<Self as DbTxGAT>::DupCursor<T>, DatabaseError> {
Ok(CursorMock { _cursor: 0 })
}

Expand Down Expand Up @@ -99,13 +98,13 @@ impl DbTxMut for TxMock {

fn cursor_write<T: Table>(
&self,
) -> Result<<Self as DbTxMutGAT<'_>>::CursorMut<T>, DatabaseError> {
) -> Result<<Self as DbTxMutGAT>::CursorMut<T>, DatabaseError> {
todo!()
}

fn cursor_dup_write<T: DupSort>(
&self,
) -> Result<<Self as DbTxMutGAT<'_>>::DupCursorMut<T>, DatabaseError> {
) -> Result<<Self as DbTxMutGAT>::DupCursorMut<T>, DatabaseError> {
todo!()
}
}
Expand Down
21 changes: 10 additions & 11 deletions crates/storage/db/src/abstraction/transaction.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
use crate::{
common::{Bounds, Sealed},
common::{Sealed},
cursor::{DbCursorRO, DbCursorRW, DbDupCursorRO, DbDupCursorRW},
table::{DupSort, Table},
DatabaseError,
};

/// Implements the GAT method from:
/// <https://sabrinajewson.org/blog/the-better-alternative-to-lifetime-gats#the-better-gats>.
/// Trait that provides the different cursor types.
///
/// Sealed trait which cannot be implemented by 3rd parties, exposed only for implementers
pub trait DbTxGAT<'a, __ImplicitBounds: Sealed = Bounds<&'a Self>>: Send + Sync {
pub trait DbTxGAT : Send + Sync {
/// Cursor GAT
type Cursor<T: Table>: DbCursorRO<T> + Send + Sync;
/// DupCursor GAT
Expand All @@ -20,7 +19,7 @@ pub trait DbTxGAT<'a, __ImplicitBounds: Sealed = Bounds<&'a Self>>: Send + Sync
/// <https://sabrinajewson.org/blog/the-better-alternative-to-lifetime-gats#the-better-gats>.
///
/// Sealed trait which cannot be implemented by 3rd parties, exposed only for implementers
pub trait DbTxMutGAT<'a, __ImplicitBounds: Sealed = Bounds<&'a Self>>: Send + Sync {
pub trait DbTxMutGAT: Send + Sync {
/// Cursor GAT
type CursorMut<T: Table>: DbCursorRW<T> + DbCursorRO<T> + Send + Sync;
/// DupCursor GAT
Expand All @@ -33,7 +32,7 @@ pub trait DbTxMutGAT<'a, __ImplicitBounds: Sealed = Bounds<&'a Self>>: Send + Sy
}

/// Read only transaction
pub trait DbTx: for<'a> DbTxGAT<'a> {
pub trait DbTx: DbTxGAT {
/// Get value
fn get<T: Table>(&self, key: T::Key) -> Result<Option<T::Value>, DatabaseError>;
/// Commit for read only transaction will consume and free transaction and allows
Expand All @@ -42,17 +41,17 @@ pub trait DbTx: for<'a> DbTxGAT<'a> {
/// Aborts transaction
fn abort(self);
/// Iterate over read only values in table.
fn cursor_read<T: Table>(&self) -> Result<<Self as DbTxGAT<'_>>::Cursor<T>, DatabaseError>;
fn cursor_read<T: Table>(&self) -> Result<<Self as DbTxGAT>::Cursor<T>, DatabaseError>;
/// Iterate over read only values in dup sorted table.
fn cursor_dup_read<T: DupSort>(
&self,
) -> Result<<Self as DbTxGAT<'_>>::DupCursor<T>, DatabaseError>;
) -> Result<<Self as DbTxGAT>::DupCursor<T>, DatabaseError>;
/// Returns number of entries in the table.
fn entries<T: Table>(&self) -> Result<usize, DatabaseError>;
}

/// Read write transaction that allows writing to database
pub trait DbTxMut: for<'a> DbTxMutGAT<'a> {
pub trait DbTxMut: DbTxMutGAT {
/// Put value to database
fn put<T: Table>(&self, key: T::Key, value: T::Value) -> Result<(), DatabaseError>;
/// Delete value from database
Expand All @@ -63,9 +62,9 @@ pub trait DbTxMut: for<'a> DbTxMutGAT<'a> {
/// Cursor mut
fn cursor_write<T: Table>(
&self,
) -> Result<<Self as DbTxMutGAT<'_>>::CursorMut<T>, DatabaseError>;
) -> Result<<Self as DbTxMutGAT>::CursorMut<T>, DatabaseError>;
/// DupCursor mut.
fn cursor_dup_write<T: DupSort>(
&self,
) -> Result<<Self as DbTxMutGAT<'_>>::DupCursorMut<T>, DatabaseError>;
) -> Result<<Self as DbTxMutGAT>::DupCursorMut<T>, DatabaseError>;
}
6 changes: 3 additions & 3 deletions crates/storage/db/src/implementation/mdbx/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,20 +40,20 @@ pub struct DatabaseEnv {
with_metrics: bool,
}

impl<'a> DatabaseGAT<'a> for DatabaseEnv {
impl DatabaseGAT for DatabaseEnv {
type TX = tx::Tx<RO>;
type TXMut = tx::Tx<RW>;
}

impl Database for DatabaseEnv {
fn tx(&self) -> Result<<Self as DatabaseGAT<'_>>::TX, DatabaseError> {
fn tx(&self) -> Result<<Self as DatabaseGAT>::TX, DatabaseError> {
Ok(Tx::new_with_metrics(
self.inner.begin_ro_txn().map_err(|e| DatabaseError::InitTx(e.into()))?,
self.with_metrics,
))
}

fn tx_mut(&self) -> Result<<Self as DatabaseGAT<'_>>::TXMut, DatabaseError> {
fn tx_mut(&self) -> Result<<Self as DatabaseGAT>::TXMut, DatabaseError> {
Ok(Tx::new_with_metrics(
self.inner.begin_rw_txn().map_err(|e| DatabaseError::InitTx(e.into()))?,
self.with_metrics,
Expand Down
16 changes: 8 additions & 8 deletions crates/storage/db/src/implementation/mdbx/tx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,12 +167,12 @@ impl<K: TransactionKind> Drop for MetricsHandler<K> {
}
}

impl<'a, K: TransactionKind> DbTxGAT<'a> for Tx<K> {
type Cursor<T: Table> = Cursor<'a, K, T>;
type DupCursor<T: DupSort> = Cursor<'a, K, T>;
impl<K: TransactionKind> DbTxGAT for Tx<K> {
type Cursor<T: Table> = Cursor<'_, K, T>;
type DupCursor<T: DupSort> = Cursor<'_, K, T>;
}

impl<'a, K: TransactionKind> DbTxMutGAT<'a> for Tx<K> {
impl<'a, K: TransactionKind> DbTxMutGAT for Tx<K> {
type CursorMut<T: Table> = Cursor<'a, RW, T>;
type DupCursorMut<T: DupSort> = Cursor<'a, RW, T>;
}
Expand Down Expand Up @@ -202,14 +202,14 @@ impl<K: TransactionKind> DbTx for Tx<K> {
}

// Iterate over read only values in database.
fn cursor_read<T: Table>(&self) -> Result<<Self as DbTxGAT<'_>>::Cursor<T>, DatabaseError> {
fn cursor_read<T: Table>(&self) -> Result<<Self as DbTxGAT>::Cursor<T>, DatabaseError> {
self.new_cursor()
}

/// Iterate over read only values in database.
fn cursor_dup_read<T: DupSort>(
&self,
) -> Result<<Self as DbTxGAT<'_>>::DupCursor<T>, DatabaseError> {
) -> Result<<Self as DbTxGAT>::DupCursor<T>, DatabaseError> {
self.new_cursor()
}

Expand Down Expand Up @@ -270,13 +270,13 @@ impl DbTxMut for Tx<RW> {

fn cursor_write<T: Table>(
&self,
) -> Result<<Self as DbTxMutGAT<'_>>::CursorMut<T>, DatabaseError> {
) -> Result<<Self as DbTxMutGAT>::CursorMut<T>, DatabaseError> {
self.new_cursor()
}

fn cursor_dup_write<T: DupSort>(
&self,
) -> Result<<Self as DbTxMutGAT<'_>>::DupCursorMut<T>, DatabaseError> {
) -> Result<<Self as DbTxMutGAT>::DupCursorMut<T>, DatabaseError> {
self.new_cursor()
}
}
10 changes: 5 additions & 5 deletions crates/storage/db/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,17 +193,17 @@ pub mod test_utils {
}
}

impl<'a, DB: Database> DatabaseGAT<'a> for TempDatabase<DB> {
type TX = <DB as DatabaseGAT<'a>>::TX;
type TXMut = <DB as DatabaseGAT<'a>>::TXMut;
impl<DB: Database> DatabaseGAT for TempDatabase<DB> {
type TX = <DB as DatabaseGAT>::TX;
type TXMut = <DB as DatabaseGAT>::TXMut;
}

impl<DB: Database> Database for TempDatabase<DB> {
fn tx(&self) -> Result<<Self as DatabaseGAT<'_>>::TX, DatabaseError> {
fn tx(&self) -> Result<<Self as DatabaseGAT>::TX, DatabaseError> {
self.db().tx()
}

fn tx_mut(&self) -> Result<<Self as DatabaseGAT<'_>>::TXMut, DatabaseError> {
fn tx_mut(&self) -> Result<<Self as DatabaseGAT>::TXMut, DatabaseError> {
self.db().tx_mut()
}
}
Expand Down
Loading