github.com/m3db/m3@v1.5.0/src/metrics/transformation/type.go (about) 1 // go:generate stringer -type=Type 2 // Copyright (c) 2017 Uber Technologies, Inc. 3 // 4 // Permission is hereby granted, free of charge, to any person obtaining a copy 5 // of this software and associated documentation files (the "Software"), to deal 6 // in the Software without restriction, including without limitation the rights 7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 // copies of the Software, and to permit persons to whom the Software is 9 // furnished to do so, subject to the following conditions: 10 // 11 // The above copyright notice and this permission notice shall be included in 12 // all copies or substantial portions of the Software. 13 // 14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 // THE SOFTWARE. 21 22 package transformation 23 24 import ( 25 "errors" 26 "fmt" 27 28 "github.com/m3db/m3/src/metrics/generated/proto/transformationpb" 29 ) 30 31 // Type defines a transformation function. 32 type Type int32 33 34 var errUnknownTransformationType = errors.New("unknown transformation type") 35 36 // Supported transformation types. 37 const ( 38 UnknownType Type = iota 39 Absolute 40 PerSecond 41 Increase 42 Add 43 Reset 44 ) 45 46 const ( 47 _minValidTransformationType = Absolute 48 _maxValidTransformationType = Reset 49 ) 50 51 // IsValid checks if the transformation type is valid. 52 func (t Type) IsValid() bool { 53 return t.IsUnaryTransform() || t.IsBinaryTransform() || t.IsUnaryMultiOutputTransform() 54 } 55 56 // IsUnaryTransform returns whether this is a unary transformation. 57 func (t Type) IsUnaryTransform() bool { 58 _, exists := unaryTransforms[t] 59 return exists 60 } 61 62 // IsBinaryTransform returns whether this is a binary transformation. 63 func (t Type) IsBinaryTransform() bool { 64 _, exists := binaryTransforms[t] 65 return exists 66 } 67 68 func (t Type) IsUnaryMultiOutputTransform() bool { 69 _, exists := unaryMultiOutputTransforms[t] 70 return exists 71 } 72 73 // NewOp returns a constructed operation that is allocated once and can be 74 // reused. 75 func (t Type) NewOp() (Op, error) { 76 var ( 77 err error 78 unary UnaryTransform 79 binary BinaryTransform 80 unaryMulti UnaryMultiOutputTransform 81 ) 82 switch { 83 case t.IsUnaryTransform(): 84 unary, err = t.UnaryTransform() 85 case t.IsBinaryTransform(): 86 binary, err = t.BinaryTransform() 87 case t.IsUnaryMultiOutputTransform(): 88 unaryMulti, err = t.UnaryMultiOutputTransform() 89 default: 90 err = errUnknownTransformationType 91 } 92 if err != nil { 93 return Op{}, err 94 } 95 return Op{ 96 opType: t, 97 unary: unary, 98 binary: binary, 99 unaryMulti: unaryMulti, 100 }, nil 101 } 102 103 // UnaryTransform returns the unary transformation function associated with 104 // the transformation type if applicable, or an error otherwise. 105 func (t Type) UnaryTransform() (UnaryTransform, error) { 106 tf, exists := unaryTransforms[t] 107 if !exists { 108 return nil, fmt.Errorf("%v is not a unary transfomration", t) 109 } 110 return tf(), nil 111 } 112 113 // MustUnaryTransform returns the unary transformation function associated with 114 // the transformation type if applicable, or panics otherwise. 115 func (t Type) MustUnaryTransform() UnaryTransform { 116 tf, err := t.UnaryTransform() 117 if err != nil { 118 panic(err) 119 } 120 return tf 121 } 122 123 // BinaryTransform returns the binary transformation function associated with 124 // the transformation type if applicable, or an error otherwise. 125 func (t Type) BinaryTransform() (BinaryTransform, error) { 126 tf, exists := binaryTransforms[t] 127 if !exists { 128 return nil, fmt.Errorf("%v is not a binary transfomration", t) 129 } 130 return tf(), nil 131 } 132 133 // MustBinaryTransform returns the binary transformation function associated with 134 // the transformation type if applicable, or an error otherwise. 135 func (t Type) MustBinaryTransform() BinaryTransform { 136 tf, err := t.BinaryTransform() 137 if err != nil { 138 panic(err) 139 } 140 return tf 141 } 142 143 // UnaryMultiOutputTransform returns the unary transformation function associated with 144 // the transformation type if applicable, or an error otherwise. 145 func (t Type) UnaryMultiOutputTransform() (UnaryMultiOutputTransform, error) { 146 tf, exists := unaryMultiOutputTransforms[t] 147 if !exists { 148 return nil, fmt.Errorf("%v is not a unary transfomration", t) 149 } 150 return tf(), nil 151 } 152 153 // MustUnaryMultiOutputTransform returns the unary transformation function associated with 154 // the transformation type if applicable, or panics otherwise. 155 func (t Type) MustUnaryMultiOutputTransform() UnaryMultiOutputTransform { 156 tf, err := t.UnaryMultiOutputTransform() 157 if err != nil { 158 panic(err) 159 } 160 return tf 161 } 162 163 // ToProto converts the transformation type to a protobuf message in place. 164 func (t Type) ToProto(pb *transformationpb.TransformationType) error { 165 if t < _minValidTransformationType || t > _maxValidTransformationType { 166 return errUnknownTransformationType 167 } 168 *pb = transformationpb.TransformationType(t) 169 return nil 170 } 171 172 // FromProto converts the protobuf message to a transformation type in place. 173 func (t *Type) FromProto(pb transformationpb.TransformationType) error { 174 *t = Type(pb) 175 if *t < _minValidTransformationType || *t > _maxValidTransformationType { 176 return errUnknownTransformationType 177 } 178 return nil 179 } 180 181 // UnmarshalText extracts this type from the textual representation 182 func (t *Type) UnmarshalText(text []byte) error { 183 parsed, err := ParseType(string(text)) 184 if err != nil { 185 return err 186 } 187 *t = parsed 188 return nil 189 } 190 191 // UnmarshalYAML unmarshals text-encoded data into an transformation type. 192 func (t *Type) UnmarshalYAML(unmarshal func(interface{}) error) error { 193 var str string 194 if err := unmarshal(&str); err != nil { 195 return err 196 } 197 value, err := ParseType(str) 198 if err != nil { 199 return err 200 } 201 *t = value 202 return nil 203 } 204 205 // MarshalText serializes this type to its textual representation. 206 func (t Type) MarshalText() (text []byte, err error) { 207 if !t.IsValid() { 208 return nil, fmt.Errorf("invalid aggregation type %s", t.String()) 209 } 210 return []byte(t.String()), nil 211 } 212 213 // ParseType parses a transformation type. 214 func ParseType(str string) (Type, error) { 215 t, ok := typeStringMap[str] 216 if !ok { 217 return UnknownType, fmt.Errorf("invalid transformation type: %s", str) 218 } 219 return t, nil 220 } 221 222 // Op represents a transform operation. 223 type Op struct { 224 unary UnaryTransform 225 binary BinaryTransform 226 unaryMulti UnaryMultiOutputTransform 227 // opType determines which one of the above transformations are applied 228 opType Type 229 } 230 231 // Type returns the op type. 232 func (o Op) Type() Type { 233 return o.opType 234 } 235 236 // UnaryTransform returns the active unary transform if op is unary transform. 237 func (o Op) UnaryTransform() (UnaryTransform, bool) { 238 if !o.Type().IsUnaryTransform() { 239 return nil, false 240 } 241 return o.unary, true 242 } 243 244 // BinaryTransform returns the active binary transform if op is binary transform. 245 func (o Op) BinaryTransform() (BinaryTransform, bool) { 246 if !o.Type().IsBinaryTransform() { 247 return nil, false 248 } 249 return o.binary, true 250 } 251 252 // UnaryMultiOutputTransform returns the active unary multi transform if op is unary multi transform. 253 func (o Op) UnaryMultiOutputTransform() (UnaryMultiOutputTransform, bool) { 254 if !o.Type().IsUnaryMultiOutputTransform() { 255 return nil, false 256 } 257 return o.unaryMulti, true 258 } 259 260 var ( 261 unaryTransforms = map[Type]func() UnaryTransform{ 262 Absolute: transformAbsolute, 263 Add: transformAdd, 264 } 265 binaryTransforms = map[Type]func() BinaryTransform{ 266 PerSecond: transformPerSecond, 267 Increase: transformIncrease, 268 } 269 unaryMultiOutputTransforms = map[Type]func() UnaryMultiOutputTransform{ 270 Reset: transformReset, 271 } 272 typeStringMap map[string]Type 273 ) 274 275 func init() { 276 typeStringMap = make(map[string]Type) 277 for t := range unaryTransforms { 278 typeStringMap[t.String()] = t 279 } 280 for t := range binaryTransforms { 281 typeStringMap[t.String()] = t 282 } 283 for t := range unaryMultiOutputTransforms { 284 typeStringMap[t.String()] = t 285 } 286 }