mirror of
https://github.com/narrrl/proton-drive-linux.git
synced 2026-11-04 16:56:59 +01:00
fix(fuse): a file read just as its create lands has its bytes (B179)
This commit is contained in:
1 parent
a6f019ebe6
commit
4e0fd3c0b1
6 files changed
+81
-6
No files matched your search
@@ -3225,8 +3225,19 @@ impl Core {
|
||||
/// `None` while it is still queued. Read from the row, which has it before
|
||||
/// the tree does.
|
||||
pub(crate) fn landed_row_uid(&self, ino: u64) -> Option<NodeUid> {
|
||||
state::ino_lid(ino)
|
||||
.and_then(|lid| self.db.uid_of_lid(lid).ok().flatten())
|
||||
state::ino_lid(ino).and_then(|lid| self.landed_lid_uid(lid))
|
||||
}
|
||||
|
||||
/// [`Core::landed_row_uid`] for a node known by its stand-in `uid`.
|
||||
pub(crate) fn landed_stand_in_uid(&self, uid: &NodeUid) -> Option<NodeUid> {
|
||||
pdfs_core::db::local_lid(&uid.to_string()).and_then(|lid| self.landed_lid_uid(lid))
|
||||
}
|
||||
|
||||
fn landed_lid_uid(&self, lid: i64) -> Option<NodeUid> {
|
||||
self.db
|
||||
.uid_of_lid(lid)
|
||||
.ok()
|
||||
.flatten()
|
||||
.and_then(|uid| parse_node_uid(&uid))
|
||||
.filter(|uid| !is_local_uid(uid))
|
||||
}
|
||||
|
||||
@@ -499,9 +499,14 @@ impl Core {
|
||||
}
|
||||
// A node created offline and never written has no blob and no remote: it
|
||||
// is an empty file, and asking the API about a `local~` uid would only
|
||||
// earn a 404 (offline.md Phase 3b).
|
||||
// earn a 404 (offline.md Phase 3b). Unless its create landed since the
|
||||
// read looked: the landing moved the queued write to the uid Drive
|
||||
// gave it, and the row says which (`docs/BUGS.md` B179).
|
||||
if is_local_uid(uid) {
|
||||
return Ok(Vec::new());
|
||||
return match self.landed_stand_in_uid(uid) {
|
||||
Some(real) => self.read_range(&real, mtime, fsize, offset, len, cache_blocks),
|
||||
None => Ok(Vec::new()),
|
||||
};
|
||||
}
|
||||
self.read_range_remote(uid, mtime, fsize, offset, len, cache_blocks)
|
||||
}
|
||||
|
||||
@@ -609,6 +609,41 @@ mod tests {
|
||||
let _ = std::fs::remove_dir_all(&dir);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore = "mounts FUSE: run with `cargo test -p pdfs-fuse sim:: -- --ignored`"]
|
||||
fn a_file_read_as_its_create_lands_has_its_bytes() {
|
||||
// The landing moved the queued write to the uid Drive gave the file.
|
||||
// A read that still knew the file by its stand-in found no write
|
||||
// queued under it, took the file for one never written and read it
|
||||
// empty (B179).
|
||||
let drive = FakeDrive::new();
|
||||
let dir = scratch("read-as-create-lands");
|
||||
let daemon = Daemon::start(&dir, drive.client(1, Faults::lan())).unwrap();
|
||||
let mnt = daemon.mountpoint.clone();
|
||||
let create = daemon.client.hold_reply_to_next_create();
|
||||
std::fs::write(mnt.join("a.txt"), b"old").unwrap();
|
||||
assert!(wait_until(Duration::from_secs(30), || create.reached()));
|
||||
std::fs::write(mnt.join("a.txt"), b"newer").unwrap();
|
||||
let uid = drive.lookup("a.txt").unwrap();
|
||||
let landing = daemon.client.hold_next_landing(&uid);
|
||||
drop(create);
|
||||
assert!(wait_until(Duration::from_secs(30), || landing.reached()));
|
||||
assert_eq!(std::fs::read(mnt.join("a.txt")).unwrap(), b"newer");
|
||||
drop(landing);
|
||||
assert!(
|
||||
wait_until(Duration::from_secs(30), || {
|
||||
daemon.pending().is_ok_and(|items| items.is_empty())
|
||||
&& drive.tree().get("a.txt") == Some(&Entry::File(Arc::new(b"newer".to_vec())))
|
||||
}),
|
||||
"{:?} {:?}",
|
||||
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_file_moved_while_its_create_was_on_the_wire_keeps_its_new_name() {
|
||||
|
||||
Reference in new issue
Block a user