1impl PacketTx {
2 pub(crate) fn set_fast_ingress_sink(&mut self, sink: Arc<dyn PacketFastIngressSink>) {
3 self.fast_ingress = Some(sink);
4 }
5
6 pub(crate) fn try_fast_ingress_packet_batch(&self, batch: &mut PacketBatch) -> usize {
7 let Some(sink) = &self.fast_ingress else {
8 return 0;
9 };
10 sink.try_ingest_batch(&mut batch.packets)
11 }
12
13 pub(crate) fn packet_batch(&self, capacity: usize) -> PacketBatch {
14 self.batch_pool.take(capacity)
15 }
16
17 #[cfg(any(test, target_os = "linux", target_os = "macos"))]
18 pub(crate) fn recv_buffer(&self, capacity: usize) -> Vec<u8> {
19 self.buffer_pool.take(capacity)
20 }
21
22 #[cfg(any(test, target_os = "linux", target_os = "macos"))]
23 pub(crate) fn packet_buffer(&self, data: Vec<u8>) -> PacketBuffer {
24 PacketBuffer::pooled(data, self.buffer_pool.clone())
25 }
26
27 pub fn send(
28 &self,
29 packet: ReceivedPacket,
30 ) -> Result<(), tokio::sync::mpsc::error::SendError<ReceivedPacket>> {
31 let tx = if packet.is_transport_priority() {
32 PacketQueueTx::Priority
33 } else {
34 PacketQueueTx::Bulk
35 };
36 self.send_item(tx, PacketQueueItem::One(packet))
37 .map_err(|item| match item {
38 PacketQueueItem::One(packet) => tokio::sync::mpsc::error::SendError(packet),
39 PacketQueueItem::Batch(_) => {
40 unreachable!("single packet send cannot fail with a batch item")
41 }
42 })
43 }
44
45 pub(crate) fn send_packet_batch(&self, mut batch: PacketBatch) -> Result<(), ()> {
46 if batch.is_empty() {
47 return Ok(());
48 }
49
50 let packet_count = batch.packets.len();
51 let priority_count = batch
52 .packets
53 .iter()
54 .filter(|packet| packet.is_transport_priority())
55 .count();
56 if priority_count == 0 || priority_count == packet_count {
57 let tx = if priority_count == 0 {
58 PacketQueueTx::Bulk
59 } else {
60 PacketQueueTx::Priority
61 };
62 return self.send_packet_items(tx, batch);
63 }
64
65 let mut priority_packets = self.packet_batch(priority_count);
66 let mut bulk_packets = self.packet_batch(packet_count - priority_count);
67 for packet in batch.packets.drain(..) {
68 if packet.is_transport_priority() {
69 priority_packets.push(packet);
70 } else {
71 bulk_packets.push(packet);
72 }
73 }
74
75 self.send_packet_items(PacketQueueTx::Priority, priority_packets)?;
76 self.send_packet_items(PacketQueueTx::Bulk, bulk_packets)?;
77 Ok(())
78 }
79
80 fn send_packet_items(&self, tx: PacketQueueTx, packets: PacketBatch) -> Result<(), ()> {
81 if matches!(tx, PacketQueueTx::Bulk) {
82 return self.send_bulk_packet_items(packets);
83 }
84
85 let item = match packets.packets.len() {
86 0 => return Ok(()),
87 _ => PacketQueueItem::Batch(packets),
88 };
89 self.send_item(tx, item).map_err(|_| ())
90 }
91
92 fn send_bulk_packet_items(&self, mut packets: PacketBatch) -> Result<(), ()> {
93 let packet_count = packets.packets.len();
94 if packet_count == 0 {
95 return Ok(());
96 }
97
98 let granted = self.try_reserve_bulk_packet_prefix(packet_count);
99 if granted == 0 {
100 crate::perf_profile::record_event_count(
101 crate::perf_profile::Event::TransportBulkDropped,
102 packet_count as u64,
103 );
104 return Ok(());
105 }
106
107 if granted < packet_count {
108 let dropped = packet_count - granted;
109 let _dropped_tail = packets.packets.split_off(granted);
110 crate::perf_profile::record_event_count(
111 crate::perf_profile::Event::TransportBulkDropped,
112 dropped as u64,
113 );
114 }
115
116 let item = match packets.packets.len() {
117 0 => return Ok(()),
118 _ => PacketQueueItem::Batch(packets),
119 };
120 self.send_reserved_item(PacketQueueTx::Bulk, item, Some(granted))
121 .map_err(|_| ())
122 }
123
124 fn send_item(&self, tx: PacketQueueTx, item: PacketQueueItem) -> Result<(), PacketQueueItem> {
125 let packet_count = item.packet_count();
126 let bulk_reserved = if matches!(tx, PacketQueueTx::Bulk) && packet_count > 0 {
127 if !self.try_reserve_bulk_packets(packet_count) {
128 crate::perf_profile::record_event_count(
129 crate::perf_profile::Event::TransportBulkDropped,
130 packet_count as u64,
131 );
132 return Ok(());
133 }
134 Some(packet_count)
135 } else {
136 None
137 };
138 self.send_reserved_item(tx, item, bulk_reserved)
139 }
140
141 fn send_reserved_item(
142 &self,
143 tx: PacketQueueTx,
144 item: PacketQueueItem,
145 bulk_reserved: Option<usize>,
146 ) -> Result<(), PacketQueueItem> {
147 let packet_count = item.packet_count();
148 debug_assert_eq!(
149 bulk_reserved,
150 matches!(tx, PacketQueueTx::Bulk)
151 .then_some(packet_count)
152 .filter(|count| *count > 0)
153 );
154 let priority_reserved = matches!(tx, PacketQueueTx::Priority)
155 .then_some(packet_count)
156 .filter(|count| *count > 0);
157 if let Some(count) = priority_reserved {
158 self.priority_queued_packets.fetch_add(count, Relaxed);
159 }
160
161 let tracked_count = if self.track_backlog {
162 Some(packet_count)
163 } else {
164 None
165 };
166 let previous = tracked_count.map(|count| self.queued_packets.fetch_add(count, Relaxed));
167 match tx.try_send(self, item) {
168 Ok(()) => {
169 if let (Some(count), Some(previous)) = (tracked_count, previous) {
170 let queued = previous.saturating_add(count);
171 if previous < TRANSPORT_CHANNEL_BACKLOG_HIGH_WATER
172 && queued >= TRANSPORT_CHANNEL_BACKLOG_HIGH_WATER
173 {
174 crate::perf_profile::record_event(
175 crate::perf_profile::Event::TransportChannelBacklogHigh,
176 );
177 }
178 }
179 Ok(())
180 }
181 Err(PacketSendFailure::Closed(item)) => {
182 if let Some(count) = tracked_count {
183 self.queued_packets.fetch_sub(count, Relaxed);
184 }
185 if let Some(count) = priority_reserved {
186 release_priority_packets(&self.priority_queued_packets, count);
187 }
188 if let Some(count) = bulk_reserved {
189 self.release_bulk_packets(count);
190 }
191 Err(item)
192 }
193 Err(PacketSendFailure::DroppedBulk(dropped_count)) => {
194 if let Some(count) = tracked_count {
195 self.queued_packets.fetch_sub(count, Relaxed);
196 }
197 if let Some(count) = priority_reserved {
198 release_priority_packets(&self.priority_queued_packets, count);
199 }
200 if let Some(count) = bulk_reserved {
201 self.release_bulk_packets(count);
202 }
203 crate::perf_profile::record_event_count(
204 crate::perf_profile::Event::TransportBulkDropped,
205 dropped_count as u64,
206 );
207 Ok(())
208 }
209 }
210 }
211
212 fn try_reserve_bulk_packets(&self, count: usize) -> bool {
213 self.bulk_queued_packets
214 .fetch_update(Relaxed, Relaxed, |current| {
215 current
216 .checked_add(count)
217 .filter(|next| *next <= self.bulk_packet_capacity)
218 })
219 .is_ok()
220 }
221
222 fn try_reserve_bulk_packet_prefix(&self, requested: usize) -> usize {
223 if requested == 0 {
224 return 0;
225 }
226
227 let mut current = self.bulk_queued_packets.load(Relaxed);
228 loop {
229 let available = self.bulk_packet_capacity.saturating_sub(current);
230 let granted = requested.min(available);
231 if granted == 0 {
232 return 0;
233 }
234 match self.bulk_queued_packets.compare_exchange_weak(
235 current,
236 current + granted,
237 Relaxed,
238 Relaxed,
239 ) {
240 Ok(_) => return granted,
241 Err(actual) => current = actual,
242 }
243 }
244 }
245
246 fn release_bulk_packets(&self, count: usize) {
247 release_reserved_bulk_packets(&self.bulk_queued_packets, count);
248 }
249}
250
251impl PacketRx {
252 #[cfg(test)]
253 pub(crate) fn queued_packets_for_test(&self) -> usize {
254 self.pending_priority
255 .as_ref()
256 .map_or(0, |packets| packets.batch.packets.len())
257 .saturating_add(
258 self.pending_bulk
259 .as_ref()
260 .map_or(0, |packets| packets.batch.packets.len()),
261 )
262 .saturating_add(self.queued_packets.load(Relaxed))
263 }
264
265 pub(crate) fn priority_queued_packets(&self) -> usize {
266 self.priority_queued_packets.load(Relaxed)
267 }
268
269 pub(crate) fn priority_ready_packets(&self) -> usize {
270 self.pending_priority
271 .as_ref()
272 .map_or(0, |packets| packets.batch.packets.len())
273 .saturating_add(self.priority_queued_packets())
274 }
275
276 pub async fn recv(&mut self) -> Option<ReceivedPacket> {
277 loop {
278 match self.try_recv() {
279 Ok(packet) => return Some(packet),
280 Err(TryRecvError::Disconnected) => return None,
281 Err(TryRecvError::Empty) => {}
282 }
283
284 tokio::select! {
285 biased;
286 item = self.priority.recv(), if !self.priority_closed => {
287 match item {
288 Some(item) => {
289 if let Some(packet) = self.packet_from_item(item, PacketLane::Priority) {
290 return Some(packet);
291 }
292 }
293 None => self.priority_closed = true,
294 }
295 }
296 item = self.bulk.recv(), if !self.bulk_closed => {
297 match item {
298 Some(item) => {
299 if let Some(packet) = self.packet_from_item(item, PacketLane::Bulk) {
300 return Some(packet);
301 }
302 }
303 None => self.bulk_closed = true,
304 }
305 }
306 }
307 }
308 }
309
310 pub fn try_recv(&mut self) -> Result<ReceivedPacket, TryRecvError> {
311 if let Some(packet) = Self::take_pending(&mut self.pending_priority) {
312 return Ok(packet);
313 }
314
315 if self.should_probe_priority() {
316 match self.priority.try_recv() {
317 Ok(item) => {
318 if let Some(packet) = self.packet_from_item(item, PacketLane::Priority) {
319 return Ok(packet);
320 }
321 }
322 Err(TryRecvError::Empty) => {}
323 Err(TryRecvError::Disconnected) => {
324 self.priority_closed = true;
325 }
326 }
327 }
328
329 if let Some(packet) = Self::take_pending(&mut self.pending_bulk) {
330 return Ok(packet);
331 }
332
333 match self.bulk.try_recv() {
334 Ok(item) => self
335 .packet_from_item(item, PacketLane::Bulk)
336 .ok_or(TryRecvError::Empty),
337 Err(TryRecvError::Empty) => {
338 if self.priority_closed && self.bulk_closed {
339 Err(TryRecvError::Disconnected)
340 } else {
341 Err(TryRecvError::Empty)
342 }
343 }
344 Err(TryRecvError::Disconnected) => {
345 self.bulk_closed = true;
346 if self.priority_closed {
347 Err(TryRecvError::Disconnected)
348 } else {
349 Err(TryRecvError::Empty)
350 }
351 }
352 }
353 }
354
355 pub(crate) fn drain_ready<F>(&mut self, limit: usize, mut consume: F) -> usize
356 where
357 F: FnMut(ReceivedPacket) -> bool,
358 {
359 let mut drained = 0usize;
360 while drained < limit {
361 if !self.drain_pending_priority(limit, &mut drained, &mut consume) {
362 break;
363 }
364 if drained >= limit {
365 break;
366 }
367
368 if self.should_probe_priority() {
369 match self.priority.try_recv() {
370 Ok(item) => {
371 if !self.drain_item(
372 item,
373 PacketLane::Priority,
374 limit,
375 &mut drained,
376 &mut consume,
377 ) {
378 break;
379 }
380 continue;
381 }
382 Err(TryRecvError::Empty) => {}
383 Err(TryRecvError::Disconnected) => {
384 self.priority_closed = true;
385 }
386 }
387 }
388 if drained >= limit {
389 break;
390 }
391
392 if !self.drain_pending_bulk(limit, &mut drained, &mut consume) {
393 break;
394 }
395 if drained >= limit {
396 break;
397 }
398
399 match self.bulk.try_recv() {
400 Ok(item) => {
401 if !self.drain_item(item, PacketLane::Bulk, limit, &mut drained, &mut consume) {
402 break;
403 }
404 }
405 Err(TryRecvError::Empty) => break,
406 Err(TryRecvError::Disconnected) => {
407 self.bulk_closed = true;
408 break;
409 }
410 }
411 }
412 drained
413 }
414
415 fn packet_from_item(
416 &mut self,
417 item: PacketQueueItem,
418 lane: PacketLane,
419 ) -> Option<ReceivedPacket> {
420 item.record_dequeue_wait(lane);
421 let packet_count = item.packet_count();
422 if self.track_backlog {
423 self.queued_packets.fetch_sub(packet_count, Relaxed);
424 }
425 if matches!(lane, PacketLane::Priority) {
426 release_priority_packets(&self.priority_queued_packets, packet_count);
427 }
428 if matches!(lane, PacketLane::Bulk) {
429 release_reserved_bulk_packets(&self.bulk_queued_packets, packet_count);
430 }
431 let rx_loop_owned_at = crate::perf_profile::stamp();
432 match item {
433 PacketQueueItem::One(mut packet) => {
434 packet.trace_rx_loop_owned_at = rx_loop_owned_at;
435 Some(packet)
436 }
437 PacketQueueItem::Batch(packets) => {
438 let mut pending = PendingPackets::new(packets, rx_loop_owned_at);
439 let packet = pending.next()?;
440 if !pending.batch.packets.is_empty() {
441 match lane {
442 PacketLane::Priority => self.pending_priority = Some(pending),
443 PacketLane::Bulk => self.pending_bulk = Some(pending),
444 }
445 }
446 Some(packet)
447 }
448 }
449 }
450
451 fn drain_item<F>(
452 &mut self,
453 item: PacketQueueItem,
454 lane: PacketLane,
455 limit: usize,
456 drained: &mut usize,
457 consume: &mut F,
458 ) -> bool
459 where
460 F: FnMut(ReceivedPacket) -> bool,
461 {
462 if let Some(packet) = self.packet_from_item(item, lane) {
463 *drained += 1;
464 if !consume(packet) {
465 return false;
466 }
467 }
468
469 match lane {
470 PacketLane::Priority => self.drain_pending_priority(limit, drained, consume),
471 PacketLane::Bulk => self.drain_pending_bulk(limit, drained, consume),
472 }
473 }
474
475 fn drain_pending_priority<F>(
476 &mut self,
477 limit: usize,
478 drained: &mut usize,
479 consume: &mut F,
480 ) -> bool
481 where
482 F: FnMut(ReceivedPacket) -> bool,
483 {
484 while *drained < limit {
485 let Some(packet) = Self::take_pending(&mut self.pending_priority) else {
486 return true;
487 };
488 *drained += 1;
489 if !consume(packet) {
490 return false;
491 }
492 }
493 true
494 }
495
496 fn drain_pending_bulk<F>(&mut self, limit: usize, drained: &mut usize, consume: &mut F) -> bool
497 where
498 F: FnMut(ReceivedPacket) -> bool,
499 {
500 while *drained < limit {
501 if self.should_probe_priority() {
502 return true;
503 }
504 let Some(packet) = Self::take_pending(&mut self.pending_bulk) else {
505 return true;
506 };
507 *drained += 1;
508 if !consume(packet) {
509 return false;
510 }
511 }
512 true
513 }
514
515 fn should_probe_priority(&self) -> bool {
516 !self.priority_closed
517 && (self.priority_queued_packets.load(Relaxed) > 0 || self.bulk_closed)
518 }
519
520 fn take_pending(pending: &mut Option<PendingPackets>) -> Option<ReceivedPacket> {
521 let packets = pending.as_mut()?;
522 let packet = packets.next();
523 if packets.batch.packets.is_empty() {
524 *pending = None;
525 }
526 packet
527 }
528}
529
530#[inline]
531fn packet_channel_tracks_backlog() -> bool {
532 cfg!(test) || crate::perf_profile::enabled()
533}
534
535fn release_reserved_bulk_packets(counter: &AtomicUsize, count: usize) {
536 if count == 0 {
537 return;
538 }
539
540 let previous = counter.fetch_sub(count, Relaxed);
541 debug_assert!(
542 previous >= count,
543 "transport bulk queued packet accounting underflow"
544 );
545}
546
547fn release_priority_packets(counter: &AtomicUsize, count: usize) {
548 if count == 0 {
549 return;
550 }
551
552 let previous = counter.fetch_sub(count, Relaxed);
553 debug_assert!(
554 previous >= count,
555 "transport priority queued packet accounting underflow"
556 );
557}
558
559pub fn packet_channel(buffer: usize) -> (PacketTx, PacketRx) {
565 let (priority_tx, priority_rx) = tokio::sync::mpsc::unbounded_channel();
566 let (bulk_tx, bulk_rx) = tokio::sync::mpsc::channel(buffer.max(1));
567 let priority_queued_packets = Arc::new(AtomicUsize::new(0));
568 let queued_packets = Arc::new(AtomicUsize::new(0));
569 let bulk_queued_packets = Arc::new(AtomicUsize::new(0));
570 let track_backlog = packet_channel_tracks_backlog();
571 (
572 PacketTx {
573 priority: priority_tx,
574 bulk: bulk_tx,
575 fast_ingress: None,
576 batch_pool: PacketBatchPool::new(),
577 #[cfg(any(test, target_os = "linux", target_os = "macos"))]
578 buffer_pool: PacketBufferPool::new(),
579 priority_queued_packets: Arc::clone(&priority_queued_packets),
580 queued_packets: Arc::clone(&queued_packets),
581 bulk_queued_packets: Arc::clone(&bulk_queued_packets),
582 bulk_packet_capacity: buffer.max(1),
583 track_backlog,
584 },
585 PacketRx {
586 priority: priority_rx,
587 bulk: bulk_rx,
588 priority_queued_packets,
589 queued_packets,
590 bulk_queued_packets,
591 track_backlog,
592 pending_priority: None,
593 pending_bulk: None,
594 priority_closed: false,
595 bulk_closed: false,
596 },
597 )
598}
599
600#[cfg(test)]
601#[path = "packet_channel/tests.rs"]
602mod tests;