Browse Source

add dirty bit to BlockCache accounts and storages.

construct account’s storage lazily.
pull/43/merge
Jae Kwon 10 years ago
parent
commit
42e2e11364
2 changed files with 49 additions and 26 deletions
  1. +47
    -22
      state/block_cache.go
  2. +2
    -4
      state/tx_cache.go

+ 47
- 22
state/block_cache.go View File

@ -1,6 +1,7 @@
package state package state
import ( import (
"bytes"
"sort" "sort"
ac "github.com/tendermint/tendermint/account" ac "github.com/tendermint/tendermint/account"
@ -25,7 +26,7 @@ type BlockCache struct {
db dbm.DB db dbm.DB
backend *State backend *State
accounts map[string]accountInfo accounts map[string]accountInfo
storages map[Tuple256]Word256
storages map[Tuple256]storageInfo
} }
func NewBlockCache(backend *State) *BlockCache { func NewBlockCache(backend *State) *BlockCache {
@ -33,7 +34,7 @@ func NewBlockCache(backend *State) *BlockCache {
db: backend.DB, db: backend.DB,
backend: backend, backend: backend,
accounts: make(map[string]accountInfo), accounts: make(map[string]accountInfo),
storages: make(map[Tuple256]Word256),
storages: make(map[Tuple256]storageInfo),
} }
} }
@ -45,15 +46,14 @@ func (cache *BlockCache) State() *State {
// BlockCache.account // BlockCache.account
func (cache *BlockCache) GetAccount(addr []byte) *ac.Account { func (cache *BlockCache) GetAccount(addr []byte) *ac.Account {
acc, storage, removed := unpack(cache.accounts[string(addr)])
acc, _, removed, _ := cache.accounts[string(addr)].unpack()
if removed { if removed {
return nil return nil
} else if acc != nil { } else if acc != nil {
return acc return acc
} else { } else {
acc = cache.backend.GetAccount(addr) acc = cache.backend.GetAccount(addr)
storage = makeStorage(cache.db, acc.StorageRoot)
cache.accounts[string(addr)] = accountInfo{acc, storage, false}
cache.accounts[string(addr)] = accountInfo{acc, nil, false, false}
return acc return acc
} }
} }
@ -61,22 +61,22 @@ func (cache *BlockCache) GetAccount(addr []byte) *ac.Account {
func (cache *BlockCache) UpdateAccount(acc *ac.Account) { func (cache *BlockCache) UpdateAccount(acc *ac.Account) {
addr := acc.Address addr := acc.Address
// SANITY CHECK // SANITY CHECK
_, storage, removed := unpack(cache.accounts[string(addr)])
_, storage, removed, _ := cache.accounts[string(addr)].unpack()
if removed { if removed {
panic("UpdateAccount on a removed account") panic("UpdateAccount on a removed account")
} }
// SANITY CHECK END // SANITY CHECK END
cache.accounts[string(addr)] = accountInfo{acc, storage, false}
cache.accounts[string(addr)] = accountInfo{acc, storage, false, true}
} }
func (cache *BlockCache) RemoveAccount(addr []byte) { func (cache *BlockCache) RemoveAccount(addr []byte) {
// SANITY CHECK // SANITY CHECK
_, _, removed := unpack(cache.accounts[string(addr)])
_, _, removed, _ := cache.accounts[string(addr)].unpack()
if removed { if removed {
panic("RemoveAccount on a removed account") panic("RemoveAccount on a removed account")
} }
// SANITY CHECK END // SANITY CHECK END
cache.accounts[string(addr)] = accountInfo{nil, nil, true}
cache.accounts[string(addr)] = accountInfo{nil, nil, true, false}
} }
// BlockCache.account // BlockCache.account
@ -85,16 +85,20 @@ func (cache *BlockCache) RemoveAccount(addr []byte) {
func (cache *BlockCache) GetStorage(addr Word256, key Word256) (value Word256) { func (cache *BlockCache) GetStorage(addr Word256, key Word256) (value Word256) {
// Check cache // Check cache
value, ok := cache.storages[Tuple256{addr, key}]
info, ok := cache.storages[Tuple256{addr, key}]
if ok { if ok {
return value
return info.value
} }
// Get or load storage // Get or load storage
_, storage, removed := unpack(cache.accounts[string(addr.Prefix(20))])
acc, storage, removed, dirty := cache.accounts[string(addr.Prefix(20))].unpack()
if removed { if removed {
panic("GetStorage() on removed account") panic("GetStorage() on removed account")
} }
if storage == nil {
storage = makeStorage(cache.db, acc.StorageRoot)
cache.accounts[string(addr.Prefix(20))] = accountInfo{acc, storage, false, dirty}
}
// Load and set cache // Load and set cache
_, val_ := storage.Get(key.Bytes()) _, val_ := storage.Get(key.Bytes())
@ -102,17 +106,17 @@ func (cache *BlockCache) GetStorage(addr Word256, key Word256) (value Word256) {
if val_ != nil { if val_ != nil {
value = RightPadWord256(val_.([]byte)) value = RightPadWord256(val_.([]byte))
} }
cache.storages[Tuple256{addr, key}] = value
cache.storages[Tuple256{addr, key}] = storageInfo{value, false}
return value return value
} }
// NOTE: Set value to zero to removed from the trie. // NOTE: Set value to zero to removed from the trie.
func (cache *BlockCache) SetStorage(addr Word256, key Word256, value Word256) { func (cache *BlockCache) SetStorage(addr Word256, key Word256, value Word256) {
_, _, removed := unpack(cache.accounts[string(addr.Prefix(20))])
_, _, removed, _ := cache.accounts[string(addr.Prefix(20))].unpack()
if removed { if removed {
panic("SetStorage() on a removed account") panic("SetStorage() on a removed account")
} }
cache.storages[Tuple256{addr, key}] = value
cache.storages[Tuple256{addr, key}] = storageInfo{value, true}
} }
// BlockCache.storage // BlockCache.storage
@ -140,7 +144,7 @@ func (cache *BlockCache) Sync() {
for _, storageKey := range storageKeys { for _, storageKey := range storageKeys {
addr, key := Tuple256Split(storageKey) addr, key := Tuple256Split(storageKey)
if addr != curAddr || curAcc == nil { if addr != curAddr || curAcc == nil {
acc, storage, removed := unpack(cache.accounts[string(addr.Prefix(20))])
acc, storage, removed, _ := cache.accounts[string(addr.Prefix(20))].unpack()
curAddr = addr curAddr = addr
curAcc = acc curAcc = acc
curAccRemoved = removed curAccRemoved = removed
@ -149,7 +153,10 @@ func (cache *BlockCache) Sync() {
if curAccRemoved { if curAccRemoved {
continue continue
} }
value := cache.storages[storageKey]
value, dirty := cache.storages[storageKey].unpack()
if !dirty {
continue
}
if value.IsZero() { if value.IsZero() {
curStorage.Remove(key.Bytes()) curStorage.Remove(key.Bytes())
} else { } else {
@ -166,7 +173,7 @@ func (cache *BlockCache) Sync() {
// Update or delete accounts. // Update or delete accounts.
for _, addrStr := range addrStrs { for _, addrStr := range addrStrs {
acc, storage, removed := unpack(cache.accounts[addrStr])
acc, storage, removed, dirty := cache.accounts[addrStr].unpack()
if removed { if removed {
removed := cache.backend.RemoveAccount(acc.Address) removed := cache.backend.RemoveAccount(acc.Address)
if !removed { if !removed {
@ -176,8 +183,16 @@ func (cache *BlockCache) Sync() {
if acc == nil { if acc == nil {
panic(Fmt("Account should not be nil for addr: %X", acc.Address)) panic(Fmt("Account should not be nil for addr: %X", acc.Address))
} }
acc.StorageRoot = storage.Save()
cache.backend.UpdateAccount(acc)
if storage != nil {
newStorageRoot := storage.Save()
if !bytes.Equal(newStorageRoot, acc.StorageRoot) {
acc.StorageRoot = newStorageRoot
dirty = true
}
}
if dirty {
cache.backend.UpdateAccount(acc)
}
} }
} }
@ -189,8 +204,18 @@ type accountInfo struct {
account *ac.Account account *ac.Account
storage merkle.Tree storage merkle.Tree
removed bool removed bool
dirty bool
}
func (accInfo accountInfo) unpack() (*ac.Account, merkle.Tree, bool, bool) {
return accInfo.account, accInfo.storage, accInfo.removed, accInfo.dirty
}
type storageInfo struct {
value Word256
dirty bool
} }
func unpack(accInfo accountInfo) (*ac.Account, merkle.Tree, bool) {
return accInfo.account, accInfo.storage, accInfo.removed
func (stjInfo storageInfo) unpack() (Word256, bool) {
return stjInfo.value, stjInfo.dirty
} }

+ 2
- 4
state/tx_cache.go View File

@ -94,10 +94,8 @@ func (cache *TxCache) GetStorage(addr Word256, key Word256) Word256 {
return value return value
} }
// Load and set cache
value = cache.backend.GetStorage(addr, key)
cache.storages[Tuple256{addr, key}] = value
return value
// Load from backend
return cache.backend.GetStorage(addr, key)
} }
// NOTE: Set value to zero to removed from the trie. // NOTE: Set value to zero to removed from the trie.


Loading…
Cancel
Save