private static async Task RunDbccCheckDb(RestoreState state, RestoreItem item) { if (state.RestoreCommand.CheckDb == false) { return; } await using var sqlConnectionOnDatabase = state.RestoreCommand.CreateConnectionMars(item.Name); try { var checkdbResults = await sqlConnectionOnDatabase.QueryAsync <DbccCheckDbResult>("DBCC CHECKDB with TABLERESULTS", commandTimeout : state.RestoreCommand.Timeout); foreach (var r in checkdbResults.Where(i => i.Level >= 17)) { state.Loggger.Fatal($"[{item.Name}] Error found while DBCC CHECKDB : " + r.MessageText); var errors = state.IntegrityErrors.GetValueOrDefault(item.Name, new List <string>()); errors.Add(r.MessageText); } } catch (Exception e) { state.Loggger.Error(e, $"[{item.Name}] Error while DBCC CHECKDB"); return; } }
private static bool StartFromFull(RestoreState state, RestoreItem item) { if (!state.ActualDbs.ContainsKey(item.Name)) { // no db present, we need to start from full return(true); } if (state.ActualDbs[item.Name].State != DatabaseState.RESTORING) { // need restart from scratch state.Loggger.Debug($"Can't continue logs : {item.Name} in state {state.ActualDbs[item.Name].State}. Restarting from FULL."); return(true); } // db present in restoring mode, we can continue logs return(false); }
public static bool TryCreateRestoreItem(DirectoryInfo item, RestoreState state, out RestoreItem restoreItem) { restoreItem = new RestoreItem(); restoreItem.BaseDirectoryInfo = item; if (!TryGetFullFolder(state.RestoreCommand, item, out var full)) { state.MissingBackupFull.Add(restoreItem); return(false); } restoreItem.Full = full; restoreItem.FullSize = full.GetFiles("*.bak").Sum(i => i.Length); restoreItem.Diff = item.EnumerateDirectories("DIFF").FirstOrDefault(); restoreItem.Log = item.EnumerateDirectories("LOG").FirstOrDefault(); return(true); }
public static Task PrepareRestoreJobAsync(this RestoreState state) { return(Task.Run(async() => { await Task.Yield(); state.Loggger.Information("Crawling folders"); var sourceFolders = GetSourceFolder(state); var po = new ParallelOptions { MaxDegreeOfParallelism = state.RestoreCommand.Threads * 4 }; var explicitDatabases = state.RestoreCommand.Databases?.ToHashSet(StringComparer.InvariantCultureIgnoreCase); bool IsExcluded(DirectoryInfo directoryInfo) { return state.RestoreCommand.IsDatabaseIgnored(directoryInfo.Name); } var restoreItems = new ConcurrentBag <(int sourceId, RestoreItem item)>(); Stopwatch sw = Stopwatch.StartNew(); Parallel.ForEach(sourceFolders.MixSourceFolders(), po, i => { if (IsExcluded(i.directory)) { return; } // ignore folder without FULL backup if (RestoreItem.TryCreateRestoreItem(i.directory, state, out RestoreItem ri)) { if (explicitDatabases != null && explicitDatabases.Count != 0) { if (explicitDatabases.Contains(ri.Name)) { restoreItems.Add((i.sourceId, ri)); } }
private static async Task <RestoreItem> RestoreBackupAsync(IRestoreMethod restoreMethod, RestoreItem item, RestoreState state) { RestoreCommand restoreCommand = state.RestoreCommand; state.Loggger.Debug($"Starting restore for {item.Name}"); item.SetStart(); await using var sqlConnection = restoreCommand.CreateConnectionMars(); Exception exception; if (restoreCommand.FullOnly) { exception = await restoreMethod.RestoreFullAsync(item); } else { bool startFromFull = StartFromFull(state, item); exception = await restoreMethod.RestoreFullDiffLogAsync(item, startFromFull); } var incremented = state.Increment(); state.Loggger.Information($"[{incremented}/{state.Directories.Count}] OK : {item.Name} {item.Stats()}"); if (exception != null) { state.ExceptionBackupFull.Add((exception, item)); item.SetError(exception); state.Loggger.Error(exception, $"Error restoring {item.Name}"); return(item); } try { Exception scriptException = null; if (restoreCommand.RunRecovery) { var recoveryException = await restoreMethod.RunRecoveryAsync(item); if (recoveryException != null) { state.ExceptionBackupFull.Add((recoveryException, item)); item.SetError(recoveryException); throw recoveryException; } scriptException = await PostScriptExecuteAsync(state, item); await RunDbccCheckDb(state, item); } if (scriptException != null) { state.ExceptionBackupFull.Add((scriptException, item)); item.SetError(scriptException); } if (restoreCommand.IsUncheckedModeEnable) { try { // overwrite destination if exists var target = Path.Combine(restoreCommand.Checked.FullName, item.Name); if (Directory.Exists(target)) { Directory.Delete(target, true); } item.BaseDirectoryInfo.MoveTo(target); } catch (Exception e) { state.Loggger.Error(e, $"Error moving {item.Name}"); return(item); } } if (scriptException != null) { return(item); } } catch (Exception e) { item.SetError(e); return(item); } item.SetSuccess(); state.OkBackupFull.Add(item); state.Loggger.Debug($"Finished restore for {item.Name}"); return(item); }
private static async Task <Exception> PostScriptExecuteAsync(RestoreState state, RestoreItem restoreItem) { if (state.RestoreCommand.PostScripts == null) { return(null); } if (!state.RestoreCommand.PostScripts.Any()) { state.RestoreCommand.PostScripts = null; return(null); } if (!string.IsNullOrEmpty(state.RestoreCommand.PostScriptFilter)) { if (!restoreItem.Name.StartsWith(state.RestoreCommand.PostScriptFilter, StringComparison.OrdinalIgnoreCase)) { state.Loggger.Debug("Ignoring database " + restoreItem.Name + " because of PostScriptFilter : " + state.RestoreCommand.PostScriptFilter); return(null); } } try { var scripts = LoadScripts(state.RestoreCommand); state.Loggger.Debug("Applying " + scripts.Count + " sql scripts"); await using var sqlConnectionOnDatabase = state.RestoreCommand.CreateConnectionMars(restoreItem.Name); foreach (var script in scripts) { await sqlConnectionOnDatabase.ExecuteAsync(script, commandTimeout : state.RestoreCommand.Timeout); } } catch (Exception e) { state.Loggger.Error(e, $"[{restoreItem.Name}] Error while executing post scripts"); return(e); } return(null); }