I have an library I'm implementing that writes some data to a file and records the timestamp. It then checks the timestamp of the written file to see if it has been updated externally. But one of the test is failing^1 occasionally because the fs::metadata(&self.path)?.modified()?;
returns different values in consecutive calls despite no change to the file. I'm noticing this behaviour on Mac M1 and Ubuntu on an AMD laptop. Could it be specific to an ARM architecture thing?
The pseudo logic for the test is something like this
let file = create_file
let writer = BufWriter(file)
writer.write_all(b"This test is killing me");
let latest_update = fs::metadata(file_path).modified;
self.modified = latest_update
let check_update = fs::metadata(file_path).modified;
assert_eq!(check_update, latest_update); // fails
The exact failing test is shared in the below link. You might have to run it multiple times to get it to fail.
This can happen if the BufWriter
is dropped between the first and second checks.
This is because BufWriter
keeps a buffer of data that may not be written yet, with the intention of delaying until it fills up its buffer. If that is the case when it is dropped, it must issue one last write to the file to finish writing what it was given. Thus the first will see the metadata that is reflective of how it was before the final write and the second will see the consequence of it.
To avoid this problem, you can .flush()
the writer before retrieving the first metadata.
let file = std::fs::File::create(file_path).unwrap();
let mut writer = BufWriter::new(file);
writer.write_all(b"This test is killing me").unwrap();
writer.flush().unwrap(); // this fixes it
let latest_update = std::fs::metadata(file_path).unwrap().modified().unwrap();
drop(writer); // this is the original problem
let check_update = std::fs::metadata(file_path).unwrap().modified().unwrap();
assert_eq!(check_update, latest_update);