github.com/pingcap/br@v5.3.0-alpha.0.20220125034240-ec59c7b6ce30+incompatible/pkg/task/backup_raw.go (about) 1 // Copyright 2020 PingCAP, Inc. Licensed under Apache-2.0. 2 3 package task 4 5 import ( 6 "bytes" 7 "context" 8 9 "github.com/pingcap/br/pkg/metautil" 10 11 "github.com/opentracing/opentracing-go" 12 "github.com/pingcap/errors" 13 backuppb "github.com/pingcap/kvproto/pkg/backup" 14 "github.com/pingcap/log" 15 "github.com/spf13/cobra" 16 "github.com/spf13/pflag" 17 "go.uber.org/zap" 18 19 "github.com/pingcap/br/pkg/backup" 20 berrors "github.com/pingcap/br/pkg/errors" 21 "github.com/pingcap/br/pkg/glue" 22 "github.com/pingcap/br/pkg/rtree" 23 "github.com/pingcap/br/pkg/storage" 24 "github.com/pingcap/br/pkg/summary" 25 "github.com/pingcap/br/pkg/utils" 26 ) 27 28 const ( 29 flagKeyFormat = "format" 30 flagTiKVColumnFamily = "cf" 31 flagStartKey = "start" 32 flagEndKey = "end" 33 ) 34 35 // RawKvConfig is the common config for rawkv backup and restore. 36 type RawKvConfig struct { 37 Config 38 39 StartKey []byte `json:"start-key" toml:"start-key"` 40 EndKey []byte `json:"end-key" toml:"end-key"` 41 CF string `json:"cf" toml:"cf"` 42 CompressionConfig 43 RemoveSchedulers bool `json:"remove-schedulers" toml:"remove-schedulers"` 44 } 45 46 // DefineRawBackupFlags defines common flags for the backup command. 47 func DefineRawBackupFlags(command *cobra.Command) { 48 command.Flags().StringP(flagKeyFormat, "", "hex", "start/end key format, support raw|escaped|hex") 49 command.Flags().StringP(flagTiKVColumnFamily, "", "default", "backup specify cf, correspond to tikv cf") 50 command.Flags().StringP(flagStartKey, "", "", "backup raw kv start key, key is inclusive") 51 command.Flags().StringP(flagEndKey, "", "", "backup raw kv end key, key is exclusive") 52 command.Flags().String(flagCompressionType, "zstd", 53 "backup sst file compression algorithm, value can be one of 'lz4|zstd|snappy'") 54 command.Flags().Bool(flagRemoveSchedulers, false, 55 "disable the balance, shuffle and region-merge schedulers in PD to speed up backup") 56 // This flag can impact the online cluster, so hide it in case of abuse. 57 _ = command.Flags().MarkHidden(flagRemoveSchedulers) 58 } 59 60 // ParseFromFlags parses the raw kv backup&restore common flags from the flag set. 61 func (cfg *RawKvConfig) ParseFromFlags(flags *pflag.FlagSet) error { 62 format, err := flags.GetString(flagKeyFormat) 63 if err != nil { 64 return errors.Trace(err) 65 } 66 start, err := flags.GetString(flagStartKey) 67 if err != nil { 68 return errors.Trace(err) 69 } 70 cfg.StartKey, err = utils.ParseKey(format, start) 71 if err != nil { 72 return errors.Trace(err) 73 } 74 end, err := flags.GetString(flagEndKey) 75 if err != nil { 76 return errors.Trace(err) 77 } 78 cfg.EndKey, err = utils.ParseKey(format, end) 79 if err != nil { 80 return errors.Trace(err) 81 } 82 83 if len(cfg.StartKey) > 0 && len(cfg.EndKey) > 0 && bytes.Compare(cfg.StartKey, cfg.EndKey) >= 0 { 84 return errors.Annotate(berrors.ErrBackupInvalidRange, "endKey must be greater than startKey") 85 } 86 cfg.CF, err = flags.GetString(flagTiKVColumnFamily) 87 if err != nil { 88 return errors.Trace(err) 89 } 90 if err = cfg.Config.ParseFromFlags(flags); err != nil { 91 return errors.Trace(err) 92 } 93 return nil 94 } 95 96 // ParseBackupConfigFromFlags parses the backup-related flags from the flag set. 97 func (cfg *RawKvConfig) ParseBackupConfigFromFlags(flags *pflag.FlagSet) error { 98 err := cfg.ParseFromFlags(flags) 99 if err != nil { 100 return errors.Trace(err) 101 } 102 103 compressionCfg, err := parseCompressionFlags(flags) 104 if err != nil { 105 return errors.Trace(err) 106 } 107 cfg.CompressionConfig = *compressionCfg 108 109 cfg.RemoveSchedulers, err = flags.GetBool(flagRemoveSchedulers) 110 if err != nil { 111 return errors.Trace(err) 112 } 113 level, err := flags.GetInt32(flagCompressionLevel) 114 if err != nil { 115 return errors.Trace(err) 116 } 117 cfg.CompressionLevel = level 118 119 return nil 120 } 121 122 // RunBackupRaw starts a backup task inside the current goroutine. 123 func RunBackupRaw(c context.Context, g glue.Glue, cmdName string, cfg *RawKvConfig) error { 124 cfg.adjust() 125 126 defer summary.Summary(cmdName) 127 ctx, cancel := context.WithCancel(c) 128 defer cancel() 129 130 if span := opentracing.SpanFromContext(ctx); span != nil && span.Tracer() != nil { 131 span1 := span.Tracer().StartSpan("task.RunBackupRaw", opentracing.ChildOf(span.Context())) 132 defer span1.Finish() 133 ctx = opentracing.ContextWithSpan(ctx, span1) 134 } 135 136 u, err := storage.ParseBackend(cfg.Storage, &cfg.BackendOptions) 137 if err != nil { 138 return errors.Trace(err) 139 } 140 // Backup raw does not need domain. 141 needDomain := false 142 mgr, err := NewMgr(ctx, g, cfg.PD, cfg.TLS, GetKeepalive(&cfg.Config), cfg.CheckRequirements, needDomain) 143 if err != nil { 144 return errors.Trace(err) 145 } 146 defer mgr.Close() 147 148 client, err := backup.NewBackupClient(ctx, mgr) 149 if err != nil { 150 return errors.Trace(err) 151 } 152 opts := storage.ExternalStorageOptions{ 153 NoCredentials: cfg.NoCreds, 154 SendCredentials: cfg.SendCreds, 155 SkipCheckPath: cfg.SkipCheckPath, 156 } 157 if err = client.SetStorage(ctx, u, &opts); err != nil { 158 return errors.Trace(err) 159 } 160 161 backupRange := rtree.Range{StartKey: cfg.StartKey, EndKey: cfg.EndKey} 162 163 if cfg.RemoveSchedulers { 164 restore, e := mgr.RemoveSchedulers(ctx) 165 defer func() { 166 if ctx.Err() != nil { 167 log.Warn("context canceled, try shutdown") 168 ctx = context.Background() 169 } 170 if restoreE := restore(ctx); restoreE != nil { 171 log.Warn("failed to restore removed schedulers, you may need to restore them manually", zap.Error(restoreE)) 172 } 173 }() 174 if e != nil { 175 return errors.Trace(err) 176 } 177 } 178 179 brVersion := g.GetVersion() 180 clusterVersion, err := mgr.GetClusterVersion(ctx) 181 if err != nil { 182 return errors.Trace(err) 183 } 184 185 // The number of regions need to backup 186 approximateRegions, err := mgr.GetRegionCount(ctx, backupRange.StartKey, backupRange.EndKey) 187 if err != nil { 188 return errors.Trace(err) 189 } 190 191 summary.CollectInt("backup total regions", approximateRegions) 192 193 // Backup 194 // Redirect to log if there is no log file to avoid unreadable output. 195 updateCh := g.StartProgress( 196 ctx, cmdName, int64(approximateRegions), !cfg.LogProgress) 197 198 progressCallBack := func(unit backup.ProgressUnit) { 199 if unit == backup.RangeUnit { 200 return 201 } 202 updateCh.Inc() 203 } 204 205 req := backuppb.BackupRequest{ 206 ClusterId: client.GetClusterID(), 207 StartVersion: 0, 208 EndVersion: 0, 209 RateLimit: cfg.RateLimit, 210 Concurrency: cfg.Concurrency, 211 IsRawKv: true, 212 Cf: cfg.CF, 213 CompressionType: cfg.CompressionType, 214 CompressionLevel: cfg.CompressionLevel, 215 } 216 metaWriter := metautil.NewMetaWriter(client.GetStorage(), metautil.MetaFileSize, false) 217 metaWriter.StartWriteMetasAsync(ctx, metautil.AppendDataFile) 218 err = client.BackupRange(ctx, backupRange.StartKey, backupRange.EndKey, req, metaWriter, progressCallBack) 219 if err != nil { 220 return errors.Trace(err) 221 } 222 // Backup has finished 223 updateCh.Close() 224 rawRanges := []*backuppb.RawRange{{StartKey: backupRange.StartKey, EndKey: backupRange.EndKey, Cf: cfg.CF}} 225 metaWriter.Update(func(m *backuppb.BackupMeta) { 226 m.StartVersion = req.StartVersion 227 m.EndVersion = req.EndVersion 228 m.IsRawKv = req.IsRawKv 229 m.RawRanges = rawRanges 230 m.ClusterId = req.ClusterId 231 m.ClusterVersion = clusterVersion 232 m.BrVersion = brVersion 233 }) 234 err = metaWriter.FinishWriteMetas(ctx, metautil.AppendDataFile) 235 if err != nil { 236 return errors.Trace(err) 237 } 238 g.Record(summary.BackupDataSize, metaWriter.ArchiveSize()) 239 240 // Set task summary to success status. 241 summary.SetSuccessStatus(true) 242 return nil 243 }