fetcher: Guard fetched against stale node results
- Clear active[rid] only when the result's node matches the node that started the fetch; mismatched results now report NotFound - Prevent a late completion from a disconnected peer clearing a newer fetch for the same repo started by a different node - Add test covering the stale-from mismatch path
This commit is contained in:
parent
7b910476c3
commit
4a05e52ba1
|
|
@ -203,16 +203,28 @@ impl FetcherState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Process a [`Fetched`] command, which removes the given fetch from the set of active fetches.
|
/// Process a [`Fetched`] command, which removes the given fetch from the
|
||||||
|
/// set of active fetches, but only if the active fetch was from the given
|
||||||
|
/// node.
|
||||||
|
///
|
||||||
/// Note that this is agnostic of whether the fetch succeeded or failed.
|
/// Note that this is agnostic of whether the fetch succeeded or failed.
|
||||||
///
|
///
|
||||||
/// The caller will be notified if the completed fetch did not exist in the active set.
|
/// The caller will be notified if the completed fetch did not exist in the active set.
|
||||||
///
|
///
|
||||||
/// [`Fetched`]: command::Fetched
|
/// [`Fetched`]: command::Fetched
|
||||||
pub fn fetched(&mut self, command::Fetched { from, rid }: command::Fetched) -> event::Fetched {
|
pub fn fetched(&mut self, command::Fetched { from, rid }: command::Fetched) -> event::Fetched {
|
||||||
match self.active.remove(&rid) {
|
// Only the node that started the active fetch may complete it. A result from any
|
||||||
None => event::Fetched::NotFound { from, rid },
|
// other node is stale — e.g. a late completion delivered after the peer disconnected
|
||||||
|
// and the repo was re-fetched from elsewhere. Clearing the entry on a mismatch would
|
||||||
|
// drop the wrong (newer) fetch, so we leave it and report `NotFound`.
|
||||||
|
match self.active.get(&rid) {
|
||||||
|
Some(ActiveFetch {
|
||||||
|
from: active_from, ..
|
||||||
|
}) if *active_from == from => match self.active.remove(&rid) {
|
||||||
Some(ActiveFetch { from, refs }) => event::Fetched::Completed { from, rid, refs },
|
Some(ActiveFetch { from, refs }) => event::Fetched::Completed { from, rid, refs },
|
||||||
|
None => event::Fetched::NotFound { from, rid },
|
||||||
|
},
|
||||||
|
_ => event::Fetched::NotFound { from, rid },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue