diff --git a/br/cmd/br/debug.go b/br/cmd/br/debug.go index 3a7fd64c..abf10ee9 100644 --- a/br/cmd/br/debug.go +++ b/br/cmd/br/debug.go @@ -4,17 +4,23 @@ package main import ( "context" + "crypto/tls" "path" "reflect" + "strings" "github.com/gogo/protobuf/proto" "github.com/pingcap/errors" "github.com/pingcap/log" "github.com/spf13/cobra" + "github.com/tikv/migration/br/pkg/checksum" + "github.com/tikv/migration/br/pkg/conn" "github.com/tikv/migration/br/pkg/metautil" + "github.com/tikv/migration/br/pkg/pdutil" "github.com/tikv/migration/br/pkg/task" "github.com/tikv/migration/br/pkg/utils" "github.com/tikv/migration/br/pkg/version/build" + pd "github.com/tikv/pd/client" ) // NewDebugCommand return a debug subcommand. @@ -51,10 +57,9 @@ func newCheckSumCommand() *cobra.Command { Short: "check the backup data", Args: cobra.NoArgs, RunE: func(cmd *cobra.Command, _ []string) error { - return errors.Errorf("checksum is unsupported") + return runRawChecksumCommand(cmd, "RawChecksum") }, } - command.Hidden = true return command } @@ -77,6 +82,7 @@ func newBackupMetaValidateCommand() *cobra.Command { }, } command.Flags().Uint64("offset", 0, "the offset of table id alloctor") + command.Hidden = true return command } @@ -223,3 +229,55 @@ func setPDConfigCommand() *cobra.Command { } return pdConfigCmd } + +func runRawChecksumCommand(command *cobra.Command, cmdName string) error { + cfg := task.Config{LogProgress: HasLogFile()} + err := cfg.ParseFromFlags(command.Flags()) + if err != nil { + command.SilenceUsage = false + return errors.Trace(err) + } + + ctx := GetDefaultContext() + pdAddress := strings.Join(cfg.PD, ",") + securityOption := pd.SecurityOption{} + var tlsConf *tls.Config = nil + if cfg.TLS.IsEnabled() { + securityOption.CAPath = cfg.TLS.CA + securityOption.CertPath = cfg.TLS.Cert + securityOption.KeyPath = cfg.TLS.Key + tlsConf, err = cfg.TLS.ToTLSConfig() + if err != nil { + return errors.Trace(err) + } + } + pdCtrl, err := pdutil.NewPdController(ctx, pdAddress, tlsConf, securityOption) + if err != nil { + return errors.Trace(err) + } + storageAPIVersion, err := conn.GetTiKVApiVersion(ctx, pdCtrl.GetPDClient(), tlsConf) + if err != nil { + return errors.Trace(err) + } + _, _, backupMeta, err := task.ReadBackupMeta(ctx, metautil.MetaFile, &cfg) + if err != nil { + return errors.Trace(err) + } + fileChecksum, keyRanges := task.CalcChecksumAndRangeFromBackupMeta(ctx, backupMeta, storageAPIVersion) + if !task.CheckBackupAPIVersion(storageAPIVersion, backupMeta.ApiVersion) { + return errors.Errorf("Unsupported api version, storage:%s, backup meta:%s.", + storageAPIVersion.String(), backupMeta.ApiVersion.String()) + } + checksumMethod := checksum.StorageChecksumCommand + if storageAPIVersion != backupMeta.ApiVersion { + checksumMethod = checksum.StorageScanCommand + } + + executor := checksum.NewExecutor(keyRanges, cfg.PD, pdCtrl.GetPDClient(), storageAPIVersion, + cfg.ChecksumConcurrency) + err = checksum.Run(ctx, cmdName, executor, checksumMethod, fileChecksum) + if err != nil { + return errors.Trace(err) + } + return nil +} diff --git a/br/pkg/backup/client.go b/br/pkg/backup/client.go index d81f9885..eec7fa38 100644 --- a/br/pkg/backup/client.go +++ b/br/pkg/backup/client.go @@ -6,11 +6,8 @@ import ( "context" "crypto/tls" "encoding/hex" - "encoding/json" "fmt" "io" - "io/ioutil" - "net/http" "os" "strings" "sync" @@ -66,14 +63,6 @@ const ( RegionUnit ProgressUnit = "region" ) -type StorageConfig struct { - APIVersion int `json:"api-version"` - EnableTTL bool `json:"enable-ttl"` -} -type StoreConfig struct { - Storage StorageConfig `json:"storage"` -} - // Client is a client instructs TiKV how to do a backup. type Client struct { mgr ClientMgr @@ -91,7 +80,7 @@ func NewBackupClient(ctx context.Context, mgr ClientMgr, config *tls.Config) (*C log.Info("new backup client") pdClient := mgr.GetPDClient() clusterID := pdClient.GetClusterID(ctx) - curAPIVer, err := GetCurrentTiKVApiVersion(ctx, mgr.GetPDClient(), config) + curAPIVer, err := conn.GetTiKVApiVersion(ctx, mgr.GetPDClient(), config) if err != nil { return nil, errors.Trace(err) } @@ -142,53 +131,6 @@ func (bc *Client) GetTS(ctx context.Context, duration time.Duration, ts uint64) return backupTS, nil } -func GetCurrentTiKVApiVersion(ctx context.Context, pdClient pd.Client, tlsConf *tls.Config) (kvrpcpb.APIVersion, error) { - allStores, err := conn.GetAllTiKVStoresWithRetry(ctx, pdClient, conn.SkipTiFlash) - if err != nil { - return kvrpcpb.APIVersion_V1, errors.Trace(err) - } else if len(allStores) == 0 { - return kvrpcpb.APIVersion_V1, errors.New("store are empty") - } - schema := "http" - httpClient := http.Client{} - if tlsConf != nil { - httpClient = http.Client{ - Transport: &http.Transport{TLSClientConfig: tlsConf}, - } - schema = "https" - } - url := fmt.Sprintf("%s://%s/config", schema, allStores[0].StatusAddress) - resp, err := httpClient.Get(url) - if err != nil { - return kvrpcpb.APIVersion_V1, errors.Trace(err) - } - defer resp.Body.Close() - body, err := ioutil.ReadAll(resp.Body) - if err != nil { - return kvrpcpb.APIVersion_V1, errors.Trace(err) - } - var cfg StoreConfig - if err := json.Unmarshal(body, &cfg); err != nil { - return kvrpcpb.APIVersion_V1, errors.Trace(err) - } - var apiVersion kvrpcpb.APIVersion - if cfg.Storage.APIVersion == 0 { // in old version without apiversion config. it's APIV1. - apiVersion = kvrpcpb.APIVersion_V1 - } else if cfg.Storage.APIVersion == 1 { - if cfg.Storage.EnableTTL { - apiVersion = kvrpcpb.APIVersion_V1TTL - } else { - apiVersion = kvrpcpb.APIVersion_V1 - } - } else if cfg.Storage.APIVersion == 2 { - apiVersion = kvrpcpb.APIVersion_V2 - } else { - errMsg := fmt.Sprintf("Invalid apiversion %d", cfg.Storage.APIVersion) - return kvrpcpb.APIVersion_V1, errors.New(errMsg) - } - return apiVersion, nil -} - func (bc *Client) GetCurAPIVersion() kvrpcpb.APIVersion { return bc.curAPIVer } diff --git a/br/pkg/backup/client_test.go b/br/pkg/backup/client_test.go index f4c86eb3..77c7f740 100644 --- a/br/pkg/backup/client_test.go +++ b/br/pkg/backup/client_test.go @@ -11,7 +11,6 @@ import ( . "github.com/pingcap/check" backuppb "github.com/pingcap/kvproto/pkg/brpb" "github.com/pingcap/kvproto/pkg/errorpb" - "github.com/pingcap/kvproto/pkg/kvrpcpb" "github.com/tikv/client-go/v2/oracle" "github.com/tikv/client-go/v2/testutils" "github.com/tikv/client-go/v2/tikv" @@ -226,31 +225,3 @@ func (r *testBackup) TestCheckBackupIsLocked(c *C) { err = backup.CheckBackupStorageIsLocked(ctx, r.storage) c.Assert(err, ErrorMatches, "backup lock file and sst file exist in(.+)") } - -func (r *testBackup) TestGetCurrentTiKVApiVersion(c *C) { - ctx := context.Background() - - httpmock.Activate() - defer httpmock.DeactivateAndReset() - // Exact URL match - httpmock.RegisterResponder("GET", `=~^/config`, - httpmock.NewStringResponder(200, `{"storage":{"api-version":1, "enable-ttl":false}}`)) - - apiVer, err := backup.GetCurrentTiKVApiVersion(ctx, r.mockPDClient, nil) - c.Assert(err, IsNil) - c.Assert(apiVer, Equals, kvrpcpb.APIVersion_V1) - - httpmock.RegisterResponder("GET", `=~^/config`, - httpmock.NewStringResponder(200, `{"storage":{"api-version":1, "enable-ttl":true}}`)) - - apiVer, err = backup.GetCurrentTiKVApiVersion(ctx, r.mockPDClient, nil) - c.Assert(err, IsNil) - c.Assert(apiVer, Equals, kvrpcpb.APIVersion_V1TTL) - - httpmock.RegisterResponder("GET", `=~^/config`, - httpmock.NewStringResponder(200, `{"storage":{"api-version":2, "enable-ttl":true}}`)) - - apiVer, err = backup.GetCurrentTiKVApiVersion(ctx, r.mockPDClient, nil) - c.Assert(err, IsNil) - c.Assert(apiVer, Equals, kvrpcpb.APIVersion_V2) -} diff --git a/br/pkg/checksum/executor.go b/br/pkg/checksum/executor.go index 14bd459f..5cc22f5c 100644 --- a/br/pkg/checksum/executor.go +++ b/br/pkg/checksum/executor.go @@ -333,6 +333,9 @@ func (exec *Executor) Execute( func Run(ctx context.Context, cmdName string, executor *Executor, method StorageChecksumMethod, expect Checksum) error { + if executor.apiVersion != kvrpcpb.APIVersion_V1 { + fmt.Printf("\033[1;37;41m%s\033[0m\n", "Warning: TiKV cluster is TTL enabled, checksum may be mismatch if some data expired during backup/restore.") + } glue := new(gluetikv.Glue) updateCh := glue.StartProgress(ctx, cmdName+" Checksum", int64(len(executor.keyRanges)), false) progressCallBack := func(unit backup.ProgressUnit) { diff --git a/br/pkg/conn/conn.go b/br/pkg/conn/conn.go index f65dd45d..8e295ce1 100755 --- a/br/pkg/conn/conn.go +++ b/br/pkg/conn/conn.go @@ -5,7 +5,10 @@ package conn import ( "context" "crypto/tls" + "encoding/json" "fmt" + "io/ioutil" + "net/http" "os" "sync" "time" @@ -14,8 +17,10 @@ import ( "github.com/pingcap/errors" "github.com/pingcap/failpoint" backuppb "github.com/pingcap/kvproto/pkg/brpb" + "github.com/pingcap/kvproto/pkg/kvrpcpb" "github.com/pingcap/kvproto/pkg/metapb" "github.com/pingcap/log" + "github.com/pingcap/tidb/br/pkg/conn" "github.com/tikv/client-go/v2/tikv" "github.com/tikv/client-go/v2/txnkv/txnlock" berrors "github.com/tikv/migration/br/pkg/errors" @@ -416,3 +421,58 @@ func (mgr *Mgr) Close() { mgr.PdController.Close() } + +type StorageConfig struct { + APIVersion int `json:"api-version"` + EnableTTL bool `json:"enable-ttl"` +} +type StoreConfig struct { + Storage StorageConfig `json:"storage"` +} + +func GetTiKVApiVersion(ctx context.Context, pdClient pd.Client, tlsConf *tls.Config) (kvrpcpb.APIVersion, error) { + allStores, err := conn.GetAllTiKVStoresWithRetry(ctx, pdClient, conn.SkipTiFlash) + if err != nil { + return kvrpcpb.APIVersion_V1, errors.Trace(err) + } else if len(allStores) == 0 { + return kvrpcpb.APIVersion_V1, errors.New("store are empty") + } + schema := "http" + httpClient := http.Client{} + if tlsConf != nil { + httpClient = http.Client{ + Transport: &http.Transport{TLSClientConfig: tlsConf}, + } + schema = "https" + } + url := fmt.Sprintf("%s://%s/config", schema, allStores[0].StatusAddress) + resp, err := httpClient.Get(url) + if err != nil { + return kvrpcpb.APIVersion_V1, errors.Trace(err) + } + defer resp.Body.Close() + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return kvrpcpb.APIVersion_V1, errors.Trace(err) + } + var cfg StoreConfig + if err := json.Unmarshal(body, &cfg); err != nil { + return kvrpcpb.APIVersion_V1, errors.Trace(err) + } + var apiVersion kvrpcpb.APIVersion + if cfg.Storage.APIVersion == 0 { // in old version without apiversion config. it's APIV1. + apiVersion = kvrpcpb.APIVersion_V1 + } else if cfg.Storage.APIVersion == 1 { + if cfg.Storage.EnableTTL { + apiVersion = kvrpcpb.APIVersion_V1TTL + } else { + apiVersion = kvrpcpb.APIVersion_V1 + } + } else if cfg.Storage.APIVersion == 2 { + apiVersion = kvrpcpb.APIVersion_V2 + } else { + errMsg := fmt.Sprintf("Invalid apiversion %d", cfg.Storage.APIVersion) + return kvrpcpb.APIVersion_V1, errors.New(errMsg) + } + return apiVersion, nil +} diff --git a/br/pkg/conn/conn_test.go b/br/pkg/conn/conn_test.go index 16c204ed..beecc5fb 100644 --- a/br/pkg/conn/conn_test.go +++ b/br/pkg/conn/conn_test.go @@ -6,8 +6,10 @@ import ( "context" "testing" + "github.com/jarcoal/httpmock" "github.com/pingcap/errors" "github.com/pingcap/failpoint" + "github.com/pingcap/kvproto/pkg/kvrpcpb" "github.com/pingcap/kvproto/pkg/metapb" "github.com/stretchr/testify/require" "github.com/tikv/migration/br/pkg/pdutil" @@ -269,3 +271,45 @@ func TestGetConnOnCanceledContext(t *testing.T) { require.Error(t, err) require.Contains(t, err.Error(), "context canceled") } + +type mockPDClient struct { + pd.Client +} + +func (c *mockPDClient) GetAllStores(ctx context.Context, opts ...pd.GetStoreOption) ([]*metapb.Store, error) { + store := &metapb.Store{ + Id: 0, + Address: "127.0.0.1", + } + return []*metapb.Store{store}, nil +} + +func TestGetTiKVApiVersion(t *testing.T) { + ctx := context.Background() + + mockPdClient := mockPDClient{} + + httpmock.Activate() + defer httpmock.DeactivateAndReset() + // Exact URL match + httpmock.RegisterResponder("GET", `=~^/config`, + httpmock.NewStringResponder(200, `{"storage":{"api-version":1, "enable-ttl":false}}`)) + + apiVer, err := GetTiKVApiVersion(ctx, &mockPdClient, nil) + require.Equal(t, err, nil) + require.Equal(t, apiVer, kvrpcpb.APIVersion_V1) + + httpmock.RegisterResponder("GET", `=~^/config`, + httpmock.NewStringResponder(200, `{"storage":{"api-version":1, "enable-ttl":true}}`)) + + apiVer, err = GetTiKVApiVersion(ctx, &mockPdClient, nil) + require.Equal(t, err, nil) + require.Equal(t, apiVer, kvrpcpb.APIVersion_V1TTL) + + httpmock.RegisterResponder("GET", `=~^/config`, + httpmock.NewStringResponder(200, `{"storage":{"api-version":2, "enable-ttl":true}}`)) + + apiVer, err = GetTiKVApiVersion(ctx, &mockPdClient, nil) + require.Equal(t, err, nil) + require.Equal(t, apiVer, kvrpcpb.APIVersion_V2) +} diff --git a/br/pkg/restore/client.go b/br/pkg/restore/client.go index 2c0ee6d0..f8bb009b 100644 --- a/br/pkg/restore/client.go +++ b/br/pkg/restore/client.go @@ -12,6 +12,7 @@ import ( "github.com/pingcap/errors" backuppb "github.com/pingcap/kvproto/pkg/brpb" "github.com/pingcap/kvproto/pkg/import_sstpb" + "github.com/pingcap/kvproto/pkg/kvrpcpb" "github.com/pingcap/log" "github.com/tikv/client-go/v2/oracle" "github.com/tikv/migration/br/pkg/conn" @@ -43,7 +44,8 @@ type Client struct { tlsConf *tls.Config keepaliveConf keepalive.ClientParameters - backupMeta *backuppb.BackupMeta + backupMeta *backuppb.BackupMeta + dstAPIVersion kvrpcpb.APIVersion rateLimit uint64 isOnline bool @@ -64,12 +66,17 @@ func NewRestoreClient( keepaliveConf keepalive.ClientParameters, isRawKv bool, ) (*Client, error) { + apiVerion, err := conn.GetTiKVApiVersion(context.Background(), pdClient, tlsConf) + if err != nil { + return nil, errors.Trace(err) + } return &Client{ pdClient: pdClient, toolClient: NewSplitClient(pdClient, tlsConf, isRawKv), tlsConf: tlsConf, keepaliveConf: keepaliveConf, switchCh: make(chan struct{}), + dstAPIVersion: apiVerion, }, nil } @@ -398,3 +405,7 @@ func (rc *Client) switchTiKVMode(ctx context.Context, mode import_sstpb.SwitchMo } return nil } + +func (rc *Client) GetAPIVersion() kvrpcpb.APIVersion { + return rc.dstAPIVersion +} diff --git a/br/pkg/task/backup_raw.go b/br/pkg/task/backup_raw.go index fbd2ceb6..efd386f3 100644 --- a/br/pkg/task/backup_raw.go +++ b/br/pkg/task/backup_raw.go @@ -58,11 +58,7 @@ func DefineRawBackupFlags(command *cobra.Command) { } // CalcChecksumFromBackupMeta read the backup meta and return Checksum -func CalcChecksumFromBackupMeta(ctx context.Context, curAPIVersion kvrpcpb.APIVersion, cfg *Config) (checksum.Checksum, []*utils.KeyRange, error) { - _, _, backupMeta, err := ReadBackupMeta(ctx, metautil.MetaFile, cfg) - if err != nil { - return checksum.Checksum{}, nil, errors.Trace(err) - } +func CalcChecksumAndRangeFromBackupMeta(ctx context.Context, backupMeta *backuppb.BackupMeta, curAPIVersion kvrpcpb.APIVersion) (checksum.Checksum, []*utils.KeyRange) { fileChecksum := checksum.Checksum{} keyRanges := make([]*utils.KeyRange, 0, len(backupMeta.Files)) for _, file := range backupMeta.Files { @@ -70,7 +66,7 @@ func CalcChecksumFromBackupMeta(ctx context.Context, curAPIVersion kvrpcpb.APIVe keyRange := utils.ConvertBackupConfigKeyRange(file.StartKey, file.EndKey, backupMeta.ApiVersion, curAPIVersion) keyRanges = append(keyRanges, keyRange) } - return fileChecksum, keyRanges, nil + return fileChecksum, keyRanges } // RunBackupRaw starts a backup task inside the current goroutine. @@ -104,7 +100,12 @@ func RunBackupRaw(c context.Context, g glue.Glue, cmdName string, cfg *RawKvConf curAPIVersion := client.GetCurAPIVersion() cfg.adjustBackupRange(curAPIVersion) if len(cfg.DstAPIVersion) == 0 { // if no DstAPIVersion is specified, backup to same api-version. - cfg.DstAPIVersion = kvrpcpb.APIVersion_name[int32(curAPIVersion)] + cfg.DstAPIVersion = curAPIVersion.String() + } + dstAPIVersion := kvrpcpb.APIVersion(kvrpcpb.APIVersion_value[cfg.DstAPIVersion]) + if !CheckBackupAPIVersion(curAPIVersion, dstAPIVersion) { + return errors.Errorf("Unsupported backup api version, cur:%s, dst:%s.", + curAPIVersion.String(), cfg.DstAPIVersion) } opts := storage.ExternalStorageOptions{ NoCredentials: cfg.NoCreds, @@ -157,7 +158,6 @@ func RunBackupRaw(c context.Context, g glue.Glue, cmdName string, cfg *RawKvConf } updateCh.Inc() } - dstAPIVersion := kvrpcpb.APIVersion(kvrpcpb.APIVersion_value[cfg.DstAPIVersion]) req := backuppb.BackupRequest{ ClusterId: client.GetClusterID(), StartVersion: 0, @@ -207,11 +207,12 @@ func RunBackupRaw(c context.Context, g glue.Glue, cmdName string, cfg *RawKvConf g.Record(summary.BackupDataSize, metaWriter.ArchiveSize()) if cfg.Checksum { - fileChecksum, keyRanges, err := CalcChecksumFromBackupMeta(ctx, curAPIVersion, &cfg.Config) + _, _, backupMeta, err := ReadBackupMeta(ctx, metautil.MetaFile, &cfg.Config) if err != nil { log.Error("fail to read backup meta", zap.Error(err)) - return err + return errors.Trace(err) } + fileChecksum, keyRanges := CalcChecksumAndRangeFromBackupMeta(ctx, backupMeta, curAPIVersion) checksumMethod := checksum.StorageChecksumCommand if curAPIVersion.String() != cfg.DstAPIVersion { checksumMethod = checksum.StorageScanCommand diff --git a/br/pkg/task/common.go b/br/pkg/task/common.go index a099cd48..e6bb1c6f 100644 --- a/br/pkg/task/common.go +++ b/br/pkg/task/common.go @@ -19,6 +19,7 @@ import ( "github.com/pingcap/errors" backuppb "github.com/pingcap/kvproto/pkg/brpb" "github.com/pingcap/kvproto/pkg/encryptionpb" + "github.com/pingcap/kvproto/pkg/kvrpcpb" "github.com/pingcap/log" "github.com/spf13/cobra" "github.com/spf13/pflag" @@ -95,7 +96,7 @@ func DefineCommonFlags(flags *pflag.FlagSet) { flags.Uint64(flagRateLimit, unlimited, "The rate limit of the task, MB/s per node") _ = flags.MarkHidden(flagRateLimit) - flags.Bool(flagChecksum, true, "Run checksum at end of task") + flags.Bool(flagChecksum, false, "Run checksum at end of task") // Default concurrency is different for backup and restore. // Leave it 0 and let them adjust the value. flags.Uint32(flagConcurrency, 0, "The size of thread pool on each node that executes the task") @@ -365,3 +366,9 @@ func normalizePDURL(pd string, useTLS bool) (string, error) { func gcsObjectNotFound(err error) bool { return errors.Cause(err) == gcs.ErrObjectNotExist // nolint:errorlint } + +// CheckBackupAPIVersion return false if backup api version is not supported. +func CheckBackupAPIVersion(storageAPIVersion, dstAPIVersion kvrpcpb.APIVersion) bool { + // only support apiv1/v1ttl->apiv2 if apiversions are not the same. + return storageAPIVersion == dstAPIVersion || dstAPIVersion == kvrpcpb.APIVersion_V2 +} diff --git a/br/pkg/task/common_test.go b/br/pkg/task/common_test.go index e980f5a4..d4d37258 100644 --- a/br/pkg/task/common_test.go +++ b/br/pkg/task/common_test.go @@ -9,6 +9,7 @@ import ( backup "github.com/pingcap/kvproto/pkg/brpb" "github.com/pingcap/kvproto/pkg/encryptionpb" + "github.com/pingcap/kvproto/pkg/kvrpcpb" "github.com/spf13/pflag" "github.com/stretchr/testify/require" ) @@ -148,3 +149,15 @@ func TestCheckCipherKey(t *testing.T) { } } } + +func TestCheckBackupAPIVersion(t *testing.T) { + require.Equal(t, CheckBackupAPIVersion(kvrpcpb.APIVersion_V1, kvrpcpb.APIVersion_V1), true) + require.Equal(t, CheckBackupAPIVersion(kvrpcpb.APIVersion_V1TTL, kvrpcpb.APIVersion_V1TTL), true) + require.Equal(t, CheckBackupAPIVersion(kvrpcpb.APIVersion_V2, kvrpcpb.APIVersion_V2), true) + require.Equal(t, CheckBackupAPIVersion(kvrpcpb.APIVersion_V1, kvrpcpb.APIVersion_V2), true) + require.Equal(t, CheckBackupAPIVersion(kvrpcpb.APIVersion_V1TTL, kvrpcpb.APIVersion_V2), true) + require.Equal(t, CheckBackupAPIVersion(kvrpcpb.APIVersion_V1, kvrpcpb.APIVersion_V1TTL), false) + require.Equal(t, CheckBackupAPIVersion(kvrpcpb.APIVersion_V1TTL, kvrpcpb.APIVersion_V1), false) + require.Equal(t, CheckBackupAPIVersion(kvrpcpb.APIVersion_V2, kvrpcpb.APIVersion_V1), false) + require.Equal(t, CheckBackupAPIVersion(kvrpcpb.APIVersion_V2, kvrpcpb.APIVersion_V1TTL), false) +} diff --git a/br/pkg/task/restore_raw.go b/br/pkg/task/restore_raw.go index 92e99b2b..b4dfc2cb 100644 --- a/br/pkg/task/restore_raw.go +++ b/br/pkg/task/restore_raw.go @@ -64,8 +64,12 @@ func RunRestoreRaw(c context.Context, g glue.Glue, cmdName string, cfg *RestoreR if err != nil { return errors.Trace(err) } + if client.GetAPIVersion() != backupMeta.ApiVersion { + return errors.Errorf("Unsupported backup api version, backup meta: %s, dst:%s.", + backupMeta.ApiVersion.String(), client.GetAPIVersion().String()) + } // for restore, dst and cur are the same. - cfg.DstAPIVersion = backupMeta.ApiVersion.String() + cfg.DstAPIVersion = client.GetAPIVersion().String() cfg.adjustBackupRange(backupMeta.ApiVersion) reader := metautil.NewMetaReader(backupMeta, s, &cfg.CipherInfo) if err = client.InitBackupMeta(c, backupMeta, u, s, reader); err != nil {