Skip to content

Commit 801a25e

Browse files
authored
Merge pull request #183 from vulcanize/port_retry
port retry on deadlock detection feature
2 parents 68f2390 + 488309b commit 801a25e

File tree

1 file changed

+28
-6
lines changed

1 file changed

+28
-6
lines changed

statediff/service.go

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import (
2020
"bytes"
2121
"math/big"
2222
"strconv"
23+
"strings"
2324
"sync"
2425
"sync/atomic"
2526
"time"
@@ -46,8 +47,12 @@ import (
4647
types2 "github.com/ethereum/go-ethereum/statediff/types"
4748
)
4849

49-
const chainEventChanSize = 20000
50-
const genesisBlockNumber = 0
50+
const (
51+
chainEventChanSize = 20000
52+
genesisBlockNumber = 0
53+
defaultRetryLimit = 3 // default retry limit once deadlock is detected.
54+
deadlockDetected = "deadlock detected" // 40P01 https://www.postgresql.org/docs/current/errcodes-appendix.html
55+
)
5156

5257
var writeLoopParams = Params{
5358
IntermediateStateNodes: true,
@@ -122,6 +127,8 @@ type Service struct {
122127
enableWriteLoop bool
123128
// Size of the worker pool
124129
numWorkers uint
130+
// Number of retry for aborted transactions due to deadlock.
131+
maxRetry uint
125132
}
126133

127134
// BlockCache caches the last block for safe access from different service loops
@@ -174,6 +181,7 @@ func New(stack *node.Node, ethServ *eth.Ethereum, cfg *ethconfig.Config, params
174181
indexer: indexer,
175182
enableWriteLoop: params.EnableWriteLoop,
176183
numWorkers: workers,
184+
maxRetry: defaultRetryLimit,
177185
}
178186
stack.RegisterLifecycle(sds)
179187
stack.RegisterAPIs(sds.APIs())
@@ -266,7 +274,7 @@ func (sds *Service) WriteLoop(chainEventCh chan core.ChainEvent) {
266274
func (sds *Service) writeGenesisStateDiff(currBlock *types.Block, workerId uint) {
267275
// For genesis block we need to return the entire state trie hence we diff it with an empty trie.
268276
log.Info("Writing state diff", "block height", genesisBlockNumber, "worker", workerId)
269-
err := sds.writeStateDiff(currBlock, common.Hash{}, writeLoopParams)
277+
err := sds.writeStateDiffWithRetry(currBlock, common.Hash{}, writeLoopParams)
270278
if err != nil {
271279
log.Error("statediff.Service.WriteLoop: processing error", "block height",
272280
genesisBlockNumber, "error", err.Error(), "worker", workerId)
@@ -295,7 +303,7 @@ func (sds *Service) writeLoopWorker(params workerParams) {
295303
}
296304

297305
log.Info("Writing state diff", "block height", currentBlock.Number().Uint64(), "worker", params.id)
298-
err := sds.writeStateDiff(currentBlock, parentBlock.Root(), writeLoopParams)
306+
err := sds.writeStateDiffWithRetry(currentBlock, parentBlock.Root(), writeLoopParams)
299307
if err != nil {
300308
log.Error("statediff.Service.WriteLoop: processing error", "block height", currentBlock.Number().Uint64(), "error", err.Error(), "worker", params.id)
301309
continue
@@ -632,7 +640,7 @@ func (sds *Service) WriteStateDiffAt(blockNumber uint64, params Params) error {
632640
parentBlock := sds.BlockChain.GetBlockByHash(currentBlock.ParentHash())
633641
parentRoot = parentBlock.Root()
634642
}
635-
return sds.writeStateDiff(currentBlock, parentRoot, params)
643+
return sds.writeStateDiffWithRetry(currentBlock, parentRoot, params)
636644
}
637645

638646
// WriteStateDiffFor writes a state diff for the specific blockhash directly to the database
@@ -645,7 +653,7 @@ func (sds *Service) WriteStateDiffFor(blockHash common.Hash, params Params) erro
645653
parentBlock := sds.BlockChain.GetBlockByHash(currentBlock.ParentHash())
646654
parentRoot = parentBlock.Root()
647655
}
648-
return sds.writeStateDiff(currentBlock, parentRoot, params)
656+
return sds.writeStateDiffWithRetry(currentBlock, parentRoot, params)
649657
}
650658

651659
// Writes a state diff from the current block, parent state root, and provided params
@@ -689,3 +697,17 @@ func (sds *Service) writeStateDiff(block *types.Block, parentRoot common.Hash, p
689697
}
690698
return nil
691699
}
700+
701+
// Wrapper function on writeStateDiff to retry when the deadlock is detected.
702+
func (sds *Service) writeStateDiffWithRetry(block *types.Block, parentRoot common.Hash, params Params) error {
703+
var err error
704+
for i := uint(0); i < sds.maxRetry; i++ {
705+
err = sds.writeStateDiff(block, parentRoot, params)
706+
if err != nil && strings.Contains(err.Error(), deadlockDetected) {
707+
// Retry only when the deadlock is detected.
708+
continue
709+
}
710+
break
711+
}
712+
return err
713+
}

0 commit comments

Comments
 (0)