From c2ee61076d1a87c4322603f44dae275919171c47 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gustavo=20I=C3=B1iguez=20Goia?= Date: Wed, 21 Oct 2020 08:13:41 +0200 Subject: [PATCH] sort rules by name Sort rules by name, so they're checked in alphabetical order. This way, you can place deny rules at the top of the list to get better performance, since it won't check the rest of the rules. Discussion: #36 --- daemon/rule/loader.go | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/daemon/rule/loader.go b/daemon/rule/loader.go index e44ce29517..6c183630f4 100644 --- a/daemon/rule/loader.go +++ b/daemon/rule/loader.go @@ -7,6 +7,7 @@ import ( "os" "path" "path/filepath" + "sort" "strings" "sync" "time" @@ -24,6 +25,7 @@ type Loader struct { sync.RWMutex path string rules map[string]*Rule + rulesKeys []string watcher *fsnotify.Watcher liveReload bool liveReloadRunning bool @@ -103,6 +105,8 @@ func (l *Loader) Load(path string) error { } } + l.sortRules() + if l.liveReload && l.liveReloadRunning == false { go l.liveReloadWorker() } @@ -167,6 +171,14 @@ func (l *Loader) setUniqueName(rule *Rule) { } } +func (l *Loader) sortRules() { + l.rulesKeys = make([]string, 0, len(l.rules)) + for k := range l.rules { + l.rulesKeys = append(l.rulesKeys, k) + } + sort.Strings(l.rulesKeys) +} + func (l *Loader) addUserRule(rule *Rule) { if rule.Duration == Once { return @@ -184,6 +196,7 @@ func (l *Loader) replaceUserRule(rule *Rule) { } } l.rules[rule.Name] = rule + l.sortRules() l.Unlock() if rule.Duration == Restart || rule.Duration == Always { @@ -198,6 +211,7 @@ func (l *Loader) replaceUserRule(rule *Rule) { time.AfterFunc(tTime, func() { l.Lock() delete(l.rules, rule.Name) + l.sortRules() l.Unlock() }) } @@ -248,10 +262,17 @@ func (l *Loader) Delete(ruleName string) error { defer l.Unlock() rule := l.rules[ruleName] + if rule == nil { + return nil + } + delete(l.rules, ruleName) - if rule == nil || rule.Duration != Always { + l.sortRules() + + if rule.Duration != Always { return nil } + log.Info("Delete() rule: ", rule) path := fmt.Sprint(l.path, "/", ruleName, ".json") return os.Remove(path) @@ -262,7 +283,11 @@ func (l *Loader) FindFirstMatch(con *conman.Connection) (match *Rule) { l.RLock() defer l.RUnlock() - for _, rule := range l.rules { + for _, ruleIdx := range l.rulesKeys { + rule, valid := l.rules[ruleIdx] + if !valid { + continue + } // if we already have a match, we don't need // to evaluate 'allow' rules anymore, we only // need to make sure there's no 'deny' rule