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 }