-
Notifications
You must be signed in to change notification settings - Fork 211
/
clock.go
75 lines (64 loc) · 1.76 KB
/
clock.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
package timesync
import (
"github.com/spacemeshos/go-spacemesh/log"
"sync"
"time"
)
type Clock interface {
Now() time.Time
}
type RealClock struct{}
func (RealClock) Now() time.Time {
return time.Now()
}
type TimeClock struct {
*Ticker
tickInterval time.Duration
startEpoch time.Time
stop chan struct{}
once sync.Once
log log.Log
}
func NewClock(c Clock, tickInterval time.Duration, genesisTime time.Time, logger log.Log) *TimeClock {
if tickInterval == 0 {
logger.Panic("could not create new clock: bad configuration: tick interval is zero")
}
t := &TimeClock{
Ticker: NewTicker(c, LayerConv{duration: tickInterval, genesis: genesisTime}),
tickInterval: tickInterval,
startEpoch: genesisTime,
stop: make(chan struct{}),
once: sync.Once{},
log: logger,
}
go t.startClock()
return t
}
func (t *TimeClock) startClock() {
t.log.Info("starting global clock now=%v genesis=%v", t.clock.Now(), t.startEpoch)
for {
currLayer := t.Ticker.conv.TimeToLayer(t.clock.Now()) // get current layer
nextTickTime := t.Ticker.conv.LayerToTime(currLayer + 1) // get next tick time for the next layer
diff := nextTickTime.Sub(t.clock.Now())
tmr := time.NewTimer(diff)
t.log.With().Info("global clock going to sleep before next layer", log.String("diff", diff.String()), log.Uint64("next_layer", uint64(currLayer)))
select {
case <-tmr.C:
// notify subscribers
if missed, err := t.Notify(); err != nil {
t.log.With().Error("could not notify subscribers", log.Err(err), log.Int("missed", missed))
}
case <-t.stop:
tmr.Stop()
return
}
}
}
func (t *TimeClock) GetGenesisTime() time.Time {
return t.startEpoch
}
func (t *TimeClock) Close() {
t.once.Do(func() {
close(t.stop)
})
}