Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clone w/ version; Remove orphanIndex #19

Merged
merged 5 commits into from
Dec 9, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
vendor
.glide
*.swp
*.swo

# created in test code
test.db
Expand Down
22 changes: 11 additions & 11 deletions basic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ func TestBasic(t *testing.T) {

// Test 0x00
{
idx, val := tree.Get([]byte{0x00})
idx, val := tree.Get64([]byte{0x00})
if val != nil {
t.Errorf("Expected no value to exist")
}
Expand All @@ -46,7 +46,7 @@ func TestBasic(t *testing.T) {

// Test "1"
{
idx, val := tree.Get([]byte("1"))
idx, val := tree.Get64([]byte("1"))
if val == nil {
t.Errorf("Expected value to exist")
}
Expand All @@ -60,7 +60,7 @@ func TestBasic(t *testing.T) {

// Test "2"
{
idx, val := tree.Get([]byte("2"))
idx, val := tree.Get64([]byte("2"))
if val == nil {
t.Errorf("Expected value to exist")
}
Expand All @@ -74,7 +74,7 @@ func TestBasic(t *testing.T) {

// Test "4"
{
idx, val := tree.Get([]byte("4"))
idx, val := tree.Get64([]byte("4"))
if val != nil {
t.Errorf("Expected no value to exist")
}
Expand All @@ -88,7 +88,7 @@ func TestBasic(t *testing.T) {

// Test "6"
{
idx, val := tree.Get([]byte("6"))
idx, val := tree.Get64([]byte("6"))
if val != nil {
t.Errorf("Expected no value to exist")
}
Expand All @@ -103,7 +103,7 @@ func TestBasic(t *testing.T) {

func TestUnit(t *testing.T) {

expectHash := func(tree *Tree, hashCount int) {
expectHash := func(tree *Tree, hashCount int64) {
// ensure number of new hash calculations is as expected.
hash, count := tree.hashWithCount()
if count != hashCount {
Expand All @@ -121,7 +121,7 @@ func TestUnit(t *testing.T) {
}
}

expectSet := func(tree *Tree, i int, repr string, hashCount int) {
expectSet := func(tree *Tree, i int, repr string, hashCount int64) {
origNode := tree.root
updated := tree.Set(i2b(i), []byte{})
// ensure node was added & structure is as expected.
Expand All @@ -134,7 +134,7 @@ func TestUnit(t *testing.T) {
tree.root = origNode
}

expectRemove := func(tree *Tree, i int, repr string, hashCount int) {
expectRemove := func(tree *Tree, i int, repr string, hashCount int64) {
origNode := tree.root
value, removed := tree.Remove(i2b(i))
// ensure node was added & structure is as expected.
Expand Down Expand Up @@ -249,7 +249,7 @@ func TestIntegration(t *testing.T) {
if has := tree.Has([]byte(randstr(12))); has {
t.Error("Table has extra key")
}
if _, val := tree.Get([]byte(r.key)); string(val) != string(r.value) {
if _, val := tree.Get64([]byte(r.key)); string(val) != string(r.value) {
t.Error("wrong value")
}
}
Expand All @@ -267,7 +267,7 @@ func TestIntegration(t *testing.T) {
if has := tree.Has([]byte(randstr(12))); has {
t.Error("Table has extra key")
}
_, val := tree.Get([]byte(r.key))
_, val := tree.Get64([]byte(r.key))
if string(val) != string(r.value) {
t.Error("wrong value")
}
Expand Down Expand Up @@ -379,7 +379,7 @@ func TestPersistence(t *testing.T) {
t2 := NewVersionedTree(0, db)
t2.Load()
for key, value := range records {
_, t2value := t2.Get([]byte(key))
_, t2value := t2.Get64([]byte(key))
if string(t2value) != value {
t.Fatalf("Invalid value. Expected %v, got %v", value, t2value)
}
Expand Down
11 changes: 11 additions & 0 deletions logger.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package iavl

import (
"fmt"
)

func debug(format string, args ...interface{}) {
if false {
fmt.Printf(format, args...)
}
}
71 changes: 38 additions & 33 deletions node.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package iavl

// NOTE: This file favors int64 as opposed to int for size/counts.
// The Tree on the other hand favors int. This is intentional.

import (
"bytes"
"fmt"
Expand All @@ -8,7 +11,6 @@ import (
"golang.org/x/crypto/ripemd160"

"github.com/tendermint/go-wire"
cmn "github.com/tendermint/tmlibs/common"
)

// Node represents a node in a Tree.
Expand All @@ -17,7 +19,7 @@ type Node struct {
value []byte
version int64
height int8
size int
size int64
hash []byte
leftHash []byte
leftNode *Node
Expand Down Expand Up @@ -51,21 +53,18 @@ func MakeNode(buf []byte) (node *Node, err error) {
n := 1 // Keeps track of bytes read.
buf = buf[n:]

node.size, n, err = wire.GetVarint(buf)
if err != nil {
return nil, err
}
buf = buf[n:]
node.size = wire.GetInt64(buf)
buf = buf[8:]

node.version = wire.GetInt64(buf)
buf = buf[8:]

node.key, n, err = wire.GetByteSlice(buf)
if err != nil {
return nil, err
}
buf = buf[n:]

node.version = wire.GetInt64(buf)
buf = buf[8:]

// Read node body.

if node.isLeaf() {
Expand Down Expand Up @@ -100,14 +99,14 @@ func (node *Node) String() string {
}

// clone creates a shallow copy of a node with its hash set to nil.
func (node *Node) clone() *Node {
func (node *Node) clone(version int64) *Node {
if node.isLeaf() {
cmn.PanicSanity("Attempt to copy a leaf node")
panic("Attempt to copy a leaf node")
}
return &Node{
key: node.key,
height: node.height,
version: node.version,
version: version,
size: node.size,
hash: nil,
leftHash: node.leftHash,
Expand Down Expand Up @@ -138,7 +137,7 @@ func (node *Node) has(t *Tree, key []byte) (has bool) {
}

// Get a key under the node.
func (node *Node) get(t *Tree, key []byte) (index int, value []byte) {
func (node *Node) get(t *Tree, key []byte) (index int64, value []byte) {
if node.isLeaf() {
switch bytes.Compare(node.key, key) {
case -1:
Expand All @@ -160,7 +159,7 @@ func (node *Node) get(t *Tree, key []byte) (index int, value []byte) {
}
}

func (node *Node) getByIndex(t *Tree, index int) (key []byte, value []byte) {
func (node *Node) getByIndex(t *Tree, index int64) (key []byte, value []byte) {
if node.isLeaf() {
if index == 0 {
return node.key, node.value
Expand Down Expand Up @@ -189,7 +188,7 @@ func (node *Node) _hash() []byte {
hasher := ripemd160.New()
buf := new(bytes.Buffer)
if _, err := node.writeHashBytes(buf); err != nil {
cmn.PanicCrisis(err)
panic(err)
}
hasher.Write(buf.Bytes())
node.hash = hasher.Sum(nil)
Expand All @@ -199,7 +198,7 @@ func (node *Node) _hash() []byte {

// Hash the node and its descendants recursively. This usually mutates all
// descendant nodes. Returns the node hash and number of nodes hashed.
func (node *Node) hashWithCount() ([]byte, int) {
func (node *Node) hashWithCount() ([]byte, int64) {
if node.hash != nil {
return node.hash, 0
}
Expand All @@ -208,7 +207,7 @@ func (node *Node) hashWithCount() ([]byte, int) {
buf := new(bytes.Buffer)
_, hashCount, err := node.writeHashBytesRecursively(buf)
if err != nil {
cmn.PanicCrisis(err)
panic(err)
}
hasher.Write(buf.Bytes())
node.hash = hasher.Sum(nil)
Expand All @@ -220,17 +219,17 @@ func (node *Node) hashWithCount() ([]byte, int) {
// child hashes to be already set.
func (node *Node) writeHashBytes(w io.Writer) (n int, err error) {
wire.WriteInt8(node.height, w, &n, &err)
wire.WriteVarint(node.size, w, &n, &err)
wire.WriteInt64(node.size, w, &n, &err)
wire.WriteInt64(node.version, w, &n, &err)

// Key is not written for inner nodes, unlike writeBytes.

if node.isLeaf() {
wire.WriteByteSlice(node.key, w, &n, &err)
wire.WriteByteSlice(node.value, w, &n, &err)
wire.WriteInt64(node.version, w, &n, &err)
} else {
if node.leftHash == nil || node.rightHash == nil {
cmn.PanicSanity("Found an empty child hash")
panic("Found an empty child hash")
}
wire.WriteByteSlice(node.leftHash, w, &n, &err)
wire.WriteByteSlice(node.rightHash, w, &n, &err)
Expand All @@ -240,7 +239,7 @@ func (node *Node) writeHashBytes(w io.Writer) (n int, err error) {

// Writes the node's hash to the given io.Writer.
// This function has the side-effect of calling hashWithCount.
func (node *Node) writeHashBytesRecursively(w io.Writer) (n int, hashCount int, err error) {
func (node *Node) writeHashBytesRecursively(w io.Writer) (n int, hashCount int64, err error) {
if node.leftNode != nil {
leftHash, leftCount := node.leftNode.hashWithCount()
node.leftHash = leftHash
Expand All @@ -259,22 +258,22 @@ func (node *Node) writeHashBytesRecursively(w io.Writer) (n int, hashCount int,
// Writes the node as a serialized byte slice to the supplied io.Writer.
func (node *Node) writeBytes(w io.Writer) (n int, err error) {
wire.WriteInt8(node.height, w, &n, &err)
wire.WriteVarint(node.size, w, &n, &err)
wire.WriteInt64(node.size, w, &n, &err)
wire.WriteInt64(node.version, w, &n, &err)

// Unlike writeHashBytes, key is written for inner nodes.
wire.WriteByteSlice(node.key, w, &n, &err)
wire.WriteInt64(node.version, w, &n, &err)

if node.isLeaf() {
wire.WriteByteSlice(node.value, w, &n, &err)
} else {
if node.leftHash == nil {
cmn.PanicSanity("node.leftHash was nil in writeBytes")
panic("node.leftHash was nil in writeBytes")
}
wire.WriteByteSlice(node.leftHash, w, &n, &err)

if node.rightHash == nil {
cmn.PanicSanity("node.rightHash was nil in writeBytes")
panic("node.rightHash was nil in writeBytes")
}
wire.WriteByteSlice(node.rightHash, w, &n, &err)
}
Expand Down Expand Up @@ -311,7 +310,7 @@ func (node *Node) set(t *Tree, key []byte, value []byte) (
}
} else {
orphaned = append(orphaned, node)
node = node.clone()
node = node.clone(version)

if bytes.Compare(key, node.key) < 0 {
var leftOrphaned []*Node
Expand Down Expand Up @@ -341,6 +340,8 @@ func (node *Node) set(t *Tree, key []byte, value []byte) (
func (node *Node) remove(t *Tree, key []byte) (
newHash []byte, newNode *Node, newKey []byte, value []byte, orphaned []*Node,
) {
version := t.version + 1

if node.isLeaf() {
if bytes.Equal(key, node.key) {
return nil, nil, nil, node.value, []*Node{node}
Expand All @@ -362,7 +363,7 @@ func (node *Node) remove(t *Tree, key []byte) (
}
orphaned = append(orphaned, node)

newNode := node.clone()
newNode := node.clone(version)
newNode.leftHash, newNode.leftNode = newLeftHash, newLeftNode
newNode.calcHeightAndSize(t)
newNode, balanceOrphaned := newNode.balance(t)
Expand All @@ -382,7 +383,7 @@ func (node *Node) remove(t *Tree, key []byte) (
}
orphaned = append(orphaned, node)

newNode := node.clone()
newNode := node.clone(version)
newNode.rightHash, newNode.rightNode = newRightHash, newRightNode
if newKey != nil {
newNode.key = newKey
Expand Down Expand Up @@ -410,10 +411,12 @@ func (node *Node) getRightNode(t *Tree) *Node {

// Rotate right and return the new node and orphan.
func (node *Node) rotateRight(t *Tree) (newNode *Node, orphan *Node) {
version := t.version + 1

// TODO: optimize balance & rotate.
node = node.clone()
node = node.clone(version)
l := node.getLeftNode(t)
_l := l.clone()
_l := l.clone(version)

_lrHash, _lrCached := _l.rightHash, _l.rightNode
_l.rightHash, _l.rightNode = node.hash, node
Expand All @@ -427,10 +430,12 @@ func (node *Node) rotateRight(t *Tree) (newNode *Node, orphan *Node) {

// Rotate left and return the new node and orphan.
func (node *Node) rotateLeft(t *Tree) (newNode *Node, orphan *Node) {
version := t.version + 1

// TODO: optimize balance & rotate.
node = node.clone()
node = node.clone(version)
r := node.getRightNode(t)
_r := r.clone()
_r := r.clone(version)

_rlHash, _rlCached := _r.leftHash, _r.leftNode
_r.leftHash, _r.leftNode = node.hash, node
Expand Down
Loading