Skip to main content

reth_db_api/
table.rs

1use crate::{
2    cursor::{DbCursorRO, DbCursorRW, DbDupCursorRO, DbDupCursorRW},
3    transaction::{DbTx, DbTxMut},
4    DatabaseError,
5};
6use serde::{Deserialize, Serialize};
7use std::fmt::Debug;
8
9pub use reth_codecs::{Compress, Decompress};
10
11/// Trait for converting encoded types to `Vec<u8>`.
12///
13/// This is implemented for all `AsRef<[u8]>` types. For `Vec<u8>` this is a no-op,
14/// for other types like `ArrayVec` or fixed arrays it performs a copy.
15pub trait IntoVec: AsRef<[u8]> {
16    /// Convert to a `Vec<u8>`.
17    fn into_vec(self) -> Vec<u8>;
18}
19
20impl IntoVec for Vec<u8> {
21    #[inline]
22    fn into_vec(self) -> Vec<u8> {
23        self
24    }
25}
26
27impl<const N: usize> IntoVec for [u8; N] {
28    #[inline]
29    fn into_vec(self) -> Vec<u8> {
30        self.to_vec()
31    }
32}
33
34impl<const N: usize> IntoVec for arrayvec::ArrayVec<u8, N> {
35    #[inline]
36    fn into_vec(self) -> Vec<u8> {
37        self.to_vec()
38    }
39}
40
41/// Trait that will transform the data to be saved in the DB.
42pub trait Encode: Send + Sync + Sized + Debug {
43    /// Encoded type.
44    type Encoded: AsRef<[u8]> + IntoVec + Send + Sync + Ord + Debug;
45
46    /// Encodes data going into the database.
47    fn encode(self) -> Self::Encoded;
48}
49
50/// Trait that will transform the data to be read from the DB.
51pub trait Decode: Send + Sync + Sized + Debug {
52    /// Decodes data coming from the database.
53    fn decode(value: &[u8]) -> Result<Self, DatabaseError>;
54
55    /// Decodes owned data coming from the database.
56    fn decode_owned(value: Vec<u8>) -> Result<Self, DatabaseError> {
57        Self::decode(&value)
58    }
59}
60
61/// Generic trait that enforces the database key to implement [`Encode`] and [`Decode`].
62pub trait Key: Encode + Decode + Ord + Clone + Serialize + for<'a> Deserialize<'a> {}
63
64impl<T> Key for T where T: Encode + Decode + Ord + Clone + Serialize + for<'a> Deserialize<'a> {}
65
66/// Generic trait that enforces the database value to implement [`Compress`] and [`Decompress`].
67pub trait Value: Compress + Decompress + Serialize {}
68
69impl<T> Value for T where T: Compress + Decompress + Serialize {}
70
71/// Generic trait that a database table should follow.
72///
73/// The [`Table::Key`] and [`Table::Value`] types should implement [`Encode`] and
74/// [`Decode`] when appropriate. These traits define how the data is stored and read from the
75/// database.
76///
77/// It allows for the use of codecs. See [`crate::models::ShardedKey`] for a custom
78/// implementation.
79pub trait Table: Send + Sync + Debug + 'static {
80    /// The table's name.
81    const NAME: &'static str;
82
83    /// Whether the table is also a `DUPSORT` table.
84    const DUPSORT: bool;
85
86    /// Key element of `Table`.
87    ///
88    /// Sorting should be taken into account when encoding this.
89    type Key: Key;
90
91    /// Value element of `Table`.
92    type Value: Value;
93}
94
95/// Trait that provides object-safe access to the table's metadata.
96pub trait TableInfo: Send + Sync + Debug + 'static {
97    /// The table's name.
98    fn name(&self) -> &'static str;
99
100    /// Whether the table is a `DUPSORT` table.
101    fn is_dupsort(&self) -> bool;
102}
103
104/// Tuple with `T::Key` and `T::Value`.
105pub type TableRow<T> = (<T as Table>::Key, <T as Table>::Value);
106
107/// `DupSort` allows for keys to be repeated in the database.
108///
109/// Upstream docs: <https://libmdbx.dqdkfa.ru/usage.html#autotoc_md48>
110pub trait DupSort: Table {
111    /// The table subkey. This type must implement [`Encode`] and [`Decode`].
112    ///
113    /// Sorting should be taken into account when encoding this.
114    ///
115    /// Upstream docs: <https://libmdbx.dqdkfa.ru/usage.html#autotoc_md48>
116    type SubKey: Key;
117}
118
119/// Allows duplicating tables across databases
120pub trait TableImporter: DbTxMut {
121    /// Imports all table data from another transaction.
122    fn import_table<T: Table, R: DbTx>(&self, source_tx: &R) -> Result<(), DatabaseError> {
123        let mut destination_cursor = self.cursor_write::<T>()?;
124
125        for kv in source_tx.cursor_read::<T>()?.walk(None)? {
126            let (k, v) = kv?;
127            destination_cursor.append(k, &v)?;
128        }
129
130        Ok(())
131    }
132
133    /// Imports table data from another transaction within a range.
134    ///
135    /// This method works correctly with both regular and `DupSort` tables. For `DupSort` tables,
136    /// all duplicate entries within the range are preserved during import.
137    fn import_table_with_range<T: Table, R: DbTx>(
138        &self,
139        source_tx: &R,
140        from: Option<<T as Table>::Key>,
141        to: <T as Table>::Key,
142    ) -> Result<(), DatabaseError>
143    where
144        T::Key: Default,
145    {
146        let mut destination_cursor = self.cursor_write::<T>()?;
147        let mut source_cursor = source_tx.cursor_read::<T>()?;
148
149        let source_range = match from {
150            Some(from) => source_cursor.walk_range(from..=to),
151            None => source_cursor.walk_range(..=to),
152        };
153        for row in source_range? {
154            let (key, value) = row?;
155            destination_cursor.append(key, &value)?;
156        }
157
158        Ok(())
159    }
160
161    /// Imports all dupsort data from another transaction.
162    fn import_dupsort<T: DupSort, R: DbTx>(&self, source_tx: &R) -> Result<(), DatabaseError> {
163        let mut destination_cursor = self.cursor_dup_write::<T>()?;
164        let mut cursor = source_tx.cursor_dup_read::<T>()?;
165
166        while let Some((k, _)) = cursor.next_no_dup()? {
167            for kv in cursor.walk_dup(Some(k), None)? {
168                let (k, v) = kv?;
169                destination_cursor.append_dup(k, v)?;
170            }
171        }
172
173        Ok(())
174    }
175}