Repository navigation
test(yamux): wait for the pong deadline before the clock moves - #83
Conversation
The keepalive check advanced the test clock past the pong deadline without waiting for the timer. The alarm reads the time, then arms a timer for the time left, and TestClock counts that from its own now. An advance that fell between the two steps left the timer due past the clock. The deadline never fired. The join waited forever, in about one run of the suite in fifty at four workers. The check now waits, through nextTimer, for the two timers the ping arms: the writer's deadline for its write, and the ticker's for the pong. TestClock's doc asks this of every advance, and every other advance in the suites already does it. The session code is unchanged: on the system clock the gap only makes a timer late by the time between the two steps, and no timer fires early.
The check asserts that the writer's deadline and the pong deadline armed, but its message named only the pong. A run where the write timer missed its arming would print a message about the pong, and send the investigation the wrong way. The message now names both.
dff45f3 to
2d85a06
Compare
|
Reviewed at 2d85a06. I rebased the branch onto origin/hackathon26 (5fa9e63, which carries the merged #84); the rebase was clean. The branch now holds the author's commit b63a8fc and one nit commit of mine, 2d85a06, pushed to the fork. Test-only. Both commits touch The race, checked against the code. The wait semantics, checked. The keepalive ping arms exactly two timers: the writer's write deadline, which Other advances in the file. Nit, fixed and pushed. The new check's message named only the pong deadline, while its condition asserts both timers. A run where the write timer missed its arming would have printed a message about the pong, and sent the investigation the wrong way. Commit 2d85a06 rewords the message to name both. Checks I ran. Stress. I ran the test binary 30 times at default workers, each under a 60 s timeout: 30 of 30 pass. That is on top of the two The fix restores the documented rule every other advance follows, and the hang at the merged tip goes with it. APPROVE |
Summary
The test binary hung in about one run in fifty at 4 workers. The cause is the keepalive check of the yamux suite: it advanced the test clock past the pong deadline without waiting for the timer, as
TestClock.nextTimerasks of every advance. This PR adds the wait. The session code does not change.What changed
Tests/Yamux.lean, the keepalive check ofhostileChecks:pingDeadlineMs, the check waits throughtc.nextTimerfor the two timers the keepalive ping arms: the writer's deadline for its write, and the ticker's deadline for the pong. A new check records that both armed.The race
Conc.Alarm.runreadsclock.nowMs, then armsclock.after (due - now).TestClock.aftercounts the wait from the clock'snowat the moment of arming. When the test's advance fell between the read and the arming, the pong timer was due atI + 2Pon a clock that stopped atI + P. The tick never came, andserver.joinwaited forever with every task parked.On the system clock the same gap only makes a timer late by the time between the two steps, and the clock contract allows a late timer ("no timer fires early"). So the session is correct, and the test broke the documented
TestClockrule. Every otheradvanceinTests/already waits onnextTimer, or arms its timer in the test itself.How it was found: under gdb, one hung run showed
mainwaiting inConc.Async.run, every pool worker idle, and libuv with no work. Stderr markers per section, then per check group, then per block narrowed it to this check onhackathon26itself (hangs at runs 2, 26, and 146 of the marked loops).Test plan
lake build --wfailis green.lake testpasses: 27170 passed, 0 failed, 10 skipped. It passes again withLEAN_NUM_THREADS=1.Risk / trust footprint
None. The change is in a test.
Notes for reviewers
hackathon26. It is the hang that refactor(negotiate): run the upgrader over the seam types of libp2p/core #82's description notes.LICENSE (LGPL version 3)