fix(fuse): a restart no longer brings back the write of a file deleted while open (B188)

This commit is contained in:
nvrl committed 2026-10-05 03:37:41 +02:00
1 parent 2baad6720d
commit b47620651f
4 files changed
+80 -1

No files matched your search

+14
View File
@@ -1961,6 +1961,20 @@ impl Core {
"staged bytes are superseded by a queued write; kept for recovery");
continue;
}
if self
.db
.has_pending_op(&uid.to_string(), OP_TRASH)
.unwrap_or(false)
{
// The node was deleted while a handle still read these bytes,
// and the daemon stopped before its trash went out. Queued again,
// they lost their blob when the trash landed and retried on it
// for good (`docs/BUGS.md` B188).
info!(%uid, blob = %blob.display(),
"staged bytes belong to a node whose trash is queued; discarded");
self.cache.discard_staged(&blob);
continue;
}
let op = PendingOp {
id: 0,
kind: OP_REVISION.to_string(),
+43
View File
@@ -476,6 +476,49 @@ mod tests {
let _ = std::fs::remove_dir_all(&dir);
}
#[test]
#[ignore = "mounts FUSE: run with `cargo test -p pdfs-fuse sim:: -- --ignored`"]
fn a_restart_does_not_bring_back_the_write_of_a_file_deleted_while_open() {
// The bytes kept for the open handle outlived a restart, which queued
// them again as a revision; the trash then landed and removed them, and
// the revision retried on a missing blob for good (B188).
use std::io::Write;
let drive = FakeDrive::new();
let dir = scratch("unlink-open-restart");
let daemon = Daemon::start(&dir, drive.client(1, Faults::lan())).unwrap();
let path = daemon.mountpoint.join("f.txt");
std::fs::write(&path, b"0123456789").unwrap();
assert!(wait_until(Duration::from_secs(30), || {
daemon.pending().is_ok_and(|items| items.is_empty())
&& drive.tree().get("f.txt") == Some(&Entry::File(Arc::new(b"0123456789".to_vec())))
}));
daemon.client.set_online(false);
std::fs::write(&path, b"abcdef").unwrap();
let mut file = std::fs::OpenOptions::new()
.read(true)
.write(true)
.open(&path)
.unwrap();
std::fs::remove_file(&path).unwrap();
file.write_all(b"xy").unwrap();
drop(file);
let daemon = daemon.restart().unwrap();
daemon.client.set_online(true);
assert!(
wait_until(Duration::from_secs(30), || {
daemon.pending().is_ok_and(|items| items.is_empty()) && drive.tree().is_empty()
}),
"{:?} {:?}",
daemon.pending(),
drive.tree()
);
assert!(matches!(daemon.stop(), Ok(MountOutcome::Shutdown)));
let _ = std::fs::remove_dir_all(&dir);
}
#[test]
#[ignore = "mounts FUSE: run with `cargo test -p pdfs-fuse sim:: -- --ignored`"]
fn a_write_opened_as_an_upload_lands_takes_the_landed_revision_as_its_base() {