use try_read_for() with timeout for tui status updates (header and pool stats) (#3129)

* use try_read_for with timeout for tui status updates (header and pool stats)

* rework based on feedback
This commit is contained in:
Antioch Peverell 2019-11-22 12:46:07 +00:00 committed by GitHub
parent 32609fc542
commit 78220febed
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 42 additions and 46 deletions

View file

@ -1216,21 +1216,23 @@ impl Chain {
.map_err(|e| ErrorKind::StoreErr(e, "chain tail".to_owned()).into())
}
/// Tip (head) of the header chain if read lock can be acquired right now.
pub fn try_header_head(&self) -> Result<Option<Tip>, Error> {
match self.header_pmmr.try_read() {
Some(lock) => {
let hash = lock.head_hash()?;
let header = self.store.get_block_header(&hash)?;
Ok(Some(Tip::from_header(&header)))
}
None => Ok(None),
}
/// Tip (head) of the header chain if read lock can be acquired reasonably quickly.
/// Used by the TUI when updating stats to avoid locking the TUI up.
pub fn try_header_head(&self, timeout: Duration) -> Result<Option<Tip>, Error> {
self.header_pmmr
.try_read_for(timeout)
.map(|ref pmmr| self.read_header_head(pmmr).map(|x| Some(x)))
.unwrap_or(Ok(None))
}
/// Tip (head) of the header chain.
pub fn header_head(&self) -> Result<Tip, Error> {
let hash = self.header_pmmr.read().head_hash()?;
self.read_header_head(&self.header_pmmr.read())
}
/// Read head from the provided PMMR handle.
fn read_header_head(&self, pmmr: &txhashset::PMMRHandle<BlockHeader>) -> Result<Tip, Error> {
let hash = pmmr.head_hash()?;
let header = self.store.get_block_header(&hash)?;
Ok(Tip::from_header(&header))
}

View file

@ -63,7 +63,7 @@ pub struct ServerStats {
/// Difficulty calculation statistics
pub diff_stats: DiffStats,
/// Transaction pool statistics
pub tx_stats: TxStats,
pub tx_stats: Option<TxStats>,
/// Disk usage in GB
pub disk_usage_gb: String,
}

View file

@ -23,7 +23,7 @@ use std::path::Path;
use std::sync::{mpsc, Arc};
use std::{
thread::{self, JoinHandle},
time,
time::{self, Duration},
};
use fs2::FileExt;
@ -480,23 +480,16 @@ impl Server {
.map(|p| PeerStats::from_peer(&p))
.collect();
let tx_stats = {
let pool = self.tx_pool.try_read();
match pool {
Some(pool) => TxStats {
tx_pool_size: pool.txpool.size(),
tx_pool_kernels: pool.txpool.kernel_count(),
stem_pool_size: pool.stempool.size(),
stem_pool_kernels: pool.stempool.kernel_count(),
},
None => TxStats {
tx_pool_size: 0,
tx_pool_kernels: 0,
stem_pool_size: 0,
stem_pool_kernels: 0,
},
}
};
// Updating TUI stats should not block any other processing so only attempt to
// acquire various read locks with a timeout.
let read_timeout = Duration::from_millis(500);
let tx_stats = self.tx_pool.try_read_for(read_timeout).map(|pool| TxStats {
tx_pool_size: pool.txpool.size(),
tx_pool_kernels: pool.txpool.kernel_count(),
stem_pool_size: pool.stempool.size(),
stem_pool_kernels: pool.stempool.kernel_count(),
});
let head = self.chain.head_header()?;
let head_stats = ChainStats {
@ -506,16 +499,15 @@ impl Server {
total_difficulty: head.total_difficulty(),
};
let header_stats = match self.chain.try_header_head()? {
Some(tip) => {
let header = self.chain.get_block_header(&tip.hash())?;
let header_stats = match self.chain.try_header_head(read_timeout)? {
Some(head) => self.chain.get_block_header(&head.hash()).map(|header| {
Some(ChainStats {
latest_timestamp: header.timestamp,
height: header.height,
last_block_h: header.prev_hash,
total_difficulty: header.total_difficulty(),
})
}
})?,
_ => None,
};

View file

@ -284,18 +284,20 @@ impl TUIStatusListener for TUIStatusView {
t.set_content(header_stats.latest_timestamp.to_string());
});
}
c.call_on_id("tx_pool_size", |t: &mut TextView| {
t.set_content(stats.tx_stats.tx_pool_size.to_string());
});
c.call_on_id("stem_pool_size", |t: &mut TextView| {
t.set_content(stats.tx_stats.stem_pool_size.to_string());
});
c.call_on_id("tx_pool_kernels", |t: &mut TextView| {
t.set_content(stats.tx_stats.tx_pool_kernels.to_string());
});
c.call_on_id("stem_pool_kernels", |t: &mut TextView| {
t.set_content(stats.tx_stats.stem_pool_kernels.to_string());
});
if let Some(tx_stats) = &stats.tx_stats {
c.call_on_id("tx_pool_size", |t: &mut TextView| {
t.set_content(tx_stats.tx_pool_size.to_string());
});
c.call_on_id("stem_pool_size", |t: &mut TextView| {
t.set_content(tx_stats.stem_pool_size.to_string());
});
c.call_on_id("tx_pool_kernels", |t: &mut TextView| {
t.set_content(tx_stats.tx_pool_kernels.to_string());
});
c.call_on_id("stem_pool_kernels", |t: &mut TextView| {
t.set_content(tx_stats.stem_pool_kernels.to_string());
});
}
}
}