-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcollision_test.go
131 lines (93 loc) · 3.02 KB
/
collision_test.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/*
Copyright (c) 2023 Vishal Bihani
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 tsid
import (
"sync"
"sync/atomic"
"testing"
"github.com/stretchr/testify/assert"
)
func TestCollision(t *testing.T) {
t.Run("one goroutine per node", func(t *testing.T) {
// One goroutine demonstrates one node
goroutineCount := 10
iterationCount := 100_000
var collisionCounter atomic.Uint32
var tsidMap sync.Map
wg := &sync.WaitGroup{}
for i := 0; i < goroutineCount; i++ {
nodeId := i
wg.Add(1)
go func(nodeId int32, iterationCount int32, collisionCounter *atomic.Uint32,
tsidMap *sync.Map, wg *sync.WaitGroup) {
defer wg.Done()
tsidFactory, err := TsidFactoryBuilder().
WithNode(nodeId).
Build()
assert.Nil(t, err)
for j := 0; j < int(iterationCount); j++ {
tsid, err := tsidFactory.Generate()
assert.Nil(t, err)
// check if this tsid was already generated
if _, ok := tsidMap.Load(tsid); !ok {
// not present, store it
tsidMap.Store(tsid, (nodeId*iterationCount)+int32(j))
continue
}
// collision detected, increment counter and break out
collisionCounter.Add(1)
break
}
}(int32(nodeId), int32(iterationCount), &collisionCounter, &tsidMap, wg)
}
// Wait for all goroutines to complete
wg.Wait()
assert.Zero(t, collisionCounter.Load(), 0, "Collision detected")
})
t.Run("multiple goroutines per node", func(t *testing.T) {
node := 1
nodeBit := 1
goroutineCount := 10
iterationCount := 200_000
var collisionCounter atomic.Uint32
var tsidMap sync.Map
wg := &sync.WaitGroup{}
for i := 0; i < goroutineCount; i++ {
wg.Add(1)
go func(nodeId int32, nodeBit int32, iterationCount int32, collisionCounter *atomic.Uint32,
tsidMap *sync.Map, wg *sync.WaitGroup) {
defer wg.Done()
tsidFactory, err := TsidFactoryBuilder().
WithNodeBits(nodeBit).
Build()
assert.Nil(t, err)
for j := 0; j < int(iterationCount); j++ {
tsid, err := tsidFactory.Generate()
assert.Nil(t, err)
// check if this tsid was already generated
if _, ok := tsidMap.Load(tsid); !ok {
// not present, store it
tsidMap.Store(tsid, (nodeId*iterationCount)+int32(j))
continue
}
// collision detected, increment counter and break out
collisionCounter.Add(1)
break
}
}(int32(node), int32(nodeBit), int32(iterationCount), &collisionCounter, &tsidMap, wg)
}
// Wait for all goroutines to complete
wg.Wait()
assert.Zero(t, collisionCounter.Load(), 0, "Collision detected")
})
}