Repository navigation
engines: OnDetach rollback first, io_uring pause wake, zoned bind address, one-dump NIC table, MaxEvents by allowed nodes, upgrade-carry count, backlog hook (v1.6.0, Refs #885 #886 #889 #890) - #1127
Merged
Conversation
|
Caution Review failedThe pull request is closed.
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
FumingPower3925
force-pushed
the
l7-xeng
branch
2 times, most recently
from
October 27, 2026 00:15
eb3e9e8 to
c18146b
Compare
… Refs #885 #886 #889 #890) Failing-first half of the lane. Every behaviour change below has a test here that fails on baa43d9; the fixes follow in the next commit. 886.23 has its own test and fix commits at the end, so that it can be dropped on its own. - 889.48: OnDetach panic injected right after the count (detachPostCountHook, a no-op seam called between the rollback's snapshot and the place the rollback is registered); io_uring rollback test also asserts the detachedConns gauge. - 890.22: TestBackloggedPeerIsClosed waits for the engine's refusal (conn.BacklogRefusedHook, defined here, called in the next commit) instead of sleeping. - 885.54: parseAddr of a zoned IPv6 host, Listen on a zoned link-local address on both engines, and a Server start on one for every engine including adaptive. - 886.24: BeginPauseAccept must signal the io_uring workers' wake eventfd; pause-to-closed lag measurements for both engines. - 885.31: the MaxEvents split follows the nodes the allowed set meets (splitMaxEvents, detectNUMA seam; the split still uses the host count here). - 885.53: osIfaceAddrs is one RTM_GETADDR dump (netlinkRIB seam).
The fixes for the tests of the previous commit. - 889.48: OnDetach's rollback is registered right after the snapshot, before detachMu is allocated and the count is made, and the promoted-path gate is decided there from the snapshot's detachMu; the sync path's reliance on the rollback leaving detachCounted false is commented. Both engines. - 890.22: conn.BacklogRefusedHook is called where a request is refused for the back-pressure cap, and TestBackloggedPeerIsClosed waits for it instead of sleeping 100 ms. - 885.54: parseAddr reads a zoned IPv6 host with netip and sets the scope id as net.Listen does (bindiag.ZoneID). Both engines. - 886.24: io_uring's BeginPauseAccept signals every worker's wake eventfd after it stores the flag. epoll's is not changed: its listening loop waits at most 4 ms (measured 0.8 to 5.9 ms). The 2-worker pause test joins the CI step that runs the multi-worker listener tests by name (ci.yml). - 885.31: epoll divides MaxEvents by the NUMA nodes the plan's allowed set meets, not the host's node count. - 885.53: osIfaceAddrs reads all addresses from one RTM_GETADDR dump, mapped by interface index, instead of one dump per interface (311 interfaces: 21.6 ms to 0.94 ms, 313 netlink requests to 3). - 885.14: h2PoolSettled's doc says what becomes of a refused GOAWAY.
…886) No behaviour change. - 886.9: endH1Verdict of both engines states the OnError difference on a conn with no detachMu (epoll delivers, io_uring does not), how a sync conn gets into that state, and that the rule is an open decision. The io_uring side is pinned by two tests (the epoll side already was). - U-12: the rx-port rule's doc says when it does not engage (since-boot counters at the first Listen; an evenly split network) and that it is left as it is. Godoc only; nothing in README.
…uest (v1.6.0, Refs #886) The four h2c-upgrade-carry replay tests expect 0 requests and read the 101 off the client first (expectCount886 returns at once on 0 and only holds 400 ms, so without the 101 it could pass before the replay ran). They fail on baa43d9 (the replay counts 1). Kept apart from the rest of the lane on purpose: the fix touches the two reqBatch++ lines of epoll/adopt.go that #1122 rewrites (recvCounted), so this pair is the one to drop or rebase.
…lay (v1.6.0, Refs #886) 886.23: the recv path (drainRead, handleRecv) returns on the upgrade verdict before it counts, so a conn that upgraded on a recv counted its upgrade request as none, while the replay of a carry that is an upgrade request counted one. The replay now counts none, at the four sites (epoll sync and async, io_uring sync and async). The other rule needs drainRead/handleRecv. h2 conns count no request on either engine, so BytesPerReq moves by one request per upgraded conn that was replayed. On epoll the condition sits beside #1122's: `!recvCounted && !errors.Is(perr, conn.ErrUpgradeH2C)`. A reclaim of an upgrade carry keeps the count drainRead made when it read the bytes (it counts before it transplants), so that one case still counts 1; it needs drainRead.
FumingPower3925
force-pushed
the
l7-xeng
branch
from
October 27, 2026 00:37
c18146b to
e39fd57
Compare
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
… malformed zone (v1.6.0, Refs #885) - 885.53: a dump whose last attribute is not padded to 4 makes the std attribute walker panic (slice bounds out of range [12:9]); rows through addrsByIndex for the review's fuzz crasher and six hand-built ones, and TestOSIfaceAddrsFallsBackOnAnUnparseableDump885. The binary panics before the fix. - 885.54: ZoneID rows for a malformed zone ("12abc" is 12, a number of 0xFFFFFF or more saturates), in bindiag and in both engines' parseAddr table, whose oracle now follows net's rule.
…a malformed zone as std does (v1.6.0, Refs #885) Fixes for the tests of the previous commit (review of #1127). - 885.53: addrsByIndex recovers from the std attribute walker's panic on an unpadded final attribute and reports not-ok, so osIfaceAddrs builds the table the old way, as its doc says. A comment says an interrupted dump (NLM_F_DUMP_INTR) is read as net reads it. - 885.54: bindiag.ZoneID reads the digits a zone starts with and saturates at 0xFFFFFF, as net's dtoi does, instead of returning 0 for "12abc" and for a number past 32 bits. The smaller change of the two options (matching std rather than narrowing the godoc). - the backlog test's comment says a peer-address mismatch fails after 10 s and cannot pass falsely.
FumingPower3925
marked this pull request as ready for review
October 27, 2026 02:25
19 of 31 tasks
FumingPower3925
added a commit
that referenced
this pull request
Oct 27, 2026
…the merged tree (Refs #890 item 87) Main 8936e89 (with #1123 and #1127) run through the job's logic in docker at CELERIS_MAX_IOURING_TIER=base: the iouring package gives 577 top-level PASS and 13 SKIP lines, the new one being TestListenOnAZonedLinkLocalServes885 (the container has no fe80:: address); root and test/server give 118 PASS and 46 SKIP lines, all allowed. The zoned test fails instead of skipping under CELERIS_REQUIRE_ZONED_PEER=1, as in the unit job, so both steps set it and the list stays as it was. min-pass floors 540 and 105.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Lane L7 XENG of v1.6.0, cross-engine small fixes. Refs #885, Refs #886, Refs #889, Refs #890.
Review r1 (Opus) approved with fixes; commits 6 and 7 are its fixes (tests first), and main (a5fb8f1 and later, #1123 included) is merged in with a merge commit, no conflict.
Method: each item's premise was checked on main (baa43d9) first; the branch is rebased onto 3f420c6 (#1122 and #1118 merged). Commit 1 is the tests (and the no-op seams they need), red on main; commit 2 is the fixes; commit 3 is comments and godoc, no behaviour; commits 4 and 5 are the tests and the fix of 886.23 alone, so that pair can be dropped or rebased on its own (it was the one item that conflicted with #1122, see below). Item numbers are the ordinal of the checkbox in the issue body, counting every box, ticked or not (not the numbers of #1099, which counts only the unticked ones); each row quotes the item's opening words.
loop.go~2324, io_uringworker.go~3066 ..."detachMuallocation and the count; the io_uring rollback test did not assert thedetachedConnsgaugeTest{Epoll,Iouring}AdoptRequestCountUpgradeCarry886)TestSplitBodyResponsesKeepTheConnectionandTestConcurrentResponsesOwnTheirBodieswere already replaced by #1055;TestBackloggedPeerIsClosedstill slept 100 ms (backlogGrace761)parseAddrrefuses a zoned IPv6 bind address"invalid addr: [fe80::1234%dz0]:0; epoll, io_uring and adaptive fail to start throughceleris.New(...).Start())BeginPauseAccept... only storesacceptPausedand does not signal the wake eventfd"internal/platform): the NIC interrupt detection of PR #1062 builds its interface table withnet.Interfaces()thenAddrs()"len(events)only above 4 nodes (finding below)OnErrordelivery on a conn with nodetachMudiffers by engine"rxFreeCPUsonly, no README889.48 (OnDetach rollback)
OnDetach(epollLoop.initProtocol, io_uringWorker.initProtocol) registered its rollback insideif !unlockDetachMu, which was computed afterdetachMuwas allocated and the count made. A panic between the snapshot and that point left the count (anddetachedConns) up,detachMuset andasyncDetachPendingset. Now the gate is computed from the snapshot (prevMu != nilin place ofcs.detachMu != nil: in sync model.asyncis false so the gate is false either way; in async modedetachMuwas allocated atacquireConnState, soprevMuis not nil; the one state where they differ, async + promoted + no mutex, could not unlock a mutex it does not hold anyway) and the rollback is registered right after the snapshot. The sync path's reliance on the rollback leavingdetachCountedfalse is commented.Test: a new seam
detachPostCountHook(nil in production, called once per Detach between the count and the install; same shape asdetachPostInstallHook) letsTestOnDetachPanicLeavesTheConnAsIfNeverRan889panic right after the count: red on main (detachedCount=1 counted=true,cs.detachMu is still set,asyncDetachPending is still set, and on io_uringthe detachedConns gauge is 1), green now. The io_uring test also asserts the gauge in the early and late cases (the port ofTestFinalGaugeRolledBack); that part passes on main, it is a stronger test, not failing-first.886.23 (request count of an h2c upgrade carry): commits 4 and 5
Rule picked: the replay counts none for an upgrade carry (
!errors.Is(perr, conn.ErrUpgradeH2C)at the epoll sync/async and io_uring sync/async replay sites). The other rule needsdrainRead/handleRecv(not mine to edit here). h2 conns count no request on either engine, so the upgrade request is not counted anywhere afterwards;BytesPerReqmoves by one request per upgraded replayed conn, as the issue says. The four pinned tests now expect 0 and read the 101 off the client first (expectCount886returns at once on 0 and only holds 400 ms; without the 101 it could pass before the replay ran).Conflict with #1122, resolved:
attachAdoptedFDandreplayCarriedAsyncare functions #1122 rewrote (they were not on the list of functions to keep away from, but the same tworeqBatch++lines are involved), which is why this item is a commit pair of its own. #1122 and #1118 merged while this was open (main is now 3f420c6); this branch is rebased onto it, and the epoll condition isif !recvCounted && !errors.Is(perr, conn.ErrUpgradeH2C) {at both sites../internal/engine/epoll/...passes on the rebased tree, plain and-race(TestReclaimTransplantDoesNotCountTheCarriedRecvTwice886included). One corner stays: a reclaim of an upgrade carry keeps the countdrainReadmade when it read the bytes (it counts before it transplants), so that one case counts 1; it needsdrainRead.git merge-treeof this branch with #1123's head (fetched after the rebase): clean.890.22 (sleep in
TestBackloggedPeerIsClosed)conn.BacklogRefusedHook(nil in production) is called inhandleH1Requestin the branch whereWriteBacklogged()answers true and the request is refused (ErrWriteBacklog), with the peer address; the test watches its own client address and waits for it (std has no cap: no wait). The call is out of line (//go:noinline), in the taken branch only: the code of a request that is served is unchanged. The test went from 2.3 s to 0.34 s for the nine native arms.Hot path (the branch sits beside the per-request
WriteBackloggedquery):BenchmarkProcessH1Backlogged890(a GET with the query installed, answering false), docker--cpus 2, 12 rounds interleaved main / this PR / A/A twin of main, 1 s each, medians:this PR / main 0.996, twin / main 1.001 (the noise floor).
"Can fail falsely" was NOT reproduced:
backlogGrace761set to 0 on main,TestBackloggedPeerIsClosed10 of 10 pass, and 10 of 10 pass under 8 busy-loop processes on the same 2 CPUs. So this is a removal of a timing guess for the 100 ms that cost, not a fix of an observed flake. Red state: with the seam defined but not called (commit 1) the test fails in nine arms (no request was refused within 10s).885.54 (zoned bind address)
parseAddr(both engines): a host with a%is read withnetip.ParseAddr, which keeps the zone, and the zone becomesSockaddrInet6.ZoneIdthroughbindiag.ZoneID, std's rule (net'sipv6ZoneCache.index, read in go1.27.3): the interface of that name, else the decimal digits the zone starts with (12abcis 12; a number of 0xFFFFFF or more saturates at 0xFFFFFF, net'sdtoi), else 0 (the bind then fails for a link-local address, as std's does). The first version returned 0 for12abcand for a number past 32 bits while its godoc claimed std's rule (review nit); I matched std (the smaller change: eight lines, against narrowing the godoc and leaving a difference), with rows inTestZoneIDIsStdsRuleand in both engines'parseAddrtable. An IPv4-mapped host is IPv4 whatever its zone, and1.2.3.4%lo,[fe80::1%],[%lo]are errors, all asnet.ResolveTCPAddrdoes (checked in a container;[fe80::1%lo%lo]is a zonelo%lofor std too and here). The old table row that pinned the error ([fe80::1%eth0]:80) is replaced byTestParseAddrReadsAZonedIPv6Host885, which compares each row withnet.ResolveTCPAddr.TestListenOnAZonedLinkLocalServes885listens on[fe80::1234%dz0]:0(a dummy link;--cap-add NET_ADMIN, ipv6 on), serves a request and checksAddr()prints the zone asnet.Listendoes; it skips without a link-local address and fails underCELERIS_REQUIRE_ZONED_PEER=1.bindiag.WithPortneeded no change.TestZonedListenAddressServesOnEveryEngine885(test/server) goes through the exported API:celeris.New(Config{Engine, Addr: "[fe80::1234%dz0]:port"}).Start()for std, epoll, epoll-async, io_uring, io_uring-async and adaptive (its port hold included), a request to the zoned address, and, for the native engines,Addr()printing the zone (std's ownAddr()printed no zone on a hosted runner in the first CI run, so it is not asserted; std is the oracle here); on main five of the six arms fail withinvalid addr(adaptive:sub-engine startup failed ... invalid addr), now all pass. The CI root step already runs./test/serverwithCELERIS_REQUIRE_ZONED_PEER=1.886.24 (BeginPauseAccept wakes the workers): io_uring changed, epoll declined
The item names both engines; only io_uring changed. Epoll was declined on measurement: its listening loop waits at most 4 ms (
adaptiveTimeoutMs, base 1 ms times 4), and the measured pause-to-closed lag is 0.8 to 5.9 ms (table below). Ticking 886.24 must not read as a code change on both engines: add "epoll: not changed, measured 0.8-5.9 ms, the wait is capped at 4 ms" to the item when ticking.Measured first, before the change:
BeginPauseAccept(DisableDeferAccept, so the listener closes at once) to no listener in the kernel's table, 2 loops / workers, 3 runs of 8 cycles = 24 samples per arm, a 1.2 s idle settle then 0.3 s before each cycle (ms):So on io_uring the tail the issue describes is real (up to 99 ms) and rare (the sweep tick keeps the median near 5 ms); epoll's is not:
adaptiveTimeoutMscaps a listening loop's wait at 4 ms, andrun()'s own comment says so ("while the listener is open the wait is already at most a few ms"). The signal costs epoll a write per loop per pause for nothing, so epoll'sBeginPauseAcceptis not changed (the issue asked for both; premise false for epoll). Its lag test is kept as a guard (bound 100 ms; it passes on main).Fix (io_uring
Engine.BeginPauseAccept): after the flag store,wakeFD.Signal()on every worker undere.mu(asResumeAccept, after the store so a woken worker reads the flag set). Deterministic test, red on main:TestBeginPauseAcceptSignalsEveryWorkerWakeFD886(three workers with real eventfds; the counter must be non-zero). The end-to-end lag test cannot fail reliably before the change (the tail is rare), so it is a guard with a loose bound (100 ms, every arm). Its 2-worker arm needs raised memlock, soTestBeginPauseAcceptReachesAnIdleWorker886is added by name to the CI step that runs the multi-worker listener tests withCELERIS_REQUIRE_IOURING_WORKERS=1(ci.yml: the name list, the comment and the count, now eight); lags there under-racein my container: median 0.5 to 1.6 ms, max 3.0 ms (24 samples per arm).886.11: its flap-inside-pause-latency sub-point is this item; the 250 ms bound stays (U-14: keep as a safety net).
885.31 (MaxEvents split)
splitMaxEvents(maxEvents, topo, plan.Allowed)divides by the nodes whose CPU list meets the plan's allowed set; where that cannot be told (no allowed set, no per-node CPU lists, none of the allowed CPUs on a listed node) it uses the host's count, as before. Seams:detectNUMA. Tests (red on main): the tableTestSplitMaxEventsFollowsTheNodesTheAllowedSetMeets885and, throughListen,TestListenSplitsMaxEventsByTheNodesOfThePlan885(8-node host stood in: a process kept to one node gets 2048 events per loop, one spanning the nodes 1024).Finding: a loop's event array is
min(MaxEvents, 2048)(maxEpollEvents) and the default MaxEvents is 8192, so the split shows inlen(events)only on a host with more than 4 nodes (8192/5 < 2048), or with a configured MaxEvents under2048 x nodes. On the usual 1 to 4 node hosts the fix changes nothing observable. The issue's "larger MaxEvents on a restricted host" is true for the resolved value, not for the array.885.53 (interface table: one dump)
osIfaceAddrsisnet.Interfaces()(one RTM_GETLINK) plus oneRTM_GETADDRdump mapped by interface index (parseAddrRIB: IFA_LOCAL if present, else IFA_ADDRESS, asnet'snewAddr; mapped IPv6 unmapped; the 512 cap and the order are kept); if the dump cannot be read or parsed it builds the table the old way. That includes a panic of the std attribute walker (syscall.ParseNetlinkRouteAttr, whichnetcalls on the same bytes) on a final attribute that is not padded to 4, which a kernel dump never has:addrsByIndexrecovers and reports not-ok (review minor 1; the fuzz crasher and six hand-built unpadded dumps are table rows, andTestOSIfaceAddrsFallsBackOnAnUnparseableDump885checks the fallback table; the test binary panics before the fix). An interrupted dump (NLM_F_DUMP_INTR) is read asnetreads it, and the code comment says so. Seam:netlinkRIB. Equivalence with the old per-interface table on the host's own interfaces:TestOSIfaceAddrsIsOneAddressDump885(red on main: the seam sees 0 dumps; it counts 1 now).TestParseAddrRIB885builds dumps byte by byte (point-to-point in both attribute orders, IPv6, mapped, interleaved interfaces, another family, short or oversized messages, messages after NLMSG_DONE);TestHostDumpParses885rejects the silent fallback.Measured, docker
--cpus 2, 311 interfaces (300 dummy links with an address each), 10 runs each,BenchmarkOSIfaceAddrs885againstBenchmarkRefIfaceAddrs885(the old code verbatim, in the same binary):sendtocalls (strace, one call)(The 3: the RTM_GETLINK of
net.Interfaces, the one RTM_GETADDR, and the benchmark's ownnet.Interfacesfor the interface count.) This is the startup cost of the detection, paid again at the adaptive engine's standbyListen. The first-cluster-run figure the issue suggested (irq_took) is not used.885.14 and 886.9: comments
885.14: read from the code, not measured (the lane plan makes it comment-only; the issue also asked for an explicit close and a test, which this does not do). A refused GOAWAY (the conn's backlog is over the 64 MiB h2 cap, so its peer stopped reading) sets
writeRefused;h2PoolSettleddoes not look at it. Traced: the nextdrainH2Writeswith a frame queued closes the conn (epoll discards the queue andcloseWhenFlushed; io_uringcloseConn), a read of the conn findswriteRefused(epolldrainRead's tail; io_uringhandleRecv) and ends it, and a conn with none of those is notbusyinh2PoolSettled, so the pass settles and shutdown closes it. What is lost is the client's graceful notice from a peer that was not reading; the cost of a conn that stays busy (OutboundPendingwith a WINDOW_UPDATE that never comes) is the wait up to the drain's bound. Bothh2PoolSettleddocs say so.886.9: the item asks "if it cannot [hold a callback without a
detachMu], state that in both engines, otherwise pick one rule". It can, so no rule is stated as unreachable. A sync conn holds anOnErrorwithout adetachMuwhen a handler registers one (Context.SetWSErrorHandler, exported) and does not Detach, and after a Detach that panicked and was rolled back (the rollback putsdetachMuback to nil, the callback stays; websocket and sse register before they Detach, so this is how they get there). epoll'sendH1Verdictthen delivers it, io_uring's does not (if mu != nil).TestEpollRecvPathOnErrorSync908andTestEpollAdoptCarriedOnErrorSync908pin epoll's side; the two new testsTestIouringRecvPathOnErrorSyncNoDetachMuIsDropped886andTestIouringAdoptCarriedOnErrorSyncNoDetachMuIsDropped886pin io_uring's (run 3 of 3). BothendH1Verdictdocs now say it. Picking the rule is still open: ticking this box on the strength of comments alone is the maintainer's call.U-12 (rx-port rule note)
rxFreeCPUs's godoc (internal/platform/cpuplan_rxfree_linux.go) now says when the rule does not engage (since-boot counters read once at the firstListen; msr1's two bond ports split each cell about 50/50: enp49s0 median 50.0%, range 39.2% to 61.8% over 64 cells, so no window reliably shows one port over the 60% of step 1) and that the rule is left as it is. No README change, no io512 claim.Tests run
Local, docker
golang:1.27.3,--cpus 2, one container at a time.-race./internal/engine/epoll/..../internal/engine/iouring/...(memlock unlimited, seccomp unconfined)./internal/platform/...(incl.pintest)./internal/conn/..../internal/engine/internal/bindiag./test/server(TestBackloggedPeerIsClosed,TestStreamedResponseIsDelivered,TestPipelinedResponsesOwnTheirBodies,TestConcurrentResponsesOwnTheirBodies, the 761 group)-count=5, in a container with a dummy linkdz0(CELERIS_REQUIRE_ZONED_PEER=1)TestZonedListenAddressServesOnEveryEngine885, same containerTestBeginPauseAcceptReachesAnIdleWorker886+ the eventfd test,-count=3./internal/adaptive/...FAILS in this container, and fails the same on main:TestReverseTransplant,TestReverseTransplantAsync,TestBidirectionalFlap,TestBidirectionalFlapAsync(the controller switches by itself under the test's own load: "engine switch recommended ... sustained high load", thenreverse transplant did not converge). On baa43d9 and on this branch,-run 'TestReverseTransplant|TestBidirectionalFlap' -count=3: 12 of 12 fail on each. Every other adaptive test passes (12,315 test events). Not caused by this PR, not investigated further here.Red on main: the tests of commits 1 and 4 run on those commits (main plus the no-op seams):
TestOnDetachPanicLeavesTheConnAsIfNeverRan889/count/{sync,async-unpromoted}(both engines),Test{Epoll,Iouring}AdoptRequestCountUpgradeCarry886and...Async886(RequestCount after the adoption = 1, want 0; commit 4),TestParseAddrReadsAZonedIPv6Host885andTestListenOnAZonedLinkLocalServes885(both engines;invalid addr: [fe80::1234%dz0]:0),TestZonedListenAddressServesOnEveryEngine885(five of six arms),TestBeginPauseAcceptSignalsEveryWorkerWakeFD886,TestSplitMaxEventsFollowsTheNodesTheAllowedSetMeets885,TestListenSplitsMaxEventsByTheNodesOfThePlan885/process-kept-to-one-node,TestOSIfaceAddrsIsOneAddressDump885, andTestBackloggedPeerIsClosed(nine native arms,no request was refused within 10s). Logs: scratchpadl7xeng/logs/red-*.log.golangci-lint run ./internal/... ./test/...(arm64 and amd64): 3 issues, allerrcheckininternal/engine/std/*_test.go, files this PR does not touch.mage apiCheck: matches (no exported API changed: the new identifiersconn.BacklogRefusedHookandbindiag.ZoneIDare internal).Mutants (each fails the named test, then restored)
detachedConns.Add(-1)TestOnDetachPanicLeavesTheConnAsIfNeverRan889(count, early and late, sync)cs.detachCounted = falseTestOnDetachPanicLeavesTheConnAsIfNeverRan889(count, early, late).../count/sync,.../count/async-unpromoted, both enginesTest{Epoll,Iouring}AdoptRequestCountUpgradeCarry886,...Async886BeginPauseAcceptwithout the signalTestBeginPauseAcceptSignalsEveryWorkerWakeFD886TestBackloggedPeerIsClosed(nine native arms)ZoneIdalways 0, each engineTestParseAddrReadsAZonedIPv6Host885,TestListenOnAZonedLinkLocalServes885TestSplitMaxEventsFollowsTheNodesTheAllowedSetMeets885,TestListenSplitsMaxEventsByTheNodesOfThePlan885TestParseAddrRIB885/p2p-address-first,/p2p-local-firstTestParseAddrRIB885(all rows),TestHostDumpParses885Release notes
BeginPauseAccept, the adaptive engine's switch) now reaches an idle worker at once; before, a worker whose ring wait had not ended saw it up to 100 ms later (measured max 99 ms, median 4.8 ms; now max 4 ms).[fe80::1%eth0]:8080) now binds, as it does on the std engine; before, both engines refused to start on it.RequestCount, as the receive path does (it counted one).MaxEventsis divided by the NUMA nodes the process may use, not by the host's node count (visible in the event array only above 4 nodes).Found, not fixed here
drainReadmade (needsdrainRead).busywaits up to the drain bound; an explicit close inh2PoolSettledwould remove that wait; not done (comment-only item).maxEpollEvents) makes the split a no-op up to 4 nodes.For the reviewer to attack
prevMu != nilis the same gate as the oldcs.detachMu != nilon every reachable state, and that registering the rollback before the mutex allocation changes nothing for the promoted path (it is registered only for!unlockDetachMu).drainRead/handleRecv), and that no consumer ofRequestCountfor an h2 conn expects the upgrade request counted.handleH1Request's taken branch), keyed onH1State.RemoteAddr(the test relies on it equalling the client'sLocalAddr().String(); a mismatch, a v4-mapped peer on a dual-stack listener, fails loudly after 10 s and cannot pass falsely, as the test's comment says), and that//go:noinlinekeeps the served path unchanged (the benchmark says so).bind(2)with EINVAL instead of at parse.adaptiveTimeoutMswithbase1 ms; a loop with a driver conn or a dirty list waits less.net'snewAddron a message whose attributes are in an unusual order (the typed pick differs from net's "first attribute" only there); the fallback path.nodesMetcounts the nodes that hold an allowed CPU, so on a host with CPU-less memory nodes (CXL) even an unrestricted process now divides by fewer nodes thanNumNodesand gets a largerMaxEventsthan before (only visible above 4 nodes, see the finding).