Skip to content

Commit f47e1be

Browse files
author
Dan Laine
authored
sync -- add workheap test (#1879)
1 parent 7ec5bb3 commit f47e1be

File tree

1 file changed

+138
-2
lines changed

1 file changed

+138
-2
lines changed

x/sync/workheap_test.go

Lines changed: 138 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,17 @@
44
package sync
55

66
import (
7+
"math/rand"
78
"testing"
8-
9-
"github.com/ava-labs/avalanchego/utils/maybe"
9+
"time"
1010

1111
"github.com/stretchr/testify/require"
1212

13+
"golang.org/x/exp/slices"
14+
1315
"github.com/ava-labs/avalanchego/ids"
16+
"github.com/ava-labs/avalanchego/utils"
17+
"github.com/ava-labs/avalanchego/utils/maybe"
1418
)
1519

1620
// Tests heap.Interface methods Push, Pop, Swap, Len, Less.
@@ -271,3 +275,135 @@ func Test_WorkHeap_Merge_Insert(t *testing.T) {
271275
syncHeap.MergeInsert(&workItem{start: maybe.Some([]byte{63}), end: maybe.Some([]byte{127}), priority: lowPriority})
272276
require.Equal(t, 1, syncHeap.Len())
273277
}
278+
279+
func TestWorkHeapMergeInsertRandom(t *testing.T) {
280+
var (
281+
require = require.New(t)
282+
seed = time.Now().UnixNano()
283+
rand = rand.New(rand.NewSource(seed)) // #nosec G404
284+
numRanges = 1_000
285+
bounds = [][]byte{}
286+
rootID = ids.GenerateTestID()
287+
)
288+
t.Logf("seed: %d", seed)
289+
290+
// Create start and end bounds
291+
for i := 0; i < numRanges; i++ {
292+
bound := make([]byte, 32)
293+
_, _ = rand.Read(bound)
294+
bounds = append(bounds, bound)
295+
}
296+
utils.SortBytes(bounds)
297+
298+
// Note that start < end for all ranges.
299+
// It is possible but extremely unlikely that
300+
// two elements of [bounds] are equal.
301+
ranges := []workItem{}
302+
for i := 0; i < numRanges/2; i++ {
303+
start := bounds[i*2]
304+
end := bounds[i*2+1]
305+
ranges = append(ranges, workItem{
306+
start: maybe.Some(start),
307+
end: maybe.Some(end),
308+
priority: lowPriority,
309+
// Note they all share the same root ID.
310+
localRootID: rootID,
311+
})
312+
}
313+
// Set beginning of first range to Nothing.
314+
ranges[0].start = maybe.Nothing[[]byte]()
315+
// Set end of last range to Nothing.
316+
ranges[len(ranges)-1].end = maybe.Nothing[[]byte]()
317+
318+
setup := func() *workHeap {
319+
// Insert all the ranges into the heap.
320+
h := newWorkHeap()
321+
for i, r := range ranges {
322+
require.Equal(i, h.Len())
323+
rCopy := r
324+
h.MergeInsert(&rCopy)
325+
}
326+
return h
327+
}
328+
329+
{
330+
// Case 1: Merging an item with the range before and after
331+
h := setup()
332+
// Keep merging ranges until there's only one range left.
333+
for i := 0; i < len(ranges)-1; i++ {
334+
// Merge ranges[i] with ranges[i+1]
335+
h.MergeInsert(&workItem{
336+
start: ranges[i].end,
337+
end: ranges[i+1].start,
338+
priority: lowPriority,
339+
localRootID: rootID,
340+
})
341+
require.Equal(len(ranges)-i-1, h.Len())
342+
}
343+
got := h.GetWork()
344+
require.True(got.start.IsNothing())
345+
require.True(got.end.IsNothing())
346+
}
347+
348+
{
349+
// Case 2: Merging an item with the range before
350+
h := setup()
351+
for i := 0; i < len(ranges)-1; i++ {
352+
// Extend end of ranges[i]
353+
newEnd := slices.Clone(ranges[i].end.Value())
354+
newEnd = append(newEnd, 0)
355+
h.MergeInsert(&workItem{
356+
start: ranges[i].end,
357+
end: maybe.Some(newEnd),
358+
priority: lowPriority,
359+
localRootID: rootID,
360+
})
361+
362+
// Shouldn't cause number of elements to change
363+
require.Equal(len(ranges), h.Len())
364+
365+
start := ranges[i].start
366+
if i == 0 {
367+
start = maybe.Nothing[[]byte]()
368+
}
369+
// Make sure end is updated
370+
got, ok := h.sortedItems.Get(&heapItem{
371+
workItem: &workItem{
372+
start: start,
373+
},
374+
})
375+
require.True(ok)
376+
require.Equal(newEnd, got.workItem.end.Value())
377+
}
378+
}
379+
380+
{
381+
// Case 3: Merging an item with the range after
382+
h := setup()
383+
for i := 1; i < len(ranges); i++ {
384+
// Extend start of ranges[i]
385+
newStartBytes := slices.Clone(ranges[i].start.Value())
386+
newStartBytes = newStartBytes[:len(newStartBytes)-1]
387+
newStart := maybe.Some(newStartBytes)
388+
389+
h.MergeInsert(&workItem{
390+
start: newStart,
391+
end: ranges[i].start,
392+
priority: lowPriority,
393+
localRootID: rootID,
394+
})
395+
396+
// Shouldn't cause number of elements to change
397+
require.Equal(len(ranges), h.Len())
398+
399+
// Make sure start is updated
400+
got, ok := h.sortedItems.Get(&heapItem{
401+
workItem: &workItem{
402+
start: newStart,
403+
},
404+
})
405+
require.True(ok)
406+
require.Equal(newStartBytes, got.workItem.start.Value())
407+
}
408+
}
409+
}

0 commit comments

Comments
 (0)