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  }