watch: a new strategy for handling spurious events, hoping to fix race conditions (#163)

This commit is contained in:
Nick Santos 2018-08-23 13:24:47 -04:00 committed by Nicolas De loof
parent 4801d2b1a4
commit 4562b0bf95
2 changed files with 25 additions and 15 deletions

View File

@ -134,6 +134,9 @@ func TestWatchNonExistentPath(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
f.fsync()
d1 := []byte("hello\ngo\n") d1 := []byte("hello\ngo\n")
err = ioutil.WriteFile(path, d1, 0644) err = ioutil.WriteFile(path, d1, 0644)
if err != nil { if err != nil {

View File

@ -20,21 +20,13 @@ type darwinNotify struct {
// so that, for recursive watches, we can guarantee that the path list doesn't // so that, for recursive watches, we can guarantee that the path list doesn't
// change. // change.
sm *sync.Mutex sm *sync.Mutex
}
func (d *darwinNotify) isTrackingPath(path string) bool { // ignore the first event that says the watched directory
d.sm.Lock() // has been created. these are fired spuriously on initiation.
defer d.sm.Unlock() ignoreCreatedEvents map[string]bool
for _, p := range d.stream.Paths {
if p == path {
return true
}
}
return false
} }
func (d *darwinNotify) loop() { func (d *darwinNotify) loop() {
ignoredSpuriousEvents := make(map[string]bool, 0)
for { for {
select { select {
case <-d.stop: case <-d.stop:
@ -47,11 +39,20 @@ func (d *darwinNotify) loop() {
for _, e := range events { for _, e := range events {
e.Path = filepath.Join("/", e.Path) e.Path = filepath.Join("/", e.Path)
// ignore the first event that says the watched directory
// has been created. these are fired spuriously on initiation.
if e.Flags&fsevents.ItemCreated == fsevents.ItemCreated { if e.Flags&fsevents.ItemCreated == fsevents.ItemCreated {
if !ignoredSpuriousEvents[e.Path] && d.isTrackingPath(e.Path) { d.sm.Lock()
ignoredSpuriousEvents[e.Path] = true shouldIgnore := d.ignoreCreatedEvents[e.Path]
if shouldIgnore {
d.ignoreCreatedEvents[e.Path] = false
} else {
// If we got a created event for something
// that's not on the ignore list, we assume
// we're done with the spurious events.
d.ignoreCreatedEvents = nil
}
d.sm.Unlock()
if shouldIgnore {
continue continue
} }
} }
@ -80,6 +81,12 @@ func (d *darwinNotify) Add(name string) error {
} }
es.Paths = append(es.Paths, name) es.Paths = append(es.Paths, name)
if d.ignoreCreatedEvents == nil {
d.ignoreCreatedEvents = make(map[string]bool, 1)
}
d.ignoreCreatedEvents[name] = true
if len(es.Paths) == 1 { if len(es.Paths) == 1 {
go d.loop() go d.loop()
es.Start() es.Start()