Commit f8323757 authored by Martin Holst Swende's avatar Martin Holst Swende Committed by Péter Szilágyi

core: make current*Block atomic, and accessor functions mutex-free (#16171)

* core: make current*Block atomic, and accessor functions mutex-free

* core: fix review concerns

* core: fix error in atomic assignment

* core/light: implement atomic getter/setter for headerchain
parent d398d04e
This diff is collapsed.
...@@ -32,6 +32,7 @@ import ( ...@@ -32,6 +32,7 @@ import (
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/hashicorp/golang-lru" "github.com/hashicorp/golang-lru"
"sync/atomic"
) )
const ( const (
...@@ -51,8 +52,8 @@ type HeaderChain struct { ...@@ -51,8 +52,8 @@ type HeaderChain struct {
chainDb ethdb.Database chainDb ethdb.Database
genesisHeader *types.Header genesisHeader *types.Header
currentHeader *types.Header // Current head of the header chain (may be above the block chain!) currentHeader atomic.Value // Current head of the header chain (may be above the block chain!)
currentHeaderHash common.Hash // Hash of the current head of the header chain (prevent recomputing all the time) currentHeaderHash common.Hash // Hash of the current head of the header chain (prevent recomputing all the time)
headerCache *lru.Cache // Cache for the most recent block headers headerCache *lru.Cache // Cache for the most recent block headers
tdCache *lru.Cache // Cache for the most recent block total difficulties tdCache *lru.Cache // Cache for the most recent block total difficulties
...@@ -95,13 +96,13 @@ func NewHeaderChain(chainDb ethdb.Database, config *params.ChainConfig, engine c ...@@ -95,13 +96,13 @@ func NewHeaderChain(chainDb ethdb.Database, config *params.ChainConfig, engine c
return nil, ErrNoGenesis return nil, ErrNoGenesis
} }
hc.currentHeader = hc.genesisHeader hc.currentHeader.Store(hc.genesisHeader)
if head := GetHeadBlockHash(chainDb); head != (common.Hash{}) { if head := GetHeadBlockHash(chainDb); head != (common.Hash{}) {
if chead := hc.GetHeaderByHash(head); chead != nil { if chead := hc.GetHeaderByHash(head); chead != nil {
hc.currentHeader = chead hc.currentHeader.Store(chead)
} }
} }
hc.currentHeaderHash = hc.currentHeader.Hash() hc.currentHeaderHash = hc.CurrentHeader().Hash()
return hc, nil return hc, nil
} }
...@@ -139,7 +140,7 @@ func (hc *HeaderChain) WriteHeader(header *types.Header) (status WriteStatus, er ...@@ -139,7 +140,7 @@ func (hc *HeaderChain) WriteHeader(header *types.Header) (status WriteStatus, er
if ptd == nil { if ptd == nil {
return NonStatTy, consensus.ErrUnknownAncestor return NonStatTy, consensus.ErrUnknownAncestor
} }
localTd := hc.GetTd(hc.currentHeaderHash, hc.currentHeader.Number.Uint64()) localTd := hc.GetTd(hc.currentHeaderHash, hc.CurrentHeader().Number.Uint64())
externTd := new(big.Int).Add(header.Difficulty, ptd) externTd := new(big.Int).Add(header.Difficulty, ptd)
// Irrelevant of the canonical status, write the td and header to the database // Irrelevant of the canonical status, write the td and header to the database
...@@ -181,7 +182,8 @@ func (hc *HeaderChain) WriteHeader(header *types.Header) (status WriteStatus, er ...@@ -181,7 +182,8 @@ func (hc *HeaderChain) WriteHeader(header *types.Header) (status WriteStatus, er
if err := WriteHeadHeaderHash(hc.chainDb, hash); err != nil { if err := WriteHeadHeaderHash(hc.chainDb, hash); err != nil {
log.Crit("Failed to insert head header hash", "err", err) log.Crit("Failed to insert head header hash", "err", err)
} }
hc.currentHeaderHash, hc.currentHeader = hash, types.CopyHeader(header) hc.currentHeaderHash = hash
hc.currentHeader.Store(types.CopyHeader(header))
status = CanonStatTy status = CanonStatTy
} else { } else {
...@@ -383,7 +385,7 @@ func (hc *HeaderChain) GetHeaderByNumber(number uint64) *types.Header { ...@@ -383,7 +385,7 @@ func (hc *HeaderChain) GetHeaderByNumber(number uint64) *types.Header {
// CurrentHeader retrieves the current head header of the canonical chain. The // CurrentHeader retrieves the current head header of the canonical chain. The
// header is retrieved from the HeaderChain's internal cache. // header is retrieved from the HeaderChain's internal cache.
func (hc *HeaderChain) CurrentHeader() *types.Header { func (hc *HeaderChain) CurrentHeader() *types.Header {
return hc.currentHeader return hc.currentHeader.Load().(*types.Header)
} }
// SetCurrentHeader sets the current head header of the canonical chain. // SetCurrentHeader sets the current head header of the canonical chain.
...@@ -391,7 +393,7 @@ func (hc *HeaderChain) SetCurrentHeader(head *types.Header) { ...@@ -391,7 +393,7 @@ func (hc *HeaderChain) SetCurrentHeader(head *types.Header) {
if err := WriteHeadHeaderHash(hc.chainDb, head.Hash()); err != nil { if err := WriteHeadHeaderHash(hc.chainDb, head.Hash()); err != nil {
log.Crit("Failed to insert head header hash", "err", err) log.Crit("Failed to insert head header hash", "err", err)
} }
hc.currentHeader = head hc.currentHeader.Store(head)
hc.currentHeaderHash = head.Hash() hc.currentHeaderHash = head.Hash()
} }
...@@ -403,19 +405,20 @@ type DeleteCallback func(common.Hash, uint64) ...@@ -403,19 +405,20 @@ type DeleteCallback func(common.Hash, uint64)
// will be deleted and the new one set. // will be deleted and the new one set.
func (hc *HeaderChain) SetHead(head uint64, delFn DeleteCallback) { func (hc *HeaderChain) SetHead(head uint64, delFn DeleteCallback) {
height := uint64(0) height := uint64(0)
if hc.currentHeader != nil {
height = hc.currentHeader.Number.Uint64() if hdr := hc.CurrentHeader(); hdr != nil {
height = hdr.Number.Uint64()
} }
for hc.currentHeader != nil && hc.currentHeader.Number.Uint64() > head { for hdr := hc.CurrentHeader(); hdr != nil && hdr.Number.Uint64() > head; hdr = hc.CurrentHeader() {
hash := hc.currentHeader.Hash() hash := hdr.Hash()
num := hc.currentHeader.Number.Uint64() num := hdr.Number.Uint64()
if delFn != nil { if delFn != nil {
delFn(hash, num) delFn(hash, num)
} }
DeleteHeader(hc.chainDb, hash, num) DeleteHeader(hc.chainDb, hash, num)
DeleteTd(hc.chainDb, hash, num) DeleteTd(hc.chainDb, hash, num)
hc.currentHeader = hc.GetHeader(hc.currentHeader.ParentHash, hc.currentHeader.Number.Uint64()-1) hc.currentHeader.Store(hc.GetHeader(hdr.ParentHash, hdr.Number.Uint64()-1))
} }
// Roll back the canonical chain numbering // Roll back the canonical chain numbering
for i := height; i > head; i-- { for i := height; i > head; i-- {
...@@ -426,10 +429,10 @@ func (hc *HeaderChain) SetHead(head uint64, delFn DeleteCallback) { ...@@ -426,10 +429,10 @@ func (hc *HeaderChain) SetHead(head uint64, delFn DeleteCallback) {
hc.tdCache.Purge() hc.tdCache.Purge()
hc.numberCache.Purge() hc.numberCache.Purge()
if hc.currentHeader == nil { if hc.CurrentHeader() == nil {
hc.currentHeader = hc.genesisHeader hc.currentHeader.Store(hc.genesisHeader)
} }
hc.currentHeaderHash = hc.currentHeader.Hash() hc.currentHeaderHash = hc.CurrentHeader().Hash()
if err := WriteHeadHeaderHash(hc.chainDb, hc.currentHeaderHash); err != nil { if err := WriteHeadHeaderHash(hc.chainDb, hc.currentHeaderHash); err != nil {
log.Crit("Failed to reset head header hash", "err", err) log.Crit("Failed to reset head header hash", "err", err)
......
...@@ -171,9 +171,6 @@ func (bc *LightChain) SetHead(head uint64) { ...@@ -171,9 +171,6 @@ func (bc *LightChain) SetHead(head uint64) {
// GasLimit returns the gas limit of the current HEAD block. // GasLimit returns the gas limit of the current HEAD block.
func (self *LightChain) GasLimit() uint64 { func (self *LightChain) GasLimit() uint64 {
self.mu.RLock()
defer self.mu.RUnlock()
return self.hc.CurrentHeader().GasLimit return self.hc.CurrentHeader().GasLimit
} }
...@@ -387,9 +384,6 @@ func (self *LightChain) InsertHeaderChain(chain []*types.Header, checkFreq int) ...@@ -387,9 +384,6 @@ func (self *LightChain) InsertHeaderChain(chain []*types.Header, checkFreq int)
// CurrentHeader retrieves the current head header of the canonical chain. The // CurrentHeader retrieves the current head header of the canonical chain. The
// header is retrieved from the HeaderChain's internal cache. // header is retrieved from the HeaderChain's internal cache.
func (self *LightChain) CurrentHeader() *types.Header { func (self *LightChain) CurrentHeader() *types.Header {
self.mu.RLock()
defer self.mu.RUnlock()
return self.hc.CurrentHeader() return self.hc.CurrentHeader()
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment