unison-fsmonitor
unison-fsmonitor copied to clipboard
Race condition can leave files out of sync while syncing between local dirs
To reproduce (I'm on macOS 12.3.1):
mkdir /tmp/a /tmp/b
unison /tmp/a /tmp/b -repeat watch -ui text -debug fswatch+
While this is running, try
echo $RANDOM > /tmp/a/x
I see a bunch of output, quoted below. Importantly, there is a delay between "Synchronization complete" being printed and new WAIT
commands being sent. If you modify /tmp/a/x
again during this interval, a second synchronization does not occur, and so /tmp/a/x
and /tmp/b/x
stay out of sync (until one of them is changed yet again or Unison is restarted).
I can reproduce this on Unison 2.51.5 as well as the latest master
at time of writing. It doesn't occur when using Unison's built-in fsmonitor implementation on Linux.
The cause appears to be the timing of CHANGES
responses. This fsmonitor implementation sends CHANGES
immediately as soon as changes occur. But the built-in fsmonitor has more of a polling model, where CHANGES
responses are sent only in response to WAIT
commands; a CHANGE
response terminates a wait, and changes that occur while not waiting should be reported at the next wait. In fact, Unison itself seems to ignore the arguments to CHANGES
responses; it simply uses CHANGES
as a notification that it should terminate the wait and send its own CHANGES
command to request filenames of the files that changed. (Nevertheless, the built-in fsmonitor does include the hashes of changed files in its CHANGES
response; there can be multiple hashes in a single response.)
Edit: To further clarify: WAIT
is like select()
, terminated by a CHANGES
response, and CHANGES
commands are like read()
. They affect the same state (list of pending changes). I think.
[fswatch+] >> CHANGES d03c239c5bae8b7a9a35a6284d8a9512
Looking for changes
[fswatch+] << CHANGES d03c239c5bae8b7a9a35a6284d8a9512
[fswatch+] >> RECURSIVE x
[fswatch+] >> DONE
[fswatch+] << START d03c239c5bae8b7a9a35a6284d8a9512 /private/tmp/a x
[fswatch+] >> OK
[fswatch+] << DONE
[fswatch+] << CHANGES ee6f81089ac5b4e616740c34d688212d
[fswatch+] >> RECURSIVE x
[fswatch+] >> RECURSIVE %2Eunison%2Ex%2Eee6f81089ac5b4e616740c34d688212d%2Eunison%2Etmp
[fswatch+] >> DONE
[fswatch+] << START ee6f81089ac5b4e616740c34d688212d /private/tmp/b x
[fswatch+] >> OK
[fswatch+] << DONE
Reconciling changes
changed ----> x
a : changed file modified on 2022-05-09 at 19:05:43 size 6 rw-r--r--
b : unchanged file modified on 2022-05-09 at 19:05:39 size 6 rw-r--r--
Propagating updates
Unison 2.51.5 (ocaml 4.12.1) started propagating changes at 19:05:44.67 on 09 May 2022
[BGN] Updating file x from /private/tmp/a to /private/tmp/b
[END] Updating file x
Unison 2.51.5 (ocaml 4.12.1) finished propagating changes at 19:05:44.67 on 09 May 2022, 0.001 s
Saving synchronizer state
Synchronization complete at 19:05:44 (1 item transferred, 0 skipped, 0 failed)
[fswatch+] >> CHANGES ee6f81089ac5b4e616740c34d688212d
[fswatch+] >> CHANGES ee6f81089ac5b4e616740c34d688212d
[fswatch+] >> CHANGES ee6f81089ac5b4e616740c34d688212d
[fswatch+] << WAIT d03c239c5bae8b7a9a35a6284d8a9512
[fswatch+] << WAIT ee6f81089ac5b4e616740c34d688212d
Thank you very much for reporting! Will have a closer look as soon as I can.
Has there been any updates on this issue? I want to use this with unison to sync two local directories on my MacBook but am hesitant to try because this issue is still open.
Either way, thank you for all of your work on this. Much appreciated.