Skip to content

Commit 53c6b3c

Browse files
authored
PBM-1358: support selective backup and restore with configshard (#1037)
1 parent 3d16717 commit 53c6b3c

File tree

9 files changed

+212
-117
lines changed

9 files changed

+212
-117
lines changed

cmd/pbm/backup.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,7 @@ type bcpReplDesc struct {
348348
LastWriteTime string `json:"last_write_time" yaml:"last_write_time"`
349349
LastTransitionTime string `json:"last_transition_time" yaml:"last_transition_time"`
350350
IsConfigSvr *bool `json:"configsvr,omitempty" yaml:"configsvr,omitempty"`
351+
IsConfigShard *bool `json:"configshard,omitempty" yaml:"configshard,omitempty"`
351352
SecurityOpts *topo.MongodOptsSec `json:"security,omitempty" yaml:"security,omitempty"`
352353
Error *string `json:"error,omitempty" yaml:"error,omitempty"`
353354
Collections []string `json:"collections,omitempty" yaml:"collections,omitempty"`
@@ -442,6 +443,7 @@ func describeBackup(
442443
Name: r.Name,
443444
Node: r.Node,
444445
IsConfigSvr: r.IsConfigSvr,
446+
IsConfigShard: r.IsConfigShard,
445447
Status: r.Status,
446448
LastWriteTS: int64(r.LastWriteTS.T),
447449
LastTransitionTS: r.LastTransitionTS,

pbm/archive/backup.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import (
1919
"github.com/percona/percona-backup-mongodb/pbm/version"
2020
)
2121

22-
var configCollectionsToKeep = []string{
22+
var RouterConfigCollections = []string{
2323
"chunks",
2424
"collections",
2525
"databases",
@@ -191,7 +191,7 @@ func (bcp *backupImpl) listDBNamespaces(ctx context.Context, db string) ([]*Name
191191
case "admin":
192192
filter = bson.D{{"name", bson.M{"$ne": "system.keys"}}}
193193
case "config":
194-
filter = bson.D{{"name", bson.M{"$in": configCollectionsToKeep}}}
194+
filter = bson.D{{"name", bson.M{"$in": RouterConfigCollections}}}
195195
}
196196

197197
cur, err := bcp.conn.Database(db).ListCollections(ctx, filter)
@@ -279,6 +279,14 @@ func (bcp *backupImpl) dumpAllCollections(ctx context.Context, nss []*NamespaceV
279279
}
280280

281281
func (bcp *backupImpl) dumpCollection(ctx context.Context, ns *NamespaceV2) error {
282+
count, err := bcp.conn.Database(ns.DB).Collection(ns.Name).EstimatedDocumentCount(ctx)
283+
if err != nil {
284+
return errors.Wrap(err, "estimate document count")
285+
}
286+
if count == 0 {
287+
return nil
288+
}
289+
282290
file, err := bcp.newFile(ns.NS())
283291
if err != nil {
284292
return errors.Wrap(err, "new file")

pbm/archive/conv.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ func convertMetaToV1(metaV2 *ArchiveMetaV2) (*archiveMeta, error) {
6868
ServerVersion: metaV2.ServerVersion,
6969
ToolVersion: metaV2.Version,
7070
},
71+
Namespaces: []*Namespace{},
7172
}
7273

7374
for _, coll := range metaV2.Namespaces {

pbm/backup/backup.go

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -166,18 +166,6 @@ func (b *Backup) Init(
166166
//
167167
//nolint:nonamedreturns
168168
func (b *Backup) Run(ctx context.Context, bcp *ctrl.BackupCmd, opid ctrl.OPID, l log.LogEvent) (err error) {
169-
if b.brief.Sharded &&
170-
b.brief.Version.IsConfigShardSupported() &&
171-
util.IsSelective(bcp.Namespaces) {
172-
hasConfigShard, err := topo.HasConfigShard(ctx, b.leadConn)
173-
if err != nil {
174-
return errors.Wrap(err, "check for Config Shard")
175-
}
176-
if hasConfigShard {
177-
return errors.New("selective backup is not supported with Config Shard")
178-
}
179-
}
180-
181169
inf, err := topo.GetNodeInfoExt(ctx, b.nodeConn)
182170
if err != nil {
183171
return errors.Wrap(err, "get cluster info")
@@ -199,6 +187,14 @@ func (b *Backup) Run(ctx context.Context, bcp *ctrl.BackupCmd, opid ctrl.OPID, l
199187
}
200188
if v := inf.IsConfigSrv(); v {
201189
rsMeta.IsConfigSvr = &v
190+
191+
isConfigShard, err := topo.HasConfigShard(ctx, b.leadConn)
192+
if err != nil {
193+
return errors.Wrap(err, "has configshard")
194+
}
195+
if isConfigShard {
196+
rsMeta.IsConfigShard = &isConfigShard
197+
}
202198
}
203199

204200
stg, err := util.StorageFromConfig(&b.config.Storage, inf.Me, l)

pbm/backup/logical.go

Lines changed: 20 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -41,19 +41,7 @@ func (b *Backup) doLogical(
4141
return errors.Wrap(err, "check for timeseries")
4242
}
4343
}
44-
45-
var db, coll string
46-
if util.IsSelective(bcp.Namespaces) {
47-
// for selective backup, configsvr does not hold any data.
48-
// only some collections from config db is required to restore cluster state
49-
if inf.IsConfigSrv() {
50-
db = "config"
51-
} else {
52-
db, coll = util.ParseNS(bcp.Namespaces[0])
53-
}
54-
}
55-
56-
nssSize, err := getNamespacesSize(ctx, b.nodeConn, db, coll)
44+
nssSize, err := getNamespacesSize(ctx, b.nodeConn, bcp.Namespaces)
5745
if err != nil {
5846
return errors.Wrap(err, "get namespaces size")
5947
}
@@ -153,8 +141,9 @@ func (b *Backup) doLogical(
153141
return errors.Wrap(err, "fetch uuids")
154142
}
155143

156-
nsFilter = makeConfigsvrNSFilter()
157144
docFilter = makeConfigsvrDocFilter(bcp.Namespaces, chunkSelector)
145+
nsFilter = makeConfigsvrNSFilter(bcp.Namespaces)
146+
158147
} else {
159148
nsFilter = util.MakeSelectedPred(bcp.Namespaces)
160149
}
@@ -358,17 +347,16 @@ func createBackupChunkSelector(ctx context.Context, m connect.Client, nss []stri
358347
return chunkSelector, nil
359348
}
360349

361-
func makeConfigsvrNSFilter() archive.NSFilterFn {
350+
func makeConfigsvrNSFilter(nss []string) archive.NSFilterFn {
351+
selected := make([]string, len(nss)+len(archive.RouterConfigCollections))
352+
n := copy(selected, nss)
353+
362354
// list of required namespaces for further selective restore
363-
allowed := map[string]bool{
364-
"config.databases": true,
365-
"config.collections": true,
366-
"config.chunks": true,
355+
for i, name := range archive.RouterConfigCollections {
356+
selected[n+i] = "config." + name
367357
}
368358

369-
return func(ns string) bool {
370-
return allowed[ns]
371-
}
359+
return util.MakeSelectedPred(selected)
372360
}
373361

374362
func makeConfigsvrDocFilter(nss []string, selector util.ChunkSelector) archive.DocFilterFn {
@@ -395,33 +383,27 @@ func makeConfigsvrDocFilter(nss []string, selector util.ChunkSelector) archive.D
395383
}
396384
}
397385

398-
func getNamespacesSize(ctx context.Context, m *mongo.Client, db, coll string) (map[string]int64, error) {
386+
func getNamespacesSize(ctx context.Context, m *mongo.Client, nss []string) (map[string]int64, error) {
399387
rv := make(map[string]int64)
400388

401-
q := bson.D{}
402-
if db != "" {
403-
q = append(q, bson.E{"name", db})
404-
}
405-
dbs, err := m.ListDatabaseNames(ctx, q)
389+
dbs, err := m.ListDatabaseNames(ctx, bson.D{})
406390
if err != nil {
407391
return nil, errors.Wrap(err, "list databases")
408392
}
409393
if len(dbs) == 0 {
410394
return rv, nil
411395
}
412396

397+
isSelected := util.MakeSelectedPred(nss)
398+
413399
mu := sync.Mutex{}
414400
eg, ctx := errgroup.WithContext(ctx)
415401

416402
for _, db := range dbs {
417403
db := db
418404

419405
eg.Go(func() error {
420-
q := bson.D{}
421-
if coll != "" {
422-
q = append(q, bson.E{"name", coll})
423-
}
424-
res, err := m.Database(db).ListCollectionSpecifications(ctx, q)
406+
res, err := m.Database(db).ListCollectionSpecifications(ctx, bson.D{})
425407
if err != nil {
426408
return errors.Wrapf(err, "list collections for %q", db)
427409
}
@@ -432,14 +414,16 @@ func getNamespacesSize(ctx context.Context, m *mongo.Client, db, coll string) (m
432414
eg, ctx := errgroup.WithContext(ctx)
433415

434416
for _, coll := range res {
435-
coll := coll
436-
437417
if coll.Type == "view" || strings.HasPrefix(coll.Name, "system.buckets.") {
438418
continue
439419
}
440420

421+
ns := db + "." + coll.Name
422+
if !isSelected(ns) {
423+
continue
424+
}
425+
441426
eg.Go(func() error {
442-
ns := db + "." + coll.Name
443427
res := m.Database(db).RunCommand(ctx, bson.D{{"collStats", coll.Name}})
444428
if err := res.Err(); err != nil {
445429
return errors.Wrapf(err, "collStats %q", ns)

pbm/backup/types.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ type BackupReplset struct {
118118
StartTS int64 `bson:"start_ts" json:"start_ts"`
119119
Status defs.Status `bson:"status" json:"status"`
120120
IsConfigSvr *bool `bson:"iscs,omitempty" json:"iscs,omitempty"`
121+
IsConfigShard *bool `bson:"configshard,omitempty" json:"configshard,omitempty"`
121122
LastTransitionTS int64 `bson:"last_transition_ts" json:"last_transition_ts"`
122123
FirstWriteTS primitive.Timestamp `bson:"first_write_ts" json:"first_write_ts"`
123124
LastWriteTS primitive.Timestamp `bson:"last_write_ts" json:"last_write_ts"`

0 commit comments

Comments
 (0)