github.com/m3db/m3@v1.5.0/src/metrics/matcher/match.go (about) 1 // Copyright (c) 2017 Uber Technologies, Inc. 2 // 3 // Permission is hereby granted, free of charge, to any person obtaining a copy 4 // of this software and associated documentation files (the "Software"), to deal 5 // in the Software without restriction, including without limitation the rights 6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 // copies of the Software, and to permit persons to whom the Software is 8 // furnished to do so, subject to the following conditions: 9 // 10 // The above copyright notice and this permission notice shall be included in 11 // all copies or substantial portions of the Software. 12 // 13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 // THE SOFTWARE. 20 21 package matcher 22 23 import ( 24 "time" 25 26 "github.com/uber-go/tally" 27 28 "github.com/m3db/m3/src/metrics/aggregation" 29 "github.com/m3db/m3/src/metrics/matcher/cache" 30 "github.com/m3db/m3/src/metrics/metric" 31 "github.com/m3db/m3/src/metrics/metric/id" 32 "github.com/m3db/m3/src/metrics/rules" 33 "github.com/m3db/m3/src/metrics/rules/view" 34 ) 35 36 // Matcher matches rules against metric IDs. 37 type Matcher interface { 38 rules.ActiveSet 39 40 // Close closes the matcher. 41 Close() error 42 } 43 44 type matcher struct { 45 namespaces Namespaces 46 cache cache.Cache 47 metrics matcherMetrics 48 } 49 50 // NewMatcher creates a new rule matcher, optionally with a cache. 51 func NewMatcher(cache cache.Cache, opts Options) (Matcher, error) { 52 instrumentOpts := opts.InstrumentOptions() 53 scope := instrumentOpts.MetricsScope() 54 iOpts := instrumentOpts.SetMetricsScope(scope.SubScope("namespaces")) 55 namespacesOpts := opts.SetInstrumentOptions(iOpts) 56 57 if cache != nil { 58 namespacesOpts = namespacesOpts. 59 SetOnNamespaceAddedFn(func(namespace []byte, ruleSet RuleSet) { 60 cache.Register(namespace, ruleSet) 61 }). 62 SetOnNamespaceRemovedFn(func(namespace []byte) { 63 cache.Unregister(namespace) 64 }). 65 SetOnRuleSetUpdatedFn(func(namespace []byte, ruleSet RuleSet) { 66 cache.Refresh(namespace, ruleSet) 67 }) 68 } 69 70 namespaces := NewNamespaces(opts.NamespacesKey(), namespacesOpts) 71 if err := namespaces.Open(); err != nil { 72 return nil, err 73 } 74 75 if cache == nil { 76 return &noCacheMatcher{ 77 namespaces: namespaces, 78 metrics: newMatcherMetrics(scope.SubScope("matcher")), 79 }, nil 80 } 81 82 return &matcher{ 83 namespaces: namespaces, 84 cache: cache, 85 metrics: newMatcherMetrics(scope.SubScope("cached-matcher")), 86 }, nil 87 } 88 89 func (m *matcher) LatestRollupRules(namespace []byte, timeNanos int64) ([]view.RollupRule, error) { 90 return m.namespaces.LatestRollupRules(namespace, timeNanos) 91 } 92 93 func (m *matcher) ForwardMatch( 94 id id.ID, 95 fromNanos, toNanos int64, 96 opts rules.MatchOptions, 97 ) (rules.MatchResult, error) { 98 sw := m.metrics.matchLatency.Start() 99 defer sw.Stop() 100 return m.cache.ForwardMatch(id, fromNanos, toNanos, opts) 101 } 102 103 func (m *matcher) ReverseMatch( 104 id id.ID, 105 fromNanos, toNanos int64, 106 mt metric.Type, 107 at aggregation.Type, 108 isMultiAggregationTypesAllowed bool, 109 aggTypesOpts aggregation.TypesOptions, 110 ) (rules.MatchResult, error) { 111 sw := m.metrics.matchLatency.Start() 112 defer sw.Stop() 113 // Cache does not support reverse matching. 114 return m.namespaces.ReverseMatch(id, fromNanos, toNanos, mt, at, isMultiAggregationTypesAllowed, aggTypesOpts) 115 } 116 117 func (m *matcher) Close() error { 118 m.namespaces.Close() 119 return m.cache.Close() 120 } 121 122 type noCacheMatcher struct { 123 namespaces Namespaces 124 metrics matcherMetrics 125 } 126 127 type matcherMetrics struct { 128 matchLatency tally.Histogram 129 } 130 131 func newMatcherMetrics(scope tally.Scope) matcherMetrics { 132 return matcherMetrics{ 133 matchLatency: scope.Histogram( 134 "match-latency", 135 append( 136 tally.DurationBuckets{0}, 137 tally.MustMakeExponentialDurationBuckets(time.Millisecond, 1.5, 15)..., 138 ), 139 ), 140 } 141 } 142 143 func (m *noCacheMatcher) LatestRollupRules(namespace []byte, timeNanos int64) ([]view.RollupRule, error) { 144 return m.namespaces.LatestRollupRules(namespace, timeNanos) 145 } 146 147 func (m *noCacheMatcher) ForwardMatch( 148 id id.ID, 149 fromNanos, toNanos int64, 150 opts rules.MatchOptions, 151 ) (rules.MatchResult, error) { 152 sw := m.metrics.matchLatency.Start() 153 defer sw.Stop() 154 return m.namespaces.ForwardMatch(id, fromNanos, toNanos, opts) 155 } 156 157 func (m *noCacheMatcher) ReverseMatch( 158 id id.ID, 159 fromNanos, toNanos int64, 160 mt metric.Type, 161 at aggregation.Type, 162 isMultiAggregationTypesAllowed bool, 163 aggTypesOpts aggregation.TypesOptions, 164 ) (rules.MatchResult, error) { 165 sw := m.metrics.matchLatency.Start() 166 defer sw.Stop() 167 return m.namespaces.ReverseMatch(id, fromNanos, toNanos, mt, at, isMultiAggregationTypesAllowed, aggTypesOpts) 168 } 169 170 func (m *noCacheMatcher) Close() error { 171 m.namespaces.Close() 172 return nil 173 }