Skip to content

Commit 1d798bb

Browse files
chore[duckdb]: set max threads (#5062)
This allows setting the max thread count used by the vortex-duckdb extension, also query_bench `-t X` will set the thread count. This is useful for a single threaded run of a query. --------- Signed-off-by: Joe Isaacs <[email protected]>
1 parent f5ce8f7 commit 1d798bb

File tree

12 files changed

+232
-19
lines changed

12 files changed

+232
-19
lines changed

bench-vortex/src/benchmark_driver.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,7 @@ pub fn run_benchmark<B: Benchmark>(benchmark: B, config: DriverConfig) -> Result
106106
config.disable_datafusion_cache,
107107
config.emit_plan,
108108
config.delete_duckdb_database,
109+
config.threads,
109110
)?;
110111

111112
tokio_runtime.block_on(benchmark.register_tables(&engine_ctx, target.format()))?;
@@ -346,6 +347,7 @@ fn run_explain_query<B: Benchmark>(
346347
config.disable_datafusion_cache,
347348
config.emit_plan,
348349
config.delete_duckdb_database,
350+
config.threads,
349351
)?;
350352

351353
tokio_runtime.block_on(benchmark.register_tables(&engine_ctx, target.format()))?;

bench-vortex/src/benchmark_trait.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ pub trait Benchmark {
2020
disable_datafusion_cache: bool,
2121
emit_plan: bool,
2222
delete_duckdb_database: bool,
23+
threads: Option<usize>,
2324
) -> Result<EngineCtx> {
2425
let engine = target.engine();
2526
let format = target.format();
@@ -37,6 +38,7 @@ pub trait Benchmark {
3738
self.dataset(),
3839
format,
3940
delete_duckdb_database,
41+
threads,
4042
)?)
4143
}
4244
_ => unreachable!("engine not supported"),

bench-vortex/src/engines/ddb/mod.rs

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use log::trace;
99
use url::Url;
1010
use vortex::error::VortexExpect;
1111
use vortex_duckdb::duckdb::{Config, Connection, Database};
12+
use vortex_duckdb::register_extension_options;
1213

1314
use crate::statpopgen::StatPopGenBenchmark;
1415
use crate::{BenchmarkDataset, Format, IdempotentPath};
@@ -33,10 +34,16 @@ pub struct DuckDBCtx {
3334
pub db: Database,
3435
pub connection: Connection,
3536
pub db_path: Option<PathBuf>,
37+
pub threads: Option<usize>,
3638
}
3739

3840
impl DuckDBCtx {
39-
pub fn new(dataset: BenchmarkDataset, format: Format, delete_database: bool) -> Result<Self> {
41+
pub fn new(
42+
dataset: BenchmarkDataset,
43+
format: Format,
44+
delete_database: bool,
45+
threads: Option<usize>,
46+
) -> Result<Self> {
4047
let dir = match dataset {
4148
BenchmarkDataset::ClickBench { flavor, .. } => {
4249
format!("clickbench_{}/{}", flavor, format.name()).to_data_path()
@@ -60,22 +67,30 @@ impl DuckDBCtx {
6067
std::fs::remove_file(&db_path)?;
6168
}
6269

63-
let (db, connection) = Self::open_and_setup_database(Some(db_path.clone()))?;
70+
let (db, connection) = Self::open_and_setup_database(Some(db_path.clone()), threads)?;
6471

6572
Ok(Self {
6673
db,
6774
connection,
6875
db_path: Some(db_path),
76+
threads,
6977
})
7078
}
7179

72-
pub fn open_and_setup_database(path: Option<PathBuf>) -> Result<(Database, Connection)> {
80+
pub fn open_and_setup_database(
81+
path: Option<PathBuf>,
82+
threads: Option<usize>,
83+
) -> Result<(Database, Connection)> {
7384
let config = Config::new().vortex_expect("failed to create duckdb config");
7485

86+
// Register Vortex extension options before creating connection
87+
register_extension_options(&config);
88+
7589
let db = match path {
7690
Some(path) => Database::open_with_config(path, config),
7791
None => Database::open_in_memory_with_config(config),
7892
}?;
93+
7994
let connection = db.connect()?;
8095
vortex_duckdb::register_table_functions(&connection)?;
8196

@@ -90,6 +105,11 @@ impl DuckDBCtx {
90105
// parquet_metadata_cache" when running DuckDB in debug mode.
91106
connection.query("SET parquet_metadata_cache = true")?;
92107

108+
// Set vortex_max_threads if specified
109+
if let Some(thread_count) = threads {
110+
connection.query(&format!("SET vortex_max_threads = {}", thread_count))?;
111+
}
112+
93113
Ok((db, connection))
94114
}
95115

@@ -105,7 +125,8 @@ impl DuckDBCtx {
105125
drop(connection);
106126
drop(db);
107127

108-
let (mut db, mut connection) = Self::open_and_setup_database(self.db_path.clone())?;
128+
let (mut db, mut connection) =
129+
Self::open_and_setup_database(self.db_path.clone(), self.threads)?;
109130

110131
std::mem::swap(&mut self.connection, &mut connection);
111132
std::mem::swap(&mut self.db, &mut db);
@@ -114,13 +135,12 @@ impl DuckDBCtx {
114135
}
115136

116137
pub fn new_in_memory() -> Result<Self> {
117-
let db = Database::open_in_memory()?;
118-
let connection = db.connect()?;
119-
vortex_duckdb::register_table_functions(&connection)?;
138+
let (db, connection) = Self::open_and_setup_database(None, None)?;
120139
Ok(Self {
121140
db,
122141
connection,
123142
db_path: None,
143+
threads: None,
124144
})
125145
}
126146

bench-vortex/src/engines/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,13 @@ impl EngineCtx {
3232
dataset: BenchmarkDataset,
3333
format: Format,
3434
delete_duckdb_database: bool,
35+
threads: Option<usize>,
3536
) -> anyhow::Result<Self> {
3637
Ok(EngineCtx::DuckDB(ddb::DuckDBCtx::new(
3738
dataset,
3839
format,
3940
delete_duckdb_database,
41+
threads,
4042
)?))
4143
}
4244

vortex-duckdb/cpp/client_context.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,25 @@ duckdb_vx_client_context_get_object_cache(duckdb_vx_client_context context) {
2626
} catch (...) {
2727
return nullptr;
2828
}
29+
}
30+
31+
extern "C" duckdb_value duckdb_vx_client_context_try_get_current_setting(duckdb_vx_client_context context,
32+
const char *key) {
33+
if (!context || !key) {
34+
return nullptr;
35+
}
36+
37+
try {
38+
auto client_context = reinterpret_cast<duckdb::ClientContext *>(context);
39+
duckdb::Value result;
40+
auto lookup_result = client_context->TryGetCurrentSetting(key, result);
41+
42+
if (lookup_result) {
43+
return reinterpret_cast<duckdb_value>(new duckdb::Value(result));
44+
}
45+
46+
return nullptr;
47+
} catch (...) {
48+
return nullptr;
49+
}
2950
}

vortex-duckdb/cpp/config.cpp

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33

44
#include "include/duckdb_vx/config.h"
55
#include "duckdb.hpp"
6+
#include "duckdb/main/config.hpp"
67
#include <string>
78
#include <memory>
89
#include <cstdlib>
910
#include <cstring>
11+
#include <thread>
1012

1113
using namespace duckdb;
1214

@@ -111,4 +113,35 @@ char *duckdb_vx_value_to_string(duckdb_value value) {
111113
}
112114
}
113115

116+
duckdb_state duckdb_vx_add_extension_option(duckdb_config config,
117+
const char *name,
118+
const char *description,
119+
duckdb_logical_type logical_type,
120+
duckdb_value default_value) {
121+
if (!name || !description || !logical_type || !default_value) {
122+
return DuckDBError;
123+
}
124+
125+
try {
126+
auto *db_config = reinterpret_cast<DBConfig *>(config);
127+
if (!db_config) {
128+
return DuckDBError;
129+
}
130+
131+
auto *type = reinterpret_cast<LogicalType *>(logical_type);
132+
auto *value = reinterpret_cast<Value *>(default_value);
133+
134+
db_config->AddExtensionOption(
135+
string(name),
136+
string(description),
137+
*type,
138+
*value
139+
);
140+
141+
return DuckDBSuccess;
142+
} catch (...) {
143+
return DuckDBError;
144+
}
145+
}
146+
114147
} // extern "C"

vortex-duckdb/cpp/include/duckdb_vx/client_context.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ typedef struct duckdb_vx_client_context_ *duckdb_vx_client_context;
1515
// This reference is valid as long as the connection is valid.
1616
duckdb_vx_client_context duckdb_vx_connection_get_client_context(duckdb_connection conn);
1717

18+
// Try to get the current value of a configuration setting.
19+
// Returns a duckdb_value if the setting exists, or NULL if it doesn't.
20+
// The caller is responsible for freeing the returned value using duckdb_destroy_value.
21+
duckdb_value duckdb_vx_client_context_try_get_current_setting(duckdb_vx_client_context context, const char *key);
22+
1823
#ifdef __cplusplus /* End C ABI */
1924
}
2025
#endif

vortex-duckdb/cpp/include/duckdb_vx/config.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,21 @@ int duckdb_vx_config_has_key(duckdb_config config, const char* key);
3333
/// @return A newly allocated string containing the value's string representation, or NULL on error
3434
char* duckdb_vx_value_to_string(duckdb_value value);
3535

36+
/// Add an extension-specific configuration option to DuckDB.
37+
/// This allows extensions to register custom SET variables.
38+
///
39+
/// @param config The DuckDB config instance
40+
/// @param name The name of the configuration option
41+
/// @param description A description of what the option does
42+
/// @param logical_type The DuckDB logical type for the option
43+
/// @param default_value The default value for the option
44+
/// @return DuckDBSuccess on success, DuckDBError on error
45+
duckdb_state duckdb_vx_add_extension_option(duckdb_config config,
46+
const char *name,
47+
const char *description,
48+
duckdb_logical_type logical_type,
49+
duckdb_value default_value);
50+
3651
#ifdef __cplusplus
3752
}
3853
#endif

vortex-duckdb/src/duckdb/client_context.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
// SPDX-License-Identifier: Apache-2.0
22
// SPDX-FileCopyrightText: Copyright the Vortex contributors
33

4+
use std::ffi::CStr;
5+
46
use vortex::error::vortex_panic;
57

6-
use crate::duckdb::ObjectCacheRef;
8+
use crate::duckdb::{ObjectCacheRef, Value};
79
use crate::{cpp, wrapper};
810

911
wrapper!(
@@ -24,4 +26,18 @@ impl ClientContext {
2426
ObjectCacheRef::borrow(cache)
2527
}
2628
}
29+
30+
/// Try to get the current value of a configuration setting.
31+
/// Returns None if the setting doesn't exist.
32+
pub fn try_get_current_setting(&self, key: &CStr) -> Option<Value> {
33+
unsafe {
34+
let value_ptr =
35+
cpp::duckdb_vx_client_context_try_get_current_setting(self.as_ptr(), key.as_ptr());
36+
if value_ptr.is_null() {
37+
None
38+
} else {
39+
Some(Value::own(value_ptr))
40+
}
41+
}
42+
}
2743
}

vortex-duckdb/src/duckdb/logical_type.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,10 @@ impl LogicalType {
175175
Self::new(DUCKDB_TYPE::DUCKDB_TYPE_BIGINT)
176176
}
177177

178+
pub fn uint64() -> Self {
179+
Self::new(DUCKDB_TYPE::DUCKDB_TYPE_UBIGINT)
180+
}
181+
178182
pub fn int32() -> Self {
179183
Self::new(DUCKDB_TYPE::DUCKDB_TYPE_INTEGER)
180184
}

0 commit comments

Comments
 (0)