github.com/google/cloudprober@v0.11.3/metrics/int.go (about) 1 // Copyright 2017 The Cloudprober Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package metrics 16 17 import ( 18 "errors" 19 "strconv" 20 "sync/atomic" 21 ) 22 23 // Int implements NumValue with int64 storage. Note that Int is not concurrency 24 // safe, if you want a concurrency safe integer NumValue, use AtomicInt. 25 type Int struct { 26 i int64 27 // If Str is defined, this is method used to convert Int into a string. 28 Str func(int64) string 29 } 30 31 // NewInt returns a new Int 32 func NewInt(i int64) *Int { 33 return &Int{i: i} 34 } 35 36 // Clone returns a copy the receiver Int 37 func (i *Int) Clone() Value { 38 return &Int{ 39 i: i.i, 40 Str: i.Str, 41 } 42 } 43 44 // Int64 returns the stored int64 45 func (i *Int) Int64() int64 { 46 return i.i 47 } 48 49 // Float64 returns the stored int64 as a float64 50 func (i *Int) Float64() float64 { 51 return float64(i.i) 52 } 53 54 // Inc increments the receiver Int by one. 55 // It's part of the NumValue interface. 56 func (i *Int) Inc() { 57 i.i++ 58 } 59 60 // IncBy increments the receiver Int by "delta" NumValue. 61 // It's part of the NumValue interface. 62 func (i *Int) IncBy(delta NumValue) { 63 i.i += delta.Int64() 64 } 65 66 // Add adds a Value to the receiver Int. If Value is not Int, an error is returned. 67 // It's part of the Value interface. 68 func (i *Int) Add(val Value) error { 69 delta, ok := val.(*Int) 70 if !ok { 71 return errors.New("incompatible value to add") 72 } 73 i.i += delta.i 74 return nil 75 } 76 77 // SubtractCounter subtracts the provided "lastVal", assuming that value 78 // represents a counter, i.e. if "value" is less than "lastVal", we assume that 79 // counter has been reset and don't subtract. 80 func (i *Int) SubtractCounter(lastVal Value) (bool, error) { 81 lv, ok := lastVal.(*Int) 82 if !ok { 83 return false, errors.New("incompatible value to subtract") 84 } 85 86 if i.i < lv.i { 87 return true, nil 88 } 89 90 i.i -= lv.i 91 return false, nil 92 } 93 94 // AddInt64 adds an int64 to the receiver Int. 95 func (i *Int) AddInt64(ii int64) { 96 i.i += ii 97 } 98 99 // AddFloat64 adds a float64 to the receiver Int. 100 func (i *Int) AddFloat64(f float64) { 101 i.i += int64(f) 102 } 103 104 // String returns the string representation of Int. 105 // It's part of the Value interface. 106 func (i *Int) String() string { 107 if i.Str != nil { 108 return i.Str(i.Int64()) 109 } 110 return strconv.FormatInt(i.Int64(), 10) 111 } 112 113 // AtomicInt implements NumValue with int64 storage and atomic operations. If 114 // concurrency-safety is not a requirement, e.g. for use in already mutex 115 // protected map, you could use Int. 116 type AtomicInt struct { 117 i int64 118 // If Str is defined, this is method used to convert AtomicInt into a string. 119 Str func(int64) string 120 } 121 122 // NewAtomicInt returns a new AtomicInt 123 func NewAtomicInt(i int64) *AtomicInt { 124 return &AtomicInt{i: i} 125 } 126 127 // Clone returns a copy the receiver AtomicInt 128 func (i *AtomicInt) Clone() Value { 129 return &AtomicInt{ 130 i: i.Int64(), 131 Str: i.Str, 132 } 133 } 134 135 // Int64 returns the stored int64 136 func (i *AtomicInt) Int64() int64 { 137 return atomic.LoadInt64(&i.i) 138 } 139 140 // Float64 returns the stored int64 as a float64 141 func (i *AtomicInt) Float64() float64 { 142 return float64(atomic.LoadInt64(&i.i)) 143 } 144 145 // Inc increments the receiver AtomicInt by one. 146 // It's part of the NumValue interface. 147 func (i *AtomicInt) Inc() { 148 atomic.AddInt64(&i.i, 1) 149 } 150 151 // IncBy increments the receiver AtomicInt by "delta" NumValue. 152 // It's part of the NumValue interface. 153 func (i *AtomicInt) IncBy(delta NumValue) { 154 atomic.AddInt64(&i.i, delta.Int64()) 155 } 156 157 // Add adds a Value to the receiver AtomicInt. If Value is not AtomicInt, an error is returned. 158 // It's part of the Value interface. 159 func (i *AtomicInt) Add(val Value) error { 160 delta, ok := val.(NumValue) 161 if !ok { 162 return errors.New("incompatible value to add") 163 } 164 atomic.AddInt64(&i.i, delta.Int64()) 165 return nil 166 } 167 168 // SubtractCounter subtracts the provided "lastVal". Note that this function 169 // is not fully atomic: we first load the values, compare them, and then update 170 // the receiver if required. There is a possibility that either receiver, or 171 // lastVal may change between loading of the values and updating them. We 172 // should still not get negative values though, as we use the snapshots to 173 // finally update the value. 174 func (i *AtomicInt) SubtractCounter(lastVal Value) (bool, error) { 175 lv, ok := lastVal.(NumValue) 176 if !ok { 177 return false, errors.New("incompatible value to subtract") 178 } 179 180 valS := i.Int64() 181 lvS := lv.Int64() 182 183 if valS < lvS { 184 return true, nil 185 } 186 atomic.StoreInt64(&i.i, valS-lvS) 187 return false, nil 188 } 189 190 // AddInt64 adds an int64 to the receiver Int. 191 func (i *AtomicInt) AddInt64(ii int64) { 192 atomic.AddInt64(&i.i, ii) 193 } 194 195 // AddFloat64 adds a float64 to the receiver Int. 196 func (i *AtomicInt) AddFloat64(f float64) { 197 atomic.AddInt64(&i.i, int64(f)) 198 } 199 200 // String returns the string representation of AtomicInt. 201 // It's part of the Value interface. 202 func (i *AtomicInt) String() string { 203 if i.Str != nil { 204 return i.Str(i.Int64()) 205 } 206 return strconv.FormatInt(i.Int64(), 10) 207 }