mirror of
https://gitlab.com/pulsechaincom/erigon-pulse.git
synced 2024-12-22 03:30:37 +00:00
Remove getNodeData experimental feature (#4559)
This commit is contained in:
parent
880a339456
commit
8f86c5d615
@ -4,46 +4,9 @@ import (
|
||||
"os"
|
||||
"strconv"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"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 (
|
||||
bigRoTx uint
|
||||
getBigRoTx sync.Once
|
||||
|
@ -25,11 +25,9 @@ import (
|
||||
libcommon "github.com/ledgerwatch/erigon-lib/common"
|
||||
"github.com/ledgerwatch/erigon-lib/common/cmp"
|
||||
"github.com/ledgerwatch/erigon/common"
|
||||
"github.com/ledgerwatch/erigon/common/debug"
|
||||
"github.com/ledgerwatch/erigon/core/types/accounts"
|
||||
"github.com/ledgerwatch/erigon/crypto"
|
||||
"github.com/ledgerwatch/erigon/ethdb"
|
||||
"github.com/ledgerwatch/log/v3"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -52,8 +50,6 @@ type Trie struct {
|
||||
root node
|
||||
|
||||
newHasherFunc func() *hasher
|
||||
|
||||
hashMap map[common.Hash]node
|
||||
}
|
||||
|
||||
// New creates a trie with an existing root node from db.
|
||||
@ -67,7 +63,6 @@ type Trie struct {
|
||||
func New(root common.Hash) *Trie {
|
||||
trie := &Trie{
|
||||
newHasherFunc: func() *hasher { return newHasher( /*valueNodesRlpEncoded = */ false) },
|
||||
hashMap: make(map[common.Hash]node),
|
||||
}
|
||||
if (root != common.Hash{}) && root != EmptyRoot {
|
||||
trie.root = hashNode{hash: root[:]}
|
||||
@ -80,7 +75,6 @@ func New(root common.Hash) *Trie {
|
||||
func NewTestRLPTrie(root common.Hash) *Trie {
|
||||
trie := &Trie{
|
||||
newHasherFunc: func() *hasher { return newHasher( /*valueNodesRlpEncoded = */ true) },
|
||||
hashMap: make(map[common.Hash]node),
|
||||
}
|
||||
if (root != common.Hash{}) && root != EmptyRoot {
|
||||
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
|
||||
if !origNok {
|
||||
t.evictSubtreeFromHashMap(origNode)
|
||||
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 {
|
||||
updated, nn = t.insertRecursive(n.Val, key, pos+matchlen, value)
|
||||
if updated {
|
||||
t.evictNodeFromHashMap(n)
|
||||
n.Val = nn
|
||||
n.ref.len = 0
|
||||
}
|
||||
newNode = n
|
||||
} else {
|
||||
// Otherwise branch out at the index where they differ.
|
||||
t.evictNodeFromHashMap(n)
|
||||
var c1 node
|
||||
if len(n.Key) == matchlen+1 {
|
||||
c1 = n.Val
|
||||
@ -588,7 +579,6 @@ func (t *Trie) insertRecursive(origNode node, key []byte, pos int, value node) (
|
||||
case i1:
|
||||
updated, nn = t.insertRecursive(n.child1, key, pos+1, value)
|
||||
if updated {
|
||||
t.evictNodeFromHashMap(n)
|
||||
n.child1 = nn
|
||||
n.ref.len = 0
|
||||
}
|
||||
@ -596,13 +586,11 @@ func (t *Trie) insertRecursive(origNode node, key []byte, pos int, value node) (
|
||||
case i2:
|
||||
updated, nn = t.insertRecursive(n.child2, key, pos+1, value)
|
||||
if updated {
|
||||
t.evictNodeFromHashMap(n)
|
||||
n.child2 = nn
|
||||
n.ref.len = 0
|
||||
}
|
||||
newNode = n
|
||||
default:
|
||||
t.evictNodeFromHashMap(n)
|
||||
var child node
|
||||
if len(key) == pos+1 {
|
||||
child = value
|
||||
@ -622,7 +610,6 @@ func (t *Trie) insertRecursive(origNode node, key []byte, pos int, value node) (
|
||||
case *fullNode:
|
||||
child := n.Children[key[pos]]
|
||||
if child == nil {
|
||||
t.evictNodeFromHashMap(n)
|
||||
if len(key) == pos+1 {
|
||||
n.Children[key[pos]] = value
|
||||
} else {
|
||||
@ -633,7 +620,6 @@ func (t *Trie) insertRecursive(origNode node, key []byte, pos int, value node) (
|
||||
} else {
|
||||
updated, nn = t.insertRecursive(child, key, pos+1, value)
|
||||
if updated {
|
||||
t.evictNodeFromHashMap(n)
|
||||
n.Children[key[pos]] = nn
|
||||
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) {
|
||||
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) {
|
||||
case *shortNode:
|
||||
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
|
||||
// check.
|
||||
if short, ok := child.(*shortNode); ok {
|
||||
t.evictNodeFromHashMap(child)
|
||||
k := make([]byte, len(short.Key)+1)
|
||||
k[0] = byte(pos)
|
||||
copy(k[1:], short.Key)
|
||||
@ -854,7 +831,6 @@ func (t *Trie) deleteRecursive(origNode node, key []byte, keyStart int, preserve
|
||||
}
|
||||
|
||||
if removeNodeEntirely {
|
||||
t.evictNodeFromHashMap(n)
|
||||
updated = true
|
||||
touchKey := key[:keyStart+matchlen]
|
||||
if touchKey[len(touchKey)-1] == 16 {
|
||||
@ -871,7 +847,6 @@ func (t *Trie) deleteRecursive(origNode node, key []byte, keyStart int, preserve
|
||||
if !updated {
|
||||
newNode = n
|
||||
} else {
|
||||
t.evictNodeFromHashMap(n)
|
||||
if nn == nil {
|
||||
newNode = nil
|
||||
} else {
|
||||
@ -905,7 +880,6 @@ func (t *Trie) deleteRecursive(origNode node, key []byte, keyStart int, preserve
|
||||
if !updated {
|
||||
newNode = n
|
||||
} else {
|
||||
t.evictNodeFromHashMap(n)
|
||||
if nn == nil {
|
||||
newNode = t.convertToShortNode(n.child2, uint(i2))
|
||||
} else {
|
||||
@ -919,7 +893,6 @@ func (t *Trie) deleteRecursive(origNode node, key []byte, keyStart int, preserve
|
||||
if !updated {
|
||||
newNode = n
|
||||
} else {
|
||||
t.evictNodeFromHashMap(n)
|
||||
if nn == nil {
|
||||
newNode = t.convertToShortNode(n.child1, uint(i1))
|
||||
} else {
|
||||
@ -940,7 +913,6 @@ func (t *Trie) deleteRecursive(origNode node, key []byte, keyStart int, preserve
|
||||
if !updated {
|
||||
newNode = n
|
||||
} else {
|
||||
t.evictNodeFromHashMap(n)
|
||||
n.Children[key[keyStart]] = nn
|
||||
// Check how many non-nil entries are left after deleting and
|
||||
// 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 {
|
||||
h := t.newHasherFunc()
|
||||
if debug.IsGetNodeData() {
|
||||
h.callback = func(key common.Hash, nd node) {
|
||||
t.hashMap[key] = nd
|
||||
}
|
||||
}
|
||||
return h
|
||||
return t.newHasherFunc()
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
t.evictSubtreeFromHashMap(nd)
|
||||
|
||||
var hn common.Hash
|
||||
if nd == nil {
|
||||
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 {
|
||||
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/ledgerwatch/erigon/common"
|
||||
"github.com/ledgerwatch/erigon/common/debug"
|
||||
"github.com/ledgerwatch/erigon/core/types/accounts"
|
||||
"github.com/ledgerwatch/erigon/crypto"
|
||||
"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 {
|
||||
array := make([]byte, length)
|
||||
for i := uint(0); i < length; i++ {
|
||||
|
Loading…
Reference in New Issue
Block a user