Skip to main content

nimiq_database/mdbx/transaction/
mod.rs

1mod proxy;
2mod wrapper;
3
4use std::borrow::Cow;
5
6use libmdbx::{NoWriteMap, WriteFlags};
7pub use libmdbx::{TransactionKind, RO, RW};
8use nimiq_database_value::{AsDatabaseBytes, FromDatabaseBytes, IntoDatabaseValue};
9pub use proxy::*;
10pub use wrapper::*;
11
12use super::{MdbxCursor, MdbxWriteCursor};
13use crate::traits::{DupTable, ReadTransaction, Table, WriteTransaction};
14
15/// Wrapper around mdbx transactions that only exposes our own methods.
16#[derive(Debug)]
17pub struct MdbxTransaction<'db, K: TransactionKind> {
18    txn: libmdbx::Transaction<'db, K, NoWriteMap>,
19}
20
21impl<'db, Kind> MdbxTransaction<'db, Kind>
22where
23    Kind: TransactionKind,
24{
25    pub(crate) fn new(txn: libmdbx::Transaction<'db, Kind, NoWriteMap>) -> Self {
26        MdbxTransaction { txn }
27    }
28
29    pub(super) fn open_table<T: Table>(&self, _table: &T) -> libmdbx::Table<'_> {
30        self.txn.open_table(Some(T::NAME)).unwrap()
31    }
32}
33
34impl<'db, Kind> ReadTransaction<'db> for MdbxTransaction<'db, Kind>
35where
36    Kind: TransactionKind,
37{
38    type Cursor<'txn, T: Table>
39        = MdbxCursor<'txn, Kind, T>
40    where
41        'db: 'txn;
42
43    type DupCursor<'txn, T: DupTable>
44        = MdbxCursor<'txn, Kind, T>
45    where
46        'db: 'txn;
47
48    fn get<T: Table>(&self, table: &T, key: &T::Key) -> Option<T::Value> {
49        let table = self.open_table(table);
50
51        let result: Option<Cow<[u8]>> = self
52            .txn
53            .get(&table, &AsDatabaseBytes::as_key_bytes(key))
54            .unwrap();
55
56        Some(FromDatabaseBytes::from_value_bytes(&result?))
57    }
58
59    fn cursor<'txn, T: Table>(&'txn self, table: &T) -> Self::Cursor<'txn, T> {
60        let table = self.open_table(table);
61
62        MdbxCursor::new(self.txn.cursor(&table).unwrap())
63    }
64
65    fn dup_cursor<'txn, T: DupTable>(&'txn self, table: &T) -> Self::DupCursor<'txn, T> {
66        let table = self.open_table(table);
67
68        MdbxCursor::new(self.txn.cursor(&table).unwrap())
69    }
70}
71
72impl<'db> WriteTransaction<'db> for MdbxTransaction<'db, RW> {
73    type WriteCursor<'txn, T: Table>
74        = MdbxWriteCursor<'txn, T>
75    where
76        'db: 'txn;
77
78    type DupWriteCursor<'txn, T: DupTable>
79        = MdbxWriteCursor<'txn, T>
80    where
81        'db: 'txn;
82
83    fn put_reserve<T: Table>(&mut self, table: &T, key: &T::Key, value: &T::Value)
84    where
85        T::Value: IntoDatabaseValue,
86    {
87        let table = self.open_table(table);
88
89        let key = AsDatabaseBytes::as_key_bytes(key);
90        let value_size = IntoDatabaseValue::database_byte_size(value);
91
92        let bytes: &mut [u8] = self
93            .txn
94            .reserve(&table, key, value_size, WriteFlags::empty())
95            .unwrap();
96
97        IntoDatabaseValue::copy_into_database(value, bytes);
98    }
99
100    fn put<T: Table>(&mut self, table: &T, key: &T::Key, value: &T::Value) {
101        let table = self.open_table(table);
102
103        let key = AsDatabaseBytes::as_key_bytes(key);
104        let value = AsDatabaseBytes::as_value_bytes(value);
105
106        self.txn
107            .put(&table, key, value, WriteFlags::empty())
108            .unwrap();
109    }
110
111    fn append<T: Table>(&mut self, table: &T, key: &T::Key, value: &T::Value) {
112        let table = self.open_table(table);
113
114        let key = AsDatabaseBytes::as_key_bytes(key);
115        let value = AsDatabaseBytes::as_value_bytes(value);
116
117        self.txn
118            .put(&table, key, value, WriteFlags::APPEND)
119            .unwrap();
120    }
121
122    fn remove<T: Table>(&mut self, table: &T, key: &T::Key) {
123        let table = self.open_table(table);
124
125        self.txn
126            .del(&table, AsDatabaseBytes::as_key_bytes(key).as_ref(), None)
127            .unwrap();
128    }
129
130    fn remove_item<T: Table>(&mut self, table: &T, key: &T::Key, value: &T::Value) {
131        let table = self.open_table(table);
132
133        self.txn
134            .del(
135                &table,
136                AsDatabaseBytes::as_key_bytes(key).as_ref(),
137                Some(AsDatabaseBytes::as_value_bytes(value).as_ref()),
138            )
139            .unwrap();
140    }
141
142    fn commit(self) {
143        self.txn.commit().unwrap();
144    }
145
146    fn cursor<'txn, T: Table>(&'txn self, table: &T) -> MdbxWriteCursor<'txn, T> {
147        let table = self.open_table(table);
148
149        MdbxWriteCursor::new(self.txn.cursor(&table).unwrap())
150    }
151
152    fn dup_cursor<'txn, T: DupTable>(&'txn self, table: &T) -> Self::DupWriteCursor<'txn, T> {
153        let table = self.open_table(table);
154
155        MdbxCursor::new(self.txn.cursor(&table).unwrap())
156    }
157
158    fn clear_table<T: Table>(&mut self, table: &T) {
159        let table = self.open_table(table);
160
161        self.txn.clear_table(&table).unwrap();
162    }
163}