Ejemplo n.º 1
0
        private static void ConfigureRecoveryCommand()
        {
            _app.Command("recover", cmd =>
            {
                cmd.ExtendedHelpText = cmd.Description = "Recovering a database into recovery.ravendump.";
                cmd.HelpOption(HelpOptionString);

                var dataFileDirectoryArg = cmd.Argument("DataFileDirectory", "The database directory which contains the data file");
                var recoverDirectoryArg  = cmd.Argument("RecoverDirectory", "The directory to recover the recovery.ravendump file");

                var outputFileNameArg                  = cmd.Option("--OutputFileName", "Will overwrite the default file name () with your own file name (under output directory).", CommandOptionType.SingleValue);
                var pageSizeInKbArg                    = cmd.Option("--PageSizeInKB", "Will set the recovery tool to work with page sizes other than 4kb.", CommandOptionType.SingleValue);
                var initialContextSizeInMbArg          = cmd.Option("--InitialContextSizeInMB", "Will set the recovery tool to use a context of the provided size in MB.", CommandOptionType.SingleValue);
                var initialContextLongLivedSizeInKbArg = cmd.Option("--InitialContextLongLivedSizeInKB", "Will set the recovery tool to use a long lived context size of the provided size in KB.", CommandOptionType.SingleValue);
                var progressIntervalInSecArg           = cmd.Option("--ProgressIntervalInSec", "Will set the recovery tool refresh to console rate interval in seconds.", CommandOptionType.SingleValue);
                var disableCopyOnWriteModeArg          = cmd.Option("--DisableCopyOnWriteMode", "Default is false.", CommandOptionType.SingleValue);
                var ignoreInvalidJournalErrorsArg      = cmd.Option("--IgnoreInvalidJournalErrors", "Default is false.", CommandOptionType.SingleValue);
                var ignoreDataIntegrityErrorsOfAlreadySyncedTransactionsArg = cmd.Option("--IgnoreInvalidDataErrorsOfAlreadySyncedTransactions", "Default is false.", CommandOptionType.SingleValue);


                var loggingModeArg = cmd.Option("--LoggingMode", "Logging mode: Operations or Information.", CommandOptionType.SingleValue);

                var masterKey = cmd.Option("--MasterKey", "Encryption key: base64 string of the encryption master key", CommandOptionType.SingleValue);

                cmd.OnExecute(() =>
                {
                    VoronRecoveryConfiguration config = new VoronRecoveryConfiguration
                    {
                        DataFileDirectory = dataFileDirectoryArg.Value,
                    };

                    if (string.IsNullOrWhiteSpace(config.DataFileDirectory) ||
                        Directory.Exists(config.DataFileDirectory) == false ||
                        File.Exists(Path.Combine(config.DataFileDirectory, DatafileName)) == false)
                    {
                        return(ExitWithError($"Missing {nameof(config.DataFileDirectory)} argument", cmd));
                    }
                    config.PathToDataFile = Path.Combine(config.DataFileDirectory, DatafileName);

                    var recoverDirectory = recoverDirectoryArg.Value;
                    if (string.IsNullOrWhiteSpace(recoverDirectory))
                    {
                        return(ExitWithError("Missing RecoverDirectory argument", cmd));
                    }

                    config.OutputFileName = Path.Combine(recoverDirectory, outputFileNameArg.HasValue() ? outputFileNameArg.Value() : RecoveryFileName);
                    try
                    {
                        if (!Directory.Exists(recoverDirectory))
                        {
                            Directory.CreateDirectory(recoverDirectory);
                        }
                        File.WriteAllText(config.OutputFileName, "I have write permission!");
                        File.Delete(config.OutputFileName);
                    }
                    catch
                    {
                        return(ExitWithError($"Cannot write to the output directory ({recoverDirectory}). " +
                                             "Permissions issue?", cmd));
                    }

                    if (pageSizeInKbArg.HasValue())
                    {
                        if (int.TryParse(pageSizeInKbArg.Value(), out var pageSize) == false ||
                            pageSize < 1)
                        {
                            return(ExitWithError($"{nameof(config.PageSizeInKB)} argument value ({pageSize}) is invalid", cmd));
                        }
                        config.PageSizeInKB = pageSize;
                    }

                    if (initialContextSizeInMbArg.HasValue())
                    {
                        if (int.TryParse(initialContextSizeInMbArg.Value(), out var contextSize) == false ||
                            contextSize < 1)
                        {
                            return(ExitWithError($"{nameof(config.InitialContextSizeInMB)} argument value ({contextSize}) is invalid", cmd));
                        }
                        config.InitialContextSizeInMB = contextSize;
                    }

                    if (initialContextLongLivedSizeInKbArg.HasValue())
                    {
                        if (int.TryParse(initialContextLongLivedSizeInKbArg.Value(), out var longLivedContextSize) == false ||
                            longLivedContextSize < 1)
                        {
                            return(ExitWithError($"{nameof(config.InitialContextLongLivedSizeInKB)} argument value ({longLivedContextSize}) is invalid", cmd));
                        }
                        config.InitialContextLongLivedSizeInKB = longLivedContextSize;
                    }

                    if (progressIntervalInSecArg.HasValue())
                    {
                        if (int.TryParse(progressIntervalInSecArg.Value(), out var refreshRate) == false ||
                            refreshRate < 1)
                        {
                            return(ExitWithError($"{nameof(config.ProgressIntervalInSec)} argument value ({refreshRate}) is invalid", cmd));
                        }
                        config.ProgressIntervalInSec = refreshRate;
                    }

                    if (disableCopyOnWriteModeArg.HasValue())
                    {
                        var value = disableCopyOnWriteModeArg.Value();
                        if (bool.TryParse(value, out var disableCopyOnWriteMode) == false)
                        {
                            return(ExitWithError($"{nameof(config.DisableCopyOnWriteMode)} argument value ({value}) is invalid", cmd));
                        }
                        config.DisableCopyOnWriteMode = disableCopyOnWriteMode;
                    }

                    if (ignoreInvalidJournalErrorsArg.HasValue())
                    {
                        var value = ignoreInvalidJournalErrorsArg.Value();
                        if (bool.TryParse(value, out var ignoreInvalidJournalErrors) == false)
                        {
                            return(ExitWithError($"{nameof(config.IgnoreInvalidJournalErrors)} argument value ({value}) is invalid", cmd));
                        }

                        config.IgnoreInvalidJournalErrors = ignoreInvalidJournalErrors;
                    }

                    if (ignoreDataIntegrityErrorsOfAlreadySyncedTransactionsArg.HasValue())
                    {
                        var value = ignoreDataIntegrityErrorsOfAlreadySyncedTransactionsArg.Value();
                        if (bool.TryParse(value, out var ignoreDataIntegrityErrorsOfAlreadySyncedTransactions) == false)
                        {
                            return(ExitWithError($"{nameof(config.IgnoreDataIntegrityErrorsOfAlreadySyncedTransactions)} argument value ({value}) is invalid", cmd));
                        }

                        config.IgnoreDataIntegrityErrorsOfAlreadySyncedTransactions = ignoreDataIntegrityErrorsOfAlreadySyncedTransactions;
                    }

                    if (loggingModeArg.HasValue())
                    {
                        var value = loggingModeArg.Value();
                        if (Enum.TryParse(value, out LogMode mode) == false)
                        {
                            return(ExitWithError($"{nameof(config.LoggingMode)} argument value ({value}) is invalid", cmd));
                        }
                        config.LoggingMode = mode;
                    }

                    if (masterKey.HasValue())
                    {
                        var value = masterKey.Value();
                        byte[] key;
                        try
                        {
                            key = Convert.FromBase64String(value);
                        }
                        catch
                        {
                            return(ExitWithError($"{nameof(config.MasterKey)} argument value ({value}) is not a valid base64 string", cmd));
                        }

                        config.MasterKey = key;
                    }
                    using (var recovery = new Recovery(config))
                    {
                        var cts = new CancellationTokenSource();
                        Console.WriteLine("Press 'q' to quit the recovery process");
                        var cancellationTask = Task.Factory.StartNew(() =>
                        {
                            while (Console.Read() != 'q')
                            {
                            }

                            cts.Cancel();
                            //The reason i do an exit here is because if we are in the middle of journal recovery
                            //we can't cancel it and it may take a long time.
                            //That said i'm still going to give it a while to do a proper exit
                            Task.Delay(5000).ContinueWith(_ => { Environment.Exit(1); });
                        }, cts.Token);

                        try
                        {
                            recovery.Execute(Console.Out, cts.Token);
                        }
                        catch (Exception e)
                        {
                            if (e.Data["ReturnCode"] is int returnCode)
                            {
                                return(returnCode);
                            }

                            return(ExitWithError(e.Message, _app));
                        }

                        cts.Cancel();
                    }

                    return(0);
                });
            });
        }
Ejemplo n.º 2
0
        public static void Main(string[] args)
        {
            VoronRecoveryConfiguration config;

            switch (VoronRecoveryConfiguration.ProcessArgs(args, out config))
            {
            case VoronRecoveryConfiguration.VoronRecoveryArgsProcessStatus.Success:
                break;

            case VoronRecoveryConfiguration.VoronRecoveryArgsProcessStatus.NotEnoughArguments:
                PrintUsage();
                return;

            case VoronRecoveryConfiguration.VoronRecoveryArgsProcessStatus.MissingDataFile:
                PrintUsage();
                return;

            case VoronRecoveryConfiguration.VoronRecoveryArgsProcessStatus.CantWriteToOutputDirectory:
                PrintUsage();
                return;

            case VoronRecoveryConfiguration.VoronRecoveryArgsProcessStatus.WrongNumberOfArgs:
                Console.WriteLine($"The given amount of args doesn't dived by 2 like expected.{Environment.NewLine}");
                goto default;

            case VoronRecoveryConfiguration.VoronRecoveryArgsProcessStatus.InvalidPageSize:
                Console.WriteLine($"Page size should be a positive number.{Environment.NewLine}");
                goto default;

            case VoronRecoveryConfiguration.VoronRecoveryArgsProcessStatus.InvalidTableValueCount:
                Console.WriteLine($"Table value count should be a positive number.{Environment.NewLine}");
                goto default;

            case VoronRecoveryConfiguration.VoronRecoveryArgsProcessStatus.InvalidContextSize:
                Console.WriteLine($"Context size should be a positive number.{Environment.NewLine}");
                goto default;

            case VoronRecoveryConfiguration.VoronRecoveryArgsProcessStatus.InvalidLongLivedContextSize:
                Console.WriteLine($"Long lived size should be a positive number.{Environment.NewLine}");
                goto default;

            case VoronRecoveryConfiguration.VoronRecoveryArgsProcessStatus.InvalidRefreshRate:
                Console.WriteLine($"Refresh rate should be a positive number.{Environment.NewLine}");
                goto default;

            case VoronRecoveryConfiguration.VoronRecoveryArgsProcessStatus.BadArg:
                Console.WriteLine($"Unexpected argument provided.{Environment.NewLine}");
                goto default;

            default:
                PrintUsage();
                return;
            }
            var recovery = new Recovery(config);
            var cts      = new CancellationTokenSource();

            Console.WriteLine("Press 'q' to quit the recovery process");
            var cancellationTask = Task.Factory.StartNew(() =>
            {
                while (Console.Read() != 'q')
                {
                }
                cts.Cancel();
                //The reason i do an exit here is because if we are in the middle of journal recovery
                //we can't cancel it and it may take a long time.
                //That said i'm still going to give it a while to do a proper exit
                Task.Delay(5000).ContinueWith(_ =>
                {
                    Environment.Exit(1);
                });
            }, cts.Token);

            recovery.Execute(cts.Token);
            cts.Cancel();
        }