diff --git a/go/cmd/vtgate/status.go b/go/cmd/vtgate/status.go index b2548a24360..ee0ff6788a3 100644 --- a/go/cmd/vtgate/status.go +++ b/go/cmd/vtgate/status.go @@ -38,13 +38,13 @@ func addStatusParts(vtg *vtgate.VTGate) { servenv.AddStatusPart("Gateway Status", vtgate.StatusTemplate, func() interface{} { return vtg.GetGatewayCacheStatus() }) - if *vtgate.GatewayImplementation == vtgate.GatewayImplementationDiscovery { + if vtgate.UsingLegacyGateway() { servenv.AddStatusPart("Health Check Cache", discovery.LegacyHealthCheckTemplate, func() interface{} { return legacyHealthCheck.CacheStatus() }) } else { servenv.AddStatusPart("Health Check Cache", discovery.HealthCheckTemplate, func() interface{} { - return vtg.Gateway().HealthCheck().CacheStatus() + return vtg.Gateway().TabletsCacheStatus() }) } } diff --git a/go/mysql/fakesqldb/server.go b/go/mysql/fakesqldb/server.go index b71a5c83695..5ca771001ca 100644 --- a/go/mysql/fakesqldb/server.go +++ b/go/mysql/fakesqldb/server.go @@ -531,6 +531,11 @@ func (db *DB) QueryLog() string { return strings.Join(db.querylog, ";") } +//ResetQueryLog resets the query log +func (db *DB) ResetQueryLog() { + db.querylog = nil +} + // EnableConnFail makes connection to this fake DB fail. func (db *DB) EnableConnFail() { db.mu.Lock() diff --git a/go/test/endtoend/backup/transform/backup_transform_utils.go b/go/test/endtoend/backup/transform/backup_transform_utils.go index 99b8346bd60..47719309b9b 100644 --- a/go/test/endtoend/backup/transform/backup_transform_utils.go +++ b/go/test/endtoend/backup/transform/backup_transform_utils.go @@ -59,6 +59,7 @@ var ( "-serving_state_grace_period", "1s"} ) +// TestMainSetup sets up the basic test cluster func TestMainSetup(m *testing.M, useMysqlctld bool) { defer cluster.PanicHandler(nil) flag.Parse() @@ -100,8 +101,8 @@ func TestMainSetup(m *testing.M, useMysqlctld bool) { var mysqlProcs []*exec.Cmd for i := 0; i < 3; i++ { tabletType := "replica" - tablet := localCluster.GetVttabletInstance(tabletType, 0, cell) - tablet.VttabletProcess = localCluster.GetVtprocessInstanceFromVttablet(tablet, shard.Name, keyspaceName) + tablet := localCluster.NewVttabletInstance(tabletType, 0, cell) + tablet.VttabletProcess = localCluster.VtprocessInstanceFromVttablet(tablet, shard.Name, keyspaceName) tablet.VttabletProcess.DbPassword = dbPassword tablet.VttabletProcess.ExtraArgs = commonTabletArg tablet.VttabletProcess.SupportsBackup = true @@ -182,6 +183,7 @@ var vtInsertTest = `create table vt_insert_test ( primary key (id) ) Engine=InnoDB` +// TestBackupTransformImpl tests backups with transform hooks func TestBackupTransformImpl(t *testing.T) { // insert data in master, validate same in slave defer cluster.PanicHandler(t) @@ -266,8 +268,8 @@ func TestBackupTransformImpl(t *testing.T) { } -// TestBackupTransformErrorImpl validate backup with test_backup_error -// backup_storage_hook, which should fail. +// TestBackupTransformErrorImpl validates backup behavior with transform hook +// when the hook encounters an error func TestBackupTransformErrorImpl(t *testing.T) { // restart the replica with transform hook parameter defer cluster.PanicHandler(t) diff --git a/go/test/endtoend/backup/vtbackup/main_test.go b/go/test/endtoend/backup/vtbackup/main_test.go index b7412abe27f..70c84e556d3 100644 --- a/go/test/endtoend/backup/vtbackup/main_test.go +++ b/go/test/endtoend/backup/vtbackup/main_test.go @@ -96,15 +96,15 @@ func TestMain(m *testing.M) { extraArgs := []string{"-db-credentials-file", dbCredentialFile} commonTabletArg = append(commonTabletArg, "-db-credentials-file", dbCredentialFile) - master = localCluster.GetVttabletInstance("replica", 0, "") - replica1 = localCluster.GetVttabletInstance("replica", 0, "") - replica2 = localCluster.GetVttabletInstance("replica", 0, "") + master = localCluster.NewVttabletInstance("replica", 0, "") + replica1 = localCluster.NewVttabletInstance("replica", 0, "") + replica2 = localCluster.NewVttabletInstance("replica", 0, "") shard.Vttablets = []*cluster.Vttablet{master, replica1, replica2} // Start MySql processes var mysqlProcs []*exec.Cmd for _, tablet := range shard.Vttablets { - tablet.VttabletProcess = localCluster.GetVtprocessInstanceFromVttablet(tablet, shard.Name, keyspaceName) + tablet.VttabletProcess = localCluster.VtprocessInstanceFromVttablet(tablet, shard.Name, keyspaceName) tablet.VttabletProcess.DbPassword = dbPassword tablet.VttabletProcess.ExtraArgs = commonTabletArg tablet.VttabletProcess.SupportsBackup = true @@ -116,6 +116,7 @@ func TestMain(m *testing.M) { if proc, err := tablet.MysqlctlProcess.StartProcess(); err != nil { return 1, err } else { + // ignore golint warning, we need the else block to use proc mysqlProcs = append(mysqlProcs, proc) } } diff --git a/go/test/endtoend/backup/vtctlbackup/backup_utils.go b/go/test/endtoend/backup/vtctlbackup/backup_utils.go index a7e858abf0f..b8922e402c7 100644 --- a/go/test/endtoend/backup/vtctlbackup/backup_utils.go +++ b/go/test/endtoend/backup/vtctlbackup/backup_utils.go @@ -39,19 +39,20 @@ import ( ) const ( - ExtraBackup = iota + XtraBackup = iota Backup Mysqlctld ) var ( - master *cluster.Vttablet - replica1 *cluster.Vttablet - replica2 *cluster.Vttablet - localCluster *cluster.LocalProcessCluster - newInitDBFile string - useXtrabackup bool - cell = cluster.DefaultCell + master *cluster.Vttablet + replica1 *cluster.Vttablet + replica2 *cluster.Vttablet + localCluster *cluster.LocalProcessCluster + newInitDBFile string + useXtrabackup bool + cell = cluster.DefaultCell + hostname = "localhost" keyspaceName = "ks" dbPassword = "VtDbaPass" @@ -114,7 +115,7 @@ func LaunchCluster(setupType int, streamMode string, stripes int) (int, error) { commonTabletArg = append(commonTabletArg, "-db-credentials-file", dbCredentialFile) // Update arguments for xtrabackup - if setupType == ExtraBackup { + if setupType == XtraBackup { useXtrabackup = true xtrabackupArgs := []string{ @@ -139,8 +140,8 @@ func LaunchCluster(setupType int, streamMode string, stripes int) (int, error) { if i == 0 { tabletType = "master" } - tablet := localCluster.GetVttabletInstance(tabletType, 0, cell) - tablet.VttabletProcess = localCluster.GetVtprocessInstanceFromVttablet(tablet, shard.Name, keyspaceName) + tablet := localCluster.NewVttabletInstance(tabletType, 0, cell) + tablet.VttabletProcess = localCluster.VtprocessInstanceFromVttablet(tablet, shard.Name, keyspaceName) tablet.VttabletProcess.DbPassword = dbPassword tablet.VttabletProcess.ExtraArgs = commonTabletArg tablet.VttabletProcess.SupportsBackup = true @@ -200,10 +201,12 @@ func LaunchCluster(setupType int, streamMode string, stripes int) (int, error) { return 0, nil } +// TearDownCluster shuts down all cluster processes func TearDownCluster() { localCluster.Teardown() } +// TestBackup runs all the backup tests func TestBackup(t *testing.T, setupType int, streamMode string, stripes int) { testMethods := []struct { diff --git a/go/test/endtoend/backup/xtrabackup/xtrabackup_test.go b/go/test/endtoend/backup/xtrabackup/xtrabackup_test.go index 0802d116c93..7dbef9df25e 100644 --- a/go/test/endtoend/backup/xtrabackup/xtrabackup_test.go +++ b/go/test/endtoend/backup/xtrabackup/xtrabackup_test.go @@ -24,5 +24,5 @@ import ( // TestXtraBackup - tests the backup using xtrabackup func TestXtrabackup(t *testing.T) { - backup.TestBackup(t, backup.ExtraBackup, "tar", 0) + backup.TestBackup(t, backup.XtraBackup, "tar", 0) } diff --git a/go/test/endtoend/backup/xtrabackupstream/xtrabackup_stream_test.go b/go/test/endtoend/backup/xtrabackupstream/xtrabackup_stream_test.go index 0f1544e8f14..99eec5a8c53 100644 --- a/go/test/endtoend/backup/xtrabackupstream/xtrabackup_stream_test.go +++ b/go/test/endtoend/backup/xtrabackupstream/xtrabackup_stream_test.go @@ -24,5 +24,5 @@ import ( // TestXtrabackupStream - tests the backup using xtrabackup with xbstream mode func TestXtrabackupStream(t *testing.T) { - backup.TestBackup(t, backup.ExtraBackup, "xbstream", 8) + backup.TestBackup(t, backup.XtraBackup, "xbstream", 8) } diff --git a/go/test/endtoend/cellalias/cell_alias_test.go b/go/test/endtoend/cellalias/cell_alias_test.go index c87380d86b4..b4bf8804f91 100644 --- a/go/test/endtoend/cellalias/cell_alias_test.go +++ b/go/test/endtoend/cellalias/cell_alias_test.go @@ -118,13 +118,13 @@ func TestMain(m *testing.M) { return 1, err } - shard1Master = localCluster.GetVttabletInstance("master", 0, "") - shard1Replica = localCluster.GetVttabletInstance("replica", 0, cell2) - shard1Rdonly = localCluster.GetVttabletInstance("rdonly", 0, cell2) + shard1Master = localCluster.NewVttabletInstance("master", 0, "") + shard1Replica = localCluster.NewVttabletInstance("replica", 0, cell2) + shard1Rdonly = localCluster.NewVttabletInstance("rdonly", 0, cell2) - shard2Master = localCluster.GetVttabletInstance("master", 0, "") - shard2Replica = localCluster.GetVttabletInstance("replica", 0, cell2) - shard2Rdonly = localCluster.GetVttabletInstance("rdonly", 0, cell2) + shard2Master = localCluster.NewVttabletInstance("master", 0, "") + shard2Replica = localCluster.NewVttabletInstance("replica", 0, cell2) + shard2Rdonly = localCluster.NewVttabletInstance("rdonly", 0, cell2) var mysqlProcs []*exec.Cmd for _, tablet := range []*cluster.Vttablet{shard1Master, shard1Replica, shard1Rdonly, shard2Master, shard2Replica, shard2Rdonly} { @@ -265,7 +265,7 @@ func TestAlias(t *testing.T) { "region_east_coast") require.Nil(t, err) - vtgateInstance := localCluster.GetVtgateInstance() + vtgateInstance := localCluster.NewVtgateInstance() vtgateInstance.CellsToWatch = allCells vtgateInstance.TabletTypesToWait = "MASTER,REPLICA" err = vtgateInstance.Setup() @@ -319,7 +319,7 @@ func TestAddAliasWhileVtgateUp(t *testing.T) { sharding.CheckSrvKeyspace(t, cell1, keyspaceName, "", 0, expectedPartitions, *localCluster) sharding.CheckSrvKeyspace(t, cell2, keyspaceName, "", 0, expectedPartitions, *localCluster) - vtgateInstance := localCluster.GetVtgateInstance() + vtgateInstance := localCluster.NewVtgateInstance() vtgateInstance.CellsToWatch = allCells vtgateInstance.TabletTypesToWait = "MASTER,REPLICA,RDONLY" err = vtgateInstance.Setup() diff --git a/go/test/endtoend/cluster/cluster_process.go b/go/test/endtoend/cluster/cluster_process.go index 8af0043e1dc..e56a0171f81 100644 --- a/go/test/endtoend/cluster/cluster_process.go +++ b/go/test/endtoend/cluster/cluster_process.go @@ -242,6 +242,7 @@ func (cluster *LocalProcessCluster) StartKeyspace(keyspace Keyspace, shardNames tabletUID := cluster.GetAndReserveTabletUID() tablet := &Vttablet{ TabletUID: tabletUID, + Type: "replica", HTTPPort: cluster.GetAndReservePort(), GrpcPort: cluster.GetAndReservePort(), MySQLPort: cluster.GetAndReservePort(), @@ -407,15 +408,15 @@ func (cluster *LocalProcessCluster) LaunchCluster(keyspace *Keyspace, shards []S // StartVtgate starts vtgate func (cluster *LocalProcessCluster) StartVtgate() (err error) { - vtgateInstance := *cluster.GetVtgateInstance() + vtgateInstance := *cluster.NewVtgateInstance() cluster.VtgateProcess = vtgateInstance log.Infof("Starting vtgate on port %d", vtgateInstance.Port) log.Infof("Vtgate started, connect to mysql using : mysql -h 127.0.0.1 -P %d", cluster.VtgateMySQLPort) return cluster.VtgateProcess.Setup() } -// GetVtgateInstance returns an instance of vtgateprocess -func (cluster *LocalProcessCluster) GetVtgateInstance() *VtgateProcess { +// NewVtgateInstance returns an instance of vtgateprocess +func (cluster *LocalProcessCluster) NewVtgateInstance() *VtgateProcess { vtgateHTTPPort := cluster.GetAndReservePort() vtgateGrpcPort := cluster.GetAndReservePort() cluster.VtgateMySQLPort = cluster.GetAndReservePort() @@ -647,8 +648,8 @@ func getVtStartPort() int { return DefaultStartPort } -// GetVttabletInstance creates a new vttablet object -func (cluster *LocalProcessCluster) GetVttabletInstance(tabletType string, UID int, cell string) *Vttablet { +// NewVttabletInstance creates a new vttablet object +func (cluster *LocalProcessCluster) NewVttabletInstance(tabletType string, UID int, cell string) *Vttablet { if UID == 0 { UID = cluster.GetAndReserveTabletUID() } @@ -666,8 +667,8 @@ func (cluster *LocalProcessCluster) GetVttabletInstance(tabletType string, UID i } } -// GetVtprocessInstanceFromVttablet creates a new vttablet object -func (cluster *LocalProcessCluster) GetVtprocessInstanceFromVttablet(tablet *Vttablet, shardName string, ksName string) *VttabletProcess { +// VtprocessInstanceFromVttablet creates a new vttablet object +func (cluster *LocalProcessCluster) VtprocessInstanceFromVttablet(tablet *Vttablet, shardName string, ksName string) *VttabletProcess { return VttabletProcessInstance(tablet.HTTPPort, tablet.GrpcPort, tablet.TabletUID, diff --git a/go/test/endtoend/cluster/vttablet_process.go b/go/test/endtoend/cluster/vttablet_process.go index e3db2019139..5b05a149bab 100644 --- a/go/test/endtoend/cluster/vttablet_process.go +++ b/go/test/endtoend/cluster/vttablet_process.go @@ -75,7 +75,7 @@ type VttabletProcess struct { exit chan error } -// Setup starts vtctld process with required arguements +// Setup starts vttablet process with required arguements func (vttablet *VttabletProcess) Setup() (err error) { vttablet.proc = exec.Command( diff --git a/go/test/endtoend/clustertest/vtgate_test.go b/go/test/endtoend/clustertest/vtgate_test.go index a688125ead4..29ec9e19134 100644 --- a/go/test/endtoend/clustertest/vtgate_test.go +++ b/go/test/endtoend/clustertest/vtgate_test.go @@ -43,7 +43,7 @@ func TestVtgateProcess(t *testing.T) { defer conn.Close() exec(t, conn, "insert into customer(id, email) values(1,'email1')") - + _ = exec(t, conn, "begin") qr := exec(t, conn, "select id, email from customer") if got, want := fmt.Sprintf("%v", qr.Rows), `[[INT64(1) VARCHAR("email1")]]`; got != want { t.Errorf("select:\n%v want\n%v", got, want) diff --git a/go/test/endtoend/encryption/encryptedreplication/encrypted_replication_test.go b/go/test/endtoend/encryption/encryptedreplication/encrypted_replication_test.go index 5affd253a3c..f15ab08503b 100644 --- a/go/test/endtoend/encryption/encryptedreplication/encrypted_replication_test.go +++ b/go/test/endtoend/encryption/encryptedreplication/encrypted_replication_test.go @@ -146,13 +146,14 @@ func initializeCluster(t *testing.T) (int, error) { for i := 0; i < 2; i++ { // instantiate vttablet object with reserved ports tabletUID := clusterInstance.GetAndReserveTabletUID() - tablet := clusterInstance.GetVttabletInstance("replica", tabletUID, cell) + tablet := clusterInstance.NewVttabletInstance("replica", tabletUID, cell) // Start Mysqlctl process tablet.MysqlctlProcess = *cluster.MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, clusterInstance.TmpDirectory) if proc, err := tablet.MysqlctlProcess.StartProcess(); err != nil { return 1, err } else { + // ignore golint warning, we need the else block to use proc mysqlProcesses = append(mysqlProcesses, proc) } // start vttablet process diff --git a/go/test/endtoend/encryption/encryptedtransport/encrypted_transport_test.go b/go/test/endtoend/encryption/encryptedtransport/encrypted_transport_test.go index 2a37bf2f796..0b6f5a29e21 100644 --- a/go/test/endtoend/encryption/encryptedtransport/encrypted_transport_test.go +++ b/go/test/endtoend/encryption/encryptedtransport/encrypted_transport_test.go @@ -303,13 +303,14 @@ func clusterSetUp(t *testing.T) (int, error) { } for i := 0; i < 2; i++ { // instantiate vttablet object with reserved ports - tablet := clusterInstance.GetVttabletInstance("replica", 0, cell) + tablet := clusterInstance.NewVttabletInstance("replica", 0, cell) // Start Mysqlctl process tablet.MysqlctlProcess = *cluster.MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, clusterInstance.TmpDirectory) if proc, err := tablet.MysqlctlProcess.StartProcess(); err != nil { return 1, err } else { + // ignore golint warning, we need the else block to use proc mysqlProcesses = append(mysqlProcesses, proc) } // start vttablet process diff --git a/go/test/endtoend/preparestmt/main_test.go b/go/test/endtoend/preparestmt/main_test.go index d00ec84da65..15d27f19482 100644 --- a/go/test/endtoend/preparestmt/main_test.go +++ b/go/test/endtoend/preparestmt/main_test.go @@ -185,14 +185,6 @@ func TestMain(m *testing.M) { return 1, err } - // add extra arguments - clusterInstance.VtGateExtraArgs = []string{ - "-mysql_auth_server_impl", "static", - "-mysql_server_query_timeout", "1s", - "-mysql_auth_server_static_file", clusterInstance.TmpDirectory + "/" + mysqlAuthServerStatic, - "-mysql_server_version", "8.0.16-7", - } - // Start keyspace keyspace := &cluster.Keyspace{ Name: keyspaceName, @@ -202,10 +194,23 @@ func TestMain(m *testing.M) { return 1, err } + vtgateInstance := clusterInstance.NewVtgateInstance() + // set the gateway and other params we want to use + vtgateInstance.GatewayImplementation = "tabletgateway" + vtgateInstance.MySQLAuthServerImpl = "static" + // add extra arguments + vtgateInstance.ExtraArgs = []string{ + "-mysql_server_query_timeout", "1s", + "-mysql_auth_server_static_file", clusterInstance.TmpDirectory + "/" + mysqlAuthServerStatic, + "-mysql_server_version", "8.0.16-7", + } + // Start vtgate - if err := clusterInstance.StartVtgate(); err != nil { + if err := vtgateInstance.Setup(); err != nil { return 1, err } + // ensure it is torn down during cluster TearDown + clusterInstance.VtgateProcess = *vtgateInstance dbInfo.Host = clusterInstance.Hostname dbInfo.Port = uint(clusterInstance.VtgateMySQLPort) @@ -296,3 +301,25 @@ func selectWhere(t *testing.T, dbo *sql.DB, where string, params ...interface{}) } return out } + +// selectWhereWithTx select the row corresponding to the where condition. +func selectWhereWithTx(t *testing.T, tx *sql.Tx, where string, params ...interface{}) []tableData { + var out []tableData + // prepare query + qry := "SELECT msg, data, text_col, t_datetime, t_datetime_micros FROM " + tableName + if where != "" { + qry += " WHERE (" + where + ")" + } + + // execute query + r, err := tx.Query(qry, params...) + require.Nil(t, err) + + // prepare result + for r.Next() { + var t tableData + r.Scan(&t.Msg, &t.Data, &t.TextCol, &t.DateTime, &t.DateTimeMicros) + out = append(out, t) + } + return out +} diff --git a/go/test/endtoend/preparestmt/stmt_methods_test.go b/go/test/endtoend/preparestmt/stmt_methods_test.go index b18ea1883a0..1ee99ad7f44 100644 --- a/go/test/endtoend/preparestmt/stmt_methods_test.go +++ b/go/test/endtoend/preparestmt/stmt_methods_test.go @@ -90,16 +90,29 @@ func TestInsertUpdateDelete(t *testing.T) { // Validate a datetime field (with micros) assert.Equal(t, time.Date(2009, 5, 5, 0, 0, 0, 50000, location), data[0].DateTimeMicros) + testReplica(t) // testing record update updateRecord(t, dbo) // testing record deletion deleteRecord(t, dbo) - // testing recontion and deleted data validation + // testing reconnection and deleted data validation reconnectAndTest(t) } +func testReplica(t *testing.T) { + replicaConn := Connect(t, "") + require.NotNil(t, replicaConn, "unable to connect") + _, err := replicaConn.Exec("use @replica") + require.NoError(t, err) + tx, err := replicaConn.Begin() + require.NoError(t, err, "error creating replica transaction") + data := selectWhereWithTx(t, tx, "id = ?", testingID) + assert.Equal(t, fmt.Sprintf("%d21", testingID), data[0].Msg) + require.NoError(t, tx.Commit()) +} + // testcount validates inserted rows count with expected count. func testcount(t *testing.T, dbo *sql.DB, except int) { defer cluster.PanicHandler(t) diff --git a/go/test/endtoend/recovery/shardedrecovery/sharded_recovery_test.go b/go/test/endtoend/recovery/shardedrecovery/sharded_recovery_test.go index 9d9fc00756c..340addda6aa 100644 --- a/go/test/endtoend/recovery/shardedrecovery/sharded_recovery_test.go +++ b/go/test/endtoend/recovery/shardedrecovery/sharded_recovery_test.go @@ -209,7 +209,7 @@ func TestUnShardedRecoveryAfterSharding(t *testing.T) { // check the new replica does not have the data cluster.VerifyRowsInTablet(t, replica2, keyspaceName, 2) - vtgateInstance := localCluster.GetVtgateInstance() + vtgateInstance := localCluster.NewVtgateInstance() vtgateInstance.TabletTypesToWait = "REPLICA" err = vtgateInstance.Setup() localCluster.VtgateGrpcPort = vtgateInstance.GrpcPort @@ -358,11 +358,11 @@ func TestShardedRecovery(t *testing.T) { shard0CountStr := fmt.Sprintf("%s", qr.Rows[0][0].ToBytes()) shard0Count, err := strconv.Atoi(shard0CountStr) require.Nil(t, err) - var shard0TestId string + var shard0TestID string if shard0Count > 0 { qr, err := shard0Master.VttabletProcess.QueryTablet("select id from vt_insert_test", keyspaceName, true) require.Nil(t, err) - shard0TestId = fmt.Sprintf("%s", qr.Rows[0][0].ToBytes()) + shard0TestID = fmt.Sprintf("%s", qr.Rows[0][0].ToBytes()) require.Nil(t, err) } @@ -371,11 +371,11 @@ func TestShardedRecovery(t *testing.T) { shard1CountStr := fmt.Sprintf("%s", qr.Rows[0][0].ToBytes()) shard1Count, err := strconv.Atoi(shard1CountStr) require.Nil(t, err) - var shard1TestId string + var shard1TestID string if shard1Count > 0 { qr, err := shard1Master.VttabletProcess.QueryTablet("select id from vt_insert_test", keyspaceName, true) require.Nil(t, err) - shard1TestId = fmt.Sprintf("%s", qr.Rows[0][0].ToBytes()) + shard1TestID = fmt.Sprintf("%s", qr.Rows[0][0].ToBytes()) require.Nil(t, err) } @@ -396,7 +396,7 @@ func TestShardedRecovery(t *testing.T) { assert.Equal(t, 1, len(output)) assert.True(t, strings.HasSuffix(output[0], shard1Replica.Alias)) - vtgateInstance := localCluster.GetVtgateInstance() + vtgateInstance := localCluster.NewVtgateInstance() vtgateInstance.TabletTypesToWait = "MASTER" err = vtgateInstance.Setup() localCluster.VtgateGrpcPort = vtgateInstance.GrpcPort @@ -428,7 +428,7 @@ func TestShardedRecovery(t *testing.T) { cluster.VerifyRowsInTablet(t, replica3, keyspaceName, shard1Count) // start vtgate - vtgateInstance = localCluster.GetVtgateInstance() + vtgateInstance = localCluster.NewVtgateInstance() vtgateInstance.TabletTypesToWait = "REPLICA" err = vtgateInstance.Setup() localCluster.VtgateGrpcPort = vtgateInstance.GrpcPort @@ -463,11 +463,11 @@ func TestShardedRecovery(t *testing.T) { // check that new tablet is accessible with use `ks:shard` cluster.ExecuteQueriesUsingVtgate(t, session, "use `recovery_keyspace:-80@replica`") recovery.VerifyQueriesUsingVtgate(t, session, "select count(*) from vt_insert_test", "INT64("+shard0CountStr+")") - recovery.VerifyQueriesUsingVtgate(t, session, "select id from vt_insert_test", "INT64("+shard0TestId+")") + recovery.VerifyQueriesUsingVtgate(t, session, "select id from vt_insert_test", "INT64("+shard0TestID+")") cluster.ExecuteQueriesUsingVtgate(t, session, "use `recovery_keyspace:80-@replica`") recovery.VerifyQueriesUsingVtgate(t, session, "select count(*) from vt_insert_test", "INT64("+shard1CountStr+")") - recovery.VerifyQueriesUsingVtgate(t, session, "select id from vt_insert_test", "INT64("+shard1TestId+")") + recovery.VerifyQueriesUsingVtgate(t, session, "select id from vt_insert_test", "INT64("+shard1TestID+")") vtgateConn.Close() err = vtgateInstance.TearDown() @@ -514,17 +514,17 @@ func initializeCluster(t *testing.T) (int, error) { } // Defining all the tablets - master = localCluster.GetVttabletInstance("replica", 0, "") - replica1 = localCluster.GetVttabletInstance("replica", 0, "") - rdOnly = localCluster.GetVttabletInstance("rdonly", 0, "") - replica2 = localCluster.GetVttabletInstance("replica", 0, "") - replica3 = localCluster.GetVttabletInstance("replica", 0, "") - shard0Master = localCluster.GetVttabletInstance("replica", 0, "") - shard0Replica = localCluster.GetVttabletInstance("replica", 0, "") - shard0RdOnly = localCluster.GetVttabletInstance("rdonly", 0, "") - shard1Master = localCluster.GetVttabletInstance("replica", 0, "") - shard1Replica = localCluster.GetVttabletInstance("replica", 0, "") - shard1RdOnly = localCluster.GetVttabletInstance("rdonly", 0, "") + master = localCluster.NewVttabletInstance("replica", 0, "") + replica1 = localCluster.NewVttabletInstance("replica", 0, "") + rdOnly = localCluster.NewVttabletInstance("rdonly", 0, "") + replica2 = localCluster.NewVttabletInstance("replica", 0, "") + replica3 = localCluster.NewVttabletInstance("replica", 0, "") + shard0Master = localCluster.NewVttabletInstance("replica", 0, "") + shard0Replica = localCluster.NewVttabletInstance("replica", 0, "") + shard0RdOnly = localCluster.NewVttabletInstance("rdonly", 0, "") + shard1Master = localCluster.NewVttabletInstance("replica", 0, "") + shard1Replica = localCluster.NewVttabletInstance("replica", 0, "") + shard1RdOnly = localCluster.NewVttabletInstance("rdonly", 0, "") shard.Vttablets = []*cluster.Vttablet{master, replica1, rdOnly, replica2, replica3} shard0.Vttablets = []*cluster.Vttablet{shard0Master, shard0Replica, shard0RdOnly} @@ -534,7 +534,7 @@ func initializeCluster(t *testing.T) (int, error) { localCluster.VtTabletExtraArgs = append(localCluster.VtTabletExtraArgs, "-restore_from_backup", "-enable_semi_sync") err = localCluster.LaunchCluster(keyspace, []cluster.Shard{*shard, *shard0, *shard1}) - + require.NoError(t, err) // Start MySql var mysqlCtlProcessList []*exec.Cmd for _, shard := range localCluster.Keyspaces[0].Shards { diff --git a/go/test/endtoend/recovery/unshardedrecovery/recovery.go b/go/test/endtoend/recovery/unshardedrecovery/recovery.go index 567c24e4fec..f583e4273a0 100644 --- a/go/test/endtoend/recovery/unshardedrecovery/recovery.go +++ b/go/test/endtoend/recovery/unshardedrecovery/recovery.go @@ -114,8 +114,8 @@ func TestMainImpl(m *testing.M) { if i == 0 { tabletType = "master" } - tablet := localCluster.GetVttabletInstance(tabletType, 0, cell) - tablet.VttabletProcess = localCluster.GetVtprocessInstanceFromVttablet(tablet, shard.Name, keyspaceName) + tablet := localCluster.NewVttabletInstance(tabletType, 0, cell) + tablet.VttabletProcess = localCluster.VtprocessInstanceFromVttablet(tablet, shard.Name, keyspaceName) tablet.VttabletProcess.DbPassword = dbPassword tablet.VttabletProcess.ExtraArgs = commonTabletArg if recovery.UseXb { @@ -274,7 +274,7 @@ func TestRecoveryImpl(t *testing.T) { assert.Nil(t, err) assert.Equal(t, "msgx1", fmt.Sprintf("%s", qr.Rows[0][0].ToBytes())) - vtgateInstance := localCluster.GetVtgateInstance() + vtgateInstance := localCluster.NewVtgateInstance() vtgateInstance.TabletTypesToWait = "REPLICA" err = vtgateInstance.Setup() localCluster.VtgateGrpcPort = vtgateInstance.GrpcPort diff --git a/go/test/endtoend/reparent/main_test.go b/go/test/endtoend/reparent/main_test.go index 19e50b469b5..c3600e95ad4 100644 --- a/go/test/endtoend/reparent/main_test.go +++ b/go/test/endtoend/reparent/main_test.go @@ -93,17 +93,17 @@ func TestMain(m *testing.M) { return 1 } - tablet62344 = clusterInstance.GetVttabletInstance("replica", 62344, "") - tablet62044 = clusterInstance.GetVttabletInstance("replica", 62044, "") - tablet41983 = clusterInstance.GetVttabletInstance("replica", 41983, "") - tablet31981 = clusterInstance.GetVttabletInstance("replica", 31981, cell2) + tablet62344 = clusterInstance.NewVttabletInstance("replica", 62344, "") + tablet62044 = clusterInstance.NewVttabletInstance("replica", 62044, "") + tablet41983 = clusterInstance.NewVttabletInstance("replica", 41983, "") + tablet31981 = clusterInstance.NewVttabletInstance("replica", 31981, cell2) shard0 := &cluster.Shard{Name: shardName} shard0.Vttablets = []*cluster.Vttablet{tablet62344, tablet62044, tablet41983, tablet31981} // Initiate shard1 - required for ranged based reparenting - masterTablet = clusterInstance.GetVttabletInstance("replica", 0, "") - replicaTablet = clusterInstance.GetVttabletInstance("replica", 0, "") + masterTablet = clusterInstance.NewVttabletInstance("replica", 0, "") + replicaTablet = clusterInstance.NewVttabletInstance("replica", 0, "") shard1 := &cluster.Shard{Name: shard1Name} shard1.Vttablets = []*cluster.Vttablet{masterTablet, replicaTablet} @@ -127,6 +127,7 @@ func TestMain(m *testing.M) { if proc, err := tablet.MysqlctlProcess.StartProcess(); err != nil { return 1 } else { + // ignore golint warning, we need the else block to use proc mysqlCtlProcessList = append(mysqlCtlProcessList, proc) } } diff --git a/go/test/endtoend/sharding/initialsharding/sharding_util.go b/go/test/endtoend/sharding/initialsharding/sharding_util.go index 09b603fc3df..00d63ca4e45 100644 --- a/go/test/endtoend/sharding/initialsharding/sharding_util.go +++ b/go/test/endtoend/sharding/initialsharding/sharding_util.go @@ -145,11 +145,11 @@ func initClusterForInitialSharding(keyspaceName string, shardNames []string, tot // instantiate vttablet object with reserved ports var tablet *cluster.Vttablet if i == totalTabletsRequired-1 && rdonly { - tablet = ClusterInstance.GetVttabletInstance("rdonly", 0, "") + tablet = ClusterInstance.NewVttabletInstance("rdonly", 0, "") } else if i == 0 { - tablet = ClusterInstance.GetVttabletInstance("master", 0, "") + tablet = ClusterInstance.NewVttabletInstance("master", 0, "") } else { - tablet = ClusterInstance.GetVttabletInstance("replica", 0, "") + tablet = ClusterInstance.NewVttabletInstance("replica", 0, "") } // Start Mysqlctl process tablet.MysqlctlProcess = *cluster.MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, ClusterInstance.TmpDirectory) @@ -163,6 +163,7 @@ func initClusterForInitialSharding(keyspaceName string, shardNames []string, tot if proc, err := tablet.MysqlctlProcess.StartProcess(); err != nil { return } else { + // ignore golint warning, we need the else block to use proc mysqlProcesses = append(mysqlProcesses, proc) } } else { // Since we'll be using mysql procs of keyspace-1 for ks-2, resetting this to 0 @@ -320,7 +321,7 @@ func TestInitialSharding(t *testing.T, keyspace *cluster.Keyspace, keyType query for _, vttablet := range shard1.Vttablets { _ = ClusterInstance.VtctlclientProcess.ExecuteCommand("ReloadSchema", vttablet.Alias) } - vtgateInstance := ClusterInstance.GetVtgateInstance() + vtgateInstance := ClusterInstance.NewVtgateInstance() vtgateInstance.PidFile = path.Join(ClusterInstance.TmpDirectory, fmt.Sprintf("vtgate-%s.pid", keyspaceName)) vtgateInstance.MySQLServerSocketPath = path.Join(ClusterInstance.TmpDirectory, fmt.Sprintf("mysql-%s.sock", keyspaceName)) vtgateInstance.ExtraArgs = []string{"-retry-count", fmt.Sprintf("%d", 2), "-tablet_protocol", "grpc", "-normalize_queries", "-tablet_refresh_interval", "2s"} diff --git a/go/test/endtoend/sharding/mergesharding/mergesharding_base.go b/go/test/endtoend/sharding/mergesharding/mergesharding_base.go index 29930ab28d6..761409c1604 100644 --- a/go/test/endtoend/sharding/mergesharding/mergesharding_base.go +++ b/go/test/endtoend/sharding/mergesharding/mergesharding_base.go @@ -115,21 +115,21 @@ func TestMergesharding(t *testing.T, useVarbinaryShardingKeyType bool) { require.Nil(t, err) // Defining all the tablets - shard0Master := clusterInstance.GetVttabletInstance("replica", 0, "") - shard0Replica := clusterInstance.GetVttabletInstance("replica", 0, "") - shard0Rdonly := clusterInstance.GetVttabletInstance("rdonly", 0, "") + shard0Master := clusterInstance.NewVttabletInstance("replica", 0, "") + shard0Replica := clusterInstance.NewVttabletInstance("replica", 0, "") + shard0Rdonly := clusterInstance.NewVttabletInstance("rdonly", 0, "") - shard1Master := clusterInstance.GetVttabletInstance("replica", 0, "") - shard1Replica := clusterInstance.GetVttabletInstance("replica", 0, "") - shard1Rdonly := clusterInstance.GetVttabletInstance("rdonly", 0, "") + shard1Master := clusterInstance.NewVttabletInstance("replica", 0, "") + shard1Replica := clusterInstance.NewVttabletInstance("replica", 0, "") + shard1Rdonly := clusterInstance.NewVttabletInstance("rdonly", 0, "") - shard2Master := clusterInstance.GetVttabletInstance("replica", 0, "") - shard2Replica := clusterInstance.GetVttabletInstance("replica", 0, "") - shard2Rdonly := clusterInstance.GetVttabletInstance("rdonly", 0, "") + shard2Master := clusterInstance.NewVttabletInstance("replica", 0, "") + shard2Replica := clusterInstance.NewVttabletInstance("replica", 0, "") + shard2Rdonly := clusterInstance.NewVttabletInstance("rdonly", 0, "") - shard3Master := clusterInstance.GetVttabletInstance("replica", 0, "") - shard3Replica := clusterInstance.GetVttabletInstance("replica", 0, "") - shard3Rdonly := clusterInstance.GetVttabletInstance("rdonly", 0, "") + shard3Master := clusterInstance.NewVttabletInstance("replica", 0, "") + shard3Replica := clusterInstance.NewVttabletInstance("replica", 0, "") + shard3Rdonly := clusterInstance.NewVttabletInstance("rdonly", 0, "") shard0.Vttablets = []*cluster.Vttablet{shard0Master, shard0Replica, shard0Rdonly} shard1.Vttablets = []*cluster.Vttablet{shard1Master, shard1Replica, shard1Rdonly} diff --git a/go/test/endtoend/sharding/resharding/resharding_base.go b/go/test/endtoend/sharding/resharding/resharding_base.go index b79b17ff5a3..6a80ec1ea9b 100644 --- a/go/test/endtoend/sharding/resharding/resharding_base.go +++ b/go/test/endtoend/sharding/resharding/resharding_base.go @@ -201,24 +201,24 @@ func TestResharding(t *testing.T, useVarbinaryShardingKeyType bool) { require.Nil(t, err) // Defining all the tablets - shard0Master := clusterInstance.GetVttabletInstance("replica", 0, "") - shard0Replica := clusterInstance.GetVttabletInstance("replica", 0, "") - shard0RdonlyZ2 := clusterInstance.GetVttabletInstance("rdonly", 0, cell2) - - shard1Master := clusterInstance.GetVttabletInstance("replica", 0, "") - shard1Replica1 := clusterInstance.GetVttabletInstance("replica", 0, "") - shard1Replica2 := clusterInstance.GetVttabletInstance("replica", 0, "") - shard1Rdonly := clusterInstance.GetVttabletInstance("rdonly", 0, "") - shard1RdonlyZ2 := clusterInstance.GetVttabletInstance("rdonly", 0, cell2) - - shard2Master := clusterInstance.GetVttabletInstance("replica", 0, "") - shard2Replica1 := clusterInstance.GetVttabletInstance("replica", 0, "") - shard2Replica2 := clusterInstance.GetVttabletInstance("replica", 0, "") - shard2Rdonly := clusterInstance.GetVttabletInstance("rdonly", 0, "") - - shard3Master := clusterInstance.GetVttabletInstance("replica", 0, "") - shard3Replica := clusterInstance.GetVttabletInstance("replica", 0, "") - shard3Rdonly := clusterInstance.GetVttabletInstance("rdonly", 0, "") + shard0Master := clusterInstance.NewVttabletInstance("replica", 0, "") + shard0Replica := clusterInstance.NewVttabletInstance("replica", 0, "") + shard0RdonlyZ2 := clusterInstance.NewVttabletInstance("rdonly", 0, cell2) + + shard1Master := clusterInstance.NewVttabletInstance("replica", 0, "") + shard1Replica1 := clusterInstance.NewVttabletInstance("replica", 0, "") + shard1Replica2 := clusterInstance.NewVttabletInstance("replica", 0, "") + shard1Rdonly := clusterInstance.NewVttabletInstance("rdonly", 0, "") + shard1RdonlyZ2 := clusterInstance.NewVttabletInstance("rdonly", 0, cell2) + + shard2Master := clusterInstance.NewVttabletInstance("replica", 0, "") + shard2Replica1 := clusterInstance.NewVttabletInstance("replica", 0, "") + shard2Replica2 := clusterInstance.NewVttabletInstance("replica", 0, "") + shard2Rdonly := clusterInstance.NewVttabletInstance("rdonly", 0, "") + + shard3Master := clusterInstance.NewVttabletInstance("replica", 0, "") + shard3Replica := clusterInstance.NewVttabletInstance("replica", 0, "") + shard3Rdonly := clusterInstance.NewVttabletInstance("rdonly", 0, "") shard0.Vttablets = []*cluster.Vttablet{shard0Master, shard0Replica, shard0RdonlyZ2} shard1.Vttablets = []*cluster.Vttablet{shard1Master, shard1Replica1, shard1Replica2, shard1Rdonly, shard1RdonlyZ2} diff --git a/go/test/endtoend/sharding/verticalsplit/vertical_split_test.go b/go/test/endtoend/sharding/verticalsplit/vertical_split_test.go index 64e8e1f3705..93935981857 100644 --- a/go/test/endtoend/sharding/verticalsplit/vertical_split_test.go +++ b/go/test/endtoend/sharding/verticalsplit/vertical_split_test.go @@ -670,11 +670,11 @@ func initializeCluster() (int, error) { tabletUID := clusterInstance.GetAndReserveTabletUID() var tablet *cluster.Vttablet if i == 0 { - tablet = clusterInstance.GetVttabletInstance("replica", tabletUID, cellj) + tablet = clusterInstance.NewVttabletInstance("replica", tabletUID, cellj) } else if i == 1 { - tablet = clusterInstance.GetVttabletInstance("replica", tabletUID, cellj) + tablet = clusterInstance.NewVttabletInstance("replica", tabletUID, cellj) } else { - tablet = clusterInstance.GetVttabletInstance("rdonly", tabletUID, cellj) + tablet = clusterInstance.NewVttabletInstance("rdonly", tabletUID, cellj) } // Start Mysqlctl process tablet.MysqlctlProcess = *cluster.MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, clusterInstance.TmpDirectory) diff --git a/go/test/endtoend/tabletgateway/cellalias/cell_alias_test.go b/go/test/endtoend/tabletgateway/cellalias/cell_alias_test.go index 3ee4809ff8f..1dc0ad10bd2 100644 --- a/go/test/endtoend/tabletgateway/cellalias/cell_alias_test.go +++ b/go/test/endtoend/tabletgateway/cellalias/cell_alias_test.go @@ -118,13 +118,13 @@ func TestMain(m *testing.M) { return 1, err } - shard1Master = localCluster.GetVttabletInstance("master", 0, "") - shard1Replica = localCluster.GetVttabletInstance("replica", 0, cell2) - shard1Rdonly = localCluster.GetVttabletInstance("rdonly", 0, cell2) + shard1Master = localCluster.NewVttabletInstance("master", 0, "") + shard1Replica = localCluster.NewVttabletInstance("replica", 0, cell2) + shard1Rdonly = localCluster.NewVttabletInstance("rdonly", 0, cell2) - shard2Master = localCluster.GetVttabletInstance("master", 0, "") - shard2Replica = localCluster.GetVttabletInstance("replica", 0, cell2) - shard2Rdonly = localCluster.GetVttabletInstance("rdonly", 0, cell2) + shard2Master = localCluster.NewVttabletInstance("master", 0, "") + shard2Replica = localCluster.NewVttabletInstance("replica", 0, cell2) + shard2Rdonly = localCluster.NewVttabletInstance("rdonly", 0, cell2) var mysqlProcs []*exec.Cmd for _, tablet := range []*cluster.Vttablet{shard1Master, shard1Replica, shard1Rdonly, shard2Master, shard2Replica, shard2Rdonly} { @@ -265,7 +265,7 @@ func TestAlias(t *testing.T) { "region_east_coast") require.Nil(t, err) - vtgateInstance := localCluster.GetVtgateInstance() + vtgateInstance := localCluster.NewVtgateInstance() vtgateInstance.CellsToWatch = allCells vtgateInstance.TabletTypesToWait = "MASTER,REPLICA" vtgateInstance.GatewayImplementation = "tabletgateway" diff --git a/go/test/endtoend/tabletgateway/healthcheck/vtgate_test.go b/go/test/endtoend/tabletgateway/healthcheck/vtgate_test.go deleted file mode 100644 index 26925afd96d..00000000000 --- a/go/test/endtoend/tabletgateway/healthcheck/vtgate_test.go +++ /dev/null @@ -1,107 +0,0 @@ -/* -Copyright 2020 The Vitess Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. - -This tests select/insert using the unshared keyspace added in main_test -*/ -package healthcheck - -import ( - "context" - "encoding/json" - "fmt" - "io/ioutil" - "net/http" - "reflect" - "strings" - "testing" - "time" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "vitess.io/vitess/go/mysql" - "vitess.io/vitess/go/sqltypes" - "vitess.io/vitess/go/test/endtoend/cluster" -) - -func TestVtgateProcess(t *testing.T) { - defer cluster.PanicHandler(t) - // Healthcheck interval on tablet is set to 1s, so sleep for 2s - time.Sleep(2 * time.Second) - verifyVtgateVariables(t, clusterInstance.VtgateProcess.VerifyURL) - ctx := context.Background() - conn, err := mysql.Connect(ctx, &vtParams) - require.Nil(t, err) - defer conn.Close() - - exec(t, conn, "insert into customer(id, email) values(1,'email1')") - - qr := exec(t, conn, "select id, email from customer") - assert.Equal(t, fmt.Sprintf("%v", qr.Rows), `[[INT64(1) VARCHAR("email1")]]`, "select returned wrong result") - qr = exec(t, conn, "show vitess_tablets") - assert.Equal(t, len(qr.Rows), 3, "wrong number of results from show") -} - -func verifyVtgateVariables(t *testing.T, url string) { - resp, _ := http.Get(url) - require.True(t, resp != nil && resp.StatusCode == 200, "Vtgate api url response not found") - resultMap := make(map[string]interface{}) - respByte, _ := ioutil.ReadAll(resp.Body) - err := json.Unmarshal(respByte, &resultMap) - require.Nil(t, err) - assert.True(t, resultMap["VtgateVSchemaCounts"] != nil, "Vschema count should be present in variables") - vschemaCountMap := getMapFromJSON(resultMap, "VtgateVSchemaCounts") - _, present := vschemaCountMap["Reload"] - assert.True(t, present, "Reload count should be present in vschemacount") - object := reflect.ValueOf(vschemaCountMap["Reload"]) - assert.True(t, object.NumField() > 0, "Reload count should be greater than 0") - _, present = vschemaCountMap["WatchError"] - assert.False(t, present, "There should not be any WatchError in VschemaCount") - _, present = vschemaCountMap["Parsing"] - assert.False(t, present, "There should not be any Parsing in VschemaCount") - - assert.True(t, resultMap["HealthcheckConnections"] != nil, "HealthcheckConnections count should be present in variables") - healthCheckConnection := getMapFromJSON(resultMap, "HealthcheckConnections") - assert.True(t, len(healthCheckConnection) > 0, "Atleast one healthy tablet needs to be present") - assert.True(t, isMasterTabletPresent(healthCheckConnection), "Atleast one master tablet needs to be present") -} - -func getMapFromJSON(JSON map[string]interface{}, key string) map[string]interface{} { - result := make(map[string]interface{}) - object := reflect.ValueOf(JSON[key]) - if object.Kind() == reflect.Map { - for _, key := range object.MapKeys() { - value := object.MapIndex(key) - result[key.String()] = value - } - } - return result -} - -func isMasterTabletPresent(tablets map[string]interface{}) bool { - for key := range tablets { - if strings.Contains(key, "master") { - return true - } - } - return false -} - -func exec(t *testing.T, conn *mysql.Conn, query string) *sqltypes.Result { - t.Helper() - qr, err := conn.ExecuteFetch(query, 1000, true) - require.Nil(t, err) - return qr -} diff --git a/go/test/endtoend/tabletgateway/healthcheck/main_test.go b/go/test/endtoend/tabletgateway/main_test.go similarity index 96% rename from go/test/endtoend/tabletgateway/healthcheck/main_test.go rename to go/test/endtoend/tabletgateway/main_test.go index e2054fc2554..be0c5e8a493 100644 --- a/go/test/endtoend/tabletgateway/healthcheck/main_test.go +++ b/go/test/endtoend/tabletgateway/main_test.go @@ -84,9 +84,10 @@ func TestMain(m *testing.M) { return 1 } - // Start vtgate - vtgateInstance := clusterInstance.GetVtgateInstance() + vtgateInstance := clusterInstance.NewVtgateInstance() + // set the gateway we want to use vtgateInstance.GatewayImplementation = "tabletgateway" + // Start vtgate err = vtgateInstance.Setup() if err != nil { return 1 diff --git a/go/test/endtoend/tabletgateway/vtgate_test.go b/go/test/endtoend/tabletgateway/vtgate_test.go new file mode 100644 index 00000000000..378338ec812 --- /dev/null +++ b/go/test/endtoend/tabletgateway/vtgate_test.go @@ -0,0 +1,226 @@ +/* +Copyright 2020 The Vitess Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +This tests select/insert using the unshared keyspace added in main_test +*/ +package healthcheck + +import ( + "context" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "reflect" + "strings" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "vitess.io/vitess/go/mysql" + "vitess.io/vitess/go/sqltypes" + "vitess.io/vitess/go/test/endtoend/cluster" +) + +func TestVtgateHealthCheck(t *testing.T) { + defer cluster.PanicHandler(t) + // Healthcheck interval on tablet is set to 1s, so sleep for 2s + time.Sleep(2 * time.Second) + verifyVtgateVariables(t, clusterInstance.VtgateProcess.VerifyURL) + ctx := context.Background() + conn, err := mysql.Connect(ctx, &vtParams) + require.Nil(t, err) + defer conn.Close() + + qr := exec(t, conn, "show vitess_tablets", "") + assert.Equal(t, 3, len(qr.Rows), "wrong number of results from show") +} + +func verifyVtgateVariables(t *testing.T, url string) { + resp, err := http.Get(url) + require.NoError(t, err) + require.Equal(t, 200, resp.StatusCode, "Vtgate api url response not found") + + resultMap := make(map[string]interface{}) + respByte, _ := ioutil.ReadAll(resp.Body) + err = json.Unmarshal(respByte, &resultMap) + require.NoError(t, err) + assert.Contains(t, resultMap, "VtgateVSchemaCounts", "Vschema count should be present in variables") + + vschemaCountMap := getMapFromJSON(resultMap, "VtgateVSchemaCounts") + assert.Contains(t, vschemaCountMap, "Reload", "Reload count should be present in vschemacount") + + object := reflect.ValueOf(vschemaCountMap["Reload"]) + assert.Greater(t, object.NumField(), 0, "Reload count should be greater than 0") + assert.NotContains(t, vschemaCountMap, "WatchError", "There should not be any WatchError in VschemaCount") + assert.NotContains(t, vschemaCountMap, "Parsing", "There should not be any Parsing in VschemaCount") + assert.Contains(t, resultMap, "HealthcheckConnections", "HealthcheckConnections count should be present in variables") + + healthCheckConnection := getMapFromJSON(resultMap, "HealthcheckConnections") + assert.NotEmpty(t, healthCheckConnection, "Atleast one healthy tablet needs to be present") + assert.True(t, isMasterTabletPresent(healthCheckConnection), "Atleast one master tablet needs to be present") +} + +func retryNTimes(t *testing.T, maxRetries int, f func() bool) { + i := 0 + for { + res := f() + if res { + return + } + if i > maxRetries { + t.Fatalf("retried %d times and failed", maxRetries) + return + } + i++ + } +} + +func TestReplicaTransactions(t *testing.T) { + // TODO(deepthi): this test seems to depend on previous test. Fix tearDown so that tests are independent + defer cluster.PanicHandler(t) + // Healthcheck interval on tablet is set to 1s, so sleep for 2s + time.Sleep(2 * time.Second) + ctx := context.Background() + masterConn, err := mysql.Connect(ctx, &vtParams) + require.NoError(t, err) + defer masterConn.Close() + + replicaConn, err := mysql.Connect(ctx, &vtParams) + require.NoError(t, err) + defer replicaConn.Close() + + replicaConn2, err := mysql.Connect(ctx, &vtParams) + require.NoError(t, err) + defer replicaConn2.Close() + + fetchAllCustomers := "select id, email from customer" + checkCustomerRows := func(expectedRows int) func() bool { + return func() bool { + result := exec(t, replicaConn2, fetchAllCustomers, "") + return len(result.Rows) == expectedRows + } + } + + // point the replica connections to the replica target + exec(t, replicaConn, "use @replica", "") + exec(t, replicaConn2, "use @replica", "") + + // insert a row using master + exec(t, masterConn, "insert into customer(id, email) values(1,'email1')", "") + + // we'll run this query a number of times, and then give up if the row count never reaches this value + retryNTimes(t, 10 /*maxRetries*/, checkCustomerRows(1)) + + // after a short pause, SELECT the data inside a tx on a replica + // begin transaction on replica + exec(t, replicaConn, "begin", "") + qr := exec(t, replicaConn, fetchAllCustomers, "") + assert.Equal(t, `[[INT64(1) VARCHAR("email1")]]`, fmt.Sprintf("%v", qr.Rows), "select returned wrong result") + + // insert more data on master using a transaction + exec(t, masterConn, "begin", "") + exec(t, masterConn, "insert into customer(id, email) values(2,'email2')", "") + exec(t, masterConn, "commit", "") + + retryNTimes(t, 10 /*maxRetries*/, checkCustomerRows(2)) + + // replica doesn't see new row because it is in a transaction + qr2 := exec(t, replicaConn, fetchAllCustomers, "") + assert.Equal(t, qr.Rows, qr2.Rows) + + // replica should see new row after closing the transaction + exec(t, replicaConn, "commit", "") + + qr3 := exec(t, replicaConn, fetchAllCustomers, "") + assert.Equal(t, `[[INT64(1) VARCHAR("email1")] [INT64(2) VARCHAR("email2")]]`, fmt.Sprintf("%v", qr3.Rows), "we are not seeing the updates after closing the replica transaction") + + // begin transaction on replica + exec(t, replicaConn, "begin", "") + // try to delete a row, should fail + exec(t, replicaConn, "delete from customer where id=1", "supported only for master tablet type, current type: replica") + exec(t, replicaConn, "commit", "") + + // begin transaction on replica + exec(t, replicaConn, "begin", "") + // try to update a row, should fail + exec(t, replicaConn, "update customer set email='emailn' where id=1", "supported only for master tablet type, current type: replica") + exec(t, replicaConn, "commit", "") + + // begin transaction on replica + exec(t, replicaConn, "begin", "") + // try to insert a row, should fail + exec(t, replicaConn, "insert into customer(id, email) values(1,'email1')", "supported only for master tablet type, current type: replica") + // call rollback just for fun + exec(t, replicaConn, "rollback", "") + + // start another transaction + exec(t, replicaConn, "begin", "") + exec(t, replicaConn, fetchAllCustomers, "") + // bring down the tablet and try to select again + replicaTablet := clusterInstance.Keyspaces[0].Shards[0].Replica() + // this gives us a "signal: killed" error, ignore it + _ = replicaTablet.VttabletProcess.TearDown() + // Healthcheck interval on tablet is set to 1s, so sleep for 2s + time.Sleep(2 * time.Second) + exec(t, replicaConn, fetchAllCustomers, "is either down or nonexistent") + + // bring up tablet again + // query using same transaction will fail + _ = replicaTablet.VttabletProcess.Setup() + exec(t, replicaConn, fetchAllCustomers, "not found") + exec(t, replicaConn, "commit", "") + // create a new connection, should be able to query again + replicaConn, err = mysql.Connect(ctx, &vtParams) + require.NoError(t, err) + exec(t, replicaConn, "begin", "") + qr4 := exec(t, replicaConn, fetchAllCustomers, "") + assert.Equal(t, `[[INT64(1) VARCHAR("email1")] [INT64(2) VARCHAR("email2")]]`, fmt.Sprintf("%v", qr4.Rows), "we are not able to reconnect after restart") +} + +func getMapFromJSON(JSON map[string]interface{}, key string) map[string]interface{} { + result := make(map[string]interface{}) + object := reflect.ValueOf(JSON[key]) + if object.Kind() == reflect.Map { + for _, key := range object.MapKeys() { + value := object.MapIndex(key) + result[key.String()] = value + } + } + return result +} + +func isMasterTabletPresent(tablets map[string]interface{}) bool { + for key := range tablets { + if strings.Contains(key, "master") { + return true + } + } + return false +} + +func exec(t *testing.T, conn *mysql.Conn, query string, expectError string) *sqltypes.Result { + t.Helper() + qr, err := conn.ExecuteFetch(query, 1000, true) + if expectError == "" { + require.NoError(t, err) + } else { + require.Error(t, err, "error should not be nil") + assert.Contains(t, err.Error(), expectError, "Unexpected error") + } + return qr +} diff --git a/go/test/endtoend/tabletmanager/custom_rule_topo_test.go b/go/test/endtoend/tabletmanager/custom_rule_topo_test.go index 31a697249d0..ff70a88cb51 100644 --- a/go/test/endtoend/tabletmanager/custom_rule_topo_test.go +++ b/go/test/endtoend/tabletmanager/custom_rule_topo_test.go @@ -62,7 +62,7 @@ func TestTopoCustomRule(t *testing.T) { } // Start a new Tablet - rTablet := clusterInstance.GetVttabletInstance("replica", 0, "") + rTablet := clusterInstance.NewVttabletInstance("replica", 0, "") // Init Tablets err = clusterInstance.VtctlclientProcess.InitTablet(rTablet, cell, keyspaceName, hostname, shardName) diff --git a/go/test/endtoend/tabletmanager/tablet_health_test.go b/go/test/endtoend/tabletmanager/tablet_health_test.go index 16ca2a4ac94..ee7e43790e2 100644 --- a/go/test/endtoend/tabletmanager/tablet_health_test.go +++ b/go/test/endtoend/tabletmanager/tablet_health_test.go @@ -54,7 +54,7 @@ func TestTabletReshuffle(t *testing.T) { checkDataOnReplica(t, replicaConn, `[[VARCHAR("a")] [VARCHAR("b")]]`) //Create new tablet - rTablet := clusterInstance.GetVttabletInstance("replica", 0, "") + rTablet := clusterInstance.NewVttabletInstance("replica", 0, "") //Init Tablets err = clusterInstance.VtctlclientProcess.InitTablet(rTablet, cell, keyspaceName, hostname, shardName) @@ -98,7 +98,7 @@ func TestHealthCheck(t *testing.T) { defer cluster.PanicHandler(t) ctx := context.Background() - rTablet := clusterInstance.GetVttabletInstance("replica", 0, "") + rTablet := clusterInstance.NewVttabletInstance("replica", 0, "") // Start Mysql Processes and return connection replicaConn, err := cluster.StartMySQLAndGetConnection(ctx, rTablet, username, clusterInstance.TmpDirectory) @@ -261,7 +261,7 @@ func TestIgnoreHealthError(t *testing.T) { } // Start mysql process - tablet := clusterInstance.GetVttabletInstance("replica", 0, "") + tablet := clusterInstance.NewVttabletInstance("replica", 0, "") tablet.MysqlctlProcess = *cluster.MysqlCtlProcessInstance(tablet.TabletUID, tablet.MySQLPort, clusterInstance.TmpDirectory) err := tablet.MysqlctlProcess.Start() require.Nil(t, err) @@ -326,8 +326,8 @@ func TestNoMysqlHealthCheck(t *testing.T) { defer cluster.PanicHandler(t) ctx := context.Background() - rTablet := clusterInstance.GetVttabletInstance("replica", 0, "") - mTablet := clusterInstance.GetVttabletInstance("replica", 0, "") + rTablet := clusterInstance.NewVttabletInstance("replica", 0, "") + mTablet := clusterInstance.NewVttabletInstance("replica", 0, "") // Start Mysql Processes and return connection masterConn, err := cluster.StartMySQLAndGetConnection(ctx, mTablet, username, clusterInstance.TmpDirectory) diff --git a/go/test/endtoend/tabletmanager/tablet_security_policy_test.go b/go/test/endtoend/tabletmanager/tablet_security_policy_test.go index 9bf78382040..61df124f2fe 100644 --- a/go/test/endtoend/tabletmanager/tablet_security_policy_test.go +++ b/go/test/endtoend/tabletmanager/tablet_security_policy_test.go @@ -30,7 +30,7 @@ import ( func TestFallbackSecurityPolicy(t *testing.T) { defer cluster.PanicHandler(t) ctx := context.Background() - mTablet := clusterInstance.GetVttabletInstance("replica", 0, "") + mTablet := clusterInstance.NewVttabletInstance("replica", 0, "") //Init Tablets err := clusterInstance.VtctlclientProcess.InitTablet(mTablet, cell, keyspaceName, hostname, shardName) @@ -89,7 +89,7 @@ func assertAllowedURLTest(t *testing.T, url string) { func TestDenyAllSecurityPolicy(t *testing.T) { defer cluster.PanicHandler(t) ctx := context.Background() - mTablet := clusterInstance.GetVttabletInstance("replica", 0, "") + mTablet := clusterInstance.NewVttabletInstance("replica", 0, "") //Init Tablets err := clusterInstance.VtctlclientProcess.InitTablet(mTablet, cell, keyspaceName, hostname, shardName) @@ -125,7 +125,7 @@ func TestDenyAllSecurityPolicy(t *testing.T) { func TestReadOnlySecurityPolicy(t *testing.T) { defer cluster.PanicHandler(t) ctx := context.Background() - mTablet := clusterInstance.GetVttabletInstance("replica", 0, "") + mTablet := clusterInstance.NewVttabletInstance("replica", 0, "") //Init Tablets err := clusterInstance.VtctlclientProcess.InitTablet(mTablet, cell, keyspaceName, hostname, shardName) diff --git a/go/test/endtoend/tabletmanager/tablet_test.go b/go/test/endtoend/tabletmanager/tablet_test.go index 50ab6a75730..fe84a69bafd 100644 --- a/go/test/endtoend/tabletmanager/tablet_test.go +++ b/go/test/endtoend/tabletmanager/tablet_test.go @@ -34,7 +34,7 @@ func TestLocalMetadata(t *testing.T) { cluster.VerifyLocalMetadata(t, &replicaTablet, keyspaceName, shardName, cell) // Create new tablet - rTablet := clusterInstance.GetVttabletInstance("replica", 0, "") + rTablet := clusterInstance.NewVttabletInstance("replica", 0, "") // Init Tablet err := clusterInstance.VtctlclientProcess.InitTablet(rTablet, cell, keyspaceName, hostname, shardName) @@ -57,7 +57,7 @@ func TestLocalMetadata(t *testing.T) { cluster.VerifyLocalMetadata(t, rTablet, keyspaceName, shardName, cell) // Create another new tablet - rTablet2 := clusterInstance.GetVttabletInstance("replica", 0, "") + rTablet2 := clusterInstance.NewVttabletInstance("replica", 0, "") // Init Tablet err = clusterInstance.VtctlclientProcess.InitTablet(rTablet2, cell, keyspaceName, hostname, shardName) diff --git a/go/test/endtoend/worker/worker_test.go b/go/test/endtoend/worker/worker_test.go index 48b8f2a7ef3..520f3d6ba44 100644 --- a/go/test/endtoend/worker/worker_test.go +++ b/go/test/endtoend/worker/worker_test.go @@ -560,15 +560,15 @@ func initializeCluster(t *testing.T, onlyTopo bool) (int, error) { } // Defining all the tablets - master = localCluster.GetVttabletInstance("replica", 0, "") - replica1 = localCluster.GetVttabletInstance("replica", 0, "") - rdOnly1 = localCluster.GetVttabletInstance("rdonly", 0, "") - shard0Master = localCluster.GetVttabletInstance("replica", 0, "") - shard0Replica = localCluster.GetVttabletInstance("replica", 0, "") - shard0RdOnly1 = localCluster.GetVttabletInstance("rdonly", 0, "") - shard1Master = localCluster.GetVttabletInstance("replica", 0, "") - shard1Replica = localCluster.GetVttabletInstance("replica", 0, "") - shard1RdOnly1 = localCluster.GetVttabletInstance("rdonly", 0, "") + master = localCluster.NewVttabletInstance("replica", 0, "") + replica1 = localCluster.NewVttabletInstance("replica", 0, "") + rdOnly1 = localCluster.NewVttabletInstance("rdonly", 0, "") + shard0Master = localCluster.NewVttabletInstance("replica", 0, "") + shard0Replica = localCluster.NewVttabletInstance("replica", 0, "") + shard0RdOnly1 = localCluster.NewVttabletInstance("rdonly", 0, "") + shard1Master = localCluster.NewVttabletInstance("replica", 0, "") + shard1Replica = localCluster.NewVttabletInstance("replica", 0, "") + shard1RdOnly1 = localCluster.NewVttabletInstance("rdonly", 0, "") shard.Vttablets = []*cluster.Vttablet{master, replica1, rdOnly1} shard0.Vttablets = []*cluster.Vttablet{shard0Master, shard0Replica, shard0RdOnly1} diff --git a/go/vt/discovery/fake_healthcheck.go b/go/vt/discovery/fake_healthcheck.go index 460aa5a934d..ef21b9f1d69 100644 --- a/go/vt/discovery/fake_healthcheck.go +++ b/go/vt/discovery/fake_healthcheck.go @@ -65,7 +65,7 @@ func (fhc *FakeHealthCheck) RegisterStats() { func (fhc *FakeHealthCheck) WaitForInitialStatsUpdates() { } -// AddTablet adds the tablet and calls the listener. +// AddTablet adds the tablet. func (fhc *FakeHealthCheck) AddTablet(tablet *topodatapb.Tablet) { key := TabletToMapKey(tablet) item := &fhcItem{ @@ -111,8 +111,8 @@ func (fhc *FakeHealthCheck) ReplaceTablet(old, new *topodatapb.Tablet) { fhc.AddTablet(new) } -// GetConnection returns the TabletConn of the given tablet. -func (fhc *FakeHealthCheck) GetConnection(key string) queryservice.QueryService { +// TabletConnection returns the TabletConn of the given tablet. +func (fhc *FakeHealthCheck) TabletConnection(key string) queryservice.QueryService { fhc.mu.RLock() defer fhc.mu.RUnlock() if item := fhc.items[key]; item != nil { diff --git a/go/vt/discovery/healthcheck.go b/go/vt/discovery/healthcheck.go index 5b6fceec399..504a367f9d0 100644 --- a/go/vt/discovery/healthcheck.go +++ b/go/vt/discovery/healthcheck.go @@ -45,6 +45,10 @@ import ( "sync" "time" + "vitess.io/vitess/go/vt/proto/vtrpc" + "vitess.io/vitess/go/vt/vterrors" + "vitess.io/vitess/go/vt/vttablet/queryservice" + "vitess.io/vitess/go/flagutil" "vitess.io/vitess/go/vt/topo" @@ -160,7 +164,7 @@ type TabletRecorder interface { type keyspaceShardTabletType string type tabletAliasString string -// HealthCheck performs health checking and stores the results. +// HealthCheckImpl performs health checking and stores the results. // The goal of this object is to maintain a StreamHealth RPC // to a lot of tablets. Tablets are added / removed by calling the // AddTablet / RemoveTablet methods (other discovery module objects @@ -173,7 +177,7 @@ type tabletAliasString string // is removed from the map. When a tabletHealthCheck // gets removed from the map, its cancelFunc gets called, which ensures that the associated // checkConn goroutine eventually terminates. -type HealthCheck struct { +type HealthCheckImpl struct { // Immutable fields set at construction time. retryDelay time.Duration healthCheckTimeout time.Duration @@ -216,10 +220,10 @@ type HealthCheck struct { // The localCell for this healthcheck // callback. // A function to call when there is a master change. Used to notify vtgate's buffer to stop buffering. -func NewHealthCheck(ctx context.Context, retryDelay, healthCheckTimeout time.Duration, topoServer *topo.Server, localCell string) *HealthCheck { +func NewHealthCheck(ctx context.Context, retryDelay, healthCheckTimeout time.Duration, topoServer *topo.Server, localCell string) *HealthCheckImpl { log.Infof("loading tablets for cells: %v", *CellsToWatch) - hc := &HealthCheck{ + hc := &HealthCheckImpl{ ts: topoServer, cell: localCell, retryDelay: retryDelay, @@ -273,7 +277,7 @@ func NewHealthCheck(ctx context.Context, retryDelay, healthCheckTimeout time.Dur // AddTablet adds the tablet, and starts health check. // It does not block on making connection. // name is an optional tag for the tablet, e.g. an alternative address. -func (hc *HealthCheck) AddTablet(tablet *topodata.Tablet) { +func (hc *HealthCheckImpl) AddTablet(tablet *topodata.Tablet) { log.Infof("Calling AddTablet for tablet: %v", tablet) // check whether we should really add this tablet if !hc.isIncluded(tablet) { @@ -323,7 +327,7 @@ func (hc *HealthCheck) AddTablet(tablet *topodata.Tablet) { // RemoveTablet removes the tablet, and stops the health check. // It does not block. -func (hc *HealthCheck) RemoveTablet(tablet *topodata.Tablet) { +func (hc *HealthCheckImpl) RemoveTablet(tablet *topodata.Tablet) { if !hc.isIncluded(tablet) { return } @@ -331,12 +335,12 @@ func (hc *HealthCheck) RemoveTablet(tablet *topodata.Tablet) { } // ReplaceTablet removes the old tablet and adds the new tablet. -func (hc *HealthCheck) ReplaceTablet(old, new *topodata.Tablet) { +func (hc *HealthCheckImpl) ReplaceTablet(old, new *topodata.Tablet) { hc.deleteTablet(old) hc.AddTablet(new) } -func (hc *HealthCheck) deleteTablet(tablet *topodata.Tablet) { +func (hc *HealthCheckImpl) deleteTablet(tablet *topodata.Tablet) { hc.mu.Lock() defer hc.mu.Unlock() @@ -361,7 +365,7 @@ func (hc *HealthCheck) deleteTablet(tablet *topodata.Tablet) { delete(ths, tabletAlias) } -func (hc *HealthCheck) updateHealth(th *TabletHealth, shr *query.StreamHealthResponse, currentTarget *query.Target, trivialNonMasterUpdate bool, isMasterUpdate bool, isMasterChange bool) { +func (hc *HealthCheckImpl) updateHealth(th *TabletHealth, shr *query.StreamHealthResponse, currentTarget *query.Target, trivialNonMasterUpdate bool, isMasterUpdate bool, isMasterChange bool) { // hc.healthByAlias is authoritative, it should be updated hc.mu.Lock() defer hc.mu.Unlock() @@ -432,7 +436,7 @@ func (hc *HealthCheck) updateHealth(th *TabletHealth, shr *query.StreamHealthRes } // Subscribe adds a listener. Only used for testing right now -func (hc *HealthCheck) Subscribe() chan *TabletHealth { +func (hc *HealthCheckImpl) Subscribe() chan *TabletHealth { hc.subMu.Lock() defer hc.subMu.Unlock() c := make(chan *TabletHealth, 2) @@ -441,13 +445,13 @@ func (hc *HealthCheck) Subscribe() chan *TabletHealth { } // Unsubscribe removes a listener. Only used for testing right now -func (hc *HealthCheck) Unsubscribe(c chan *TabletHealth) { +func (hc *HealthCheckImpl) Unsubscribe(c chan *TabletHealth) { hc.subMu.Lock() defer hc.subMu.Unlock() delete(hc.subscribers, c) } -func (hc *HealthCheck) broadcast(th *TabletHealth) { +func (hc *HealthCheckImpl) broadcast(th *TabletHealth) { hc.subMu.Lock() defer hc.subMu.Unlock() for c := range hc.subscribers { @@ -459,7 +463,7 @@ func (hc *HealthCheck) broadcast(th *TabletHealth) { } // CacheStatus returns a displayable version of the cache. -func (hc *HealthCheck) CacheStatus() TabletsCacheStatusList { +func (hc *HealthCheckImpl) CacheStatus() TabletsCacheStatusList { tcsMap := hc.cacheStatusMap() tcsl := make(TabletsCacheStatusList, 0, len(tcsMap)) for _, tcs := range tcsMap { @@ -469,7 +473,7 @@ func (hc *HealthCheck) CacheStatus() TabletsCacheStatusList { return tcsl } -func (hc *HealthCheck) cacheStatusMap() map[string]*TabletsCacheStatus { +func (hc *HealthCheckImpl) cacheStatusMap() map[string]*TabletsCacheStatus { tcsMap := make(map[string]*TabletsCacheStatus) hc.mu.Lock() defer hc.mu.Unlock() @@ -492,7 +496,7 @@ func (hc *HealthCheck) cacheStatusMap() map[string]*TabletsCacheStatus { } // Close stops the healthcheck. -func (hc *HealthCheck) Close() error { +func (hc *HealthCheckImpl) Close() error { hc.mu.Lock() for _, th := range hc.healthByAlias { th.cancelFunc() @@ -523,7 +527,7 @@ func (hc *HealthCheck) Close() error { // the most recent tablet of type master. // This returns a copy of the data so that callers can access without // synchronization -func (hc *HealthCheck) GetHealthyTabletStats(target *query.Target) []*TabletHealth { +func (hc *HealthCheckImpl) GetHealthyTabletStats(target *query.Target) []*TabletHealth { var result []*TabletHealth hc.mu.Lock() defer hc.mu.Unlock() @@ -534,7 +538,7 @@ func (hc *HealthCheck) GetHealthyTabletStats(target *query.Target) []*TabletHeal // The returned array is owned by the caller. // For TabletType_MASTER, this will only return at most one entry, // the most recent tablet of type master. -func (hc *HealthCheck) getTabletStats(target *query.Target) []*TabletHealth { +func (hc *HealthCheckImpl) getTabletStats(target *query.Target) []*TabletHealth { var result []*TabletHealth hc.mu.Lock() defer hc.mu.Unlock() @@ -548,7 +552,7 @@ func (hc *HealthCheck) getTabletStats(target *query.Target) []*TabletHealth { // WaitForTablets waits for at least one tablet in the given // keyspace / shard / tablet type before returning. The tablets do not // have to be healthy. It will return ctx.Err() if the context is canceled. -func (hc *HealthCheck) WaitForTablets(ctx context.Context, keyspace, shard string, tabletType topodata.TabletType) error { +func (hc *HealthCheckImpl) WaitForTablets(ctx context.Context, keyspace, shard string, tabletType topodata.TabletType) error { targets := []*query.Target{ { Keyspace: keyspace, @@ -563,12 +567,12 @@ func (hc *HealthCheck) WaitForTablets(ctx context.Context, keyspace, shard strin // each given target before returning. // It will return ctx.Err() if the context is canceled. // It will return an error if it can't read the necessary topology records. -func (hc *HealthCheck) WaitForAllServingTablets(ctx context.Context, targets []*query.Target) error { +func (hc *HealthCheckImpl) WaitForAllServingTablets(ctx context.Context, targets []*query.Target) error { return hc.waitForTablets(ctx, targets, true) } // waitForTablets is the internal method that polls for tablets. -func (hc *HealthCheck) waitForTablets(ctx context.Context, targets []*query.Target, requireServing bool) error { +func (hc *HealthCheckImpl) waitForTablets(ctx context.Context, targets []*query.Target, requireServing bool) error { for { // We nil targets as we find them. allPresent := true @@ -606,17 +610,29 @@ func (hc *HealthCheck) waitForTablets(ctx context.Context, targets []*query.Targ } } +// TabletConnection returns the Connection to a given tablet. +func (hc *HealthCheckImpl) TabletConnection(alias *topodata.TabletAlias) (queryservice.QueryService, error) { + hc.mu.Lock() + thc := hc.healthByAlias[tabletAliasString(topoproto.TabletAliasString(alias))] + hc.mu.Unlock() + if thc == nil || thc.Conn == nil { + //TODO: test that throws this error + return nil, vterrors.Errorf(vtrpc.Code_NOT_FOUND, "tablet: %v is either down or nonexistent", alias) + } + return thc.Connection(), nil +} + // Target includes cell which we ignore here // because tabletStatsCache is intended to be per-cell -func (hc *HealthCheck) keyFromTarget(target *query.Target) keyspaceShardTabletType { +func (hc *HealthCheckImpl) keyFromTarget(target *query.Target) keyspaceShardTabletType { return keyspaceShardTabletType(fmt.Sprintf("%s.%s.%s", target.Keyspace, target.Shard, topoproto.TabletTypeLString(target.TabletType))) } -func (hc *HealthCheck) keyFromTablet(tablet *topodata.Tablet) keyspaceShardTabletType { +func (hc *HealthCheckImpl) keyFromTablet(tablet *topodata.Tablet) keyspaceShardTabletType { return keyspaceShardTabletType(fmt.Sprintf("%s.%s.%s", tablet.Keyspace, tablet.Shard, topoproto.TabletTypeLString(tablet.Type))) } -func (hc *HealthCheck) getAliasByCell(cell string) string { +func (hc *HealthCheckImpl) getAliasByCell(cell string) string { hc.mu.Lock() defer hc.mu.Unlock() @@ -632,7 +648,7 @@ func (hc *HealthCheck) getAliasByCell(cell string) string { return alias } -func (hc *HealthCheck) isIncluded(tablet *topodata.Tablet) bool { +func (hc *HealthCheckImpl) isIncluded(tablet *topodata.Tablet) bool { if tablet.Type == topodata.TabletType_MASTER { return true } @@ -647,7 +663,7 @@ func (hc *HealthCheck) isIncluded(tablet *topodata.Tablet) bool { // topologyWatcherMaxRefreshLag returns the maximum lag since the watched // cells were refreshed from the topo server -func (hc *HealthCheck) topologyWatcherMaxRefreshLag() time.Duration { +func (hc *HealthCheckImpl) topologyWatcherMaxRefreshLag() time.Duration { var lag time.Duration for _, tw := range hc.topoWatchers { cellLag := tw.RefreshLag() @@ -659,7 +675,7 @@ func (hc *HealthCheck) topologyWatcherMaxRefreshLag() time.Duration { } // topologyWatcherChecksum returns a checksum of the topology watcher state -func (hc *HealthCheck) topologyWatcherChecksum() int64 { +func (hc *HealthCheckImpl) topologyWatcherChecksum() int64 { var checksum int64 for _, tw := range hc.topoWatchers { checksum = checksum ^ int64(tw.TopoChecksum()) @@ -668,7 +684,7 @@ func (hc *HealthCheck) topologyWatcherChecksum() int64 { } // RegisterStats registers the connection counts stats -func (hc *HealthCheck) RegisterStats() { +func (hc *HealthCheckImpl) RegisterStats() { stats.NewGaugeDurationFunc( "TopologyWatcherMaxRefreshLag", "maximum time since the topology watcher refreshed a cell", @@ -694,7 +710,7 @@ func (hc *HealthCheck) RegisterStats() { } // ServeHTTP is part of the http.Handler interface. It renders the current state of the discovery gateway tablet cache into json. -func (hc *HealthCheck) ServeHTTP(w http.ResponseWriter, _ *http.Request) { +func (hc *HealthCheckImpl) ServeHTTP(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Content-Type", "application/json; charset=utf-8") status := hc.CacheStatus() b, err := json.MarshalIndent(status, "", " ") @@ -709,7 +725,7 @@ func (hc *HealthCheck) ServeHTTP(w http.ResponseWriter, _ *http.Request) { } // servingConnStats returns the number of serving tablets per keyspace/shard/tablet type. -func (hc *HealthCheck) servingConnStats() map[string]int64 { +func (hc *HealthCheckImpl) servingConnStats() map[string]int64 { res := make(map[string]int64) hc.mu.Lock() defer hc.mu.Unlock() @@ -724,7 +740,7 @@ func (hc *HealthCheck) servingConnStats() map[string]int64 { } // stateChecksum returns a crc32 checksum of the healthcheck state -func (hc *HealthCheck) stateChecksum() int64 { +func (hc *HealthCheckImpl) stateChecksum() int64 { // CacheStatus is sorted so this should be stable across vtgates cacheStatus := hc.CacheStatus() var buf bytes.Buffer diff --git a/go/vt/discovery/healthcheck_test.go b/go/vt/discovery/healthcheck_test.go index 2e638a53acd..79497b2d80b 100644 --- a/go/vt/discovery/healthcheck_test.go +++ b/go/vt/discovery/healthcheck_test.go @@ -766,7 +766,7 @@ func tabletDialer(tablet *topodatapb.Tablet, _ grpcclient.FailFast) (queryservic return nil, fmt.Errorf("tablet %v not found", key) } -func createTestHc(ts *topo.Server) *HealthCheck { +func createTestHc(ts *topo.Server) *HealthCheckImpl { return NewHealthCheck(context.Background(), 1*time.Millisecond, time.Hour, ts, "cell") } diff --git a/go/vt/discovery/tablet_health_check.go b/go/vt/discovery/tablet_health_check.go index 39aa9895c0c..79a8acd40b9 100644 --- a/go/vt/discovery/tablet_health_check.go +++ b/go/vt/discovery/tablet_health_check.go @@ -20,6 +20,7 @@ import ( "context" "fmt" "strings" + "sync" "time" "vitess.io/vitess/go/sync2" @@ -47,6 +48,8 @@ type tabletHealthCheck struct { cancelFunc context.CancelFunc // Tablet is the tablet object that was sent to HealthCheck.AddTablet. Tablet *topodata.Tablet + // mutex to protect Conn + connMu sync.Mutex // Conn is the connection associated with the tablet. Conn queryservice.QueryService // Target is the current target as returned by the streaming @@ -80,6 +83,8 @@ func (thc *tabletHealthCheck) String() string { // Note that this is not a deep copy because we point to the same underlying RealtimeStats. // That is fine because the RealtimeStats object is never changed after creation. func (thc *tabletHealthCheck) SimpleCopy() *TabletHealth { + thc.connMu.Lock() + defer thc.connMu.Unlock() return &TabletHealth{ Conn: thc.Conn, Tablet: thc.Tablet, @@ -117,7 +122,7 @@ func (thc *tabletHealthCheck) setServingState(serving bool, reason string) { // stream streams healthcheck responses to callback. func (thc *tabletHealthCheck) stream(ctx context.Context, callback func(*query.StreamHealthResponse) error) error { - conn := thc.getConnection() + conn := thc.Connection() if conn == nil { // This signals the caller to retry return nil @@ -130,7 +135,13 @@ func (thc *tabletHealthCheck) stream(ctx context.Context, callback func(*query.S return err } -func (thc *tabletHealthCheck) getConnection() queryservice.QueryService { +func (thc *tabletHealthCheck) Connection() queryservice.QueryService { + thc.connMu.Lock() + defer thc.connMu.Unlock() + return thc.connectionLocked() +} + +func (thc *tabletHealthCheck) connectionLocked() queryservice.QueryService { if thc.Conn == nil { conn, err := tabletconn.GetDialer()(thc.Tablet, grpcclient.FailFast(true)) if err != nil { @@ -144,7 +155,7 @@ func (thc *tabletHealthCheck) getConnection() queryservice.QueryService { } // processResponse reads one health check response, and updates health -func (thc *tabletHealthCheck) processResponse(hc *HealthCheck, shr *query.StreamHealthResponse) error { +func (thc *tabletHealthCheck) processResponse(hc *HealthCheckImpl, shr *query.StreamHealthResponse) error { select { case <-thc.ctx.Done(): return thc.ctx.Err() @@ -221,7 +232,7 @@ func (thc *tabletHealthCheck) isTrivialReplagChange(newStats *query.RealtimeStat } // checkConn performs health checking on the given tablet. -func (thc *tabletHealthCheck) checkConn(hc *HealthCheck) { +func (thc *tabletHealthCheck) checkConn(hc *HealthCheckImpl) { defer func() { // TODO(deepthi): We should ensure any return from this func calls the equivalent of hc.deleteTablet thc.finalizeConn() diff --git a/go/vt/proto/query/query.pb.go b/go/vt/proto/query/query.pb.go index 45f9128cebd..cd029d6e0a5 100644 --- a/go/vt/proto/query/query.pb.go +++ b/go/vt/proto/query/query.pb.go @@ -1838,10 +1838,11 @@ func (m *BeginRequest) GetOptions() *ExecuteOptions { // BeginResponse is the returned value from Begin type BeginResponse struct { - TransactionId int64 `protobuf:"varint,1,opt,name=transaction_id,json=transactionId,proto3" json:"transaction_id,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + TransactionId int64 `protobuf:"varint,1,opt,name=transaction_id,json=transactionId,proto3" json:"transaction_id,omitempty"` + TabletAlias *topodata.TabletAlias `protobuf:"bytes,2,opt,name=tablet_alias,json=tabletAlias,proto3" json:"tablet_alias,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *BeginResponse) Reset() { *m = BeginResponse{} } @@ -1876,6 +1877,13 @@ func (m *BeginResponse) GetTransactionId() int64 { return 0 } +func (m *BeginResponse) GetTabletAlias() *topodata.TabletAlias { + if m != nil { + return m.TabletAlias + } + return nil +} + // CommitRequest is the payload to Commit type CommitRequest struct { EffectiveCallerId *vtrpc.CallerID `protobuf:"bytes,1,opt,name=effective_caller_id,json=effectiveCallerId,proto3" json:"effective_caller_id,omitempty"` @@ -2964,10 +2972,11 @@ type BeginExecuteResponse struct { Error *vtrpc.RPCError `protobuf:"bytes,1,opt,name=error,proto3" json:"error,omitempty"` Result *QueryResult `protobuf:"bytes,2,opt,name=result,proto3" json:"result,omitempty"` // transaction_id might be non-zero even if an error is present. - TransactionId int64 `protobuf:"varint,3,opt,name=transaction_id,json=transactionId,proto3" json:"transaction_id,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + TransactionId int64 `protobuf:"varint,3,opt,name=transaction_id,json=transactionId,proto3" json:"transaction_id,omitempty"` + TabletAlias *topodata.TabletAlias `protobuf:"bytes,4,opt,name=tablet_alias,json=tabletAlias,proto3" json:"tablet_alias,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *BeginExecuteResponse) Reset() { *m = BeginExecuteResponse{} } @@ -3016,6 +3025,13 @@ func (m *BeginExecuteResponse) GetTransactionId() int64 { return 0 } +func (m *BeginExecuteResponse) GetTabletAlias() *topodata.TabletAlias { + if m != nil { + return m.TabletAlias + } + return nil +} + // BeginExecuteBatchRequest is the payload to BeginExecuteBatch type BeginExecuteBatchRequest struct { EffectiveCallerId *vtrpc.CallerID `protobuf:"bytes,1,opt,name=effective_caller_id,json=effectiveCallerId,proto3" json:"effective_caller_id,omitempty"` @@ -3104,10 +3120,11 @@ type BeginExecuteBatchResponse struct { Error *vtrpc.RPCError `protobuf:"bytes,1,opt,name=error,proto3" json:"error,omitempty"` Results []*QueryResult `protobuf:"bytes,2,rep,name=results,proto3" json:"results,omitempty"` // transaction_id might be non-zero even if an error is present. - TransactionId int64 `protobuf:"varint,3,opt,name=transaction_id,json=transactionId,proto3" json:"transaction_id,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + TransactionId int64 `protobuf:"varint,3,opt,name=transaction_id,json=transactionId,proto3" json:"transaction_id,omitempty"` + TabletAlias *topodata.TabletAlias `protobuf:"bytes,4,opt,name=tablet_alias,json=tabletAlias,proto3" json:"tablet_alias,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *BeginExecuteBatchResponse) Reset() { *m = BeginExecuteBatchResponse{} } @@ -3156,6 +3173,13 @@ func (m *BeginExecuteBatchResponse) GetTransactionId() int64 { return 0 } +func (m *BeginExecuteBatchResponse) GetTabletAlias() *topodata.TabletAlias { + if m != nil { + return m.TabletAlias + } + return nil +} + // MessageStreamRequest is the request payload for MessageStream. type MessageStreamRequest struct { EffectiveCallerId *vtrpc.CallerID `protobuf:"bytes,1,opt,name=effective_caller_id,json=effectiveCallerId,proto3" json:"effective_caller_id,omitempty"` @@ -3833,192 +3857,193 @@ func init() { func init() { proto.RegisterFile("query.proto", fileDescriptor_5c6ac9b241082464) } var fileDescriptor_5c6ac9b241082464 = []byte{ - // 2983 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x5a, 0x4b, 0x70, 0xdb, 0xd6, - 0xb9, 0x36, 0xf8, 0x12, 0xf9, 0x53, 0xa4, 0x8e, 0x8e, 0x24, 0x9b, 0x96, 0xf3, 0x50, 0x90, 0x38, - 0xd1, 0xd5, 0xbd, 0x57, 0x76, 0x64, 0xc7, 0xd7, 0x37, 0x49, 0x5b, 0x43, 0x14, 0xe4, 0xd0, 0x26, - 0x41, 0xfa, 0x10, 0xb4, 0x63, 0x4f, 0x67, 0x30, 0x10, 0x79, 0x4c, 0x61, 0x04, 0x02, 0x34, 0x00, - 0xc9, 0xd6, 0xce, 0x6d, 0x9a, 0xbe, 0x1f, 0xe9, 0x33, 0x4d, 0x33, 0xcd, 0x74, 0xa6, 0x8b, 0x4e, - 0x37, 0x5d, 0x77, 0xd9, 0xe9, 0xa2, 0xcb, 0xee, 0xdb, 0x2e, 0xba, 0xea, 0x74, 0x97, 0xe9, 0xaa, - 0x8b, 0x2e, 0x3a, 0x9d, 0xf3, 0x00, 0x48, 0x59, 0x8c, 0xed, 0xb8, 0xdd, 0xd8, 0xc9, 0xee, 0xfc, - 0x8f, 0xf3, 0xf8, 0xbe, 0xf3, 0xe3, 0x3f, 0x3f, 0x80, 0x03, 0xc5, 0x5b, 0xbb, 0x34, 0xd8, 0x5f, - 0x1d, 0x06, 0x7e, 0xe4, 0xe3, 0x2c, 0x17, 0x16, 0xcb, 0x91, 0x3f, 0xf4, 0x7b, 0x76, 0x64, 0x0b, - 0xf5, 0x62, 0x71, 0x2f, 0x0a, 0x86, 0x5d, 0x21, 0xa8, 0x6f, 0x2b, 0x90, 0x33, 0xed, 0xa0, 0x4f, - 0x23, 0xbc, 0x08, 0xf9, 0x1d, 0xba, 0x1f, 0x0e, 0xed, 0x2e, 0xad, 0x28, 0x4b, 0xca, 0x72, 0x81, - 0x24, 0x32, 0x9e, 0x87, 0x6c, 0xb8, 0x6d, 0x07, 0xbd, 0x4a, 0x8a, 0x1b, 0x84, 0x80, 0x5f, 0x81, - 0x62, 0x64, 0x6f, 0xb9, 0x34, 0xb2, 0xa2, 0xfd, 0x21, 0xad, 0xa4, 0x97, 0x94, 0xe5, 0xf2, 0xda, - 0xfc, 0x6a, 0x32, 0x9f, 0xc9, 0x8d, 0xe6, 0xfe, 0x90, 0x12, 0x88, 0x92, 0x36, 0xc6, 0x90, 0xe9, - 0x52, 0xd7, 0xad, 0x64, 0xf8, 0x58, 0xbc, 0xad, 0x6e, 0x40, 0xf9, 0xaa, 0x79, 0xd1, 0x8e, 0x68, - 0xd5, 0x76, 0x5d, 0x1a, 0xd4, 0x36, 0xd8, 0x72, 0x76, 0x43, 0x1a, 0x78, 0xf6, 0x20, 0x59, 0x4e, - 0x2c, 0xe3, 0xa3, 0x90, 0xeb, 0x07, 0xfe, 0xee, 0x30, 0xac, 0xa4, 0x96, 0xd2, 0xcb, 0x05, 0x22, - 0x25, 0xf5, 0xf3, 0x00, 0xfa, 0x1e, 0xf5, 0x22, 0xd3, 0xdf, 0xa1, 0x1e, 0x7e, 0x0a, 0x0a, 0x91, - 0x33, 0xa0, 0x61, 0x64, 0x0f, 0x86, 0x7c, 0x88, 0x34, 0x19, 0x29, 0x3e, 0x02, 0xd2, 0x22, 0xe4, - 0x87, 0x7e, 0xe8, 0x44, 0x8e, 0xef, 0x71, 0x3c, 0x05, 0x92, 0xc8, 0xea, 0x67, 0x21, 0x7b, 0xd5, - 0x76, 0x77, 0x29, 0x7e, 0x16, 0x32, 0x1c, 0xb0, 0xc2, 0x01, 0x17, 0x57, 0x05, 0xe9, 0x1c, 0x27, - 0x37, 0xb0, 0xb1, 0xf7, 0x98, 0x27, 0x1f, 0x7b, 0x9a, 0x08, 0x41, 0xdd, 0x81, 0xe9, 0x75, 0xc7, - 0xeb, 0x5d, 0xb5, 0x03, 0x87, 0x91, 0xf1, 0x88, 0xc3, 0xe0, 0x17, 0x20, 0xc7, 0x1b, 0x61, 0x25, - 0xbd, 0x94, 0x5e, 0x2e, 0xae, 0x4d, 0xcb, 0x8e, 0x7c, 0x6d, 0x44, 0xda, 0xd4, 0xdf, 0x2a, 0x00, - 0xeb, 0xfe, 0xae, 0xd7, 0xbb, 0xc2, 0x8c, 0x18, 0x41, 0x3a, 0xbc, 0xe5, 0x4a, 0x22, 0x59, 0x13, - 0x5f, 0x86, 0xf2, 0x96, 0xe3, 0xf5, 0xac, 0x3d, 0xb9, 0x1c, 0xc1, 0x65, 0x71, 0xed, 0x05, 0x39, - 0xdc, 0xa8, 0xf3, 0xea, 0xf8, 0xaa, 0x43, 0xdd, 0x8b, 0x82, 0x7d, 0x52, 0xda, 0x1a, 0xd7, 0x2d, - 0x76, 0x00, 0x1f, 0x76, 0x62, 0x93, 0xee, 0xd0, 0xfd, 0x78, 0xd2, 0x1d, 0xba, 0x8f, 0xff, 0x6b, - 0x1c, 0x51, 0x71, 0x6d, 0x2e, 0x9e, 0x6b, 0xac, 0xaf, 0x84, 0xf9, 0x6a, 0xea, 0xbc, 0xa2, 0xfe, - 0x3a, 0x0b, 0x65, 0xfd, 0x0e, 0xed, 0xee, 0x46, 0xb4, 0x39, 0x64, 0x7b, 0x10, 0xe2, 0x06, 0xcc, - 0x38, 0x5e, 0xd7, 0xdd, 0xed, 0xd1, 0x9e, 0x75, 0xd3, 0xa1, 0x6e, 0x2f, 0xe4, 0x71, 0x54, 0x4e, - 0xd6, 0x7d, 0xd0, 0x7f, 0xb5, 0x26, 0x9d, 0x37, 0xb9, 0x2f, 0x29, 0x3b, 0x07, 0x64, 0xbc, 0x02, - 0xb3, 0x5d, 0xd7, 0xa1, 0x5e, 0x64, 0xdd, 0x64, 0x78, 0xad, 0xc0, 0xbf, 0x1d, 0x56, 0xb2, 0x4b, - 0xca, 0x72, 0x9e, 0xcc, 0x08, 0xc3, 0x26, 0xd3, 0x13, 0xff, 0x76, 0x88, 0x5f, 0x85, 0xfc, 0x6d, - 0x3f, 0xd8, 0x71, 0x7d, 0xbb, 0x57, 0xc9, 0xf1, 0x39, 0x9f, 0x99, 0x3c, 0xe7, 0x35, 0xe9, 0x45, - 0x12, 0x7f, 0xbc, 0x0c, 0x28, 0xbc, 0xe5, 0x5a, 0x21, 0x75, 0x69, 0x37, 0xb2, 0x5c, 0x67, 0xe0, - 0x44, 0x95, 0x3c, 0x0f, 0xc9, 0x72, 0x78, 0xcb, 0x6d, 0x73, 0x75, 0x9d, 0x69, 0xb1, 0x05, 0x0b, - 0x51, 0x60, 0x7b, 0xa1, 0xdd, 0x65, 0x83, 0x59, 0x4e, 0xe8, 0xbb, 0x36, 0x0f, 0xc7, 0x02, 0x9f, - 0x72, 0x65, 0xf2, 0x94, 0xe6, 0xa8, 0x4b, 0x2d, 0xee, 0x41, 0xe6, 0xa3, 0x09, 0x5a, 0xfc, 0x32, - 0x2c, 0x84, 0x3b, 0xce, 0xd0, 0xe2, 0xe3, 0x58, 0x43, 0xd7, 0xf6, 0xac, 0xae, 0xdd, 0xdd, 0xa6, - 0x15, 0xe0, 0xb0, 0x31, 0x33, 0xf2, 0x7d, 0x6f, 0xb9, 0xb6, 0x57, 0x65, 0x16, 0xf5, 0x35, 0x28, - 0x1f, 0xe4, 0x11, 0xcf, 0x42, 0xc9, 0xbc, 0xde, 0xd2, 0x2d, 0xcd, 0xd8, 0xb0, 0x0c, 0xad, 0xa1, - 0xa3, 0x23, 0xb8, 0x04, 0x05, 0xae, 0x6a, 0x1a, 0xf5, 0xeb, 0x48, 0xc1, 0x53, 0x90, 0xd6, 0xea, - 0x75, 0x94, 0x52, 0xcf, 0x43, 0x3e, 0x26, 0x04, 0xcf, 0x40, 0xb1, 0x63, 0xb4, 0x5b, 0x7a, 0xb5, - 0xb6, 0x59, 0xd3, 0x37, 0xd0, 0x11, 0x9c, 0x87, 0x4c, 0xb3, 0x6e, 0xb6, 0x90, 0x22, 0x5a, 0x5a, - 0x0b, 0xa5, 0x58, 0xcf, 0x8d, 0x75, 0x0d, 0xa5, 0xd5, 0x5f, 0x28, 0x30, 0x3f, 0x09, 0x18, 0x2e, - 0xc2, 0xd4, 0x86, 0xbe, 0xa9, 0x75, 0xea, 0x26, 0x3a, 0x82, 0xe7, 0x60, 0x86, 0xe8, 0x2d, 0x5d, - 0x33, 0xb5, 0xf5, 0xba, 0x6e, 0x11, 0x5d, 0xdb, 0x40, 0x0a, 0xc6, 0x50, 0x66, 0x2d, 0xab, 0xda, - 0x6c, 0x34, 0x6a, 0xa6, 0xa9, 0x6f, 0xa0, 0x14, 0x9e, 0x07, 0xc4, 0x75, 0x1d, 0x63, 0xa4, 0x4d, - 0x63, 0x04, 0xd3, 0x6d, 0x9d, 0xd4, 0xb4, 0x7a, 0xed, 0x06, 0x1b, 0x00, 0x65, 0xf0, 0x73, 0xf0, - 0x74, 0xb5, 0x69, 0xb4, 0x6b, 0x6d, 0x53, 0x37, 0x4c, 0xab, 0x6d, 0x68, 0xad, 0xf6, 0x1b, 0x4d, - 0x93, 0x8f, 0x2c, 0xc0, 0x65, 0x71, 0x19, 0x40, 0xeb, 0x98, 0x4d, 0x31, 0x0e, 0xca, 0x5d, 0xca, - 0xe4, 0x15, 0x94, 0xba, 0x94, 0xc9, 0xa7, 0x50, 0xfa, 0x52, 0x26, 0x9f, 0x46, 0x19, 0xf5, 0xdd, - 0x14, 0x64, 0x39, 0x57, 0x2c, 0xdd, 0x8d, 0x25, 0x31, 0xde, 0x4e, 0x1e, 0xfd, 0xd4, 0x7d, 0x1e, - 0x7d, 0x9e, 0x31, 0x65, 0x12, 0x12, 0x02, 0x3e, 0x01, 0x05, 0x3f, 0xe8, 0x5b, 0xc2, 0x22, 0xd2, - 0x67, 0xde, 0x0f, 0xfa, 0x3c, 0xcf, 0xb2, 0xd4, 0xc5, 0xb2, 0xee, 0x96, 0x1d, 0x52, 0x1e, 0xc1, - 0x05, 0x92, 0xc8, 0xf8, 0x38, 0x30, 0x3f, 0x8b, 0xaf, 0x23, 0xc7, 0x6d, 0x53, 0x7e, 0xd0, 0x37, - 0xd8, 0x52, 0x9e, 0x87, 0x52, 0xd7, 0x77, 0x77, 0x07, 0x9e, 0xe5, 0x52, 0xaf, 0x1f, 0x6d, 0x57, - 0xa6, 0x96, 0x94, 0xe5, 0x12, 0x99, 0x16, 0xca, 0x3a, 0xd7, 0xe1, 0x0a, 0x4c, 0x75, 0xb7, 0xed, - 0x20, 0xa4, 0x22, 0x6a, 0x4b, 0x24, 0x16, 0xf9, 0xac, 0xb4, 0xeb, 0x0c, 0x6c, 0x37, 0xe4, 0x11, - 0x5a, 0x22, 0x89, 0xcc, 0x40, 0xdc, 0x74, 0xed, 0x7e, 0xc8, 0x23, 0xab, 0x44, 0x84, 0xa0, 0xfe, - 0x1f, 0xa4, 0x89, 0x7f, 0x9b, 0x0d, 0x29, 0x26, 0x0c, 0x2b, 0xca, 0x52, 0x7a, 0x19, 0x93, 0x58, - 0x64, 0xd9, 0x5d, 0x26, 0x38, 0x91, 0xf7, 0xe2, 0x94, 0xf6, 0xbe, 0x02, 0x45, 0x1e, 0x98, 0x84, - 0x86, 0xbb, 0x6e, 0xc4, 0x12, 0xa1, 0xcc, 0x00, 0xca, 0x81, 0x44, 0xc8, 0x69, 0x27, 0xd2, 0xc6, - 0xf0, 0xb1, 0x87, 0xda, 0xb2, 0x6f, 0xde, 0xa4, 0xdd, 0x88, 0x8a, 0x7c, 0x9f, 0x21, 0xd3, 0x4c, - 0xa9, 0x49, 0x1d, 0x23, 0xd6, 0xf1, 0x42, 0x1a, 0x44, 0x96, 0xd3, 0xe3, 0x94, 0x67, 0x48, 0x5e, - 0x28, 0x6a, 0x3d, 0xfc, 0x0c, 0x64, 0x78, 0x5a, 0xc8, 0xf0, 0x59, 0x40, 0xce, 0x42, 0xfc, 0xdb, - 0x84, 0xeb, 0x2f, 0x65, 0xf2, 0x59, 0x94, 0x53, 0x5f, 0x87, 0x69, 0xbe, 0xb8, 0x6b, 0x76, 0xe0, - 0x39, 0x5e, 0x9f, 0x9f, 0x72, 0x7e, 0x4f, 0x6c, 0x7b, 0x89, 0xf0, 0x36, 0xc3, 0x3c, 0xa0, 0x61, - 0x68, 0xf7, 0xa9, 0x3c, 0x75, 0x62, 0x51, 0xfd, 0x59, 0x1a, 0x8a, 0xed, 0x28, 0xa0, 0xf6, 0x80, - 0x1f, 0x60, 0xf8, 0x75, 0x80, 0x30, 0xb2, 0x23, 0x3a, 0xa0, 0x5e, 0x14, 0xe3, 0x7b, 0x4a, 0xce, - 0x3c, 0xe6, 0xb7, 0xda, 0x8e, 0x9d, 0xc8, 0x98, 0x3f, 0x5e, 0x83, 0x22, 0x65, 0x66, 0x2b, 0x62, - 0x07, 0xa1, 0x4c, 0xb6, 0xb3, 0x71, 0xe6, 0x48, 0x4e, 0x48, 0x02, 0x34, 0x69, 0x2f, 0x7e, 0x90, - 0x82, 0x42, 0x32, 0x1a, 0xd6, 0x20, 0xdf, 0xb5, 0x23, 0xda, 0xf7, 0x83, 0x7d, 0x79, 0x3e, 0x9d, - 0xbc, 0xdf, 0xec, 0xab, 0x55, 0xe9, 0x4c, 0x92, 0x6e, 0xf8, 0x69, 0x10, 0x87, 0xbe, 0x88, 0x3a, - 0x81, 0xb7, 0xc0, 0x35, 0x3c, 0xee, 0x5e, 0x05, 0x3c, 0x0c, 0x9c, 0x81, 0x1d, 0xec, 0x5b, 0x3b, - 0x74, 0x3f, 0xce, 0xe5, 0xe9, 0x09, 0x3b, 0x89, 0xa4, 0xdf, 0x65, 0xba, 0x2f, 0xb3, 0xcf, 0xf9, - 0x83, 0x7d, 0x65, 0xb4, 0x1c, 0xde, 0x9f, 0xb1, 0x9e, 0xfc, 0x74, 0x0c, 0xe3, 0x73, 0x30, 0xcb, - 0x03, 0x8b, 0x35, 0xd5, 0x97, 0x20, 0x1f, 0x2f, 0x1e, 0x17, 0x20, 0xab, 0x07, 0x81, 0x1f, 0xa0, - 0x23, 0x3c, 0x09, 0x35, 0xea, 0x22, 0x8f, 0x6d, 0x6c, 0xb0, 0x3c, 0xf6, 0x9b, 0x54, 0x72, 0x18, - 0x11, 0x7a, 0x6b, 0x97, 0x86, 0x11, 0xfe, 0x1c, 0xcc, 0x51, 0x1e, 0x42, 0xce, 0x1e, 0xb5, 0xba, - 0xbc, 0x72, 0x61, 0x01, 0xa4, 0x70, 0xbe, 0x67, 0x56, 0x45, 0xa1, 0x15, 0x57, 0x34, 0x64, 0x36, - 0xf1, 0x95, 0xaa, 0x1e, 0xd6, 0x61, 0xce, 0x19, 0x0c, 0x68, 0xcf, 0xb1, 0xa3, 0xf1, 0x01, 0xc4, - 0x86, 0x2d, 0xc4, 0x07, 0xfb, 0x81, 0xc2, 0x88, 0xcc, 0x26, 0x3d, 0x92, 0x61, 0x4e, 0x42, 0x2e, - 0xe2, 0x45, 0x1c, 0x8f, 0xdd, 0xe2, 0x5a, 0x29, 0x4e, 0x28, 0x5c, 0x49, 0xa4, 0x11, 0xbf, 0x04, - 0xa2, 0x24, 0xe4, 0xa9, 0x63, 0x14, 0x10, 0xa3, 0x93, 0x9e, 0x08, 0x3b, 0x3e, 0x09, 0xe5, 0x03, - 0x67, 0x50, 0x8f, 0x13, 0x96, 0x26, 0xa5, 0xf1, 0x03, 0xa5, 0x87, 0x4f, 0xc1, 0x94, 0x2f, 0xce, - 0x1f, 0x9e, 0x54, 0x46, 0x2b, 0x3e, 0x78, 0x38, 0x91, 0xd8, 0x4b, 0xfd, 0x0c, 0xcc, 0x24, 0x0c, - 0x86, 0x43, 0xdf, 0x0b, 0x29, 0x5e, 0x81, 0x5c, 0xc0, 0x1f, 0x67, 0xc9, 0x1a, 0x96, 0x43, 0x8c, - 0x3d, 0xe8, 0x44, 0x7a, 0xa8, 0x3d, 0x98, 0x11, 0x9a, 0x6b, 0x4e, 0xb4, 0xcd, 0x37, 0x0a, 0x9f, - 0x84, 0x2c, 0x65, 0x8d, 0x7b, 0x38, 0x27, 0xad, 0x2a, 0xb7, 0x13, 0x61, 0x1d, 0x9b, 0x25, 0xf5, - 0xc0, 0x59, 0xfe, 0x96, 0x82, 0x39, 0xb9, 0xca, 0x75, 0x3b, 0xea, 0x6e, 0x3f, 0xa6, 0x9b, 0xfd, - 0xdf, 0x30, 0xc5, 0xf4, 0x4e, 0xf2, 0x60, 0x4c, 0xd8, 0xee, 0xd8, 0x83, 0x6d, 0xb8, 0x1d, 0x5a, - 0x63, 0xbb, 0x2b, 0x6b, 0xa0, 0x92, 0x1d, 0x8e, 0x1d, 0xc0, 0x13, 0xe2, 0x22, 0xf7, 0x80, 0xb8, - 0x98, 0x7a, 0xa8, 0xb8, 0xd8, 0x80, 0xf9, 0x83, 0x8c, 0xcb, 0xe0, 0xf8, 0x1f, 0x98, 0x12, 0x9b, - 0x12, 0xa7, 0xc0, 0x49, 0xfb, 0x16, 0xbb, 0xa8, 0xbf, 0x4b, 0xc1, 0xbc, 0xcc, 0x4e, 0x9f, 0x8c, - 0xc7, 0x74, 0x8c, 0xe7, 0xec, 0xc3, 0xf0, 0xfc, 0x90, 0xfb, 0xa7, 0x56, 0x61, 0xe1, 0x1e, 0x1e, - 0x1f, 0xe1, 0x61, 0xfd, 0x50, 0x81, 0xe9, 0x75, 0xda, 0x77, 0xbc, 0xc7, 0x74, 0x17, 0xc6, 0xc8, - 0xcd, 0x3c, 0x54, 0x10, 0x9f, 0x83, 0x92, 0xc4, 0x2b, 0xd9, 0x3a, 0xcc, 0xb6, 0x32, 0x89, 0xed, - 0xbf, 0x28, 0x50, 0xaa, 0xfa, 0x83, 0x81, 0x13, 0x3d, 0xa6, 0x4c, 0x1d, 0xc6, 0x99, 0x99, 0x84, - 0x13, 0x41, 0x39, 0x86, 0x29, 0x08, 0x52, 0xff, 0xaa, 0xc0, 0x0c, 0xf1, 0x5d, 0x77, 0xcb, 0xee, - 0xee, 0x3c, 0xd9, 0xd8, 0x31, 0xa0, 0x11, 0x50, 0x89, 0xfe, 0x1f, 0x0a, 0x94, 0x5b, 0x01, 0x1d, - 0xda, 0x01, 0x7d, 0xa2, 0xc1, 0xb3, 0x4a, 0xb8, 0x17, 0xc9, 0x1a, 0xa2, 0x40, 0x78, 0x5b, 0x9d, - 0x85, 0x99, 0x04, 0xbb, 0xe4, 0xe3, 0x8f, 0x0a, 0x2c, 0x88, 0x00, 0x91, 0x96, 0xde, 0x63, 0x4a, - 0x4b, 0x8c, 0x37, 0x33, 0x86, 0xb7, 0x02, 0x47, 0xef, 0xc5, 0x26, 0x61, 0xbf, 0x95, 0x82, 0x63, - 0x71, 0x6c, 0x3c, 0xe6, 0xc0, 0xff, 0x8d, 0x78, 0x58, 0x84, 0xca, 0x61, 0x12, 0x24, 0x43, 0xef, - 0xa4, 0xa0, 0x52, 0x0d, 0xa8, 0x1d, 0xd1, 0xb1, 0x5a, 0xe4, 0xc9, 0x89, 0x0d, 0xfc, 0x32, 0x4c, - 0x0f, 0xed, 0x20, 0x72, 0xba, 0xce, 0xd0, 0x66, 0x6f, 0x7b, 0x59, 0x5e, 0xea, 0xdc, 0x33, 0xc0, - 0x01, 0x17, 0xf5, 0x04, 0x1c, 0x9f, 0xc0, 0x88, 0xe4, 0xeb, 0x9f, 0x0a, 0xe0, 0x76, 0x64, 0x07, - 0xd1, 0x27, 0xe0, 0x54, 0x99, 0x18, 0x4c, 0x0b, 0x30, 0x77, 0x00, 0xff, 0x38, 0x2f, 0x34, 0xfa, - 0x44, 0x9c, 0x38, 0x1f, 0xc9, 0xcb, 0x38, 0x7e, 0xc9, 0xcb, 0x9f, 0x15, 0x58, 0xac, 0xfa, 0xe2, - 0xfb, 0xde, 0x13, 0xf9, 0x84, 0xa9, 0x4f, 0xc3, 0x89, 0x89, 0x00, 0x25, 0x01, 0x7f, 0x52, 0xe0, - 0x28, 0xa1, 0x76, 0xef, 0xc9, 0x04, 0x7f, 0x05, 0x8e, 0x1d, 0x02, 0x27, 0x2b, 0xd4, 0x73, 0x90, - 0x1f, 0xd0, 0xc8, 0xee, 0xd9, 0x91, 0x2d, 0x21, 0x2d, 0xc6, 0xe3, 0x8e, 0xbc, 0x1b, 0xd2, 0x83, - 0x24, 0xbe, 0xea, 0x07, 0x29, 0x98, 0xe3, 0xb5, 0xee, 0xa7, 0x2f, 0x5a, 0x93, 0xdf, 0x05, 0xde, - 0x51, 0x60, 0xfe, 0x20, 0x41, 0xc9, 0x3b, 0xc1, 0x7f, 0xfa, 0x7b, 0xc5, 0x84, 0x84, 0x90, 0x9e, - 0x54, 0x82, 0xfe, 0x3e, 0x05, 0x95, 0xf1, 0x25, 0x7d, 0xfa, 0x6d, 0xe3, 0xe0, 0xb7, 0x8d, 0x8f, - 0xfd, 0x31, 0xeb, 0x5d, 0x05, 0x8e, 0x4f, 0x20, 0xf4, 0xe3, 0x6d, 0xf4, 0xd8, 0x17, 0x8e, 0xd4, - 0x03, 0xbf, 0x70, 0x3c, 0xec, 0x56, 0xff, 0x41, 0x81, 0xf9, 0x86, 0xf8, 0xb0, 0x2c, 0xde, 0xe3, - 0x1f, 0xdf, 0x6c, 0xc6, 0xbf, 0x1d, 0x67, 0x46, 0x7f, 0x4e, 0xd4, 0x2a, 0x2c, 0xdc, 0x03, 0xed, - 0x11, 0xbe, 0x4d, 0xfc, 0x5d, 0x81, 0x59, 0x39, 0x8a, 0xf6, 0xd8, 0x16, 0x02, 0x13, 0xd8, 0xc1, - 0xcf, 0x40, 0xda, 0xe9, 0xc5, 0x15, 0xe4, 0xc1, 0x1f, 0xc3, 0xcc, 0xa0, 0x5e, 0x00, 0x3c, 0x8e, - 0xfb, 0x11, 0xa8, 0xe3, 0xb5, 0x15, 0x23, 0xfe, 0x0d, 0x6a, 0xbb, 0x51, 0x9c, 0x40, 0xd4, 0x9f, - 0xa7, 0xa0, 0x44, 0x98, 0xc6, 0x19, 0xd0, 0x76, 0x64, 0x47, 0x21, 0x7e, 0x0e, 0xa6, 0xb7, 0xb9, - 0x8b, 0x35, 0x7a, 0x0e, 0x0a, 0xa4, 0x28, 0x74, 0xe2, 0xe3, 0xed, 0x1a, 0x2c, 0x84, 0xb4, 0xeb, - 0x7b, 0xbd, 0xd0, 0xda, 0xa2, 0xdb, 0x8e, 0xd7, 0xb3, 0x06, 0x76, 0x18, 0xd1, 0x80, 0x33, 0x56, - 0x22, 0x73, 0xd2, 0xb8, 0xce, 0x6d, 0x0d, 0x6e, 0xc2, 0xa7, 0x61, 0x7e, 0xcb, 0xf1, 0x5c, 0xbf, - 0x6f, 0x0d, 0x5d, 0x7b, 0x9f, 0x06, 0xa1, 0xd5, 0xf5, 0x77, 0x3d, 0x41, 0x55, 0x96, 0x60, 0x61, - 0x6b, 0x09, 0x53, 0x95, 0x59, 0xf0, 0x0d, 0x58, 0x99, 0x38, 0x8b, 0x75, 0xd3, 0x71, 0x23, 0x1a, - 0xd0, 0x9e, 0x15, 0xd0, 0xa1, 0xeb, 0x74, 0xc5, 0x5f, 0x56, 0x51, 0x4c, 0xbd, 0x38, 0x61, 0xea, - 0x4d, 0xe9, 0x4e, 0x46, 0xde, 0xf8, 0x04, 0x14, 0xba, 0xc3, 0x5d, 0x6b, 0x97, 0xff, 0xd2, 0x61, - 0x69, 0x45, 0x21, 0xf9, 0xee, 0x70, 0xb7, 0xc3, 0x64, 0x8c, 0x20, 0x7d, 0x6b, 0x28, 0xb2, 0x89, - 0x42, 0x58, 0x53, 0xfd, 0x50, 0x81, 0xb2, 0xd6, 0xef, 0x07, 0xb4, 0x6f, 0x47, 0x92, 0xa6, 0xd3, - 0x30, 0x2f, 0x28, 0xd9, 0xb7, 0xe4, 0x5d, 0x0a, 0x81, 0x47, 0x11, 0x78, 0xa4, 0x4d, 0xdc, 0xa4, - 0x10, 0x78, 0xce, 0xc2, 0xd1, 0x5d, 0x6f, 0x62, 0x9f, 0x14, 0xef, 0x33, 0x9f, 0x58, 0xc7, 0x7b, - 0xfd, 0x3f, 0x1c, 0x9f, 0xcc, 0xc2, 0xc0, 0x11, 0x37, 0x1d, 0x4a, 0xe4, 0xe8, 0x04, 0xd0, 0x0d, - 0xc7, 0xbb, 0x4f, 0x57, 0xfb, 0x0e, 0xe7, 0xeb, 0x23, 0xba, 0xda, 0x77, 0xd4, 0x5f, 0x26, 0x9f, - 0x64, 0xe3, 0x70, 0x49, 0xd2, 0x63, 0x1c, 0xe3, 0xca, 0xfd, 0x62, 0xbc, 0x02, 0x53, 0x21, 0x0d, - 0xf6, 0x1c, 0xaf, 0xcf, 0xc1, 0xe5, 0x49, 0x2c, 0xe2, 0x36, 0xbc, 0x28, 0xb1, 0xd3, 0x3b, 0x11, - 0x0d, 0x3c, 0xdb, 0x75, 0xf7, 0x2d, 0xf1, 0xe6, 0xe8, 0x45, 0xb4, 0x67, 0x8d, 0x6e, 0x7e, 0x88, - 0x14, 0xf9, 0xbc, 0xf0, 0xd6, 0x13, 0x67, 0x92, 0xf8, 0x9a, 0xc9, 0x9d, 0x90, 0xd7, 0xa0, 0x1c, - 0xc8, 0x20, 0xb6, 0x42, 0xb6, 0x3d, 0xb2, 0x32, 0x98, 0x8f, 0xff, 0x29, 0x8d, 0x47, 0x38, 0x29, - 0x05, 0x07, 0x02, 0xfe, 0x3c, 0x4c, 0xcb, 0x15, 0xd9, 0xae, 0x63, 0x8f, 0x2a, 0x85, 0x7b, 0xae, - 0xc3, 0x68, 0xcc, 0x48, 0xe4, 0xc5, 0x19, 0x2e, 0x5c, 0xca, 0xe4, 0x73, 0x68, 0x4a, 0xfd, 0x95, - 0x02, 0x73, 0x13, 0xca, 0xae, 0xa4, 0xa6, 0x53, 0xc6, 0x5e, 0x19, 0xff, 0x17, 0xb2, 0xfc, 0x77, - 0x9f, 0xfc, 0x81, 0x7c, 0xec, 0x70, 0xd5, 0xc6, 0x7f, 0xcd, 0x11, 0xe1, 0xc5, 0x9e, 0x45, 0x8e, - 0xa9, 0xcb, 0xdf, 0x19, 0xe3, 0x53, 0xa3, 0xc8, 0x74, 0xe2, 0x35, 0xf2, 0xf0, 0x4b, 0x68, 0xe6, - 0x81, 0x2f, 0xa1, 0x2b, 0xdf, 0x4b, 0x43, 0xa1, 0xb1, 0xdf, 0xbe, 0xe5, 0x6e, 0xba, 0x76, 0x9f, - 0xff, 0x3b, 0x6b, 0xb4, 0xcc, 0xeb, 0xe8, 0x08, 0x9e, 0x85, 0x92, 0xd1, 0x34, 0x2d, 0xa3, 0x53, - 0xaf, 0x5b, 0x9b, 0x75, 0xed, 0x22, 0x52, 0x30, 0x82, 0xe9, 0x16, 0xa9, 0x59, 0x97, 0xf5, 0xeb, - 0x42, 0x93, 0xc2, 0x73, 0x30, 0xd3, 0x31, 0x6a, 0x57, 0x3a, 0xfa, 0x48, 0x99, 0xc1, 0x0b, 0x30, - 0xdb, 0xe8, 0xd4, 0xcd, 0x5a, 0xab, 0x3e, 0xa6, 0xce, 0xe3, 0x12, 0x14, 0xd6, 0xeb, 0xcd, 0x75, - 0x21, 0x22, 0x36, 0x7e, 0xc7, 0x68, 0xd7, 0x2e, 0x1a, 0xfa, 0x86, 0x50, 0x2d, 0x31, 0xd5, 0x0d, - 0x9d, 0x34, 0x37, 0x6b, 0xf1, 0x94, 0x17, 0x30, 0x82, 0xe2, 0x7a, 0xcd, 0xd0, 0x88, 0x1c, 0xe5, - 0xae, 0x82, 0xcb, 0x50, 0xd0, 0x8d, 0x4e, 0x43, 0xca, 0x29, 0x5c, 0x81, 0x39, 0xad, 0x63, 0x36, - 0xad, 0x9a, 0x51, 0x25, 0x7a, 0x43, 0x37, 0x4c, 0x69, 0xc9, 0xe0, 0x39, 0x28, 0x9b, 0xb5, 0x86, - 0xde, 0x36, 0xb5, 0x46, 0x4b, 0x2a, 0xd9, 0x2a, 0xf2, 0x6d, 0x3d, 0xf6, 0x41, 0x78, 0x11, 0x16, - 0x8c, 0xa6, 0x25, 0xef, 0x21, 0x58, 0x57, 0xb5, 0x7a, 0x47, 0x97, 0xb6, 0x25, 0x7c, 0x0c, 0x70, - 0xd3, 0xb0, 0x3a, 0xad, 0x0d, 0xcd, 0xd4, 0x2d, 0xa3, 0x79, 0x4d, 0x1a, 0x2e, 0xe0, 0x32, 0xe4, - 0x47, 0x2b, 0xb8, 0xcb, 0x58, 0x28, 0xb5, 0x34, 0x62, 0x8e, 0xc0, 0xde, 0xbd, 0xcb, 0xc8, 0x82, - 0x8b, 0xa4, 0xd9, 0x69, 0x8d, 0xdc, 0x66, 0xa1, 0x28, 0xc9, 0x92, 0xaa, 0x0c, 0x53, 0xad, 0xd7, - 0x8c, 0x6a, 0xb2, 0xbe, 0xbb, 0xf9, 0xc5, 0x14, 0x52, 0x56, 0x76, 0x20, 0xc3, 0xb7, 0x23, 0x0f, - 0x19, 0xa3, 0x69, 0xe8, 0xe8, 0x08, 0x9e, 0x01, 0xa8, 0xb5, 0x6b, 0x86, 0xa9, 0x5f, 0x24, 0x5a, - 0x9d, 0xc1, 0xe6, 0x8a, 0x98, 0x40, 0x86, 0x76, 0x1a, 0xa6, 0x6a, 0xed, 0xcd, 0x7a, 0x53, 0x33, - 0x25, 0xcc, 0x5a, 0xfb, 0x4a, 0xa7, 0x69, 0x32, 0x23, 0xc2, 0x45, 0xc8, 0xd5, 0xda, 0xa6, 0xfe, - 0xa6, 0xc9, 0x70, 0x71, 0x9b, 0x60, 0x15, 0xdd, 0xbd, 0xb0, 0xf2, 0x5e, 0x1a, 0x32, 0xfc, 0x4a, - 0x57, 0x09, 0x0a, 0x7c, 0xb7, 0xcd, 0xeb, 0x2d, 0x36, 0x65, 0x01, 0x32, 0x35, 0xc3, 0x3c, 0x8f, - 0xbe, 0x90, 0xc2, 0x00, 0xd9, 0x0e, 0x6f, 0x7f, 0x31, 0xc7, 0xda, 0x35, 0xc3, 0x7c, 0xf9, 0x1c, - 0x7a, 0x2b, 0xc5, 0x86, 0xed, 0x08, 0xe1, 0x4b, 0xb1, 0x61, 0xed, 0x2c, 0x7a, 0x3b, 0x31, 0xac, - 0x9d, 0x45, 0x5f, 0x8e, 0x0d, 0x67, 0xd6, 0xd0, 0x57, 0x12, 0xc3, 0x99, 0x35, 0xf4, 0xd5, 0xd8, - 0x70, 0xee, 0x2c, 0xfa, 0x5a, 0x62, 0x38, 0x77, 0x16, 0x7d, 0x3d, 0xc7, 0xb0, 0x70, 0x24, 0x67, - 0xd6, 0xd0, 0x37, 0xf2, 0x89, 0x74, 0xee, 0x2c, 0xfa, 0x66, 0x9e, 0xed, 0x7f, 0xb2, 0xab, 0xe8, - 0x5b, 0x88, 0x2d, 0x93, 0x6d, 0x10, 0xfa, 0x36, 0x6f, 0x32, 0x13, 0xfa, 0x0e, 0x62, 0x18, 0x99, - 0x96, 0x8b, 0xef, 0x70, 0xcb, 0x75, 0x5d, 0x23, 0xe8, 0xbb, 0x39, 0x71, 0xed, 0xa4, 0x5a, 0x6b, - 0x68, 0x75, 0x84, 0x79, 0x0f, 0xc6, 0xca, 0xf7, 0x4f, 0xb3, 0x26, 0x0b, 0x4f, 0xf4, 0x83, 0x16, - 0x9b, 0xf0, 0xaa, 0x46, 0xaa, 0x6f, 0x68, 0x04, 0xfd, 0xf0, 0x34, 0x9b, 0xf0, 0xaa, 0x46, 0x24, - 0x5f, 0x3f, 0x6a, 0x31, 0x47, 0x6e, 0x7a, 0xf7, 0x34, 0x5b, 0xb4, 0xd4, 0xff, 0xb8, 0x85, 0xf3, - 0x90, 0x5e, 0xaf, 0x99, 0xe8, 0x3d, 0x3e, 0x1b, 0x0b, 0x51, 0xf4, 0x13, 0xc4, 0x94, 0x6d, 0xdd, - 0x44, 0xef, 0x33, 0x65, 0xd6, 0xec, 0xb4, 0xea, 0x3a, 0x7a, 0x8a, 0x2d, 0xee, 0xa2, 0xde, 0x6c, - 0xe8, 0x26, 0xb9, 0x8e, 0x7e, 0xca, 0xdd, 0x2f, 0xb5, 0x9b, 0x06, 0xfa, 0x00, 0xe1, 0x32, 0x80, - 0xfe, 0x66, 0x8b, 0xe8, 0xed, 0x76, 0xad, 0x69, 0xa0, 0x67, 0x57, 0x36, 0x01, 0xdd, 0x9b, 0x0e, - 0x18, 0x80, 0x8e, 0x71, 0xd9, 0x68, 0x5e, 0x33, 0xd0, 0x11, 0x26, 0xb4, 0x88, 0xde, 0xd2, 0x88, - 0x8e, 0x14, 0x0c, 0x90, 0x93, 0x97, 0x59, 0x52, 0x78, 0x1a, 0xf2, 0xa4, 0x59, 0xaf, 0xaf, 0x6b, - 0xd5, 0xcb, 0x28, 0xbd, 0xfe, 0x0a, 0xcc, 0x38, 0xfe, 0xea, 0x9e, 0x13, 0xd1, 0x30, 0x14, 0x97, - 0x06, 0x6f, 0xa8, 0x52, 0x72, 0xfc, 0x53, 0xa2, 0x75, 0xaa, 0xef, 0x9f, 0xda, 0x8b, 0x4e, 0x71, - 0xeb, 0x29, 0x9e, 0x31, 0xb6, 0x72, 0x5c, 0x38, 0xf3, 0xaf, 0x00, 0x00, 0x00, 0xff, 0xff, 0x69, - 0x36, 0x21, 0xf2, 0x92, 0x28, 0x00, 0x00, + // 2996 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xec, 0x5a, 0x49, 0x70, 0x1b, 0xc7, + 0xb9, 0xd6, 0x60, 0x23, 0xf0, 0x83, 0x00, 0x9b, 0x4d, 0x52, 0x82, 0x28, 0x2f, 0xf4, 0xd8, 0xb2, + 0xf9, 0xf8, 0xde, 0xa3, 0x64, 0x4a, 0x56, 0x14, 0xdb, 0x49, 0x34, 0x04, 0x87, 0x32, 0x24, 0x60, + 0x00, 0x35, 0x06, 0x92, 0xa5, 0x4a, 0xd5, 0xd4, 0x10, 0x68, 0x81, 0x53, 0x1c, 0x60, 0xa0, 0x99, + 0x21, 0x25, 0xde, 0x94, 0x38, 0xce, 0xbe, 0x38, 0xab, 0xe3, 0xb8, 0xe2, 0x4a, 0x55, 0x0e, 0xa9, + 0x5c, 0x72, 0xce, 0x31, 0x95, 0x43, 0x0e, 0x39, 0xa4, 0x2a, 0xc7, 0x24, 0x87, 0x9c, 0x52, 0xb9, + 0xb9, 0x72, 0xca, 0x21, 0x87, 0x54, 0xaa, 0x97, 0x19, 0x00, 0x24, 0x2c, 0xc9, 0x4a, 0x72, 0x90, + 0xec, 0x5b, 0xff, 0x4b, 0x2f, 0xdf, 0xd7, 0x7f, 0xff, 0xbd, 0xcc, 0x40, 0xfe, 0xd6, 0x2e, 0xf5, + 0xf7, 0x57, 0x07, 0xbe, 0x17, 0x7a, 0x38, 0xcd, 0x85, 0xc5, 0x62, 0xe8, 0x0d, 0xbc, 0x8e, 0x1d, + 0xda, 0x42, 0xbd, 0x98, 0xdf, 0x0b, 0xfd, 0x41, 0x5b, 0x08, 0xea, 0x9b, 0x0a, 0x64, 0x4c, 0xdb, + 0xef, 0xd2, 0x10, 0x2f, 0x42, 0x76, 0x87, 0xee, 0x07, 0x03, 0xbb, 0x4d, 0x4b, 0xca, 0x92, 0xb2, + 0x9c, 0x23, 0xb1, 0x8c, 0xe7, 0x21, 0x1d, 0x6c, 0xdb, 0x7e, 0xa7, 0x94, 0xe0, 0x06, 0x21, 0xe0, + 0x97, 0x20, 0x1f, 0xda, 0x5b, 0x2e, 0x0d, 0xad, 0x70, 0x7f, 0x40, 0x4b, 0xc9, 0x25, 0x65, 0xb9, + 0xb8, 0x36, 0xbf, 0x1a, 0xf7, 0x67, 0x72, 0xa3, 0xb9, 0x3f, 0xa0, 0x04, 0xc2, 0xb8, 0x8c, 0x31, + 0xa4, 0xda, 0xd4, 0x75, 0x4b, 0x29, 0xde, 0x16, 0x2f, 0xab, 0x1b, 0x50, 0xbc, 0x6a, 0x5e, 0xb4, + 0x43, 0x5a, 0xb6, 0x5d, 0x97, 0xfa, 0x95, 0x0d, 0x36, 0x9c, 0xdd, 0x80, 0xfa, 0x7d, 0xbb, 0x17, + 0x0f, 0x27, 0x92, 0xf1, 0x51, 0xc8, 0x74, 0x7d, 0x6f, 0x77, 0x10, 0x94, 0x12, 0x4b, 0xc9, 0xe5, + 0x1c, 0x91, 0x92, 0xfa, 0x59, 0x00, 0x7d, 0x8f, 0xf6, 0x43, 0xd3, 0xdb, 0xa1, 0x7d, 0xfc, 0x04, + 0xe4, 0x42, 0xa7, 0x47, 0x83, 0xd0, 0xee, 0x0d, 0x78, 0x13, 0x49, 0x32, 0x54, 0x7c, 0x00, 0xa4, + 0x45, 0xc8, 0x0e, 0xbc, 0xc0, 0x09, 0x1d, 0xaf, 0xcf, 0xf1, 0xe4, 0x48, 0x2c, 0xab, 0x9f, 0x86, + 0xf4, 0x55, 0xdb, 0xdd, 0xa5, 0xf8, 0x69, 0x48, 0x71, 0xc0, 0x0a, 0x07, 0x9c, 0x5f, 0x15, 0xa4, + 0x73, 0x9c, 0xdc, 0xc0, 0xda, 0xde, 0x63, 0x9e, 0xbc, 0xed, 0x69, 0x22, 0x04, 0x75, 0x07, 0xa6, + 0xd7, 0x9d, 0x7e, 0xe7, 0xaa, 0xed, 0x3b, 0x8c, 0x8c, 0x87, 0x6c, 0x06, 0x3f, 0x07, 0x19, 0x5e, + 0x08, 0x4a, 0xc9, 0xa5, 0xe4, 0x72, 0x7e, 0x6d, 0x5a, 0x56, 0xe4, 0x63, 0x23, 0xd2, 0xa6, 0xfe, + 0x5a, 0x01, 0x58, 0xf7, 0x76, 0xfb, 0x9d, 0x2b, 0xcc, 0x88, 0x11, 0x24, 0x83, 0x5b, 0xae, 0x24, + 0x92, 0x15, 0xf1, 0x65, 0x28, 0x6e, 0x39, 0xfd, 0x8e, 0xb5, 0x27, 0x87, 0x23, 0xb8, 0xcc, 0xaf, + 0x3d, 0x27, 0x9b, 0x1b, 0x56, 0x5e, 0x1d, 0x1d, 0x75, 0xa0, 0xf7, 0x43, 0x7f, 0x9f, 0x14, 0xb6, + 0x46, 0x75, 0x8b, 0x2d, 0xc0, 0x87, 0x9d, 0x58, 0xa7, 0x3b, 0x74, 0x3f, 0xea, 0x74, 0x87, 0xee, + 0xe3, 0xff, 0x19, 0x45, 0x94, 0x5f, 0x9b, 0x8b, 0xfa, 0x1a, 0xa9, 0x2b, 0x61, 0xbe, 0x9c, 0x38, + 0xaf, 0xa8, 0xbf, 0x4c, 0x43, 0x51, 0xbf, 0x43, 0xdb, 0xbb, 0x21, 0xad, 0x0f, 0xd8, 0x1c, 0x04, + 0xb8, 0x06, 0x33, 0x4e, 0xbf, 0xed, 0xee, 0x76, 0x68, 0xc7, 0xba, 0xe9, 0x50, 0xb7, 0x13, 0xf0, + 0x38, 0x2a, 0xc6, 0xe3, 0x1e, 0xf7, 0x5f, 0xad, 0x48, 0xe7, 0x4d, 0xee, 0x4b, 0x8a, 0xce, 0x98, + 0x8c, 0x57, 0x60, 0xb6, 0xed, 0x3a, 0xb4, 0x1f, 0x5a, 0x37, 0x19, 0x5e, 0xcb, 0xf7, 0x6e, 0x07, + 0xa5, 0xf4, 0x92, 0xb2, 0x9c, 0x25, 0x33, 0xc2, 0xb0, 0xc9, 0xf4, 0xc4, 0xbb, 0x1d, 0xe0, 0x97, + 0x21, 0x7b, 0xdb, 0xf3, 0x77, 0x5c, 0xcf, 0xee, 0x94, 0x32, 0xbc, 0xcf, 0xa7, 0x26, 0xf7, 0x79, + 0x4d, 0x7a, 0x91, 0xd8, 0x1f, 0x2f, 0x03, 0x0a, 0x6e, 0xb9, 0x56, 0x40, 0x5d, 0xda, 0x0e, 0x2d, + 0xd7, 0xe9, 0x39, 0x61, 0x29, 0xcb, 0x43, 0xb2, 0x18, 0xdc, 0x72, 0x9b, 0x5c, 0x5d, 0x65, 0x5a, + 0x6c, 0xc1, 0x42, 0xe8, 0xdb, 0xfd, 0xc0, 0x6e, 0xb3, 0xc6, 0x2c, 0x27, 0xf0, 0x5c, 0x9b, 0x87, + 0x63, 0x8e, 0x77, 0xb9, 0x32, 0xb9, 0x4b, 0x73, 0x58, 0xa5, 0x12, 0xd5, 0x20, 0xf3, 0xe1, 0x04, + 0x2d, 0x7e, 0x11, 0x16, 0x82, 0x1d, 0x67, 0x60, 0xf1, 0x76, 0xac, 0x81, 0x6b, 0xf7, 0xad, 0xb6, + 0xdd, 0xde, 0xa6, 0x25, 0xe0, 0xb0, 0x31, 0x33, 0xf2, 0x79, 0x6f, 0xb8, 0x76, 0xbf, 0xcc, 0x2c, + 0xea, 0x2b, 0x50, 0x1c, 0xe7, 0x11, 0xcf, 0x42, 0xc1, 0xbc, 0xde, 0xd0, 0x2d, 0xcd, 0xd8, 0xb0, + 0x0c, 0xad, 0xa6, 0xa3, 0x23, 0xb8, 0x00, 0x39, 0xae, 0xaa, 0x1b, 0xd5, 0xeb, 0x48, 0xc1, 0x53, + 0x90, 0xd4, 0xaa, 0x55, 0x94, 0x50, 0xcf, 0x43, 0x36, 0x22, 0x04, 0xcf, 0x40, 0xbe, 0x65, 0x34, + 0x1b, 0x7a, 0xb9, 0xb2, 0x59, 0xd1, 0x37, 0xd0, 0x11, 0x9c, 0x85, 0x54, 0xbd, 0x6a, 0x36, 0x90, + 0x22, 0x4a, 0x5a, 0x03, 0x25, 0x58, 0xcd, 0x8d, 0x75, 0x0d, 0x25, 0xd5, 0x9f, 0x29, 0x30, 0x3f, + 0x09, 0x18, 0xce, 0xc3, 0xd4, 0x86, 0xbe, 0xa9, 0xb5, 0xaa, 0x26, 0x3a, 0x82, 0xe7, 0x60, 0x86, + 0xe8, 0x0d, 0x5d, 0x33, 0xb5, 0xf5, 0xaa, 0x6e, 0x11, 0x5d, 0xdb, 0x40, 0x0a, 0xc6, 0x50, 0x64, + 0x25, 0xab, 0x5c, 0xaf, 0xd5, 0x2a, 0xa6, 0xa9, 0x6f, 0xa0, 0x04, 0x9e, 0x07, 0xc4, 0x75, 0x2d, + 0x63, 0xa8, 0x4d, 0x62, 0x04, 0xd3, 0x4d, 0x9d, 0x54, 0xb4, 0x6a, 0xe5, 0x06, 0x6b, 0x00, 0xa5, + 0xf0, 0x33, 0xf0, 0x64, 0xb9, 0x6e, 0x34, 0x2b, 0x4d, 0x53, 0x37, 0x4c, 0xab, 0x69, 0x68, 0x8d, + 0xe6, 0x6b, 0x75, 0x93, 0xb7, 0x2c, 0xc0, 0xa5, 0x71, 0x11, 0x40, 0x6b, 0x99, 0x75, 0xd1, 0x0e, + 0xca, 0x5c, 0x4a, 0x65, 0x15, 0x94, 0xb8, 0x94, 0xca, 0x26, 0x50, 0xf2, 0x52, 0x2a, 0x9b, 0x44, + 0x29, 0xf5, 0xed, 0x04, 0xa4, 0x39, 0x57, 0x2c, 0xdd, 0x8d, 0x24, 0x31, 0x5e, 0x8e, 0x97, 0x7e, + 0xe2, 0x1e, 0x4b, 0x9f, 0x67, 0x4c, 0x99, 0x84, 0x84, 0x80, 0x4f, 0x40, 0xce, 0xf3, 0xbb, 0x96, + 0xb0, 0x88, 0xf4, 0x99, 0xf5, 0xfc, 0x2e, 0xcf, 0xb3, 0x2c, 0x75, 0xb1, 0xac, 0xbb, 0x65, 0x07, + 0x94, 0x47, 0x70, 0x8e, 0xc4, 0x32, 0x3e, 0x0e, 0xcc, 0xcf, 0xe2, 0xe3, 0xc8, 0x70, 0xdb, 0x94, + 0xe7, 0x77, 0x0d, 0x36, 0x94, 0x67, 0xa1, 0xd0, 0xf6, 0xdc, 0xdd, 0x5e, 0xdf, 0x72, 0x69, 0xbf, + 0x1b, 0x6e, 0x97, 0xa6, 0x96, 0x94, 0xe5, 0x02, 0x99, 0x16, 0xca, 0x2a, 0xd7, 0xe1, 0x12, 0x4c, + 0xb5, 0xb7, 0x6d, 0x3f, 0xa0, 0x22, 0x6a, 0x0b, 0x24, 0x12, 0x79, 0xaf, 0xb4, 0xed, 0xf4, 0x6c, + 0x37, 0xe0, 0x11, 0x5a, 0x20, 0xb1, 0xcc, 0x40, 0xdc, 0x74, 0xed, 0x6e, 0xc0, 0x23, 0xab, 0x40, + 0x84, 0xa0, 0x7e, 0x02, 0x92, 0xc4, 0xbb, 0xcd, 0x9a, 0x14, 0x1d, 0x06, 0x25, 0x65, 0x29, 0xb9, + 0x8c, 0x49, 0x24, 0xb2, 0xec, 0x2e, 0x13, 0x9c, 0xc8, 0x7b, 0x51, 0x4a, 0x7b, 0x57, 0x81, 0x3c, + 0x0f, 0x4c, 0x42, 0x83, 0x5d, 0x37, 0x64, 0x89, 0x50, 0x66, 0x00, 0x65, 0x2c, 0x11, 0x72, 0xda, + 0x89, 0xb4, 0x31, 0x7c, 0x6c, 0x51, 0x5b, 0xf6, 0xcd, 0x9b, 0xb4, 0x1d, 0x52, 0x91, 0xef, 0x53, + 0x64, 0x9a, 0x29, 0x35, 0xa9, 0x63, 0xc4, 0x3a, 0xfd, 0x80, 0xfa, 0xa1, 0xe5, 0x74, 0x38, 0xe5, + 0x29, 0x92, 0x15, 0x8a, 0x4a, 0x07, 0x3f, 0x05, 0x29, 0x9e, 0x16, 0x52, 0xbc, 0x17, 0x90, 0xbd, + 0x10, 0xef, 0x36, 0xe1, 0xfa, 0x4b, 0xa9, 0x6c, 0x1a, 0x65, 0xd4, 0x57, 0x61, 0x9a, 0x0f, 0xee, + 0x9a, 0xed, 0xf7, 0x9d, 0x7e, 0x97, 0xef, 0x72, 0x5e, 0x47, 0x4c, 0x7b, 0x81, 0xf0, 0x32, 0xc3, + 0xdc, 0xa3, 0x41, 0x60, 0x77, 0xa9, 0xdc, 0x75, 0x22, 0x51, 0xfd, 0x49, 0x12, 0xf2, 0xcd, 0xd0, + 0xa7, 0x76, 0x8f, 0x6f, 0x60, 0xf8, 0x55, 0x80, 0x20, 0xb4, 0x43, 0xda, 0xa3, 0xfd, 0x30, 0xc2, + 0xf7, 0x84, 0xec, 0x79, 0xc4, 0x6f, 0xb5, 0x19, 0x39, 0x91, 0x11, 0x7f, 0xbc, 0x06, 0x79, 0xca, + 0xcc, 0x56, 0xc8, 0x36, 0x42, 0x99, 0x6c, 0x67, 0xa3, 0xcc, 0x11, 0xef, 0x90, 0x04, 0x68, 0x5c, + 0x5e, 0x7c, 0x2f, 0x01, 0xb9, 0xb8, 0x35, 0xac, 0x41, 0xb6, 0x6d, 0x87, 0xb4, 0xeb, 0xf9, 0xfb, + 0x72, 0x7f, 0x3a, 0x79, 0xaf, 0xde, 0x57, 0xcb, 0xd2, 0x99, 0xc4, 0xd5, 0xf0, 0x93, 0x20, 0x36, + 0x7d, 0x11, 0x75, 0x02, 0x6f, 0x8e, 0x6b, 0x78, 0xdc, 0xbd, 0x0c, 0x78, 0xe0, 0x3b, 0x3d, 0xdb, + 0xdf, 0xb7, 0x76, 0xe8, 0x7e, 0x94, 0xcb, 0x93, 0x13, 0x66, 0x12, 0x49, 0xbf, 0xcb, 0x74, 0x5f, + 0x66, 0x9f, 0xf3, 0xe3, 0x75, 0x65, 0xb4, 0x1c, 0x9e, 0x9f, 0x91, 0x9a, 0x7c, 0x77, 0x0c, 0xa2, + 0x7d, 0x30, 0xcd, 0x03, 0x8b, 0x15, 0xd5, 0x17, 0x20, 0x1b, 0x0d, 0x1e, 0xe7, 0x20, 0xad, 0xfb, + 0xbe, 0xe7, 0xa3, 0x23, 0x3c, 0x09, 0xd5, 0xaa, 0x22, 0x8f, 0x6d, 0x6c, 0xb0, 0x3c, 0xf6, 0xab, + 0x44, 0xbc, 0x19, 0x11, 0x7a, 0x6b, 0x97, 0x06, 0x21, 0xfe, 0x0c, 0xcc, 0x51, 0x1e, 0x42, 0xce, + 0x1e, 0xb5, 0xda, 0xfc, 0xe4, 0xc2, 0x02, 0x48, 0xe1, 0x7c, 0xcf, 0xac, 0x8a, 0x83, 0x56, 0x74, + 0xa2, 0x21, 0xb3, 0xb1, 0xaf, 0x54, 0x75, 0xb0, 0x0e, 0x73, 0x4e, 0xaf, 0x47, 0x3b, 0x8e, 0x1d, + 0x8e, 0x36, 0x20, 0x26, 0x6c, 0x21, 0xda, 0xd8, 0xc7, 0x0e, 0x46, 0x64, 0x36, 0xae, 0x11, 0x37, + 0x73, 0x12, 0x32, 0x21, 0x3f, 0xc4, 0xf1, 0xd8, 0xcd, 0xaf, 0x15, 0xa2, 0x84, 0xc2, 0x95, 0x44, + 0x1a, 0xf1, 0x0b, 0x20, 0x8e, 0x84, 0x3c, 0x75, 0x0c, 0x03, 0x62, 0xb8, 0xd3, 0x13, 0x61, 0xc7, + 0x27, 0xa1, 0x38, 0xb6, 0x07, 0x75, 0x38, 0x61, 0x49, 0x52, 0x18, 0xdd, 0x50, 0x3a, 0xf8, 0x14, + 0x4c, 0x79, 0x62, 0xff, 0xe1, 0x49, 0x65, 0x38, 0xe2, 0xf1, 0xcd, 0x89, 0x44, 0x5e, 0xea, 0xa7, + 0x60, 0x26, 0x66, 0x30, 0x18, 0x78, 0xfd, 0x80, 0xe2, 0x15, 0xc8, 0xf8, 0x7c, 0x39, 0x4b, 0xd6, + 0xb0, 0x6c, 0x62, 0x64, 0xa1, 0x13, 0xe9, 0xa1, 0x76, 0x60, 0x46, 0x68, 0xae, 0x39, 0xe1, 0x36, + 0x9f, 0x28, 0x7c, 0x12, 0xd2, 0x94, 0x15, 0x0e, 0x70, 0x4e, 0x1a, 0x65, 0x6e, 0x27, 0xc2, 0x3a, + 0xd2, 0x4b, 0xe2, 0xbe, 0xbd, 0xfc, 0x2d, 0x01, 0x73, 0x72, 0x94, 0xeb, 0x76, 0xd8, 0xde, 0x7e, + 0x44, 0x27, 0xfb, 0x7f, 0x61, 0x8a, 0xe9, 0x9d, 0x78, 0x61, 0x4c, 0x98, 0xee, 0xc8, 0x83, 0x4d, + 0xb8, 0x1d, 0x58, 0x23, 0xb3, 0x2b, 0xcf, 0x40, 0x05, 0x3b, 0x18, 0xd9, 0x80, 0x27, 0xc4, 0x45, + 0xe6, 0x3e, 0x71, 0x31, 0xf5, 0x40, 0x71, 0xb1, 0x01, 0xf3, 0xe3, 0x8c, 0xcb, 0xe0, 0xf8, 0x3f, + 0x98, 0x12, 0x93, 0x12, 0xa5, 0xc0, 0x49, 0xf3, 0x16, 0xb9, 0xa8, 0xbf, 0x49, 0xc0, 0xbc, 0xcc, + 0x4e, 0x1f, 0x8d, 0x65, 0x3a, 0xc2, 0x73, 0xfa, 0x41, 0x78, 0x7e, 0xc0, 0xf9, 0x53, 0xcb, 0xb0, + 0x70, 0x80, 0xc7, 0x87, 0x58, 0xac, 0xef, 0x2b, 0x30, 0xbd, 0x4e, 0xbb, 0x4e, 0xff, 0x11, 0x9d, + 0x85, 0x11, 0x72, 0x53, 0x0f, 0x14, 0xc4, 0x03, 0x28, 0x48, 0xbc, 0x92, 0xad, 0xc3, 0x6c, 0x2b, + 0x93, 0x56, 0xcb, 0x79, 0x98, 0x96, 0xb7, 0x68, 0xdb, 0x75, 0xec, 0x20, 0xc6, 0x73, 0xe0, 0x1a, + 0xad, 0x31, 0x23, 0x91, 0x17, 0x6e, 0x2e, 0xa8, 0x7f, 0x51, 0xa0, 0x50, 0xf6, 0x7a, 0x3d, 0x27, + 0x7c, 0x44, 0x39, 0x3e, 0xcc, 0x50, 0x6a, 0x52, 0x3c, 0x22, 0x28, 0x46, 0x30, 0x05, 0xb5, 0xea, + 0x5f, 0x15, 0x98, 0x21, 0x9e, 0xeb, 0x6e, 0xd9, 0xed, 0x9d, 0xc7, 0x1b, 0x3b, 0x06, 0x34, 0x04, + 0x2a, 0xd1, 0xff, 0x43, 0x81, 0x62, 0xc3, 0xa7, 0x03, 0xdb, 0xa7, 0x8f, 0x35, 0x78, 0x76, 0x86, + 0xee, 0x84, 0xf2, 0xf4, 0x91, 0x23, 0xbc, 0xac, 0xce, 0xc2, 0x4c, 0x8c, 0x5d, 0xf2, 0xf1, 0x47, + 0x05, 0x16, 0x44, 0x80, 0x48, 0x4b, 0xe7, 0x11, 0xa5, 0x25, 0xc2, 0x9b, 0x1a, 0xc1, 0x5b, 0x82, + 0xa3, 0x07, 0xb1, 0x49, 0xd8, 0x6f, 0x24, 0xe0, 0x58, 0x14, 0x1b, 0x8f, 0x38, 0xf0, 0x7f, 0x23, + 0x1e, 0x16, 0xa1, 0x74, 0x98, 0x04, 0xc9, 0xd0, 0x5b, 0x09, 0x28, 0x95, 0x7d, 0x6a, 0x87, 0x74, + 0xe4, 0x14, 0xf3, 0xf8, 0xc4, 0x06, 0x7e, 0x11, 0xa6, 0x07, 0xb6, 0x1f, 0x3a, 0x6d, 0x67, 0x60, + 0xb3, 0x7b, 0x62, 0x9a, 0x1f, 0x92, 0x0e, 0x34, 0x30, 0xe6, 0xa2, 0x9e, 0x80, 0xe3, 0x13, 0x18, + 0x91, 0x7c, 0xfd, 0x53, 0x01, 0xdc, 0x0c, 0x6d, 0x3f, 0xfc, 0x08, 0xec, 0x2a, 0x13, 0x83, 0x69, + 0x01, 0xe6, 0xc6, 0xf0, 0x8f, 0xf2, 0x42, 0xc3, 0x8f, 0xc4, 0x8e, 0xf3, 0x81, 0xbc, 0x8c, 0xe2, + 0x97, 0xbc, 0xfc, 0x59, 0x81, 0xc5, 0xb2, 0x27, 0x5e, 0x06, 0x1f, 0xcb, 0x15, 0xa6, 0x3e, 0x09, + 0x27, 0x26, 0x02, 0x94, 0x04, 0xfc, 0x49, 0x81, 0xa3, 0x84, 0xda, 0x9d, 0xc7, 0x13, 0xfc, 0x15, + 0x38, 0x76, 0x08, 0x9c, 0x3c, 0xdb, 0x9e, 0x83, 0x6c, 0x8f, 0x86, 0x36, 0x3b, 0x9f, 0x4a, 0x48, + 0x8b, 0x51, 0xbb, 0x43, 0xef, 0x9a, 0xf4, 0x20, 0xb1, 0xaf, 0xfa, 0x5e, 0x02, 0xe6, 0xf8, 0x29, + 0xf9, 0xe3, 0x2b, 0xda, 0xe4, 0x5b, 0xc4, 0x6f, 0x15, 0x98, 0x1f, 0x27, 0x28, 0xbe, 0x4d, 0xfc, + 0xa7, 0x5f, 0x3a, 0x26, 0x24, 0x84, 0xe4, 0x83, 0x5c, 0x50, 0x52, 0x0f, 0x7c, 0x41, 0xf9, 0x5d, + 0x02, 0x4a, 0xa3, 0x60, 0x3e, 0x7e, 0x4f, 0x19, 0x7f, 0x4f, 0xf9, 0xd0, 0x0f, 0x68, 0xbf, 0x57, + 0xe0, 0xf8, 0x04, 0x42, 0x3f, 0x5c, 0x88, 0x8c, 0xbc, 0xaa, 0x24, 0xee, 0xfb, 0xaa, 0xf2, 0xdf, + 0x0f, 0x92, 0x3f, 0x28, 0x30, 0x5f, 0x13, 0xcf, 0xe0, 0xe2, 0xd5, 0xe1, 0xd1, 0xcd, 0xa0, 0xfc, + 0xa5, 0x3b, 0x35, 0xfc, 0xce, 0xa3, 0x96, 0x61, 0xe1, 0x00, 0xb4, 0x87, 0x78, 0x49, 0xf9, 0xbb, + 0x02, 0xb3, 0xb2, 0x15, 0xed, 0x91, 0x3d, 0x7c, 0x4c, 0x60, 0x07, 0x3f, 0x05, 0x49, 0xa7, 0x13, + 0x9d, 0x5a, 0xc7, 0x3f, 0x63, 0x33, 0x83, 0x7a, 0x01, 0xf0, 0x28, 0xee, 0x87, 0xa0, 0x8e, 0x9f, + 0xe7, 0x18, 0xf1, 0xaf, 0x51, 0xdb, 0x0d, 0xa3, 0xd4, 0xa3, 0xfe, 0x34, 0x01, 0x05, 0xc2, 0x34, + 0x4e, 0x8f, 0x36, 0x43, 0x3b, 0x0c, 0xf0, 0x33, 0x30, 0xbd, 0xcd, 0x5d, 0xac, 0xe1, 0x0a, 0xca, + 0x91, 0xbc, 0xd0, 0x89, 0xa7, 0xe6, 0x35, 0x58, 0x08, 0x68, 0xdb, 0xeb, 0x77, 0x02, 0x6b, 0x8b, + 0x6e, 0x3b, 0xfd, 0x8e, 0xd5, 0xb3, 0x83, 0x90, 0xfa, 0x9c, 0xb1, 0x02, 0x99, 0x93, 0xc6, 0x75, + 0x6e, 0xab, 0x71, 0x13, 0x3e, 0x0d, 0xf3, 0x5b, 0x4e, 0xdf, 0xf5, 0xba, 0xd6, 0xc0, 0xb5, 0xf7, + 0xa9, 0x1f, 0x58, 0x6d, 0x6f, 0xb7, 0x2f, 0xa8, 0x4a, 0x13, 0x2c, 0x6c, 0x0d, 0x61, 0x2a, 0x33, + 0x0b, 0xbe, 0x01, 0x2b, 0x13, 0x7b, 0xb1, 0x6e, 0x3a, 0x6e, 0x48, 0x7d, 0xda, 0xb1, 0x7c, 0x3a, + 0x70, 0x9d, 0xb6, 0xf8, 0x26, 0x2c, 0x0e, 0x70, 0xcf, 0x4f, 0xe8, 0x7a, 0x53, 0xba, 0x93, 0xa1, + 0x37, 0x3e, 0x01, 0xb9, 0xf6, 0x60, 0xd7, 0xda, 0xe5, 0x1f, 0xa0, 0x58, 0x42, 0x52, 0x48, 0xb6, + 0x3d, 0xd8, 0x6d, 0x31, 0x19, 0x23, 0x48, 0xde, 0x1a, 0x88, 0x3c, 0xa4, 0x10, 0x56, 0x54, 0xdf, + 0x57, 0xa0, 0xa8, 0x75, 0xbb, 0x3e, 0xed, 0xda, 0xa1, 0xa4, 0xe9, 0x34, 0xcc, 0x0b, 0x4a, 0xf6, + 0x2d, 0xb9, 0xda, 0x05, 0x1e, 0x45, 0xe0, 0x91, 0x36, 0xb1, 0xd4, 0x05, 0x9e, 0xb3, 0x70, 0x74, + 0xb7, 0x3f, 0xb1, 0x4e, 0x82, 0xd7, 0x99, 0x8f, 0xad, 0xa3, 0xb5, 0x3e, 0x09, 0xc7, 0x27, 0xb3, + 0xd0, 0x73, 0xc4, 0x7f, 0x19, 0x05, 0x72, 0x74, 0x02, 0xe8, 0x9a, 0xd3, 0xbf, 0x47, 0x55, 0xfb, + 0x0e, 0xe7, 0xeb, 0x03, 0xaa, 0xda, 0x77, 0xd4, 0x9f, 0xc7, 0x0f, 0xc8, 0x51, 0xb8, 0xc4, 0x89, + 0x35, 0x8a, 0x71, 0xe5, 0x5e, 0x31, 0x5e, 0x82, 0xa9, 0x80, 0xfa, 0x7b, 0x4e, 0xbf, 0xcb, 0xc1, + 0x65, 0x49, 0x24, 0xe2, 0x26, 0x3c, 0x2f, 0xb1, 0xd3, 0x3b, 0x21, 0xf5, 0xfb, 0xb6, 0xeb, 0xee, + 0x5b, 0xe2, 0xb6, 0xda, 0x0f, 0x69, 0xc7, 0x1a, 0xfe, 0xa7, 0x22, 0x92, 0xeb, 0xb3, 0xc2, 0x5b, + 0x8f, 0x9d, 0x49, 0xec, 0x6b, 0xc6, 0x7f, 0xb0, 0xbc, 0x02, 0x45, 0x5f, 0x06, 0xb1, 0x15, 0xb0, + 0xe9, 0x91, 0x49, 0x77, 0x3e, 0xfa, 0x02, 0x36, 0x1a, 0xe1, 0xa4, 0xe0, 0x8f, 0x05, 0xfc, 0xc1, + 0x7c, 0x9d, 0x7e, 0xd0, 0x7c, 0x7d, 0x29, 0x95, 0xcd, 0xa0, 0x29, 0xf5, 0x17, 0x0a, 0xcc, 0x4d, + 0x38, 0xea, 0xc5, 0xe7, 0x48, 0x65, 0xe4, 0x9a, 0xfa, 0xff, 0x90, 0xe6, 0x1f, 0x27, 0xe5, 0xe7, + 0xee, 0x63, 0x87, 0x4f, 0x8a, 0xfc, 0x43, 0x22, 0x11, 0x5e, 0x6c, 0x2d, 0x72, 0x4c, 0x6d, 0x7e, + 0x4f, 0x8d, 0xf6, 0x9b, 0x3c, 0xd3, 0x89, 0xab, 0xeb, 0xe1, 0x8b, 0x6f, 0xea, 0xbe, 0x17, 0xdf, + 0x95, 0xef, 0x24, 0x21, 0x57, 0xdb, 0x6f, 0xde, 0x72, 0x37, 0x5d, 0xbb, 0xcb, 0xbf, 0xf4, 0xd5, + 0x1a, 0xe6, 0x75, 0x74, 0x04, 0xcf, 0x42, 0xc1, 0xa8, 0x9b, 0x96, 0xd1, 0xaa, 0x56, 0xad, 0xcd, + 0xaa, 0x76, 0x11, 0x29, 0x18, 0xc1, 0x74, 0x83, 0x54, 0xac, 0xcb, 0xfa, 0x75, 0xa1, 0x49, 0xe0, + 0x39, 0x98, 0x69, 0x19, 0x95, 0x2b, 0x2d, 0x7d, 0xa8, 0x4c, 0xe1, 0x05, 0x98, 0xad, 0xb5, 0xaa, + 0x66, 0xa5, 0x51, 0x1d, 0x51, 0x67, 0x71, 0x01, 0x72, 0xeb, 0xd5, 0xfa, 0xba, 0x10, 0x11, 0x6b, + 0xbf, 0x65, 0x34, 0x2b, 0x17, 0x0d, 0x7d, 0x43, 0xa8, 0x96, 0x98, 0xea, 0x86, 0x4e, 0xea, 0x9b, + 0x95, 0xa8, 0xcb, 0x0b, 0x18, 0x41, 0x7e, 0xbd, 0x62, 0x68, 0x44, 0xb6, 0x72, 0x57, 0xc1, 0x45, + 0xc8, 0xe9, 0x46, 0xab, 0x26, 0xe5, 0x04, 0x2e, 0xc1, 0x9c, 0xd6, 0x32, 0xeb, 0x56, 0xc5, 0x28, + 0x13, 0xbd, 0xa6, 0x1b, 0xa6, 0xb4, 0xa4, 0xf0, 0x1c, 0x14, 0xcd, 0x4a, 0x4d, 0x6f, 0x9a, 0x5a, + 0xad, 0x21, 0x95, 0x6c, 0x14, 0xd9, 0xa6, 0x1e, 0xf9, 0x20, 0xbc, 0x08, 0x0b, 0x46, 0xdd, 0x92, + 0x7f, 0x4d, 0x58, 0x57, 0xb5, 0x6a, 0x4b, 0x97, 0xb6, 0x25, 0x7c, 0x0c, 0x70, 0xdd, 0xb0, 0x5a, + 0x8d, 0x0d, 0xcd, 0xd4, 0x2d, 0xa3, 0x7e, 0x4d, 0x1a, 0x2e, 0xe0, 0x22, 0x64, 0x87, 0x23, 0xb8, + 0xcb, 0x58, 0x28, 0x34, 0x34, 0x62, 0x0e, 0xc1, 0xde, 0xbd, 0xcb, 0xc8, 0x82, 0x8b, 0xa4, 0xde, + 0x6a, 0x0c, 0xdd, 0x66, 0x21, 0x2f, 0xc9, 0x92, 0xaa, 0x14, 0x53, 0xad, 0x57, 0x8c, 0x72, 0x3c, + 0xbe, 0xbb, 0xd9, 0xc5, 0x04, 0x52, 0x56, 0x76, 0x20, 0xc5, 0xa7, 0x23, 0x0b, 0x29, 0xa3, 0x6e, + 0xe8, 0xe8, 0x08, 0x9e, 0x01, 0xa8, 0x34, 0x2b, 0x86, 0xa9, 0x5f, 0x24, 0x5a, 0x95, 0xc1, 0xe6, + 0x8a, 0x88, 0x40, 0x86, 0x76, 0x1a, 0xa6, 0x2a, 0xcd, 0xcd, 0x6a, 0x5d, 0x33, 0x25, 0xcc, 0x4a, + 0xf3, 0x4a, 0xab, 0x6e, 0x32, 0x23, 0xc2, 0x79, 0xc8, 0x54, 0x9a, 0xa6, 0xfe, 0xba, 0xc9, 0x70, + 0x71, 0x9b, 0x60, 0x15, 0xdd, 0xbd, 0xb0, 0xf2, 0x4e, 0x12, 0x52, 0xfc, 0x07, 0xb4, 0x02, 0xe4, + 0xf8, 0x6c, 0x9b, 0xd7, 0x1b, 0xac, 0xcb, 0x1c, 0xa4, 0x2a, 0x86, 0x79, 0x1e, 0x7d, 0x2e, 0x81, + 0x01, 0xd2, 0x2d, 0x5e, 0xfe, 0x7c, 0x86, 0x95, 0x2b, 0x86, 0xf9, 0xe2, 0x39, 0xf4, 0x46, 0x82, + 0x35, 0xdb, 0x12, 0xc2, 0x17, 0x22, 0xc3, 0xda, 0x59, 0xf4, 0x66, 0x6c, 0x58, 0x3b, 0x8b, 0xbe, + 0x18, 0x19, 0xce, 0xac, 0xa1, 0x2f, 0xc5, 0x86, 0x33, 0x6b, 0xe8, 0xcb, 0x91, 0xe1, 0xdc, 0x59, + 0xf4, 0x95, 0xd8, 0x70, 0xee, 0x2c, 0xfa, 0x6a, 0x86, 0x61, 0xe1, 0x48, 0xce, 0xac, 0xa1, 0xaf, + 0x65, 0x63, 0xe9, 0xdc, 0x59, 0xf4, 0xf5, 0x2c, 0x9b, 0xff, 0x78, 0x56, 0xd1, 0x37, 0x10, 0x1b, + 0x26, 0x9b, 0x20, 0xf4, 0x4d, 0x5e, 0x64, 0x26, 0xf4, 0x2d, 0xc4, 0x30, 0x32, 0x2d, 0x17, 0xdf, + 0xe2, 0x96, 0xeb, 0xba, 0x46, 0xd0, 0xb7, 0x33, 0xe2, 0x27, 0x99, 0x72, 0xa5, 0xa6, 0x55, 0x11, + 0xe6, 0x35, 0x18, 0x2b, 0xdf, 0x3d, 0xcd, 0x8a, 0x2c, 0x3c, 0xd1, 0xf7, 0x1a, 0xac, 0xc3, 0xab, + 0x1a, 0x29, 0xbf, 0xa6, 0x11, 0xf4, 0xfd, 0xd3, 0xac, 0xc3, 0xab, 0x1a, 0x91, 0x7c, 0xfd, 0xa0, + 0xc1, 0x1c, 0xb9, 0xe9, 0xed, 0xd3, 0x6c, 0xd0, 0x52, 0xff, 0xc3, 0x06, 0xce, 0x42, 0x72, 0xbd, + 0x62, 0xa2, 0x77, 0x78, 0x6f, 0x2c, 0x44, 0xd1, 0x8f, 0x10, 0x53, 0x36, 0x75, 0x13, 0xbd, 0xcb, + 0x94, 0x69, 0xb3, 0xd5, 0xa8, 0xea, 0xe8, 0x09, 0x36, 0xb8, 0x8b, 0x7a, 0xbd, 0xa6, 0x9b, 0xe4, + 0x3a, 0xfa, 0x31, 0x77, 0xbf, 0xd4, 0xac, 0x1b, 0xe8, 0x3d, 0x84, 0x8b, 0x00, 0xfa, 0xeb, 0x0d, + 0xa2, 0x37, 0x9b, 0x95, 0xba, 0x81, 0x9e, 0x5e, 0xd9, 0x04, 0x74, 0x30, 0x1d, 0x30, 0x00, 0x2d, + 0xe3, 0xb2, 0x51, 0xbf, 0x66, 0xa0, 0x23, 0x4c, 0x68, 0x10, 0xbd, 0xa1, 0x11, 0x1d, 0x29, 0x18, + 0x20, 0x23, 0x7f, 0xbd, 0x49, 0xe0, 0x69, 0xc8, 0x92, 0x7a, 0xb5, 0xba, 0xae, 0x95, 0x2f, 0xa3, + 0xe4, 0xfa, 0x4b, 0x30, 0xe3, 0x78, 0xab, 0x7b, 0x4e, 0x48, 0x83, 0x40, 0xfc, 0xe2, 0x78, 0x43, + 0x95, 0x92, 0xe3, 0x9d, 0x12, 0xa5, 0x53, 0x5d, 0xef, 0xd4, 0x5e, 0x78, 0x8a, 0x5b, 0x4f, 0xf1, + 0x8c, 0xb1, 0x95, 0xe1, 0xc2, 0x99, 0x7f, 0x05, 0x00, 0x00, 0xff, 0xff, 0x9e, 0xa2, 0x63, 0xc8, + 0x40, 0x29, 0x00, 0x00, } diff --git a/go/vt/proto/vtgate/vtgate.pb.go b/go/vt/proto/vtgate/vtgate.pb.go index 7b7370e8a07..5e23cf2aab6 100644 --- a/go/vt/proto/vtgate/vtgate.pb.go +++ b/go/vt/proto/vtgate/vtgate.pb.go @@ -143,6 +143,7 @@ type Session struct { // user_defined_variables contains all the @variables defined for this session UserDefinedVariables map[string]*query.BindVariable `protobuf:"bytes,13,rep,name=user_defined_variables,json=userDefinedVariables,proto3" json:"user_defined_variables,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` // system_variables keeps track of all session variables set for this connection + // TODO: systay should we keep this so we can apply it ordered? SystemVariables map[string]string `protobuf:"bytes,14,rep,name=system_variables,json=systemVariables,proto3" json:"system_variables,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` // row_count keeps track of the last seen rows affected for this session RowCount int64 `protobuf:"varint,15,opt,name=row_count,json=rowCount,proto3" json:"row_count,omitempty"` @@ -282,11 +283,12 @@ func (m *Session) GetRowCount() int64 { } type Session_ShardSession struct { - Target *query.Target `protobuf:"bytes,1,opt,name=target,proto3" json:"target,omitempty"` - TransactionId int64 `protobuf:"varint,2,opt,name=transaction_id,json=transactionId,proto3" json:"transaction_id,omitempty"` - XXX_NoUnkeyedLiteral struct{} `json:"-"` - XXX_unrecognized []byte `json:"-"` - XXX_sizecache int32 `json:"-"` + Target *query.Target `protobuf:"bytes,1,opt,name=target,proto3" json:"target,omitempty"` + TransactionId int64 `protobuf:"varint,2,opt,name=transaction_id,json=transactionId,proto3" json:"transaction_id,omitempty"` + TabletAlias *topodata.TabletAlias `protobuf:"bytes,3,opt,name=tablet_alias,json=tabletAlias,proto3" json:"tablet_alias,omitempty"` + XXX_NoUnkeyedLiteral struct{} `json:"-"` + XXX_unrecognized []byte `json:"-"` + XXX_sizecache int32 `json:"-"` } func (m *Session_ShardSession) Reset() { *m = Session_ShardSession{} } @@ -328,6 +330,13 @@ func (m *Session_ShardSession) GetTransactionId() int64 { return 0 } +func (m *Session_ShardSession) GetTabletAlias() *topodata.TabletAlias { + if m != nil { + return m.TabletAlias + } + return nil +} + // ExecuteRequest is the payload to Execute. type ExecuteRequest struct { // caller_id identifies the caller. This is the effective caller ID, @@ -973,75 +982,76 @@ func init() { func init() { proto.RegisterFile("vtgate.proto", fileDescriptor_aab96496ceaf1ebb) } var fileDescriptor_aab96496ceaf1ebb = []byte{ - // 1117 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0xdb, 0x6e, 0x1b, 0x37, - 0x13, 0xce, 0xea, 0xac, 0xd1, 0x69, 0x7f, 0x46, 0xc9, 0xbf, 0x51, 0xd3, 0x42, 0x50, 0x12, 0x44, - 0x71, 0x0b, 0xa9, 0x50, 0xd1, 0xa2, 0x28, 0x5a, 0x14, 0xb6, 0xac, 0x04, 0x2a, 0x6c, 0xcb, 0xa5, - 0x64, 0x1b, 0x28, 0x52, 0x2c, 0xd6, 0x5a, 0x5a, 0x26, 0x22, 0x2f, 0x37, 0x24, 0x25, 0x57, 0x4f, - 0xd1, 0xab, 0xde, 0xf4, 0x05, 0xfa, 0x2e, 0xbd, 0xeb, 0x1b, 0x15, 0x24, 0x57, 0xd2, 0x5a, 0x75, - 0x1b, 0xc7, 0x81, 0x6f, 0x16, 0xe4, 0xcc, 0x70, 0x38, 0xf3, 0x7d, 0x33, 0xc3, 0x85, 0xe2, 0x5c, - 0x4e, 0x3c, 0x49, 0x5a, 0x21, 0x67, 0x92, 0xa1, 0x8c, 0xd9, 0xd5, 0xec, 0x53, 0x1a, 0x4c, 0xd9, - 0xc4, 0xf7, 0xa4, 0x67, 0x34, 0xb5, 0xc2, 0xdb, 0x19, 0xe1, 0x8b, 0x68, 0x53, 0x96, 0x2c, 0x64, - 0x71, 0xe5, 0x5c, 0xf2, 0x70, 0x6c, 0x36, 0x8d, 0xdf, 0x72, 0x90, 0x1d, 0x12, 0x21, 0x28, 0x0b, - 0xd0, 0x33, 0x28, 0xd3, 0xc0, 0x95, 0xdc, 0x0b, 0x84, 0x37, 0x96, 0x94, 0x05, 0x8e, 0x55, 0xb7, - 0x9a, 0x39, 0x5c, 0xa2, 0xc1, 0x68, 0x2d, 0x44, 0x5d, 0x28, 0x8b, 0x73, 0x8f, 0xfb, 0xae, 0x30, - 0xe7, 0x84, 0x93, 0xa8, 0x27, 0x9b, 0x85, 0xce, 0xe3, 0x56, 0x14, 0x5d, 0xe4, 0xaf, 0x35, 0x54, - 0x56, 0xd1, 0x06, 0x97, 0x44, 0x6c, 0x27, 0xd0, 0x47, 0x90, 0x17, 0x34, 0x98, 0x4c, 0x89, 0xeb, - 0x9f, 0x3a, 0x49, 0x7d, 0x4d, 0xce, 0x08, 0x76, 0x4f, 0xd1, 0x27, 0x00, 0xde, 0x4c, 0xb2, 0x31, - 0xbb, 0xb8, 0xa0, 0xd2, 0x49, 0x69, 0x6d, 0x4c, 0x82, 0x9e, 0x40, 0x49, 0x7a, 0x7c, 0x42, 0xa4, - 0x2b, 0x24, 0xa7, 0xc1, 0xc4, 0x49, 0xd7, 0xad, 0x66, 0x1e, 0x17, 0x8d, 0x70, 0xa8, 0x65, 0xa8, - 0x0d, 0x59, 0x16, 0x4a, 0x1d, 0x5f, 0xa6, 0x6e, 0x35, 0x0b, 0x9d, 0x07, 0x2d, 0x83, 0x4a, 0xef, - 0x17, 0x32, 0x9e, 0x49, 0x32, 0x30, 0x4a, 0xbc, 0xb4, 0x42, 0x3b, 0x60, 0xc7, 0x72, 0x77, 0x2f, - 0x98, 0x4f, 0x9c, 0x6c, 0xdd, 0x6a, 0x96, 0x3b, 0xff, 0x5f, 0x66, 0x16, 0x83, 0x61, 0x9f, 0xf9, - 0x04, 0x57, 0xe4, 0x55, 0x01, 0x6a, 0x43, 0xee, 0xd2, 0xe3, 0x01, 0x0d, 0x26, 0xc2, 0xc9, 0x69, - 0x54, 0xee, 0x47, 0xb7, 0xfe, 0xa8, 0xbe, 0x27, 0x46, 0x87, 0x57, 0x46, 0xe8, 0x7b, 0x28, 0x86, - 0x9c, 0xac, 0xa1, 0xcc, 0xdf, 0x00, 0xca, 0x42, 0xc8, 0xc9, 0x0a, 0xc8, 0x6d, 0x28, 0x85, 0x4c, - 0xc8, 0xb5, 0x07, 0xb8, 0x81, 0x87, 0xa2, 0x3a, 0xb2, 0x72, 0xf1, 0x14, 0xca, 0x53, 0x4f, 0x48, - 0x97, 0x06, 0x82, 0x70, 0xe9, 0x52, 0xdf, 0x29, 0xd4, 0xad, 0x66, 0x0a, 0x17, 0x95, 0xb4, 0xaf, - 0x85, 0x7d, 0x1f, 0x7d, 0x0c, 0x70, 0xc6, 0x66, 0x81, 0xef, 0x72, 0x76, 0x29, 0x9c, 0xa2, 0xb6, - 0xc8, 0x6b, 0x09, 0x66, 0x97, 0x02, 0xb9, 0xf0, 0x70, 0x26, 0x08, 0x77, 0x7d, 0x72, 0x46, 0x03, - 0xe2, 0xbb, 0x73, 0x8f, 0x53, 0xef, 0x74, 0x4a, 0x84, 0x53, 0xd2, 0x01, 0xbd, 0xd8, 0x0c, 0xe8, - 0x48, 0x10, 0xbe, 0x6b, 0x8c, 0x8f, 0x97, 0xb6, 0xbd, 0x40, 0xf2, 0x05, 0xae, 0xce, 0xae, 0x51, - 0xa1, 0x01, 0xd8, 0x62, 0x21, 0x24, 0xb9, 0x88, 0xb9, 0x2e, 0x6b, 0xd7, 0x4f, 0xff, 0x91, 0xab, - 0xb6, 0xdb, 0xf0, 0x5a, 0x11, 0x57, 0xa5, 0xaa, 0x04, 0x39, 0xbb, 0x74, 0xc7, 0x6c, 0x16, 0x48, - 0xa7, 0x52, 0xb7, 0x9a, 0x49, 0x9c, 0xe3, 0xec, 0xb2, 0xab, 0xf6, 0xb5, 0xd7, 0x50, 0x8c, 0x23, - 0x86, 0x9e, 0x41, 0xc6, 0x54, 0x97, 0xee, 0x89, 0x42, 0xa7, 0x14, 0xd1, 0x3a, 0xd2, 0x42, 0x1c, - 0x29, 0x55, 0x0b, 0xc5, 0x6b, 0x88, 0xfa, 0x4e, 0x42, 0x3b, 0x2e, 0xc5, 0xa4, 0x7d, 0xbf, 0xf6, - 0x1a, 0x1e, 0xfd, 0x6b, 0xfa, 0xc8, 0x86, 0xe4, 0x1b, 0xb2, 0xd0, 0xf7, 0xe4, 0xb1, 0x5a, 0xa2, - 0x17, 0x90, 0x9e, 0x7b, 0xd3, 0x19, 0xd1, 0xce, 0xd6, 0x25, 0xb5, 0x43, 0x83, 0xd5, 0x59, 0x6c, - 0x2c, 0xbe, 0x49, 0x7c, 0x6d, 0xd5, 0x76, 0xa0, 0x7a, 0x1d, 0x02, 0xd7, 0x38, 0xae, 0xc6, 0x1d, - 0xe7, 0x63, 0x3e, 0x1a, 0x7f, 0x24, 0xa0, 0x1c, 0x35, 0x0a, 0x26, 0x6f, 0x67, 0x44, 0x48, 0xf4, - 0x19, 0xe4, 0xc7, 0xde, 0x74, 0x4a, 0xb8, 0x4a, 0xcb, 0xa0, 0x50, 0x69, 0x99, 0x59, 0xd2, 0xd5, - 0xf2, 0xfe, 0x2e, 0xce, 0x19, 0x8b, 0xbe, 0x8f, 0x5e, 0x40, 0x36, 0x2a, 0xc9, 0x28, 0xea, 0xca, - 0x06, 0x4b, 0x78, 0xa9, 0x47, 0xcf, 0x21, 0xad, 0x13, 0xd2, 0x73, 0xa0, 0xd0, 0xf9, 0xdf, 0x32, - 0x3d, 0x55, 0x5b, 0xba, 0x6d, 0xb0, 0xd1, 0xa3, 0x2f, 0xa1, 0x20, 0x55, 0x3e, 0xd2, 0x95, 0x8b, - 0x90, 0xe8, 0xc1, 0x50, 0xee, 0x54, 0x5b, 0xab, 0xf9, 0x36, 0xd2, 0xca, 0xd1, 0x22, 0x24, 0x18, - 0xe4, 0x6a, 0xad, 0x48, 0x79, 0x43, 0x16, 0x22, 0xf4, 0xc6, 0xc4, 0xd5, 0x53, 0x48, 0x0f, 0x84, - 0x3c, 0x2e, 0x2d, 0xa5, 0x9a, 0xe9, 0xf8, 0xc0, 0xc8, 0xde, 0x64, 0x60, 0xfc, 0x90, 0xca, 0xa5, - 0xed, 0x4c, 0xe3, 0x57, 0x0b, 0x2a, 0x2b, 0xa4, 0x44, 0xc8, 0x02, 0xa1, 0x6e, 0x4c, 0x13, 0xce, - 0x19, 0xdf, 0x80, 0x09, 0x1f, 0x76, 0x7b, 0x4a, 0x8c, 0x8d, 0xf6, 0x7d, 0x30, 0xda, 0x82, 0x0c, - 0x27, 0x62, 0x36, 0x95, 0x11, 0x48, 0x28, 0x3e, 0x56, 0xb0, 0xd6, 0xe0, 0xc8, 0xa2, 0xf1, 0x57, - 0x02, 0xee, 0x47, 0x11, 0xed, 0x78, 0x72, 0x7c, 0x7e, 0xe7, 0x04, 0x7e, 0x0a, 0x59, 0x15, 0x0d, - 0x25, 0xc2, 0x49, 0xea, 0x8e, 0xbc, 0x86, 0xc2, 0xa5, 0xc5, 0x07, 0x90, 0xe8, 0x89, 0x2b, 0x8f, - 0x53, 0xda, 0x3c, 0x4e, 0x9e, 0x88, 0x3f, 0x4e, 0x77, 0xc4, 0x75, 0xe3, 0x77, 0x0b, 0xaa, 0x57, - 0x31, 0xbd, 0x33, 0xaa, 0x3f, 0x87, 0xac, 0x21, 0x72, 0x89, 0xe6, 0xc3, 0x28, 0x36, 0x43, 0xf3, - 0x09, 0x95, 0xe7, 0xc6, 0xf5, 0xd2, 0x4c, 0x35, 0x6b, 0x75, 0x28, 0x39, 0xf1, 0x2e, 0x3e, 0xa8, - 0x65, 0x57, 0x7d, 0x98, 0x78, 0xbf, 0x3e, 0x4c, 0xde, 0xba, 0x0f, 0x53, 0xef, 0xe0, 0x26, 0x7d, - 0xa3, 0x87, 0x3b, 0x86, 0x6d, 0xe6, 0xbf, 0xb1, 0x6d, 0x74, 0xe1, 0xc1, 0x06, 0x50, 0x11, 0x8d, - 0xeb, 0xfe, 0xb2, 0xde, 0xd9, 0x5f, 0x3f, 0xc3, 0x23, 0x4c, 0x04, 0x9b, 0xce, 0x49, 0xac, 0xf2, - 0x6e, 0x07, 0x39, 0x82, 0x94, 0x2f, 0xa3, 0x57, 0x22, 0x8f, 0xf5, 0xba, 0xf1, 0x18, 0x6a, 0xd7, - 0xb9, 0x37, 0x81, 0x36, 0xfe, 0xb4, 0xa0, 0x7c, 0x6c, 0x72, 0xb8, 0xdd, 0x95, 0x1b, 0xe4, 0x25, - 0x6e, 0x48, 0xde, 0x73, 0x48, 0xcf, 0x27, 0x2a, 0xd4, 0xe5, 0x90, 0x8e, 0xfd, 0x74, 0x1e, 0xbf, - 0x92, 0xd4, 0xc7, 0x46, 0xaf, 0x90, 0x3c, 0xa3, 0x53, 0x49, 0xb8, 0x66, 0x57, 0x21, 0x19, 0xb3, - 0x7c, 0xa9, 0x35, 0x38, 0xb2, 0x68, 0x7c, 0x07, 0x95, 0x55, 0x2e, 0x6b, 0x22, 0xc8, 0x9c, 0x04, - 0x52, 0x38, 0x96, 0x2e, 0xfe, 0x2b, 0xc7, 0x8f, 0x7b, 0x4a, 0x85, 0x23, 0x8b, 0xad, 0x5d, 0xa8, - 0x6c, 0xfc, 0x91, 0xa1, 0x0a, 0x14, 0x8e, 0x0e, 0x86, 0x87, 0xbd, 0x6e, 0xff, 0x65, 0xbf, 0xb7, - 0x6b, 0xdf, 0x43, 0x00, 0x99, 0x61, 0xff, 0xe0, 0xd5, 0x5e, 0xcf, 0xb6, 0x50, 0x1e, 0xd2, 0xfb, - 0x47, 0x7b, 0xa3, 0xbe, 0x9d, 0x50, 0xcb, 0xd1, 0xc9, 0xe0, 0xb0, 0x6b, 0x27, 0xb7, 0xbe, 0x85, - 0x42, 0x57, 0xff, 0x57, 0x0e, 0xb8, 0x4f, 0xb8, 0x3a, 0x70, 0x30, 0xc0, 0xfb, 0xdb, 0x7b, 0xf6, - 0x3d, 0x94, 0x85, 0xe4, 0x21, 0x56, 0x27, 0x73, 0x90, 0x3a, 0x1c, 0x0c, 0x47, 0x76, 0x02, 0x95, - 0x01, 0xb6, 0x8f, 0x46, 0x83, 0xee, 0x60, 0x7f, 0xbf, 0x3f, 0xb2, 0x93, 0x3b, 0x5f, 0x41, 0x85, - 0xb2, 0xd6, 0x9c, 0x4a, 0x22, 0x84, 0xf9, 0xa7, 0xfe, 0xe9, 0x49, 0xb4, 0xa3, 0xac, 0x6d, 0x56, - 0xed, 0x09, 0x6b, 0xcf, 0x65, 0x5b, 0x6b, 0xdb, 0xa6, 0x34, 0x4f, 0x33, 0x7a, 0xf7, 0xc5, 0xdf, - 0x01, 0x00, 0x00, 0xff, 0xff, 0x8d, 0xfe, 0x6c, 0x91, 0xd3, 0x0b, 0x00, 0x00, + // 1133 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x56, 0xdd, 0x6e, 0x1b, 0x45, + 0x14, 0xee, 0xfa, 0xdf, 0xc7, 0x7f, 0xcb, 0xd4, 0x2d, 0x5b, 0x53, 0x90, 0xe5, 0xb6, 0xaa, 0x13, + 0x90, 0x8d, 0x82, 0x40, 0x15, 0x02, 0xa1, 0xc4, 0x71, 0x2b, 0xa3, 0x24, 0x0e, 0x63, 0x27, 0x91, + 0x10, 0x68, 0xb5, 0xf1, 0x4e, 0x9c, 0x51, 0x9d, 0x9d, 0xed, 0xcc, 0xd8, 0xc1, 0x4f, 0xc1, 0x1d, + 0x17, 0xbc, 0x00, 0xef, 0xc2, 0x15, 0xbc, 0x11, 0x9a, 0x99, 0xb5, 0xbd, 0x31, 0x81, 0xa6, 0xa9, + 0x72, 0xb3, 0x9a, 0x73, 0xbe, 0x33, 0x67, 0xcf, 0x7c, 0xe7, 0x67, 0x06, 0x8a, 0x33, 0x39, 0xf6, + 0x24, 0x69, 0x85, 0x9c, 0x49, 0x86, 0x32, 0x46, 0xaa, 0xd9, 0xa7, 0x34, 0x98, 0xb0, 0xb1, 0xef, + 0x49, 0xcf, 0x20, 0xb5, 0xc2, 0x9b, 0x29, 0xe1, 0xf3, 0x48, 0x28, 0x4b, 0x16, 0xb2, 0x38, 0x38, + 0x93, 0x3c, 0x1c, 0x19, 0xa1, 0xf1, 0x57, 0x0e, 0xb2, 0x03, 0x22, 0x04, 0x65, 0x01, 0x7a, 0x06, + 0x65, 0x1a, 0xb8, 0x92, 0x7b, 0x81, 0xf0, 0x46, 0x92, 0xb2, 0xc0, 0xb1, 0xea, 0x56, 0x33, 0x87, + 0x4b, 0x34, 0x18, 0xae, 0x94, 0xa8, 0x03, 0x65, 0x71, 0xee, 0x71, 0xdf, 0x15, 0x66, 0x9f, 0x70, + 0x12, 0xf5, 0x64, 0xb3, 0xb0, 0xf5, 0xb8, 0x15, 0x45, 0x17, 0xf9, 0x6b, 0x0d, 0x94, 0x55, 0x24, + 0xe0, 0x92, 0x88, 0x49, 0x02, 0x7d, 0x04, 0x79, 0x41, 0x83, 0xf1, 0x84, 0xb8, 0xfe, 0xa9, 0x93, + 0xd4, 0xbf, 0xc9, 0x19, 0xc5, 0xee, 0x29, 0xfa, 0x04, 0xc0, 0x9b, 0x4a, 0x36, 0x62, 0x17, 0x17, + 0x54, 0x3a, 0x29, 0x8d, 0xc6, 0x34, 0xe8, 0x09, 0x94, 0xa4, 0xc7, 0xc7, 0x44, 0xba, 0x42, 0x72, + 0x1a, 0x8c, 0x9d, 0x74, 0xdd, 0x6a, 0xe6, 0x71, 0xd1, 0x28, 0x07, 0x5a, 0x87, 0xda, 0x90, 0x65, + 0xa1, 0xd4, 0xf1, 0x65, 0xea, 0x56, 0xb3, 0xb0, 0xf5, 0xa0, 0x65, 0x58, 0xe9, 0xfe, 0x42, 0x46, + 0x53, 0x49, 0xfa, 0x06, 0xc4, 0x0b, 0x2b, 0xb4, 0x03, 0x76, 0xec, 0xec, 0xee, 0x05, 0xf3, 0x89, + 0x93, 0xad, 0x5b, 0xcd, 0xf2, 0xd6, 0x87, 0x8b, 0x93, 0xc5, 0x68, 0xd8, 0x67, 0x3e, 0xc1, 0x15, + 0x79, 0x55, 0x81, 0xda, 0x90, 0xbb, 0xf4, 0x78, 0x40, 0x83, 0xb1, 0x70, 0x72, 0x9a, 0x95, 0xfb, + 0xd1, 0x5f, 0x7f, 0x50, 0xdf, 0x13, 0x83, 0xe1, 0xa5, 0x11, 0xfa, 0x0e, 0x8a, 0x21, 0x27, 0x2b, + 0x2a, 0xf3, 0x37, 0xa0, 0xb2, 0x10, 0x72, 0xb2, 0x24, 0x72, 0x1b, 0x4a, 0x21, 0x13, 0x72, 0xe5, + 0x01, 0x6e, 0xe0, 0xa1, 0xa8, 0xb6, 0x2c, 0x5d, 0x3c, 0x85, 0xf2, 0xc4, 0x13, 0xd2, 0xa5, 0x81, + 0x20, 0x5c, 0xba, 0xd4, 0x77, 0x0a, 0x75, 0xab, 0x99, 0xc2, 0x45, 0xa5, 0xed, 0x69, 0x65, 0xcf, + 0x47, 0x1f, 0x03, 0x9c, 0xb1, 0x69, 0xe0, 0xbb, 0x9c, 0x5d, 0x0a, 0xa7, 0xa8, 0x2d, 0xf2, 0x5a, + 0x83, 0xd9, 0xa5, 0x40, 0x2e, 0x3c, 0x9c, 0x0a, 0xc2, 0x5d, 0x9f, 0x9c, 0xd1, 0x80, 0xf8, 0xee, + 0xcc, 0xe3, 0xd4, 0x3b, 0x9d, 0x10, 0xe1, 0x94, 0x74, 0x40, 0x1b, 0xeb, 0x01, 0x1d, 0x09, 0xc2, + 0x77, 0x8d, 0xf1, 0xf1, 0xc2, 0xb6, 0x1b, 0x48, 0x3e, 0xc7, 0xd5, 0xe9, 0x35, 0x10, 0xea, 0x83, + 0x2d, 0xe6, 0x42, 0x92, 0x8b, 0x98, 0xeb, 0xb2, 0x76, 0xfd, 0xf4, 0x5f, 0x67, 0xd5, 0x76, 0x6b, + 0x5e, 0x2b, 0xe2, 0xaa, 0x56, 0x95, 0x20, 0x67, 0x97, 0xee, 0x88, 0x4d, 0x03, 0xe9, 0x54, 0xea, + 0x56, 0x33, 0x89, 0x73, 0x9c, 0x5d, 0x76, 0x94, 0x5c, 0xfb, 0xcd, 0x82, 0x62, 0x9c, 0x32, 0xf4, + 0x0c, 0x32, 0xa6, 0xbc, 0x74, 0x53, 0x14, 0xb6, 0x4a, 0x51, 0x5e, 0x87, 0x5a, 0x89, 0x23, 0x50, + 0xf5, 0x50, 0xbc, 0x88, 0xa8, 0xef, 0x24, 0xb4, 0xe7, 0x52, 0x4c, 0xdb, 0xf3, 0xd1, 0x0b, 0x28, + 0x4a, 0x15, 0x85, 0x74, 0xbd, 0x09, 0xf5, 0x84, 0xee, 0x00, 0x55, 0xa1, 0xcb, 0x56, 0x1d, 0x6a, + 0x74, 0x5b, 0x81, 0xb8, 0x20, 0x57, 0x42, 0xed, 0x27, 0x78, 0xf4, 0x9f, 0xcc, 0x21, 0x1b, 0x92, + 0xaf, 0xc9, 0x5c, 0x47, 0x98, 0xc7, 0x6a, 0x89, 0x36, 0x20, 0x3d, 0xf3, 0x26, 0x53, 0xa2, 0xc3, + 0x58, 0x55, 0xe3, 0x0e, 0x0d, 0x96, 0x7b, 0xb1, 0xb1, 0xf8, 0x3a, 0xf1, 0xc2, 0xaa, 0xed, 0x40, + 0xf5, 0x3a, 0xf2, 0xae, 0x71, 0x5c, 0x8d, 0x3b, 0xce, 0xc7, 0x7c, 0x34, 0xfe, 0x48, 0x40, 0x39, + 0xea, 0x31, 0x4c, 0xde, 0x4c, 0x89, 0x90, 0xe8, 0x33, 0xc8, 0x8f, 0xbc, 0xc9, 0x84, 0x70, 0x45, + 0x88, 0xe1, 0xaf, 0xd2, 0x32, 0x63, 0xa8, 0xa3, 0xf5, 0xbd, 0x5d, 0x9c, 0x33, 0x16, 0x3d, 0x1f, + 0x6d, 0x40, 0x36, 0xaa, 0xe6, 0x28, 0xea, 0xca, 0x5a, 0x82, 0xf1, 0x02, 0x47, 0xcf, 0x21, 0xad, + 0x0f, 0x14, 0x11, 0xf8, 0xc1, 0xe2, 0x78, 0xaa, 0x2c, 0x75, 0xc7, 0x61, 0x83, 0xa3, 0x2f, 0x21, + 0x62, 0xd1, 0x95, 0xf3, 0x90, 0xe8, 0x99, 0x52, 0xde, 0xaa, 0xae, 0xf3, 0x3d, 0x9c, 0x87, 0x04, + 0x83, 0x5c, 0xae, 0x55, 0x3a, 0x5f, 0x93, 0xb9, 0x08, 0xbd, 0x11, 0x71, 0xf5, 0x00, 0xd3, 0xb3, + 0x24, 0x8f, 0x4b, 0x0b, 0xad, 0xae, 0x91, 0xf8, 0xac, 0xc9, 0xde, 0x64, 0xd6, 0x7c, 0x9f, 0xca, + 0xa5, 0xed, 0x4c, 0xe3, 0x57, 0x0b, 0x2a, 0x4b, 0xa6, 0x44, 0xc8, 0x02, 0xa1, 0xfe, 0x98, 0x26, + 0x9c, 0x33, 0xbe, 0x46, 0x13, 0x3e, 0xec, 0x74, 0x95, 0x1a, 0x1b, 0xf4, 0x5d, 0x38, 0xda, 0x84, + 0x0c, 0x27, 0x62, 0x3a, 0x91, 0x11, 0x49, 0x28, 0x3e, 0x91, 0xb0, 0x46, 0x70, 0x64, 0xd1, 0xf8, + 0x3b, 0x01, 0xf7, 0xa3, 0x88, 0x76, 0x3c, 0x39, 0x3a, 0xbf, 0xf3, 0x04, 0x7e, 0x0a, 0x59, 0x15, + 0x0d, 0x25, 0xaa, 0x07, 0x92, 0xd7, 0xa7, 0x70, 0x61, 0xf1, 0x1e, 0x49, 0xf4, 0xc4, 0x95, 0x7b, + 0x2d, 0x6d, 0xee, 0x35, 0x4f, 0xc4, 0xef, 0xb5, 0x3b, 0xca, 0x75, 0xe3, 0x77, 0x0b, 0xaa, 0x57, + 0x39, 0xbd, 0xb3, 0x54, 0x7f, 0x0e, 0x59, 0x93, 0xc8, 0x05, 0x9b, 0x0f, 0xa3, 0xd8, 0x4c, 0x9a, + 0x4f, 0xa8, 0x3c, 0x37, 0xae, 0x17, 0x66, 0xaa, 0x59, 0xab, 0x03, 0xc9, 0x89, 0x77, 0xf1, 0x5e, + 0x2d, 0xbb, 0xec, 0xc3, 0xc4, 0xbb, 0xf5, 0x61, 0xf2, 0xd6, 0x7d, 0x98, 0x7a, 0x4b, 0x6e, 0xd2, + 0x37, 0xba, 0xf3, 0x63, 0xdc, 0x66, 0xfe, 0x9f, 0xdb, 0x46, 0x07, 0x1e, 0xac, 0x11, 0x15, 0xa5, + 0x71, 0xd5, 0x5f, 0xd6, 0x5b, 0xfb, 0xeb, 0x67, 0x78, 0x84, 0x89, 0x60, 0x93, 0x19, 0x89, 0x55, + 0xde, 0xed, 0x28, 0x47, 0x90, 0xf2, 0x65, 0x74, 0xbf, 0xe4, 0xb1, 0x5e, 0x37, 0x1e, 0x43, 0xed, + 0x3a, 0xf7, 0x26, 0xd0, 0xc6, 0x9f, 0x16, 0x94, 0x8f, 0xcd, 0x19, 0x6e, 0xf7, 0xcb, 0xb5, 0xe4, + 0x25, 0x6e, 0x98, 0xbc, 0xe7, 0x90, 0x9e, 0x8d, 0x55, 0xa8, 0x8b, 0x21, 0x1d, 0x7b, 0xaf, 0x1e, + 0xbf, 0x92, 0xd4, 0xc7, 0x06, 0x57, 0x4c, 0x9e, 0xd1, 0x89, 0x24, 0x5c, 0x67, 0x57, 0x31, 0x19, + 0xb3, 0x7c, 0xa9, 0x11, 0x1c, 0x59, 0x34, 0xbe, 0x85, 0xca, 0xf2, 0x2c, 0xab, 0x44, 0x90, 0x19, + 0x09, 0xa4, 0x70, 0x2c, 0x5d, 0xfc, 0x57, 0xb6, 0x1f, 0x77, 0x15, 0x84, 0x23, 0x8b, 0xcd, 0x5d, + 0xa8, 0xac, 0x3d, 0xe6, 0x50, 0x05, 0x0a, 0x47, 0x07, 0x83, 0xc3, 0x6e, 0xa7, 0xf7, 0xb2, 0xd7, + 0xdd, 0xb5, 0xef, 0x21, 0x80, 0xcc, 0xa0, 0x77, 0xf0, 0x6a, 0xaf, 0x6b, 0x5b, 0x28, 0x0f, 0xe9, + 0xfd, 0xa3, 0xbd, 0x61, 0xcf, 0x4e, 0xa8, 0xe5, 0xf0, 0xa4, 0x7f, 0xd8, 0xb1, 0x93, 0x9b, 0xdf, + 0x40, 0xa1, 0xa3, 0x9f, 0xa4, 0x7d, 0xee, 0x13, 0xae, 0x36, 0x1c, 0xf4, 0xf1, 0xfe, 0xf6, 0x9e, + 0x7d, 0x0f, 0x65, 0x21, 0x79, 0x88, 0xd5, 0xce, 0x1c, 0xa4, 0x0e, 0xfb, 0x83, 0xa1, 0x9d, 0x40, + 0x65, 0x80, 0xed, 0xa3, 0x61, 0xbf, 0xd3, 0xdf, 0xdf, 0xef, 0x0d, 0xed, 0xe4, 0xce, 0x57, 0x50, + 0xa1, 0xac, 0x35, 0xa3, 0x92, 0x08, 0x61, 0x9e, 0xe3, 0x3f, 0x3e, 0x89, 0x24, 0xca, 0xda, 0x66, + 0xd5, 0x1e, 0xb3, 0xf6, 0x4c, 0xb6, 0x35, 0xda, 0x36, 0xa5, 0x79, 0x9a, 0xd1, 0xd2, 0x17, 0xff, + 0x04, 0x00, 0x00, 0xff, 0xff, 0x07, 0xaa, 0x95, 0x79, 0x0e, 0x0c, 0x00, 0x00, } diff --git a/go/vt/srvtopo/resolver.go b/go/vt/srvtopo/resolver.go index fdbc1c1cb5a..1d25975cf16 100644 --- a/go/vt/srvtopo/resolver.go +++ b/go/vt/srvtopo/resolver.go @@ -31,6 +31,16 @@ import ( vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" ) +// A Gateway is the query processing module for each shard, +// which is used by ScatterConn. +type Gateway interface { + // the query service that this Gateway wraps around + queryservice.QueryService + + // QueryServiceByAlias returns a QueryService + QueryServiceByAlias(alias *topodatapb.TabletAlias) (queryservice.QueryService, error) +} + // A Resolver can resolve keyspace ids and key ranges into ResolvedShard* // objects. It uses an underlying srvtopo.Server to find the topology, // and a TargetStats object to find the healthy destinations. @@ -38,8 +48,8 @@ type Resolver struct { // topoServ is the srvtopo.Server to use for topo queries. topoServ Server - // queryService is the actual query service that will be used to execute queries. - queryService queryservice.QueryService + // gateway + gateway Gateway // localCell is the local cell for the queries. localCell string @@ -50,11 +60,11 @@ type Resolver struct { } // NewResolver creates a new Resolver. -func NewResolver(topoServ Server, queryService queryservice.QueryService, localCell string) *Resolver { +func NewResolver(topoServ Server, gateway Gateway, localCell string) *Resolver { return &Resolver{ - topoServ: topoServ, - queryService: queryService, - localCell: localCell, + topoServ: topoServ, + gateway: gateway, + localCell: localCell, } } @@ -63,8 +73,8 @@ type ResolvedShard struct { // Target describes the target shard. Target *querypb.Target - // QueryService is the actual way to execute the query. - QueryService queryservice.QueryService + // Gateway is the way to execute a query on this shard + Gateway Gateway } // ResolvedShardEqual is an equality check on *ResolvedShard. @@ -135,8 +145,8 @@ func (r *Resolver) GetAllShards(ctx context.Context, keyspace string, tabletType // We would then need to read the SrvKeyspace there too. target.Cell = "" res[i] = &ResolvedShard{ - Target: target, - QueryService: r.queryService, + Target: target, + Gateway: r.gateway, } } return res, srvKeyspace, nil @@ -194,8 +204,8 @@ func (r *Resolver) ResolveDestinations(ctx context.Context, keyspace string, tab target.Cell = "" s = len(result) result = append(result, &ResolvedShard{ - Target: target, - QueryService: r.queryService, + Target: target, + Gateway: r.gateway, }) if ids != nil { values = append(values, nil) diff --git a/go/vt/vtcombo/tablet_map.go b/go/vt/vtcombo/tablet_map.go index cb711f5b80a..095eb04f962 100644 --- a/go/vt/vtcombo/tablet_map.go +++ b/go/vt/vtcombo/tablet_map.go @@ -327,12 +327,12 @@ func (itc *internalTabletConn) StreamExecute(ctx context.Context, target *queryp } // Begin is part of queryservice.QueryService -func (itc *internalTabletConn) Begin(ctx context.Context, target *querypb.Target, options *querypb.ExecuteOptions) (int64, error) { - transactionID, err := itc.tablet.qsc.QueryService().Begin(ctx, target, options) +func (itc *internalTabletConn) Begin(ctx context.Context, target *querypb.Target, options *querypb.ExecuteOptions) (int64, *topodatapb.TabletAlias, error) { + transactionID, alias, err := itc.tablet.qsc.QueryService().Begin(ctx, target, options) if err != nil { - return 0, tabletconn.ErrorFromGRPC(vterrors.ToGRPC(err)) + return 0, nil, tabletconn.ErrorFromGRPC(vterrors.ToGRPC(err)) } - return transactionID, nil + return transactionID, alias, nil } // Commit is part of queryservice.QueryService @@ -396,23 +396,23 @@ func (itc *internalTabletConn) ReadTransaction(ctx context.Context, target *quer } // BeginExecute is part of queryservice.QueryService -func (itc *internalTabletConn) BeginExecute(ctx context.Context, target *querypb.Target, query string, bindVars map[string]*querypb.BindVariable, options *querypb.ExecuteOptions) (*sqltypes.Result, int64, error) { - transactionID, err := itc.Begin(ctx, target, options) +func (itc *internalTabletConn) BeginExecute(ctx context.Context, target *querypb.Target, query string, bindVars map[string]*querypb.BindVariable, options *querypb.ExecuteOptions) (*sqltypes.Result, int64, *topodatapb.TabletAlias, error) { + transactionID, alias, err := itc.Begin(ctx, target, options) if err != nil { - return nil, 0, err + return nil, 0, nil, err } result, err := itc.Execute(ctx, target, query, bindVars, transactionID, options) - return result, transactionID, err + return result, transactionID, alias, err } // BeginExecuteBatch is part of queryservice.QueryService -func (itc *internalTabletConn) BeginExecuteBatch(ctx context.Context, target *querypb.Target, queries []*querypb.BoundQuery, asTransaction bool, options *querypb.ExecuteOptions) ([]sqltypes.Result, int64, error) { - transactionID, err := itc.Begin(ctx, target, options) +func (itc *internalTabletConn) BeginExecuteBatch(ctx context.Context, target *querypb.Target, queries []*querypb.BoundQuery, asTransaction bool, options *querypb.ExecuteOptions) ([]sqltypes.Result, int64, *topodatapb.TabletAlias, error) { + transactionID, alias, err := itc.Begin(ctx, target, options) if err != nil { - return nil, 0, err + return nil, 0, nil, err } results, err := itc.ExecuteBatch(ctx, target, queries, asTransaction, transactionID, options) - return results, transactionID, err + return results, transactionID, alias, err } // MessageStream is part of queryservice.QueryService diff --git a/go/vt/vtctl/query.go b/go/vt/vtctl/query.go index e6cd28b7c04..b30b6ab83a7 100644 --- a/go/vt/vtctl/query.go +++ b/go/vt/vtctl/query.go @@ -276,7 +276,7 @@ func commandVtTabletBegin(ctx context.Context, wr *wrangler.Wrangler, subFlags * } defer conn.Close(ctx) - transactionID, err := conn.Begin(ctx, &querypb.Target{ + transactionID, _, err := conn.Begin(ctx, &querypb.Target{ Keyspace: tabletInfo.Tablet.Keyspace, Shard: tabletInfo.Tablet.Shard, TabletType: tabletInfo.Tablet.Type, diff --git a/go/vt/vtexplain/vtexplain_vtgate.go b/go/vt/vtexplain/vtexplain_vtgate.go index 4b42b30d0d6..bbe9e48ab43 100644 --- a/go/vt/vtexplain/vtexplain_vtgate.go +++ b/go/vt/vtexplain/vtexplain_vtgate.go @@ -82,7 +82,7 @@ func newFakeResolver(opts *Options, hc discovery.LegacyHealthCheck, serv srvtopo txMode = vtgatepb.TransactionMode_TWOPC } tc := vtgate.NewTxConn(gw, txMode) - sc := vtgate.LegacyNewScatterConn("", tc, gw, hc) + sc := vtgate.NewLegacyScatterConn("", tc, gw, hc) srvResolver := srvtopo.NewResolver(serv, gw, cell) return vtgate.NewResolver(srvResolver, serv, cell, sc) } diff --git a/go/vt/vtexplain/vtexplain_vttablet.go b/go/vt/vtexplain/vtexplain_vttablet.go index 0249aac9a98..26724bc0684 100644 --- a/go/vt/vtexplain/vtexplain_vttablet.go +++ b/go/vt/vtexplain/vtexplain_vttablet.go @@ -119,7 +119,7 @@ func newTablet(opts *Options, t *topodatapb.Tablet) *explainTablet { var _ queryservice.QueryService = (*explainTablet)(nil) // compile-time interface check // Begin is part of the QueryService interface. -func (t *explainTablet) Begin(ctx context.Context, target *querypb.Target, options *querypb.ExecuteOptions) (int64, error) { +func (t *explainTablet) Begin(ctx context.Context, target *querypb.Target, options *querypb.ExecuteOptions) (int64, *topodatapb.TabletAlias, error) { t.mu.Lock() t.currentTime = batchTime.Wait() t.tabletQueries = append(t.tabletQueries, &TabletQuery{ @@ -248,7 +248,7 @@ func (t *explainTablet) ExecuteBatch(ctx context.Context, target *querypb.Target } // BeginExecute is part of the QueryService interface. -func (t *explainTablet) BeginExecute(ctx context.Context, target *querypb.Target, sql string, bindVariables map[string]*querypb.BindVariable, options *querypb.ExecuteOptions) (*sqltypes.Result, int64, error) { +func (t *explainTablet) BeginExecute(ctx context.Context, target *querypb.Target, sql string, bindVariables map[string]*querypb.BindVariable, options *querypb.ExecuteOptions) (*sqltypes.Result, int64, *topodatapb.TabletAlias, error) { t.mu.Lock() t.currentTime = batchTime.Wait() bindVariables = sqltypes.CopyBindVariables(bindVariables) diff --git a/go/vt/vtgate/api.go b/go/vt/vtgate/api.go index bf4d1ca5ef5..f6ed78cec00 100644 --- a/go/vt/vtgate/api.go +++ b/go/vt/vtgate/api.go @@ -22,7 +22,6 @@ import ( "net/http" "strings" - "golang.org/x/net/context" "vitess.io/vitess/go/vt/discovery" "vitess.io/vitess/go/vt/log" ) @@ -88,7 +87,7 @@ func getItemPath(url string) string { return parts[1] } -func initAPI(ctx context.Context, hc *discovery.HealthCheck) { +func initAPI(hc HealthCheck) { // Healthcheck real time status per (cell, keyspace, tablet type, metric). handleCollection("health-check", func(r *http.Request) (interface{}, error) { cacheStatus := hc.CacheStatus() @@ -144,7 +143,7 @@ func initAPI(ctx context.Context, hc *discovery.HealthCheck) { }) } -func legacyInitAPI(ctx context.Context, hc discovery.LegacyHealthCheck) { +func legacyInitAPI(hc discovery.LegacyHealthCheck) { // Healthcheck real time status per (cell, keyspace, tablet type, metric). handleCollection("health-check", func(r *http.Request) (interface{}, error) { cacheStatus := hc.CacheStatus() diff --git a/go/vt/vtgate/discoverygateway.go b/go/vt/vtgate/discoverygateway.go index 057e620d7f2..3fc31218f95 100644 --- a/go/vt/vtgate/discoverygateway.go +++ b/go/vt/vtgate/discoverygateway.go @@ -47,6 +47,11 @@ const ( GatewayImplementationDiscovery = "discoverygateway" ) +//UsingLegacyGateway returns true when legacy +func UsingLegacyGateway() bool { + return *GatewayImplementation == GatewayImplementationDiscovery +} + func init() { RegisterGatewayCreator(GatewayImplementationDiscovery, createDiscoveryGateway) } @@ -75,6 +80,13 @@ type DiscoveryGateway struct { buffer *buffer.Buffer } +//TabletsCacheStatus is not implemented for this struct +func (dg *DiscoveryGateway) TabletsCacheStatus() discovery.TabletsCacheStatusList { + return nil +} + +var _ Gateway = (*DiscoveryGateway)(nil) + func createDiscoveryGateway(ctx context.Context, hc discovery.LegacyHealthCheck, serv srvtopo.Server, cell string, retryCount int) Gateway { return NewDiscoveryGateway(ctx, hc, serv, cell, retryCount) } @@ -409,8 +421,7 @@ func NewShardError(in error, target *querypb.Target, tablet *topodatapb.Tablet) return in } -// HealthCheck should never be called on a DiscoveryGateway -// This exists only to satisfy the interface -func (dg *DiscoveryGateway) HealthCheck() *discovery.HealthCheck { - return nil +// QueryServiceByAlias satisfies the Gateway interface +func (dg *DiscoveryGateway) QueryServiceByAlias(_ *topodatapb.TabletAlias) (queryservice.QueryService, error) { + return nil, vterrors.New(vtrpcpb.Code_UNIMPLEMENTED, "DiscoveryGateway does not implement QueryServiceByAlias") } diff --git a/go/vt/vtgate/discoverygateway_test.go b/go/vt/vtgate/discoverygateway_test.go index b02ec1fa471..d2fc547f293 100644 --- a/go/vt/vtgate/discoverygateway_test.go +++ b/go/vt/vtgate/discoverygateway_test.go @@ -71,7 +71,7 @@ func TestDiscoveryGatewayExecuteStream(t *testing.T) { func TestDiscoveryGatewayBegin(t *testing.T) { testDiscoveryGatewayGeneric(t, func(dg *DiscoveryGateway, target *querypb.Target) error { - _, err := dg.Begin(context.Background(), target, nil) + _, _, err := dg.Begin(context.Background(), target, nil) return err }) } @@ -90,7 +90,7 @@ func TestDiscoveryGatewayRollback(t *testing.T) { func TestDiscoveryGatewayBeginExecute(t *testing.T) { testDiscoveryGatewayGeneric(t, func(dg *DiscoveryGateway, target *querypb.Target) error { - _, _, err := dg.BeginExecute(context.Background(), target, "query", nil, nil) + _, _, _, err := dg.BeginExecute(context.Background(), target, "query", nil, nil) return err }) } @@ -98,7 +98,7 @@ func TestDiscoveryGatewayBeginExecute(t *testing.T) { func TestDiscoveryGatewayBeginExecuteBatch(t *testing.T) { testDiscoveryGatewayGeneric(t, func(dg *DiscoveryGateway, target *querypb.Target) error { queries := []*querypb.BoundQuery{{Sql: "query", BindVariables: nil}} - _, _, err := dg.BeginExecuteBatch(context.Background(), target, queries, false, nil) + _, _, _, err := dg.BeginExecuteBatch(context.Background(), target, queries, false, nil) return err }) } diff --git a/go/vt/vtgate/engine/delete.go b/go/vt/vtgate/engine/delete.go index d1d935a6add..8aa40f6d7d1 100644 --- a/go/vt/vtgate/engine/delete.go +++ b/go/vt/vtgate/engine/delete.go @@ -69,7 +69,7 @@ func (del *Delete) GetTableName() string { } // Execute performs a non-streaming exec. -func (del *Delete) Execute(vcursor VCursor, bindVars map[string]*querypb.BindVariable, wantfields bool) (*sqltypes.Result, error) { +func (del *Delete) Execute(vcursor VCursor, bindVars map[string]*querypb.BindVariable, _ bool) (*sqltypes.Result, error) { if del.QueryTimeout != 0 { cancel := vcursor.SetContextTimeout(time.Duration(del.QueryTimeout) * time.Millisecond) defer cancel() @@ -93,12 +93,12 @@ func (del *Delete) Execute(vcursor VCursor, bindVars map[string]*querypb.BindVar } // StreamExecute performs a streaming exec. -func (del *Delete) StreamExecute(vcursor VCursor, bindVars map[string]*querypb.BindVariable, wantfields bool, callback func(*sqltypes.Result) error) error { +func (del *Delete) StreamExecute(VCursor, map[string]*querypb.BindVariable, bool, func(*sqltypes.Result) error) error { return fmt.Errorf("query %q cannot be used for streaming", del.Query) } // GetFields fetches the field info. -func (del *Delete) GetFields(vcursor VCursor, bindVars map[string]*querypb.BindVariable) (*sqltypes.Result, error) { +func (del *Delete) GetFields(VCursor, map[string]*querypb.BindVariable) (*sqltypes.Result, error) { return nil, fmt.Errorf("BUG: unreachable code for %q", del.Query) } @@ -110,6 +110,10 @@ func (del *Delete) execDeleteUnsharded(vcursor VCursor, bindVars map[string]*que if len(rss) != 1 { return nil, vterrors.Errorf(vtrpcpb.Code_FAILED_PRECONDITION, "Keyspace does not have exactly one shard: %v", rss) } + err = allowOnlyMaster(rss...) + if err != nil { + return nil, err + } return execShard(vcursor, del.Query, bindVars, rss[0], true, true /* canAutocommit */) } @@ -122,6 +126,11 @@ func (del *Delete) execDeleteEqual(vcursor VCursor, bindVars map[string]*querypb if err != nil { return nil, vterrors.Wrap(err, "execDeleteEqual") } + err = allowOnlyMaster(rs) + if err != nil { + return nil, err + } + if len(ksid) == 0 { return &sqltypes.Result{}, nil } @@ -139,6 +148,11 @@ func (del *Delete) execDeleteIn(vcursor VCursor, bindVars map[string]*querypb.Bi if err != nil { return nil, err } + err = allowOnlyMaster(rss...) + if err != nil { + return nil, err + } + if del.OwnedVindexQuery != "" { if err := del.deleteVindexEntries(vcursor, bindVars, rss); err != nil { return nil, vterrors.Wrap(err, "execDeleteIn") @@ -152,6 +166,10 @@ func (del *Delete) execDeleteByDestination(vcursor VCursor, bindVars map[string] if err != nil { return nil, vterrors.Wrap(err, "execDeleteScatter") } + err = allowOnlyMaster(rss...) + if err != nil { + return nil, err + } queries := make([]*querypb.BoundQuery, len(rss)) for i := range rss { diff --git a/go/vt/vtgate/engine/delete_test.go b/go/vt/vtgate/engine/delete_test.go index 5045d06fcb8..595e07e6735 100644 --- a/go/vt/vtgate/engine/delete_test.go +++ b/go/vt/vtgate/engine/delete_test.go @@ -20,6 +20,8 @@ import ( "errors" "testing" + "github.com/stretchr/testify/require" + "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/vtgate/vindexes" @@ -38,11 +40,9 @@ func TestDeleteUnsharded(t *testing.T) { }, } - vc := &loggingVCursor{shards: []string{"0"}} + vc := newDMLTestVCursor("0") _, err := del.Execute(vc, map[string]*querypb.BindVariable{}, false) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) vc.ExpectLog(t, []string{ `ResolveDestinations ks [] Destinations:DestinationAllShards()`, `ExecuteMultiShard ks.0: dummy_delete {} true true`, @@ -73,11 +73,9 @@ func TestDeleteEqual(t *testing.T) { }, } - vc := &loggingVCursor{shards: []string{"-20", "20-"}} + vc := newDMLTestVCursor("-20", "20-") _, err := del.Execute(vc, map[string]*querypb.BindVariable{}, false) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) vc.ExpectLog(t, []string{ `ResolveDestinations ks [] Destinations:DestinationKeyspaceID(166b40b44aba4bd6)`, `ExecuteMultiShard ks.-20: dummy_delete {} true true`, @@ -108,11 +106,9 @@ func TestDeleteEqualNoRoute(t *testing.T) { }, } - vc := &loggingVCursor{shards: []string{"0"}} + vc := newDMLTestVCursor("0") _, err := del.Execute(vc, map[string]*querypb.BindVariable{}, false) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) vc.ExpectLog(t, []string{ // This lookup query will return no rows. So, the DML will not be sent anywhere. `Execute select toc from lkp where from = :from from: type:INT64 value:"1" false`, @@ -139,7 +135,7 @@ func TestDeleteEqualNoScatter(t *testing.T) { }, } - vc := &loggingVCursor{shards: []string{"0"}} + vc := newDMLTestVCursor("0") _, err := del.Execute(vc, map[string]*querypb.BindVariable{}, false) expectError(t, "Execute", err, "execDeleteEqual: cannot map vindex to unique keyspace id: DestinationKeyRange(-)") } @@ -166,15 +162,12 @@ func TestDeleteOwnedVindex(t *testing.T) { ), "1|4|5|6", )} - vc := &loggingVCursor{ - shards: []string{"-20", "20-"}, - results: results, - } + + vc := newDMLTestVCursor("-20", "20-") + vc.results = results _, err := del.Execute(vc, map[string]*querypb.BindVariable{}, false) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) vc.ExpectLog(t, []string{ `ResolveDestinations sharded [] Destinations:DestinationKeyspaceID(166b40b44aba4bd6)`, // ResolveDestinations is hard-coded to return -20. @@ -188,13 +181,9 @@ func TestDeleteOwnedVindex(t *testing.T) { }) // No rows changing - vc = &loggingVCursor{ - shards: []string{"-20", "20-"}, - } + vc = newDMLTestVCursor("-20", "20-") _, err = del.Execute(vc, map[string]*querypb.BindVariable{}, false) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) vc.ExpectLog(t, []string{ `ResolveDestinations sharded [] Destinations:DestinationKeyspaceID(166b40b44aba4bd6)`, // ResolveDestinations is hard-coded to return -20. @@ -213,14 +202,11 @@ func TestDeleteOwnedVindex(t *testing.T) { "1|4|5|6", "1|7|8|9", )} - vc = &loggingVCursor{ - shards: []string{"-20", "20-"}, - results: results, - } + vc = newDMLTestVCursor("-20", "20-") + vc.results = results + _, err = del.Execute(vc, map[string]*querypb.BindVariable{}, false) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) vc.ExpectLog(t, []string{ `ResolveDestinations sharded [] Destinations:DestinationKeyspaceID(166b40b44aba4bd6)`, // ResolveDestinations is hard-coded to return -20. @@ -248,11 +234,9 @@ func TestDeleteSharded(t *testing.T) { }, } - vc := &loggingVCursor{shards: []string{"-20", "20-"}} + vc := newDMLTestVCursor("-20", "20-") _, err := del.Execute(vc, map[string]*querypb.BindVariable{}, false) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) vc.ExpectLog(t, []string{ `ResolveDestinations sharded [] Destinations:DestinationAllShards()`, `ExecuteMultiShard sharded.-20: dummy_delete {} sharded.20-: dummy_delete {} true false`, @@ -290,15 +274,12 @@ func TestDeleteScatterOwnedVindex(t *testing.T) { ), "1|4|5|6", )} - vc := &loggingVCursor{ - shards: []string{"-20", "20-"}, - results: results, - } + + vc := newDMLTestVCursor("-20", "20-") + vc.results = results _, err := del.Execute(vc, map[string]*querypb.BindVariable{}, false) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) vc.ExpectLog(t, []string{ `ResolveDestinations sharded [] Destinations:DestinationAllShards()`, // ResolveDestinations is hard-coded to return -20. @@ -312,13 +293,10 @@ func TestDeleteScatterOwnedVindex(t *testing.T) { }) // No rows changing - vc = &loggingVCursor{ - shards: []string{"-20", "20-"}, - } + vc = newDMLTestVCursor("-20", "20-") + _, err = del.Execute(vc, map[string]*querypb.BindVariable{}, false) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) vc.ExpectLog(t, []string{ `ResolveDestinations sharded [] Destinations:DestinationAllShards()`, // ResolveDestinations is hard-coded to return -20. @@ -337,14 +315,11 @@ func TestDeleteScatterOwnedVindex(t *testing.T) { "1|4|5|6", "1|7|8|9", )} - vc = &loggingVCursor{ - shards: []string{"-20", "20-"}, - results: results, - } + vc = newDMLTestVCursor("-20", "20-") + vc.results = results + _, err = del.Execute(vc, map[string]*querypb.BindVariable{}, false) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) vc.ExpectLog(t, []string{ `ResolveDestinations sharded [] Destinations:DestinationAllShards()`, // ResolveDestinations is hard-coded to return -20. diff --git a/go/vt/vtgate/engine/fake_vcursor_test.go b/go/vt/vtgate/engine/fake_vcursor_test.go index 5f4b2c71db9..7d93c779a72 100644 --- a/go/vt/vtgate/engine/fake_vcursor_test.go +++ b/go/vt/vtgate/engine/fake_vcursor_test.go @@ -25,6 +25,8 @@ import ( "testing" "time" + topodatapb "vitess.io/vitess/go/vt/proto/topodata" + "vitess.io/vitess/go/vt/sqlparser" "github.com/stretchr/testify/require" @@ -133,6 +135,8 @@ type loggingVCursor struct { multiShardErrs []error log []string + + resolvedTargetTabletType topodatapb.TabletType } func (f *loggingVCursor) SetUDV(key string, value interface{}) error { @@ -263,8 +267,9 @@ func (f *loggingVCursor) ResolveDestinations(keyspace string, ids []*querypb.Val visited[shard] = vi rss = append(rss, &srvtopo.ResolvedShard{ Target: &querypb.Target{ - Keyspace: keyspace, - Shard: shard, + Keyspace: keyspace, + Shard: shard, + TabletType: f.resolvedTargetTabletType, }, }) if ids != nil { diff --git a/go/vt/vtgate/engine/insert.go b/go/vt/vtgate/engine/insert.go index 7e9d7af07e5..86783b06f79 100644 --- a/go/vt/vtgate/engine/insert.go +++ b/go/vt/vtgate/engine/insert.go @@ -227,6 +227,10 @@ func (ins *Insert) execInsertUnsharded(vcursor VCursor, bindVars map[string]*que if len(rss) != 1 { return nil, vterrors.Errorf(vtrpcpb.Code_FAILED_PRECONDITION, "Keyspace does not have exactly one shard: %v", rss) } + err = allowOnlyMaster(rss...) + if err != nil { + return nil, err + } result, err := execShard(vcursor, ins.Query, bindVars, rss[0], true, true /* canAutocommit */) if err != nil { return nil, vterrors.Wrap(err, "execInsertUnsharded") @@ -253,6 +257,10 @@ func (ins *Insert) execInsertSharded(vcursor VCursor, bindVars map[string]*query } autocommit := (len(rss) == 1 || ins.MultiShardAutocommit) && vcursor.AutocommitApproval() + err = allowOnlyMaster(rss...) + if err != nil { + return nil, err + } result, errs := vcursor.ExecuteMultiShard(rss, queries, true /* rollbackOnError */, autocommit) if errs != nil { return nil, vterrors.Wrap(vterrors.Aggregate(errs), "execInsertSharded") diff --git a/go/vt/vtgate/engine/insert_test.go b/go/vt/vtgate/engine/insert_test.go index c51d4f37a61..53f495fd168 100644 --- a/go/vt/vtgate/engine/insert_test.go +++ b/go/vt/vtgate/engine/insert_test.go @@ -37,12 +37,11 @@ func TestInsertUnsharded(t *testing.T) { "dummy_insert", ) - vc := &loggingVCursor{ - shards: []string{"0"}, - results: []*sqltypes.Result{{ - InsertID: 4, - }}, - } + vc := newDMLTestVCursor("0") + vc.results = []*sqltypes.Result{{ + InsertID: 4, + }} + result, err := ins.Execute(vc, map[string]*querypb.BindVariable{}, false) if err != nil { t.Fatal(err) @@ -89,19 +88,18 @@ func TestInsertUnshardedGenerate(t *testing.T) { }, } - vc := &loggingVCursor{ - shards: []string{"0"}, - results: []*sqltypes.Result{ - sqltypes.MakeTestResult( - sqltypes.MakeTestFields( - "nextval", - "int64", - ), - "4", + vc := newDMLTestVCursor("0") + vc.results = []*sqltypes.Result{ + sqltypes.MakeTestResult( + sqltypes.MakeTestFields( + "nextval", + "int64", ), - {InsertID: 1}, - }, + "4", + ), + {InsertID: 1}, } + result, err := ins.Execute(vc, map[string]*querypb.BindVariable{}, false) if err != nil { t.Fatal(err) @@ -164,10 +162,9 @@ func TestInsertShardedSimple(t *testing.T) { []string{" mid1"}, " suffix", ) - vc := &loggingVCursor{ - shards: []string{"-20", "20-"}, - shardForKsid: []string{"20-", "-20", "20-"}, - } + vc := newDMLTestVCursor("-20", "20-") + vc.shardForKsid = []string{"20-", "-20", "20-"} + _, err = ins.Execute(vc, map[string]*querypb.BindVariable{}, false) if err != nil { t.Fatal(err) @@ -203,10 +200,9 @@ func TestInsertShardedSimple(t *testing.T) { []string{" mid1", " mid2", " mid3"}, " suffix", ) - vc = &loggingVCursor{ - shards: []string{"-20", "20-"}, - shardForKsid: []string{"20-", "-20", "20-"}, - } + vc = newDMLTestVCursor("-20", "20-") + vc.shardForKsid = []string{"20-", "-20", "20-"} + _, err = ins.Execute(vc, map[string]*querypb.BindVariable{}, false) if err != nil { t.Fatal(err) @@ -245,10 +241,9 @@ func TestInsertShardedSimple(t *testing.T) { ) ins.MultiShardAutocommit = true - vc = &loggingVCursor{ - shards: []string{"-20", "20-"}, - shardForKsid: []string{"20-", "-20", "20-"}, - } + vc = newDMLTestVCursor("-20", "20-") + vc.shardForKsid = []string{"20-", "-20", "20-"} + _, err = ins.Execute(vc, map[string]*querypb.BindVariable{}, false) if err != nil { t.Fatal(err) @@ -385,20 +380,19 @@ func TestInsertShardedGenerate(t *testing.T) { }, } - vc := &loggingVCursor{ - shards: []string{"-20", "20-"}, - shardForKsid: []string{"20-", "-20", "20-"}, - results: []*sqltypes.Result{ - sqltypes.MakeTestResult( - sqltypes.MakeTestFields( - "nextval", - "int64", - ), - "2", + vc := newDMLTestVCursor("-20", "20-") + vc.shardForKsid = []string{"20-", "-20", "20-"} + vc.results = []*sqltypes.Result{ + sqltypes.MakeTestResult( + sqltypes.MakeTestFields( + "nextval", + "int64", ), - {InsertID: 1}, - }, + "2", + ), + {InsertID: 1}, } + result, err := ins.Execute(vc, map[string]*querypb.BindVariable{}, false) if err != nil { t.Fatal(err) @@ -529,10 +523,9 @@ func TestInsertShardedOwned(t *testing.T) { " suffix", ) - vc := &loggingVCursor{ - shards: []string{"-20", "20-"}, - shardForKsid: []string{"20-", "-20", "20-"}, - } + vc := newDMLTestVCursor("-20", "20-") + vc.shardForKsid = []string{"20-", "-20", "20-"} + _, err = ins.Execute(vc, map[string]*querypb.BindVariable{}, false) if err != nil { t.Fatal(err) @@ -628,10 +621,9 @@ func TestInsertShardedOwnedWithNull(t *testing.T) { " suffix", ) - vc := &loggingVCursor{ - shards: []string{"-20", "20-"}, - shardForKsid: []string{"20-", "-20", "20-"}, - } + vc := newDMLTestVCursor("-20", "20-") + vc.shardForKsid = []string{"20-", "-20", "20-"} + _, err = ins.Execute(vc, map[string]*querypb.BindVariable{}, false) if err != nil { t.Fatal(err) @@ -722,10 +714,9 @@ func TestInsertShardedGeo(t *testing.T) { " suffix", ) - vc := &loggingVCursor{ - shards: []string{"-20", "20-"}, - shardForKsid: []string{"20-", "-20"}, - } + vc := newDMLTestVCursor("-20", "20-") + vc.shardForKsid = []string{"20-", "-20"} + _, err = ins.Execute(vc, map[string]*querypb.BindVariable{}, false) if err != nil { t.Fatal(err) @@ -872,28 +863,27 @@ func TestInsertShardedIgnoreOwned(t *testing.T) { "\x00", ) noresult := &sqltypes.Result{} - vc := &loggingVCursor{ - shards: []string{"-20", "20-"}, - shardForKsid: []string{"20-", "-20"}, - results: []*sqltypes.Result{ - // primary vindex lookups: fail row 2. - ksid0, - noresult, - ksid0, - ksid0, - // insert lkp2 - noresult, - // fail one verification (row 3) - ksid0, - noresult, - ksid0, - // insert lkp1 - noresult, - // verify lkp1 (only two rows to verify) - ksid0, - ksid0, - }, + vc := newDMLTestVCursor("-20", "20-") + vc.shardForKsid = []string{"20-", "-20"} + vc.results = []*sqltypes.Result{ + // primary vindex lookups: fail row 2. + ksid0, + noresult, + ksid0, + ksid0, + // insert lkp2 + noresult, + // fail one verification (row 3) + ksid0, + noresult, + ksid0, + // insert lkp1 + noresult, + // verify lkp1 (only two rows to verify) + ksid0, + ksid0, } + _, err = ins.Execute(vc, map[string]*querypb.BindVariable{}, false) if err != nil { t.Fatal(err) @@ -1009,15 +999,14 @@ func TestInsertShardedIgnoreOwnedWithNull(t *testing.T) { ), "\x00", ) - vc := &loggingVCursor{ - shards: []string{"-20", "20-"}, - shardForKsid: []string{"-20", "20-"}, - results: []*sqltypes.Result{ - ksid0, - ksid0, - ksid0, - }, + vc := newDMLTestVCursor("-20", "20-") + vc.shardForKsid = []string{"-20", "20-"} + vc.results = []*sqltypes.Result{ + ksid0, + ksid0, + ksid0, } + _, err = ins.Execute(vc, map[string]*querypb.BindVariable{}, false) if err != nil { t.Fatal(err) @@ -1143,17 +1132,15 @@ func TestInsertShardedUnownedVerify(t *testing.T) { "1", ) - vc := &loggingVCursor{ - shards: []string{"-20", "20-"}, - shardForKsid: []string{"20-", "-20", "20-"}, - results: []*sqltypes.Result{ - nonemptyResult, - nonemptyResult, - nonemptyResult, - nonemptyResult, - nonemptyResult, - nonemptyResult, - }, + vc := newDMLTestVCursor("-20", "20-") + vc.shardForKsid = []string{"20-", "-20", "20-"} + vc.results = []*sqltypes.Result{ + nonemptyResult, + nonemptyResult, + nonemptyResult, + nonemptyResult, + nonemptyResult, + nonemptyResult, } _, err = ins.Execute(vc, map[string]*querypb.BindVariable{}, false) if err != nil { @@ -1266,15 +1253,13 @@ func TestInsertShardedIgnoreUnownedVerify(t *testing.T) { "1", ) - vc := &loggingVCursor{ - shards: []string{"-20", "20-"}, - shardForKsid: []string{"20-", "-20"}, - results: []*sqltypes.Result{ - nonemptyResult, - // fail verification of second row. - {}, - nonemptyResult, - }, + vc := newDMLTestVCursor("-20", "20-") + vc.shardForKsid = []string{"20-", "-20"} + vc.results = []*sqltypes.Result{ + nonemptyResult, + // fail verification of second row. + {}, + nonemptyResult, } _, err = ins.Execute(vc, map[string]*querypb.BindVariable{}, false) if err != nil { @@ -1363,9 +1348,8 @@ func TestInsertShardedIgnoreUnownedVerifyFail(t *testing.T) { " suffix", ) - vc := &loggingVCursor{ - shards: []string{"-20", "20-"}, - } + vc := newDMLTestVCursor("-20", "20-") + _, err = ins.Execute(vc, map[string]*querypb.BindVariable{}, false) expectError(t, "Execute", err, "execInsertSharded: getInsertShardedRoute: values [[INT64(2)]] for column [c3] does not map to keyspace ids") } @@ -1483,13 +1467,12 @@ func TestInsertShardedUnownedReverseMap(t *testing.T) { "1", ) - vc := &loggingVCursor{ - shards: []string{"-20", "20-"}, - shardForKsid: []string{"20-", "-20", "20-"}, - results: []*sqltypes.Result{ - nonemptyResult, - }, + vc := newDMLTestVCursor("-20", "20-") + vc.shardForKsid = []string{"20-", "-20", "20-"} + vc.results = []*sqltypes.Result{ + nonemptyResult, } + _, err = ins.Execute(vc, map[string]*querypb.BindVariable{}, false) if err != nil { t.Fatal(err) @@ -1575,9 +1558,8 @@ func TestInsertShardedUnownedReverseMapFail(t *testing.T) { " suffix", ) - vc := &loggingVCursor{ - shards: []string{"-20", "20-"}, - } + vc := newDMLTestVCursor("-20", "20-") + _, err = ins.Execute(vc, map[string]*querypb.BindVariable{}, false) expectError(t, "Execute", err, "execInsertSharded: getInsertShardedRoute: value must be supplied for column [c3]") } diff --git a/go/vt/vtgate/engine/route.go b/go/vt/vtgate/engine/route.go index 0e799d93c24..16adb701003 100644 --- a/go/vt/vtgate/engine/route.go +++ b/go/vt/vtgate/engine/route.go @@ -23,6 +23,9 @@ import ( "strconv" "time" + vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" + "vitess.io/vitess/go/vt/topo/topoproto" + "vitess.io/vitess/go/vt/vtgate/evalengine" "vitess.io/vitess/go/mysql" @@ -553,6 +556,15 @@ func shardVars(bv map[string]*querypb.BindVariable, mapVals [][]*querypb.Value) return shardVars } +func allowOnlyMaster(rss ...*srvtopo.ResolvedShard) error { + for _, rs := range rss { + if rs != nil && rs.Target.TabletType != topodatapb.TabletType_MASTER { + return vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "supported only for master tablet type, current type: %v", topoproto.TabletTypeLString(rs.Target.TabletType)) + } + } + return nil +} + func (route *Route) description() PrimitiveDescription { other := map[string]interface{}{ "Query": route.Query, diff --git a/go/vt/vtgate/engine/update.go b/go/vt/vtgate/engine/update.go index c8717589da9..14b0a2682fb 100644 --- a/go/vt/vtgate/engine/update.go +++ b/go/vt/vtgate/engine/update.go @@ -117,6 +117,10 @@ func (upd *Update) execUpdateUnsharded(vcursor VCursor, bindVars map[string]*que if len(rss) != 1 { return nil, vterrors.Errorf(vtrpcpb.Code_FAILED_PRECONDITION, "Keyspace does not have exactly one shard: %v", rss) } + err = allowOnlyMaster(rss...) + if err != nil { + return nil, err + } return execShard(vcursor, upd.Query, bindVars, rss[0], true, true /* canAutocommit */) } @@ -129,6 +133,10 @@ func (upd *Update) execUpdateEqual(vcursor VCursor, bindVars map[string]*querypb if err != nil { return nil, vterrors.Wrap(err, "execUpdateEqual") } + err = allowOnlyMaster(rs) + if err != nil { + return nil, err + } if len(ksid) == 0 { return &sqltypes.Result{}, nil } @@ -145,6 +153,10 @@ func (upd *Update) execUpdateIn(vcursor VCursor, bindVars map[string]*querypb.Bi if err != nil { return nil, err } + err = allowOnlyMaster(rss...) + if err != nil { + return nil, err + } if len(upd.ChangedVindexValues) != 0 { if err := upd.updateVindexEntries(vcursor, bindVars, rss); err != nil { return nil, vterrors.Wrap(err, "execUpdateIn") @@ -158,6 +170,10 @@ func (upd *Update) execUpdateByDestination(vcursor VCursor, bindVars map[string] if err != nil { return nil, vterrors.Wrap(err, "execUpdateByDestination") } + err = allowOnlyMaster(rss...) + if err != nil { + return nil, err + } queries := make([]*querypb.BoundQuery, len(rss)) for i := range rss { diff --git a/go/vt/vtgate/engine/update_test.go b/go/vt/vtgate/engine/update_test.go index 7851e6568fc..a9a391d0e81 100644 --- a/go/vt/vtgate/engine/update_test.go +++ b/go/vt/vtgate/engine/update_test.go @@ -20,6 +20,8 @@ import ( "errors" "testing" + topodatapb "vitess.io/vitess/go/vt/proto/topodata" + "github.com/stretchr/testify/require" "vitess.io/vitess/go/sqltypes" @@ -41,7 +43,7 @@ func TestUpdateUnsharded(t *testing.T) { }, } - vc := &loggingVCursor{shards: []string{"0"}} + vc := newDMLTestVCursor("0") _, err := upd.Execute(vc, map[string]*querypb.BindVariable{}, false) require.NoError(t, err) vc.ExpectLog(t, []string{ @@ -74,7 +76,7 @@ func TestUpdateEqual(t *testing.T) { }, } - vc := &loggingVCursor{shards: []string{"-20", "20-"}} + vc := newDMLTestVCursor("-20", "20-") _, err := upd.Execute(vc, map[string]*querypb.BindVariable{}, false) require.NoError(t, err) vc.ExpectLog(t, []string{ @@ -103,7 +105,7 @@ func TestUpdateScatter(t *testing.T) { }, } - vc := &loggingVCursor{shards: []string{"-20", "20-"}} + vc := newDMLTestVCursor("-20", "20-") _, err := upd.Execute(vc, map[string]*querypb.BindVariable{}, false) require.NoError(t, err) @@ -127,7 +129,7 @@ func TestUpdateScatter(t *testing.T) { }, } - vc = &loggingVCursor{shards: []string{"-20", "20-"}} + vc = newDMLTestVCursor("-20", "20-") _, err = upd.Execute(vc, map[string]*querypb.BindVariable{}, false) require.NoError(t, err) @@ -156,7 +158,7 @@ func TestUpdateEqualNoRoute(t *testing.T) { }, } - vc := &loggingVCursor{shards: []string{"0"}} + vc := newDMLTestVCursor("0") _, err := upd.Execute(vc, map[string]*querypb.BindVariable{}, false) require.NoError(t, err) vc.ExpectLog(t, []string{ @@ -185,7 +187,7 @@ func TestUpdateEqualNoScatter(t *testing.T) { }, } - vc := &loggingVCursor{shards: []string{"0"}} + vc := newDMLTestVCursor("0") _, err := upd.Execute(vc, map[string]*querypb.BindVariable{}, false) expectError(t, "Execute", err, "execUpdateEqual: cannot map vindex to unique keyspace id: DestinationKeyRange(-)") } @@ -221,10 +223,8 @@ func TestUpdateEqualChangedVindex(t *testing.T) { ), "1|4|5|6", )} - vc := &loggingVCursor{ - shards: []string{"-20", "20-"}, - results: results, - } + vc := newDMLTestVCursor("-20", "20-") + vc.results = results _, err := upd.Execute(vc, map[string]*querypb.BindVariable{}, false) require.NoError(t, err) @@ -245,9 +245,8 @@ func TestUpdateEqualChangedVindex(t *testing.T) { }) // No rows changing - vc = &loggingVCursor{ - shards: []string{"-20", "20-"}, - } + vc = newDMLTestVCursor("-20", "20-") + _, err = upd.Execute(vc, map[string]*querypb.BindVariable{}, false) require.NoError(t, err) vc.ExpectLog(t, []string{ @@ -268,10 +267,9 @@ func TestUpdateEqualChangedVindex(t *testing.T) { "1|4|5|6", "1|7|8|9", )} - vc = &loggingVCursor{ - shards: []string{"-20", "20-"}, - results: results, - } + vc = newDMLTestVCursor("-20", "20-") + vc.results = results + _, err = upd.Execute(vc, map[string]*querypb.BindVariable{}, false) require.NoError(t, err) vc.ExpectLog(t, []string{ @@ -326,10 +324,8 @@ func TestUpdateScatterChangedVindex(t *testing.T) { ), "1|4|5|6", )} - vc := &loggingVCursor{ - shards: []string{"-20", "20-"}, - results: results, - } + vc := newDMLTestVCursor("-20", "20-") + vc.results = results _, err := upd.Execute(vc, map[string]*querypb.BindVariable{}, false) require.NoError(t, err) @@ -348,9 +344,8 @@ func TestUpdateScatterChangedVindex(t *testing.T) { }) // No rows changing - vc = &loggingVCursor{ - shards: []string{"-20", "20-"}, - } + vc = newDMLTestVCursor("-20", "20-") + _, err = upd.Execute(vc, map[string]*querypb.BindVariable{}, false) if err != nil { t.Fatal(err) @@ -373,10 +368,9 @@ func TestUpdateScatterChangedVindex(t *testing.T) { "1|4|5|6", "1|7|8|9", )} - vc = &loggingVCursor{ - shards: []string{"-20", "20-"}, - results: results, - } + vc = newDMLTestVCursor("-20", "20-") + vc.results = results + _, err = upd.Execute(vc, map[string]*querypb.BindVariable{}, false) require.NoError(t, err) vc.ExpectLog(t, []string{ @@ -419,7 +413,7 @@ func TestUpdateIn(t *testing.T) { }}, } - vc := &loggingVCursor{shards: []string{"-20", "20-"}} + vc := newDMLTestVCursor("-20", "20-") _, err := upd.Execute(vc, map[string]*querypb.BindVariable{}, false) require.NoError(t, err) vc.ExpectLog(t, []string{ @@ -466,10 +460,8 @@ func TestUpdateInChangedVindex(t *testing.T) { "1|4|5|6", "2|21|22|23", )} - vc := &loggingVCursor{ - shards: []string{"-20", "20-"}, - results: results, - } + vc := newDMLTestVCursor("-20", "20-") + vc.results = results _, err := upd.Execute(vc, map[string]*querypb.BindVariable{}, false) require.NoError(t, err) @@ -496,9 +488,8 @@ func TestUpdateInChangedVindex(t *testing.T) { }) // No rows changing - vc = &loggingVCursor{ - shards: []string{"-20", "20-"}, - } + vc = newDMLTestVCursor("-20", "20-") + _, err = upd.Execute(vc, map[string]*querypb.BindVariable{}, false) require.NoError(t, err) vc.ExpectLog(t, []string{ @@ -520,10 +511,9 @@ func TestUpdateInChangedVindex(t *testing.T) { "1|7|8|9", "2|21|22|23", )} - vc = &loggingVCursor{ - shards: []string{"-20", "20-"}, - results: results, - } + vc = newDMLTestVCursor("-20", "20-") + vc.results = results + _, err = upd.Execute(vc, map[string]*querypb.BindVariable{}, false) require.NoError(t, err) vc.ExpectLog(t, []string{ @@ -619,3 +609,7 @@ func buildTestVSchema() *vindexes.VSchema { } return vs } + +func newDMLTestVCursor(shards ...string) *loggingVCursor { + return &loggingVCursor{shards: shards, resolvedTargetTabletType: topodatapb.TabletType_MASTER} +} diff --git a/go/vt/vtgate/executor.go b/go/vt/vtgate/executor.go index 4c1f74a071a..fd67b23ddae 100644 --- a/go/vt/vtgate/executor.go +++ b/go/vt/vtgate/executor.go @@ -195,8 +195,9 @@ func (e *Executor) legacyExecute(ctx context.Context, safeSession *SafeSession, return 0, nil, err } - if safeSession.InTransaction() && destTabletType != topodatapb.TabletType_MASTER { - return 0, nil, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "transactions are supported only for master tablet types, current type: %v", destTabletType) + // Legacy gateway allows transactions only on MASTER + if UsingLegacyGateway() && safeSession.InTransaction() && destTabletType != topodatapb.TabletType_MASTER { + return 0, nil, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "Executor.execute: transactions are supported only for master tablet types, current type: %v", destTabletType) } if bindVars == nil { bindVars = make(map[string]*querypb.BindVariable) @@ -267,9 +268,6 @@ func (e *Executor) destinationExec(ctx context.Context, safeSession *SafeSession } func (e *Executor) handleBegin(ctx context.Context, safeSession *SafeSession, destTabletType topodatapb.TabletType, logStats *LogStats) (*sqltypes.Result, error) { - if destTabletType != topodatapb.TabletType_MASTER { - return nil, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "transactions are supported only for master tablet types, current type: %v", destTabletType) - } execStart := time.Now() logStats.PlanTime = execStart.Sub(logStats.StartTime) err := e.txConn.Begin(ctx, safeSession) @@ -834,64 +832,7 @@ func (e *Executor) handleShow(ctx context.Context, safeSession *SafeSession, sql RowsAffected: uint64(len(rows)), }, nil case "vitess_tablets": - var rows [][]sqltypes.Value - if *GatewayImplementation == GatewayImplementationDiscovery { - status := e.scatterConn.GetLegacyHealthCheckCacheStatus() - for _, s := range status { - for _, ts := range s.TabletsStats { - state := "SERVING" - if !ts.Serving { - state = "NOT_SERVING" - } - mtst := ts.Tablet.MasterTermStartTime - mtstStr := "" - if mtst != nil && mtst.Seconds > 0 { - mtstStr = logutil.ProtoToTime(ts.Tablet.MasterTermStartTime).Format(time.RFC3339) - } - rows = append(rows, buildVarCharRow( - s.Cell, - s.Target.Keyspace, - s.Target.Shard, - ts.Target.TabletType.String(), - state, - topoproto.TabletAliasString(ts.Tablet.Alias), - ts.Tablet.Hostname, - mtstStr, - )) - } - } - } - if *GatewayImplementation == tabletGatewayImplementation { - status := e.scatterConn.GetHealthCheckCacheStatus() - for _, s := range status { - for _, ts := range s.TabletsStats { - state := "SERVING" - if !ts.Serving { - state = "NOT_SERVING" - } - mtst := ts.Tablet.MasterTermStartTime - mtstStr := "" - if mtst != nil && mtst.Seconds > 0 { - mtstStr = logutil.ProtoToTime(ts.Tablet.MasterTermStartTime).Format(time.RFC3339) - } - rows = append(rows, buildVarCharRow( - s.Cell, - s.Target.Keyspace, - s.Target.Shard, - ts.Target.TabletType.String(), - state, - topoproto.TabletAliasString(ts.Tablet.Alias), - ts.Tablet.Hostname, - mtstStr, - )) - } - } - } - return &sqltypes.Result{ - Fields: buildVarCharFields("Cell", "Keyspace", "Shard", "TabletType", "State", "Alias", "Hostname", "MasterTermStartTime"), - Rows: rows, - RowsAffected: uint64(len(rows)), - }, nil + return e.showTablets() case "vitess_target": var rows [][]sqltypes.Value rows = append(rows, buildVarCharRow(safeSession.TargetString)) @@ -1038,6 +979,66 @@ func (e *Executor) handleShow(ctx context.Context, safeSession *SafeSession, sql return e.handleOther(ctx, safeSession, sql, bindVars, dest, destKeyspace, destTabletType, logStats) } +func (e *Executor) showTablets() (*sqltypes.Result, error) { + var rows [][]sqltypes.Value + if UsingLegacyGateway() { + status := e.scatterConn.GetLegacyHealthCheckCacheStatus() + for _, s := range status { + for _, ts := range s.TabletsStats { + state := "SERVING" + if !ts.Serving { + state = "NOT_SERVING" + } + mtst := ts.Tablet.MasterTermStartTime + mtstStr := "" + if mtst != nil && mtst.Seconds > 0 { + mtstStr = logutil.ProtoToTime(ts.Tablet.MasterTermStartTime).Format(time.RFC3339) + } + rows = append(rows, buildVarCharRow( + s.Cell, + s.Target.Keyspace, + s.Target.Shard, + ts.Target.TabletType.String(), + state, + topoproto.TabletAliasString(ts.Tablet.Alias), + ts.Tablet.Hostname, + mtstStr, + )) + } + } + } else { + status := e.scatterConn.GetHealthCheckCacheStatus() + for _, s := range status { + for _, ts := range s.TabletsStats { + state := "SERVING" + if !ts.Serving { + state = "NOT_SERVING" + } + mtst := ts.Tablet.MasterTermStartTime + mtstStr := "" + if mtst != nil && mtst.Seconds > 0 { + mtstStr = logutil.ProtoToTime(ts.Tablet.MasterTermStartTime).Format(time.RFC3339) + } + rows = append(rows, buildVarCharRow( + s.Cell, + s.Target.Keyspace, + s.Target.Shard, + ts.Target.TabletType.String(), + state, + topoproto.TabletAliasString(ts.Tablet.Alias), + ts.Tablet.Hostname, + mtstStr, + )) + } + } + } + return &sqltypes.Result{ + Fields: buildVarCharFields("Cell", "Keyspace", "Shard", "TabletType", "State", "Alias", "Hostname", "MasterTermStartTime"), + Rows: rows, + RowsAffected: uint64(len(rows)), + }, nil +} + func (e *Executor) handleOther(ctx context.Context, safeSession *SafeSession, sql string, bindVars map[string]*querypb.BindVariable, dest key.Destination, destKeyspace string, destTabletType topodatapb.TabletType, logStats *LogStats) (*sqltypes.Result, error) { if destKeyspace == "" { return nil, errNoKeyspace @@ -1515,8 +1516,8 @@ func (e *Executor) prepare(ctx context.Context, safeSession *SafeSession, sql st return nil, err } - if safeSession.InTransaction() && destTabletType != topodatapb.TabletType_MASTER { - return nil, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "transactions are supported only for master tablet types, current type: %v", destTabletType) + if UsingLegacyGateway() && safeSession.InTransaction() && destTabletType != topodatapb.TabletType_MASTER { + return nil, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "Executor.prepare: transactions are supported only for master tablet types, current type: %v", destTabletType) } if bindVars == nil { bindVars = make(map[string]*querypb.BindVariable) diff --git a/go/vt/vtgate/executor_framework_test.go b/go/vt/vtgate/executor_framework_test.go index e46c67dcffe..344c6688885 100644 --- a/go/vt/vtgate/executor_framework_test.go +++ b/go/vt/vtgate/executor_framework_test.go @@ -332,6 +332,8 @@ func newKeyRangeLookuperUnique(name string, params map[string]string) (vindexes. func init() { vindexes.Register("keyrange_lookuper", newKeyRangeLookuper) vindexes.Register("keyrange_lookuper_unique", newKeyRangeLookuperUnique) + // Use legacy gateway until we can rewrite these tests to use new tabletgateway + *GatewayImplementation = GatewayImplementationDiscovery } func createExecutorEnv() (executor *Executor, sbc1, sbc2, sbclookup *sandboxconn.SandboxConn) { @@ -342,7 +344,7 @@ func createExecutorEnv() (executor *Executor, sbc1, sbc2, sbclookup *sandboxconn s := createSandbox("TestExecutor") s.VSchema = executorVSchema serv := newSandboxForCells([]string{cell}) - resolver := newTestResolver(hc, serv, cell) + resolver := newTestLegacyResolver(hc, serv, cell) sbc1 = hc.AddTestTablet(cell, "-20", 1, "TestExecutor", "-20", topodatapb.TabletType_MASTER, true, 1, nil) sbc2 = hc.AddTestTablet(cell, "40-60", 1, "TestExecutor", "40-60", topodatapb.TabletType_MASTER, true, 1, nil) // Create these connections so scatter queries don't fail. @@ -374,7 +376,7 @@ func createCustomExecutor(vschema string) (executor *Executor, sbc1, sbc2, sbclo s := createSandbox("TestExecutor") s.VSchema = vschema serv := newSandboxForCells([]string{cell}) - resolver := newTestResolver(hc, serv, cell) + resolver := newTestLegacyResolver(hc, serv, cell) sbc1 = hc.AddTestTablet(cell, "-20", 1, "TestExecutor", "-20", topodatapb.TabletType_MASTER, true, 1, nil) sbc2 = hc.AddTestTablet(cell, "40-60", 1, "TestExecutor", "40-60", topodatapb.TabletType_MASTER, true, 1, nil) @@ -559,8 +561,8 @@ func testQueryLog(t *testing.T, logChan chan interface{}, method, stmtType, sql return logStats } -func newTestResolver(hc discovery.LegacyHealthCheck, serv srvtopo.Server, cell string) *Resolver { - sc := newTestScatterConn(hc, serv, cell) +func newTestLegacyResolver(hc discovery.LegacyHealthCheck, serv srvtopo.Server, cell string) *Resolver { + sc := newTestLegacyScatterConn(hc, serv, cell) srvResolver := srvtopo.NewResolver(serv, sc.gateway, cell) return NewResolver(srvResolver, serv, cell, sc) } diff --git a/go/vt/vtgate/executor_select_test.go b/go/vt/vtgate/executor_select_test.go index c0ce94c4ac4..6f760832710 100644 --- a/go/vt/vtgate/executor_select_test.go +++ b/go/vt/vtgate/executor_select_test.go @@ -899,7 +899,7 @@ func TestSelectScatter(t *testing.T) { s.VSchema = executorVSchema getSandbox(KsTestUnsharded).VSchema = unshardedVSchema serv := new(sandboxTopo) - resolver := newTestResolver(hc, serv, cell) + resolver := newTestLegacyResolver(hc, serv, cell) shards := []string{"-20", "20-40", "40-60", "60-80", "80-a0", "a0-c0", "c0-e0", "e0-"} var conns []*sandboxconn.SandboxConn for _, shard := range shards { @@ -932,7 +932,7 @@ func TestSelectScatterPartial(t *testing.T) { s.VSchema = executorVSchema getSandbox(KsTestUnsharded).VSchema = unshardedVSchema serv := new(sandboxTopo) - resolver := newTestResolver(hc, serv, cell) + resolver := newTestLegacyResolver(hc, serv, cell) shards := []string{"-20", "20-40", "40-60", "60-80", "80-a0", "a0-c0", "c0-e0", "e0-"} var conns []*sandboxconn.SandboxConn for _, shard := range shards { @@ -992,7 +992,7 @@ func TestStreamSelectScatter(t *testing.T) { s.VSchema = executorVSchema getSandbox(KsTestUnsharded).VSchema = unshardedVSchema serv := new(sandboxTopo) - resolver := newTestResolver(hc, serv, cell) + resolver := newTestLegacyResolver(hc, serv, cell) shards := []string{"-20", "20-40", "40-60", "60-80", "80-a0", "a0-c0", "c0-e0", "e0-"} for _, shard := range shards { _ = hc.AddTestTablet(cell, shard, 1, "TestExecutor", shard, topodatapb.TabletType_MASTER, true, 1, nil) @@ -1029,7 +1029,7 @@ func TestSelectScatterOrderBy(t *testing.T) { s.VSchema = executorVSchema getSandbox(KsTestUnsharded).VSchema = unshardedVSchema serv := new(sandboxTopo) - resolver := newTestResolver(hc, serv, cell) + resolver := newTestLegacyResolver(hc, serv, cell) shards := []string{"-20", "20-40", "40-60", "60-80", "80-a0", "a0-c0", "c0-e0", "e0-"} var conns []*sandboxconn.SandboxConn for i, shard := range shards { @@ -1099,7 +1099,7 @@ func TestSelectScatterOrderByVarChar(t *testing.T) { s.VSchema = executorVSchema getSandbox(KsTestUnsharded).VSchema = unshardedVSchema serv := new(sandboxTopo) - resolver := newTestResolver(hc, serv, cell) + resolver := newTestLegacyResolver(hc, serv, cell) shards := []string{"-20", "20-40", "40-60", "60-80", "80-a0", "a0-c0", "c0-e0", "e0-"} var conns []*sandboxconn.SandboxConn for i, shard := range shards { @@ -1169,7 +1169,7 @@ func TestStreamSelectScatterOrderBy(t *testing.T) { s.VSchema = executorVSchema getSandbox(KsTestUnsharded).VSchema = unshardedVSchema serv := new(sandboxTopo) - resolver := newTestResolver(hc, serv, cell) + resolver := newTestLegacyResolver(hc, serv, cell) shards := []string{"-20", "20-40", "40-60", "60-80", "80-a0", "a0-c0", "c0-e0", "e0-"} var conns []*sandboxconn.SandboxConn for i, shard := range shards { @@ -1230,7 +1230,7 @@ func TestStreamSelectScatterOrderByVarChar(t *testing.T) { s.VSchema = executorVSchema getSandbox(KsTestUnsharded).VSchema = unshardedVSchema serv := new(sandboxTopo) - resolver := newTestResolver(hc, serv, cell) + resolver := newTestLegacyResolver(hc, serv, cell) shards := []string{"-20", "20-40", "40-60", "60-80", "80-a0", "a0-c0", "c0-e0", "e0-"} var conns []*sandboxconn.SandboxConn for i, shard := range shards { @@ -1293,7 +1293,7 @@ func TestSelectScatterAggregate(t *testing.T) { s.VSchema = executorVSchema getSandbox(KsTestUnsharded).VSchema = unshardedVSchema serv := new(sandboxTopo) - resolver := newTestResolver(hc, serv, cell) + resolver := newTestLegacyResolver(hc, serv, cell) shards := []string{"-20", "20-40", "40-60", "60-80", "80-a0", "a0-c0", "c0-e0", "e0-"} var conns []*sandboxconn.SandboxConn for i, shard := range shards { @@ -1356,7 +1356,7 @@ func TestStreamSelectScatterAggregate(t *testing.T) { s.VSchema = executorVSchema getSandbox(KsTestUnsharded).VSchema = unshardedVSchema serv := new(sandboxTopo) - resolver := newTestResolver(hc, serv, cell) + resolver := newTestLegacyResolver(hc, serv, cell) shards := []string{"-20", "20-40", "40-60", "60-80", "80-a0", "a0-c0", "c0-e0", "e0-"} var conns []*sandboxconn.SandboxConn for i, shard := range shards { @@ -1419,7 +1419,7 @@ func TestSelectScatterLimit(t *testing.T) { s.VSchema = executorVSchema getSandbox(KsTestUnsharded).VSchema = unshardedVSchema serv := new(sandboxTopo) - resolver := newTestResolver(hc, serv, cell) + resolver := newTestLegacyResolver(hc, serv, cell) shards := []string{"-20", "20-40", "40-60", "60-80", "80-a0", "a0-c0", "c0-e0", "e0-"} var conns []*sandboxconn.SandboxConn for i, shard := range shards { @@ -1491,7 +1491,7 @@ func TestStreamSelectScatterLimit(t *testing.T) { s.VSchema = executorVSchema getSandbox(KsTestUnsharded).VSchema = unshardedVSchema serv := new(sandboxTopo) - resolver := newTestResolver(hc, serv, cell) + resolver := newTestLegacyResolver(hc, serv, cell) shards := []string{"-20", "20-40", "40-60", "60-80", "80-a0", "a0-c0", "c0-e0", "e0-"} var conns []*sandboxconn.SandboxConn for i, shard := range shards { diff --git a/go/vt/vtgate/executor_stream_test.go b/go/vt/vtgate/executor_stream_test.go index 45cc8068c81..c934b9cffd6 100644 --- a/go/vt/vtgate/executor_stream_test.go +++ b/go/vt/vtgate/executor_stream_test.go @@ -45,14 +45,14 @@ func TestStreamSQLUnsharded(t *testing.T) { } func TestStreamSQLSharded(t *testing.T) { - // Special setup: Don't use createExecutorEnv. + // Special setup: Don't use createLegacyExecutorEnv. cell := "aa" hc := discovery.NewFakeLegacyHealthCheck() s := createSandbox("TestExecutor") s.VSchema = executorVSchema getSandbox(KsTestUnsharded).VSchema = unshardedVSchema serv := new(sandboxTopo) - resolver := newTestResolver(hc, serv, cell) + resolver := newTestLegacyResolver(hc, serv, cell) shards := []string{"-20", "20-40", "40-60", "60-80", "80-a0", "a0-c0", "c0-e0", "e0-"} for _, shard := range shards { _ = hc.AddTestTablet(cell, shard, 1, "TestExecutor", shard, topodatapb.TabletType_MASTER, true, 1, nil) diff --git a/go/vt/vtgate/executor_test.go b/go/vt/vtgate/executor_test.go index 420d1198143..9176022c940 100644 --- a/go/vt/vtgate/executor_test.go +++ b/go/vt/vtgate/executor_test.go @@ -27,6 +27,7 @@ import ( "reflect" "strings" "testing" + "time" "vitess.io/vitess/go/test/utils" @@ -51,7 +52,30 @@ import ( "github.com/stretchr/testify/require" ) -func TestExecutorTransactionsNoAutoCommit(t *testing.T) { +func TestExecutorResultsExceeded(t *testing.T) { + save := *warnMemoryRows + *warnMemoryRows = 3 + defer func() { *warnMemoryRows = save }() + + executor, _, _, sbclookup := createExecutorEnv() + session := NewSafeSession(&vtgatepb.Session{TargetString: "@master"}) + + initial := warnings.Counts()["ResultsExceeded"] + + result1 := sqltypes.MakeTestResult(sqltypes.MakeTestFields("col", "int64"), "1") + result2 := sqltypes.MakeTestResult(sqltypes.MakeTestFields("col", "int64"), "1", "2", "3", "4") + sbclookup.SetResults([]*sqltypes.Result{result1, result2}) + + _, err := executor.Execute(ctx, "TestExecutorResultsExceeded", session, "select * from main1", nil) + require.NoError(t, err) + assert.Equal(t, initial, warnings.Counts()["ResultsExceeded"], "warnings count") + + _, err = executor.Execute(ctx, "TestExecutorResultsExceeded", session, "select * from main1", nil) + require.NoError(t, err) + assert.Equal(t, initial+1, warnings.Counts()["ResultsExceeded"], "warnings count") +} + +func TestLegacyExecutorTransactionsNoAutoCommit(t *testing.T) { executor, _, _, sbclookup := createExecutorEnv() session := NewSafeSession(&vtgatepb.Session{TargetString: "@master"}) @@ -59,31 +83,19 @@ func TestExecutorTransactionsNoAutoCommit(t *testing.T) { defer QueryLogger.Unsubscribe(logChan) // begin. - _, err := executor.Execute(context.Background(), "TestExecute", session, "begin", nil) - if err != nil { - t.Fatal(err) - } + _, err := executor.Execute(ctx, "TestExecute", session, "begin", nil) + require.NoError(t, err) wantSession := &vtgatepb.Session{InTransaction: true, TargetString: "@master"} - if !proto.Equal(session.Session, wantSession) { - t.Errorf("begin: %v, want %v", session.Session, wantSession) - } - if commitCount := sbclookup.CommitCount.Get(); commitCount != 0 { - t.Errorf("want 0, got %d", commitCount) - } + utils.MustMatch(t, wantSession, session.Session, "session") + assert.EqualValues(t, 0, sbclookup.CommitCount.Get(), "commit count") logStats := testQueryLog(t, logChan, "TestExecute", "BEGIN", "begin", 0) - if logStats.CommitTime != 0 { - t.Errorf("logstats: expected zero CommitTime") - } + assert.EqualValues(t, 0, logStats.CommitTime, "logstats: expected zero CommitTime") // commit. - _, err = executor.Execute(context.Background(), "TestExecute", session, "select id from main1", nil) - if err != nil { - t.Fatal(err) - } + _, err = executor.Execute(ctx, "TestExecute", session, "select id from main1", nil) + require.NoError(t, err) logStats = testQueryLog(t, logChan, "TestExecute", "SELECT", "select id from main1", 1) - if logStats.CommitTime != 0 { - t.Errorf("logstats: expected zero CommitTime") - } + assert.EqualValues(t, 0, logStats.CommitTime, "logstats: expected zero CommitTime") _, err = executor.Execute(context.Background(), "TestExecute", session, "commit", nil) if err != nil { @@ -102,25 +114,15 @@ func TestExecutorTransactionsNoAutoCommit(t *testing.T) { } // rollback. - _, err = executor.Execute(context.Background(), "TestExecute", session, "begin", nil) - if err != nil { - t.Fatal(err) - } - _, err = executor.Execute(context.Background(), "TestExecute", session, "select id from main1", nil) - if err != nil { - t.Fatal(err) - } - _, err = executor.Execute(context.Background(), "TestExecute", session, "rollback", nil) - if err != nil { - t.Fatal(err) - } + _, err = executor.Execute(ctx, "TestExecute", session, "begin", nil) + require.NoError(t, err) + _, err = executor.Execute(ctx, "TestExecute", session, "select id from main1", nil) + require.NoError(t, err) + _, err = executor.Execute(ctx, "TestExecute", session, "rollback", nil) + require.NoError(t, err) wantSession = &vtgatepb.Session{TargetString: "@master"} - if !proto.Equal(session.Session, wantSession) { - t.Errorf("begin: %v, want %v", session.Session, wantSession) - } - if rollbackCount := sbclookup.RollbackCount.Get(); rollbackCount != 1 { - t.Errorf("want 1, got %d", rollbackCount) - } + utils.MustMatch(t, wantSession, session.Session, "session") + assert.EqualValues(t, 1, sbclookup.RollbackCount.Get(), "rollback count") _ = testQueryLog(t, logChan, "TestExecute", "BEGIN", "begin", 0) _ = testQueryLog(t, logChan, "TestExecute", "SELECT", "select id from main1", 1) logStats = testQueryLog(t, logChan, "TestExecute", "ROLLBACK", "rollback", 1) @@ -129,10 +131,8 @@ func TestExecutorTransactionsNoAutoCommit(t *testing.T) { } // CloseSession doesn't log anything - err = executor.CloseSession(context.Background(), session) - if err != nil { - t.Fatal(err) - } + err = executor.CloseSession(ctx, session) + require.NoError(t, err) logStats = getQueryLog(logChan) if logStats != nil { t.Errorf("logstats: expected no record for no-op rollback, got %v", logStats) @@ -140,22 +140,20 @@ func TestExecutorTransactionsNoAutoCommit(t *testing.T) { // Prevent transactions on non-master. session = NewSafeSession(&vtgatepb.Session{TargetString: "@replica", InTransaction: true}) - _, err = executor.Execute(context.Background(), "TestExecute", session, "select id from main1", nil) + _, err = executor.Execute(ctx, "TestExecute", session, "select id from main1", nil) + require.Error(t, err) want := "transactions are supported only for master tablet types, current type: REPLICA" - if err == nil || err.Error() != want { - t.Errorf("Execute(@replica, in_transaction) err: %v, want %s", err, want) - } + require.Contains(t, err.Error(), want) // Prevent begin on non-master. session = NewSafeSession(&vtgatepb.Session{TargetString: "@replica"}) - _, err = executor.Execute(context.Background(), "TestExecute", session, "begin", nil) - if err == nil || err.Error() != want { - t.Errorf("Execute(@replica, in_transaction) err: %v, want %s", err, want) - } + _, err = executor.Execute(ctx, "TestExecute", session, "begin", nil) + require.Error(t, err) + require.Contains(t, err.Error(), want) // Prevent use of non-master if in_transaction is on. session = NewSafeSession(&vtgatepb.Session{TargetString: "@master", InTransaction: true}) - _, err = executor.Execute(context.Background(), "TestExecute", session, "use @replica", nil) + _, err = executor.Execute(ctx, "TestExecute", session, "use @replica", nil) want = "cannot change to a non-master type in the middle of a transaction: REPLICA" if err == nil || err.Error() != want { t.Errorf("Execute(@replica, in_transaction) err: %v, want %s", err, want) @@ -173,7 +171,7 @@ func TestDirectTargetRewrites(t *testing.T) { } sql := "select database()" - _, err := executor.Execute(context.Background(), "TestExecute", NewSafeSession(session), sql, map[string]*querypb.BindVariable{}) + _, err := executor.Execute(ctx, "TestExecute", NewSafeSession(session), sql, map[string]*querypb.BindVariable{}) require.NoError(t, err) testQueries(t, "sbclookup", sbclookup, []*querypb.BoundQuery{{ Sql: "select :__vtdbname as `database()` from dual", @@ -189,62 +187,38 @@ func TestExecutorTransactionsAutoCommit(t *testing.T) { defer QueryLogger.Unsubscribe(logChan) // begin. - _, err := executor.Execute(context.Background(), "TestExecute", session, "begin", nil) - if err != nil { - t.Fatal(err) - } + _, err := executor.Execute(ctx, "TestExecute", session, "begin", nil) + require.NoError(t, err) wantSession := &vtgatepb.Session{InTransaction: true, TargetString: "@master", Autocommit: true} - if !proto.Equal(session.Session, wantSession) { - t.Errorf("begin: %v, want %v", session.Session, wantSession) - } + utils.MustMatch(t, wantSession, session.Session, "session") if commitCount := sbclookup.CommitCount.Get(); commitCount != 0 { t.Errorf("want 0, got %d", commitCount) } _ = testQueryLog(t, logChan, "TestExecute", "BEGIN", "begin", 0) // commit. - _, err = executor.Execute(context.Background(), "TestExecute", session, "select id from main1", nil) - if err != nil { - t.Fatal(err) - } - _, err = executor.Execute(context.Background(), "TestExecute", session, "commit", nil) - if err != nil { - t.Fatal(err) - } + _, err = executor.Execute(ctx, "TestExecute", session, "select id from main1", nil) + require.NoError(t, err) + _, err = executor.Execute(ctx, "TestExecute", session, "commit", nil) + require.NoError(t, err) wantSession = &vtgatepb.Session{TargetString: "@master", Autocommit: true} - if !proto.Equal(session.Session, wantSession) { - t.Errorf("begin: %v, want %v", session.Session, wantSession) - } - if commitCount := sbclookup.CommitCount.Get(); commitCount != 1 { - t.Errorf("want 1, got %d", commitCount) - } + utils.MustMatch(t, wantSession, session.Session, "session") + assert.EqualValues(t, 1, sbclookup.CommitCount.Get()) logStats := testQueryLog(t, logChan, "TestExecute", "SELECT", "select id from main1", 1) - if logStats.CommitTime != 0 { - t.Errorf("logstats: expected zero CommitTime") - } + assert.EqualValues(t, 0, logStats.CommitTime) logStats = testQueryLog(t, logChan, "TestExecute", "COMMIT", "commit", 1) - if logStats.CommitTime == 0 { - t.Errorf("logstats: expected non-zero CommitTime") - } + assert.NotEqual(t, 0, logStats.CommitTime) // rollback. - _, err = executor.Execute(context.Background(), "TestExecute", session, "begin", nil) - if err != nil { - t.Fatal(err) - } - _, err = executor.Execute(context.Background(), "TestExecute", session, "select id from main1", nil) - if err != nil { - t.Fatal(err) - } - _, err = executor.Execute(context.Background(), "TestExecute", session, "rollback", nil) - if err != nil { - t.Fatal(err) - } + _, err = executor.Execute(ctx, "TestExecute", session, "begin", nil) + require.NoError(t, err) + _, err = executor.Execute(ctx, "TestExecute", session, "select id from main1", nil) + require.NoError(t, err) + _, err = executor.Execute(ctx, "TestExecute", session, "rollback", nil) + require.NoError(t, err) wantSession = &vtgatepb.Session{TargetString: "@master", Autocommit: true} - if !proto.Equal(session.Session, wantSession) { - t.Errorf("begin: %v, want %v", session.Session, wantSession) - } + utils.MustMatch(t, wantSession, session.Session, "session") if rollbackCount := sbclookup.RollbackCount.Get(); rollbackCount != 1 { t.Errorf("want 1, got %d", rollbackCount) } @@ -260,25 +234,25 @@ func TestExecutorDeleteMetadata(t *testing.T) { session := NewSafeSession(&vtgatepb.Session{TargetString: "@master", Autocommit: true}) set := "set @@vitess_metadata.app_v1= '1'" - _, err := executor.Execute(context.Background(), "TestExecute", session, set, nil) + _, err := executor.Execute(ctx, "TestExecute", session, set, nil) assert.NoError(t, err, "%s error: %v", set, err) show := `show vitess_metadata variables like 'app\\_%'` - result, _ := executor.Execute(context.Background(), "TestExecute", session, show, nil) + result, _ := executor.Execute(ctx, "TestExecute", session, show, nil) assert.Len(t, result.Rows, 1) // Fails if deleting key that doesn't exist - delete := "set @@vitess_metadata.doesn't_exist=''" - _, err = executor.Execute(context.Background(), "TestExecute", session, delete, nil) + delQuery := "set @@vitess_metadata.doesn't_exist=''" + _, err = executor.Execute(ctx, "TestExecute", session, delQuery, nil) assert.True(t, topo.IsErrType(err, topo.NoNode)) // Delete existing key, show should fail given the node doesn't exist - delete = "set @@vitess_metadata.app_v1=''" - _, err = executor.Execute(context.Background(), "TestExecute", session, delete, nil) + delQuery = "set @@vitess_metadata.app_v1=''" + _, err = executor.Execute(ctx, "TestExecute", session, delQuery, nil) assert.NoError(t, err) show = `show vitess_metadata variables like 'app\\_%'` - _, err = executor.Execute(context.Background(), "TestExecute", session, show, nil) + _, err = executor.Execute(ctx, "TestExecute", session, show, nil) assert.True(t, topo.IsErrType(err, topo.NoNode)) } @@ -291,10 +265,8 @@ func TestExecutorAutocommit(t *testing.T) { // autocommit = 0 startCount := sbclookup.CommitCount.Get() - _, err := executor.Execute(context.Background(), "TestExecute", session, "select id from main1", nil) - if err != nil { - t.Fatal(err) - } + _, err := executor.Execute(ctx, "TestExecute", session, "select id from main1", nil) + require.NoError(t, err) wantSession := &vtgatepb.Session{TargetString: "@master", InTransaction: true, FoundRows: 1, RowCount: -1} testSession := *session.Session testSession.ShardSessions = nil @@ -309,10 +281,8 @@ func TestExecutorAutocommit(t *testing.T) { } // autocommit = 1 - _, err = executor.Execute(context.Background(), "TestExecute", session, "set autocommit=1", nil) - if err != nil { - t.Fatal(err) - } + _, err = executor.Execute(ctx, "TestExecute", session, "set autocommit=1", nil) + require.NoError(t, err) _ = testQueryLog(t, logChan, "TestExecute", "SET", "set session autocommit = 1", 0) // Setting autocommit=1 commits existing transaction. @@ -323,10 +293,8 @@ func TestExecutorAutocommit(t *testing.T) { // In the following section, we look at AsTransaction count instead of CommitCount because // the update results in a single round-trip ExecuteBatch call. startCount = sbclookup.AsTransactionCount.Get() - _, err = executor.Execute(context.Background(), "TestExecute", session, "update main1 set id=1", nil) - if err != nil { - t.Fatal(err) - } + _, err = executor.Execute(ctx, "TestExecute", session, "update main1 set id=1", nil) + require.NoError(t, err) wantSession = &vtgatepb.Session{Autocommit: true, TargetString: "@master", FoundRows: 1, RowCount: 1} utils.MustMatch(t, wantSession, session.Session, "session does not match for autocommit=1") if got, want := sbclookup.AsTransactionCount.Get(), startCount+1; got != want { @@ -334,26 +302,18 @@ func TestExecutorAutocommit(t *testing.T) { } logStats = testQueryLog(t, logChan, "TestExecute", "UPDATE", "update main1 set id=1", 1) - if logStats.CommitTime == 0 { - t.Errorf("logstats: expected non-zero CommitTime") - } - if logStats.RowsAffected == 0 { - t.Errorf("logstats: expected non-zero RowsAffected") - } + assert.NotEqual(t, time.Duration(0), logStats.CommitTime, "logstats: expected non-zero CommitTime") + assert.NotEqual(t, uint64(0), logStats.RowsAffected, "logstats: expected non-zero RowsAffected") // autocommit = 1, "begin" session.Reset() startCount = sbclookup.CommitCount.Get() - _, err = executor.Execute(context.Background(), "TestExecute", session, "begin", nil) - if err != nil { - t.Fatal(err) - } + _, err = executor.Execute(ctx, "TestExecute", session, "begin", nil) + require.NoError(t, err) _ = testQueryLog(t, logChan, "TestExecute", "BEGIN", "begin", 0) - _, err = executor.Execute(context.Background(), "TestExecute", session, "update main1 set id=1", nil) - if err != nil { - t.Fatal(err) - } + _, err = executor.Execute(ctx, "TestExecute", session, "update main1 set id=1", nil) + require.NoError(t, err) wantSession = &vtgatepb.Session{InTransaction: true, Autocommit: true, TargetString: "@master", FoundRows: 1, RowCount: 1} testSession = *session.Session testSession.ShardSessions = nil @@ -370,10 +330,8 @@ func TestExecutorAutocommit(t *testing.T) { t.Errorf("logstats: expected non-zero RowsAffected") } - _, err = executor.Execute(context.Background(), "TestExecute", session, "commit", nil) - if err != nil { - t.Fatal(err) - } + _, err = executor.Execute(ctx, "TestExecute", session, "commit", nil) + require.NoError(t, err) wantSession = &vtgatepb.Session{Autocommit: true, TargetString: "@master"} if !proto.Equal(session.Session, wantSession) { t.Errorf("autocommit=1: %v, want %v", session.Session, wantSession) @@ -386,21 +344,15 @@ func TestExecutorAutocommit(t *testing.T) { // transition autocommit from 0 to 1 in the middle of a transaction. startCount = sbclookup.CommitCount.Get() session = NewSafeSession(&vtgatepb.Session{TargetString: "@master"}) - _, err = executor.Execute(context.Background(), "TestExecute", session, "begin", nil) - if err != nil { - t.Fatal(err) - } - _, err = executor.Execute(context.Background(), "TestExecute", session, "update main1 set id=1", nil) - if err != nil { - t.Fatal(err) - } + _, err = executor.Execute(ctx, "TestExecute", session, "begin", nil) + require.NoError(t, err) + _, err = executor.Execute(ctx, "TestExecute", session, "update main1 set id=1", nil) + require.NoError(t, err) if got, want := sbclookup.CommitCount.Get(), startCount; got != want { t.Errorf("Commit count: %d, want %d", got, want) } - _, err = executor.Execute(context.Background(), "TestExecute", session, "set autocommit=1", nil) - if err != nil { - t.Fatal(err) - } + _, err = executor.Execute(ctx, "TestExecute", session, "set autocommit=1", nil) + require.NoError(t, err) wantSession = &vtgatepb.Session{Autocommit: true, TargetString: "@master"} if !proto.Equal(session.Session, wantSession) { t.Errorf("autocommit=1: %v, want %v", session.Session, wantSession) @@ -422,7 +374,7 @@ func TestExecutorShowColumns(t *testing.T) { } for _, query := range queries { t.Run(query, func(t *testing.T) { - _, err := executor.Execute(context.Background(), "TestExecute", session, query, nil) + _, err := executor.Execute(ctx, "TestExecute", session, query, nil) require.NoError(t, err) wantQueries := []*querypb.BoundQuery{{ @@ -453,7 +405,7 @@ func TestExecutorShow(t *testing.T) { session := NewSafeSession(&vtgatepb.Session{TargetString: "@master"}) for _, query := range []string{"show databases", "show vitess_keyspaces", "show keyspaces", "show DATABASES"} { - qr, err := executor.Execute(context.Background(), "TestExecute", session, query, nil) + qr, err := executor.Execute(ctx, "TestExecute", session, query, nil) if err != nil { t.Error(err) } @@ -472,14 +424,14 @@ func TestExecutorShow(t *testing.T) { t.Errorf("%v:\n%+v, want\n%+v", query, qr, wantqr) } } - _, err := executor.Execute(context.Background(), "TestExecute", session, "show variables", nil) + _, err := executor.Execute(ctx, "TestExecute", session, "show variables", nil) require.NoError(t, err) - _, err = executor.Execute(context.Background(), "TestExecute", session, "show collation", nil) + _, err = executor.Execute(ctx, "TestExecute", session, "show collation", nil) require.NoError(t, err) - _, err = executor.Execute(context.Background(), "TestExecute", session, "show collation where `Charset` = 'utf8' and `Collation` = 'utf8_bin'", nil) + _, err = executor.Execute(ctx, "TestExecute", session, "show collation where `Charset` = 'utf8' and `Collation` = 'utf8_bin'", nil) require.NoError(t, err) - _, err = executor.Execute(context.Background(), "TestExecute", session, "show tables", nil) + _, err = executor.Execute(ctx, "TestExecute", session, "show tables", nil) if err != errNoKeyspace { t.Errorf("'show tables' should fail without a keyspace") } @@ -501,7 +453,7 @@ func TestExecutorShow(t *testing.T) { sbclookup.SetResults([]*sqltypes.Result{showResults}) query := fmt.Sprintf("show tables from %v", KsTestUnsharded) - qr, err := executor.Execute(context.Background(), "TestExecute", session, query, nil) + qr, err := executor.Execute(ctx, "TestExecute", session, query, nil) require.NoError(t, err) if len(sbclookup.Queries) != 1 { @@ -520,13 +472,13 @@ func TestExecutorShow(t *testing.T) { } wantErrNoTable := "table unknown_table not found" - _, err = executor.Execute(context.Background(), "TestExecute", session, "show create table unknown_table", nil) + _, err = executor.Execute(ctx, "TestExecute", session, "show create table unknown_table", nil) if err.Error() != wantErrNoTable { t.Errorf("Got: %v. Want: %v", err, wantErrNoTable) } // SHOW CREATE table using vschema to find keyspace. - _, err = executor.Execute(context.Background(), "TestExecute", session, "show create table user_seq", nil) + _, err = executor.Execute(ctx, "TestExecute", session, "show create table user_seq", nil) if err != nil { t.Errorf("Unexpected error: %v", err) } @@ -538,7 +490,7 @@ func TestExecutorShow(t *testing.T) { } // SHOW CREATE table with query-provided keyspace - _, err = executor.Execute(context.Background(), "TestExecute", session, fmt.Sprintf("show create table %v.unknown", KsTestUnsharded), nil) + _, err = executor.Execute(ctx, "TestExecute", session, fmt.Sprintf("show create table %v.unknown", KsTestUnsharded), nil) if err != nil { t.Errorf("Unexpected error: %v", err) } @@ -549,7 +501,7 @@ func TestExecutorShow(t *testing.T) { } // SHOW KEYS with two different syntax - _, err = executor.Execute(context.Background(), "TestExecute", session, fmt.Sprintf("show keys from %v.unknown", KsTestUnsharded), nil) + _, err = executor.Execute(ctx, "TestExecute", session, fmt.Sprintf("show keys from %v.unknown", KsTestUnsharded), nil) if err != nil { t.Errorf("Unexpected error: %v", err) } @@ -559,7 +511,7 @@ func TestExecutorShow(t *testing.T) { t.Errorf("Got: %v. Want: %v", lastQuery, wantQuery) } - _, err = executor.Execute(context.Background(), "TestExecute", session, fmt.Sprintf("show keys from unknown from %v", KsTestUnsharded), nil) + _, err = executor.Execute(ctx, "TestExecute", session, fmt.Sprintf("show keys from unknown from %v", KsTestUnsharded), nil) if err != nil { t.Errorf("Unexpected error: %v", err) } @@ -570,7 +522,7 @@ func TestExecutorShow(t *testing.T) { } // SHOW INDEX with two different syntax - _, err = executor.Execute(context.Background(), "TestExecute", session, fmt.Sprintf("show index from %v.unknown", KsTestUnsharded), nil) + _, err = executor.Execute(ctx, "TestExecute", session, fmt.Sprintf("show index from %v.unknown", KsTestUnsharded), nil) if err != nil { t.Errorf("Unexpected error: %v", err) } @@ -580,7 +532,7 @@ func TestExecutorShow(t *testing.T) { t.Errorf("Got: %v. Want: %v", lastQuery, wantQuery) } - _, err = executor.Execute(context.Background(), "TestExecute", session, fmt.Sprintf("show index from unknown from %v", KsTestUnsharded), nil) + _, err = executor.Execute(ctx, "TestExecute", session, fmt.Sprintf("show index from unknown from %v", KsTestUnsharded), nil) if err != nil { t.Errorf("Unexpected error: %v", err) } @@ -591,7 +543,7 @@ func TestExecutorShow(t *testing.T) { } // SHOW INDEXES with two different syntax - _, err = executor.Execute(context.Background(), "TestExecute", session, fmt.Sprintf("show indexes from %v.unknown", KsTestUnsharded), nil) + _, err = executor.Execute(ctx, "TestExecute", session, fmt.Sprintf("show indexes from %v.unknown", KsTestUnsharded), nil) if err != nil { t.Errorf("Unexpected error: %v", err) } @@ -601,7 +553,7 @@ func TestExecutorShow(t *testing.T) { t.Errorf("Got: %v. Want: %v", lastQuery, wantQuery) } - _, err = executor.Execute(context.Background(), "TestExecute", session, fmt.Sprintf("show indexes from unknown from %v", KsTestUnsharded), nil) + _, err = executor.Execute(ctx, "TestExecute", session, fmt.Sprintf("show indexes from unknown from %v", KsTestUnsharded), nil) if err != nil { t.Errorf("Unexpected error: %v", err) } @@ -612,7 +564,7 @@ func TestExecutorShow(t *testing.T) { } // SHOW EXTENDED {INDEX | INDEXES | KEYS} - _, err = executor.Execute(context.Background(), "TestExecute", session, fmt.Sprintf("show extended index from unknown from %v", KsTestUnsharded), nil) + _, err = executor.Execute(ctx, "TestExecute", session, fmt.Sprintf("show extended index from unknown from %v", KsTestUnsharded), nil) if err != nil { t.Errorf("Unexpected error: %v", err) } @@ -622,7 +574,7 @@ func TestExecutorShow(t *testing.T) { t.Errorf("Got: %v. Want: %v", lastQuery, wantQuery) } - _, err = executor.Execute(context.Background(), "TestExecute", session, fmt.Sprintf("show extended indexes from unknown from %v", KsTestUnsharded), nil) + _, err = executor.Execute(ctx, "TestExecute", session, fmt.Sprintf("show extended indexes from unknown from %v", KsTestUnsharded), nil) if err != nil { t.Errorf("Unexpected error: %v", err) } @@ -632,7 +584,7 @@ func TestExecutorShow(t *testing.T) { t.Errorf("Got: %v. Want: %v", lastQuery, wantQuery) } - _, err = executor.Execute(context.Background(), "TestExecute", session, fmt.Sprintf("show extended keys from unknown from %v", KsTestUnsharded), nil) + _, err = executor.Execute(ctx, "TestExecute", session, fmt.Sprintf("show extended keys from unknown from %v", KsTestUnsharded), nil) if err != nil { t.Errorf("Unexpected error: %v", err) } @@ -644,18 +596,18 @@ func TestExecutorShow(t *testing.T) { // Set desitation keyspace in session session.TargetString = KsTestUnsharded - _, err = executor.Execute(context.Background(), "TestExecute", session, "show create table unknown", nil) + _, err = executor.Execute(ctx, "TestExecute", session, "show create table unknown", nil) require.NoError(t, err) - _, err = executor.Execute(context.Background(), "TestExecute", session, "show full columns from table1", nil) + _, err = executor.Execute(ctx, "TestExecute", session, "show full columns from table1", nil) require.NoError(t, err) // Reset target string so other tests dont fail. session.TargetString = "@master" - _, err = executor.Execute(context.Background(), "TestExecute", session, fmt.Sprintf("show full columns from unknown from %v", KsTestUnsharded), nil) + _, err = executor.Execute(ctx, "TestExecute", session, fmt.Sprintf("show full columns from unknown from %v", KsTestUnsharded), nil) require.NoError(t, err) for _, query := range []string{"show charset", "show character set"} { - qr, err := executor.Execute(context.Background(), "TestExecute", session, query, nil) + qr, err := executor.Execute(ctx, "TestExecute", session, query, nil) require.NoError(t, err) wantqr := &sqltypes.Result{ Fields: append(buildVarCharFields("Charset", "Description", "Default collation"), &querypb.Field{Name: "Maxlen", Type: sqltypes.Int32}), @@ -677,7 +629,7 @@ func TestExecutorShow(t *testing.T) { } } for _, query := range []string{"show charset like '%foo'", "show character set like 'foo%'", "show charset like 'foo%'", "show character set where foo like 'utf8'", "show character set where charset like '%foo'", "show charset where charset = '%foo'"} { - qr, err := executor.Execute(context.Background(), "TestExecute", session, query, nil) + qr, err := executor.Execute(ctx, "TestExecute", session, query, nil) require.NoError(t, err) wantqr := &sqltypes.Result{ Fields: append(buildVarCharFields("Charset", "Description", "Default collation"), &querypb.Field{Name: "Maxlen", Type: sqltypes.Int32}), @@ -689,7 +641,7 @@ func TestExecutorShow(t *testing.T) { } } for _, query := range []string{"show charset like 'utf8'", "show character set like 'utf8'", "show charset where charset = 'utf8'", "show character set where charset = 'utf8'"} { - qr, err := executor.Execute(context.Background(), "TestExecute", session, query, nil) + qr, err := executor.Execute(ctx, "TestExecute", session, query, nil) require.NoError(t, err) wantqr := &sqltypes.Result{ Fields: append(buildVarCharFields("Charset", "Description", "Default collation"), &querypb.Field{Name: "Maxlen", Type: sqltypes.Int32}), @@ -706,7 +658,7 @@ func TestExecutorShow(t *testing.T) { } } for _, query := range []string{"show charset like 'utf8mb4'", "show character set like 'utf8mb4'", "show charset where charset = 'utf8mb4'", "show character set where charset = 'utf8mb4'"} { - qr, err := executor.Execute(context.Background(), "TestExecute", session, query, nil) + qr, err := executor.Execute(ctx, "TestExecute", session, query, nil) require.NoError(t, err) wantqr := &sqltypes.Result{ Fields: append(buildVarCharFields("Charset", "Description", "Default collation"), &querypb.Field{Name: "Maxlen", Type: sqltypes.Int32}), @@ -724,7 +676,7 @@ func TestExecutorShow(t *testing.T) { } } - qr, err = executor.Execute(context.Background(), "TestExecute", session, "show engines", nil) + qr, err = executor.Execute(ctx, "TestExecute", session, "show engines", nil) require.NoError(t, err) wantqr = &sqltypes.Result{ Fields: buildVarCharFields("Engine", "Support", "Comment", "Transactions", "XA", "Savepoints"), @@ -742,7 +694,7 @@ func TestExecutorShow(t *testing.T) { if !reflect.DeepEqual(qr, wantqr) { t.Errorf("show engines:\n%+v, want\n%+v", qr, wantqr) } - qr, err = executor.Execute(context.Background(), "TestExecute", session, "show plugins", nil) + qr, err = executor.Execute(ctx, "TestExecute", session, "show plugins", nil) require.NoError(t, err) wantqr = &sqltypes.Result{ Fields: buildVarCharFields("Name", "Status", "Type", "Library", "License"), @@ -760,7 +712,7 @@ func TestExecutorShow(t *testing.T) { t.Errorf("show plugins:\n%+v, want\n%+v", qr, wantqr) } for _, query := range []string{"show session status", "show session status like 'Ssl_cipher'"} { - qr, err = executor.Execute(context.Background(), "TestExecute", session, "show session status", nil) + qr, err = executor.Execute(ctx, "TestExecute", session, "show session status", nil) if err != nil { t.Error(err) } @@ -773,11 +725,11 @@ func TestExecutorShow(t *testing.T) { t.Errorf("%v:\n%+v, want\n%+v", query, qr, wantqr) } } - qr, err = executor.Execute(context.Background(), "TestExecute", session, "show vitess_shards", nil) + qr, err = executor.Execute(ctx, "TestExecute", session, "show vitess_shards", nil) require.NoError(t, err) // Test SHOW FULL COLUMNS FROM where query has a qualifier - _, err = executor.Execute(context.Background(), "TestExecute", session, fmt.Sprintf("show full columns from %v.table1", KsTestUnsharded), nil) + _, err = executor.Execute(ctx, "TestExecute", session, fmt.Sprintf("show full columns from %v.table1", KsTestUnsharded), nil) require.NoError(t, err) // Just test for first & last. @@ -794,7 +746,7 @@ func TestExecutorShow(t *testing.T) { t.Errorf("show vitess_shards:\n%+v, want\n%+v", qr, wantqr) } - qr, err = executor.Execute(context.Background(), "TestExecute", session, "show vitess_tablets", nil) + qr, err = executor.Execute(ctx, "TestExecute", session, "show vitess_tablets", nil) require.NoError(t, err) // Just test for first & last. qr.Rows = [][]sqltypes.Value{qr.Rows[0], qr.Rows[len(qr.Rows)-1]} @@ -810,7 +762,7 @@ func TestExecutorShow(t *testing.T) { t.Errorf("show vitess_tablets:\n%+v, want\n%+v", qr, wantqr) } - qr, err = executor.Execute(context.Background(), "TestExecute", session, "show vschema vindexes", nil) + qr, err = executor.Execute(ctx, "TestExecute", session, "show vschema vindexes", nil) require.NoError(t, err) wantqr = &sqltypes.Result{ Fields: buildVarCharFields("Keyspace", "Name", "Type", "Params", "Owner"), @@ -832,7 +784,7 @@ func TestExecutorShow(t *testing.T) { t.Errorf("show vschema vindexes:\n%+v, want\n%+v", qr, wantqr) } - qr, err = executor.Execute(context.Background(), "TestExecute", session, "show vschema vindexes on TestExecutor.user", nil) + qr, err = executor.Execute(ctx, "TestExecute", session, "show vschema vindexes on TestExecutor.user", nil) require.NoError(t, err) wantqr = &sqltypes.Result{ Fields: buildVarCharFields("Columns", "Name", "Type", "Params", "Owner"), @@ -846,20 +798,20 @@ func TestExecutorShow(t *testing.T) { t.Errorf("show vschema vindexes on TestExecutor.user:\n%+v, want\n%+v", qr, wantqr) } - _, err = executor.Execute(context.Background(), "TestExecute", session, "show vschema vindexes on user", nil) + _, err = executor.Execute(ctx, "TestExecute", session, "show vschema vindexes on user", nil) wantErr := errNoKeyspace.Error() if err == nil || err.Error() != wantErr { t.Errorf("show vschema vindexes on user: %v, want %v", err, wantErr) } - _, err = executor.Execute(context.Background(), "TestExecute", session, "show vschema vindexes on TestExecutor.garbage", nil) + _, err = executor.Execute(ctx, "TestExecute", session, "show vschema vindexes on TestExecutor.garbage", nil) wantErr = "table `garbage` does not exist in keyspace `TestExecutor`" if err == nil || err.Error() != wantErr { t.Errorf("show vschema vindexes on user: %v, want %v", err, wantErr) } session.TargetString = "TestExecutor" - qr, err = executor.Execute(context.Background(), "TestExecute", session, "show vschema vindexes on user", nil) + qr, err = executor.Execute(ctx, "TestExecute", session, "show vschema vindexes on user", nil) require.NoError(t, err) wantqr = &sqltypes.Result{ Fields: buildVarCharFields("Columns", "Name", "Type", "Params", "Owner"), @@ -874,7 +826,7 @@ func TestExecutorShow(t *testing.T) { } session.TargetString = "TestExecutor" - qr, err = executor.Execute(context.Background(), "TestExecute", session, "show vschema vindexes on user2", nil) + qr, err = executor.Execute(ctx, "TestExecute", session, "show vschema vindexes on user2", nil) require.NoError(t, err) wantqr = &sqltypes.Result{ Fields: buildVarCharFields("Columns", "Name", "Type", "Params", "Owner"), @@ -888,13 +840,13 @@ func TestExecutorShow(t *testing.T) { t.Errorf("show vschema vindexes on user2:\n%+v, want\n%+v", qr, wantqr) } - _, err = executor.Execute(context.Background(), "TestExecute", session, "show vschema vindexes on garbage", nil) + _, err = executor.Execute(ctx, "TestExecute", session, "show vschema vindexes on garbage", nil) wantErr = "table `garbage` does not exist in keyspace `TestExecutor`" if err == nil || err.Error() != wantErr { t.Errorf("show vschema vindexes on user: %v, want %v", err, wantErr) } - qr, err = executor.Execute(context.Background(), "TestExecute", session, "show warnings", nil) + qr, err = executor.Execute(ctx, "TestExecute", session, "show warnings", nil) require.NoError(t, err) wantqr = &sqltypes.Result{ Fields: []*querypb.Field{ @@ -911,7 +863,7 @@ func TestExecutorShow(t *testing.T) { } session.Warnings = []*querypb.QueryWarning{} - qr, err = executor.Execute(context.Background(), "TestExecute", session, "show warnings", nil) + qr, err = executor.Execute(ctx, "TestExecute", session, "show warnings", nil) require.NoError(t, err) wantqr = &sqltypes.Result{ Fields: []*querypb.Field{ @@ -930,7 +882,7 @@ func TestExecutorShow(t *testing.T) { {Code: mysql.ERBadTable, Message: "bad table"}, {Code: mysql.EROutOfResources, Message: "ks/-40: query timed out"}, } - qr, err = executor.Execute(context.Background(), "TestExecute", session, "show warnings", nil) + qr, err = executor.Execute(ctx, "TestExecute", session, "show warnings", nil) require.NoError(t, err) wantqr = &sqltypes.Result{ Fields: []*querypb.Field{ @@ -951,7 +903,7 @@ func TestExecutorShow(t *testing.T) { // Make sure it still works when one of the keyspaces is in a bad state getSandbox("TestExecutor").SrvKeyspaceMustFail++ - qr, err = executor.Execute(context.Background(), "TestExecute", session, "show vitess_shards", nil) + qr, err = executor.Execute(ctx, "TestExecute", session, "show vitess_shards", nil) require.NoError(t, err) // Just test for first & last. qr.Rows = [][]sqltypes.Value{qr.Rows[0], qr.Rows[len(qr.Rows)-1]} @@ -968,7 +920,7 @@ func TestExecutorShow(t *testing.T) { } session = NewSafeSession(&vtgatepb.Session{TargetString: KsTestUnsharded}) - qr, err = executor.Execute(context.Background(), "TestExecute", session, "show vschema tables", nil) + qr, err = executor.Execute(ctx, "TestExecute", session, "show vschema tables", nil) require.NoError(t, err) wantqr = &sqltypes.Result{ Fields: buildVarCharFields("Tables"), @@ -990,20 +942,20 @@ func TestExecutorShow(t *testing.T) { } session = NewSafeSession(&vtgatepb.Session{}) - _, err = executor.Execute(context.Background(), "TestExecute", session, "show vschema tables", nil) + _, err = executor.Execute(ctx, "TestExecute", session, "show vschema tables", nil) want := errNoKeyspace.Error() if err == nil || err.Error() != want { t.Errorf("show vschema tables: %v, want %v", err, want) } - _, err = executor.Execute(context.Background(), "TestExecute", session, "show 10", nil) + _, err = executor.Execute(ctx, "TestExecute", session, "show 10", nil) want = "syntax error at position 8 near '10'" if err == nil || err.Error() != want { t.Errorf("show vschema tables: %v, want %v", err, want) } session = NewSafeSession(&vtgatepb.Session{TargetString: "no_such_keyspace"}) - _, err = executor.Execute(context.Background(), "TestExecute", session, "show vschema tables", nil) + _, err = executor.Execute(ctx, "TestExecute", session, "show vschema tables", nil) want = "keyspace no_such_keyspace not found in vschema" if err == nil || err.Error() != want { t.Errorf("show vschema tables: %v, want %v", err, want) @@ -1023,7 +975,7 @@ func TestExecutorUse(t *testing.T) { "TestExecutor:-80@master", } for i, stmt := range stmts { - _, err := executor.Execute(context.Background(), "TestExecute", session, stmt, nil) + _, err := executor.Execute(ctx, "TestExecute", session, stmt, nil) if err != nil { t.Error(err) } @@ -1031,13 +983,13 @@ func TestExecutorUse(t *testing.T) { utils.MustMatch(t, wantSession, session.Session, "session does not match") } - _, err := executor.Execute(context.Background(), "TestExecute", NewSafeSession(&vtgatepb.Session{}), "use 1", nil) + _, err := executor.Execute(ctx, "TestExecute", NewSafeSession(&vtgatepb.Session{}), "use 1", nil) wantErr := "syntax error at position 6 near '1'" if err == nil || err.Error() != wantErr { t.Errorf("got: %v, want %v", err, wantErr) } - _, err = executor.Execute(context.Background(), "TestExecute", NewSafeSession(&vtgatepb.Session{}), "use UnexistentKeyspace", nil) + _, err = executor.Execute(ctx, "TestExecute", NewSafeSession(&vtgatepb.Session{}), "use UnexistentKeyspace", nil) wantErr = "Unknown database 'UnexistentKeyspace' (errno 1049) (sqlstate 42000)" if err == nil || err.Error() != wantErr { t.Errorf("got: %v, want %v", err, wantErr) @@ -1054,7 +1006,7 @@ func TestExecutorComment(t *testing.T) { wantResult := &sqltypes.Result{} for _, stmt := range stmts { - gotResult, err := executor.Execute(context.Background(), "TestExecute", NewSafeSession(&vtgatepb.Session{TargetString: KsTestUnsharded}), stmt, nil) + gotResult, err := executor.Execute(ctx, "TestExecute", NewSafeSession(&vtgatepb.Session{TargetString: KsTestUnsharded}), stmt, nil) if err != nil { t.Error(err) } @@ -1137,7 +1089,7 @@ func TestExecutorOther(t *testing.T) { sbc2.ExecCount.Set(0) sbclookup.ExecCount.Set(0) - _, err := executor.Execute(context.Background(), "TestExecute", NewSafeSession(&vtgatepb.Session{TargetString: tc.targetStr}), stmt, nil) + _, err := executor.Execute(ctx, "TestExecute", NewSafeSession(&vtgatepb.Session{TargetString: tc.targetStr}), stmt, nil) if tc.hasNoKeyspaceErr { assert.Error(t, err, errNoKeyspace) } else if tc.hasDestinationShardErr { @@ -1233,7 +1185,7 @@ func TestExecutorDDL(t *testing.T) { sbc2.ExecCount.Set(0) sbclookup.ExecCount.Set(0) - _, err := executor.Execute(context.Background(), "TestExecute", NewSafeSession(&vtgatepb.Session{TargetString: tc.targetStr}), stmt, nil) + _, err := executor.Execute(ctx, "TestExecute", NewSafeSession(&vtgatepb.Session{TargetString: tc.targetStr}), stmt, nil) if tc.hasNoKeyspaceErr { require.EqualError(t, err, "keyspace not specified", "expect query to fail") } else { @@ -1263,7 +1215,7 @@ func TestExecutorAlterVSchemaKeyspace(t *testing.T) { session := NewSafeSession(&vtgatepb.Session{TargetString: "@master", Autocommit: true}) vschemaUpdates := make(chan *vschemapb.SrvVSchema, 2) - executor.serv.WatchSrvVSchema(context.Background(), "aa", func(vschema *vschemapb.SrvVSchema, err error) { + executor.serv.WatchSrvVSchema(ctx, "aa", func(vschema *vschemapb.SrvVSchema, err error) { vschemaUpdates <- vschema }) @@ -1274,7 +1226,7 @@ func TestExecutorAlterVSchemaKeyspace(t *testing.T) { } stmt := "alter vschema create vindex TestExecutor.test_vindex using hash" - _, err := executor.Execute(context.Background(), "TestExecute", session, stmt, nil) + _, err := executor.Execute(ctx, "TestExecute", session, stmt, nil) require.NoError(t, err) _, vindex := waitForVindex(t, "TestExecutor", "test_vindex", vschemaUpdates, executor) @@ -1290,7 +1242,7 @@ func TestExecutorCreateVindexDDL(t *testing.T) { ks := "TestExecutor" vschemaUpdates := make(chan *vschemapb.SrvVSchema, 4) - executor.serv.WatchSrvVSchema(context.Background(), "aa", func(vschema *vschemapb.SrvVSchema, err error) { + executor.serv.WatchSrvVSchema(ctx, "aa", func(vschema *vschemapb.SrvVSchema, err error) { vschemaUpdates <- vschema }) @@ -1302,7 +1254,7 @@ func TestExecutorCreateVindexDDL(t *testing.T) { session := NewSafeSession(&vtgatepb.Session{TargetString: ks}) stmt := "alter vschema create vindex test_vindex using hash" - _, err := executor.Execute(context.Background(), "TestExecute", session, stmt, nil) + _, err := executor.Execute(ctx, "TestExecute", session, stmt, nil) require.NoError(t, err) _, vindex := waitForVindex(t, ks, "test_vindex", vschemaUpdates, executor) @@ -1310,7 +1262,7 @@ func TestExecutorCreateVindexDDL(t *testing.T) { t.Errorf("updated vschema did not contain test_vindex") } - _, err = executor.Execute(context.Background(), "TestExecute", session, stmt, nil) + _, err = executor.Execute(ctx, "TestExecute", session, stmt, nil) wantErr := "vindex test_vindex already exists in keyspace TestExecutor" if err == nil || err.Error() != wantErr { t.Errorf("create duplicate vindex: %v, want %s", err, wantErr) @@ -1326,7 +1278,7 @@ func TestExecutorCreateVindexDDL(t *testing.T) { //ksNew := "test_new_keyspace" session = NewSafeSession(&vtgatepb.Session{TargetString: ks}) stmt = "alter vschema create vindex test_vindex2 using hash" - _, err = executor.Execute(context.Background(), "TestExecute", session, stmt, nil) + _, err = executor.Execute(ctx, "TestExecute", session, stmt, nil) if err != nil { t.Fatalf("error in %s: %v", stmt, err) } @@ -1361,7 +1313,7 @@ func TestExecutorAddDropVschemaTableDDL(t *testing.T) { ks := KsTestUnsharded vschemaUpdates := make(chan *vschemapb.SrvVSchema, 4) - executor.serv.WatchSrvVSchema(context.Background(), "aa", func(vschema *vschemapb.SrvVSchema, err error) { + executor.serv.WatchSrvVSchema(ctx, "aa", func(vschema *vschemapb.SrvVSchema, err error) { vschemaUpdates <- vschema }) @@ -1371,30 +1323,27 @@ func TestExecutorAddDropVschemaTableDDL(t *testing.T) { t.Fatalf("test_table should not exist in original vschema") } - vschemaTables := []string{} + var vschemaTables []string for t := range vschema.Keyspaces[ks].Tables { vschemaTables = append(vschemaTables, t) } session := NewSafeSession(&vtgatepb.Session{TargetString: ks}) stmt := "alter vschema add table test_table" - _, err := executor.Execute(context.Background(), "TestExecute", session, stmt, nil) + _, err := executor.Execute(ctx, "TestExecute", session, stmt, nil) require.NoError(t, err) _ = waitForVschemaTables(t, ks, append(vschemaTables, "test_table"), executor) stmt = "alter vschema add table test_table2" - _, err = executor.Execute(context.Background(), "TestExecute", session, stmt, nil) + _, err = executor.Execute(ctx, "TestExecute", session, stmt, nil) require.NoError(t, err) _ = waitForVschemaTables(t, ks, append(vschemaTables, []string{"test_table", "test_table2"}...), executor) // Should fail adding a table on a sharded keyspace session = NewSafeSession(&vtgatepb.Session{TargetString: "TestExecutor"}) stmt = "alter vschema add table test_table" - _, err = executor.Execute(context.Background(), "TestExecute", session, stmt, nil) - wantErr := "add vschema table: unsupported on sharded keyspace TestExecutor" - if err == nil || err.Error() != wantErr { - t.Errorf("want error %v got %v", wantErr, err) - } + _, err = executor.Execute(ctx, "TestExecute", session, stmt, nil) + require.EqualError(t, err, "add vschema table: unsupported on sharded keyspace TestExecutor") // No queries should have gone to any tablets wantCount := []int64{0, 0, 0} @@ -1403,9 +1352,7 @@ func TestExecutorAddDropVschemaTableDDL(t *testing.T) { sbc2.ExecCount.Get(), sbclookup.ExecCount.Get(), } - if !reflect.DeepEqual(gotCount, wantCount) { - t.Errorf("Exec %s: %v, want %v", stmt, gotCount, wantCount) - } + utils.MustMatch(t, wantCount, gotCount, "") } func TestExecutorVindexDDLACL(t *testing.T) { @@ -1413,8 +1360,8 @@ func TestExecutorVindexDDLACL(t *testing.T) { ks := "TestExecutor" session := NewSafeSession(&vtgatepb.Session{TargetString: ks}) - ctxRedUser := callerid.NewContext(context.Background(), &vtrpcpb.CallerID{}, &querypb.VTGateCallerID{Username: "redUser"}) - ctxBlueUser := callerid.NewContext(context.Background(), &vtrpcpb.CallerID{}, &querypb.VTGateCallerID{Username: "blueUser"}) + ctxRedUser := callerid.NewContext(ctx, &vtrpcpb.CallerID{}, &querypb.VTGateCallerID{Username: "redUser"}) + ctxBlueUser := callerid.NewContext(ctx, &vtrpcpb.CallerID{}, &querypb.VTGateCallerID{Username: "blueUser"}) // test that by default no users can perform the operation stmt := "alter vschema create vindex test_hash using hash" @@ -1461,7 +1408,7 @@ func TestExecutorVindexDDLACL(t *testing.T) { func TestExecutorUnrecognized(t *testing.T) { executor, _, _, _ := createExecutorEnv() - _, err := executor.Execute(context.Background(), "TestExecute", NewSafeSession(&vtgatepb.Session{}), "invalid statement", nil) + _, err := executor.Execute(ctx, "TestExecute", NewSafeSession(&vtgatepb.Session{}), "invalid statement", nil) require.Error(t, err, "unrecognized statement: invalid statement'") } @@ -1490,10 +1437,10 @@ func TestVSchemaStats(t *testing.T) { func TestGetPlanUnnormalized(t *testing.T) { r, _, _, _ := createExecutorEnv() - emptyvc, _ := newVCursorImpl(context.Background(), NewSafeSession(&vtgatepb.Session{TargetString: "@unknown"}), makeComments(""), r, nil, r.vm, r.VSchema(), r.resolver.resolver) - unshardedvc, _ := newVCursorImpl(context.Background(), NewSafeSession(&vtgatepb.Session{TargetString: KsTestUnsharded + "@unknown"}), makeComments(""), r, nil, r.vm, r.VSchema(), r.resolver.resolver) + emptyvc, _ := newVCursorImpl(ctx, NewSafeSession(&vtgatepb.Session{TargetString: "@unknown"}), makeComments(""), r, nil, r.vm, r.VSchema(), r.resolver.resolver) + unshardedvc, _ := newVCursorImpl(ctx, NewSafeSession(&vtgatepb.Session{TargetString: KsTestUnsharded + "@unknown"}), makeComments(""), r, nil, r.vm, r.VSchema(), r.resolver.resolver) - logStats1 := NewLogStats(context.Background(), "Test", "", nil) + logStats1 := NewLogStats(ctx, "Test", "", nil) query1 := "select * from music_user_map where id = 1" plan1, err := r.getPlan(emptyvc, query1, makeComments(" /* comment */"), map[string]*querypb.BindVariable{}, false, logStats1) require.NoError(t, err) @@ -1502,7 +1449,7 @@ func TestGetPlanUnnormalized(t *testing.T) { t.Errorf("logstats sql want \"%s\" got \"%s\"", wantSQL, logStats1.SQL) } - logStats2 := NewLogStats(context.Background(), "Test", "", nil) + logStats2 := NewLogStats(ctx, "Test", "", nil) plan2, err := r.getPlan(emptyvc, query1, makeComments(" /* comment */"), map[string]*querypb.BindVariable{}, false, logStats2) require.NoError(t, err) if plan1 != plan2 { @@ -1517,7 +1464,7 @@ func TestGetPlanUnnormalized(t *testing.T) { if logStats2.SQL != wantSQL { t.Errorf("logstats sql want \"%s\" got \"%s\"", wantSQL, logStats2.SQL) } - logStats3 := NewLogStats(context.Background(), "Test", "", nil) + logStats3 := NewLogStats(ctx, "Test", "", nil) plan3, err := r.getPlan(unshardedvc, query1, makeComments(" /* comment */"), map[string]*querypb.BindVariable{}, false, logStats3) require.NoError(t, err) if plan1 == plan3 { @@ -1526,7 +1473,7 @@ func TestGetPlanUnnormalized(t *testing.T) { if logStats3.SQL != wantSQL { t.Errorf("logstats sql want \"%s\" got \"%s\"", wantSQL, logStats3.SQL) } - logStats4 := NewLogStats(context.Background(), "Test", "", nil) + logStats4 := NewLogStats(ctx, "Test", "", nil) plan4, err := r.getPlan(unshardedvc, query1, makeComments(" /* comment */"), map[string]*querypb.BindVariable{}, false, logStats4) require.NoError(t, err) if plan3 != plan4 { @@ -1549,9 +1496,9 @@ func TestGetPlanUnnormalized(t *testing.T) { func TestGetPlanCacheUnnormalized(t *testing.T) { r, _, _, _ := createExecutorEnv() - emptyvc, _ := newVCursorImpl(context.Background(), NewSafeSession(&vtgatepb.Session{TargetString: "@unknown"}), makeComments(""), r, nil, r.vm, r.VSchema(), r.resolver.resolver) + emptyvc, _ := newVCursorImpl(ctx, NewSafeSession(&vtgatepb.Session{TargetString: "@unknown"}), makeComments(""), r, nil, r.vm, r.VSchema(), r.resolver.resolver) query1 := "select * from music_user_map where id = 1" - logStats1 := NewLogStats(context.Background(), "Test", "", nil) + logStats1 := NewLogStats(ctx, "Test", "", nil) _, err := r.getPlan(emptyvc, query1, makeComments(" /* comment */"), map[string]*querypb.BindVariable{}, true /* skipQueryPlanCache */, logStats1) require.NoError(t, err) if r.plans.Size() != 0 { @@ -1561,7 +1508,7 @@ func TestGetPlanCacheUnnormalized(t *testing.T) { if logStats1.SQL != wantSQL { t.Errorf("logstats sql want \"%s\" got \"%s\"", wantSQL, logStats1.SQL) } - logStats2 := NewLogStats(context.Background(), "Test", "", nil) + logStats2 := NewLogStats(ctx, "Test", "", nil) _, err = r.getPlan(emptyvc, query1, makeComments(" /* comment 2 */"), map[string]*querypb.BindVariable{}, false /* skipQueryPlanCache */, logStats2) require.NoError(t, err) if r.plans.Size() != 1 { @@ -1574,10 +1521,10 @@ func TestGetPlanCacheUnnormalized(t *testing.T) { // Skip cache using directive r, _, _, _ = createExecutorEnv() - unshardedvc, _ := newVCursorImpl(context.Background(), NewSafeSession(&vtgatepb.Session{TargetString: KsTestUnsharded + "@unknown"}), makeComments(""), r, nil, r.vm, r.VSchema(), r.resolver.resolver) + unshardedvc, _ := newVCursorImpl(ctx, NewSafeSession(&vtgatepb.Session{TargetString: KsTestUnsharded + "@unknown"}), makeComments(""), r, nil, r.vm, r.VSchema(), r.resolver.resolver) query1 = "insert /*vt+ SKIP_QUERY_PLAN_CACHE=1 */ into user(id) values (1), (2)" - logStats1 = NewLogStats(context.Background(), "Test", "", nil) + logStats1 = NewLogStats(ctx, "Test", "", nil) _, err = r.getPlan(unshardedvc, query1, makeComments(" /* comment */"), map[string]*querypb.BindVariable{}, false, logStats1) require.NoError(t, err) if len(r.plans.Keys()) != 0 { @@ -1595,9 +1542,9 @@ func TestGetPlanCacheUnnormalized(t *testing.T) { func TestGetPlanCacheNormalized(t *testing.T) { r, _, _, _ := createExecutorEnv() r.normalize = true - emptyvc, _ := newVCursorImpl(context.Background(), NewSafeSession(&vtgatepb.Session{TargetString: "@unknown"}), makeComments(""), r, nil, r.vm, r.VSchema(), r.resolver.resolver) + emptyvc, _ := newVCursorImpl(ctx, NewSafeSession(&vtgatepb.Session{TargetString: "@unknown"}), makeComments(""), r, nil, r.vm, r.VSchema(), r.resolver.resolver) query1 := "select * from music_user_map where id = 1" - logStats1 := NewLogStats(context.Background(), "Test", "", nil) + logStats1 := NewLogStats(ctx, "Test", "", nil) _, err := r.getPlan(emptyvc, query1, makeComments(" /* comment */"), map[string]*querypb.BindVariable{}, true /* skipQueryPlanCache */, logStats1) require.NoError(t, err) if r.plans.Size() != 0 { @@ -1607,7 +1554,7 @@ func TestGetPlanCacheNormalized(t *testing.T) { if logStats1.SQL != wantSQL { t.Errorf("logstats sql want \"%s\" got \"%s\"", wantSQL, logStats1.SQL) } - logStats2 := NewLogStats(context.Background(), "Test", "", nil) + logStats2 := NewLogStats(ctx, "Test", "", nil) _, err = r.getPlan(emptyvc, query1, makeComments(" /* comment */"), map[string]*querypb.BindVariable{}, false /* skipQueryPlanCache */, logStats2) require.NoError(t, err) if r.plans.Size() != 1 { @@ -1620,10 +1567,10 @@ func TestGetPlanCacheNormalized(t *testing.T) { // Skip cache using directive r, _, _, _ = createExecutorEnv() r.normalize = true - unshardedvc, _ := newVCursorImpl(context.Background(), NewSafeSession(&vtgatepb.Session{TargetString: KsTestUnsharded + "@unknown"}), makeComments(""), r, nil, r.vm, r.VSchema(), r.resolver.resolver) + unshardedvc, _ := newVCursorImpl(ctx, NewSafeSession(&vtgatepb.Session{TargetString: KsTestUnsharded + "@unknown"}), makeComments(""), r, nil, r.vm, r.VSchema(), r.resolver.resolver) query1 = "insert /*vt+ SKIP_QUERY_PLAN_CACHE=1 */ into user(id) values (1), (2)" - logStats1 = NewLogStats(context.Background(), "Test", "", nil) + logStats1 = NewLogStats(ctx, "Test", "", nil) _, err = r.getPlan(unshardedvc, query1, makeComments(" /* comment */"), map[string]*querypb.BindVariable{}, false, logStats1) require.NoError(t, err) if len(r.plans.Keys()) != 0 { @@ -1641,16 +1588,16 @@ func TestGetPlanCacheNormalized(t *testing.T) { func TestGetPlanNormalized(t *testing.T) { r, _, _, _ := createExecutorEnv() r.normalize = true - emptyvc, _ := newVCursorImpl(context.Background(), NewSafeSession(&vtgatepb.Session{TargetString: "@unknown"}), makeComments(""), r, nil, r.vm, r.VSchema(), r.resolver.resolver) - unshardedvc, _ := newVCursorImpl(context.Background(), NewSafeSession(&vtgatepb.Session{TargetString: KsTestUnsharded + "@unknown"}), makeComments(""), r, nil, r.vm, r.VSchema(), r.resolver.resolver) + emptyvc, _ := newVCursorImpl(ctx, NewSafeSession(&vtgatepb.Session{TargetString: "@unknown"}), makeComments(""), r, nil, r.vm, r.VSchema(), r.resolver.resolver) + unshardedvc, _ := newVCursorImpl(ctx, NewSafeSession(&vtgatepb.Session{TargetString: KsTestUnsharded + "@unknown"}), makeComments(""), r, nil, r.vm, r.VSchema(), r.resolver.resolver) query1 := "select * from music_user_map where id = 1" query2 := "select * from music_user_map where id = 2" normalized := "select * from music_user_map where id = :vtg1" - logStats1 := NewLogStats(context.Background(), "Test", "", nil) + logStats1 := NewLogStats(ctx, "Test", "", nil) plan1, err := r.getPlan(emptyvc, query1, makeComments(" /* comment 1 */"), map[string]*querypb.BindVariable{}, false, logStats1) require.NoError(t, err) - logStats2 := NewLogStats(context.Background(), "Test", "", nil) + logStats2 := NewLogStats(ctx, "Test", "", nil) plan2, err := r.getPlan(emptyvc, query1, makeComments(" /* comment 2 */"), map[string]*querypb.BindVariable{}, false, logStats2) require.NoError(t, err) if plan1 != plan2 { @@ -1672,7 +1619,7 @@ func TestGetPlanNormalized(t *testing.T) { t.Errorf("logstats sql want \"%s\" got \"%s\"", wantSQL, logStats2.SQL) } - logStats3 := NewLogStats(context.Background(), "Test", "", nil) + logStats3 := NewLogStats(ctx, "Test", "", nil) plan3, err := r.getPlan(emptyvc, query2, makeComments(" /* comment 3 */"), map[string]*querypb.BindVariable{}, false, logStats3) require.NoError(t, err) if plan1 != plan3 { @@ -1683,7 +1630,7 @@ func TestGetPlanNormalized(t *testing.T) { t.Errorf("logstats sql want \"%s\" got \"%s\"", wantSQL, logStats3.SQL) } - logStats4 := NewLogStats(context.Background(), "Test", "", nil) + logStats4 := NewLogStats(ctx, "Test", "", nil) plan4, err := r.getPlan(emptyvc, normalized, makeComments(" /* comment 4 */"), map[string]*querypb.BindVariable{}, false, logStats4) require.NoError(t, err) if plan1 != plan4 { @@ -1694,7 +1641,7 @@ func TestGetPlanNormalized(t *testing.T) { t.Errorf("logstats sql want \"%s\" got \"%s\"", wantSQL, logStats4.SQL) } - logStats5 := NewLogStats(context.Background(), "Test", "", nil) + logStats5 := NewLogStats(ctx, "Test", "", nil) plan3, err = r.getPlan(unshardedvc, query1, makeComments(" /* comment 5 */"), map[string]*querypb.BindVariable{}, false, logStats5) require.NoError(t, err) if plan1 == plan3 { @@ -1705,7 +1652,7 @@ func TestGetPlanNormalized(t *testing.T) { t.Errorf("logstats sql want \"%s\" got \"%s\"", wantSQL, logStats5.SQL) } - logStats6 := NewLogStats(context.Background(), "Test", "", nil) + logStats6 := NewLogStats(ctx, "Test", "", nil) plan4, err = r.getPlan(unshardedvc, query1, makeComments(" /* comment 6 */"), map[string]*querypb.BindVariable{}, false, logStats6) require.NoError(t, err) if plan3 != plan4 { @@ -1720,7 +1667,7 @@ func TestGetPlanNormalized(t *testing.T) { } // Errors - logStats7 := NewLogStats(context.Background(), "Test", "", nil) + logStats7 := NewLogStats(ctx, "Test", "", nil) _, err = r.getPlan(emptyvc, "syntax", makeComments(""), map[string]*querypb.BindVariable{}, false, logStats7) wantErr := "syntax error at position 7 near 'syntax'" if err == nil || err.Error() != wantErr { @@ -1940,37 +1887,6 @@ func TestOlapSelectDatabase(t *testing.T) { assert.True(t, cbInvoked) } -func TestExecutorResultsExceeded(t *testing.T) { - save := *warnMemoryRows - *warnMemoryRows = 3 - defer func() { *warnMemoryRows = save }() - - executor, _, _, sbclookup := createExecutorEnv() - session := NewSafeSession(&vtgatepb.Session{TargetString: "@master"}) - - initial := warnings.Counts()["ResultsExceeded"] - - result1 := sqltypes.MakeTestResult(sqltypes.MakeTestFields("col", "int64"), "1") - result2 := sqltypes.MakeTestResult(sqltypes.MakeTestFields("col", "int64"), "1", "2", "3", "4") - sbclookup.SetResults([]*sqltypes.Result{result1, result2}) - - _, err := executor.Execute(context.Background(), "TestExecutorResultsExceeded", session, "select * from main1", nil) - if err != nil { - t.Fatal(err) - } - if got, want := warnings.Counts()["ResultsExceeded"], initial; got != want { - t.Errorf("warnings count: %v, want %v", got, want) - } - - _, err = executor.Execute(context.Background(), "TestExecutorResultsExceeded", session, "select * from main1", nil) - if err != nil { - t.Fatal(err) - } - if got, want := warnings.Counts()["ResultsExceeded"], initial+1; got != want { - t.Errorf("warnings count: %v, want %v", got, want) - } -} - func TestExecutorClearsWarnings(t *testing.T) { executor, _, _, _ := createExecutorEnv() session := NewSafeSession(&vtgatepb.Session{ diff --git a/go/vt/vtgate/executor_vschema_ddl_test.go b/go/vt/vtgate/executor_vschema_ddl_test.go index 9fb943a1661..d7f320842d1 100644 --- a/go/vt/vtgate/executor_vschema_ddl_test.go +++ b/go/vt/vtgate/executor_vschema_ddl_test.go @@ -21,6 +21,9 @@ import ( "sort" "testing" "time" + "vitess.io/vitess/go/vt/callerid" + querypb "vitess.io/vitess/go/vt/proto/query" + vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" "context" @@ -707,3 +710,55 @@ func TestExecutorAddDropVindexDDL(t *testing.T) { t.Errorf("Exec %s: %v, want %v", "", gotCount, wantCount) } } + +func TestPlanExecutorVindexDDLACL(t *testing.T) { + //t.Skip("not yet planned") + executor, _, _, _ := createExecutorEnv() + ks := "TestExecutor" + session := NewSafeSession(&vtgatepb.Session{TargetString: ks}) + + ctxRedUser := callerid.NewContext(context.Background(), &vtrpcpb.CallerID{}, &querypb.VTGateCallerID{Username: "redUser"}) + ctxBlueUser := callerid.NewContext(context.Background(), &vtrpcpb.CallerID{}, &querypb.VTGateCallerID{Username: "blueUser"}) + + // test that by default no users can perform the operation + stmt := "alter vschema create vindex test_hash using hash" + authErr := "not authorized to perform vschema operations" + _, err := executor.Execute(ctxRedUser, "TestExecute", session, stmt, nil) + if err == nil || err.Error() != authErr { + t.Errorf("expected error '%s' got '%v'", authErr, err) + } + + _, err = executor.Execute(ctxBlueUser, "TestExecute", session, stmt, nil) + if err == nil || err.Error() != authErr { + t.Errorf("expected error '%s' got '%v'", authErr, err) + } + + // test when all users are enabled + *vschemaacl.AuthorizedDDLUsers = "%" + vschemaacl.Init() + _, err = executor.Execute(ctxRedUser, "TestExecute", session, stmt, nil) + if err != nil { + t.Errorf("unexpected error '%v'", err) + } + stmt = "alter vschema create vindex test_hash2 using hash" + _, err = executor.Execute(ctxBlueUser, "TestExecute", session, stmt, nil) + if err != nil { + t.Errorf("unexpected error '%v'", err) + } + + // test when only one user is enabled + *vschemaacl.AuthorizedDDLUsers = "orangeUser, blueUser, greenUser" + vschemaacl.Init() + _, err = executor.Execute(ctxRedUser, "TestExecute", session, stmt, nil) + if err == nil || err.Error() != authErr { + t.Errorf("expected error '%s' got '%v'", authErr, err) + } + stmt = "alter vschema create vindex test_hash3 using hash" + _, err = executor.Execute(ctxBlueUser, "TestExecute", session, stmt, nil) + if err != nil { + t.Errorf("unexpected error '%v'", err) + } + + // restore the disallowed state + *vschemaacl.AuthorizedDDLUsers = "" +} diff --git a/go/vt/vtgate/gateway.go b/go/vt/vtgate/gateway.go index fe7468efe67..585b64b29d2 100644 --- a/go/vt/vtgate/gateway.go +++ b/go/vt/vtgate/gateway.go @@ -63,8 +63,11 @@ type Gateway interface { // CacheStatus returns a list of TabletCacheStatus per shard / tablet type. CacheStatus() TabletCacheStatusList - // HealthCheck returns a reference to the healthCheck being used by this gateway - HealthCheck() *discovery.HealthCheck + // TabletsCacheStatus returns a displayable version of the health check cache. + TabletsCacheStatus() discovery.TabletsCacheStatusList + + // TabletByAlias returns a QueryService + QueryServiceByAlias(alias *topodatapb.TabletAlias) (queryservice.QueryService, error) } // Creator is the factory method which can create the actual gateway object. diff --git a/go/vt/vtgate/gateway_test_suite.go b/go/vt/vtgate/gateway_test_suite.go index 6241399a21d..8a89250d063 100644 --- a/go/vt/vtgate/gateway_test_suite.go +++ b/go/vt/vtgate/gateway_test_suite.go @@ -43,7 +43,7 @@ import ( // CreateFakeServers returns the servers to use for these tests func CreateFakeServers(t *testing.T) (*tabletconntest.FakeQueryService, *topo.Server, string) { - cell := "local" + cell := tabletconntest.TestCell // the FakeServer is just slightly modified f := tabletconntest.CreateFakeServer(t) @@ -104,5 +104,6 @@ func TestSuite(t *testing.T, name string, g Gateway, f *tabletconntest.FakeQuery Keyspace: tabletconntest.TestTarget.Keyspace, Shard: tabletconntest.TestTarget.Shard, Type: tabletconntest.TestTarget.TabletType, + Alias: tabletconntest.TestAlias, }, f, nil) } diff --git a/go/vt/vtgate/grpc_discovery_test.go b/go/vt/vtgate/grpc_discovery_test.go index 61b12aa47e2..b13d443fd9c 100644 --- a/go/vt/vtgate/grpc_discovery_test.go +++ b/go/vt/vtgate/grpc_discovery_test.go @@ -66,10 +66,7 @@ func TestGRPCDiscovery(t *testing.T) { rs := srvtopo.NewResilientServer(ts, "TestGRPCDiscovery") dg := NewDiscoveryGateway(context.Background(), hc, rs, cell, 2) hc.AddTablet(&topodatapb.Tablet{ - Alias: &topodatapb.TabletAlias{ - Cell: cell, - Uid: 43, - }, + Alias: tabletconntest.TestAlias, Keyspace: tabletconntest.TestTarget.Keyspace, Shard: tabletconntest.TestTarget.Shard, Type: tabletconntest.TestTarget.TabletType, diff --git a/go/vt/vtgate/safe_session.go b/go/vt/vtgate/safe_session.go index 1bba7857239..2eaacdbd6d3 100644 --- a/go/vt/vtgate/safe_session.go +++ b/go/vt/vtgate/safe_session.go @@ -150,8 +150,8 @@ func (session *SafeSession) InTransaction() bool { return session.Session.InTransaction } -// Find returns the transactionId, if any, for a session -func (session *SafeSession) Find(keyspace, shard string, tabletType topodatapb.TabletType) int64 { +// Find returns the transactionId and tabletAlias, if any, for a session +func (session *SafeSession) Find(keyspace, shard string, tabletType topodatapb.TabletType) (transactionID int64, alias *topodatapb.TabletAlias) { session.mu.Lock() defer session.mu.Unlock() sessions := session.ShardSessions @@ -163,10 +163,10 @@ func (session *SafeSession) Find(keyspace, shard string, tabletType topodatapb.T } for _, shardSession := range sessions { if keyspace == shardSession.Target.Keyspace && tabletType == shardSession.Target.TabletType && shard == shardSession.Target.Shard { - return shardSession.TransactionId + return shardSession.TransactionId, shardSession.TabletAlias } } - return 0 + return 0, nil } // Append adds a new ShardSession diff --git a/go/vt/vtgate/scatter_conn.go b/go/vt/vtgate/scatter_conn.go index 98aec586c7b..4ece8d648fb 100644 --- a/go/vt/vtgate/scatter_conn.go +++ b/go/vt/vtgate/scatter_conn.go @@ -22,6 +22,10 @@ import ( "sync" "time" + topodatapb "vitess.io/vitess/go/vt/proto/topodata" + + "vitess.io/vitess/go/vt/vttablet/queryservice" + "golang.org/x/net/context" "vitess.io/vitess/go/sqltypes" @@ -65,10 +69,10 @@ type shardActionFunc func(rs *srvtopo.ResolvedShard, i int) error // multiGoTransaction is capable of executing multiple // shardActionTransactionFunc actions in parallel and consolidating // the results and errors for the caller. -type shardActionTransactionFunc func(rs *srvtopo.ResolvedShard, i int, shouldBegin bool, transactionID int64) (int64, error) +type shardActionTransactionFunc func(rs *srvtopo.ResolvedShard, i int, shouldBegin bool, transactionID int64, alias *topodatapb.TabletAlias) (int64, *topodatapb.TabletAlias, error) -// LegacyNewScatterConn creates a new ScatterConn. -func LegacyNewScatterConn(statsName string, txConn *TxConn, gw Gateway, hc discovery.LegacyHealthCheck) *ScatterConn { +// NewLegacyScatterConn creates a new ScatterConn. +func NewLegacyScatterConn(statsName string, txConn *TxConn, gw Gateway, hc discovery.LegacyHealthCheck) *ScatterConn { tabletCallErrorCountStatsName := "" if statsName != "" { tabletCallErrorCountStatsName = statsName + "ErrorCount" @@ -156,7 +160,7 @@ func (stc *ScatterConn) Execute( rss, session, notInTransaction, - func(rs *srvtopo.ResolvedShard, i int, shouldBegin bool, transactionID int64) (int64, error) { + func(rs *srvtopo.ResolvedShard, i int, shouldBegin bool, transactionID int64, alias *topodatapb.TabletAlias) (int64, *topodatapb.TabletAlias, error) { var ( innerqr *sqltypes.Result err error @@ -166,12 +170,25 @@ func (stc *ScatterConn) Execute( case autocommit: innerqr, err = stc.executeAutocommit(ctx, rs, query, bindVars, opts) case shouldBegin: - innerqr, transactionID, err = rs.QueryService.BeginExecute(ctx, rs.Target, query, bindVars, options) + innerqr, transactionID, alias, err = rs.Gateway.BeginExecute(ctx, rs.Target, query, bindVars, options) default: - innerqr, err = rs.QueryService.Execute(ctx, rs.Target, query, bindVars, transactionID, options) + var qs queryservice.QueryService + _, usingLegacy := rs.Gateway.(*DiscoveryGateway) + if transactionID != 0 && usingLegacy && rs.Target.TabletType != topodatapb.TabletType_MASTER { + return 0, nil, vterrors.Errorf(vtrpcpb.Code_UNIMPLEMENTED, "replica transactions not supported using the legacy healthcheck") + } + + if usingLegacy || transactionID == 0 { + qs = rs.Gateway + } else { + qs, err = rs.Gateway.QueryServiceByAlias(alias) + } + if err == nil { + innerqr, err = qs.Execute(ctx, rs.Target, query, bindVars, transactionID, options) + } } if err != nil { - return transactionID, err + return transactionID, alias, err } mu.Lock() @@ -180,7 +197,7 @@ func (stc *ScatterConn) Execute( if len(qr.Rows) <= *maxMemoryRows { qr.AppendResult(innerqr) } - return transactionID, nil + return transactionID, alias, nil }, ) @@ -216,7 +233,7 @@ func (stc *ScatterConn) ExecuteMultiShard( rss, session, notInTransaction, - func(rs *srvtopo.ResolvedShard, i int, shouldBegin bool, transactionID int64) (int64, error) { + func(rs *srvtopo.ResolvedShard, i int, shouldBegin bool, transactionID int64, alias *topodatapb.TabletAlias) (int64, *topodatapb.TabletAlias, error) { var ( innerqr *sqltypes.Result err error @@ -228,14 +245,24 @@ func (stc *ScatterConn) ExecuteMultiShard( switch { case autocommit: + // tansactionID and alias are not used by this call, it is one round trip innerqr, err = stc.executeAutocommit(ctx, rs, queries[i].Sql, queries[i].BindVariables, opts) case shouldBegin: - innerqr, transactionID, err = rs.QueryService.BeginExecute(ctx, rs.Target, queries[i].Sql, queries[i].BindVariables, opts) + innerqr, transactionID, alias, err = rs.Gateway.BeginExecute(ctx, rs.Target, queries[i].Sql, queries[i].BindVariables, opts) default: - innerqr, err = rs.QueryService.Execute(ctx, rs.Target, queries[i].Sql, queries[i].BindVariables, transactionID, opts) + var qs queryservice.QueryService + _, usingLegacy := rs.Gateway.(*DiscoveryGateway) + if usingLegacy || transactionID == 0 { + qs = rs.Gateway + } else { + qs, err = rs.Gateway.QueryServiceByAlias(alias) + } + if err == nil { + innerqr, err = qs.Execute(ctx, rs.Target, queries[i].Sql, queries[i].BindVariables, transactionID, opts) + } } if err != nil { - return transactionID, err + return transactionID, alias, err } mu.Lock() @@ -244,7 +271,7 @@ func (stc *ScatterConn) ExecuteMultiShard( if len(qr.Rows) <= *maxMemoryRows { qr.AppendResult(innerqr) } - return transactionID, nil + return transactionID, alias, nil }, ) @@ -262,7 +289,7 @@ func (stc *ScatterConn) executeAutocommit(ctx context.Context, rs *srvtopo.Resol }} // ExecuteBatch is a stop-gap because it's the only function that can currently do // single round-trip commit. - qrs, err := rs.QueryService.ExecuteBatch(ctx, rs.Target, queries, true /* asTransaction */, 0, options) + qrs, err := rs.Gateway.ExecuteBatch(ctx, rs.Target, queries, true /* asTransaction */, 0, options) if err != nil { return nil, err } @@ -305,7 +332,7 @@ func (stc *ScatterConn) StreamExecute( fieldSent := false allErrors := stc.multiGo("StreamExecute", rss, func(rs *srvtopo.ResolvedShard, i int) error { - return rs.QueryService.StreamExecute(ctx, rs.Target, query, bindVars, 0, options, func(qr *sqltypes.Result) error { + return rs.Gateway.StreamExecute(ctx, rs.Target, query, bindVars, 0, options, func(qr *sqltypes.Result) error { return stc.processOneStreamingResult(&mu, &fieldSent, qr, callback) }) }) @@ -330,7 +357,7 @@ func (stc *ScatterConn) StreamExecuteMulti( fieldSent := false allErrors := stc.multiGo("StreamExecute", rss, func(rs *srvtopo.ResolvedShard, i int) error { - return rs.QueryService.StreamExecute(ctx, rs.Target, query, bindVars[i], 0, options, func(qr *sqltypes.Result) error { + return rs.Gateway.StreamExecute(ctx, rs.Target, query, bindVars[i], 0, options, func(qr *sqltypes.Result) error { return stc.processOneStreamingResult(&mu, &fieldSent, qr, callback) }) }) @@ -388,7 +415,7 @@ func (stc *ScatterConn) MessageStream(ctx context.Context, rss []*srvtopo.Resolv // an individual stream to end. If we don't succeed on the retries for // messageStreamGracePeriod, we abort and return an error. for { - err := rs.QueryService.MessageStream(ctx, rs.Target, name, func(qr *sqltypes.Result) error { + err := rs.Gateway.MessageStream(ctx, rs.Target, name, func(qr *sqltypes.Result) error { lastErrors.Reset(rs.Target) return stc.processOneStreamingResult(&mu, &fieldSent, qr, callback) }) @@ -445,11 +472,11 @@ func (stc *ScatterConn) GetLegacyHealthCheckCacheStatus() discovery.LegacyTablet // GetHealthCheckCacheStatus returns a displayable version of the HealthCheck cache. func (stc *ScatterConn) GetHealthCheckCacheStatus() discovery.TabletsCacheStatusList { - gw, ok := stc.gateway.(*TabletGateway) - if ok { - return gw.HealthCheck().CacheStatus() + if UsingLegacyGateway() { + panic("this should never be called") } - return nil + + return stc.gateway.TabletsCacheStatus() } // multiGo performs the requested 'action' on the specified @@ -522,12 +549,13 @@ func (stc *ScatterConn) multiGoTransaction( startTime, statsKey := stc.startAction(name, rs.Target) defer stc.endAction(startTime, allErrors, statsKey, &err, session) - shouldBegin, transactionID := transactionInfo(rs.Target, session, notInTransaction) - transactionID, err = action(rs, i, shouldBegin, transactionID) + shouldBegin, transactionID, alias := transactionInfo(rs.Target, session, notInTransaction) + transactionID, alias, err = action(rs, i, shouldBegin, transactionID, alias) if shouldBegin && transactionID != 0 { if appendErr := session.Append(&vtgatepb.Session_ShardSession{ Target: rs.Target, TransactionId: transactionID, + TabletAlias: alias, }, stc.txConn.mode); appendErr != nil { err = appendErr } @@ -564,24 +592,24 @@ func transactionInfo( target *querypb.Target, session *SafeSession, notInTransaction bool, -) (shouldBegin bool, transactionID int64) { +) (shouldBegin bool, transactionID int64, alias *topodatapb.TabletAlias) { if !session.InTransaction() { - return false, 0 + return false, 0, nil } // No need to protect ourselves from the race condition between // Find and Append. The higher level functions ensure that no // duplicate (target) tuples can execute // this at the same time. - transactionID = session.Find(target.Keyspace, target.Shard, target.TabletType) + transactionID, alias = session.Find(target.Keyspace, target.Shard, target.TabletType) if transactionID != 0 { - return false, transactionID + return false, transactionID, alias } // We are in a transaction at higher level, // but client requires not to start a transaction for this query. // If a transaction was started on this conn, we will use it (as above). if notInTransaction { - return false, 0 + return false, 0, nil } - return true, 0 + return true, 0, nil } diff --git a/go/vt/vtgate/scatter_conn_test.go b/go/vt/vtgate/scatter_conn_test.go index 1e508bac31f..078c5704994 100644 --- a/go/vt/vtgate/scatter_conn_test.go +++ b/go/vt/vtgate/scatter_conn_test.go @@ -22,6 +22,8 @@ import ( "strings" "testing" + "github.com/stretchr/testify/assert" + "golang.org/x/net/context" "github.com/golang/protobuf/proto" @@ -123,7 +125,7 @@ func testScatterConnGeneric(t *testing.T, name string, f func(sc *ScatterConn, s // no shard s := createSandbox(name) - sc := newTestScatterConn(hc, new(sandboxTopo), "aa") + sc := newTestLegacyScatterConn(hc, new(sandboxTopo), "aa") qr, err := f(sc, nil) if qr.RowsAffected != 0 { t.Errorf("want 0, got %v", qr.RowsAffected) @@ -134,7 +136,7 @@ func testScatterConnGeneric(t *testing.T, name string, f func(sc *ScatterConn, s // single shard s.Reset() - sc = newTestScatterConn(hc, new(sandboxTopo), "aa") + sc = newTestLegacyScatterConn(hc, new(sandboxTopo), "aa") sbc := hc.AddTestTablet("aa", "0", 1, name, "0", topodatapb.TabletType_REPLICA, true, 1, nil) sbc.MustFailCodes[vtrpcpb.Code_INVALID_ARGUMENT] = 1 _, err = f(sc, []string{"0"}) @@ -151,7 +153,7 @@ func testScatterConnGeneric(t *testing.T, name string, f func(sc *ScatterConn, s // two shards s.Reset() hc.Reset() - sc = newTestScatterConn(hc, new(sandboxTopo), "aa") + sc = newTestLegacyScatterConn(hc, new(sandboxTopo), "aa") sbc0 := hc.AddTestTablet("aa", "0", 1, name, "0", topodatapb.TabletType_REPLICA, true, 1, nil) sbc1 := hc.AddTestTablet("aa", "1", 1, name, "1", topodatapb.TabletType_REPLICA, true, 1, nil) sbc0.MustFailCodes[vtrpcpb.Code_INVALID_ARGUMENT] = 1 @@ -171,7 +173,7 @@ func testScatterConnGeneric(t *testing.T, name string, f func(sc *ScatterConn, s // two shards with different errors s.Reset() hc.Reset() - sc = newTestScatterConn(hc, new(sandboxTopo), "aa") + sc = newTestLegacyScatterConn(hc, new(sandboxTopo), "aa") sbc0 = hc.AddTestTablet("aa", "0", 1, name, "0", topodatapb.TabletType_REPLICA, true, 1, nil) sbc1 = hc.AddTestTablet("aa", "1", 1, name, "1", topodatapb.TabletType_REPLICA, true, 1, nil) sbc0.MustFailCodes[vtrpcpb.Code_INVALID_ARGUMENT] = 1 @@ -192,7 +194,7 @@ func testScatterConnGeneric(t *testing.T, name string, f func(sc *ScatterConn, s // duplicate shards s.Reset() hc.Reset() - sc = newTestScatterConn(hc, new(sandboxTopo), "aa") + sc = newTestLegacyScatterConn(hc, new(sandboxTopo), "aa") sbc = hc.AddTestTablet("aa", "0", 1, name, "0", topodatapb.TabletType_REPLICA, true, 1, nil) _, _ = f(sc, []string{"0", "0"}) // Ensure that we executed only once. @@ -203,7 +205,7 @@ func testScatterConnGeneric(t *testing.T, name string, f func(sc *ScatterConn, s // no errors s.Reset() hc.Reset() - sc = newTestScatterConn(hc, new(sandboxTopo), "aa") + sc = newTestLegacyScatterConn(hc, new(sandboxTopo), "aa") sbc0 = hc.AddTestTablet("aa", "0", 1, name, "0", topodatapb.TabletType_REPLICA, true, 1, nil) sbc1 = hc.AddTestTablet("aa", "1", 1, name, "1", topodatapb.TabletType_REPLICA, true, 1, nil) qr, err = f(sc, []string{"0", "1"}) @@ -231,7 +233,7 @@ func TestMaxMemoryRows(t *testing.T) { createSandbox("TestMaxMemoryRows") hc := discovery.NewFakeLegacyHealthCheck() - sc := newTestScatterConn(hc, new(sandboxTopo), "aa") + sc := newTestLegacyScatterConn(hc, new(sandboxTopo), "aa") sbc0 := hc.AddTestTablet("aa", "0", 1, "TestMaxMemoryRows", "0", topodatapb.TabletType_REPLICA, true, 1, nil) sbc1 := hc.AddTestTablet("aa", "1", 1, "TestMaxMemoryRows", "1", topodatapb.TabletType_REPLICA, true, 1, nil) @@ -250,16 +252,13 @@ func TestMaxMemoryRows(t *testing.T) { res := srvtopo.NewResolver(&sandboxTopo{}, sc.gateway, "aa") rss, _, err := res.ResolveDestinations(ctx, "TestMaxMemoryRows", topodatapb.TabletType_REPLICA, nil, []key.Destination{key.DestinationShard("0"), key.DestinationShard("1")}) - if err != nil { - t.Fatalf("ResolveDestination(0) failed: %v", err) - } + require.NoError(t, err) + session := NewSafeSession(&vtgatepb.Session{InTransaction: true}) _, err = sc.Execute(ctx, "query1", nil, rss, session, true, nil, false) want := "in-memory row count exceeded allowed limit of 3" - if err == nil || err.Error() != want { - t.Errorf("Execute(): %v, want %v", err, want) - } + assert.EqualError(t, err, want) queries := []*querypb.BoundQuery{{ Sql: "query1", @@ -269,16 +268,13 @@ func TestMaxMemoryRows(t *testing.T) { BindVariables: map[string]*querypb.BindVariable{}, }} _, errs := sc.ExecuteMultiShard(ctx, rss, queries, session, false, false) - err = errs[0] - if err == nil || err.Error() != want { - t.Errorf("Execute(): %v, want %v", err, want) - } + assert.EqualError(t, errs[0], want) } func TestMultiExecs(t *testing.T) { createSandbox("TestMultiExecs") hc := discovery.NewFakeLegacyHealthCheck() - sc := newTestScatterConn(hc, new(sandboxTopo), "aa") + sc := newTestLegacyScatterConn(hc, new(sandboxTopo), "aa") sbc0 := hc.AddTestTablet("aa", "0", 1, "TestMultiExecs", "0", topodatapb.TabletType_REPLICA, true, 1, nil) sbc1 := hc.AddTestTablet("aa", "1", 1, "TestMultiExecs", "1", topodatapb.TabletType_REPLICA, true, 1, nil) @@ -288,14 +284,14 @@ func TestMultiExecs(t *testing.T) { Keyspace: "TestMultiExecs", Shard: "0", }, - QueryService: sbc0, + Gateway: sbc0, }, { Target: &querypb.Target{ Keyspace: "TestMultiExecs", Shard: "1", }, - QueryService: sbc1, + Gateway: sbc1, }, } queries := []*querypb.BoundQuery{ @@ -338,14 +334,14 @@ func TestMultiExecs(t *testing.T) { Keyspace: "TestMultiExecs", Shard: "0", }, - QueryService: sbc0, + Gateway: sbc0, }, { Target: &querypb.Target{ Keyspace: "TestMultiExecs", Shard: "1", }, - QueryService: sbc1, + Gateway: sbc1, }, } bvs := []map[string]*querypb.BindVariable{ @@ -370,7 +366,7 @@ func TestMultiExecs(t *testing.T) { func TestScatterConnStreamExecuteSendError(t *testing.T) { createSandbox("TestScatterConnStreamExecuteSendError") hc := discovery.NewFakeLegacyHealthCheck() - sc := newTestScatterConn(hc, new(sandboxTopo), "aa") + sc := newTestLegacyScatterConn(hc, new(sandboxTopo), "aa") hc.AddTestTablet("aa", "0", 1, "TestScatterConnStreamExecuteSendError", "0", topodatapb.TabletType_REPLICA, true, 1, nil) res := srvtopo.NewResolver(&sandboxTopo{}, sc.gateway, "aa") rss, err := res.ResolveDestination(ctx, "TestScatterConnStreamExecuteSendError", topodatapb.TabletType_REPLICA, key.DestinationShard("0")) @@ -393,7 +389,7 @@ func TestScatterConnQueryNotInTransaction(t *testing.T) { // case 1: read query (not in transaction) followed by write query, not in the same shard. hc.Reset() - sc := newTestScatterConn(hc, new(sandboxTopo), "aa") + sc := newTestLegacyScatterConn(hc, new(sandboxTopo), "aa") sbc0 := hc.AddTestTablet("aa", "0", 1, "TestScatterConnQueryNotInTransaction", "0", topodatapb.TabletType_REPLICA, true, 1, nil) sbc1 := hc.AddTestTablet("aa", "1", 1, "TestScatterConnQueryNotInTransaction", "1", topodatapb.TabletType_REPLICA, true, 1, nil) @@ -420,6 +416,7 @@ func TestScatterConnQueryNotInTransaction(t *testing.T) { TabletType: topodatapb.TabletType_REPLICA, }, TransactionId: 1, + TabletAlias: sbc0.Tablet().Alias, }}, } if !proto.Equal(&wantSession, session.Session) { @@ -443,7 +440,7 @@ func TestScatterConnQueryNotInTransaction(t *testing.T) { // case 2: write query followed by read query (not in transaction), not in the same shard. s.Reset() hc.Reset() - sc = newTestScatterConn(hc, new(sandboxTopo), "aa") + sc = newTestLegacyScatterConn(hc, new(sandboxTopo), "aa") sbc0 = hc.AddTestTablet("aa", "0", 1, "TestScatterConnQueryNotInTransaction", "0", topodatapb.TabletType_REPLICA, true, 1, nil) sbc1 = hc.AddTestTablet("aa", "1", 1, "TestScatterConnQueryNotInTransaction", "1", topodatapb.TabletType_REPLICA, true, 1, nil) session = NewSafeSession(&vtgatepb.Session{InTransaction: true}) @@ -470,6 +467,7 @@ func TestScatterConnQueryNotInTransaction(t *testing.T) { TabletType: topodatapb.TabletType_REPLICA, }, TransactionId: 1, + TabletAlias: sbc0.Tablet().Alias, }}, } if !proto.Equal(&wantSession, session.Session) { @@ -493,23 +491,22 @@ func TestScatterConnQueryNotInTransaction(t *testing.T) { // case 3: write query followed by read query, in the same shard. s.Reset() hc.Reset() - sc = newTestScatterConn(hc, new(sandboxTopo), "aa") + sc = newTestLegacyScatterConn(hc, new(sandboxTopo), "aa") sbc0 = hc.AddTestTablet("aa", "0", 1, "TestScatterConnQueryNotInTransaction", "0", topodatapb.TabletType_REPLICA, true, 1, nil) sbc1 = hc.AddTestTablet("aa", "1", 1, "TestScatterConnQueryNotInTransaction", "1", topodatapb.TabletType_REPLICA, true, 1, nil) session = NewSafeSession(&vtgatepb.Session{InTransaction: true}) + noTxSession := NewSafeSession(&vtgatepb.Session{InTransaction: false}) res = srvtopo.NewResolver(&sandboxTopo{}, sc.gateway, "aa") rss0, err = res.ResolveDestination(ctx, "TestScatterConnQueryNotInTransaction", topodatapb.TabletType_REPLICA, key.DestinationShard("0")) - if err != nil { - t.Fatalf("ResolveDestination(0) failed: %v", err) - } + require.NoError(t, err) rss1, err = res.ResolveDestination(ctx, "TestScatterConnQueryNotInTransaction", topodatapb.TabletType_REPLICA, key.DestinationShards([]string{"0", "1"})) - if err != nil { - t.Fatalf("ResolveDestination(1) failed: %v", err) - } + require.NoError(t, err) - sc.Execute(ctx, "query1", nil, rss0, session, false, nil, false) - sc.Execute(ctx, "query1", nil, rss1, session, true, nil, false) + _, err = sc.Execute(ctx, "query1", nil, rss0, session, false, nil, false) + require.NoError(t, err) + _, err = sc.Execute(ctx, "query1", nil, rss1, noTxSession, true, nil, false) + require.NoError(t, err) wantSession = vtgatepb.Session{ InTransaction: true, @@ -520,18 +517,19 @@ func TestScatterConnQueryNotInTransaction(t *testing.T) { TabletType: topodatapb.TabletType_REPLICA, }, TransactionId: 1, + TabletAlias: sbc0.Tablet().Alias, }}, } if !proto.Equal(&wantSession, session.Session) { t.Errorf("want\n%+v\ngot\n%+v", wantSession, *session.Session) } - sc.txConn.Commit(ctx, session) - { - execCount0 := sbc0.ExecCount.Get() - execCount1 := sbc1.ExecCount.Get() - if execCount0 != 2 || execCount1 != 1 { - t.Errorf("want 2/1, got %d/%d", execCount0, execCount1) - } + err = sc.txConn.Commit(ctx, session) + require.NoError(t, err) + + execCount0 := sbc0.ExecCount.Get() + execCount1 := sbc1.ExecCount.Get() + if execCount0 != 2 || execCount1 != 1 { + t.Errorf("want 2/1, got %d/%d", execCount0, execCount1) } if commitCount := sbc0.CommitCount.Get(); commitCount != 1 { t.Errorf("want 1, got %d", commitCount) @@ -546,7 +544,7 @@ func TestScatterConnSingleDB(t *testing.T) { hc := discovery.NewFakeLegacyHealthCheck() hc.Reset() - sc := newTestScatterConn(hc, new(sandboxTopo), "aa") + sc := newTestLegacyScatterConn(hc, new(sandboxTopo), "aa") hc.AddTestTablet("aa", "0", 1, "TestScatterConnSingleDB", "0", topodatapb.TabletType_MASTER, true, 1, nil) hc.AddTestTablet("aa", "1", 1, "TestScatterConnSingleDB", "1", topodatapb.TabletType_MASTER, true, 1, nil) @@ -648,13 +646,13 @@ func TestAppendResult(t *testing.T) { } } -func newTestScatterConn(hc discovery.LegacyHealthCheck, serv srvtopo.Server, cell string) *ScatterConn { +func newTestLegacyScatterConn(hc discovery.LegacyHealthCheck, serv srvtopo.Server, cell string) *ScatterConn { // The topo.Server is used to start watching the cells described // in '-cells_to_watch' command line parameter, which is // empty by default. So it's unused in this test, set to nil. gw := GatewayCreator()(ctx, hc, serv, cell, 3) tc := NewTxConn(gw, vtgatepb.TransactionMode_TWOPC) - return LegacyNewScatterConn("", tc, gw, hc) + return NewLegacyScatterConn("", tc, gw, hc) } var ctx = context.Background() diff --git a/go/vt/vtgate/tabletgateway.go b/go/vt/vtgate/tabletgateway.go index 255c492326a..68255e16add 100644 --- a/go/vt/vtgate/tabletgateway.go +++ b/go/vt/vtgate/tabletgateway.go @@ -48,11 +48,42 @@ func init() { RegisterGatewayCreator(tabletGatewayImplementation, createTabletGateway) } +//HealthCheck declares what the TabletGateway needs from the HealthCheck +type HealthCheck interface { + // CacheStatus returns a displayable version of the health check cache. + CacheStatus() discovery.TabletsCacheStatusList + + // Close stops the healthcheck. + Close() error + + // WaitForAllServingTablets waits for at least one healthy serving tablet in + // each given target before returning. + // It will return ctx.Err() if the context is canceled. + // It will return an error if it can't read the necessary topology records. + WaitForAllServingTablets(ctx context.Context, targets []*querypb.Target) error + + // TabletConnection returns the TabletConn of the given tablet. + TabletConnection(alias *topodatapb.TabletAlias) (queryservice.QueryService, error) + + // RegisterStats registers the connection counts stats + RegisterStats() + + // GetHealthyTabletStats returns only the healthy tablets. + // The returned array is owned by the caller. + // For TabletType_MASTER, this will only return at most one entry, + // the most recent tablet of type master. + // This returns a copy of the data so that callers can access without + // synchronization + GetHealthyTabletStats(target *querypb.Target) []*discovery.TabletHealth +} + +var _ HealthCheck = (*discovery.HealthCheckImpl)(nil) + // TabletGateway implements the Gateway interface. // This implementation uses the new healthcheck module. type TabletGateway struct { queryservice.QueryService - hc *discovery.HealthCheck + hc HealthCheck srvTopoServer srvtopo.Server localCell string retryCount int @@ -67,8 +98,7 @@ type TabletGateway struct { buffer *buffer.Buffer } -func createTabletGateway(ctx context.Context, unused discovery.LegacyHealthCheck, serv srvtopo.Server, - cell string, unused2 int) Gateway { +func createTabletGateway(ctx context.Context, _ discovery.LegacyHealthCheck, serv srvtopo.Server, cell string, _ int) Gateway { return NewTabletGateway(ctx, serv, cell) } @@ -117,6 +147,11 @@ func NewTabletGateway(ctx context.Context, serv srvtopo.Server, localCell string return gw } +// QueryServiceByAlias satisfies the Gateway interface +func (gw *TabletGateway) QueryServiceByAlias(alias *topodatapb.TabletAlias) (queryservice.QueryService, error) { + return gw.hc.TabletConnection(alias) +} + // RegisterStats registers the stats to export the lag since the last refresh // and the checksum of the topology func (gw *TabletGateway) RegisterStats() { @@ -140,7 +175,7 @@ func (gw *TabletGateway) WaitForTablets(ctx context.Context, tabletTypesToWait [ // Close shuts down underlying connections. // This function hides the inner implementation. -func (gw *TabletGateway) Close(ctx context.Context) error { +func (gw *TabletGateway) Close(_ context.Context) error { gw.buffer.Shutdown() return gw.hc.Close() } @@ -163,8 +198,12 @@ func (gw *TabletGateway) CacheStatus() TabletCacheStatusList { // the middle of a transaction. While returning the error check if it maybe a result of // a resharding event, and set the re-resolve bit and let the upper layers // re-resolve and retry. -func (gw *TabletGateway) withRetry(ctx context.Context, target *querypb.Target, unused queryservice.QueryService, - name string, inTransaction bool, inner func(ctx context.Context, target *querypb.Target, conn queryservice.QueryService) (bool, error)) error { +func (gw *TabletGateway) withRetry(ctx context.Context, target *querypb.Target, _ queryservice.QueryService, + _ string, inTransaction bool, inner func(ctx context.Context, target *querypb.Target, conn queryservice.QueryService) (bool, error)) error { + // for transactions, we connect to a specific tablet instead of letting gateway choose one + if inTransaction { + return vterrors.Errorf(vtrpcpb.Code_INTERNAL, "gateway's query service can only be used for non-transactional queries") + } var tabletLastUsed *topodatapb.Tablet var err error invalidTablets := make(map[string]bool) @@ -238,7 +277,7 @@ func (gw *TabletGateway) withRetry(ctx context.Context, target *querypb.Target, } // execute - if th.Conn == nil { + if th == nil || th.Conn == nil { err = vterrors.Errorf(vtrpcpb.Code_UNAVAILABLE, "no connection for tablet %v", tabletLastUsed) invalidTablets[topoproto.TabletAliasString(tabletLastUsed.Alias)] = true continue @@ -326,7 +365,7 @@ func (gw *TabletGateway) nextTablet(cell string, tablets []*discovery.TabletHeal return -1 } -// HealthCheck satisfies the Gateway interface -func (gw *TabletGateway) HealthCheck() *discovery.HealthCheck { - return gw.hc +// TabletsCacheStatus returns a displayable version of the health check cache. +func (gw *TabletGateway) TabletsCacheStatus() discovery.TabletsCacheStatusList { + return gw.hc.CacheStatus() } diff --git a/go/vt/vtgate/tx_conn.go b/go/vt/vtgate/tx_conn.go index 7a3ba326974..4041497c20a 100644 --- a/go/vt/vtgate/tx_conn.go +++ b/go/vt/vtgate/tx_conn.go @@ -20,6 +20,10 @@ import ( "fmt" "sync" + topodatapb "vitess.io/vitess/go/vt/proto/topodata" + + "vitess.io/vitess/go/vt/vttablet/queryservice" + "golang.org/x/net/context" "vitess.io/vitess/go/vt/concurrency" @@ -78,29 +82,45 @@ func (txc *TxConn) Commit(ctx context.Context, session *SafeSession) error { return txc.commitNormal(ctx, session) } +func (txc *TxConn) queryService(alias *topodatapb.TabletAlias) (queryservice.QueryService, error) { + qs, _ := txc.gateway.(*DiscoveryGateway) + if qs != nil { + return qs, nil + } + return txc.gateway.QueryServiceByAlias(alias) +} + +func (txc *TxConn) commitShard(ctx context.Context, s *vtgatepb.Session_ShardSession) error { + var qs queryservice.QueryService + var err error + qs, err = txc.queryService(s.TabletAlias) + if err != nil { + return err + } + return qs.Commit(ctx, s.Target, s.TransactionId) +} + func (txc *TxConn) commitNormal(ctx context.Context, session *SafeSession) error { - if err := txc.runSessions(session.PreSessions, func(s *vtgatepb.Session_ShardSession) error { - defer func() { s.TransactionId = 0 }() - return txc.gateway.Commit(ctx, s.Target, s.TransactionId) - }); err != nil { + if err := txc.runSessions(ctx, session.PreSessions, txc.commitShard); err != nil { _ = txc.Rollback(ctx, session) return err } + // Close all PreSessions + for _, shardSession := range session.PreSessions { + shardSession.TransactionId = 0 + } + // Retain backward compatibility on commit order for the normal session. for _, shardSession := range session.ShardSessions { - if err := txc.gateway.Commit(ctx, shardSession.Target, shardSession.TransactionId); err != nil { - shardSession.TransactionId = 0 + if err := txc.commitShard(ctx, shardSession); err != nil { _ = txc.Rollback(ctx, session) return err } shardSession.TransactionId = 0 } - if err := txc.runSessions(session.PostSessions, func(s *vtgatepb.Session_ShardSession) error { - defer func() { s.TransactionId = 0 }() - return txc.gateway.Commit(ctx, s.Target, s.TransactionId) - }); err != nil { + if err := txc.runSessions(ctx, session.PostSessions, txc.commitShard); err != nil { // If last commit fails, there will be nothing to rollback. session.RecordWarning(&querypb.QueryWarning{Message: fmt.Sprintf("post-operation transaction had an error: %v", err)}) } @@ -131,8 +151,14 @@ func (txc *TxConn) commit2PC(ctx context.Context, session *SafeSession) error { return err } - err = txc.runSessions(session.ShardSessions[1:], func(s *vtgatepb.Session_ShardSession) error { - return txc.gateway.Prepare(ctx, s.Target, s.TransactionId, dtid) + err = txc.runSessions(ctx, session.ShardSessions[1:], func(ctx context.Context, s *vtgatepb.Session_ShardSession) error { + var qs queryservice.QueryService + var err error + qs, err = txc.queryService(s.TabletAlias) + if err != nil { + return err + } + return qs.Prepare(ctx, s.Target, s.TransactionId, dtid) }) if err != nil { // TODO(sougou): Perform a more fine-grained cleanup @@ -144,12 +170,16 @@ func (txc *TxConn) commit2PC(ctx context.Context, session *SafeSession) error { return err } - err = txc.gateway.StartCommit(ctx, mmShard.Target, mmShard.TransactionId, dtid) + qs, err := txc.queryService(mmShard.TabletAlias) + if err != nil { + return err + } + err = qs.StartCommit(ctx, mmShard.Target, mmShard.TransactionId, dtid) if err != nil { return err } - err = txc.runSessions(session.ShardSessions[1:], func(s *vtgatepb.Session_ShardSession) error { + err = txc.runSessions(ctx, session.ShardSessions[1:], func(ctx context.Context, s *vtgatepb.Session_ShardSession) error { return txc.gateway.CommitPrepared(ctx, s.Target, dtid) }) if err != nil { @@ -169,11 +199,15 @@ func (txc *TxConn) Rollback(ctx context.Context, session *SafeSession) error { allsessions := append(session.PreSessions, session.ShardSessions...) allsessions = append(allsessions, session.PostSessions...) - return txc.runSessions(allsessions, func(s *vtgatepb.Session_ShardSession) error { + return txc.runSessions(ctx, allsessions, func(ctx context.Context, s *vtgatepb.Session_ShardSession) error { if s.TransactionId == 0 { return nil } - return txc.gateway.Rollback(ctx, s.Target, s.TransactionId) + qs, err := txc.queryService(s.TabletAlias) + if err != nil { + return err + } + return qs.Rollback(ctx, s.Target, s.TransactionId) }) } @@ -196,7 +230,11 @@ func (txc *TxConn) Resolve(ctx context.Context, dtid string) error { case querypb.TransactionState_PREPARE: // If state is PREPARE, make a decision to rollback and // fallthrough to the rollback workflow. - if err := txc.gateway.SetRollback(ctx, mmShard.Target, transaction.Dtid, mmShard.TransactionId); err != nil { + qs, err := txc.queryService(mmShard.TabletAlias) + if err != nil { + return err + } + if err := qs.SetRollback(ctx, mmShard.Target, transaction.Dtid, mmShard.TransactionId); err != nil { return err } fallthrough @@ -236,10 +274,10 @@ func (txc *TxConn) resumeCommit(ctx context.Context, target *querypb.Target, tra } // runSessions executes the action for all shardSessions in parallel and returns a consolildated error. -func (txc *TxConn) runSessions(shardSessions []*vtgatepb.Session_ShardSession, action func(*vtgatepb.Session_ShardSession) error) error { +func (txc *TxConn) runSessions(ctx context.Context, shardSessions []*vtgatepb.Session_ShardSession, action func(context.Context, *vtgatepb.Session_ShardSession) error) error { // Fastpath. if len(shardSessions) == 1 { - return action(shardSessions[0]) + return action(ctx, shardSessions[0]) } allErrors := new(concurrency.AllErrorRecorder) @@ -248,7 +286,7 @@ func (txc *TxConn) runSessions(shardSessions []*vtgatepb.Session_ShardSession, a wg.Add(1) go func(s *vtgatepb.Session_ShardSession) { defer wg.Done() - if err := action(s); err != nil { + if err := action(ctx, s); err != nil { allErrors.RecordError(err) } }(s) diff --git a/go/vt/vtgate/tx_conn_test.go b/go/vt/vtgate/tx_conn_test.go index 85ec6da9248..11a04051a8e 100644 --- a/go/vt/vtgate/tx_conn_test.go +++ b/go/vt/vtgate/tx_conn_test.go @@ -17,10 +17,11 @@ limitations under the License. package vtgate import ( - "strings" "testing" - "github.com/golang/protobuf/proto" + "github.com/stretchr/testify/assert" + "vitess.io/vitess/go/test/utils" + "github.com/stretchr/testify/require" "golang.org/x/net/context" @@ -41,27 +42,18 @@ func TestTxConnBegin(t *testing.T) { session := &vtgatepb.Session{} // begin - if err := sc.txConn.Begin(context.Background(), NewSafeSession(session)); err != nil { - t.Error(err) - } - wantSession := &vtgatepb.Session{InTransaction: true} - if !proto.Equal(session, wantSession) { - t.Errorf("begin: %v, want %v", session, wantSession) - } - if _, err := sc.Execute(context.Background(), "query1", nil, rss0, NewSafeSession(session), false, nil, false); err != nil { - t.Error(err) - } + err := sc.txConn.Begin(ctx, NewSafeSession(session)) + require.NoError(t, err) + wantSession := vtgatepb.Session{InTransaction: true} + utils.MustMatch(t, &wantSession, session, "Session") + _, err = sc.Execute(ctx, "query1", nil, rss0, NewSafeSession(session), false, nil, false) + require.NoError(t, err) // Begin again should cause a commit and a new begin. - if err := sc.txConn.Begin(context.Background(), NewSafeSession(session)); err != nil { - t.Error(err) - } - if !proto.Equal(session, wantSession) { - t.Errorf("begin: %v, want %v", session, wantSession) - } - if commitCount := sbc0.CommitCount.Get(); commitCount != 1 { - t.Errorf("want 1, got %d", commitCount) - } + require.NoError(t, + sc.txConn.Begin(ctx, NewSafeSession(session))) + utils.MustMatch(t, &wantSession, session, "Session") + assert.EqualValues(t, 1, sbc0.CommitCount.Get(), "sbc0.CommitCount") } func TestTxConnCommitSuccess(t *testing.T) { @@ -70,7 +62,7 @@ func TestTxConnCommitSuccess(t *testing.T) { // Sequence the executes to ensure commit order session := NewSafeSession(&vtgatepb.Session{InTransaction: true}) - sc.Execute(context.Background(), "query1", nil, rss0, session, false, nil, false) + sc.Execute(ctx, "query1", nil, rss0, session, false, nil, false) wantSession := vtgatepb.Session{ InTransaction: true, ShardSessions: []*vtgatepb.Session_ShardSession{{ @@ -80,12 +72,11 @@ func TestTxConnCommitSuccess(t *testing.T) { TabletType: topodatapb.TabletType_MASTER, }, TransactionId: 1, + TabletAlias: sbc0.Tablet().Alias, }}, } - if !proto.Equal(session.Session, &wantSession) { - t.Errorf("Session:\n%+v, want\n%+v", *session.Session, wantSession) - } - sc.Execute(context.Background(), "query1", nil, rss01, session, false, nil, false) + utils.MustMatch(t, &wantSession, session.Session, "Session") + sc.Execute(ctx, "query1", nil, rss01, session, false, nil, false) wantSession = vtgatepb.Session{ InTransaction: true, ShardSessions: []*vtgatepb.Session_ShardSession{{ @@ -95,6 +86,7 @@ func TestTxConnCommitSuccess(t *testing.T) { TabletType: topodatapb.TabletType_MASTER, }, TransactionId: 1, + TabletAlias: sbc0.Tablet().Alias, }, { Target: &querypb.Target{ Keyspace: "TestTxConn", @@ -102,65 +94,48 @@ func TestTxConnCommitSuccess(t *testing.T) { TabletType: topodatapb.TabletType_MASTER, }, TransactionId: 1, + TabletAlias: sbc0.Tablet().Alias, }}, } - if !proto.Equal(session.Session, &wantSession) { - t.Errorf("Session:\n%+v, want\n%+v", *session.Session, wantSession) - } + utils.MustMatch(t, &wantSession, session.Session, "Session") - if err := sc.txConn.Commit(context.Background(), session); err != nil { - t.Error(err) - } + require.NoError(t, + sc.txConn.Commit(ctx, session)) wantSession = vtgatepb.Session{} - if !proto.Equal(session.Session, &wantSession) { - t.Errorf("Session:\n%+v, want\n%+v", *session.Session, wantSession) - } - if commitCount := sbc0.CommitCount.Get(); commitCount != 1 { - t.Errorf("sbc0.CommitCount: %d, want 1", commitCount) - } - if commitCount := sbc1.CommitCount.Get(); commitCount != 1 { - t.Errorf("sbc1.commitCount: %d, want 1", commitCount) - } + utils.MustMatch(t, &wantSession, session.Session, "Session") + assert.EqualValues(t, 1, sbc0.CommitCount.Get(), "sbc0.CommitCount") + assert.EqualValues(t, 1, sbc1.CommitCount.Get(), "sbc1.CommitCount") } func TestTxConnCommitOrderFailure1(t *testing.T) { sc, sbc0, sbc1, rss0, rss1, _ := newTestTxConnEnv(t, "TestTxConn") sc.txConn.mode = vtgatepb.TransactionMode_MULTI - queries := []*querypb.BoundQuery{{ - Sql: "query1", - }} + queries := []*querypb.BoundQuery{{Sql: "query1"}} // Sequence the executes to ensure commit order session := NewSafeSession(&vtgatepb.Session{InTransaction: true}) - sc.ExecuteMultiShard(context.Background(), rss0, queries, session, false, false) + sc.ExecuteMultiShard(ctx, rss0, queries, session, false, false) session.SetCommitOrder(vtgatepb.CommitOrder_PRE) - sc.ExecuteMultiShard(context.Background(), rss0, queries, session, false, false) + sc.ExecuteMultiShard(ctx, rss0, queries, session, false, false) session.SetCommitOrder(vtgatepb.CommitOrder_POST) - sc.ExecuteMultiShard(context.Background(), rss1, queries, session, false, false) + sc.ExecuteMultiShard(ctx, rss1, queries, session, false, false) sbc0.MustFailCodes[vtrpcpb.Code_INVALID_ARGUMENT] = 1 - err := sc.txConn.Commit(context.Background(), session) - want := "INVALID_ARGUMENT error" - if err == nil || !strings.Contains(err.Error(), want) { - t.Errorf("Commit: %v, want %s", err, want) - } + err := sc.txConn.Commit(ctx, session) + require.Error(t, err) + assert.Contains(t, err.Error(), "INVALID_ARGUMENT error", "commit error") wantSession := vtgatepb.Session{} - if !proto.Equal(session.Session, &wantSession) { - t.Errorf("Session:\n%+v, want\n%+v", *session.Session, wantSession) - } - if commitCount := sbc0.CommitCount.Get(); commitCount != 1 { - t.Errorf("sbc0.CommitCount: %d, want 1", commitCount) - } - if rollbackCount := sbc0.RollbackCount.Get(); rollbackCount != 1 { - t.Errorf("sbc0.rollbackCount: %d, want 1", rollbackCount) - } - if rollbackCount := sbc1.RollbackCount.Get(); rollbackCount != 1 { - t.Errorf("sbc1.rollbackCount: %d, want 1", rollbackCount) - } + utils.MustMatch(t, &wantSession, session.Session, "Session") + assert.EqualValues(t, 1, sbc0.CommitCount.Get(), "sbc0.CommitCount") + // first commit failed so we don't try to commit the second shard + assert.EqualValues(t, 0, sbc1.CommitCount.Get(), "sbc1.CommitCount") + // When the commit fails, we try to clean up by issuing a rollback + assert.EqualValues(t, 2, sbc0.RollbackCount.Get(), "sbc0.RollbackCount") + assert.EqualValues(t, 1, sbc1.RollbackCount.Get(), "sbc1.RollbackCount") } func TestTxConnCommitOrderFailure2(t *testing.T) { @@ -182,25 +157,17 @@ func TestTxConnCommitOrderFailure2(t *testing.T) { sc.ExecuteMultiShard(context.Background(), rss1, queries, session, false, false) sbc1.MustFailCodes[vtrpcpb.Code_INVALID_ARGUMENT] = 1 - err := sc.txConn.Commit(context.Background(), session) - want := "INVALID_ARGUMENT error" - if err == nil || !strings.Contains(err.Error(), want) { - t.Errorf("Commit: %v, want %s", err, want) - } + err := sc.txConn.Commit(ctx, session) + require.Error(t, err) + assert.Contains(t, err.Error(), "INVALID_ARGUMENT error", "Commit") wantSession := vtgatepb.Session{} - if !proto.Equal(session.Session, &wantSession) { - t.Errorf("Session:\n%+v, want\n%+v", *session.Session, wantSession) - } - if commitCount := sbc0.CommitCount.Get(); commitCount != 1 { - t.Errorf("sbc0.CommitCount: %d, want 1", commitCount) - } - if commitCount := sbc1.CommitCount.Get(); commitCount != 1 { - t.Errorf("sbc1.commitCount: %d, want 1", commitCount) - } - if rollbackCount := sbc1.RollbackCount.Get(); rollbackCount != 1 { - t.Errorf("sbc1.rollbackCount: %d, want 1", rollbackCount) - } + utils.MustMatch(t, &wantSession, session.Session, "Session") + assert.EqualValues(t, 1, sbc0.CommitCount.Get(), "sbc0.CommitCount") + assert.EqualValues(t, 1, sbc1.CommitCount.Get(), "sbc1.CommitCount") + // When the commit fails, we try to clean up by issuing a rollback + assert.EqualValues(t, 0, sbc0.RollbackCount.Get(), "sbc0.RollbackCount") + assert.EqualValues(t, 2, sbc1.RollbackCount.Get(), "sbc1.RollbackCount") } func TestTxConnCommitOrderFailure3(t *testing.T) { @@ -213,18 +180,17 @@ func TestTxConnCommitOrderFailure3(t *testing.T) { // Sequence the executes to ensure commit order session := NewSafeSession(&vtgatepb.Session{InTransaction: true}) - sc.ExecuteMultiShard(context.Background(), rss0, queries, session, false, false) + sc.ExecuteMultiShard(ctx, rss0, queries, session, false, false) session.SetCommitOrder(vtgatepb.CommitOrder_PRE) - sc.ExecuteMultiShard(context.Background(), rss0, queries, session, false, false) + sc.ExecuteMultiShard(ctx, rss0, queries, session, false, false) session.SetCommitOrder(vtgatepb.CommitOrder_POST) - sc.ExecuteMultiShard(context.Background(), rss1, queries, session, false, false) + sc.ExecuteMultiShard(ctx, rss1, queries, session, false, false) sbc1.MustFailCodes[vtrpcpb.Code_INVALID_ARGUMENT] = 1 - if err := sc.txConn.Commit(context.Background(), session); err != nil { - t.Error(err) - } + require.NoError(t, + sc.txConn.Commit(ctx, session)) // The last failed commit must generate a warning. wantSession := vtgatepb.Session{ @@ -232,15 +198,9 @@ func TestTxConnCommitOrderFailure3(t *testing.T) { Message: "post-operation transaction had an error: Code: INVALID_ARGUMENT\nINVALID_ARGUMENT error\n\ntarget: TestTxConn.1.master, used tablet: aa-0 (1)", }}, } - if !proto.Equal(session.Session, &wantSession) { - t.Errorf("Session:\n%+v, want\n%+v", *session.Session, wantSession) - } - if commitCount := sbc0.CommitCount.Get(); commitCount != 2 { - t.Errorf("sbc0.CommitCount: %d, want 2", commitCount) - } - if commitCount := sbc1.CommitCount.Get(); commitCount != 1 { - t.Errorf("sbc1.commitCount: %d, want 1", commitCount) - } + utils.MustMatch(t, &wantSession, session.Session, "Session") + assert.EqualValues(t, 2, sbc0.CommitCount.Get(), "sbc0.CommitCount") + assert.EqualValues(t, 1, sbc1.CommitCount.Get(), "sbc1.CommitCount") } func TestTxConnCommitOrderSuccess(t *testing.T) { @@ -253,7 +213,7 @@ func TestTxConnCommitOrderSuccess(t *testing.T) { // Sequence the executes to ensure commit order session := NewSafeSession(&vtgatepb.Session{InTransaction: true}) - sc.ExecuteMultiShard(context.Background(), rss0, queries, session, false, false) + sc.ExecuteMultiShard(ctx, rss0, queries, session, false, false) wantSession := vtgatepb.Session{ InTransaction: true, ShardSessions: []*vtgatepb.Session_ShardSession{{ @@ -263,14 +223,13 @@ func TestTxConnCommitOrderSuccess(t *testing.T) { TabletType: topodatapb.TabletType_MASTER, }, TransactionId: 1, + TabletAlias: sbc0.Tablet().Alias, }}, } - if !proto.Equal(session.Session, &wantSession) { - t.Errorf("Session:\n%+v, want\n%+v", *session.Session, wantSession) - } + utils.MustMatch(t, &wantSession, session.Session, "Session") session.SetCommitOrder(vtgatepb.CommitOrder_PRE) - sc.ExecuteMultiShard(context.Background(), rss0, queries, session, false, false) + sc.ExecuteMultiShard(ctx, rss0, queries, session, false, false) wantSession = vtgatepb.Session{ InTransaction: true, PreSessions: []*vtgatepb.Session_ShardSession{{ @@ -280,6 +239,7 @@ func TestTxConnCommitOrderSuccess(t *testing.T) { TabletType: topodatapb.TabletType_MASTER, }, TransactionId: 2, + TabletAlias: sbc0.Tablet().Alias, }}, ShardSessions: []*vtgatepb.Session_ShardSession{{ Target: &querypb.Target{ @@ -288,14 +248,13 @@ func TestTxConnCommitOrderSuccess(t *testing.T) { TabletType: topodatapb.TabletType_MASTER, }, TransactionId: 1, + TabletAlias: sbc0.Tablet().Alias, }}, } - if !proto.Equal(session.Session, &wantSession) { - t.Errorf("Session:\n%+v, want\n%+v", *session.Session, wantSession) - } + utils.MustMatch(t, &wantSession, session.Session, "Session") session.SetCommitOrder(vtgatepb.CommitOrder_POST) - sc.ExecuteMultiShard(context.Background(), rss1, queries, session, false, false) + sc.ExecuteMultiShard(ctx, rss1, queries, session, false, false) wantSession = vtgatepb.Session{ InTransaction: true, PreSessions: []*vtgatepb.Session_ShardSession{{ @@ -305,6 +264,7 @@ func TestTxConnCommitOrderSuccess(t *testing.T) { TabletType: topodatapb.TabletType_MASTER, }, TransactionId: 2, + TabletAlias: sbc0.Tablet().Alias, }}, ShardSessions: []*vtgatepb.Session_ShardSession{{ Target: &querypb.Target{ @@ -313,6 +273,7 @@ func TestTxConnCommitOrderSuccess(t *testing.T) { TabletType: topodatapb.TabletType_MASTER, }, TransactionId: 1, + TabletAlias: sbc0.Tablet().Alias, }}, PostSessions: []*vtgatepb.Session_ShardSession{{ Target: &querypb.Target{ @@ -321,253 +282,163 @@ func TestTxConnCommitOrderSuccess(t *testing.T) { TabletType: topodatapb.TabletType_MASTER, }, TransactionId: 1, + TabletAlias: sbc0.Tablet().Alias, }}, } - if !proto.Equal(session.Session, &wantSession) { - t.Errorf("Session:\n%+v, want\n%+v", *session.Session, wantSession) - } + utils.MustMatch(t, &wantSession, session.Session, "Session") // Ensure nothing changes if we reuse a transaction. - sc.ExecuteMultiShard(context.Background(), rss1, queries, session, false, false) - if !proto.Equal(session.Session, &wantSession) { - t.Errorf("Session:\n%+v, want\n%+v", *session.Session, wantSession) - } + sc.ExecuteMultiShard(ctx, rss1, queries, session, false, false) + utils.MustMatch(t, &wantSession, session.Session, "Session") - if err := sc.txConn.Commit(context.Background(), session); err != nil { - t.Error(err) - } + require.NoError(t, + sc.txConn.Commit(ctx, session)) wantSession = vtgatepb.Session{} - if !proto.Equal(session.Session, &wantSession) { - t.Errorf("Session:\n%+v, want\n%+v", *session.Session, wantSession) - } - if commitCount := sbc0.CommitCount.Get(); commitCount != 2 { - t.Errorf("sbc0.CommitCount: %d, want 2", commitCount) - } - if commitCount := sbc1.CommitCount.Get(); commitCount != 1 { - t.Errorf("sbc1.commitCount: %d, want 1", commitCount) - } + utils.MustMatch(t, &wantSession, session.Session, "Session") + assert.EqualValues(t, 2, sbc0.CommitCount.Get(), "sbc0.CommitCount") + assert.EqualValues(t, 1, sbc1.CommitCount.Get(), "sbc1.CommitCount") } func TestTxConnCommit2PC(t *testing.T) { sc, sbc0, sbc1, rss0, _, rss01 := newTestTxConnEnv(t, "TestTxConnCommit2PC") session := NewSafeSession(&vtgatepb.Session{InTransaction: true}) - sc.Execute(context.Background(), "query1", nil, rss0, session, false, nil, false) - sc.Execute(context.Background(), "query1", nil, rss01, session, false, nil, false) + sc.Execute(ctx, "query1", nil, rss0, session, false, nil, false) + sc.Execute(ctx, "query1", nil, rss01, session, false, nil, false) session.TransactionMode = vtgatepb.TransactionMode_TWOPC - if err := sc.txConn.Commit(context.Background(), session); err != nil { - t.Error(err) - } - if c := sbc0.CreateTransactionCount.Get(); c != 1 { - t.Errorf("sbc0.CreateTransactionCount: %d, want 1", c) - } - if c := sbc1.PrepareCount.Get(); c != 1 { - t.Errorf("sbc1.PrepareCount: %d, want 1", c) - } - if c := sbc0.StartCommitCount.Get(); c != 1 { - t.Errorf("sbc0.StartCommitCount: %d, want 1", c) - } - if c := sbc1.CommitPreparedCount.Get(); c != 1 { - t.Errorf("sbc1.CommitPreparedCount: %d, want 1", c) - } - if c := sbc0.ConcludeTransactionCount.Get(); c != 1 { - t.Errorf("sbc0.ConcludeTransactionCount: %d, want 1", c) - } + require.NoError(t, + sc.txConn.Commit(ctx, session)) + assert.EqualValues(t, 1, sbc0.CreateTransactionCount.Get(), "sbc0.CreateTransactionCount") + assert.EqualValues(t, 1, sbc1.PrepareCount.Get(), "sbc1.PrepareCount") + assert.EqualValues(t, 1, sbc0.StartCommitCount.Get(), "sbc0.StartCommitCount") + assert.EqualValues(t, 1, sbc1.CommitPreparedCount.Get(), "sbc1.CommitPreparedCount") + assert.EqualValues(t, 1, sbc0.ConcludeTransactionCount.Get(), "sbc0.ConcludeTransactionCount") } func TestTxConnCommit2PCOneParticipant(t *testing.T) { sc, sbc0, _, rss0, _, _ := newTestTxConnEnv(t, "TestTxConnCommit2PCOneParticipant") session := NewSafeSession(&vtgatepb.Session{InTransaction: true}) - sc.Execute(context.Background(), "query1", nil, rss0, session, false, nil, false) + sc.Execute(ctx, "query1", nil, rss0, session, false, nil, false) session.TransactionMode = vtgatepb.TransactionMode_TWOPC - if err := sc.txConn.Commit(context.Background(), session); err != nil { - t.Error(err) - } - if c := sbc0.CommitCount.Get(); c != 1 { - t.Errorf("sbc0.CommitCount: %d, want 1", c) - } + require.NoError(t, + sc.txConn.Commit(ctx, session)) + assert.EqualValues(t, 1, sbc0.CommitCount.Get(), "sbc0.CommitCount") } func TestTxConnCommit2PCCreateTransactionFail(t *testing.T) { sc, sbc0, sbc1, rss0, rss1, _ := newTestTxConnEnv(t, "TestTxConnCommit2PCCreateTransactionFail") session := NewSafeSession(&vtgatepb.Session{InTransaction: true}) - sc.Execute(context.Background(), "query1", nil, rss0, session, false, nil, false) - sc.Execute(context.Background(), "query1", nil, rss1, session, false, nil, false) + sc.Execute(ctx, "query1", nil, rss0, session, false, nil, false) + sc.Execute(ctx, "query1", nil, rss1, session, false, nil, false) sbc0.MustFailCreateTransaction = 1 session.TransactionMode = vtgatepb.TransactionMode_TWOPC - err := sc.txConn.Commit(context.Background(), session) + err := sc.txConn.Commit(ctx, session) want := "error: err" - if err == nil || !strings.Contains(err.Error(), want) { - t.Errorf("Commit: %v, must contain %s", err, want) - } - if c := sbc0.CreateTransactionCount.Get(); c != 1 { - t.Errorf("sbc0.CreateTransactionCount: %d, want 1", c) - } - if c := sbc0.RollbackCount.Get(); c != 1 { - t.Errorf("sbc0.RollbackCount: %d, want 1", c) - } - if c := sbc1.RollbackCount.Get(); c != 1 { - t.Errorf("sbc1.RollbackCount: %d, want 1", c) - } - if c := sbc1.PrepareCount.Get(); c != 0 { - t.Errorf("sbc1.PrepareCount: %d, want 0", c) - } - if c := sbc0.StartCommitCount.Get(); c != 0 { - t.Errorf("sbc0.StartCommitCount: %d, want 0", c) - } - if c := sbc1.CommitPreparedCount.Get(); c != 0 { - t.Errorf("sbc1.CommitPreparedCount: %d, want 0", c) - } - if c := sbc0.ConcludeTransactionCount.Get(); c != 0 { - t.Errorf("sbc0.ConcludeTransactionCount: %d, want 0", c) - } + require.Error(t, err) + assert.Contains(t, err.Error(), want, "Commit") + assert.EqualValues(t, 1, sbc0.CreateTransactionCount.Get(), "sbc0.CreateTransactionCount") + assert.EqualValues(t, 1, sbc0.RollbackCount.Get(), "sbc0.RollbackCount") + assert.EqualValues(t, 1, sbc1.RollbackCount.Get(), "sbc1.RollbackCount") + assert.EqualValues(t, 0, sbc1.PrepareCount.Get(), "sbc1.PrepareCount") + assert.EqualValues(t, 0, sbc0.StartCommitCount.Get(), "sbc0.StartCommitCount") + assert.EqualValues(t, 0, sbc1.CommitPreparedCount.Get(), "sbc1.CommitPreparedCount") + assert.EqualValues(t, 0, sbc0.ConcludeTransactionCount.Get(), "sbc0.ConcludeTransactionCount") } func TestTxConnCommit2PCPrepareFail(t *testing.T) { sc, sbc0, sbc1, rss0, _, rss01 := newTestTxConnEnv(t, "TestTxConnCommit2PCPrepareFail") session := NewSafeSession(&vtgatepb.Session{InTransaction: true}) - sc.Execute(context.Background(), "query1", nil, rss0, session, false, nil, false) - sc.Execute(context.Background(), "query1", nil, rss01, session, false, nil, false) + sc.Execute(ctx, "query1", nil, rss0, session, false, nil, false) + sc.Execute(ctx, "query1", nil, rss01, session, false, nil, false) sbc1.MustFailPrepare = 1 session.TransactionMode = vtgatepb.TransactionMode_TWOPC - err := sc.txConn.Commit(context.Background(), session) + err := sc.txConn.Commit(ctx, session) want := "error: err" - if err == nil || !strings.Contains(err.Error(), want) { - t.Errorf("Commit: %v, must contain %s", err, want) - } - if c := sbc0.CreateTransactionCount.Get(); c != 1 { - t.Errorf("sbc0.CreateTransactionCount: %d, want 1", c) - } - if c := sbc1.PrepareCount.Get(); c != 1 { - t.Errorf("sbc1.PrepareCount: %d, want 1", c) - } - if c := sbc0.StartCommitCount.Get(); c != 0 { - t.Errorf("sbc0.StartCommitCount: %d, want 0", c) - } - if c := sbc1.CommitPreparedCount.Get(); c != 0 { - t.Errorf("sbc1.CommitPreparedCount: %d, want 0", c) - } - if c := sbc0.ConcludeTransactionCount.Get(); c != 0 { - t.Errorf("sbc0.ConcludeTransactionCount: %d, want 0", c) - } + require.Error(t, err) + assert.Contains(t, err.Error(), want, "Commit") + assert.EqualValues(t, 1, sbc0.CreateTransactionCount.Get(), "sbc0.CreateTransactionCount") + assert.EqualValues(t, 1, sbc1.PrepareCount.Get(), "sbc1.PrepareCount") + assert.EqualValues(t, 0, sbc0.StartCommitCount.Get(), "sbc0.StartCommitCount") + assert.EqualValues(t, 0, sbc1.CommitPreparedCount.Get(), "sbc1.CommitPreparedCount") + assert.EqualValues(t, 0, sbc0.ConcludeTransactionCount.Get(), "sbc0.ConcludeTransactionCount") } func TestTxConnCommit2PCStartCommitFail(t *testing.T) { sc, sbc0, sbc1, rss0, _, rss01 := newTestTxConnEnv(t, "TestTxConnCommit2PCStartCommitFail") session := NewSafeSession(&vtgatepb.Session{InTransaction: true}) - sc.Execute(context.Background(), "query1", nil, rss0, session, false, nil, false) - sc.Execute(context.Background(), "query1", nil, rss01, session, false, nil, false) + sc.Execute(ctx, "query1", nil, rss0, session, false, nil, false) + sc.Execute(ctx, "query1", nil, rss01, session, false, nil, false) sbc0.MustFailStartCommit = 1 session.TransactionMode = vtgatepb.TransactionMode_TWOPC - err := sc.txConn.Commit(context.Background(), session) + err := sc.txConn.Commit(ctx, session) want := "error: err" - if err == nil || !strings.Contains(err.Error(), want) { - t.Errorf("Commit: %v, must contain %s", err, want) - } - if c := sbc0.CreateTransactionCount.Get(); c != 1 { - t.Errorf("sbc0.CreateTransactionCount: %d, want 1", c) - } - if c := sbc1.PrepareCount.Get(); c != 1 { - t.Errorf("sbc1.PrepareCount: %d, want 1", c) - } - if c := sbc0.StartCommitCount.Get(); c != 1 { - t.Errorf("sbc0.StartCommitCount: %d, want 1", c) - } - if c := sbc1.CommitPreparedCount.Get(); c != 0 { - t.Errorf("sbc1.CommitPreparedCount: %d, want 0", c) - } - if c := sbc0.ConcludeTransactionCount.Get(); c != 0 { - t.Errorf("sbc0.ConcludeTransactionCount: %d, want 0", c) - } + require.Error(t, err) + assert.Contains(t, err.Error(), want, "Commit") + assert.EqualValues(t, 1, sbc0.CreateTransactionCount.Get(), "sbc0.CreateTransactionCount") + assert.EqualValues(t, 1, sbc1.PrepareCount.Get(), "sbc1.PrepareCount") + assert.EqualValues(t, 1, sbc0.StartCommitCount.Get(), "sbc0.StartCommitCount") + assert.EqualValues(t, 0, sbc1.CommitPreparedCount.Get(), "sbc1.CommitPreparedCount") + assert.EqualValues(t, 0, sbc0.ConcludeTransactionCount.Get(), "sbc0.ConcludeTransactionCount") } func TestTxConnCommit2PCCommitPreparedFail(t *testing.T) { sc, sbc0, sbc1, rss0, _, rss01 := newTestTxConnEnv(t, "TestTxConnCommit2PCCommitPreparedFail") session := NewSafeSession(&vtgatepb.Session{InTransaction: true}) - sc.Execute(context.Background(), "query1", nil, rss0, session, false, nil, false) - sc.Execute(context.Background(), "query1", nil, rss01, session, false, nil, false) + sc.Execute(ctx, "query1", nil, rss0, session, false, nil, false) + sc.Execute(ctx, "query1", nil, rss01, session, false, nil, false) sbc1.MustFailCommitPrepared = 1 session.TransactionMode = vtgatepb.TransactionMode_TWOPC - err := sc.txConn.Commit(context.Background(), session) + err := sc.txConn.Commit(ctx, session) want := "error: err" - if err == nil || !strings.Contains(err.Error(), want) { - t.Errorf("Commit: %v, must contain %s", err, want) - } - if c := sbc0.CreateTransactionCount.Get(); c != 1 { - t.Errorf("sbc0.CreateTransactionCount: %d, want 1", c) - } - if c := sbc1.PrepareCount.Get(); c != 1 { - t.Errorf("sbc1.PrepareCount: %d, want 1", c) - } - if c := sbc0.StartCommitCount.Get(); c != 1 { - t.Errorf("sbc0.StartCommitCount: %d, want 1", c) - } - if c := sbc1.CommitPreparedCount.Get(); c != 1 { - t.Errorf("sbc1.CommitPreparedCount: %d, want 1", c) - } - if c := sbc0.ConcludeTransactionCount.Get(); c != 0 { - t.Errorf("sbc0.ConcludeTransactionCount: %d, want 0", c) - } + require.Error(t, err) + assert.Contains(t, err.Error(), want, "Commit") + assert.EqualValues(t, 1, sbc0.CreateTransactionCount.Get(), "sbc0.CreateTransactionCount") + assert.EqualValues(t, 1, sbc1.PrepareCount.Get(), "sbc1.PrepareCount") + assert.EqualValues(t, 1, sbc0.StartCommitCount.Get(), "sbc0.StartCommitCount") + assert.EqualValues(t, 1, sbc1.CommitPreparedCount.Get(), "sbc1.CommitPreparedCount") + assert.EqualValues(t, 0, sbc0.ConcludeTransactionCount.Get(), "sbc0.ConcludeTransactionCount") } func TestTxConnCommit2PCConcludeTransactionFail(t *testing.T) { sc, sbc0, sbc1, rss0, _, rss01 := newTestTxConnEnv(t, "TestTxConnCommit2PCConcludeTransactionFail") session := NewSafeSession(&vtgatepb.Session{InTransaction: true}) - sc.Execute(context.Background(), "query1", nil, rss0, session, false, nil, false) - sc.Execute(context.Background(), "query1", nil, rss01, session, false, nil, false) + sc.Execute(ctx, "query1", nil, rss0, session, false, nil, false) + sc.Execute(ctx, "query1", nil, rss01, session, false, nil, false) sbc0.MustFailConcludeTransaction = 1 session.TransactionMode = vtgatepb.TransactionMode_TWOPC - err := sc.txConn.Commit(context.Background(), session) + err := sc.txConn.Commit(ctx, session) want := "error: err" - if err == nil || !strings.Contains(err.Error(), want) { - t.Errorf("Commit: %v, must contain %s", err, want) - } - if c := sbc0.CreateTransactionCount.Get(); c != 1 { - t.Errorf("sbc0.CreateTransactionCount: %d, want 1", c) - } - if c := sbc1.PrepareCount.Get(); c != 1 { - t.Errorf("sbc1.PrepareCount: %d, want 1", c) - } - if c := sbc0.StartCommitCount.Get(); c != 1 { - t.Errorf("sbc0.StartCommitCount: %d, want 1", c) - } - if c := sbc1.CommitPreparedCount.Get(); c != 1 { - t.Errorf("sbc1.CommitPreparedCount: %d, want 1", c) - } - if c := sbc0.ConcludeTransactionCount.Get(); c != 1 { - t.Errorf("sbc0.ConcludeTransactionCount: %d, want 1", c) - } + require.Error(t, err) + assert.Contains(t, err.Error(), want, "Commit") + assert.EqualValues(t, 1, sbc0.CreateTransactionCount.Get(), "sbc0.CreateTransactionCount") + assert.EqualValues(t, 1, sbc1.PrepareCount.Get(), "sbc1.PrepareCount") + assert.EqualValues(t, 1, sbc0.StartCommitCount.Get(), "sbc0.StartCommitCount") + assert.EqualValues(t, 1, sbc1.CommitPreparedCount.Get(), "sbc1.CommitPreparedCount") + assert.EqualValues(t, 1, sbc0.ConcludeTransactionCount.Get(), "sbc0.ConcludeTransactionCount") } func TestTxConnRollback(t *testing.T) { sc, sbc0, sbc1, rss0, _, rss01 := newTestTxConnEnv(t, "TxConnRollback") session := NewSafeSession(&vtgatepb.Session{InTransaction: true}) - sc.Execute(context.Background(), "query1", nil, rss0, session, false, nil, false) - sc.Execute(context.Background(), "query1", nil, rss01, session, false, nil, false) - if err := sc.txConn.Rollback(context.Background(), session); err != nil { - t.Error(err) - } + sc.Execute(ctx, "query1", nil, rss0, session, false, nil, false) + sc.Execute(ctx, "query1", nil, rss01, session, false, nil, false) + require.NoError(t, + sc.txConn.Rollback(ctx, session)) wantSession := vtgatepb.Session{} - if !proto.Equal(session.Session, &wantSession) { - t.Errorf("Session:\n%+v, want\n%+v", *session.Session, wantSession) - } - if c := sbc0.RollbackCount.Get(); c != 1 { - t.Errorf("sbc0.RollbackCount: %d, want 1", c) - } - if c := sbc1.RollbackCount.Get(); c != 1 { - t.Errorf("sbc1.RollbackCount: %d, want 1", c) - } + utils.MustMatch(t, &wantSession, session.Session, "Session") + assert.EqualValues(t, 1, sbc0.RollbackCount.Get(), "sbc0.RollbackCount") + assert.EqualValues(t, 1, sbc1.RollbackCount.Get(), "sbc1.RollbackCount") } func TestTxConnResolveOnPrepare(t *testing.T) { @@ -583,20 +454,12 @@ func TestTxConnResolveOnPrepare(t *testing.T) { TabletType: topodatapb.TabletType_MASTER, }}, }} - err := sc.txConn.Resolve(context.Background(), dtid) + err := sc.txConn.Resolve(ctx, dtid) require.NoError(t, err) - if c := sbc0.SetRollbackCount.Get(); c != 1 { - t.Errorf("sbc0.SetRollbackCount: %d, want 1", c) - } - if c := sbc1.RollbackPreparedCount.Get(); c != 1 { - t.Errorf("sbc1.RollbackPreparedCount: %d, want 1", c) - } - if c := sbc1.CommitPreparedCount.Get(); c != 0 { - t.Errorf("sbc1.CommitPreparedCount: %d, want 0", c) - } - if c := sbc0.ConcludeTransactionCount.Get(); c != 1 { - t.Errorf("sbc0.ConcludeTransactionCount: %d, want 1", c) - } + assert.EqualValues(t, 1, sbc0.SetRollbackCount.Get(), "sbc0.SetRollbackCount") + assert.EqualValues(t, 1, sbc1.RollbackPreparedCount.Get(), "sbc1.RollbackPreparedCount") + assert.EqualValues(t, 0, sbc1.CommitPreparedCount.Get(), "sbc1.CommitPreparedCount") + assert.EqualValues(t, 1, sbc0.ConcludeTransactionCount.Get(), "sbc0.ConcludeTransactionCount") } func TestTxConnResolveOnRollback(t *testing.T) { @@ -612,21 +475,12 @@ func TestTxConnResolveOnRollback(t *testing.T) { TabletType: topodatapb.TabletType_MASTER, }}, }} - if err := sc.txConn.Resolve(context.Background(), dtid); err != nil { - t.Error(err) - } - if c := sbc0.SetRollbackCount.Get(); c != 0 { - t.Errorf("sbc0.SetRollbackCount: %d, want 0", c) - } - if c := sbc1.RollbackPreparedCount.Get(); c != 1 { - t.Errorf("sbc1.RollbackPreparedCount: %d, want 1", c) - } - if c := sbc1.CommitPreparedCount.Get(); c != 0 { - t.Errorf("sbc1.CommitPreparedCount: %d, want 0", c) - } - if c := sbc0.ConcludeTransactionCount.Get(); c != 1 { - t.Errorf("sbc0.ConcludeTransactionCount: %d, want 1", c) - } + require.NoError(t, + sc.txConn.Resolve(ctx, dtid)) + assert.EqualValues(t, 0, sbc0.SetRollbackCount.Get(), "sbc0.SetRollbackCount") + assert.EqualValues(t, 1, sbc1.RollbackPreparedCount.Get(), "sbc1.RollbackPreparedCount") + assert.EqualValues(t, 0, sbc1.CommitPreparedCount.Get(), "sbc1.CommitPreparedCount") + assert.EqualValues(t, 1, sbc0.ConcludeTransactionCount.Get(), "sbc0.ConcludeTransactionCount") } func TestTxConnResolveOnCommit(t *testing.T) { @@ -642,31 +496,20 @@ func TestTxConnResolveOnCommit(t *testing.T) { TabletType: topodatapb.TabletType_MASTER, }}, }} - if err := sc.txConn.Resolve(context.Background(), dtid); err != nil { - t.Error(err) - } - if c := sbc0.SetRollbackCount.Get(); c != 0 { - t.Errorf("sbc0.SetRollbackCount: %d, want 0", c) - } - if c := sbc1.RollbackPreparedCount.Get(); c != 0 { - t.Errorf("sbc1.RollbackPreparedCount: %d, want 0", c) - } - if c := sbc1.CommitPreparedCount.Get(); c != 1 { - t.Errorf("sbc1.CommitPreparedCount: %d, want 1", c) - } - if c := sbc0.ConcludeTransactionCount.Get(); c != 1 { - t.Errorf("sbc0.ConcludeTransactionCount: %d, want 1", c) - } + require.NoError(t, + sc.txConn.Resolve(ctx, dtid)) + assert.EqualValues(t, 0, sbc0.SetRollbackCount.Get(), "sbc0.SetRollbackCount") + assert.EqualValues(t, 0, sbc1.RollbackPreparedCount.Get(), "sbc1.RollbackPreparedCount") + assert.EqualValues(t, 1, sbc1.CommitPreparedCount.Get(), "sbc1.CommitPreparedCount") + assert.EqualValues(t, 1, sbc0.ConcludeTransactionCount.Get(), "sbc0.ConcludeTransactionCount") } func TestTxConnResolveInvalidDTID(t *testing.T) { sc, _, _, _, _, _ := newTestTxConnEnv(t, "TestTxConn") - err := sc.txConn.Resolve(context.Background(), "abcd") + err := sc.txConn.Resolve(ctx, "abcd") want := "invalid parts in dtid: abcd" - if err == nil || err.Error() != want { - t.Errorf("Resolve: %v, want %s", err, want) - } + require.EqualError(t, err, want, "Resolve") } func TestTxConnResolveReadTransactionFail(t *testing.T) { @@ -674,11 +517,10 @@ func TestTxConnResolveReadTransactionFail(t *testing.T) { dtid := "TestTxConn:0:1234" sbc0.MustFailCodes[vtrpcpb.Code_INVALID_ARGUMENT] = 1 - err := sc.txConn.Resolve(context.Background(), dtid) + err := sc.txConn.Resolve(ctx, dtid) want := "INVALID_ARGUMENT error" - if err == nil || !strings.Contains(err.Error(), want) { - t.Errorf("Resolve: %v, want %s", err, want) - } + require.Error(t, err) + assert.Contains(t, err.Error(), want, "Resolve") } func TestTxConnResolveInternalError(t *testing.T) { @@ -694,11 +536,10 @@ func TestTxConnResolveInternalError(t *testing.T) { TabletType: topodatapb.TabletType_MASTER, }}, }} - err := sc.txConn.Resolve(context.Background(), dtid) + err := sc.txConn.Resolve(ctx, dtid) want := "invalid state: UNKNOWN" - if err == nil || !strings.Contains(err.Error(), want) { - t.Errorf("Resolve: %v, want %s", err, want) - } + require.Error(t, err) + assert.Contains(t, err.Error(), want, "Resolve") } func TestTxConnResolveSetRollbackFail(t *testing.T) { @@ -715,23 +556,14 @@ func TestTxConnResolveSetRollbackFail(t *testing.T) { }}, }} sbc0.MustFailSetRollback = 1 - err := sc.txConn.Resolve(context.Background(), dtid) + err := sc.txConn.Resolve(ctx, dtid) want := "error: err" - if err == nil || !strings.Contains(err.Error(), want) { - t.Errorf("Resolve: %v, want %s", err, want) - } - if c := sbc0.SetRollbackCount.Get(); c != 1 { - t.Errorf("sbc0.SetRollbackCount: %d, want 1", c) - } - if c := sbc1.RollbackPreparedCount.Get(); c != 0 { - t.Errorf("sbc1.RollbackPreparedCount: %d, want 0", c) - } - if c := sbc1.CommitPreparedCount.Get(); c != 0 { - t.Errorf("sbc1.CommitPreparedCount: %d, want 0", c) - } - if c := sbc0.ConcludeTransactionCount.Get(); c != 0 { - t.Errorf("sbc0.ConcludeTransactionCount: %d, want 0", c) - } + require.Error(t, err) + assert.Contains(t, err.Error(), want, "Resolve") + assert.EqualValues(t, 1, sbc0.SetRollbackCount.Get(), "sbc0.SetRollbackCount") + assert.EqualValues(t, 0, sbc1.RollbackPreparedCount.Get(), "sbc1.RollbackPreparedCount") + assert.EqualValues(t, 0, sbc1.CommitPreparedCount.Get(), "sbc1.CommitPreparedCount") + assert.EqualValues(t, 0, sbc0.ConcludeTransactionCount.Get(), "sbc0.ConcludeTransactionCount") } func TestTxConnResolveRollbackPreparedFail(t *testing.T) { @@ -748,23 +580,14 @@ func TestTxConnResolveRollbackPreparedFail(t *testing.T) { }}, }} sbc1.MustFailRollbackPrepared = 1 - err := sc.txConn.Resolve(context.Background(), dtid) + err := sc.txConn.Resolve(ctx, dtid) want := "error: err" - if err == nil || !strings.Contains(err.Error(), want) { - t.Errorf("Resolve: %v, want %s", err, want) - } - if c := sbc0.SetRollbackCount.Get(); c != 0 { - t.Errorf("sbc0.SetRollbackCount: %d, want 0", c) - } - if c := sbc1.RollbackPreparedCount.Get(); c != 1 { - t.Errorf("sbc1.RollbackPreparedCount: %d, want 1", c) - } - if c := sbc1.CommitPreparedCount.Get(); c != 0 { - t.Errorf("sbc1.CommitPreparedCount: %d, want 0", c) - } - if c := sbc0.ConcludeTransactionCount.Get(); c != 0 { - t.Errorf("sbc0.ConcludeTransactionCount: %d, want 0", c) - } + require.Error(t, err) + assert.Contains(t, err.Error(), want, "Resolve") + assert.EqualValues(t, 0, sbc0.SetRollbackCount.Get(), "sbc0.SetRollbackCount") + assert.EqualValues(t, 1, sbc1.RollbackPreparedCount.Get(), "sbc1.RollbackPreparedCount") + assert.EqualValues(t, 0, sbc1.CommitPreparedCount.Get(), "sbc1.CommitPreparedCount") + assert.EqualValues(t, 0, sbc0.ConcludeTransactionCount.Get(), "sbc0.ConcludeTransactionCount") } func TestTxConnResolveCommitPreparedFail(t *testing.T) { @@ -781,23 +604,14 @@ func TestTxConnResolveCommitPreparedFail(t *testing.T) { }}, }} sbc1.MustFailCommitPrepared = 1 - err := sc.txConn.Resolve(context.Background(), dtid) + err := sc.txConn.Resolve(ctx, dtid) want := "error: err" - if err == nil || !strings.Contains(err.Error(), want) { - t.Errorf("Resolve: %v, want %s", err, want) - } - if c := sbc0.SetRollbackCount.Get(); c != 0 { - t.Errorf("sbc0.SetRollbackCount: %d, want 0", c) - } - if c := sbc1.RollbackPreparedCount.Get(); c != 0 { - t.Errorf("sbc1.RollbackPreparedCount: %d, want 0", c) - } - if c := sbc1.CommitPreparedCount.Get(); c != 1 { - t.Errorf("sbc1.CommitPreparedCount: %d, want 1", c) - } - if c := sbc0.ConcludeTransactionCount.Get(); c != 0 { - t.Errorf("sbc0.ConcludeTransactionCount: %d, want 0", c) - } + require.Error(t, err) + assert.Contains(t, err.Error(), want, "Resolve") + assert.EqualValues(t, 0, sbc0.SetRollbackCount.Get(), "sbc0.SetRollbackCount") + assert.EqualValues(t, 0, sbc1.RollbackPreparedCount.Get(), "sbc1.RollbackPreparedCount") + assert.EqualValues(t, 1, sbc1.CommitPreparedCount.Get(), "sbc1.CommitPreparedCount") + assert.EqualValues(t, 0, sbc0.ConcludeTransactionCount.Get(), "sbc0.ConcludeTransactionCount") } func TestTxConnResolveConcludeTransactionFail(t *testing.T) { @@ -814,23 +628,14 @@ func TestTxConnResolveConcludeTransactionFail(t *testing.T) { }}, }} sbc0.MustFailConcludeTransaction = 1 - err := sc.txConn.Resolve(context.Background(), dtid) + err := sc.txConn.Resolve(ctx, dtid) want := "error: err" - if err == nil || !strings.Contains(err.Error(), want) { - t.Errorf("Resolve: %v, want %s", err, want) - } - if c := sbc0.SetRollbackCount.Get(); c != 0 { - t.Errorf("sbc0.SetRollbackCount: %d, want 0", c) - } - if c := sbc1.RollbackPreparedCount.Get(); c != 0 { - t.Errorf("sbc1.RollbackPreparedCount: %d, want 0", c) - } - if c := sbc1.CommitPreparedCount.Get(); c != 1 { - t.Errorf("sbc1.CommitPreparedCount: %d, want 1", c) - } - if c := sbc0.ConcludeTransactionCount.Get(); c != 1 { - t.Errorf("sbc0.ConcludeTransactionCount: %d, want 1", c) - } + require.Error(t, err) + assert.Contains(t, err.Error(), want, "Resolve") + assert.EqualValues(t, 0, sbc0.SetRollbackCount.Get(), "sbc0.SetRollbackCount") + assert.EqualValues(t, 0, sbc1.RollbackPreparedCount.Get(), "sbc1.RollbackPreparedCount") + assert.EqualValues(t, 1, sbc1.CommitPreparedCount.Get(), "sbc1.CommitPreparedCount") + assert.EqualValues(t, 1, sbc0.ConcludeTransactionCount.Get(), "sbc0.ConcludeTransactionCount") } func TestTxConnMultiGoSessions(t *testing.T) { @@ -841,13 +646,11 @@ func TestTxConnMultiGoSessions(t *testing.T) { Keyspace: "0", }, }} - err := txc.runSessions(input, func(s *vtgatepb.Session_ShardSession) error { + err := txc.runSessions(ctx, input, func(ctx context.Context, s *vtgatepb.Session_ShardSession) error { return vterrors.Errorf(vtrpcpb.Code_INTERNAL, "err %s", s.Target.Keyspace) }) want := "err 0" - if err == nil || err.Error() != want { - t.Errorf("runSessions(1): %v, want %s", err, want) - } + require.EqualError(t, err, want, "runSessions(1)") input = []*vtgatepb.Session_ShardSession{{ Target: &querypb.Target{ @@ -858,19 +661,15 @@ func TestTxConnMultiGoSessions(t *testing.T) { Keyspace: "1", }, }} - err = txc.runSessions(input, func(s *vtgatepb.Session_ShardSession) error { + err = txc.runSessions(ctx, input, func(ctx context.Context, s *vtgatepb.Session_ShardSession) error { return vterrors.Errorf(vtrpcpb.Code_INTERNAL, "err %s", s.Target.Keyspace) }) want = "err 0\nerr 1" - if err == nil || err.Error() != want { - t.Errorf("runSessions(2): %v, want %s", err, want) - } + require.EqualError(t, err, want, "runSessions(2)") wantCode := vtrpcpb.Code_INTERNAL - if code := vterrors.Code(err); code != wantCode { - t.Errorf("Error code: %v, want %v", code, wantCode) - } + assert.Equal(t, wantCode, vterrors.Code(err), "error code") - err = txc.runSessions(input, func(s *vtgatepb.Session_ShardSession) error { + err = txc.runSessions(ctx, input, func(ctx context.Context, s *vtgatepb.Session_ShardSession) error { return nil }) require.NoError(t, err) @@ -885,9 +684,7 @@ func TestTxConnMultiGoTargets(t *testing.T) { return vterrors.Errorf(vtrpcpb.Code_INTERNAL, "err %s", t.Keyspace) }) want := "err 0" - if err == nil || err.Error() != want { - t.Errorf("runTargets(1): %v, want %s", err, want) - } + require.EqualError(t, err, want, "runTargets(1)") input = []*querypb.Target{{ Keyspace: "0", @@ -898,13 +695,9 @@ func TestTxConnMultiGoTargets(t *testing.T) { return vterrors.Errorf(vtrpcpb.Code_INTERNAL, "err %s", t.Keyspace) }) want = "err 0\nerr 1" - if err == nil || err.Error() != want { - t.Errorf("runTargets(2): %v, want %s", err, want) - } + require.EqualError(t, err, want, "runTargets(2)") wantCode := vtrpcpb.Code_INTERNAL - if code := vterrors.Code(err); code != wantCode { - t.Errorf("Error code: %v, want %v", code, wantCode) - } + assert.Equal(t, wantCode, vterrors.Code(err), "error code") err = txc.runTargets(input, func(t *querypb.Target) error { return nil @@ -913,24 +706,19 @@ func TestTxConnMultiGoTargets(t *testing.T) { } func newTestTxConnEnv(t *testing.T, name string) (sc *ScatterConn, sbc0, sbc1 *sandboxconn.SandboxConn, rss0, rss1, rss01 []*srvtopo.ResolvedShard) { + t.Helper() createSandbox(name) hc := discovery.NewFakeLegacyHealthCheck() - sc = newTestScatterConn(hc, new(sandboxTopo), "aa") + sc = newTestLegacyScatterConn(hc, new(sandboxTopo), "aa") sbc0 = hc.AddTestTablet("aa", "0", 1, name, "0", topodatapb.TabletType_MASTER, true, 1, nil) sbc1 = hc.AddTestTablet("aa", "1", 1, name, "1", topodatapb.TabletType_MASTER, true, 1, nil) res := srvtopo.NewResolver(&sandboxTopo{}, sc.gateway, "aa") var err error - rss0, err = res.ResolveDestination(context.Background(), name, topodatapb.TabletType_MASTER, key.DestinationShard("0")) - if err != nil { - t.Fatalf("ResolveDestination(0) failed: %v", err) - } - rss1, err = res.ResolveDestination(context.Background(), name, topodatapb.TabletType_MASTER, key.DestinationShard("1")) - if err != nil { - t.Fatalf("ResolveDestination(1) failed: %v", err) - } - rss01, err = res.ResolveDestination(context.Background(), name, topodatapb.TabletType_MASTER, key.DestinationShards([]string{"0", "1"})) - if err != nil { - t.Fatalf("ResolveDestination(0, 1) failed: %v", err) - } + rss0, err = res.ResolveDestination(ctx, name, topodatapb.TabletType_MASTER, key.DestinationShard("0")) + require.NoError(t, err) + rss1, err = res.ResolveDestination(ctx, name, topodatapb.TabletType_MASTER, key.DestinationShard("1")) + require.NoError(t, err) + rss01, err = res.ResolveDestination(ctx, name, topodatapb.TabletType_MASTER, key.DestinationShards([]string{"0", "1"})) + require.NoError(t, err) return sc, sbc0, sbc1, rss0, rss1, rss01 } diff --git a/go/vt/vtgate/vcursor_impl.go b/go/vt/vtgate/vcursor_impl.go index 097c7aed267..3ed08a34bcd 100644 --- a/go/vt/vtgate/vcursor_impl.go +++ b/go/vt/vtgate/vcursor_impl.go @@ -135,9 +135,9 @@ func newVCursorImpl(ctx context.Context, safeSession *SafeSession, marginComment return nil, err } - // Check for transaction to be only application in master. - if safeSession.InTransaction() && tabletType != topodatapb.TabletType_MASTER { - return nil, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "transactions are supported only for master tablet types, current type: %v", tabletType) + // With DiscoveryGateway transactions are only allowed on master. + if UsingLegacyGateway() && safeSession.InTransaction() && tabletType != topodatapb.TabletType_MASTER { + return nil, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "newVCursorImpl: transactions are supported only for master tablet types, current type: %v", tabletType) } return &vcursorImpl{ diff --git a/go/vt/vtgate/vstream_manager.go b/go/vt/vtgate/vstream_manager.go index c85437ce2de..81ee3765e8b 100644 --- a/go/vt/vtgate/vstream_manager.go +++ b/go/vt/vtgate/vstream_manager.go @@ -212,7 +212,7 @@ func (vs *vstream) streamFromTablet(ctx context.Context, sgtid *binlogdatapb.Sha return vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "unexpected number or shards: %v", rss) } // Safe to access sgtid.Gtid here (because it can't change until streaming begins). - err = rss[0].QueryService.VStream(ctx, rss[0].Target, sgtid.Gtid, vs.filter, func(events []*binlogdatapb.VEvent) error { + err = rss[0].Gateway.VStream(ctx, rss[0].Target, sgtid.Gtid, vs.filter, func(events []*binlogdatapb.VEvent) error { // We received a valid event. Reset error count. errCount = 0 diff --git a/go/vt/vtgate/vtgate.go b/go/vt/vtgate/vtgate.go index 0e2e4b9cf8b..cd04de6dbc1 100644 --- a/go/vt/vtgate/vtgate.go +++ b/go/vt/vtgate/vtgate.go @@ -207,7 +207,7 @@ func Init(ctx context.Context, serv srvtopo.Server, cell string, tabletTypesToWa log.Fatalf("error initializing query logger: %v", err) } - initAPI(ctx, gw.hc) + initAPI(gw.hc) return rpcVTGate } @@ -498,7 +498,7 @@ func LegacyInit(ctx context.Context, hc discovery.LegacyHealthCheck, serv srvtop tc := NewTxConn(gw, getTxMode()) // ScatterConn depends on TxConn to perform forced rollbacks. - sc := LegacyNewScatterConn("VttabletCall", tc, gw, hc) + sc := NewLegacyScatterConn("VttabletCall", tc, gw, hc) srvResolver := srvtopo.NewResolver(serv, gw, cell) resolver := NewResolver(srvResolver, serv, cell, sc) vsm := newVStreamManager(srvResolver, serv, cell) @@ -546,7 +546,7 @@ func LegacyInit(ctx context.Context, hc discovery.LegacyHealthCheck, serv srvtop log.Fatalf("error initializing query logger: %v", err) } - legacyInitAPI(ctx, hc) + legacyInitAPI(hc) return rpcVTGate } diff --git a/go/vt/vttablet/endtoend/framework/client.go b/go/vt/vttablet/endtoend/framework/client.go index 279344beea9..a1c3021b6fe 100644 --- a/go/vt/vttablet/endtoend/framework/client.go +++ b/go/vt/vttablet/endtoend/framework/client.go @@ -85,7 +85,7 @@ func (client *QueryClient) Begin(clientFoundRows bool) error { if clientFoundRows { options = &querypb.ExecuteOptions{ClientFoundRows: clientFoundRows} } - transactionID, err := client.server.Begin(client.ctx, &client.target, options) + transactionID, _, err := client.server.Begin(client.ctx, &client.target, options) if err != nil { return err } @@ -164,7 +164,7 @@ func (client *QueryClient) BeginExecute(query string, bindvars map[string]*query if client.transactionID != 0 { return nil, errors.New("already in transaction") } - qr, transactionID, err := client.server.BeginExecute( + qr, transactionID, _, err := client.server.BeginExecute( client.ctx, &client.target, query, diff --git a/go/vt/vttablet/grpcqueryservice/server.go b/go/vt/vttablet/grpcqueryservice/server.go index d48037f26a9..e7979e14972 100644 --- a/go/vt/vttablet/grpcqueryservice/server.go +++ b/go/vt/vttablet/grpcqueryservice/server.go @@ -91,13 +91,14 @@ func (q *query) Begin(ctx context.Context, request *querypb.BeginRequest) (respo request.EffectiveCallerId, request.ImmediateCallerId, ) - transactionID, err := q.server.Begin(ctx, request.Target, request.Options) + transactionID, alias, err := q.server.Begin(ctx, request.Target, request.Options) if err != nil { return nil, vterrors.ToGRPC(err) } return &querypb.BeginResponse{ TransactionId: transactionID, + TabletAlias: alias, }, nil } @@ -248,14 +249,14 @@ func (q *query) BeginExecute(ctx context.Context, request *querypb.BeginExecuteR request.EffectiveCallerId, request.ImmediateCallerId, ) - - result, transactionID, err := q.server.BeginExecute(ctx, request.Target, request.Query.Sql, request.Query.BindVariables, request.Options) + result, transactionID, alias, err := q.server.BeginExecute(ctx, request.Target, request.Query.Sql, request.Query.BindVariables, request.Options) if err != nil { // if we have a valid transactionID, return the error in-band if transactionID != 0 { return &querypb.BeginExecuteResponse{ Error: vterrors.ToVTRPC(err), TransactionId: transactionID, + TabletAlias: alias, }, nil } return nil, vterrors.ToGRPC(err) @@ -263,6 +264,7 @@ func (q *query) BeginExecute(ctx context.Context, request *querypb.BeginExecuteR return &querypb.BeginExecuteResponse{ Result: sqltypes.ResultToProto3(result), TransactionId: transactionID, + TabletAlias: alias, }, nil } @@ -273,14 +275,14 @@ func (q *query) BeginExecuteBatch(ctx context.Context, request *querypb.BeginExe request.EffectiveCallerId, request.ImmediateCallerId, ) - - results, transactionID, err := q.server.BeginExecuteBatch(ctx, request.Target, request.Queries, request.AsTransaction, request.Options) + results, transactionID, alias, err := q.server.BeginExecuteBatch(ctx, request.Target, request.Queries, request.AsTransaction, request.Options) if err != nil { // if we have a valid transactionID, return the error in-band if transactionID != 0 { return &querypb.BeginExecuteBatchResponse{ Error: vterrors.ToVTRPC(err), TransactionId: transactionID, + TabletAlias: alias, }, nil } return nil, vterrors.ToGRPC(err) @@ -288,6 +290,7 @@ func (q *query) BeginExecuteBatch(ctx context.Context, request *querypb.BeginExe return &querypb.BeginExecuteBatchResponse{ Results: sqltypes.ResultsToProto3(results), TransactionId: transactionID, + TabletAlias: alias, }, nil } diff --git a/go/vt/vttablet/grpctabletconn/conn.go b/go/vt/vttablet/grpctabletconn/conn.go index 478b0c0ff5f..3c3a62cb32b 100644 --- a/go/vt/vttablet/grpctabletconn/conn.go +++ b/go/vt/vttablet/grpctabletconn/conn.go @@ -197,11 +197,11 @@ func (conn *gRPCQueryClient) StreamExecute(ctx context.Context, target *querypb. } // Begin starts a transaction. -func (conn *gRPCQueryClient) Begin(ctx context.Context, target *querypb.Target, options *querypb.ExecuteOptions) (transactionID int64, err error) { +func (conn *gRPCQueryClient) Begin(ctx context.Context, target *querypb.Target, options *querypb.ExecuteOptions) (transactionID int64, alias *topodatapb.TabletAlias, err error) { conn.mu.RLock() defer conn.mu.RUnlock() if conn.cc == nil { - return 0, tabletconn.ConnClosed + return 0, nil, tabletconn.ConnClosed } req := &querypb.BeginRequest{ @@ -212,9 +212,13 @@ func (conn *gRPCQueryClient) Begin(ctx context.Context, target *querypb.Target, } br, err := conn.c.Begin(ctx, req) if err != nil { - return 0, tabletconn.ErrorFromGRPC(err) + return 0, nil, tabletconn.ErrorFromGRPC(err) } - return br.TransactionId, nil + // For backwards compatibility, we don't require tablet alias to be present in the response + // TODO(deepthi): After 7.0 change this + // return br.TransactionId, br.TabletAlias, nil + // also assert that br.TabletAlias == conn.tablet.Alias + return br.TransactionId, conn.tablet.Alias, nil } // Commit commits the ongoing transaction. @@ -436,11 +440,11 @@ func (conn *gRPCQueryClient) ReadTransaction(ctx context.Context, target *queryp } // BeginExecute starts a transaction and runs an Execute. -func (conn *gRPCQueryClient) BeginExecute(ctx context.Context, target *querypb.Target, query string, bindVars map[string]*querypb.BindVariable, options *querypb.ExecuteOptions) (result *sqltypes.Result, transactionID int64, err error) { +func (conn *gRPCQueryClient) BeginExecute(ctx context.Context, target *querypb.Target, query string, bindVars map[string]*querypb.BindVariable, options *querypb.ExecuteOptions) (result *sqltypes.Result, transactionID int64, alias *topodatapb.TabletAlias, err error) { conn.mu.RLock() defer conn.mu.RUnlock() if conn.cc == nil { - return nil, 0, tabletconn.ConnClosed + return nil, 0, nil, tabletconn.ConnClosed } req := &querypb.BeginExecuteRequest{ @@ -455,20 +459,20 @@ func (conn *gRPCQueryClient) BeginExecute(ctx context.Context, target *querypb.T } reply, err := conn.c.BeginExecute(ctx, req) if err != nil { - return nil, 0, tabletconn.ErrorFromGRPC(err) + return nil, 0, nil, tabletconn.ErrorFromGRPC(err) } if reply.Error != nil { - return nil, reply.TransactionId, tabletconn.ErrorFromVTRPC(reply.Error) + return nil, reply.TransactionId, conn.tablet.Alias, tabletconn.ErrorFromVTRPC(reply.Error) } - return sqltypes.Proto3ToResult(reply.Result), reply.TransactionId, nil + return sqltypes.Proto3ToResult(reply.Result), reply.TransactionId, conn.tablet.Alias, nil } // BeginExecuteBatch starts a transaction and runs an ExecuteBatch. -func (conn *gRPCQueryClient) BeginExecuteBatch(ctx context.Context, target *querypb.Target, queries []*querypb.BoundQuery, asTransaction bool, options *querypb.ExecuteOptions) (results []sqltypes.Result, transactionID int64, err error) { +func (conn *gRPCQueryClient) BeginExecuteBatch(ctx context.Context, target *querypb.Target, queries []*querypb.BoundQuery, asTransaction bool, options *querypb.ExecuteOptions) (results []sqltypes.Result, transactionID int64, alias *topodatapb.TabletAlias, err error) { conn.mu.RLock() defer conn.mu.RUnlock() if conn.cc == nil { - return nil, 0, tabletconn.ConnClosed + return nil, 0, nil, tabletconn.ConnClosed } req := &querypb.BeginExecuteBatchRequest{ @@ -482,12 +486,12 @@ func (conn *gRPCQueryClient) BeginExecuteBatch(ctx context.Context, target *quer reply, err := conn.c.BeginExecuteBatch(ctx, req) if err != nil { - return nil, 0, tabletconn.ErrorFromGRPC(err) + return nil, 0, nil, tabletconn.ErrorFromGRPC(err) } if reply.Error != nil { - return nil, reply.TransactionId, tabletconn.ErrorFromVTRPC(reply.Error) + return nil, reply.TransactionId, conn.tablet.Alias, tabletconn.ErrorFromVTRPC(reply.Error) } - return sqltypes.Proto3ToResults(reply.Results), reply.TransactionId, nil + return sqltypes.Proto3ToResults(reply.Results), reply.TransactionId, conn.tablet.Alias, nil } // MessageStream streams messages. diff --git a/go/vt/vttablet/grpctabletconn/conn_test.go b/go/vt/vttablet/grpctabletconn/conn_test.go index 943cbdd134c..1bacb0884df 100644 --- a/go/vt/vttablet/grpctabletconn/conn_test.go +++ b/go/vt/vttablet/grpctabletconn/conn_test.go @@ -55,6 +55,7 @@ func TestGRPCTabletConn(t *testing.T) { Keyspace: tabletconntest.TestTarget.Keyspace, Shard: tabletconntest.TestTarget.Shard, Type: tabletconntest.TestTarget.TabletType, + Alias: tabletconntest.TestAlias, Hostname: host, PortMap: map[string]int32{ "grpc": int32(port), @@ -106,6 +107,7 @@ func TestGRPCTabletAuthConn(t *testing.T) { Keyspace: tabletconntest.TestTarget.Keyspace, Shard: tabletconntest.TestTarget.Shard, Type: tabletconntest.TestTarget.TabletType, + Alias: tabletconntest.TestAlias, Hostname: host, PortMap: map[string]int32{ "grpc": int32(port), diff --git a/go/vt/vttablet/queryservice/fakes/stream_health_query_service.go b/go/vt/vttablet/queryservice/fakes/stream_health_query_service.go index 09d93232f3c..3c21cf8314b 100644 --- a/go/vt/vttablet/queryservice/fakes/stream_health_query_service.go +++ b/go/vt/vttablet/queryservice/fakes/stream_health_query_service.go @@ -56,8 +56,8 @@ func NewStreamHealthQueryService(target querypb.Target) *StreamHealthQueryServic } // Begin implemented as a no op -func (q *StreamHealthQueryService) Begin(ctx context.Context, target *querypb.Target, options *querypb.ExecuteOptions) (int64, error) { - return 0, nil +func (q *StreamHealthQueryService) Begin(ctx context.Context, target *querypb.Target, options *querypb.ExecuteOptions) (int64, *topodatapb.TabletAlias, error) { + return 0, nil, nil } // Execute implemented as a no op diff --git a/go/vt/vttablet/queryservice/queryservice.go b/go/vt/vttablet/queryservice/queryservice.go index 574d5b2d2db..2f6a9b68ba9 100644 --- a/go/vt/vttablet/queryservice/queryservice.go +++ b/go/vt/vttablet/queryservice/queryservice.go @@ -21,6 +21,8 @@ package queryservice import ( "io" + topodatapb "vitess.io/vitess/go/vt/proto/topodata" + "golang.org/x/net/context" "vitess.io/vitess/go/sqltypes" @@ -41,7 +43,7 @@ type QueryService interface { // Transaction management // Begin returns the transaction id to use for further operations - Begin(ctx context.Context, target *querypb.Target, options *querypb.ExecuteOptions) (int64, error) + Begin(ctx context.Context, target *querypb.Target, options *querypb.ExecuteOptions) (int64, *topodatapb.TabletAlias, error) // Commit commits the current transaction Commit(ctx context.Context, target *querypb.Target, transactionID int64) error @@ -78,15 +80,17 @@ type QueryService interface { // Query execution Execute(ctx context.Context, target *querypb.Target, sql string, bindVariables map[string]*querypb.BindVariable, transactionID int64, options *querypb.ExecuteOptions) (*sqltypes.Result, error) + // Currently always called with transactionID = 0 StreamExecute(ctx context.Context, target *querypb.Target, sql string, bindVariables map[string]*querypb.BindVariable, transactionID int64, options *querypb.ExecuteOptions, callback func(*sqltypes.Result) error) error + // Currently always called with transactionID = 0 ExecuteBatch(ctx context.Context, target *querypb.Target, queries []*querypb.BoundQuery, asTransaction bool, transactionID int64, options *querypb.ExecuteOptions) ([]sqltypes.Result, error) // Combo methods, they also return the transactionID from the // Begin part. If err != nil, the transactionID may still be // non-zero, and needs to be propagated back (like for a DB // Integrity Error) - BeginExecute(ctx context.Context, target *querypb.Target, sql string, bindVariables map[string]*querypb.BindVariable, options *querypb.ExecuteOptions) (*sqltypes.Result, int64, error) - BeginExecuteBatch(ctx context.Context, target *querypb.Target, queries []*querypb.BoundQuery, asTransaction bool, options *querypb.ExecuteOptions) ([]sqltypes.Result, int64, error) + BeginExecute(ctx context.Context, target *querypb.Target, sql string, bindVariables map[string]*querypb.BindVariable, options *querypb.ExecuteOptions) (*sqltypes.Result, int64, *topodatapb.TabletAlias, error) + BeginExecuteBatch(ctx context.Context, target *querypb.Target, queries []*querypb.BoundQuery, asTransaction bool, options *querypb.ExecuteOptions) ([]sqltypes.Result, int64, *topodatapb.TabletAlias, error) // Messaging methods. MessageStream(ctx context.Context, target *querypb.Target, name string, callback func(*sqltypes.Result) error) error diff --git a/go/vt/vttablet/queryservice/wrapped.go b/go/vt/vttablet/queryservice/wrapped.go index 185046dd9df..2ac41122d4d 100644 --- a/go/vt/vttablet/queryservice/wrapped.go +++ b/go/vt/vttablet/queryservice/wrapped.go @@ -18,6 +18,7 @@ package queryservice import ( "golang.org/x/net/context" + topodatapb "vitess.io/vitess/go/vt/proto/topodata" "vitess.io/vitess/go/sqltypes" "vitess.io/vitess/go/vt/vterrors" @@ -83,13 +84,13 @@ type wrappedService struct { wrapper WrapperFunc } -func (ws *wrappedService) Begin(ctx context.Context, target *querypb.Target, options *querypb.ExecuteOptions) (transactionID int64, err error) { +func (ws *wrappedService) Begin(ctx context.Context, target *querypb.Target, options *querypb.ExecuteOptions) (transactionID int64, alias *topodatapb.TabletAlias, err error) { err = ws.wrapper(ctx, target, ws.impl, "Begin", false, func(ctx context.Context, target *querypb.Target, conn QueryService) (bool, error) { var innerErr error - transactionID, innerErr = conn.Begin(ctx, target, options) + transactionID, alias, innerErr = conn.Begin(ctx, target, options) return canRetry(ctx, innerErr), innerErr }) - return transactionID, err + return transactionID, alias, err } func (ws *wrappedService) Commit(ctx context.Context, target *querypb.Target, transactionID int64) error { @@ -201,22 +202,22 @@ func (ws *wrappedService) ExecuteBatch(ctx context.Context, target *querypb.Targ return qrs, err } -func (ws *wrappedService) BeginExecute(ctx context.Context, target *querypb.Target, query string, bindVars map[string]*querypb.BindVariable, options *querypb.ExecuteOptions) (qr *sqltypes.Result, transactionID int64, err error) { +func (ws *wrappedService) BeginExecute(ctx context.Context, target *querypb.Target, query string, bindVars map[string]*querypb.BindVariable, options *querypb.ExecuteOptions) (qr *sqltypes.Result, transactionID int64, alias *topodatapb.TabletAlias, err error) { err = ws.wrapper(ctx, target, ws.impl, "BeginExecute", false, func(ctx context.Context, target *querypb.Target, conn QueryService) (bool, error) { var innerErr error - qr, transactionID, innerErr = conn.BeginExecute(ctx, target, query, bindVars, options) + qr, transactionID, alias, innerErr = conn.BeginExecute(ctx, target, query, bindVars, options) return canRetry(ctx, innerErr), innerErr }) - return qr, transactionID, err + return qr, transactionID, alias, err } -func (ws *wrappedService) BeginExecuteBatch(ctx context.Context, target *querypb.Target, queries []*querypb.BoundQuery, asTransaction bool, options *querypb.ExecuteOptions) (qrs []sqltypes.Result, transactionID int64, err error) { +func (ws *wrappedService) BeginExecuteBatch(ctx context.Context, target *querypb.Target, queries []*querypb.BoundQuery, asTransaction bool, options *querypb.ExecuteOptions) (qrs []sqltypes.Result, transactionID int64, alias *topodatapb.TabletAlias, err error) { err = ws.wrapper(ctx, target, ws.impl, "BeginExecuteBatch", false, func(ctx context.Context, target *querypb.Target, conn QueryService) (bool, error) { var innerErr error - qrs, transactionID, innerErr = conn.BeginExecuteBatch(ctx, target, queries, asTransaction, options) + qrs, transactionID, alias, innerErr = conn.BeginExecuteBatch(ctx, target, queries, asTransaction, options) return canRetry(ctx, innerErr), innerErr }) - return qrs, transactionID, err + return qrs, transactionID, alias, err } func (ws *wrappedService) MessageStream(ctx context.Context, target *querypb.Target, name string, callback func(*sqltypes.Result) error) error { diff --git a/go/vt/vttablet/sandboxconn/sandboxconn.go b/go/vt/vttablet/sandboxconn/sandboxconn.go index 1f05142e698..a37d50ae556 100644 --- a/go/vt/vttablet/sandboxconn/sandboxconn.go +++ b/go/vt/vttablet/sandboxconn/sandboxconn.go @@ -177,13 +177,13 @@ func (sbc *SandboxConn) StreamExecute(ctx context.Context, target *querypb.Targe } // Begin is part of the QueryService interface. -func (sbc *SandboxConn) Begin(ctx context.Context, target *querypb.Target, options *querypb.ExecuteOptions) (int64, error) { +func (sbc *SandboxConn) Begin(ctx context.Context, target *querypb.Target, options *querypb.ExecuteOptions) (int64, *topodatapb.TabletAlias, error) { sbc.BeginCount.Add(1) err := sbc.getError() if err != nil { - return 0, err + return 0, nil, err } - return sbc.TransactionID.Add(1), nil + return sbc.TransactionID.Add(1), sbc.tablet.Alias, nil } // Commit is part of the QueryService interface. @@ -286,23 +286,23 @@ func (sbc *SandboxConn) ReadTransaction(ctx context.Context, target *querypb.Tar } // BeginExecute is part of the QueryService interface. -func (sbc *SandboxConn) BeginExecute(ctx context.Context, target *querypb.Target, query string, bindVars map[string]*querypb.BindVariable, options *querypb.ExecuteOptions) (*sqltypes.Result, int64, error) { - transactionID, err := sbc.Begin(ctx, target, options) +func (sbc *SandboxConn) BeginExecute(ctx context.Context, target *querypb.Target, query string, bindVars map[string]*querypb.BindVariable, options *querypb.ExecuteOptions) (*sqltypes.Result, int64, *topodatapb.TabletAlias, error) { + transactionID, alias, err := sbc.Begin(ctx, target, options) if err != nil { - return nil, 0, err + return nil, 0, nil, err } result, err := sbc.Execute(ctx, target, query, bindVars, transactionID, options) - return result, transactionID, err + return result, transactionID, alias, err } // BeginExecuteBatch is part of the QueryService interface. -func (sbc *SandboxConn) BeginExecuteBatch(ctx context.Context, target *querypb.Target, queries []*querypb.BoundQuery, asTransaction bool, options *querypb.ExecuteOptions) ([]sqltypes.Result, int64, error) { - transactionID, err := sbc.Begin(ctx, target, options) +func (sbc *SandboxConn) BeginExecuteBatch(ctx context.Context, target *querypb.Target, queries []*querypb.BoundQuery, asTransaction bool, options *querypb.ExecuteOptions) ([]sqltypes.Result, int64, *topodatapb.TabletAlias, error) { + transactionID, alias, err := sbc.Begin(ctx, target, options) if err != nil { - return nil, 0, err + return nil, 0, nil, err } results, err := sbc.ExecuteBatch(ctx, target, queries, asTransaction, transactionID, options) - return results, transactionID, err + return results, transactionID, alias, err } // MessageStream is part of the QueryService interface. @@ -375,6 +375,11 @@ func (sbc *SandboxConn) VStreamResults(ctx context.Context, target *querypb.Targ return fmt.Errorf("not implemented in test") } +// QueryServiceByAlias is part of the Gateway interface. +func (sbc *SandboxConn) QueryServiceByAlias(_ *topodatapb.TabletAlias) (queryservice.QueryService, error) { + return sbc, nil +} + // HandlePanic is part of the QueryService interface. func (sbc *SandboxConn) HandlePanic(err *error) { } diff --git a/go/vt/vttablet/tabletconntest/fakequeryservice.go b/go/vt/vttablet/tabletconntest/fakequeryservice.go index a1ad9c39cb7..f49776f6164 100644 --- a/go/vt/vttablet/tabletconntest/fakequeryservice.go +++ b/go/vt/vttablet/tabletconntest/fakequeryservice.go @@ -21,6 +21,8 @@ import ( "fmt" "testing" + "vitess.io/vitess/go/vt/vttablet/queryservice" + "golang.org/x/net/context" "github.com/golang/protobuf/proto" @@ -77,6 +79,15 @@ var TestTarget = &querypb.Target{ TabletType: topodatapb.TabletType_REPLICA, } +// TestCell is the cell we use for this test (and TestGRPCDiscovery) +var TestCell = "aa" + +// TestAlias is the tablet alias we use for this test (and TestGRPCDiscovery) +var TestAlias = &topodatapb.TabletAlias{ + Cell: TestCell, + Uid: 1, +} + // TestCallerID is a test caller id. var TestCallerID = &vtrpcpb.CallerID{ Principal: "test_principal", @@ -122,13 +133,13 @@ func (f *FakeQueryService) checkTargetCallerID(ctx context.Context, name string, } } -// BeginTransactionID is a test transaction id for Begin. -const BeginTransactionID int64 = 9990 +// beginTransactionID is a test transaction id for Begin. +const beginTransactionID int64 = 9990 // Begin is part of the queryservice.QueryService interface -func (f *FakeQueryService) Begin(ctx context.Context, target *querypb.Target, options *querypb.ExecuteOptions) (int64, error) { +func (f *FakeQueryService) Begin(ctx context.Context, target *querypb.Target, options *querypb.ExecuteOptions) (int64, *topodatapb.TabletAlias, error) { if f.HasBeginError { - return 0, f.TabletError + return 0, nil, f.TabletError } if f.Panics { panic(fmt.Errorf("test-triggered panic")) @@ -137,11 +148,11 @@ func (f *FakeQueryService) Begin(ctx context.Context, target *querypb.Target, op if !proto.Equal(options, TestExecuteOptions) { f.t.Errorf("invalid Execute.ExecuteOptions: got %v expected %v", options, TestExecuteOptions) } - return BeginTransactionID, nil + return beginTransactionID, nil, nil } -// CommitTransactionID is a test transaction id for Commit. -const CommitTransactionID int64 = 999044 +// commitTransactionID is a test transaction id for Commit. +const commitTransactionID int64 = 999044 // Commit is part of the queryservice.QueryService interface func (f *FakeQueryService) Commit(ctx context.Context, target *querypb.Target, transactionID int64) error { @@ -152,14 +163,14 @@ func (f *FakeQueryService) Commit(ctx context.Context, target *querypb.Target, t panic(fmt.Errorf("test-triggered panic")) } f.checkTargetCallerID(ctx, "Commit", target) - if transactionID != CommitTransactionID { - f.t.Errorf("Commit: invalid TransactionId: got %v expected %v", transactionID, CommitTransactionID) + if transactionID != commitTransactionID { + f.t.Errorf("Commit: invalid TransactionId: got %v expected %v", transactionID, commitTransactionID) } return nil } -// RollbackTransactionID is a test transactin id for Rollback. -const RollbackTransactionID int64 = 999044 +// rollbackTransactionID is a test transactin id for Rollback. +const rollbackTransactionID int64 = 999044 // Rollback is part of the queryservice.QueryService interface func (f *FakeQueryService) Rollback(ctx context.Context, target *querypb.Target, transactionID int64) error { @@ -170,8 +181,8 @@ func (f *FakeQueryService) Rollback(ctx context.Context, target *querypb.Target, panic(fmt.Errorf("test-triggered panic")) } f.checkTargetCallerID(ctx, "Rollback", target) - if transactionID != RollbackTransactionID { - f.t.Errorf("Rollback: invalid TransactionId: got %v expected %v", transactionID, RollbackTransactionID) + if transactionID != rollbackTransactionID { + f.t.Errorf("Rollback: invalid TransactionId: got %v expected %v", transactionID, rollbackTransactionID) } return nil } @@ -188,8 +199,8 @@ func (f *FakeQueryService) Prepare(ctx context.Context, target *querypb.Target, panic(fmt.Errorf("test-triggered panic")) } f.checkTargetCallerID(ctx, "Prepare", target) - if transactionID != CommitTransactionID { - f.t.Errorf("Prepare: invalid TransactionID: got %v expected %v", transactionID, CommitTransactionID) + if transactionID != commitTransactionID { + f.t.Errorf("Prepare: invalid TransactionID: got %v expected %v", transactionID, commitTransactionID) } if dtid != Dtid { f.t.Errorf("Prepare: invalid dtid: got %s expected %s", dtid, Dtid) @@ -221,8 +232,8 @@ func (f *FakeQueryService) RollbackPrepared(ctx context.Context, target *querypb panic(fmt.Errorf("test-triggered panic")) } f.checkTargetCallerID(ctx, "RollbackPrepared", target) - if originalID != RollbackTransactionID { - f.t.Errorf("RollbackPrepared: invalid TransactionID: got %v expected %v", originalID, RollbackTransactionID) + if originalID != rollbackTransactionID { + f.t.Errorf("RollbackPrepared: invalid TransactionID: got %v expected %v", originalID, rollbackTransactionID) } if dtid != Dtid { f.t.Errorf("RollbackPrepared: invalid dtid: got %s expected %s", dtid, Dtid) @@ -279,8 +290,8 @@ func (f *FakeQueryService) StartCommit(ctx context.Context, target *querypb.Targ panic(fmt.Errorf("test-triggered panic")) } f.checkTargetCallerID(ctx, "StartCommit", target) - if transactionID != CommitTransactionID { - f.t.Errorf("StartCommit: invalid TransactionID: got %v expected %v", transactionID, CommitTransactionID) + if transactionID != commitTransactionID { + f.t.Errorf("StartCommit: invalid TransactionID: got %v expected %v", transactionID, commitTransactionID) } if dtid != Dtid { f.t.Errorf("StartCommit: invalid dtid: got %s expected %s", dtid, Dtid) @@ -297,8 +308,8 @@ func (f *FakeQueryService) SetRollback(ctx context.Context, target *querypb.Targ panic(fmt.Errorf("test-triggered panic")) } f.checkTargetCallerID(ctx, "SetRollback", target) - if transactionID != CommitTransactionID { - f.t.Errorf("SetRollback: invalid TransactionID: got %v expected %v", transactionID, CommitTransactionID) + if transactionID != commitTransactionID { + f.t.Errorf("SetRollback: invalid TransactionID: got %v expected %v", transactionID, commitTransactionID) } if dtid != Dtid { f.t.Errorf("SetRollback: invalid dtid: got %s expected %s", dtid, Dtid) @@ -564,25 +575,27 @@ func (f *FakeQueryService) ExecuteBatch(ctx context.Context, target *querypb.Tar } // BeginExecute combines Begin and Execute. -func (f *FakeQueryService) BeginExecute(ctx context.Context, target *querypb.Target, sql string, bindVariables map[string]*querypb.BindVariable, options *querypb.ExecuteOptions) (*sqltypes.Result, int64, error) { - transactionID, err := f.Begin(ctx, target, options) +func (f *FakeQueryService) BeginExecute(ctx context.Context, target *querypb.Target, sql string, bindVariables map[string]*querypb.BindVariable, options *querypb.ExecuteOptions) (*sqltypes.Result, int64, *topodatapb.TabletAlias, error) { + transactionID, _, err := f.Begin(ctx, target, options) if err != nil { - return nil, 0, err + return nil, 0, nil, err } + // TODO(deepthi): what alias should we actually return here? result, err := f.Execute(ctx, target, sql, bindVariables, transactionID, options) - return result, transactionID, err + return result, transactionID, nil, err } // BeginExecuteBatch combines Begin and ExecuteBatch. -func (f *FakeQueryService) BeginExecuteBatch(ctx context.Context, target *querypb.Target, queries []*querypb.BoundQuery, asTransaction bool, options *querypb.ExecuteOptions) ([]sqltypes.Result, int64, error) { - transactionID, err := f.Begin(ctx, target, options) +func (f *FakeQueryService) BeginExecuteBatch(ctx context.Context, target *querypb.Target, queries []*querypb.BoundQuery, asTransaction bool, options *querypb.ExecuteOptions) ([]sqltypes.Result, int64, *topodatapb.TabletAlias, error) { + transactionID, _, err := f.Begin(ctx, target, options) if err != nil { - return nil, 0, err + return nil, 0, nil, err } + // TODO(deepthi): what alias should we actually return here? results, err := f.ExecuteBatch(ctx, target, queries, asTransaction, transactionID, options) - return results, transactionID, err + return results, transactionID, nil, err } var ( @@ -698,6 +711,11 @@ func (f *FakeQueryService) VStreamResults(ctx context.Context, target *querypb.T panic("not implemented") } +// QueryServiceByAlias satisfies the Gateway interface +func (f *FakeQueryService) QueryServiceByAlias(_ *topodatapb.TabletAlias) (queryservice.QueryService, error) { + panic("not implemented") +} + // CreateFakeServer returns the fake server for the tests func CreateFakeServer(t *testing.T) *FakeQueryService { return &FakeQueryService{ diff --git a/go/vt/vttablet/tabletconntest/tabletconntest.go b/go/vt/vttablet/tabletconntest/tabletconntest.go index 6c9743f7b00..80a01603cd0 100644 --- a/go/vt/vttablet/tabletconntest/tabletconntest.go +++ b/go/vt/vttablet/tabletconntest/tabletconntest.go @@ -25,6 +25,8 @@ import ( "strings" "testing" + "github.com/stretchr/testify/assert" + "golang.org/x/net/context" "github.com/golang/protobuf/proto" @@ -98,20 +100,21 @@ func testBegin(t *testing.T, conn queryservice.QueryService, f *FakeQueryService t.Log("testBegin") ctx := context.Background() ctx = callerid.NewContext(ctx, TestCallerID, TestVTGateCallerID) - transactionID, err := conn.Begin(ctx, TestTarget, TestExecuteOptions) + transactionID, alias, err := conn.Begin(ctx, TestTarget, TestExecuteOptions) if err != nil { t.Fatalf("Begin failed: %v", err) } - if transactionID != BeginTransactionID { - t.Errorf("Unexpected result from Begin: got %v wanted %v", transactionID, BeginTransactionID) + if transactionID != beginTransactionID { + t.Errorf("Unexpected result from Begin: got %v wanted %v", transactionID, beginTransactionID) } + assert.Equal(t, TestAlias, alias, "Unexpected tablet alias from Begin") } func testBeginError(t *testing.T, conn queryservice.QueryService, f *FakeQueryService) { t.Log("testBeginError") f.HasBeginError = true testErrorHelper(t, f, "Begin", func(ctx context.Context) error { - _, err := conn.Begin(ctx, TestTarget, nil) + _, _, err := conn.Begin(ctx, TestTarget, nil) return err }) f.HasBeginError = false @@ -120,7 +123,7 @@ func testBeginError(t *testing.T, conn queryservice.QueryService, f *FakeQuerySe func testBeginPanics(t *testing.T, conn queryservice.QueryService, f *FakeQueryService) { t.Log("testBeginPanics") testPanicHelper(t, f, "Begin", func(ctx context.Context) error { - _, err := conn.Begin(ctx, TestTarget, nil) + _, _, err := conn.Begin(ctx, TestTarget, nil) return err }) } @@ -129,7 +132,7 @@ func testCommit(t *testing.T, conn queryservice.QueryService, f *FakeQueryServic t.Log("testCommit") ctx := context.Background() ctx = callerid.NewContext(ctx, TestCallerID, TestVTGateCallerID) - err := conn.Commit(ctx, TestTarget, CommitTransactionID) + err := conn.Commit(ctx, TestTarget, commitTransactionID) if err != nil { t.Fatalf("Commit failed: %v", err) } @@ -139,7 +142,7 @@ func testCommitError(t *testing.T, conn queryservice.QueryService, f *FakeQueryS t.Log("testCommitError") f.HasError = true testErrorHelper(t, f, "Commit", func(ctx context.Context) error { - return conn.Commit(ctx, TestTarget, CommitTransactionID) + return conn.Commit(ctx, TestTarget, commitTransactionID) }) f.HasError = false } @@ -147,7 +150,7 @@ func testCommitError(t *testing.T, conn queryservice.QueryService, f *FakeQueryS func testCommitPanics(t *testing.T, conn queryservice.QueryService, f *FakeQueryService) { t.Log("testCommitPanics") testPanicHelper(t, f, "Commit", func(ctx context.Context) error { - return conn.Commit(ctx, TestTarget, CommitTransactionID) + return conn.Commit(ctx, TestTarget, commitTransactionID) }) } @@ -155,7 +158,7 @@ func testRollback(t *testing.T, conn queryservice.QueryService, f *FakeQueryServ t.Log("testRollback") ctx := context.Background() ctx = callerid.NewContext(ctx, TestCallerID, TestVTGateCallerID) - err := conn.Rollback(ctx, TestTarget, RollbackTransactionID) + err := conn.Rollback(ctx, TestTarget, rollbackTransactionID) if err != nil { t.Fatalf("Rollback failed: %v", err) } @@ -165,7 +168,7 @@ func testRollbackError(t *testing.T, conn queryservice.QueryService, f *FakeQuer t.Log("testRollbackError") f.HasError = true testErrorHelper(t, f, "Rollback", func(ctx context.Context) error { - return conn.Rollback(ctx, TestTarget, CommitTransactionID) + return conn.Rollback(ctx, TestTarget, commitTransactionID) }) f.HasError = false } @@ -173,7 +176,7 @@ func testRollbackError(t *testing.T, conn queryservice.QueryService, f *FakeQuer func testRollbackPanics(t *testing.T, conn queryservice.QueryService, f *FakeQueryService) { t.Log("testRollbackPanics") testPanicHelper(t, f, "Rollback", func(ctx context.Context) error { - return conn.Rollback(ctx, TestTarget, RollbackTransactionID) + return conn.Rollback(ctx, TestTarget, rollbackTransactionID) }) } @@ -181,7 +184,7 @@ func testPrepare(t *testing.T, conn queryservice.QueryService, f *FakeQueryServi t.Log("testPrepare") ctx := context.Background() ctx = callerid.NewContext(ctx, TestCallerID, TestVTGateCallerID) - err := conn.Prepare(ctx, TestTarget, CommitTransactionID, Dtid) + err := conn.Prepare(ctx, TestTarget, commitTransactionID, Dtid) if err != nil { t.Fatalf("Prepare failed: %v", err) } @@ -191,7 +194,7 @@ func testPrepareError(t *testing.T, conn queryservice.QueryService, f *FakeQuery t.Log("testPrepareError") f.HasError = true testErrorHelper(t, f, "Prepare", func(ctx context.Context) error { - return conn.Prepare(ctx, TestTarget, CommitTransactionID, Dtid) + return conn.Prepare(ctx, TestTarget, commitTransactionID, Dtid) }) f.HasError = false } @@ -199,7 +202,7 @@ func testPrepareError(t *testing.T, conn queryservice.QueryService, f *FakeQuery func testPreparePanics(t *testing.T, conn queryservice.QueryService, f *FakeQueryService) { t.Log("testPreparePanics") testPanicHelper(t, f, "Prepare", func(ctx context.Context) error { - return conn.Prepare(ctx, TestTarget, CommitTransactionID, Dtid) + return conn.Prepare(ctx, TestTarget, commitTransactionID, Dtid) }) } @@ -233,7 +236,7 @@ func testRollbackPrepared(t *testing.T, conn queryservice.QueryService, f *FakeQ t.Log("testRollbackPrepared") ctx := context.Background() ctx = callerid.NewContext(ctx, TestCallerID, TestVTGateCallerID) - err := conn.RollbackPrepared(ctx, TestTarget, Dtid, RollbackTransactionID) + err := conn.RollbackPrepared(ctx, TestTarget, Dtid, rollbackTransactionID) if err != nil { t.Fatalf("RollbackPrepared failed: %v", err) } @@ -243,7 +246,7 @@ func testRollbackPreparedError(t *testing.T, conn queryservice.QueryService, f * t.Log("testRollbackPreparedError") f.HasError = true testErrorHelper(t, f, "RollbackPrepared", func(ctx context.Context) error { - return conn.RollbackPrepared(ctx, TestTarget, Dtid, RollbackTransactionID) + return conn.RollbackPrepared(ctx, TestTarget, Dtid, rollbackTransactionID) }) f.HasError = false } @@ -251,7 +254,7 @@ func testRollbackPreparedError(t *testing.T, conn queryservice.QueryService, f * func testRollbackPreparedPanics(t *testing.T, conn queryservice.QueryService, f *FakeQueryService) { t.Log("testRollbackPreparedPanics") testPanicHelper(t, f, "RollbackPrepared", func(ctx context.Context) error { - return conn.RollbackPrepared(ctx, TestTarget, Dtid, RollbackTransactionID) + return conn.RollbackPrepared(ctx, TestTarget, Dtid, rollbackTransactionID) }) } @@ -285,7 +288,7 @@ func testStartCommit(t *testing.T, conn queryservice.QueryService, f *FakeQueryS t.Log("testStartCommit") ctx := context.Background() ctx = callerid.NewContext(ctx, TestCallerID, TestVTGateCallerID) - err := conn.StartCommit(ctx, TestTarget, CommitTransactionID, Dtid) + err := conn.StartCommit(ctx, TestTarget, commitTransactionID, Dtid) if err != nil { t.Fatalf("StartCommit failed: %v", err) } @@ -295,7 +298,7 @@ func testStartCommitError(t *testing.T, conn queryservice.QueryService, f *FakeQ t.Log("testStartCommitError") f.HasError = true testErrorHelper(t, f, "StartCommit", func(ctx context.Context) error { - return conn.StartCommit(ctx, TestTarget, CommitTransactionID, Dtid) + return conn.StartCommit(ctx, TestTarget, commitTransactionID, Dtid) }) f.HasError = false } @@ -303,7 +306,7 @@ func testStartCommitError(t *testing.T, conn queryservice.QueryService, f *FakeQ func testStartCommitPanics(t *testing.T, conn queryservice.QueryService, f *FakeQueryService) { t.Log("testStartCommitPanics") testPanicHelper(t, f, "StartCommit", func(ctx context.Context) error { - return conn.StartCommit(ctx, TestTarget, CommitTransactionID, Dtid) + return conn.StartCommit(ctx, TestTarget, commitTransactionID, Dtid) }) } @@ -311,7 +314,7 @@ func testSetRollback(t *testing.T, conn queryservice.QueryService, f *FakeQueryS t.Log("testSetRollback") ctx := context.Background() ctx = callerid.NewContext(ctx, TestCallerID, TestVTGateCallerID) - err := conn.SetRollback(ctx, TestTarget, Dtid, RollbackTransactionID) + err := conn.SetRollback(ctx, TestTarget, Dtid, rollbackTransactionID) if err != nil { t.Fatalf("SetRollback failed: %v", err) } @@ -321,7 +324,7 @@ func testSetRollbackError(t *testing.T, conn queryservice.QueryService, f *FakeQ t.Log("testSetRollbackError") f.HasError = true testErrorHelper(t, f, "SetRollback", func(ctx context.Context) error { - return conn.SetRollback(ctx, TestTarget, Dtid, RollbackTransactionID) + return conn.SetRollback(ctx, TestTarget, Dtid, rollbackTransactionID) }) f.HasError = false } @@ -329,7 +332,7 @@ func testSetRollbackError(t *testing.T, conn queryservice.QueryService, f *FakeQ func testSetRollbackPanics(t *testing.T, conn queryservice.QueryService, f *FakeQueryService) { t.Log("testSetRollbackPanics") testPanicHelper(t, f, "SetRollback", func(ctx context.Context) error { - return conn.SetRollback(ctx, TestTarget, Dtid, RollbackTransactionID) + return conn.SetRollback(ctx, TestTarget, Dtid, rollbackTransactionID) }) } @@ -424,26 +427,27 @@ func testExecutePanics(t *testing.T, conn queryservice.QueryService, f *FakeQuer func testBeginExecute(t *testing.T, conn queryservice.QueryService, f *FakeQueryService) { t.Log("testBeginExecute") - f.ExpectedTransactionID = BeginTransactionID + f.ExpectedTransactionID = beginTransactionID ctx := context.Background() ctx = callerid.NewContext(ctx, TestCallerID, TestVTGateCallerID) - qr, transactionID, err := conn.BeginExecute(ctx, TestTarget, ExecuteQuery, ExecuteBindVars, TestExecuteOptions) + qr, transactionID, alias, err := conn.BeginExecute(ctx, TestTarget, ExecuteQuery, ExecuteBindVars, TestExecuteOptions) if err != nil { t.Fatalf("BeginExecute failed: %v", err) } - if transactionID != BeginTransactionID { - t.Errorf("Unexpected result from BeginExecute: got %v wanted %v", transactionID, BeginTransactionID) + if transactionID != beginTransactionID { + t.Errorf("Unexpected result from BeginExecute: got %v wanted %v", transactionID, beginTransactionID) } if !qr.Equal(&ExecuteQueryResult) { t.Errorf("Unexpected result from BeginExecute: got %v wanted %v", qr, ExecuteQueryResult) } + assert.Equal(t, TestAlias, alias, "Unexpected tablet alias from Begin") } func testBeginExecuteErrorInBegin(t *testing.T, conn queryservice.QueryService, f *FakeQueryService) { t.Log("testBeginExecuteErrorInBegin") f.HasBeginError = true testErrorHelper(t, f, "BeginExecute.Begin", func(ctx context.Context) error { - _, transactionID, err := conn.BeginExecute(ctx, TestTarget, ExecuteQuery, ExecuteBindVars, TestExecuteOptions) + _, transactionID, _, err := conn.BeginExecute(ctx, TestTarget, ExecuteQuery, ExecuteBindVars, TestExecuteOptions) if transactionID != 0 { t.Errorf("Unexpected transactionID from BeginExecute: got %v wanted 0", transactionID) } @@ -457,9 +461,9 @@ func testBeginExecuteErrorInExecute(t *testing.T, conn queryservice.QueryService f.HasError = true testErrorHelper(t, f, "BeginExecute.Execute", func(ctx context.Context) error { ctx = callerid.NewContext(ctx, TestCallerID, TestVTGateCallerID) - _, transactionID, err := conn.BeginExecute(ctx, TestTarget, ExecuteQuery, ExecuteBindVars, TestExecuteOptions) - if transactionID != BeginTransactionID { - t.Errorf("Unexpected transactionID from BeginExecute: got %v wanted %v", transactionID, BeginTransactionID) + _, transactionID, _, err := conn.BeginExecute(ctx, TestTarget, ExecuteQuery, ExecuteBindVars, TestExecuteOptions) + if transactionID != beginTransactionID { + t.Errorf("Unexpected transactionID from BeginExecute: got %v wanted %v", transactionID, beginTransactionID) } return err }) @@ -469,7 +473,7 @@ func testBeginExecuteErrorInExecute(t *testing.T, conn queryservice.QueryService func testBeginExecutePanics(t *testing.T, conn queryservice.QueryService, f *FakeQueryService) { t.Log("testBeginExecutePanics") testPanicHelper(t, f, "BeginExecute", func(ctx context.Context) error { - _, _, err := conn.BeginExecute(ctx, TestTarget, ExecuteQuery, ExecuteBindVars, TestExecuteOptions) + _, _, _, err := conn.BeginExecute(ctx, TestTarget, ExecuteQuery, ExecuteBindVars, TestExecuteOptions) return err }) } @@ -608,26 +612,27 @@ func testExecuteBatchPanics(t *testing.T, conn queryservice.QueryService, f *Fak func testBeginExecuteBatch(t *testing.T, conn queryservice.QueryService, f *FakeQueryService) { t.Log("testBeginExecuteBatch") - f.ExpectedTransactionID = BeginTransactionID + f.ExpectedTransactionID = beginTransactionID ctx := context.Background() ctx = callerid.NewContext(ctx, TestCallerID, TestVTGateCallerID) - qrl, transactionID, err := conn.BeginExecuteBatch(ctx, TestTarget, ExecuteBatchQueries, true, TestExecuteOptions) + qrl, transactionID, alias, err := conn.BeginExecuteBatch(ctx, TestTarget, ExecuteBatchQueries, true, TestExecuteOptions) if err != nil { t.Fatalf("BeginExecuteBatch failed: %v", err) } - if transactionID != BeginTransactionID { - t.Errorf("Unexpected result from BeginExecuteBatch: got %v wanted %v", transactionID, BeginTransactionID) + if transactionID != beginTransactionID { + t.Errorf("Unexpected result from BeginExecuteBatch: got %v wanted %v", transactionID, beginTransactionID) } if !sqltypes.ResultsEqual(qrl, ExecuteBatchQueryResultList) { t.Errorf("Unexpected result from ExecuteBatch: got %v wanted %v", qrl, ExecuteBatchQueryResultList) } + assert.Equal(t, TestAlias, alias, "Unexpected tablet alias from Begin") } func testBeginExecuteBatchErrorInBegin(t *testing.T, conn queryservice.QueryService, f *FakeQueryService) { t.Log("testBeginExecuteBatchErrorInBegin") f.HasBeginError = true testErrorHelper(t, f, "BeginExecuteBatch.Begin", func(ctx context.Context) error { - _, transactionID, err := conn.BeginExecuteBatch(ctx, TestTarget, ExecuteBatchQueries, true, TestExecuteOptions) + _, transactionID, _, err := conn.BeginExecuteBatch(ctx, TestTarget, ExecuteBatchQueries, true, TestExecuteOptions) if transactionID != 0 { t.Errorf("Unexpected transactionID from BeginExecuteBatch: got %v wanted 0", transactionID) } @@ -641,9 +646,9 @@ func testBeginExecuteBatchErrorInExecuteBatch(t *testing.T, conn queryservice.Qu f.HasError = true testErrorHelper(t, f, "BeginExecute.ExecuteBatch", func(ctx context.Context) error { ctx = callerid.NewContext(ctx, TestCallerID, TestVTGateCallerID) - _, transactionID, err := conn.BeginExecuteBatch(ctx, TestTarget, ExecuteBatchQueries, true, TestExecuteOptions) - if transactionID != BeginTransactionID { - t.Errorf("Unexpected transactionID from BeginExecuteBatch: got %v wanted %v", transactionID, BeginTransactionID) + _, transactionID, _, err := conn.BeginExecuteBatch(ctx, TestTarget, ExecuteBatchQueries, true, TestExecuteOptions) + if transactionID != beginTransactionID { + t.Errorf("Unexpected transactionID from BeginExecuteBatch: got %v wanted %v", transactionID, beginTransactionID) } return err }) @@ -653,7 +658,7 @@ func testBeginExecuteBatchErrorInExecuteBatch(t *testing.T, conn queryservice.Qu func testBeginExecuteBatchPanics(t *testing.T, conn queryservice.QueryService, f *FakeQueryService) { t.Log("testBeginExecuteBatchPanics") testPanicHelper(t, f, "BeginExecuteBatch", func(ctx context.Context) error { - _, _, err := conn.BeginExecuteBatch(ctx, TestTarget, ExecuteBatchQueries, true, TestExecuteOptions) + _, _, _, err := conn.BeginExecuteBatch(ctx, TestTarget, ExecuteBatchQueries, true, TestExecuteOptions) return err }) } diff --git a/go/vt/vttablet/tabletserver/query_executor.go b/go/vt/vttablet/tabletserver/query_executor.go index d637a52fd49..eb472ed3fc5 100644 --- a/go/vt/vttablet/tabletserver/query_executor.go +++ b/go/vt/vttablet/tabletserver/query_executor.go @@ -153,7 +153,7 @@ func (qre *QueryExecutor) execAutocommit(f func(conn tx.IStatefulConnection) (*s } qre.options.TransactionIsolation = querypb.ExecuteOptions_AUTOCOMMIT - conn, _, err := qre.tsv.te.txPool.Begin(qre.ctx, qre.options) + conn, _, err := qre.tsv.te.txPool.Begin(qre.ctx, qre.options, false) if err != nil { return nil, err @@ -164,7 +164,7 @@ func (qre *QueryExecutor) execAutocommit(f func(conn tx.IStatefulConnection) (*s } func (qre *QueryExecutor) execAsTransaction(f func(conn tx.IStatefulConnection) (*sqltypes.Result, error)) (*sqltypes.Result, error) { - conn, beginSQL, err := qre.tsv.te.txPool.Begin(qre.ctx, qre.options) + conn, beginSQL, err := qre.tsv.te.txPool.Begin(qre.ctx, qre.options, false) if err != nil { return nil, err } diff --git a/go/vt/vttablet/tabletserver/query_executor_test.go b/go/vt/vttablet/tabletserver/query_executor_test.go index 1b54e198a66..0c794c44bca 100644 --- a/go/vt/vttablet/tabletserver/query_executor_test.go +++ b/go/vt/vttablet/tabletserver/query_executor_test.go @@ -231,8 +231,10 @@ func TestQueryExecutorPlans(t *testing.T) { assert.Equal(t, tcase.logWant, qre.logStats.RewrittenSQL(), tcase.input) // Test inside a transaction. - txid, err := tsv.Begin(ctx, &tsv.target, nil) + txid, alias, err := tsv.Begin(ctx, &tsv.target, nil) require.NoError(t, err) + require.NotNil(t, alias, "alias should not be nil") + assert.Equal(t, tsv.alias, *alias, "Wrong alias returned by Begin") defer tsv.Commit(ctx, &tsv.target, txid) qre = newTestQueryExecutor(ctx, tsv, tcase.input, txid) @@ -295,8 +297,10 @@ func TestQueryExecutorSelectImpossible(t *testing.T) { assert.Equal(t, tcase.resultWant, got, tcase.input) assert.Equal(t, tcase.planWant, qre.logStats.PlanType, tcase.input) assert.Equal(t, tcase.logWant, qre.logStats.RewrittenSQL(), tcase.input) - txid, err := tsv.Begin(ctx, &tsv.target, nil) + txid, alias, err := tsv.Begin(ctx, &tsv.target, nil) require.NoError(t, err) + require.NotNil(t, alias, "alias should not be nil") + assert.Equal(t, tsv.alias, *alias, "Wrong tablet alias from Begin") defer tsv.Commit(ctx, &tsv.target, txid) qre = newTestQueryExecutor(ctx, tsv, tcase.input, txid) @@ -400,9 +404,10 @@ func TestQueryExecutorLimitFailure(t *testing.T) { assert.Equal(t, tcase.logWant, qre.logStats.RewrittenSQL(), tcase.input) // Test inside a transaction. - txid, err := tsv.Begin(ctx, &tsv.target, nil) - + txid, alias, err := tsv.Begin(ctx, &tsv.target, nil) require.NoError(t, err) + require.NotNil(t, alias, "alias should not be nil") + assert.Equal(t, tsv.alias, *alias, "Wrong tablet alias from Begin") defer tsv.Commit(ctx, &tsv.target, txid) qre = newTestQueryExecutor(ctx, tsv, tcase.input, txid) @@ -1075,7 +1080,7 @@ func newTestTabletServer(ctx context.Context, flags executorFlags, db *fakesqldb } func newTransaction(tsv *TabletServer, options *querypb.ExecuteOptions) int64 { - transactionID, err := tsv.Begin(context.Background(), &tsv.target, options) + transactionID, _, err := tsv.Begin(context.Background(), &tsv.target, options) if err != nil { panic(vterrors.Wrap(err, "failed to start a transaction")) } diff --git a/go/vt/vttablet/tabletserver/tabletserver.go b/go/vt/vttablet/tabletserver/tabletserver.go index a786376194a..dcf1951f937 100644 --- a/go/vt/vttablet/tabletserver/tabletserver.go +++ b/go/vt/vttablet/tabletserver/tabletserver.go @@ -772,7 +772,7 @@ func (tsv *TabletServer) SchemaEngine() *schema.Engine { } // Begin starts a new transaction. This is allowed only if the state is StateServing. -func (tsv *TabletServer) Begin(ctx context.Context, target *querypb.Target, options *querypb.ExecuteOptions) (transactionID int64, err error) { +func (tsv *TabletServer) Begin(ctx context.Context, target *querypb.Target, options *querypb.ExecuteOptions) (transactionID int64, tablet *topodatapb.TabletAlias, err error) { err = tsv.execRequest( ctx, tsv.QueryTimeout.Get(), "Begin", "begin", nil, @@ -799,7 +799,7 @@ func (tsv *TabletServer) Begin(ctx context.Context, target *querypb.Target, opti return err }, ) - return transactionID, err + return transactionID, &tsv.alias, err } // Commit commits the specified transaction. @@ -1089,7 +1089,7 @@ func (tsv *TabletServer) ExecuteBatch(ctx context.Context, target *querypb.Targe } } - allowOnShutdown := (transactionID != 0) + allowOnShutdown := transactionID != 0 // TODO(sougou): Convert startRequest/endRequest pattern to use wrapper // function tsv.execRequest() instead. // Note that below we always return "err" right away and do not call @@ -1118,7 +1118,8 @@ func (tsv *TabletServer) ExecuteBatch(ctx context.Context, target *querypb.Targe } if asTransaction { - transactionID, err = tsv.Begin(ctx, target, options) + // We ignore the return alias because this transaction only exists in the scope of this call + transactionID, _, err = tsv.Begin(ctx, target, options) if err != nil { return nil, err } @@ -1149,24 +1150,24 @@ func (tsv *TabletServer) ExecuteBatch(ctx context.Context, target *querypb.Targe } // BeginExecute combines Begin and Execute. -func (tsv *TabletServer) BeginExecute(ctx context.Context, target *querypb.Target, sql string, bindVariables map[string]*querypb.BindVariable, options *querypb.ExecuteOptions) (*sqltypes.Result, int64, error) { +func (tsv *TabletServer) BeginExecute(ctx context.Context, target *querypb.Target, sql string, bindVariables map[string]*querypb.BindVariable, options *querypb.ExecuteOptions) (*sqltypes.Result, int64, *topodatapb.TabletAlias, error) { if tsv.enableHotRowProtection { txDone, err := tsv.beginWaitForSameRangeTransactions(ctx, target, options, sql, bindVariables) if err != nil { - return nil, 0, err + return nil, 0, nil, err } if txDone != nil { defer txDone() } } - transactionID, err := tsv.Begin(ctx, target, options) + transactionID, alias, err := tsv.Begin(ctx, target, options) if err != nil { - return nil, 0, err + return nil, 0, nil, err } result, err := tsv.Execute(ctx, target, sql, bindVariables, transactionID, options) - return result, transactionID, err + return result, transactionID, alias, err } func (tsv *TabletServer) beginWaitForSameRangeTransactions(ctx context.Context, target *querypb.Target, options *querypb.ExecuteOptions, sql string, bindVariables map[string]*querypb.BindVariable) (txserializer.DoneFunc, error) { @@ -1248,16 +1249,16 @@ func (tsv *TabletServer) computeTxSerializerKey(ctx context.Context, logStats *t } // BeginExecuteBatch combines Begin and ExecuteBatch. -func (tsv *TabletServer) BeginExecuteBatch(ctx context.Context, target *querypb.Target, queries []*querypb.BoundQuery, asTransaction bool, options *querypb.ExecuteOptions) ([]sqltypes.Result, int64, error) { +func (tsv *TabletServer) BeginExecuteBatch(ctx context.Context, target *querypb.Target, queries []*querypb.BoundQuery, asTransaction bool, options *querypb.ExecuteOptions) ([]sqltypes.Result, int64, *topodatapb.TabletAlias, error) { // TODO(mberlin): Integrate hot row protection here as we did for BeginExecute() // and ExecuteBatch(asTransaction=true). - transactionID, err := tsv.Begin(ctx, target, options) + transactionID, alias, err := tsv.Begin(ctx, target, options) if err != nil { - return nil, 0, err + return nil, 0, nil, err } results, err := tsv.ExecuteBatch(ctx, target, queries, asTransaction, transactionID, options) - return results, transactionID, err + return results, transactionID, alias, err } // MessageStream streams messages from the requested table. @@ -1328,7 +1329,7 @@ func (tsv *TabletServer) execDML(ctx context.Context, target *querypb.Target, qu return 0, vterrors.Errorf(vtrpcpb.Code_INVALID_ARGUMENT, "%v", err) } - transactionID, err := tsv.Begin(ctx, target, nil) + transactionID, _, err := tsv.Begin(ctx, target, nil) if err != nil { return 0, err } diff --git a/go/vt/vttablet/tabletserver/tabletserver_test.go b/go/vt/vttablet/tabletserver/tabletserver_test.go index 8f1ebdc2b33..2478f92ee76 100644 --- a/go/vt/vttablet/tabletserver/tabletserver_test.go +++ b/go/vt/vttablet/tabletserver/tabletserver_test.go @@ -29,6 +29,8 @@ import ( "testing" "time" + "vitess.io/vitess/go/test/utils" + "github.com/stretchr/testify/assert" "github.com/golang/protobuf/proto" @@ -71,14 +73,10 @@ func TestTabletServerGetState(t *testing.T) { tsv := NewTabletServer("TabletServerTest", config, memorytopo.NewServer(""), topodatapb.TabletAlias{}) for i, state := range states { tsv.setState(state) - if stateName := tsv.GetState(); stateName != names[i] { - t.Errorf("GetState: %s, want %s", stateName, names[i]) - } + require.Equal(t, names[i], tsv.GetState(), "GetState") } tsv.EnterLameduck() - if stateName := tsv.GetState(); stateName != "NOT_SERVING" { - t.Errorf("GetState: %s, want NOT_SERVING", stateName) - } + require.Equal(t, "NOT_SERVING", tsv.GetState(), "GetState") } func TestTabletServerAllowQueriesFailBadConn(t *testing.T) { @@ -91,9 +89,7 @@ func TestTabletServerAllowQueriesFailBadConn(t *testing.T) { dbcfgs := newDBConfigs(db) target := querypb.Target{TabletType: topodatapb.TabletType_MASTER} err := tsv.StartService(target, dbcfgs) - if err == nil { - t.Fatalf("TabletServer.StartService should fail") - } + require.Error(t, err, "TabletServer.StartService should fail") checkTabletServerState(t, tsv, StateNotConnected) } @@ -109,14 +105,11 @@ func TestTabletServerAllowQueries(t *testing.T) { err := tsv.StartService(target, dbcfgs) tsv.StopService() want := "InitDBConfig failed" - if err == nil || !strings.Contains(err.Error(), want) { - t.Fatalf("TabletServer.StartService: %v, must contain %s", err, want) - } + require.Error(t, err) + assert.Contains(t, err.Error(), want) tsv.setState(StateShuttingDown) err = tsv.StartService(target, dbcfgs) - if err == nil { - t.Fatalf("TabletServer.StartService should fail") - } + require.Error(t, err, "TabletServer.StartService should fail") tsv.StopService() } @@ -130,9 +123,8 @@ func TestTabletServerInitDBConfig(t *testing.T) { dbcfgs := newDBConfigs(db) err := tsv.InitDBConfig(target, dbcfgs) want := "InitDBConfig failed" - if err == nil || !strings.Contains(err.Error(), want) { - t.Errorf("InitDBConfig: %v, must contain %s", err, want) - } + require.Error(t, err) + assert.Contains(t, err.Error(), want) tsv.setState(StateNotConnected) err = tsv.InitDBConfig(target, dbcfgs) require.NoError(t, err) @@ -216,16 +208,14 @@ func TestDecideAction(t *testing.T) { tsv.setState(StateTransitioning) _, err = tsv.decideAction(topodatapb.TabletType_MASTER, false, nil) want := "cannot SetServingType" - if err == nil || !strings.Contains(err.Error(), want) { - t.Errorf("decideAction: %v, must contain %s", err, want) - } + require.Error(t, err) + assert.Contains(t, err.Error(), want) tsv.setState(StateShuttingDown) _, err = tsv.decideAction(topodatapb.TabletType_MASTER, false, nil) want = "cannot SetServingType" - if err == nil || !strings.Contains(err.Error(), want) { - t.Errorf("decideAction: %v, must contain %s", err, want) - } + require.Error(t, err) + assert.Contains(t, err.Error(), want) } func TestSetServingType(t *testing.T) { @@ -319,16 +309,12 @@ func TestTabletServerCheckMysql(t *testing.T) { target := querypb.Target{TabletType: topodatapb.TabletType_MASTER} err := tsv.StartService(target, dbcfgs) defer tsv.StopService() - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) if !tsv.isMySQLReachable() { t.Error("isMySQLReachable should return true") } stateChanged, err := tsv.SetServingType(topodatapb.TabletType_SPARE, false, nil) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) if stateChanged != true { t.Errorf("SetServingType() should have changed the QueryService state, but did not") } @@ -399,73 +385,60 @@ func TestTabletServerTarget(t *testing.T) { t.Fatalf("StartService failed: %v", err) } defer tsv.StopService() - ctx := context.Background() // query that works db.AddQuery("select * from test_table limit 1000", &sqltypes.Result{}) _, err = tsv.Execute(ctx, &target1, "select * from test_table limit 1000", nil, 0, nil) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // wrong tablet type target2 := proto.Clone(&target1).(*querypb.Target) target2.TabletType = topodatapb.TabletType_REPLICA _, err = tsv.Execute(ctx, target2, "select * from test_table limit 1000", nil, 0, nil) want := "invalid tablet type" - if err == nil || !strings.Contains(err.Error(), want) { - t.Errorf("err: %v, must contain %s", err, want) - } + require.Error(t, err) + assert.Contains(t, err.Error(), want) // set expected target type to MASTER, but also accept REPLICA tsv.SetServingType(topodatapb.TabletType_MASTER, true, []topodatapb.TabletType{topodatapb.TabletType_REPLICA}) _, err = tsv.Execute(ctx, &target1, "select * from test_table limit 1000", nil, 0, nil) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) _, err = tsv.Execute(ctx, target2, "select * from test_table limit 1000", nil, 0, nil) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) // wrong keyspace target2 = proto.Clone(&target1).(*querypb.Target) target2.Keyspace = "bad" _, err = tsv.Execute(ctx, target2, "select * from test_table limit 1000", nil, 0, nil) want = "invalid keyspace bad" - if err == nil || !strings.Contains(err.Error(), want) { - t.Errorf("err: %v, must contain %s", err, want) - } + require.Error(t, err) + assert.Contains(t, err.Error(), want) // wrong shard target2 = proto.Clone(&target1).(*querypb.Target) target2.Shard = "bad" _, err = tsv.Execute(ctx, target2, "select * from test_table limit 1000", nil, 0, nil) want = "invalid shard bad" - if err == nil || !strings.Contains(err.Error(), want) { - t.Errorf("err: %v, must contain %s", err, want) - } + require.Error(t, err) + assert.Contains(t, err.Error(), want) // no target _, err = tsv.Execute(ctx, nil, "select * from test_table limit 1000", nil, 0, nil) want = "No target" - if err == nil || !strings.Contains(err.Error(), want) { - t.Errorf("err: %v, must contain %s", err, want) - } + require.Error(t, err) + assert.Contains(t, err.Error(), want) // Disallow all if service is stopped. tsv.StopService() _, err = tsv.Execute(ctx, &target1, "select * from test_table limit 1000", nil, 0, nil) want = "operation not allowed in state NOT_SERVING" - if err == nil || !strings.Contains(err.Error(), want) { - t.Errorf("err: %v, must contain %s", err, want) - } + require.Error(t, err) + assert.Contains(t, err.Error(), want) } func TestBeginOnReplica(t *testing.T) { db := setUpTabletServerTest(t) - db.AddQuery("set transaction isolation level REPEATABLE READ", &sqltypes.Result{}) - db.AddQuery("start transaction with consistent snapshot, read only", &sqltypes.Result{}) + db.AddQueryPattern(".*", &sqltypes.Result{}) defer db.Close() config := tabletenv.NewDefaultConfig() tsv := NewTabletServer("TabletServerTest", config, memorytopo.NewServer(""), topodatapb.TabletAlias{}) @@ -476,55 +449,42 @@ func TestBeginOnReplica(t *testing.T) { TabletType: topodatapb.TabletType_REPLICA, } err := tsv.StartService(target1, dbcfgs) - if err != nil { - t.Fatalf("StartService failed: %v", err) - } + require.NoError(t, err) defer tsv.StopService() tsv.SetServingType(topodatapb.TabletType_REPLICA, true, nil) - ctx := context.Background() options := querypb.ExecuteOptions{ TransactionIsolation: querypb.ExecuteOptions_CONSISTENT_SNAPSHOT_READ_ONLY, } - txID, err := tsv.Begin(ctx, &target1, &options) - - if err != nil { - t.Errorf("err: %v, failed to create read only tx on replica", err) - } - + txID, alias, err := tsv.Begin(ctx, &target1, &options) + require.NoError(t, err, "failed to create read only tx on replica") + assert.Equal(t, tsv.alias, *alias, "Wrong tablet alias from Begin") err = tsv.Rollback(ctx, &target1, txID) - if err != nil { - t.Errorf("err: %v, failed to rollback read only tx", err) - } + require.NoError(t, err, "failed to rollback read only tx") - // test that RW transactions are refused - options = querypb.ExecuteOptions{ - TransactionIsolation: querypb.ExecuteOptions_DEFAULT, - } - _, err = tsv.Begin(ctx, &target1, &options) - - if err == nil { - t.Error("expected write tx to be refused") - } + // test that we can still create transactions even in read-only mode + options = querypb.ExecuteOptions{} + txID, _, err = tsv.Begin(ctx, &target1, &options) + require.NoError(t, err, "expected write tx to be allowed") + err = tsv.Rollback(ctx, &target1, txID) + require.NoError(t, err) } func TestTabletServerMasterToReplica(t *testing.T) { // Reuse code from tx_executor_test. _, tsv, db := newTestTxExecutor(t) defer db.Close() - ctx := context.Background() target := querypb.Target{TabletType: topodatapb.TabletType_MASTER} - txid1, err := tsv.Begin(ctx, &target, nil) + txid1, _, err := tsv.Begin(ctx, &target, nil) require.NoError(t, err) _, err = tsv.Execute(ctx, &target, "update test_table set name = 2 where pk = 1", nil, txid1, nil) require.NoError(t, err) - err = tsv.Prepare(ctx, &target, txid1, "aa") require.NoError(t, err) - - txid2, err := tsv.Begin(ctx, &target, nil) + txid2, _, err := tsv.Begin(ctx, &target, nil) require.NoError(t, err) + // This makes txid2 busy conn2, err := tsv.te.txPool.GetAndLock(txid2, "for query") require.NoError(t, err) @@ -541,7 +501,7 @@ func TestTabletServerMasterToReplica(t *testing.T) { t.Fatal("ch should not fire") case <-time.After(10 * time.Millisecond): } - assert.Equal(t, int64(1), tsv.te.txPool.scp.active.Size(), "tsv.te.txPool.scp.active.Size(): ") + require.EqualValues(t, 1, tsv.te.txPool.scp.active.Size(), "tsv.te.txPool.scp.active.Size()") // Concluding conn2 will allow the transition to go through. tsv.te.txPool.RollbackAndRelease(ctx, conn2) @@ -566,9 +526,7 @@ func TestTabletServerRedoLogIsKeptBetweenRestarts(t *testing.T) { db.AddQuery(tpc.readAllRedo, &sqltypes.Result{}) turnOnTxEngine() - if len(tsv.te.preparedPool.conns) != 0 { - t.Errorf("len(tsv.te.preparedPool.conns): %d, want 0", len(tsv.te.preparedPool.conns)) - } + assert.Empty(t, tsv.te.preparedPool.conns, "tsv.te.preparedPool.conns") turnOffTxEngine() db.AddQuery(tpc.readAllRedo, &sqltypes.Result{ @@ -586,18 +544,12 @@ func TestTabletServerRedoLogIsKeptBetweenRestarts(t *testing.T) { }}, }) turnOnTxEngine() - if len(tsv.te.preparedPool.conns) != 1 { - t.Errorf("len(tsv.te.preparedPool.conns): %d, want 1", len(tsv.te.preparedPool.conns)) - } + assert.EqualValues(t, 1, len(tsv.te.preparedPool.conns), "len(tsv.te.preparedPool.conns)") got := tsv.te.preparedPool.conns["dtid0"].TxProperties().Queries want := []string{"update test_table set name = 2 where pk = 1 limit 10001"} - if !reflect.DeepEqual(got, want) { - t.Errorf("Prepared queries: %v, want %v", got, want) - } + utils.MustMatch(t, want, got, "Prepared queries") turnOffTxEngine() - if v := len(tsv.te.preparedPool.conns); v != 0 { - t.Errorf("len(tsv.te.preparedPool.conns): %d, want 0", v) - } + assert.Empty(t, tsv.te.preparedPool.conns, "tsv.te.preparedPool.conns") tsv.te.txPool.scp.lastID.Set(1) // Ensure we continue past errors. @@ -626,33 +578,24 @@ func TestTabletServerRedoLogIsKeptBetweenRestarts(t *testing.T) { }}, }) turnOnTxEngine() - if len(tsv.te.preparedPool.conns) != 1 { - t.Errorf("len(tsv.te.preparedPool.conns): %d, want 1", len(tsv.te.preparedPool.conns)) - } + assert.EqualValues(t, 1, len(tsv.te.preparedPool.conns), "len(tsv.te.preparedPool.conns)") got = tsv.te.preparedPool.conns["a:b:10"].TxProperties().Queries want = []string{"update test_table set name = 2 where pk = 1 limit 10001"} - if !reflect.DeepEqual(got, want) { - t.Errorf("Prepared queries: %v, want %v", got, want) - } + utils.MustMatch(t, want, got, "Prepared queries") wantFailed := map[string]error{"a:b:20": errPrepFailed} if !reflect.DeepEqual(tsv.te.preparedPool.reserved, wantFailed) { t.Errorf("Failed dtids: %v, want %v", tsv.te.preparedPool.reserved, wantFailed) } // Verify last id got adjusted. - if v := tsv.te.txPool.scp.lastID.Get(); v != 20 { - t.Errorf("tsv.te.txPool.lastID.Get(): %d, want 20", v) - } + assert.EqualValues(t, 20, tsv.te.txPool.scp.lastID.Get(), "tsv.te.txPool.lastID.Get()") turnOffTxEngine() - if v := len(tsv.te.preparedPool.conns); v != 0 { - t.Errorf("len(tsv.te.preparedPool.conns): %d, want 0", v) - } + assert.Empty(t, tsv.te.preparedPool.conns, "tsv.te.preparedPool.conns") } func TestTabletServerCreateTransaction(t *testing.T) { _, tsv, db := newTestTxExecutor(t) defer db.Close() defer tsv.StopService() - ctx := context.Background() target := querypb.Target{TabletType: topodatapb.TabletType_MASTER} db.AddQueryPattern(fmt.Sprintf("insert into _vt\\.dt_state\\(dtid, state, time_created\\) values \\('aa', %d,.*", int(querypb.TransactionState_PREPARE)), &sqltypes.Result{}) @@ -668,7 +611,6 @@ func TestTabletServerStartCommit(t *testing.T) { _, tsv, db := newTestTxExecutor(t) defer db.Close() defer tsv.StopService() - ctx := context.Background() target := querypb.Target{TabletType: topodatapb.TabletType_MASTER} commitTransition := fmt.Sprintf("update _vt.dt_state set state = %d where dtid = 'aa' and state = %d", int(querypb.TransactionState_COMMIT), int(querypb.TransactionState_PREPARE)) @@ -680,17 +622,13 @@ func TestTabletServerStartCommit(t *testing.T) { db.AddQuery(commitTransition, &sqltypes.Result{}) txid = newTxForPrep(tsv) err = tsv.StartCommit(ctx, &target, txid, "aa") - want := "could not transition to COMMIT: aa" - if err == nil || err.Error() != want { - t.Errorf("Prepare err: %v, want %s", err, want) - } + assert.EqualError(t, err, "could not transition to COMMIT: aa", "Prepare err") } func TestTabletserverSetRollback(t *testing.T) { _, tsv, db := newTestTxExecutor(t) defer db.Close() defer tsv.StopService() - ctx := context.Background() target := querypb.Target{TabletType: topodatapb.TabletType_MASTER} rollbackTransition := fmt.Sprintf("update _vt.dt_state set state = %d where dtid = 'aa' and state = %d", int(querypb.TransactionState_ROLLBACK), int(querypb.TransactionState_PREPARE)) @@ -702,26 +640,20 @@ func TestTabletserverSetRollback(t *testing.T) { db.AddQuery(rollbackTransition, &sqltypes.Result{}) txid = newTxForPrep(tsv) err = tsv.SetRollback(ctx, &target, "aa", txid) - want := "could not transition to ROLLBACK: aa" - if err == nil || err.Error() != want { - t.Errorf("Prepare err: %v, want %s", err, want) - } + assert.EqualError(t, err, "could not transition to ROLLBACK: aa", "Prepare err") } func TestTabletServerReadTransaction(t *testing.T) { _, tsv, db := newTestTxExecutor(t) defer db.Close() defer tsv.StopService() - ctx := context.Background() target := querypb.Target{TabletType: topodatapb.TabletType_MASTER} db.AddQuery("select dtid, state, time_created from _vt.dt_state where dtid = 'aa'", &sqltypes.Result{}) got, err := tsv.ReadTransaction(ctx, &target, "aa") require.NoError(t, err) want := &querypb.TransactionMetadata{} - if !proto.Equal(got, want) { - t.Errorf("ReadTransaction: %v, want %v", got, want) - } + utils.MustMatch(t, want, got, "ReadTransaction") txResult := &sqltypes.Result{ Fields: []*querypb.Field{ @@ -765,9 +697,7 @@ func TestTabletServerReadTransaction(t *testing.T) { TabletType: topodatapb.TabletType_MASTER, }}, } - if !proto.Equal(got, want) { - t.Errorf("ReadTransaction: %v, want %v", got, want) - } + utils.MustMatch(t, want, got, "ReadTransaction") txResult = &sqltypes.Result{ Fields: []*querypb.Field{ @@ -785,9 +715,7 @@ func TestTabletServerReadTransaction(t *testing.T) { want.State = querypb.TransactionState_COMMIT got, err = tsv.ReadTransaction(ctx, &target, "aa") require.NoError(t, err) - if !proto.Equal(got, want) { - t.Errorf("ReadTransaction: %v, want %v", got, want) - } + utils.MustMatch(t, want, got, "ReadTransaction") txResult = &sqltypes.Result{ Fields: []*querypb.Field{ @@ -805,16 +733,13 @@ func TestTabletServerReadTransaction(t *testing.T) { want.State = querypb.TransactionState_ROLLBACK got, err = tsv.ReadTransaction(ctx, &target, "aa") require.NoError(t, err) - if !proto.Equal(got, want) { - t.Errorf("ReadTransaction: %v, want %v", got, want) - } + utils.MustMatch(t, want, got, "ReadTransaction") } func TestTabletServerConcludeTransaction(t *testing.T) { _, tsv, db := newTestTxExecutor(t) defer db.Close() defer tsv.StopService() - ctx := context.Background() target := querypb.Target{TabletType: topodatapb.TabletType_MASTER} db.AddQuery("delete from _vt.dt_state where dtid = 'aa'", &sqltypes.Result{}) @@ -832,18 +757,13 @@ func TestTabletServerBeginFail(t *testing.T) { dbcfgs := newDBConfigs(db) target := querypb.Target{TabletType: topodatapb.TabletType_MASTER} err := tsv.StartService(target, dbcfgs) - if err != nil { - t.Fatalf("StartService failed: %v", err) - } + require.NoError(t, err) defer tsv.StopService() ctx, cancel := context.WithTimeout(context.Background(), 1*time.Nanosecond) defer cancel() tsv.Begin(ctx, &target, nil) - _, err = tsv.Begin(ctx, &target, nil) - want := "transaction pool aborting request due to already expired context" - if err == nil || err.Error() != want { - t.Fatalf("Begin err: %v, want %v", err, want) - } + _, _, err = tsv.Begin(ctx, &target, nil) + require.EqualError(t, err, "transaction pool aborting request due to already expired context", "Begin err") } func TestTabletServerCommitTransaction(t *testing.T) { @@ -869,8 +789,7 @@ func TestTabletServerCommitTransaction(t *testing.T) { t.Fatalf("StartService failed: %v", err) } defer tsv.StopService() - ctx := context.Background() - transactionID, err := tsv.Begin(ctx, &target, nil) + transactionID, _, err := tsv.Begin(ctx, &target, nil) if err != nil { t.Fatalf("call TabletServer.Begin failed: %v", err) } @@ -894,7 +813,6 @@ func TestTabletServerCommiRollbacktFail(t *testing.T) { t.Fatalf("StartService failed: %v", err) } defer tsv.StopService() - ctx := context.Background() err = tsv.Commit(ctx, &target, -1) want := "transaction -1: not found" if err == nil || err.Error() != want { @@ -929,8 +847,7 @@ func TestTabletServerRollback(t *testing.T) { t.Fatalf("StartService failed: %v", err) } defer tsv.StopService() - ctx := context.Background() - transactionID, err := tsv.Begin(ctx, &target, nil) + transactionID, _, err := tsv.Begin(ctx, &target, nil) if err != nil { t.Fatalf("call TabletServer.Begin failed: %v", err) } @@ -947,19 +864,14 @@ func TestTabletServerPrepare(t *testing.T) { _, tsv, db := newTestTxExecutor(t) defer db.Close() defer tsv.StopService() - ctx := context.Background() target := querypb.Target{TabletType: topodatapb.TabletType_MASTER} - transactionID, err := tsv.Begin(ctx, &target, nil) - if err != nil { - t.Fatal(err) - } - if _, err := tsv.Execute(ctx, &target, "update test_table set name = 2 where pk = 1", nil, transactionID, nil); err != nil { - t.Fatal(err) - } + transactionID, _, err := tsv.Begin(ctx, &target, nil) + require.NoError(t, err) + _, err = tsv.Execute(ctx, &target, "update test_table set name = 2 where pk = 1", nil, transactionID, nil) + require.NoError(t, err) defer tsv.RollbackPrepared(ctx, &target, "aa", 0) - if err := tsv.Prepare(ctx, &target, transactionID, "aa"); err != nil { - t.Fatal(err) - } + err = tsv.Prepare(ctx, &target, transactionID, "aa") + require.NoError(t, err) } func TestTabletServerCommitPrepared(t *testing.T) { @@ -967,22 +879,16 @@ func TestTabletServerCommitPrepared(t *testing.T) { _, tsv, db := newTestTxExecutor(t) defer db.Close() defer tsv.StopService() - ctx := context.Background() target := querypb.Target{TabletType: topodatapb.TabletType_MASTER} - transactionID, err := tsv.Begin(ctx, &target, nil) - if err != nil { - t.Fatal(err) - } - if _, err := tsv.Execute(ctx, &target, "update test_table set name = 2 where pk = 1", nil, transactionID, nil); err != nil { - t.Fatal(err) - } - if err := tsv.Prepare(ctx, &target, transactionID, "aa"); err != nil { - t.Fatal(err) - } + transactionID, _, err := tsv.Begin(ctx, &target, nil) + require.NoError(t, err) + _, err = tsv.Execute(ctx, &target, "update test_table set name = 2 where pk = 1", nil, transactionID, nil) + require.NoError(t, err) + err = tsv.Prepare(ctx, &target, transactionID, "aa") + require.NoError(t, err) defer tsv.RollbackPrepared(ctx, &target, "aa", 0) - if err := tsv.CommitPrepared(ctx, &target, "aa"); err != nil { - t.Fatal(err) - } + err = tsv.CommitPrepared(ctx, &target, "aa") + require.NoError(t, err) } func TestTabletServerRollbackPrepared(t *testing.T) { @@ -990,21 +896,15 @@ func TestTabletServerRollbackPrepared(t *testing.T) { _, tsv, db := newTestTxExecutor(t) defer db.Close() defer tsv.StopService() - ctx := context.Background() target := querypb.Target{TabletType: topodatapb.TabletType_MASTER} - transactionID, err := tsv.Begin(ctx, &target, nil) - if err != nil { - t.Fatal(err) - } - if _, err := tsv.Execute(ctx, &target, "update test_table set name = 2 where pk = 1", nil, transactionID, nil); err != nil { - t.Fatal(err) - } - if err := tsv.Prepare(ctx, &target, transactionID, "aa"); err != nil { - t.Fatal(err) - } - if err := tsv.RollbackPrepared(ctx, &target, "aa", transactionID); err != nil { - t.Fatal(err) - } + transactionID, _, err := tsv.Begin(ctx, &target, nil) + require.NoError(t, err) + _, err = tsv.Execute(ctx, &target, "update test_table set name = 2 where pk = 1", nil, transactionID, nil) + require.NoError(t, err) + err = tsv.Prepare(ctx, &target, transactionID, "aa") + require.NoError(t, err) + err = tsv.RollbackPrepared(ctx, &target, "aa", transactionID) + require.NoError(t, err) } func TestTabletServerStreamExecute(t *testing.T) { @@ -1031,7 +931,6 @@ func TestTabletServerStreamExecute(t *testing.T) { t.Fatalf("StartService failed: %v", err) } defer tsv.StopService() - ctx := context.Background() callback := func(*sqltypes.Result) error { return nil } if err := tsv.StreamExecute(ctx, &target, executeSQL, nil, 0, nil, callback); err != nil { t.Fatalf("TabletServer.StreamExecute should success: %s, but get error: %v", @@ -1063,7 +962,6 @@ func TestTabletServerStreamExecuteComments(t *testing.T) { t.Fatalf("StartService failed: %v", err) } defer tsv.StopService() - ctx := context.Background() callback := func(*sqltypes.Result) error { return nil } ch := tabletenv.StatsLogger.Subscribe("test stats logging") @@ -1107,7 +1005,6 @@ func TestTabletServerExecuteBatch(t *testing.T) { t.Fatalf("StartService failed: %v", err) } defer tsv.StopService() - ctx := context.Background() if _, err := tsv.ExecuteBatch(ctx, &target, []*querypb.BoundQuery{ { Sql: sql, @@ -1130,12 +1027,10 @@ func TestTabletServerExecuteBatchFailEmptyQueryList(t *testing.T) { t.Fatalf("StartService failed: %v", err) } defer tsv.StopService() - ctx := context.Background() _, err = tsv.ExecuteBatch(ctx, nil, []*querypb.BoundQuery{}, false, 0, nil) want := "Empty query list" - if err == nil || !strings.Contains(err.Error(), want) { - t.Errorf("ExecuteBatch: %v, must contain %s", err, want) - } + require.Error(t, err) + assert.Contains(t, err.Error(), want) } func TestTabletServerExecuteBatchFailAsTransaction(t *testing.T) { @@ -1150,7 +1045,6 @@ func TestTabletServerExecuteBatchFailAsTransaction(t *testing.T) { t.Fatalf("StartService failed: %v", err) } defer tsv.StopService() - ctx := context.Background() _, err = tsv.ExecuteBatch(ctx, nil, []*querypb.BoundQuery{ { Sql: "begin", @@ -1158,9 +1052,8 @@ func TestTabletServerExecuteBatchFailAsTransaction(t *testing.T) { }, }, true, 1, nil) want := "cannot start a new transaction" - if err == nil || !strings.Contains(err.Error(), want) { - t.Errorf("ExecuteBatch: %v, must contain %s", err, want) - } + require.Error(t, err) + assert.Contains(t, err.Error(), want) } func TestTabletServerExecuteBatchBeginFail(t *testing.T) { @@ -1177,7 +1070,6 @@ func TestTabletServerExecuteBatchBeginFail(t *testing.T) { t.Fatalf("StartService failed: %v", err) } defer tsv.StopService() - ctx := context.Background() if _, err := tsv.ExecuteBatch(ctx, nil, []*querypb.BoundQuery{ { Sql: "begin", @@ -1202,7 +1094,6 @@ func TestTabletServerExecuteBatchCommitFail(t *testing.T) { t.Fatalf("StartService failed: %v", err) } defer tsv.StopService() - ctx := context.Background() if _, err := tsv.ExecuteBatch(ctx, nil, []*querypb.BoundQuery{ { Sql: "begin", @@ -1240,7 +1131,6 @@ func TestTabletServerExecuteBatchSqlExecFailInTransaction(t *testing.T) { t.Fatalf("StartService failed: %v", err) } defer tsv.StopService() - ctx := context.Background() if db.GetQueryCalledNum("rollback") != 0 { t.Fatalf("rollback should not be executed.") } @@ -1271,7 +1161,6 @@ func TestTabletServerExecuteBatchCallCommitWithoutABegin(t *testing.T) { t.Fatalf("StartService failed: %v", err) } defer tsv.StopService() - ctx := context.Background() if _, err := tsv.ExecuteBatch(ctx, nil, []*querypb.BoundQuery{ { Sql: "commit", @@ -1300,7 +1189,6 @@ func TestExecuteBatchNestedTransaction(t *testing.T) { t.Fatalf("StartService failed: %v", err) } defer tsv.StopService() - ctx := context.Background() if _, err := tsv.ExecuteBatch(ctx, nil, []*querypb.BoundQuery{ { Sql: "begin", @@ -1384,7 +1272,6 @@ func TestSerializeTransactionsSameRow(t *testing.T) { }) // Run all three transactions. - ctx := context.Background() wg := sync.WaitGroup{} // tx1. @@ -1392,7 +1279,7 @@ func TestSerializeTransactionsSameRow(t *testing.T) { go func() { defer wg.Done() - _, tx1, err := tsv.BeginExecute(ctx, &target, q1, bvTx1, nil) + _, tx1, _, err := tsv.BeginExecute(ctx, &target, q1, bvTx1, nil) if err != nil { t.Errorf("failed to execute query: %s: %s", q1, err) } @@ -1407,7 +1294,7 @@ func TestSerializeTransactionsSameRow(t *testing.T) { defer wg.Done() <-tx1Started - _, tx2, err := tsv.BeginExecute(ctx, &target, q2, bvTx2, nil) + _, tx2, _, err := tsv.BeginExecute(ctx, &target, q2, bvTx2, nil) if err != nil { t.Errorf("failed to execute query: %s: %s", q2, err) } @@ -1427,7 +1314,7 @@ func TestSerializeTransactionsSameRow(t *testing.T) { defer wg.Done() <-tx1Started - _, tx3, err := tsv.BeginExecute(ctx, &target, q3, bvTx3, nil) + _, tx3, _, err := tsv.BeginExecute(ctx, &target, q3, bvTx3, nil) if err != nil { t.Errorf("failed to execute query: %s: %s", q3, err) } @@ -1464,8 +1351,7 @@ func TestDMLQueryWithoutWhereClause(t *testing.T) { db.AddQuery(q+" limit 10001", &sqltypes.Result{}) - ctx := context.Background() - _, txid, err := tsv.BeginExecute(ctx, &target, q, nil, nil) + _, txid, _, err := tsv.BeginExecute(ctx, &target, q, nil, nil) require.NoError(t, err) err = tsv.Commit(ctx, &target, txid) require.NoError(t, err) @@ -1533,7 +1419,6 @@ func TestSerializeTransactionsSameRow_ExecuteBatchAsTransaction(t *testing.T) { }) // Run all three transactions. - ctx := context.Background() wg := sync.WaitGroup{} // tx1. @@ -1647,7 +1532,6 @@ func TestSerializeTransactionsSameRow_ConcurrentTransactions(t *testing.T) { }) // Run all three transactions. - ctx := context.Background() wg := sync.WaitGroup{} // tx1. @@ -1655,7 +1539,7 @@ func TestSerializeTransactionsSameRow_ConcurrentTransactions(t *testing.T) { go func() { defer wg.Done() - _, tx1, err := tsv.BeginExecute(ctx, &target, q1, bvTx1, nil) + _, tx1, _, err := tsv.BeginExecute(ctx, &target, q1, bvTx1, nil) if err != nil { t.Errorf("failed to execute query: %s: %s", q1, err) } @@ -1674,7 +1558,7 @@ func TestSerializeTransactionsSameRow_ConcurrentTransactions(t *testing.T) { // In that case, we would see less than 3 pending transactions. <-tx1Started - _, tx2, err := tsv.BeginExecute(ctx, &target, q2, bvTx2, nil) + _, tx2, _, err := tsv.BeginExecute(ctx, &target, q2, bvTx2, nil) if err != nil { t.Errorf("failed to execute query: %s: %s", q2, err) } @@ -1693,7 +1577,7 @@ func TestSerializeTransactionsSameRow_ConcurrentTransactions(t *testing.T) { // In that case, we would see less than 3 pending transactions. <-tx1Started - _, tx3, err := tsv.BeginExecute(ctx, &target, q3, bvTx3, nil) + _, tx3, _, err := tsv.BeginExecute(ctx, &target, q3, bvTx3, nil) if err != nil { t.Errorf("failed to execute query: %s: %s", q3, err) } @@ -1710,9 +1594,8 @@ func TestSerializeTransactionsSameRow_ConcurrentTransactions(t *testing.T) { // transactions via db.SetBeforeFunc() for the same reason as mentioned // in TestSerializeTransactionsSameRow: The MySQL C client does not seem // to allow more than connection attempt at a time. - if err := waitForTxSerializationPendingQueries(tsv, "test_table where pk = 1 and name = 1", 3); err != nil { - t.Fatal(err) - } + err := waitForTxSerializationPendingQueries(tsv, "test_table where pk = 1 and name = 1", 3) + require.NoError(t, err) close(allQueriesPending) wg.Wait() @@ -1785,7 +1668,6 @@ func TestSerializeTransactionsSameRow_TooManyPendingRequests(t *testing.T) { }) // Run the two transactions. - ctx := context.Background() wg := sync.WaitGroup{} // tx1. @@ -1793,7 +1675,7 @@ func TestSerializeTransactionsSameRow_TooManyPendingRequests(t *testing.T) { go func() { defer wg.Done() - _, tx1, err := tsv.BeginExecute(ctx, &target, q1, bvTx1, nil) + _, tx1, _, err := tsv.BeginExecute(ctx, &target, q1, bvTx1, nil) if err != nil { t.Errorf("failed to execute query: %s: %s", q1, err) } @@ -1809,7 +1691,7 @@ func TestSerializeTransactionsSameRow_TooManyPendingRequests(t *testing.T) { defer close(tx2Failed) <-tx1Started - _, _, err := tsv.BeginExecute(ctx, &target, q2, bvTx2, nil) + _, _, _, err := tsv.BeginExecute(ctx, &target, q2, bvTx2, nil) if err == nil || vterrors.Code(err) != vtrpcpb.Code_RESOURCE_EXHAUSTED || err.Error() != "hot row protection: too many queued transactions (1 >= 1) for the same row (table + WHERE clause: 'test_table where pk = 1 and name = 1')" { t.Errorf("tx2 should have failed because there are too many pending requests: %v", err) } @@ -1873,7 +1755,6 @@ func TestSerializeTransactionsSameRow_TooManyPendingRequests_ExecuteBatchAsTrans }) // Run the two transactions. - ctx := context.Background() wg := sync.WaitGroup{} // tx1. @@ -1970,7 +1851,6 @@ func TestSerializeTransactionsSameRow_RequestCanceled(t *testing.T) { }) // Run the two transactions. - ctx := context.Background() wg := sync.WaitGroup{} // tx1. @@ -1978,7 +1858,7 @@ func TestSerializeTransactionsSameRow_RequestCanceled(t *testing.T) { go func() { defer wg.Done() - _, tx1, err := tsv.BeginExecute(ctx, &target, q1, bvTx1, nil) + _, tx1, _, err := tsv.BeginExecute(ctx, &target, q1, bvTx1, nil) if err != nil { t.Errorf("failed to execute query: %s: %s", q1, err) } @@ -1998,7 +1878,7 @@ func TestSerializeTransactionsSameRow_RequestCanceled(t *testing.T) { // Wait until tx1 has started to make the test deterministic. <-tx1Started - _, _, err := tsv.BeginExecute(ctxTx2, &target, q2, bvTx2, nil) + _, _, _, err := tsv.BeginExecute(ctxTx2, &target, q2, bvTx2, nil) if err == nil || vterrors.Code(err) != vtrpcpb.Code_CANCELED || err.Error() != "context canceled" { t.Errorf("tx2 should have failed because the context was canceled: %v", err) } @@ -2015,7 +1895,7 @@ func TestSerializeTransactionsSameRow_RequestCanceled(t *testing.T) { t.Error(err) } - _, tx3, err := tsv.BeginExecute(ctx, &target, q3, bvTx3, nil) + _, tx3, _, err := tsv.BeginExecute(ctx, &target, q3, bvTx3, nil) if err != nil { t.Errorf("failed to execute query: %s: %s", q3, err) } @@ -2026,9 +1906,8 @@ func TestSerializeTransactionsSameRow_RequestCanceled(t *testing.T) { }() // Wait until tx1, 2 and 3 are pending. - if err := waitForTxSerializationPendingQueries(tsv, "test_table where pk = 1 and name = 1", 3); err != nil { - t.Fatal(err) - } + err := waitForTxSerializationPendingQueries(tsv, "test_table where pk = 1 and name = 1", 3) + require.NoError(t, err) // Now unblock tx2 and cancel it. cancelTx2() @@ -2045,7 +1924,6 @@ func TestMessageStream(t *testing.T) { _, tsv, db := newTestTxExecutor(t) defer db.Close() defer tsv.StopService() - ctx := context.Background() target := querypb.Target{TabletType: topodatapb.TabletType_MASTER} err := tsv.MessageStream(ctx, &target, "nomsg", func(qr *sqltypes.Result) error { @@ -2062,9 +1940,7 @@ func TestMessageStream(t *testing.T) { called = true return io.EOF }) - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) if !called { t.Fatal("callback was not called for MessageStream") } @@ -2074,7 +1950,6 @@ func TestMessageAck(t *testing.T) { _, tsv, db := newTestTxExecutor(t) defer db.Close() defer tsv.StopService() - ctx := context.Background() target := querypb.Target{TabletType: topodatapb.TabletType_MASTER} ids := []*querypb.Value{{ @@ -2092,9 +1967,8 @@ func TestMessageAck(t *testing.T) { _, err = tsv.MessageAck(ctx, &target, "msg", ids) want = "query: 'update msg set time_acked" - if err == nil || !strings.Contains(err.Error(), want) { - t.Errorf("tsv.MessageAck(invalid):\n%v, want\n%s", err, want) - } + require.Error(t, err) + assert.Contains(t, err.Error(), want) db.AddQueryPattern("update msg set time_acked = .*", &sqltypes.Result{RowsAffected: 1}) count, err := tsv.MessageAck(ctx, &target, "msg", ids) @@ -2108,7 +1982,6 @@ func TestRescheduleMessages(t *testing.T) { _, tsv, db := newTestTxExecutor(t) defer db.Close() defer tsv.StopService() - ctx := context.Background() target := querypb.Target{TabletType: topodatapb.TabletType_MASTER} _, err := tsv.PostponeMessages(ctx, &target, "nonmsg", []string{"1", "2"}) @@ -2119,9 +1992,8 @@ func TestRescheduleMessages(t *testing.T) { _, err = tsv.PostponeMessages(ctx, &target, "msg", []string{"1", "2"}) want = "query: 'update msg set time_next" - if err == nil || !strings.Contains(err.Error(), want) { - t.Errorf("tsv.PostponeMessages(invalid):\n%v, want\n%s", err, want) - } + require.Error(t, err) + assert.Contains(t, err.Error(), want) db.AddQueryPattern("update msg set time_next = .*", &sqltypes.Result{RowsAffected: 1}) count, err := tsv.PostponeMessages(ctx, &target, "msg", []string{"1", "2"}) require.NoError(t, err) @@ -2134,7 +2006,6 @@ func TestPurgeMessages(t *testing.T) { _, tsv, db := newTestTxExecutor(t) defer db.Close() defer tsv.StopService() - ctx := context.Background() target := querypb.Target{TabletType: topodatapb.TabletType_MASTER} _, err := tsv.PurgeMessages(ctx, &target, "nonmsg", 0) @@ -2145,9 +2016,8 @@ func TestPurgeMessages(t *testing.T) { _, err = tsv.PurgeMessages(ctx, &target, "msg", 0) want = "query: 'delete from msg where time_acked" - if err == nil || !strings.Contains(err.Error(), want) { - t.Errorf("tsv.PurgeMessages(invalid):\n%v, want\n%s", err, want) - } + require.Error(t, err) + assert.Contains(t, err.Error(), want) db.AddQuery("delete from msg where time_acked < 3 limit 500", &sqltypes.Result{RowsAffected: 1}) count, err := tsv.PurgeMessages(ctx, &target, "msg", 3) @@ -2158,7 +2028,6 @@ func TestPurgeMessages(t *testing.T) { } func TestHandleExecUnknownError(t *testing.T) { - ctx := context.Background() logStats := tabletenv.NewLogStats(ctx, "TestHandleExecError") config := tabletenv.NewDefaultConfig() tsv := NewTabletServer("TabletServerTest", config, memorytopo.NewServer(""), topodatapb.TabletAlias{}) @@ -2207,7 +2076,6 @@ func (tl *testLogger) getLog(i int) string { } func TestHandleExecTabletError(t *testing.T) { - ctx := context.Background() config := tabletenv.NewDefaultConfig() tsv := NewTabletServer("TabletServerTest", config, memorytopo.NewServer(""), topodatapb.TabletAlias{}) tl := newTestLogger() @@ -2219,11 +2087,9 @@ func TestHandleExecTabletError(t *testing.T) { vterrors.Errorf(vtrpcpb.Code_INTERNAL, "tablet error"), nil, ) - fmt.Println(">>>>>" + err.Error()) want := "tablet error" - if err == nil || !strings.Contains(err.Error(), want) { - t.Errorf("got `%v`, want '%s'", err, want) - } + require.Error(t, err) + assert.Contains(t, err.Error(), want) want = "Sql: \"select * from test_table\", BindVars: {}" if !strings.Contains(tl.getLog(0), want) { t.Errorf("error log %s, want '%s'", tl.getLog(0), want) @@ -2231,7 +2097,6 @@ func TestHandleExecTabletError(t *testing.T) { } func TestTerseErrorsNonSQLError(t *testing.T) { - ctx := context.Background() config := tabletenv.NewDefaultConfig() config.TerseErrors = true tsv := NewTabletServer("TabletServerTest", config, memorytopo.NewServer(""), topodatapb.TabletAlias{}) @@ -2245,9 +2110,8 @@ func TestTerseErrorsNonSQLError(t *testing.T) { nil, ) want := "tablet error" - if err == nil || !strings.Contains(err.Error(), want) { - t.Errorf("%v, want '%s'", err, want) - } + require.Error(t, err) + assert.Contains(t, err.Error(), want) want = "Sql: \"select * from test_table\", BindVars: {}" if !strings.Contains(tl.getLog(0), want) { t.Errorf("error log %s, want '%s'", tl.getLog(0), want) @@ -2255,7 +2119,6 @@ func TestTerseErrorsNonSQLError(t *testing.T) { } func TestTerseErrorsBindVars(t *testing.T) { - ctx := context.Background() config := tabletenv.NewDefaultConfig() config.TerseErrors = true tsv := NewTabletServer("TabletServerTest", config, memorytopo.NewServer(""), topodatapb.TabletAlias{}) @@ -2284,7 +2147,6 @@ func TestTerseErrorsBindVars(t *testing.T) { } func TestTerseErrorsNoBindVars(t *testing.T) { - ctx := context.Background() config := tabletenv.NewDefaultConfig() config.TerseErrors = true tsv := NewTabletServer("TabletServerTest", config, memorytopo.NewServer(""), topodatapb.TabletAlias{}) @@ -2292,9 +2154,8 @@ func TestTerseErrorsNoBindVars(t *testing.T) { defer tl.Close() err := tsv.convertAndLogError(ctx, "", nil, vterrors.Errorf(vtrpcpb.Code_DEADLINE_EXCEEDED, "sensitive message"), nil) want := "sensitive message" - if err == nil || !strings.Contains(err.Error(), want) { - t.Errorf("%v, want '%s'", err, want) - } + require.Error(t, err) + assert.Contains(t, err.Error(), want) want = "Sql: \"\", BindVars: {}" if !strings.Contains(tl.getLog(0), want) { t.Errorf("error log '%s', want '%s'", tl.getLog(0), want) @@ -2302,7 +2163,6 @@ func TestTerseErrorsNoBindVars(t *testing.T) { } func TestTruncateErrors(t *testing.T) { - ctx := context.Background() config := tabletenv.NewDefaultConfig() config.TerseErrors = true tsv := NewTabletServer("TabletServerTest", config, memorytopo.NewServer(""), topodatapb.TabletAlias{}) @@ -2352,7 +2212,6 @@ func TestTruncateErrors(t *testing.T) { } func TestTerseErrorsIgnoreFailoverInProgress(t *testing.T) { - ctx := context.Background() config := tabletenv.NewDefaultConfig() config.TerseErrors = true tsv := NewTabletServer("TabletServerTest", config, memorytopo.NewServer(""), topodatapb.TabletAlias{}) @@ -2368,9 +2227,7 @@ func TestTerseErrorsIgnoreFailoverInProgress(t *testing.T) { } // errors during failover aren't logged at all - if len(tl.logs) != 0 { - t.Errorf("unexpected error log during failover") - } + require.Empty(t, tl.logs, "unexpected error log during failover") } var aclJSON1 = `{ @@ -2400,17 +2257,13 @@ func TestACLHUP(t *testing.T) { tsv := NewTabletServer("TabletServerTest", config, memorytopo.NewServer(""), topodatapb.TabletAlias{}) f, err := ioutil.TempFile("", "tableacl") - if err != nil { - t.Fatal(err) - } + require.NoError(t, err) defer os.Remove(f.Name()) - if _, err := io.WriteString(f, aclJSON1); err != nil { - t.Fatal(err) - } - if err := f.Close(); err != nil { - t.Fatal(err) - } + _, err = io.WriteString(f, aclJSON1) + require.NoError(t, err) + err = f.Close() + require.NoError(t, err) tsv.InitACL(f.Name(), true, 0) @@ -2419,12 +2272,10 @@ func TestACLHUP(t *testing.T) { t.Fatalf("Expected name 'group01', got '%s'", name1) } - if f, err = os.Create(f.Name()); err != nil { - t.Fatal(err) - } - if _, err = io.WriteString(f, aclJSON2); err != nil { - t.Fatal(err) - } + f, err = os.Create(f.Name()) + require.NoError(t, err) + _, err = io.WriteString(f, aclJSON2) + require.NoError(t, err) syscall.Kill(syscall.Getpid(), syscall.SIGHUP) time.Sleep(100 * time.Millisecond) // wait for signal handler diff --git a/go/vt/vttablet/tabletserver/tx_engine.go b/go/vt/vttablet/tabletserver/tx_engine.go index c6580b199e0..48edebabc3f 100644 --- a/go/vt/vttablet/tabletserver/tx_engine.go +++ b/go/vt/vttablet/tabletserver/tx_engine.go @@ -229,19 +229,13 @@ func (te *TxEngine) Begin(ctx context.Context, options *querypb.ExecuteOptions) return 0, "", vterrors.Errorf(vtrpc.Code_UNAVAILABLE, "tx engine can't accept new transactions in state %v", te.state) } - isWriteTransaction := options == nil || options.TransactionIsolation != querypb.ExecuteOptions_CONSISTENT_SNAPSHOT_READ_ONLY - if te.state == AcceptingReadOnly && isWriteTransaction { - te.stateLock.Unlock() - return 0, "", vterrors.Errorf(vtrpc.Code_UNAVAILABLE, "tx engine can only accept read-only transactions in current state") - } - // By Add() to beginRequests, we block others from initiating state // changes until we have finished adding this transaction te.beginRequests.Add(1) te.stateLock.Unlock() defer te.beginRequests.Done() - conn, beginSQL, err := te.txPool.Begin(ctx, options) + conn, beginSQL, err := te.txPool.Begin(ctx, options, te.state == AcceptingReadOnly) if err != nil { return 0, "", err } @@ -438,7 +432,7 @@ outer: if txid > maxid { maxid = txid } - conn, _, err := te.txPool.Begin(ctx, &querypb.ExecuteOptions{}) + conn, _, err := te.txPool.Begin(ctx, &querypb.ExecuteOptions{}, false) if err != nil { allErr.RecordError(err) continue diff --git a/go/vt/vttablet/tabletserver/tx_engine_test.go b/go/vt/vttablet/tabletserver/tx_engine_test.go index 58d16cd81cb..5f237e83666 100644 --- a/go/vt/vttablet/tabletserver/tx_engine_test.go +++ b/go/vt/vttablet/tabletserver/tx_engine_test.go @@ -57,7 +57,7 @@ func TestTxEngineClose(t *testing.T) { // Normal close with timeout wait. te.open() - c, beginSQL, err := te.txPool.Begin(ctx, &querypb.ExecuteOptions{}) + c, beginSQL, err := te.txPool.Begin(ctx, &querypb.ExecuteOptions{}, false) require.NoError(t, err) require.Equal(t, "begin", beginSQL) c.Unlock() @@ -69,7 +69,7 @@ func TestTxEngineClose(t *testing.T) { // Immediate close. te.open() - c, _, err = te.txPool.Begin(ctx, &querypb.ExecuteOptions{}) + c, _, err = te.txPool.Begin(ctx, &querypb.ExecuteOptions{}, false) if err != nil { t.Fatal(err) } @@ -83,7 +83,7 @@ func TestTxEngineClose(t *testing.T) { // Normal close with short grace period. te.shutdownGracePeriod = 250 * time.Millisecond te.open() - c, _, err = te.txPool.Begin(ctx, &querypb.ExecuteOptions{}) + c, _, err = te.txPool.Begin(ctx, &querypb.ExecuteOptions{}, false) if err != nil { t.Fatal(err) } @@ -100,7 +100,7 @@ func TestTxEngineClose(t *testing.T) { // Normal close with short grace period, but pool gets empty early. te.shutdownGracePeriod = 250 * time.Millisecond te.open() - c, _, err = te.txPool.Begin(ctx, &querypb.ExecuteOptions{}) + c, _, err = te.txPool.Begin(ctx, &querypb.ExecuteOptions{}, false) if err != nil { t.Fatal(err) } @@ -122,7 +122,7 @@ func TestTxEngineClose(t *testing.T) { // Immediate close, but connection is in use. te.open() - c, _, err = te.txPool.Begin(ctx, &querypb.ExecuteOptions{}) + c, _, err = te.txPool.Begin(ctx, &querypb.ExecuteOptions{}, false) require.NoError(t, err) go func() { time.Sleep(100 * time.Millisecond) @@ -138,6 +138,30 @@ func TestTxEngineClose(t *testing.T) { } } +func TestTxEngineBegin(t *testing.T) { + db := setUpQueryExecutorTest(t) + defer db.Close() + db.AddQueryPattern(".*", &sqltypes.Result{}) + config := tabletenv.NewDefaultConfig() + config.DB = newDBConfigs(db) + te := NewTxEngine(tabletenv.NewEnv(config, "TabletServerTest")) + te.AcceptReadOnly() + tx1, _, err := te.Begin(ctx, &querypb.ExecuteOptions{}) + require.NoError(t, err) + _, err = te.Commit(ctx, tx1) + require.NoError(t, err) + require.Equal(t, "start transaction read only;commit", db.QueryLog()) + db.ResetQueryLog() + + te.AcceptReadWrite() + tx2, _, err := te.Begin(ctx, &querypb.ExecuteOptions{}) + require.NoError(t, err) + _, err = te.Commit(ctx, tx2) + require.NoError(t, err) + require.Equal(t, "begin;commit", db.QueryLog()) + +} + type TxType int const ( diff --git a/go/vt/vttablet/tabletserver/tx_executor.go b/go/vt/vttablet/tabletserver/tx_executor.go index 3eb067f0992..cb013952778 100644 --- a/go/vt/vttablet/tabletserver/tx_executor.go +++ b/go/vt/vttablet/tabletserver/tx_executor.go @@ -118,7 +118,7 @@ func (txe *TxExecutor) CommitPrepared(dtid string) error { func (txe *TxExecutor) markFailed(ctx context.Context, dtid string) { txe.te.env.Stats().InternalErrors.Add("TwopcCommit", 1) txe.te.preparedPool.SetFailed(dtid) - conn, _, err := txe.te.txPool.Begin(ctx, &querypb.ExecuteOptions{}) + conn, _, err := txe.te.txPool.Begin(ctx, &querypb.ExecuteOptions{}, false) if err != nil { log.Errorf("markFailed: Begin failed for dtid %s: %v", dtid, err) return @@ -261,7 +261,7 @@ func (txe *TxExecutor) ReadTwopcInflight() (distributed []*tx.DistributedTx, pre } func (txe *TxExecutor) inTransaction(f func(tx.IStatefulConnection) error) error { - conn, _, err := txe.te.txPool.Begin(txe.ctx, &querypb.ExecuteOptions{}) + conn, _, err := txe.te.txPool.Begin(txe.ctx, &querypb.ExecuteOptions{}, false) if err != nil { return err } diff --git a/go/vt/vttablet/tabletserver/tx_pool.go b/go/vt/vttablet/tabletserver/tx_pool.go index 27849d5da06..66b790f0205 100644 --- a/go/vt/vttablet/tabletserver/tx_pool.go +++ b/go/vt/vttablet/tabletserver/tx_pool.go @@ -208,18 +208,33 @@ func (tp *TxPool) Rollback(ctx context.Context, txConn tx.IStatefulConnection) e // the statements (if any) executed to initiate the transaction. In autocommit // mode the statement will be "". // The connection returned is locked for the callee and its responsibility is to unlock the connection. -func (tp *TxPool) Begin(ctx context.Context, options *querypb.ExecuteOptions) (tx.IStatefulConnection, string, error) { +func (tp *TxPool) Begin(ctx context.Context, options *querypb.ExecuteOptions, readOnly bool) (tx.IStatefulConnection, string, error) { span, ctx := trace.NewSpan(ctx, "TxPool.Begin") defer span.Finish() - beginQueries := "" immediateCaller := callerid.ImmediateCallerIDFromContext(ctx) effectiveCaller := callerid.EffectiveCallerIDFromContext(ctx) - if !tp.limiter.Get(immediateCaller, effectiveCaller) { return nil, "", vterrors.Errorf(vtrpcpb.Code_RESOURCE_EXHAUSTED, "per-user transaction pool connection limit exceeded") } + conn, err := tp.createConn(ctx, options) + if err != nil { + return nil, "", err + } + beginQueries, autocommit, err := createTransaction(ctx, options, conn, readOnly) + if err != nil { + conn.Close() + conn.Release(tx.ConnInitFail) + return nil, "", err + } + + conn.txProps = tp.NewTxProps(immediateCaller, effectiveCaller, autocommit) + + return conn, beginQueries, nil +} + +func (tp *TxPool) createConn(ctx context.Context, options *querypb.ExecuteOptions) (*StatefulConnection, error) { conn, err := tp.scp.NewConn(ctx, options) if err != nil { switch err { @@ -230,37 +245,39 @@ func (tp *TxPool) Begin(ctx context.Context, options *querypb.ExecuteOptions) (t tp.LogActive() err = vterrors.Errorf(vtrpcpb.Code_RESOURCE_EXHAUSTED, "transaction pool connection limit exceeded") } - return nil, "", err + return nil, err } - err = func() error { - autocommitTransaction := false - if queries, ok := txIsolations[options.GetTransactionIsolation()]; ok { - if queries.setIsolationLevel != "" { - txQuery := "set transaction isolation level " + queries.setIsolationLevel - if err := conn.execWithRetry(ctx, txQuery, 1, false); err != nil { - return vterrors.Wrap(err, txQuery) - } - beginQueries = queries.setIsolationLevel + "; " - } - if err := conn.execWithRetry(ctx, queries.openTransaction, 1, false); err != nil { - return vterrors.Wrap(err, queries.openTransaction) + return conn, nil +} + +func createTransaction(ctx context.Context, options *querypb.ExecuteOptions, conn *StatefulConnection, readOnly bool) (string, bool, error) { + beginQueries := "" + + autocommitTransaction := false + if queries, ok := txIsolations[options.GetTransactionIsolation()]; ok { + if queries.setIsolationLevel != "" { + txQuery := "set transaction isolation level " + queries.setIsolationLevel + if err := conn.execWithRetry(ctx, txQuery, 1, false); err != nil { + return "", false, vterrors.Wrap(err, txQuery) } - beginQueries = beginQueries + queries.openTransaction - } else if options.GetTransactionIsolation() == querypb.ExecuteOptions_AUTOCOMMIT { - autocommitTransaction = true - } else { - return vterrors.Errorf(vtrpcpb.Code_INTERNAL, "don't know how to open a transaction of this type: %v", options.GetTransactionIsolation()) + beginQueries = queries.setIsolationLevel + "; " } - conn.txProps = tp.NewTxProps(immediateCaller, effectiveCaller, autocommitTransaction) - return nil - }() - if err != nil { - conn.Close() - conn.Release(tx.ConnInitFail) - return nil, "", err + beginSQL := queries.openTransaction + if readOnly && + options.GetTransactionIsolation() != querypb.ExecuteOptions_CONSISTENT_SNAPSHOT_READ_ONLY { + beginSQL = "start transaction read only" + } + if err := conn.execWithRetry(ctx, beginSQL, 1, false); err != nil { + return "", false, vterrors.Wrap(err, beginSQL) + } + beginQueries = beginQueries + beginSQL + } else if options.GetTransactionIsolation() == querypb.ExecuteOptions_AUTOCOMMIT { + autocommitTransaction = true + } else { + return "", false, vterrors.Errorf(vtrpcpb.Code_INTERNAL, "don't know how to open a transaction of this type: %v", options.GetTransactionIsolation()) } - return conn, beginQueries, nil + return beginQueries, autocommitTransaction, nil } // LogActive causes all existing transactions to be logged when they complete. diff --git a/go/vt/vttablet/tabletserver/tx_pool_test.go b/go/vt/vttablet/tabletserver/tx_pool_test.go index 26e24eb6268..66f8b377430 100644 --- a/go/vt/vttablet/tabletserver/tx_pool_test.go +++ b/go/vt/vttablet/tabletserver/tx_pool_test.go @@ -45,7 +45,7 @@ func TestTxPoolExecuteCommit(t *testing.T) { sql := "select 'this is a query'" // begin a transaction and then return the connection - conn, _, err := txPool.Begin(ctx, &querypb.ExecuteOptions{}) + conn, _, err := txPool.Begin(ctx, &querypb.ExecuteOptions{}, false) require.NoError(t, err) id := conn.ID() @@ -77,7 +77,7 @@ func TestTxPoolExecuteRollback(t *testing.T) { db, txPool, closer := setup(t) defer closer() - conn, _, err := txPool.Begin(ctx, &querypb.ExecuteOptions{}) + conn, _, err := txPool.Begin(ctx, &querypb.ExecuteOptions{}, false) require.NoError(t, err) defer conn.Release(tx.TxRollback) @@ -95,7 +95,7 @@ func TestTxPoolExecuteRollbackOnClosedConn(t *testing.T) { db, txPool, closer := setup(t) defer closer() - conn, _, err := txPool.Begin(ctx, &querypb.ExecuteOptions{}) + conn, _, err := txPool.Begin(ctx, &querypb.ExecuteOptions{}, false) require.NoError(t, err) defer conn.Release(tx.TxRollback) @@ -113,9 +113,9 @@ func TestTxPoolRollbackNonBusy(t *testing.T) { defer closer() // start two transactions, and mark one of them as unused - conn1, _, err := txPool.Begin(ctx, &querypb.ExecuteOptions{}) + conn1, _, err := txPool.Begin(ctx, &querypb.ExecuteOptions{}, false) require.NoError(t, err) - conn2, _, err := txPool.Begin(ctx, &querypb.ExecuteOptions{}) + conn2, _, err := txPool.Begin(ctx, &querypb.ExecuteOptions{}, false) require.NoError(t, err) conn2.Unlock() // this marks conn2 as NonBusy @@ -138,7 +138,7 @@ func TestTxPoolTransactionIsolation(t *testing.T) { db, txPool, closer := setup(t) defer closer() - c2, _, err := txPool.Begin(ctx, &querypb.ExecuteOptions{TransactionIsolation: querypb.ExecuteOptions_READ_COMMITTED}) + c2, _, err := txPool.Begin(ctx, &querypb.ExecuteOptions{TransactionIsolation: querypb.ExecuteOptions_READ_COMMITTED}, false) require.NoError(t, err) c2.Release(tx.TxClose) @@ -153,7 +153,7 @@ func TestTxPoolAutocommit(t *testing.T) { // to mysql. // This test is meaningful because if txPool.Begin were to send a BEGIN statement to the connection, it will fatal // because is not in the list of expected queries (i.e db.AddQuery hasn't been called). - conn1, _, err := txPool.Begin(ctx, &querypb.ExecuteOptions{TransactionIsolation: querypb.ExecuteOptions_AUTOCOMMIT}) + conn1, _, err := txPool.Begin(ctx, &querypb.ExecuteOptions{TransactionIsolation: querypb.ExecuteOptions_AUTOCOMMIT}, false) require.NoError(t, err) // run a query to see it in the query log @@ -182,7 +182,7 @@ func TestTxPoolBeginWithPoolConnectionError_Errno2006_Transient(t *testing.T) { err := db.WaitForClose(2 * time.Second) require.NoError(t, err) - txConn, _, err := txPool.Begin(ctx, &querypb.ExecuteOptions{}) + txConn, _, err := txPool.Begin(ctx, &querypb.ExecuteOptions{}, false) require.NoError(t, err, "Begin should have succeeded after the retry in DBConn.Exec()") txConn.Release(tx.TxCommit) } @@ -201,7 +201,7 @@ func primeTxPoolWithConnection(t *testing.T) (*fakesqldb.DB, *TxPool) { // reused by subsequent transactions. db.AddQuery("begin", &sqltypes.Result{}) db.AddQuery("rollback", &sqltypes.Result{}) - txConn, _, err := txPool.Begin(ctx, &querypb.ExecuteOptions{}) + txConn, _, err := txPool.Begin(ctx, &querypb.ExecuteOptions{}, false) require.NoError(t, err) txConn.Release(tx.TxCommit) @@ -212,7 +212,7 @@ func TestTxPoolBeginWithError(t *testing.T) { db, txPool, closer := setup(t) defer closer() db.AddRejectedQuery("begin", errRejected) - _, _, err := txPool.Begin(ctx, &querypb.ExecuteOptions{}) + _, _, err := txPool.Begin(ctx, &querypb.ExecuteOptions{}, false) require.Error(t, err) require.Contains(t, err.Error(), "error: rejected") require.Equal(t, vtrpcpb.Code_UNKNOWN, vterrors.Code(err), "wrong error code for Begin error") @@ -226,7 +226,7 @@ func TestTxPoolCancelledContextError(t *testing.T) { cancel() // when - _, _, err := txPool.Begin(ctx, &querypb.ExecuteOptions{}) + _, _, err := txPool.Begin(ctx, &querypb.ExecuteOptions{}, false) // then require.Error(t, err) @@ -245,12 +245,12 @@ func TestTxPoolWaitTimeoutError(t *testing.T) { defer closer() // lock the only connection in the pool. - conn, _, err := txPool.Begin(ctx, &querypb.ExecuteOptions{}) + conn, _, err := txPool.Begin(ctx, &querypb.ExecuteOptions{}, false) require.NoError(t, err) defer conn.Unlock() // try locking one more connection. - _, _, err = txPool.Begin(ctx, &querypb.ExecuteOptions{}) + _, _, err = txPool.Begin(ctx, &querypb.ExecuteOptions{}, false) // then require.Error(t, err) @@ -266,7 +266,7 @@ func TestTxPoolRollbackFailIsPassedThrough(t *testing.T) { defer closer() db.AddRejectedQuery("rollback", errRejected) - conn1, _, err := txPool.Begin(ctx, &querypb.ExecuteOptions{}) + conn1, _, err := txPool.Begin(ctx, &querypb.ExecuteOptions{}, false) require.NoError(t, err) _, err = conn1.Exec(ctx, sql, 1, true) @@ -283,7 +283,7 @@ func TestTxPoolRollbackFailIsPassedThrough(t *testing.T) { func TestTxPoolGetConnRecentlyRemovedTransaction(t *testing.T) { db, txPool, _ := setup(t) defer db.Close() - conn1, _, _ := txPool.Begin(ctx, &querypb.ExecuteOptions{}) + conn1, _, _ := txPool.Begin(ctx, &querypb.ExecuteOptions{}, false) id := conn1.ID() conn1.Unlock() txPool.Close() @@ -305,7 +305,7 @@ func TestTxPoolGetConnRecentlyRemovedTransaction(t *testing.T) { txPool = newTxPool() txPool.Open(db.ConnParams(), db.ConnParams(), db.ConnParams()) - conn1, _, _ = txPool.Begin(ctx, &querypb.ExecuteOptions{}) + conn1, _, _ = txPool.Begin(ctx, &querypb.ExecuteOptions{}, false) id = conn1.ID() _, err := txPool.Commit(ctx, conn1) require.NoError(t, err) @@ -319,7 +319,7 @@ func TestTxPoolGetConnRecentlyRemovedTransaction(t *testing.T) { txPool.Open(db.ConnParams(), db.ConnParams(), db.ConnParams()) defer txPool.Close() - conn1, _, _ = txPool.Begin(ctx, &querypb.ExecuteOptions{}) + conn1, _, _ = txPool.Begin(ctx, &querypb.ExecuteOptions{}, false) conn1.Unlock() id = conn1.ID() time.Sleep(20 * time.Millisecond) @@ -334,7 +334,7 @@ func TestTxPoolCloseKillsStrayTransactions(t *testing.T) { startingStray := txPool.env.Stats().InternalErrors.Counts()["StrayTransactions"] // Start stray transaction. - conn, _, err := txPool.Begin(context.Background(), &querypb.ExecuteOptions{}) + conn, _, err := txPool.Begin(context.Background(), &querypb.ExecuteOptions{}, false) require.NoError(t, err) conn.Unlock() diff --git a/go/vt/worker/diff_utils.go b/go/vt/worker/diff_utils.go index b73785a037b..4084b598768 100644 --- a/go/vt/worker/diff_utils.go +++ b/go/vt/worker/diff_utils.go @@ -660,7 +660,7 @@ func createTransactions(ctx context.Context, numberOfScanners int, wr *wrangler. scanners := make([]int64, numberOfScanners) for i := 0; i < numberOfScanners; i++ { - tx, err := queryService.Begin(ctx, target, &query.ExecuteOptions{ + tx, _, err := queryService.Begin(ctx, target, &query.ExecuteOptions{ // Make sure our tx is not killed by tx sniper Workload: query.ExecuteOptions_DBA, TransactionIsolation: query.ExecuteOptions_CONSISTENT_SNAPSHOT_READ_ONLY, diff --git a/proto/query.proto b/proto/query.proto index ff4bf43b265..2f67758154c 100644 --- a/proto/query.proto +++ b/proto/query.proto @@ -464,6 +464,7 @@ message BeginRequest { // BeginResponse is the returned value from Begin message BeginResponse { int64 transaction_id = 1; + topodata.TabletAlias tablet_alias = 2; } // CommitRequest is the payload to Commit @@ -603,6 +604,7 @@ message BeginExecuteResponse { // transaction_id might be non-zero even if an error is present. int64 transaction_id = 3; + topodata.TabletAlias tablet_alias = 4; } // BeginExecuteBatchRequest is the payload to BeginExecuteBatch @@ -626,6 +628,7 @@ message BeginExecuteBatchResponse { // transaction_id might be non-zero even if an error is present. int64 transaction_id = 3; + topodata.TabletAlias tablet_alias = 4; } // MessageStreamRequest is the request payload for MessageStream. diff --git a/proto/vstreamer.proto b/proto/vstreamer.proto deleted file mode 100644 index d713f890ad2..00000000000 --- a/proto/vstreamer.proto +++ /dev/null @@ -1,17 +0,0 @@ -/* -Copyright 2020 The Vitess Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -// This file contains the proto types needed for vstreamer serializing \ No newline at end of file diff --git a/proto/vtgate.proto b/proto/vtgate.proto index d71de7595f1..32576b5741a 100644 --- a/proto/vtgate.proto +++ b/proto/vtgate.proto @@ -72,6 +72,7 @@ message Session { message ShardSession { query.Target target = 1; int64 transaction_id = 2; + topodata.TabletAlias tablet_alias = 3; } // shard_sessions keep track of per-shard transaction info. repeated ShardSession shard_sessions = 2; diff --git a/test/config.json b/test/config.json index 67fad2afdce..f5fd2f50a56 100644 --- a/test/config.json +++ b/test/config.json @@ -342,9 +342,9 @@ "RetryMax": 0, "Tags": [] }, - "tabletgateway_healthcheck": { + "tabletgateway": { "File": "unused.go", - "Args": ["vitess.io/vitess/go/test/endtoend/tabletgateway/healthcheck"], + "Args": ["vitess.io/vitess/go/test/endtoend/tabletgateway"], "Command": [], "Manual": false, "Shard": 14,