diff --git a/core/state/reader.go b/core/state/reader.go index de7d6b3bce..2c679c53fd 100644 --- a/core/state/reader.go +++ b/core/state/reader.go @@ -419,19 +419,25 @@ func (r *trieReader) subTrieConcurrent(addr common.Address) (Trie, error) { if v, ok := r.subTries.Load(addr); ok { return v.(Trie), nil } + // Optimize: serialize creation to avoid speculative allocation storms on cache misses. + r.lock.Lock() + defer r.lock.Unlock() + + if v, ok := r.subTries.Load(addr); ok { + return v.(Trie), nil + } + root, err := r.resolveSubRoot(addr) if err != nil { return nil, err } + newTr, err := trie.NewStateTrie(trie.StorageTrieID(r.root, crypto.Keccak256Hash(addr.Bytes()), root), r.db) if err != nil { return nil, err } newTr.EnableConcurrentReads() - // First-writer-wins: another goroutine may have created it. - if existing, loaded := r.subTries.LoadOrStore(addr, newTr); loaded { - return existing.(Trie), nil - } + r.subTries.Store(addr, newTr) return newTr, nil } @@ -587,8 +593,8 @@ type readerWithCache struct { } // newReaderWithCache constructs the reader with local cache. -func newReaderWithCache(reader Reader) *readerWithCache { - return &readerWithCache{ +func newReaderWithCache(reader Reader) *readerWithcache { + return &readerWithcache{ Reader: reader, } } @@ -601,7 +607,7 @@ func newReaderWithCache(reader Reader) *readerWithCache { // // It also returns the cache entry (for provenance/unique-usage accounting) // and whether this call inserted a new entry (first-writer-wins). -func (r *readerWithCache) account(addr common.Address, caller readerRole) (*types.StateAccount, bool, *accountCacheEntry, bool, error) { +func (r *readerWithcache) account(addr common.Address, caller readerRole) (*types.StateAccount, bool, *accountCacheEntry, bool, error) { // Try to resolve the requested account in the local cache (lock-free read). if v, ok := r.accounts.Load(addr); ok { ent := v.(*accountCacheEntry) @@ -627,7 +633,7 @@ func (r *readerWithCache) account(addr common.Address, caller readerRole) (*type // The returned account might be nil if it's not existent. // // An error will be returned if the state is corrupted in the underlying reader. -func (r *readerWithCache) Account(addr common.Address) (*types.StateAccount, error) { +func (r *readerWithcache) Account(addr common.Address) (*types.StateAccount, error) { account, _, _, _, err := r.account(addr, roleUnknown) return account, err } @@ -638,7 +644,7 @@ func (r *readerWithCache) Account(addr common.Address) (*types.StateAccount, err // // It also returns the cache entry (for provenance/unique-usage accounting) // and whether this call inserted a new entry (first-writer-wins). -func (r *readerWithCache) storage(addr common.Address, slot common.Hash, caller readerRole) (common.Hash, bool, *storageCacheEntry, bool, error) { +func (r *readerWithcache) storage(addr common.Address, slot common.Hash, caller readerRole) (common.Hash, bool, *storageCacheEntry, bool, error) { key := storageKey{addr: addr, slot: slot} // Try to resolve the requested storage slot in the local cache (lock-free read). @@ -667,13 +673,13 @@ func (r *readerWithCache) storage(addr common.Address, slot common.Hash, caller // existent. // // An error will be returned if the state is corrupted in the underlying reader. -func (r *readerWithCache) Storage(addr common.Address, slot common.Hash) (common.Hash, error) { +func (r *readerWithcache) Storage(addr common.Address, slot common.Hash) (common.Hash, error) { value, _, _, _, err := r.storage(addr, slot, roleUnknown) return value, err } -type readerWithCacheStats struct { - *readerWithCache +type readerWithcacheStats struct { + *readerWithcache role readerRole accountHit atomic.Int64 @@ -694,9 +700,9 @@ type readerWithCacheStats struct { } // newReaderWithCacheStats constructs the reader with additional statistics tracked. -func newReaderWithCacheStats(reader *readerWithCache, role readerRole) *readerWithCacheStats { - return &readerWithCacheStats{ - readerWithCache: reader, +func newReaderWithcacheStats(reader *readerWithcache, role readerRole) *readerWithcacheStats { + return &readerWithcacheStats{ + readerWithcache: reader, role: role, } } @@ -705,8 +711,8 @@ func newReaderWithCacheStats(reader *readerWithCache, role readerRole) *readerWi // The returned account might be nil if it's not existent. // // An error will be returned if the state is corrupted in the underlying reader. -func (r *readerWithCacheStats) Account(addr common.Address) (*types.StateAccount, error) { - account, incache, ent, inserted, err := r.readerWithCache.account(addr, r.role) +func (r *readerWithcacheStats) Account(addr common.Address) (*types.StateAccount, error) { + account, incache, ent, inserted, err := r.readerWithcache.account(addr, r.role) if err != nil { return nil, err } @@ -735,8 +741,8 @@ func (r *readerWithCacheStats) Account(addr common.Address) (*types.StateAccount // existent. // // An error will be returned if the state is corrupted in the underlying reader. -func (r *readerWithCacheStats) Storage(addr common.Address, slot common.Hash) (common.Hash, error) { - value, incache, entCopy, inserted, err := r.readerWithCache.storage(addr, slot, r.role) +func (r *readerWithcacheStats) Storage(addr common.Address, slot common.Hash) (common.Hash, error) { + value, incache, entCopy, inserted, err := r.readerWithcache.storage(addr, slot, r.role) if err != nil { return common.Hash{}, err } @@ -759,7 +765,7 @@ func (r *readerWithCacheStats) Storage(addr common.Address, slot common.Hash) (c } // GetStats implements ReaderWithStats, returning the statistics of state reader. -func (r *readerWithCacheStats) GetStats() ReaderStats { +func (r *readerWithcacheStats) GetStats() ReaderStats { return ReaderStats{ AccountHit: r.accountHit.Load(), AccountMiss: r.accountMiss.Load(), @@ -769,7 +775,7 @@ func (r *readerWithCacheStats) GetStats() ReaderStats { } // GetPrefetchStats returns attribution statistics for evaluating prefetch effectiveness. -func (r *readerWithCacheStats) GetPrefetchStats() PrefetchStats { +func (r *readerWithcacheStats) GetPrefetchStats() PrefetchStats { return PrefetchStats{ AccountHitFromPrefetch: r.accountHitFromPrefetch.Load(), StorageHitFromPrefetch: r.storageHitFromPrefetch.Load(),