diff --git a/chain/src/chain.rs b/chain/src/chain.rs
index d8c7713d8..676c69d92 100644
--- a/chain/src/chain.rs
+++ b/chain/src/chain.rs
@@ -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, 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 , 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 {
- 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) -> Result {
+ let hash = pmmr.head_hash()?;
let header = self.store.get_block_header(&hash)?;
Ok(Tip::from_header(&header))
}
diff --git a/servers/src/common/stats.rs b/servers/src/common/stats.rs
index ba44e04fb..2ca1743f7 100644
--- a/servers/src/common/stats.rs
+++ b/servers/src/common/stats.rs
@@ -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,
/// Disk usage in GB
pub disk_usage_gb: String,
}
diff --git a/servers/src/grin/server.rs b/servers/src/grin/server.rs
index c623a76fd..68b1c760d 100644
--- a/servers/src/grin/server.rs
+++ b/servers/src/grin/server.rs
@@ -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,
};
diff --git a/src/bin/tui/status.rs b/src/bin/tui/status.rs
index 90e1bb414..3e6e3099a 100644
--- a/src/bin/tui/status.rs
+++ b/src/bin/tui/status.rs
@@ -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());
+ });
+ }
}
}