From 67b368234804b4d4b8f8db4c69270f9a8a2c6549 Mon Sep 17 00:00:00 2001 From: Alex Vanin Date: Wed, 21 Jul 2021 17:28:59 +0300 Subject: [PATCH] [#708] morph/timer: Add single tick timer Signed-off-by: Alex Vanin --- pkg/morph/timer/block.go | 31 ++++++++++++++++----- pkg/morph/timer/block_test.go | 51 +++++++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+), 6 deletions(-) diff --git a/pkg/morph/timer/block.go b/pkg/morph/timer/block.go index 043347ff..c3fea906 100644 --- a/pkg/morph/timer/block.go +++ b/pkg/morph/timer/block.go @@ -31,6 +31,8 @@ type BlockTimer struct { ps []BlockTimer + once bool + deltaCfg } @@ -72,6 +74,20 @@ func NewBlockTimer(dur BlockMeter, h BlockTickHandler) *BlockTimer { } } +// NewOneTickTimer creates a new BlockTimer that ticks only once. +// +// Do not use delta handlers with pulse in this timer. +func NewOneTickTimer(dur BlockMeter, h BlockTickHandler) *BlockTimer { + return &BlockTimer{ + mtx: new(sync.Mutex), + dur: dur, + mul: 1, + div: 1, + h: h, + once: true, + } +} + // OnDelta registers handler which is executed on (mul / div * BlockMeter()) block // after basic interval reset. // @@ -87,9 +103,10 @@ func (t *BlockTimer) OnDelta(mul, div uint32, h BlockTickHandler, opts ...DeltaO } t.ps = append(t.ps, BlockTimer{ - mul: mul, - div: div, - h: h, + mul: mul, + div: div, + h: h, + once: t.once, deltaCfg: c, }) @@ -157,9 +174,11 @@ func (t *BlockTimer) tick() { // 2. call t.tickH(h) t.h() - t.cur = 0 - t.rolledBack = true - t.reset() + if !t.once { + t.cur = 0 + t.rolledBack = true + t.reset() + } } for i := range t.ps { diff --git a/pkg/morph/timer/block_test.go b/pkg/morph/timer/block_test.go index 03e4ec38..c5d6525f 100644 --- a/pkg/morph/timer/block_test.go +++ b/pkg/morph/timer/block_test.go @@ -108,3 +108,54 @@ func TestDeltaReset(t *testing.T) { require.Equal(t, 2, detlaCallCounter) } + +func TestNewOneTickTimer(t *testing.T) { + blockDur := uint32(1) + baseCallCounter := 0 + + bt := timer.NewOneTickTimer(timer.StaticBlockMeter(blockDur), func() { + baseCallCounter++ + }) + require.NoError(t, bt.Reset()) + + tickN(bt, 10) + require.Equal(t, 1, baseCallCounter) // happens once no matter what + + t.Run("zero duration", func(t *testing.T) { + blockDur = uint32(0) + baseCallCounter = 0 + + bt = timer.NewOneTickTimer(timer.StaticBlockMeter(blockDur), func() { + baseCallCounter++ + }) + require.NoError(t, bt.Reset()) + + tickN(bt, 10) + require.Equal(t, 1, baseCallCounter) + }) + + t.Run("delta without pulse", func(t *testing.T) { + blockDur = uint32(10) + baseCallCounter = 0 + + bt = timer.NewOneTickTimer(timer.StaticBlockMeter(blockDur), func() { + baseCallCounter++ + }) + + detlaCallCounter := 0 + + bt.OnDelta(1, 10, func() { + detlaCallCounter++ + }) + + require.NoError(t, bt.Reset()) + + tickN(bt, 10) + require.Equal(t, 1, baseCallCounter) + require.Equal(t, 1, detlaCallCounter) + + tickN(bt, 10) // 10 more ticks must not affect counters + require.Equal(t, 1, baseCallCounter) + require.Equal(t, 1, detlaCallCounter) + }) +}