@@ -118,9 +118,16 @@ func (c *cloneNS) SetNSPair(nsPair snapshot.CloneNS) {
118
118
c .toDB , c .toColl = nsPair .SplitToNS ()
119
119
}
120
120
121
+ // mDBCl represents client interface for MongoDB logic used by OplogRestore
122
+ type mDBCl interface {
123
+ getUUIDForNS (ctx context.Context , ns string ) (primitive.Binary , error )
124
+ ensureCollExists (dbName string ) error
125
+ applyOps (entries []interface {}) error
126
+ }
127
+
121
128
// OplogRestore is the oplog applyer
122
129
type OplogRestore struct {
123
- dst * mongo. Client
130
+ mdb mDBCl
124
131
ver * db.Version
125
132
needIdxWorkaround bool
126
133
preserveUUIDopt bool
@@ -157,15 +164,15 @@ const saveLastDistTxns = 100
157
164
158
165
// NewOplogRestore creates an object for an oplog applying
159
166
func NewOplogRestore (
160
- dst * mongo.Client ,
167
+ m * mongo.Client ,
161
168
ic * idx.IndexCatalog ,
162
169
sv * version.MongoVersion ,
163
170
unsafe ,
164
171
preserveUUID bool ,
165
172
ctxn chan phys.RestoreTxn ,
166
173
txnErr chan error ,
167
174
) (* OplogRestore , error ) {
168
- m , err := ns .NewMatcher (append (snapshot .ExcludeFromRestore , excludeFromOplog ... ))
175
+ matcher , err := ns .NewMatcher (append (snapshot .ExcludeFromRestore , excludeFromOplog ... ))
169
176
if err != nil {
170
177
return nil , errors .Wrap (err , "create matcher for the collections exclude" )
171
178
}
@@ -185,13 +192,13 @@ func NewOplogRestore(
185
192
}
186
193
ver := & db.Version {v [0 ], v [1 ], v [2 ]}
187
194
return & OplogRestore {
188
- dst : dst ,
195
+ mdb : newMDB ( m ) ,
189
196
ver : ver ,
190
197
preserveUUIDopt : preserveUUID ,
191
198
preserveUUID : preserveUUID ,
192
199
needIdxWorkaround : needsCreateIndexWorkaround (ver ),
193
200
indexCatalog : ic ,
194
- excludeNS : m ,
201
+ excludeNS : matcher ,
195
202
noUUIDns : noUUID ,
196
203
txn : ctxn ,
197
204
txnSyncErr : txnErr ,
@@ -298,7 +305,7 @@ func (o *OplogRestore) SetCloneNS(ctx context.Context, ns snapshot.CloneNS) erro
298
305
o .cloneNS .SetNSPair (ns )
299
306
300
307
var err error
301
- o .cloneNS .toUUID , err = getUUIDForNS (ctx , o . dst , o .cloneNS .ToNS )
308
+ o .cloneNS .toUUID , err = o . mdb . getUUIDForNS (ctx , o .cloneNS .ToNS )
302
309
if err != nil {
303
310
return errors .Wrap (err , "get to ns uuid" )
304
311
}
@@ -956,20 +963,14 @@ func (o *OplogRestore) handleNonTxnOp(op db.Oplog) error {
956
963
}
957
964
} else if op .Operation == "i" && collName == "system.views" {
958
965
// PBM-921: ensure the collection exists before "creating" views or timeseries
959
- err := o .dst . Database (dbName ). CreateCollection ( context . TODO (), "system.views" )
966
+ err := o .mdb . ensureCollExists (dbName )
960
967
if err != nil {
961
- // MongoDB 5.0 and 6.0 returns NamespaceExists error.
962
- // MongoDB 7.0 and 8.0 does not return error.
963
- // https://github.com/mongodb/mongo/blob/v6.0/src/mongo/base/error_codes.yml#L84
964
- const NamespaceExists = 48
965
- var cmdError mongo.CommandError
966
- if ! errors .As (err , & cmdError ) || cmdError .Code != NamespaceExists {
967
- return errors .Wrapf (err , "ensure %s.system.views collection" , dbName )
968
- }
968
+ return err
969
969
}
970
+
970
971
}
971
972
972
- err = o .applyOps ([]interface {}{op })
973
+ err = o .mdb . applyOps ([]interface {}{op })
973
974
if err != nil {
974
975
// https://jira.percona.com/browse/PBM-818
975
976
if o .unsafe && op .Namespace == "config.chunks" {
@@ -1071,25 +1072,6 @@ func extractIndexDocumentFromCommitIndexBuilds(op db.Oplog) (string, []*idx.Inde
1071
1072
return collectionName , nil
1072
1073
}
1073
1074
1074
- // applyOps is a wrapper for the applyOps database command, we pass in
1075
- // a session to avoid opening a new connection for a few inserts at a time.
1076
- func (o * OplogRestore ) applyOps (entries []interface {}) error {
1077
- singleRes := o .dst .Database ("admin" ).RunCommand (context .TODO (), bson.D {{"applyOps" , entries }})
1078
- if err := singleRes .Err (); err != nil {
1079
- return errors .Wrap (err , "applyOps" )
1080
- }
1081
- res := bson.M {}
1082
- err := singleRes .Decode (& res )
1083
- if err != nil {
1084
- return errors .Wrap (err , "decode singleRes" )
1085
- }
1086
- if isFalsy (res ["ok" ]) {
1087
- return errors .Errorf ("applyOps command: %v" , res ["errmsg" ])
1088
- }
1089
-
1090
- return nil
1091
- }
1092
-
1093
1075
// filterUUIDs removes 'ui' entries from ops, including nested applyOps ops.
1094
1076
// It also modifies ops that rely on 'ui'.
1095
1077
func (o * OplogRestore ) filterUUIDs (op db.Oplog ) (db.Oplog , error ) {
@@ -1261,29 +1243,3 @@ func isTruthy(val interface{}) bool {
1261
1243
func isFalsy (val interface {}) bool {
1262
1244
return ! isTruthy (val )
1263
1245
}
1264
-
1265
- // getUUIDForNS ruturns UUID of existing collection.
1266
- // When ns doesn't exist, it returns zero value without an error.
1267
- // In case of error, it returns zero value for UUID in addition to error.
1268
- func getUUIDForNS (ctx context.Context , m * mongo.Client , ns string ) (primitive.Binary , error ) {
1269
- var uuid primitive.Binary
1270
-
1271
- d , c , _ := strings .Cut (ns , "." )
1272
- cur , err := m .Database (d ).ListCollections (ctx , bson.D {{"name" , c }})
1273
- if err != nil {
1274
- return uuid , errors .Wrap (err , "list collections" )
1275
- }
1276
- defer cur .Close (ctx )
1277
-
1278
- for cur .Next (ctx ) {
1279
- if subtype , data , ok := cur .Current .Lookup ("info" , "uuid" ).BinaryOK (); ok {
1280
- uuid = primitive.Binary {
1281
- Subtype : subtype ,
1282
- Data : data ,
1283
- }
1284
- break
1285
- }
1286
- }
1287
-
1288
- return uuid , errors .Wrap (cur .Err (), "list collections cursor" )
1289
- }
0 commit comments