-
Notifications
You must be signed in to change notification settings - Fork 1
/
coalesce.go
96 lines (83 loc) · 2.28 KB
/
coalesce.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
package watch
import (
"time"
"github.com/windmilleng/fsnotify"
)
// We put a cap on how many sequential events to coalesce for use-cases like log
// files where we see continuous data for a long time.
const MAX_COALESCE = 10
// wait time is the maximum amount of space between two events
// to make us coalesce them.
const defaultCoalesceWaitTime = time.Millisecond
func coalesceEvents(inCh chan fsnotify.Event, outCh chan fsnotify.Event, waitTime time.Duration) {
defer func() {
close(outCh)
}()
var event fsnotify.Event
var nextEvent fsnotify.Event
var ok bool
coalesceCount := 1
var timerCh <-chan time.Time // timerCh is non-nil iff there is a pending event to send out
for {
select {
case nextEvent, ok = <-inCh:
if !ok {
if timerCh != nil {
outCh <- event
}
return
}
nextEvent = simplify(nextEvent)
if timerCh != nil {
merged := false
if coalesceCount < MAX_COALESCE {
event, merged = coalesce(event, nextEvent)
}
// If we were able to coalesce, try to coalesce against the next event.
// Otherwise, emit the event.
if merged {
coalesceCount++
} else {
outCh <- event
event = nextEvent
coalesceCount = 1
}
} else {
event = nextEvent
timerCh = time.After(waitTime)
coalesceCount = 1
}
case <-timerCh:
outCh <- event
timerCh = nil
coalesceCount = 1
}
}
}
// Narrow all events to Create or Write.
//
// We don't need fine-grained events because we're just going to compare
// what we have in the snapshot against what we have on disk anyway.
//
// We only need Create for special handling when a directory is created.
// We could probably get rid of Create too if we had a better API for querying
// a snapshot by directory.
func simplify(e fsnotify.Event) fsnotify.Event {
if e.Op&fsnotify.Create != 0 {
return fsnotify.Event{Name: e.Name, Op: fsnotify.Create}
} else {
return fsnotify.Event{Name: e.Name, Op: fsnotify.Write}
}
}
// All events passed into coalesce should be simplified.
func coalesce(old, new fsnotify.Event) (fsnotify.Event, bool) {
if old.Name != new.Name {
return old, false
}
if new.Op == fsnotify.Create {
// A create of a Dir means we have to scan the whole dir, so make sure
// we don't drop that.
return new, true
}
return old, true
}