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

Overflows #155

Merged
merged 3 commits into from
May 27, 2018
Merged

Overflows #155

merged 3 commits into from
May 27, 2018

Conversation

eatkins
Copy link
Contributor

@eatkins eatkins commented May 16, 2018

I am optimistic that these changes will stop the spurious test failures that we've seen. I was working on top of #151 because it added some additional synchronization that I needed.

eed3si9n
eed3si9n previously approved these changes May 19, 2018
Copy link
Member

@eed3si9n eed3si9n left a comment

Choose a reason for hiding this comment

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

LGTM

@@ -146,11 +155,62 @@ private[sbt] object EventMonitor {
notExist.foreach(s.unregister)
updatedFiles ++ newFiles ++ notExist
}

Copy link
Member

Choose a reason for hiding this comment

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

@eatkins Thanks for the descriptive commit message on this commit.

eatkins added 3 commits May 22, 2018 08:45
The handleFileDescendant method was recursively constructing a list of
results by calling File.list and recursively calling back into itself
for each directory that it found in the listed files. There were two
performance bugs in this approach. One was that handleFileDescendant
actually called File.list twice for each directory. The other was that
after it got the second list of files, it had to filter the results
based on whether or not it was a directory. When I called jstack on my
sbt process during a slow test run, invariably one of the threads was
bloced on File.isDirectory.

The fix is simple, if verbose. Use Files.walkFileTree instead. It is
verbose, but it recursively lists all of the files in the tree specified
by the path. An alternative would be to use Files.walk. I didn't go this
route because Files.walk is somewhat hard to reason about because the
iterator can throw an exception at any time. This is a problem if the
directory is being traversed and modified at the same time. With
Files.walkFileTree, I know that if, for example, a directory disappears
from out from underneath us, then we'll just move on without throwing an
exception.
This test sometimes spuriously fails and I'm pretty sure it's because of
concurrent modifications of lines.
While working on a related project, I realized that it's essential to
handle the OVERFLOW case for a WatchEvent. The EventMonitor relies on
subdirectory creation events to create a new watch key for each
subdirectory. If those events are missed due to overflow, the
EventMonitor will not be monitoring the newly created subdirectories. To
fix this, when the EventMonitor detects an overflow, it will now poll
the directory of the watch key repeatedly until it stabilizes. Once that
happens, it will register all of the newly found directories (if any)
with the watch service and will create events for all of the files in
said directories.

It is still possible that a trigger could be missed in the event that a
lot of files in a watched directory cause an overflow before a valid
source file is touched and before the EventMonitor handles the overflow.
I am not particularly worried about this.

I also discovered that the PollingWatchService was using an unbounded
list of events. This seemed risky so I switched to using an
ArrayBlockingQueue of size 256, which is what the MacOSXWatchService
uses as well. Since the queue is now bounded, I added overflow events to
the PollingWatchService as well.

I also added synchronization for a few methods in PollingWatchey and
MacOSXWatchKey. This is more consistent with the AbstractWatchKey in the
jdk. The other methods return constant values so synchronization is
pointless.

I ran a number of travis builds against the content of this commit and
none of them failed.
@eed3si9n eed3si9n merged commit 3328e02 into sbt:1.1.x May 27, 2018
@eatkins eatkins deleted the overflows branch October 9, 2018 17:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants