github.com/m3db/m3@v1.5.0/src/metrics/encoding/protobuf/unaggregated_encoder.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 "math" 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/metrics/metric/aggregated" 31 "github.com/m3db/m3/src/metrics/metric/unaggregated" 32 "github.com/m3db/m3/src/x/pool" 33 ) 34 35 const ( 36 // maximum number of bytes to encode message size. 37 maxMessageSizeInBytes = binary.MaxVarintLen32 38 ) 39 40 // UnaggregatedEncoder encodes unaggregated metrics. 41 type UnaggregatedEncoder interface { 42 // Len returns the number of bytes accumulated in the encoder so far. 43 Len() int 44 45 // Reset resets the encoder buffer with optional initial data. 46 Reset(initData []byte) 47 48 // Truncate discards all but the first n encoded bytes but continues to use 49 // the same allocated storage. If n is negative or greater than the length of 50 // encoded buffer, an error is returned. 51 Truncate(n int) error 52 53 // EncodeMessage encodes an unaggregated message. 54 EncodeMessage(msg encoding.UnaggregatedMessageUnion) error 55 56 // Relinquish relinquishes ownership of the encoded byte stream to the caller, 57 // and resets the internal encoding buffer. 58 Relinquish() Buffer 59 } 60 61 type unaggregatedEncoder struct { 62 pool pool.BytesPool 63 encodeMessageSizeFn func(int) 64 encodeMessageFn func(metricpb.MetricWithMetadatas) error 65 bm metricpb.BatchTimerWithMetadatas 66 tms metricpb.TimedMetricWithMetadatas 67 cm metricpb.CounterWithMetadatas 68 gm metricpb.GaugeWithMetadatas 69 buf []byte 70 fm metricpb.ForwardedMetricWithMetadata 71 pm metricpb.TimedMetricWithStoragePolicy 72 tm metricpb.TimedMetricWithMetadata 73 used int 74 initBufSize int 75 maxMessageSize int 76 } 77 78 // NewUnaggregatedEncoder creates a new unaggregated encoder. 79 func NewUnaggregatedEncoder(opts UnaggregatedOptions) UnaggregatedEncoder { 80 e := &unaggregatedEncoder{ 81 pool: opts.BytesPool(), 82 initBufSize: opts.InitBufferSize(), 83 maxMessageSize: opts.MaxMessageSize(), 84 } 85 e.encodeMessageSizeFn = e.encodeMessageSize 86 e.encodeMessageFn = e.encodeMessage 87 e.Reset(nil) 88 return e 89 } 90 91 func (enc *unaggregatedEncoder) Len() int { return enc.used } 92 93 func (enc *unaggregatedEncoder) Reset(initData []byte) { 94 if enc.buf != nil && enc.pool != nil { 95 enc.pool.Put(enc.buf) 96 } 97 bufSize := int(math.Max(float64(enc.initBufSize), float64(len(initData)))) 98 enc.buf = allocate(enc.pool, bufSize) 99 copy(enc.buf, initData) 100 enc.used = len(initData) 101 } 102 103 func (enc *unaggregatedEncoder) Truncate(n int) error { 104 if n < 0 || n > enc.used { 105 return fmt.Errorf("truncation out of range: used=%d, target=%d", enc.used, n) 106 } 107 enc.used = n 108 return nil 109 } 110 111 func (enc *unaggregatedEncoder) Relinquish() Buffer { 112 res := NewBuffer(enc.buf[:enc.used], enc.pool.Put) 113 enc.buf = nil 114 enc.used = 0 115 return res 116 } 117 118 func (enc *unaggregatedEncoder) EncodeMessage(msg encoding.UnaggregatedMessageUnion) error { 119 switch msg.Type { 120 case encoding.CounterWithMetadatasType: 121 return enc.encodeCounterWithMetadatas(msg.CounterWithMetadatas) 122 case encoding.BatchTimerWithMetadatasType: 123 return enc.encodeBatchTimerWithMetadatas(msg.BatchTimerWithMetadatas) 124 case encoding.GaugeWithMetadatasType: 125 return enc.encodeGaugeWithMetadatas(msg.GaugeWithMetadatas) 126 case encoding.ForwardedMetricWithMetadataType: 127 return enc.encodeForwardedMetricWithMetadata(msg.ForwardedMetricWithMetadata) 128 case encoding.TimedMetricWithMetadataType: 129 return enc.encodeTimedMetricWithMetadata(msg.TimedMetricWithMetadata) 130 case encoding.TimedMetricWithMetadatasType: 131 return enc.encodeTimedMetricWithMetadatas(msg.TimedMetricWithMetadatas) 132 case encoding.PassthroughMetricWithMetadataType: 133 return enc.encodePassthroughMetricWithMetadata(msg.PassthroughMetricWithMetadata) 134 default: 135 return fmt.Errorf("unknown message type: %v", msg.Type) 136 } 137 } 138 139 func (enc *unaggregatedEncoder) encodeCounterWithMetadatas(cm unaggregated.CounterWithMetadatas) error { 140 if err := cm.ToProto(&enc.cm); err != nil { 141 return fmt.Errorf("counter with metadatas proto conversion failed: %v", err) 142 } 143 mm := metricpb.MetricWithMetadatas{ 144 Type: metricpb.MetricWithMetadatas_COUNTER_WITH_METADATAS, 145 CounterWithMetadatas: &enc.cm, 146 } 147 return enc.encodeMetricWithMetadatas(mm) 148 } 149 150 func (enc *unaggregatedEncoder) encodeBatchTimerWithMetadatas(bm unaggregated.BatchTimerWithMetadatas) error { 151 if err := bm.ToProto(&enc.bm); err != nil { 152 return fmt.Errorf("batch timer with metadatas proto conversion failed: %v", err) 153 } 154 mm := metricpb.MetricWithMetadatas{ 155 Type: metricpb.MetricWithMetadatas_BATCH_TIMER_WITH_METADATAS, 156 BatchTimerWithMetadatas: &enc.bm, 157 } 158 return enc.encodeMetricWithMetadatas(mm) 159 } 160 161 func (enc *unaggregatedEncoder) encodeGaugeWithMetadatas(gm unaggregated.GaugeWithMetadatas) error { 162 if err := gm.ToProto(&enc.gm); err != nil { 163 return fmt.Errorf("gauge with metadatas proto conversion failed: %v", err) 164 } 165 mm := metricpb.MetricWithMetadatas{ 166 Type: metricpb.MetricWithMetadatas_GAUGE_WITH_METADATAS, 167 GaugeWithMetadatas: &enc.gm, 168 } 169 return enc.encodeMetricWithMetadatas(mm) 170 } 171 172 func (enc *unaggregatedEncoder) encodeForwardedMetricWithMetadata(fm aggregated.ForwardedMetricWithMetadata) error { 173 if err := fm.ToProto(&enc.fm); err != nil { 174 return fmt.Errorf("forwarded metric with metadata proto conversion failed: %v", err) 175 } 176 mm := metricpb.MetricWithMetadatas{ 177 Type: metricpb.MetricWithMetadatas_FORWARDED_METRIC_WITH_METADATA, 178 ForwardedMetricWithMetadata: &enc.fm, 179 } 180 return enc.encodeMetricWithMetadatas(mm) 181 } 182 183 func (enc *unaggregatedEncoder) encodeTimedMetricWithMetadata(tm aggregated.TimedMetricWithMetadata) error { 184 if err := tm.ToProto(&enc.tm); err != nil { 185 return fmt.Errorf("timed metric with metadata proto conversion failed: %v", err) 186 } 187 mm := metricpb.MetricWithMetadatas{ 188 Type: metricpb.MetricWithMetadatas_TIMED_METRIC_WITH_METADATA, 189 TimedMetricWithMetadata: &enc.tm, 190 } 191 return enc.encodeMetricWithMetadatas(mm) 192 } 193 194 func (enc *unaggregatedEncoder) encodeTimedMetricWithMetadatas(tms aggregated.TimedMetricWithMetadatas) error { 195 if err := tms.ToProto(&enc.tms); err != nil { 196 return fmt.Errorf("timed metric with metadatas proto conversion failed: %v", err) 197 } 198 mm := metricpb.MetricWithMetadatas{ 199 Type: metricpb.MetricWithMetadatas_TIMED_METRIC_WITH_METADATAS, 200 TimedMetricWithMetadatas: &enc.tms, 201 } 202 return enc.encodeMetricWithMetadatas(mm) 203 } 204 205 func (enc *unaggregatedEncoder) encodePassthroughMetricWithMetadata(pm aggregated.PassthroughMetricWithMetadata) error { 206 if err := pm.ToProto(&enc.pm); err != nil { 207 return fmt.Errorf("passthrough metric with metadata proto conversion failed: %v", err) 208 } 209 mm := metricpb.MetricWithMetadatas{ 210 Type: metricpb.MetricWithMetadatas_TIMED_METRIC_WITH_STORAGE_POLICY, 211 TimedMetricWithStoragePolicy: &enc.pm, 212 } 213 return enc.encodeMetricWithMetadatas(mm) 214 } 215 216 func (enc *unaggregatedEncoder) encodeMetricWithMetadatas(pb metricpb.MetricWithMetadatas) error { 217 msgSize := pb.Size() 218 if msgSize > enc.maxMessageSize { 219 return fmt.Errorf("message size %d is larger than maximum supported size %d", msgSize, enc.maxMessageSize) 220 } 221 payloadSize := maxMessageSizeInBytes + msgSize 222 enc.ensureBufferSize(enc.used + payloadSize) 223 enc.encodeMessageSizeFn(msgSize) 224 return enc.encodeMessageFn(pb) 225 } 226 227 // ensureBufferSize ensures the internal buffer has at least the specified target size. 228 func (enc *unaggregatedEncoder) ensureBufferSize(targetSize int) { 229 enc.buf = ensureBufferSize(enc.buf, enc.pool, targetSize, copyData) 230 } 231 232 func (enc *unaggregatedEncoder) encodeMessageSize(msgSize int) { 233 n := binary.PutVarint(enc.buf[enc.used:], int64(msgSize)) 234 enc.used += n 235 } 236 237 func (enc *unaggregatedEncoder) encodeMessage(pb metricpb.MetricWithMetadatas) error { 238 n, err := pb.MarshalTo(enc.buf[enc.used:]) 239 if err != nil { 240 return err 241 } 242 enc.used += n 243 return nil 244 }