Loading debian/changelog +29 −0 Original line number Diff line number Diff line libnetplus (20260801+30) unstable; urgency=high * quic: fix accept()'s datagram-drain loop stalling on a contended per-connection mutex. Two sites — the inline long-header path for an existing connection, and flush_pending_app()'s deferred short-header flush — took an existing child connection's quic_mtx() with a blocking unique_lock. Both run inline on the single thread that drains a given listener (see accept()'s own concurrency note), so a connection busy elsewhere (e.g. mid-transfer, holding its own mutex for real work) could stall this entire drain call — and with it, every other connection's traffic in the same batch, and any brand-new incoming connection sitting later in it — for as long as that other thread held the lock. Root-caused live on a production mediadb node: a healthy peer's accept loop was blocked in pthread_mutex_lock()/quic::accept() while a client elsewhere (paritypp::client::connect_to_node()) got "Failed to connect to node X" on every 5-second-bounded retry, for minutes, even though ping and the peer's own accept-loop threads looked otherwise fine. Both sites now use try_lock and skip (rather than block) when a connection's mutex isn't immediately free — QUIC's own loss detection retransmits whatever gets skipped, far cheaper than blocking the shared accept path. Full existing QUIC test suite (87 tests across quic_test/quic_rfc9000_test/quic_concurrent_test/ quic_incremental_dispatch_test/quic_retry_test/ quic_version_negotiation_test/quic_roundtrip_sha256_test) passes unchanged; benchmark_quic throughput unaffected. -- Jan Koester <jan.koester@tuxist.de> Sat, 01 Aug 2026 06:43:00 +0200 libnetplus (20260731+29) unstable; urgency=high * socket: add setStartDispatchPromoted(bool) — seeds _dispatch_promoted= Loading Loading
debian/changelog +29 −0 Original line number Diff line number Diff line libnetplus (20260801+30) unstable; urgency=high * quic: fix accept()'s datagram-drain loop stalling on a contended per-connection mutex. Two sites — the inline long-header path for an existing connection, and flush_pending_app()'s deferred short-header flush — took an existing child connection's quic_mtx() with a blocking unique_lock. Both run inline on the single thread that drains a given listener (see accept()'s own concurrency note), so a connection busy elsewhere (e.g. mid-transfer, holding its own mutex for real work) could stall this entire drain call — and with it, every other connection's traffic in the same batch, and any brand-new incoming connection sitting later in it — for as long as that other thread held the lock. Root-caused live on a production mediadb node: a healthy peer's accept loop was blocked in pthread_mutex_lock()/quic::accept() while a client elsewhere (paritypp::client::connect_to_node()) got "Failed to connect to node X" on every 5-second-bounded retry, for minutes, even though ping and the peer's own accept-loop threads looked otherwise fine. Both sites now use try_lock and skip (rather than block) when a connection's mutex isn't immediately free — QUIC's own loss detection retransmits whatever gets skipped, far cheaper than blocking the shared accept path. Full existing QUIC test suite (87 tests across quic_test/quic_rfc9000_test/quic_concurrent_test/ quic_incremental_dispatch_test/quic_retry_test/ quic_version_negotiation_test/quic_roundtrip_sha256_test) passes unchanged; benchmark_quic throughput unaffected. -- Jan Koester <jan.koester@tuxist.de> Sat, 01 Aug 2026 06:43:00 +0200 libnetplus (20260731+29) unstable; urgency=high * socket: add setStartDispatchPromoted(bool) — seeds _dispatch_promoted= Loading