howeyc/fsnotify

WatchFlags not supported on Windows?

mstum opened this issue · 7 comments

Hi,
I've setup a watcher like this:

func setupConfigWatcher() {
    configWatcher, err := fsnotify.NewWatcher()
    if err != nil {
        log.Fatal("Setup Config Watcher:",err)
    }

    done := make(chan bool)

    go func() {
        for {
            select {
        case ev := <-configWatcher.Event:
            log.Println("event:", ev)
            if strings.HasSuffix(ev.Name, "obrot-dns.json") && ev.IsModify() {
                loadConfig(true)
                showConfig()
                }
        case err := <-configWatcher.Error:
            log.Println("error:",err)
        }
    }
    }()

    err = configWatcher.WatchFlags("cfg",fsnotify.FSN_MODIFY)

    if err != nil {
        log.Fatal(err)
    }

    <-done
}

The WatchFlags is intended to only watch for modifications. However, this seems to not work, I get CREATE and DELETE and RENAME events as well:

2014/03/22 22:41:43 event: "cfg.obrot-dns.json.swp": CREATE
2014/03/22 22:41:43 event: "cfg.obrot-dns.json.swp": MODIFY
2014/03/22 22:41:48 event: "cfg\4913": CREATE
2014/03/22 22:41:48 event: "cfg\4913": MODIFY
2014/03/22 22:41:48 event: "cfg\4913": DELETE
2014/03/22 22:41:48 event: "cfg\obrot-dns.json": RENAME
2014/03/22 22:41:48 event: "cfg\obrot-dns.json~": RENAME
2014/03/22 22:41:48 event: "cfg\obrot-dns.json~": MODIFY
2014/03/22 22:41:48 event: "cfg\obrot-dns.json": CREATE
2014/03/22 22:41:48 event: "cfg\obrot-dns.json": MODIFY

Is there some limitation in Windows (Win7 x64 on a NTFS drive if it matters)?

This is most definitely a bug, as of right now we are purging events manually in user-space on every OS. See https://github.com/howeyc/fsnotify/blob/master/fsnotify.go#L20

If you track it down and have a bugfix/testcase to contribute, please note that fsnotify is now under the Go CLA #85 which requires an electronic signature. We're also shifting development to go.exp/fsnotify (as per the README), so raising the issue there and providing a CL is preferable.

Otherwise, I'll hopefully have a chance to verify the issue in the not to distant future.

Adding a log.Println at the top of the purgeEvents method shows that the method is called only once (when the Watcher is created) but then never again. It also never seems to enter the for loop. I understand it's a goroutine, but I don't know enough Go yet to see what the actual problem is.

@mstum Thanks for looking into it. I'll plan to take a look this weekend and report back.

I've identified two issues:

Overall I'm not too happy with WatchFlags and would really like to just remove what's currently there, hopefully coming back with something new that takes an advantage of the OS. I wrote about that before:

https://groups.google.com/d/msg/golang-dev/bShm2sqbrTY/PY7rEgljCZwJ
(and then did a little more research after that post).

Thanks for looking at it! Since there is a valid way to check it on the caller side by looking at the Name and the ev.IsModify()/IsDelete() etc., maybe it's valid to remove it and come up with a better way. I guess that a common use case is watching an individual file (Hot reloading configs), so maybe making fsnotify a low level construct and having a higher level helper that allows to watch an individual file (by parsing the directory and then filtering on the name?) for individual notifications?

Not sure, IF there is something cross platform native that would be great, but yeah, for my experiments I'm fine filtering myself.

The current implementation provides no tangible benefit over using ev.IsModify() on events coming over the channel, while adding a bunch of internal complexity to store the requested flags.

Windows can filter events at the OS-level which may be more efficient then waking up our thread just to filter the event out. Unfortunately Windows has a single filter to cover Create, Remove and Rename, so its not granular as Linux/BSD. At least, that's the documentation I've been able to dig up.

https://docs.google.com/document/d/1-GQrFdDVrA57-ce0kbzSth4lQqfOMMRKpih3hPJmvoU/edit?usp=sharing

This issue is resolved in go.exp/fsnotify by removing WatchFlags:

go.exp/fsnotify: remove current implementation of WatchFlags
https://codereview.appspot.com/100860043/

Still need to work out an alternative. I'm thinking of possibly configuring the Ops at the Watcher level instead of on each individual Add watch. That would result in a lot less internal bookkeeping for the library. Not sure if that will be the final solution though, still a lot to research & learn.