Skip to content

Commit

Permalink
Support creating missing sequence backing tables during init
Browse files Browse the repository at this point in the history
Signed-off-by: Matt Lord <mattalord@gmail.com>
  • Loading branch information
mattlord committed Sep 30, 2024
1 parent f5eb4e2 commit b110120
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 8 deletions.
2 changes: 1 addition & 1 deletion go/cmd/vtctldclient/command/vreplication/common/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ func AddCommonSwitchTrafficFlags(cmd *cobra.Command, initializeTargetSequences b
cmd.Flags().BoolVar(&SwitchTrafficOptions.DryRun, "dry-run", false, "Print the actions that would be taken and report any known errors that would have occurred.")
cmd.Flags().BoolVar(&SwitchTrafficOptions.Force, "force", false, "Force the traffic switch even if some potentially non-critical actions cannot be performed; for example the tablet refresh fails on some tablets in the keyspace. WARNING: this should be used with extreme caution and only in emergency situations!")
if initializeTargetSequences {
cmd.Flags().BoolVar(&SwitchTrafficOptions.InitializeTargetSequences, "initialize-target-sequences", false, "When moving tables from an unsharded keyspace to a sharded keyspace, initialize any sequences that are being used on the target when switching writes. If the sequence table is not found AND a value was specified for --global-keyspace, then we will attempt to create the sequence tables in that keyspace if they are not found elsewhere.")
cmd.Flags().BoolVar(&SwitchTrafficOptions.InitializeTargetSequences, "initialize-target-sequences", false, "When moving tables from an unsharded keyspace to a sharded keyspace, initialize any sequences that are being used on the target when switching writes. If the sequence table is not found AND the sequence table reference was fully qualified OR a value was specified for --global-keyspace, then we will attempt to create each sequence table in that keyspace if it doesn't exist.")
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ var (
}
createOptions.WorkflowOptions.StripShardedAutoIncrement = vtctldatapb.ShardedAutoIncrementHandling(val)
if val == int32(vtctldatapb.ShardedAutoIncrementHandling_REPLACE) && createOptions.WorkflowOptions.GlobalKeyspace == "" {
fmt.Println("WARNING: no global-keyspace value provided so all sequence tables must be created manually before switching traffic")
fmt.Println("WARNING: no global-keyspace value provided so all sequence table references not fully qualified must be created manually before switching traffic")
}

return nil
Expand Down
35 changes: 29 additions & 6 deletions go/vt/vtctl/workflow/traffic_switcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"golang.org/x/sync/errgroup"

"vitess.io/vitess/go/json2"
"vitess.io/vitess/go/mysql/sqlerror"
"vitess.io/vitess/go/sqlescape"
"vitess.io/vitess/go/sqltypes"
"vitess.io/vitess/go/vt/binlog/binlogplayer"
Expand Down Expand Up @@ -76,9 +77,10 @@ const (
// Use pt-osc's naming convention, this format also ensures vstreamer ignores such tables.
renameTableTemplate = "_%.59s_old" // limit table name to 64 characters

sqlDeleteWorkflow = "delete from _vt.vreplication where db_name = %s and workflow = %s"
sqlGetMaxSequenceVal = "select max(%a) as maxval from %a.%a"
sqlInitSequenceTable = "insert into %a.%a (id, next_id, cache) values (0, %d, 1000) on duplicate key update next_id = if(next_id < %d, %d, next_id)"
sqlDeleteWorkflow = "delete from _vt.vreplication where db_name = %s and workflow = %s"
sqlGetMaxSequenceVal = "select max(%a) as maxval from %a.%a"
sqlInitSequenceTable = "insert into %a.%a (id, next_id, cache) values (0, %d, 1000) on duplicate key update next_id = if(next_id < %d, %d, next_id)"
sqlCreateSequenceTable = "create table if not exists %a (id int, next_id bigint, cache bigint, primary key(id)) comment 'vitess_sequence'"
)

// accessType specifies the type of access for a shard (allow/disallow writes).
Expand Down Expand Up @@ -1525,8 +1527,10 @@ func (ts *trafficSwitcher) getTargetSequenceMetadata(ctx context.Context) (map[s
if err != nil {
return nil, err
}
stmt := fmt.Sprintf("create table if not exists %s (id int, next_id bigint, cache bigint, primary key(id)) comment 'vitess_sequence'",
tableName)
stmt, err := sqlparser.ParseAndBind(sqlCreateSequenceTable, sqltypes.StringBindVariable(sqlescape.EscapeID(tableName)))
if err != nil {
return nil, err
}
_, err = ts.ws.tmc.ApplySchema(ctx, primary.Tablet, &tmutils.SchemaChange{
SQL: stmt,
Force: false,
Expand Down Expand Up @@ -1770,13 +1774,32 @@ func (ts *trafficSwitcher) initializeTargetSequences(ctx context.Context, sequen
)
// Now execute this on the primary tablet of the unsharded keyspace
// housing the backing table.
initialize:
qr, ierr := ts.ws.tmc.ExecuteFetchAsApp(ictx, sequenceTablet.Tablet, true, &tabletmanagerdatapb.ExecuteFetchAsAppRequest{
Query: []byte(query.Query),
MaxRows: 1,
})
if ierr != nil {
return vterrors.Errorf(vtrpcpb.Code_INTERNAL, "failed to initialize the backing sequence table %s.%s: %v",
vterr := vterrors.Errorf(vtrpcpb.Code_INTERNAL, "failed to initialize the backing sequence table %s.%s: %v",
sequenceMetadata.backingTableDBName, sequenceMetadata.backingTableName, ierr)
// If the sequence table doesn't exist, let's try and create it, otherwise
// return the error.
if sqlErr, ok := sqlerror.NewSQLErrorFromError(ierr).(*sqlerror.SQLError); !ok ||
(sqlErr.Num != sqlerror.ERNoSuchTable && sqlErr.Num != sqlerror.ERBadTable) {
return vterr
}
stmt := sqlparser.BuildParsedQuery(sqlCreateSequenceTable, backingTable)
_, ierr = ts.ws.tmc.ApplySchema(ctx, sequenceTablet.Tablet, &tmutils.SchemaChange{
SQL: stmt.Query,
Force: false,
AllowReplication: true,
SQLMode: vreplication.SQLMode,
DisableForeignKeyChecks: true,
})
if ierr != nil {
return vterrors.Wrapf(vterr, "could not create missing sequence table: %v", err)
}
goto initialize
}
// If we actually updated the backing sequence table, then we need
// to tell the primary tablet managing the sequence to refresh/reset
Expand Down

0 comments on commit b110120

Please sign in to comment.