github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/metrics/encoding/protobuf/unaggregated_iterator.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 protobuf
    22  
    23  import (
    24  	"encoding/binary"
    25  	"fmt"
    26  	"io"
    27  
    28  	"github.com/m3db/m3/src/metrics/encoding"
    29  	"github.com/m3db/m3/src/metrics/generated/proto/metricpb"
    30  	"github.com/m3db/m3/src/x/pool"
    31  )
    32  
    33  // UnaggregatedIterator decodes unaggregated metrics.
    34  type UnaggregatedIterator struct {
    35  	pb             metricpb.MetricWithMetadatas
    36  	reader         encoding.ByteReadScanner
    37  	bytesPool      pool.BytesPool
    38  	err            error
    39  	buf            []byte
    40  	msg            encoding.UnaggregatedMessageUnion
    41  	maxMessageSize int
    42  	closed         bool
    43  }
    44  
    45  // NewUnaggregatedIterator creates a new unaggregated iterator.
    46  func NewUnaggregatedIterator(
    47  	reader encoding.ByteReadScanner,
    48  	opts UnaggregatedOptions,
    49  ) *UnaggregatedIterator {
    50  	bytesPool := opts.BytesPool()
    51  	return &UnaggregatedIterator{
    52  		reader:         reader,
    53  		bytesPool:      bytesPool,
    54  		maxMessageSize: opts.MaxMessageSize(),
    55  		buf:            allocate(bytesPool, opts.InitBufferSize()),
    56  	}
    57  }
    58  
    59  // Close closes the iterator.
    60  func (it *UnaggregatedIterator) Close() {
    61  	if it.closed {
    62  		return
    63  	}
    64  	it.closed = true
    65  	it.reader = nil
    66  	it.pb.Reset()
    67  	it.msg = encoding.UnaggregatedMessageUnion{}
    68  	if it.bytesPool != nil && it.buf != nil {
    69  		it.bytesPool.Put(it.buf)
    70  	}
    71  	it.bytesPool = nil
    72  	it.buf = nil
    73  	it.err = nil
    74  }
    75  
    76  // Err returns the error encountered during decoding, if any
    77  func (it *UnaggregatedIterator) Err() error { return it.err }
    78  
    79  // Current returns the current decoded value
    80  func (it *UnaggregatedIterator) Current() *encoding.UnaggregatedMessageUnion { return &it.msg }
    81  
    82  // Next returns true if there are more items to decode.
    83  func (it *UnaggregatedIterator) Next() bool {
    84  	if it.err != nil || it.closed {
    85  		return false
    86  	}
    87  	size, err := it.decodeSize()
    88  	if err != nil {
    89  		return false
    90  	}
    91  	if size > it.maxMessageSize {
    92  		it.err = fmt.Errorf("decoded message size %d is larger than supported max message size %d", size, it.maxMessageSize)
    93  		return false
    94  	}
    95  	if size <= 0 {
    96  		it.err = fmt.Errorf("decoded message size %d is zero or negative", size)
    97  		return false
    98  	}
    99  	it.ensureBufferSize(size)
   100  	if err := it.decodeMessage(size); err != nil {
   101  		return false
   102  	}
   103  	return true
   104  }
   105  
   106  func (it *UnaggregatedIterator) decodeSize() (int, error) {
   107  	n, err := binary.ReadVarint(it.reader)
   108  	if err != nil {
   109  		it.err = err
   110  		return 0, err
   111  	}
   112  	return int(n), nil
   113  }
   114  
   115  func (it *UnaggregatedIterator) ensureBufferSize(targetSize int) {
   116  	it.buf = ensureBufferSize(it.buf, it.bytesPool, targetSize, dontCopyData)
   117  }
   118  
   119  //nolint:gocyclo
   120  func (it *UnaggregatedIterator) decodeMessage(size int) error {
   121  	_, err := io.ReadFull(it.reader, it.buf[:size])
   122  	if err != nil {
   123  		it.err = err
   124  		return err
   125  	}
   126  	ReuseMetricWithMetadatasProto(&it.pb)
   127  	if err := it.pb.Unmarshal(it.buf[:size]); err != nil {
   128  		it.err = err
   129  		return err
   130  	}
   131  	switch it.pb.Type {
   132  	case metricpb.MetricWithMetadatas_COUNTER_WITH_METADATAS:
   133  		it.msg.Type = encoding.CounterWithMetadatasType
   134  		it.err = it.msg.CounterWithMetadatas.FromProto(it.pb.CounterWithMetadatas)
   135  	case metricpb.MetricWithMetadatas_BATCH_TIMER_WITH_METADATAS:
   136  		it.msg.Type = encoding.BatchTimerWithMetadatasType
   137  		it.err = it.msg.BatchTimerWithMetadatas.FromProto(it.pb.BatchTimerWithMetadatas)
   138  	case metricpb.MetricWithMetadatas_GAUGE_WITH_METADATAS:
   139  		it.msg.Type = encoding.GaugeWithMetadatasType
   140  		it.err = it.msg.GaugeWithMetadatas.FromProto(it.pb.GaugeWithMetadatas)
   141  	case metricpb.MetricWithMetadatas_FORWARDED_METRIC_WITH_METADATA:
   142  		it.msg.Type = encoding.ForwardedMetricWithMetadataType
   143  		it.err = it.msg.ForwardedMetricWithMetadata.FromProto(it.pb.ForwardedMetricWithMetadata)
   144  	case metricpb.MetricWithMetadatas_TIMED_METRIC_WITH_METADATA:
   145  		it.msg.Type = encoding.TimedMetricWithMetadataType
   146  		it.err = it.msg.TimedMetricWithMetadata.FromProto(it.pb.TimedMetricWithMetadata)
   147  	case metricpb.MetricWithMetadatas_TIMED_METRIC_WITH_METADATAS:
   148  		it.msg.Type = encoding.TimedMetricWithMetadatasType
   149  		it.err = it.msg.TimedMetricWithMetadatas.FromProto(it.pb.TimedMetricWithMetadatas)
   150  	case metricpb.MetricWithMetadatas_TIMED_METRIC_WITH_STORAGE_POLICY:
   151  		it.msg.Type = encoding.PassthroughMetricWithMetadataType
   152  		it.err = it.msg.PassthroughMetricWithMetadata.FromProto(it.pb.TimedMetricWithStoragePolicy)
   153  	default:
   154  		it.err = fmt.Errorf("unrecognized message type: %v", it.pb.Type)
   155  	}
   156  	return it.err
   157  }