github.com/matrixorigin/matrixone@v1.2.0/pkg/tnservice/store_rpc_handler.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 tnservice
    16  
    17  import (
    18  	"context"
    19  	"github.com/matrixorigin/matrixone/pkg/util/trace"
    20  	"time"
    21  
    22  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    23  	"github.com/matrixorigin/matrixone/pkg/pb/metadata"
    24  	"github.com/matrixorigin/matrixone/pkg/pb/txn"
    25  	"github.com/matrixorigin/matrixone/pkg/txn/rpc"
    26  )
    27  
    28  const (
    29  	defaultRetryInterval = time.Millisecond * 100
    30  )
    31  
    32  func (s *store) registerRPCHandlers() {
    33  	// request from CN node
    34  	s.server.RegisterMethodHandler(txn.TxnMethod_Read, s.handleRead)
    35  	s.server.RegisterMethodHandler(txn.TxnMethod_Write, s.handleWrite)
    36  	s.server.RegisterMethodHandler(txn.TxnMethod_Commit, s.handleCommit)
    37  	s.server.RegisterMethodHandler(txn.TxnMethod_Rollback, s.handleRollback)
    38  
    39  	// request from other TN node
    40  	s.server.RegisterMethodHandler(txn.TxnMethod_Prepare, s.handlePrepare)
    41  	s.server.RegisterMethodHandler(txn.TxnMethod_CommitTNShard, s.handleCommitTNShard)
    42  	s.server.RegisterMethodHandler(txn.TxnMethod_RollbackTNShard, s.handleRollbackTNShard)
    43  	s.server.RegisterMethodHandler(txn.TxnMethod_GetStatus, s.handleGetStatus)
    44  
    45  	// debug request
    46  	s.server.RegisterMethodHandler(txn.TxnMethod_DEBUG, s.handleDebug)
    47  }
    48  
    49  func (s *store) dispatchLocalRequest(shard metadata.TNShard) rpc.TxnRequestHandleFunc {
    50  	// DNShard not found, TxnSender will RPC call
    51  	r := s.getReplica(shard.ShardID)
    52  	if r == nil {
    53  		return nil
    54  	}
    55  	return r.handleLocalRequest
    56  }
    57  
    58  func (s *store) handleRead(ctx context.Context, request *txn.TxnRequest, response *txn.TxnResponse) error {
    59  	return s.handleWithRetry(ctx, request, response, s.doRead)
    60  }
    61  
    62  func (s *store) handleWrite(ctx context.Context, request *txn.TxnRequest, response *txn.TxnResponse) error {
    63  	return s.handleWithRetry(ctx, request, response, s.doWrite)
    64  }
    65  
    66  func (s *store) handleDebug(ctx context.Context, request *txn.TxnRequest, response *txn.TxnResponse) error {
    67  	return s.handleWithRetry(ctx, request, response, s.doDebug)
    68  }
    69  
    70  func (s *store) doRead(ctx context.Context, request *txn.TxnRequest, response *txn.TxnResponse) error {
    71  	r := s.validTNShard(ctx, request, response)
    72  	if r == nil {
    73  		return nil
    74  	}
    75  	r.waitStarted()
    76  
    77  	prepareResponse(request, response)
    78  	return r.service.Read(ctx, request, response)
    79  }
    80  
    81  func (s *store) doWrite(ctx context.Context, request *txn.TxnRequest, response *txn.TxnResponse) error {
    82  	r := s.validTNShard(ctx, request, response)
    83  	if r == nil {
    84  		return nil
    85  	}
    86  	r.waitStarted()
    87  	prepareResponse(request, response)
    88  	return r.service.Write(ctx, request, response)
    89  }
    90  
    91  func (s *store) doDebug(ctx context.Context, request *txn.TxnRequest, response *txn.TxnResponse) error {
    92  	r := s.validTNShard(ctx, request, response)
    93  	if r == nil {
    94  		return nil
    95  	}
    96  	r.waitStarted()
    97  
    98  	prepareResponse(request, response)
    99  	return r.service.Debug(ctx, request, response)
   100  }
   101  
   102  func (s *store) handleCommit(ctx context.Context, request *txn.TxnRequest, response *txn.TxnResponse) error {
   103  	_, span := trace.Start(ctx, "store.handleCommit",
   104  		trace.WithKind(trace.SpanKindStatement))
   105  	defer span.End()
   106  
   107  	r := s.validTNShard(ctx, request, response)
   108  	if r == nil {
   109  		return nil
   110  	}
   111  	r.waitStarted()
   112  	if request.CommitRequest != nil {
   113  		for _, req := range request.CommitRequest.Payload {
   114  			//response is shared by all requests
   115  			prepareResponse(req, response)
   116  			err := s.handleWrite(ctx, req, response)
   117  			if err != nil {
   118  				return err
   119  			}
   120  		}
   121  	}
   122  	prepareResponse(request, response)
   123  	return r.service.Commit(ctx, request, response)
   124  }
   125  
   126  func (s *store) handleRollback(ctx context.Context, request *txn.TxnRequest, response *txn.TxnResponse) error {
   127  	r := s.validTNShard(ctx, request, response)
   128  	if r == nil {
   129  		return nil
   130  	}
   131  	r.waitStarted()
   132  	prepareResponse(request, response)
   133  	return r.service.Rollback(ctx, request, response)
   134  }
   135  
   136  func (s *store) handlePrepare(ctx context.Context, request *txn.TxnRequest, response *txn.TxnResponse) error {
   137  	r := s.validTNShard(ctx, request, response)
   138  	if r == nil {
   139  		return nil
   140  	}
   141  	r.waitStarted()
   142  	prepareResponse(request, response)
   143  	return r.service.Prepare(ctx, request, response)
   144  }
   145  
   146  func (s *store) handleCommitTNShard(ctx context.Context, request *txn.TxnRequest, response *txn.TxnResponse) error {
   147  	r := s.validTNShard(ctx, request, response)
   148  	if r == nil {
   149  		return nil
   150  	}
   151  	r.waitStarted()
   152  	prepareResponse(request, response)
   153  	return r.service.CommitTNShard(ctx, request, response)
   154  }
   155  
   156  func (s *store) handleRollbackTNShard(ctx context.Context, request *txn.TxnRequest, response *txn.TxnResponse) error {
   157  	r := s.validTNShard(ctx, request, response)
   158  	if r == nil {
   159  		return nil
   160  	}
   161  	r.waitStarted()
   162  	prepareResponse(request, response)
   163  	return r.service.RollbackTNShard(ctx, request, response)
   164  }
   165  
   166  func (s *store) handleGetStatus(ctx context.Context, request *txn.TxnRequest, response *txn.TxnResponse) error {
   167  	r := s.validTNShard(ctx, request, response)
   168  	if r == nil {
   169  		return nil
   170  	}
   171  	r.waitStarted()
   172  	prepareResponse(request, response)
   173  	return r.service.GetStatus(ctx, request, response)
   174  }
   175  
   176  func (s *store) validTNShard(ctx context.Context, request *txn.TxnRequest, response *txn.TxnResponse) *replica {
   177  	shard := request.GetTargetTN()
   178  	r := s.getReplica(shard.ShardID)
   179  	if r == nil ||
   180  		r.shard.GetReplicaID() != shard.GetReplicaID() {
   181  		response.TxnError = txn.WrapError(moerr.NewTNShardNotFound(ctx, s.cfg.UUID, shard.ShardID), 0)
   182  		return nil
   183  	}
   184  	return r
   185  }
   186  
   187  func prepareResponse(request *txn.TxnRequest, response *txn.TxnResponse) {
   188  	response.Method = request.Method
   189  	response.Flag = request.Flag
   190  	response.RequestID = request.RequestID
   191  }
   192  
   193  func (s *store) handleWithRetry(ctx context.Context,
   194  	request *txn.TxnRequest,
   195  	response *txn.TxnResponse,
   196  	delegate rpc.TxnRequestHandleFunc) error {
   197  	for {
   198  		response.Reset()
   199  		err := delegate(ctx, request, response)
   200  		if err != nil {
   201  			return err
   202  		}
   203  
   204  		if !s.maybeRetry(ctx, request, response) {
   205  			return nil
   206  		}
   207  	}
   208  }
   209  
   210  func (s *store) maybeRetry(ctx context.Context, request *txn.TxnRequest, response *txn.TxnResponse) bool {
   211  	if response.TxnError == nil {
   212  		return false
   213  	}
   214  	if request.Options == nil {
   215  		return false
   216  	}
   217  	if len(request.Options.RetryCodes) == 0 {
   218  		return false
   219  	}
   220  
   221  	select {
   222  	case <-ctx.Done():
   223  		return false
   224  	default:
   225  		for _, code := range request.Options.RetryCodes {
   226  			if code == int32(response.TxnError.TxnErrCode) {
   227  				wait := time.Duration(request.Options.RetryInterval)
   228  				if wait == 0 {
   229  					wait = defaultRetryInterval
   230  				}
   231  				time.Sleep(wait)
   232  				return true
   233  			}
   234  		}
   235  		return false
   236  	}
   237  }