node: dynamic fetch timeout via channels

Instead of using `DEFAULT_CHANNEL_TIMEOUT`, the timeout is dynamically set
per-fetch by the caller.

This passed via the `Io::Fetch` variant -- when initiating a fetch, and the
`Control::Open` variant when responding to a fetch.

Signed-off-by: Fintan Halpenny <fintan.halpenny@gmail.com>
X-Clacks-Overhead: GNU Terry Pratchett
This commit is contained in:
Fintan Halpenny 2024-04-23 14:43:49 +01:00
parent cadd996a76
commit fd4c4cd0af
No known key found for this signature in database
GPG Key ID: C93C17467280C75B
3 changed files with 15 additions and 18 deletions

View File

@ -280,6 +280,8 @@ struct QueuedFetch {
from: NodeId, from: NodeId,
/// Refs being fetched. /// Refs being fetched.
refs_at: Vec<RefsAt>, refs_at: Vec<RefsAt>,
/// The timeout given for the fetch request.
timeout: time::Duration,
/// Result channel. /// Result channel.
channel: Option<chan::Sender<FetchResult>>, channel: Option<chan::Sender<FetchResult>>,
} }
@ -948,6 +950,7 @@ where
rid, rid,
refs_at, refs_at,
from, from,
timeout,
channel, channel,
}; };
if self.queue.contains(&fetch) { if self.queue.contains(&fetch) {
@ -964,6 +967,7 @@ where
rid, rid,
refs_at, refs_at,
from, from,
timeout,
channel, channel,
}); });
} }
@ -1128,6 +1132,7 @@ where
rid, rid,
from, from,
refs_at, refs_at,
timeout,
channel, channel,
}) = self.queue.pop_front() }) = self.queue.pop_front()
{ {
@ -1140,12 +1145,12 @@ where
.expect("Service::dequeue_fetch: error accessing repo seeding configuration"); .expect("Service::dequeue_fetch: error accessing repo seeding configuration");
// Keep dequeueing if there was nothing to fetch, otherwise break. // Keep dequeueing if there was nothing to fetch, otherwise break.
if self.fetch_refs_at(rid, from, refs, repo_entry.scope, FETCH_TIMEOUT, channel) { if self.fetch_refs_at(rid, from, refs, repo_entry.scope, timeout, channel) {
break; break;
} }
} else { } else {
// If no refs are specified, always do a full fetch. // If no refs are specified, always do a full fetch.
self.fetch(rid, from, FETCH_TIMEOUT, channel); self.fetch(rid, from, timeout, channel);
break; break;
} }
} }

View File

@ -29,6 +29,7 @@ use crate::crypto::Signer;
use crate::prelude::Deserializer; use crate::prelude::Deserializer;
use crate::service; use crate::service;
use crate::service::io::Io; use crate::service::io::Io;
use crate::service::FETCH_TIMEOUT;
use crate::service::{session, DisconnectReason, Service}; use crate::service::{session, DisconnectReason, Service};
use crate::wire::frame; use crate::wire::frame;
use crate::wire::frame::{Frame, FrameData, StreamId}; use crate::wire::frame::{Frame, FrameData, StreamId};
@ -43,10 +44,6 @@ pub const NOISE_XK: HandshakePattern = HandshakePattern {
responder: cyphernet::encrypt::noise::OneWayPattern::Known, responder: cyphernet::encrypt::noise::OneWayPattern::Known,
}; };
/// Default time to wait to receive something from a worker channel. Applies to
/// workers waiting for data from remotes as well.
pub const DEFAULT_CHANNEL_TIMEOUT: time::Duration = time::Duration::from_secs(30);
/// Default time to wait until a network connection is considered inactive. /// Default time to wait until a network connection is considered inactive.
pub const DEFAULT_CONNECTION_TIMEOUT: time::Duration = time::Duration::from_secs(6); pub const DEFAULT_CONNECTION_TIMEOUT: time::Duration = time::Duration::from_secs(6);
@ -131,22 +128,22 @@ impl Streams {
} }
/// Open a new stream. /// Open a new stream.
fn open(&mut self) -> (StreamId, worker::Channels) { fn open(&mut self, timeout: time::Duration) -> (StreamId, worker::Channels) {
self.seq += 1; self.seq += 1;
let id = StreamId::git(self.link) let id = StreamId::git(self.link)
.nth(self.seq) .nth(self.seq)
.expect("Streams::open: too many streams"); .expect("Streams::open: too many streams");
let channels = self let channels = self
.register(id) .register(id, timeout)
.expect("Streams::open: stream was already open"); .expect("Streams::open: stream was already open");
(id, channels) (id, channels)
} }
/// Register an open stream. /// Register an open stream.
fn register(&mut self, stream: StreamId) -> Option<worker::Channels> { fn register(&mut self, stream: StreamId, timeout: time::Duration) -> Option<worker::Channels> {
let (wire, worker) = worker::Channels::pair(DEFAULT_CHANNEL_TIMEOUT) let (wire, worker) = worker::Channels::pair(timeout)
.expect("Streams::register: fatal: unable to create channels"); .expect("Streams::register: fatal: unable to create channels");
match self.streams.entry(stream) { match self.streams.entry(stream) {
@ -718,7 +715,7 @@ where
})) => { })) => {
log::debug!(target: "wire", "Received `open` command for stream {stream} from {nid}"); log::debug!(target: "wire", "Received `open` command for stream {stream} from {nid}");
let Some(channels) = streams.register(stream) else { let Some(channels) = streams.register(stream, FETCH_TIMEOUT) else {
log::warn!(target: "wire", "Peer attempted to open already-open stream stream {stream}"); log::warn!(target: "wire", "Peer attempted to open already-open stream stream {stream}");
continue; continue;
}; };
@ -1017,7 +1014,7 @@ where
log::error!(target: "wire", "Peer {remote} is not connected: dropping fetch"); log::error!(target: "wire", "Peer {remote} is not connected: dropping fetch");
continue; continue;
}; };
let (stream, channels) = streams.open(); let (stream, channels) = streams.open(timeout);
log::debug!(target: "wire", "Opened new stream with id {stream} for {rid} and remote {remote}"); log::debug!(target: "wire", "Opened new stream with id {stream} for {rid} and remote {remote}");
@ -1027,7 +1024,6 @@ where
rid, rid,
remote, remote,
refs_at, refs_at,
timeout,
}, },
stream, stream,
channels, channels,

View File

@ -5,8 +5,8 @@ mod upload_pack;
pub mod fetch; pub mod fetch;
pub mod garbage; pub mod garbage;
use std::io;
use std::path::PathBuf; use std::path::PathBuf;
use std::{io, time};
use crossbeam_channel as chan; use crossbeam_channel as chan;
@ -107,8 +107,6 @@ pub enum FetchRequest {
remote: NodeId, remote: NodeId,
/// If this fetch is for a particular set of `rad/sigrefs`. /// If this fetch is for a particular set of `rad/sigrefs`.
refs_at: Option<Vec<RefsAt>>, refs_at: Option<Vec<RefsAt>>,
/// Fetch timeout.
timeout: time::Duration,
}, },
/// Server is responding to a fetch request by uploading the /// Server is responding to a fetch request by uploading the
/// specified `refspecs` sent by the client. /// specified `refspecs` sent by the client.
@ -230,8 +228,6 @@ impl Worker {
rid, rid,
remote, remote,
refs_at, refs_at,
// TODO: nowhere to use this currently
timeout: _timeout,
} => { } => {
log::debug!(target: "worker", "Worker processing outgoing fetch for {rid}"); log::debug!(target: "worker", "Worker processing outgoing fetch for {rid}");
let result = self.fetch(rid, remote, refs_at, channels, notifs); let result = self.fetch(rid, remote, refs_at, channels, notifs);