diff --git a/lib/watchaggregator/aggregator.go b/lib/watchaggregator/aggregator.go index e69ed5257..93a38c4ba 100644 --- a/lib/watchaggregator/aggregator.go +++ b/lib/watchaggregator/aggregator.go @@ -104,18 +104,32 @@ type aggregator struct { notifyTimer *time.Timer notifyTimerNeedsReset bool notifyTimerResetChan chan time.Duration - counts map[fs.EventType]int + counts eventCounter root *eventDir ctx context.Context } +type eventCounter struct { + removes int // Includes mixed events. + nonRemoves int +} + +func (c *eventCounter) add(typ fs.EventType, n int) { + if typ&fs.Remove != 0 { + c.removes += n + } else { + c.nonRemoves += n + } +} + +func (c *eventCounter) total() int { return c.removes + c.nonRemoves } + func newAggregator(ctx context.Context, folderCfg config.FolderConfiguration) *aggregator { a := &aggregator{ folderID: folderCfg.ID, folderCfgUpdate: make(chan config.FolderConfiguration), notifyTimerNeedsReset: false, notifyTimerResetChan: make(chan time.Duration), - counts: make(map[fs.EventType]int), root: newEventDir(), ctx: ctx, } @@ -176,7 +190,7 @@ func (a *aggregator) newEvent(event fs.Event, inProgress map[string]struct{}) { } func (a *aggregator) aggregateEvent(event fs.Event, evTime time.Time) { - if event.Name == "." || a.eventCount() == maxFiles { + if event.Name == "." || a.counts.total() == maxFiles { l.Debugln(a, "Scan entire folder") firstModTime := evTime if a.root.childCount() != 0 { @@ -190,8 +204,8 @@ func (a *aggregator) aggregateEvent(event fs.Event, evTime time.Time) { lastModTime: evTime, evType: event.Type, } - a.counts = make(map[fs.EventType]int) - a.counts[event.Type]++ + a.counts = eventCounter{} + a.counts.add(event.Type, 1) a.resetNotifyTimerIfNeeded() return } @@ -212,9 +226,9 @@ func (a *aggregator) aggregateEvent(event fs.Event, evTime time.Time) { if ev, ok := parentDir.events[name]; ok { ev.lastModTime = evTime if merged := event.Type.Merge(ev.evType); ev.evType != merged { - a.counts[ev.evType]-- + a.counts.add(ev.evType, -1) + a.counts.add(merged, 1) ev.evType = merged - a.counts[ev.evType]++ } l.Debugf("%v Parent %s (type %s) already tracked: %s", a, currPath, ev.evType, event.Name) return @@ -249,9 +263,9 @@ func (a *aggregator) aggregateEvent(event fs.Event, evTime time.Time) { if ev, ok := parentDir.events[name]; ok { ev.lastModTime = evTime if merged := event.Type.Merge(ev.evType); ev.evType != merged { - a.counts[ev.evType]-- + a.counts.add(ev.evType, -1) + a.counts.add(merged, 1) ev.evType = merged - a.counts[ev.evType]++ } l.Debugf("%v Already tracked (type %v): %s", a, ev.evType, event.Name) return @@ -272,7 +286,7 @@ func (a *aggregator) aggregateEvent(event fs.Event, evTime time.Time) { if ok { firstModTime = childDir.firstModTime() if merged := event.Type.Merge(childDir.eventType()); event.Type != merged { - a.counts[event.Type]-- + a.counts.add(event.Type, -1) event.Type = merged } delete(parentDir.dirs, name) @@ -283,7 +297,7 @@ func (a *aggregator) aggregateEvent(event fs.Event, evTime time.Time) { lastModTime: evTime, evType: event.Type, } - a.counts[event.Type]++ + a.counts.add(event.Type, 1) a.resetNotifyTimerIfNeeded() } @@ -302,7 +316,7 @@ func (a *aggregator) resetNotifyTimer(duration time.Duration) { } func (a *aggregator) actOnTimer(out chan<- []string) { - c := a.eventCount() + c := a.counts.total() if c == 0 { l.Debugln(a, "No tracked events, waiting for new event.") a.notifyTimerNeedsReset = true @@ -310,7 +324,7 @@ func (a *aggregator) actOnTimer(out chan<- []string) { } oldEvents := make(map[string]*aggregatedEvent, c) a.popOldEventsTo(oldEvents, a.root, ".", time.Now(), true) - if a.notifyDelay != a.notifyTimeout && a.counts[fs.NonRemove] == 0 && a.counts[fs.Remove]+a.counts[fs.Mixed] != 0 { + if a.notifyDelay != a.notifyTimeout && a.counts.nonRemoves == 0 && a.counts.removes != 0 { // Only delayed events remaining, no need to delay them additionally a.popOldEventsTo(oldEvents, a.root, ".", time.Now(), false) } @@ -376,7 +390,7 @@ func (a *aggregator) popOldEventsTo(to map[string]*aggregatedEvent, dir *eventDi if a.isOld(event, currTime, delayRem) { to[filepath.Join(dirPath, name)] = event delete(dir.events, name) - a.counts[event.evType]-- + a.counts.add(event.evType, -1) } } } @@ -401,14 +415,6 @@ func (a *aggregator) isOld(ev *aggregatedEvent, currTime time.Time, delayRem boo return currTime.Sub(ev.firstModTime) > a.notifyTimeout } -func (a *aggregator) eventCount() int { - c := 0 - for _, v := range a.counts { - c += v - } - return c -} - func (a *aggregator) String() string { return fmt.Sprintf("aggregator/%s:", a.folderCfg.Description()) }