diff --git a/pkg/local_object_storage/pilorama/forest_test.go b/pkg/local_object_storage/pilorama/forest_test.go index 001d095c8..c6c6e8c8b 100644 --- a/pkg/local_object_storage/pilorama/forest_test.go +++ b/pkg/local_object_storage/pilorama/forest_test.go @@ -1,11 +1,13 @@ package pilorama import ( + "bytes" "context" "crypto/rand" "fmt" mrand "math/rand" "path/filepath" + "slices" "strconv" "strings" "sync" @@ -232,6 +234,66 @@ func BenchmarkForestSortedIteration(b *testing.B) { } } +// The issue which we call "BugWithSkip" is easiest to understand when filenames are +// monotonically increasing numbers. We want the list of sorted filenames to have different length interleaved. +// The bug happens when we switch between length during listing. +// Thus this test contains numbers from 1 to 1000 and batch size of size 100. +func TestForest_TreeSortedIterationBugWithSkip(t *testing.T) { + t.Skip() + for i := range providers { + t.Run(providers[i].name, func(t *testing.T) { + testForestTreeSortedIterationBugWithSkip(t, providers[i].construct(t)) + }) + } +} + +func testForestTreeSortedIterationBugWithSkip(t *testing.T, s ForestStorage) { + defer func() { require.NoError(t, s.Close()) }() + + cid := cidtest.ID() + d := CIDDescriptor{cid, 0, 1} + treeID := "version" + treeAdd := func(t *testing.T, ts int, filename string) { + _, err := s.TreeMove(context.Background(), d, treeID, &Move{ + Child: RootID + uint64(ts), + Parent: RootID, + Meta: Meta{ + Time: Timestamp(ts), + Items: []KeyValue{ + {Key: AttributeFilename, Value: []byte(filename)}, + }, + }, + }) + require.NoError(t, err) + } + + const count = 2000 + treeAdd(t, 1, "") + for i := 1; i < count; i++ { + treeAdd(t, i+1, strconv.Itoa(i+1)) + } + + var result []MultiNodeInfo + treeAppend := func(t *testing.T, last *string, count int) *string { + res, cursor, err := s.TreeSortedByFilename(context.Background(), d.CID, treeID, MultiNode{RootID}, last, count) + require.NoError(t, err) + result = append(result, res...) + return cursor + } + + const batchSize = 10 + last := treeAppend(t, nil, batchSize) + for i := 1; i < count/batchSize; i++ { + last = treeAppend(t, last, batchSize) + } + require.Len(t, result, count) + require.True(t, slices.IsSortedFunc(result, func(a, b MultiNodeInfo) int { + filenameA := findAttr(a.Meta, AttributeFilename) + filenameB := findAttr(b.Meta, AttributeFilename) + return bytes.Compare(filenameA, filenameB) + })) +} + func TestForest_TreeSortedIteration(t *testing.T) { for i := range providers { t.Run(providers[i].name, func(t *testing.T) {