github.com/matrixorigin/matrixone@v1.2.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  	"time"
    22  
    23  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    24  	"github.com/matrixorigin/matrixone/pkg/common/morpc"
    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  	v2 "github.com/matrixorigin/matrixone/pkg/util/metric/v2"
    29  	"github.com/matrixorigin/matrixone/pkg/util/trace"
    30  )
    31  
    32  // WithSenderLocalDispatch set options for dispatch request to local to avoid rpc call
    33  func WithSenderLocalDispatch(localDispatch LocalDispatch) SenderOption {
    34  	return func(s *sender) {
    35  		s.options.localDispatch = localDispatch
    36  	}
    37  }
    38  
    39  type sender struct {
    40  	cfg    *Config
    41  	rt     moruntime.Runtime
    42  	client morpc.RPCClient
    43  
    44  	options struct {
    45  		localDispatch LocalDispatch
    46  	}
    47  
    48  	pool struct {
    49  		resultPool      *sync.Pool
    50  		responsePool    *sync.Pool
    51  		localStreamPool *sync.Pool
    52  	}
    53  }
    54  
    55  // NewSender create a txn sender
    56  func NewSender(
    57  	cfg Config,
    58  	rt moruntime.Runtime,
    59  	options ...SenderOption) (TxnSender, error) {
    60  	s := &sender{rt: rt, cfg: &cfg}
    61  	for _, opt := range options {
    62  		opt(s)
    63  	}
    64  	s.adjust()
    65  
    66  	s.pool.localStreamPool = &sync.Pool{
    67  		New: func() any {
    68  			return newLocalStream(s.releaseLocalStream, s.acquireResponse)
    69  		},
    70  	}
    71  	s.pool.resultPool = &sync.Pool{
    72  		New: func() any {
    73  			rs := &SendResult{
    74  				pool:    s.pool.resultPool,
    75  				streams: make(map[uint64]morpc.Stream, 16),
    76  			}
    77  			return rs
    78  		},
    79  	}
    80  	s.pool.responsePool = &sync.Pool{
    81  		New: func() any {
    82  			return &txn.TxnResponse{}
    83  		},
    84  	}
    85  
    86  	s.cfg.BackendOptions = append(s.cfg.BackendOptions,
    87  		morpc.WithBackendStreamBufferSize(10000))
    88  	client, err := s.cfg.NewClient(
    89  		"txn-client",
    90  		s.rt.Logger().RawLogger(),
    91  		func() morpc.Message { return s.acquireResponse() })
    92  	if err != nil {
    93  		return nil, err
    94  	}
    95  	s.client = client
    96  	return s, nil
    97  }
    98  
    99  func (s *sender) adjust() {
   100  	s.cfg.Adjust()
   101  	s.cfg.CodecOptions = append(s.cfg.CodecOptions, morpc.WithCodecIntegrationHLC(s.rt.Clock()))
   102  }
   103  
   104  func (s *sender) Close() error {
   105  	return s.client.Close()
   106  }
   107  
   108  func (s *sender) Send(ctx context.Context, requests []txn.TxnRequest) (*SendResult, error) {
   109  	sr := s.acquireSendResult()
   110  	if len(requests) == 1 {
   111  		sr.reset(requests)
   112  		resp, err := s.doSend(ctx, requests[0])
   113  		if err != nil {
   114  			sr.Release()
   115  			return nil, err
   116  		}
   117  		sr.Responses[0] = resp
   118  		return sr, nil
   119  	}
   120  
   121  	sr.reset(requests)
   122  	for idx := range requests {
   123  		tn := requests[idx].GetTargetTN()
   124  		st := sr.getStream(tn.ShardID)
   125  		if st == nil {
   126  			v, err := s.createStream(ctx, tn, len(requests))
   127  			if err != nil {
   128  				sr.Release()
   129  				return nil, err
   130  			}
   131  			st = v
   132  			sr.setStream(tn.ShardID, v)
   133  		}
   134  
   135  		requests[idx].RequestID = st.ID()
   136  		if err := st.Send(ctx, &requests[idx]); err != nil {
   137  			sr.Release()
   138  			return nil, err
   139  		}
   140  	}
   141  
   142  	for idx := range requests {
   143  		st := sr.getStream(requests[idx].GetTargetTN().ShardID)
   144  		c, err := st.Receive()
   145  		if err != nil {
   146  			sr.Release()
   147  			return nil, err
   148  		}
   149  		v, ok := <-c
   150  		if !ok {
   151  			return nil, moerr.NewStreamClosedNoCtx()
   152  		}
   153  		resp := v.(*txn.TxnResponse)
   154  		sr.setResponse(resp, idx)
   155  		s.releaseResponse(resp)
   156  	}
   157  	return sr, nil
   158  }
   159  
   160  func (s *sender) doSend(ctx context.Context, request txn.TxnRequest) (txn.TxnResponse, error) {
   161  	ctx, span := trace.Debug(ctx, "sender.doSend")
   162  	defer span.End()
   163  	tn := request.GetTargetTN()
   164  	if s.options.localDispatch != nil {
   165  		if handle := s.options.localDispatch(tn); handle != nil {
   166  			response := txn.TxnResponse{}
   167  			err := handle(ctx, &request, &response)
   168  			return response, err
   169  		}
   170  	}
   171  
   172  	start := time.Now()
   173  	f, err := s.client.Send(ctx, tn.Address, &request)
   174  	if err != nil {
   175  		return txn.TxnResponse{}, err
   176  	}
   177  	v2.TxnCNSendCommitDurationHistogram.Observe(time.Since(start).Seconds())
   178  	defer f.Close()
   179  
   180  	v, err := f.Get()
   181  	if err != nil {
   182  		return txn.TxnResponse{}, err
   183  	}
   184  	return *(v.(*txn.TxnResponse)), nil
   185  }
   186  
   187  func (s *sender) createStream(ctx context.Context, tn metadata.TNShard, size int) (morpc.Stream, error) {
   188  	if s.options.localDispatch != nil {
   189  		if h := s.options.localDispatch(tn); h != nil {
   190  			ls := s.acquireLocalStream()
   191  			ls.setup(ctx, h)
   192  			return ls, nil
   193  		}
   194  	}
   195  	return s.client.NewStream(tn.Address, false)
   196  }
   197  
   198  func (s *sender) acquireLocalStream() *localStream {
   199  	return s.pool.localStreamPool.Get().(*localStream)
   200  }
   201  
   202  func (s *sender) releaseLocalStream(ls *localStream) {
   203  	s.pool.localStreamPool.Put(ls)
   204  }
   205  
   206  func (s *sender) acquireResponse() *txn.TxnResponse {
   207  	return s.pool.responsePool.Get().(*txn.TxnResponse)
   208  }
   209  
   210  func (s *sender) releaseResponse(response *txn.TxnResponse) {
   211  	response.Reset()
   212  	s.pool.responsePool.Put(response)
   213  }
   214  
   215  func (s *sender) acquireSendResult() *SendResult {
   216  	return s.pool.resultPool.Get().(*SendResult)
   217  }
   218  
   219  type sendMessage struct {
   220  	request morpc.Message
   221  	// opts            morpc.SendOptions
   222  	handleFunc      TxnRequestHandleFunc
   223  	responseFactory func() *txn.TxnResponse
   224  	ctx             context.Context
   225  }
   226  
   227  type localStream struct {
   228  	releaseFunc     func(ls *localStream)
   229  	responseFactory func() *txn.TxnResponse
   230  	in              chan sendMessage
   231  	out             chan morpc.Message
   232  
   233  	// reset fields
   234  	closed     bool
   235  	handleFunc TxnRequestHandleFunc
   236  	ctx        context.Context
   237  }
   238  
   239  func newLocalStream(releaseFunc func(ls *localStream), responseFactory func() *txn.TxnResponse) *localStream {
   240  	ls := &localStream{
   241  		releaseFunc:     releaseFunc,
   242  		responseFactory: responseFactory,
   243  		in:              make(chan sendMessage, 32),
   244  		out:             make(chan morpc.Message, 32),
   245  	}
   246  	ls.setFinalizer()
   247  	ls.start()
   248  	return ls
   249  }
   250  
   251  func (ls *localStream) setFinalizer() {
   252  	runtime.SetFinalizer(ls, func(ls *localStream) {
   253  		ls.destroy()
   254  	})
   255  }
   256  
   257  func (ls *localStream) setup(ctx context.Context, handleFunc TxnRequestHandleFunc) {
   258  	ls.handleFunc = handleFunc
   259  	ls.ctx = ctx
   260  	ls.closed = false
   261  }
   262  
   263  func (ls *localStream) ID() uint64 {
   264  	return 0
   265  }
   266  
   267  func (ls *localStream) Send(ctx context.Context, request morpc.Message) error {
   268  	if ls.closed {
   269  		panic("send after closed")
   270  	}
   271  
   272  	ls.in <- sendMessage{
   273  		request:         request,
   274  		handleFunc:      ls.handleFunc,
   275  		responseFactory: ls.responseFactory,
   276  		ctx:             ls.ctx,
   277  	}
   278  	return nil
   279  }
   280  
   281  func (ls *localStream) Receive() (chan morpc.Message, error) {
   282  	if ls.closed {
   283  		panic("send after closed")
   284  	}
   285  
   286  	return ls.out, nil
   287  }
   288  
   289  func (ls *localStream) Close(closeConn bool) error {
   290  	if ls.closed {
   291  		return nil
   292  	}
   293  	ls.closed = true
   294  	ls.ctx = nil
   295  	ls.releaseFunc(ls)
   296  	return nil
   297  }
   298  
   299  func (ls *localStream) destroy() {
   300  	close(ls.in)
   301  	close(ls.out)
   302  }
   303  
   304  func (ls *localStream) start() {
   305  	go func(in chan sendMessage, out chan morpc.Message) {
   306  		for {
   307  			v, ok := <-in
   308  			if !ok {
   309  				return
   310  			}
   311  
   312  			response := v.responseFactory()
   313  			err := v.handleFunc(v.ctx, v.request.(*txn.TxnRequest), response)
   314  			if err != nil {
   315  				response.TxnError = txn.WrapError(moerr.NewRpcErrorNoCtx(err.Error()), 0)
   316  			}
   317  			out <- response
   318  		}
   319  	}(ls.in, ls.out)
   320  }
   321  
   322  func (sr *SendResult) reset(requests []txn.TxnRequest) {
   323  	size := len(requests)
   324  	if size == len(sr.Responses) {
   325  		for i := 0; i < size; i++ {
   326  			sr.Responses[i] = txn.TxnResponse{}
   327  		}
   328  		return
   329  	}
   330  
   331  	for i := 0; i < size; i++ {
   332  		sr.Responses = append(sr.Responses, txn.TxnResponse{})
   333  	}
   334  }
   335  
   336  func (sr *SendResult) setStream(tn uint64, st morpc.Stream) {
   337  	sr.streams[tn] = st
   338  }
   339  
   340  func (sr *SendResult) getStream(tn uint64) morpc.Stream {
   341  	return sr.streams[tn]
   342  }
   343  
   344  func (sr *SendResult) setResponse(resp *txn.TxnResponse, index int) {
   345  	sr.Responses[index] = *resp
   346  }
   347  
   348  // Release release send result
   349  func (sr *SendResult) Release() {
   350  	if sr.pool != nil {
   351  		for k, st := range sr.streams {
   352  			if st != nil {
   353  				_ = st.Close(false)
   354  			}
   355  			delete(sr.streams, k)
   356  		}
   357  		sr.Responses = sr.Responses[:0]
   358  		sr.pool.Put(sr)
   359  	}
   360  }