dao: optimize storage cache flushing

Items were serialized several times if there were several successful
transactions in a block, prevent that by using State field as a bitfield (as
it almost was intended to) and adding one more bit. It also eliminates useless
duplicate MPT traversions.

Confirmed to not break storage changes up to 3.3M on testnet.
This commit is contained in:
Roman Khimov 2020-06-04 17:21:58 +03:00
parent 69ccca675d
commit e3af560d11
2 changed files with 8 additions and 4 deletions

View file

@ -245,6 +245,7 @@ func (cd *Cached) FlushStorage() error {
return err return err
} }
} }
ti.State |= flushedState
} }
} }
return nil return nil
@ -275,7 +276,7 @@ func (cd *Cached) getStorageItemNoCache(scripthash util.Uint160, key []byte) *st
func (cd *Cached) getStorageItemInt(scripthash util.Uint160, key []byte, putToCache bool) *state.StorageItem { func (cd *Cached) getStorageItemInt(scripthash util.Uint160, key []byte, putToCache bool) *state.StorageItem {
ti := cd.storage.getItem(scripthash, key) ti := cd.storage.getItem(scripthash, key)
if ti != nil { if ti != nil {
if ti.State == delOp { if ti.State&delOp != 0 {
return nil return nil
} }
return copyItem(&ti.StorageItem) return copyItem(&ti.StorageItem)
@ -303,8 +304,10 @@ func (cd *Cached) PutStorageItem(scripthash util.Uint160, key []byte, si *state.
item := copyItem(si) item := copyItem(si)
ti := cd.storage.getItem(scripthash, key) ti := cd.storage.getItem(scripthash, key)
if ti != nil { if ti != nil {
if ti.State == delOp || ti.State == getOp { if ti.State&(delOp|getOp) != 0 {
ti.State = putOp ti.State = putOp
} else {
ti.State = addOp
} }
ti.StorageItem = *item ti.StorageItem = *item
return nil return nil
@ -357,7 +360,7 @@ func (cd *Cached) GetStorageItemsIterator(hash util.Uint160, prefix []byte) (Sto
for ; keyIndex < len(cd.storage.keys[hash]); keyIndex++ { for ; keyIndex < len(cd.storage.keys[hash]); keyIndex++ {
k := cd.storage.keys[hash][keyIndex] k := cd.storage.keys[hash][keyIndex]
v := cache[k] v := cache[k]
if v.State != delOp && bytes.HasPrefix([]byte(k), prefix) { if v.State&delOp == 0 && bytes.HasPrefix([]byte(k), prefix) {
val := make([]byte, len(v.StorageItem.Value)) val := make([]byte, len(v.StorageItem.Value))
copy(val, v.StorageItem.Value) copy(val, v.StorageItem.Value)
return []byte(k), val, nil return []byte(k), val, nil
@ -404,7 +407,7 @@ func (cd *Cached) GetStorageItems(hash util.Uint160, prefix []byte) ([]StorageIt
for _, k := range cd.storage.keys[hash] { for _, k := range cd.storage.keys[hash] {
v := cache[k] v := cache[k]
if v.State != delOp { if v.State&delOp == 0 {
val := make([]byte, len(v.StorageItem.Value)) val := make([]byte, len(v.StorageItem.Value))
copy(val, v.StorageItem.Value) copy(val, v.StorageItem.Value)
result = append(result, StorageItemWithKey{ result = append(result, StorageItemWithKey{

View file

@ -24,6 +24,7 @@ const (
delOp delOp
addOp addOp
putOp putOp
flushedState
) )
func newItemCache() *itemCache { func newItemCache() *itemCache {