Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Experimental: Add missing tables to globally routed list in schema tracker only if they are not already present in a VSchema #17371

Draft
wants to merge 8 commits into
base: main
Choose a base branch
from
37 changes: 37 additions & 0 deletions go/test/endtoend/vtgate/gen4/gen4_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -520,3 +520,40 @@ func TestDualJoinQueries(t *testing.T) {
mcmp.Exec("select t.title, t2.id from t2 left join (select 'ABC' as title) as t on t.title = t2.tcol1")

}

// TestSchemaTrackingGlobalTables tests that schema tracking works as intended with global table routing.
// This test creates a new table in a schema and verifies we can query it without needing to add it to the vschema as long
// as the name of the table is unique. It also creates a table which is already in the vschema to ensure that we
// don't mark it as ambiguous when schema tracking also finds it.
func TestSchemaTrackingGlobalTables(t *testing.T) {
// Create a new vtgate connection.
tables := []string{"uniqueTableName", "t1"}
for _, table := range tables {
t.Run(table, func(t *testing.T) {
vtConn, err := mysql.Connect(context.Background(), &vtParams)
require.NoError(t, err)
defer vtConn.Close()

// Create a new table in the unsharded keyspace such that it has a unique name that allows for global routing.
utils.Exec(t, vtConn, `use `+unshardedKs)
// Use the same schema as t1 from sharded_schema.sql
utils.Exec(t, vtConn, fmt.Sprintf(`create table if not exists %s(id bigint, col bigint, primary key(id))`, table))
defer utils.Exec(t, vtConn, fmt.Sprintf(`drop table %s`, table))

// Wait for schema tracking to see this column.
err = utils.WaitForAuthoritative(t, unshardedKs, table, clusterInstance.VtgateProcess.ReadVSchema)
require.NoError(t, err)

// Create a new vtgate connection.
vtConn2, err := mysql.Connect(context.Background(), &vtParams)
require.NoError(t, err)
defer vtConn2.Close()

// Insert rows into the table and select them to verify we can use them.
utils.Exec(t, vtConn2, fmt.Sprintf(`insert into %s(id, col) values (10, 100),(20, 200)`, table))
require.NoError(t, err)
utils.AssertMatches(t, vtConn2, fmt.Sprintf(`select * from %s order by id`, table),
`[[INT64(10) INT64(100)] [INT64(20) INT64(200)]]`)
})
}
}
12 changes: 8 additions & 4 deletions go/vt/vtgate/vindexes/vschema.go
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ func BuildVSchema(source *vschemapb.SrvVSchema, parser *sqlparser.Parser) (vsche
buildKeyspaces(source, vschema, parser)
// buildGlobalTables before buildReferences so that buildReferences can
// resolve sources which reference global tables.
buildGlobalTables(source, vschema)
BuildGlobalTables(source, vschema, false)
buildReferences(source, vschema)
buildRoutingRule(source, vschema, parser)
buildShardRoutingRule(source, vschema)
Expand Down Expand Up @@ -461,23 +461,27 @@ func (vschema *VSchema) AddUDF(ksname, udfName string) error {
return nil
}

func buildGlobalTables(source *vschemapb.SrvVSchema, vschema *VSchema) {
func BuildGlobalTables(source *vschemapb.SrvVSchema, vschema *VSchema, skipIfAlreadyGlobal bool) {
for ksname, ks := range source.Keyspaces {
ksvschema := vschema.Keyspaces[ksname]
// If the keyspace requires explicit routing, don't include any of
// its tables in global tables.
if ks.RequireExplicitRouting {
continue
}
buildKeyspaceGlobalTables(vschema, ksvschema)
buildKeyspaceGlobalTables(vschema, ksvschema, skipIfAlreadyGlobal)
}
}

func buildKeyspaceGlobalTables(vschema *VSchema, ksvschema *KeyspaceSchema) {
func buildKeyspaceGlobalTables(vschema *VSchema, ksvschema *KeyspaceSchema, skipIfAlreadyGlobal bool) {
for tname, t := range ksvschema.Tables {
if gt, ok := vschema.globalTables[tname]; ok {
// There is already an entry table stored in global tables
// with this name.
if !skipIfAlreadyGlobal {
// Called when updating from schema tracking
continue
}
rohit-nayak-ps marked this conversation as resolved.
Show resolved Hide resolved
if gt == nil {
// Table name is already marked ambiguous, nothing to do.
continue
Expand Down
4 changes: 4 additions & 0 deletions go/vt/vtgate/vschema_manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,10 @@ func (vm *VSchemaManager) buildAndEnhanceVSchema(v *vschemapb.SrvVSchema) *vinde
// We mark the keyspaces that have foreign key management in Vitess and have cyclic foreign keys
// to have an error. This makes all queries against them to fail.
markErrorIfCyclesInFk(vschema)
// Add tables from schema tracking into globally routable tables, if they are not already present.
// We need to skip if already present, to handle the case where MoveTables has switched traffic
// and removed the source vschema but not from the source database because user asked to --keep-data
vindexes.BuildGlobalTables(v, vschema, true)
}
return vschema
}
Expand Down
Loading