Repository navigation
[Bugfix][TENT] Don't throw when aggregating transfer status during teardown - #3768
Conversation
|
The new completion wait can deadlock when one benchmark worker fails before every other worker has dequeued its assigned task. Please account for every scheduled slot exactly once even when a worker exits before dequeue—for example, cancel and retire still-assigned tasks under Related non-blocking cleanup: |
|
@catyans Thanks — that hang is real. The assigned slot is now retired under the gate mutex on the stop path, so every scheduled slot still contributes to completion. |
3a557e8 to
953d820
Compare
tebench called exit() from worker threads when a transfer FAILED, so a SIGKILL'd RDMA target made concurrent workers abort with unordered_map::at. Return failure to main so threads can join, rank unknown statuses without throwing, and wait on stop or pending==0 under the mutex like classic TE. Signed-off-by: staryxchen <staryxchen@tencent.com> Co-authored-by: Cursor <cursoragent@cursor.com>
953d820 to
13803d7
Compare
catyans
left a comment
There was a problem hiding this comment.
LGTM. Re-reviewed the current head; transfer failures now stop the atomic run state, release the batch, wake the task waiters, and let runInitiatorTasks() return so stopInitiator() can join every worker. All CI checks pass.
suggestion (non-blocking): the FailureBeforeDequeueDoesNotHang regression mentioned above is not present in the current squashed head. Please restore that deterministic coverage in this PR or a follow-up.
Description
When an RDMA peer disappears (process SIGKILL, host crash), posted writes
often complete with no error CQE. Slices wait for the software timeout,
failover exhausts the only enabled transport, and
getTransferStatusreports
FAILED. Clients that poll from several threads then tear downthe engine (or exit the process) overlap
getBatchStatuswith destructionof a function-local
unordered_map..at()throwsstd::out_of_range,which during
terminate/exitbecomesterminate called recursively.That is an engine teardown bug, not a benchmark-only failure. tebench
with 8 initiator threads and a killed target is how we reproduced it
end-to-end; any multi-threaded Transfer Engine client that stops the
engine on
FAILEDcan hit the same throw.This change:
transferStatusSeverity()(a switch,unknown values treated as
FAILED) sogetBatchStatusnever throwsfrom
unordered_map::atduring teardowncalling
exit()on eachFAILED(also treatsTIMEOUT/CANCELED/INVALIDas terminal so the poll loop cannot spin)No GitHub issue filed. Distinct from #3636 (worker self-deadlock on a
full MPSC queue); this path reached
FAILEDin ~12s.Module
mooncake-transfer-engine)mooncake-store)mooncake-reshard)mooncake-ep)mooncake-pg)mooncake-integration)mooncake-p2p-store)mooncake-wheel)mooncake-common)mooncake-rl)Type of Change
How Has This Been Tested?
Test commands:
Test results:
Unit tests pass
Integration tests pass (if applicable)
Manual testing done (describe below)
tent_failover_test: 16/16 passed (includingTransferStatusSeverityTestknown ranks and unknown enum)Two-node DRAM / TENT / RDMA, 8 concurrent transfers × 1MB WRITE:
SIGKILL peer →
FAILEDsurfaced, process exit 1; noterminate called/unordered_map::at. Previously abort, exit 134.Checklist
./scripts/code_format.shAI Assistance Disclosure
Cursor (Grok 4.6) helped diagnose the status-aggregation throw during
peer-death teardown, implement the ranking helper and stop-without-exit
path, and retest with a killed peer. The submitter reviewed every changed
line and reproduced the failure before and after the fix.
Made with Cursor