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 }