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  }