Skip to content
Open
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
42 changes: 42 additions & 0 deletions export_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,48 @@ func TestExporter_Close(t *testing.T) {
exporter.Close()
}

// TestExporter_ConcurrentSet exports a version while the next one is written,
// as the Cosmos SDK's state sync snapshots do. With a node cache the exporter
// and the writer share the persisted nodes, so under -race this fails if
// cloning a persisted node writes to it.
func TestExporter_ConcurrentSet(t *testing.T) {
tree := NewMutableTree(dbm.NewMemDB(), 1000, false, NewNopLogger())
for i := 0; i < 256; i++ {
_, err := tree.Set([]byte{byte(i)}, []byte{byte(i)})
require.NoError(t, err)
}
_, version, err := tree.SaveVersion()
require.NoError(t, err)
itree, err := tree.GetImmutable(version)
require.NoError(t, err)

exporter, err := itree.Export()
require.NoError(t, err)
defer exporter.Close()

for i := 0; i < 256; i++ {
_, err := tree.Set([]byte{byte(i)}, []byte{byte(i), 1})
require.NoError(t, err)
}
_, _, err = tree.SaveVersion()
require.NoError(t, err)

newTree := NewMutableTree(dbm.NewMemDB(), 0, false, NewNopLogger())
importer, err := newTree.Import(version)
require.NoError(t, err)
defer importer.Close()
for {
node, err := exporter.Next()
if errors.Is(err, ErrorExportDone) {
break
}
require.NoError(t, err)
require.NoError(t, importer.Add(node))
}
require.NoError(t, importer.Commit())
require.Equal(t, itree.Hash(), newTree.Hash())
}

func TestExporter_DeleteVersionErrors(t *testing.T) {
tree := NewMutableTree(dbm.NewMemDB(), 0, false, NewNopLogger())

Expand Down
5 changes: 3 additions & 2 deletions node.go
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,9 @@ func (node *Node) clone(tree *MutableTree) (*Node, error) {
var err error
leftNode := node.leftNode
rightNode := node.rightNode
// A persisted node is shared with every ImmutableTree reading its version,
// such as a concurrent Exporter, so it is not written here. Its child
// pointers were already cleared when it was saved, in saveNewNodes.
if node.nodeKey != nil {
leftNode, err = node.getLeftNode(tree.ImmutableTree)
if err != nil {
Expand All @@ -311,8 +314,6 @@ func (node *Node) clone(tree *MutableTree) (*Node, error) {
if err != nil {
return nil, err
}
node.leftNode = nil
node.rightNode = nil
}

return &Node{
Expand Down
Loading