/// <summary> /// SQL Server takes awhile to recover to a usable state after restoring. Wait until it is. /// </summary> public static void WaitForDatabaseRecovery(Database database) { if (database is NoDatabase) { return; } StatusStatics.SetStatus("Waiting for database to be ready..."); EwlStatics.Retry(() => database.GetLineMarker(), "Database failed to be ready."); StatusStatics.SetStatus("Database is ready."); }
void Database.RestoreNewTransactionLogs(string folderPath) { var lastRestoredTransactionLogFileName = ""; ExecuteDbMethod( cn => { var command = new InlineSelect( "TransactionLogFileName".ToSingleElementArray(), "from RsisLogBackups", false, orderByClause: "order by RsisLogBackupId desc"); command.Execute( cn, r => { if (r.Read()) { lastRestoredTransactionLogFileName = r.GetString(0); } }); }); // We want all logs whose ID is greater than that of the last restored log file. var newLogFileNames = GetLogFilesOrderedByNewest(folderPath, lastRestoredTransactionLogFileName); // The following commands must be executed against the master database because there can't be any active connections when doing a restore (including the connection you are using // to run the command). executeDbMethodAgainstMaster( cn => { try { executeLongRunningCommand(cn, "ALTER DATABASE " + info.Database + " SET SINGLE_USER WITH ROLLBACK IMMEDIATE"); foreach (var logFileName in newLogFileNames.Reverse()) { var filePath = EwlStatics.CombinePaths(folderPath, logFileName); // We do not want this to be in a transaction (it probably wouldn't even work because having a transaction writes to the transaction log, and we can't write anything to a // SQL Server database in standby mode. try { executeLongRunningCommand(cn, "RESTORE LOG " + info.Database + " FROM DISK = '" + filePath + "' WITH STANDBY = '" + getStandbyFilePath() + "'"); } catch (Exception e) { var sqlException = e.GetBaseException() as SqlException; if (sqlException != null) { // 3117: The log or differential backup cannot be restored because no files are ready to rollforward. if (sqlException.Number == 3117) { throw new UserCorrectableException( "Failed to restore log, probably because we failed to do a full restore with force new package download after creating a log-shipping-enabled backup on the live server.", e); } // 4305: The log in this backup set begins at LSN X, which is too recent to apply to the database. An earlier log backup that includes LSN Y can be restored. if (sqlException.Number == 4305) { throw new UserCorrectableException( "Failed to restore log because the oldest log available for download from the live server is still too new to restore on this standby server. This happens if the standby server falls so far behind that the live server starts cleaning up old logs before they are downloaded.", e); } } throw; } } } finally { // Sometimes the database isn't ready to go yet and this command will fail. So, we retry. EwlStatics.Retry( () => executeLongRunningCommand(cn, "ALTER DATABASE " + info.Database + " SET MULTI_USER"), "Database is in Restoring state and is not recovering."); } }); }