the node pool

Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
This commit is contained in:
Cyrill Leutwiler
2025-03-26 11:58:38 +01:00
parent 34b8879b15
commit 95d2afde05
11 changed files with 304 additions and 112 deletions
+1
View File
@@ -11,6 +11,7 @@ rust-version.workspace = true
[dependencies]
anyhow = { workspace = true }
alloy = { workspace = true }
log = { workspace = true }
serde_json = { workspace = true }
revive-dt-node-interaction = { workspace = true }
+55 -25
View File
@@ -1,38 +1,68 @@
use std::sync::{
LazyLock, Mutex,
mpsc::{Receiver, Sender},
//! This crate implements concurrent handling of testing node.
use std::{
fs::read_to_string,
sync::atomic::{AtomicUsize, Ordering},
thread,
};
pub trait NodePool<T: Node> {
fn access() -> &'static LazyLock<Mutex<Vec<T>>>;
}
use anyhow::Context;
use revive_dt_config::Arguments;
use crate::Node;
//static POOL: LazyLock<Mutex<Pool<T>>> = LazyLock::new(Default::default);
pub struct Handle<T> {
node: T,
notifier: Sender<()>,
/// The node pool starts one or more [Node] which then can be accessed
/// in a round robbin fasion.
pub struct NodePool<T> {
next: AtomicUsize,
nodes: Vec<T>,
}
pub struct Pool<T> {
request: Receiver<()>,
nodes: usize,
handles: Vec<T>,
}
impl<T> Pool<T>
impl<T> NodePool<T>
where
T: Node,
T: Node + Send + 'static,
{
pub fn spawn() {}
/// Create a new Pool. This will start as many nodes as there are workers in `config`.
pub fn new(config: &Arguments) -> anyhow::Result<Self> {
let nodes = config.workers;
let genesis = read_to_string(&config.genesis_file).context(format!(
"can not read genesis file: {}",
config.genesis_file.display()
))?;
let mut handles = Vec::with_capacity(nodes);
for _ in 0..nodes {
let config = config.clone();
let genesis = genesis.clone();
handles.push(thread::spawn(move || spawn_node::<T>(&config, genesis)));
}
let mut nodes = Vec::with_capacity(nodes);
for handle in handles {
nodes.push(
handle
.join()
.map_err(|error| anyhow::anyhow!("failed to spawn node: {:?}", error))?
.map_err(|error| anyhow::anyhow!("node failed to spawn: {error}"))?,
);
}
Ok(Self {
nodes,
next: Default::default(),
})
}
/// Get a handle to the next node.
pub fn round_robbin(&self) -> &T {
let current = self.next.fetch_add(1, Ordering::SeqCst) % self.nodes.len();
self.nodes.get(current).unwrap()
}
}
// spawner: loops on a queue
pub fn get_handle<T: Node + NodePool<T>>(config: &Arguments) -> Receiver<T> {
todo!()
fn spawn_node<T: Node + Send>(args: &Arguments, genesis: String) -> anyhow::Result<T> {
let mut node = T::new(&args);
log::info!("starting node: {}", node.connection_string());
node.spawn(genesis)?;
Ok(node)
}