reth_db_common/db_tool/
mod.rs1use boyer_moore_magiclen::BMByte;
4use eyre::Result;
5use reth_db::{RawTable, TableRawRow};
6use reth_db_api::{
7 cursor::{DbCursorRO, DbDupCursorRO},
8 database::Database,
9 table::{Decode, Decompress, DupSort, Table, TableRow},
10 transaction::{DbTx, DbTxMut},
11 DatabaseError,
12};
13use reth_fs_util as fs;
14use reth_node_types::NodeTypesWithDB;
15use reth_provider::{providers::ProviderNodeTypes, ChainSpecProvider, DBProvider, ProviderFactory};
16use std::{path::Path, rc::Rc, sync::Arc};
17use tracing::info;
18
19#[derive(Debug)]
21pub struct DbTool<N: NodeTypesWithDB> {
22 pub provider_factory: ProviderFactory<N>,
24}
25
26impl<N: NodeTypesWithDB> DbTool<N> {
27 pub fn chain(&self) -> Arc<N::ChainSpec> {
29 self.provider_factory.chain_spec()
30 }
31
32 pub fn list<T: Table>(&self, filter: &ListFilter) -> Result<(Vec<TableRow<T>>, usize)> {
38 let bmb = Rc::new(BMByte::from(&filter.search));
39 if bmb.is_none() && filter.has_search() {
40 eyre::bail!("Invalid search.")
41 }
42
43 let mut hits = 0;
44
45 let data = self.provider_factory.db_ref().view(|tx| {
46 let mut cursor =
47 tx.cursor_read::<RawTable<T>>().expect("Was not able to obtain a cursor.");
48
49 let map_filter = |row: Result<TableRawRow<T>, _>| {
50 if let Ok((k, v)) = row {
51 let (key, value) = (k.into_key(), v.into_value());
52
53 if key.len() + value.len() < filter.min_row_size {
54 return None
55 }
56 if key.len() < filter.min_key_size {
57 return None
58 }
59 if value.len() < filter.min_value_size {
60 return None
61 }
62
63 let result = || {
64 if filter.only_count {
65 return None
66 }
67 Some((
68 <T as Table>::Key::decode(&key).unwrap(),
69 <T as Table>::Value::decompress(&value).unwrap(),
70 ))
71 };
72
73 match &*bmb {
74 Some(searcher) => {
75 if searcher.find_first_in(&value).is_some() ||
76 searcher.find_first_in(&key).is_some()
77 {
78 hits += 1;
79 return result()
80 }
81 }
82 None => {
83 hits += 1;
84 return result()
85 }
86 }
87 }
88 None
89 };
90
91 if filter.reverse {
92 Ok(cursor
93 .walk_back(None)?
94 .skip(filter.skip)
95 .filter_map(map_filter)
96 .take(filter.len)
97 .collect::<Vec<(_, _)>>())
98 } else {
99 Ok(cursor
100 .walk(None)?
101 .skip(filter.skip)
102 .filter_map(map_filter)
103 .take(filter.len)
104 .collect::<Vec<(_, _)>>())
105 }
106 })?;
107
108 Ok((data.map_err(|e: DatabaseError| eyre::eyre!(e))?, hits))
109 }
110}
111
112impl<N: ProviderNodeTypes> DbTool<N> {
113 pub fn new(provider_factory: ProviderFactory<N>) -> eyre::Result<Self> {
115 provider_factory.provider()?.disable_long_read_transaction_safety();
118 Ok(Self { provider_factory })
119 }
120
121 pub fn get<T: Table>(&self, key: T::Key) -> Result<Option<T::Value>> {
123 self.provider_factory.db_ref().view(|tx| tx.get::<T>(key))?.map_err(|e| eyre::eyre!(e))
124 }
125
126 pub fn get_dup<T: DupSort>(&self, key: T::Key, subkey: T::SubKey) -> Result<Option<T::Value>> {
128 self.provider_factory
129 .db_ref()
130 .view(|tx| tx.cursor_dup_read::<T>()?.seek_by_key_subkey(key, subkey))?
131 .map_err(|e| eyre::eyre!(e))
132 }
133
134 pub fn drop(
136 &self,
137 db_path: impl AsRef<Path>,
138 static_files_path: impl AsRef<Path>,
139 ) -> Result<()> {
140 let db_path = db_path.as_ref();
141 info!(target: "reth::cli", "Dropping database at {:?}", db_path);
142 fs::remove_dir_all(db_path)?;
143
144 let static_files_path = static_files_path.as_ref();
145 info!(target: "reth::cli", "Dropping static files at {:?}", static_files_path);
146 fs::remove_dir_all(static_files_path)?;
147 fs::create_dir_all(static_files_path)?;
148
149 Ok(())
150 }
151
152 pub fn drop_table<T: Table>(&self) -> Result<()> {
154 self.provider_factory.db_ref().update(|tx| tx.clear::<T>())??;
155 Ok(())
156 }
157}
158
159#[derive(Debug)]
161pub struct ListFilter {
162 pub skip: usize,
164 pub len: usize,
166 pub search: Vec<u8>,
168 pub min_row_size: usize,
170 pub min_key_size: usize,
172 pub min_value_size: usize,
174 pub reverse: bool,
176 pub only_count: bool,
178}
179
180impl ListFilter {
181 pub fn has_search(&self) -> bool {
183 !self.search.is_empty()
184 }
185
186 pub fn update_page(&mut self, skip: usize, len: usize) {
188 self.skip = skip;
189 self.len = len;
190 }
191}