Source/NuGetGallery.Operations/Tasks/RestoreDatabaseTask.cs (96 lines of code) (raw):

using System; using System.Data.SqlClient; using System.Threading; using AnglicanGeek.DbExecutor; using NuGetGallery.Operations.Common; namespace NuGetGallery.Operations { [Command("restoredb", "Restore a database backup which already resides on the specified database server", AltName = "rdb")] public class RestoreDatabaseTask : DatabaseTask { [Option("Name of the backup file", AltName = "n")] public string BackupName { get; set; } public override void ValidateArguments() { base.ValidateArguments(); ArgCheck.Required(BackupName, "BackupName"); } public override void ExecuteCommand() { using (var masterDbConnection = new SqlConnection(Util.GetMasterConnectionString(ConnectionString.ConnectionString))) using (var masterDbExecutor = new SqlExecutor(masterDbConnection)) { masterDbConnection.Open(); var restoreDbName = CopyDatabaseForRestore( masterDbExecutor); using (var restoreDbConnection = new SqlConnection(Util.GetConnectionString(ConnectionString.ConnectionString, restoreDbName))) using (var restoreDbExecutor = new SqlExecutor(restoreDbConnection)) { restoreDbConnection.Open(); PrepareDataForRestore( restoreDbExecutor); RenameLiveDatabase( masterDbExecutor); RenameDatabaseBackup( masterDbExecutor, restoreDbName); } } } private string CopyDatabaseForRestore( SqlExecutor masterDbExecutor) { var restoreDbName = string.Format("Restore_{0}", Util.GetTimestamp()); Log.Info("Copying {0} to {1}.", BackupName, restoreDbName); masterDbExecutor.Execute(string.Format("CREATE DATABASE {0} AS COPY OF {1}", restoreDbName, BackupName)); Log.Info("Waiting for copy to complete."); WaitForBackupCopy( masterDbExecutor, restoreDbName); return restoreDbName; } private void WaitForBackupCopy( SqlExecutor masterDbExecutor, string restoreDbName) { var timeToGiveUp = DateTime.UtcNow.AddHours(1).AddSeconds(30); while (DateTime.UtcNow < timeToGiveUp) { if (Util.DatabaseExistsAndIsOnline( masterDbExecutor, restoreDbName)) { Log.Info("Copy is complete."); return; } Thread.Sleep(1 * 60 * 1000); } } private void PrepareDataForRestore( IDbExecutor dbExecutor) { Log.Info("Deleting incomplete jobs."); dbExecutor.Execute("DELETE FROM WorkItems WHERE Completed IS NULL"); Log.Info("Deleted incomplete jobs."); } private void RenameDatabaseBackup( IDbExecutor masterDbExecutor, string restoreDbName) { Log.Info("Renaming {0} to NuGetGallery.", restoreDbName); var sql = string.Format("ALTER DATABASE {0} MODIFY Name = NuGetGallery", restoreDbName); masterDbExecutor.Execute(sql); Log.Info("Renamed {0} to NuGetGallery.", restoreDbName); } private void RenameLiveDatabase( IDbExecutor masterDbExecutor) { var timestamp = Util.GetTimestamp(); var liveDbName = "Live_" + timestamp; Log.Info("Renaming NuGetGallery to {0}.", liveDbName); var sql = string.Format("ALTER DATABASE NuGetGallery MODIFY Name = {0}", liveDbName); masterDbExecutor.Execute(sql); Log.Info("Renamed NuGetGallery to {0}.", liveDbName); } } }