github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/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  }