Skip to main content

reth_db_api/
table.rs

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