Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NotifyWatcher #70

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open

NotifyWatcher #70

wants to merge 10 commits into from

Conversation

utgheith
Copy link
Contributor

@utgheith utgheith commented Apr 1, 2021

An inotify based watcher for Linux NotifyWatcher

Why?

  • Doesn't reorder/drop events (assuming no overflow)
  • gives us much finer control/information about events

This is an opt-in feature. To enable it:

    os.watch(..., watchConfig = WatchConfig(preferNative=true))

Test cases enable it.

This is a large pull request and it might be wise to split it into multiple parts:

  • Randomized testing
  • The NotifyWatcher
  • ...

To do:
- property based testing
- white box unit tests

Issues:
- You can opt-out of the 'NotifyWatcher' by setting an environment variable OS_WATCH_OLD=1. This is mostly for testing.
- The WatchServiceWatcher fails the randomized rm test after a few iterations when run natively. I've been running the same with the NotifyWatcher for a few days without failure.
- The NotifyWatcher does fail with a small probability when run in Docker.
- The current implementation WatchServiceWatcher has different semantics from the OSX implementation. I made the NotifyService match the WatchServiceWatcher semantics but maybe it's a good idea to make Linux and OSX have identical semantics
- overflow events stop event delivery. I see one of 2 solutions (other than ignoring them): (1) re-process all watches (might lead to unexpected events), (2) report to the caller and let them do what they want (requires an error reporting mechanism)

@utgheith utgheith marked this pull request as draft April 2, 2021 17:48
@utgheith utgheith force-pushed the inotify branch 4 times, most recently from baa1d5d to db93d86 Compare April 3, 2021 22:09
@utgheith utgheith changed the title [WIP -- Please don't merge] NotifyWatcher NotifyWatcher Apr 3, 2021
@utgheith utgheith force-pushed the inotify branch 5 times, most recently from 025f2ca to 69b6591 Compare April 4, 2021 15:29
@utgheith utgheith marked this pull request as ready for review April 4, 2021 16:01
@utgheith utgheith force-pushed the inotify branch 8 times, most recently from cbf2d46 to de32868 Compare April 4, 2021 22:26
@lihaoyi
Copy link
Member

lihaoyi commented Apr 8, 2021

@utgheith I haven't gone through this in detail, but the overall approach looks reasonable. Honestly the most important thing is the tests: given that the old implementation fails tests and the new implementation passes, that's probably enough to be confident that we're making forward progress

@lefou
Copy link
Member

lefou commented Apr 18, 2021

What's the status of this PR? (And who is the main-maintainer of os-lib?) Is anybody OK with me merging it? I'd rather like to, as it would also solve the currently very flaky CI, which blocks PR #53 from getting green, which itself fixes a BSP bug in mill.

@lihaoyi
Copy link
Member

lihaoyi commented Apr 19, 2021

@lefou I suppose I'm still the main maintainer, but if you are willing to give it a review and @utgheith is happy with the PR go ahead and merge it

@utgheith
Copy link
Contributor Author

How about if we started by making it opt-in and enable it by default once it has been tested extensively?

Something like:

os.watch2(...)

or

os.watch.enable_linux_inotify = true

Rationale:

@utgheith
Copy link
Contributor Author

Added os.watch.use_linux_inotify to ease the transition. It defaults to false but the os.watch tests set it to true

Copy link
Member

@lefou lefou left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I haven't reviewed the actual inotify implementation, just the integeration for now.

os/src/Internals.scala Outdated Show resolved Hide resolved
@@ -45,4 +52,6 @@ package object watch{
thread.start()
watcher
}

var use_linux_inotify: Boolean = false
Copy link
Member

@lefou lefou Apr 23, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like the idea of switching this globally. I'd prefer a parameter which enables "native" support. The scaladoc should explain what "native" means for each platform. Also, making this binary compatible would be good idea, e.g. keeping the old def watch signature with sensible default to current behavior.

There is one issue though, as for Mac OS there seems to be currently no choice but only the native implementation. I can't tell if it's because the native version just works better or because the generic version doesn't work at all.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did it this way in order to stress the fact that it's an internal implementation detail not intended to survive for a long time and should be neither documented not show up on the public API.

A reasonable alternative is to add an extra argument to os.watch. Naming it something like preferNative would suggest that it's just a preference. It will always be picked on MacOS because it's the only choice.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member

@lihaoyi lihaoyi Apr 25, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@lefou the generic OSX version uses polling on every watched file, which is as good as "doesn't work at all" on non-trivial folder hierarchies https://macosx-port-dev.openjdk.java.narkive.com/PW3Ir4Q4/file-watching-on-oracle-jdk-on-mac-os-x-and-other-platforms

Copy link
Member

@lefou lefou Apr 25, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the idea with the WatchConfig, as it avoids future changes to watch API for such kind of tweaks. I don't like the deprecated annotation without any hint though. Also, we should give the user the fine control she wants, and make a flag per platform, when appropriate. And after @lihaoyi s comment I think it will end up with only one flag right now: useLinuxInotify.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think when we make the new NotifyWatcher optional and disabled by default, this is good enough to merge as-is. I doubt, we will find a reviewer familiar enough with Linux inotify system to review this timely.

build.sc Outdated Show resolved Hide resolved
os/watch/src/main.scala Outdated Show resolved Hide resolved
@lefou lefou added the help wanted Extra attention is needed label Dec 21, 2021
build.sc Outdated Show resolved Hide resolved
build.sc Outdated Show resolved Hide resolved
build.sc Outdated Show resolved Hide resolved
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Extra attention is needed
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants