Use safe timer reset method (#757)

* use saft timer reset method

* use saft timer reset method
This commit is contained in:
benjamin202410 2024-12-09 01:40:18 -08:00 committed by GitHub
parent 1b89654663
commit 89256cb2c2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -116,6 +116,8 @@ type worker struct {
chainHeadSub event.Subscription chainHeadSub event.Subscription
chainSideCh chan core.ChainSideEvent chainSideCh chan core.ChainSideEvent
chainSideSub event.Subscription chainSideSub event.Subscription
resetCh chan time.Duration // Channel to request timer resets
wg sync.WaitGroup wg sync.WaitGroup
agents map[Agent]struct{} agents map[Agent]struct{}
@ -158,6 +160,7 @@ func newWorker(config *params.ChainConfig, engine consensus.Engine, coinbase com
txsCh: make(chan core.NewTxsEvent, txChanSize), txsCh: make(chan core.NewTxsEvent, txChanSize),
chainHeadCh: make(chan core.ChainHeadEvent, chainHeadChanSize), chainHeadCh: make(chan core.ChainHeadEvent, chainHeadChanSize),
chainSideCh: make(chan core.ChainSideEvent, chainSideChanSize), chainSideCh: make(chan core.ChainSideEvent, chainSideChanSize),
resetCh: make(chan time.Duration, 1),
chainDb: eth.ChainDb(), chainDb: eth.ChainDb(),
recv: make(chan *Result, resultQueueSize), recv: make(chan *Result, resultQueueSize),
chain: eth.BlockChain(), chain: eth.BlockChain(),
@ -284,6 +287,16 @@ func (self *worker) update() {
for { for {
// A real event arrived, process interesting content // A real event arrived, process interesting content
select { select {
case d := <-self.resetCh:
// Reset the timer to the new duration.
if !timeout.Stop() {
// Drain the timer channel if it had already expired.
select {
case <-timeout.C:
default:
}
}
timeout.Reset(d)
case <-timeout.C: case <-timeout.C:
c <- struct{}{} c <- struct{}{}
case <-finish: case <-finish:
@ -292,32 +305,31 @@ func (self *worker) update() {
} }
}() }()
for { for {
prevReset0TimeMillisec := int64(0)
// A real event arrived, process interesting content // A real event arrived, process interesting content
select { select {
case v := <-MinePeriodCh: case v := <-MinePeriodCh:
log.Info("[worker] update wait period", "period", v) log.Info("[worker] update wait period", "period", v)
minePeriod = v minePeriod = v
timeout.Reset(time.Duration(minePeriod) * time.Second) self.resetCh <- time.Duration(minePeriod) * time.Second
case <-c: case <-c:
if atomic.LoadInt32(&self.mining) == 1 { if atomic.LoadInt32(&self.mining) == 1 {
self.commitNewWork() self.commitNewWork()
} }
resetTime := getResetTime(self.chain, minePeriod, &prevReset0TimeMillisec) resetTime := getResetTime(self.chain, minePeriod)
timeout.Reset(resetTime) self.resetCh <- resetTime
// Handle ChainHeadEvent // Handle ChainHeadEvent
case <-self.chainHeadCh: case <-self.chainHeadCh:
self.commitNewWork() self.commitNewWork()
resetTime := getResetTime(self.chain, minePeriod, &prevReset0TimeMillisec) resetTime := getResetTime(self.chain, minePeriod)
timeout.Reset(resetTime) self.resetCh <- resetTime
// Handle new round // Handle new round
case <-NewRoundCh: case <-NewRoundCh:
self.commitNewWork() self.commitNewWork()
resetTime := getResetTime(self.chain, minePeriod, &prevReset0TimeMillisec) resetTime := getResetTime(self.chain, minePeriod)
timeout.Reset(resetTime) self.resetCh <- resetTime
// Handle ChainSideEvent // Handle ChainSideEvent
case <-self.chainSideCh: case <-self.chainSideCh:
@ -364,27 +376,15 @@ func (self *worker) update() {
} }
} }
func getResetTime(chain *core.BlockChain, minePeriod int, prevReset0TimeMillisec *int64) time.Duration { func getResetTime(chain *core.BlockChain, minePeriod int) time.Duration {
minePeriodDuration := time.Duration(minePeriod) * time.Second minePeriodDuration := time.Duration(minePeriod) * time.Second
currentBlockTime := chain.CurrentBlock().Time().Int64() currentBlockTime := chain.CurrentBlock().Time().Int64()
nowTime := time.Now().UnixMilli() nowTime := time.Now().UnixMilli()
resetTime := time.Duration(currentBlockTime)*time.Second + minePeriodDuration - time.Duration(nowTime)*time.Millisecond resetTime := time.Duration(currentBlockTime)*time.Second + minePeriodDuration - time.Duration(nowTime)*time.Millisecond
// in case the current block time is not very accurate // in case the current block time is not very accurate
if resetTime > minePeriodDuration { if resetTime > minePeriodDuration || resetTime <= 0 {
resetTime = minePeriodDuration resetTime = minePeriodDuration
} }
// in case the current block is too far in the past, the block time already is huge, we wait for 0 time (which will be handled in the next if statement)
if resetTime < 0 {
resetTime = 0
}
if resetTime == 0 {
if nowTime == *prevReset0TimeMillisec {
// in case it resets to 0 in one millisecond too many times, we wait for mine period
resetTime = minePeriodDuration
} else {
*prevReset0TimeMillisec = nowTime
}
}
log.Debug("[update] Miner worker timer reset", "resetMilliseconds", resetTime.Milliseconds(), "minePeriodSec", minePeriod, "currentBlockTimeSec", fmt.Sprintf("%d", currentBlockTime), "currentSystemTimeSec", fmt.Sprintf("%d.%03d", nowTime/1000, nowTime%1000)) log.Debug("[update] Miner worker timer reset", "resetMilliseconds", resetTime.Milliseconds(), "minePeriodSec", minePeriod, "currentBlockTimeSec", fmt.Sprintf("%d", currentBlockTime), "currentSystemTimeSec", fmt.Sprintf("%d.%03d", nowTime/1000, nowTime%1000))
return resetTime return resetTime
} }