Skip to content
This repository has been archived by the owner on Dec 1, 2023. It is now read-only.

Commit

Permalink
Merge pull request #4 from binance-chain/develop
Browse files Browse the repository at this point in the history
release iavl
  • Loading branch information
ackratos authored Mar 4, 2019
2 parents de07409 + 1e35b68 commit 65e487d
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 16 deletions.
22 changes: 21 additions & 1 deletion immutable_tree.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package iavl

import (
"bytes"
"fmt"
"strings"

Expand All @@ -24,10 +25,14 @@ func NewImmutableTree(db dbm.DB, cacheSize int) *ImmutableTree {
}
return &ImmutableTree{
// NodeDB-backed Tree.
ndb: newNodeDB(db, cacheSize),
ndb: NewNodeDB(db, cacheSize),
}
}

func GetRoot(t *ImmutableTree) *Node {
return t.root
}

// String returns a string representation of Tree.
func (t *ImmutableTree) String() string {
leaves := []string{}
Expand Down Expand Up @@ -114,6 +119,21 @@ func (t *ImmutableTree) Iterate(fn func(key []byte, value []byte) bool) (stopped
})
}

// used by state syncing
func (t *ImmutableTree) IterateFirst(fn func(nodeBytes []byte)) {
if t.root == nil {
return
}
t.root.traverseFirst(t, true, func(node *Node) bool {
var b bytes.Buffer
if err := node.writeBytes(&b); err != nil {
panic(err)
}
fn(b.Bytes())
return false
})
}

// IterateRange makes a callback for all nodes with key between start and end non-inclusive.
// If either are nil, then it is open on that side (nil, nil is the same as Iterate)
func (t *ImmutableTree) IterateRange(start, end []byte, ascending bool, fn func(key []byte, value []byte) bool) (stopped bool) {
Expand Down
12 changes: 8 additions & 4 deletions mutable_tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ type MutableTree struct {

// NewMutableTree returns a new tree with the specified cache size and datastore.
func NewMutableTree(db dbm.DB, cacheSize int) *MutableTree {
ndb := newNodeDB(db, cacheSize)
ndb := NewNodeDB(db, cacheSize)
head := &ImmutableTree{ndb: ndb}

return &MutableTree{
Expand Down Expand Up @@ -270,7 +270,7 @@ func (tree *MutableTree) LoadVersionForOverwriting(targetVersion int64) (int64,
if err != nil {
return latestVersion, err
}
tree.deleteVersionsFrom(targetVersion+1)
tree.deleteVersionsFrom(targetVersion + 1)
return targetVersion, nil
}

Expand Down Expand Up @@ -343,13 +343,13 @@ func (tree *MutableTree) SaveVersion() ([]byte, int64, error) {
// removed.
debug("SAVE EMPTY TREE %v\n", version)
tree.ndb.SaveOrphans(version, tree.orphans)
tree.ndb.SaveEmptyRoot(version)
tree.ndb.SaveEmptyRoot(version, false)
} else {
debug("SAVE TREE %v\n", version)
// Save the current tree.
tree.ndb.SaveBranch(tree.root)
tree.ndb.SaveOrphans(version, tree.orphans)
tree.ndb.SaveRoot(tree.root, version)
tree.ndb.SaveRoot(tree.root, version, false)
}
tree.ndb.Commit()
tree.version = version
Expand Down Expand Up @@ -501,3 +501,7 @@ func (tree *MutableTree) addOrphans(orphans []*Node) {
tree.orphans[string(node.hash)] = node.version
}
}

func (tree *MutableTree) GetVersions() map[int64]bool {
return tree.versions
}
20 changes: 18 additions & 2 deletions node.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,10 @@ func (node *Node) clone(version int64) *Node {
}
}

func Key(node *Node) []byte { return node.key }
func Value(node *Node) []byte { return node.value }

func IsLeaf(node *Node) bool { return node.isLeaf() }
func (node *Node) isLeaf() bool {
return node.height == 0
}
Expand Down Expand Up @@ -194,6 +198,7 @@ func (node *Node) getByIndex(t *ImmutableTree, index int64) (key []byte, value [

// Computes the hash of the node without computing its descendants. Must be
// called on nodes which have descendant node hashes already computed.
func Hash(node *Node) []byte { return node._hash() }
func (node *Node) _hash() []byte {
if node.hash != nil {
return node.hash
Expand Down Expand Up @@ -341,18 +346,22 @@ func (node *Node) writeBytes(w io.Writer) cmn.Error {
return nil
}

func GetLeftNode(node *Node, t *ImmutableTree) *Node { return node.getLeftNode(t) }
func (node *Node) getLeftNode(t *ImmutableTree) *Node {
if node.leftNode != nil {
return node.leftNode
}
return t.ndb.GetNode(node.leftHash)
node.leftNode = t.ndb.GetNode(node.leftHash)
return node.leftNode
}

func GetRightNode(node *Node, t *ImmutableTree) *Node { return node.getRightNode(t) }
func (node *Node) getRightNode(t *ImmutableTree) *Node {
if node.rightNode != nil {
return node.rightNode
}
return t.ndb.GetNode(node.rightHash)
node.rightNode = t.ndb.GetNode(node.rightHash)
return node.rightNode
}

// NOTE: mutates height and size
Expand All @@ -372,6 +381,13 @@ func (node *Node) traverse(t *ImmutableTree, ascending bool, cb func(*Node) bool
})
}

// traverseFirst is a wrapper over traverseInRange when we want the whole tree and will traverse the leaf nodes
func (node *Node) traverseFirst(t *ImmutableTree, ascending bool, cb func(*Node) bool) bool {
return node.traverseInRange(t, nil, nil, ascending, false, 0, func(node *Node, depth uint8) bool {
return cb(node)
})
}

func (node *Node) traverseWithDepth(t *ImmutableTree, ascending bool, cb func(*Node, uint8) bool) bool {
return node.traverseInRange(t, nil, nil, ascending, false, 0, cb)
}
Expand Down
14 changes: 7 additions & 7 deletions nodedb.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ type nodeDB struct {
nodeCacheQueue *list.List // LRU queue of cache elements. Used for deletion.
}

func newNodeDB(db dbm.DB, cacheSize int) *nodeDB {
func NewNodeDB(db dbm.DB, cacheSize int) *nodeDB {
ndb := &nodeDB{
db: db,
batch: db.NewBatch(),
Expand Down Expand Up @@ -350,23 +350,23 @@ func (ndb *nodeDB) getRoots() (map[int64][]byte, error) {

// SaveRoot creates an entry on disk for the given root, so that it can be
// loaded later.
func (ndb *nodeDB) SaveRoot(root *Node, version int64) error {
func (ndb *nodeDB) SaveRoot(root *Node, version int64, isFirstVersion bool) error {
if len(root.hash) == 0 {
panic("Hash should not be empty")
}
return ndb.saveRoot(root.hash, version)
return ndb.saveRoot(root.hash, version, isFirstVersion)
}

// SaveEmptyRoot creates an entry on disk for an empty root.
func (ndb *nodeDB) SaveEmptyRoot(version int64) error {
return ndb.saveRoot([]byte{}, version)
func (ndb *nodeDB) SaveEmptyRoot(version int64, isFirstVersion bool) error {
return ndb.saveRoot([]byte{}, version, isFirstVersion)
}

func (ndb *nodeDB) saveRoot(hash []byte, version int64) error {
func (ndb *nodeDB) saveRoot(hash []byte, version int64, isFirstVersion bool) error {
ndb.mtx.Lock()
defer ndb.mtx.Unlock()

if version != ndb.getLatestVersion()+1 {
if !isFirstVersion && version != ndb.getLatestVersion()+1 {
return fmt.Errorf("Must save consecutive versions. Expected %d, got %d", ndb.getLatestVersion()+1, version)
}

Expand Down
4 changes: 2 additions & 2 deletions tree_dotgraph.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,12 @@ func WriteDOTGraph(w io.Writer, tree *ImmutableTree, paths []PathToLeaf) {
}
shortHash := graphNode.Hash[:7]

graphNode.Label = mkLabel(fmt.Sprintf("%s", node.key), 16, "sans-serif")
graphNode.Label = mkLabel(fmt.Sprintf("%x", node.key), 16, "sans-serif")
graphNode.Label += mkLabel(shortHash, 10, "monospace")
graphNode.Label += mkLabel(fmt.Sprintf("version=%d", node.version), 10, "monospace")

if node.value != nil {
graphNode.Label += mkLabel(string(node.value), 10, "sans-serif")
graphNode.Label += mkLabel(fmt.Sprintf("%x", node.value), 10, "sans-serif")
}

if node.height == 0 {
Expand Down
1 change: 1 addition & 0 deletions tree_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ func TestVersionedRandomTree(t *testing.T) {

require.Len(tree.versions, 1, "tree must have one version left")
tr, err := tree.GetImmutable(int64(versions))
tr.nodeSize() // deliberately link left/right nodes with parents
require.NoError(err, "GetImmutable should not error for version %d", versions)
require.Equal(tr.root, tree.root)

Expand Down

0 comments on commit 65e487d

Please sign in to comment.