async Task BackupAsync() { this.events.StartingBackup(); Guid backupId = Guid.NewGuid(); string dbBackupDirectory = Path.Combine(this.backupPath, backupId.ToString()); BackupMetadata newBackupMetadata = new BackupMetadata(backupId, this.dataBackupRestore.DataBackupFormat, DateTime.UtcNow, this.dbStores.Keys.ToList()); BackupMetadataList backupMetadataList = new BackupMetadataList(new List <BackupMetadata> { newBackupMetadata }); try { Directory.CreateDirectory(dbBackupDirectory); // Backup other stores. foreach (string store in this.dbStores.Keys) { IDbStore dbStore = this.dbStoreProvider.GetDbStore(store); await this.DbStoreBackupAsync(store, dbStore, dbBackupDirectory); } using (StreamWriter file = File.CreateText(Path.Combine(this.backupPath, BackupMetadataFileName))) { JsonSerializer serializer = new JsonSerializer(); serializer.Serialize(file, backupMetadataList); } this.events.BackupComplete(); // Clean any old backups. this.CleanupUnknownBackups(this.backupPath, backupMetadataList); } catch (Exception exception) { this.events.BackupFailure($"The backup operation failed with error ${exception}."); // Clean up any artifacts of the attempted backup. this.CleanupKnownBackups(this.backupPath, backupMetadataList); } }
void CleanupKnownBackups(string backupPath, BackupMetadataList metadataList) { DirectoryInfo backupDirInfo = new DirectoryInfo(backupPath); HashSet <string> knownBackupDirNames = new HashSet <string>(metadataList.Backups.Select(x => x.Id.ToString()), StringComparer.OrdinalIgnoreCase); foreach (DirectoryInfo dir in backupDirInfo.GetDirectories()) { if (knownBackupDirNames.Contains(dir.Name)) { try { dir.Delete(true); } catch (Exception ex) { this.events.DeletionError(dir.FullName, ex); } } } this.events.BackupArtifactsCleanedUp(); }
async Task RestoreAsync() { string backupMetadataFilePath = Path.Combine(this.backupPath, BackupMetadataFileName); if (!File.Exists(backupMetadataFilePath)) { this.events.NoBackupsForRestore(); return; } try { string fileText = File.ReadAllText(backupMetadataFilePath); BackupMetadataList backupMetadataList = JsonConvert.DeserializeObject <BackupMetadataList>(fileText); BackupMetadata backupMetadata = backupMetadataList.Backups[0]; this.events.BackupInformation(backupMetadata.Id, backupMetadata.SerializationFormat, backupMetadata.TimestampUtc, backupMetadata.Stores); string latestBackupDirPath = Path.Combine(this.backupPath, backupMetadata.Id.ToString()); if (Directory.Exists(latestBackupDirPath)) { this.events.RestoringFromBackup(backupMetadata.Id); foreach (string store in backupMetadata.Stores) { IDbStore dbStore; if (!store.Equals(DefaultStoreBackupName, StringComparison.OrdinalIgnoreCase)) { dbStore = this.GetDbStore(store); } else { dbStore = this.GetDbStore(); } await this.DbStoreRestoreAsync(store, dbStore, latestBackupDirPath); } this.events.RestoreComplete(); } else { this.events.NoBackupsForRestore(); } } catch (Exception exception) { this.events.RestoreFailure($"The restore operation failed with error ${exception}."); // Clean up any restored state in the dictionary if the backup fails midway. foreach (string store in this.dbStores.Keys.ToList()) { this.RemoveDbStore(store); } this.RemoveDbStore(); } finally { // Delete all other backups as we've either: // 1. Restored successfully. // 2. Failed during restore which would indicate a bad backup. this.CleanupAllBackups(this.backupPath); } }