Skip to content

Commit 5d2ffd6

Browse files
authored
Merge pull request #1425 from input-output-hk/apply-block-ooo
Handle concurrency in CandidateForest::apply_block
2 parents 5d28516 + aa4d62d commit 5d2ffd6

File tree

2 files changed

+45
-30
lines changed

2 files changed

+45
-30
lines changed

jormungandr/src/blockchain/candidate.rs

Lines changed: 44 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -407,30 +407,12 @@ impl CandidateForest {
407407
/// in the cache, the block value is not updated and the returned future
408408
/// resolves successfully.
409409
pub fn cache_block(&self, block: Block) -> impl Future<Item = (), Error = chain::Error> {
410-
let header = block.header();
411-
let block_hash = header.hash();
410+
let block_hash = block.id();
412411
let mut inner = self.inner.clone();
413412
future::poll_fn(move || Ok(inner.poll_lock())).and_then(move |mut forest| {
414-
use std::collections::hash_map::Entry::*;
415-
416-
match forest.candidate_map.entry(block_hash) {
417-
Occupied(mut entry) => match &entry.get().data {
418-
CandidateData::Header(header) => {
419-
debug_assert!(header.hash() == block_hash);
420-
entry.insert(Candidate::from_block(block));
421-
Ok(())
422-
}
423-
CandidateData::Block(block) => {
424-
debug_assert!(block.header().hash() == block_hash);
425-
Ok(())
426-
}
427-
CandidateData::Applied(header) => {
428-
debug_assert!(header.hash() == block_hash);
429-
Ok(())
430-
}
431-
},
432-
Vacant(_) => Err(chain::ErrorKind::BlockNotRequested(block_hash).into()),
433-
}
413+
forest
414+
.cache_requested_block(block_hash, block)
415+
.map_err(|_block| chain::ErrorKind::BlockNotRequested(block_hash).into())
434416
})
435417
}
436418

@@ -509,13 +491,13 @@ impl CandidateForestThickets {
509491
use std::collections::hash_map::Entry::*;
510492

511493
let block_hash = block.id();
512-
let mut block_avalanche = vec![block];
513494
if self.roots.contains_key(&block_hash) {
514495
let candidate = self.apply_candidate(block_hash);
515496
debug_assert!(
516497
!candidate.has_block(),
517498
"a chain pull root candidate should not cache a block",
518499
);
500+
let mut block_avalanche = vec![block];
519501
let mut child_hashes = candidate.children;
520502
while let Some(child_hash) = child_hashes.pop() {
521503
match self.candidate_map.entry(child_hash) {
@@ -549,14 +531,47 @@ impl CandidateForestThickets {
549531
Vacant(_) => panic!("referential integrity failure in CandidateForest"),
550532
}
551533
}
534+
block_avalanche
552535
} else {
553-
assert!(
554-
!self.candidate_map.contains_key(&block_hash),
555-
"missed chain pull root candidate {} that got committed to storage",
556-
block_hash,
557-
);
536+
match self.cache_requested_block(block_hash, block) {
537+
Ok(()) => {
538+
// The task that applies the block has won the lock before
539+
// other tasks that should apply preceding blocks.
540+
// The block is cached for later, return an empty vector.
541+
Vec::default()
542+
}
543+
Err(block) => {
544+
// The block is not part of a chain pull.
545+
// Pass it through so that it gets applied to storage
546+
// or fails to validate against the parent that should be
547+
// already stored.
548+
vec![block]
549+
}
550+
}
551+
}
552+
}
553+
554+
fn cache_requested_block(&mut self, block_hash: HeaderHash, block: Block) -> Result<(), Block> {
555+
use std::collections::hash_map::Entry::*;
556+
557+
match self.candidate_map.entry(block_hash) {
558+
Vacant(_) => Err(block),
559+
Occupied(mut entry) => {
560+
match &entry.get().data {
561+
CandidateData::Header(header) => {
562+
debug_assert!(header.hash() == block_hash);
563+
entry.insert(Candidate::from_block(block));
564+
}
565+
CandidateData::Block(block) => {
566+
debug_assert!(block.header().hash() == block_hash);
567+
}
568+
CandidateData::Applied(header) => {
569+
debug_assert!(header.hash() == block_hash);
570+
}
571+
}
572+
Ok(())
573+
}
558574
}
559-
block_avalanche
560575
}
561576

562577
// Removes the root from, then walks up the tree and

jormungandr/src/blockchain/process.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -562,7 +562,7 @@ fn process_block_announcement(
562562
.map_err(|err| Error::with_chain(err, "cannot process block announcement"))
563563
}
564564

565-
pub fn process_network_block(
565+
fn process_network_block(
566566
blockchain: Blockchain,
567567
candidate_forest: CandidateForest,
568568
block: Block,

0 commit comments

Comments
 (0)