spacedb_store/
redb_engine.rs1use std::path::Path;
16
17use redb::{Database, ReadableTable, TableDefinition, TableError};
18
19use crate::engine::{Durability, KvEngine, ReadTx, Readable, WriteTx};
20use crate::error::{StoreError, StoreResult};
21
22type ByteTable<'a> = TableDefinition<'a, &'static [u8], &'static [u8]>;
24
25fn table_def(name: &str) -> ByteTable<'_> {
26 TableDefinition::new(name)
27}
28
29pub struct RedbEngine {
31 db: Database,
32}
33
34impl RedbEngine {
35 pub fn open(path: impl AsRef<Path>) -> StoreResult<Self> {
37 let db = Database::create(path).map_err(StoreError::engine)?;
38 Ok(Self { db })
39 }
40
41 pub fn from_db(db: Database) -> Self {
43 Self { db }
44 }
45}
46
47pub struct RedbReadTx {
51 txn: redb::ReadTransaction,
52}
53
54impl Readable for RedbReadTx {
55 fn get_raw(&self, table: &str, key: &[u8]) -> StoreResult<Option<Vec<u8>>> {
56 let t = match self.txn.open_table(table_def(table)) {
57 Ok(t) => t,
58 Err(TableError::TableDoesNotExist(_)) => return Ok(None),
61 Err(e) => return Err(StoreError::engine(e)),
62 };
63 let got = t.get(key).map_err(StoreError::engine)?;
64 Ok(got.map(|g| g.value().to_vec()))
65 }
66
67 fn range_raw(&self, table: &str, lo: &[u8], hi: &[u8]) -> StoreResult<Vec<(Vec<u8>, Vec<u8>)>> {
68 let t = match self.txn.open_table(table_def(table)) {
69 Ok(t) => t,
70 Err(TableError::TableDoesNotExist(_)) => return Ok(Vec::new()),
71 Err(e) => return Err(StoreError::engine(e)),
72 };
73 let mut out = Vec::new();
74 for entry in t.range(lo..hi).map_err(StoreError::engine)? {
75 let (k, v) = entry.map_err(StoreError::engine)?;
76 out.push((k.value().to_vec(), v.value().to_vec()));
77 }
78 Ok(out)
79 }
80}
81
82impl ReadTx for RedbReadTx {}
83
84pub struct RedbWriteTx {
89 txn: redb::WriteTransaction,
90}
91
92impl Readable for RedbWriteTx {
93 fn get_raw(&self, table: &str, key: &[u8]) -> StoreResult<Option<Vec<u8>>> {
94 let t = self.txn.open_table(table_def(table)).map_err(StoreError::engine)?;
97 let got = t.get(key).map_err(StoreError::engine)?;
98 Ok(got.map(|g| g.value().to_vec()))
99 }
100
101 fn range_raw(&self, table: &str, lo: &[u8], hi: &[u8]) -> StoreResult<Vec<(Vec<u8>, Vec<u8>)>> {
102 let t = self.txn.open_table(table_def(table)).map_err(StoreError::engine)?;
103 let mut out = Vec::new();
104 for entry in t.range(lo..hi).map_err(StoreError::engine)? {
105 let (k, v) = entry.map_err(StoreError::engine)?;
106 out.push((k.value().to_vec(), v.value().to_vec()));
107 }
108 Ok(out)
109 }
110}
111
112impl WriteTx for RedbWriteTx {
113 fn put_raw(&mut self, table: &str, key: &[u8], val: &[u8]) -> StoreResult<()> {
114 let mut t = self.txn.open_table(table_def(table)).map_err(StoreError::engine)?;
115 t.insert(key, val).map_err(StoreError::engine)?;
116 Ok(())
117 }
118
119 fn delete_raw(&mut self, table: &str, key: &[u8]) -> StoreResult<bool> {
120 let mut t = self.txn.open_table(table_def(table)).map_err(StoreError::engine)?;
121 let removed = t.remove(key).map_err(StoreError::engine)?;
122 Ok(removed.is_some())
123 }
124
125 fn commit(self) -> StoreResult<()> {
126 self.txn.commit().map_err(StoreError::engine)
127 }
128}
129
130impl KvEngine for RedbEngine {
133 type RTx<'a> = RedbReadTx;
134 type WTx<'a> = RedbWriteTx;
135
136 fn begin_read(&self) -> StoreResult<Self::RTx<'_>> {
137 let txn = self.db.begin_read().map_err(StoreError::engine)?;
138 Ok(RedbReadTx { txn })
139 }
140
141 fn begin_write(&self, durability: Durability) -> StoreResult<Self::WTx<'_>> {
142 let mut txn = self.db.begin_write().map_err(StoreError::engine)?;
143 let redb_durability = match durability {
144 Durability::Immediate => redb::Durability::Immediate,
145 Durability::Eventual => redb::Durability::Eventual,
146 };
147 txn.set_durability(redb_durability);
148 Ok(RedbWriteTx { txn })
149 }
150}