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
Built-in event filtering of Ops #7
Comments
My current suggestion is to set the Op filter globally at the Watcher level instead of for each Watch added. Preferably in such a way that it cannot be changed later. Perhaps something like: watcher, err := fsnotify.NewWatcher(fsnotify.Create|fsnotify.Write)
|
I like your proposal of doing the Ops filtering on creation of the watcher. One usually creates such a watcher with a purpose in mind and the events being delivered are usually suitable for this purpose for the lifetime of the watcher. And after all this is just an optimization. One can always choose a broader scope in order to be sure. So maybe an additional simple creation function like |
The current code of const agnosticEvents = unix.IN_MOVED_TO | unix.IN_MOVED_FROM |
unix.IN_CREATE | unix.IN_ATTRIB | unix.IN_MODIFY |
unix.IN_MOVE_SELF | unix.IN_DELETE | unix.IN_DELETE_SELF
var flags uint32 = agnosticEvents So basically the flags are hard-coded to the ones above. Would there be any opposition to adding another API, like: func (w *Watcher) Add(name string) error {
return w.AddWithFlags(name, agnosticEvents)
}
func (w *Watcher) AddWithFlags(name string, flags uint32) error {
// mostly the same code as the current Add() but use flags passed in argument I need to ignore |
I hear you, although I personally don't think it's a big problem that the flags differ across the platforms, since this API would just take a Now when I reviewed the open issues I missed #173, that's obviously a more elegant solution, and at this rate between this bug and #97 and #123, it's very hard for me to get correctness out of fsnotify, so I was considering writing my own little inotify wrapper anyway, so I'm glad to hear that this is being considered. For now I think I'll just fork the project to quickly fix/hack the bugs that are impacting me. |
Pull requests are welcome, and once we have more people reviewing and merging pull requests, things should start to move faster. I think breaking out the low-level platform specific libraries (such as #173) will also help there. It should allow experts in inotify to work on that without worrying about the cross-platform API, and others to tackle cross-platform consistency without dealing with all the low-level details. |
On Linux, implementing a recursive watch with IN_DELETE_SELF is virtually impossible. Since the API doesn't offer any way to pick which flags to use (see issue fsnotify#7), such an API is needed, and this is a crude but effective attempt at adding one.
On Linux, implementing a recursive watch with IN_DELETE_SELF is virtually impossible. Since the API doesn't offer any way to pick which flags to use (see issue fsnotify#7), such an API is needed, and this is a crude but effective attempt at adding one.
…notify/fsnotify package There is an unfortunate behaviour in the fsnotify package in that it watches for all events on a path, and doesn't give the user the option of only watching for specific events. This means that when watching, for example on /dev/net, any writes to /dev/net/tun will cause a WRITE event to be sent to LXD. As you can image, for high traffic interfaces this can cause many events and causes LXD to use a lot of CPU. This is equally the case for other devices that can be written to, such as block devices. The issue is identified in the upstream package (fsnotify/fsnotify#7) but there doesn't seem to be any consensus on how to move forward so the issue has languished. LXD however doesn't need cross-platform support that fsnotify package offers and so can use a lightweight wrapper around the inotify feature (which is what we use with fsnotify anyway). There used to be an inotify wrapper at golang.org/x/exp/inotify which has subsequently moved to gopkg.in/fsnotify.v0. Unfortunately that doesn't support go mod and so isn't usable by LXD. Its also not been updated since 2015. There is however a fork of golang.org/x/exp/inotify at https://github.com/kubernetes/utils/tree/master/inotify which has seen some minor maintenance this year. This package also has go mod support. This commit also makes the following changes: - Avoids the need to make a stat syscall to detect if event is for a directory by using the InIsdir flag in the event Mask. - Avoids calling every registered handler for every new directory and instead performs a path prefix match. - Improves comments and readability. - Cleans the path coming from the event to ensure comparison with registered handlers works. - Reduces repitition in event action logic. Fixes canonical#11151 Signed-off-by: Thomas Parrott <thomas.parrott@canonical.com>
…notify/fsnotify package There is an unfortunate behaviour in the fsnotify package in that it watches for all events on a path, and doesn't give the user the option of only watching for specific events. This means that when watching, for example on /dev/net, any writes to /dev/net/tun will cause a WRITE event to be sent to LXD. As you can image, for high traffic interfaces this can cause many events and causes LXD to use a lot of CPU. This is equally the case for other devices that can be written to, such as block devices. The issue is identified in the upstream package (fsnotify/fsnotify#7) but there doesn't seem to be any consensus on how to move forward so the issue has languished. LXD however doesn't need cross-platform support that fsnotify package offers and so can use a lightweight wrapper around the inotify feature (which is what we use with fsnotify anyway). There used to be an inotify wrapper at golang.org/x/exp/inotify which has subsequently moved to gopkg.in/fsnotify.v0. Unfortunately that doesn't support go mod and so isn't usable by LXD. Its also not been updated since 2015. There is however a fork of golang.org/x/exp/inotify at https://github.com/kubernetes/utils/tree/master/inotify which has seen some minor maintenance this year. This package also has go mod support. This commit also makes the following changes: - Avoids the need to make a stat syscall to detect if event is for a directory by using the InIsdir flag in the event Mask. - Avoids calling every registered handler for every new directory and instead performs a path prefix match. - Improves comments and readability. - Cleans the path coming from the event to ensure comparison with registered handlers works. - Reduces repetition in event action logic. Fixes canonical#11151 Signed-off-by: Thomas Parrott <thomas.parrott@canonical.com>
…notify/fsnotify package There is an unfortunate behaviour in the fsnotify package in that it watches for all events on a path, and doesn't give the user the option of only watching for specific events. This means that when watching, for example on /dev/net, any writes to /dev/net/tun will cause a WRITE event to be sent to LXD. As you can image, for high traffic interfaces this can cause many events and causes LXD to use a lot of CPU. This is equally the case for other devices that can be written to, such as block devices. The issue is identified in the upstream package (fsnotify/fsnotify#7) but there doesn't seem to be any consensus on how to move forward so the issue has languished. LXD however doesn't need cross-platform support that fsnotify package offers and so can use a lightweight wrapper around the inotify feature (which is what we use with fsnotify anyway). There used to be an inotify wrapper at golang.org/x/exp/inotify which has subsequently moved to gopkg.in/fsnotify.v0. Unfortunately that doesn't support go mod and so isn't usable by LXD. Its also not been updated since 2015. There is however a fork of golang.org/x/exp/inotify at https://github.com/kubernetes/utils/tree/master/inotify which has seen some minor maintenance this year. This package also has go mod support. This commit also makes the following changes: - Avoids the need to make a stat syscall to detect if event is for a directory by using the InIsdir flag in the event Mask. - Avoids calling every registered handler for every new directory and instead performs a path prefix match. - Improves comments and readability. - Cleans the path coming from the event to ensure comparison with registered handlers works. - Reduces repetition in event action logic. Fixes canonical#11151 Signed-off-by: Thomas Parrott <thomas.parrott@canonical.com>
…notify/fsnotify package There is an unfortunate behaviour in the fsnotify package in that it watches for all events on a path, and doesn't give the user the option of only watching for specific events. This means that when watching, for example on /dev/net, any writes to /dev/net/tun will cause a WRITE event to be sent to LXD. As you can image, for high traffic interfaces this can cause many events and causes LXD to use a lot of CPU. This is equally the case for other devices that can be written to, such as block devices. The issue is identified in the upstream package (fsnotify/fsnotify#7) but there doesn't seem to be any consensus on how to move forward so the issue has languished. LXD however doesn't need cross-platform support that fsnotify package offers and so can use a lightweight wrapper around the inotify feature (which is what we use with fsnotify anyway). There used to be an inotify wrapper at golang.org/x/exp/inotify which has subsequently moved to gopkg.in/fsnotify.v0. Unfortunately that doesn't support go mod and so isn't usable by LXD. Its also not been updated since 2015. There is however a fork of golang.org/x/exp/inotify at https://github.com/kubernetes/utils/tree/master/inotify which has seen some minor maintenance this year. This package also has go mod support. This commit also makes the following changes: - Avoids the need to make a stat syscall to detect if event is for a directory by using the InIsdir flag in the event Mask. - Avoids calling every registered handler for every new directory and instead performs a path prefix match. - Improves comments and readability. - Cleans the path coming from the event to ensure comparison with registered handlers works. - Reduces repetition in event action logic. Fixes #11151 Signed-off-by: Thomas Parrott <thomas.parrott@canonical.com>
This adds the ability to only listen for some event types. If you're only interested in Created events and you're getting a lot of Write events then you're just wasting CPU cycles This also adds the ability listen on extra unportable event types; since this is so related I figured I might as well do both. Ideally we want to 1) make it very very obvious you're doing something unportable, and 2) make it reasonably easy "fallback" for platforms where this isn't supported. Unportable events start with "Unportable", which should document their unportabilitiness. Also add a new Supports(Op) method, which should make adding fallback logic relatively painless. For example, to use CloseWrite where supported, but falling back to Write when it's not: var op fsnotify.Op if w.Supports(fsnotify.UnportableCloseWrite) { op |= fsnotify.UnportableCloseWrite } else { op |= fsnotify.Create | fsnotify.Write } w.AddWith("/tmp", fsnotify.WithEvents(op)) And then you can deal with this in the write loop. There's a full example in cmd/fsnotify/closewrite.go All of this is unexported for now, until support for other platforms has been added. Updates #7 Updates #519
The current mechanism for filtering events is to inspect the Op bitmask:
In howeyc/fsnotify there is a
WatchFlags
method to filter operations. WatchFlags was removed in 10e1440 (v0.10.0) because:@nightlyone pointed out that it still is desirable to specify filters so the kernel doesn't need to wakeup our thread/process for an event we'll just ignore.
Some research (API doc) reveal differences from one OS to the next:
NOTE_CREATE
), much less a filter for it.FILE_NOTIFY_CHANGE_FILE_NAME
that covers Create, Remove and Rename. An event does indicate which one of these it is, but some user-space filtering is still necessary.The text was updated successfully, but these errors were encountered: