diff --git a/CHANGELOG.md b/CHANGELOG.md index 881799984..0add0ae41 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ - [#636](https://github.com/cosmos/iavl/pull/636) Speed up rollback method: `LoadVersionForOverwriting`. - [#654](https://github.com/cosmos/iavl/pull/654) Add API `TraverseStateChanges` to extract state changes from iavl versions. - [#638](https://github.com/cosmos/iavl/pull/638) Make LazyLoadVersion check the opts.InitialVersion, add API `LazyLoadVersionForOverwriting`. +- [#695](https://github.com/cosmos/iavl/pull/695) Add API `SaveChangeSet` to save the changeset as a new version. ## 0.19.4 (October 28, 2022) diff --git a/diff_test.go b/diff_test.go index 388f1f23e..baa87c982 100644 --- a/diff_test.go +++ b/diff_test.go @@ -21,19 +21,10 @@ func TestDiffRoundTrip(t *testing.T) { db := db.NewMemDB() tree, err := NewMutableTree(db, 0, true) require.NoError(t, err) - for _, cs := range changeSets { - for _, pair := range cs.Pairs { - if pair.Delete { - _, removed, err := tree.Remove(pair.Key) - require.True(t, removed) - require.NoError(t, err) - } else { - _, err := tree.Set(pair.Key, pair.Value) - require.NoError(t, err) - } - } - _, _, err := tree.SaveVersion() + for i := range changeSets { + v, err := tree.SaveChangeSet(&changeSets[i]) require.NoError(t, err) + require.Equal(t, int64(i+1), v) } // extract change sets from db diff --git a/mutable_tree.go b/mutable_tree.go index 272acba7f..ebfa457fa 100644 --- a/mutable_tree.go +++ b/mutable_tree.go @@ -1012,3 +1012,29 @@ func (tree *MutableTree) balance(node *Node) (newSelf *Node, err error) { // Nothing changed return node, nil } + +// SaveChangeSet saves a ChangeSet to the tree. +// It is used to replay a ChangeSet as a new version. +func (tree *MutableTree) SaveChangeSet(cs *ChangeSet) (int64, error) { + // if the tree has uncommitted changes, return error + if tree.root != nil && !tree.root.persisted { + return 0, fmt.Errorf("cannot save changeset with uncommitted changes") + } + for _, pair := range cs.Pairs { + if pair.Delete { + _, removed, err := tree.Remove(pair.Key) + if !removed { + return 0, fmt.Errorf("attempted to remove non-existent key %s", pair.Key) + } + if err != nil { + return 0, err + } + } else { + if _, err := tree.Set(pair.Key, pair.Value); err != nil { + return 0, err + } + } + } + _, version, err := tree.SaveVersion() + return version, err +}