// CreateIntentForCollection builds an intent for the given database and collection name // along with a path to a .bson collection file. It searches the file's parent directory // for a matching metadata file. // // This method is not called by CreateIntentsForDB, // it is only used in the case where --db and --collection flags are set. func (restore *MongoRestore) CreateIntentForCollection(db string, collection string, dir archive.DirLike) error { log.Logvf(log.DebugLow, "reading collection %v for database %v from %v", collection, db, dir.Path()) // first make sure the bson file exists and is valid _, err := dir.Stat() if err != nil { return err } if dir.IsDir() { return fmt.Errorf("file %v is a directory, not a bson file", dir.Path()) } baseName, fileType := restore.getInfoFromFilename(dir.Name()) if fileType != BSONFileType { return fmt.Errorf("file %v does not have .bson extension", dir.Path()) } // then create its intent intent := &intents.Intent{ DB: db, C: collection, Size: dir.Size(), Location: dir.Path(), } intent.BSONFile = &realBSONFile{path: dir.Path(), intent: intent, gzip: restore.InputOptions.Gzip} // finally, check if it has a .metadata.json file in its folder log.Logvf(log.DebugLow, "scanning directory %v for metadata", dir.Name()) entries, err := dir.Parent().ReadDir() if err != nil { // try and carry on if we can log.Logvf(log.Info, "error attempting to locate metadata for file: %v", err) log.Logv(log.Info, "restoring collection without metadata") restore.manager.Put(intent) return nil } metadataName := baseName + ".metadata.json" if restore.InputOptions.Gzip { metadataName += ".gz" } for _, entry := range entries { if entry.Name() == metadataName { metadataPath := entry.Path() log.Logvf(log.Info, "found metadata for collection at %v", metadataPath) intent.MetadataLocation = metadataPath intent.MetadataFile = &realMetadataFile{path: metadataPath, intent: intent, gzip: restore.InputOptions.Gzip} break } } if intent.MetadataFile == nil { log.Logv(log.Info, "restoring collection without metadata") } restore.manager.Put(intent) return nil }
// CreateIntentsForDB drills down into the dir folder, creating intents // for all of the collection dump files it finds for the db database. func (restore *MongoRestore) CreateIntentsForDB(db string, filterCollection string, dir archive.DirLike, mute bool) (err error) { var entries []archive.DirLike log.Logf(log.DebugHigh, "reading collections for database %v in %v", db, dir.Name()) entries, err = dir.ReadDir() if err != nil { return fmt.Errorf("error reading db folder %v: %v", db, err) } usesMetadataFiles := hasMetadataFiles(entries) for _, entry := range entries { if entry.IsDir() { log.Logf(log.Always, `don't know what to do with subdirectory "%v", skipping...`, filepath.Join(dir.Name(), entry.Name())) } else { collection, fileType := restore.getInfoFromFilename(entry.Name()) switch fileType { case BSONFileType: var skip = mute // Dumps of a single database (i.e. with the -d flag) may contain special // db-specific collections that start with a "$" (for example, $admin.system.users // holds the users for a database that was dumped with --dumpDbUsersAndRoles enabled). // If these special files manage to be included in a dump directory during a full // (multi-db) restore, we should ignore them. if restore.ToolOptions.DB == "" && strings.HasPrefix(collection, "$") { log.Logf(log.DebugLow, "not restoring special collection %v.%v", db, collection) skip = true } // TOOLS-717: disallow restoring to the system.profile collection. // Server versions >= 3.0.3 disallow user inserts to system.profile so // it would likely fail anyway. if collection == "system.profile" { log.Logf(log.DebugLow, "skipping restore of system.profile collection", db) skip = true } // skip restoring the indexes collection if we are using metadata // files to store index information, to eliminate redundancy if collection == "system.indexes" && usesMetadataFiles { log.Logf(log.DebugLow, "not restoring system.indexes collection because database %v "+ "has .metadata.json files", db) skip = true } // TOOLS-976: skip restoring the collections should be excluded if filterCollection == "" && restore.shouldSkipCollection(collection) { log.Logf(log.DebugLow, "skipping restoring %v.%v, it is excluded", db, collection) skip = true } if filterCollection != "" && filterCollection != collection { skip = true } intent := &intents.Intent{ DB: db, C: collection, Size: entry.Size(), } if restore.InputOptions.Archive != "" { if restore.InputOptions.Archive == "-" { intent.Location = "archive on stdin" } else { intent.Location = fmt.Sprintf("archive '%v'", restore.InputOptions.Archive) } if skip { // adding the DemuxOut to the demux, but not adding the intent to the manager mutedOut := &archive.MutedCollection{Intent: intent, Demux: restore.archive.Demux} restore.archive.Demux.Open(intent.Namespace(), mutedOut) continue } else { if intent.IsSpecialCollection() { intent.BSONFile = &archive.SpecialCollectionCache{Intent: intent, Demux: restore.archive.Demux} restore.archive.Demux.Open(intent.Namespace(), intent.BSONFile) } else { intent.BSONFile = &archive.RegularCollectionReceiver{Intent: intent, Demux: restore.archive.Demux} } } } else { if skip { continue } intent.Location = entry.Path() intent.BSONFile = &realBSONFile{path: entry.Path(), intent: intent, gzip: restore.InputOptions.Gzip} } log.Logf(log.Info, "found collection %v bson to restore", intent.Namespace()) restore.manager.Put(intent) case MetadataFileType: // TOOLS-976: skip restoring the collections should be excluded if filterCollection == "" && restore.shouldSkipCollection(collection) { log.Logf(log.DebugLow, "skipping restoring %v.%v metadata, it is excluded", db, collection) continue } usesMetadataFiles = true intent := &intents.Intent{ DB: db, C: collection, } if restore.InputOptions.Archive != "" { if restore.InputOptions.Archive == "-" { intent.MetadataLocation = "archive on stdin" } else { intent.MetadataLocation = fmt.Sprintf("archive '%v'", restore.InputOptions.Archive) } intent.MetadataFile = &archive.MetadataPreludeFile{Intent: intent, Prelude: restore.archive.Prelude} } else { intent.MetadataLocation = entry.Path() intent.MetadataFile = &realMetadataFile{path: entry.Path(), intent: intent, gzip: restore.InputOptions.Gzip} } log.Logf(log.Info, "found collection %v metadata to restore", intent.Namespace()) restore.manager.Put(intent) default: log.Logf(log.Always, `don't know what to do with file "%v", skipping...`, entry.Path()) } } } return nil }