1use crate::{table::TableImporter, transaction::DbTx, DatabaseError};
2use std::{fmt::Debug, path::PathBuf, sync::Arc};
3
4pub trait Database: Send + Sync + Debug {
8 type TX: DbTx + Sync + 'static;
10 type TXMut: DbTx + TableImporter + Sync + 'static;
12
13 #[track_caller]
15 fn tx(&self) -> Result<Self::TX, DatabaseError>;
16
17 #[track_caller]
19 fn tx_mut(&self) -> Result<Self::TXMut, DatabaseError>;
20
21 fn path(&self) -> PathBuf;
23
24 fn oldest_reader_txnid(&self) -> Option<u64>;
32
33 fn last_txnid(&self) -> Option<u64>;
35
36 fn view<T, F>(&self, f: F) -> Result<T, DatabaseError>
39 where
40 F: FnOnce(&mut Self::TX) -> T,
41 {
42 let mut tx = self.tx()?;
43
44 let res = f(&mut tx);
45 tx.commit()?;
46
47 Ok(res)
48 }
49
50 fn update<T, F>(&self, f: F) -> Result<T, DatabaseError>
53 where
54 F: FnOnce(&Self::TXMut) -> T,
55 {
56 let tx = self.tx_mut()?;
57
58 let res = f(&tx);
59 tx.commit()?;
60
61 Ok(res)
62 }
63}
64
65impl<DB: Database> Database for Arc<DB> {
66 type TX = <DB as Database>::TX;
67 type TXMut = <DB as Database>::TXMut;
68
69 fn tx(&self) -> Result<Self::TX, DatabaseError> {
70 <DB as Database>::tx(self)
71 }
72
73 fn tx_mut(&self) -> Result<Self::TXMut, DatabaseError> {
74 <DB as Database>::tx_mut(self)
75 }
76
77 fn path(&self) -> PathBuf {
78 <DB as Database>::path(self)
79 }
80
81 fn oldest_reader_txnid(&self) -> Option<u64> {
82 <DB as Database>::oldest_reader_txnid(self)
83 }
84
85 fn last_txnid(&self) -> Option<u64> {
86 <DB as Database>::last_txnid(self)
87 }
88}
89
90impl<DB: Database> Database for &DB {
91 type TX = <DB as Database>::TX;
92 type TXMut = <DB as Database>::TXMut;
93
94 fn tx(&self) -> Result<Self::TX, DatabaseError> {
95 <DB as Database>::tx(self)
96 }
97
98 fn tx_mut(&self) -> Result<Self::TXMut, DatabaseError> {
99 <DB as Database>::tx_mut(self)
100 }
101
102 fn path(&self) -> PathBuf {
103 <DB as Database>::path(self)
104 }
105
106 fn oldest_reader_txnid(&self) -> Option<u64> {
107 <DB as Database>::oldest_reader_txnid(self)
108 }
109
110 fn last_txnid(&self) -> Option<u64> {
111 <DB as Database>::last_txnid(self)
112 }
113}
114
115pub trait ReaderTxnTracker: Send + Sync {
117 fn wait_for_pre_commit_readers(&self);
119}
120
121impl<DB: Database> ReaderTxnTracker for DB {
122 fn wait_for_pre_commit_readers(&self) {
123 if let Some(committed_txnid) = Database::last_txnid(self) {
124 while Database::oldest_reader_txnid(self).is_some_and(|oldest| oldest < committed_txnid)
125 {
126 std::thread::sleep(std::time::Duration::from_millis(10));
127 }
128 }
129 }
130}