-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[R4R]add sharedStorage for prefetching to L1 #792
Changes from 7 commits
8bccd6f
6626e02
7abd888
57f224a
9a9b231
55349e0
e031e4e
63edb9d
85bd395
a7a785c
8a4dc60
eded677
c8425bf
76dac12
f2f75d7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
package state | ||
|
||
import ( | ||
"github.com/ethereum/go-ethereum/common" | ||
unclezoro marked this conversation as resolved.
Show resolved
Hide resolved
|
||
"sync" | ||
) | ||
|
||
// sharedStorage is used to store maps of originStorage of stateObjects | ||
type SharedStorage struct { | ||
*sync.RWMutex | ||
unclezoro marked this conversation as resolved.
Show resolved
Hide resolved
|
||
sharedMap map[common.Address]*sync.Map | ||
} | ||
|
||
func NewSharedStorage() *SharedStorage { | ||
sharedMap := make(map[common.Address]*sync.Map, 1500) | ||
unclezoro marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return &SharedStorage{ | ||
&sync.RWMutex{}, | ||
sharedMap, | ||
} | ||
} | ||
|
||
// Check whether the storage exist in pool, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would be better to follow the commenting style used in go-ethereum, like, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. updated |
||
// new one if not exist, it will be fetched in stateObjects.GetCommittedState() | ||
func (storage *SharedStorage) getOrInertStorage(address common.Address) *sync.Map { | ||
unclezoro marked this conversation as resolved.
Show resolved
Hide resolved
|
||
storage.RLock() | ||
storageMap, ok := storage.sharedMap[address] | ||
storage.RUnlock() | ||
if !ok { | ||
m := new(sync.Map) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Has race condition. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. updated |
||
storage.Lock() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. concurrent race condition? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes, newObjects called by main preoces or prefetcher will both call this function to check or update the sharedpool |
||
storage.sharedMap[address] = m | ||
storage.Unlock() | ||
return m | ||
} | ||
return storageMap | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,6 +21,7 @@ import ( | |
"fmt" | ||
"io" | ||
"math/big" | ||
"sync" | ||
"time" | ||
|
||
"github.com/ethereum/go-ethereum/common" | ||
|
@@ -79,7 +80,9 @@ type StateObject struct { | |
trie Trie // storage trie, which becomes non-nil on first access | ||
code Code // contract bytecode, which gets set when code is loaded | ||
|
||
originStorage Storage // Storage cache of original entries to dedup rewrites, reset for every transaction | ||
sharedOriginMap *sync.Map // Storage cache of original entries to dedup rewrites, reset for every transaction | ||
unclezoro marked this conversation as resolved.
Show resolved
Hide resolved
|
||
originStorage Storage | ||
|
||
pendingStorage Storage // Storage entries that need to be flushed to disk, at the end of an entire block | ||
dirtyStorage Storage // Storage entries that have been modified in the current transaction execution | ||
fakeStorage Storage // Fake storage which constructed by caller for debugging purpose. | ||
|
@@ -120,14 +123,21 @@ func newObject(db *StateDB, address common.Address, data Account) *StateObject { | |
if data.Root == (common.Hash{}) { | ||
data.Root = emptyRoot | ||
} | ||
var storageMap *sync.Map | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. rename |
||
// Check whether the storage exist in pool, new originStorage if not exist | ||
if db != nil { | ||
storageMap = db.GetOrInsertStorage(address) | ||
} | ||
|
||
return &StateObject{ | ||
db: db, | ||
address: address, | ||
addrHash: crypto.Keccak256Hash(address[:]), | ||
data: data, | ||
originStorage: make(Storage), | ||
pendingStorage: make(Storage), | ||
dirtyStorage: make(Storage), | ||
db: db, | ||
address: address, | ||
addrHash: crypto.Keccak256Hash(address[:]), | ||
data: data, | ||
sharedOriginMap: storageMap, | ||
originStorage: make(Storage), | ||
pendingStorage: make(Storage), | ||
dirtyStorage: make(Storage), | ||
} | ||
} | ||
|
||
|
@@ -194,6 +204,25 @@ func (s *StateObject) GetState(db Database, key common.Hash) common.Hash { | |
return s.GetCommittedState(db, key) | ||
} | ||
|
||
func (s *StateObject) getStorageKey(key common.Hash) (common.Hash, bool) { | ||
unclezoro marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if value, cached := s.originStorage[key]; cached { | ||
return value, true | ||
} | ||
// if L1 cache miss, try to get it from shared pool | ||
val, ok := s.sharedOriginMap.Load(key) | ||
if !ok { | ||
return common.HexToHash(""), false | ||
unclezoro marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
return val.(common.Hash), ok | ||
} | ||
|
||
func (s *StateObject) setStorgeKey(key common.Hash, value common.Hash) { | ||
unclezoro marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if s.db.isPrefetchDb { | ||
unclezoro marked this conversation as resolved.
Show resolved
Hide resolved
|
||
s.sharedOriginMap.Store(key, value) | ||
} | ||
s.originStorage[key] = value | ||
} | ||
|
||
// GetCommittedState retrieves a value from the committed account storage trie. | ||
func (s *StateObject) GetCommittedState(db Database, key common.Hash) common.Hash { | ||
// If the fake storage is set, only lookup the state here(in the debugging mode) | ||
|
@@ -204,7 +233,8 @@ func (s *StateObject) GetCommittedState(db Database, key common.Hash) common.Has | |
if value, pending := s.pendingStorage[key]; pending { | ||
return value | ||
} | ||
if value, cached := s.originStorage[key]; cached { | ||
|
||
if value, cached := s.getStorageKey(key); cached { | ||
return value | ||
} | ||
// If no live objects are available, attempt to use snapshots | ||
|
@@ -263,7 +293,7 @@ func (s *StateObject) GetCommittedState(db Database, key common.Hash) common.Has | |
} | ||
value.SetBytes(content) | ||
} | ||
s.originStorage[key] = value | ||
s.setStorgeKey(key, value) | ||
return value | ||
} | ||
|
||
|
@@ -316,7 +346,11 @@ func (s *StateObject) finalise(prefetch bool) { | |
slotsToPrefetch := make([][]byte, 0, len(s.dirtyStorage)) | ||
for key, value := range s.dirtyStorage { | ||
s.pendingStorage[key] = value | ||
if value != s.originStorage[key] { | ||
} | ||
|
||
for key, value := range s.dirtyStorage { | ||
originValue, cached := s.getStorageKey(key) | ||
if cached && value != originValue { | ||
unclezoro marked this conversation as resolved.
Show resolved
Hide resolved
|
||
slotsToPrefetch = append(slotsToPrefetch, common.CopyBytes(key[:])) // Copy needed for closure | ||
} | ||
} | ||
|
@@ -352,10 +386,11 @@ func (s *StateObject) updateTrie(db Database) Trie { | |
usedStorage := make([][]byte, 0, len(s.pendingStorage)) | ||
for key, value := range s.pendingStorage { | ||
// Skip noop changes, persist actual changes | ||
if value == s.originStorage[key] { | ||
originValue, cached := s.getStorageKey(key) | ||
if cached && value == originValue { | ||
unclezoro marked this conversation as resolved.
Show resolved
Hide resolved
|
||
continue | ||
} | ||
s.originStorage[key] = value | ||
s.setStorgeKey(key, value) | ||
|
||
var v []byte | ||
if (value == common.Hash{}) { | ||
|
@@ -478,7 +513,6 @@ func (s *StateObject) deepCopy(db *StateDB) *StateObject { | |
} | ||
stateObject.code = s.code | ||
stateObject.dirtyStorage = s.dirtyStorage.Copy() | ||
stateObject.originStorage = s.originStorage.Copy() | ||
unclezoro marked this conversation as resolved.
Show resolved
Hide resolved
|
||
stateObject.pendingStorage = s.pendingStorage.Copy() | ||
stateObject.suicided = s.suicided | ||
stateObject.dirtyCode = s.dirtyCode | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about rename the file with:
shared_storage_pool.go
,shared_pool.go
is a bit confusing, shared what?