[#1210] timers: Add IterationsTicker
It allows specifying duration in blocks and a desired number of handler calls in that period. Signed-off-by: Pavel Karpy <carpawell@nspcc.ru>
This commit is contained in:
parent
13af4e6046
commit
77d847dbea
2 changed files with 208 additions and 0 deletions
90
cmd/neofs-node/reputation/ticker/fixed.go
Normal file
90
cmd/neofs-node/reputation/ticker/fixed.go
Normal file
|
@ -0,0 +1,90 @@
|
|||
package ticker
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// IterationHandler is a callback of a certain block advance.
|
||||
type IterationHandler func()
|
||||
|
||||
// IterationsTicker represents fixed tick number block timer.
|
||||
//
|
||||
// It can tick the blocks and perform certain actions
|
||||
// on block time intervals.
|
||||
type IterationsTicker struct {
|
||||
m sync.Mutex
|
||||
|
||||
curr uint64
|
||||
period uint64
|
||||
|
||||
times uint64
|
||||
|
||||
h IterationHandler
|
||||
}
|
||||
|
||||
// NewIterationsTicker creates a new IterationsTicker.
|
||||
//
|
||||
// It guaranties that handler would be called the
|
||||
// specified amount of times in the specified amount
|
||||
// of blocks. After the last meaningful Tick IterationsTicker
|
||||
// becomes no-op timer.
|
||||
//
|
||||
// Returns error only if times is greater than totalBlocks.
|
||||
func NewIterationsTicker(totalBlocks uint64, times uint64, h IterationHandler) (*IterationsTicker, error) {
|
||||
period := totalBlocks / times
|
||||
|
||||
if period == 0 {
|
||||
return nil, fmt.Errorf("impossible to tick %d times in %d blocks",
|
||||
times, totalBlocks,
|
||||
)
|
||||
}
|
||||
|
||||
var curr uint64
|
||||
|
||||
// try to make handler calls as rare as possible
|
||||
if totalBlocks%times != 0 {
|
||||
extraBlocks := (period+1)*times - totalBlocks
|
||||
|
||||
if period >= extraBlocks {
|
||||
curr = extraBlocks + (period-extraBlocks)/2
|
||||
period++
|
||||
}
|
||||
}
|
||||
|
||||
return &IterationsTicker{
|
||||
curr: curr,
|
||||
period: period,
|
||||
times: times,
|
||||
h: h,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Tick ticks one block in the IterationsTicker.
|
||||
//
|
||||
// Returns `false` if the timer has finished its operations
|
||||
// and there will be no more handler calls.
|
||||
// Calling Tick after the returned `false` is safe, no-op
|
||||
// and also returns `false`.
|
||||
func (ft *IterationsTicker) Tick() bool {
|
||||
ft.m.Lock()
|
||||
defer ft.m.Unlock()
|
||||
|
||||
if ft.times == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
ft.curr++
|
||||
|
||||
if ft.curr%ft.period == 0 {
|
||||
ft.h()
|
||||
|
||||
ft.times--
|
||||
|
||||
if ft.times == 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue