Skip to content

Bump rocksdb-js to 2.8.0 on v5.2 so a commit parked on a never-released write intent stops wedging the worker thread - #2466

Merged
kriszyp merged 2 commits into
v5.2from
kris/rocksdb-2.8.0-v52
Sep 2, 2026
Merged

kriszyp merged 2 commits into
v5.2from
kris/rocksdb-2.8.0-v52

Conversation

@kriszyp

@kriszyp kriszyp commented Sep 2, 2026 •

Copy link
Copy Markdown
Member

rocksdb-js 2.8.0 bounds the coordinated-retry park (rocksdb-js#744): a commit waiting on a write intent whose holder never releases now wakes after ROCKSDB_JS_PARK_TIMEOUT_MS (5000ms default, unparseable/zero/negative values fall back to it, no way to disable) and consumes a retry attempt exactly as a real release would, instead of never settling. That never-settling park is the root cause of #2450 — the commit that stayed outstanding for 12.5 minutes on three worker threads until the process was restarted.

This is a dependency-pin change only; no core code changes. It moves two pins together: rocksdb-js to 2.8.0 and msgpackr to 2.0.6. build-tools/check-shrinkwrap-pins.mjs requires the root msgpackr pin to equal rocksdb-js's own so the tree carries one msgpackr instance (and so one structure/extension registry), and rocksdb-js 2.8.0 depends on 2.0.6; the docker smoke job caught the mismatch on the first push. The lockfile correspondingly loses the nested msgpackr copy under rocksdb-js. 2.0.6 over 2.0.5 is one decode-hardening commit — reject array and map lengths that exceed the remaining source data — and is the pairing main already runs. v5.2 already carries the ladder the woken commit lands in: MAX_RETRIES = 40 with abortChainAfterRetries(), abandonWrites() on a retained read handle, and per-attempt outstanding-commit tracking. Because trackOutstandingCommit() stamps each attempt at submission, every attempt now settles inside the park timeout, so a stuck intent holder no longer pushes the oldest outstanding commit past storage.maxTransactionQueueTime (45s) and checkOverloaded() stops 503-ing every unrelated write on the thread. The thread recovers without a restart, which is the part of #2450 that hurt.

For the human reviewer

  1. The whole 2.8.0, or a 2.7.2 with only rocksdb-js#744? 2.7.1 → 2.8.0 is 186 commits of mostly native change: the RocksDB prebuild jump 11.1.2 → 11.8.1, transaction-log recovery and framing rework (rocksdb-js#723, [Models] Derived caching table for @embed (low-latency writes + model-change backfill) #750, fix(analytics): get_analytics start_time/end_time filters returned zero rows #751), latched background-error observation and recovery (Deployment tracking — Slice B2: peer-side blob reads + install-line streaming #758), the Hash long URLs into primary key for cache table storage efficiency #741 pending-transaction close-path rework (Make RocksDB memory config configurable (block cache + WriteBufferManager) #780), the verification-table non-unique-version change (Test #766), and dropped-transaction snapshot release (Test123 #768). That is more native surface than a patch line usually takes at once, and 2.8.0 has about a week of soak on main only. The minimal alternative is cutting rocksdb-js 2.7.2 = 2.7.1 + HTTP Logs showing up in system (non external) logs #744 and pinning that here instead. Either way the decision is a one-line pin and trivially reversible, but it is the decision this PR is asking for — @kriszyp asked for the 2.8.0 route explicitly.
  2. Bound a request-path commit's conflict retries to its queue-time budget #2459 is deliberately not backported. It bounds the retry ladder by queue time and returns a distinct 503 TRANSACTION_COMMIT_CONFLICT_TIMEOUT. On 2.7.1 it would be inert for Outstanding-commit wedge recurs on 5.2.6/5.2.7: native commits never settle and checkOverloaded 503s every application write on the thread until restart #2450 (a commit parked forever never reaches a retry decision, so the deadline is never evaluated), and on 2.8.0 it only shortens the tail. Without it, a permanently-held intent ends the initiating request after roughly 40 × 5s ≈ 200s with the existing generic 500 "After 40 coordinated retries, unable to commit transaction" rather than a bounded, typed 503. If the reporter needs the bounded error too, Bound a request-path commit's conflict retries to its queue-time budget #2459 can be backported after it merges on main — it does not change the wedge outcome.
  3. No companion harper-pro PR. harper-pro pins @harperfast/rocksdb-js and msgpackr in its own package.json, but build-tools/sync-core.sh copies core's dependencies, devDependencies, overrides and optionalDependencies plus core's lockfile into harper-pro wholesale, so both pins arrive there from this PR through the core sync. An earlier hand-written pro PR for the same bump (harper-pro#798) was closed as redundant.
  4. Direction: this targets v5.2 directly rather than arriving as a cherry-pick — main has been on 2.8.0 since Fix sourcedFrom cache-fill conflict convergence #2065, which bumped it for the verification-table non-unique flag.

Verification

  • npm run build — clean.
  • npm run test:unit:dataLayer — 242 passing, 0 failing.
  • Dependency alignment, checked directly against the three predicates verifyRocksDbDependencyAlignment() asserts: root pin, rocksdb-js's own pin and the installed version all read 2.0.6 for msgpackr and 1.0.3 for @harperfast/extended-iterable, and no nested copy of either remains under node_modules/@harperfast/rocksdb-js/. The checker itself cannot run locally — it reads npm-shrinkwrap.packed.json, which only exists inside the packed docker image the smoke job builds.
  • npm run test:unit:resources — 1698 passing, 0 failing, re-run after the msgpackr pin moved (same counts). A first run of the same suite had one failure, Caching > Can load cached indexed data (asserted 3, got 2); the file passes in isolation and the full-suite re-run is green, so it is a pre-existing ordering flake, not a bump regression.
  • npm run test:unit:main — not run locally. The suite stalled on the storage locks shared with two other local Harper suites running concurrently in sibling worktrees (a known local-only contention on this machine, not a product behavior); it was killed rather than reported. CI runs it on this PR.
  • Not observable end-to-end here: reproducing the wedge requires deliberately leaking a native write intent that is never released. The park timeout itself is covered inside rocksdb-js (test/fixtures/fork-park-timeout.mts, asserting both a lower and an upper bound on elapsed time so the timeout branch is distinguishable from the not-parked fast path), and the retry ladder the woken commit lands in is already covered on this branch.

Refs #2450

Complexity: easy

🤖 Generated with Claude Code

Review-Coverage: authored=unknown; ran=none; rounds=1 @ 6ca418d

Human-Review-Need: 4 @ 6ca418d

rocksdb-js 2.8.0 bounds the coordinated-retry park with
ROCKSDB_JS_PARK_TIMEOUT_MS (rocksdb-js#744), so a commit waiting on a
write intent that is never released now wakes and consumes a retry
attempt instead of never settling.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the dependency @harperfast/rocksdb-js from version 2.7.1 to 2.8.0 in package.json. There are no review comments, and I have no feedback to provide.

@socket-security

socket-security Bot commented Sep 2, 2026 •

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Updatedmsgpackr@​2.0.5 ⏵ 2.0.699100100 +193100
Updated@​harperfast/​rocksdb-js@​2.7.1 ⏵ 2.8.095 +1910010099100

View full report

@kriszyp kriszyp added this to the v5.2 milestone Sep 2, 2026
@kriszyp
kriszyp marked this pull request as ready for review September 2, 2026 11:38
check-shrinkwrap-pins.mjs requires the root msgpackr pin to equal
rocksdb-js's own, so one module instance (and one structure/extension
registry) is shared; rocksdb-js 2.8.0 depends on msgpackr 2.0.6. The
lockfile loses the nested msgpackr copy under rocksdb-js accordingly.
2.0.6 over 2.0.5 is a single decode-hardening change (reject array/map
lengths that exceed the remaining source data), and is what main runs.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@kriszyp

kriszyp commented Sep 2, 2026

Copy link
Copy Markdown
Member Author

@cb1kenobi I believe you felt like 2.8.0 was probably reasonable to apply to 5.2.x. I know we could do a more targeted 2.7.2, but I believe 2.8.0 has a gotten some decent testing, and seems reasonable to adopt, if you still agree.

@claude

claude Bot commented Sep 2, 2026 •

Copy link
Copy Markdown
Contributor

Reviewed; no blockers found.

@kriszyp

kriszyp commented Sep 2, 2026

Copy link
Copy Markdown
Member Author

I think we need to move ahead with this, Fabric is kind of waiting for this fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant