fix: a full reorder ring keeps the arriving packet and counts the overflow, instead of dropping it silently
A packet that needed a slot and found none was neither held nor delivered: no counter recorded it and the consumer reserved a hole nothing could ever backfill. It now commits the gap to free a slot and takes the ordering decision once more against the sequence that commit left behind, bounded to one retry; past that it is delivered in order with the counters it skipped as its `lost`, never flagged late, because a packet ahead of the sequence has no hole to be looked up by. A duplicate can now replace its slot at a full ring, as hold_packet's own comment already promised, and the 20 ms default window is a named constant. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
cb1bbd2b7b
commit
176ef1df9f
6 files changed
+113
-38
No files matched your search
@@ -94,6 +94,7 @@ void Acquisition::run() {
|
||||
out.resequenced.store(s.late_resequenced, std::memory_order_relaxed);
|
||||
out.late.store(s.late_delivered, std::memory_order_relaxed);
|
||||
out.stale.store(s.stale_packets, std::memory_order_relaxed);
|
||||
out.overflows.store(s.reorder_overflows, std::memory_order_relaxed);
|
||||
out.reconnects.store(s.reconnects, std::memory_order_relaxed);
|
||||
out.connected.store(udps_client_is_connected(client_) != 0, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
@@ -216,6 +216,10 @@ struct StreamStats {
|
||||
std::atomic<std::uint64_t> resequenced{0};
|
||||
/// Out-of-order packets delivered behind the sequence, past the window.
|
||||
std::atomic<std::uint64_t> late{0};
|
||||
/// Times the client's reorder ring was full when a packet needed a slot, so the gap was
|
||||
/// committed early. Nothing is dropped; the window was just shorter than asked for, and a
|
||||
/// non-zero reading is what says the ring is undersized for the stream.
|
||||
std::atomic<std::uint64_t> overflows{0};
|
||||
/// Packets the client still refused outright (a duplicate, or any late packet while
|
||||
/// resequencing is disabled). Counted since the beginning and displayed nowhere until
|
||||
/// now, which is why an inversion had to be inferred from `packets` and `frames`
|
||||
@@ -547,6 +551,7 @@ class ScopeModel {
|
||||
/// Rebuilds buffers from the current channel list. Caller holds `mutex()`.
|
||||
void rebuild_locked();
|
||||
|
||||
|
||||
private:
|
||||
void rebuild_channels();
|
||||
/// Re-appends one synthetic signal per math channel, after the stream's own. Called under the
|
||||
|
||||
+6
-3
@@ -10559,12 +10559,14 @@ gboolean reseq_probe(gpointer user) {
|
||||
}
|
||||
}
|
||||
std::fprintf(stderr,
|
||||
"[reseq-probe] reseq=%llu late=%llu stale=%llu holes=%llu hole_slots=%llu "
|
||||
"[reseq-probe] reseq=%llu late=%llu stale=%llu overflows=%llu holes=%llu "
|
||||
"hole_slots=%llu "
|
||||
"backfilled=%llu open_holes=%zu bands=%zu bands_repaired=%zu nan_slots=%llu "
|
||||
"scanned=%llu trigger_in_hole=%d\n",
|
||||
static_cast<unsigned long long>(m.stats().resequenced.load()),
|
||||
static_cast<unsigned long long>(m.stats().late.load()),
|
||||
static_cast<unsigned long long>(m.stats().stale.load()),
|
||||
static_cast<unsigned long long>(m.stats().overflows.load()),
|
||||
static_cast<unsigned long long>(m.stats().holes.load()),
|
||||
static_cast<unsigned long long>(m.stats().hole_slots.load()),
|
||||
static_cast<unsigned long long>(m.stats().backfilled.load()), open_holes, bands,
|
||||
@@ -10809,8 +10811,8 @@ int run_ui(int argc, char** argv, const Config& cfg, ScopeModel& model, Acquisit
|
||||
const Partition& part = model.partition();
|
||||
std::printf("[udpscope] frames=%llu packets=%llu gaps=%llu channels=%zu span=%.3fs "
|
||||
"stride=%llu"
|
||||
" reseq=%llu late=%llu stale=%llu holes=%llu hole_slots=%llu backfilled=%llu"
|
||||
"\n",
|
||||
" reseq=%llu late=%llu stale=%llu overflows=%llu holes=%llu hole_slots=%llu"
|
||||
" backfilled=%llu\n",
|
||||
static_cast<unsigned long long>(model.stats().frames.load()),
|
||||
static_cast<unsigned long long>(model.stats().packets.load()),
|
||||
static_cast<unsigned long long>(model.stats().gaps.load()),
|
||||
@@ -10819,6 +10821,7 @@ int run_ui(int argc, char** argv, const Config& cfg, ScopeModel& model, Acquisit
|
||||
static_cast<unsigned long long>(model.stats().resequenced.load()),
|
||||
static_cast<unsigned long long>(model.stats().late.load()),
|
||||
static_cast<unsigned long long>(model.stats().stale.load()),
|
||||
static_cast<unsigned long long>(model.stats().overflows.load()),
|
||||
static_cast<unsigned long long>(model.stats().holes.load()),
|
||||
static_cast<unsigned long long>(model.stats().hole_slots.load()),
|
||||
static_cast<unsigned long long>(model.stats().backfilled.load()));
|
||||
|
||||
Reference in new issue
Block a user