github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/pkg/p2p/internal/send_chan_test.go (about) 1 // Copyright 2022 PingCAP, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package internal 15 16 import ( 17 "context" 18 "sync" 19 "testing" 20 "time" 21 22 "github.com/stretchr/testify/require" 23 "go.uber.org/atomic" 24 ) 25 26 const ( 27 defaultSendChanCap = 8 28 numProducers = 8 29 numMsgPerProducer = 1000 30 numMsgPerProducerForSync = 100 31 ) 32 33 func TestSendChanBasics(t *testing.T) { 34 ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) 35 defer cancel() 36 37 seq := atomic.NewInt64(0) 38 c := NewSendChan(defaultSendChanCap) 39 40 var wg sync.WaitGroup 41 42 // Runs the producers 43 for i := 0; i < numProducers; i++ { 44 wg.Add(1) 45 go func() { 46 defer wg.Done() 47 lastSeq := int64(0) 48 for j := 0; j < numMsgPerProducer; { 49 ok, seq := c.SendAsync( 50 "test-topic", 51 []byte("test-value"), 52 func() int64 { 53 return seq.Inc() 54 }) 55 if !ok { 56 continue 57 } 58 j++ 59 require.Greater(t, seq, lastSeq) 60 lastSeq = seq 61 } 62 }() 63 } 64 65 // Runs the consumer 66 wg.Add(1) 67 go func() { 68 defer wg.Done() 69 ticker := time.NewTicker(time.Millisecond * 10) 70 71 recvCount := 0 72 lastSeq := int64(0) 73 for { 74 msg, ok, err := c.Receive(ctx, ticker.C) 75 require.NoError(t, err) 76 if !ok { 77 continue 78 } 79 recvCount++ 80 require.Equal(t, lastSeq+1, msg.Sequence) 81 lastSeq = msg.Sequence 82 if recvCount == numProducers*numMsgPerProducer { 83 return 84 } 85 } 86 }() 87 88 wg.Wait() 89 cancel() 90 } 91 92 func TestSendChanSendSync(t *testing.T) { 93 ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) 94 defer cancel() 95 96 dummyCloseCh := make(chan struct{}) 97 98 seq := atomic.NewInt64(0) 99 c := NewSendChan(defaultSendChanCap) 100 101 var wg sync.WaitGroup 102 103 // Runs the producers 104 for i := 0; i < numProducers; i++ { 105 wg.Add(1) 106 go func() { 107 defer wg.Done() 108 lastSeq := int64(0) 109 for j := 0; j < numMsgPerProducerForSync; j++ { 110 seq, err := c.SendSync( 111 ctx, 112 "test-topic", 113 []byte("test-value"), 114 dummyCloseCh, 115 func() int64 { 116 return seq.Inc() 117 }) 118 require.NoError(t, err) 119 require.Greater(t, seq, lastSeq) 120 lastSeq = seq 121 } 122 }() 123 } 124 125 // Runs the consumer 126 wg.Add(1) 127 go func() { 128 defer wg.Done() 129 ticker := time.NewTicker(time.Millisecond * 10) 130 131 recvCount := 0 132 lastSeq := int64(0) 133 for { 134 msg, ok, err := c.Receive(ctx, ticker.C) 135 require.NoError(t, err) 136 if !ok { 137 continue 138 } 139 recvCount++ 140 require.Equal(t, lastSeq+1, msg.Sequence) 141 lastSeq = msg.Sequence 142 if recvCount == numProducers*numMsgPerProducerForSync { 143 return 144 } 145 } 146 }() 147 148 wg.Wait() 149 cancel() 150 } 151 152 func BenchmarkSendChanSendAsyncSPSC(b *testing.B) { 153 var wg sync.WaitGroup 154 155 seq := atomic.NewInt64(0) 156 c := NewSendChan(defaultSendChanCap) 157 158 wg.Add(1) 159 go func() { 160 defer wg.Done() 161 for j := 0; j < b.N; { 162 ok, _ := c.SendAsync("test-topic", []byte("test-value"), func() int64 { 163 return seq.Inc() 164 }) 165 if !ok { 166 continue 167 } 168 j++ 169 } 170 }() 171 172 recvCount := 0 173 dummyTicker := make(chan time.Time) 174 for { 175 _, ok, err := c.Receive(context.Background(), dummyTicker) 176 if err != nil { 177 b.Fail() 178 } 179 if !ok { 180 continue 181 } 182 recvCount++ 183 if recvCount == b.N { 184 break 185 } 186 } 187 188 wg.Wait() 189 } 190 191 func BenchmarkSendChanSendSyncSPSC(b *testing.B) { 192 var wg sync.WaitGroup 193 194 dummyCloseCh := make(chan struct{}) 195 196 seq := atomic.NewInt64(0) 197 c := NewSendChan(defaultSendChanCap) 198 199 wg.Add(1) 200 go func() { 201 defer wg.Done() 202 for j := 0; j < b.N; j++ { 203 _, _ = c.SendSync( 204 context.TODO(), 205 "test-topic", 206 []byte("test-value"), 207 dummyCloseCh, func() int64 { 208 return seq.Inc() 209 }) 210 } 211 }() 212 213 recvCount := 0 214 dummyTicker := make(chan time.Time) 215 for { 216 _, ok, err := c.Receive(context.Background(), dummyTicker) 217 if err != nil { 218 b.Fail() 219 } 220 if !ok { 221 continue 222 } 223 recvCount++ 224 if recvCount == b.N { 225 break 226 } 227 } 228 229 wg.Wait() 230 } 231 232 func BenchmarkSendChanSendAsyncMPSC8(b *testing.B) { 233 var wg sync.WaitGroup 234 235 seq := atomic.NewInt64(0) 236 c := NewSendChan(defaultSendChanCap) 237 238 for i := 0; i < 8; i++ { 239 wg.Add(1) 240 go func() { 241 defer wg.Done() 242 for j := 0; j < b.N; { 243 ok, _ := c.SendAsync("test-topic", []byte("test-value"), func() int64 { 244 return seq.Inc() 245 }) 246 if !ok { 247 continue 248 } 249 j++ 250 } 251 }() 252 } 253 254 recvCount := 0 255 dummyTicker := make(chan time.Time) 256 for { 257 _, ok, err := c.Receive(context.Background(), dummyTicker) 258 if err != nil { 259 b.Fail() 260 } 261 if !ok { 262 continue 263 } 264 recvCount++ 265 if recvCount == b.N*8 { 266 break 267 } 268 } 269 270 wg.Wait() 271 } 272 273 func BenchmarkSendChanSendSyncMPSC8(b *testing.B) { 274 var wg sync.WaitGroup 275 276 seq := atomic.NewInt64(0) 277 c := NewSendChan(defaultSendChanCap) 278 dummyCloseCh := make(chan struct{}) 279 280 for i := 0; i < 8; i++ { 281 wg.Add(1) 282 go func() { 283 defer wg.Done() 284 for j := 0; j < b.N; j++ { 285 _, _ = c.SendSync( 286 context.TODO(), 287 "test-topic", 288 []byte("test-value"), 289 dummyCloseCh, func() int64 { 290 return seq.Inc() 291 }) 292 } 293 }() 294 } 295 296 recvCount := 0 297 dummyTicker := make(chan time.Time) 298 for { 299 _, ok, err := c.Receive(context.Background(), dummyTicker) 300 if err != nil { 301 b.Fail() 302 } 303 if !ok { 304 continue 305 } 306 recvCount++ 307 if recvCount == b.N*8 { 308 break 309 } 310 } 311 312 wg.Wait() 313 }