Skip to content

fix(bootstrap): bump pinned hyperd to 0.0.26225 (rbf04a855) - #219

Draft
StefanSteiner wants to merge 9 commits into
tableau:mainfrom
StefanSteiner:chore/bump-hyperd-0.0.26225
Draft

fix(bootstrap): bump pinned hyperd to 0.0.26225 (rbf04a855)#219
StefanSteiner wants to merge 9 commits into
tableau:mainfrom
StefanSteiner:chore/bump-hyperd-0.0.26225

Conversation

@StefanSteiner

@StefanSteiner StefanSteiner commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Summary

Bumps the pinned hyperd release used by hyperdb-bootstrap from 0.0.25080 / r2bfd835b to 0.0.26225 / rbf04a855 — the latest advertised on Tableau's Hyper DB releases page.

Changes: hyperdb-bootstrap/hyperd-version.toml (version + build id + all four per-platform sha256s) and the crate CHANGELOG.

Verification

  • make verify-hyperd-pin — all four platform zips reachable (HTTP 200) at the new version/build.
  • sha256 — recomputed for all four Java bundles and pinned; make download-hyperd verified the macos-arm64 digest on download.
  • arm64 invariant preserved — the macos-arm64 Java bundle's hyperd is a native Mach-O 64-bit executable arm64 (the reason this crate pulls from the Java bundle, not C++). hyperd --version reports main.0.0.26225.rbf04a855.
  • Full workspace test suitecargo test --workspace against the new binary: 1485 passed, 0 failed.
  • cargo fmt --all --check clean; cargo clippy --workspace --all-targets --all-features -- -D warnings clean.

Performance (A/B vs 0.0.25080)

Unified suite (hyperdb-api/benches/benchmark_suite.rs), 100M rows, median of 3 runs, Apple Silicon:

Workload Old 25080 New 26225 Δ median
query.full_scan (sync) 18.79 M/s 31.23 M/s +66%
query.full_scan (async) 18.73 M/s 25.10 M/s +34%
query.filtered (sync) 33.23 M/s 32.89 M/s ~flat
query.filtered (async) 27.05 M/s 27.18 M/s ~flat
insert Inserter (sync) 26.87 M/s 24.94 M/s −7%
insert ChunkSender (sync) 26.10 M/s 24.67 M/s −5%
insert AsyncArrowInserter 30.01 M/s 29.95 M/s ~flat

Net: a large, repeatable win on the dominant single-connection query path against a small single-threaded insert cost. Multi-connection (× 4) workloads were dominated by thermal throttling on the test laptop (throughput declined monotonically across sequential runs) and are not reported as a reliable delta — they'd need a cooled/pinned host to trust. Only the unified suite was run; the specialized "dig-deeper" benches (arrow-batching, gRPC, async-parallel, kv, Node.js cross-language) were not.

Tooling added alongside the bump

  • update-hyperd-release skill — a project skill codifying this whole procedure (find latest → sha256 → verify pin → native-arm64 check → test → A/B benchmark → log → PR), so the next bump is repeatable.
  • docs/hyperd-release-benchmarks.md — per-release engine performance history (complements BENCHMARK_GUIDE.md's by-platform tables), seeded with the 0.0.25080 → 0.0.26225 A/B.
  • Cross-links from AGENTS.md + BENCHMARK_GUIDE.md; corrected the stale "bump the crate version" note (versioning is workspace-driven + release-please).
  • Commits the reusable plan-to-release Harness workflow driver.

Release impact

fix: commit → targets a 0.7.1 patch release.

Updates version, build id, and all four per-platform sha256s in
hyperd-version.toml. Verified all platform zips are reachable
(verify-hyperd-pin), the macos-arm64 Java bundle ships a native arm64
hyperd, and the full workspace test suite passes (1485 tests, 0 failed)
against the new binary.
Records the unified-suite benchmark comparison vs 0.0.25080 in the
0.7.1 changelog entry: single-connection full-scan query throughput
+66% sync / +34% async, single-threaded insert -5-7%; multi-connection
deltas withheld as thermally noisy.
…ark tracker

Codifies the hyperd version-bump procedure as a project skill
(.claude/skills/update-hyperd-release/) including the Java-not-C++ bundle
rationale, the native-arm64 invariant check, and the benchmarking gotchas
(100M-row medians; distrust thermally-throttled ×4 numbers).

Adds docs/hyperd-release-benchmarks.md tracking engine performance per
release (complements BENCHMARK_GUIDE.md's by-platform tables), seeded with
the 0.0.25080 -> 0.0.26225 A/B. Cross-links from AGENTS.md and
BENCHMARK_GUIDE.md, and corrects the stale 'bump the crate version' note
(versioning is workspace-driven + release-please).

Also commits the reusable plan-to-release Harness workflow driver.
Copies the release-package verifier (SKILL.md + stdlib-only verify_release.py)
from awesome-context (plugins/dataplat/skills/) into the repo so contributors
get it without a user-level install. The script fetches the releases page,
checks all 12 advertised packages (4 platforms x 3 bindings) for filename
version match, downloadability, and zip/whl integrity via urllib+zipfile.

Wires it into the update-hyperd-release skill (step 2) as the page-validation
aid. Smoke-tested against 0.0.26225: 12/12 PASS.
hyperd 0.0.26225 (rbf04a855) wedges *after* its callback connection
succeeds on the macOS-14 (Sonoma, 3-core) runner only: the unit tests
pass, then the first hyperd-backed test binary (arrow_inserter_tests)
stalls in the libpq startup handshake read until the 45-min job cap.
Linux, Windows, and local macOS 26 all pass. See PR tableau#219.

This is a diagnostic-only change (no product code): a macOS-only
watchdog, backgrounded before the test step, that once a hyperd has
been alive past a threshold `sample`s its symbolized native C++ stack
and the stalled test process, copies hyperd's JSON log, uploads them
as an artifact (if: always()), then kills the wedged processes so the
job ends in minutes instead of 45. The sample names the exact wedged
engine function, which the hyperd log alone does not.

Guarded by `runner.os == 'macOS'`, so Linux/Windows are unaffected.
Remove once the hang is root-caused and fixed.
@StefanSteiner
StefanSteiner marked this pull request as draft August 8, 2026 03:01
@StefanSteiner

Copy link
Copy Markdown
Contributor Author

🛑 Holding this bump — hyperd 0.0.26225 deadlocks on macOS 14 (upstream engine bug)

Root-caused the macOS-14 CI hang on this PR. It is not a client/test bug — it's a hyperd 0.0.26225 defect on macOS 14 arm64, so I'm converting this PR to draft and holding it until there's a fixed engine build. Reverting to 0.0.25080 is not needed on main (this bump never merged); we just don't merge it.

What happens

On macOS 14 (Sonoma) / arm64, hyperd 0.0.26225 (rbf04a855) hangs the first time a connection issues CREATE TABLE. The engine JIT-compiles the relation and, during RuntimeDyldMachOAArch64::registerEHFrames(), a fatal signal fires inside the system unwinder (libunwind.__unw_add_dynamic_eh_frame_section). Hyper's own fatal-signal handler then re-enters libunwind via _Unwind_Backtrace and spins forever in UnwindCursor::step — the process never dies and never responds. The test client is a passive victim, blocked in recv() on the query response.

Wedged worker stack (symbolized sample):

CreateTable::executeImpl (.resume)
  Schema::addRelation → codegen::Relation::compile → LLVMBackend::doCompile
    llvm::orc::…::MaterializationTask::run → RTDyldObjectLinkingLayer::emit
      RuntimeDyldImpl::finalizeAsync
        RuntimeDyldMachOCRTPBase<AArch64>::registerEHFrames()
          __unw_add_dynamic_eh_frame_section   (libunwind)   ← faults
            _sigtramp → hyper::fatalSignalHandler → backtraceSignalHandler
              StackWalker::collectStackFrames → _Unwind_Backtrace
                UnwindCursor<…, Registers_arm64>::step(bool)  ← SPINS

Main thread is separately wedged in PriorityScheduler::shutdownAndStop() on a std::mutex.

Confirmed

  • 100% deterministic — all 3 hyperd instances in the run wedged with the byte-identical chain.
  • Not transport-related — the tests run over TCP (tab.tcp://), not UDS; forcing TCP is a no-op.
  • Regression vs 0.0.25080 — the prior pin passes on the same runner. Linux, Windows, and macOS 26 all pass on 0.0.26225; only the macos-14 image is affected.

Diagnostics

A temporary CI watchdog (commit dbae7e3) samples the wedged engine + client, uploads the stacks as an artifact, and kills the processes so the job fast-fails in ~5 min instead of hanging to the 45-min cap. See run: https://github.com/tableau/hyper-api-rust/actions/runs/31235142633 (artifact macos-hang-diagnostics). The watchdog stays in place until this is resolved upstream.

Next

Filing an upstream report to the Hyper team (primary: EH-frame registration fault in JIT codegen on macOS 14 arm64; secondary: fatal-signal handler re-entering libunwind → hang instead of crash-report). Will re-test any candidate build on the same runner before un-drafting.

@StefanSteiner

Copy link
Copy Markdown
Contributor Author

✅ Root cause pinpointed in engine source — it's a JIT unwind-registration API swap

Diffed the good→bad engine range (2bfd835b..bf04a855, 1145 commits) in a local hyper-db checkout. The macOS-14 arm64 hang is two specific commits, and #12263's own message describes the bug. Every fact below re-verified by hand with git show/log/merge-base.

Introducer — bd6440a994 (#12186, 2026-05-07) "Use eh_frame registration to reduce libunwind lock contention"

Swapped the size-bounded per-FDE path for the section-level Apple SPI in hyper/ir/infra/EHFrameGuard.posix.cpp:

-extern "C" void __register_frame(void*);
-   enumerateFDEsInEHFrame(ehInfo_, sizeInBytes_, __register_frame);      // GOOD: size-bounded
+extern "C" void __unw_add_dynamic_eh_frame_section(uintptr_t eh_frame_start);
+   __unw_add_dynamic_eh_frame_section(reinterpret_cast<uintptr_t>(ehInfo_));  // BAD: start ptr only, NO size

No size arg ⇒ the OS libunwind self-walks the whole JIT .eh_frame. macOS-14's older system libunwind.dylib 1700.242 faults doing that; macOS-26's newer one tolerates the identical bytes. This is the exact crash frame.

Why arm64 was left exposed — 2f8c234993 (#12263, 2026-05-12) "Revert to __register_frame on macOS ARM"

Misleading title — it reverted only x86_64 and deliberately kept the SPI for __aarch64__. Its message is a verbatim description of this bug:

the newly introduced __unw_add_dynamic_eh_frame_section call crashes… needs a zero-terminator there, but even with that it crashes in some mutex. As it works on Mac ARM… reverting to use __register_frame calls on Mac x86.

"crashes in some mutex" = our main thread wedged on std::mutex::lock in shutdownAndStop(). "works on Mac ARM" was validated on macOS 26 only — macOS 14 arm64 was never tested, and that's the config that faults.

Exonerated (by byte-comparison)

  • Emitted CFI is not the differentiatorEHFrameWriter.{cpp,hpp} and MCMemoryManager.cpp are bit-identical good↔bad. Only the registration mechanism changed.
  • LLVM 22.1.2→22.1.7 bump: refuted — landed a month later, build-files only; the crashing call was already live.

Proposed fix (actionable upstream)

Route macOS arm64 back to __register_frame too — drop the #ifdef __aarch64__ special-case in EHFrameGuard.macos.cpp so all macOS uses the size-bounded path #12263 already restored for x86_64. (Or version-gate the SPI to macOS ≥ 26 at runtime if the lock-contention win matters on Apple Silicon.) Plus an independent hardening: the fatal-signal handler re-enters libunwind via _Unwind_Backtrace and spins — that's what turns the crash into the 45-min hang (pre-existing, only exposed here).

Filing this upstream with the sampled stacks + the commit analysis. Holding this PR until there's a fixed engine build.

Reverts the __unw_add_dynamic_eh_frame_section SPI on macOS arm64 back to
__register_frame (the deadlock root cause on macOS-14's older system
libunwind; see PR tableau#219 analysis). Downloads a locally-patched hyperd from
the fork's release assets (sha256-verified), narrows the matrix to
macos-14, and isolates the hyperd cache under a -ehframefix key.

TEMPORARY scaffolding — revert this commit and delete the release asset
once the run confirms the fix (green instead of the watchdog fast-fail).
@StefanSteiner

Copy link
Copy Markdown
Contributor Author

✅ Fix VALIDATED on the real macOS-14 arm64 runner

Built a patched hyperd with the proposed fix and ran it through this PR's CI on macos-14. It passes — the deadlock is gone.

The fix

In hyper/ir/infra/EHFrameGuard.macos.cpp, route macOS arm64 back through the size-bounded per-FDE __register_frame path (dropping the #ifdef __aarch64____unw_add_dynamic_eh_frame_section SPI branch), so all macOS arches use the same registration x86_64 already reverted to in #12263. This is the pre-#12186 behavior. Confirmed in the built binary: __unw_add_dynamic_eh_frame_section symbol gone, __register_frame present, arm64 Mach-O.

How it was tested

Patched hyper-db HEAD (crash-relevant files + MODULE.bazel are byte-identical to the pinned bf04a855, so it's causally equivalent), rebuilt via bzl.py … //hyper/tools/hyperd:hyperd, and — via a temporary, now-reverted CI change — downloaded that binary into .hyperd/current (sha256-verified) on the macos-14 job, matrix narrowed to macOS, hyperd cache isolated under a throwaway key.

Result — ci run 31239711070, test (macos-14)

  • Job green in 5m30s (the broken build fast-failed at 4m42s on the watchdog wedge).
  • Override hyperd step logged the patched binary in use: Hyper version __UNVERSIONED_HYPER__.0.0.0.r00000000.
  • arrow_inserter_tests — the binary that hung — test result: ok. 129 passed, plus ~20 more suites all ok.
  • Zero has been running for over 60 seconds warnings; watchdog stayed silent (no wedge to capture).

The scaffolding (temp CI commit + fork release asset) has been reverted/deleted — this branch is back to the held state. Handing the confirmed fix + the sampled root-cause analysis to the Hyper team; keeping this PR held (draft) until a fixed engine build is pinned.

cc @W-22027763

…S-14

Same scaffolding as 822a950 but points at the Option B binary: the fix
version-gates the eh_frame registration API (section SPI on macOS>=26,
__register_frame on <26). On the macos-14 runner this exercises the
__register_frame fallback branch — the half not validatable on local
macOS-26 hardware (which takes the SPI branch and passed the full
hyperdb-api suite). sha256-pinned; matrix narrowed; cache isolated.

TEMPORARY — revert + delete the release asset once the run confirms green.
@StefanSteiner

Copy link
Copy Markdown
Contributor Author

✅ Both candidate fixes validated on the real macOS-14 runner

Followed up the root-cause with two build-and-test passes. Both fix shapes pass on the macos-14 runner (the platform that hangs on the unpatched engine); pick based on whether the Apple-Silicon lock-contention win from #12186 is worth carrying a small version gate.

Option A — route macOS arm64 back to __register_frame

Drop the #ifdef __aarch64__ special-case in EHFrameGuard.macos.cpp so all macOS uses the size-bounded per-FDE path (as #12263 already did for x86_64). Smallest diff; gives up the SPI lock-contention optimization on Apple Silicon (a 100-concurrent-compile server scenario — Linux keeps the SPI regardless).

  • macos-14 CI: run 31239711069 green in ~5m30s; arrow_inserter_tests 129 passed, 0 stalls.

Option B — runtime version-gate the SPI (keeps the perf win)

Use the section SPI only on macOS ≥ 26 (the OS whose system libunwind implements it correctly — the threshold #12186 itself assumed), else __register_frame. Reads kern.osproductversion via the existing OSInfo::fromSysctl (no new Bazel dep); fails safe to __register_frame on any sysctl/parse error. x86_64 stays on __register_frame. Both branches of the gate are validated:

  • SPI branch (macOS ≥ 26): full hyperdb-api suite green on local macOS-26 hardware (177+ tests) — no regression on the working platform.
  • __register_frame fallback (macOS < 26): run 31241583960 green on macos-14 in ~5m36s; arrow_inserter_tests 129 passed, 0 stalls, watchdog silent.

Recommendation

Lead with Option B (preserves the perf win, both branches proven, small self-contained gate); Option A is the zero-machinery fallback if minimalism is preferred. Full write-up, both diffs, and the sampled root-cause stacks are ready to hand to the Hyper team (W-22027763).

All test scaffolding (temp CI commits + fork release assets) has been reverted/deleted — this branch is back to the held state. Keeping this PR held (draft) until a fixed engine build is pinned.

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