Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

En 6839 dump goroutines #2009

Merged
merged 11 commits into from
Jun 25, 2020
9 changes: 9 additions & 0 deletions cmd/node/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,14 @@ import (
"github.com/ElrondNetwork/elrond-go/consensus/round"
"github.com/ElrondNetwork/elrond-go/core"
"github.com/ElrondNetwork/elrond-go/core/accumulator"
"github.com/ElrondNetwork/elrond-go/core/alarm"
"github.com/ElrondNetwork/elrond-go/core/check"
"github.com/ElrondNetwork/elrond-go/core/indexer"
"github.com/ElrondNetwork/elrond-go/core/random"
"github.com/ElrondNetwork/elrond-go/core/serviceContainer"
"github.com/ElrondNetwork/elrond-go/core/statistics"
"github.com/ElrondNetwork/elrond-go/core/throttler"
"github.com/ElrondNetwork/elrond-go/core/watchdog"
"github.com/ElrondNetwork/elrond-go/crypto"
"github.com/ElrondNetwork/elrond-go/crypto/signing/mcl"
"github.com/ElrondNetwork/elrond-go/data"
Expand Down Expand Up @@ -2047,6 +2049,12 @@ func createNode(
return nil, err
}

alarmScheduler := alarm.NewAlarmScheduler()
watchdogTimer, err := watchdog.NewWatchdog(alarmScheduler, chanStopNodeProcess)
if err != nil {
return nil, err
}

peerDenialEvaluator, err := blackList.NewPeerDenialEvaluator(
network.PeerBlackListHandler,
network.PkTimeCache,
Expand Down Expand Up @@ -2122,6 +2130,7 @@ func createNode(
node.WithNodeStopChannel(chanStopNodeProcess),
node.WithApiTransactionByHashThrottler(apiTxsByHashThrottler),
node.WithPeerHonestyHandler(peerHonestyHandler),
node.WithWatchdogTimer(watchdogTimer),
)
if err != nil {
return nil, errors.New("error creating node: " + err.Error())
Expand Down
18 changes: 17 additions & 1 deletion consensus/chronology/chronology.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ var log = logger.GetOrCreate("consensus/chronology")
// srBeforeStartRound defines the state which exist before the start of the round
const srBeforeStartRound = -1

const numRoundsToWaitBeforeSignalingChronologyStuck = 10
const chronologyAlarmID = "chronology"

// chronology defines the data needed by the chronology
type chronology struct {
genesisTime time.Time
Expand All @@ -38,20 +41,23 @@ type chronology struct {
mutSubrounds sync.RWMutex
appStatusHandler core.AppStatusHandler
cancelFunc func()

watchdog core.WatchdogTimer
}

// NewChronology creates a new chronology object
func NewChronology(
genesisTime time.Time,
rounder consensus.Rounder,
syncTimer ntp.SyncTimer,
watchdog core.WatchdogTimer,
) (*chronology, error) {

err := checkNewChronologyParams(
rounder,
syncTimer,
watchdog,
)

if err != nil {
return nil, err
}
Expand All @@ -61,6 +67,7 @@ func NewChronology(
rounder: rounder,
syncTimer: syncTimer,
appStatusHandler: statusHandler.NewNilStatusHandler(),
watchdog: watchdog,
}

chr.subroundId = srBeforeStartRound
Expand All @@ -74,6 +81,7 @@ func NewChronology(
func checkNewChronologyParams(
rounder consensus.Rounder,
syncTimer ntp.SyncTimer,
watchdog core.WatchdogTimer,
) error {

if check.IfNil(rounder) {
Expand All @@ -82,6 +90,9 @@ func checkNewChronologyParams(
if check.IfNil(syncTimer) {
return ErrNilSyncTimer
}
if check.IfNil(watchdog) {
return ErrNilWatchdog
}

return nil
}
Expand Down Expand Up @@ -118,6 +129,9 @@ func (chr *chronology) RemoveAllSubrounds() {

// StartRounds actually starts the chronology and calls the DoWork() method of the subroundHandlers loaded
func (chr *chronology) StartRounds() {
watchdogAlarmDuration := chr.rounder.TimeDuration() * numRoundsToWaitBeforeSignalingChronologyStuck
chr.watchdog.SetDefault(watchdogAlarmDuration, chronologyAlarmID)

var ctx context.Context
ctx, chr.cancelFunc = context.WithCancel(context.Background())
go chr.startRounds(ctx)
Expand Down Expand Up @@ -151,6 +165,8 @@ func (chr *chronology) startRound() {
return
}

chr.watchdog.Reset(chronologyAlarmID)
iulianpascalau marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you move the reset at the beginning of updateRound() maybe where there is a change of round, otherwise for example in BON where we start with negative rounds, there will be a lot of watchdog expiries before round 0 is reached.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


msg := fmt.Sprintf("SUBROUND %s BEGINS", sr.Name())
log.Debug(display.Headline(msg, chr.syncTimer.FormattedCurrentTime(), "."))
logger.SetCorrelationSubround(sr.Name())
Expand Down
34 changes: 34 additions & 0 deletions consensus/chronology/chronology_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ func TestChronology_NewChronologyNilRounderShouldFail(t *testing.T) {
genesisTime,
nil,
syncTimerMock,
&mock.WatchdogMock{},
)

assert.Nil(t, chr)
Expand All @@ -50,12 +51,28 @@ func TestChronology_NewChronologyNilSyncerShouldFail(t *testing.T) {
genesisTime,
rounderMock,
nil,
&mock.WatchdogMock{},
)

assert.Nil(t, chr)
assert.Equal(t, err, chronology.ErrNilSyncTimer)
}

func TestChronology_NewChronologyNilWatchdogShouldFail(t *testing.T) {
t.Parallel()
rounderMock := &mock.RounderMock{}
genesisTime := time.Now()
chr, err := chronology.NewChronology(
genesisTime,
rounderMock,
&mock.SyncTimerMock{},
nil,
)

assert.Nil(t, chr)
assert.Equal(t, err, chronology.ErrNilWatchdog)
}

func TestChronology_NewChronologyShouldWork(t *testing.T) {
t.Parallel()
rounderMock := &mock.RounderMock{}
Expand All @@ -65,6 +82,7 @@ func TestChronology_NewChronologyShouldWork(t *testing.T) {
genesisTime,
rounderMock,
syncTimerMock,
&mock.WatchdogMock{},
)

assert.Nil(t, err)
Expand All @@ -80,6 +98,7 @@ func TestChronology_AddSubroundShouldWork(t *testing.T) {
genesisTime,
rounderMock,
syncTimerMock,
&mock.WatchdogMock{},
)

chr.AddSubround(initSubroundHandlerMock())
Expand All @@ -98,6 +117,7 @@ func TestChronology_RemoveAllSubroundsShouldReturnEmptySubroundHandlersArray(t *
genesisTime,
rounderMock,
syncTimerMock,
&mock.WatchdogMock{},
)

chr.AddSubround(initSubroundHandlerMock())
Expand All @@ -124,6 +144,7 @@ func TestChronology_StartRoundShouldReturnWhenRoundIndexIsNegative(t *testing.T)
genesisTime,
rounderMock,
syncTimerMock,
&mock.WatchdogMock{},
)

srm := initSubroundHandlerMock()
Expand All @@ -143,6 +164,7 @@ func TestChronology_StartRoundShouldReturnWhenLoadSubroundHandlerReturnsNil(t *t
genesisTime,
rounderMock,
syncTimerMock,
&mock.WatchdogMock{},
)

initSubroundHandlerMock()
Expand All @@ -161,6 +183,7 @@ func TestChronology_StartRoundShouldReturnWhenDoWorkReturnsFalse(t *testing.T) {
genesisTime,
rounderMock,
syncTimerMock,
&mock.WatchdogMock{},
)

srm := initSubroundHandlerMock()
Expand All @@ -181,6 +204,7 @@ func TestChronology_StartRoundShouldWork(t *testing.T) {
genesisTime,
rounderMock,
syncTimerMock,
&mock.WatchdogMock{},
)

srm := initSubroundHandlerMock()
Expand All @@ -203,6 +227,7 @@ func TestChronology_UpdateRoundShouldInitRound(t *testing.T) {
genesisTime,
rounderMock,
syncTimerMock,
&mock.WatchdogMock{},
)

srm := initSubroundHandlerMock()
Expand All @@ -221,6 +246,7 @@ func TestChronology_LoadSubrounderShouldReturnNilWhenSubroundHandlerNotExists(t
genesisTime,
rounderMock,
syncTimerMock,
&mock.WatchdogMock{},
)

assert.Nil(t, chr.LoadSubroundHandler(0))
Expand All @@ -235,6 +261,7 @@ func TestChronology_LoadSubrounderShouldReturnNilWhenIndexIsOutOfBound(t *testin
genesisTime,
rounderMock,
syncTimerMock,
&mock.WatchdogMock{},
)

chr.AddSubround(initSubroundHandlerMock())
Expand All @@ -251,6 +278,7 @@ func TestChronology_InitRoundShouldNotSetSubroundWhenRoundIndexIsNegative(t *tes
syncTimerMock.CurrentTime(),
rounderMock,
syncTimerMock,
&mock.WatchdogMock{},
)

chr.AddSubround(initSubroundHandlerMock())
Expand All @@ -274,6 +302,7 @@ func TestChronology_InitRoundShouldSetSubroundWhenRoundIndexIsPositive(t *testin
syncTimerMock.CurrentTime(),
rounderMock,
syncTimerMock,
&mock.WatchdogMock{},
)

sr := initSubroundHandlerMock()
Expand All @@ -291,6 +320,7 @@ func TestChronology_StartRoundShouldNotUpdateRoundWhenCurrentRoundIsNotFinished(
syncTimerMock.CurrentTime(),
rounderMock,
syncTimerMock,
&mock.WatchdogMock{},
)

chr.SetSubroundId(0)
Expand All @@ -308,6 +338,7 @@ func TestChronology_StartRoundShouldUpdateRoundWhenCurrentRoundIsFinished(t *tes
syncTimerMock.CurrentTime(),
rounderMock,
syncTimerMock,
&mock.WatchdogMock{},
)

chr.SetSubroundId(-1)
Expand All @@ -325,6 +356,7 @@ func TestChronology_SetAppStatusHandlerWithNilValueShouldErr(t *testing.T) {
syncTimerMock.CurrentTime(),
rounderMock,
syncTimerMock,
&mock.WatchdogMock{},
)
err := chr.SetAppStatusHandler(nil)

Expand All @@ -340,6 +372,7 @@ func TestChronology_SetAppStatusHandlerWithOkValueShouldPass(t *testing.T) {
syncTimerMock.CurrentTime(),
rounderMock,
syncTimerMock,
&mock.WatchdogMock{},
)

err := chr.SetAppStatusHandler(&mock.AppStatusHandlerMock{})
Expand All @@ -357,6 +390,7 @@ func TestChronology_CheckIfStatusHandlerWorks(t *testing.T) {
syncTimerMock.CurrentTime(),
rounderMock,
syncTimerMock,
&mock.WatchdogMock{},
)

err := chr.SetAppStatusHandler(&mock.AppStatusHandlerStub{
Expand Down
3 changes: 3 additions & 0 deletions consensus/chronology/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,6 @@ var ErrNilSyncTimer = errors.New("sync timer is nil")

// ErrNilAppStatusHandler is raised when the AppStatusHandler is nil when setting it
var ErrNilAppStatusHandler = errors.New("nil AppStatusHandler")

// ErrNilWatchdog signals that a nil watchdog has been provided
var ErrNilWatchdog = errors.New("nil watchdog")
30 changes: 30 additions & 0 deletions consensus/mock/watchdogMock.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package mock

import (
"time"
)

// WatchdogMock -
type WatchdogMock struct {
}

// Set -
func (w *WatchdogMock) Set(callback func(alarmID string), duration time.Duration, alarmID string) {
}

// SetDefault -
func (w *WatchdogMock) SetDefault(duration time.Duration, alarmID string) {
}

// Stop -
func (w *WatchdogMock) Stop(alarmID string) {
}

// Reset -
func (w *WatchdogMock) Reset(alarmID string) {
}

// IsInterfaceNil -
func (w *WatchdogMock) IsInterfaceNil() bool {
return false
}
6 changes: 0 additions & 6 deletions consensus/spos/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,6 @@ var ErrNilPublicKey = errors.New("public key is nil")
// ErrNilPrivateKey is raised when a valid private key was expected but nil was used
var ErrNilPrivateKey = errors.New("private key is nil")

// ErrNilPrevRandSeed is raised when the provided previous random seed is nil
var ErrNilPrevRandSeed = errors.New("previous random seed is nil")

// ErrNilConsensusData is raised when valid consensus data was expected but nil was received
var ErrNilConsensusData = errors.New("consensus data is nil")

Expand Down Expand Up @@ -151,9 +148,6 @@ var ErrNilHeaderHash = errors.New("header hash is nil")
// ErrNilBody is raised when an expected body is nil
var ErrNilBody = errors.New("body is nil")

// ErrInvalidDataToBroadcast is raised when invalid data is set to be broadcast
var ErrInvalidDataToBroadcast = errors.New("data to broadcast is invalid")

// ErrNilMetaHeader is raised when an expected meta header is nil
var ErrNilMetaHeader = errors.New("meta header is nil")

Expand Down
8 changes: 7 additions & 1 deletion consensus/spos/sposFactory/sposFactory.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,13 @@ func GetSubroundsFactory(
) (spos.SubroundsFactory, error) {
switch consensusType {
case blsConsensusType:
subRoundFactoryBls, err := bls.NewSubroundsFactory(consensusDataContainer, consensusState, worker, chainID, currentPid)
subRoundFactoryBls, err := bls.NewSubroundsFactory(
consensusDataContainer,
consensusState,
worker,
chainID,
currentPid,
)
if err != nil {
return nil, err
}
Expand Down
23 changes: 23 additions & 0 deletions core/alarm/alarm.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,29 @@ func (as *alarmScheduler) Close() {
as.cancelFunc()
}

// Reset resets the alarm with the given id
func (as *alarmScheduler) Reset(alarmID string) {
as.mutScheduledAlarms.RLock()
alarm, ok := as.scheduledAlarms[alarmID]
callback := alarm.callback
duration := alarm.initialDuration
as.mutScheduledAlarms.RUnlock()

if !ok {
return
}

evt := alarmEvent{
alarmID: alarmID,
alarm: nil,
event: cancel,
}

as.event <- evt

as.Add(callback, duration, alarmID)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we call Add here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because the alarm was canceled before, so it needs to be readded.

}

// IsInterfaceNil returns true if interface is nil
func (as *alarmScheduler) IsInterfaceNil() bool {
return as == nil
Expand Down