core/state: add mutex to protect global statedb and trie caches

This commit is contained in:
Péter Szilágyi 2016-09-27 16:32:42 +03:00
parent 5cbe71a9c4
commit c907726d8b

View file

@ -20,6 +20,7 @@ package state
import ( import (
"fmt" "fmt"
"math/big" "math/big"
"sync"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/core/vm"
@ -66,6 +67,8 @@ type StateDB struct {
txIndex int txIndex int
logs map[common.Hash]vm.Logs logs map[common.Hash]vm.Logs
logSize uint logSize uint
lock sync.Mutex
} }
// Create a new state from a given trie // Create a new state from a given trie
@ -89,15 +92,17 @@ func New(root common.Hash, db ethdb.Database) (*StateDB, error) {
// New creates a new statedb by reusing any journalled tries to avoid costly // New creates a new statedb by reusing any journalled tries to avoid costly
// disk io. // disk io.
func (self *StateDB) New(root common.Hash) (*StateDB, error) { func (self *StateDB) New(root common.Hash) (*StateDB, error) {
self.lock.Lock()
defer self.lock.Unlock()
tr, err := self.openTrie(root) tr, err := self.openTrie(root)
if err != nil { if err != nil {
return nil, err return nil, err
} }
csc, _ := lru.New(codeSizeCacheSize)
return &StateDB{ return &StateDB{
db: self.db, db: self.db,
trie: tr, trie: tr,
codeSizeCache: csc, codeSizeCache: self.codeSizeCache,
stateObjects: make(map[common.Address]*StateObject), stateObjects: make(map[common.Address]*StateObject),
stateObjectsDirty: make(map[common.Address]struct{}), stateObjectsDirty: make(map[common.Address]struct{}),
refund: new(big.Int), refund: new(big.Int),
@ -108,30 +113,29 @@ func (self *StateDB) New(root common.Hash) (*StateDB, error) {
// Reset clears out all emphemeral state objects from the state db, but keeps // Reset clears out all emphemeral state objects from the state db, but keeps
// the underlying state trie to avoid reloading data for the next operations. // the underlying state trie to avoid reloading data for the next operations.
func (self *StateDB) Reset(root common.Hash) error { func (self *StateDB) Reset(root common.Hash) error {
self.lock.Lock()
defer self.lock.Unlock()
tr, err := self.openTrie(root) tr, err := self.openTrie(root)
if err != nil { if err != nil {
return err return err
} }
*self = StateDB{ self.trie = tr
db: self.db, self.stateObjects = make(map[common.Address]*StateObject)
trie: tr, self.stateObjectsDirty = make(map[common.Address]struct{})
pastTries: self.pastTries, self.refund = new(big.Int)
codeSizeCache: self.codeSizeCache, self.thash = common.Hash{}
stateObjects: make(map[common.Address]*StateObject), self.bhash = common.Hash{}
stateObjectsDirty: make(map[common.Address]struct{}), self.txIndex = 0
refund: new(big.Int), self.logs = make(map[common.Hash]vm.Logs)
logs: make(map[common.Hash]vm.Logs), self.logSize = 0
}
return nil return nil
} }
// openTrie creates a trie. It uses an existing trie if one is available // openTrie creates a trie. It uses an existing trie if one is available
// from the journal if available. // from the journal if available.
func (self *StateDB) openTrie(root common.Hash) (*trie.SecureTrie, error) { func (self *StateDB) openTrie(root common.Hash) (*trie.SecureTrie, error) {
if self.trie != nil && self.trie.Hash() == root {
cpy := *self.trie
return &cpy, nil
}
for i := len(self.pastTries) - 1; i >= 0; i-- { for i := len(self.pastTries) - 1; i >= 0; i-- {
if self.pastTries[i].Hash() == root { if self.pastTries[i].Hash() == root {
tr := *self.pastTries[i] tr := *self.pastTries[i]
@ -142,6 +146,9 @@ func (self *StateDB) openTrie(root common.Hash) (*trie.SecureTrie, error) {
} }
func (self *StateDB) pushTrie(t *trie.SecureTrie) { func (self *StateDB) pushTrie(t *trie.SecureTrie) {
self.lock.Lock()
defer self.lock.Unlock()
if len(self.pastTries) >= maxJournalLength { if len(self.pastTries) >= maxJournalLength {
copy(self.pastTries, self.pastTries[1:]) copy(self.pastTries, self.pastTries[1:])
self.pastTries[len(self.pastTries)-1] = t self.pastTries[len(self.pastTries)-1] = t
@ -401,6 +408,9 @@ func (self *StateDB) CreateAccount(addr common.Address) vm.Account {
// //
func (self *StateDB) Copy() *StateDB { func (self *StateDB) Copy() *StateDB {
self.lock.Lock()
defer self.lock.Unlock()
// Copy all the basic fields, initialize the memory ones // Copy all the basic fields, initialize the memory ones
state := &StateDB{ state := &StateDB{
db: self.db, db: self.db,
@ -426,6 +436,9 @@ func (self *StateDB) Copy() *StateDB {
} }
func (self *StateDB) Set(state *StateDB) { func (self *StateDB) Set(state *StateDB) {
self.lock.Lock()
defer self.lock.Unlock()
self.db = state.db self.db = state.db
self.trie = state.trie self.trie = state.trie
self.pastTries = state.pastTries self.pastTries = state.pastTries