github.com/m3db/m3@v1.5.0/src/metrics/policy/policy.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 policy 22 23 import ( 24 "errors" 25 "strings" 26 27 "github.com/m3db/m3/src/metrics/aggregation" 28 "github.com/m3db/m3/src/metrics/generated/proto/policypb" 29 ) 30 31 const ( 32 policyAggregationTypeSeparator = "|" 33 ) 34 35 var ( 36 // DefaultPolicy represents a default policy. 37 DefaultPolicy Policy 38 39 errNilPolicyProto = errors.New("nil policy proto") 40 errInvalidPolicyString = errors.New("invalid policy string") 41 errInvalidDropPolicyString = errors.New("invalid drop policy string") 42 ) 43 44 // Policy contains a storage policy and a list of custom aggregation types. 45 type Policy struct { 46 StoragePolicy 47 AggregationID aggregation.ID 48 } 49 50 // NewPolicy creates a policy. 51 func NewPolicy(sp StoragePolicy, aggID aggregation.ID) Policy { 52 return Policy{StoragePolicy: sp, AggregationID: aggID} 53 } 54 55 // NewPolicyFromProto creates a new policy from a proto policy. 56 func NewPolicyFromProto(p *policypb.Policy) (Policy, error) { 57 if p == nil { 58 return DefaultPolicy, errNilPolicyProto 59 } 60 61 policy, err := NewStoragePolicyFromProto(p.StoragePolicy) 62 if err != nil { 63 return DefaultPolicy, err 64 } 65 66 aggID, err := aggregation.NewIDFromProto(p.AggregationTypes) 67 if err != nil { 68 return DefaultPolicy, err 69 } 70 71 return NewPolicy(policy, aggID), nil 72 73 } 74 75 // Proto returns the proto of the policy. 76 func (p Policy) Proto() (*policypb.Policy, error) { 77 var storagePolicyProto policypb.StoragePolicy 78 err := p.StoragePolicy.ToProto(&storagePolicyProto) 79 if err != nil { 80 return nil, err 81 } 82 83 aggTypes, err := aggregation.NewIDDecompressor().Decompress(p.AggregationID) 84 if err != nil { 85 return nil, err 86 } 87 88 protoAggTypes, err := aggTypes.Proto() 89 if err != nil { 90 return nil, err 91 } 92 93 return &policypb.Policy{ 94 StoragePolicy: &storagePolicyProto, 95 AggregationTypes: protoAggTypes, 96 }, nil 97 } 98 99 // String is the string representation of a policy. 100 func (p Policy) String() string { 101 if p.AggregationID.IsDefault() { 102 return p.StoragePolicy.String() 103 } 104 return p.StoragePolicy.String() + policyAggregationTypeSeparator + p.AggregationID.String() 105 } 106 107 // MarshalText returns the text encoding of a policy. 108 func (p Policy) MarshalText() ([]byte, error) { 109 return []byte(p.String()), nil 110 } 111 112 // UnmarshalText unmarshals text-encoded data into a policy. 113 func (p *Policy) UnmarshalText(data []byte) error { 114 parsed, err := ParsePolicy(string(data)) 115 if err != nil { 116 return err 117 } 118 *p = parsed 119 return nil 120 } 121 122 // ParsePolicy parses a policy in the form of resolution:retention|aggregationTypes. 123 func ParsePolicy(str string) (Policy, error) { 124 parts := strings.Split(str, policyAggregationTypeSeparator) 125 l := len(parts) 126 if l > 2 { 127 return DefaultPolicy, errInvalidPolicyString 128 } 129 130 sp, err := ParseStoragePolicy(parts[0]) 131 if err != nil { 132 return DefaultPolicy, err 133 } 134 135 var aggID = aggregation.DefaultID 136 if l == 2 { 137 aggTypes, err := aggregation.ParseTypes(parts[1]) 138 if err != nil { 139 return DefaultPolicy, err 140 } 141 142 aggID, err = aggregation.NewIDCompressor().Compress(aggTypes) 143 if err != nil { 144 return DefaultPolicy, err 145 } 146 } 147 148 return NewPolicy(sp, aggID), nil 149 } 150 151 // NewPoliciesFromProto creates multiple new policies from given proto policies. 152 func NewPoliciesFromProto(policies []*policypb.Policy) ([]Policy, error) { 153 res := make([]Policy, 0, len(policies)) 154 for _, p := range policies { 155 policy, err := NewPolicyFromProto(p) 156 if err != nil { 157 return nil, err 158 } 159 res = append(res, policy) 160 } 161 return res, nil 162 } 163 164 // IsDefaultPolicies checks if the policies are the default policies. 165 func IsDefaultPolicies(ps []Policy) bool { 166 return len(ps) == 0 167 } 168 169 // Policies is a list of policies. Used to check ploicy list equivalence. 170 type Policies []Policy 171 172 // Equals takes a list of policies and checks equivalence. 173 func (p Policies) Equals(other Policies) bool { 174 if len(p) != len(other) { 175 return false 176 } 177 for i := 0; i < len(p); i++ { 178 if p[i] != other[i] { 179 return false 180 } 181 } 182 return true 183 } 184 185 // UnmarshalText unmarshals a drop policy value from a string. 186 // Empty string defaults to DefaultDropPolicy. 187 func (p *DropPolicy) UnmarshalText(data []byte) error { 188 str := string(data) 189 // Allow default string value (not specified) to mean default 190 if str == "" { 191 *p = DefaultDropPolicy 192 return nil 193 } 194 195 parsed, err := ParseDropPolicy(str) 196 if err != nil { 197 return err 198 } 199 200 *p = parsed 201 return nil 202 } 203 204 // MarshalText marshals a drop policy to a string. 205 func (p DropPolicy) MarshalText() ([]byte, error) { 206 return []byte(p.String()), nil 207 } 208 209 // ParseDropPolicy parses a drop policy. 210 func ParseDropPolicy(str string) (DropPolicy, error) { 211 for _, valid := range validDropPolicies { 212 if valid.String() == str { 213 return valid, nil 214 } 215 } 216 217 return DefaultDropPolicy, errInvalidDropPolicyString 218 }