2022-12-09 15:40:23 +00:00
|
|
|
// Copyright (C) 2022 Storj Labs, Inc.
|
|
|
|
// See LICENSE for copying information.
|
|
|
|
|
|
|
|
package rangedlooptest
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
"math/rand"
|
|
|
|
"testing"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
|
|
|
|
"storj.io/common/uuid"
|
|
|
|
"storj.io/storj/satellite/metabase"
|
2023-05-09 12:13:19 +01:00
|
|
|
"storj.io/storj/satellite/metabase/rangedloop"
|
2022-12-09 15:40:23 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
r = rand.New(rand.NewSource(time.Now().Unix()))
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestSplitter(t *testing.T) {
|
2023-05-09 12:13:19 +01:00
|
|
|
mkseg := func(streamID byte, pos uint64) rangedloop.Segment {
|
|
|
|
return rangedloop.Segment{
|
2022-12-09 15:40:23 +00:00
|
|
|
StreamID: uuid.UUID{0: streamID},
|
|
|
|
Position: metabase.SegmentPositionFromEncoded(pos),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-09 12:13:19 +01:00
|
|
|
mkstream := func(streamID byte, numSegments int) []rangedloop.Segment {
|
|
|
|
var stream []rangedloop.Segment
|
2022-12-09 15:40:23 +00:00
|
|
|
for i := 0; i < numSegments; i++ {
|
|
|
|
stream = append(stream, mkseg(streamID, uint64(numSegments)))
|
|
|
|
}
|
|
|
|
return stream
|
|
|
|
}
|
|
|
|
|
2023-05-09 12:13:19 +01:00
|
|
|
intermix := func(segments []rangedloop.Segment) []rangedloop.Segment {
|
|
|
|
segments = append([]rangedloop.Segment(nil), segments...)
|
2022-12-09 15:40:23 +00:00
|
|
|
r.Shuffle(len(segments), func(i, j int) {
|
|
|
|
segments[i], segments[j] = segments[j], segments[i]
|
|
|
|
})
|
|
|
|
return segments
|
|
|
|
}
|
|
|
|
|
2023-05-09 12:13:19 +01:00
|
|
|
combine := func(streams ...[]rangedloop.Segment) []rangedloop.Segment {
|
2022-12-09 15:40:23 +00:00
|
|
|
return segmentsFromStreams(streams)
|
|
|
|
}
|
|
|
|
|
|
|
|
stream1 := mkstream(1, 3)
|
|
|
|
stream2 := mkstream(2, 5)
|
|
|
|
stream3 := mkstream(3, 1)
|
|
|
|
stream4 := mkstream(4, 2)
|
|
|
|
stream5 := mkstream(5, 4)
|
|
|
|
|
|
|
|
for _, tt := range []struct {
|
|
|
|
desc string
|
2023-05-09 12:13:19 +01:00
|
|
|
segments []rangedloop.Segment
|
2022-12-09 15:40:23 +00:00
|
|
|
numRanges int
|
2023-05-09 12:13:19 +01:00
|
|
|
expectRanges [][]rangedloop.Segment
|
2022-12-09 15:40:23 +00:00
|
|
|
}{
|
|
|
|
{
|
|
|
|
desc: "no segments",
|
|
|
|
segments: nil,
|
|
|
|
numRanges: 2,
|
2023-05-09 12:13:19 +01:00
|
|
|
expectRanges: [][]rangedloop.Segment{
|
2022-12-09 15:40:23 +00:00
|
|
|
{},
|
|
|
|
{},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
desc: "one stream over two ranges",
|
|
|
|
segments: stream1,
|
|
|
|
numRanges: 2,
|
2023-05-09 12:13:19 +01:00
|
|
|
expectRanges: [][]rangedloop.Segment{
|
2022-12-09 15:40:23 +00:00
|
|
|
stream1,
|
|
|
|
{},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
desc: "two streams over two ranges",
|
|
|
|
segments: combine(stream1, stream2),
|
|
|
|
numRanges: 2,
|
2023-05-09 12:13:19 +01:00
|
|
|
expectRanges: [][]rangedloop.Segment{
|
2022-12-09 15:40:23 +00:00
|
|
|
stream1,
|
|
|
|
stream2,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
desc: "three streams over two ranges",
|
|
|
|
segments: combine(stream1, stream2, stream3),
|
|
|
|
numRanges: 2,
|
2023-05-09 12:13:19 +01:00
|
|
|
expectRanges: [][]rangedloop.Segment{
|
2022-12-09 15:40:23 +00:00
|
|
|
combine(stream1, stream2),
|
|
|
|
stream3,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
desc: "three streams intermixed over two ranges",
|
|
|
|
segments: intermix(combine(stream1, stream2, stream3)),
|
|
|
|
numRanges: 2,
|
2023-05-09 12:13:19 +01:00
|
|
|
expectRanges: [][]rangedloop.Segment{
|
2022-12-09 15:40:23 +00:00
|
|
|
combine(stream1, stream2),
|
|
|
|
stream3,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
desc: "five streams intermixed over three ranges",
|
|
|
|
segments: intermix(combine(stream1, stream2, stream3, stream4, stream5)),
|
|
|
|
numRanges: 3,
|
2023-05-09 12:13:19 +01:00
|
|
|
expectRanges: [][]rangedloop.Segment{
|
2022-12-09 15:40:23 +00:00
|
|
|
combine(stream1, stream2),
|
|
|
|
combine(stream3, stream4),
|
|
|
|
stream5,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
} {
|
|
|
|
t.Run(tt.desc, func(t *testing.T) {
|
|
|
|
const batchSize = 3
|
|
|
|
|
|
|
|
splitter := RangeSplitter{Segments: tt.segments}
|
|
|
|
|
|
|
|
providers, err := splitter.CreateRanges(tt.numRanges, batchSize)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
2023-05-09 12:13:19 +01:00
|
|
|
var actualRanges [][]rangedloop.Segment
|
2022-12-09 15:40:23 +00:00
|
|
|
for _, provider := range providers {
|
2023-05-09 12:13:19 +01:00
|
|
|
rangeSegments := []rangedloop.Segment{}
|
|
|
|
err := provider.Iterate(context.Background(), func(segments []rangedloop.Segment) error {
|
2022-12-09 15:40:23 +00:00
|
|
|
if len(segments) > batchSize {
|
|
|
|
return fmt.Errorf("iterated segments (%d) larger than batch size (%d)", len(segments), batchSize)
|
|
|
|
}
|
|
|
|
rangeSegments = append(rangeSegments, segments...)
|
|
|
|
return nil
|
|
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
|
|
actualRanges = append(actualRanges, rangeSegments)
|
|
|
|
}
|
|
|
|
require.Equal(t, tt.expectRanges, actualRanges)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|