github.com/pingcap/br@v5.3.0-alpha.0.20220125034240-ec59c7b6ce30+incompatible/pkg/task/common.go (about)

     1  // Copyright 2020 PingCAP, Inc. Licensed under Apache-2.0.
     2  
     3  package task
     4  
     5  import (
     6  	"context"
     7  	"crypto/tls"
     8  	"fmt"
     9  	"net/url"
    10  	"path"
    11  	"strings"
    12  	"time"
    13  
    14  	gcs "cloud.google.com/go/storage"
    15  	"github.com/docker/go-units"
    16  	"github.com/gogo/protobuf/proto"
    17  	"github.com/pingcap/errors"
    18  	backuppb "github.com/pingcap/kvproto/pkg/backup"
    19  	"github.com/pingcap/log"
    20  	filter "github.com/pingcap/tidb-tools/pkg/table-filter"
    21  	"github.com/pingcap/tidb/sessionctx/variable"
    22  	"github.com/spf13/cobra"
    23  	"github.com/spf13/pflag"
    24  	pd "github.com/tikv/pd/client"
    25  	"go.etcd.io/etcd/pkg/transport"
    26  	"go.uber.org/zap"
    27  	"google.golang.org/grpc/keepalive"
    28  
    29  	"github.com/pingcap/br/pkg/conn"
    30  	berrors "github.com/pingcap/br/pkg/errors"
    31  	"github.com/pingcap/br/pkg/glue"
    32  	"github.com/pingcap/br/pkg/storage"
    33  	"github.com/pingcap/br/pkg/utils"
    34  )
    35  
    36  const (
    37  	// flagSendCreds specify whether to send credentials to tikv
    38  	flagSendCreds = "send-credentials-to-tikv"
    39  	// No credentials specifies that cloud credentials should not be loaded
    40  	flagNoCreds = "no-credentials"
    41  	// flagStorage is the name of storage flag.
    42  	flagStorage = "storage"
    43  	// flagPD is the name of PD url flag.
    44  	flagPD = "pd"
    45  	// flagCA is the name of TLS CA flag.
    46  	flagCA = "ca"
    47  	// flagCert is the name of TLS cert flag.
    48  	flagCert = "cert"
    49  	// flagKey is the name of TLS key flag.
    50  	flagKey = "key"
    51  
    52  	flagDatabase = "db"
    53  	flagTable    = "table"
    54  
    55  	flagChecksumConcurrency = "checksum-concurrency"
    56  	flagRateLimit           = "ratelimit"
    57  	flagRateLimitUnit       = "ratelimit-unit"
    58  	flagConcurrency         = "concurrency"
    59  	flagChecksum            = "checksum"
    60  	flagFilter              = "filter"
    61  	flagCaseSensitive       = "case-sensitive"
    62  	flagRemoveTiFlash       = "remove-tiflash"
    63  	flagCheckRequirement    = "check-requirements"
    64  	flagSwitchModeInterval  = "switch-mode-interval"
    65  	// flagGrpcKeepaliveTime is the interval of pinging the server.
    66  	flagGrpcKeepaliveTime = "grpc-keepalive-time"
    67  	// flagGrpcKeepaliveTimeout is the max time a grpc conn can keep idel before killed.
    68  	flagGrpcKeepaliveTimeout = "grpc-keepalive-timeout"
    69  	// flagEnableOpenTracing is whether to enable opentracing
    70  	flagEnableOpenTracing = "enable-opentracing"
    71  	flagSkipCheckPath     = "skip-check-path"
    72  
    73  	defaultSwitchInterval       = 5 * time.Minute
    74  	defaultGRPCKeepaliveTime    = 10 * time.Second
    75  	defaultGRPCKeepaliveTimeout = 3 * time.Second
    76  
    77  	unlimited = 0
    78  )
    79  
    80  // TLSConfig is the common configuration for TLS connection.
    81  type TLSConfig struct {
    82  	CA   string `json:"ca" toml:"ca"`
    83  	Cert string `json:"cert" toml:"cert"`
    84  	Key  string `json:"key" toml:"key"`
    85  }
    86  
    87  // IsEnabled checks if TLS open or not.
    88  func (tls *TLSConfig) IsEnabled() bool {
    89  	return tls.CA != ""
    90  }
    91  
    92  // ToTLSConfig generate tls.Config.
    93  func (tls *TLSConfig) ToTLSConfig() (*tls.Config, error) {
    94  	tlsInfo := transport.TLSInfo{
    95  		CertFile:      tls.Cert,
    96  		KeyFile:       tls.Key,
    97  		TrustedCAFile: tls.CA,
    98  	}
    99  	tlsConfig, err := tlsInfo.ClientConfig()
   100  	if err != nil {
   101  		return nil, errors.Trace(err)
   102  	}
   103  	return tlsConfig, nil
   104  }
   105  
   106  // Config is the common configuration for all BRIE tasks.
   107  type Config struct {
   108  	storage.BackendOptions
   109  
   110  	Storage             string    `json:"storage" toml:"storage"`
   111  	PD                  []string  `json:"pd" toml:"pd"`
   112  	TLS                 TLSConfig `json:"tls" toml:"tls"`
   113  	RateLimit           uint64    `json:"rate-limit" toml:"rate-limit"`
   114  	ChecksumConcurrency uint      `json:"checksum-concurrency" toml:"checksum-concurrency"`
   115  	Concurrency         uint32    `json:"concurrency" toml:"concurrency"`
   116  	Checksum            bool      `json:"checksum" toml:"checksum"`
   117  	SendCreds           bool      `json:"send-credentials-to-tikv" toml:"send-credentials-to-tikv"`
   118  	// LogProgress is true means the progress bar is printed to the log instead of stdout.
   119  	LogProgress bool `json:"log-progress" toml:"log-progress"`
   120  
   121  	// CaseSensitive should not be used.
   122  	//
   123  	// Deprecated: This field is kept only to satisfy the cyclic dependency with TiDB. This field
   124  	// should be removed after TiDB upgrades the BR dependency.
   125  	CaseSensitive bool
   126  
   127  	// NoCreds means don't try to load cloud credentials
   128  	NoCreds bool `json:"no-credentials" toml:"no-credentials"`
   129  
   130  	CheckRequirements bool `json:"check-requirements" toml:"check-requirements"`
   131  	// EnableOpenTracing is whether to enable opentracing
   132  	EnableOpenTracing bool `json:"enable-opentracing" toml:"enable-opentracing"`
   133  	// SkipCheckPath skips verifying the path
   134  	// deprecated
   135  	SkipCheckPath bool `json:"skip-check-path" toml:"skip-check-path"`
   136  	// Filter should not be used, use TableFilter instead.
   137  	//
   138  	// Deprecated: This field is kept only to satisfy the cyclic dependency with TiDB. This field
   139  	// should be removed after TiDB upgrades the BR dependency.
   140  	Filter filter.MySQLReplicationRules
   141  
   142  	TableFilter        filter.Filter `json:"-" toml:"-"`
   143  	SwitchModeInterval time.Duration `json:"switch-mode-interval" toml:"switch-mode-interval"`
   144  	// Schemas is a database name set, to check whether the restore database has been backup
   145  	Schemas map[string]struct{}
   146  	// Tables is a table name set, to check whether the restore table has been backup
   147  	Tables map[string]struct{}
   148  
   149  	// GrpcKeepaliveTime is the interval of pinging the server.
   150  	GRPCKeepaliveTime time.Duration `json:"grpc-keepalive-time" toml:"grpc-keepalive-time"`
   151  	// GrpcKeepaliveTimeout is the max time a grpc conn can keep idel before killed.
   152  	GRPCKeepaliveTimeout time.Duration `json:"grpc-keepalive-timeout" toml:"grpc-keepalive-timeout"`
   153  }
   154  
   155  // DefineCommonFlags defines the flags common to all BRIE commands.
   156  func DefineCommonFlags(flags *pflag.FlagSet) {
   157  	flags.BoolP(flagSendCreds, "c", true, "Whether send credentials to tikv")
   158  	flags.StringP(flagStorage, "s", "", `specify the url where backup storage, eg, "s3://bucket/path/prefix"`)
   159  	flags.StringSliceP(flagPD, "u", []string{"127.0.0.1:2379"}, "PD address")
   160  	flags.String(flagCA, "", "CA certificate path for TLS connection")
   161  	flags.String(flagCert, "", "Certificate path for TLS connection")
   162  	flags.String(flagKey, "", "Private key path for TLS connection")
   163  	flags.Uint(flagChecksumConcurrency, variable.DefChecksumTableConcurrency, "The concurrency of table checksumming")
   164  	_ = flags.MarkHidden(flagChecksumConcurrency)
   165  
   166  	flags.Uint64(flagRateLimit, unlimited, "The rate limit of the task, MB/s per node")
   167  	flags.Bool(flagChecksum, true, "Run checksum at end of task")
   168  	flags.Bool(flagRemoveTiFlash, true,
   169  		"Remove TiFlash replicas before backup or restore, for unsupported versions of TiFlash")
   170  
   171  	// Default concurrency is different for backup and restore.
   172  	// Leave it 0 and let them adjust the value.
   173  	flags.Uint32(flagConcurrency, 0, "The size of thread pool on each node that executes the task")
   174  	// It may confuse users , so just hide it.
   175  	_ = flags.MarkHidden(flagConcurrency)
   176  
   177  	flags.Uint64(flagRateLimitUnit, units.MiB, "The unit of rate limit")
   178  	_ = flags.MarkHidden(flagRateLimitUnit)
   179  	_ = flags.MarkDeprecated(flagRemoveTiFlash,
   180  		"TiFlash is fully supported by BR now, removing TiFlash isn't needed any more. This flag would be ignored.")
   181  
   182  	flags.Bool(flagCheckRequirement, true,
   183  		"Whether start version check before execute command")
   184  	flags.Duration(flagSwitchModeInterval, defaultSwitchInterval, "maintain import mode on TiKV during restore")
   185  	flags.Duration(flagGrpcKeepaliveTime, defaultGRPCKeepaliveTime,
   186  		"the interval of pinging gRPC peer, must keep the same value with TiKV and PD")
   187  	flags.Duration(flagGrpcKeepaliveTimeout, defaultGRPCKeepaliveTimeout,
   188  		"the max time a gRPC connection can keep idle before killed, must keep the same value with TiKV and PD")
   189  	_ = flags.MarkHidden(flagGrpcKeepaliveTime)
   190  	_ = flags.MarkHidden(flagGrpcKeepaliveTimeout)
   191  
   192  	flags.Bool(flagEnableOpenTracing, false,
   193  		"Set whether to enable opentracing during the backup/restore process")
   194  
   195  	flags.BoolP(flagNoCreds, "", false, "Don't load credentials")
   196  	_ = flags.MarkHidden(flagNoCreds)
   197  	flags.BoolP(flagSkipCheckPath, "", false, "Skip path verification")
   198  	_ = flags.MarkHidden(flagSkipCheckPath)
   199  
   200  	storage.DefineFlags(flags)
   201  }
   202  
   203  // DefineDatabaseFlags defines the required --db flag for `db` subcommand.
   204  func DefineDatabaseFlags(command *cobra.Command) {
   205  	command.Flags().String(flagDatabase, "", "database name")
   206  	_ = command.MarkFlagRequired(flagDatabase)
   207  }
   208  
   209  // DefineTableFlags defines the required --db and --table flags for `table` subcommand.
   210  func DefineTableFlags(command *cobra.Command) {
   211  	DefineDatabaseFlags(command)
   212  	command.Flags().StringP(flagTable, "t", "", "table name")
   213  	_ = command.MarkFlagRequired(flagTable)
   214  }
   215  
   216  // DefineFilterFlags defines the --filter and --case-sensitive flags for `full` subcommand.
   217  func DefineFilterFlags(command *cobra.Command, defaultFilter []string) {
   218  	flags := command.Flags()
   219  	flags.StringArrayP(flagFilter, "f", defaultFilter, "select tables to process")
   220  	flags.Bool(flagCaseSensitive, false, "whether the table names used in --filter should be case-sensitive")
   221  }
   222  
   223  // ParseFromFlags parses the TLS config from the flag set.
   224  func (tls *TLSConfig) ParseFromFlags(flags *pflag.FlagSet) error {
   225  	var err error
   226  	tls.CA, tls.Cert, tls.Key, err = ParseTLSTripleFromFlags(flags)
   227  	return err
   228  }
   229  
   230  // ParseTLSTripleFromFlags parses the (ca, cert, key) triple from flags.
   231  func ParseTLSTripleFromFlags(flags *pflag.FlagSet) (ca, cert, key string, err error) {
   232  	ca, err = flags.GetString(flagCA)
   233  	if err != nil {
   234  		return
   235  	}
   236  	cert, err = flags.GetString(flagCert)
   237  	if err != nil {
   238  		return
   239  	}
   240  	key, err = flags.GetString(flagKey)
   241  	if err != nil {
   242  		return
   243  	}
   244  	return
   245  }
   246  
   247  func (cfg *Config) normalizePDURLs() error {
   248  	for i := range cfg.PD {
   249  		var err error
   250  		cfg.PD[i], err = normalizePDURL(cfg.PD[i], cfg.TLS.IsEnabled())
   251  		if err != nil {
   252  			return errors.Trace(err)
   253  		}
   254  	}
   255  	return nil
   256  }
   257  
   258  // ParseFromFlags parses the config from the flag set.
   259  func (cfg *Config) ParseFromFlags(flags *pflag.FlagSet) error {
   260  	var err error
   261  	if cfg.Storage, err = flags.GetString(flagStorage); err != nil {
   262  		return errors.Trace(err)
   263  	}
   264  	if cfg.SendCreds, err = flags.GetBool(flagSendCreds); err != nil {
   265  		return errors.Trace(err)
   266  	}
   267  	if cfg.NoCreds, err = flags.GetBool(flagNoCreds); err != nil {
   268  		return errors.Trace(err)
   269  	}
   270  	if cfg.Concurrency, err = flags.GetUint32(flagConcurrency); err != nil {
   271  		return errors.Trace(err)
   272  	}
   273  	if cfg.Checksum, err = flags.GetBool(flagChecksum); err != nil {
   274  		return errors.Trace(err)
   275  	}
   276  	if cfg.ChecksumConcurrency, err = flags.GetUint(flagChecksumConcurrency); err != nil {
   277  		return errors.Trace(err)
   278  	}
   279  
   280  	var rateLimit, rateLimitUnit uint64
   281  	if rateLimit, err = flags.GetUint64(flagRateLimit); err != nil {
   282  		return errors.Trace(err)
   283  	}
   284  	if rateLimitUnit, err = flags.GetUint64(flagRateLimitUnit); err != nil {
   285  		return errors.Trace(err)
   286  	}
   287  	cfg.RateLimit = rateLimit * rateLimitUnit
   288  
   289  	cfg.Schemas = make(map[string]struct{})
   290  	cfg.Tables = make(map[string]struct{})
   291  	var caseSensitive bool
   292  	if filterFlag := flags.Lookup(flagFilter); filterFlag != nil {
   293  		var f filter.Filter
   294  		f, err = filter.Parse(filterFlag.Value.(pflag.SliceValue).GetSlice())
   295  		if err != nil {
   296  			return errors.Trace(err)
   297  		}
   298  		cfg.TableFilter = f
   299  		caseSensitive, err = flags.GetBool(flagCaseSensitive)
   300  		if err != nil {
   301  			return errors.Trace(err)
   302  		}
   303  	} else if dbFlag := flags.Lookup(flagDatabase); dbFlag != nil {
   304  		db := dbFlag.Value.String()
   305  		if len(db) == 0 {
   306  			return errors.Annotate(berrors.ErrInvalidArgument, "empty database name is not allowed")
   307  		}
   308  		cfg.Schemas[utils.EncloseName(db)] = struct{}{}
   309  		if tblFlag := flags.Lookup(flagTable); tblFlag != nil {
   310  			tbl := tblFlag.Value.String()
   311  			if len(tbl) == 0 {
   312  				return errors.Annotate(berrors.ErrInvalidArgument, "empty table name is not allowed")
   313  			}
   314  			cfg.Tables[utils.EncloseDBAndTable(db, tbl)] = struct{}{}
   315  			cfg.TableFilter = filter.NewTablesFilter(filter.Table{
   316  				Schema: db,
   317  				Name:   tbl,
   318  			})
   319  		} else {
   320  			cfg.TableFilter = filter.NewSchemasFilter(db)
   321  		}
   322  	} else {
   323  		cfg.TableFilter, _ = filter.Parse([]string{"*.*"})
   324  	}
   325  	if !caseSensitive {
   326  		cfg.TableFilter = filter.CaseInsensitive(cfg.TableFilter)
   327  	}
   328  	checkRequirements, err := flags.GetBool(flagCheckRequirement)
   329  	if err != nil {
   330  		return errors.Trace(err)
   331  	}
   332  	cfg.CheckRequirements = checkRequirements
   333  
   334  	cfg.SwitchModeInterval, err = flags.GetDuration(flagSwitchModeInterval)
   335  	if err != nil {
   336  		return errors.Trace(err)
   337  	}
   338  	cfg.GRPCKeepaliveTime, err = flags.GetDuration(flagGrpcKeepaliveTime)
   339  	if err != nil {
   340  		return errors.Trace(err)
   341  	}
   342  	cfg.GRPCKeepaliveTimeout, err = flags.GetDuration(flagGrpcKeepaliveTimeout)
   343  	if err != nil {
   344  		return errors.Trace(err)
   345  	}
   346  	cfg.EnableOpenTracing, err = flags.GetBool(flagEnableOpenTracing)
   347  	if err != nil {
   348  		return errors.Trace(err)
   349  	}
   350  
   351  	if cfg.SwitchModeInterval <= 0 {
   352  		return errors.Annotatef(berrors.ErrInvalidArgument, "--switch-mode-interval must be positive, %s is not allowed", cfg.SwitchModeInterval)
   353  	}
   354  
   355  	if err = cfg.BackendOptions.ParseFromFlags(flags); err != nil {
   356  		return errors.Trace(err)
   357  	}
   358  	if err = cfg.TLS.ParseFromFlags(flags); err != nil {
   359  		return errors.Trace(err)
   360  	}
   361  	cfg.PD, err = flags.GetStringSlice(flagPD)
   362  	if err != nil {
   363  		return errors.Trace(err)
   364  	}
   365  	if len(cfg.PD) == 0 {
   366  		return errors.Annotate(berrors.ErrInvalidArgument, "must provide at least one PD server address")
   367  	}
   368  	if cfg.SkipCheckPath, err = flags.GetBool(flagSkipCheckPath); err != nil {
   369  		return errors.Trace(err)
   370  	}
   371  	return cfg.normalizePDURLs()
   372  }
   373  
   374  // NewMgr creates a new mgr at the given PD address.
   375  func NewMgr(ctx context.Context,
   376  	g glue.Glue, pds []string,
   377  	tlsConfig TLSConfig,
   378  	keepalive keepalive.ClientParameters,
   379  	checkRequirements bool,
   380  	needDomain bool,
   381  ) (*conn.Mgr, error) {
   382  	var (
   383  		tlsConf *tls.Config
   384  		err     error
   385  	)
   386  	pdAddress := strings.Join(pds, ",")
   387  	if len(pdAddress) == 0 {
   388  		return nil, errors.Annotate(berrors.ErrInvalidArgument, "pd address can not be empty")
   389  	}
   390  
   391  	securityOption := pd.SecurityOption{}
   392  	if tlsConfig.IsEnabled() {
   393  		securityOption.CAPath = tlsConfig.CA
   394  		securityOption.CertPath = tlsConfig.Cert
   395  		securityOption.KeyPath = tlsConfig.Key
   396  		tlsConf, err = tlsConfig.ToTLSConfig()
   397  		if err != nil {
   398  			return nil, errors.Trace(err)
   399  		}
   400  	}
   401  
   402  	// Disable GC because TiDB enables GC already.
   403  	store, err := g.Open(fmt.Sprintf("tikv://%s?disableGC=true", pdAddress), securityOption)
   404  	if err != nil {
   405  		return nil, errors.Trace(err)
   406  	}
   407  
   408  	// Is it necessary to remove `StoreBehavior`?
   409  	return conn.NewMgr(
   410  		ctx, g, pdAddress, store, tlsConf, securityOption, keepalive, conn.SkipTiFlash,
   411  		checkRequirements, needDomain,
   412  	)
   413  }
   414  
   415  // GetStorage gets the storage backend from the config.
   416  func GetStorage(
   417  	ctx context.Context,
   418  	cfg *Config,
   419  ) (*backuppb.StorageBackend, storage.ExternalStorage, error) {
   420  	u, err := storage.ParseBackend(cfg.Storage, &cfg.BackendOptions)
   421  	if err != nil {
   422  		return nil, nil, errors.Trace(err)
   423  	}
   424  	s, err := storage.New(ctx, u, storageOpts(cfg))
   425  	if err != nil {
   426  		return nil, nil, errors.Annotate(err, "create storage failed")
   427  	}
   428  	return u, s, nil
   429  }
   430  
   431  func storageOpts(cfg *Config) *storage.ExternalStorageOptions {
   432  	return &storage.ExternalStorageOptions{
   433  		NoCredentials:   cfg.NoCreds,
   434  		SendCredentials: cfg.SendCreds,
   435  		SkipCheckPath:   cfg.SkipCheckPath,
   436  	}
   437  }
   438  
   439  // ReadBackupMeta reads the backupmeta file from the storage.
   440  func ReadBackupMeta(
   441  	ctx context.Context,
   442  	fileName string,
   443  	cfg *Config,
   444  ) (*backuppb.StorageBackend, storage.ExternalStorage, *backuppb.BackupMeta, error) {
   445  	u, s, err := GetStorage(ctx, cfg)
   446  	if err != nil {
   447  		return nil, nil, nil, errors.Trace(err)
   448  	}
   449  	metaData, err := s.ReadFile(ctx, fileName)
   450  	if err != nil {
   451  		if gcsObjectNotFound(err) {
   452  			// change gcs://bucket/abc/def to gcs://bucket/abc and read defbackupmeta
   453  			oldPrefix := u.GetGcs().GetPrefix()
   454  			newPrefix, file := path.Split(oldPrefix)
   455  			newFileName := file + fileName
   456  			u.GetGcs().Prefix = newPrefix
   457  			s, err = storage.New(ctx, u, storageOpts(cfg))
   458  			if err != nil {
   459  				return nil, nil, nil, errors.Trace(err)
   460  			}
   461  			log.Info("retry load metadata in gcs", zap.String("newPrefix", newPrefix), zap.String("newFileName", newFileName))
   462  			metaData, err = s.ReadFile(ctx, newFileName)
   463  			if err != nil {
   464  				return nil, nil, nil, errors.Trace(err)
   465  			}
   466  			// reset prefix for tikv download sst file correctly.
   467  			u.GetGcs().Prefix = oldPrefix
   468  		} else {
   469  			return nil, nil, nil, errors.Annotate(err, "load backupmeta failed")
   470  		}
   471  	}
   472  	backupMeta := &backuppb.BackupMeta{}
   473  	if err = proto.Unmarshal(metaData, backupMeta); err != nil {
   474  		return nil, nil, nil, errors.Annotate(err, "parse backupmeta failed")
   475  	}
   476  	return u, s, backupMeta, nil
   477  }
   478  
   479  // flagToZapField checks whether this flag can be logged,
   480  // if need to log, return its zap field. Or return a field with hidden value.
   481  func flagToZapField(f *pflag.Flag) zap.Field {
   482  	if f.Name == flagStorage {
   483  		hiddenQuery, err := url.Parse(f.Value.String())
   484  		if err != nil {
   485  			return zap.String(f.Name, "<invalid URI>")
   486  		}
   487  		// hide all query here.
   488  		hiddenQuery.RawQuery = ""
   489  		return zap.Stringer(f.Name, hiddenQuery)
   490  	}
   491  	return zap.Stringer(f.Name, f.Value)
   492  }
   493  
   494  // LogArguments prints origin command arguments.
   495  func LogArguments(cmd *cobra.Command) {
   496  	flags := cmd.Flags()
   497  	fields := make([]zap.Field, 1, flags.NFlag()+1)
   498  	fields[0] = zap.String("__command", cmd.CommandPath())
   499  	flags.Visit(func(f *pflag.Flag) {
   500  		fields = append(fields, flagToZapField(f))
   501  	})
   502  	log.Info("arguments", fields...)
   503  }
   504  
   505  // GetKeepalive get the keepalive info from the config.
   506  func GetKeepalive(cfg *Config) keepalive.ClientParameters {
   507  	return keepalive.ClientParameters{
   508  		Time:    cfg.GRPCKeepaliveTime,
   509  		Timeout: cfg.GRPCKeepaliveTimeout,
   510  	}
   511  }
   512  
   513  // adjust adjusts the abnormal config value in the current config.
   514  // useful when not starting BR from CLI (e.g. from BRIE in SQL).
   515  func (cfg *Config) adjust() {
   516  	if cfg.GRPCKeepaliveTime == 0 {
   517  		cfg.GRPCKeepaliveTime = defaultGRPCKeepaliveTime
   518  	}
   519  	if cfg.GRPCKeepaliveTimeout == 0 {
   520  		cfg.GRPCKeepaliveTimeout = defaultGRPCKeepaliveTimeout
   521  	}
   522  	if cfg.ChecksumConcurrency == 0 {
   523  		cfg.ChecksumConcurrency = variable.DefChecksumTableConcurrency
   524  	}
   525  }
   526  
   527  func normalizePDURL(pd string, useTLS bool) (string, error) {
   528  	if strings.HasPrefix(pd, "http://") {
   529  		if useTLS {
   530  			return "", errors.Annotate(berrors.ErrInvalidArgument, "pd url starts with http while TLS enabled")
   531  		}
   532  		return strings.TrimPrefix(pd, "http://"), nil
   533  	}
   534  	if strings.HasPrefix(pd, "https://") {
   535  		if !useTLS {
   536  			return "", errors.Annotate(berrors.ErrInvalidArgument, "pd url starts with https while TLS disabled")
   537  		}
   538  		return strings.TrimPrefix(pd, "https://"), nil
   539  	}
   540  	return pd, nil
   541  }
   542  
   543  // check whether it's a bug before #647, to solve case #1
   544  // If the storage is set as gcs://bucket/prefix,
   545  // the SSTs are written correctly to gcs://bucket/prefix/*.sst
   546  // but the backupmeta is written wrongly to gcs://bucket/prefixbackupmeta.
   547  // see details https://github.com/pingcap/br/issues/675#issuecomment-753780742
   548  func gcsObjectNotFound(err error) bool {
   549  	return errors.Cause(err) == gcs.ErrObjectNotExist // nolint:errorlint
   550  }