Skip to content

Commit 40c0a39

Browse files
committed
Fix multiple duckdb instances clash on the same temporary directory.
Have to be revised once duckdb/duckdb#15173 is resolved.
1 parent 55874e3 commit 40c0a39

File tree

1 file changed

+45
-1
lines changed

1 file changed

+45
-1
lines changed

src/pgduckdb_duckdb.cpp

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,48 @@ extern "C" {
3636
#include "nodes/value.h" // strVal
3737
#include "utils/fmgrprotos.h" // pg_sequence_last_value
3838
#include "utils/lsyscache.h" // get_relname_relid
39+
#include "storage/ipc.h" // on_proc_exit
3940
}
4041

4142
namespace pgduckdb {
4243

44+
/*
45+
* Make sure the hook is registered once for a backend.
46+
* This flag is also used to get a unique temporary directory name
47+
* for in-memory duckdb instance, otherwise they clash on the same
48+
* temporary file names. The fix is on pg_duckdb side until
49+
* https://github.com/duckdb/duckdb/issues/15173 is resolved.
50+
*/
51+
static bool set_up_instance_directory_hook = false;
52+
53+
/*
54+
* The length is 37, because a UUID has 36 characters and we need to add a NULL
55+
* byte. The approach is the same as for bgw_session_hint.
56+
*/
57+
static char duckdb_instance_directory[37];
58+
void RemoveTemporaryDirectory(int code = 0, Datum arg = 0);
59+
60+
std::string
61+
GetInstanceTempDir() {
62+
if (!set_up_instance_directory_hook) {
63+
Datum random_uuid = DirectFunctionCall1(gen_random_uuid, 0);
64+
Datum uuid_datum = DirectFunctionCall1(uuid_out, random_uuid);
65+
char *uuid_cstr = DatumGetCString(uuid_datum);
66+
strcpy(duckdb_instance_directory, uuid_cstr);
67+
68+
/* Set up the flag first to avoid re-generating uuid in the hook */
69+
set_up_instance_directory_hook = true;
70+
on_proc_exit(RemoveTemporaryDirectory, 0);
71+
}
72+
73+
return (std::string)duckdb_temporary_directory + "/" + (std::string)duckdb_instance_directory;
74+
}
75+
76+
void
77+
RemoveTemporaryDirectory(int /*code*/, Datum /*arg*/) {
78+
std::filesystem::remove_all(GetInstanceTempDir());
79+
}
80+
4381
const char *
4482
GetSessionHint() {
4583
if (!IsEmptyString(duckdb_motherduck_session_hint)) {
@@ -96,14 +134,19 @@ DuckDBManager::Initialize() {
96134
std::filesystem::create_directories(duckdb_extension_directory);
97135

98136
duckdb::DBConfig config;
137+
138+
// Special case for temporary directory, that should be unique for every instance
139+
std::string instance_temp_directory = GetInstanceTempDir();
140+
config.options.temporary_directory = instance_temp_directory;
141+
std::filesystem::create_directory(instance_temp_directory);
142+
99143
config.SetOptionByName("custom_user_agent", "pg_duckdb");
100144

101145
SET_DUCKDB_OPTION(allow_unsigned_extensions);
102146
SET_DUCKDB_OPTION(enable_external_access);
103147
SET_DUCKDB_OPTION(allow_community_extensions);
104148
SET_DUCKDB_OPTION(autoinstall_known_extensions);
105149
SET_DUCKDB_OPTION(autoload_known_extensions);
106-
SET_DUCKDB_OPTION(temporary_directory);
107150
SET_DUCKDB_OPTION(extension_directory);
108151

109152
if (duckdb_maximum_memory > 0) {
@@ -215,6 +258,7 @@ DuckDBManager::Reset() {
215258
delete database;
216259
database = nullptr;
217260
UnclaimBgwSessionHint();
261+
RemoveTemporaryDirectory();
218262
}
219263

220264
int64

0 commit comments

Comments
 (0)