vitess.io/vitess@v0.16.2/go/vt/vttablet/grpctabletconn/conn.go (about) 1 /* 2 Copyright 2019 The Vitess Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package grpctabletconn 18 19 import ( 20 "context" 21 "io" 22 "sync" 23 24 "github.com/spf13/pflag" 25 "google.golang.org/grpc" 26 27 "vitess.io/vitess/go/netutil" 28 "vitess.io/vitess/go/sqltypes" 29 "vitess.io/vitess/go/vt/callerid" 30 "vitess.io/vitess/go/vt/grpcclient" 31 "vitess.io/vitess/go/vt/servenv" 32 "vitess.io/vitess/go/vt/vttablet/queryservice" 33 "vitess.io/vitess/go/vt/vttablet/tabletconn" 34 35 binlogdatapb "vitess.io/vitess/go/vt/proto/binlogdata" 36 querypb "vitess.io/vitess/go/vt/proto/query" 37 queryservicepb "vitess.io/vitess/go/vt/proto/queryservice" 38 topodatapb "vitess.io/vitess/go/vt/proto/topodata" 39 ) 40 41 const protocolName = "grpc" 42 43 var ( 44 cert string 45 key string 46 ca string 47 crl string 48 name string 49 ) 50 51 func registerFlags(fs *pflag.FlagSet) { 52 fs.StringVar(&cert, "tablet_grpc_cert", cert, "the cert to use to connect") 53 fs.StringVar(&key, "tablet_grpc_key", key, "the key to use to connect") 54 fs.StringVar(&ca, "tablet_grpc_ca", ca, "the server ca to use to validate servers when connecting") 55 fs.StringVar(&crl, "tablet_grpc_crl", crl, "the server crl to use to validate server certificates when connecting") 56 fs.StringVar(&name, "tablet_grpc_server_name", name, "the server name to use to validate server certificate") 57 } 58 59 func init() { 60 tabletconn.RegisterDialer(protocolName, DialTablet) 61 for _, cmd := range []string{ 62 "vtbench", 63 "vtctl", 64 "vtctld", 65 "vtgate", 66 "vttablet", 67 } { 68 servenv.OnParseFor(cmd, registerFlags) 69 } 70 } 71 72 // gRPCQueryClient implements a gRPC implementation for QueryService 73 type gRPCQueryClient struct { 74 // tablet is set at construction time, and never changed 75 tablet *topodatapb.Tablet 76 77 // mu protects the next fields 78 mu sync.RWMutex 79 cc *grpc.ClientConn 80 c queryservicepb.QueryClient 81 } 82 83 var _ queryservice.QueryService = (*gRPCQueryClient)(nil) 84 85 // DialTablet creates and initializes gRPCQueryClient. 86 func DialTablet(tablet *topodatapb.Tablet, failFast grpcclient.FailFast) (queryservice.QueryService, error) { 87 // create the RPC client 88 addr := "" 89 if grpcPort, ok := tablet.PortMap["grpc"]; ok { 90 addr = netutil.JoinHostPort(tablet.Hostname, grpcPort) 91 } else { 92 addr = tablet.Hostname 93 } 94 opt, err := grpcclient.SecureDialOption(cert, key, ca, crl, name) 95 if err != nil { 96 return nil, err 97 } 98 cc, err := grpcclient.Dial(addr, failFast, opt) 99 if err != nil { 100 return nil, err 101 } 102 c := queryservicepb.NewQueryClient(cc) 103 104 result := &gRPCQueryClient{ 105 tablet: tablet, 106 cc: cc, 107 c: c, 108 } 109 110 return result, nil 111 } 112 113 // Execute sends the query to VTTablet. 114 func (conn *gRPCQueryClient) Execute(ctx context.Context, target *querypb.Target, query string, bindVars map[string]*querypb.BindVariable, transactionID, reservedID int64, options *querypb.ExecuteOptions) (*sqltypes.Result, error) { 115 conn.mu.RLock() 116 defer conn.mu.RUnlock() 117 if conn.cc == nil { 118 return nil, tabletconn.ConnClosed 119 } 120 121 req := &querypb.ExecuteRequest{ 122 EffectiveCallerId: callerid.EffectiveCallerIDFromContext(ctx), 123 ImmediateCallerId: callerid.ImmediateCallerIDFromContext(ctx), 124 Target: target, 125 Query: &querypb.BoundQuery{ 126 Sql: query, 127 BindVariables: bindVars, 128 }, 129 TransactionId: transactionID, 130 Options: options, 131 ReservedId: reservedID, 132 } 133 er, err := conn.c.Execute(ctx, req) 134 if err != nil { 135 return nil, tabletconn.ErrorFromGRPC(err) 136 } 137 return sqltypes.Proto3ToResult(er.Result), nil 138 } 139 140 // StreamExecute executes the query and streams results back through callback. 141 func (conn *gRPCQueryClient) StreamExecute(ctx context.Context, target *querypb.Target, query string, bindVars map[string]*querypb.BindVariable, transactionID int64, reservedID int64, options *querypb.ExecuteOptions, callback func(*sqltypes.Result) error) error { 142 // All streaming clients should follow the code pattern below. 143 // The first part of the function starts the stream while holding 144 // a lock on conn.mu. The second part receives the data and calls 145 // callback. 146 // A new cancelable context is needed because there's currently 147 // no direct API to end a stream from the client side. If callback 148 // returns an error, we return from the function. The deferred 149 // cancel will then cause the stream to be terminated. 150 ctx, cancel := context.WithCancel(ctx) 151 defer cancel() 152 153 stream, err := func() (queryservicepb.Query_StreamExecuteClient, error) { 154 conn.mu.RLock() 155 defer conn.mu.RUnlock() 156 if conn.cc == nil { 157 return nil, tabletconn.ConnClosed 158 } 159 160 req := &querypb.StreamExecuteRequest{ 161 Target: target, 162 EffectiveCallerId: callerid.EffectiveCallerIDFromContext(ctx), 163 ImmediateCallerId: callerid.ImmediateCallerIDFromContext(ctx), 164 Query: &querypb.BoundQuery{ 165 Sql: query, 166 BindVariables: bindVars, 167 }, 168 Options: options, 169 TransactionId: transactionID, 170 ReservedId: reservedID, 171 } 172 stream, err := conn.c.StreamExecute(ctx, req) 173 if err != nil { 174 return nil, tabletconn.ErrorFromGRPC(err) 175 } 176 return stream, nil 177 }() 178 if err != nil { 179 return err 180 } 181 var fields []*querypb.Field 182 for { 183 ser, err := stream.Recv() 184 if err != nil { 185 return tabletconn.ErrorFromGRPC(err) 186 } 187 if fields == nil { 188 fields = ser.Result.Fields 189 } 190 if err := callback(sqltypes.CustomProto3ToResult(fields, ser.Result)); err != nil { 191 if err == nil || err == io.EOF { 192 return nil 193 } 194 return err 195 } 196 } 197 } 198 199 // Begin starts a transaction. 200 func (conn *gRPCQueryClient) Begin(ctx context.Context, target *querypb.Target, options *querypb.ExecuteOptions) (state queryservice.TransactionState, err error) { 201 conn.mu.RLock() 202 defer conn.mu.RUnlock() 203 if conn.cc == nil { 204 return state, tabletconn.ConnClosed 205 } 206 207 req := &querypb.BeginRequest{ 208 Target: target, 209 EffectiveCallerId: callerid.EffectiveCallerIDFromContext(ctx), 210 ImmediateCallerId: callerid.ImmediateCallerIDFromContext(ctx), 211 Options: options, 212 } 213 br, err := conn.c.Begin(ctx, req) 214 if err != nil { 215 return state, tabletconn.ErrorFromGRPC(err) 216 } 217 state.TransactionID = br.TransactionId 218 state.TabletAlias = br.TabletAlias 219 state.SessionStateChanges = br.SessionStateChanges 220 return state, nil 221 } 222 223 // Commit commits the ongoing transaction. 224 func (conn *gRPCQueryClient) Commit(ctx context.Context, target *querypb.Target, transactionID int64) (int64, error) { 225 conn.mu.RLock() 226 defer conn.mu.RUnlock() 227 if conn.cc == nil { 228 return 0, tabletconn.ConnClosed 229 } 230 231 req := &querypb.CommitRequest{ 232 Target: target, 233 EffectiveCallerId: callerid.EffectiveCallerIDFromContext(ctx), 234 ImmediateCallerId: callerid.ImmediateCallerIDFromContext(ctx), 235 TransactionId: transactionID, 236 } 237 resp, err := conn.c.Commit(ctx, req) 238 if err != nil { 239 return 0, tabletconn.ErrorFromGRPC(err) 240 } 241 return resp.ReservedId, nil 242 } 243 244 // Rollback rolls back the ongoing transaction. 245 func (conn *gRPCQueryClient) Rollback(ctx context.Context, target *querypb.Target, transactionID int64) (int64, error) { 246 conn.mu.RLock() 247 defer conn.mu.RUnlock() 248 if conn.cc == nil { 249 return 0, tabletconn.ConnClosed 250 } 251 252 req := &querypb.RollbackRequest{ 253 Target: target, 254 EffectiveCallerId: callerid.EffectiveCallerIDFromContext(ctx), 255 ImmediateCallerId: callerid.ImmediateCallerIDFromContext(ctx), 256 TransactionId: transactionID, 257 } 258 resp, err := conn.c.Rollback(ctx, req) 259 if err != nil { 260 return 0, tabletconn.ErrorFromGRPC(err) 261 } 262 return resp.ReservedId, nil 263 } 264 265 // Prepare executes a Prepare on the ongoing transaction. 266 func (conn *gRPCQueryClient) Prepare(ctx context.Context, target *querypb.Target, transactionID int64, dtid string) error { 267 conn.mu.RLock() 268 defer conn.mu.RUnlock() 269 if conn.cc == nil { 270 return tabletconn.ConnClosed 271 } 272 273 req := &querypb.PrepareRequest{ 274 Target: target, 275 EffectiveCallerId: callerid.EffectiveCallerIDFromContext(ctx), 276 ImmediateCallerId: callerid.ImmediateCallerIDFromContext(ctx), 277 TransactionId: transactionID, 278 Dtid: dtid, 279 } 280 _, err := conn.c.Prepare(ctx, req) 281 if err != nil { 282 return tabletconn.ErrorFromGRPC(err) 283 } 284 return nil 285 } 286 287 // CommitPrepared commits the prepared transaction. 288 func (conn *gRPCQueryClient) CommitPrepared(ctx context.Context, target *querypb.Target, dtid string) error { 289 conn.mu.RLock() 290 defer conn.mu.RUnlock() 291 if conn.cc == nil { 292 return tabletconn.ConnClosed 293 } 294 295 req := &querypb.CommitPreparedRequest{ 296 Target: target, 297 EffectiveCallerId: callerid.EffectiveCallerIDFromContext(ctx), 298 ImmediateCallerId: callerid.ImmediateCallerIDFromContext(ctx), 299 Dtid: dtid, 300 } 301 _, err := conn.c.CommitPrepared(ctx, req) 302 if err != nil { 303 return tabletconn.ErrorFromGRPC(err) 304 } 305 return nil 306 } 307 308 // RollbackPrepared rolls back the prepared transaction. 309 func (conn *gRPCQueryClient) RollbackPrepared(ctx context.Context, target *querypb.Target, dtid string, originalID int64) error { 310 conn.mu.RLock() 311 defer conn.mu.RUnlock() 312 if conn.cc == nil { 313 return tabletconn.ConnClosed 314 } 315 316 req := &querypb.RollbackPreparedRequest{ 317 Target: target, 318 EffectiveCallerId: callerid.EffectiveCallerIDFromContext(ctx), 319 ImmediateCallerId: callerid.ImmediateCallerIDFromContext(ctx), 320 TransactionId: originalID, 321 Dtid: dtid, 322 } 323 _, err := conn.c.RollbackPrepared(ctx, req) 324 if err != nil { 325 return tabletconn.ErrorFromGRPC(err) 326 } 327 return nil 328 } 329 330 // CreateTransaction creates the metadata for a 2PC transaction. 331 func (conn *gRPCQueryClient) CreateTransaction(ctx context.Context, target *querypb.Target, dtid string, participants []*querypb.Target) error { 332 conn.mu.RLock() 333 defer conn.mu.RUnlock() 334 if conn.cc == nil { 335 return tabletconn.ConnClosed 336 } 337 338 req := &querypb.CreateTransactionRequest{ 339 Target: target, 340 EffectiveCallerId: callerid.EffectiveCallerIDFromContext(ctx), 341 ImmediateCallerId: callerid.ImmediateCallerIDFromContext(ctx), 342 Dtid: dtid, 343 Participants: participants, 344 } 345 _, err := conn.c.CreateTransaction(ctx, req) 346 if err != nil { 347 return tabletconn.ErrorFromGRPC(err) 348 } 349 return nil 350 } 351 352 // StartCommit atomically commits the transaction along with the 353 // decision to commit the associated 2pc transaction. 354 func (conn *gRPCQueryClient) StartCommit(ctx context.Context, target *querypb.Target, transactionID int64, dtid string) error { 355 conn.mu.RLock() 356 defer conn.mu.RUnlock() 357 if conn.cc == nil { 358 return tabletconn.ConnClosed 359 } 360 361 req := &querypb.StartCommitRequest{ 362 Target: target, 363 EffectiveCallerId: callerid.EffectiveCallerIDFromContext(ctx), 364 ImmediateCallerId: callerid.ImmediateCallerIDFromContext(ctx), 365 TransactionId: transactionID, 366 Dtid: dtid, 367 } 368 _, err := conn.c.StartCommit(ctx, req) 369 if err != nil { 370 return tabletconn.ErrorFromGRPC(err) 371 } 372 return nil 373 } 374 375 // SetRollback transitions the 2pc transaction to the Rollback state. 376 // If a transaction id is provided, that transaction is also rolled back. 377 func (conn *gRPCQueryClient) SetRollback(ctx context.Context, target *querypb.Target, dtid string, transactionID int64) error { 378 conn.mu.RLock() 379 defer conn.mu.RUnlock() 380 if conn.cc == nil { 381 return tabletconn.ConnClosed 382 } 383 384 req := &querypb.SetRollbackRequest{ 385 Target: target, 386 EffectiveCallerId: callerid.EffectiveCallerIDFromContext(ctx), 387 ImmediateCallerId: callerid.ImmediateCallerIDFromContext(ctx), 388 TransactionId: transactionID, 389 Dtid: dtid, 390 } 391 _, err := conn.c.SetRollback(ctx, req) 392 if err != nil { 393 return tabletconn.ErrorFromGRPC(err) 394 } 395 return nil 396 } 397 398 // ConcludeTransaction deletes the 2pc transaction metadata 399 // essentially resolving it. 400 func (conn *gRPCQueryClient) ConcludeTransaction(ctx context.Context, target *querypb.Target, dtid string) error { 401 conn.mu.RLock() 402 defer conn.mu.RUnlock() 403 if conn.cc == nil { 404 return tabletconn.ConnClosed 405 } 406 407 req := &querypb.ConcludeTransactionRequest{ 408 Target: target, 409 EffectiveCallerId: callerid.EffectiveCallerIDFromContext(ctx), 410 ImmediateCallerId: callerid.ImmediateCallerIDFromContext(ctx), 411 Dtid: dtid, 412 } 413 _, err := conn.c.ConcludeTransaction(ctx, req) 414 if err != nil { 415 return tabletconn.ErrorFromGRPC(err) 416 } 417 return nil 418 } 419 420 // ReadTransaction returns the metadata for the sepcified dtid. 421 func (conn *gRPCQueryClient) ReadTransaction(ctx context.Context, target *querypb.Target, dtid string) (*querypb.TransactionMetadata, error) { 422 conn.mu.RLock() 423 defer conn.mu.RUnlock() 424 if conn.cc == nil { 425 return nil, tabletconn.ConnClosed 426 } 427 428 req := &querypb.ReadTransactionRequest{ 429 Target: target, 430 EffectiveCallerId: callerid.EffectiveCallerIDFromContext(ctx), 431 ImmediateCallerId: callerid.ImmediateCallerIDFromContext(ctx), 432 Dtid: dtid, 433 } 434 response, err := conn.c.ReadTransaction(ctx, req) 435 if err != nil { 436 return nil, tabletconn.ErrorFromGRPC(err) 437 } 438 return response.Metadata, nil 439 } 440 441 // BeginExecute starts a transaction and runs an Execute. 442 func (conn *gRPCQueryClient) BeginExecute(ctx context.Context, target *querypb.Target, preQueries []string, query string, bindVars map[string]*querypb.BindVariable, reservedID int64, options *querypb.ExecuteOptions) (state queryservice.TransactionState, result *sqltypes.Result, err error) { 443 conn.mu.RLock() 444 defer conn.mu.RUnlock() 445 if conn.cc == nil { 446 return state, nil, tabletconn.ConnClosed 447 } 448 449 req := &querypb.BeginExecuteRequest{ 450 Target: target, 451 EffectiveCallerId: callerid.EffectiveCallerIDFromContext(ctx), 452 ImmediateCallerId: callerid.ImmediateCallerIDFromContext(ctx), 453 PreQueries: preQueries, 454 Query: &querypb.BoundQuery{ 455 Sql: query, 456 BindVariables: bindVars, 457 }, 458 ReservedId: reservedID, 459 Options: options, 460 } 461 reply, err := conn.c.BeginExecute(ctx, req) 462 if err != nil { 463 return state, nil, tabletconn.ErrorFromGRPC(err) 464 } 465 state.TransactionID = reply.TransactionId 466 state.TabletAlias = conn.tablet.Alias 467 state.SessionStateChanges = reply.SessionStateChanges 468 if reply.Error != nil { 469 return state, nil, tabletconn.ErrorFromVTRPC(reply.Error) 470 } 471 return state, sqltypes.Proto3ToResult(reply.Result), nil 472 } 473 474 // BeginStreamExecute starts a transaction and runs an Execute. 475 func (conn *gRPCQueryClient) BeginStreamExecute(ctx context.Context, target *querypb.Target, preQueries []string, query string, bindVars map[string]*querypb.BindVariable, reservedID int64, options *querypb.ExecuteOptions, callback func(*sqltypes.Result) error) (state queryservice.TransactionState, err error) { 476 conn.mu.RLock() 477 defer conn.mu.RUnlock() 478 if conn.cc == nil { 479 return state, tabletconn.ConnClosed 480 } 481 482 stream, err := func() (queryservicepb.Query_BeginStreamExecuteClient, error) { 483 conn.mu.RLock() 484 defer conn.mu.RUnlock() 485 if conn.cc == nil { 486 return nil, tabletconn.ConnClosed 487 } 488 489 req := &querypb.BeginStreamExecuteRequest{ 490 Target: target, 491 EffectiveCallerId: callerid.EffectiveCallerIDFromContext(ctx), 492 ImmediateCallerId: callerid.ImmediateCallerIDFromContext(ctx), 493 PreQueries: preQueries, 494 Query: &querypb.BoundQuery{ 495 Sql: query, 496 BindVariables: bindVars, 497 }, 498 ReservedId: reservedID, 499 Options: options, 500 } 501 stream, err := conn.c.BeginStreamExecute(ctx, req) 502 if err != nil { 503 return nil, tabletconn.ErrorFromGRPC(err) 504 } 505 return stream, nil 506 }() 507 if err != nil { 508 return state, err 509 } 510 var fields []*querypb.Field 511 for { 512 ser, err := stream.Recv() 513 if state.TransactionID == 0 && ser.GetTransactionId() != 0 { 514 state.TransactionID = ser.GetTransactionId() 515 } 516 if state.TabletAlias == nil && ser.GetTabletAlias() != nil { 517 state.TabletAlias = ser.GetTabletAlias() 518 } 519 if state.SessionStateChanges == "" && ser.GetSessionStateChanges() != "" { 520 state.SessionStateChanges = ser.GetSessionStateChanges() 521 } 522 523 if err != nil { 524 return state, tabletconn.ErrorFromGRPC(err) 525 } 526 527 if ser.Error != nil { 528 return state, tabletconn.ErrorFromVTRPC(ser.Error) 529 } 530 531 // The last stream receive will not have a result, so callback will not be called for it. 532 if ser.Result == nil { 533 return state, nil 534 } 535 536 if fields == nil { 537 fields = ser.Result.Fields 538 } 539 if err := callback(sqltypes.CustomProto3ToResult(fields, ser.Result)); err != nil { 540 if err == nil || err == io.EOF { 541 return state, nil 542 } 543 return state, err 544 } 545 } 546 } 547 548 // MessageStream streams messages. 549 func (conn *gRPCQueryClient) MessageStream(ctx context.Context, target *querypb.Target, name string, callback func(*sqltypes.Result) error) error { 550 // Please see comments in StreamExecute to see how this works. 551 ctx, cancel := context.WithCancel(ctx) 552 defer cancel() 553 554 stream, err := func() (queryservicepb.Query_MessageStreamClient, error) { 555 conn.mu.RLock() 556 defer conn.mu.RUnlock() 557 if conn.cc == nil { 558 return nil, tabletconn.ConnClosed 559 } 560 561 req := &querypb.MessageStreamRequest{ 562 Target: target, 563 EffectiveCallerId: callerid.EffectiveCallerIDFromContext(ctx), 564 ImmediateCallerId: callerid.ImmediateCallerIDFromContext(ctx), 565 Name: name, 566 } 567 stream, err := conn.c.MessageStream(ctx, req) 568 if err != nil { 569 return nil, tabletconn.ErrorFromGRPC(err) 570 } 571 return stream, nil 572 }() 573 if err != nil { 574 return err 575 } 576 var fields []*querypb.Field 577 for { 578 msr, err := stream.Recv() 579 if err != nil { 580 return tabletconn.ErrorFromGRPC(err) 581 } 582 if fields == nil { 583 fields = msr.Result.Fields 584 } 585 if err := callback(sqltypes.CustomProto3ToResult(fields, msr.Result)); err != nil { 586 if err == nil || err == io.EOF { 587 return nil 588 } 589 return err 590 } 591 } 592 } 593 594 // MessageAck acks messages. 595 func (conn *gRPCQueryClient) MessageAck(ctx context.Context, target *querypb.Target, name string, ids []*querypb.Value) (int64, error) { 596 conn.mu.RLock() 597 defer conn.mu.RUnlock() 598 if conn.cc == nil { 599 return 0, tabletconn.ConnClosed 600 } 601 req := &querypb.MessageAckRequest{ 602 Target: target, 603 EffectiveCallerId: callerid.EffectiveCallerIDFromContext(ctx), 604 ImmediateCallerId: callerid.ImmediateCallerIDFromContext(ctx), 605 Name: name, 606 Ids: ids, 607 } 608 reply, err := conn.c.MessageAck(ctx, req) 609 if err != nil { 610 return 0, tabletconn.ErrorFromGRPC(err) 611 } 612 return int64(reply.Result.RowsAffected), nil 613 } 614 615 // StreamHealth starts a streaming RPC for VTTablet health status updates. 616 func (conn *gRPCQueryClient) StreamHealth(ctx context.Context, callback func(*querypb.StreamHealthResponse) error) error { 617 // Please see comments in StreamExecute to see how this works. 618 ctx, cancel := context.WithCancel(ctx) 619 defer cancel() 620 621 stream, err := func() (queryservicepb.Query_StreamHealthClient, error) { 622 conn.mu.RLock() 623 defer conn.mu.RUnlock() 624 if conn.cc == nil { 625 return nil, tabletconn.ConnClosed 626 } 627 628 stream, err := conn.c.StreamHealth(ctx, &querypb.StreamHealthRequest{}) 629 if err != nil { 630 return nil, tabletconn.ErrorFromGRPC(err) 631 } 632 return stream, nil 633 }() 634 if err != nil { 635 return err 636 } 637 for { 638 shr, err := stream.Recv() 639 if err != nil { 640 return tabletconn.ErrorFromGRPC(err) 641 } 642 if err := callback(shr); err != nil { 643 if err == nil || err == io.EOF { 644 return nil 645 } 646 return err 647 } 648 } 649 } 650 651 // VStream starts a VReplication stream. 652 func (conn *gRPCQueryClient) VStream(ctx context.Context, request *binlogdatapb.VStreamRequest, send func([]*binlogdatapb.VEvent) error) error { 653 stream, err := func() (queryservicepb.Query_VStreamClient, error) { 654 conn.mu.RLock() 655 defer conn.mu.RUnlock() 656 if conn.cc == nil { 657 return nil, tabletconn.ConnClosed 658 } 659 660 req := &binlogdatapb.VStreamRequest{ 661 Target: request.Target, 662 EffectiveCallerId: callerid.EffectiveCallerIDFromContext(ctx), 663 ImmediateCallerId: callerid.ImmediateCallerIDFromContext(ctx), 664 Position: request.Position, 665 Filter: request.Filter, 666 TableLastPKs: request.TableLastPKs, 667 } 668 stream, err := conn.c.VStream(ctx, req) 669 if err != nil { 670 return nil, tabletconn.ErrorFromGRPC(err) 671 } 672 return stream, nil 673 }() 674 if err != nil { 675 return err 676 } 677 for { 678 r, err := stream.Recv() 679 if err != nil { 680 return tabletconn.ErrorFromGRPC(err) 681 } 682 select { 683 case <-ctx.Done(): 684 return nil 685 default: 686 } 687 if err := send(r.Events); err != nil { 688 if err == io.EOF { 689 return nil 690 } 691 return err 692 } 693 } 694 } 695 696 // VStreamRows streams rows of a query from the specified starting point. 697 func (conn *gRPCQueryClient) VStreamRows(ctx context.Context, request *binlogdatapb.VStreamRowsRequest, send func(*binlogdatapb.VStreamRowsResponse) error) error { 698 stream, err := func() (queryservicepb.Query_VStreamRowsClient, error) { 699 conn.mu.RLock() 700 defer conn.mu.RUnlock() 701 if conn.cc == nil { 702 return nil, tabletconn.ConnClosed 703 } 704 705 req := &binlogdatapb.VStreamRowsRequest{ 706 Target: request.Target, 707 EffectiveCallerId: callerid.EffectiveCallerIDFromContext(ctx), 708 ImmediateCallerId: callerid.ImmediateCallerIDFromContext(ctx), 709 Query: request.Query, 710 Lastpk: request.Lastpk, 711 } 712 stream, err := conn.c.VStreamRows(ctx, req) 713 if err != nil { 714 return nil, tabletconn.ErrorFromGRPC(err) 715 } 716 return stream, nil 717 }() 718 if err != nil { 719 return err 720 } 721 r := binlogdatapb.VStreamRowsResponseFromVTPool() 722 defer r.ReturnToVTPool() 723 for { 724 err := stream.RecvMsg(r) 725 if err != nil { 726 return tabletconn.ErrorFromGRPC(err) 727 } 728 if ctx.Err() != nil { 729 return ctx.Err() 730 } 731 if err := send(r); err != nil { 732 return err 733 } 734 r.ResetVT() 735 } 736 } 737 738 // VStreamResults streams rows of a query from the specified starting point. 739 func (conn *gRPCQueryClient) VStreamResults(ctx context.Context, target *querypb.Target, query string, send func(*binlogdatapb.VStreamResultsResponse) error) error { 740 stream, err := func() (queryservicepb.Query_VStreamResultsClient, error) { 741 conn.mu.RLock() 742 defer conn.mu.RUnlock() 743 if conn.cc == nil { 744 return nil, tabletconn.ConnClosed 745 } 746 747 req := &binlogdatapb.VStreamResultsRequest{ 748 Target: target, 749 EffectiveCallerId: callerid.EffectiveCallerIDFromContext(ctx), 750 ImmediateCallerId: callerid.ImmediateCallerIDFromContext(ctx), 751 Query: query, 752 } 753 stream, err := conn.c.VStreamResults(ctx, req) 754 if err != nil { 755 return nil, tabletconn.ErrorFromGRPC(err) 756 } 757 return stream, nil 758 }() 759 if err != nil { 760 return err 761 } 762 for { 763 r, err := stream.Recv() 764 if err != nil { 765 return tabletconn.ErrorFromGRPC(err) 766 } 767 select { 768 case <-ctx.Done(): 769 return ctx.Err() 770 default: 771 } 772 if err := send(r); err != nil { 773 return err 774 } 775 } 776 } 777 778 // HandlePanic is a no-op. 779 func (conn *gRPCQueryClient) HandlePanic(err *error) { 780 } 781 782 // ReserveBeginExecute implements the queryservice interface 783 func (conn *gRPCQueryClient) ReserveBeginExecute(ctx context.Context, target *querypb.Target, preQueries []string, postBeginQueries []string, sql string, bindVariables map[string]*querypb.BindVariable, options *querypb.ExecuteOptions) (state queryservice.ReservedTransactionState, result *sqltypes.Result, err error) { 784 conn.mu.RLock() 785 defer conn.mu.RUnlock() 786 if conn.cc == nil { 787 return state, nil, tabletconn.ConnClosed 788 } 789 790 req := &querypb.ReserveBeginExecuteRequest{ 791 Target: target, 792 EffectiveCallerId: callerid.EffectiveCallerIDFromContext(ctx), 793 ImmediateCallerId: callerid.ImmediateCallerIDFromContext(ctx), 794 Options: options, 795 PreQueries: preQueries, 796 PostBeginQueries: postBeginQueries, 797 Query: &querypb.BoundQuery{ 798 Sql: sql, 799 BindVariables: bindVariables, 800 }, 801 } 802 reply, err := conn.c.ReserveBeginExecute(ctx, req) 803 if err != nil { 804 return state, nil, tabletconn.ErrorFromGRPC(err) 805 } 806 state.ReservedID = reply.ReservedId 807 state.TransactionID = reply.TransactionId 808 state.TabletAlias = conn.tablet.Alias 809 state.SessionStateChanges = reply.SessionStateChanges 810 if reply.Error != nil { 811 return state, nil, tabletconn.ErrorFromVTRPC(reply.Error) 812 } 813 814 return state, sqltypes.Proto3ToResult(reply.Result), nil 815 } 816 817 // ReserveBeginStreamExecute implements the queryservice interface 818 func (conn *gRPCQueryClient) ReserveBeginStreamExecute(ctx context.Context, target *querypb.Target, preQueries []string, postBeginQueries []string, sql string, bindVariables map[string]*querypb.BindVariable, options *querypb.ExecuteOptions, callback func(*sqltypes.Result) error) (state queryservice.ReservedTransactionState, err error) { 819 conn.mu.RLock() 820 defer conn.mu.RUnlock() 821 if conn.cc == nil { 822 return state, tabletconn.ConnClosed 823 } 824 825 stream, err := func() (queryservicepb.Query_ReserveBeginStreamExecuteClient, error) { 826 conn.mu.RLock() 827 defer conn.mu.RUnlock() 828 if conn.cc == nil { 829 return nil, tabletconn.ConnClosed 830 } 831 832 req := &querypb.ReserveBeginStreamExecuteRequest{ 833 Target: target, 834 EffectiveCallerId: callerid.EffectiveCallerIDFromContext(ctx), 835 ImmediateCallerId: callerid.ImmediateCallerIDFromContext(ctx), 836 Options: options, 837 PreQueries: preQueries, 838 PostBeginQueries: postBeginQueries, 839 Query: &querypb.BoundQuery{ 840 Sql: sql, 841 BindVariables: bindVariables, 842 }, 843 } 844 stream, err := conn.c.ReserveBeginStreamExecute(ctx, req) 845 if err != nil { 846 return nil, tabletconn.ErrorFromGRPC(err) 847 } 848 return stream, nil 849 }() 850 if err != nil { 851 return state, tabletconn.ErrorFromGRPC(err) 852 } 853 854 var fields []*querypb.Field 855 for { 856 ser, err := stream.Recv() 857 if state.TransactionID == 0 && ser.GetTransactionId() != 0 { 858 state.TransactionID = ser.GetTransactionId() 859 } 860 if state.ReservedID == 0 && ser.GetReservedId() != 0 { 861 state.ReservedID = ser.GetReservedId() 862 } 863 if state.TabletAlias == nil && ser.GetTabletAlias() != nil { 864 state.TabletAlias = ser.GetTabletAlias() 865 } 866 if state.SessionStateChanges == "" && ser.GetSessionStateChanges() != "" { 867 state.SessionStateChanges = ser.GetSessionStateChanges() 868 } 869 870 if err != nil { 871 return state, tabletconn.ErrorFromGRPC(err) 872 } 873 874 if ser.Error != nil { 875 return state, tabletconn.ErrorFromVTRPC(ser.Error) 876 } 877 878 // The last stream receive will not have a result, so callback will not be called for it. 879 if ser.Result == nil { 880 return state, nil 881 } 882 883 if fields == nil { 884 fields = ser.Result.Fields 885 } 886 if err := callback(sqltypes.CustomProto3ToResult(fields, ser.Result)); err != nil { 887 if err == nil || err == io.EOF { 888 return state, nil 889 } 890 return state, err 891 } 892 } 893 } 894 895 // ReserveExecute implements the queryservice interface 896 func (conn *gRPCQueryClient) ReserveExecute(ctx context.Context, target *querypb.Target, preQueries []string, sql string, bindVariables map[string]*querypb.BindVariable, transactionID int64, options *querypb.ExecuteOptions) (state queryservice.ReservedState, result *sqltypes.Result, err error) { 897 conn.mu.RLock() 898 defer conn.mu.RUnlock() 899 if conn.cc == nil { 900 return state, nil, tabletconn.ConnClosed 901 } 902 903 req := &querypb.ReserveExecuteRequest{ 904 EffectiveCallerId: callerid.EffectiveCallerIDFromContext(ctx), 905 ImmediateCallerId: callerid.ImmediateCallerIDFromContext(ctx), 906 Target: target, 907 Query: &querypb.BoundQuery{ 908 Sql: sql, 909 BindVariables: bindVariables, 910 }, 911 TransactionId: transactionID, 912 Options: options, 913 PreQueries: preQueries, 914 } 915 reply, err := conn.c.ReserveExecute(ctx, req) 916 if err != nil { 917 return state, nil, tabletconn.ErrorFromGRPC(err) 918 } 919 state.ReservedID = reply.ReservedId 920 state.TabletAlias = reply.TabletAlias 921 if reply.Error != nil { 922 return state, nil, tabletconn.ErrorFromVTRPC(reply.Error) 923 } 924 925 return state, sqltypes.Proto3ToResult(reply.Result), nil 926 } 927 928 // ReserveStreamExecute implements the queryservice interface 929 func (conn *gRPCQueryClient) ReserveStreamExecute(ctx context.Context, target *querypb.Target, preQueries []string, sql string, bindVariables map[string]*querypb.BindVariable, transactionID int64, options *querypb.ExecuteOptions, callback func(*sqltypes.Result) error) (state queryservice.ReservedState, err error) { 930 conn.mu.RLock() 931 defer conn.mu.RUnlock() 932 if conn.cc == nil { 933 return state, tabletconn.ConnClosed 934 } 935 936 stream, err := func() (queryservicepb.Query_ReserveStreamExecuteClient, error) { 937 conn.mu.RLock() 938 defer conn.mu.RUnlock() 939 if conn.cc == nil { 940 return nil, tabletconn.ConnClosed 941 } 942 943 req := &querypb.ReserveStreamExecuteRequest{ 944 Target: target, 945 EffectiveCallerId: callerid.EffectiveCallerIDFromContext(ctx), 946 ImmediateCallerId: callerid.ImmediateCallerIDFromContext(ctx), 947 Options: options, 948 PreQueries: preQueries, 949 Query: &querypb.BoundQuery{ 950 Sql: sql, 951 BindVariables: bindVariables, 952 }, 953 TransactionId: transactionID, 954 } 955 stream, err := conn.c.ReserveStreamExecute(ctx, req) 956 if err != nil { 957 return nil, tabletconn.ErrorFromGRPC(err) 958 } 959 return stream, nil 960 }() 961 if err != nil { 962 return state, tabletconn.ErrorFromGRPC(err) 963 } 964 965 var fields []*querypb.Field 966 for { 967 ser, err := stream.Recv() 968 if state.ReservedID == 0 && ser.GetReservedId() != 0 { 969 state.ReservedID = ser.GetReservedId() 970 } 971 if state.TabletAlias == nil && ser.GetTabletAlias() != nil { 972 state.TabletAlias = ser.GetTabletAlias() 973 } 974 975 if err != nil { 976 return state, tabletconn.ErrorFromGRPC(err) 977 } 978 979 if ser.Error != nil { 980 return state, tabletconn.ErrorFromVTRPC(ser.Error) 981 } 982 983 // The last stream receive will not have a result, so callback will not be called for it. 984 if ser.Result == nil { 985 return state, nil 986 } 987 988 if fields == nil { 989 fields = ser.Result.Fields 990 } 991 if err := callback(sqltypes.CustomProto3ToResult(fields, ser.Result)); err != nil { 992 if err == nil || err == io.EOF { 993 return state, nil 994 } 995 return state, err 996 } 997 } 998 } 999 1000 func (conn *gRPCQueryClient) Release(ctx context.Context, target *querypb.Target, transactionID, reservedID int64) error { 1001 conn.mu.RLock() 1002 defer conn.mu.RUnlock() 1003 if conn.cc == nil { 1004 return tabletconn.ConnClosed 1005 } 1006 1007 req := &querypb.ReleaseRequest{ 1008 EffectiveCallerId: callerid.EffectiveCallerIDFromContext(ctx), 1009 ImmediateCallerId: callerid.ImmediateCallerIDFromContext(ctx), 1010 Target: target, 1011 TransactionId: transactionID, 1012 ReservedId: reservedID, 1013 } 1014 _, err := conn.c.Release(ctx, req) 1015 if err != nil { 1016 return tabletconn.ErrorFromGRPC(err) 1017 } 1018 return nil 1019 } 1020 1021 // GetSchema implements the queryservice interface 1022 func (conn *gRPCQueryClient) GetSchema(ctx context.Context, target *querypb.Target, tableType querypb.SchemaTableType, tableNames []string, callback func(schemaRes *querypb.GetSchemaResponse) error) error { 1023 conn.mu.RLock() 1024 defer conn.mu.RUnlock() 1025 if conn.cc == nil { 1026 return tabletconn.ConnClosed 1027 } 1028 1029 stream, err := func() (queryservicepb.Query_GetSchemaClient, error) { 1030 conn.mu.RLock() 1031 defer conn.mu.RUnlock() 1032 if conn.cc == nil { 1033 return nil, tabletconn.ConnClosed 1034 } 1035 1036 stream, err := conn.c.GetSchema(ctx, &querypb.GetSchemaRequest{ 1037 Target: target, 1038 TableType: tableType, 1039 TableNames: tableNames, 1040 }) 1041 if err != nil { 1042 return nil, tabletconn.ErrorFromGRPC(err) 1043 } 1044 return stream, nil 1045 }() 1046 if err != nil { 1047 return err 1048 } 1049 for { 1050 shr, err := stream.Recv() 1051 if err != nil { 1052 return tabletconn.ErrorFromGRPC(err) 1053 } 1054 if err := callback(shr); err != nil { 1055 if err == nil || err == io.EOF { 1056 return nil 1057 } 1058 return err 1059 } 1060 } 1061 } 1062 1063 // Close closes underlying gRPC channel. 1064 func (conn *gRPCQueryClient) Close(ctx context.Context) error { 1065 conn.mu.Lock() 1066 defer conn.mu.Unlock() 1067 if conn.cc == nil { 1068 return nil 1069 } 1070 1071 cc := conn.cc 1072 conn.cc = nil 1073 return cc.Close() 1074 } 1075 1076 // Tablet returns the rpc end point. 1077 func (conn *gRPCQueryClient) Tablet() *topodatapb.Tablet { 1078 return conn.tablet 1079 }