Add per-worker proxy thread primitive - #1364
Conversation
Introduce a per-worker proxy: one dedicated Ruby thread per DuckDB worker thread, using the same mutex/condvar hand-off protocol as the global executor but private to a single worker. This commit lands only the lifecycle -- rbduckdb_worker_proxy_create and rbduckdb_worker_proxy_destroy, plus the proxy thread loop and the GC-protection array. The dispatch wiring that feeds requests to a proxy follows in a separate commit, so these symbols are unused for now (public linkage, no warning) and the full suite is unchanged. worker_proxy_destroy releases the GVL while joining the proxy thread when the caller holds it, since the proxy must run Ruby code (removing itself from the GC array) before exiting -- otherwise teardown from a Ruby thread would deadlock.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughThis PR adds per-worker proxy threads to ruby-duckdb that allow DuckDB worker threads to dispatch UDF callbacks onto dedicated Ruby threads without serializing through a global queue. The implementation includes GC-safe thread lifecycle management, platform-specific synchronization, and proper teardown logic. ChangesPer-worker proxy thread infrastructure
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Warning Review ran into problems🔥 ProblemsGit: Failed to clone repository. Please run the Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
I did my best to minimize the diff, but it grew larger than I intended.
Apologies for the size of this change.
GitHub: GH-1136
This PR adds only the lifecycle primitive that a
worker_proxyyou can createand destroy. There is no consumer yet, so it is behavior-preserving dead code
until the dispatch wiring and the scalar/table integrations is merged on top.
For the overall picture I have in mind — the full mechanism with every step
integrated — Please see otegami#7 on my fork.
What it adds
struct worker_proxyplusrbduckdb_worker_proxy_create/_destroy.destroy's signature matchesduckdb_delete_callback_tso DuckDB can call itdirectly later.
non-Ruby init hooks aren't collected mid-flight.
For reviewer's information
destroyreleases the GVL while joining only when the caller holds it,because the proxy must run Ruby code (leaving the GC array) before it exits.
rb_ensure, so teardown still signals completion ifan async exception (
Thread#kill, VM shutdown) unwinds it — otherwise thejoin deadlocks.
calloc/free, notxcalloc/xfree, sincedestroymay run off a non-Rubythread.gi
Summary by CodeRabbit