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  }