github.com/matrixorigin/matrixone@v0.7.0/pkg/txn/rpc/sender_test.go (about) 1 // Copyright 2021 - 2022 Matrix Origin 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 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package rpc 16 17 import ( 18 "context" 19 "fmt" 20 "os" 21 "runtime/debug" 22 "sync/atomic" 23 "testing" 24 "time" 25 26 "github.com/lni/goutils/leaktest" 27 "github.com/matrixorigin/matrixone/pkg/common/morpc" 28 "github.com/matrixorigin/matrixone/pkg/common/mpool" 29 "github.com/matrixorigin/matrixone/pkg/pb/metadata" 30 "github.com/matrixorigin/matrixone/pkg/pb/txn" 31 "github.com/stretchr/testify/assert" 32 "github.com/stretchr/testify/require" 33 ) 34 35 var ( 36 testDN1Addr = "unix:///tmp/test-dn1.sock" 37 testDN2Addr = "unix:///tmp/test-dn2.sock" 38 testDN3Addr = "unix:///tmp/test-dn3.sock" 39 ) 40 41 func TestSendWithSingleRequest(t *testing.T) { 42 s := newTestTxnServer(t, testDN1Addr) 43 defer func() { 44 assert.NoError(t, s.Close()) 45 }() 46 47 s.RegisterRequestHandler(func(ctx context.Context, request morpc.Message, sequence uint64, cs morpc.ClientSession) error { 48 return cs.Write(ctx, &txn.TxnResponse{ 49 RequestID: request.GetID(), 50 Method: txn.TxnMethod_Write, 51 }) 52 }) 53 54 sd, err := NewSender(newTestRuntime(newTestClock(), nil)) 55 assert.NoError(t, err) 56 defer func() { 57 assert.NoError(t, sd.Close()) 58 }() 59 60 ctx, cancel := context.WithTimeout(context.Background(), time.Minute) 61 defer cancel() 62 63 req := txn.TxnRequest{ 64 Method: txn.TxnMethod_Write, 65 CNRequest: &txn.CNOpRequest{ 66 Target: metadata.DNShard{ 67 Address: testDN1Addr, 68 }, 69 }, 70 } 71 result, err := sd.Send(ctx, []txn.TxnRequest{req}) 72 assert.NoError(t, err) 73 defer result.Release() 74 assert.Equal(t, 1, len(result.Responses)) 75 assert.Equal(t, txn.TxnMethod_Write, result.Responses[0].Method) 76 } 77 78 func TestSendEnableCompressWithSingleRequest(t *testing.T) { 79 mp, err := mpool.NewMPool("test", 0, mpool.NoFixed) 80 require.NoError(t, err) 81 s := newTestTxnServer(t, testDN1Addr, morpc.WithCodecEnableCompress(mp)) 82 defer func() { 83 assert.NoError(t, s.Close()) 84 }() 85 86 s.RegisterRequestHandler(func(ctx context.Context, request morpc.Message, sequence uint64, cs morpc.ClientSession) error { 87 return cs.Write(ctx, &txn.TxnResponse{ 88 RequestID: request.GetID(), 89 Method: txn.TxnMethod_Write, 90 }) 91 }) 92 93 sd, err := NewSender(newTestRuntime(newTestClock(), nil), WithSenderEnableCompress(true)) 94 assert.NoError(t, err) 95 defer func() { 96 assert.NoError(t, sd.Close()) 97 }() 98 99 ctx, cancel := context.WithTimeout(context.Background(), time.Minute) 100 defer cancel() 101 102 req := txn.TxnRequest{ 103 Method: txn.TxnMethod_Write, 104 CNRequest: &txn.CNOpRequest{ 105 Target: metadata.DNShard{ 106 Address: testDN1Addr, 107 }, 108 }, 109 } 110 result, err := sd.Send(ctx, []txn.TxnRequest{req}) 111 assert.NoError(t, err) 112 defer result.Release() 113 assert.Equal(t, 1, len(result.Responses)) 114 assert.Equal(t, txn.TxnMethod_Write, result.Responses[0].Method) 115 } 116 117 func TestSendWithMultiDN(t *testing.T) { 118 addrs := []string{testDN1Addr, testDN2Addr, testDN3Addr} 119 for _, addr := range addrs { 120 s := newTestTxnServer(t, addr) 121 defer func() { 122 assert.NoError(t, s.Close()) 123 }() 124 125 s.RegisterRequestHandler(func(ctx context.Context, m morpc.Message, sequence uint64, cs morpc.ClientSession) error { 126 request := m.(*txn.TxnRequest) 127 return cs.Write(ctx, &txn.TxnResponse{ 128 RequestID: request.GetID(), 129 CNOpResponse: &txn.CNOpResponse{Payload: []byte(fmt.Sprintf("%s-%d", request.GetTargetDN().Address, sequence))}, 130 }) 131 }) 132 } 133 134 sd, err := NewSender(newTestRuntime(newTestClock(), nil)) 135 assert.NoError(t, err) 136 defer func() { 137 assert.NoError(t, sd.Close()) 138 }() 139 140 ctx, cancel := context.WithTimeout(context.Background(), time.Minute) 141 defer cancel() 142 143 var requests []txn.TxnRequest 144 n := 10 145 for i := 0; i < n; i++ { 146 requests = append(requests, txn.TxnRequest{ 147 Method: txn.TxnMethod_Read, 148 CNRequest: &txn.CNOpRequest{ 149 Target: metadata.DNShard{ 150 DNShardRecord: metadata.DNShardRecord{ 151 ShardID: uint64(i % len(addrs)), 152 }, 153 Address: addrs[i%len(addrs)], 154 }, 155 }, 156 }) 157 } 158 159 result, err := sd.Send(ctx, requests) 160 assert.NoError(t, err) 161 defer result.Release() 162 assert.Equal(t, n, len(result.Responses)) 163 164 counts := make(map[string]int) 165 for i := 0; i < n; i++ { 166 addr := addrs[i%len(addrs)] 167 seq := 1 168 if v, ok := counts[addr]; ok { 169 seq = v + 1 170 } 171 counts[addr] = seq 172 assert.Equal(t, []byte(fmt.Sprintf("%s-%d", addr, seq)), result.Responses[i].CNOpResponse.Payload) 173 } 174 } 175 176 func TestSendWithMultiDNAndLocal(t *testing.T) { 177 addrs := []string{testDN1Addr, testDN2Addr, testDN3Addr} 178 for _, addr := range addrs[1:] { 179 s := newTestTxnServer(t, addr) 180 defer func() { 181 assert.NoError(t, s.Close()) 182 }() 183 184 s.RegisterRequestHandler(func(ctx context.Context, m morpc.Message, sequence uint64, cs morpc.ClientSession) error { 185 request := m.(*txn.TxnRequest) 186 return cs.Write(ctx, &txn.TxnResponse{ 187 RequestID: request.GetID(), 188 CNOpResponse: &txn.CNOpResponse{Payload: []byte(fmt.Sprintf("%s-%d", request.GetTargetDN().Address, sequence))}, 189 }) 190 }) 191 } 192 193 sd, err := NewSender( 194 newTestRuntime(newTestClock(), nil), 195 WithSenderLocalDispatch(func(d metadata.DNShard) TxnRequestHandleFunc { 196 if d.Address != testDN1Addr { 197 return nil 198 } 199 sequence := uint64(0) 200 return func(_ context.Context, req *txn.TxnRequest, resp *txn.TxnResponse) error { 201 v := atomic.AddUint64(&sequence, 1) 202 resp.RequestID = req.RequestID 203 resp.CNOpResponse = &txn.CNOpResponse{Payload: []byte(fmt.Sprintf("%s-%d", req.GetTargetDN().Address, v))} 204 return nil 205 } 206 })) 207 assert.NoError(t, err) 208 defer func() { 209 assert.NoError(t, sd.Close()) 210 }() 211 212 ctx, cancel := context.WithTimeout(context.Background(), time.Minute) 213 defer cancel() 214 215 var requests []txn.TxnRequest 216 n := 10 217 for i := 0; i < n; i++ { 218 requests = append(requests, txn.TxnRequest{ 219 Method: txn.TxnMethod_Read, 220 CNRequest: &txn.CNOpRequest{ 221 Target: metadata.DNShard{ 222 DNShardRecord: metadata.DNShardRecord{ 223 ShardID: uint64(i % len(addrs)), 224 }, 225 Address: addrs[i%len(addrs)], 226 }, 227 }, 228 }) 229 } 230 231 result, err := sd.Send(ctx, requests) 232 assert.NoError(t, err) 233 defer result.Release() 234 assert.Equal(t, n, len(result.Responses)) 235 236 counts := make(map[string]int) 237 for i := 0; i < n; i++ { 238 addr := addrs[i%len(addrs)] 239 seq := 1 240 if v, ok := counts[addr]; ok { 241 seq = v + 1 242 } 243 counts[addr] = seq 244 assert.Equal(t, []byte(fmt.Sprintf("%s-%d", addr, seq)), result.Responses[i].CNOpResponse.Payload) 245 } 246 } 247 248 func TestLocalStreamDestroy(t *testing.T) { 249 ls := newLocalStream(func(ls *localStream) {}, func() *txn.TxnResponse { return &txn.TxnResponse{} }) 250 c := ls.in 251 ls = nil 252 debug.FreeOSMemory() 253 _, ok := <-c 254 assert.False(t, ok) 255 } 256 257 func BenchmarkLocalSend(b *testing.B) { 258 sd, err := NewSender( 259 newTestRuntime(newTestClock(), nil), 260 WithSenderLocalDispatch(func(d metadata.DNShard) TxnRequestHandleFunc { 261 return func(_ context.Context, req *txn.TxnRequest, resp *txn.TxnResponse) error { 262 resp.RequestID = req.RequestID 263 return nil 264 } 265 })) 266 assert.NoError(b, err) 267 defer func() { 268 assert.NoError(b, sd.Close()) 269 }() 270 271 ctx, cancel := context.WithTimeout(context.Background(), time.Minute) 272 defer cancel() 273 274 var requests []txn.TxnRequest 275 n := 10 276 for i := 0; i < n; i++ { 277 requests = append(requests, txn.TxnRequest{ 278 Method: txn.TxnMethod_Read, 279 CNRequest: &txn.CNOpRequest{ 280 Target: metadata.DNShard{}, 281 }, 282 }) 283 } 284 285 b.ResetTimer() 286 for i := 0; i < b.N; i++ { 287 result, err := sd.Send(ctx, requests) 288 assert.NoError(b, err) 289 assert.Equal(b, n, len(result.Responses)) 290 result.Release() 291 } 292 } 293 294 func TestNewSenderWithOptions(t *testing.T) { 295 defer leaktest.AfterTest(t)() 296 297 s, err := NewSender( 298 newTestRuntime(newTestClock(), nil), 299 WithSenderPayloadBufferSize(100), 300 WithSenderBackendOptions(morpc.WithBackendBusyBufferSize(1))) 301 assert.NoError(t, err) 302 defer func() { 303 require.NoError(t, s.Close()) 304 }() 305 306 assert.Equal(t, 100, s.(*sender).options.payloadCopyBufferSize) 307 assert.True(t, len(s.(*sender).options.backendCreateOptions) >= 2) 308 assert.True(t, len(s.(*sender).options.clientOptions) >= 1) 309 } 310 311 func TestCanSendWithLargeRequest(t *testing.T) { 312 size := 1024 * 1024 * 20 313 s := newTestTxnServer(t, testDN1Addr, morpc.WithCodecMaxBodySize(size+1024)) 314 defer func() { 315 assert.NoError(t, s.Close()) 316 }() 317 318 s.RegisterRequestHandler(func(ctx context.Context, request morpc.Message, sequence uint64, cs morpc.ClientSession) error { 319 return cs.Write(ctx, &txn.TxnResponse{ 320 RequestID: request.GetID(), 321 Method: txn.TxnMethod_Write, 322 CNOpResponse: &txn.CNOpResponse{ 323 Payload: make([]byte, size), 324 }, 325 }) 326 }) 327 328 sd, err := NewSender(newTestRuntime(newTestClock(), nil), WithSenderMaxMessageSize(size+1024)) 329 assert.NoError(t, err) 330 defer func() { 331 assert.NoError(t, sd.Close()) 332 }() 333 334 ctx, cancel := context.WithTimeout(context.Background(), time.Minute) 335 defer cancel() 336 337 req := txn.TxnRequest{ 338 Method: txn.TxnMethod_Write, 339 CNRequest: &txn.CNOpRequest{ 340 Target: metadata.DNShard{ 341 Address: testDN1Addr, 342 }, 343 Payload: make([]byte, size), 344 }, 345 } 346 result, err := sd.Send(ctx, []txn.TxnRequest{req}) 347 assert.NoError(t, err) 348 defer result.Release() 349 assert.Equal(t, 1, len(result.Responses)) 350 assert.Equal(t, txn.TxnMethod_Write, result.Responses[0].Method) 351 } 352 353 func newTestTxnServer(t assert.TestingT, addr string, opts ...morpc.CodecOption) morpc.RPCServer { 354 assert.NoError(t, os.RemoveAll(addr[7:])) 355 opts = append(opts, 356 morpc.WithCodecIntegrationHLC(newTestClock()), 357 morpc.WithCodecEnableChecksum()) 358 codec := morpc.NewMessageCodec(func() morpc.Message { return &txn.TxnRequest{} }, 359 opts...) 360 s, err := morpc.NewRPCServer("test-txn-server", addr, codec) 361 assert.NoError(t, err) 362 assert.NoError(t, s.Start()) 363 return s 364 }