@@ -61,6 +61,10 @@ const (
6161 // maxInFlightRounds is the maximum number of rounds that should be fetched before waiting
6262 // for them to be applied.
6363 maxInFlightRounds = 100
64+
65+ // maxNonFinalizedRoots is the maximum number of allowed non-finalized roots.
66+ // It should be set lower than the limit configured by the underlying node database.
67+ maxNonFinalizedRoots = 1000
6468)
6569
6670type roundItem interface {
@@ -1101,22 +1105,21 @@ func (n *Node) worker() { // nolint: gocyclo
11011105 pendingApply := & minRoundPQ {}
11021106 pendingFinalize := & minRoundPQ {}
11031107
1104- // Main processing loop. When a new block comes in, its state and io roots are inspected and their
1105- // writelogs fetched from peers in case we don't have them locally yet. Fetches are
1106- // asynchronous and, once complete, trigger local Apply operations. These are serialized
1107- // per round (all applies for a given round have to be complete before applying anything for following
1108- // rounds) using the fetched diffs and pending finalization priority queue. Once a round has all its write
1109- // logs applied, a Finalize for it is triggered, again serialized by round but otherwise asynchronous
1110- // (pendingFinalization and cachedLastRound).
1108+ // Main processing loop. When a new block arrives, its state and I/O roots are inspected.
1109+ // If missing locally, diffs are fetched from peers, possibly for many rounds in parallel,
1110+ // including all missing rounds since the last fully applied one. Fetched diffs are then applied
1111+ // in round order, ensuring no gaps. Once a round has all its roots applied, background finalization
1112+ // for that round is triggered asynchronously, not blocking concurrent fetching and diff application.
11111113mainLoop:
11121114 for {
1113- // Drain the Apply and Finalize queues first, before waiting for new events in the select
1114- // below. Applies are drained first, followed by finalizations (which are asynchronous
1115- // but serialized, i.e. only one Finalize can be in progress at a time).
1116-
1117- // Apply any writelogs that came in through fetchDiff, but only if they are for the round
1118- // after the last fully applied one (lastFullyAppliedRound).
1119- if len (* pendingApply ) > 0 && lastFullyAppliedRound + 1 == (* pendingApply )[0 ].GetRound () {
1115+ // Drain the Apply and Finalize queues first, before waiting for new events in the select below.
1116+
1117+ // Apply fetched writelogs, but only if they are for the round after the last fully applied one
1118+ // and current number of pending roots to be finalized is smaller than max allowed.
1119+ applyNext := pendingApply .Len () > 0 &&
1120+ lastFullyAppliedRound + 1 == (* pendingApply )[0 ].GetRound () &&
1121+ pendingFinalize .Len () < maxNonFinalizedRoots - 1 // -1 since one may be finalizing (popped already)
1122+ if applyNext {
11201123 lastDiff := heap .Pop (pendingApply ).(* fetchedDiff )
11211124 // Apply the write log if one exists.
11221125 err = nil
@@ -1173,15 +1176,13 @@ mainLoop:
11731176 continue
11741177 }
11751178
1176- // Check if any new rounds were fully applied and need to be finalized. Only finalize
1177- // if it's the round after the one that was finalized last (cachedLastRound).
1178- // The finalization happens asynchronously with respect to this worker loop and any
1179- // applies that happen for subsequent rounds (which can proceed while earlier rounds are
1180- // still finalizing).
1179+ // Check if any new rounds were fully applied and need to be finalized.
1180+ // Only finalize if it's the round after the one that was finalized last.
1181+ // As a consequence at most one finalization can be happening at the time.
11811182 if len (* pendingFinalize ) > 0 && cachedLastRound + 1 == (* pendingFinalize )[0 ].GetRound () {
11821183 lastSummary := heap .Pop (pendingFinalize ).(* blockSummary )
11831184 wg .Add (1 )
1184- go func () {
1185+ go func () { // don't block fetching and applying remaining rounds.
11851186 defer wg .Done ()
11861187 n .finalize (lastSummary )
11871188 }()
0 commit comments