Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
5458bcd
mysqlctl: add MySQL CLONE support infrastructure
nickvanw Dec 19, 2025
0fe8efd
add flags to tests + fix errors from linters
nickvanw Dec 19, 2025
8941459
fix up more tests
nickvanw Dec 19, 2025
94624dc
go/vt/mysqlctl: add CloneFromDonor
maxenglander Dec 20, 2025
0342d74
actually validate the source and destination, and poll for the copy t…
nickvanw Dec 20, 2025
95dccd1
TestCloneFromDonor: add a few cases
maxenglander Dec 20, 2025
ba66344
merge <- clone-infrastructure
maxenglander Dec 20, 2025
e66d1ee
more tests
maxenglander Dec 20, 2025
0d57e26
make it nicer
maxenglander Dec 20, 2025
06a370b
make tests nicer
maxenglander Dec 20, 2025
88340e5
slight reorg add comments
maxenglander Dec 20, 2025
01fabc0
fix imports
maxenglander Dec 20, 2025
ca83a7a
fix lint
maxenglander Dec 20, 2025
2cdb9c4
one more lint
maxenglander Dec 23, 2025
66e4998
tidy
maxenglander Dec 23, 2025
8633eaf
add an end to end test and do some cleanup
nickvanw Dec 23, 2025
13ace33
use time tickers in the for loop
nickvanw Dec 23, 2025
43a534f
tmrpctest: fix flaky TestGRPCTMServer timeout test
nickvanw Dec 23, 2025
0599231
Merge branch 'clone-infrastructure' into clone-from-donor
maxenglander Dec 24, 2025
dbe89f7
fix test
maxenglander Dec 25, 2025
e7e2559
go/vt/{mysqlctl,vttablet}: support restore tablet with CLONE
maxenglander Dec 25, 2025
d4f5da8
rm redundant clone capability check
maxenglander Dec 26, 2025
48d3940
fix bug, tests
maxenglander Dec 26, 2025
b44ad0f
rm redundant clone sql init
maxenglander Dec 26, 2025
d40490b
Merge branch 'clone-infrastructure' into clone-from-donor
maxenglander Dec 26, 2025
425c440
Merge branch 'clone-from-donor' into clone-restore-init
maxenglander Dec 26, 2025
a50414a
fix imports
maxenglander Dec 26, 2025
dbbf495
fix tests
maxenglander Dec 26, 2025
cf1a804
fix tests
maxenglander Dec 26, 2025
3c58666
go/cmd/vtbackup: add `--restore-from-clone` support to `vtbackup` (#1…
maxenglander Jan 14, 2026
327b31a
merge <- main
maxenglander Jan 14, 2026
05bb719
update flags
maxenglander Jan 14, 2026
3f157ae
tidy
maxenglander Jan 14, 2026
4d539b7
flags
maxenglander Jan 14, 2026
fc6b8e7
address cr feedback
maxenglander Jan 17, 2026
4f94b9e
cr: use logger var
maxenglander Jan 17, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 46 additions & 36 deletions go/cmd/vtbackup/cli/vtbackup.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ import (

tabletmanagerdatapb "vitess.io/vitess/go/vt/proto/tabletmanagerdata"
topodatapb "vitess.io/vitess/go/vt/proto/topodata"
"vitess.io/vitess/go/vt/proto/vtrpc"
)

const (
Expand Down Expand Up @@ -93,6 +94,7 @@ var (
initShard string
concurrency = 4
incrementalFromPos string
restoreWithClone bool

// mysqlctld-like flags
mysqlPort = 3306
Expand Down Expand Up @@ -157,7 +159,7 @@ When run periodically for each shard, vtbackup can ensure these configurable pol
* Old backups for the shard are removed.

Whatever system launches vtbackup is responsible for the following:
- Running vtbackup with similar flags that would be used for a vttablet and
- Running vtbackup with similar flags that would be used for a vttablet and
mysqlctld in the target shard to be backed up.

- Provisioning as much disk space for vtbackup as would be given to vttablet.
Expand Down Expand Up @@ -226,6 +228,7 @@ func init() {
utils.SetFlagStringVar(Main.Flags(), &initShard, "init-shard", initShard, "(init parameter) shard to use for this tablet")
Main.Flags().IntVar(&concurrency, "concurrency", concurrency, "(init restore parameter) how many concurrent files to restore at once")
utils.SetFlagStringVar(Main.Flags(), &incrementalFromPos, "incremental-from-pos", incrementalFromPos, "Position, or name of backup from which to create an incremental backup. Default: empty. If given, then this backup becomes an incremental backup from given position or given backup. If value is 'auto', this backup will be taken from the last successful backup position.")
Main.Flags().BoolVar(&restoreWithClone, "restore-with-clone", restoreWithClone, "(init parameter) will perform the restore phase with MySQL CLONE, requires either --clone-from-primary or --clone-from-tablet")

// mysqlctld-like flags
utils.SetFlagIntVar(Main.Flags(), &mysqlPort, "mysql-port", mysqlPort, "MySQL port")
Expand Down Expand Up @@ -457,42 +460,49 @@ func takeBackup(ctx, backgroundCtx context.Context, topoServer *topo.Server, bac
return nil
}

phase.Set(phaseNameRestoreLastBackup, int64(1))
defer phase.Set(phaseNameRestoreLastBackup, int64(0))
backupDir := mysqlctl.GetBackupDir(initKeyspace, initShard)
log.Infof("Restoring latest backup from directory %v", backupDir)
restoreAt := time.Now()
params := mysqlctl.RestoreParams{
Cnf: mycnf,
Mysqld: mysqld,
Logger: logutil.NewConsoleLogger(),
Concurrency: concurrency,
HookExtraEnv: extraEnv,
DeleteBeforeRestore: true,
DbName: dbName,
Keyspace: initKeyspace,
Shard: initShard,
Stats: backupstats.RestoreStats(),
MysqlShutdownTimeout: mysqlShutdownTimeout,
}
backupManifest, err := mysqlctl.Restore(ctx, params)
var restorePos replication.Position
switch err {
case nil:
// if err is nil, we expect backupManifest to be non-nil
restorePos = backupManifest.Position
log.Infof("Successfully restored from backup at replication position %v", restorePos)
case mysqlctl.ErrNoBackup:
// There is no backup found, but we may be taking the initial backup of a shard
if !allowFirstBackup {
return errors.New("no backup found; not starting up empty since --initial_backup flag was not enabled")
}
restorePos = replication.Position{}
default:
return fmt.Errorf("can't restore from backup: %v", err)
}
deprecatedDurationByPhase.Set("RestoreLastBackup", int64(time.Since(restoreAt).Seconds()))
phase.Set(phaseNameRestoreLastBackup, int64(0))
if restoreWithClone {
restorePos, err = mysqlctl.CloneFromDonor(ctx, topoServer, mysqld, initKeyspace, initShard)
if err != nil {
return vterrors.Wrap(err, "restore with clone failed")
}
} else {
phase.Set(phaseNameRestoreLastBackup, int64(1))
defer phase.Set(phaseNameRestoreLastBackup, int64(0))
backupDir := mysqlctl.GetBackupDir(initKeyspace, initShard)
log.Infof("Restoring latest backup from directory %v", backupDir)
restoreAt := time.Now()
params := mysqlctl.RestoreParams{
Cnf: mycnf,
Mysqld: mysqld,
Logger: logutil.NewConsoleLogger(),
Concurrency: concurrency,
HookExtraEnv: extraEnv,
DeleteBeforeRestore: true,
DbName: dbName,
Keyspace: initKeyspace,
Shard: initShard,
Stats: backupstats.RestoreStats(),
MysqlShutdownTimeout: mysqlShutdownTimeout,
}
backupManifest, err := mysqlctl.Restore(ctx, params)
switch err {
case nil:
// if err is nil, we expect backupManifest to be non-nil
restorePos = backupManifest.Position
log.Infof("Successfully restored from backup at replication position %v", restorePos)
case mysqlctl.ErrNoBackup:
// There is no backup found, but we may be taking the initial backup of a shard
if !allowFirstBackup {
return vterrors.New(vtrpc.Code_FAILED_PRECONDITION, "no backup found; not starting up empty since --initial_backup flag was not enabled")
}
restorePos = replication.Position{}
default:
return vterrors.Wrap(err, "can't restore from backup")
}
deprecatedDurationByPhase.Set("RestoreLastBackup", int64(time.Since(restoreAt).Seconds()))
phase.Set(phaseNameRestoreLastBackup, int64(0))
}

// As of MySQL 8.0.21, you can disable redo logging using the ALTER INSTANCE
// DISABLE INNODB REDO_LOG statement. This functionality is intended for
Expand Down
2 changes: 1 addition & 1 deletion go/cmd/vttablet/cli/cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,5 +69,5 @@ func TestRunFailsToStartTabletManager(t *testing.T) {
defer cancel()

err := Main.ExecuteContext(ctx)
require.ErrorContains(t, err, "you cannot enable --restore-from-backup without a my.cnf file")
require.ErrorContains(t, err, "you cannot enable --restore-from-backup or --restore-with-clone without a my.cnf file")
}
1 change: 0 additions & 1 deletion go/flags/endtoend/mysqlctl.txt
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,6 @@ Flags:
--log_dir string If non-empty, write log files in this directory
--logtostderr log to standard error instead of files
--max-stack-size int configure the maximum stack size in bytes (default 67108864)
--mysql-clone-enabled Enable MySQL CLONE plugin and user for backup/replica provisioning (requires MySQL 8.0.17+)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this was added in an earlier PR, i don't think it's relevant for this binary

--mysql-port int MySQL port. (default 3306)
--mysql-server-version string MySQL server version to advertise. (default "8.4.6-Vitess")
--mysql-socket string Path to the mysqld socket file.
Expand Down
1 change: 0 additions & 1 deletion go/flags/endtoend/mysqlctld.txt
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,6 @@ Flags:
--log_dir string If non-empty, write log files in this directory
--logtostderr log to standard error instead of files
--max-stack-size int configure the maximum stack size in bytes (default 67108864)
--mysql-clone-enabled Enable MySQL CLONE plugin and user for backup/replica provisioning (requires MySQL 8.0.17+)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as comment above

--mysql-port int MySQL port (default 3306)
--mysql-server-version string MySQL server version to advertise. (default "8.4.6-Vitess")
--mysql-socket string Path to the mysqld socket file
Expand Down
7 changes: 6 additions & 1 deletion go/flags/endtoend/vtbackup.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ When run periodically for each shard, vtbackup can ensure these configurable pol
* Old backups for the shard are removed.

Whatever system launches vtbackup is responsible for the following:
- Running vtbackup with similar flags that would be used for a vttablet and
- Running vtbackup with similar flags that would be used for a vttablet and
mysqlctld in the target shard to be backed up.

- Provisioning as much disk space for vtbackup as would be given to vttablet.
Expand Down Expand Up @@ -68,6 +68,9 @@ Flags:
--builtinbackup-mysqld-timeout duration how long to wait for mysqld to shutdown at the start of the backup. (default 10m0s)
--builtinbackup-progress duration how often to send progress updates when backing up large files. (default 5s)
--ceph-backup-storage-config string Path to JSON config file for ceph backup storage. (default "ceph_backup_config.json")
--clone-from-primary Clone data from the primary tablet in the shard using MySQL CLONE REMOTE instead of restoring from backup. Requires MySQL 8.0.17+. Mutually exclusive with --clone-from-tablet.
--clone-from-tablet string Clone data from this tablet using MySQL CLONE REMOTE instead of restoring from backup (tablet alias, e.g., zone1-123). Requires MySQL 8.0.17+. Mutually exclusive with --clone-from-primary.
--clone-restart-wait-timeout duration Timeout for waiting for MySQL to restart after CLONE REMOTE. (default 5m0s)
--compression-engine-name string compressor engine used for compression. (default "pargzip")
--compression-level int what level to pass to the compressor. (default 1)
--concurrency int (init restore parameter) how many concurrent files to restore at once (default 4)
Expand Down Expand Up @@ -189,6 +192,7 @@ Flags:
--mycnf-slow-log-path string mysql slow query log path
--mycnf-socket-file string mysql socket file
--mycnf-tmp-dir string mysql tmp directory
--mysql-clone-enabled Enable MySQL CLONE plugin and user for backup/replica provisioning (requires MySQL 8.0.17+)
--mysql-port int MySQL port (default 3306)
--mysql-server-version string MySQL server version to advertise. (default "8.4.6-Vitess")
--mysql-shell-backup-location string location where the backup will be stored
Expand All @@ -207,6 +211,7 @@ Flags:
--purge-logs-interval duration how often try to remove old logs (default 1h0m0s)
--remote-operation-timeout duration time to wait for a remote operation (default 15s)
--restart-before-backup Perform a mysqld clean/full restart after applying binlogs, but before taking the backup. Only makes sense to work around xtrabackup bugs.
--restore-with-clone (init parameter) will perform the restore phase with MySQL CLONE, requires either --clone-from-primary or --clone-from-tablet
--s3-backup-aws-endpoint string endpoint of the S3 backend (region must be provided).
--s3-backup-aws-min-partsize int Minimum part size to use, defaults to 5MiB but can be increased due to the dataset size. (default 5242880)
--s3-backup-aws-region string AWS region to use. (default "us-east-1")
Expand Down
4 changes: 4 additions & 0 deletions go/flags/endtoend/vtcombo.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ Flags:
--builtinbackup-progress duration how often to send progress updates when backing up large files. (default 5s)
--catch-sigpipe catch and ignore SIGPIPE on stdout and stderr if specified
--cell string cell to use
--clone-from-primary Clone data from the primary tablet in the shard using MySQL CLONE REMOTE instead of restoring from backup. Requires MySQL 8.0.17+. Mutually exclusive with --clone-from-tablet.
--clone-from-tablet string Clone data from this tablet using MySQL CLONE REMOTE instead of restoring from backup (tablet alias, e.g., zone1-123). Requires MySQL 8.0.17+. Mutually exclusive with --clone-from-primary.
--clone-restart-wait-timeout duration Timeout for waiting for MySQL to restart after CLONE REMOTE. (default 5m0s)
--compression-engine-name string compressor engine used for compression. (default "pargzip")
--compression-level int what level to pass to the compressor. (default 1)
--config-file string Full path of the config file (with extension) to use. If set, --config-path, --config-type, and --config-name are ignored.
Expand Down Expand Up @@ -323,6 +326,7 @@ Flags:
--restore-from-backup-ts string (init restore parameter) if set, restore the latest backup taken at or before this timestamp. Example: '2021-04-29.133050'
--restore-to-pos string (init incremental restore parameter) if set, run a point in time recovery that ends with the given position. This will attempt to use one full backup followed by zero or more incremental backups
--restore-to-timestamp string (init incremental restore parameter) if set, run a point in time recovery that restores up to the given timestamp, if possible. Given timestamp in RFC3339 format. Example: '2006-01-02T15:04:05Z07:00'
--restore-with-clone (init restore parameter) will restore from a clone, requires either --clone-from-primary or --clone-from-tablet, mutually exclusive with --restore-from-backup
--retain-online-ddl-tables duration How long should vttablet keep an old migrated table before purging it (default 24h0m0s)
--sanitize-log-messages Remove potentially sensitive information in tablet INFO, WARNING, and ERROR log messages such as query parameters.
--schema-change-reload-timeout duration query server schema change reload timeout, this is how long to wait for the signaled schema reload operation to complete before giving up (default 30s)
Expand Down
4 changes: 4 additions & 0 deletions go/flags/endtoend/vttablet.txt
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,9 @@ Flags:
--builtinbackup-progress duration how often to send progress updates when backing up large files. (default 5s)
--catch-sigpipe catch and ignore SIGPIPE on stdout and stderr if specified
--ceph-backup-storage-config string Path to JSON config file for ceph backup storage. (default "ceph_backup_config.json")
--clone-from-primary Clone data from the primary tablet in the shard using MySQL CLONE REMOTE instead of restoring from backup. Requires MySQL 8.0.17+. Mutually exclusive with --clone-from-tablet.
--clone-from-tablet string Clone data from this tablet using MySQL CLONE REMOTE instead of restoring from backup (tablet alias, e.g., zone1-123). Requires MySQL 8.0.17+. Mutually exclusive with --clone-from-primary.
--clone-restart-wait-timeout duration Timeout for waiting for MySQL to restart after CLONE REMOTE. (default 5m0s)
--compression-engine-name string compressor engine used for compression. (default "pargzip")
--compression-level int what level to pass to the compressor. (default 1)
--config-file string Full path of the config file (with extension) to use. If set, --config-path, --config-type, and --config-name are ignored.
Expand Down Expand Up @@ -314,6 +317,7 @@ Flags:
--restore-from-backup-ts string (init restore parameter) if set, restore the latest backup taken at or before this timestamp. Example: '2021-04-29.133050'
--restore-to-pos string (init incremental restore parameter) if set, run a point in time recovery that ends with the given position. This will attempt to use one full backup followed by zero or more incremental backups
--restore-to-timestamp string (init incremental restore parameter) if set, run a point in time recovery that restores up to the given timestamp, if possible. Given timestamp in RFC3339 format. Example: '2006-01-02T15:04:05Z07:00'
--restore-with-clone (init restore parameter) will restore from a clone, requires either --clone-from-primary or --clone-from-tablet, mutually exclusive with --restore-from-backup
--retain-online-ddl-tables duration How long should vttablet keep an old migrated table before purging it (default 24h0m0s)
--s3-backup-aws-endpoint string endpoint of the S3 backend (region must be provided).
--s3-backup-aws-min-partsize int Minimum part size to use, defaults to 5MiB but can be increased due to the dataset size. (default 5242880)
Expand Down
3 changes: 3 additions & 0 deletions go/flags/endtoend/vttestserver.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ Flags:
--catch-sigpipe catch and ignore SIGPIPE on stdout and stderr if specified
--cells strings Comma separated list of cells (default [test])
--charset string MySQL charset (default "utf8mb4")
--clone-from-primary Clone data from the primary tablet in the shard using MySQL CLONE REMOTE instead of restoring from backup. Requires MySQL 8.0.17+. Mutually exclusive with --clone-from-tablet.
--clone-from-tablet string Clone data from this tablet using MySQL CLONE REMOTE instead of restoring from backup (tablet alias, e.g., zone1-123). Requires MySQL 8.0.17+. Mutually exclusive with --clone-from-primary.
--clone-restart-wait-timeout duration Timeout for waiting for MySQL to restart after CLONE REMOTE. (default 5m0s)
--compression-engine-name string compressor engine used for compression. (default "pargzip")
--compression-level int what level to pass to the compressor. (default 1)
--config-file string Full path of the config file (with extension) to use. If set, --config-path, --config-type, and --config-name are ignored.
Expand Down
Loading
Loading