yep, seems like I can reproduce it on CI: https://github.com/keynmol/test-os-lib-scala-native/runs/1801082808#step:6:8
Unless there's something stupid I'm doing, I'm going to create an issue
here it is: lihaoyi/os-lib#59
Need to figure out how to read gdb's output again, after many years :D
checkChanges(
os.remove.all(wd / "folder4"),
Set(
os.sub / "folder4",
os.sub / "folder4" / "nestedA",
os.sub / "folder4" / "nestedA" / "a.txt",
os.sub / "folder4" / "nestedB",
os.sub / "folder4" / "nestedB" / "b.txt"
)
)
delete folder4
event arrives before the delete folder4/nestedA
(or B) event. This causes the implementation to cancel the folder/nestedA
watch and that update is lost.
I take it back. Running something like:
declare -i i=0; while ./mill -i os.watch.jvm[2.13.4].test; do i=$((i+1)); echo $i; done
Produced this output:
[103/103] os.watch.jvm[2.13.4].test.test
-------------------------------- Running Tests --------------------------------
+ test.os.watch.WatchTests.singleFolder 5784ms
1
[103/103] os.watch.jvm[2.13.4].test.test
-------------------------------- Running Tests --------------------------------
+ test.os.watch.WatchTests.singleFolder 5786ms
2
[103/103] os.watch.jvm[2.13.4].test.test
-------------------------------- Running Tests --------------------------------
+ test.os.watch.WatchTests.singleFolder 5778ms
3
[103/103] os.watch.jvm[2.13.4].test.test
-------------------------------- Running Tests --------------------------------
+ test.os.watch.WatchTests.singleFolder 5786ms
4
[103/103] os.watch.jvm[2.13.4].test.test
...
+ test.os.watch.WatchTests.singleFolder 5783ms
50
[103/103] os.watch.jvm[2.13.4].test.test
-------------------------------- Running Tests --------------------------------
+ test.os.watch.WatchTests.singleFolder 5794ms
51
[103/103] os.watch.jvm[2.13.4].test.test
-------------------------------- Running Tests --------------------------------
X test.os.watch.WatchTests.singleFolder 3200ms
utest.AssertionError: assert(expectedChangedPaths == changedSubPaths)
expectedChangedPaths: Set[os.SubPath] = HashSet(folder4/nestedB, folder4/nestedA, folder4, folder4/nestedA/a.txt, folder4/nestedB/b.txt)
changedSubPaths: scala.collection.mutable.Set[os.SubPath] = HashSet(folder4/nestedA/a.txt, folder4/nestedB, folder4, folder4/nestedB/b.txt)
utest.asserts.Asserts$.assertImpl(Asserts.scala:30)
test.os.watch.WatchTests$.checkChanges$1(WatchTests.scala:52)
test.os.watch.WatchTests$.$anonfun$tests$3(WatchTests.scala:93)
test.os.TestUtil$.prep(TestUtil.scala:71)
test.os.watch.WatchTests$.$anonfun$tests$2(WatchTests.scala:7)
1 targets failed
os.watch.jvm[2.13.4].test.test test.os.watch.WatchTests test.os.watch.WatchTests.singleFolder
Question 1: consistency between MacOS and Linux. Removing the watched directory (an obvious corner-case) behaves differently on MacOS and Linux. What is the expectation? Maybe it should be documented as undefined behavior?
[Sample program] (https://github.com/utgheith/watch/blob/master/src/main/scala/main.scala)
MacOS
event
data
Linux
event
data/a
data/b
Here is a stress test that leads to failure in 3 native environments: MacOS, Ubuntu/ext4, Ubuntu/ZFS. There seem to be 2 separate issues:
(1) a race condition that causes the watch thread to die with FileNotFoundException.
(2) events get reordered leading to premature watch cancelation on some subdirectories
WatchService
only drops directory DELETE
events (at least in the stress tests I tried)DELETE
eventsDELETE
events for sub directories of moved directories:Once the call to watch returns, onEvent is guaranteed to receive a an event containing the path for:
- Every file or folder that gets created, deleted, updated or moved within the watched folders
- For copied or moved folders, the path of the new folder as well as every file or folder within it.
- For deleted or moved folders, the root folder which was deleted/moved, but without the paths of every file that was within it at the original location