Skip to content

Commit 4d97c9a

Browse files
committed
refactor and update cache
Signed-off-by: Coleen Iona Quadros <[email protected]>
1 parent 35be6d7 commit 4d97c9a

File tree

3 files changed

+333
-63
lines changed

3 files changed

+333
-63
lines changed

inhibit/inhibit.go

Lines changed: 141 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -87,22 +87,25 @@ func (ih *Inhibitor) run(ctx context.Context) {
8787
// Update the inhibition rules' cache.
8888
cachedSum := 0
8989
indexedSum := 0
90+
cached := 0
91+
indexed := 0
9092
for _, r := range ih.rules {
9193
if len(r.Sources) > 0 {
92-
allSrcMatched := true
94+
cached = 0
95+
indexed = 0
9396
for _, src := range r.Sources {
94-
if !src.SrcMatchers.Matches(a.Labels) {
95-
allSrcMatched = false
97+
if src.SrcMatchers.Matches(a.Labels) {
98+
if err := src.scache.Set(a); err != nil {
99+
ih.logger.Error("error on set alert", "err", err)
100+
continue
101+
}
102+
src.updateIndex(a)
103+
cached += src.scache.Len()
104+
indexed += src.sindex.Len()
96105
break
97106
}
98107
}
99-
if allSrcMatched {
100-
if err := r.scache.Set(a); err != nil {
101-
ih.logger.Error("error on set alert", "err", err)
102-
continue
103-
}
104-
r.updateIndex(a)
105-
}
108+
106109
} else {
107110
if r.SourceMatchers.Matches(a.Labels) {
108111
if err := r.scache.Set(a); err != nil {
@@ -111,16 +114,14 @@ func (ih *Inhibitor) run(ctx context.Context) {
111114
}
112115
r.updateIndex(a)
113116
}
114-
}
115-
116-
cached := r.scache.Len()
117-
indexed := r.sindex.Len()
117+
cached = r.scache.Len()
118+
indexed = r.sindex.Len()
118119

120+
}
119121
if r.Name != "" {
120122
r.metrics.sourceAlertsCacheItems.With(prometheus.Labels{"rule": r.Name}).Set(float64(cached))
121123
r.metrics.sourceAlertsIndexItems.With(prometheus.Labels{"rule": r.Name}).Set(float64(indexed))
122124
}
123-
124125
cachedSum += cached
125126
indexedSum += indexed
126127
}
@@ -189,17 +190,14 @@ func (ih *Inhibitor) Mutes(lset model.LabelSet) bool {
189190
// need to exclude inhibiting alerts for which the same is true.
190191

191192
if len(r.Sources) > 0 {
192-
allSourcesMatched := true
193193
var inhibitorIDs []string
194194
for _, source := range r.Sources {
195-
if inhibitedByFP, eq := r.hasEqual(lset, source.SrcMatchers.Matches(lset), ruleStart); eq {
195+
if inhibitedByFP, eq := source.hasEqual(lset, source.SrcMatchers.Matches(lset), ruleStart, r.TargetMatchers); eq && !source.foundMatch {
196196
inhibitorIDs = append(inhibitorIDs, inhibitedByFP.String())
197-
} else {
198-
allSourcesMatched = false
199-
break
197+
source.foundMatch = true
200198
}
201199
}
202-
if allSourcesMatched {
200+
if allSourcesMatched := r.allSourcesSatisfied(); allSourcesMatched {
203201
compositeInhibitorID := strings.Join(inhibitorIDs, ",")
204202
ih.marker.SetInhibited(fp, compositeInhibitorID)
205203
now := time.Now()
@@ -209,6 +207,11 @@ func (ih *Inhibitor) Mutes(lset model.LabelSet) bool {
209207
r.metrics.mutesDurationMuted.Observe(sinceRuleStart.Seconds())
210208
return true
211209
}
210+
// Reset for next use.
211+
for _, source := range r.Sources {
212+
source.foundMatch = false
213+
}
214+
212215
} else {
213216
if inhibitedByFP, eq := r.hasEqual(lset, r.SourceMatchers.Matches(lset), ruleStart); eq {
214217
ih.marker.SetInhibited(fp, inhibitedByFP.String())
@@ -237,6 +240,16 @@ type Source struct {
237240
// A set of label names whose label values need to be identical in source and
238241
// target alerts in order for the inhibition to take effect.
239242
Equal map[model.LabelName]struct{}
243+
// Cache of alerts matching source labels.
244+
scache *store.Alerts
245+
246+
// Index of fingerprints of source alert equal labels to fingerprint of source alert.
247+
// The index helps speed up source alert lookups from scache significantely in scenarios with 100s of source alerts cached.
248+
// The index items might overwrite eachother if multiple source alerts have exact equal labels.
249+
// Overwrites only happen if the new source alert has bigger EndsAt value.
250+
sindex *index
251+
252+
foundMatch bool
240253
}
241254

242255
// An InhibitRule specifies that a class of (source) alerts should inhibit
@@ -250,7 +263,7 @@ type InhibitRule struct {
250263
// The set of Filters which define the group of source alerts (which inhibit
251264
// the target alerts).
252265
SourceMatchers labels.Matchers
253-
Sources []Source
266+
Sources []*Source
254267
// The set of Filters which define the group of target alerts (which are
255268
// inhibited by the source alerts).
256269
TargetMatchers labels.Matchers
@@ -273,21 +286,24 @@ type InhibitRule struct {
273286
// NewInhibitRule returns a new InhibitRule based on a configuration definition.
274287
func NewInhibitRule(cr config.InhibitRule, metrics *RuleMetrics) *InhibitRule {
275288
var (
276-
sources []Source
289+
sources []*Source
277290
sourcem labels.Matchers
278291
targetm labels.Matchers
279292
)
280293

281294
if len(cr.Sources) > 0 {
282295
for _, sm := range cr.Sources {
283-
sourcem = append(sourcem, sm.SrcMatchers...)
296+
var sourcesm labels.Matchers
297+
sourcesm = append(sourcesm, sm.SrcMatchers...)
284298
equal := map[model.LabelName]struct{}{}
285299
for _, ln := range sm.Equal {
286300
equal[model.LabelName(ln)] = struct{}{}
287301
}
288-
sources = append(sources, Source{
289-
SrcMatchers: sourcem,
302+
sources = append(sources, &Source{
303+
SrcMatchers: sourcesm,
290304
Equal: equal,
305+
scache: store.NewAlerts(),
306+
sindex: newIndex(),
291307
})
292308
}
293309
} else {
@@ -359,10 +375,18 @@ func NewInhibitRule(cr config.InhibitRule, metrics *RuleMetrics) *InhibitRule {
359375
// fingerprintEquals returns the fingerprint of the equal labels of the given label set.
360376
func (r *InhibitRule) fingerprintEquals(lset model.LabelSet) model.Fingerprint {
361377
equalSet := model.LabelSet{}
362-
363378
for n := range r.Equal {
364379
equalSet[n] = lset[n]
365380
}
381+
382+
return equalSet.Fingerprint()
383+
}
384+
385+
func (s *Source) fingerprintEquals(lset model.LabelSet) model.Fingerprint {
386+
equalSet := model.LabelSet{}
387+
for n := range s.Equal {
388+
equalSet[n] = lset[n]
389+
}
366390
return equalSet.Fingerprint()
367391
}
368392

@@ -400,6 +424,39 @@ func (r *InhibitRule) updateIndex(alert *types.Alert) {
400424
// If the existing alert resolves after the new alert, do nothing.
401425
}
402426

427+
func (src *Source) updateIndex(alert *types.Alert) {
428+
fp := alert.Fingerprint()
429+
// Calculate source labelset subset which is in equals.
430+
eq := src.fingerprintEquals(alert.Labels)
431+
432+
// Check if the equal labelset is already in the index.
433+
indexed, ok := src.sindex.Get(eq)
434+
if !ok {
435+
// If not, add it.
436+
src.sindex.Set(eq, fp)
437+
return
438+
}
439+
// If the indexed fingerprint is the same as the new fingerprint, do nothing.
440+
if indexed == fp {
441+
return
442+
}
443+
444+
// New alert and existing index are not the same, compare them.
445+
existing, err := src.scache.Get(indexed)
446+
if err != nil {
447+
// failed to get the existing alert, overwrite the index.
448+
src.sindex.Set(eq, fp)
449+
return
450+
}
451+
452+
// If the new alert resolves after the existing alert, replace the index.
453+
if existing.ResolvedAt(alert.EndsAt) {
454+
src.sindex.Set(eq, fp)
455+
return
456+
}
457+
// If the existing alert resolves after the new alert, do nothing.
458+
}
459+
403460
// findEqualSourceAlert returns the source alert that matches the equal labels of the given label set.
404461
func (r *InhibitRule) findEqualSourceAlert(lset model.LabelSet, now time.Time) (*types.Alert, bool) {
405462
equalsFP := r.fingerprintEquals(lset)
@@ -420,10 +477,40 @@ func (r *InhibitRule) findEqualSourceAlert(lset model.LabelSet, now time.Time) (
420477
return nil, false
421478
}
422479

480+
func (s *Source) findEqualSourceAlert(lset model.LabelSet, now time.Time) (*types.Alert, bool) {
481+
equalsFP := s.fingerprintEquals(lset)
482+
sourceFP, ok := s.sindex.Get(equalsFP)
483+
if ok {
484+
alert, err := s.scache.Get(sourceFP)
485+
if err != nil {
486+
return nil, false
487+
}
488+
489+
if alert.ResolvedAt(now) {
490+
return nil, false
491+
}
492+
493+
return alert, true
494+
}
495+
496+
return nil, false
497+
}
498+
423499
func (r *InhibitRule) gcCallback(alerts []types.Alert) {
424500
for _, a := range alerts {
425-
fp := r.fingerprintEquals(a.Labels)
426-
r.sindex.Delete(fp)
501+
if len(r.Sources) > 0 {
502+
for _, src := range r.Sources {
503+
if src.SrcMatchers.Matches(a.Labels) {
504+
fp := src.fingerprintEquals(a.Labels)
505+
src.sindex.Delete(fp)
506+
507+
break
508+
}
509+
}
510+
} else {
511+
fp := r.fingerprintEquals(a.Labels)
512+
r.sindex.Delete(fp)
513+
}
427514
}
428515
if r.Name != "" {
429516
r.metrics.sourceAlertsCacheItems.With(prometheus.Labels{"rule": r.Name}).Set(float64(r.scache.Len()))
@@ -446,3 +533,28 @@ func (r *InhibitRule) hasEqual(lset model.LabelSet, excludeTwoSidedMatch bool, n
446533

447534
return model.Fingerprint(0), false
448535
}
536+
537+
func (s *Source) hasEqual(lset model.LabelSet, excludeTwoSidedMatch bool, now time.Time, targetMatchers labels.Matchers) (model.Fingerprint, bool) {
538+
equal, found := s.findEqualSourceAlert(lset, now)
539+
if found {
540+
if excludeTwoSidedMatch && targetMatchers.Matches(equal.Labels) {
541+
return model.Fingerprint(0), false
542+
}
543+
return equal.Fingerprint(), found
544+
}
545+
546+
return model.Fingerprint(0), false
547+
}
548+
549+
func (r *InhibitRule) allSourcesSatisfied() bool {
550+
for _, source := range r.Sources {
551+
if !source.foundMatch {
552+
return false
553+
}
554+
}
555+
// Reset for next use.
556+
for _, source := range r.Sources {
557+
source.foundMatch = false
558+
}
559+
return true
560+
}

0 commit comments

Comments
 (0)