diff --git a/go.mod1 b/go.mod1 index 9d0d41202..60e162334 100644 --- a/go.mod1 +++ b/go.mod1 @@ -23,10 +23,10 @@ require ( github.com/pingcap/check v0.0.0-20200212061837-5e12011dc712 github.com/pingcap/errors v0.11.5-0.20201126102027-b0a155152ca3 github.com/pingcap/failpoint v0.0.0-20200702092429-9f69995143ce - github.com/pingcap/kvproto v0.0.0-20201126113434-70db5fb4b0dc + github.com/pingcap/kvproto v0.0.0-20210308075244-560097d1309b github.com/pingcap/log v0.0.0-20201112100606-8f1e84a3abc8 - github.com/pingcap/parser v0.0.0-20210107054750-53e33b4018fe - github.com/pingcap/tidb v1.1.0-beta.0.20210205053311-631dbfdc3215 + github.com/pingcap/parser v0.0.0-20210303062609-d1d977c9ceed + github.com/pingcap/tidb v1.1.0-beta.0.20210308110454-a7199ff91648 github.com/pingcap/tidb-tools v4.0.9-0.20201127090955-2707c97b3853+incompatible github.com/pingcap/tipb v0.0.0-20200618092958-4fad48b4c8c3 github.com/prometheus/client_golang v1.5.1 @@ -46,7 +46,7 @@ require ( golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f - golang.org/x/text v0.3.4 + golang.org/x/text v0.3.5 google.golang.org/api v0.22.0 google.golang.org/grpc v1.27.1 modernc.org/mathutil v1.1.1 diff --git a/go.sum1 b/go.sum1 index 9af82200e..dce65a5b4 100644 --- a/go.sum1 +++ b/go.sum1 @@ -426,20 +426,20 @@ github.com/pingcap/goleveldb v0.0.0-20191226122134-f82aafb29989/go.mod h1:O17Xtb github.com/pingcap/kvproto v0.0.0-20191211054548-3c6b38ea5107/go.mod h1:WWLmULLO7l8IOcQG+t+ItJ3fEcrL5FxF0Wu+HrMy26w= github.com/pingcap/kvproto v0.0.0-20200411081810-b85805c9476c/go.mod h1:IOdRDPLyda8GX2hE/jO7gqaCV/PNFh8BZQCQZXfIOqI= github.com/pingcap/kvproto v0.0.0-20200907074027-32a3a0accf7d/go.mod h1:IOdRDPLyda8GX2hE/jO7gqaCV/PNFh8BZQCQZXfIOqI= -github.com/pingcap/kvproto v0.0.0-20201126113434-70db5fb4b0dc h1:BtszN3YR5EScxiGGTD3tAf4CQE90bczkOY0lLa07EJA= -github.com/pingcap/kvproto v0.0.0-20201126113434-70db5fb4b0dc/go.mod h1:IOdRDPLyda8GX2hE/jO7gqaCV/PNFh8BZQCQZXfIOqI= +github.com/pingcap/kvproto v0.0.0-20210308075244-560097d1309b h1:Jp0V5PDzdOy666n4XbDDaEjOKHsp2nk7b2uR6qjFI0s= +github.com/pingcap/kvproto v0.0.0-20210308075244-560097d1309b/go.mod h1:IOdRDPLyda8GX2hE/jO7gqaCV/PNFh8BZQCQZXfIOqI= github.com/pingcap/log v0.0.0-20191012051959-b742a5d432e9/go.mod h1:4rbK1p9ILyIfb6hU7OG2CiWSqMXnp3JMbiaVJ6mvoY8= github.com/pingcap/log v0.0.0-20200117041106-d28c14d3b1cd/go.mod h1:4rbK1p9ILyIfb6hU7OG2CiWSqMXnp3JMbiaVJ6mvoY8= github.com/pingcap/log v0.0.0-20200511115504-543df19646ad/go.mod h1:4rbK1p9ILyIfb6hU7OG2CiWSqMXnp3JMbiaVJ6mvoY8= github.com/pingcap/log v0.0.0-20201112100606-8f1e84a3abc8 h1:M+DNpOu/I3uDmwee6vcnoPd6GgSMqND4gxvDQ/W584U= github.com/pingcap/log v0.0.0-20201112100606-8f1e84a3abc8/go.mod h1:4rbK1p9ILyIfb6hU7OG2CiWSqMXnp3JMbiaVJ6mvoY8= -github.com/pingcap/parser v0.0.0-20210107054750-53e33b4018fe h1:sukVKRva68HNGZ4nuPvQS/wMvH7NMxTXV2NIhmoYP4Y= -github.com/pingcap/parser v0.0.0-20210107054750-53e33b4018fe/go.mod h1:GbEr2PgY72/4XqPZzmzstlOU/+il/wrjeTNFs6ihsSE= +github.com/pingcap/parser v0.0.0-20210303062609-d1d977c9ceed h1:+ENLMPNRG8+/YGNJChC5QRgfrcmFnsrHl9WoVLXRZok= +github.com/pingcap/parser v0.0.0-20210303062609-d1d977c9ceed/go.mod h1:GbEr2PgY72/4XqPZzmzstlOU/+il/wrjeTNFs6ihsSE= github.com/pingcap/sysutil v0.0.0-20200206130906-2bfa6dc40bcd/go.mod h1:EB/852NMQ+aRKioCpToQ94Wl7fktV+FNnxf3CX/TTXI= github.com/pingcap/sysutil v0.0.0-20201130064824-f0c8aa6a6966 h1:JI0wOAb8aQML0vAVLHcxTEEC0VIwrk6gtw3WjbHvJLA= github.com/pingcap/sysutil v0.0.0-20201130064824-f0c8aa6a6966/go.mod h1:EB/852NMQ+aRKioCpToQ94Wl7fktV+FNnxf3CX/TTXI= -github.com/pingcap/tidb v1.1.0-beta.0.20210205053311-631dbfdc3215 h1:7bf172wT10o7RltnrPI/TmxIb8XN37z16LasQ6k+NHo= -github.com/pingcap/tidb v1.1.0-beta.0.20210205053311-631dbfdc3215/go.mod h1:SCx4L0ST/1OpW/KBfmw/s/cyzIvIIwVvNdrC/m0apgg= +github.com/pingcap/tidb v1.1.0-beta.0.20210308110454-a7199ff91648 h1:O/XlgK69L7EHkyKck32bCt17plzZnPo9J+Vp7QNe8Ww= +github.com/pingcap/tidb v1.1.0-beta.0.20210308110454-a7199ff91648/go.mod h1:MCJOHX8pPlU9mMQfyTko9EDg1mDwohW0+fvBE01WUC0= github.com/pingcap/tidb-tools v4.0.9-0.20201127090955-2707c97b3853+incompatible h1:ceznmu/lLseGHP/jKyOa/3u/5H3wtLLLqkH2V3ssSjg= github.com/pingcap/tidb-tools v4.0.9-0.20201127090955-2707c97b3853+incompatible/go.mod h1:XGdcy9+yqlDSEMTpOXnwf3hiTeqrV6MN/u1se9N8yIM= github.com/pingcap/tipb v0.0.0-20200618092958-4fad48b4c8c3 h1:ESL3eIt1kUt8IMvR1011ejZlAyDcOzw89ARvVHvpD5k= @@ -750,8 +750,8 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc= -golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ= +golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= diff --git a/pkg/backup/client.go b/pkg/backup/client.go index 17b4ea2db..00cd2d382 100644 --- a/pkg/backup/client.go +++ b/pkg/backup/client.go @@ -181,12 +181,17 @@ func BuildBackupMeta( files []*kvproto.File, rawRanges []*kvproto.RawRange, ddlJobs []*model.Job, + clusterVersion string, + brVersion string, ) (backupMeta kvproto.BackupMeta, err error) { backupMeta.StartVersion = req.StartVersion backupMeta.EndVersion = req.EndVersion backupMeta.IsRawKv = req.IsRawKv backupMeta.RawRanges = rawRanges backupMeta.Files = files + backupMeta.ClusterId = req.ClusterId + backupMeta.ClusterVersion = clusterVersion + backupMeta.BrVersion = brVersion backupMeta.Ddls, err = json.Marshal(ddlJobs) if err != nil { err = errors.Trace(err) @@ -207,6 +212,11 @@ func (bc *Client) SaveBackupMeta(ctx context.Context, backupMeta *kvproto.Backup return bc.storage.Write(ctx, utils.MetaFile, backupMetaData) } +// GetClusterID returns the cluster ID of the tidb cluster to backup. +func (bc *Client) GetClusterID() uint64 { + return bc.clusterID +} + // BuildTableRanges returns the key ranges encompassing the entire table, // and its partitions if exists. func BuildTableRanges(tbl *model.TableInfo) ([]kv.KeyRange, error) { @@ -513,7 +523,6 @@ func (bc *Client) BackupRange( return nil, errors.Trace(err) } - req.ClusterId = bc.clusterID req.StartKey = startKey req.EndKey = endKey req.StorageBackend = bc.backend diff --git a/pkg/backup/client_test.go b/pkg/backup/client_test.go index d7cdac3d7..cb36a7cd2 100644 --- a/pkg/backup/client_test.go +++ b/pkg/backup/client_test.go @@ -22,6 +22,7 @@ import ( "github.com/pingcap/br/pkg/backup" "github.com/pingcap/br/pkg/conn" + "github.com/pingcap/br/pkg/gluetidb" "github.com/pingcap/br/pkg/pdutil" ) @@ -180,3 +181,18 @@ func (r *testBackup) TestOnBackupRegionErrorResponse(c *C) { } } } + +func (r *testBackup) TestBuildBackupMeta(c *C) { + req := kvproto.BackupRequest{ + ClusterId: r.mockPDClient.GetClusterID(r.ctx), + StartVersion: 0, + EndVersion: 0, + } + clusterVersion := "v4.0.10" + brVersion := gluetidb.New().GetVersion() + backupMeta, err := backup.BuildBackupMeta(&req, nil, nil, nil, clusterVersion, brVersion) + c.Assert(err, IsNil) + c.Assert(backupMeta.ClusterId, Equals, req.ClusterId) + c.Assert(backupMeta.ClusterVersion, Equals, clusterVersion) + c.Assert(backupMeta.BrVersion, Equals, brVersion) +} diff --git a/pkg/glue/glue.go b/pkg/glue/glue.go index 34c83756d..7375c676c 100644 --- a/pkg/glue/glue.go +++ b/pkg/glue/glue.go @@ -25,6 +25,9 @@ type Glue interface { // Record records some information useful for log-less summary. Record(name string, value uint64) + + // GetVersion gets BR package version to run backup/restore job + GetVersion() string } // Session is an abstraction of the session.Session interface. diff --git a/pkg/gluetidb/glue.go b/pkg/gluetidb/glue.go index 6d2325456..58ab4a012 100644 --- a/pkg/gluetidb/glue.go +++ b/pkg/gluetidb/glue.go @@ -99,6 +99,12 @@ func (g Glue) Record(name string, value uint64) { g.tikvGlue.Record(name, value) } +// GetVersion implements glue.Glue. +func (g Glue) GetVersion() string { + return g.tikvGlue.GetVersion() +} + +// Execute implements glue.Session. func (gs *tidbSession) Execute(ctx context.Context, sql string) error { _, err := gs.se.Execute(ctx, sql) return errors.Trace(err) diff --git a/pkg/gluetikv/glue.go b/pkg/gluetikv/glue.go index 02954c8eb..6bb28a2c8 100644 --- a/pkg/gluetikv/glue.go +++ b/pkg/gluetikv/glue.go @@ -55,3 +55,8 @@ func (Glue) StartProgress(ctx context.Context, cmdName string, total int64, redi func (Glue) Record(name string, val uint64) { summary.CollectUint(name, val) } + +// GetVersion implements glue.Glue. +func (Glue) GetVersion() string { + return "BR\n" + utils.BRInfo() +} diff --git a/pkg/gluetikv/glue_test.go b/pkg/gluetikv/glue_test.go new file mode 100644 index 000000000..71b445e70 --- /dev/null +++ b/pkg/gluetikv/glue_test.go @@ -0,0 +1,20 @@ +package gluetikv + +import ( + "testing" + + . "github.com/pingcap/check" +) + +type testGlue struct{} + +var _ = Suite(&testGlue{}) + +func TestT(t *testing.T) { + TestingT(t) +} + +func (r *testGlue) TestGetVersion(c *C) { + g := Glue{} + c.Assert(g.GetVersion(), Matches, "BR(.|\n)*Release Version(.|\n)*Git Commit Hash(.|\n)*") +} diff --git a/pkg/task/backup.go b/pkg/task/backup.go index d6d2634e5..118b0d350 100644 --- a/pkg/task/backup.go +++ b/pkg/task/backup.go @@ -252,6 +252,7 @@ func RunBackup(c context.Context, g glue.Glue, cmdName string, cfg *BackupConfig } req := kvproto.BackupRequest{ + ClusterId: client.GetClusterID(), StartVersion: cfg.LastBackupTS, EndVersion: backupTS, RateLimit: cfg.RateLimit, @@ -259,6 +260,11 @@ func RunBackup(c context.Context, g glue.Glue, cmdName string, cfg *BackupConfig CompressionType: cfg.CompressionType, CompressionLevel: cfg.CompressionLevel, } + brVersion := g.GetVersion() + clusterVersion, err := mgr.GetClusterVersion(ctx) + if err != nil { + return errors.Trace(err) + } ranges, backupSchemas, err := backup.BuildBackupRangeAndSchema( mgr.GetDomain(), mgr.GetTiKV(), cfg.TableFilter, backupTS, cfg.IgnoreStats) @@ -267,7 +273,7 @@ func RunBackup(c context.Context, g glue.Glue, cmdName string, cfg *BackupConfig } // nothing to backup if ranges == nil { - backupMeta, err2 := backup.BuildBackupMeta(&req, nil, nil, nil) + backupMeta, err2 := backup.BuildBackupMeta(&req, nil, nil, nil, clusterVersion, brVersion) if err2 != nil { return errors.Trace(err2) } @@ -319,7 +325,7 @@ func RunBackup(c context.Context, g glue.Glue, cmdName string, cfg *BackupConfig // Backup has finished updateCh.Close() - backupMeta, err := backup.BuildBackupMeta(&req, files, nil, ddlJobs) + backupMeta, err := backup.BuildBackupMeta(&req, files, nil, ddlJobs, clusterVersion, brVersion) if err != nil { return errors.Trace(err) } diff --git a/pkg/task/backup_raw.go b/pkg/task/backup_raw.go index 732d9d76c..4bf0c8533 100644 --- a/pkg/task/backup_raw.go +++ b/pkg/task/backup_raw.go @@ -160,6 +160,12 @@ func RunBackupRaw(c context.Context, g glue.Glue, cmdName string, cfg *RawKvConf } } + brVersion := g.GetVersion() + clusterVersion, err := mgr.GetClusterVersion(ctx) + if err != nil { + return errors.Trace(err) + } + // The number of regions need to backup approximateRegions, err := mgr.GetRegionCount(ctx, backupRange.StartKey, backupRange.EndKey) if err != nil { @@ -174,6 +180,7 @@ func RunBackupRaw(c context.Context, g glue.Glue, cmdName string, cfg *RawKvConf ctx, cmdName, int64(approximateRegions), !cfg.LogProgress) req := kvproto.BackupRequest{ + ClusterId: client.GetClusterID(), StartVersion: 0, EndVersion: 0, RateLimit: cfg.RateLimit, @@ -192,7 +199,7 @@ func RunBackupRaw(c context.Context, g glue.Glue, cmdName string, cfg *RawKvConf // Checksum rawRanges := []*kvproto.RawRange{{StartKey: backupRange.StartKey, EndKey: backupRange.EndKey, Cf: cfg.CF}} - backupMeta, err := backup.BuildBackupMeta(&req, files, rawRanges, nil) + backupMeta, err := backup.BuildBackupMeta(&req, files, rawRanges, nil, clusterVersion, brVersion) if err != nil { return errors.Trace(err) } diff --git a/tests/br_backup_version/run.sh b/tests/br_backup_version/run.sh new file mode 100644 index 000000000..cef2e5b55 --- /dev/null +++ b/tests/br_backup_version/run.sh @@ -0,0 +1,83 @@ +#!/bin/bash +# +# Copyright 2021 PingCAP, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# See the License for the specific language governing permissions and +# limitations under the License. + +set -eu +DB="$TEST_NAME" + +# example +# "cluster_id": 6931331682760961243 +expected_cluster_id=`run_curl "https://$PD_ADDR/pd/api/v1/members" | grep "cluster_id"` +# example +#"4.0.10" +expected_cluster_version=`run_curl "https://$PD_ADDR/pd/api/v1/config/cluster-version"` +unset BR_LOG_TO_TERM + +function check_version() { + folder=$1 + expected_br_version=$2 + br_version=`run_br -s "local://$TEST_DIR/$folder" debug decode --field "BrVersion"` + [[ $br_version =~ $expected_br_version ]] + cluster_version=`run_br -s "local://$TEST_DIR/$folder" debug decode --field "ClusterVersion"` + [[ $cluster_version =~ $expected_cluster_version ]] + cluster_id=`run_br -s "local://$TEST_DIR/$folder" debug decode --field "ClusterId" | sed -n -e '1p'` + [[ $expected_cluster_id =~ $cluster_id ]] +} + +# backup empty using BR +echo "backup start..." +run_br --pd $PD_ADDR backup full -s "local://$TEST_DIR/br_version_1" --ratelimit 5 --concurrency 4 +if [ $? -ne 0 ]; then + echo "TEST: [$TEST_NAME] failed on backup empty cluster version!" + exit 1 +fi + +check_version "br_version_1" "BR" + +# backup empty using BR via SQL +echo "backup start..." +run_sql "BACKUP DATABASE $DB TO \"local://$TEST_DIR/br_version_2\"" + +# FIXME: uncomment this after TiDB updates this BR dependency +# check_version "br_version_2" "TiDB" + +# create a database and insert some data +run_sql "CREATE DATABASE $DB;" +run_sql "CREATE TABLE $DB.usertable1 ( \ + YCSB_KEY varchar(64) NOT NULL, \ + FIELD0 varchar(1) DEFAULT NULL, \ + PRIMARY KEY (YCSB_KEY) \ +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin;" +# insert one row to make sure table is restored. +run_sql "INSERT INTO $DB.usertable1 VALUES (\"a\", \"b\");" + +# backup tables using BR +echo "backup start..." +run_br --pd $PD_ADDR backup full -s "local://$TEST_DIR/br_version_3" --ratelimit 5 --concurrency 4 +if [ $? -ne 0 ]; then + echo "TEST: [$TEST_NAME] failed on backup empty cluster version!" + exit 1 +fi + +check_version "br_version_3" "BR" + +# backup tables using BR via SQL +echo "backup start..." +run_sql "BACKUP DATABASE $DB TO \"local://$TEST_DIR/br_version_4\"" + +# FIXME: uncomment this after TiDB updates this BR dependency +# check_version "br_version_4" "TiDB" + +run_sql "DROP DATABASE $DB" +echo "TEST: [$TEST_NAME] successed!"