Skip to content

Commit

Permalink
fix: resize on failed MDB_FULL error
Browse files Browse the repository at this point in the history
Resize everytime the database indicates it has run out of space rather
than checking for each and every write.
  • Loading branch information
sdbondi committed Sep 1, 2021
1 parent fced869 commit b6bcb69
Show file tree
Hide file tree
Showing 9 changed files with 249 additions and 151 deletions.
62 changes: 39 additions & 23 deletions applications/tari_base_node/src/command_handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ use tari_core::{
LocalNodeCommsInterface,
},
blocks::BlockHeader,
chain_storage,
chain_storage::{async_db::AsyncBlockchainDb, ChainHeader, LMDBDatabase},
consensus::ConsensusManager,
mempool::service::LocalMempoolService,
Expand Down Expand Up @@ -1057,21 +1056,12 @@ impl CommandHandler {
}

pub fn get_blockchain_db_stats(&self) {
let db = self.blockchain_db.clone();
const BYTES_PER_MB: usize = 1024 * 1024;

fn stat_to_row(stat: &chain_storage::DbStat) -> Vec<String> {
row![
stat.name,
stat.entries,
stat.depth,
stat.branch_pages,
stat.leaf_pages,
stat.overflow_pages,
]
}
let db = self.blockchain_db.clone();

self.executor.spawn(async move {
match db.get_stats().await {
let total_db_size = match db.get_stats().await {
Ok(stats) => {
let mut table = Table::new();
table.set_titles(vec![
Expand All @@ -1081,24 +1071,40 @@ impl CommandHandler {
"Branch Pages",
"Leaf Pages",
"Overflow Pages",
"Est. Size (MiB)",
"% of total",
]);
let total_db_size = stats.db_stats().iter().map(|s| s.total_page_size()).sum::<usize>();
stats.db_stats().iter().for_each(|stat| {
table.add_row(stat_to_row(stat));
table.add_row(row![
stat.name,
stat.entries,
stat.depth,
stat.branch_pages,
stat.leaf_pages,
stat.overflow_pages,
format!("{:.2}", stat.total_page_size() as f32 / BYTES_PER_MB as f32),
format!("{:.2}%", (stat.total_page_size() as f32 / total_db_size as f32) * 100.0)
]);
});

table.print_stdout();
println!();
println!(
"{} databases, page size: {} bytes, env_info = ({})",
"{} databases, {:.2} MiB used ({:.2}%), page size: {} bytes, env_info = ({})",
stats.root().entries,
total_db_size as f32 / BYTES_PER_MB as f32,
(total_db_size as f32 / stats.env_info().mapsize as f32) * 100.0,
stats.root().psize as usize,
stats.env_info()
);
total_db_size
},
Err(err) => {
println!("{}", err);
return;
},
}
};

println!();
println!("Totalling DB entry sizes. This may take a few seconds...");
Expand All @@ -1107,21 +1113,31 @@ impl CommandHandler {
Ok(stats) => {
println!();
let mut table = Table::new();
table.set_titles(vec!["Name", "Entries", "Total Size", "Avg. Size/Entry", "% of total"]);
let total_db_size = stats.sizes().iter().map(|s| s.total()).sum::<u64>();
table.set_titles(vec![
"Name",
"Entries",
"Total Size (MiB)",
"Avg. Size/Entry (bytes)",
"% of total",
]);
let total_data_size = stats.sizes().iter().map(|s| s.total()).sum::<u64>();
stats.sizes().iter().for_each(|size| {
let total = size.total() as f32 / 1024.0 / 1024.0;
let total = size.total() as f32 / BYTES_PER_MB as f32;
table.add_row(row![
size.name,
size.num_entries,
format!("{:.2} MiB", total),
format!("{} bytes", size.avg_bytes_per_entry()),
format!("{:.2}%", (size.total() as f32 / total_db_size as f32) * 100.0)
format!("{:.2}", total),
format!("{}", size.avg_bytes_per_entry()),
format!("{:.2}%", (size.total() as f32 / total_data_size as f32) * 100.0)
])
});
table.print_stdout();
println!();
println!("Total data size: {:.2} MiB", total_db_size as f32 / 1024.0 / 1024.0);
println!(
"Total blockchain data size: {:.2} MiB ({:.2} % of LMDB map size)",
total_data_size as f32 / BYTES_PER_MB as f32,
(total_data_size as f32 / total_db_size as f32) * 100.0
);
},
Err(err) => {
println!("{}", err);
Expand Down
4 changes: 0 additions & 4 deletions base_layer/core/src/chain_storage/db_transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -255,10 +255,6 @@ impl DbTransaction {
&self.operations
}

pub(crate) fn into_operations(self) -> Vec<WriteOperation> {
self.operations
}

/// This will store the seed key with the height. This is called when a block is accepted into the main chain.
/// This will only update the hieght of the seed, if its lower then currently stored.
pub fn insert_monero_seed_height(&mut self, monero_seed: Vec<u8>, height: u64) {
Expand Down
6 changes: 5 additions & 1 deletion base_layer/core/src/chain_storage/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
// USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

use crate::{chain_storage::MmrTree, proof_of_work::PowError, validation::ValidationError};
use lmdb_zero::error;
use tari_mmr::{error::MerkleMountainRangeError, MerkleProofError};
use tari_storage::lmdb_store::LMDBError;
use thiserror::Error;
Expand Down Expand Up @@ -109,6 +110,8 @@ pub enum ChainStorageError {
CannotCalculateNonTipMmr(String),
#[error("Key {key} in {table_name} already exists")]
KeyExists { table_name: &'static str, key: String },
#[error("Database resize required")]
DbResizeRequired,
}

impl ChainStorageError {
Expand All @@ -131,11 +134,12 @@ impl From<lmdb_zero::Error> for ChainStorageError {
fn from(err: lmdb_zero::Error) -> Self {
use lmdb_zero::Error::*;
match err {
Code(c) if c == lmdb_zero::error::NOTFOUND => ChainStorageError::ValueNotFound {
Code(error::NOTFOUND) => ChainStorageError::ValueNotFound {
entity: "<unspecified entity>",
field: "<unknown>",
value: "<unknown>".to_string(),
},
Code(error::MAP_FULL) => ChainStorageError::DbResizeRequired,
_ => ChainStorageError::AccessError(err.to_string()),
}
}
Expand Down
10 changes: 8 additions & 2 deletions base_layer/core/src/chain_storage/lmdb_db/lmdb.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,16 +87,17 @@ where
val,
e,
);

if let lmdb_zero::Error::Code(code) = &e {
if *code == lmdb_zero::error::KEYEXIST {
return ChainStorageError::KeyExists {
table_name,
key: to_hex(key.as_lmdb_bytes()),
};
}
if *code == lmdb_zero::error::MAP_FULL {
return ChainStorageError::DbResizeRequired;
}
}

ChainStorageError::InsertError {
table: table_name,
error: e.to_string(),
Expand All @@ -121,6 +122,11 @@ where
target: LOG_TARGET,
"Could not insert value into lmdb transaction: {:?}", e
);
if let lmdb_zero::Error::Code(code) = &e {
if *code == lmdb_zero::error::MAP_FULL {
return ChainStorageError::DbResizeRequired;
}
}
ChainStorageError::AccessError(e.to_string())
})
}
Expand Down
Loading

0 comments on commit b6bcb69

Please sign in to comment.