Skip to content

Commit

Permalink
Merge branch 'develop' into chore/stacks-node-logs
Browse files Browse the repository at this point in the history
  • Loading branch information
jcnelson authored Nov 5, 2024
2 parents 3c812cf + d11ed3c commit 813dc9b
Show file tree
Hide file tree
Showing 7 changed files with 42 additions and 38 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to the versioning scheme outlined in the [README.md](RE

## [Unreleased]

### Changed
- Add index for StacksBlockId to nakamoto block headers table (improves node performance)
- Remove the panic for reporting DB deadlocks (just error and continue waiting)

## [3.0.0.0.0]

### Added
Expand Down
13 changes: 6 additions & 7 deletions stacks-common/src/util/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,26 +51,25 @@ pub fn update_lock_table(conn: &Connection) {
/// Called by `rusqlite` if we are waiting too long on a database lock
/// If called too many times, will assume a deadlock and panic
pub fn tx_busy_handler(run_count: i32) -> bool {
const TIMEOUT: Duration = Duration::from_secs(300);
const AVG_SLEEP_TIME_MS: u64 = 100;

// Every ~5min, report an error with a backtrace
// 5min * 60s/min * 1_000ms/s / 100ms
const ERROR_COUNT: u32 = 3_000;

// First, check if this is taking unreasonably long. If so, it's probably a deadlock
let run_count = run_count.unsigned_abs();
let approx_time_elapsed =
Duration::from_millis(AVG_SLEEP_TIME_MS.saturating_mul(u64::from(run_count)));
if approx_time_elapsed > TIMEOUT {
error!("Deadlock detected. Waited {} seconds (estimated) for database lock. Giving up", approx_time_elapsed.as_secs();
if run_count > 0 && run_count % ERROR_COUNT == 0 {
error!("Deadlock detected. Waited 5 minutes (estimated) for database lock.";
"run_count" => run_count,
"backtrace" => ?Backtrace::capture()
);
for (k, v) in LOCK_TABLE.lock().unwrap().iter() {
error!("Database '{k}' last locked by {v}");
}
panic!("Deadlock in thread {:?}", thread::current().name());
}

let mut sleep_time_ms = 2u64.saturating_pow(run_count);

sleep_time_ms = sleep_time_ms.saturating_add(thread_rng().gen_range(0..sleep_time_ms));

if sleep_time_ms > AVG_SLEEP_TIME_MS {
Expand Down
8 changes: 8 additions & 0 deletions stackslib/src/chainstate/nakamoto/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,14 @@ lazy_static! {
);
"#,
];

pub static ref NAKAMOTO_CHAINSTATE_SCHEMA_5: [&'static str; 2] = [
r#"
UPDATE db_config SET version = "8";
"#,
// Add an index for index block hash in nakamoto block headers
"CREATE INDEX IF NOT EXISTS index_block_hash ON nakamoto_block_headers(index_block_hash);",
];
}

#[cfg(test)]
Expand Down
34 changes: 18 additions & 16 deletions stackslib/src/chainstate/stacks/db/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ use crate::chainstate::burn::{ConsensusHash, ConsensusHashExtensions};
use crate::chainstate::nakamoto::{
HeaderTypeNames, NakamotoBlock, NakamotoBlockHeader, NakamotoChainState,
NakamotoStagingBlocksConn, NAKAMOTO_CHAINSTATE_SCHEMA_1, NAKAMOTO_CHAINSTATE_SCHEMA_2,
NAKAMOTO_CHAINSTATE_SCHEMA_3, NAKAMOTO_CHAINSTATE_SCHEMA_4,
NAKAMOTO_CHAINSTATE_SCHEMA_3, NAKAMOTO_CHAINSTATE_SCHEMA_4, NAKAMOTO_CHAINSTATE_SCHEMA_5,
};
use crate::chainstate::stacks::address::StacksAddressExtensions;
use crate::chainstate::stacks::boot::*;
Expand Down Expand Up @@ -299,14 +299,14 @@ impl DBConfig {
});
match epoch_id {
StacksEpochId::Epoch10 => true,
StacksEpochId::Epoch20 => version_u32 >= 1 && version_u32 <= 7,
StacksEpochId::Epoch2_05 => version_u32 >= 2 && version_u32 <= 7,
StacksEpochId::Epoch21 => version_u32 >= 3 && version_u32 <= 7,
StacksEpochId::Epoch22 => version_u32 >= 3 && version_u32 <= 7,
StacksEpochId::Epoch23 => version_u32 >= 3 && version_u32 <= 7,
StacksEpochId::Epoch24 => version_u32 >= 3 && version_u32 <= 7,
StacksEpochId::Epoch25 => version_u32 >= 3 && version_u32 <= 7,
StacksEpochId::Epoch30 => version_u32 >= 3 && version_u32 <= 7,
StacksEpochId::Epoch20 => version_u32 >= 1 && version_u32 <= 8,
StacksEpochId::Epoch2_05 => version_u32 >= 2 && version_u32 <= 8,
StacksEpochId::Epoch21 => version_u32 >= 3 && version_u32 <= 8,
StacksEpochId::Epoch22 => version_u32 >= 3 && version_u32 <= 8,
StacksEpochId::Epoch23 => version_u32 >= 3 && version_u32 <= 8,
StacksEpochId::Epoch24 => version_u32 >= 3 && version_u32 <= 8,
StacksEpochId::Epoch25 => version_u32 >= 3 && version_u32 <= 8,
StacksEpochId::Epoch30 => version_u32 >= 3 && version_u32 <= 8,
}
}
}
Expand Down Expand Up @@ -680,7 +680,7 @@ impl<'a> DerefMut for ChainstateTx<'a> {
}
}

pub const CHAINSTATE_VERSION: &'static str = "7";
pub const CHAINSTATE_VERSION: &'static str = "8";

const CHAINSTATE_INITIAL_SCHEMA: &'static [&'static str] = &[
"PRAGMA foreign_keys = ON;",
Expand Down Expand Up @@ -1087,28 +1087,24 @@ impl StacksChainState {
while db_config.version != CHAINSTATE_VERSION {
match db_config.version.as_str() {
"1" => {
// migrate to 2
info!("Migrating chainstate schema from version 1 to 2");
for cmd in CHAINSTATE_SCHEMA_2.iter() {
tx.execute_batch(cmd)?;
}
}
"2" => {
// migrate to 3
info!("Migrating chainstate schema from version 2 to 3");
for cmd in CHAINSTATE_SCHEMA_3.iter() {
tx.execute_batch(cmd)?;
}
}
"3" => {
// migrate to nakamoto 1
info!("Migrating chainstate schema from version 3 to 4: nakamoto support");
for cmd in NAKAMOTO_CHAINSTATE_SCHEMA_1.iter() {
tx.execute_batch(cmd)?;
}
}
"4" => {
// migrate to nakamoto 2
info!(
"Migrating chainstate schema from version 4 to 5: fix nakamoto tenure typo"
);
Expand All @@ -1117,21 +1113,27 @@ impl StacksChainState {
}
}
"5" => {
// migrate to nakamoto 3
info!("Migrating chainstate schema from version 5 to 6: adds height_in_tenure field");
for cmd in NAKAMOTO_CHAINSTATE_SCHEMA_3.iter() {
tx.execute_batch(cmd)?;
}
}
"6" => {
// migrate to nakamoto 3
info!(
"Migrating chainstate schema from version 6 to 7: adds signer_stats table"
);
for cmd in NAKAMOTO_CHAINSTATE_SCHEMA_4.iter() {
tx.execute_batch(cmd)?;
}
}
"7" => {
info!(
"Migrating chainstate schema from version 7 to 8: add index for nakamoto block headers"
);
for cmd in NAKAMOTO_CHAINSTATE_SCHEMA_5.iter() {
tx.execute_batch(cmd)?;
}
}
_ => {
error!(
"Invalid chain state database: expected version = {}, got {}",
Expand Down
9 changes: 4 additions & 5 deletions stackslib/src/net/api/getattachmentsinv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,10 @@ impl HttpRequest for RPCGetAttachmentsInvRequestHandler {
if key == "index_block_hash" {
index_block_hash = StacksBlockId::from_hex(&value).ok();
} else if key == "pages_indexes" {
if let Ok(pages_indexes_value) = value.parse::<String>() {
for entry in pages_indexes_value.split(',') {
if let Ok(page_index) = entry.parse::<u32>() {
page_indexes.insert(page_index);
}
let pages_indexes_value = value.to_string();
for entry in pages_indexes_value.split(',') {
if let Ok(page_index) = entry.parse::<u32>() {
page_indexes.insert(page_index);
}
}
}
Expand Down
6 changes: 1 addition & 5 deletions testnet/stacks-node/src/nakamoto_node/relayer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -303,13 +303,9 @@ impl RelayerThread {

/// have we waited for the right conditions under which to start mining a block off of our
/// chain tip?
#[allow(clippy::nonminimal_bool)]
#[allow(clippy::eq_op)]
fn has_waited_for_latest_blocks(&self) -> bool {
// a network download pass took place
(self.min_network_download_passes <= self.last_network_download_passes
// a network inv pass took place
&& self.min_network_download_passes <= self.last_network_download_passes)
self.min_network_download_passes <= self.last_network_download_passes
// we waited long enough for a download pass, but timed out waiting
|| self.last_network_block_height_ts + (self.config.node.wait_time_for_blocks as u128) < get_epoch_time_ms()
// we're not supposed to wait at all
Expand Down
6 changes: 1 addition & 5 deletions testnet/stacks-node/src/neon_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2896,13 +2896,9 @@ impl RelayerThread {

/// have we waited for the right conditions under which to start mining a block off of our
/// chain tip?
#[allow(clippy::nonminimal_bool)]
#[allow(clippy::eq_op)]
pub fn has_waited_for_latest_blocks(&self) -> bool {
// a network download pass took place
(self.min_network_download_passes <= self.last_network_download_passes
// a network inv pass took place
&& self.min_network_download_passes <= self.last_network_download_passes)
self.min_network_download_passes <= self.last_network_download_passes
// we waited long enough for a download pass, but timed out waiting
|| self.last_network_block_height_ts + (self.config.node.wait_time_for_blocks as u128) < get_epoch_time_ms()
// we're not supposed to wait at all
Expand Down

0 comments on commit 813dc9b

Please sign in to comment.