fix: soporte Windows UNC paths y busy timeout en SQLite
En Windows, si el path a registry.db es UNC (\\wsl.localhost\...), SQLite no puede hacer locking correctamente. Se copia el DB a un archivo temporal local antes de abrirlo. Se añade busy_timeout de 3 segundos para evitar SQLITE_BUSY en lecturas concurrentes. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,13 @@
|
|||||||
#include "data.h"
|
#include "data.h"
|
||||||
#include <sqlite3.h>
|
#include <sqlite3.h>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
#include <cstring>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#include <shlobj.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
// Helper: execute a query and call row_fn for each row
|
// Helper: execute a query and call row_fn for each row
|
||||||
template<typename F>
|
template<typename F>
|
||||||
@@ -52,13 +59,57 @@ void RegistryData::prepare_chart_data() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Copy file src to dst. Returns true on success.
|
||||||
|
static bool copy_file(const char* src, const char* dst) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
return CopyFileA(src, dst, FALSE) != 0;
|
||||||
|
#else
|
||||||
|
FILE* in = fopen(src, "rb");
|
||||||
|
if (!in) return false;
|
||||||
|
FILE* out = fopen(dst, "wb");
|
||||||
|
if (!out) { fclose(in); return false; }
|
||||||
|
char buf[65536];
|
||||||
|
size_t n;
|
||||||
|
while ((n = fread(buf, 1, sizeof(buf), in)) > 0)
|
||||||
|
fwrite(buf, 1, n, out);
|
||||||
|
fclose(in);
|
||||||
|
fclose(out);
|
||||||
|
return true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// On Windows, if the path is a network/UNC path (like \\wsl.localhost\...),
|
||||||
|
// copy the DB to a local temp file so SQLite locking works correctly.
|
||||||
|
// Returns the path to use (may be the original or a temp copy).
|
||||||
|
static std::string ensure_local_db(const char* db_path) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
// Detect UNC / network paths
|
||||||
|
if (strncmp(db_path, "\\\\", 2) == 0 || strncmp(db_path, "//", 2) == 0) {
|
||||||
|
char temp_dir[MAX_PATH] = {0};
|
||||||
|
GetTempPathA(MAX_PATH, temp_dir);
|
||||||
|
std::string local_path = std::string(temp_dir) + "fn_registry_dashboard.db";
|
||||||
|
|
||||||
|
fprintf(stdout, "Copying DB to local temp: %s\n", local_path.c_str());
|
||||||
|
if (copy_file(db_path, local_path.c_str())) {
|
||||||
|
return local_path;
|
||||||
|
}
|
||||||
|
fprintf(stderr, "Warning: failed to copy DB locally, using original path\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return db_path;
|
||||||
|
}
|
||||||
|
|
||||||
bool load_registry_data(const char* db_path, RegistryData& out) {
|
bool load_registry_data(const char* db_path, RegistryData& out) {
|
||||||
|
std::string effective_path = ensure_local_db(db_path);
|
||||||
|
|
||||||
sqlite3* db = nullptr;
|
sqlite3* db = nullptr;
|
||||||
if (sqlite3_open_v2(db_path, &db, SQLITE_OPEN_READONLY, nullptr) != SQLITE_OK) {
|
if (sqlite3_open_v2(effective_path.c_str(), &db, SQLITE_OPEN_READONLY, nullptr) != SQLITE_OK) {
|
||||||
fprintf(stderr, "Cannot open %s: %s\n", db_path, sqlite3_errmsg(db));
|
fprintf(stderr, "Cannot open %s: %s\n", effective_path.c_str(), sqlite3_errmsg(db));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sqlite3_busy_timeout(db, 3000);
|
||||||
|
|
||||||
// --- Counts ---
|
// --- Counts ---
|
||||||
query(db, "SELECT COUNT(*) FROM functions", [&](sqlite3_stmt* s) {
|
query(db, "SELECT COUNT(*) FROM functions", [&](sqlite3_stmt* s) {
|
||||||
out.stats.total_functions = col_int(s, 0);
|
out.stats.total_functions = col_int(s, 0);
|
||||||
|
|||||||
Reference in New Issue
Block a user