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 pub(crate) fn priority_queued_packets(&self) -> usize {
253 self.priority_queued_packets.load(Relaxed)
254 }
255
256 pub(crate) fn priority_ready_packets(&self) -> usize {
257 self.pending_priority
258 .as_ref()
259 .map_or(0, |packets| packets.batch.packets.len())
260 .saturating_add(self.priority_queued_packets())
261 }
262
263 pub async fn recv(&mut self) -> Option<ReceivedPacket> {
264 loop {
265 match self.try_recv() {
266 Ok(packet) => return Some(packet),
267 Err(TryRecvError::Disconnected) => return None,
268 Err(TryRecvError::Empty) => {}
269 }
270
271 tokio::select! {
272 biased;
273 item = self.priority.recv(), if !self.priority_closed => {
274 match item {
275 Some(item) => {
276 if let Some(packet) = self.packet_from_item(item, PacketLane::Priority) {
277 return Some(packet);
278 }
279 }
280 None => self.priority_closed = true,
281 }
282 }
283 item = self.bulk.recv(), if !self.bulk_closed => {
284 match item {
285 Some(item) => {
286 if let Some(packet) = self.packet_from_item(item, PacketLane::Bulk) {
287 return Some(packet);
288 }
289 }
290 None => self.bulk_closed = true,
291 }
292 }
293 }
294 }
295 }
296
297 pub fn try_recv(&mut self) -> Result<ReceivedPacket, TryRecvError> {
298 if let Some(packet) = Self::take_pending(&mut self.pending_priority) {
299 return Ok(packet);
300 }
301
302 if self.should_probe_priority() {
303 match self.priority.try_recv() {
304 Ok(item) => {
305 if let Some(packet) = self.packet_from_item(item, PacketLane::Priority) {
306 return Ok(packet);
307 }
308 }
309 Err(TryRecvError::Empty) => {}
310 Err(TryRecvError::Disconnected) => {
311 self.priority_closed = true;
312 }
313 }
314 }
315
316 if let Some(packet) = Self::take_pending(&mut self.pending_bulk) {
317 return Ok(packet);
318 }
319
320 match self.bulk.try_recv() {
321 Ok(item) => self
322 .packet_from_item(item, PacketLane::Bulk)
323 .ok_or(TryRecvError::Empty),
324 Err(TryRecvError::Empty) => {
325 if self.priority_closed && self.bulk_closed {
326 Err(TryRecvError::Disconnected)
327 } else {
328 Err(TryRecvError::Empty)
329 }
330 }
331 Err(TryRecvError::Disconnected) => {
332 self.bulk_closed = true;
333 if self.priority_closed {
334 Err(TryRecvError::Disconnected)
335 } else {
336 Err(TryRecvError::Empty)
337 }
338 }
339 }
340 }
341
342 pub(crate) fn drain_ready<F>(&mut self, limit: usize, mut consume: F) -> usize
343 where
344 F: FnMut(ReceivedPacket) -> bool,
345 {
346 let mut drained = 0usize;
347 while drained < limit {
348 if !self.drain_pending_priority(limit, &mut drained, &mut consume) {
349 break;
350 }
351 if drained >= limit {
352 break;
353 }
354
355 if self.should_probe_priority() {
356 match self.priority.try_recv() {
357 Ok(item) => {
358 if !self.drain_item(
359 item,
360 PacketLane::Priority,
361 limit,
362 &mut drained,
363 &mut consume,
364 ) {
365 break;
366 }
367 continue;
368 }
369 Err(TryRecvError::Empty) => {}
370 Err(TryRecvError::Disconnected) => {
371 self.priority_closed = true;
372 }
373 }
374 }
375 if drained >= limit {
376 break;
377 }
378
379 if !self.drain_pending_bulk(limit, &mut drained, &mut consume) {
380 break;
381 }
382 if drained >= limit {
383 break;
384 }
385
386 match self.bulk.try_recv() {
387 Ok(item) => {
388 if !self.drain_item(item, PacketLane::Bulk, limit, &mut drained, &mut consume) {
389 break;
390 }
391 }
392 Err(TryRecvError::Empty) => break,
393 Err(TryRecvError::Disconnected) => {
394 self.bulk_closed = true;
395 break;
396 }
397 }
398 }
399 drained
400 }
401
402 fn packet_from_item(
403 &mut self,
404 item: PacketQueueItem,
405 lane: PacketLane,
406 ) -> Option<ReceivedPacket> {
407 item.record_dequeue_wait(lane);
408 let packet_count = item.packet_count();
409 if self.track_backlog {
410 self.queued_packets.fetch_sub(packet_count, Relaxed);
411 }
412 if matches!(lane, PacketLane::Priority) {
413 release_priority_packets(&self.priority_queued_packets, packet_count);
414 }
415 if matches!(lane, PacketLane::Bulk) {
416 release_reserved_bulk_packets(&self.bulk_queued_packets, packet_count);
417 }
418 let rx_loop_owned_at = crate::perf_profile::stamp();
419 match item {
420 PacketQueueItem::One(mut packet) => {
421 packet.trace_rx_loop_owned_at = rx_loop_owned_at;
422 Some(packet)
423 }
424 PacketQueueItem::Batch(packets) => {
425 let mut pending = PendingPackets::new(packets, rx_loop_owned_at);
426 let packet = pending.next()?;
427 if !pending.batch.packets.is_empty() {
428 match lane {
429 PacketLane::Priority => self.pending_priority = Some(pending),
430 PacketLane::Bulk => self.pending_bulk = Some(pending),
431 }
432 }
433 Some(packet)
434 }
435 }
436 }
437
438 fn drain_item<F>(
439 &mut self,
440 item: PacketQueueItem,
441 lane: PacketLane,
442 limit: usize,
443 drained: &mut usize,
444 consume: &mut F,
445 ) -> bool
446 where
447 F: FnMut(ReceivedPacket) -> bool,
448 {
449 if let Some(packet) = self.packet_from_item(item, lane) {
450 *drained += 1;
451 if !consume(packet) {
452 return false;
453 }
454 }
455
456 match lane {
457 PacketLane::Priority => self.drain_pending_priority(limit, drained, consume),
458 PacketLane::Bulk => self.drain_pending_bulk(limit, drained, consume),
459 }
460 }
461
462 fn drain_pending_priority<F>(
463 &mut self,
464 limit: usize,
465 drained: &mut usize,
466 consume: &mut F,
467 ) -> bool
468 where
469 F: FnMut(ReceivedPacket) -> bool,
470 {
471 while *drained < limit {
472 let Some(packet) = Self::take_pending(&mut self.pending_priority) else {
473 return true;
474 };
475 *drained += 1;
476 if !consume(packet) {
477 return false;
478 }
479 }
480 true
481 }
482
483 fn drain_pending_bulk<F>(&mut self, limit: usize, drained: &mut usize, consume: &mut F) -> bool
484 where
485 F: FnMut(ReceivedPacket) -> bool,
486 {
487 while *drained < limit {
488 if self.should_probe_priority() {
489 return true;
490 }
491 let Some(packet) = Self::take_pending(&mut self.pending_bulk) else {
492 return true;
493 };
494 *drained += 1;
495 if !consume(packet) {
496 return false;
497 }
498 }
499 true
500 }
501
502 fn should_probe_priority(&self) -> bool {
503 !self.priority_closed
504 && (self.priority_queued_packets.load(Relaxed) > 0 || self.bulk_closed)
505 }
506
507 fn take_pending(pending: &mut Option<PendingPackets>) -> Option<ReceivedPacket> {
508 let packets = pending.as_mut()?;
509 let packet = packets.next();
510 if packets.batch.packets.is_empty() {
511 *pending = None;
512 }
513 packet
514 }
515}
516
517#[inline]
518fn packet_channel_tracks_backlog() -> bool {
519 cfg!(test) || crate::perf_profile::enabled()
520}
521
522fn release_reserved_bulk_packets(counter: &AtomicUsize, count: usize) {
523 if count == 0 {
524 return;
525 }
526
527 let previous = counter.fetch_sub(count, Relaxed);
528 debug_assert!(
529 previous >= count,
530 "transport bulk queued packet accounting underflow"
531 );
532}
533
534fn release_priority_packets(counter: &AtomicUsize, count: usize) {
535 if count == 0 {
536 return;
537 }
538
539 let previous = counter.fetch_sub(count, Relaxed);
540 debug_assert!(
541 previous >= count,
542 "transport priority queued packet accounting underflow"
543 );
544}
545
546pub fn packet_channel(buffer: usize) -> (PacketTx, PacketRx) {
552 let (priority_tx, priority_rx) = tokio::sync::mpsc::unbounded_channel();
553 let (bulk_tx, bulk_rx) = tokio::sync::mpsc::channel(buffer.max(1));
554 let priority_queued_packets = Arc::new(AtomicUsize::new(0));
555 let queued_packets = Arc::new(AtomicUsize::new(0));
556 let bulk_queued_packets = Arc::new(AtomicUsize::new(0));
557 let track_backlog = packet_channel_tracks_backlog();
558 (
559 PacketTx {
560 priority: priority_tx,
561 bulk: bulk_tx,
562 fast_ingress: None,
563 batch_pool: PacketBatchPool::new(),
564 #[cfg(any(test, target_os = "linux", target_os = "macos"))]
565 buffer_pool: PacketBufferPool::new(),
566 priority_queued_packets: Arc::clone(&priority_queued_packets),
567 queued_packets: Arc::clone(&queued_packets),
568 bulk_queued_packets: Arc::clone(&bulk_queued_packets),
569 bulk_packet_capacity: buffer.max(1),
570 track_backlog,
571 },
572 PacketRx {
573 priority: priority_rx,
574 bulk: bulk_rx,
575 priority_queued_packets,
576 queued_packets,
577 bulk_queued_packets,
578 track_backlog,
579 pending_priority: None,
580 pending_bulk: None,
581 priority_closed: false,
582 bulk_closed: false,
583 },
584 )
585}
586
587#[cfg(test)]
588#[path = "packet_channel/tests.rs"]
589mod tests;