mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-26 06:36:43 +00:00
Merge ddf63d3c06 into f2ae2f7eef
This commit is contained in:
commit
3abf3580a3
8 changed files with 53 additions and 36 deletions
4
Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db.go
generated
vendored
4
Godeps/_workspace/src/github.com/syndtr/goleveldb/leveldb/db.go
generated
vendored
|
|
@ -1017,6 +1017,10 @@ func (db *DB) SizeOf(ranges []util.Range) (Sizes, error) {
|
|||
return sizes, nil
|
||||
}
|
||||
|
||||
func (db *DB) ReturnBuffer(b []byte) {
|
||||
db.s.tops.bpool.Put(b)
|
||||
}
|
||||
|
||||
// Close closes the DB. This will also releases any outstanding snapshot,
|
||||
// abort any in-flight compaction and discard open transaction.
|
||||
//
|
||||
|
|
|
|||
|
|
@ -142,6 +142,10 @@ func (self *LDBDatabase) Get(key []byte) ([]byte, error) {
|
|||
//return rle.Decompress(dat)
|
||||
}
|
||||
|
||||
func (self *LDBDatabase) ReturnBuffer(b []byte) {
|
||||
self.db.ReturnBuffer(b)
|
||||
}
|
||||
|
||||
// Delete deletes the key from the queue and database
|
||||
func (self *LDBDatabase) Delete(key []byte) error {
|
||||
// Measure the database delete latency, if requested
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@ type Database interface {
|
|||
Delete(key []byte) error
|
||||
Close()
|
||||
NewBatch() Batch
|
||||
|
||||
ReturnBuffer([]byte)
|
||||
}
|
||||
|
||||
type Batch interface {
|
||||
|
|
|
|||
|
|
@ -62,6 +62,9 @@ func (db *MemDatabase) Get(key []byte) ([]byte, error) {
|
|||
return nil, errors.New("not found")
|
||||
}
|
||||
|
||||
func (db *MemDatabase) ReturnBuffer(b []byte) {
|
||||
}
|
||||
|
||||
func (db *MemDatabase) Keys() [][]byte {
|
||||
db.lock.RLock()
|
||||
defer db.lock.RUnlock()
|
||||
|
|
|
|||
|
|
@ -85,11 +85,13 @@ func (h *hasher) hash(n node, db DatabaseWriter, force bool) (node, node, error)
|
|||
cn.flags.hash = cachedHash
|
||||
if db != nil {
|
||||
cn.flags.dirty = false
|
||||
cn.flags.new = false
|
||||
}
|
||||
case *fullNode:
|
||||
cn.flags.hash = cachedHash
|
||||
if db != nil {
|
||||
cn.flags.dirty = false
|
||||
cn.flags.new = false
|
||||
}
|
||||
}
|
||||
return hashed, cached, nil
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ type nodeFlag struct {
|
|||
hash hashNode // cached hash of the node (may be nil)
|
||||
gen uint16 // cache generation counter
|
||||
dirty bool // whether the node has changes that must be written to the database
|
||||
new bool // whether the node was allocated in the current generation
|
||||
}
|
||||
|
||||
// canUnload tells whether a node can be unloaded.
|
||||
|
|
@ -138,7 +139,7 @@ func decodeShort(hash, buf, elems []byte, cachegen uint16) (node, error) {
|
|||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
flag := nodeFlag{hash: hash, gen: cachegen}
|
||||
flag := nodeFlag{hash: hash, gen: cachegen, new: true}
|
||||
key := compactDecode(kbuf)
|
||||
if key[len(key)-1] == 16 {
|
||||
// value node
|
||||
|
|
@ -156,7 +157,7 @@ func decodeShort(hash, buf, elems []byte, cachegen uint16) (node, error) {
|
|||
}
|
||||
|
||||
func decodeFull(hash, buf, elems []byte, cachegen uint16) (*fullNode, error) {
|
||||
n := &fullNode{flags: nodeFlag{hash: hash, gen: cachegen}}
|
||||
n := &fullNode{flags: nodeFlag{hash: hash, gen: cachegen, new: true}}
|
||||
for i := 0; i < 16; i++ {
|
||||
cld, rest, err := decodeRef(elems, cachegen)
|
||||
if err != nil {
|
||||
|
|
|
|||
60
trie/trie.go
60
trie/trie.go
|
|
@ -23,6 +23,7 @@ import (
|
|||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/crypto/sha3"
|
||||
"github.com/ethereum/go-ethereum/ethdb"
|
||||
"github.com/ethereum/go-ethereum/logger"
|
||||
"github.com/ethereum/go-ethereum/logger/glog"
|
||||
"github.com/rcrowley/go-metrics"
|
||||
|
|
@ -98,7 +99,7 @@ func (t *Trie) SetCacheLimit(l uint16) {
|
|||
|
||||
// newFlag returns the cache flag value for a newly created node.
|
||||
func (t *Trie) newFlag() nodeFlag {
|
||||
return nodeFlag{dirty: true, gen: t.cachegen}
|
||||
return nodeFlag{new: true, dirty: true, gen: t.cachegen}
|
||||
}
|
||||
|
||||
// New creates a trie with an existing root node from db.
|
||||
|
|
@ -142,46 +143,52 @@ func (t *Trie) Get(key []byte) []byte {
|
|||
// If a node was not found in the database, a MissingNodeError is returned.
|
||||
func (t *Trie) TryGet(key []byte) ([]byte, error) {
|
||||
key = compactHexDecode(key)
|
||||
value, newroot, didResolve, err := t.tryGet(t.root, key, 0)
|
||||
if err == nil && didResolve {
|
||||
value, newroot, err := t.tryGet(t.root, key, 0)
|
||||
if err == nil {
|
||||
t.root = newroot
|
||||
}
|
||||
return value, err
|
||||
}
|
||||
|
||||
func (t *Trie) tryGet(origNode node, key []byte, pos int) (value []byte, newnode node, didResolve bool, err error) {
|
||||
func (t *Trie) tryGet(origNode node, key []byte, pos int) (value []byte, newnode node, err error) {
|
||||
switch n := (origNode).(type) {
|
||||
case nil:
|
||||
return nil, nil, false, nil
|
||||
return nil, nil, nil
|
||||
case valueNode:
|
||||
return n, n, false, nil
|
||||
return n, n, nil
|
||||
case *shortNode:
|
||||
if len(key)-pos < len(n.Key) || !bytes.Equal(n.Key, key[pos:pos+len(n.Key)]) {
|
||||
// key not found in trie
|
||||
return nil, n, false, nil
|
||||
return nil, n, nil
|
||||
}
|
||||
value, newnode, didResolve, err = t.tryGet(n.Val, key, pos+len(n.Key))
|
||||
if err == nil && didResolve {
|
||||
n = n.copy()
|
||||
n.Val = newnode
|
||||
value, newnode, err = t.tryGet(n.Val, key, pos+len(n.Key))
|
||||
if err == nil {
|
||||
if !n.flags.new {
|
||||
n = n.copy()
|
||||
n.flags.new = true
|
||||
}
|
||||
n.flags.gen = t.cachegen
|
||||
n.Val = newnode
|
||||
}
|
||||
return value, n, didResolve, err
|
||||
return value, n, err
|
||||
case *fullNode:
|
||||
value, newnode, didResolve, err = t.tryGet(n.Children[key[pos]], key, pos+1)
|
||||
if err == nil && didResolve {
|
||||
n = n.copy()
|
||||
value, newnode, err = t.tryGet(n.Children[key[pos]], key, pos+1)
|
||||
if err == nil {
|
||||
if !n.flags.new {
|
||||
n = n.copy()
|
||||
n.flags.new = true
|
||||
}
|
||||
n.flags.gen = t.cachegen
|
||||
n.Children[key[pos]] = newnode
|
||||
}
|
||||
return value, n, didResolve, err
|
||||
return value, n, err
|
||||
case hashNode:
|
||||
child, err := t.resolveHash(n, key[:pos], key[pos:])
|
||||
if err != nil {
|
||||
return nil, n, true, err
|
||||
return nil, n, err
|
||||
}
|
||||
value, newnode, _, err := t.tryGet(child, key, pos)
|
||||
return value, newnode, true, err
|
||||
value, newnode, err := t.tryGet(child, key, pos)
|
||||
return value, newnode, err
|
||||
default:
|
||||
panic(fmt.Sprintf("%T: invalid node: %v", origNode, origNode))
|
||||
}
|
||||
|
|
@ -283,11 +290,7 @@ func (t *Trie) insert(n node, prefix, key []byte, value node) (bool, node, error
|
|||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
dirty, nn, err := t.insert(rn, prefix, key, value)
|
||||
if !dirty || err != nil {
|
||||
return false, rn, err
|
||||
}
|
||||
return true, nn, nil
|
||||
return t.insert(rn, prefix, key, value)
|
||||
|
||||
default:
|
||||
panic(fmt.Sprintf("%T: invalid node: %v", n, n))
|
||||
|
|
@ -414,11 +417,7 @@ func (t *Trie) delete(n node, prefix, key []byte) (bool, node, error) {
|
|||
if err != nil {
|
||||
return false, nil, err
|
||||
}
|
||||
dirty, nn, err := t.delete(rn, prefix, key)
|
||||
if !dirty || err != nil {
|
||||
return false, rn, err
|
||||
}
|
||||
return true, nn, nil
|
||||
return t.delete(rn, prefix, key)
|
||||
|
||||
default:
|
||||
panic(fmt.Sprintf("%T: invalid node: %v (%v)", n, n, key))
|
||||
|
|
@ -453,6 +452,9 @@ func (t *Trie) resolveHash(n hashNode, prefix, suffix []byte) (node, error) {
|
|||
}
|
||||
}
|
||||
dec := mustDecodeNode(n, enc, t.cachegen)
|
||||
if edb, ok := t.db.(*ethdb.LDBDatabase); ok {
|
||||
edb.ReturnBuffer(enc)
|
||||
}
|
||||
return dec, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -329,8 +329,7 @@ func TestCacheUnload(t *testing.T) {
|
|||
root, _ := trie.Commit()
|
||||
|
||||
// Commit the trie repeatedly and access key1.
|
||||
// The branch containing it is loaded from DB exactly two times:
|
||||
// in the 0th and 6th iteration.
|
||||
// The branch containing it is loaded from DB exactly once.
|
||||
db := &countingDB{Database: trie.db, gets: make(map[string]int)}
|
||||
trie, _ = New(root, db)
|
||||
trie.SetCacheLimit(5)
|
||||
|
|
@ -339,10 +338,10 @@ func TestCacheUnload(t *testing.T) {
|
|||
trie.Commit()
|
||||
}
|
||||
|
||||
// Check that it got loaded two times.
|
||||
// Check that it got loaded once.
|
||||
for dbkey, count := range db.gets {
|
||||
if count != 2 {
|
||||
t.Errorf("db key %x loaded %d times, want %d times", []byte(dbkey), count, 2)
|
||||
if count != 1 {
|
||||
t.Errorf("db key %x loaded %d times, want %d times", []byte(dbkey), count, 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue