Skip to content

Commit 5327b98

Browse files
committed
feat: add per-worker proxy to table function execute callback
Add per-worker proxy support to the table function execute callback for DuckDB >= 1.5.0: - Add table_function_local_init_callback() that creates a per-worker proxy for each non-Ruby DuckDB worker thread - Register via duckdb_table_function_set_local_init in set_execute - Update execute callback Case 3 to use proxy when available, falling back to global executor otherwise All code is guarded by HAVE_DUCKDB_H_GE_V1_5_0. The SET threads=1 restriction is not yet removed (done in the next commit).
1 parent c70fdae commit 5327b98

1 file changed

Lines changed: 47 additions & 1 deletion

File tree

ext/duckdb/table_function.c

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ static VALUE rbduckdb_table_function_set_init(VALUE self);
2727
static void table_function_init_callback(duckdb_init_info info);
2828
static VALUE rbduckdb_table_function_set_execute(VALUE self);
2929
static void table_function_execute_callback(duckdb_function_info info, duckdb_data_chunk output);
30+
#ifdef HAVE_DUCKDB_H_GE_V1_5_0
31+
static void table_function_local_init_callback(duckdb_init_info info);
32+
#endif
3033

3134
static const rb_data_type_t table_function_data_type = {
3235
"DuckDB/TableFunction",
@@ -386,6 +389,9 @@ static VALUE rbduckdb_table_function_set_execute(VALUE self) {
386389

387390
ctx->execute_proc = rb_block_proc();
388391
duckdb_table_function_set_function(ctx->table_function, table_function_execute_callback);
392+
#ifdef HAVE_DUCKDB_H_GE_V1_5_0
393+
duckdb_table_function_set_local_init(ctx->table_function, table_function_local_init_callback);
394+
#endif
389395

390396
/* Ensure the global executor thread is running for multi-thread dispatch */
391397
rbduckdb_executor_ensure_started();
@@ -454,10 +460,50 @@ static void table_function_execute_callback(duckdb_function_info info, duckdb_da
454460
rb_thread_call_with_gvl(table_execute_gvl_wrapper, &arg);
455461
}
456462
} else {
457-
/* Non-Ruby thread — dispatch to global executor */
463+
/* Non-Ruby thread */
464+
#ifdef HAVE_DUCKDB_H_GE_V1_5_0
465+
/* Use per-worker proxy if available (DuckDB >= 1.5.0) */
466+
struct worker_proxy *proxy = (struct worker_proxy *)duckdb_function_get_local_init_data(info);
467+
if (proxy) {
468+
rbduckdb_worker_proxy_dispatch(proxy, table_execute_with_gvl, &arg);
469+
} else {
470+
rbduckdb_executor_dispatch(table_execute_with_gvl, &arg);
471+
}
472+
#else
458473
rbduckdb_executor_dispatch(table_execute_with_gvl, &arg);
474+
#endif
475+
}
476+
}
477+
478+
#ifdef HAVE_DUCKDB_H_GE_V1_5_0
479+
/*
480+
* local_init callback for table functions.
481+
* Creates a per-worker proxy for non-Ruby threads.
482+
* Requires DuckDB >= 1.5.0 (duckdb_table_function_set_local_init).
483+
*/
484+
struct table_proxy_create_arg {
485+
struct worker_proxy *proxy;
486+
};
487+
488+
static void table_create_proxy_callback(void *data) {
489+
struct table_proxy_create_arg *arg = (struct table_proxy_create_arg *)data;
490+
arg->proxy = rbduckdb_worker_proxy_create();
491+
}
492+
493+
static void table_function_local_init_callback(duckdb_init_info info) {
494+
if (ruby_native_thread_p()) {
495+
return;
496+
}
497+
498+
struct table_proxy_create_arg arg;
499+
arg.proxy = NULL;
500+
rbduckdb_executor_dispatch(table_create_proxy_callback, &arg);
501+
502+
if (arg.proxy != NULL) {
503+
duckdb_init_set_init_data(info, arg.proxy, rbduckdb_worker_proxy_destroy);
459504
}
460505
}
506+
#endif
461507

462508
rubyDuckDBTableFunction *get_struct_table_function(VALUE self) {
463509
rubyDuckDBTableFunction *ctx;

0 commit comments

Comments
 (0)