Optimize resolver cached (#404)

* remove allocations related to "remove incarnation" actions

* invalidate startKeyNoInc when startKey changed

* dbutils.RemoveIncarnationFromKey - doesn't do allocation
This commit is contained in:
Alex Sharov 2020-03-25 16:43:55 +07:00 committed by GitHub
parent b0f962e3ba
commit 8d7e1e9374
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 41 additions and 15 deletions

View File

@ -119,14 +119,15 @@ func DecodeIncarnation(buf []byte) uint64 {
return incarnation ^ ^uint64(0)
}
func RemoveIncarnationFromKey(storageKey []byte) []byte {
if len(storageKey) <= common.HashLength {
return storageKey
func RemoveIncarnationFromKey(key []byte, buf *[]byte) {
tmp := *buf
if len(key) <= common.HashLength {
tmp = append(tmp, key...)
} else {
tmp = append(tmp, key[:common.HashLength]...)
tmp = append(tmp, key[common.HashLength+8:]...)
}
buf := make([]byte, 0, common.HashLength*2)
buf = append(buf, storageKey[:common.HashLength]...)
buf = append(buf, storageKey[common.HashLength+8:]...)
return buf
*buf = tmp
}
// Key + blockNum

View File

@ -294,6 +294,9 @@ func ClearTombstonesForReCreatedAccount(db ethdb.MinDatabase, addrHash common.Ha
return nil
}
buf := pool.GetBuffer(256)
defer pool.PutBuffer(buf)
incarnation := dbutils.DecodeIncarnation(k[common.HashLength : common.HashLength+8])
for ; incarnation > 0; incarnation-- {
accWithInc := dbutils.GenerateStoragePrefix(addrHash, incarnation)
@ -306,8 +309,9 @@ func ClearTombstonesForReCreatedAccount(db ethdb.MinDatabase, addrHash common.Ha
break
}
kNoInc := dbutils.RemoveIncarnationFromKey(k)
toPut = append(toPut, common.CopyBytes(kNoInc[:common.HashLength+1]))
buf.Reset()
dbutils.RemoveIncarnationFromKey(k, &buf.B)
toPut = append(toPut, common.CopyBytes(buf.B[:common.HashLength+1]))
}
}
return nil
@ -412,6 +416,9 @@ func ClearTombstonesForNewStorage(db ethdb.MinDatabase, storageKeyNoInc []byte)
kWithInc.B = append(kWithInc.B, storageK[:common.HashLength+8]...)
kWithInc.B = append(kWithInc.B, storageKeyNoInc[common.HashLength:]...)
buf := pool.GetBuffer(256)
defer pool.PutBuffer(buf)
for i := common.HashLength + 1; i < len(storageKeyNoInc)-1; i++ { // +1 because first step happened during account re-creation
tombStone, _ := interBucket.Get(storageKeyNoInc[:i])
foundTombstone := tombStone != nil && len(tombStone) == 0
@ -431,7 +438,9 @@ func ClearTombstonesForNewStorage(db ethdb.MinDatabase, storageKeyNoInc []byte)
continue
}
toPut = append(toPut, dbutils.RemoveIncarnationFromKey(storageK[:i+1+8]))
buf.Reset()
dbutils.RemoveIncarnationFromKey(storageK[:i+1+8], &buf.B)
toPut = append(toPut, common.CopyBytes(buf.B))
}
toDelete = append(toDelete, common.CopyBytes(storageKeyNoInc[:i]))
break

View File

@ -343,9 +343,16 @@ func (tr *ResolverStatefulCached) MultiWalk2(db *bolt.DB, blockNr uint64, bucket
keyAsNibbles := pool.GetBuffer(256)
defer pool.PutBuffer(keyAsNibbles)
startKeyNoInc := pool.GetBuffer(common.HashLength * 2)
defer pool.PutBuffer(startKeyNoInc)
rangeIdx := 0 // What is the current range we are extracting
fixedbytes, mask := ethdb.Bytesmask(fixedbits[rangeIdx])
startkey := startkeys[rangeIdx]
startKeyNoInc.Reset()
dbutils.RemoveIncarnationFromKey(startkey, &startKeyNoInc.B)
err := db.View(func(tx *bolt.Tx) error {
cacheBucket := tx.Bucket(dbutils.IntermediateTrieHashBucket)
if cacheBucket == nil {
@ -360,7 +367,7 @@ func (tr *ResolverStatefulCached) MultiWalk2(db *bolt.DB, blockNr uint64, bucket
c := b.Cursor()
k, v := c.Seek(startkey)
cacheK, cacheV := cache.Seek(dbutils.RemoveIncarnationFromKey(startkey))
cacheK, cacheV := cache.Seek(startKeyNoInc.B)
var minKey []byte
var fromCache bool
@ -391,7 +398,7 @@ func (tr *ResolverStatefulCached) MultiWalk2(db *bolt.DB, blockNr uint64, bucket
startKeyIndex = minInt(len(startkey), fixedbytes-1-8)
cmp = bytes.Compare(minKey[:minKeyIndex], startkey[:startKeyIndex])
} else if fromCache && fixedbytes > 40 {
cmp = bytes.Compare(minKey[:minKeyIndex], dbutils.RemoveIncarnationFromKey(startkey[:startKeyIndex]))
cmp = bytes.Compare(minKey[:minKeyIndex], startKeyNoInc.B[:startKeyIndex])
} else {
cmp = bytes.Compare(minKey[:minKeyIndex], startkey[:startKeyIndex])
}
@ -411,7 +418,7 @@ func (tr *ResolverStatefulCached) MultiWalk2(db *bolt.DB, blockNr uint64, bucket
}
if cmp < 0 {
k, v = c.SeekTo(startkey)
cacheK, cacheV = cache.SeekTo(dbutils.RemoveIncarnationFromKey(startkey))
cacheK, cacheV = cache.SeekTo(startKeyNoInc.B)
// for Address bucket, skip cache keys longer than 31 bytes
if isAccountBucket && len(cacheK) > maxAccountKeyLen {
for len(cacheK) > maxAccountKeyLen {
@ -430,6 +437,8 @@ func (tr *ResolverStatefulCached) MultiWalk2(db *bolt.DB, blockNr uint64, bucket
}
fixedbytes, mask = ethdb.Bytesmask(fixedbits[rangeIdx])
startkey = startkeys[rangeIdx]
startKeyNoInc.Reset()
dbutils.RemoveIncarnationFromKey(startkey, &startKeyNoInc.B)
}
}
}
@ -495,11 +504,18 @@ func (tr *ResolverStatefulCached) MultiWalk2(db *bolt.DB, blockNr uint64, bucket
continue
}
if isAccountBucket {
if isAccountBucket || len(cacheK) <= common.HashLength {
k, v = c.Seek(next)
} else {
// skip subtree - can't .Seek because storage bucket has incarnation in keys
for k, v = c.Next(); bytes.HasPrefix(dbutils.RemoveIncarnationFromKey(k), cacheK); k, v = c.Next() {
for k, v = c.Next(); k != nil; k, v = c.Next() {
matchAcc := bytes.HasPrefix(k[:common.HashLength], next[:common.HashLength])
// don't check incarnation ...
matchStorage := bytes.HasPrefix(k[common.HashLength+8:], next[common.HashLength:])
if matchAcc && matchStorage {
break
}
}
}