mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-19 19:30:44 +00:00
core/state: rework state reader
This commit is contained in:
parent
b67888ab97
commit
6da4960306
1 changed files with 32 additions and 16 deletions
|
|
@ -382,30 +382,44 @@ func (r *multiStateReader) Storage(addr common.Address, slot common.Hash) (commo
|
||||||
return common.Hash{}, errors.Join(errs...)
|
return common.Hash{}, errors.Join(errs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const stateReaderCacheBuckets = 64
|
||||||
|
|
||||||
// stateReaderWithCache is a wrapper around StateReader that maintains additional
|
// stateReaderWithCache is a wrapper around StateReader that maintains additional
|
||||||
// state caches to support concurrent state access.
|
// state caches to support concurrent state access.
|
||||||
type stateReaderWithCache struct {
|
type stateReaderWithCache struct {
|
||||||
StateReader
|
StateReader
|
||||||
|
|
||||||
// Previously resolved state entries.
|
// Account buckets are selected by account address. This reader is typically
|
||||||
accounts map[common.Address]*types.StateAccount
|
// used in scenarios requiring concurrent access to accounts; multiple buckets
|
||||||
accountLock sync.RWMutex
|
// reduce lock contention.
|
||||||
|
accountBuckets [stateReaderCacheBuckets]struct {
|
||||||
|
lock sync.RWMutex
|
||||||
|
accounts map[common.Address]*types.StateAccount
|
||||||
|
}
|
||||||
|
|
||||||
// List of storage buckets, each of which is thread-safe.
|
// Storage buckets are selected by both account address and storage key. This
|
||||||
// This reader is typically used in scenarios requiring concurrent
|
// avoids serializing accesses to distinct slots of the same account.
|
||||||
// access to storage. Using multiple buckets helps mitigate
|
storageBuckets [stateReaderCacheBuckets]struct {
|
||||||
// the overhead caused by locking.
|
|
||||||
storageBuckets [16]struct {
|
|
||||||
lock sync.RWMutex
|
lock sync.RWMutex
|
||||||
storages map[common.Address]map[common.Hash]common.Hash
|
storages map[common.Address]map[common.Hash]common.Hash
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func accountCacheBucket(addr common.Address) int {
|
||||||
|
return int(addr[0] & (stateReaderCacheBuckets - 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
func storageCacheBucket(addr common.Address, slot common.Hash) int {
|
||||||
|
return int((addr[0] ^ slot[0] ^ slot[len(slot)-1]) & (stateReaderCacheBuckets - 1))
|
||||||
|
}
|
||||||
|
|
||||||
// newStateReaderWithCache constructs the state reader with local cache.
|
// newStateReaderWithCache constructs the state reader with local cache.
|
||||||
func newStateReaderWithCache(sr StateReader) *stateReaderWithCache {
|
func newStateReaderWithCache(sr StateReader) *stateReaderWithCache {
|
||||||
r := &stateReaderWithCache{
|
r := &stateReaderWithCache{
|
||||||
StateReader: sr,
|
StateReader: sr,
|
||||||
accounts: make(map[common.Address]*types.StateAccount),
|
}
|
||||||
|
for i := range r.accountBuckets {
|
||||||
|
r.accountBuckets[i].accounts = make(map[common.Address]*types.StateAccount)
|
||||||
}
|
}
|
||||||
for i := range r.storageBuckets {
|
for i := range r.storageBuckets {
|
||||||
r.storageBuckets[i].storages = make(map[common.Address]map[common.Hash]common.Hash)
|
r.storageBuckets[i].storages = make(map[common.Address]map[common.Hash]common.Hash)
|
||||||
|
|
@ -419,10 +433,12 @@ func newStateReaderWithCache(sr StateReader) *stateReaderWithCache {
|
||||||
//
|
//
|
||||||
// An error will be returned if the state is corrupted in the underlying reader.
|
// An error will be returned if the state is corrupted in the underlying reader.
|
||||||
func (r *stateReaderWithCache) account(addr common.Address) (*types.StateAccount, bool, error) {
|
func (r *stateReaderWithCache) account(addr common.Address) (*types.StateAccount, bool, error) {
|
||||||
|
bucket := &r.accountBuckets[accountCacheBucket(addr)]
|
||||||
|
|
||||||
// Try to resolve the requested account in the local cache
|
// Try to resolve the requested account in the local cache
|
||||||
r.accountLock.RLock()
|
bucket.lock.RLock()
|
||||||
acct, ok := r.accounts[addr]
|
acct, ok := bucket.accounts[addr]
|
||||||
r.accountLock.RUnlock()
|
bucket.lock.RUnlock()
|
||||||
if ok {
|
if ok {
|
||||||
return acct, true, nil
|
return acct, true, nil
|
||||||
}
|
}
|
||||||
|
|
@ -431,9 +447,9 @@ func (r *stateReaderWithCache) account(addr common.Address) (*types.StateAccount
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
r.accountLock.Lock()
|
bucket.lock.Lock()
|
||||||
r.accounts[addr] = acct
|
bucket.accounts[addr] = acct
|
||||||
r.accountLock.Unlock()
|
bucket.lock.Unlock()
|
||||||
return acct, false, nil
|
return acct, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -453,7 +469,7 @@ func (r *stateReaderWithCache) storage(addr common.Address, slot common.Hash) (c
|
||||||
var (
|
var (
|
||||||
value common.Hash
|
value common.Hash
|
||||||
ok bool
|
ok bool
|
||||||
bucket = &r.storageBuckets[addr[0]&0x0f]
|
bucket = &r.storageBuckets[storageCacheBucket(addr, slot)]
|
||||||
)
|
)
|
||||||
// Try to resolve the requested storage slot in the local cache
|
// Try to resolve the requested storage slot in the local cache
|
||||||
bucket.lock.RLock()
|
bucket.lock.RLock()
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue