pub struct PacedWriter<S> {
inner: S,
window: WindowController,
clock: DeliveryClock,
supply: SurbSupply,
deadline: Duration,
park: Option<Pin<Box<dyn Future<Output = ()> + Send>>>,
stalled_parks: u32,
persist_after: u32,
sent_total: u64,
refreshes: u64,
}Expand description
Wraps a Session socket, admitting writes only while the [WindowController] has room against the
honest delivery clock and the SURB ceiling. Reads are delegated untouched (never gated), so the
duplex socket cannot deadlock; the window always keeps at least min_window_size admissible.
S is Unpin (the boxed Session socket is), so this needs no pin projection.
Fields§
§inner: S§window: WindowController§clock: DeliveryClock§supply: SurbSupply§deadline: DurationKeep-progress deadline: how long to park when the window is momentarily full before
re-checking, and the persist-probe interval (see stalled_parks).
park: Option<Pin<Box<dyn Future<Output = ()> + Send>>>Pending park timer, recreated per park.
stalled_parks: u32Consecutive keep-progress parks that saw no honest delivery and admitted no bytes.
Reset to 0 on any admission or any delivery. When it reaches persist_after (> 0), the
persist probe fires (see Self::admissible).
persist_after: u32Persist-probe threshold (consecutive no-progress parks). 0 disables the probe — the default
clean behaviour; a robust profile sets it (~8). Sourced from FlowControlConfig.
sent_total: u64Cumulative bytes admitted (diagnostics).
refreshes: u64refresh_window call counter, for throttling the diagnostic trace.
Implementations§
Source§impl<S> PacedWriter<S>
impl<S> PacedWriter<S>
Sourcepub fn new(
inner: S,
cfg: FlowControlConfig,
clock: DeliveryClock,
supply: SurbSupply,
) -> Self
pub fn new( inner: S, cfg: FlowControlConfig, clock: DeliveryClock, supply: SurbSupply, ) -> Self
Assembles a paced writer. clock is the honest delivery clock (fed by the reliable ack tap
or return bytes); supply is the SURB ceiling; cfg seeds the window.
Sourcefn refresh_window(&mut self)
fn refresh_window(&mut self)
Folds the latest honest delivery into the window. cwnd moves only on the honest delivery
clock (up on ack, down on loss); SURB supply never touches cwnd — so a transient
buffer_level dip cannot destroy the learned window (it can only clamp the effective window
down via the ceiling, in Self::admissible).
Sourcefn admissible(&self) -> usize
fn admissible(&self) -> usize
Bytes admissible right now, against the live SURB ceiling.
Normally this is min(cwnd, surb_ceiling) − inflight: the AIMD window bounds the send rate to
the drain rate, and the SURB ceiling clamps it down when supply is low (never up — invariant 2).
Persist probe (opt-in, anti-deadlock). At end-of-stream a HOPR session has no half-close,
so the final frames may be acked slowly (or their retransmissions must exhaust before their
bytes retire from inflight). Meanwhile inflight sits at cwnd, so the normal formula
admits 0 and the writer would park forever — the tail deadlock the 5-sample measurement
showed. When enabled (persist_after > 0), after that many consecutive no-progress parks we
admit a bounded min_window_size beyond cwnd but still capped by the SURB ceiling. This is the
classic TCP persist-timer escape, and it is invariant-safe: it never spends past the SURB
ceiling (anti-grief intact), and a peer withholding acks can extract at most min_window_size per
persist_after × deadline — it can only ever make us slower, never faster or over-spending.
persist_after == 0 (the default) disables it entirely: the verified clean behaviour.
Trait Implementations§
Source§impl<S: AsyncRead + Unpin> AsyncRead for PacedWriter<S>
impl<S: AsyncRead + Unpin> AsyncRead for PacedWriter<S>
Source§impl<S: AsyncWrite + Unpin> AsyncWrite for PacedWriter<S>
impl<S: AsyncWrite + Unpin> AsyncWrite for PacedWriter<S>
Source§fn poll_write(
self: Pin<&mut Self>,
cx: &mut Context<'_>,
buf: &[u8],
) -> Poll<Result<usize>>
fn poll_write( self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8], ) -> Poll<Result<usize>>
buf into the object. Read moreSource§fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<()>>
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<()>>
Auto Trait Implementations§
impl<S> !RefUnwindSafe for PacedWriter<S>
impl<S> !Sync for PacedWriter<S>
impl<S> !UnwindSafe for PacedWriter<S>
impl<S> Freeze for PacedWriter<S>where
S: Freeze,
impl<S> Send for PacedWriter<S>where
S: Send,
impl<S> Unpin for PacedWriter<S>where
S: Unpin,
impl<S> UnsafeUnpin for PacedWriter<S>where
S: UnsafeUnpin,
Blanket Implementations§
§impl<R> AsyncReadExt for Rwhere
R: AsyncRead + ?Sized,
impl<R> AsyncReadExt for Rwhere
R: AsyncRead + ?Sized,
§fn chain<R>(self, next: R) -> Chain<Self, R>where
Self: Sized,
R: AsyncRead,
fn chain<R>(self, next: R) -> Chain<Self, R>where
Self: Sized,
R: AsyncRead,
§fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Read<'a, Self>where
Self: Unpin,
fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> Read<'a, Self>where
Self: Unpin,
buf in asynchronous
manner, returning a future type. Read more§fn read_vectored<'a>(
&'a mut self,
bufs: &'a mut [IoSliceMut<'a>],
) -> ReadVectored<'a, Self>where
Self: Unpin,
fn read_vectored<'a>(
&'a mut self,
bufs: &'a mut [IoSliceMut<'a>],
) -> ReadVectored<'a, Self>where
Self: Unpin,
AsyncRead into bufs using vectored
IO operations. Read more§fn read_exact<'a>(&'a mut self, buf: &'a mut [u8]) -> ReadExact<'a, Self>where
Self: Unpin,
fn read_exact<'a>(&'a mut self, buf: &'a mut [u8]) -> ReadExact<'a, Self>where
Self: Unpin,
buf,
returning an error if end of file (EOF) is hit sooner. Read more§fn read_to_end<'a>(&'a mut self, buf: &'a mut Vec<u8>) -> ReadToEnd<'a, Self>where
Self: Unpin,
fn read_to_end<'a>(&'a mut self, buf: &'a mut Vec<u8>) -> ReadToEnd<'a, Self>where
Self: Unpin,
AsyncRead. Read more§fn read_to_string<'a>(
&'a mut self,
buf: &'a mut String,
) -> ReadToString<'a, Self>where
Self: Unpin,
fn read_to_string<'a>(
&'a mut self,
buf: &'a mut String,
) -> ReadToString<'a, Self>where
Self: Unpin,
AsyncRead. Read more§impl<R> AsyncReadExt for Rwhere
R: AsyncRead + ?Sized,
impl<R> AsyncReadExt for Rwhere
R: AsyncRead + ?Sized,
§fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> ReadFuture<'a, Self>where
Self: Unpin,
fn read<'a>(&'a mut self, buf: &'a mut [u8]) -> ReadFuture<'a, Self>where
Self: Unpin,
§fn read_vectored<'a>(
&'a mut self,
bufs: &'a mut [IoSliceMut<'a>],
) -> ReadVectoredFuture<'a, Self>where
Self: Unpin,
fn read_vectored<'a>(
&'a mut self,
bufs: &'a mut [IoSliceMut<'a>],
) -> ReadVectoredFuture<'a, Self>where
Self: Unpin,
§fn read_to_end<'a>(
&'a mut self,
buf: &'a mut Vec<u8>,
) -> ReadToEndFuture<'a, Self>where
Self: Unpin,
fn read_to_end<'a>(
&'a mut self,
buf: &'a mut Vec<u8>,
) -> ReadToEndFuture<'a, Self>where
Self: Unpin,
§fn read_to_string<'a>(
&'a mut self,
buf: &'a mut String,
) -> ReadToStringFuture<'a, Self>where
Self: Unpin,
fn read_to_string<'a>(
&'a mut self,
buf: &'a mut String,
) -> ReadToStringFuture<'a, Self>where
Self: Unpin,
§fn read_exact<'a>(&'a mut self, buf: &'a mut [u8]) -> ReadExactFuture<'a, Self>where
Self: Unpin,
fn read_exact<'a>(&'a mut self, buf: &'a mut [u8]) -> ReadExactFuture<'a, Self>where
Self: Unpin,
buf. Read more§fn take(self, limit: u64) -> Take<Self>where
Self: Sized,
fn take(self, limit: u64) -> Take<Self>where
Self: Sized,
limit bytes from it. Read more§impl<W> AsyncWriteExt for Wwhere
W: AsyncWrite + ?Sized,
impl<W> AsyncWriteExt for Wwhere
W: AsyncWrite + ?Sized,
§fn flush(&mut self) -> Flush<'_, Self>where
Self: Unpin,
fn flush(&mut self) -> Flush<'_, Self>where
Self: Unpin,
AsyncWrite. Read more§fn close(&mut self) -> Close<'_, Self>where
Self: Unpin,
fn close(&mut self) -> Close<'_, Self>where
Self: Unpin,
AsyncWrite.§fn write<'a>(&'a mut self, buf: &'a [u8]) -> Write<'a, Self>where
Self: Unpin,
fn write<'a>(&'a mut self, buf: &'a [u8]) -> Write<'a, Self>where
Self: Unpin,
buf into the object. Read more§fn write_vectored<'a>(
&'a mut self,
bufs: &'a [IoSlice<'a>],
) -> WriteVectored<'a, Self>where
Self: Unpin,
fn write_vectored<'a>(
&'a mut self,
bufs: &'a [IoSlice<'a>],
) -> WriteVectored<'a, Self>where
Self: Unpin,
bufs into the object using vectored
IO operations. Read more§impl<W> AsyncWriteExt for Wwhere
W: AsyncWrite + ?Sized,
impl<W> AsyncWriteExt for Wwhere
W: AsyncWrite + ?Sized,
§fn write<'a>(&'a mut self, buf: &'a [u8]) -> WriteFuture<'a, Self>where
Self: Unpin,
fn write<'a>(&'a mut self, buf: &'a [u8]) -> WriteFuture<'a, Self>where
Self: Unpin,
§fn write_vectored<'a>(
&'a mut self,
bufs: &'a [IoSlice<'a>],
) -> WriteVectoredFuture<'a, Self>where
Self: Unpin,
fn write_vectored<'a>(
&'a mut self,
bufs: &'a [IoSlice<'a>],
) -> WriteVectoredFuture<'a, Self>where
Self: Unpin,
§fn write_all<'a>(&'a mut self, buf: &'a [u8]) -> WriteAllFuture<'a, Self>where
Self: Unpin,
fn write_all<'a>(&'a mut self, buf: &'a [u8]) -> WriteAllFuture<'a, Self>where
Self: Unpin,
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
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
§impl<T> Conv for T
impl<T> Conv for T
§impl<T> FmtForward for T
impl<T> FmtForward for T
§fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
fn fmt_binary(self) -> FmtBinary<Self>where
Self: Binary,
self to use its Binary implementation when Debug-formatted.§fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
fn fmt_display(self) -> FmtDisplay<Self>where
Self: Display,
self to use its Display implementation when
Debug-formatted.§fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
fn fmt_lower_exp(self) -> FmtLowerExp<Self>where
Self: LowerExp,
self to use its LowerExp implementation when
Debug-formatted.§fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
fn fmt_lower_hex(self) -> FmtLowerHex<Self>where
Self: LowerHex,
self to use its LowerHex implementation when
Debug-formatted.§fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
fn fmt_octal(self) -> FmtOctal<Self>where
Self: Octal,
self to use its Octal implementation when Debug-formatted.§fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
fn fmt_pointer(self) -> FmtPointer<Self>where
Self: Pointer,
self to use its Pointer implementation when
Debug-formatted.§fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
fn fmt_upper_exp(self) -> FmtUpperExp<Self>where
Self: UpperExp,
self to use its UpperExp implementation when
Debug-formatted.§fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
fn fmt_upper_hex(self) -> FmtUpperHex<Self>where
Self: UpperHex,
self to use its UpperHex implementation when
Debug-formatted.§fn fmt_list(self) -> FmtList<Self>where
&'a Self: for<'a> IntoIterator,
fn fmt_list(self) -> FmtList<Self>where
&'a Self: for<'a> IntoIterator,
§impl<T> FutureExt for T
impl<T> FutureExt for T
§fn with_context(self, otel_cx: Context) -> WithContext<Self>
fn with_context(self, otel_cx: Context) -> WithContext<Self>
§fn with_current_context(self) -> WithContext<Self>
fn with_current_context(self) -> WithContext<Self>
§impl<T> FuturesAsyncReadCompatExt for Twhere
T: AsyncRead,
impl<T> FuturesAsyncReadCompatExt for Twhere
T: AsyncRead,
§impl<T> FuturesAsyncWriteCompatExt for Twhere
T: AsyncWrite,
impl<T> FuturesAsyncWriteCompatExt for Twhere
T: AsyncWrite,
§fn compat_write(self) -> Compat<Self>where
Self: Sized,
fn compat_write(self) -> Compat<Self>where
Self: Sized,
self with a compatibility layer that implements
tokio::io::AsyncWrite.§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§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 more§impl<T> Pipe for Twhere
T: ?Sized,
impl<T> Pipe for Twhere
T: ?Sized,
§fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
fn pipe<R>(self, func: impl FnOnce(Self) -> R) -> Rwhere
Self: Sized,
§fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref<'a, R>(&'a self, func: impl FnOnce(&'a Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read more§fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
fn pipe_ref_mut<'a, R>(&'a mut self, func: impl FnOnce(&'a mut Self) -> R) -> Rwhere
R: 'a,
self and passes that borrow into the pipe function. Read more§fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
fn pipe_borrow<'a, B, R>(&'a self, func: impl FnOnce(&'a B) -> R) -> R
§fn pipe_borrow_mut<'a, B, R>(
&'a mut self,
func: impl FnOnce(&'a mut B) -> R,
) -> R
fn pipe_borrow_mut<'a, B, R>( &'a mut self, func: impl FnOnce(&'a mut B) -> R, ) -> R
§fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
fn pipe_as_ref<'a, U, R>(&'a self, func: impl FnOnce(&'a U) -> R) -> R
self, then passes self.as_ref() into the pipe function.§fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
fn pipe_as_mut<'a, U, R>(&'a mut self, func: impl FnOnce(&'a mut U) -> R) -> R
self, then passes self.as_mut() into the pipe
function.§fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
fn pipe_deref<'a, T, R>(&'a self, func: impl FnOnce(&'a T) -> R) -> R
self, then passes self.deref() into the pipe function.§impl<T> Pointable for T
impl<T> Pointable for T
§impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> Read<Exclusive, BecauseExclusive> for Twhere
T: ?Sized,
§impl<T> SessionSocketExt for T
impl<T> SessionSocketExt for T
§fn reliable_session<const MTU: usize>(
self,
ack: AcknowledgementState<MTU>,
cfg: SessionSocketConfig,
) -> Result<SessionSocket<MTU, AcknowledgementState<MTU>>, SessionError>where
Self: Sized + 'static,
fn reliable_session<const MTU: usize>(
self,
ack: AcknowledgementState<MTU>,
cfg: SessionSocketConfig,
) -> Result<SessionSocket<MTU, AcknowledgementState<MTU>>, SessionError>where
Self: Sized + 'static,
§fn unreliable_session<const MTU: usize>(
self,
id: &str,
cfg: SessionSocketConfig,
) -> Result<SessionSocket<MTU, Stateless<MTU>>, SessionError>where
Self: Sized + 'static,
fn unreliable_session<const MTU: usize>(
self,
id: &str,
cfg: SessionSocketConfig,
) -> Result<SessionSocket<MTU, Stateless<MTU>>, SessionError>where
Self: Sized + 'static,
§impl<T> Tap for T
impl<T> Tap for T
§fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow<B>(self, func: impl FnOnce(&B)) -> Self
Borrow<B> of a value. Read more§fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut<B>(self, func: impl FnOnce(&mut B)) -> Self
BorrowMut<B> of a value. Read more§fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref<R>(self, func: impl FnOnce(&R)) -> Self
AsRef<R> view of a value. Read more§fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut<R>(self, func: impl FnOnce(&mut R)) -> Self
AsMut<R> view of a value. Read more§fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref<T>(self, func: impl FnOnce(&T)) -> Self
Deref::Target of a value. Read more§fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
fn tap_deref_mut<T>(self, func: impl FnOnce(&mut T)) -> Self
Deref::Target of a value. Read more§fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
fn tap_dbg(self, func: impl FnOnce(&Self)) -> Self
.tap() only in debug builds, and is erased in release builds.§fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
fn tap_mut_dbg(self, func: impl FnOnce(&mut Self)) -> Self
.tap_mut() only in debug builds, and is erased in release
builds.§fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
fn tap_borrow_dbg<B>(self, func: impl FnOnce(&B)) -> Self
.tap_borrow() only in debug builds, and is erased in release
builds.§fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
fn tap_borrow_mut_dbg<B>(self, func: impl FnOnce(&mut B)) -> Self
.tap_borrow_mut() only in debug builds, and is erased in release
builds.§fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
fn tap_ref_dbg<R>(self, func: impl FnOnce(&R)) -> Self
.tap_ref() only in debug builds, and is erased in release
builds.§fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
fn tap_ref_mut_dbg<R>(self, func: impl FnOnce(&mut R)) -> Self
.tap_ref_mut() only in debug builds, and is erased in release
builds.§fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
fn tap_deref_dbg<T>(self, func: impl FnOnce(&T)) -> Self
.tap_deref() only in debug builds, and is erased in release
builds.