In this exercise, you will learn
-
how to implement
DropandWritetraits. -
the “Drop guard” pattern.
-
how to test panicking APIs.
std::fs::File type has a
sync_all method which ensures that all data is written to disk.
This method is not called by default: syncing is slow and OS has good heuristics for optimistically delaying syncing.
In this assignment, we’ll implement a DurableFile wrapper for File, which helps to ensure that applications calls sync_all.
Specifically, DurableFile tracks syncs and writes.
If a DurableFile is dropped with an outstanding write, its Drop panics.
Not calling sync_all before disposing the file is considered a bug in this case.
Panic helps to elevate silent potential data loss into a loud failure.
- Step 1
-
Implement
DurableFiledata structure:struct DurableFile { file: std::fs::File, needs_sync: bool, } - Step 2
-
Implement a constructor:
impl DurableFile { pub fn new(file: std::fs::File) -> DurableFile { ... } }Optional: implement
From<std::fs::File>for DurableFile - Step 3
-
Implement the
std::io::Writetrait forDurableFile. Usesync_allin the implementation of theflushmethod. All write operations should set theneeds_syncflag, theflushmethod should clear it. - Step 4
-
Implement the
std::ops::Droptrait forDurableFileso that it panics if the file is not flushed. What is the right behavior forDrop? Are there any edge cases to worry about? - Step 5
-
Add an inherent
closemethod for forDurableFile, to explicitly sync&dispose the file and handle potential errors. What is the appropriate signature (type ofselfand the return type) forclose? - Step 6
-
Write a couple of simple smoke tests. You might find the
tempdircrate and#[should_panic] attribute useful!#[test] #[should_panic(expected = "not yet implemented")] fn smoke_test() { let dir = tempdir::TempDir::new("tests").unwrap(); let file = std::fs::File::create(dir.path().join("foo.txt")).unwrap(); todo!() }