Flesh out new scanner a bit more

Adds the task to mark blocks safe to scan, and outlines the task to report
blocks.
This commit is contained in:
Luke Parker
2024-08-20 16:24:18 -04:00
parent 8763ef23ed
commit a2717d73f0
7 changed files with 259 additions and 32 deletions

View File

@@ -1,4 +1,6 @@
use core::fmt::Debug;
use core::{fmt::Debug, time::Duration};
use tokio::sync::mpsc;
use primitives::{ReceivedOutput, Block};
@@ -50,11 +52,50 @@ pub trait ScannerFeed: Send + Sync {
) -> Result<Self::Output, Self::EphemeralError>;
}
/// A handle to immediately run an iteration of a task.
#[derive(Clone)]
pub(crate) struct RunNowHandle(mpsc::Sender<()>);
/// An instruction recipient to immediately run an iteration of a task.
pub(crate) struct RunNowRecipient(mpsc::Receiver<()>);
impl RunNowHandle {
/// Create a new run-now handle to be assigned to a task.
pub(crate) fn new() -> (Self, RunNowRecipient) {
// Uses a capacity of 1 as any call to run as soon as possible satisfies all calls to run as
// soon as possible
let (send, recv) = mpsc::channel(1);
(Self(send), RunNowRecipient(recv))
}
/// Tell the task to run now (and not whenever its next iteration on a timer is).
///
/// Panics if the task has been dropped.
pub(crate) fn run_now(&self) {
#[allow(clippy::match_same_arms)]
match self.0.try_send(()) {
Ok(()) => {}
// NOP on full, as this task will already be ran as soon as possible
Err(mpsc::error::TrySendError::Full(())) => {}
Err(mpsc::error::TrySendError::Closed(())) => {
panic!("task was unexpectedly closed when calling run_now")
}
}
}
}
#[async_trait::async_trait]
pub(crate) trait ContinuallyRan: Sized {
async fn run_instance(&mut self) -> Result<(), String>;
/// Run an iteration of the task.
///
/// If this returns `true`, all dependents of the task will immediately have a new iteration ran
/// (without waiting for whatever timer they were already on).
async fn run_iteration(&mut self) -> Result<bool, String>;
async fn continually_run(mut self) {
/// Continually run the task.
///
/// This returns a channel which can have a message set to immediately trigger a new run of an
/// iteration.
async fn continually_run(mut self, mut run_now: RunNowRecipient, dependents: Vec<RunNowHandle>) {
// The default number of seconds to sleep before running the task again
let default_sleep_before_next_task = 5;
// The current number of seconds to sleep before running the task again
@@ -67,10 +108,16 @@ pub(crate) trait ContinuallyRan: Sized {
};
loop {
match self.run_instance().await {
Ok(()) => {
match self.run_iteration().await {
Ok(run_dependents) => {
// Upon a successful (error-free) loop iteration, reset the amount of time we sleep
current_sleep_before_next_task = default_sleep_before_next_task;
if run_dependents {
for dependent in &dependents {
dependent.run_now();
}
}
}
Err(e) => {
log::debug!("{}", e);
@@ -78,9 +125,11 @@ pub(crate) trait ContinuallyRan: Sized {
}
}
// Don't run the task again for another few seconds
// This is at the start of the loop so we can continue without skipping this delay
tokio::time::sleep(core::time::Duration::from_secs(current_sleep_before_next_task)).await;
// Don't run the task again for another few seconds UNLESS told to run now
tokio::select! {
() = tokio::time::sleep(Duration::from_secs(current_sleep_before_next_task)) => {},
msg = run_now.0.recv() => assert_eq!(msg, Some(()), "run now handle was dropped"),
}
}
}
}