Rewrite the BasiQueue using channels (#1327)

* use channels to implement basic import queue

* async justification import

* better conditional for is_done in tests

* reword the test for presence of link

* fix conditional

* trace instead of panic when no link present

* reword expectations when sending to importers

* fix

* debug justification import error

* update expectations

* use NumberFor

* nits

* add general description

* move error handling into closure
This commit is contained in:
Gregory Terzian
2019-02-17 17:13:14 +08:00
committed by Gav Wood
parent 797de27d2b
commit 72bb8ef4c5
16 changed files with 614 additions and 575 deletions
+37 -23
View File
@@ -15,7 +15,6 @@
// along with Substrate. If not, see <http://www.gnu.org/licenses/>.
use std::collections::{HashMap, HashSet, VecDeque};
use std::sync::Arc;
use std::time::{Duration, Instant};
use log::{trace, debug};
use crate::protocol::Context;
@@ -30,6 +29,7 @@ use runtime_primitives::traits::{Block as BlockT, Header as HeaderT, As, NumberF
use runtime_primitives::generic::BlockId;
use crate::message::{self, generic::Message as GenericMessage};
use crate::config::Roles;
use std::sync::atomic::{AtomicBool, Ordering};
// Maximum blocks to request in a single packet.
const MAX_BLOCKS_TO_REQUEST: usize = 128;
@@ -197,14 +197,25 @@ impl<B: BlockT> PendingJustifications<B> {
}
}
/// Process the import of a justification.
/// Queues a retry in case the import failed.
fn justification_import_result(&mut self, hash: B::Hash, number: NumberFor<B>, success: bool) {
let request = (hash, number);
if success {
self.justifications.remove(&request);
self.previous_requests.remove(&request);
return;
}
self.pending_requests.push_front(request);
}
/// Processes the response for the request previously sent to the given
/// peer. Queues a retry in case the import fails or the given justification
/// peer. Queues a retry in case the given justification
/// was `None`.
fn on_response(
&mut self,
who: NodeIndex,
justification: Option<Justification>,
protocol: &mut Context<B>,
import_queue: &ImportQueue<B>,
) {
// we assume that the request maps to the given response, this is
@@ -212,23 +223,13 @@ impl<B: BlockT> PendingJustifications<B> {
// messages to chain sync.
if let Some(request) = self.peer_requests.remove(&who) {
if let Some(justification) = justification {
if import_queue.import_justification(request.0, request.1, justification) {
self.justifications.remove(&request);
self.previous_requests.remove(&request);
return;
} else {
protocol.report_peer(
who,
Severity::Bad(format!("Invalid justification provided for #{}", request.0)),
);
}
} else {
self.previous_requests
.entry(request)
.or_insert(Vec::new())
.push((who, Instant::now()));
import_queue.import_justification(who.clone(), request.0, request.1, justification);
return
}
self.previous_requests
.entry(request)
.or_insert(Vec::new())
.push((who, Instant::now()));
self.pending_requests.push_front(request);
}
}
@@ -251,8 +252,9 @@ pub struct ChainSync<B: BlockT> {
best_queued_number: NumberFor<B>,
best_queued_hash: B::Hash,
required_block_attributes: message::BlockAttributes,
import_queue: Arc<ImportQueue<B>>,
justifications: PendingJustifications<B>,
import_queue: Box<ImportQueue<B>>,
is_stopping: AtomicBool,
}
/// Reported sync state.
@@ -293,7 +295,7 @@ impl<B: BlockT> Status<B> {
impl<B: BlockT> ChainSync<B> {
/// Create a new instance.
pub(crate) fn new(role: Roles, info: &ClientInfo<B>, import_queue: Arc<ImportQueue<B>>) -> Self {
pub(crate) fn new(role: Roles, info: &ClientInfo<B>, import_queue: Box<ImportQueue<B>>) -> Self {
let mut required_block_attributes = message::BlockAttributes::HEADER | message::BlockAttributes::JUSTIFICATION;
if role.intersects(Roles::FULL | Roles::AUTHORITY) {
required_block_attributes |= message::BlockAttributes::BODY;
@@ -308,6 +310,7 @@ impl<B: BlockT> ChainSync<B> {
justifications: PendingJustifications::new(),
required_block_attributes,
import_queue,
is_stopping: Default::default(),
}
}
@@ -316,7 +319,7 @@ impl<B: BlockT> ChainSync<B> {
}
/// Returns import queue reference.
pub(crate) fn import_queue(&self) -> Arc<ImportQueue<B>> {
pub(crate) fn import_queue(&self) -> Box<ImportQueue<B>> {
self.import_queue.clone()
}
@@ -536,7 +539,6 @@ impl<B: BlockT> ChainSync<B> {
self.justifications.on_response(
who,
response.justification,
protocol,
&*self.import_queue,
);
},
@@ -558,6 +560,9 @@ impl<B: BlockT> ChainSync<B> {
/// Maintain the sync process (download new blocks, fetch justifications).
pub fn maintain_sync(&mut self, protocol: &mut Context<B>) {
if self.is_stopping.load(Ordering::SeqCst) {
return
}
let peers: Vec<NodeIndex> = self.peers.keys().map(|p| *p).collect();
for peer in peers {
self.download_new(protocol, peer);
@@ -578,6 +583,15 @@ impl<B: BlockT> ChainSync<B> {
self.justifications.dispatch(&mut self.peers, protocol);
}
pub fn justification_import_result(&mut self, hash: B::Hash, number: NumberFor<B>, success: bool) {
self.justifications.justification_import_result(hash, number, success);
}
pub fn stop(&self) {
self.is_stopping.store(true, Ordering::SeqCst);
self.import_queue.stop();
}
/// Notify about successful import of the given block.
pub fn block_imported(&mut self, hash: &B::Hash, number: NumberFor<B>) {
trace!(target: "sync", "Block imported successfully {} ({})", number, hash);