Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Atomic file replacement in Clojure

I have an app that writes that updates a disk file, but I want to make sure, as much as possible, that the previous version of the file doesn't get corrupted.

The most straight forward way to update a file, of course, is to simply write:

(spit "myfile.txt" mystring)

However, if the PC (or java process) dies in the middle of writing, this has a small chance of corrupting the file.

A better solution is probably to write:

(do (spit "tempfile" mystring)
    (.rename (file "tempfile") "myfile.txt")
    (delete-file "tempfile"))

This uses the java file rename function, which I gather is typically atomic when performed on a single storage device in most cases.

Do any Clojurians with some deeper knowledge of Clojure file IO have any advice on whether this is the best approach, or if there's a better way to minimize the risk of file corruption when updating a disk file?

Thanks!

like image 395
drcode Avatar asked Jan 18 '26 11:01

drcode


1 Answers

This is not specific to Clojure; a temp-rename-delete scenario does not guarantee an atomic replace under the POSIX standard. This is due to the possibility of write reordering - the rename might get to the physical disk before the temp writes do, so when a power failure happens within this time window, data loss happens. This is not a purely theoretical possibility:

http://en.wikipedia.org/wiki/Ext4#Delayed_allocation_and_potential_data_loss

You need an fsync() after writing the temp file. This question discusses calling fsync() from Java.

like image 151
Rafał Dowgird Avatar answered Jan 21 '26 06:01

Rafał Dowgird



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!