Card data update: release reference.db before replacing it

Windows refuses to replace a file SQLite has open, so every update after the first failed at the final swap with "Access is denied". Building and installing are now separate: the app stays usable during the build, then closes the catalog, swaps the file and reopens under the state lock. The swap retries briefly in case a virus scanner is holding the new file, and a failed one puts the previous data back in service and removes the temp file. Importing a card database shares the same swap.
This commit is contained in:
2026-10-30 20:15:34 -05:00
parent 70c89a5644
commit c527e5d6f7
4 changed files with 144 additions and 36 deletions

View File

@@ -127,15 +127,15 @@ pub async fn update_card_data(app: AppHandle, db: Db<'_>) -> Res<Status> {
.map_err(|e| e.to_string())?;
db.lock().unwrap().ingest_cancel = None;
let stats = crate::logged("update_card_data", result.map_err(|e| e.to_string()))?;
let (built, stats) = crate::logged("update_card_data", result.map_err(|e| e.to_string()))?;
crate::mlog!(
"update_card_data: ok ({} oracle cards, {} printings)",
"update_card_data: built ({} oracle cards, {} printings)",
stats.oracle_cards,
stats.printings
);
let mut s = db.lock().unwrap();
crate::logged("update_card_data reopen", s.reopen())?;
crate::logged("update_card_data install", s.replace_reference(&built))?;
Ok(status_of(&s))
}
@@ -182,16 +182,7 @@ pub fn import_reference_db(app: AppHandle, db: Db, path: String) -> Res<Status>
})?;
crate::mlog!("import_reference_db: source holds {cards} oracle cards");
// Release the handles on the file we're about to replace.
s.close();
if let Err(e) = std::fs::rename(&tmp, &dest) {
let _ = std::fs::remove_file(&tmp);
let _ = s.reopen(); // put the previous db back into service
return Err(format!("Couldn't install that card database: {e}"));
}
s.reopen()?;
s.replace_reference(&tmp)?;
Ok(status_of(&s))
}