github.com/m3db/m3@v1.5.0/src/cmd/services/m3coordinator/downsample/samples_appender.go (about)

     1  // Copyright (c) 2018 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 downsample
    22  
    23  import (
    24  	"github.com/uber-go/tally"
    25  
    26  	"github.com/m3db/m3/src/aggregator/aggregator"
    27  	"github.com/m3db/m3/src/aggregator/client"
    28  	"github.com/m3db/m3/src/metrics/metadata"
    29  	"github.com/m3db/m3/src/metrics/metric"
    30  	"github.com/m3db/m3/src/metrics/metric/aggregated"
    31  	"github.com/m3db/m3/src/metrics/metric/unaggregated"
    32  	xerrors "github.com/m3db/m3/src/x/errors"
    33  	xtime "github.com/m3db/m3/src/x/time"
    34  )
    35  
    36  // samplesAppender must have one of agg or client set
    37  type samplesAppender struct {
    38  	agg                     aggregator.Aggregator
    39  	clientRemote            client.Client
    40  	processedCountNonRollup tally.Counter
    41  	processedCountRollup    tally.Counter
    42  	operationsCount         tally.Counter
    43  
    44  	unownedID       []byte
    45  	stagedMetadatas metadata.StagedMetadatas
    46  }
    47  
    48  // Ensure samplesAppender implements SamplesAppender.
    49  var _ SamplesAppender = (*samplesAppender)(nil)
    50  
    51  // nolint:dupl
    52  func (a samplesAppender) AppendUntimedCounterSample(t xtime.UnixNano, value int64, annotation []byte) error {
    53  	a.emitMetrics()
    54  	if a.clientRemote != nil {
    55  		// Remote client write instead of local aggregation.
    56  		sample := unaggregated.Counter{
    57  			ID:              a.unownedID,
    58  			Value:           value,
    59  			Annotation:      annotation,
    60  			ClientTimeNanos: t,
    61  		}
    62  		return a.clientRemote.WriteUntimedCounter(sample, a.stagedMetadatas)
    63  	}
    64  
    65  	sample := unaggregated.MetricUnion{
    66  		Type:       metric.CounterType,
    67  		ID:         a.unownedID,
    68  		CounterVal: value,
    69  		Annotation: annotation,
    70  	}
    71  	return a.agg.AddUntimed(sample, a.stagedMetadatas)
    72  }
    73  
    74  // nolint:dupl
    75  func (a samplesAppender) AppendUntimedGaugeSample(t xtime.UnixNano, value float64, annotation []byte) error {
    76  	a.emitMetrics()
    77  	if a.clientRemote != nil {
    78  		// Remote client write instead of local aggregation.
    79  		sample := unaggregated.Gauge{
    80  			ID:              a.unownedID,
    81  			Value:           value,
    82  			Annotation:      annotation,
    83  			ClientTimeNanos: t,
    84  		}
    85  		return a.clientRemote.WriteUntimedGauge(sample, a.stagedMetadatas)
    86  	}
    87  
    88  	sample := unaggregated.MetricUnion{
    89  		Type:       metric.GaugeType,
    90  		ID:         a.unownedID,
    91  		GaugeVal:   value,
    92  		Annotation: annotation,
    93  	}
    94  	return a.agg.AddUntimed(sample, a.stagedMetadatas)
    95  }
    96  
    97  func (a samplesAppender) AppendUntimedTimerSample(t xtime.UnixNano, value float64, annotation []byte) error {
    98  	a.emitMetrics()
    99  	if a.clientRemote != nil {
   100  		// Remote client write instead of local aggregation.
   101  		sample := unaggregated.BatchTimer{
   102  			ID:              a.unownedID,
   103  			Values:          []float64{value},
   104  			Annotation:      annotation,
   105  			ClientTimeNanos: t,
   106  		}
   107  		return a.clientRemote.WriteUntimedBatchTimer(sample, a.stagedMetadatas)
   108  	}
   109  
   110  	sample := unaggregated.MetricUnion{
   111  		Type:          metric.TimerType,
   112  		ID:            a.unownedID,
   113  		BatchTimerVal: []float64{value},
   114  		Annotation:    annotation,
   115  	}
   116  	return a.agg.AddUntimed(sample, a.stagedMetadatas)
   117  }
   118  
   119  func (a *samplesAppender) AppendCounterSample(t xtime.UnixNano, value int64, annotation []byte) error {
   120  	return a.appendTimedSample(aggregated.Metric{
   121  		Type:       metric.CounterType,
   122  		ID:         a.unownedID,
   123  		TimeNanos:  int64(t),
   124  		Value:      float64(value),
   125  		Annotation: annotation,
   126  	})
   127  }
   128  
   129  func (a *samplesAppender) AppendGaugeSample(t xtime.UnixNano, value float64, annotation []byte) error {
   130  	return a.appendTimedSample(aggregated.Metric{
   131  		Type:       metric.GaugeType,
   132  		ID:         a.unownedID,
   133  		TimeNanos:  int64(t),
   134  		Value:      value,
   135  		Annotation: annotation,
   136  	})
   137  }
   138  
   139  func (a *samplesAppender) AppendTimerSample(
   140  	t xtime.UnixNano, value float64, annotation []byte,
   141  ) error {
   142  	return a.appendTimedSample(aggregated.Metric{
   143  		Type:       metric.TimerType,
   144  		ID:         a.unownedID,
   145  		TimeNanos:  int64(t),
   146  		Value:      value,
   147  		Annotation: annotation,
   148  	})
   149  }
   150  
   151  func (a *samplesAppender) appendTimedSample(sample aggregated.Metric) error {
   152  	a.emitMetrics()
   153  	if a.clientRemote != nil {
   154  		return a.clientRemote.WriteTimedWithStagedMetadatas(sample, a.stagedMetadatas)
   155  	}
   156  
   157  	return a.agg.AddTimedWithStagedMetadatas(sample, a.stagedMetadatas)
   158  }
   159  
   160  func (a *samplesAppender) emitMetrics() {
   161  	for _, metadata := range a.stagedMetadatas {
   162  		// Separate out the rollup and non-rollup processed counts. For rollups
   163  		// additionally emit a metric that indicates the number of non-rollup
   164  		// operations in the rules.
   165  		var (
   166  			numOperations = 0
   167  			isRollup      bool
   168  		)
   169  		for _, pipeline := range metadata.Pipelines {
   170  			if pipeline.IsAnyRollupRules() {
   171  				isRollup = true
   172  			}
   173  			numOperations += len(pipeline.Pipeline.Operations)
   174  		}
   175  		if isRollup {
   176  			a.processedCountRollup.Inc(1)
   177  		} else {
   178  			a.processedCountNonRollup.Inc(1)
   179  		}
   180  		// This includes operations other than the actual rollup.
   181  		if numOperations > 1 {
   182  			a.operationsCount.Inc(int64(numOperations - 1))
   183  		}
   184  	}
   185  }
   186  
   187  // Ensure multiSamplesAppender implements SamplesAppender.
   188  var _ SamplesAppender = (*multiSamplesAppender)(nil)
   189  
   190  type multiSamplesAppender struct {
   191  	appenders []samplesAppender
   192  }
   193  
   194  func newMultiSamplesAppender() *multiSamplesAppender {
   195  	return &multiSamplesAppender{}
   196  }
   197  
   198  func (a *multiSamplesAppender) reset() {
   199  	for i := range a.appenders {
   200  		a.appenders[i] = samplesAppender{}
   201  	}
   202  	a.appenders = a.appenders[:0]
   203  }
   204  
   205  func (a *multiSamplesAppender) addSamplesAppender(v samplesAppender) {
   206  	a.appenders = append(a.appenders, v)
   207  }
   208  
   209  func (a *multiSamplesAppender) AppendUntimedCounterSample(t xtime.UnixNano, value int64, annotation []byte) error {
   210  	var multiErr xerrors.MultiError
   211  	for _, appender := range a.appenders {
   212  		multiErr = multiErr.Add(appender.AppendUntimedCounterSample(t, value, annotation))
   213  	}
   214  	return multiErr.LastError()
   215  }
   216  
   217  func (a *multiSamplesAppender) AppendUntimedGaugeSample(t xtime.UnixNano, value float64, annotation []byte) error {
   218  	var multiErr xerrors.MultiError
   219  	for _, appender := range a.appenders {
   220  		multiErr = multiErr.Add(appender.AppendUntimedGaugeSample(t, value, annotation))
   221  	}
   222  	return multiErr.LastError()
   223  }
   224  
   225  func (a *multiSamplesAppender) AppendUntimedTimerSample(t xtime.UnixNano, value float64, annotation []byte) error {
   226  	var multiErr xerrors.MultiError
   227  	for _, appender := range a.appenders {
   228  		multiErr = multiErr.Add(appender.AppendUntimedTimerSample(t, value, annotation))
   229  	}
   230  	return multiErr.LastError()
   231  }
   232  
   233  func (a *multiSamplesAppender) AppendCounterSample(
   234  	t xtime.UnixNano, value int64, annotation []byte,
   235  ) error {
   236  	var multiErr xerrors.MultiError
   237  	for _, appender := range a.appenders {
   238  		multiErr = multiErr.Add(appender.AppendCounterSample(t, value, annotation))
   239  	}
   240  	return multiErr.LastError()
   241  }
   242  
   243  func (a *multiSamplesAppender) AppendGaugeSample(
   244  	t xtime.UnixNano, value float64, annotation []byte,
   245  ) error {
   246  	var multiErr xerrors.MultiError
   247  	for _, appender := range a.appenders {
   248  		multiErr = multiErr.Add(appender.AppendGaugeSample(t, value, annotation))
   249  	}
   250  	return multiErr.LastError()
   251  }
   252  
   253  func (a *multiSamplesAppender) AppendTimerSample(
   254  	t xtime.UnixNano, value float64, annotation []byte,
   255  ) error {
   256  	var multiErr xerrors.MultiError
   257  	for _, appender := range a.appenders {
   258  		multiErr = multiErr.Add(appender.AppendTimerSample(t, value, annotation))
   259  	}
   260  	return multiErr.LastError()
   261  }