mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 10:22:23 +00:00
trie: refresh cache generations on subsequent reads
This commit is contained in:
parent
f95811e65b
commit
d7a90c71c1
2 changed files with 26 additions and 11 deletions
12
trie/trie.go
12
trie/trie.go
|
|
@ -151,18 +151,26 @@ func (t *Trie) tryGet(origNode node, key []byte, pos int) (value []byte, newnode
|
|||
return nil, n, false, nil
|
||||
}
|
||||
value, newnode, didResolve, err = t.tryGet(n.Val, key, pos+len(n.Key))
|
||||
if err == nil && didResolve {
|
||||
if err == nil && (didResolve || n.canUnload(t.cachegen, t.cachelimit/2)) {
|
||||
// Subtrie expanded or generation old enough to reset
|
||||
n = n.copy()
|
||||
n.Val = newnode
|
||||
n.flags.gen = t.cachegen
|
||||
|
||||
// Fake a resolution so all nodes towards the root are refreshed
|
||||
didResolve = true
|
||||
}
|
||||
return value, n, didResolve, err
|
||||
case *fullNode:
|
||||
value, newnode, didResolve, err = t.tryGet(n.Children[key[pos]], key, pos+1)
|
||||
if err == nil && didResolve {
|
||||
if err == nil && (didResolve || n.canUnload(t.cachegen, t.cachelimit/2)) {
|
||||
// Subtrie expanded or generation old enough to reset
|
||||
n = n.copy()
|
||||
n.flags.gen = t.cachegen
|
||||
n.Children[key[pos]] = newnode
|
||||
|
||||
// Fake a resolution so all nodes towards the root are refreshed
|
||||
didResolve = true
|
||||
}
|
||||
return value, n, didResolve, err
|
||||
case hashNode:
|
||||
|
|
|
|||
|
|
@ -339,21 +339,28 @@ func TestCacheUnload(t *testing.T) {
|
|||
root, _ := trie.Commit(nil)
|
||||
trie.db.Commit(root, true)
|
||||
|
||||
// Commit the trie repeatedly and access key1.
|
||||
// The branch containing it is loaded from DB exactly two times:
|
||||
// in the 0th and 6th iteration.
|
||||
// Commit the trie repeatedly and update key1. The branch containing it is
|
||||
// loaded from DB once, in the 0th iteration. We attempt to load key2 before
|
||||
// and after cache-generation numer of iterations. In both cases it should
|
||||
// reach out to disk.
|
||||
db := &countingDB{Database: trie.db.diskdb, gets: make(map[string]int)}
|
||||
trie, _ = New(root, NewDatabase(db))
|
||||
trie.SetCacheLimit(5)
|
||||
for i := 0; i < 12; i++ {
|
||||
getString(trie, key1)
|
||||
|
||||
getString(trie, key2)
|
||||
for i := 0; i < 6; i++ {
|
||||
updateString(trie, key1, fmt.Sprintf("this is the branch of key1, update #%d", i))
|
||||
trie.Commit(nil)
|
||||
}
|
||||
getString(trie, key2)
|
||||
|
||||
// Check that it got loaded two times.
|
||||
for dbkey, count := range db.gets {
|
||||
if count != 2 {
|
||||
t.Errorf("db key %x loaded %d times, want %d times", []byte(dbkey), count, 2)
|
||||
loads := make(map[int]int)
|
||||
for _, count := range db.gets {
|
||||
loads[count]++
|
||||
}
|
||||
if len(loads) != 2 || loads[1] != 3 || loads[2] != 1 {
|
||||
t.Fatalf("Mismatching number of database loads: want map[1:3 2:1], have %v", loads)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue