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