github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/module/counters/monotonous_counter.go (about) 1 package counters 2 3 import "sync/atomic" 4 5 // StrictMonotonousCounter is a helper struct which implements a strict monotonous counter. 6 // StrictMonotonousCounter is implemented using atomic operations and doesn't allow to set a value 7 // which is lower or equal to the already stored one. The counter is implemented 8 // solely with non-blocking atomic operations for concurrency safety. 9 type StrictMonotonousCounter struct { 10 atomicCounter uint64 11 } 12 13 // NewMonotonousCounter creates new counter with initial value 14 func NewMonotonousCounter(initialValue uint64) StrictMonotonousCounter { 15 return StrictMonotonousCounter{ 16 atomicCounter: initialValue, 17 } 18 } 19 20 // Set updates value of counter if and only if it's strictly larger than value which is already stored. 21 // Returns true if update was successful or false if stored value is larger. 22 func (c *StrictMonotonousCounter) Set(newValue uint64) bool { 23 for { 24 oldValue := c.Value() 25 if newValue <= oldValue { 26 return false 27 } 28 if atomic.CompareAndSwapUint64(&c.atomicCounter, oldValue, newValue) { 29 return true 30 } 31 } 32 } 33 34 // Value returns value which is stored in atomic variable 35 func (c *StrictMonotonousCounter) Value() uint64 { 36 return atomic.LoadUint64(&c.atomicCounter) 37 } 38 39 // Increment atomically increments counter and returns updated value 40 func (c *StrictMonotonousCounter) Increment() uint64 { 41 for { 42 oldValue := c.Value() 43 newValue := oldValue + 1 44 if atomic.CompareAndSwapUint64(&c.atomicCounter, oldValue, newValue) { 45 return newValue 46 } 47 } 48 }