better data structures for matches & actions maps

This commit is contained in:
ppom 2023-09-24 16:44:16 +02:00
parent b6d7e5a946
commit d26c7f24f2
3 changed files with 33 additions and 53 deletions

View File

@ -111,12 +111,7 @@ func ActionsManager() {
go action.exec(match) go action.exec(match)
} else { } else {
actionsLock.Lock() actionsLock.Lock()
// make sure map exists actions[PAT{match, action, then}] = struct{}{}
if actions[action] == nil {
actions[action] = make(PatternTimes)
}
// append() to nil is valid go
actions[action][match] = append(actions[action][match], then)
actionsLock.Unlock() actionsLock.Unlock()
go func(pat PAT, now time.Time) { go func(pat PAT, now time.Time) {
time.Sleep(pat.t.Sub(now)) time.Sleep(pat.t.Sub(now))
@ -124,23 +119,20 @@ func ActionsManager() {
}(pat, now) }(pat, now)
} }
case pat = <-pendingActionsC: case pat = <-pendingActionsC:
match = pat.p match, action, then = pat.p, pat.a, pat.t
action = pat.a
actionsLock.Lock() actionsLock.Lock()
actions[action][match] = actions[action][match][1:] delete(actions, PAT{match, action, then})
actionsLock.Unlock() actionsLock.Unlock()
wgActions.Add(1) wgActions.Add(1)
go action.exec(match) go action.exec(match)
case _, _ = <-stopActions: case _, _ = <-stopActions:
actionsLock.Lock() actionsLock.Lock()
for action := range actions { for pat := range actions {
if action.OnExit { if pat.a.OnExit {
for match := range actions[action] {
wgActions.Add(1) wgActions.Add(1)
go action.exec(match) go action.exec(match)
} }
} }
}
actionsLock.Unlock() actionsLock.Unlock()
wgActions.Done() wgActions.Done()
return return
@ -156,7 +148,7 @@ func MatchesManager() {
for !end { for !end {
select { select {
case pf = <-cleanMatchesC: case pf = <-cleanMatchesC:
delete(matches[pf.f], pf.p) delete(matches, pf)
case pft, ok := <-startupMatchesC: case pft, ok := <-startupMatchesC:
if !ok { if !ok {
end = true end = true
@ -170,7 +162,7 @@ func MatchesManager() {
select { select {
case pf = <-cleanMatchesC: case pf = <-cleanMatchesC:
matchesLock.Lock() matchesLock.Lock()
delete(matches[pf.f], pf.p) delete(matches, pf)
matchesLock.Unlock() matchesLock.Unlock()
case pft = <-matchesC: case pft = <-matchesC:
@ -187,26 +179,25 @@ func MatchesManager() {
func matchesManagerHandleMatch(pft PFT) bool { func matchesManagerHandleMatch(pft PFT) bool {
filter, match, then := pft.f, pft.p, pft.t filter, match, then := pft.f, pft.p, pft.t
pf := PF{pft.p, pft.f}
if filter.Retry > 1 { if filter.Retry > 1 {
// make sure map exists // make sure map exists
if matches[filter] == nil { if matches[pf] == nil {
matches[filter] = make(PatternTimes) matches[pf] = make(map[time.Time]struct{})
} }
// clean old matches // clean old matches
newMatches := make([]time.Time, 0, len(matches[filter][match])) for old := range matches[pf] {
for _, old := range matches[filter][match] { if !old.Add(filter.retryDuration).After(then) {
if old.Add(filter.retryDuration).After(then) { delete(matches[pf], old)
newMatches = append(newMatches, old)
} }
} }
// add new match // add new match
newMatches = append(newMatches, then) matches[pf][then] = struct{}{}
matches[filter][match] = newMatches
} }
if filter.Retry <= 1 || len(matches[filter][match]) >= filter.Retry { if filter.Retry <= 1 || len(matches[pf]) >= filter.Retry {
delete(matches[filter], match) delete(matches, pf)
filter.sendActions(match, then) filter.sendActions(match, then)
return true return true
} }

View File

@ -14,45 +14,37 @@ func genClientStatus() ClientStatus {
matchesLock.Lock() matchesLock.Lock()
// Painful data manipulation // Painful data manipulation
for filter, filterMatches := range matches { for pf, times := range matches {
pattern, filter := pf.p, pf.f
if cs[filter.stream.name] == nil { if cs[filter.stream.name] == nil {
cs[filter.stream.name] = make(map[string]MapPatternStatus) cs[filter.stream.name] = make(map[string]MapPatternStatus)
} }
if cs[filter.stream.name][filter.name] == nil { if cs[filter.stream.name][filter.name] == nil {
cs[filter.stream.name][filter.name] = make(MapPatternStatus) cs[filter.stream.name][filter.name] = make(MapPatternStatus)
} }
for pattern, patternMatches := range filterMatches { cs[filter.stream.name][filter.name][pattern] = &PatternStatus{len(times), nil}
var ps PatternStatus
cs[filter.stream.name][filter.name][pattern] = &ps
ps.Matches = len(patternMatches)
}
} }
matchesLock.Unlock() matchesLock.Unlock()
actionsLock.Lock() actionsLock.Lock()
// Painful data manipulation // Painful data manipulation
for action, pendingActions := range actions { for pat := range actions {
pattern, action, then := pat.p, pat.a, pat.t
if cs[action.filter.stream.name] == nil { if cs[action.filter.stream.name] == nil {
cs[action.filter.stream.name] = make(map[string]MapPatternStatus) cs[action.filter.stream.name] = make(map[string]MapPatternStatus)
} }
if cs[action.filter.stream.name][action.filter.name] == nil { if cs[action.filter.stream.name][action.filter.name] == nil {
cs[action.filter.stream.name][action.filter.name] = make(MapPatternStatus) cs[action.filter.stream.name][action.filter.name] = make(MapPatternStatus)
} }
for pattern, patternPendingActions := range pendingActions {
if cs[action.filter.stream.name][action.filter.name][pattern] == nil { if cs[action.filter.stream.name][action.filter.name][pattern] == nil {
var ps PatternStatus cs[action.filter.stream.name][action.filter.name][pattern] = new(PatternStatus)
cs[action.filter.stream.name][action.filter.name][pattern] = &ps
} }
var ps *PatternStatus ps := cs[action.filter.stream.name][action.filter.name][pattern]
ps = cs[action.filter.stream.name][action.filter.name][pattern] if ps.Actions == nil {
ps.Actions = make(map[string][]string) ps.Actions = make(map[string][]string)
for _, t := range patternPendingActions {
ps.Actions[action.name] = append(ps.Actions[action.name], t.Format(time.DateTime))
}
} }
ps.Actions[action.name] = append(ps.Actions[action.name], then.Format(time.DateTime))
} }
actionsLock.Unlock() actionsLock.Unlock()
return cs return cs

View File

@ -75,13 +75,10 @@ type WriteDB struct {
enc *gob.Encoder enc *gob.Encoder
} }
type PatternTimes map[string][]time.Time type MatchesMap map[PF]map[time.Time]struct{}
type ActionsMap map[PAT]struct{}
type MatchesMap map[*Filter]PatternTimes // Helper structs made to carry information
type ActionsMap map[*Action]PatternTimes
// Helper structs made to carry information across channels
type SF struct{ s, f string } type SF struct{ s, f string }
type PSF struct{ p, s, f string } type PSF struct{ p, s, f string }
type PF struct { type PF struct {