Skip to content
This repository has been archived by the owner on Jul 24, 2024. It is now read-only.

task: expose table filter for backup full and restore full #313

Merged
merged 6 commits into from
Jun 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions cmd/backup.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ func newFullBackupCommand() *cobra.Command {
return runBackupCommand(command, "Full backup")
},
}
task.DefineFilterFlags(command)
return command
}

Expand Down
1 change: 1 addition & 0 deletions cmd/restore.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ func newFullRestoreCommand() *cobra.Command {
return runRestoreCommand(cmd, "Full restore")
},
}
task.DefineFilterFlags(command)
return command
}

Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ require (
github.com/pingcap/parser v0.0.0-20200518090819-ec1e13b948b1
github.com/pingcap/pd/v4 v4.0.0-rc.2.0.20200520083007-2c251bd8f181
github.com/pingcap/tidb v1.1.0-beta.0.20200521154755-134e691d6f5f
github.com/pingcap/tidb-tools v4.0.0-rc.1.0.20200514040632-f76b3e428e19+incompatible
github.com/pingcap/tidb-tools v4.0.0-rc.2.0.20200521050818-6dd445d83fe0+incompatible
github.com/pingcap/tipb v0.0.0-20200417094153-7316d94df1ee
github.com/prometheus/client_golang v1.5.1
github.com/prometheus/common v0.9.1
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,8 @@ github.com/pingcap/tidb-tools v4.0.0-rc.1.0.20200421113014-507d2bb3a15e+incompat
github.com/pingcap/tidb-tools v4.0.0-rc.1.0.20200421113014-507d2bb3a15e+incompatible/go.mod h1:XGdcy9+yqlDSEMTpOXnwf3hiTeqrV6MN/u1se9N8yIM=
github.com/pingcap/tidb-tools v4.0.0-rc.1.0.20200514040632-f76b3e428e19+incompatible h1:/JKsYjsa5Ug8v5CN4zIbJGIqsvgBUkGwaP/rEScVvWM=
github.com/pingcap/tidb-tools v4.0.0-rc.1.0.20200514040632-f76b3e428e19+incompatible/go.mod h1:XGdcy9+yqlDSEMTpOXnwf3hiTeqrV6MN/u1se9N8yIM=
github.com/pingcap/tidb-tools v4.0.0-rc.2.0.20200521050818-6dd445d83fe0+incompatible h1:e+j+rsJYX+J7eTkgjnGBH2/T3NS6GNSPD6nHA5bPdCI=
github.com/pingcap/tidb-tools v4.0.0-rc.2.0.20200521050818-6dd445d83fe0+incompatible/go.mod h1:XGdcy9+yqlDSEMTpOXnwf3hiTeqrV6MN/u1se9N8yIM=
github.com/pingcap/tipb v0.0.0-20190428032612-535e1abaa330/go.mod h1:RtkHW8WbcNxj8lsbzjaILci01CtYnYbIkQhjyZWrWVI=
github.com/pingcap/tipb v0.0.0-20200417094153-7316d94df1ee h1:XJQ6/LGzOSc/jo33AD8t7jtc4GohxcyODsYnb+kZXJM=
github.com/pingcap/tipb v0.0.0-20200417094153-7316d94df1ee/go.mod h1:RtkHW8WbcNxj8lsbzjaILci01CtYnYbIkQhjyZWrWVI=
Expand Down
6 changes: 3 additions & 3 deletions pkg/backup/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import (
"github.com/pingcap/log"
"github.com/pingcap/parser/model"
pd "github.com/pingcap/pd/v4/client"
"github.com/pingcap/tidb-tools/pkg/filter"
"github.com/pingcap/tidb-tools/pkg/table-filter"
"github.com/pingcap/tidb/distsql"
"github.com/pingcap/tidb/domain"
"github.com/pingcap/tidb/kv"
Expand Down Expand Up @@ -210,7 +210,7 @@ func appendRanges(tbl *model.TableInfo, tblID int64) ([]kv.KeyRange, error) {
func BuildBackupRangeAndSchema(
dom *domain.Domain,
storage kv.Storage,
tableFilter *filter.Filter,
tableFilter filter.Filter,
backupTS uint64,
) ([]rtree.Range, *Schemas, error) {
info, err := dom.GetSnapshotInfoSchema(backupTS)
Expand All @@ -232,7 +232,7 @@ func BuildBackupRangeAndSchema(
randAlloc := autoid.NewAllocator(storage, dbInfo.ID, false, autoid.AutoRandomType)

for _, tableInfo := range dbInfo.Tables {
if !tableFilter.Match(&filter.Table{Schema: dbInfo.Name.L, Name: tableInfo.Name.L}) {
if !tableFilter.MatchTable(dbInfo.Name.O, tableInfo.Name.O) {
// Skip tables other than the given table.
continue
}
Expand Down
12 changes: 4 additions & 8 deletions pkg/backup/schema_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
"sync/atomic"

. "github.com/pingcap/check"
"github.com/pingcap/tidb-tools/pkg/filter"
"github.com/pingcap/tidb-tools/pkg/table-filter"
"github.com/pingcap/tidb/util/testkit"
"github.com/pingcap/tidb/util/testleak"

Expand Down Expand Up @@ -57,27 +57,23 @@ func (s *testBackupSchemaSuite) TestBuildBackupRangeAndSchema(c *C) {
tk := testkit.NewTestKit(c, s.mock.Storage)

// Table t1 is not exist.
testFilter, err := filter.New(false, &filter.Rules{
DoTables: []*filter.Table{{Schema: "test", Name: "t1"}},
})
testFilter, err := filter.Parse([]string{"test.t1"})
c.Assert(err, IsNil)
_, backupSchemas, err := backup.BuildBackupRangeAndSchema(
s.mock.Domain, s.mock.Storage, testFilter, math.MaxUint64)
c.Assert(err, IsNil)
c.Assert(backupSchemas, IsNil)

// Database is not exist.
fooFilter, err := filter.New(false, &filter.Rules{
DoTables: []*filter.Table{{Schema: "foo", Name: "t1"}},
})
fooFilter, err := filter.Parse([]string{"foo.t1"})
c.Assert(err, IsNil)
_, backupSchemas, err = backup.BuildBackupRangeAndSchema(
s.mock.Domain, s.mock.Storage, fooFilter, math.MaxUint64)
c.Assert(err, IsNil)
c.Assert(backupSchemas, IsNil)

// Empty database.
noFilter, err := filter.New(false, &filter.Rules{})
noFilter, err := filter.Parse([]string{"*.*"})
c.Assert(err, IsNil)
_, backupSchemas, err = backup.BuildBackupRangeAndSchema(
s.mock.Domain, s.mock.Storage, noFilter, math.MaxUint64)
Expand Down
7 changes: 1 addition & 6 deletions pkg/task/backup.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import (
"github.com/pingcap/log"
"github.com/pingcap/parser/model"
"github.com/pingcap/parser/mysql"
"github.com/pingcap/tidb-tools/pkg/filter"
"github.com/pingcap/tidb/sessionctx/stmtctx"
"github.com/pingcap/tidb/sessionctx/variable"
"github.com/pingcap/tidb/types"
Expand Down Expand Up @@ -109,10 +108,6 @@ func RunBackup(c context.Context, g glue.Glue, cmdName string, cfg *BackupConfig
if err != nil {
return err
}
tableFilter, err := filter.New(cfg.CaseSensitive, &cfg.Filter)
if err != nil {
return err
}
mgr, err := newMgr(ctx, g, cfg.PD, cfg.TLS, conn.SkipTiFlash, cfg.CheckRequirements)
if err != nil {
return err
Expand All @@ -135,7 +130,7 @@ func RunBackup(c context.Context, g glue.Glue, cmdName string, cfg *BackupConfig
g.Record("BackupTS", backupTS)

ranges, backupSchemas, err := backup.BuildBackupRangeAndSchema(
mgr.GetDomain(), mgr.GetTiKV(), tableFilter, backupTS)
mgr.GetDomain(), mgr.GetTiKV(), cfg.TableFilter, backupTS)
if err != nil {
return err
}
Expand Down
70 changes: 50 additions & 20 deletions pkg/task/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,14 @@ import (
"crypto/tls"
"fmt"
"net/url"
"regexp"
"strings"

"github.com/gogo/protobuf/proto"
"github.com/pingcap/errors"
"github.com/pingcap/kvproto/pkg/backup"
"github.com/pingcap/log"
pd "github.com/pingcap/pd/v4/client"
"github.com/pingcap/tidb-tools/pkg/filter"
filter "github.com/pingcap/tidb-tools/pkg/table-filter"
"github.com/pingcap/tidb/store/tikv"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
Expand Down Expand Up @@ -49,6 +48,8 @@ const (
flagRateLimitUnit = "ratelimit-unit"
flagConcurrency = "concurrency"
flagChecksum = "checksum"
flagFilter = "filter"
flagCaseSensitive = "case-sensitive"
flagRemoveTiFlash = "remove-tiflash"
flagCheckRequirement = "check-requirements"
)
Expand Down Expand Up @@ -93,10 +94,20 @@ type Config struct {
// LogProgress is true means the progress bar is printed to the log instead of stdout.
LogProgress bool `json:"log-progress" toml:"log-progress"`

RemoveTiFlash bool `json:"remove-tiflash" toml:"remove-tiflash"`
CaseSensitive bool `json:"case-sensitive" toml:"case-sensitive"`
CheckRequirements bool `json:"check-requirements" toml:"check-requirements"`
Filter filter.Rules `json:"black-white-list" toml:"black-white-list"`
// CaseSensitive should not be used.
//
// Deprecated: This field is kept only to satisfy the cyclic dependency with TiDB. This field
// should be removed after TiDB upgrades the BR dependency.
CaseSensitive bool
// Filter should not be used, use TableFilter instead.
//
// Deprecated: This field is kept only to satisfy the cyclic dependency with TiDB. This field
// should be removed after TiDB upgrades the BR dependency.
Filter filter.MySQLReplicationRules

TableFilter filter.Filter `json:"-" toml:"-"`
RemoveTiFlash bool `json:"remove-tiflash" toml:"remove-tiflash"`
CheckRequirements bool `json:"check-requirements" toml:"check-requirements"`
}

// DefineCommonFlags defines the flags common to all BRIE commands.
Expand Down Expand Up @@ -128,19 +139,26 @@ func DefineCommonFlags(flags *pflag.FlagSet) {
storage.DefineFlags(flags)
}

// DefineDatabaseFlags defines the required --db flag.
// DefineDatabaseFlags defines the required --db flag for `db` subcommand.
func DefineDatabaseFlags(command *cobra.Command) {
command.Flags().String(flagDatabase, "", "database name")
_ = command.MarkFlagRequired(flagDatabase)
}

// DefineTableFlags defines the required --db and --table flags.
// DefineTableFlags defines the required --db and --table flags for `table` subcommand.
func DefineTableFlags(command *cobra.Command) {
DefineDatabaseFlags(command)
command.Flags().StringP(flagTable, "t", "", "table name")
_ = command.MarkFlagRequired(flagTable)
}

// DefineFilterFlags defines the --filter and --case-sensitive flags for `full` subcommand.
func DefineFilterFlags(command *cobra.Command) {
flags := command.Flags()
flags.StringArrayP(flagFilter, "f", []string{"*.*"}, "select tables to process")
flags.Bool(flagCaseSensitive, false, "whether the table names used in --filter should be case-sensitive")
}

// ParseFromFlags parses the TLS config from the flag set.
func (tls *TLSConfig) ParseFromFlags(flags *pflag.FlagSet) error {
var err error
Expand Down Expand Up @@ -202,20 +220,39 @@ func (cfg *Config) ParseFromFlags(flags *pflag.FlagSet) error {
return errors.Trace(err)
}

if dbFlag := flags.Lookup(flagDatabase); dbFlag != nil {
db := escapeFilterName(dbFlag.Value.String())
var caseSensitive bool
if filterFlag := flags.Lookup(flagFilter); filterFlag != nil {
f, err := filter.Parse(filterFlag.Value.(pflag.SliceValue).GetSlice())
if err != nil {
return err
}
cfg.TableFilter = f
caseSensitive, err = flags.GetBool(flagCaseSensitive)
if err != nil {
return errors.Trace(err)
}
} else if dbFlag := flags.Lookup(flagDatabase); dbFlag != nil {
db := dbFlag.Value.String()
if len(db) == 0 {
return errors.New("empty database name is not allowed")
}
if tblFlag := flags.Lookup(flagTable); tblFlag != nil {
tbl := escapeFilterName(tblFlag.Value.String())
tbl := tblFlag.Value.String()
if len(tbl) == 0 {
return errors.New("empty table name is not allowed")
}
cfg.Filter.DoTables = []*filter.Table{{Schema: db, Name: tbl}}
cfg.TableFilter = filter.NewTablesFilter(filter.Table{
Schema: db,
Name: tbl,
})
} else {
cfg.Filter.DoDBs = []string{db}
cfg.TableFilter = filter.NewSchemasFilter(db)
}
} else {
cfg.TableFilter, _ = filter.Parse([]string{"*.*"})
}
if !caseSensitive {
cfg.TableFilter = filter.CaseInsensitive(cfg.TableFilter)
}
checkRequirements, err := flags.GetBool(flagCheckRequirement)
if err != nil {
Expand Down Expand Up @@ -303,13 +340,6 @@ func ReadBackupMeta(
return u, s, backupMeta, nil
}

func escapeFilterName(name string) string {
if !strings.HasPrefix(name, "~") {
return name
}
return "~^" + regexp.QuoteMeta(name) + "$"
}

// flagToZapField checks whether this flag can be logged,
// if need to log, return its zap field. Or return a field with hidden value.
func flagToZapField(f *pflag.Flag) zap.Field {
Expand Down
22 changes: 5 additions & 17 deletions pkg/task/restore.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"github.com/pingcap/kvproto/pkg/backup"
"github.com/pingcap/log"
"github.com/pingcap/parser/model"
"github.com/pingcap/tidb-tools/pkg/filter"
"github.com/pingcap/tidb/config"
"github.com/spf13/pflag"
"go.uber.org/zap"
Expand Down Expand Up @@ -148,9 +147,9 @@ func RunRestore(c context.Context, g glue.Glue, cmdName string, cfg *RestoreConf
return errors.New("cannot do transactional restore from raw kv data")
}

files, tables, dbs, err := filterRestoreFiles(client, cfg)
if err != nil {
return err
files, tables, dbs := filterRestoreFiles(client, cfg)
if len(dbs) == 0 && len(tables) != 0 {
return errors.New("invalid backup, contain tables but no databases")
}

var newTS uint64
Expand All @@ -161,9 +160,6 @@ func RunRestore(c context.Context, g glue.Glue, cmdName string, cfg *RestoreConf
}
}
ddlJobs := restore.FilterDDLJobs(client.GetDDLJobs(), tables)
if err != nil {
return err
}

// pre-set TiDB config for restore
enableTiDBConfig()
Expand Down Expand Up @@ -328,16 +324,11 @@ func RunRestore(c context.Context, g glue.Glue, cmdName string, cfg *RestoreConf
func filterRestoreFiles(
client *restore.Client,
cfg *RestoreConfig,
) (files []*backup.File, tables []*utils.Table, dbs []*utils.Database, err error) {
tableFilter, err := filter.New(cfg.CaseSensitive, &cfg.Filter)
if err != nil {
return nil, nil, nil, err
}

) (files []*backup.File, tables []*utils.Table, dbs []*utils.Database) {
for _, db := range client.GetDatabases() {
createdDatabase := false
for _, table := range db.Tables {
if !tableFilter.Match(&filter.Table{Schema: db.Info.Name.O, Name: table.Info.Name.O}) {
if !cfg.TableFilter.MatchTable(db.Info.Name.O, table.Info.Name.O) {
continue
}

Expand All @@ -349,9 +340,6 @@ func filterRestoreFiles(
tables = append(tables, table)
}
}
if len(dbs) == 0 && len(tables) != 0 {
err = errors.New("invalid backup, contain tables but no databases")
}
return
}

Expand Down
Loading