Skip to content

Commit 6cfb3da

Browse files
beer-1mergify[bot]corverroos
authored
fix: batch write race on commit (backport #983) (#992) (#1057)
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com> Co-authored-by: corver <corver.roos@gmail.com>
1 parent 2d4b162 commit 6cfb3da

File tree

2 files changed

+85
-1
lines changed

2 files changed

+85
-1
lines changed

import.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -213,7 +213,17 @@ func (i *Importer) Commit() error {
213213
len(i.stack))
214214
}
215215

216-
err := i.batch.WriteSync()
216+
// Wait for previous batch.
217+
var err error
218+
if i.inflightCommit != nil {
219+
err = <-i.inflightCommit
220+
i.inflightCommit = nil
221+
}
222+
if err != nil {
223+
return err
224+
}
225+
226+
err = i.batch.WriteSync()
217227
if err != nil {
218228
return err
219229
}

import_test.go

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
package iavl
22

33
import (
4+
"encoding/binary"
45
"testing"
56

67
"github.com/stretchr/testify/assert"
78
"github.com/stretchr/testify/require"
9+
"golang.org/x/crypto/sha3"
810

911
dbm "github.com/cosmos/iavl/db"
1012
)
@@ -271,3 +273,75 @@ func benchmarkImport(b *testing.B, nodes int) {
271273
require.NoError(b, err)
272274
}
273275
}
276+
277+
func TestImporterDataIntegrity(t *testing.T) {
278+
// run multiple times to ensure the data integrity
279+
tree := NewMutableTree(dbm.NewMemDB(), 0, false, NewNopLogger())
280+
281+
// write more than maxBatchSize
282+
for i := 0; i < maxBatchSize+1; i++ {
283+
bz := sha3.Sum256(binary.BigEndian.AppendUint64([]byte{}, uint64(i)))
284+
_, err := tree.Set(bz[:], []byte{byte(i)})
285+
require.NoError(t, err)
286+
}
287+
288+
_, version, err := tree.SaveVersion()
289+
require.NoError(t, err)
290+
291+
itree, err := tree.GetImmutable(version)
292+
require.NoError(t, err)
293+
294+
exporter, err := itree.Export()
295+
require.NoError(t, err)
296+
297+
defer exporter.Close()
298+
exported := []*ExportNode{}
299+
for {
300+
var node *ExportNode
301+
node, err = exporter.Next()
302+
if err == ErrorExportDone {
303+
break
304+
}
305+
306+
require.NoError(t, err)
307+
exported = append(exported, node)
308+
}
309+
310+
tempDir := t.TempDir()
311+
db, err := dbm.NewDB("importer-test", "goleveldb", tempDir)
312+
require.NoError(t, err)
313+
newTree := NewMutableTree(db, 0, false, NewNopLogger())
314+
importer, err := newTree.Import(version)
315+
require.NoError(t, err)
316+
317+
for _, node := range exported {
318+
err = importer.Add(node)
319+
require.NoError(t, err)
320+
}
321+
err = importer.Commit()
322+
require.NoError(t, err)
323+
importer.Close()
324+
325+
_, version, err = newTree.SaveVersion()
326+
require.NoError(t, err)
327+
err = newTree.Close()
328+
require.NoError(t, err)
329+
err = db.Close()
330+
require.NoError(t, err)
331+
332+
// check if the tree is the same
333+
db, err = dbm.NewDB("importer-test", "goleveldb", tempDir)
334+
require.NoError(t, err)
335+
newTree = NewMutableTree(db, 0, false, NewNopLogger())
336+
_, err = newTree.LoadVersion(version)
337+
require.NoError(t, err)
338+
itree, err = newTree.GetImmutable(version)
339+
require.NoError(t, err)
340+
341+
for i := 0; i < maxBatchSize+1; i++ {
342+
bz := sha3.Sum256(binary.BigEndian.AppendUint64([]byte{}, uint64(i)))
343+
value, err := itree.Get(bz[:])
344+
require.NoError(t, err)
345+
require.Equal(t, []byte{byte(i)}, value)
346+
}
347+
}

0 commit comments

Comments
 (0)