Skip to content

Commit a279637

Browse files
committed
wip: set destination in the right places
Signed-off-by: Nick Van Wiggeren <[email protected]>
1 parent 8ab64dc commit a279637

File tree

6 files changed

+43
-33
lines changed

6 files changed

+43
-33
lines changed

go/test/endtoend/vtgate/misc_test.go

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -835,8 +835,8 @@ func TestDDLTargeted(t *testing.T) {
835835
utils.AssertMatches(t, conn, `select id from ddl_targeted`, `[[INT64(1)]]`)
836836
}
837837

838-
// TestTabletTargeting tests tablet-specific routing with USE keyspace@tablet-alias syntax.
839-
// In a sharded keyspace, this validates that tablet-specific routing overrides normal hash-based routing.
838+
// TestTabletTargeting tests tablet-specific routing with USE keyspace:shard@tablet-alias syntax.
839+
// When shard is specified, tablet-specific routing bypasses vindex-based shard resolution.
840840
func TestTabletTargeting(t *testing.T) {
841841
ctx := context.Background()
842842
conn, err := mysql.Connect(ctx, &vtParams)
@@ -865,41 +865,46 @@ func TestTabletTargeting(t *testing.T) {
865865
require.NotEmpty(t, primaryShard80Minus, "no PRIMARY tablet found for -80 shard")
866866
require.NotEmpty(t, primaryShard80Plus, "no PRIMARY tablet found for 80- shard")
867867

868-
// Test: Target the -80 shard's PRIMARY and insert rows that normally hash to -80
869-
// id1=1 and id1=2 both hash to -80 shard based on the hash vindex
870-
utils.Exec(t, conn, fmt.Sprintf("USE ks@%s", primaryShard80Minus))
868+
// Test: Target a specific tablet in -80 shard and insert rows
869+
// id1=1 and id1=2 both hash to -80 shard - this validates normal behavior
870+
utils.Exec(t, conn, fmt.Sprintf("USE ks:-80@%s", primaryShard80Minus))
871871
utils.Exec(t, conn, "insert into t1(id1, id2) values(1, 100), (2, 200)")
872872
utils.AssertMatches(t, conn, "select id1 from t1 where id1 in (1, 2) order by id1", "[[INT64(1)] [INT64(2)]]")
873873

874-
// Test: Verify the other shard (80-) did not receive these writes
875-
utils.Exec(t, conn, fmt.Sprintf("USE ks@%s", primaryShard80Plus))
876-
utils.AssertIsEmpty(t, conn, "select id1 from t1 where id1 in (1, 2)")
874+
// Test: Insert data that would normally hash to 80- shard, but goes to -80 because of shard targeting
875+
// id1=4 hashes to 80-, but we're targeting -80 shard explicitly
876+
utils.Exec(t, conn, fmt.Sprintf("USE ks:-80@%s", primaryShard80Minus))
877+
utils.Exec(t, conn, "insert into t1(id1, id2) values(4, 400)")
878+
879+
// Verify the data went to -80 shard (not where vindex would have put it)
880+
utils.Exec(t, conn, "USE ks:-80")
881+
utils.AssertMatches(t, conn, "select id1 from t1 where id1=4", "[[INT64(4)]]")
882+
883+
// Verify the data did NOT go to 80- shard (where vindex says it should be)
884+
utils.Exec(t, conn, "USE ks:80-")
885+
utils.AssertIsEmpty(t, conn, "select id1 from t1 where id1=4")
877886

878887
// Test: Transaction with tablet-specific routing
879-
utils.Exec(t, conn, fmt.Sprintf("USE ks@%s", primaryShard80Minus))
888+
utils.Exec(t, conn, fmt.Sprintf("USE ks:-80@%s", primaryShard80Minus))
880889
utils.Exec(t, conn, "begin")
881890
utils.Exec(t, conn, "insert into t1(id1, id2) values(10, 300)")
882891
utils.Exec(t, conn, "commit")
883892
utils.AssertMatches(t, conn, "select id1 from t1 where id1=10", "[[INT64(10)]]")
884893

885-
// Test: Verify the other shard still has no data for our test rows
886-
utils.Exec(t, conn, fmt.Sprintf("USE ks@%s", primaryShard80Plus))
887-
utils.AssertIsEmpty(t, conn, "select id1 from t1 where id1 in (1, 2, 10)")
888-
889894
// Test: Rollback with tablet-specific routing
890-
utils.Exec(t, conn, fmt.Sprintf("USE ks@%s", primaryShard80Minus))
895+
utils.Exec(t, conn, fmt.Sprintf("USE ks:-80@%s", primaryShard80Minus))
891896
utils.Exec(t, conn, "begin")
892-
utils.Exec(t, conn, "insert into t1(id1, id2) values(20, 400)")
897+
utils.Exec(t, conn, "insert into t1(id1, id2) values(20, 500)")
893898
utils.Exec(t, conn, "rollback")
894899
// 20 should not exist
895900
utils.AssertIsEmpty(t, conn, "select id1 from t1 where id1=20")
896901

897902
// Test: Clear tablet targeting returns to normal routing
898903
utils.Exec(t, conn, "USE ks")
899-
utils.AssertMatches(t, conn, "select id1 from t1 where id1 in (1, 2, 10) order by id1", "[[INT64(1)] [INT64(2)] [INT64(10)]]")
904+
utils.AssertMatches(t, conn, "select id1 from t1 where id1 in (1, 2, 4, 10) order by id1", "[[INT64(1)] [INT64(2)] [INT64(4)] [INT64(10)]]")
900905

901906
// Cleanup
902-
utils.Exec(t, conn, "delete from t1 where id1 in (1, 2, 10)")
907+
utils.Exec(t, conn, "delete from t1 where id1 in (1, 2, 4, 10)")
903908
}
904909

905910
// TestDynamicConfig tests the dynamic configurations.

go/vt/vtgate/executor.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1104,7 +1104,7 @@ func (e *Executor) SaveVSchema(vschema *vindexes.VSchema, stats *VSchemaStats) {
11041104
}
11051105

11061106
// ParseDestinationTarget parses destination target string and sets default keyspace if possible.
1107-
func (e *Executor) ParseDestinationTarget(targetString string) (string, topodatapb.TabletType, key.ShardDestination, error) {
1107+
func (e *Executor) ParseDestinationTarget(targetString string) (string, topodatapb.TabletType, key.ShardDestination, *topodatapb.TabletAlias, error) {
11081108
return econtext.ParseDestinationTarget(targetString, defaultTabletType, e.VSchema())
11091109
}
11101110

go/vt/vtgate/executor_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1923,7 +1923,7 @@ func TestParseEmptyTargetSingleKeyspace(t *testing.T) {
19231923
}
19241924
r.vschema = altVSchema
19251925

1926-
destKeyspace, destTabletType, _, _ := r.ParseDestinationTarget("")
1926+
destKeyspace, destTabletType, _, _, _ := r.ParseDestinationTarget("")
19271927
if destKeyspace != KsTestUnsharded || destTabletType != topodatapb.TabletType_PRIMARY {
19281928
t.Errorf(
19291929
"parseDestinationTarget(%s): got (%v, %v), want (%v, %v)",
@@ -1947,7 +1947,7 @@ func TestParseEmptyTargetMultiKeyspace(t *testing.T) {
19471947
}
19481948
r.vschema = altVSchema
19491949

1950-
destKeyspace, destTabletType, _, _ := r.ParseDestinationTarget("")
1950+
destKeyspace, destTabletType, _, _, _ := r.ParseDestinationTarget("")
19511951
if destKeyspace != "" || destTabletType != topodatapb.TabletType_PRIMARY {
19521952
t.Errorf(
19531953
"parseDestinationTarget(%s): got (%v, %v), want (%v, %v)",
@@ -1970,7 +1970,7 @@ func TestParseTargetSingleKeyspace(t *testing.T) {
19701970
}
19711971
r.vschema = altVSchema
19721972

1973-
destKeyspace, destTabletType, _, _ := r.ParseDestinationTarget("@replica")
1973+
destKeyspace, destTabletType, _, _, _ := r.ParseDestinationTarget("@replica")
19741974
if destKeyspace != KsTestUnsharded || destTabletType != topodatapb.TabletType_REPLICA {
19751975
t.Errorf(
19761976
"parseDestinationTarget(%s): got (%v, %v), want (%v, %v)",

go/vt/vtgate/executorcontext/vcursor_impl.go

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -208,11 +208,15 @@ func NewVCursorImpl(
208208
cfg VCursorConfig,
209209
metrics Metrics,
210210
) (*VCursorImpl, error) {
211-
keyspace, tabletType, destination, err := ParseDestinationTarget(safeSession.TargetString, cfg.DefaultTabletType, vschema)
211+
keyspace, tabletType, destination, tabletAlias, err := ParseDestinationTarget(safeSession.TargetString, cfg.DefaultTabletType, vschema)
212212
if err != nil {
213213
return nil, err
214214
}
215215

216+
// Store tablet alias from target string into session
217+
// This ensures tablet-specific routing persists across queries
218+
safeSession.SetTargetTabletAlias(tabletAlias)
219+
216220
var ts *topo.Server
217221
// We don't have access to the underlying TopoServer if this vtgate is
218222
// filtering keyspaces because we don't have an accurate view of the topo.
@@ -533,20 +537,20 @@ func (vc *VCursorImpl) FindViewTarget(name sqlparser.TableName) (*vindexes.Keysp
533537
}
534538

535539
func (vc *VCursorImpl) parseDestinationTarget(targetString string) (string, topodatapb.TabletType, key.ShardDestination, error) {
536-
return ParseDestinationTarget(targetString, vc.tabletType, vc.vschema)
540+
keyspace, tabletType, dest, _, err := ParseDestinationTarget(targetString, vc.tabletType, vc.vschema)
541+
return keyspace, tabletType, dest, err
537542
}
538543

539544
// ParseDestinationTarget parses destination target string and provides a keyspace if possible.
540-
func ParseDestinationTarget(targetString string, tablet topodatapb.TabletType, vschema *vindexes.VSchema) (string, topodatapb.TabletType, key.ShardDestination, error) {
541-
destKeyspace, destTabletType, dest, _, err := topoprotopb.ParseDestination(targetString, tablet)
542-
// Note: We ignore the tablet alias here as it's handled separately in SetTarget
545+
func ParseDestinationTarget(targetString string, tablet topodatapb.TabletType, vschema *vindexes.VSchema) (string, topodatapb.TabletType, key.ShardDestination, *topodatapb.TabletAlias, error) {
546+
destKeyspace, destTabletType, dest, tabletAlias, err := topoprotopb.ParseDestination(targetString, tablet)
543547
// If the keyspace is not specified, and there is only one keyspace in the VSchema, use that.
544548
if destKeyspace == "" && len(vschema.Keyspaces) == 1 {
545549
for k := range vschema.Keyspaces {
546550
destKeyspace = k
547551
}
548552
}
549-
return destKeyspace, destTabletType, dest, err
553+
return destKeyspace, destTabletType, dest, tabletAlias, err
550554
}
551555

552556
func (vc *VCursorImpl) getDualTable() (*vindexes.BaseTable, vindexes.Vindex, string, topodatapb.TabletType, key.ShardDestination, error) {
@@ -1025,7 +1029,7 @@ func (vc *VCursorImpl) Session() engine.SessionActions {
10251029
}
10261030

10271031
func (vc *VCursorImpl) SetTarget(target string) error {
1028-
keyspace, tabletType, _, tabletAlias, err := topoprotopb.ParseDestination(target, vc.config.DefaultTabletType)
1032+
keyspace, tabletType, destination, tabletAlias, err := topoprotopb.ParseDestination(target, vc.config.DefaultTabletType)
10291033
if err != nil {
10301034
return err
10311035
}
@@ -1052,6 +1056,7 @@ func (vc *VCursorImpl) SetTarget(target string) error {
10521056
}
10531057
vc.SafeSession.SetTargetString(target)
10541058
vc.keyspace = keyspace
1059+
vc.destination = destination
10551060
vc.tabletType = tabletType
10561061
return nil
10571062
}

go/vt/vtgate/executorcontext/vcursor_impl_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,7 @@ func (f fakeExecutor) SetVitessMetadata(ctx context.Context, name, value string)
393393
panic("implement me")
394394
}
395395

396-
func (f fakeExecutor) ParseDestinationTarget(targetString string) (string, topodatapb.TabletType, key.ShardDestination, error) {
396+
func (f fakeExecutor) ParseDestinationTarget(targetString string) (string, topodatapb.TabletType, key.ShardDestination, *topodatapb.TabletAlias, error) {
397397
// TODO implement me
398398
panic("implement me")
399399
}

go/vt/vtgate/vtgate.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -558,7 +558,7 @@ func (vtg *VTGate) Execute(
558558
prepared bool,
559559
) (newSession *vtgatepb.Session, qr *sqltypes.Result, err error) {
560560
// In this context, we don't care if we can't fully parse destination
561-
destKeyspace, destTabletType, _, _ := vtg.executor.ParseDestinationTarget(session.TargetString)
561+
destKeyspace, destTabletType, _, _, _ := vtg.executor.ParseDestinationTarget(session.TargetString)
562562
statsKey := []string{"Execute", destKeyspace, topoproto.TabletTypeLString(destTabletType)}
563563
defer vtg.timings.Record(statsKey, time.Now())
564564

@@ -620,7 +620,7 @@ func (vtg *VTGate) ExecuteMulti(
620620
// ExecuteBatch executes a batch of queries.
621621
func (vtg *VTGate) ExecuteBatch(ctx context.Context, session *vtgatepb.Session, sqlList []string, bindVariablesList []map[string]*querypb.BindVariable) (*vtgatepb.Session, []sqltypes.QueryResponse, error) {
622622
// In this context, we don't care if we can't fully parse destination
623-
destKeyspace, destTabletType, _, _ := vtg.executor.ParseDestinationTarget(session.TargetString)
623+
destKeyspace, destTabletType, _, _, _ := vtg.executor.ParseDestinationTarget(session.TargetString)
624624
statsKey := []string{"ExecuteBatch", destKeyspace, topoproto.TabletTypeLString(destTabletType)}
625625
defer vtg.timings.Record(statsKey, time.Now())
626626

@@ -649,7 +649,7 @@ func (vtg *VTGate) ExecuteBatch(ctx context.Context, session *vtgatepb.Session,
649649
// Note we guarantee the callback will not be called concurrently by multiple go routines.
650650
func (vtg *VTGate) StreamExecute(ctx context.Context, mysqlCtx vtgateservice.MySQLConnection, session *vtgatepb.Session, sql string, bindVariables map[string]*querypb.BindVariable, callback func(*sqltypes.Result) error) (*vtgatepb.Session, error) {
651651
// In this context, we don't care if we can't fully parse destination
652-
destKeyspace, destTabletType, _, _ := vtg.executor.ParseDestinationTarget(session.TargetString)
652+
destKeyspace, destTabletType, _, _, _ := vtg.executor.ParseDestinationTarget(session.TargetString)
653653
statsKey := []string{"StreamExecute", destKeyspace, topoproto.TabletTypeLString(destTabletType)}
654654

655655
defer vtg.timings.Record(statsKey, time.Now())
@@ -735,7 +735,7 @@ func (vtg *VTGate) CloseSession(ctx context.Context, session *vtgatepb.Session)
735735
// Prepare supports non-streaming prepare statement query with multi shards
736736
func (vtg *VTGate) Prepare(ctx context.Context, session *vtgatepb.Session, sql string) (newSession *vtgatepb.Session, fld []*querypb.Field, paramsCount uint16, err error) {
737737
// In this context, we don't care if we can't fully parse destination
738-
destKeyspace, destTabletType, _, _ := vtg.executor.ParseDestinationTarget(session.TargetString)
738+
destKeyspace, destTabletType, _, _, _ := vtg.executor.ParseDestinationTarget(session.TargetString)
739739
statsKey := []string{"Prepare", destKeyspace, topoproto.TabletTypeLString(destTabletType)}
740740
defer vtg.timings.Record(statsKey, time.Now())
741741

0 commit comments

Comments
 (0)