mirror of
https://gitlab.com/pulsechaincom/erigon-pulse.git
synced 2024-12-22 19:50:36 +00:00
Remove getNodeData experimental feature (#4559)
This commit is contained in:
parent
880a339456
commit
8f86c5d615
@ -4,46 +4,9 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
// atomic: bit 0 is the value, bit 1 is the initialized flag
|
|
||||||
var getNodeData uint32
|
|
||||||
|
|
||||||
const (
|
|
||||||
gndValueFlag = 1 << iota
|
|
||||||
gndInitializedFlag
|
|
||||||
)
|
|
||||||
|
|
||||||
// IsGetNodeData indicates whether the GetNodeData functionality should be enabled.
|
|
||||||
// By default that's driven by the presence or absence of DISABLE_GET_NODE_DATA environment variable.
|
|
||||||
func IsGetNodeData() bool {
|
|
||||||
x := atomic.LoadUint32(&getNodeData)
|
|
||||||
if x&gndInitializedFlag != 0 { // already initialized
|
|
||||||
return x&gndValueFlag != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
RestoreGetNodeData()
|
|
||||||
return IsGetNodeData()
|
|
||||||
}
|
|
||||||
|
|
||||||
// RestoreGetNodeData enables or disables the GetNodeData functionality
|
|
||||||
// according to the presence or absence of GET_NODE_DATA environment variable.
|
|
||||||
func RestoreGetNodeData() {
|
|
||||||
_, envVarSet := os.LookupEnv("GET_NODE_DATA")
|
|
||||||
OverrideGetNodeData(envVarSet)
|
|
||||||
}
|
|
||||||
|
|
||||||
// OverrideGetNodeData allows to explicitly enable or disable the GetNodeData functionality.
|
|
||||||
func OverrideGetNodeData(val bool) {
|
|
||||||
if val {
|
|
||||||
atomic.StoreUint32(&getNodeData, gndInitializedFlag|gndValueFlag)
|
|
||||||
} else {
|
|
||||||
atomic.StoreUint32(&getNodeData, gndInitializedFlag)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
var (
|
||||||
bigRoTx uint
|
bigRoTx uint
|
||||||
getBigRoTx sync.Once
|
getBigRoTx sync.Once
|
||||||
|
@ -25,11 +25,9 @@ import (
|
|||||||
libcommon "github.com/ledgerwatch/erigon-lib/common"
|
libcommon "github.com/ledgerwatch/erigon-lib/common"
|
||||||
"github.com/ledgerwatch/erigon-lib/common/cmp"
|
"github.com/ledgerwatch/erigon-lib/common/cmp"
|
||||||
"github.com/ledgerwatch/erigon/common"
|
"github.com/ledgerwatch/erigon/common"
|
||||||
"github.com/ledgerwatch/erigon/common/debug"
|
|
||||||
"github.com/ledgerwatch/erigon/core/types/accounts"
|
"github.com/ledgerwatch/erigon/core/types/accounts"
|
||||||
"github.com/ledgerwatch/erigon/crypto"
|
"github.com/ledgerwatch/erigon/crypto"
|
||||||
"github.com/ledgerwatch/erigon/ethdb"
|
"github.com/ledgerwatch/erigon/ethdb"
|
||||||
"github.com/ledgerwatch/log/v3"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -52,8 +50,6 @@ type Trie struct {
|
|||||||
root node
|
root node
|
||||||
|
|
||||||
newHasherFunc func() *hasher
|
newHasherFunc func() *hasher
|
||||||
|
|
||||||
hashMap map[common.Hash]node
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// New creates a trie with an existing root node from db.
|
// New creates a trie with an existing root node from db.
|
||||||
@ -67,7 +63,6 @@ type Trie struct {
|
|||||||
func New(root common.Hash) *Trie {
|
func New(root common.Hash) *Trie {
|
||||||
trie := &Trie{
|
trie := &Trie{
|
||||||
newHasherFunc: func() *hasher { return newHasher( /*valueNodesRlpEncoded = */ false) },
|
newHasherFunc: func() *hasher { return newHasher( /*valueNodesRlpEncoded = */ false) },
|
||||||
hashMap: make(map[common.Hash]node),
|
|
||||||
}
|
}
|
||||||
if (root != common.Hash{}) && root != EmptyRoot {
|
if (root != common.Hash{}) && root != EmptyRoot {
|
||||||
trie.root = hashNode{hash: root[:]}
|
trie.root = hashNode{hash: root[:]}
|
||||||
@ -80,7 +75,6 @@ func New(root common.Hash) *Trie {
|
|||||||
func NewTestRLPTrie(root common.Hash) *Trie {
|
func NewTestRLPTrie(root common.Hash) *Trie {
|
||||||
trie := &Trie{
|
trie := &Trie{
|
||||||
newHasherFunc: func() *hasher { return newHasher( /*valueNodesRlpEncoded = */ true) },
|
newHasherFunc: func() *hasher { return newHasher( /*valueNodesRlpEncoded = */ true) },
|
||||||
hashMap: make(map[common.Hash]node),
|
|
||||||
}
|
}
|
||||||
if (root != common.Hash{}) && root != EmptyRoot {
|
if (root != common.Hash{}) && root != EmptyRoot {
|
||||||
trie.root = hashNode{hash: root[:]}
|
trie.root = hashNode{hash: root[:]}
|
||||||
@ -515,7 +509,6 @@ func (t *Trie) insertRecursive(origNode node, key []byte, pos int, value node) (
|
|||||||
|
|
||||||
// replacing nodes except accounts
|
// replacing nodes except accounts
|
||||||
if !origNok {
|
if !origNok {
|
||||||
t.evictSubtreeFromHashMap(origNode)
|
|
||||||
return true, value
|
return true, value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -538,14 +531,12 @@ func (t *Trie) insertRecursive(origNode node, key []byte, pos int, value node) (
|
|||||||
if matchlen == len(n.Key) || n.Key[matchlen] == 16 {
|
if matchlen == len(n.Key) || n.Key[matchlen] == 16 {
|
||||||
updated, nn = t.insertRecursive(n.Val, key, pos+matchlen, value)
|
updated, nn = t.insertRecursive(n.Val, key, pos+matchlen, value)
|
||||||
if updated {
|
if updated {
|
||||||
t.evictNodeFromHashMap(n)
|
|
||||||
n.Val = nn
|
n.Val = nn
|
||||||
n.ref.len = 0
|
n.ref.len = 0
|
||||||
}
|
}
|
||||||
newNode = n
|
newNode = n
|
||||||
} else {
|
} else {
|
||||||
// Otherwise branch out at the index where they differ.
|
// Otherwise branch out at the index where they differ.
|
||||||
t.evictNodeFromHashMap(n)
|
|
||||||
var c1 node
|
var c1 node
|
||||||
if len(n.Key) == matchlen+1 {
|
if len(n.Key) == matchlen+1 {
|
||||||
c1 = n.Val
|
c1 = n.Val
|
||||||
@ -588,7 +579,6 @@ func (t *Trie) insertRecursive(origNode node, key []byte, pos int, value node) (
|
|||||||
case i1:
|
case i1:
|
||||||
updated, nn = t.insertRecursive(n.child1, key, pos+1, value)
|
updated, nn = t.insertRecursive(n.child1, key, pos+1, value)
|
||||||
if updated {
|
if updated {
|
||||||
t.evictNodeFromHashMap(n)
|
|
||||||
n.child1 = nn
|
n.child1 = nn
|
||||||
n.ref.len = 0
|
n.ref.len = 0
|
||||||
}
|
}
|
||||||
@ -596,13 +586,11 @@ func (t *Trie) insertRecursive(origNode node, key []byte, pos int, value node) (
|
|||||||
case i2:
|
case i2:
|
||||||
updated, nn = t.insertRecursive(n.child2, key, pos+1, value)
|
updated, nn = t.insertRecursive(n.child2, key, pos+1, value)
|
||||||
if updated {
|
if updated {
|
||||||
t.evictNodeFromHashMap(n)
|
|
||||||
n.child2 = nn
|
n.child2 = nn
|
||||||
n.ref.len = 0
|
n.ref.len = 0
|
||||||
}
|
}
|
||||||
newNode = n
|
newNode = n
|
||||||
default:
|
default:
|
||||||
t.evictNodeFromHashMap(n)
|
|
||||||
var child node
|
var child node
|
||||||
if len(key) == pos+1 {
|
if len(key) == pos+1 {
|
||||||
child = value
|
child = value
|
||||||
@ -622,7 +610,6 @@ func (t *Trie) insertRecursive(origNode node, key []byte, pos int, value node) (
|
|||||||
case *fullNode:
|
case *fullNode:
|
||||||
child := n.Children[key[pos]]
|
child := n.Children[key[pos]]
|
||||||
if child == nil {
|
if child == nil {
|
||||||
t.evictNodeFromHashMap(n)
|
|
||||||
if len(key) == pos+1 {
|
if len(key) == pos+1 {
|
||||||
n.Children[key[pos]] = value
|
n.Children[key[pos]] = value
|
||||||
} else {
|
} else {
|
||||||
@ -633,7 +620,6 @@ func (t *Trie) insertRecursive(origNode node, key []byte, pos int, value node) (
|
|||||||
} else {
|
} else {
|
||||||
updated, nn = t.insertRecursive(child, key, pos+1, value)
|
updated, nn = t.insertRecursive(child, key, pos+1, value)
|
||||||
if updated {
|
if updated {
|
||||||
t.evictNodeFromHashMap(n)
|
|
||||||
n.Children[key[pos]] = nn
|
n.Children[key[pos]] = nn
|
||||||
n.ref.len = 0
|
n.ref.len = 0
|
||||||
}
|
}
|
||||||
@ -760,14 +746,6 @@ func (t *Trie) hook(hex []byte, n node, hash []byte) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *Trie) touchAll(n node, hex []byte, del bool, incarnation uint64) {
|
func (t *Trie) touchAll(n node, hex []byte, del bool, incarnation uint64) {
|
||||||
if del {
|
|
||||||
t.evictNodeFromHashMap(n)
|
|
||||||
} else if len(n.reference()) == common.HashLength && debug.IsGetNodeData() {
|
|
||||||
var key common.Hash
|
|
||||||
copy(key[:], n.reference())
|
|
||||||
t.hashMap[key] = n
|
|
||||||
}
|
|
||||||
|
|
||||||
switch n := n.(type) {
|
switch n := n.(type) {
|
||||||
case *shortNode:
|
case *shortNode:
|
||||||
if _, ok := n.Val.(valueNode); !ok {
|
if _, ok := n.Val.(valueNode); !ok {
|
||||||
@ -819,7 +797,6 @@ func (t *Trie) convertToShortNode(child node, pos uint) node {
|
|||||||
// might not be loaded yet, resolve it just for this
|
// might not be loaded yet, resolve it just for this
|
||||||
// check.
|
// check.
|
||||||
if short, ok := child.(*shortNode); ok {
|
if short, ok := child.(*shortNode); ok {
|
||||||
t.evictNodeFromHashMap(child)
|
|
||||||
k := make([]byte, len(short.Key)+1)
|
k := make([]byte, len(short.Key)+1)
|
||||||
k[0] = byte(pos)
|
k[0] = byte(pos)
|
||||||
copy(k[1:], short.Key)
|
copy(k[1:], short.Key)
|
||||||
@ -854,7 +831,6 @@ func (t *Trie) deleteRecursive(origNode node, key []byte, keyStart int, preserve
|
|||||||
}
|
}
|
||||||
|
|
||||||
if removeNodeEntirely {
|
if removeNodeEntirely {
|
||||||
t.evictNodeFromHashMap(n)
|
|
||||||
updated = true
|
updated = true
|
||||||
touchKey := key[:keyStart+matchlen]
|
touchKey := key[:keyStart+matchlen]
|
||||||
if touchKey[len(touchKey)-1] == 16 {
|
if touchKey[len(touchKey)-1] == 16 {
|
||||||
@ -871,7 +847,6 @@ func (t *Trie) deleteRecursive(origNode node, key []byte, keyStart int, preserve
|
|||||||
if !updated {
|
if !updated {
|
||||||
newNode = n
|
newNode = n
|
||||||
} else {
|
} else {
|
||||||
t.evictNodeFromHashMap(n)
|
|
||||||
if nn == nil {
|
if nn == nil {
|
||||||
newNode = nil
|
newNode = nil
|
||||||
} else {
|
} else {
|
||||||
@ -905,7 +880,6 @@ func (t *Trie) deleteRecursive(origNode node, key []byte, keyStart int, preserve
|
|||||||
if !updated {
|
if !updated {
|
||||||
newNode = n
|
newNode = n
|
||||||
} else {
|
} else {
|
||||||
t.evictNodeFromHashMap(n)
|
|
||||||
if nn == nil {
|
if nn == nil {
|
||||||
newNode = t.convertToShortNode(n.child2, uint(i2))
|
newNode = t.convertToShortNode(n.child2, uint(i2))
|
||||||
} else {
|
} else {
|
||||||
@ -919,7 +893,6 @@ func (t *Trie) deleteRecursive(origNode node, key []byte, keyStart int, preserve
|
|||||||
if !updated {
|
if !updated {
|
||||||
newNode = n
|
newNode = n
|
||||||
} else {
|
} else {
|
||||||
t.evictNodeFromHashMap(n)
|
|
||||||
if nn == nil {
|
if nn == nil {
|
||||||
newNode = t.convertToShortNode(n.child1, uint(i1))
|
newNode = t.convertToShortNode(n.child1, uint(i1))
|
||||||
} else {
|
} else {
|
||||||
@ -940,7 +913,6 @@ func (t *Trie) deleteRecursive(origNode node, key []byte, keyStart int, preserve
|
|||||||
if !updated {
|
if !updated {
|
||||||
newNode = n
|
newNode = n
|
||||||
} else {
|
} else {
|
||||||
t.evictNodeFromHashMap(n)
|
|
||||||
n.Children[key[keyStart]] = nn
|
n.Children[key[keyStart]] = nn
|
||||||
// Check how many non-nil entries are left after deleting and
|
// Check how many non-nil entries are left after deleting and
|
||||||
// reduce the full node to a short node if only one entry is
|
// reduce the full node to a short node if only one entry is
|
||||||
@ -1078,13 +1050,7 @@ func (t *Trie) Reset() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *Trie) getHasher() *hasher {
|
func (t *Trie) getHasher() *hasher {
|
||||||
h := t.newHasherFunc()
|
return t.newHasherFunc()
|
||||||
if debug.IsGetNodeData() {
|
|
||||||
h.callback = func(key common.Hash, nd node) {
|
|
||||||
t.hashMap[key] = nd
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return h
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DeepHash returns internal hash of a node reachable by the specified key prefix.
|
// DeepHash returns internal hash of a node reachable by the specified key prefix.
|
||||||
@ -1135,8 +1101,6 @@ func (t *Trie) EvictNode(hex []byte) {
|
|||||||
// can work with other nodes type
|
// can work with other nodes type
|
||||||
}
|
}
|
||||||
|
|
||||||
t.evictSubtreeFromHashMap(nd)
|
|
||||||
|
|
||||||
var hn common.Hash
|
var hn common.Hash
|
||||||
if nd == nil {
|
if nd == nil {
|
||||||
fmt.Printf("nd == nil, hex %x, parent node: %T\n", hex, parent)
|
fmt.Printf("nd == nil, hex %x, parent node: %T\n", hex, parent)
|
||||||
@ -1214,65 +1178,3 @@ func (t *Trie) TrieSize() int {
|
|||||||
func (t *Trie) NumberOfAccounts() int {
|
func (t *Trie) NumberOfAccounts() int {
|
||||||
return calcSubtreeNodes(t.root)
|
return calcSubtreeNodes(t.root)
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetNodeByHash gets node's RLP by hash.
|
|
||||||
func (t *Trie) GetNodeByHash(hash common.Hash) []byte {
|
|
||||||
nd := t.hashMap[hash]
|
|
||||||
if nd == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
h := t.getHasher()
|
|
||||||
defer returnHasherToPool(h)
|
|
||||||
|
|
||||||
rlp, err := h.hashChildren(nd, 0)
|
|
||||||
if err != nil {
|
|
||||||
log.Warn("GetNodeByHash error while producing node RLP", "err", err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return libcommon.Copy(rlp)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Trie) evictNodeFromHashMap(nd node) {
|
|
||||||
if !debug.IsGetNodeData() || nd == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if len(nd.reference()) == common.HashLength {
|
|
||||||
var key common.Hash
|
|
||||||
copy(key[:], nd.reference())
|
|
||||||
delete(t.hashMap, key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Trie) evictSubtreeFromHashMap(n node) {
|
|
||||||
if !debug.IsGetNodeData() {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
t.evictNodeFromHashMap(n)
|
|
||||||
|
|
||||||
switch n := n.(type) {
|
|
||||||
case *shortNode:
|
|
||||||
if _, ok := n.Val.(valueNode); !ok {
|
|
||||||
t.evictSubtreeFromHashMap(n.Val)
|
|
||||||
}
|
|
||||||
case *duoNode:
|
|
||||||
t.evictSubtreeFromHashMap(n.child1)
|
|
||||||
t.evictSubtreeFromHashMap(n.child2)
|
|
||||||
case *fullNode:
|
|
||||||
for _, child := range n.Children {
|
|
||||||
if child != nil {
|
|
||||||
t.evictSubtreeFromHashMap(child)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case *accountNode:
|
|
||||||
if n.storage != nil {
|
|
||||||
t.evictSubtreeFromHashMap(n.storage)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// HashMapSize returns the number of entries in trie's hash map.
|
|
||||||
func (t *Trie) HashMapSize() int {
|
|
||||||
return len(t.hashMap)
|
|
||||||
}
|
|
||||||
|
@ -27,7 +27,6 @@ import (
|
|||||||
|
|
||||||
"github.com/davecgh/go-spew/spew"
|
"github.com/davecgh/go-spew/spew"
|
||||||
"github.com/ledgerwatch/erigon/common"
|
"github.com/ledgerwatch/erigon/common"
|
||||||
"github.com/ledgerwatch/erigon/common/debug"
|
|
||||||
"github.com/ledgerwatch/erigon/core/types/accounts"
|
"github.com/ledgerwatch/erigon/core/types/accounts"
|
||||||
"github.com/ledgerwatch/erigon/crypto"
|
"github.com/ledgerwatch/erigon/crypto"
|
||||||
"github.com/ledgerwatch/erigon/rlp"
|
"github.com/ledgerwatch/erigon/rlp"
|
||||||
@ -282,45 +281,6 @@ func TestDeepHash(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestHashMapLeak(t *testing.T) {
|
|
||||||
debug.OverrideGetNodeData(true)
|
|
||||||
defer debug.OverrideGetNodeData(false)
|
|
||||||
// freeze the randomness
|
|
||||||
random := rand.New(rand.NewSource(794656320434))
|
|
||||||
|
|
||||||
// now create a trie with some small and some big leaves
|
|
||||||
trie := newEmpty()
|
|
||||||
nTouches := 256 * 10
|
|
||||||
|
|
||||||
var key [1]byte
|
|
||||||
var val [8]byte
|
|
||||||
for i := 0; i < nTouches; i++ {
|
|
||||||
key[0] = byte(random.Intn(256))
|
|
||||||
binary.BigEndian.PutUint64(val[:], random.Uint64())
|
|
||||||
|
|
||||||
option := random.Intn(3)
|
|
||||||
if option == 0 {
|
|
||||||
// small leaf node
|
|
||||||
trie.Update(key[:], val[:])
|
|
||||||
} else if option == 1 {
|
|
||||||
// big leaf node
|
|
||||||
trie.Update(key[:], crypto.Keccak256(val[:]))
|
|
||||||
} else {
|
|
||||||
// test delete as well
|
|
||||||
trie.Delete(key[:])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// check the size of trie's hash map
|
|
||||||
trie.Hash()
|
|
||||||
|
|
||||||
nHashes := trie.HashMapSize()
|
|
||||||
nExpected := 1 + 16 + 256/3
|
|
||||||
|
|
||||||
assert.GreaterOrEqual(t, nHashes, nExpected*7/8)
|
|
||||||
assert.LessOrEqual(t, nHashes, nExpected*9/8)
|
|
||||||
}
|
|
||||||
|
|
||||||
func genRandomByteArrayOfLen(length uint) []byte {
|
func genRandomByteArrayOfLen(length uint) []byte {
|
||||||
array := make([]byte, length)
|
array := make([]byte, length)
|
||||||
for i := uint(0); i < length; i++ {
|
for i := uint(0); i < length; i++ {
|
||||||
|
Loading…
Reference in New Issue
Block a user