trie: refresh cache generations on subsequent reads

This commit is contained in:
Péter Szilágyi 2018-10-08 12:21:06 +03:00
parent f95811e65b
commit d7a90c71c1
No known key found for this signature in database
GPG key ID: E9AE538CEDF8293D
2 changed files with 26 additions and 11 deletions

View file

@ -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:

View file

@ -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)
}
}