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