github.com/matrixorigin/matrixone@v0.7.0/pkg/txn/rpc/sender.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  	"runtime"
    20  	"sync"
    21  
    22  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    23  	"github.com/matrixorigin/matrixone/pkg/common/morpc"
    24  	"github.com/matrixorigin/matrixone/pkg/common/mpool"
    25  	moruntime "github.com/matrixorigin/matrixone/pkg/common/runtime"
    26  	"github.com/matrixorigin/matrixone/pkg/pb/metadata"
    27  	"github.com/matrixorigin/matrixone/pkg/pb/txn"
    28  	"github.com/matrixorigin/matrixone/pkg/util/trace"
    29  )
    30  
    31  // WithSenderPayloadBufferSize set buffer size for copy payload data to socket.
    32  func WithSenderPayloadBufferSize(value int) SenderOption {
    33  	return func(s *sender) {
    34  		s.options.payloadCopyBufferSize = value
    35  	}
    36  }
    37  
    38  // WithSenderBackendOptions set options for create backend connections
    39  func WithSenderBackendOptions(options ...morpc.BackendOption) SenderOption {
    40  	return func(s *sender) {
    41  		s.options.backendCreateOptions = append(s.options.backendCreateOptions, options...)
    42  	}
    43  }
    44  
    45  // WithSenderClientOptions set options for create client
    46  func WithSenderClientOptions(options ...morpc.ClientOption) SenderOption {
    47  	return func(s *sender) {
    48  		s.options.clientOptions = options
    49  	}
    50  }
    51  
    52  // WithSenderLocalDispatch set options for dispatch request to local to avoid rpc call
    53  func WithSenderLocalDispatch(localDispatch LocalDispatch) SenderOption {
    54  	return func(s *sender) {
    55  		s.options.localDispatch = localDispatch
    56  	}
    57  }
    58  
    59  // WithSenderMaxMessageSize set max rpc message size
    60  func WithSenderMaxMessageSize(maxMessageSize int) SenderOption {
    61  	return func(s *sender) {
    62  		s.options.maxMessageSize = maxMessageSize
    63  	}
    64  }
    65  
    66  // WithSenderEnableCompress enable compress
    67  func WithSenderEnableCompress(enable bool) SenderOption {
    68  	return func(s *sender) {
    69  		s.options.enableCompress = enable
    70  	}
    71  }
    72  
    73  type sender struct {
    74  	rt     moruntime.Runtime
    75  	client morpc.RPCClient
    76  
    77  	options struct {
    78  		localDispatch         LocalDispatch
    79  		payloadCopyBufferSize int
    80  		maxMessageSize        int
    81  		enableCompress        bool
    82  		backendCreateOptions  []morpc.BackendOption
    83  		clientOptions         []morpc.ClientOption
    84  	}
    85  
    86  	pool struct {
    87  		resultPool      *sync.Pool
    88  		responsePool    *sync.Pool
    89  		localStreamPool *sync.Pool
    90  	}
    91  }
    92  
    93  // NewSenderWithConfig create a txn sender by config and options
    94  func NewSenderWithConfig(cfg Config,
    95  	rt moruntime.Runtime,
    96  	options ...SenderOption) (TxnSender, error) {
    97  	cfg.adjust()
    98  	options = append(options, WithSenderBackendOptions(cfg.getBackendOptions(rt.Logger().RawLogger())...))
    99  	options = append(options, WithSenderClientOptions(cfg.getClientOptions(rt.Logger().RawLogger())...))
   100  	options = append(options, WithSenderMaxMessageSize(int(cfg.MaxMessageSize)))
   101  	options = append(options, WithSenderEnableCompress(cfg.EnableCompress))
   102  	return NewSender(rt, options...)
   103  }
   104  
   105  // NewSender create a txn sender
   106  func NewSender(
   107  	rt moruntime.Runtime,
   108  	options ...SenderOption) (TxnSender, error) {
   109  	s := &sender{rt: rt}
   110  	for _, opt := range options {
   111  		opt(s)
   112  	}
   113  	s.adjust()
   114  
   115  	s.pool.localStreamPool = &sync.Pool{
   116  		New: func() any {
   117  			return newLocalStream(s.releaseLocalStream, s.acquireResponse)
   118  		},
   119  	}
   120  	s.pool.resultPool = &sync.Pool{
   121  		New: func() any {
   122  			rs := &SendResult{
   123  				pool:    s.pool.resultPool,
   124  				streams: make(map[uint64]morpc.Stream, 16),
   125  			}
   126  			return rs
   127  		},
   128  	}
   129  	s.pool.responsePool = &sync.Pool{
   130  		New: func() any {
   131  			return &txn.TxnResponse{}
   132  		},
   133  	}
   134  
   135  	var codecOpts []morpc.CodecOption
   136  	codecOpts = append(codecOpts,
   137  		morpc.WithCodecIntegrationHLC(s.rt.Clock()),
   138  		morpc.WithCodecPayloadCopyBufferSize(s.options.payloadCopyBufferSize),
   139  		morpc.WithCodecEnableChecksum(),
   140  		morpc.WithCodecMaxBodySize(s.options.maxMessageSize))
   141  	if s.options.enableCompress {
   142  		mp, err := mpool.NewMPool("txn_rpc_sender", 0, mpool.NoFixed)
   143  		if err != nil {
   144  			return nil, err
   145  		}
   146  		codecOpts = append(codecOpts, morpc.WithCodecEnableCompress(mp))
   147  	}
   148  
   149  	codec := morpc.NewMessageCodec(
   150  		func() morpc.Message { return s.acquireResponse() },
   151  		codecOpts...)
   152  	bf := morpc.NewGoettyBasedBackendFactory(codec, s.options.backendCreateOptions...)
   153  	client, err := morpc.NewClient(bf, s.options.clientOptions...)
   154  	if err != nil {
   155  		return nil, err
   156  	}
   157  	s.client = client
   158  	return s, nil
   159  }
   160  
   161  func (s *sender) adjust() {
   162  	if s.options.payloadCopyBufferSize == 0 {
   163  		s.options.payloadCopyBufferSize = 16 * 1024
   164  	}
   165  	s.options.backendCreateOptions = append(s.options.backendCreateOptions,
   166  		morpc.WithBackendLogger(s.rt.Logger().RawLogger()))
   167  
   168  	s.options.clientOptions = append(s.options.clientOptions, morpc.WithClientLogger(s.rt.Logger().RawLogger()))
   169  }
   170  
   171  func (s *sender) Close() error {
   172  	return s.client.Close()
   173  }
   174  
   175  func (s *sender) Send(ctx context.Context, requests []txn.TxnRequest) (*SendResult, error) {
   176  	sr := s.acquireSendResult()
   177  	if len(requests) == 1 {
   178  		sr.reset(requests)
   179  		resp, err := s.doSend(ctx, requests[0])
   180  		if err != nil {
   181  			sr.Release()
   182  			return nil, err
   183  		}
   184  		sr.Responses[0] = resp
   185  		return sr, nil
   186  	}
   187  
   188  	sr.reset(requests)
   189  	for idx := range requests {
   190  		dn := requests[idx].GetTargetDN()
   191  		st := sr.getStream(dn.ShardID)
   192  		if st == nil {
   193  			v, err := s.createStream(ctx, dn, len(requests))
   194  			if err != nil {
   195  				sr.Release()
   196  				return nil, err
   197  			}
   198  			st = v
   199  			sr.setStream(dn.ShardID, v)
   200  		}
   201  
   202  		requests[idx].RequestID = st.ID()
   203  		if err := st.Send(ctx, &requests[idx]); err != nil {
   204  			sr.Release()
   205  			return nil, err
   206  		}
   207  	}
   208  
   209  	for idx := range requests {
   210  		st := sr.getStream(requests[idx].GetTargetDN().ShardID)
   211  		c, err := st.Receive()
   212  		if err != nil {
   213  			sr.Release()
   214  			return nil, err
   215  		}
   216  		v, ok := <-c
   217  		if !ok {
   218  			return nil, moerr.NewStreamClosedNoCtx()
   219  		}
   220  		resp := v.(*txn.TxnResponse)
   221  		sr.setResponse(resp, idx)
   222  		s.releaseResponse(resp)
   223  	}
   224  	return sr, nil
   225  }
   226  
   227  func (s *sender) doSend(ctx context.Context, request txn.TxnRequest) (txn.TxnResponse, error) {
   228  	ctx, span := trace.Debug(ctx, "sender.doSend")
   229  	defer span.End()
   230  	dn := request.GetTargetDN()
   231  	if s.options.localDispatch != nil {
   232  		if handle := s.options.localDispatch(dn); handle != nil {
   233  			response := txn.TxnResponse{}
   234  			err := handle(ctx, &request, &response)
   235  			return response, err
   236  		}
   237  	}
   238  
   239  	f, err := s.client.Send(ctx, dn.Address, &request)
   240  	if err != nil {
   241  		return txn.TxnResponse{}, err
   242  	}
   243  	defer f.Close()
   244  
   245  	v, err := f.Get()
   246  	if err != nil {
   247  		return txn.TxnResponse{}, err
   248  	}
   249  	return *(v.(*txn.TxnResponse)), nil
   250  }
   251  
   252  func (s *sender) createStream(ctx context.Context, dn metadata.DNShard, size int) (morpc.Stream, error) {
   253  	if s.options.localDispatch != nil {
   254  		if h := s.options.localDispatch(dn); h != nil {
   255  			ls := s.acquireLocalStream()
   256  			ls.setup(ctx, h)
   257  			return ls, nil
   258  		}
   259  	}
   260  	return s.client.NewStream(dn.Address, false)
   261  }
   262  
   263  func (s *sender) acquireLocalStream() *localStream {
   264  	return s.pool.localStreamPool.Get().(*localStream)
   265  }
   266  
   267  func (s *sender) releaseLocalStream(ls *localStream) {
   268  	s.pool.localStreamPool.Put(ls)
   269  }
   270  
   271  func (s *sender) acquireResponse() *txn.TxnResponse {
   272  	return s.pool.responsePool.Get().(*txn.TxnResponse)
   273  }
   274  
   275  func (s *sender) releaseResponse(response *txn.TxnResponse) {
   276  	response.Reset()
   277  	s.pool.responsePool.Put(response)
   278  }
   279  
   280  func (s *sender) acquireSendResult() *SendResult {
   281  	return s.pool.resultPool.Get().(*SendResult)
   282  }
   283  
   284  type sendMessage struct {
   285  	request morpc.Message
   286  	// opts            morpc.SendOptions
   287  	handleFunc      TxnRequestHandleFunc
   288  	responseFactory func() *txn.TxnResponse
   289  	ctx             context.Context
   290  }
   291  
   292  type localStream struct {
   293  	releaseFunc     func(ls *localStream)
   294  	responseFactory func() *txn.TxnResponse
   295  	in              chan sendMessage
   296  	out             chan morpc.Message
   297  
   298  	// reset fields
   299  	closed     bool
   300  	handleFunc TxnRequestHandleFunc
   301  	ctx        context.Context
   302  }
   303  
   304  func newLocalStream(releaseFunc func(ls *localStream), responseFactory func() *txn.TxnResponse) *localStream {
   305  	ls := &localStream{
   306  		releaseFunc:     releaseFunc,
   307  		responseFactory: responseFactory,
   308  		in:              make(chan sendMessage, 32),
   309  		out:             make(chan morpc.Message, 32),
   310  	}
   311  	ls.setFinalizer()
   312  	ls.start()
   313  	return ls
   314  }
   315  
   316  func (ls *localStream) setFinalizer() {
   317  	runtime.SetFinalizer(ls, func(ls *localStream) {
   318  		ls.destroy()
   319  	})
   320  }
   321  
   322  func (ls *localStream) setup(ctx context.Context, handleFunc TxnRequestHandleFunc) {
   323  	ls.handleFunc = handleFunc
   324  	ls.ctx = ctx
   325  	ls.closed = false
   326  }
   327  
   328  func (ls *localStream) ID() uint64 {
   329  	return 0
   330  }
   331  
   332  func (ls *localStream) Send(ctx context.Context, request morpc.Message) error {
   333  	if ls.closed {
   334  		panic("send after closed")
   335  	}
   336  
   337  	ls.in <- sendMessage{
   338  		request:         request,
   339  		handleFunc:      ls.handleFunc,
   340  		responseFactory: ls.responseFactory,
   341  		ctx:             ls.ctx,
   342  	}
   343  	return nil
   344  }
   345  
   346  func (ls *localStream) Receive() (chan morpc.Message, error) {
   347  	if ls.closed {
   348  		panic("send after closed")
   349  	}
   350  
   351  	return ls.out, nil
   352  }
   353  
   354  func (ls *localStream) Close() error {
   355  	if ls.closed {
   356  		return nil
   357  	}
   358  	ls.closed = true
   359  	ls.ctx = nil
   360  	ls.releaseFunc(ls)
   361  	return nil
   362  }
   363  
   364  func (ls *localStream) destroy() {
   365  	close(ls.in)
   366  	close(ls.out)
   367  }
   368  
   369  func (ls *localStream) start() {
   370  	go func(in chan sendMessage, out chan morpc.Message) {
   371  		for {
   372  			v, ok := <-in
   373  			if !ok {
   374  				return
   375  			}
   376  
   377  			response := v.responseFactory()
   378  			err := v.handleFunc(v.ctx, v.request.(*txn.TxnRequest), response)
   379  			if err != nil {
   380  				response.TxnError = txn.WrapError(moerr.NewRpcErrorNoCtx(err.Error()), 0)
   381  			}
   382  			out <- response
   383  		}
   384  	}(ls.in, ls.out)
   385  }
   386  
   387  func (sr *SendResult) reset(requests []txn.TxnRequest) {
   388  	size := len(requests)
   389  	if size == len(sr.Responses) {
   390  		for i := 0; i < size; i++ {
   391  			sr.Responses[i] = txn.TxnResponse{}
   392  		}
   393  		return
   394  	}
   395  
   396  	for i := 0; i < size; i++ {
   397  		sr.Responses = append(sr.Responses, txn.TxnResponse{})
   398  	}
   399  }
   400  
   401  func (sr *SendResult) setStream(dn uint64, st morpc.Stream) {
   402  	sr.streams[dn] = st
   403  }
   404  
   405  func (sr *SendResult) getStream(dn uint64) morpc.Stream {
   406  	return sr.streams[dn]
   407  }
   408  
   409  func (sr *SendResult) setResponse(resp *txn.TxnResponse, index int) {
   410  	sr.Responses[index] = *resp
   411  }
   412  
   413  // Release release send result
   414  func (sr *SendResult) Release() {
   415  	if sr.pool != nil {
   416  		for k, st := range sr.streams {
   417  			if st != nil {
   418  				_ = st.Close()
   419  			}
   420  			delete(sr.streams, k)
   421  		}
   422  		sr.Responses = sr.Responses[:0]
   423  		sr.pool.Put(sr)
   424  	}
   425  }