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 }