This commit is contained in:
Felix Lange 2016-10-19 13:40:04 +00:00 committed by GitHub
commit 91a17cafe3
6 changed files with 23 additions and 19 deletions

View file

@ -44,7 +44,7 @@ const (
maxPastTries = 12
// Trie cache generation limit.
maxTrieCacheGen = 120
maxTrieCacheGen = 10000
// Number of codehash->size associations to keep.
codeSizeCacheSize = 100000

View file

@ -49,15 +49,20 @@ func returnHasherToPool(h *hasher) {
hasherPool.Put(h)
}
// canUnload decides whether a node can be unloaded.
func (n *nodeFlag) canUnload(cachegen, cachelimit uint16, depth int) bool {
return !n.dirty && cachegen-n.gen >= cachelimit/uint16(depth+1)
}
// hash collapses a node down into a hash node, also returning a copy of the
// original node initialzied with the computed hash to replace the original one.
func (h *hasher) hash(n node, db DatabaseWriter, force bool) (node, node, error) {
func (h *hasher) hash(n node, db DatabaseWriter, force bool, depth int) (node, node, error) {
// If we're not storing the node, just hashing, use avaialble cached data
if hash, dirty := n.cache(); hash != nil {
if db == nil {
return hash, n, nil
}
if n.canUnload(h.cachegen, h.cachelimit) {
if n.canUnload(h.cachegen, h.cachelimit, depth) {
// Unload the node from cache. All of its subnodes will have a lower or equal
// cache generation number.
return hash, hash, nil
@ -67,7 +72,7 @@ func (h *hasher) hash(n node, db DatabaseWriter, force bool) (node, node, error)
}
}
// Trie not processed yet or needs storage, walk the children
collapsed, cached, err := h.hashChildren(n, db)
collapsed, cached, err := h.hashChildren(n, db, depth)
if err != nil {
return hashNode{}, n, err
}
@ -97,7 +102,7 @@ func (h *hasher) hash(n node, db DatabaseWriter, force bool) (node, node, error)
// hashChildren replaces the children of a node with their hashes if the encoded
// size of the child is larger than a hash, returning the collapsed node as well
// as a replacement for the original node with the child hashes cached in.
func (h *hasher) hashChildren(original node, db DatabaseWriter) (node, node, error) {
func (h *hasher) hashChildren(original node, db DatabaseWriter, depth int) (node, node, error) {
var err error
switch n := original.(type) {
@ -108,7 +113,7 @@ func (h *hasher) hashChildren(original node, db DatabaseWriter) (node, node, err
cached.Key = common.CopyBytes(n.Key)
if _, ok := n.Val.(valueNode); !ok {
collapsed.Val, cached.Val, err = h.hash(n.Val, db, false)
collapsed.Val, cached.Val, err = h.hash(n.Val, db, false, depth+1)
if err != nil {
return original, original, err
}
@ -124,7 +129,7 @@ func (h *hasher) hashChildren(original node, db DatabaseWriter) (node, node, err
for i := 0; i < 16; i++ {
if n.Children[i] != nil {
collapsed.Children[i], cached.Children[i], err = h.hash(n.Children[i], db, false)
collapsed.Children[i], cached.Children[i], err = h.hash(n.Children[i], db, false, depth+1)
if err != nil {
return original, original, err
}

View file

@ -30,7 +30,7 @@ var indices = []string{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b
type node interface {
fstring(string) string
cache() (hashNode, bool)
canUnload(cachegen, cachelimit uint16) bool
canUnload(cachegen, cachelimit uint16, depth int) bool
}
type (
@ -62,15 +62,14 @@ type nodeFlag struct {
dirty bool // whether the node has changes that must be written to the database
}
// canUnload tells whether a node can be unloaded.
func (n *nodeFlag) canUnload(cachegen, cachelimit uint16) bool {
return !n.dirty && cachegen-n.gen >= cachelimit
func (n *fullNode) canUnload(gen, limit uint16, depth int) bool {
return n.flags.canUnload(gen, limit, depth)
}
func (n *fullNode) canUnload(gen, limit uint16) bool { return n.flags.canUnload(gen, limit) }
func (n *shortNode) canUnload(gen, limit uint16) bool { return n.flags.canUnload(gen, limit) }
func (n hashNode) canUnload(uint16, uint16) bool { return false }
func (n valueNode) canUnload(uint16, uint16) bool { return false }
func (n *shortNode) canUnload(gen, limit uint16, depth int) bool {
return n.flags.canUnload(gen, limit, depth)
}
func (n hashNode) canUnload(uint16, uint16, int) bool { return false }
func (n valueNode) canUnload(uint16, uint16, int) bool { return false }
func (n *fullNode) cache() (hashNode, bool) { return n.flags.hash, n.flags.dirty }
func (n *shortNode) cache() (hashNode, bool) { return n.flags.hash, n.flags.dirty }

View file

@ -51,7 +51,7 @@ func TestCanUnload(t *testing.T) {
}
for _, test := range tests {
if got := test.flag.canUnload(test.cachegen, test.cachelimit); got != test.want {
if got := test.flag.canUnload(test.cachegen, test.cachelimit, 0); got != test.want {
t.Errorf("%+v\n got %t, want %t", test, got, test.want)
}
}

View file

@ -75,7 +75,7 @@ func (t *Trie) Prove(key []byte) []rlp.RawValue {
for i, n := range nodes {
// Don't bother checking for errors here since hasher panics
// if encoding doesn't work and we're not writing to any database.
n, _, _ = hasher.hashChildren(n, nil)
n, _, _ = hasher.hashChildren(n, nil, 0)
hn, _ := hasher.store(n, nil, false)
if _, ok := hn.(hashNode); ok || i == 0 {
// If the node's database encoding is a hash (or is the

View file

@ -493,5 +493,5 @@ func (t *Trie) hashRoot(db DatabaseWriter) (node, node, error) {
}
h := newHasher(t.cachegen, t.cachelimit)
defer returnHasherToPool(h)
return h.hash(t.root, db, true)
return h.hash(t.root, db, true, 0)
}