node: Implement simple worker thread pool

This commit is contained in:
Dr. Maxim Orlovsky 2023-01-04 23:53:56 +01:00 committed by Alexis Sellier
parent a7b1c19746
commit 947c89a398
No known key found for this signature in database
2 changed files with 75 additions and 25 deletions

View File

@ -8,14 +8,13 @@ use reactor::poller::popol;
use reactor::Reactor;
use radicle::profile;
use radicle::storage::WriteStorage;
use radicle_node::client::handle::Handle;
use radicle_node::client::{ADDRESS_DB_FILE, NODE_DIR, ROUTING_DB_FILE, TRACKING_DB_FILE};
use radicle_node::crypto::ssh::keystore::MemorySigner;
use radicle_node::prelude::{Address, NodeId};
use radicle_node::service::{routing, tracking, FetchResult};
use radicle_node::service::{routing, tracking};
use radicle_node::wire::Transport;
use radicle_node::worker::{WorkerReq, WorkerResp};
use radicle_node::worker::{WorkerPool, WorkerReq};
use radicle_node::{address, control, logger, service};
#[derive(Debug)]
@ -126,27 +125,7 @@ fn main() -> anyhow::Result<()> {
);
let (worker_send, worker_recv) = crossbeam_channel::unbounded::<WorkerReq<MemorySigner>>();
let workers = thread::spawn(move || {
while let Ok(WorkerReq {
fetch,
session,
channel,
..
}) = worker_recv.recv()
{
let result = match worker_storage.repository(fetch.repo) {
Ok(_) => todo!(),
Err(err) => FetchResult::Error {
from: fetch.remote,
error: err.into(),
},
};
if channel.send(WorkerResp { result, session }).is_err() {
log::error!("Unable to report fetch result: worker channel disconnected");
}
}
});
let pool = WorkerPool::with(10, worker_storage, worker_recv);
let wire = Transport::new(service, worker_send, negotiator.clone(), proxy_addr, clock);
let reactor =
Reactor::new(wire, popol::Poller::new()).expect("unable to instantiate P2P reactor");
@ -162,9 +141,9 @@ fn main() -> anyhow::Result<()> {
let handle = Handle::from(controller);
let control = thread::spawn(move || control::listen(node, handle));
pool.join().unwrap();
control.join().unwrap()?;
reactor.join().unwrap();
workers.join().unwrap();
Ok(())
}

View File

@ -1,7 +1,11 @@
use crossbeam_channel as chan;
use netservices::noise::NoiseXk;
use std::thread;
use std::thread::JoinHandle;
use radicle::crypto::Negotiator;
use radicle::storage::WriteStorage;
use radicle::Storage;
use crate::service::reactor::Fetch;
use crate::service::FetchResult;
@ -19,3 +23,70 @@ pub struct WorkerResp<G: Negotiator> {
pub result: FetchResult,
pub session: NoiseXk<G>,
}
pub struct Worker<G: Negotiator> {
storage: Storage,
tasks: chan::Receiver<WorkerReq<G>>,
}
impl<G: Negotiator> Worker<G> {
pub fn run(self) -> Result<(), chan::RecvError> {
loop {
let task = self.tasks.recv()?;
self.process(task);
}
}
pub fn process(&self, task: WorkerReq<G>) {
let WorkerReq {
fetch,
session,
// TODO: Implement logic.
drain: _drain,
channel,
} = task;
let result = match self.storage.repository(fetch.repo) {
Ok(_) => todo!(),
Err(err) => FetchResult::Error {
from: fetch.remote,
error: err.into(),
},
};
if channel.send(WorkerResp { result, session }).is_err() {
log::error!("Unable to report fetch result: worker channel disconnected");
}
}
}
pub struct WorkerPool {
pool: Vec<JoinHandle<Result<(), chan::RecvError>>>,
}
impl WorkerPool {
pub fn with<G: Negotiator + 'static>(
capacity: usize,
storage: Storage,
tasks: chan::Receiver<WorkerReq<G>>,
) -> Self {
let mut pool = Vec::with_capacity(capacity);
for _ in 0..capacity {
let runtime = Worker {
tasks: tasks.clone(),
storage: storage.clone(),
};
let thread = thread::spawn(|| runtime.run());
pool.push(thread);
}
Self { pool }
}
pub fn join(self) -> thread::Result<()> {
for worker in self.pool {
let result = worker.join()?;
if let Err(err) = result {
log::error!(target: "pool", "Worker failed: {err}");
}
}
Ok(())
}
}