github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/module/counters/persistent_strict_monotonic_counter.go (about)

     1  package counters
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  
     7  	"github.com/onflow/flow-go/storage"
     8  )
     9  
    10  // ErrIncorrectValue indicates that a processed value is lower or equal than current value.
    11  var (
    12  	ErrIncorrectValue = errors.New("incorrect value")
    13  )
    14  
    15  // PersistentStrictMonotonicCounter represents the consumer progress with strict monotonic counter.
    16  type PersistentStrictMonotonicCounter struct {
    17  	consumerProgress storage.ConsumerProgress
    18  
    19  	// used to skip heights that are lower than the current height
    20  	counter StrictMonotonousCounter
    21  }
    22  
    23  // NewPersistentStrictMonotonicCounter creates a new PersistentStrictMonotonicCounter which inserts the default
    24  // processed index to the storage layer and creates new counter with defaultIndex value.
    25  // The consumer progress and associated db entry must not be accessed outside of calls to the returned object,
    26  // otherwise the state may become inconsistent.
    27  //
    28  // No errors are expected during normal operation.
    29  func NewPersistentStrictMonotonicCounter(consumerProgress storage.ConsumerProgress, defaultIndex uint64) (*PersistentStrictMonotonicCounter, error) {
    30  	m := &PersistentStrictMonotonicCounter{
    31  		consumerProgress: consumerProgress,
    32  	}
    33  
    34  	// sync with storage for the processed index to ensure the consistency
    35  	value, err := m.consumerProgress.ProcessedIndex()
    36  	if err != nil {
    37  		if !errors.Is(err, storage.ErrNotFound) {
    38  			return nil, fmt.Errorf("could not read consumer progress: %w", err)
    39  		}
    40  		err := m.consumerProgress.InitProcessedIndex(defaultIndex)
    41  		if err != nil {
    42  			return nil, fmt.Errorf("could not init consumer progress: %w", err)
    43  		}
    44  		value = defaultIndex
    45  	}
    46  
    47  	m.counter = NewMonotonousCounter(value)
    48  
    49  	return m, nil
    50  }
    51  
    52  // Set sets the processed index, ensuring it is strictly monotonically increasing.
    53  //
    54  // Expected errors during normal operation:
    55  //   - codes.ErrIncorrectValue - if stored value is larger than processed.
    56  //   - generic error in case of unexpected failure from the database layer or
    57  //     encoding failure.
    58  func (m *PersistentStrictMonotonicCounter) Set(processed uint64) error {
    59  	if !m.counter.Set(processed) {
    60  		return ErrIncorrectValue
    61  	}
    62  	return m.consumerProgress.SetProcessedIndex(processed)
    63  }
    64  
    65  // Value loads the current stored index.
    66  //
    67  // No errors are expected during normal operation.
    68  func (m *PersistentStrictMonotonicCounter) Value() uint64 {
    69  	return m.counter.Value()
    70  }