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  }