erigon-pulse/core/state/cached_reader.go
ledgerwatch 5ea590c18e
State cache switching writes to reads during commit (#1368)
* State cache init

* More code

* Fix lint

* More tests

* More tests

* More tests

* Fix test

* Transformations

* remove writeQueue, before fixing the tests

* Fix tests

* Add more tests, incarnation to the code items

* Fix lint

* Fix lint

* Remove shards prototype, add incarnation to the state reader code

* Clean up and replace cache in call_traces stage

* fix flaky test

* Save changes

* Readers to use addrHash, writes - addresses

* Fix lint

* Fix lint

* More accurate tracking of size

* Optimise for smaller write batches

* Attempt to integrate state cache into Execution stage

* cacheSize to default flags

* Print correct cache sizes and batch sizes

* cacheSize in the integration

* Fix tests

* Fix lint

* Remove print

* Fix exec stage

* Fix test

* Refresh sequence on write

* No double increment

* heap.Remove

* Try to fix alignment

* Refactoring, adding hashItems

* More changes

* Fix compile errors

* Fix lint

* Wrapping cached reader

* Wrap writer into cached writer

* Turn state cache off by default

* Fix plain state writer

* Fix for code/storage mixup

* Fix tests

* Fix clique test

* Better fix for the tests

* Add test and fix some more

* Fix compile error|

* More functions

* Fixes

* Fix for the tests

* sepatate DeletedFlag and AbsentFlag

* Minor fixes

* Test refactoring

* More changes

* Fix some tests

* More test fixes

* More test fixes

* Fix lint

* Move blockchain_test to be able to use stagedsync

* More fixes

* Fixes and cleanup

* Fix tests in turbo/stages

* Fix lint

* Fix lint

* Intemediate

* Fix tests

* Intemediate

* More fixes

* Compilation fixes

* More fixes

* Fix compile errors

* More test fixes

* More fixes

* More test fixes

* Fix compile error

* Fixes

* Fix

* Fix

* More fixes

* Fixes

* More fixes and cleanup

* Further fix

* Check gas used and bloom with header

Co-authored-by: Alexey Sharp <alexeysharp@Alexeys-iMac.local>
2020-12-08 09:44:29 +00:00

89 lines
2.9 KiB
Go

package state
import (
"bytes"
"github.com/ledgerwatch/turbo-geth/common"
"github.com/ledgerwatch/turbo-geth/core/types/accounts"
"github.com/ledgerwatch/turbo-geth/turbo/shards"
)
// CachedReader is a wrapper for an instance of type StateReader
// This wrapper only makes calls to the underlying reader if the item is not in the cache
type CachedReader struct {
r StateReader
cache *shards.StateCache
}
// NewCachedReader wraps a given state reader into the cached reader
func NewCachedReader(r StateReader, cache *shards.StateCache) *CachedReader {
return &CachedReader{r: r, cache: cache}
}
// ReadAccountData is called when an account needs to be fetched from the state
func (cr *CachedReader) ReadAccountData(address common.Address) (*accounts.Account, error) {
if a, ok := cr.cache.GetAccount(address.Bytes()); ok {
return a, nil
}
a, err := cr.r.ReadAccountData(address)
if err != nil {
return nil, err
}
if a == nil {
cr.cache.SetAccountAbsent(address.Bytes())
} else {
cr.cache.SetAccountRead(address.Bytes(), a)
}
return a, nil
}
// ReadAccountStorage is called when a storage item needs to be fetched from the state
func (cr *CachedReader) ReadAccountStorage(address common.Address, incarnation uint64, key *common.Hash) ([]byte, error) {
if s, ok := cr.cache.GetStorage(address.Bytes(), incarnation, key.Bytes()); ok {
return s, nil
}
v, err := cr.r.ReadAccountStorage(address, incarnation, key)
if err != nil {
return nil, err
}
if len(v) == 0 {
cr.cache.SetStorageAbsent(address.Bytes(), incarnation, key.Bytes())
} else {
cr.cache.SetStorageRead(address.Bytes(), incarnation, key.Bytes(), v)
}
return v, nil
}
// ReadAccountCode is called when code of an account needs to be fetched from the state
// Usually, one of (address;incarnation) or codeHash is enough to uniquely identify the code
func (cr *CachedReader) ReadAccountCode(address common.Address, incarnation uint64, codeHash common.Hash) ([]byte, error) {
if bytes.Equal(codeHash[:], emptyCodeHash) {
return nil, nil
}
if c, ok := cr.cache.GetCode(address.Bytes(), incarnation); ok {
return c, nil
}
c, err := cr.r.ReadAccountCode(address, incarnation, codeHash)
if err != nil {
return nil, err
}
if cr.cache != nil && len(c) <= 1024 {
cr.cache.SetCodeRead(address.Bytes(), incarnation, c)
}
return c, nil
}
func (cr *CachedReader) ReadAccountCodeSize(address common.Address, incarnation uint64, codeHash common.Hash) (int, error) {
c, err := cr.ReadAccountCode(address, incarnation, codeHash)
return len(c), err
}
// ReadAccountIncarnation is called when incarnation of the account is required (to create and recreate contract)
func (cr *CachedReader) ReadAccountIncarnation(address common.Address) (uint64, error) {
deleted := cr.cache.GetDeletedAccount(address.Bytes())
if deleted != nil {
return deleted.Incarnation, nil
}
return cr.r.ReadAccountIncarnation(address)
}