github.com/matrixorigin/matrixone@v0.7.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 22 "github.com/matrixorigin/matrixone/pkg/common/moerr" 23 "github.com/matrixorigin/matrixone/pkg/common/morpc" 24 "github.com/matrixorigin/matrixone/pkg/common/mpool" 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 "github.com/matrixorigin/matrixone/pkg/util/trace" 29 ) 30 31 // WithSenderPayloadBufferSize set buffer size for copy payload data to socket. 32 func WithSenderPayloadBufferSize(value int) SenderOption { 33 return func(s *sender) { 34 s.options.payloadCopyBufferSize = value 35 } 36 } 37 38 // WithSenderBackendOptions set options for create backend connections 39 func WithSenderBackendOptions(options ...morpc.BackendOption) SenderOption { 40 return func(s *sender) { 41 s.options.backendCreateOptions = append(s.options.backendCreateOptions, options...) 42 } 43 } 44 45 // WithSenderClientOptions set options for create client 46 func WithSenderClientOptions(options ...morpc.ClientOption) SenderOption { 47 return func(s *sender) { 48 s.options.clientOptions = options 49 } 50 } 51 52 // WithSenderLocalDispatch set options for dispatch request to local to avoid rpc call 53 func WithSenderLocalDispatch(localDispatch LocalDispatch) SenderOption { 54 return func(s *sender) { 55 s.options.localDispatch = localDispatch 56 } 57 } 58 59 // WithSenderMaxMessageSize set max rpc message size 60 func WithSenderMaxMessageSize(maxMessageSize int) SenderOption { 61 return func(s *sender) { 62 s.options.maxMessageSize = maxMessageSize 63 } 64 } 65 66 // WithSenderEnableCompress enable compress 67 func WithSenderEnableCompress(enable bool) SenderOption { 68 return func(s *sender) { 69 s.options.enableCompress = enable 70 } 71 } 72 73 type sender struct { 74 rt moruntime.Runtime 75 client morpc.RPCClient 76 77 options struct { 78 localDispatch LocalDispatch 79 payloadCopyBufferSize int 80 maxMessageSize int 81 enableCompress bool 82 backendCreateOptions []morpc.BackendOption 83 clientOptions []morpc.ClientOption 84 } 85 86 pool struct { 87 resultPool *sync.Pool 88 responsePool *sync.Pool 89 localStreamPool *sync.Pool 90 } 91 } 92 93 // NewSenderWithConfig create a txn sender by config and options 94 func NewSenderWithConfig(cfg Config, 95 rt moruntime.Runtime, 96 options ...SenderOption) (TxnSender, error) { 97 cfg.adjust() 98 options = append(options, WithSenderBackendOptions(cfg.getBackendOptions(rt.Logger().RawLogger())...)) 99 options = append(options, WithSenderClientOptions(cfg.getClientOptions(rt.Logger().RawLogger())...)) 100 options = append(options, WithSenderMaxMessageSize(int(cfg.MaxMessageSize))) 101 options = append(options, WithSenderEnableCompress(cfg.EnableCompress)) 102 return NewSender(rt, options...) 103 } 104 105 // NewSender create a txn sender 106 func NewSender( 107 rt moruntime.Runtime, 108 options ...SenderOption) (TxnSender, error) { 109 s := &sender{rt: rt} 110 for _, opt := range options { 111 opt(s) 112 } 113 s.adjust() 114 115 s.pool.localStreamPool = &sync.Pool{ 116 New: func() any { 117 return newLocalStream(s.releaseLocalStream, s.acquireResponse) 118 }, 119 } 120 s.pool.resultPool = &sync.Pool{ 121 New: func() any { 122 rs := &SendResult{ 123 pool: s.pool.resultPool, 124 streams: make(map[uint64]morpc.Stream, 16), 125 } 126 return rs 127 }, 128 } 129 s.pool.responsePool = &sync.Pool{ 130 New: func() any { 131 return &txn.TxnResponse{} 132 }, 133 } 134 135 var codecOpts []morpc.CodecOption 136 codecOpts = append(codecOpts, 137 morpc.WithCodecIntegrationHLC(s.rt.Clock()), 138 morpc.WithCodecPayloadCopyBufferSize(s.options.payloadCopyBufferSize), 139 morpc.WithCodecEnableChecksum(), 140 morpc.WithCodecMaxBodySize(s.options.maxMessageSize)) 141 if s.options.enableCompress { 142 mp, err := mpool.NewMPool("txn_rpc_sender", 0, mpool.NoFixed) 143 if err != nil { 144 return nil, err 145 } 146 codecOpts = append(codecOpts, morpc.WithCodecEnableCompress(mp)) 147 } 148 149 codec := morpc.NewMessageCodec( 150 func() morpc.Message { return s.acquireResponse() }, 151 codecOpts...) 152 bf := morpc.NewGoettyBasedBackendFactory(codec, s.options.backendCreateOptions...) 153 client, err := morpc.NewClient(bf, s.options.clientOptions...) 154 if err != nil { 155 return nil, err 156 } 157 s.client = client 158 return s, nil 159 } 160 161 func (s *sender) adjust() { 162 if s.options.payloadCopyBufferSize == 0 { 163 s.options.payloadCopyBufferSize = 16 * 1024 164 } 165 s.options.backendCreateOptions = append(s.options.backendCreateOptions, 166 morpc.WithBackendLogger(s.rt.Logger().RawLogger())) 167 168 s.options.clientOptions = append(s.options.clientOptions, morpc.WithClientLogger(s.rt.Logger().RawLogger())) 169 } 170 171 func (s *sender) Close() error { 172 return s.client.Close() 173 } 174 175 func (s *sender) Send(ctx context.Context, requests []txn.TxnRequest) (*SendResult, error) { 176 sr := s.acquireSendResult() 177 if len(requests) == 1 { 178 sr.reset(requests) 179 resp, err := s.doSend(ctx, requests[0]) 180 if err != nil { 181 sr.Release() 182 return nil, err 183 } 184 sr.Responses[0] = resp 185 return sr, nil 186 } 187 188 sr.reset(requests) 189 for idx := range requests { 190 dn := requests[idx].GetTargetDN() 191 st := sr.getStream(dn.ShardID) 192 if st == nil { 193 v, err := s.createStream(ctx, dn, len(requests)) 194 if err != nil { 195 sr.Release() 196 return nil, err 197 } 198 st = v 199 sr.setStream(dn.ShardID, v) 200 } 201 202 requests[idx].RequestID = st.ID() 203 if err := st.Send(ctx, &requests[idx]); err != nil { 204 sr.Release() 205 return nil, err 206 } 207 } 208 209 for idx := range requests { 210 st := sr.getStream(requests[idx].GetTargetDN().ShardID) 211 c, err := st.Receive() 212 if err != nil { 213 sr.Release() 214 return nil, err 215 } 216 v, ok := <-c 217 if !ok { 218 return nil, moerr.NewStreamClosedNoCtx() 219 } 220 resp := v.(*txn.TxnResponse) 221 sr.setResponse(resp, idx) 222 s.releaseResponse(resp) 223 } 224 return sr, nil 225 } 226 227 func (s *sender) doSend(ctx context.Context, request txn.TxnRequest) (txn.TxnResponse, error) { 228 ctx, span := trace.Debug(ctx, "sender.doSend") 229 defer span.End() 230 dn := request.GetTargetDN() 231 if s.options.localDispatch != nil { 232 if handle := s.options.localDispatch(dn); handle != nil { 233 response := txn.TxnResponse{} 234 err := handle(ctx, &request, &response) 235 return response, err 236 } 237 } 238 239 f, err := s.client.Send(ctx, dn.Address, &request) 240 if err != nil { 241 return txn.TxnResponse{}, err 242 } 243 defer f.Close() 244 245 v, err := f.Get() 246 if err != nil { 247 return txn.TxnResponse{}, err 248 } 249 return *(v.(*txn.TxnResponse)), nil 250 } 251 252 func (s *sender) createStream(ctx context.Context, dn metadata.DNShard, size int) (morpc.Stream, error) { 253 if s.options.localDispatch != nil { 254 if h := s.options.localDispatch(dn); h != nil { 255 ls := s.acquireLocalStream() 256 ls.setup(ctx, h) 257 return ls, nil 258 } 259 } 260 return s.client.NewStream(dn.Address, false) 261 } 262 263 func (s *sender) acquireLocalStream() *localStream { 264 return s.pool.localStreamPool.Get().(*localStream) 265 } 266 267 func (s *sender) releaseLocalStream(ls *localStream) { 268 s.pool.localStreamPool.Put(ls) 269 } 270 271 func (s *sender) acquireResponse() *txn.TxnResponse { 272 return s.pool.responsePool.Get().(*txn.TxnResponse) 273 } 274 275 func (s *sender) releaseResponse(response *txn.TxnResponse) { 276 response.Reset() 277 s.pool.responsePool.Put(response) 278 } 279 280 func (s *sender) acquireSendResult() *SendResult { 281 return s.pool.resultPool.Get().(*SendResult) 282 } 283 284 type sendMessage struct { 285 request morpc.Message 286 // opts morpc.SendOptions 287 handleFunc TxnRequestHandleFunc 288 responseFactory func() *txn.TxnResponse 289 ctx context.Context 290 } 291 292 type localStream struct { 293 releaseFunc func(ls *localStream) 294 responseFactory func() *txn.TxnResponse 295 in chan sendMessage 296 out chan morpc.Message 297 298 // reset fields 299 closed bool 300 handleFunc TxnRequestHandleFunc 301 ctx context.Context 302 } 303 304 func newLocalStream(releaseFunc func(ls *localStream), responseFactory func() *txn.TxnResponse) *localStream { 305 ls := &localStream{ 306 releaseFunc: releaseFunc, 307 responseFactory: responseFactory, 308 in: make(chan sendMessage, 32), 309 out: make(chan morpc.Message, 32), 310 } 311 ls.setFinalizer() 312 ls.start() 313 return ls 314 } 315 316 func (ls *localStream) setFinalizer() { 317 runtime.SetFinalizer(ls, func(ls *localStream) { 318 ls.destroy() 319 }) 320 } 321 322 func (ls *localStream) setup(ctx context.Context, handleFunc TxnRequestHandleFunc) { 323 ls.handleFunc = handleFunc 324 ls.ctx = ctx 325 ls.closed = false 326 } 327 328 func (ls *localStream) ID() uint64 { 329 return 0 330 } 331 332 func (ls *localStream) Send(ctx context.Context, request morpc.Message) error { 333 if ls.closed { 334 panic("send after closed") 335 } 336 337 ls.in <- sendMessage{ 338 request: request, 339 handleFunc: ls.handleFunc, 340 responseFactory: ls.responseFactory, 341 ctx: ls.ctx, 342 } 343 return nil 344 } 345 346 func (ls *localStream) Receive() (chan morpc.Message, error) { 347 if ls.closed { 348 panic("send after closed") 349 } 350 351 return ls.out, nil 352 } 353 354 func (ls *localStream) Close() error { 355 if ls.closed { 356 return nil 357 } 358 ls.closed = true 359 ls.ctx = nil 360 ls.releaseFunc(ls) 361 return nil 362 } 363 364 func (ls *localStream) destroy() { 365 close(ls.in) 366 close(ls.out) 367 } 368 369 func (ls *localStream) start() { 370 go func(in chan sendMessage, out chan morpc.Message) { 371 for { 372 v, ok := <-in 373 if !ok { 374 return 375 } 376 377 response := v.responseFactory() 378 err := v.handleFunc(v.ctx, v.request.(*txn.TxnRequest), response) 379 if err != nil { 380 response.TxnError = txn.WrapError(moerr.NewRpcErrorNoCtx(err.Error()), 0) 381 } 382 out <- response 383 } 384 }(ls.in, ls.out) 385 } 386 387 func (sr *SendResult) reset(requests []txn.TxnRequest) { 388 size := len(requests) 389 if size == len(sr.Responses) { 390 for i := 0; i < size; i++ { 391 sr.Responses[i] = txn.TxnResponse{} 392 } 393 return 394 } 395 396 for i := 0; i < size; i++ { 397 sr.Responses = append(sr.Responses, txn.TxnResponse{}) 398 } 399 } 400 401 func (sr *SendResult) setStream(dn uint64, st morpc.Stream) { 402 sr.streams[dn] = st 403 } 404 405 func (sr *SendResult) getStream(dn uint64) morpc.Stream { 406 return sr.streams[dn] 407 } 408 409 func (sr *SendResult) setResponse(resp *txn.TxnResponse, index int) { 410 sr.Responses[index] = *resp 411 } 412 413 // Release release send result 414 func (sr *SendResult) Release() { 415 if sr.pool != nil { 416 for k, st := range sr.streams { 417 if st != nil { 418 _ = st.Close() 419 } 420 delete(sr.streams, k) 421 } 422 sr.Responses = sr.Responses[:0] 423 sr.pool.Put(sr) 424 } 425 }