#[non_exhaustive]pub struct PullStalled {
pub after: Duration,
}Expand description
Typed sentinel for an upstream that went SILENT mid-stream — bytes were flowing, and
then no byte of progress for the stall budget (#1134). Distinct from PullTimeout,
which is a bound of OURS elapsing, and the distinction is load-bearing:
A whole-transfer deadline cannot tell “the provider is dead” from “this blob is big” or
“this link is slow”, so PullTimeout must NOT tar the provider — it fires on perfectly
healthy transfers. A stall deadline resets on every byte received, so it fires ONLY when
a provider stops delivering while we wait. That IS evidence the peer is unreachable, and
classify_pull_failure scores it as such in the local per-peer EWMA (ADR 008).
§What the bound rests on
Two things, and it is worth being precise about both, because scoring a peer on a bound that does not hold is how an honest node’s local reputation gets unfairly defamed.
The non-empty-ChunkData invariant (#1088). With empty frames banned, “a frame
arrived” and “bytes made progress” are the same statement, so a peer cannot hold the
floor open with padding. The receive loop ([UpstreamPull::next_chunk]) has no
independent progress check behind that floor: it is safe because no frame a peer can
send makes zero progress, not because it verifies that it did. The floor is
structural rather than advisory — ChunkData’s field is private, and its constructor
and decode gate both reject an empty payload — so it cannot be relaxed by forgetting
to call a validator (#1145 review).
At least one byte having already arrived. The reset is what makes a stall the peer’s
fault, so before the FIRST byte there has been no reset and the argument does not apply:
the clock is measuring the server’s time-to-first-byte, which scales with blob size
(the serve path materialises the whole bao wire via export_bao_range before it can emit
chunk #1). Both loops therefore raise PullTimeout — exonerating — when the budget
elapses at cumulative == 0, and this sentinel only once bytes have flowed (#1145
review). Without that split, a 1 GiB blob off a cold disk would score an honest server as
unreachable for the crime of being big.
Fields (Non-exhaustive)§
This struct is marked as non-exhaustive
Struct { .. } syntax; cannot be matched against without a wildcard ..; and struct update syntax will not work.after: DurationThe inactivity budget that elapsed after bytes had been flowing.
Trait Implementations§
Source§impl Debug for PullStalled
impl Debug for PullStalled
Source§impl Display for PullStalled
impl Display for PullStalled
Source§impl Error for PullStalled
impl Error for PullStalled
1.30.0 · Source§fn source(&self) -> Option<&(dyn Error + 'static)>
fn source(&self) -> Option<&(dyn Error + 'static)>
1.0.0 · Source§fn description(&self) -> &str
fn description(&self) -> &str
use the Display impl or to_string()
Auto Trait Implementations§
impl Freeze for PullStalled
impl RefUnwindSafe for PullStalled
impl Send for PullStalled
impl Sync for PullStalled
impl Unpin for PullStalled
impl UnsafeUnpin for PullStalled
impl UnwindSafe for PullStalled
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
Source§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreimpl<T> MaybeSend for Twhere
T: Send,
Source§impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> PolicyExt for Twhere
T: ?Sized,
Source§impl<T> ToStringFallible for Twhere
T: Display,
impl<T> ToStringFallible for Twhere
T: Display,
Source§fn try_to_string(&self) -> Result<String, TryReserveError>
fn try_to_string(&self) -> Result<String, TryReserveError>
ToString::to_string, but without panic on OOM.