fix(python-node): seed the pool-id counter randomly so restarts don't collide - #3056
fix(python-node): seed the pool-id counter randomly so restarts don't collide#3056phil-opp wants to merge 2 commits into
Conversation
… collide
Memory-pool shared-memory names are "dora_pool_{dataflow_id}_{node_id}_{counter}",
where the counter comes from a process-local static seeded at 0. Both
dataflow_id and node_id are stable across a crash-restart, so a restarted
node re-derives the exact same name as its previous incarnation. When the
old pool is still live — the sender crashes while its receiver keeps
reading, so #2881's reclaim deliberately retains it — ShmemConf::create()
fails on the leftover segment and the daemon also rejects the registration
as a duplicate. Under restart_policy: Always this is a crash-restart loop
that never recovers.
Seed PINNED_COUNTER with a random u64 (via std's OS-seeded RandomState, no
new dependency) so each incarnation gets a distinct name. The counter stays
a plain u64, so both existing name parsers (the writer fast path and
try_doradma_read) keep working unchanged. Increment via wrapping_add to
guard the now-possible overflow from a near-max seed.
Fixes #3015
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KwYrfJpHX6PSwoewwKyA9z
|
Merging to
After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here |
|
Automated review by Claude — fully automated, no human reviewed this before posting. Reviewed the change that seeds (Minor, non-blocking: Generated by Claude Code |
|
The hazards check out — every parser is With the collision gone, nothing reclaims the dead incarnation's pool. Also: neither new test can go RED (one exercises a function this PR introduces, the other re-implements the parser inline instead of calling it), and |
…ment Address review on #3056: - Extract pool_shmem_name / parse_pool_counter as the single source of truth for the on-wire pool-id format, replacing ~7 duplicated inline format!/rsplit_once+parse sites. The round-trip test now exercises the real production functions (can go RED if the format regresses) and covers node ids containing underscores plus a non-numeric tail. - Document the leak trade-off: with the collision gone, a pathological crash-loop whose receiver never frees now leaks a pool per restart up to the registry cap, instead of failing fast. The complete fix is an owner-death reclaim, tracked as follow-up. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KwYrfJpHX6PSwoewwKyA9z
|
Thanks — both points are fair. Pushed Pool leak with the collision gone. You're right that this converts fail-fast into fail-after-N: a repeatedly-crashing node whose receiver never frees now leaks a registry entry + Tests. Agreed the originals were tautological. I extracted Generated by Claude Code |
|
🤖 Automated review by Claude — fully automated; not vetted by a human. Reviewed the latest commit Generated by Claude Code |
|
Removed from the 1.0 milestone: the memory-pool transport is being parked out of the tree in #3152, so #3015 no longer blocks 1.0. This fix is not in the parked copy — #3015 is recorded in |
|
Makes sense — happy to carry this into the parked copy. I checked #3152: One sequencing question, since
I'd lean toward (2) to avoid basing on a branch that's still moving, and I'll keep #3056 as the in-tree fix in the meantime in case #3152 doesn't land — but I'll do whichever you prefer. Either way I'll flip the README re-entry row from "PR #3056 open" to the fix being present in the parked copy. Generated by Claude Code |
|
Correction to my earlier note on this issue. The memory-pool transport is not being moved out of the repository after all. It is now an opt-in extension at |
Summary
Fixes #3015.
Memory-pool shared-memory names are
dora_pool_{dataflow_id}_{node_id}_{counter}, wherecountercomes from a process-local static (PINNED_COUNTER) seeded at0. Bothdataflow_idandnode_idare stable across a crash-restart, so a restarted node re-derives the exact name its previous incarnation used.When the old pool is still live — the sender crashes while its receiver keeps reading, so #2881's reclaim deliberately retains it —
ShmemConf::create()fails on the leftover/dev/shmsegment, and the daemon independently rejects the registration as a duplicate. Underrestart_policy: Alwaysthis is a crash-restart loop that never recovers.#2881 fixed when pools are reclaimed; this is the separate question of pool ids not being unique across incarnations.
Change
PINNED_COUNTERwith a randomu64per process (via the standard library's OS-seededRandomState— no new dependency) so each incarnation derives a distinct name. The counter stays a plainu64, so both existing name parsers (the writer fast path andtry_doradma_read) keep working unchanged — this is the direction the issue recommends.wrapping_addto guard the now-possible overflow from a near-max seed.rsplit_once('_')+parse::<u64>()name parser (including for anode_idthat itself contains underscores).Testing
cargo test -p dora-node-api-python pool_id_tests— 2 passedcargo fmt --all -- --check— cleanGenerated by Claude Code