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);
        }
Beispiel #3
0
        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);
        }
Beispiel #4
0
        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);
        }