Skip to content

Commit 8a419c6

Browse files
remarks
1 parent 9b6c7c9 commit 8a419c6

File tree

2 files changed

+13
-5
lines changed

2 files changed

+13
-5
lines changed

libudpard/udpard.c

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,15 @@ typedef unsigned char byte_t; ///< For compatibility with platforms where byte s
5858

5959
/// The number of most recent transfers to keep in the history for ACK retransmission and duplicate detection.
6060
/// Should be a power of two to allow replacement of modulo operation with a bitwise AND.
61+
///
62+
/// Implementation node: we used to store bitmask windows instead of a full list of recent transfer-IDs, but they
63+
/// were found to offer no advantage except in the perfect scenario of non-restarting senders, and an increased
64+
/// implementation complexity (more branches, more lines of code), so they were replaced with a simple list.
65+
/// The list works equally well given a non-contiguous transfer-ID stream, unlike the bitmask, thus more robust.
6166
#define RX_TRANSFER_HISTORY_COUNT 16U
6267

6368
/// In the ORDERED reassembly mode, with the most recently received transfer-ID N, the library will reject
64-
/// transfers with transfer-ID less than or equal to N - ORDERING_WINDOW (modulo 2^64) as late.
69+
/// transfers with transfer-ID less than or equal to N-ORDERING_WINDOW (modulo 2^64) as late.
6570
#define RX_TRANSFER_ORDERING_WINDOW 1024U
6671

6772
#define UDP_PORT 9382U
@@ -1280,7 +1285,6 @@ static void rx_session_ordered_scan_slots(rx_session_t* const self,
12801285
}
12811286
}
12821287
}
1283-
12841288
// The slot needs to be ejected if it's in-sequence, if it's reordering window is closed, or if we're
12851289
// asked to force an ejection and we haven't done so yet.
12861290
// The reordering window timeout implies that earlier transfers will be dropped if ORDERED mode is used.
@@ -1303,14 +1307,12 @@ static void rx_session_ordered_scan_slots(rx_session_t* const self,
13031307
}
13041308
break; // No more slots can be ejected at this time.
13051309
}
1306-
13071310
// We always pick the next transfer to eject with the nearest transfer-ID, which guarantees that the other
13081311
// DONE transfers will not end up being late.
13091312
// Some of the in-progress slots may be obsoleted by this move, which will be taken care of later.
13101313
UDPARD_ASSERT((slot != NULL) && (slot->state == rx_slot_done));
13111314
rx_session_eject(self, rx, slot);
13121315
}
1313-
13141316
// Ensure that in-progress slots, if any, have not ended up within the accepted window after the update.
13151317
// We can release them early to avoid holding the payload buffers that won't be used anyway.
13161318
for (size_t i = 0; i < RX_SLOT_COUNT; i++) {
@@ -1387,6 +1389,7 @@ static void rx_session_update_ordered(rx_session_t* const self,
13871389
const rx_frame_t frame,
13881390
const udpard_mem_deleter_t payload_deleter)
13891391
{
1392+
// The queries here may be a bit time-consuming. If this becomes a problem, there are many ways to optimize this.
13901393
const bool is_ejected = rx_session_is_transfer_ejected(self, frame.meta.transfer_id);
13911394
const bool is_late_or_ejected = rx_session_is_transfer_late_or_ejected(self, frame.meta.transfer_id);
13921395
const bool is_interned = rx_session_is_transfer_interned(self, frame.meta.transfer_id);
@@ -1413,6 +1416,9 @@ static void rx_session_update_ordered(rx_session_t* const self,
14131416
rx_session_ordered_scan_slots(self, rx, ts, false);
14141417
}
14151418
} else { // retransmit ACK if needed
1419+
// Note: transfers that are no longer retained in the history will not solicit an ACK response,
1420+
// meaning that the sender will not get a confirmation if the retransmitted transfer is too old.
1421+
// We assume that RX_TRANSFER_HISTORY_COUNT is enough to cover all sensible use cases.
14161422
if ((is_interned || is_ejected) && frame.meta.flag_ack && (frame.base.offset == 0U)) {
14171423
rx_session_on_ack_mandate(self, rx, frame.meta.priority, frame.meta.transfer_id, frame.base.payload);
14181424
}

libudpard/udpard.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -487,7 +487,7 @@ void udpard_tx_free(const udpard_tx_mem_resources_t memory, udpard_tx_item_t* co
487487
///
488488
/// Mode Guarantees Limitations Reordering window setting
489489
/// -----------------------------------------−--------------------------------------------------------------------------
490-
/// ORDERED Strictly increasing transfer-ID May delay transfers Non-negative number of microseconds
490+
/// ORDERED Strictly increasing transfer-ID May delay transfers, CPU heavier Non-negative number of microseconds
491491
/// UNORDERED Unique transfer-ID Ordering not guaranteed UDPARD_RX_REORDERING_WINDOW_UNORDERED
492492
/// STATELESS Constant time, constant memory 1-frame only, dups, no responses UDPARD_RX_REORDERING_WINDOW_STATELESS
493493
///
@@ -506,6 +506,8 @@ void udpard_tx_free(const udpard_tx_mem_resources_t memory, udpard_tx_item_t* co
506506
/// the application will receive 1 2 4 5, and transfer 3 will be permanently lost even if it arrives later
507507
/// because accepting it without violating the strictly increasing transfer-ID constraint is not possible.
508508
///
509+
/// This mode requires much more bookkeeping which results in a greater processing load per received fragment/transfer.
510+
///
509511
/// The ORDERED mode is used if the reordering window is non-negative. Zero is not really a special case, it
510512
/// simply means that out-of-order transfers are not waited for at all (declared permanently lost immediately).
511513
/// This should be the default option for most subscriptions; in particular, it is intended for state estimators

0 commit comments

Comments
 (0)