1use std::{
7 collections::VecDeque,
8 io::{self, Read, Write},
9 sync::{
10 Arc, Mutex,
11 atomic::{AtomicU64, AtomicUsize, Ordering},
12 },
13 time::{Duration, Instant},
14};
15
16#[derive(Clone, Copy, Debug, PartialEq, Eq)]
18pub enum Direction {
19 Read,
21 Write,
23}
24#[derive(Clone, Copy, Debug, PartialEq, Eq)]
26#[non_exhaustive]
27pub enum Event {
28 Connected,
30 Disconnected,
32 ReadClosed,
34 IoFailed {
36 direction: Direction,
38 kind: io::ErrorKind,
40 },
41 Rejected,
43 DrainStarted,
45 DrainCompleted,
47 DrainTimedOut,
49 HandoffStarted,
51 HandoffCompleted,
53 HandoffAborted,
55}
56#[derive(Clone, Copy, Debug, PartialEq, Eq)]
58#[non_exhaustive]
59pub struct TimedEvent {
60 pub elapsed: Duration,
62 pub event: Event,
64}
65
66#[derive(Default)]
67struct Progress {
68 bytes: AtomicU64,
69 pending: AtomicUsize,
70 busy_since: AtomicU64,
71 last_progress: AtomicU64,
72 errors: AtomicU64,
73}
74#[derive(Clone, Copy, Debug, PartialEq, Eq)]
76#[non_exhaustive]
77pub struct ProgressSnapshot {
78 pub bytes: u64,
80 pub pending: usize,
82 pub busy_for: Option<Duration>,
84 pub since_progress: Option<Duration>,
86 pub errors: u64,
88}
89#[derive(Clone, Copy, Debug, PartialEq, Eq)]
91#[non_exhaustive]
92pub struct Snapshot {
93 pub connections: usize,
95 pub read: ProgressSnapshot,
97 pub write: ProgressSnapshot,
99 pub lost_events: u64,
101}
102pub struct Observations {
104 started: Instant,
105 read: Progress,
106 write: Progress,
107 connections: AtomicUsize,
108 events: Mutex<VecDeque<TimedEvent>>,
109 event_capacity: usize,
110 lost_events: AtomicU64,
111}
112impl Observations {
113 pub fn new(event_capacity: usize) -> Self {
115 Self {
116 started: Instant::now(),
117 read: Progress::default(),
118 write: Progress::default(),
119 connections: AtomicUsize::new(0),
120 events: Mutex::new(VecDeque::with_capacity(event_capacity)),
121 event_capacity,
122 lost_events: AtomicU64::new(0),
123 }
124 }
125 pub fn record(&self, event: Event) {
127 if self.event_capacity == 0 {
128 return;
129 }
130 if let Ok(mut events) = self.events.try_lock()
131 && events.len() < self.event_capacity
132 {
133 events.push_back(TimedEvent {
134 elapsed: self.started.elapsed(),
135 event,
136 });
137 return;
138 }
139 self.lost_events.fetch_add(1, Ordering::Relaxed);
140 }
141 pub fn take_events(&self) -> Vec<TimedEvent> {
143 self.events
144 .lock()
145 .unwrap_or_else(|e| e.into_inner())
146 .drain(..)
147 .collect()
148 }
149 pub fn snapshot(&self) -> Snapshot {
151 let progress = |p: &Progress| {
152 let last = p.last_progress.load(Ordering::Relaxed);
153 let pending = p.pending.load(Ordering::Relaxed);
154 ProgressSnapshot {
155 bytes: p.bytes.load(Ordering::Relaxed),
156 pending,
157 busy_for: (pending != 0).then(|| {
158 self.started
159 .elapsed()
160 .saturating_sub(Duration::from_nanos(p.busy_since.load(Ordering::Relaxed)))
161 }),
162 since_progress: (last != 0).then(|| {
163 self.started
164 .elapsed()
165 .saturating_sub(Duration::from_nanos(last - 1))
166 }),
167 errors: p.errors.load(Ordering::Relaxed),
168 }
169 };
170 Snapshot {
171 connections: self.connections.load(Ordering::Relaxed),
172 read: progress(&self.read),
173 write: progress(&self.write),
174 lost_events: self.lost_events.load(Ordering::Relaxed),
175 }
176 }
177 fn progress(&self, direction: Direction) -> &Progress {
178 match direction {
179 Direction::Read => &self.read,
180 Direction::Write => &self.write,
181 }
182 }
183 fn start(&self, direction: Direction) {
184 let progress = self.progress(direction);
185 if progress.pending.fetch_add(1, Ordering::Relaxed) == 0 {
186 progress.busy_since.store(
187 self.started.elapsed().as_nanos().min(u128::from(u64::MAX)) as u64,
188 Ordering::Relaxed,
189 );
190 }
191 }
192 fn begin(&self, direction: Direction) -> Pending<'_> {
193 self.start(direction);
194 Pending(&self.progress(direction).pending)
195 }
196 fn transferred(&self, direction: Direction, bytes: usize) {
197 if bytes == 0 {
198 return;
199 }
200 let p = self.progress(direction);
201 p.bytes.fetch_add(bytes as u64, Ordering::Relaxed);
202 let elapsed = self
203 .started
204 .elapsed()
205 .as_nanos()
206 .min(u128::from(u64::MAX - 1)) as u64;
207 p.last_progress.fetch_max(elapsed + 1, Ordering::Relaxed);
208 }
209 fn failed(&self, direction: Direction, error: &io::Error) {
210 if matches!(
211 error.kind(),
212 io::ErrorKind::Interrupted | io::ErrorKind::WouldBlock
213 ) {
214 return;
215 }
216 self.progress(direction)
217 .errors
218 .fetch_add(1, Ordering::Relaxed);
219 self.record(Event::IoFailed {
220 direction,
221 kind: error.kind(),
222 });
223 }
224}
225impl Default for Observations {
226 fn default() -> Self {
227 Self::new(64)
228 }
229}
230
231struct Pending<'a>(&'a AtomicUsize);
232impl Drop for Pending<'_> {
233 fn drop(&mut self) {
234 self.0.fetch_sub(1, Ordering::Relaxed);
235 }
236}
237
238pub struct ObservedIo<S> {
241 inner: S,
242 observations: Arc<Observations>,
243 read_closed: bool,
244}
245impl<S> ObservedIo<S> {
246 pub fn new(inner: S, observations: Arc<Observations>) -> Self {
248 observations.connections.fetch_add(1, Ordering::Relaxed);
249 observations.record(Event::Connected);
250 Self {
251 inner,
252 observations,
253 read_closed: false,
254 }
255 }
256 pub fn inner_mut(&mut self) -> &mut S {
258 &mut self.inner
259 }
260}
261impl<S> Drop for ObservedIo<S> {
262 fn drop(&mut self) {
263 self.observations
264 .connections
265 .fetch_sub(1, Ordering::Relaxed);
266 self.observations.record(Event::Disconnected);
267 }
268}
269impl<S: Read> Read for ObservedIo<S> {
270 fn read(&mut self, bytes: &mut [u8]) -> io::Result<usize> {
271 let _pending = self.observations.begin(Direction::Read);
272 let result = self.inner.read(bytes);
273 match &result {
274 Ok(0) if !bytes.is_empty() && !self.read_closed => {
275 self.read_closed = true;
276 self.observations.record(Event::ReadClosed);
277 }
278 Ok(n) => self.observations.transferred(Direction::Read, *n),
279 Err(error) => self.observations.failed(Direction::Read, error),
280 }
281 result
282 }
283}
284impl<S: Write> Write for ObservedIo<S> {
285 fn write(&mut self, bytes: &[u8]) -> io::Result<usize> {
286 let _pending = self.observations.begin(Direction::Write);
287 let result = self.inner.write(bytes);
288 match &result {
289 Ok(n) => self.observations.transferred(Direction::Write, *n),
290 Err(error) => self.observations.failed(Direction::Write, error),
291 }
292 result
293 }
294 fn flush(&mut self) -> io::Result<()> {
295 let _pending = self.observations.begin(Direction::Write);
296 let result = self.inner.flush();
297 if let Err(error) = &result {
298 self.observations.failed(Direction::Write, error);
299 }
300 result
301 }
302}
303
304#[cfg(feature = "wire-async")]
305mod asynchronous {
306 use super::*;
307 use std::{
308 pin::Pin,
309 task::{Context, Poll},
310 };
311 use tokio::io::{AsyncRead, AsyncWrite, ReadBuf};
312
313 pub struct AsyncObservedIo<S> {
317 io: ObservedIo<S>,
318 read_pending: bool,
319 write_pending: bool,
320 }
321 impl<S> AsyncObservedIo<S> {
322 pub fn new(inner: S, observations: Arc<Observations>) -> Self {
324 Self {
325 io: ObservedIo::new(inner, observations),
326 read_pending: false,
327 write_pending: false,
328 }
329 }
330 pub fn inner_mut(&mut self) -> &mut S {
332 self.io.inner_mut()
333 }
334 fn begin(&mut self, direction: Direction) {
335 let pending = match direction {
336 Direction::Read => &mut self.read_pending,
337 Direction::Write => &mut self.write_pending,
338 };
339 if !*pending {
340 self.io.observations.start(direction);
342 *pending = true;
343 }
344 }
345 fn end(&mut self, direction: Direction) {
346 let pending = match direction {
347 Direction::Read => &mut self.read_pending,
348 Direction::Write => &mut self.write_pending,
349 };
350 if std::mem::take(pending) {
351 self.io
352 .observations
353 .progress(direction)
354 .pending
355 .fetch_sub(1, Ordering::Relaxed);
356 }
357 }
358 }
359 impl<S> Drop for AsyncObservedIo<S> {
360 fn drop(&mut self) {
361 self.end(Direction::Read);
362 self.end(Direction::Write);
363 }
364 }
365 impl<S: AsyncRead + Unpin> AsyncRead for AsyncObservedIo<S> {
366 fn poll_read(
367 self: Pin<&mut Self>,
368 cx: &mut Context<'_>,
369 buf: &mut ReadBuf<'_>,
370 ) -> Poll<io::Result<()>> {
371 let this = self.get_mut();
372 this.begin(Direction::Read);
373 let before = buf.filled().len();
374 let capacity = buf.remaining();
375 let result = Pin::new(&mut this.io.inner).poll_read(cx, buf);
376 if let Poll::Ready(result) = &result {
377 this.end(Direction::Read);
378 match result {
379 Ok(()) => {
380 let bytes = buf.filled().len() - before;
381 this.io.observations.transferred(Direction::Read, bytes);
382 if bytes == 0 && capacity != 0 && !this.io.read_closed {
383 this.io.read_closed = true;
384 this.io.observations.record(Event::ReadClosed);
385 }
386 }
387 Err(error) => this.io.observations.failed(Direction::Read, error),
388 }
389 }
390 result
391 }
392 }
393 impl<S: AsyncWrite + Unpin> AsyncWrite for AsyncObservedIo<S> {
394 fn poll_write(
395 self: Pin<&mut Self>,
396 cx: &mut Context<'_>,
397 bytes: &[u8],
398 ) -> Poll<io::Result<usize>> {
399 let this = self.get_mut();
400 this.begin(Direction::Write);
401 let result = Pin::new(&mut this.io.inner).poll_write(cx, bytes);
402 if let Poll::Ready(result) = &result {
403 this.end(Direction::Write);
404 match result {
405 Ok(bytes) => this.io.observations.transferred(Direction::Write, *bytes),
406 Err(error) => this.io.observations.failed(Direction::Write, error),
407 }
408 }
409 result
410 }
411 fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
412 let this = self.get_mut();
413 this.begin(Direction::Write);
414 let result = Pin::new(&mut this.io.inner).poll_flush(cx);
415 if let Poll::Ready(result) = &result {
416 this.end(Direction::Write);
417 if let Err(error) = result {
418 this.io.observations.failed(Direction::Write, error);
419 }
420 }
421 result
422 }
423 fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
424 let this = self.get_mut();
425 this.begin(Direction::Write);
426 let result = Pin::new(&mut this.io.inner).poll_shutdown(cx);
427 if let Poll::Ready(result) = &result {
428 this.end(Direction::Write);
429 if let Err(error) = result {
430 this.io.observations.failed(Direction::Write, error);
431 }
432 }
433 result
434 }
435 }
436}
437#[cfg(feature = "wire-async")]
438pub use asynchronous::AsyncObservedIo;
439
440#[cfg(test)]
441mod tests {
442 use super::*;
443 #[test]
444 fn a_busy_event_reader_does_not_block_producers_or_snapshots() {
445 let observations = Observations::new(1);
446 let _reader = observations.events.lock().unwrap();
447 observations.record(Event::Rejected);
448 assert_eq!(observations.snapshot().lost_events, 1);
449 }
450}