fix(hang): Stop blocking some Zebra futures for up to a minute using a CPU busy-loop, Credit: Ziggurat Team (#6763), james_katz (#7000) (#7103)

* Stop busy-waiting in a Future for 45 seconds every minute

* Use the correct elapsed time calculation

* Add some TODOs for making the structure of the loop and wait times clearer
This commit is contained in:
teor 2023-07-01 02:58:05 +10:00 committed by GitHub
parent 5eea111922
commit 322cbec817
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 17 additions and 12 deletions

View File

@ -1,8 +1,12 @@
//! Progress tracking for blockchain syncing. //! Progress tracking for blockchain syncing.
use std::{cmp::min, ops::Add, time::Duration}; use std::{
cmp::min,
ops::Add,
time::{Duration, Instant},
};
use chrono::{TimeZone, Utc}; use chrono::Utc;
use num_integer::div_ceil; use num_integer::div_ceil;
use zebra_chain::{ use zebra_chain::{
@ -118,17 +122,15 @@ pub async fn show_block_chain_progress(
let mut last_state_change_height = Height(0); let mut last_state_change_height = Height(0);
// The last time we logged an update. // The last time we logged an update.
// Initialised with the unix epoch, to simplify the code while still staying in the std range. let mut last_log_time = Instant::now();
let mut last_log_time = Utc
.timestamp_opt(0, 0)
.single()
.expect("in-range number of seconds and valid nanosecond");
#[cfg(feature = "progress-bar")] #[cfg(feature = "progress-bar")]
let block_bar = howudoin::new().label("Blocks"); let block_bar = howudoin::new().label("Blocks");
loop { loop {
let now = Utc::now(); let now = Utc::now();
let instant_now = Instant::now();
let is_syncer_stopped = sync_status.is_close_to_tip(); let is_syncer_stopped = sync_status.is_close_to_tip();
if let Some(estimated_height) = if let Some(estimated_height) =
@ -142,6 +144,8 @@ pub async fn show_block_chain_progress(
let network_upgrade = NetworkUpgrade::current(network, current_height); let network_upgrade = NetworkUpgrade::current(network, current_height);
// Send progress reports for block height // Send progress reports for block height
//
// TODO: split the progress bar height update into its own function.
#[cfg(feature = "progress-bar")] #[cfg(feature = "progress-bar")]
if matches!(howudoin::cancelled(), Some(true)) { if matches!(howudoin::cancelled(), Some(true)) {
block_bar.close(); block_bar.close();
@ -152,16 +156,17 @@ pub async fn show_block_chain_progress(
.desc(network_upgrade.to_string()); .desc(network_upgrade.to_string());
} }
// Skip logging if it isn't time for it yet // Skip logging and status updates if it isn't time for them yet.
let elapsed_since_log = (now - last_log_time) let elapsed_since_log = instant_now.saturating_duration_since(last_log_time);
.to_std()
.expect("elapsed times are in range");
if elapsed_since_log < LOG_INTERVAL { if elapsed_since_log < LOG_INTERVAL {
tokio::time::sleep(PROGRESS_BAR_INTERVAL).await;
continue; continue;
} else { } else {
last_log_time = now; last_log_time = instant_now;
} }
// TODO: split logging / status updates into their own function.
// Work out the sync progress towards the estimated tip. // Work out the sync progress towards the estimated tip.
let sync_progress = f64::from(current_height.0) / f64::from(estimated_height.0); let sync_progress = f64::from(current_height.0) / f64::from(estimated_height.0);
let sync_percent = format!( let sync_percent = format!(