diff --git a/prdoc/pr_9868.prdoc b/prdoc/pr_9868.prdoc new file mode 100644 index 0000000000000..e59101e133296 --- /dev/null +++ b/prdoc/pr_9868.prdoc @@ -0,0 +1,9 @@ +title: Fix the deadlock during statements gossiping +doc: +- audience: Node Dev + description: |- + During high load the statement store experiences deadlock-like behavior: every second statements were gossiping, locking the index which possibly caused the deadlock. After the fix, the observed behavior no longer occurs. + +crates: +- name: sc-statement-store + bump: patch diff --git a/substrate/client/statement-store/src/lib.rs b/substrate/client/statement-store/src/lib.rs index e58440eccbbe8..a31258c3616b1 100644 --- a/substrate/client/statement-store/src/lib.rs +++ b/substrate/client/statement-store/src/lib.rs @@ -488,12 +488,7 @@ impl Store { where Block: BlockT, Block::Hash: From, - Client: ProvideRuntimeApi - + HeaderBackend - + sc_client_api::ExecutorProvider - + Send - + Sync - + 'static, + Client: ProvideRuntimeApi + HeaderBackend + Send + Sync + 'static, Client::Api: ValidateStatement, { let store = Arc::new(Self::new(path, options, client, keystore, prometheus)?); @@ -671,21 +666,25 @@ impl Store { /// Perform periodic store maintenance pub fn maintain(&self) { log::trace!(target: LOG_TARGET, "Started store maintenance"); - let deleted = self.index.write().maintain(self.timestamp()); + let (deleted, active_count, expired_count): (Vec<_>, usize, usize) = { + let mut index = self.index.write(); + let deleted = index.maintain(self.timestamp()); + (deleted, index.entries.len(), index.expired.len()) + }; let deleted: Vec<_> = deleted.into_iter().map(|hash| (col::EXPIRED, hash.to_vec(), None)).collect(); - let count = deleted.len() as u64; + let deleted_count = deleted.len() as u64; if let Err(e) = self.db.commit(deleted) { log::warn!(target: LOG_TARGET, "Error writing to the statement database: {:?}", e); } else { - self.metrics.report(|metrics| metrics.statements_pruned.inc_by(count)); + self.metrics.report(|metrics| metrics.statements_pruned.inc_by(deleted_count)); } log::trace!( target: LOG_TARGET, "Completed store maintenance. Purged: {}, Active: {}, Expired: {}", - count, - self.index.read().entries.len(), - self.index.read().expired.len() + deleted_count, + active_count, + expired_count ); } @@ -764,7 +763,7 @@ impl StatementStore for Store { fn statements(&self) -> Result> { let index = self.index.read(); let mut result = Vec::with_capacity(index.entries.len()); - for h in self.index.read().entries.keys() { + for h in index.entries.keys() { let encoded = self.db.get(col::STATEMENTS, h).map_err(|e| Error::Db(e.to_string()))?; if let Some(encoded) = encoded { if let Ok(statement) = Statement::decode(&mut encoded.as_slice()) {