-
Notifications
You must be signed in to change notification settings - Fork 41
Fix cache refresh on darwin #249
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
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,6 +22,7 @@ import ( | |
"io/fs" | ||
"os" | ||
"path/filepath" | ||
"runtime" | ||
"sort" | ||
"strings" | ||
"sync" | ||
|
@@ -529,17 +530,24 @@ func (w *watch) watch(fsw *fsnotify.Watcher, m *sync.Mutex, refresh func() error | |
if watch == nil { | ||
return | ||
} | ||
|
||
eventMask := fsnotify.Rename | fsnotify.Remove | fsnotify.Write | ||
// On macOS, we also need to watch for Create events. | ||
if runtime.GOOS == "darwin" { | ||
eventMask |= fsnotify.Create | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: if Darwin behaves the same way as Linux, IOW a rename to the same directory generates fsnotify.Rename+fsnotify.Create and a rename to a different directory generates an fsnotify.Rename, then I think it should not be necessary to watch for fsnotify.Create. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Interesting, does it mean that we don't need this There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @klihub events are the same, but their order is different. On Linux it generates fsnotify.Rename+fsnotify.Create, on Darwin: fsnotify.Create+fsnotify.Rename. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The specific issue in the tests is that we:
This was not triggering the refresh in the auto refresh case. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's assume the following example (adapted from the test code):
Using the example from: https://github.com/fsnotify/fsnotify/tree/main/cmd/fsnotify I run:
When I run the example above on
Repeating in a linux container, I see:
Note that when looking at the event loop, we see:
meaning that it's the Note that the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. unix.Renameat2 generates the same events as os.Rename: fsnotify.Rename+fsnotify.Create. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yep, but it's generated if the file already exists. We should probably consider testing it with the cache API calls. It could also make sense to modify it to use BTW, since then CDI supports Darwin? I was under impression that only Linux is supported. We should explicitly mention this in the docs, I believe. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We don't control HOW users write specs to the spec directories, so cannot make assumptions about which APIs are being used. My main motivator for this modification was to allow me to run the unit tests on my Mac. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @elezar I am fine with the current state where on Darwin we also watch for the create event, if that helps your daily workflow which I gather is on MacOS/Darwin. IMO, this is not necessary on Linux and not helpful either (it would only generate an extra event if someone created an empty file without ever writing any content to it). About the rest of the discussion related to trying to write/create files differently to generate a different set, or order, of inotify/fsnotify events... I think that is a bit futile. As @elezar pointed out, we don't control how users write Spec files and neither should we try. Spec reading/parsing is supposed to be fault tolerant for multiple reasons, the uncontrollability and thus unpredictability of the set and order of events generated being one of them. Therefore, as long as we make sure that we never fail to act on an event eventually, and we don't delay acting on events too long (this is the reason why we don't have an timer-based event filtering/deduplication) we should be fine... IMO. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
On linux, both events are generated after the file has been renamed. On Darwin, I'm not sure, although one would hope that a rename(2) and related variants would be atomic (IIRC, required for POSIX-compliance) which should mean that both are generated after the fact, otherwise it is not really atomic if an intermediate state is externally observable. Then again, since the tests did fail on Darwin and I assume the failing tests check the right thing to decide success/failure, some of this mut be false on Darwin... but then based on @elezar's experience and fix it looks like adding an extra watch on Darwin for fsnotify.Create fixes things there... so I think this should be now fine there, too. |
||
} | ||
|
||
for { | ||
select { | ||
case event, ok := <-watch.Events: | ||
if !ok { | ||
return | ||
} | ||
|
||
if (event.Op & (fsnotify.Rename | fsnotify.Remove | fsnotify.Write)) == 0 { | ||
if (event.Op & eventMask) == 0 { | ||
continue | ||
} | ||
if event.Op == fsnotify.Write { | ||
if event.Op == fsnotify.Write || event.Op == fsnotify.Create { | ||
if ext := filepath.Ext(event.Name); ext != ".json" && ext != ".yaml" { | ||
continue | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
//go:build darwin | ||
// +build darwin | ||
|
||
/* | ||
Copyright © 2021 The CDI Authors | ||
|
||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
|
||
http://www.apache.org/licenses/LICENSE-2.0 | ||
|
||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package cdi | ||
|
||
import "syscall" | ||
|
||
func osSync() { | ||
_ = syscall.Sync() | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bart0sh after your probing I spent some more time investigating this, and noted that the events that are generated on
darwin
areCREATE
events and notWRITE
events.I thought it safer to not modify existing behaviour on non-darwin platforms.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for investigation. I'm wondering why CREATE was not considered on Linux. I believe it's also generated when file is created. Do we intentionally skip it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@klihub since you were the one who implemented this, maybe you could comment.
Note that
fsnotify
uses two different sources for the events on Linux and MacOS systems. It may also be that theos.Rename
calls that are use in the tests trigger different events. There are also a number of issues such as fsnotify/fsnotify#54 calling out inconsistent behaviour on MacOS.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On Linux, when you
Therefore, it should not be necessary to trigger a rescan for a fsnotify.Create.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice.
Trivia. macOS itself provides two different mechanisms: FSEvents, kqueue. fsnotify seems to use kqueue.
Linux has its own mechanism, called inotify. Here is a bikeshed thread comparing both interfaces.
I like the docs of https://pythonhosted.org/watchdog/installation.html#supported-platforms-and-caveats.
Interesting: https://watchexec.github.io/docs/macos-fsevents.html