Some checks failed
NATS Server Tests / Lint (push) Failing after 3s
NATS Server Tests / Build (Latest Go) (push) Has been skipped
NATS Server Tests / Build (Minimum Go) (push) Has been skipped
NATS Server Tests / Build (Minimum Go, windows-2022) (push) Has been skipped
NATS Server Tests / Build (Minimum Go, windows-2025) (push) Has been skipped
NATS Server Tests / Test Stores (push) Has been skipped
NATS Server Tests / Test JetStream (push) Has been skipped
NATS Server Tests / Test Raft (push) Has been skipped
NATS Server Tests / Test JetStream Consumers (push) Has been skipped
NATS Server Tests / Test JetStream Cluster 1 (push) Has been skipped
NATS Server Tests / Test JetStream Cluster 2 (push) Has been skipped
NATS Server Tests / Test JetStream Cluster 3 (push) Has been skipped
NATS Server Tests / Test JetStream Cluster 4 (push) Has been skipped
NATS Server Tests / Test JetStream Supercluster (push) Has been skipped
NATS Server Tests / Test No-Race 1 (push) Has been skipped
NATS Server Tests / Test No-Race 2 (push) Has been skipped
NATS Server Tests / Test MQTT (push) Has been skipped
NATS Server Tests / Test Message Tracing (push) Has been skipped
NATS Server Tests / Test JWT (push) Has been skipped
NATS Server Tests / Test Remaining Server Tests (push) Has been skipped
NATS Server Tests / Test Other Packages (push) Has been skipped
Vulnerability Scan / govulncheck (push) Failing after 12m2s
557 lines
15 KiB
Go
557 lines
15 KiB
Go
// Copyright 2023-2026 The NATS Authors
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package avl
|
|
|
|
import (
|
|
"encoding/base64"
|
|
"encoding/binary"
|
|
"math/rand/v2"
|
|
"testing"
|
|
)
|
|
|
|
func TestSeqSetBasics(t *testing.T) {
|
|
var ss SequenceSet
|
|
|
|
seqs := []uint64{22, 222, 2000, 2, 2, 4}
|
|
for _, seq := range seqs {
|
|
ss.Insert(seq)
|
|
require_True(t, ss.Exists(seq))
|
|
}
|
|
|
|
require_True(t, ss.Nodes() == 1)
|
|
require_True(t, ss.Size() == len(seqs)-1) // We have one dup in there.
|
|
lh, rh := ss.Heights()
|
|
require_True(t, lh == 0)
|
|
require_True(t, rh == 0)
|
|
}
|
|
|
|
func TestSeqSetLeftLean(t *testing.T) {
|
|
var ss SequenceSet
|
|
|
|
for i := uint64(4 * numEntries); i > 0; i-- {
|
|
ss.Insert(i)
|
|
}
|
|
|
|
require_True(t, ss.Nodes() == 5)
|
|
require_True(t, ss.Size() == 4*numEntries)
|
|
lh, rh := ss.Heights()
|
|
require_True(t, lh == 2)
|
|
require_True(t, rh == 1)
|
|
}
|
|
|
|
func TestSeqSetRightLean(t *testing.T) {
|
|
var ss SequenceSet
|
|
|
|
for i := uint64(0); i < uint64(4*numEntries); i++ {
|
|
ss.Insert(i)
|
|
}
|
|
|
|
require_True(t, ss.Nodes() == 4)
|
|
require_True(t, ss.Size() == 4*numEntries)
|
|
lh, rh := ss.Heights()
|
|
require_True(t, lh == 1)
|
|
require_True(t, rh == 2)
|
|
}
|
|
|
|
func TestSeqSetCorrectness(t *testing.T) {
|
|
// Generate 100k sequences across 500k range.
|
|
num := 100_000
|
|
max := 500_000
|
|
|
|
set := make(map[uint64]struct{}, num)
|
|
var ss SequenceSet
|
|
for i := 0; i < num; i++ {
|
|
n := uint64(rand.Int64N(int64(max + 1)))
|
|
ss.Insert(n)
|
|
set[n] = struct{}{}
|
|
}
|
|
|
|
for i := uint64(0); i <= uint64(max); i++ {
|
|
_, exists := set[i]
|
|
require_True(t, ss.Exists(i) == exists)
|
|
}
|
|
}
|
|
|
|
func TestSeqSetRange(t *testing.T) {
|
|
num := 2*numEntries + 22
|
|
nums := make([]uint64, 0, num)
|
|
for i := 0; i < num; i++ {
|
|
nums = append(nums, uint64(i))
|
|
}
|
|
rand.Shuffle(len(nums), func(i, j int) { nums[i], nums[j] = nums[j], nums[i] })
|
|
|
|
var ss SequenceSet
|
|
for _, n := range nums {
|
|
ss.Insert(n)
|
|
}
|
|
|
|
nums = nums[:0]
|
|
ss.Range(func(n uint64) bool {
|
|
nums = append(nums, n)
|
|
return true
|
|
})
|
|
require_True(t, len(nums) == num)
|
|
for i := uint64(0); i < uint64(num); i++ {
|
|
require_True(t, nums[i] == i)
|
|
}
|
|
|
|
// Test truncating the range call.
|
|
nums = nums[:0]
|
|
ss.Range(func(n uint64) bool {
|
|
if n >= 10 {
|
|
return false
|
|
}
|
|
nums = append(nums, n)
|
|
return true
|
|
})
|
|
require_True(t, len(nums) == 10)
|
|
for i := uint64(0); i < 10; i++ {
|
|
require_True(t, nums[i] == i)
|
|
}
|
|
}
|
|
|
|
func TestSeqSetDelete(t *testing.T) {
|
|
var ss SequenceSet
|
|
|
|
// Simple single node.
|
|
seqs := []uint64{22, 222, 2222, 2, 2, 4}
|
|
for _, seq := range seqs {
|
|
ss.Insert(seq)
|
|
}
|
|
|
|
for _, seq := range seqs {
|
|
ss.Delete(seq)
|
|
require_True(t, !ss.Exists(seq))
|
|
}
|
|
require_True(t, ss.root == nil)
|
|
}
|
|
|
|
func TestSeqSetInsertAndDeletePedantic(t *testing.T) {
|
|
var ss SequenceSet
|
|
|
|
num := 50*numEntries + 22
|
|
nums := make([]uint64, 0, num)
|
|
for i := 0; i < num; i++ {
|
|
nums = append(nums, uint64(i))
|
|
}
|
|
rand.Shuffle(len(nums), func(i, j int) { nums[i], nums[j] = nums[j], nums[i] })
|
|
|
|
// Make sure always balanced.
|
|
testBalanced := func() {
|
|
t.Helper()
|
|
// Check heights.
|
|
ss.root.nodeIter(func(n *node) {
|
|
if n != nil && n.h != maxH(n)+1 {
|
|
t.Fatalf("Node height is wrong: %+v", n)
|
|
}
|
|
})
|
|
// Check balance factor.
|
|
if bf := balanceF(ss.root); bf > 1 || bf < -1 {
|
|
t.Fatalf("Unbalanced tree")
|
|
}
|
|
}
|
|
|
|
for _, n := range nums {
|
|
ss.Insert(n)
|
|
testBalanced()
|
|
}
|
|
require_True(t, ss.root != nil)
|
|
|
|
for _, n := range nums {
|
|
ss.Delete(n)
|
|
testBalanced()
|
|
require_True(t, !ss.Exists(n))
|
|
if ss.Size() > 0 {
|
|
require_True(t, ss.root != nil)
|
|
}
|
|
}
|
|
require_True(t, ss.root == nil)
|
|
}
|
|
|
|
func TestSeqSetMinMax(t *testing.T) {
|
|
var ss SequenceSet
|
|
|
|
// Simple single node.
|
|
seqs := []uint64{22, 222, 2222, 2, 2, 4}
|
|
for _, seq := range seqs {
|
|
ss.Insert(seq)
|
|
}
|
|
|
|
min, max := ss.MinMax()
|
|
require_True(t, min == 2 && max == 2222)
|
|
|
|
// Multi-node
|
|
ss.Empty()
|
|
|
|
num := 22*numEntries + 22
|
|
nums := make([]uint64, 0, num)
|
|
for i := 0; i < num; i++ {
|
|
nums = append(nums, uint64(i))
|
|
}
|
|
rand.Shuffle(len(nums), func(i, j int) { nums[i], nums[j] = nums[j], nums[i] })
|
|
for _, n := range nums {
|
|
ss.Insert(n)
|
|
}
|
|
|
|
min, max = ss.MinMax()
|
|
require_True(t, min == 0 && max == uint64(num-1))
|
|
}
|
|
|
|
func TestSeqSetClone(t *testing.T) {
|
|
// Generate 100k sequences across 500k range.
|
|
num := 100_000
|
|
max := 500_000
|
|
|
|
var ss SequenceSet
|
|
for i := 0; i < num; i++ {
|
|
ss.Insert(uint64(rand.Int64N(int64(max + 1))))
|
|
}
|
|
|
|
ssc := ss.Clone()
|
|
require_True(t, ss.Size() == ssc.Size())
|
|
require_True(t, ss.Nodes() == ssc.Nodes())
|
|
}
|
|
|
|
func TestSeqSetEqual(t *testing.T) {
|
|
var ss1, ss2, ss3 SequenceSet
|
|
|
|
// Empty and nil sets are all equal.
|
|
var nilSet *SequenceSet
|
|
require_True(t, ss1.Equal(&ss2))
|
|
require_True(t, ss1.Equal(nilSet))
|
|
require_True(t, nilSet.Equal(&ss1))
|
|
|
|
// Same state (first, last, size) but different contents.
|
|
for _, seq := range []uint64{1, 3, 5} {
|
|
ss1.Insert(seq)
|
|
}
|
|
for _, seq := range []uint64{1, 4, 5} {
|
|
ss2.Insert(seq)
|
|
}
|
|
require_False(t, ss1.Equal(&ss2))
|
|
require_False(t, ss2.Equal(&ss1))
|
|
require_False(t, ss1.Equal(nilSet))
|
|
require_False(t, nilSet.Equal(&ss1))
|
|
|
|
// Identical contents, insertion order should not matter.
|
|
for _, seq := range []uint64{5, 1, 3} {
|
|
ss3.Insert(seq)
|
|
}
|
|
require_True(t, ss1.Equal(&ss3))
|
|
require_True(t, ss3.Equal(&ss1))
|
|
|
|
// Differing sizes.
|
|
ss3.Insert(7)
|
|
require_False(t, ss1.Equal(&ss3))
|
|
}
|
|
|
|
func TestSeqSetUnion(t *testing.T) {
|
|
var ss1, ss2 SequenceSet
|
|
|
|
seqs1 := []uint64{22, 222, 2222, 2, 2, 4}
|
|
for _, seq := range seqs1 {
|
|
ss1.Insert(seq)
|
|
}
|
|
|
|
seqs2 := []uint64{33, 333, 3333, 3, 33_333, 333_333}
|
|
for _, seq := range seqs2 {
|
|
ss2.Insert(seq)
|
|
}
|
|
|
|
ss := Union(&ss1, &ss2)
|
|
require_True(t, ss.Size() == 11)
|
|
|
|
seqs := append(seqs1, seqs2...)
|
|
for _, n := range seqs {
|
|
require_True(t, ss.Exists(n))
|
|
}
|
|
}
|
|
|
|
func TestSeqSetFirst(t *testing.T) {
|
|
var ss SequenceSet
|
|
|
|
seqs := []uint64{22, 222, 2222, 222_222}
|
|
for _, seq := range seqs {
|
|
// Normal case where we pick first/base.
|
|
ss.Insert(seq)
|
|
require_True(t, ss.root.base == (seq/numEntries)*numEntries)
|
|
ss.Empty()
|
|
// Where we set the minimum start value.
|
|
ss.SetInitialMin(seq)
|
|
ss.Insert(seq)
|
|
require_True(t, ss.root.base == seq)
|
|
ss.Empty()
|
|
}
|
|
}
|
|
|
|
// Test that we can union with nodes vs individual sequence insertion.
|
|
func TestSeqSetDistinctUnion(t *testing.T) {
|
|
// Distinct sets.
|
|
var ss1 SequenceSet
|
|
seqs1 := []uint64{1, 10, 100, 200}
|
|
for _, seq := range seqs1 {
|
|
ss1.Insert(seq)
|
|
}
|
|
|
|
var ss2 SequenceSet
|
|
seqs2 := []uint64{5000, 6100, 6200, 6222}
|
|
for _, seq := range seqs2 {
|
|
ss2.Insert(seq)
|
|
}
|
|
|
|
ss := ss1.Clone()
|
|
allSeqs := append(seqs1, seqs2...)
|
|
|
|
ss.Union(&ss2)
|
|
require_True(t, ss.Size() == len(allSeqs))
|
|
for _, seq := range allSeqs {
|
|
require_True(t, ss.Exists(seq))
|
|
}
|
|
}
|
|
|
|
func TestSeqSetDecodeV1(t *testing.T) {
|
|
// Encoding from v1 which was 64 buckets.
|
|
seqs := []uint64{22, 222, 2222, 222_222, 2_222_222}
|
|
encStr := `
|
|
FgEDAAAABQAAAABgAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAADgIQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAA==
|
|
`
|
|
|
|
enc, err := base64.StdEncoding.DecodeString(encStr)
|
|
require_NoError(t, err)
|
|
|
|
ss, _, err := Decode(enc)
|
|
require_NoError(t, err)
|
|
|
|
require_True(t, ss.Size() == len(seqs))
|
|
for _, seq := range seqs {
|
|
require_True(t, ss.Exists(seq))
|
|
}
|
|
}
|
|
|
|
func TestSeqSetDecodeNodeCountOverflow(t *testing.T) {
|
|
// A replicated stream state carries an avl-encoded delete map decoded from
|
|
// a peer. The node count is read as a uint32 into an int; on 32-bit builds
|
|
// a value above MaxInt32 turns negative (and a smaller value can overflow
|
|
// the nn*perNode multiply), defeating the length check so the decode then
|
|
// panics in make([]node, nn) or reads past the buffer. Both encodings must
|
|
// reject such counts on every architecture instead.
|
|
le := binary.LittleEndian
|
|
for _, ver := range []uint8{1, 2} {
|
|
buf := make([]byte, minLen)
|
|
buf[0], buf[1] = magic, ver
|
|
le.PutUint32(buf[2:], 0xFFFFFFFF) // node count, negative as a 32-bit int
|
|
if _, _, err := Decode(buf); err != ErrBadEncoding {
|
|
t.Fatalf("v%d: expected ErrBadEncoding for oversized node count, got %v", ver, err)
|
|
}
|
|
|
|
// Positive on 32-bit but the multiply still overflows for a short buffer.
|
|
le.PutUint32(buf[2:], 0x00800000)
|
|
if _, _, err := Decode(buf); err != ErrBadEncoding {
|
|
t.Fatalf("v%d: expected ErrBadEncoding for overflowing node count, got %v", ver, err)
|
|
}
|
|
}
|
|
|
|
// A well-formed single-node v2 buffer must still decode.
|
|
valid := make([]byte, minLen+(numBuckets+1)*8+2)
|
|
valid[0], valid[1] = magic, version
|
|
le.PutUint32(valid[2:], 1)
|
|
if _, _, err := Decode(valid); err != nil {
|
|
t.Fatalf("valid single-node buffer should decode, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestSeqSetInsertExistingNodeFastPath(t *testing.T) {
|
|
var ss SequenceSet
|
|
|
|
// Build a multi-node tree with only even sequences set.
|
|
for i := uint64(0); i < 8*numEntries; i += 2 {
|
|
ss.Insert(i)
|
|
}
|
|
nodes, size := ss.Nodes(), ss.Size()
|
|
|
|
// Inserting into existing nodes must not change the tree structure.
|
|
for i := uint64(1); i < 8*numEntries; i += 2 {
|
|
ss.Insert(i)
|
|
require_True(t, ss.Exists(i))
|
|
}
|
|
require_True(t, ss.Nodes() == nodes)
|
|
require_True(t, ss.Size() == size+4*numEntries)
|
|
|
|
// Duplicate inserts must not change the size.
|
|
for i := uint64(0); i < 8*numEntries; i++ {
|
|
ss.Insert(i)
|
|
}
|
|
require_True(t, ss.Size() == 8*numEntries)
|
|
|
|
// Heights and balance must still be intact.
|
|
ss.root.nodeIter(func(n *node) {
|
|
if n.h != maxH(n)+1 {
|
|
t.Fatalf("Node height is wrong: %+v", n)
|
|
}
|
|
})
|
|
if bf := balanceF(ss.root); bf > 1 || bf < -1 {
|
|
t.Fatalf("Unbalanced tree")
|
|
}
|
|
}
|
|
|
|
func TestSeqSetInsertUnalignedBase(t *testing.T) {
|
|
var ss SequenceSet
|
|
|
|
// SetInitialMin can create a node whose base is not aligned to numEntries.
|
|
require_NoError(t, ss.SetInitialMin(1000))
|
|
for _, seq := range []uint64{1000, 1001, 1000 + numEntries - 1} {
|
|
ss.Insert(seq)
|
|
require_True(t, ss.Exists(seq))
|
|
}
|
|
require_True(t, ss.Nodes() == 1)
|
|
require_True(t, ss.Size() == 3)
|
|
|
|
// Outside the node's range still creates a new node.
|
|
ss.Insert(1000 + numEntries)
|
|
require_True(t, ss.Exists(1000+numEntries))
|
|
require_True(t, ss.Nodes() == 2)
|
|
require_True(t, ss.Size() == 4)
|
|
}
|
|
|
|
func TestSeqSetDeleteNotPresent(t *testing.T) {
|
|
var ss SequenceSet
|
|
|
|
seqs := []uint64{22, 222, 2222, 222_222}
|
|
for _, seq := range seqs {
|
|
ss.Insert(seq)
|
|
}
|
|
nodes, size := ss.Nodes(), ss.Size()
|
|
|
|
// Deleting sequences that are not set, both inside and outside
|
|
// existing node ranges, must be a no-op and report false.
|
|
for _, seq := range []uint64{0, 23, 2223, 5000, 100_000, 999_999} {
|
|
require_True(t, !ss.Delete(seq))
|
|
}
|
|
require_True(t, ss.Nodes() == nodes)
|
|
require_True(t, ss.Size() == size)
|
|
for _, seq := range seqs {
|
|
require_True(t, ss.Exists(seq))
|
|
}
|
|
|
|
// Real deletes still work and empty the set.
|
|
for _, seq := range seqs {
|
|
require_True(t, ss.Delete(seq))
|
|
}
|
|
require_True(t, ss.root == nil)
|
|
}
|
|
|
|
func TestSeqSetRangeSparse(t *testing.T) {
|
|
// Cover bucket boundaries, node boundaries and large gaps.
|
|
seqs := []uint64{0, 1, 63, 64, 127, 128, 2047, 2048, 4095, 4096, 100_000, 1_000_000}
|
|
var ss SequenceSet
|
|
for _, seq := range seqs {
|
|
ss.Insert(seq)
|
|
}
|
|
|
|
var got []uint64
|
|
ss.Range(func(n uint64) bool {
|
|
got = append(got, n)
|
|
return true
|
|
})
|
|
require_True(t, len(got) == len(seqs))
|
|
for i, seq := range seqs {
|
|
require_True(t, got[i] == seq)
|
|
}
|
|
|
|
// Terminating mid-bucket should stop the iteration immediately.
|
|
got = got[:0]
|
|
ss.Range(func(n uint64) bool {
|
|
got = append(got, n)
|
|
return n != 64
|
|
})
|
|
require_True(t, len(got) == 4)
|
|
require_True(t, got[3] == 64)
|
|
}
|
|
|
|
func BenchmarkSeqSetInsertDense(b *testing.B) {
|
|
for i := 0; i < b.N; i++ {
|
|
var ss SequenceSet
|
|
for s := uint64(0); s < 200_000; s++ {
|
|
ss.Insert(s)
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkSeqSetInsertSparse(b *testing.B) {
|
|
for i := 0; i < b.N; i++ {
|
|
var ss SequenceSet
|
|
for s := uint64(0); s < 200_000; s++ {
|
|
ss.Insert(s * 7)
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkSeqSetRangeDense(b *testing.B) {
|
|
var ss SequenceSet
|
|
for s := uint64(0); s < 200_000; s++ {
|
|
ss.Insert(s)
|
|
}
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
var sum uint64
|
|
ss.Range(func(n uint64) bool { sum += n; return true })
|
|
}
|
|
}
|
|
|
|
func BenchmarkSeqSetRangeSparse(b *testing.B) {
|
|
var ss SequenceSet
|
|
for s := uint64(0); s < 10_000; s++ {
|
|
ss.Insert(s * 211) // ~10 bits per 2048-entry node
|
|
}
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
var sum uint64
|
|
ss.Range(func(n uint64) bool { sum += n; return true })
|
|
}
|
|
}
|
|
|
|
func BenchmarkSeqSetDeleteNotPresent(b *testing.B) {
|
|
var ss SequenceSet
|
|
for s := uint64(0); s < 200_000; s += 2 {
|
|
ss.Insert(s)
|
|
}
|
|
b.ResetTimer()
|
|
for i := 0; i < b.N; i++ {
|
|
for s := uint64(1); s < 200_000; s += 2 {
|
|
ss.Delete(s)
|
|
}
|
|
}
|
|
}
|
|
|
|
func require_NoError(t *testing.T, err error) {
|
|
t.Helper()
|
|
if err != nil {
|
|
t.Fatalf("require no error, but got: %v", err)
|
|
}
|
|
}
|
|
|
|
func require_True(t *testing.T, b bool) {
|
|
t.Helper()
|
|
if !b {
|
|
t.Fatalf("require true")
|
|
}
|
|
}
|
|
|
|
func require_False(t *testing.T, b bool) {
|
|
t.Helper()
|
|
if b {
|
|
t.Fatalf("require false")
|
|
}
|
|
}
|