node: Only try to fetch from connected nodes

This commit is contained in:
Alexis Sellier 2023-01-30 11:20:33 +01:00
parent ac23f45d9b
commit be77eebc3d
No known key found for this signature in database
2 changed files with 44 additions and 21 deletions

View File

@ -394,36 +394,44 @@ where
match cmd { match cmd {
Command::Connect(id, addr) => self.reactor.connect(id, addr), Command::Connect(id, addr) => self.reactor.connect(id, addr),
Command::Fetch(id, resp) => { Command::Fetch(rid, resp) => {
if !self if !self
.tracking .tracking
.is_repo_tracked(&id) .is_repo_tracked(&rid)
.expect("Service::command: error accessing tracking configuration") .expect("Service::command: error accessing tracking configuration")
{ {
resp.send(FetchLookup::NotTracking).ok(); resp.send(FetchLookup::NotTracking).ok();
return; return;
} }
let seeds = match self.routing.get(&id) { let (connected, unconnected) = match self.routing.get(&rid) {
Ok(seeds) => seeds Ok(seeds) => seeds
.into_iter() .into_iter()
.filter(|node| *node != self.node_id()) .filter(|node| *node != self.node_id())
.collect(), .partition::<Vec<_>, _>(|node| self.sessions.is_negotiated(node)),
Err(err) => { Err(err) => {
error!(target: "service", "Error reading routing table for {id}: {err}"); error!(target: "service", "Error reading routing table for {rid}: {err}");
resp.send(FetchLookup::NotFound).ok(); resp.send(FetchLookup::NotFound).ok();
return; return;
} }
}; };
let Some(seeds) = NonEmpty::from_vec(seeds) else { debug!(
warn!(target: "service", "No seeds found to fetch from, for {}", id); target: "service",
"Found {} connected seed(s) and {} unconnected seed(s) for {}",
connected.len(), unconnected.len(), rid
);
let Some(seeds) = NonEmpty::from_vec(connected) else {
warn!(target: "service", "No connected seeds found for {}", rid);
resp.send(FetchLookup::NotFound).ok(); resp.send(FetchLookup::NotFound).ok();
// TODO: Establish connections to unconnected seeds, and retry.
// TODO: Fetch requests should be queued and re-checked to see if they can
// be fulfilled everytime a new node connects.
return; return;
}; };
debug!(target: "service", "Found {} seed(s) to fetch from, for {}", seeds.len(), id);
let (results_send, results) = chan::bounded(seeds.len()); let (results_send, results) = chan::bounded(seeds.len());
resp.send(FetchLookup::Found { resp.send(FetchLookup::Found {
@ -432,15 +440,11 @@ where
}) })
.ok(); .ok();
self.fetch_reqs.insert(id, results_send); self.fetch_reqs.insert(rid, results_send);
// TODO: Limit the number of seeds we fetch from? Randomize? // TODO: Limit the number of seeds we fetch from? Randomize?
for seed in seeds { for seed in seeds {
if let Some(session) = self.sessions.get_mut(&seed) { self.fetch(rid, &seed);
Self::fetch(id, session, &mut self.reactor);
} else {
// TODO: Establish connection?
}
} }
} }
Command::TrackRepo(id, resp) => { Command::TrackRepo(id, resp) => {
@ -480,17 +484,24 @@ where
} }
} }
pub fn fetch(rid: Id, session: &mut Session, reactor: &mut Reactor) { pub fn fetch(&mut self, rid: Id, from: &NodeId) {
let Some(session) = self.sessions.get_mut(from) else {
error!(target: "service", "Session {from} does not exist; cannot initiate fetch");
return;
};
debug_assert!(session.is_negotiated());
let seed = session.id; let seed = session.id;
if let Some(fetch) = session.fetch(rid) { if let Some(fetch) = session.fetch(rid) {
debug!(target: "service", "Fetch initiated for {rid} with {seed}.."); debug!(target: "service", "Fetch initiated for {rid} with {seed}..");
reactor.write(session.id, fetch); self.reactor.write(session.id, fetch);
} else { } else {
// TODO: If we can't fetch, it's because we're already fetching from // TODO: If we can't fetch, it's because we're already fetching from
// this peer. So we need to queue the request, or find another peer. // this peer. So we need to queue the request, or find another peer.
error!(target: "service", error!(
target: "service",
"Unable to fetch {rid} from peer {seed} that is already being fetched from" "Unable to fetch {rid} from peer {seed} that is already being fetched from"
); );
} }
@ -747,10 +758,7 @@ where
// Refs are only supposed to be relayed by peers who are tracking // Refs are only supposed to be relayed by peers who are tracking
// the resource. Therefore, it's safe to fetch from the remote // the resource. Therefore, it's safe to fetch from the remote
// peer, even though it isn't the announcer. // peer, even though it isn't the announcer.
let Some(session) = self.sessions.get_mut(relayer) else { self.fetch(message.id, relayer);
panic!(); // TODO
};
Self::fetch(message.id, session, &mut self.reactor);
return Ok(true); return Ok(true);
} else { } else {
@ -1322,6 +1330,11 @@ impl Sessions {
pub fn negotiated_mut(&mut self) -> impl Iterator<Item = (&NodeId, &mut Session)> { pub fn negotiated_mut(&mut self) -> impl Iterator<Item = (&NodeId, &mut Session)> {
self.0.iter_mut().filter(move |(_, p)| p.is_connected()) self.0.iter_mut().filter(move |(_, p)| p.is_connected())
} }
/// Return whether this node has a fully established session.
pub fn is_negotiated(&self, id: &NodeId) -> bool {
self.0.get(id).map(|s| s.is_connected()).unwrap_or(false)
}
} }
impl Deref for Sessions { impl Deref for Sessions {

View File

@ -136,6 +136,16 @@ impl Session {
matches!(self.state, State::Connected { .. }) matches!(self.state, State::Connected { .. })
} }
pub fn is_negotiated(&self) -> bool {
matches!(
self.state,
State::Connected {
initialized: true,
..
}
)
}
pub fn attempts(&self) -> usize { pub fn attempts(&self) -> usize {
self.attempts self.attempts
} }