fix(rag): delete the DuckDB write-ahead log alongside the store
Deleting a RAG removed its .duckdb file but left the sibling .duckdb.wal behind. DuckDB only removes that log on a clean close, so any RAG whose process was killed left one on disk, and creating a new RAG under the same name let it inherit a write-ahead log describing someone else's data. The test helper already cleaned the log up after itself, which is why no test noticed the production path did not.
This commit is contained in:
+13
-1
@@ -437,6 +437,14 @@ pub(crate) fn remove_rag_sidecars(dir: &Path, name: &str) -> Result<()> {
|
|||||||
if duckdb_path.exists() {
|
if duckdb_path.exists() {
|
||||||
let _ = remove_file(&duckdb_path);
|
let _ = remove_file(&duckdb_path);
|
||||||
}
|
}
|
||||||
|
// DuckDB keeps its write-ahead log in a sibling file and only removes it on a
|
||||||
|
// clean close, so a crash or a kill leaves one behind. Deleting the database
|
||||||
|
// without it strands a `.wal` that the next RAG created under the same name
|
||||||
|
// would inherit as if it were its own.
|
||||||
|
let wal_path = dir.join(format!("{name}.duckdb.wal"));
|
||||||
|
if wal_path.exists() {
|
||||||
|
let _ = remove_file(&wal_path);
|
||||||
|
}
|
||||||
let mixin_path = dir.join(format!("{name}.sbx-mixin.yaml"));
|
let mixin_path = dir.join(format!("{name}.sbx-mixin.yaml"));
|
||||||
if mixin_path.exists() {
|
if mixin_path.exists() {
|
||||||
remove_file(&mixin_path).with_context(|| {
|
remove_file(&mixin_path).with_context(|| {
|
||||||
@@ -894,16 +902,20 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn remove_rag_sidecars_removes_both() {
|
fn remove_rag_sidecars_removes_duckdb_wal_and_mixin() {
|
||||||
let root = sidecar_temp_dir("rag-sidecars-both");
|
let root = sidecar_temp_dir("rag-sidecars-both");
|
||||||
let duckdb = root.join("docs.duckdb");
|
let duckdb = root.join("docs.duckdb");
|
||||||
|
// DuckDB leaves this behind whenever it was not closed cleanly.
|
||||||
|
let wal = root.join("docs.duckdb.wal");
|
||||||
let mixin = root.join("docs.sbx-mixin.yaml");
|
let mixin = root.join("docs.sbx-mixin.yaml");
|
||||||
fs::write(&duckdb, "db").unwrap();
|
fs::write(&duckdb, "db").unwrap();
|
||||||
|
fs::write(&wal, "wal").unwrap();
|
||||||
fs::write(&mixin, "mixin").unwrap();
|
fs::write(&mixin, "mixin").unwrap();
|
||||||
|
|
||||||
remove_rag_sidecars(&root, "docs").unwrap();
|
remove_rag_sidecars(&root, "docs").unwrap();
|
||||||
|
|
||||||
assert!(!duckdb.exists(), "the .duckdb sidecar must be removed");
|
assert!(!duckdb.exists(), "the .duckdb sidecar must be removed");
|
||||||
|
assert!(!wal.exists(), "the .duckdb.wal sidecar must be removed");
|
||||||
assert!(
|
assert!(
|
||||||
!mixin.exists(),
|
!mixin.exists(),
|
||||||
"the .sbx-mixin.yaml sidecar must be removed"
|
"the .sbx-mixin.yaml sidecar must be removed"
|
||||||
|
|||||||
Reference in New Issue
Block a user