fix(duckdb): explicitly close connections to release file locks on Windows
DuckDB opens database files with exclusive locks on Windows. Previously connections were only released via Drop, which may not release the file handle synchronously, causing "file already in use" errors when reconnecting or testing connections in quick succession.
This commit is contained in:
parent
bcfad319a6
commit
a296bd6c3c
|
|
@ -529,7 +529,9 @@ impl AppState {
|
|||
.cloned()
|
||||
.collect();
|
||||
for key in keys_to_remove {
|
||||
conns.remove(&key);
|
||||
if let Some(PoolKind::DuckDb(con)) = conns.remove(&key) {
|
||||
crate::db::duckdb_driver::close_connection(con);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -54,6 +54,30 @@ pub fn is_memory_database_path(path: &str) -> bool {
|
|||
path.trim().eq_ignore_ascii_case(":memory:")
|
||||
}
|
||||
|
||||
/// Closes a DuckDB connection, releasing the file lock.
|
||||
///
|
||||
/// Unlike relying on Drop, this calls `duckdb_disconnect` synchronously
|
||||
/// so the file handle is released before this function returns.
|
||||
/// On Windows this prevents "file already in use" errors when reconnecting.
|
||||
pub fn close_connection(con: Arc<Mutex<duckdb::Connection>>) {
|
||||
match Arc::try_unwrap(con) {
|
||||
Ok(mutex) => {
|
||||
match mutex.into_inner() {
|
||||
Ok(conn) => {
|
||||
let _ = conn.close();
|
||||
}
|
||||
Err(poisoned) => {
|
||||
let _ = poisoned.into_inner().close();
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
// Arc still referenced elsewhere (e.g. running queries);
|
||||
// the last holder will drop and close the connection.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
|
|||
|
|
@ -269,8 +269,9 @@ pub async fn test_connection(state: State<'_, Arc<AppState>>, config: Connection
|
|||
if state.duckdb_existing_pool_is_usable_for_config(&config).await? {
|
||||
Ok("Connection successful".to_string())
|
||||
} else {
|
||||
db::duckdb_driver::connect_path(&expand_tilde(&config.host))
|
||||
.map(|_| "Connection successful".to_string())
|
||||
let con = db::duckdb_driver::connect_path(&expand_tilde(&config.host))?;
|
||||
dbx_core::db::duckdb_driver::close_connection(con);
|
||||
Ok("Connection successful".to_string())
|
||||
}
|
||||
}
|
||||
DatabaseType::MongoDb => {
|
||||
|
|
@ -474,7 +475,9 @@ pub async fn disconnect_db(state: State<'_, Arc<AppState>>, connection_id: Strin
|
|||
PoolKind::Postgres(p) => p.close(),
|
||||
PoolKind::Sqlite(_) => {}
|
||||
PoolKind::Redis(_) => {}
|
||||
PoolKind::DuckDb(_) => {}
|
||||
PoolKind::DuckDb(con) => {
|
||||
dbx_core::db::duckdb_driver::close_connection(con);
|
||||
}
|
||||
PoolKind::MongoDb(_) => {}
|
||||
PoolKind::ClickHouse(_) => {}
|
||||
PoolKind::SqlServer(_) => {}
|
||||
|
|
|
|||
Loading…
Reference in New Issue