native_db_32bit/
database.rs1use crate::database_builder::ModelBuilder;
2use crate::db_type::Result;
3use crate::stats::{Stats, StatsTable};
4use crate::table_definition::PrimaryTableDefinition;
5use crate::transaction::internal::r_transaction::InternalRTransaction;
6use crate::transaction::internal::rw_transaction::InternalRwTransaction;
7use crate::transaction::RTransaction;
8use crate::transaction::RwTransaction;
9use crate::watch;
10use crate::watch::query::{InternalWatch, Watch};
11#[cfg(not(target_has_atomic = "64"))]
12use portable_atomic::AtomicU64;
13use redb::TableHandle;
14use std::cell::RefCell;
15use std::collections::HashMap;
16#[cfg(target_has_atomic = "64")]
17use std::sync::atomic::AtomicU64;
18use std::sync::{Arc, RwLock};
19use std::u64;
20
21pub struct Database<'a> {
38 pub(crate) instance: redb::Database,
39 pub(crate) primary_table_definitions: HashMap<String, PrimaryTableDefinition<'a>>,
40 pub(crate) watchers: Arc<RwLock<watch::Watchers>>,
41 pub(crate) watchers_counter_id: AtomicU64,
42}
43
44impl Database<'_> {
45 pub fn rw_transaction(&self) -> Result<RwTransaction> {
47 let rw = self.instance.begin_write()?;
48 let write_txn = RwTransaction {
49 watcher: &self.watchers,
50 batch: RefCell::new(watch::Batch::new()),
51 internal: InternalRwTransaction {
52 redb_transaction: rw,
53 primary_table_definitions: &self.primary_table_definitions,
54 },
55 };
56 Ok(write_txn)
57 }
58
59 pub fn r_transaction(&self) -> Result<RTransaction> {
61 let txn = self.instance.begin_read()?;
62 let read_txn = RTransaction {
63 internal: InternalRTransaction {
64 redb_transaction: txn,
65 table_definitions: &self.primary_table_definitions,
66 },
67 };
68 Ok(read_txn)
69 }
70}
71
72impl Database<'_> {
73 pub fn watch(&self) -> Watch {
75 Watch {
76 internal: InternalWatch {
77 watchers: &self.watchers,
78 watchers_counter_id: &self.watchers_counter_id,
79 },
80 }
81 }
82
83 pub fn unwatch(&self, id: u64) -> Result<()> {
88 let mut watchers = self.watchers.write().unwrap();
89 watchers.remove_sender(id);
90 Ok(())
91 }
92}
93
94impl<'a> Database<'a> {
95 pub(crate) fn seed_model(&mut self, model_builder: &'a ModelBuilder) -> Result<()> {
96 let main_table_definition =
97 redb::TableDefinition::new(model_builder.model.primary_key.unique_table_name.as_str());
98 let mut primary_table_definition: PrimaryTableDefinition =
99 (model_builder, main_table_definition).into();
100
101 let rw = self.instance.begin_write()?;
102 rw.open_table(primary_table_definition.redb.clone())?;
103
104 for secondary_key in model_builder.model.secondary_keys.iter() {
105 primary_table_definition.secondary_tables.insert(
106 secondary_key.clone(),
107 redb::TableDefinition::new(secondary_key.unique_table_name.as_str()).into(),
108 );
109 rw.open_table(
110 primary_table_definition.secondary_tables[&secondary_key]
111 .redb
112 .clone(),
113 )?;
114 }
115 rw.commit()?;
116
117 self.primary_table_definitions.insert(
118 model_builder.model.primary_key.unique_table_name.clone(),
119 primary_table_definition,
120 );
121
122 Ok(())
123 }
124
125 pub fn redb_stats(&self) -> Result<Stats> {
126 use redb::ReadableTable;
127 let rx = self.instance.begin_read()?;
128 let mut stats_primary_tables = vec![];
129 for primary_table in self.primary_table_definitions.values() {
130 let result_table_open = rx.open_table(primary_table.redb.clone());
131 let stats_table = match result_table_open {
132 Err(redb::TableError::TableDoesNotExist(_)) => StatsTable {
133 name: primary_table.redb.name().to_string(),
134 n_entries: None,
135 },
136 Ok(table_open) => {
137 let num_raw = table_open.len()?;
138 StatsTable {
139 name: primary_table.redb.name().to_string(),
140 n_entries: Some(num_raw),
141 }
142 }
143 Err(err) => {
144 return Err(err.into());
145 }
146 };
147 stats_primary_tables.push(stats_table);
148 }
149 let mut stats_secondary_tables = vec![];
150 for primary_table in self.primary_table_definitions.values() {
151 for secondary_table in primary_table.secondary_tables.values() {
152 let result_table_open = rx.open_table(secondary_table.redb.clone());
153 let stats_table = match result_table_open {
154 Err(redb::TableError::TableDoesNotExist(_)) => StatsTable {
155 name: secondary_table.redb.name().to_string(),
156 n_entries: None,
157 },
158 Ok(table_open) => {
159 let num_raw = table_open.len()?;
160 StatsTable {
161 name: secondary_table.redb.name().to_string(),
162 n_entries: Some(num_raw),
163 }
164 }
165 Err(err) => {
166 return Err(err.into());
167 }
168 };
169 stats_secondary_tables.push(stats_table);
170 }
171 }
172 stats_primary_tables.sort_by(|a, b| a.name.cmp(&b.name));
173 stats_secondary_tables.sort_by(|a, b| a.name.cmp(&b.name));
174 Ok(Stats {
175 primary_tables: stats_primary_tables,
176 secondary_tables: stats_secondary_tables,
177 })
178 }
179}