Skip to content

Commit

Permalink
Merge PR #148: Implement LazyLoadVersion
Browse files Browse the repository at this point in the history
  • Loading branch information
alexanderbez committed Jul 1, 2019
2 parents a0c58a2 + f431f43 commit 41918de
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 3 deletions.
53 changes: 50 additions & 3 deletions mutable_tree.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,21 +224,66 @@ func (tree *MutableTree) Load() (int64, error) {
return tree.LoadVersion(int64(0))
}

// LazyLoadVersion attempts to lazy load only the specified target version
// without loading previous roots/versions. Lazy loading should be used in cases
// where only reads are expected. Any writes to a lazy loaded tree may result in
// unexpected behavior. If the targetVersion is non-positive, the latest version
// will be loaded by default. If the latest version is non-positive, this method
// performs a no-op. Otherwise, if the root does not exist, an error will be
// returned.
func (tree *MutableTree) LazyLoadVersion(targetVersion int64) (int64, error) {
latestVersion := tree.ndb.getLatestVersion()
if latestVersion < targetVersion {
return latestVersion, fmt.Errorf("wanted to load target %d but only found up to %d", targetVersion, latestVersion)
}

// no versions have been saved if the latest version is non-positive
if latestVersion <= 0 {
return 0, nil
}

// default to the latest version if the targeted version is non-positive
if targetVersion <= 0 {
targetVersion = latestVersion
}

rootHash := tree.ndb.getRoot(targetVersion)
if rootHash == nil {
return latestVersion, ErrVersionDoesNotExist
}

tree.versions[targetVersion] = true

iTree := &ImmutableTree{
ndb: tree.ndb,
version: targetVersion,
root: tree.ndb.GetNode(rootHash),
}

tree.orphans = map[string]int64{}
tree.ImmutableTree = iTree
tree.lastSaved = iTree.clone()

return targetVersion, nil
}

// Returns the version number of the latest version found
func (tree *MutableTree) LoadVersion(targetVersion int64) (int64, error) {
roots, err := tree.ndb.getRoots()
if err != nil {
return 0, err
}

if len(roots) == 0 {
return 0, nil
}

latestVersion := int64(0)

var latestRoot []byte
for version, r := range roots {
tree.versions[version] = true
if version > latestVersion &&
(targetVersion == 0 || version <= targetVersion) {
if version > latestVersion && (targetVersion == 0 || version <= targetVersion) {
latestVersion = version
latestRoot = r
}
Expand All @@ -253,13 +298,15 @@ func (tree *MutableTree) LoadVersion(targetVersion int64) (int64, error) {
ndb: tree.ndb,
version: latestVersion,
}

if len(latestRoot) != 0 {
t.root = tree.ndb.GetNode(latestRoot)
}

tree.orphans = map[string]int64{}
tree.ImmutableTree = t
tree.lastSaved = t.clone()

return latestVersion, nil
}

Expand All @@ -270,7 +317,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
39 changes: 39 additions & 0 deletions tree_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package iavl
import (
"bytes"
"flag"
"fmt"
"os"
"runtime"
"strconv"
Expand Down Expand Up @@ -1134,6 +1135,44 @@ func TestRollback(t *testing.T) {
require.Equal([]byte("v"), val)
}

func TestLazyLoadVersion(t *testing.T) {
mdb := db.NewMemDB()
tree := NewMutableTree(mdb, 0)
maxVersions := 10

version, err := tree.LazyLoadVersion(0)
require.NoError(t, err, "unexpected error")
require.Equal(t, version, int64(0), "expected latest version to be zero")

for i := 0; i < maxVersions; i++ {
tree.Set([]byte(fmt.Sprintf("key_%d", i+1)), []byte(fmt.Sprintf("value_%d", i+1)))

_, _, err := tree.SaveVersion()
require.NoError(t, err, "SaveVersion should not fail")
}

// require the ability to lazy load the latest version
version, err = tree.LazyLoadVersion(int64(maxVersions))
require.NoError(t, err, "unexpected error when lazy loading version")
require.Equal(t, version, int64(maxVersions))

_, value := tree.Get([]byte(fmt.Sprintf("key_%d", maxVersions)))
require.Equal(t, value, []byte(fmt.Sprintf("value_%d", maxVersions)), "unexpected value")

// require the ability to lazy load an older version
version, err = tree.LazyLoadVersion(int64(maxVersions - 1))
require.NoError(t, err, "unexpected error when lazy loading version")
require.Equal(t, version, int64(maxVersions-1))

_, value = tree.Get([]byte(fmt.Sprintf("key_%d", maxVersions-1)))
require.Equal(t, value, []byte(fmt.Sprintf("value_%d", maxVersions-1)), "unexpected value")

// require the inability to lazy load a non-valid version
version, err = tree.LazyLoadVersion(int64(maxVersions + 1))
require.Error(t, err, "expected error when lazy loading version")
require.Equal(t, version, int64(maxVersions))
}

func TestOverwrite(t *testing.T) {
require := require.New(t)

Expand Down

0 comments on commit 41918de

Please sign in to comment.