Пример #1
0
        public override async Task Execute()
        {
            var state = GetLastMigrationState();

            var migratedDocumentsOrAttachments = false;

            if (Options.OperateOnTypes.HasFlag(DatabaseItemType.Documents))
            {
                await MigrateDocuments(state?.LastDocsEtag ?? LastEtagsInfo.EtagEmpty);

                migratedDocumentsOrAttachments = true;
            }

            if (Options.OperateOnTypes.HasFlag(DatabaseItemType.LegacyAttachments))
            {
                await MigrateAttachments(state?.LastAttachmentsEtag ?? LastEtagsInfo.EtagEmpty, Parameters.Result);

                migratedDocumentsOrAttachments = true;
            }

            if (migratedDocumentsOrAttachments)
            {
                Parameters.Result.Documents.Processed = true;
                Parameters.OnProgress.Invoke(Parameters.Result.Progress);
                await SaveLastOperationState(GenerateLastEtagsInfo());
            }

            if (Options.OperateOnTypes.HasFlag(DatabaseItemType.Indexes))
            {
                await MigrateIndexes();
            }

            DatabaseSmuggler.EnsureProcessed(Parameters.Result);
        }
Пример #2
0
        public override async Task Execute()
        {
            var state         = GetLastMigrationState();
            var originalState = state;

            var operateOnTypes = GenerateOperateOnTypes();

            if (operateOnTypes == ItemType.None && Options.ImportRavenFs == false)
            {
                throw new BadRequestException("No types to import");
            }

            if (Options.ImportRavenFs)
            {
                Parameters.Result.AddInfo("Started processing RavenFS files");
                Parameters.OnProgress.Invoke(Parameters.Result.Progress);

                var lastRavenFsEtag = await MigrateRavenFs(state?.LastRavenFsEtag ?? LastEtagsInfo.EtagEmpty, Parameters.Result);

                state = GetLastMigrationState() ?? GenerateLastEtagsInfo();
                state.LastRavenFsEtag = lastRavenFsEtag;
                await SaveLastOperationState(state);
            }

            if (operateOnTypes != ItemType.None)
            {
                if (Options.ImportRavenFs && operateOnTypes.HasFlag(ItemType.Documents) == false)
                {
                    Parameters.Result.Documents.Processed = true;
                    Parameters.OnProgress.Invoke(Parameters.Result.Progress);
                }

                var databaseMigrationOptions = new DatabaseMigrationOptions
                {
                    BatchSize                    = 1024,
                    OperateOnTypes               = operateOnTypes,
                    ExportDeletions              = originalState != null,
                    StartDocsEtag                = state?.LastDocsEtag ?? LastEtagsInfo.EtagEmpty,
                    StartDocsDeletionEtag        = state?.LastDocDeleteEtag ?? LastEtagsInfo.EtagEmpty,
                    StartAttachmentsEtag         = state?.LastAttachmentsEtag ?? LastEtagsInfo.EtagEmpty,
                    StartAttachmentsDeletionEtag = state?.LastAttachmentsDeleteEtag ?? LastEtagsInfo.EtagEmpty
                };

                // getting a new operation id was added in v3.5
                var operationId = _majorVersion == MajorVersion.V30 ? 0 : await GetOperationId();

                object exportData;
                if (_majorVersion == MajorVersion.V30)
                {
                    exportData = new ExportDataV3
                    {
                        SmugglerOptions = JsonConvert.SerializeObject(databaseMigrationOptions)
                    };
                }
                else
                {
                    exportData = new ExportDataV35
                    {
                        DownloadOptions = JsonConvert.SerializeObject(databaseMigrationOptions),
                        ProgressTaskId  = operationId
                    };
                }

                var exportOptions = JsonConvert.SerializeObject(exportData);
                var canGetLastStateByOperationId = _buildVersion >= 35215;

                await MigrateDatabase(exportOptions, readLegacyEtag : canGetLastStateByOperationId == false);

                var lastState = await GetLastState(canGetLastStateByOperationId, operationId);

                if (lastState != null)
                {
                    // refresh the migration state, in case we are running here with a RavenFS concurrently
                    lastState.LastRavenFsEtag = GetLastMigrationState()?.LastRavenFsEtag ?? LastEtagsInfo.EtagEmpty;
                    await SaveLastOperationState(lastState);
                }
            }
            else
            {
                if (Options.ImportRavenFs)
                {
                    Parameters.Result.Documents.Processed = true;
                }

                DatabaseSmuggler.EnsureProcessed(Parameters.Result);
            }
        }
Пример #3
0
        public BackupResult RunPeriodicBackup(Action <IOperationProgress> onProgress, ref PeriodicBackupStatus runningBackupStatus)
        {
            _onProgress = onProgress;
            AddInfo($"Started task: '{_taskName}'");

            var totalSw           = Stopwatch.StartNew();
            var operationCanceled = false;

            try
            {
                if (_forTestingPurposes != null && _forTestingPurposes.SimulateFailedBackup)
                {
                    throw new Exception(nameof(_forTestingPurposes.SimulateFailedBackup));
                }
                if (_forTestingPurposes != null && _forTestingPurposes.OnBackupTaskRunHoldBackupExecution != null)
                {
                    _forTestingPurposes.OnBackupTaskRunHoldBackupExecution.Task.Wait();
                }

                if (runningBackupStatus.LocalBackup == null)
                {
                    runningBackupStatus.LocalBackup = new LocalBackup();
                }

                if (runningBackupStatus.LastRaftIndex == null)
                {
                    runningBackupStatus.LastRaftIndex = new LastRaftIndex();
                }

                runningBackupStatus.IsFull = _isFullBackup;

                if (_logger.IsInfoEnabled)
                {
                    var fullBackupText = "a " + (_configuration.BackupType == BackupType.Backup ? "full backup" : "snapshot");
                    _logger.Info($"Creating {(_isFullBackup ? fullBackupText : "an incremental backup")}");
                }

                if (_isFullBackup == false)
                {
                    // if we come from old version the _previousBackupStatus won't have LastRaftIndex
                    _previousBackupStatus.LastRaftIndex ??= new LastRaftIndex();

                    // no-op if nothing has changed
                    var(currentLastEtag, currentChangeVector) = _database.ReadLastEtagAndChangeVector();
                    var currentLastRaftIndex = GetDatabaseEtagForBackup();

                    // if we come from old version the _previousBackupStatus won't have LastRaftIndex
                    _previousBackupStatus.LastRaftIndex ??= new LastRaftIndex();

                    if (currentLastEtag == _previousBackupStatus.LastEtag &&
                        currentChangeVector == _previousBackupStatus.LastDatabaseChangeVector &&
                        currentLastRaftIndex == _previousBackupStatus.LastRaftIndex.LastEtag)
                    {
                        var message = $"Skipping incremental backup because no changes were made from last full backup on {_previousBackupStatus.LastFullBackup}.";

                        if (_logger.IsInfoEnabled)
                        {
                            _logger.Info(message);
                        }

                        runningBackupStatus.LastIncrementalBackup                     = _startTimeUtc;
                        runningBackupStatus.LocalBackup.LastIncrementalBackup         = _startTimeUtc;
                        runningBackupStatus.LocalBackup.IncrementalBackupDurationInMs = 0;
                        DatabaseSmuggler.EnsureProcessed(_backupResult);
                        AddInfo(message);

                        return(_backupResult);
                    }
                }

                // update the local configuration before starting the local backup
                var localSettings = GetBackupConfigurationFromScript(_configuration.LocalSettings, x => JsonDeserializationServer.LocalSettings(x),
                                                                     settings => PutServerWideBackupConfigurationCommand.UpdateSettingsForLocal(settings, _database.Name));

                GenerateFolderNameAndBackupDirectory(localSettings, _startTimeUtc, out var nowAsString, out var folderName, out var backupDirectory);
                var startDocumentEtag = _isFullBackup == false ? _previousBackupStatus.LastEtag : null;
                var startRaftIndex    = _isFullBackup == false ? _previousBackupStatus.LastRaftIndex.LastEtag : null;

                var fileName             = GetFileName(_isFullBackup, backupDirectory.FullPath, nowAsString, _configuration.BackupType, out string backupFilePath);
                var internalBackupResult = CreateLocalBackupOrSnapshot(runningBackupStatus, backupFilePath, startDocumentEtag, startRaftIndex);

                runningBackupStatus.LocalBackup.BackupDirectory = _backupToLocalFolder ? backupDirectory.FullPath : null;
                runningBackupStatus.LocalBackup.TempFolderUsed  = _backupToLocalFolder == false;
                runningBackupStatus.IsEncrypted = _isBackupEncrypted;

                try
                {
                    UploadToServer(backupFilePath, folderName, fileName);
                }
                finally
                {
                    runningBackupStatus.UploadToS3          = _backupResult.S3Backup;
                    runningBackupStatus.UploadToAzure       = _backupResult.AzureBackup;
                    runningBackupStatus.UploadToGoogleCloud = _backupResult.GoogleCloudBackup;
                    runningBackupStatus.UploadToGlacier     = _backupResult.GlacierBackup;
                    runningBackupStatus.UploadToFtp         = _backupResult.FtpBackup;

                    _backupResult.LocalBackup = new LocalBackup
                    {
                        BackupDirectory = folderName,
                        FileName        = fileName
                    };

                    // if user did not specify local folder we delete the temporary file
                    if (_backupToLocalFolder == false)
                    {
                        DeleteFile(backupFilePath);
                    }
                }

                runningBackupStatus.LastEtag = internalBackupResult.LastDocumentEtag;
                runningBackupStatus.LastDatabaseChangeVector = internalBackupResult.LastDatabaseChangeVector;
                runningBackupStatus.LastRaftIndex.LastEtag   = internalBackupResult.LastRaftIndex;
                runningBackupStatus.FolderName = folderName;

                if (_isFullBackup)
                {
                    runningBackupStatus.LastFullBackup = _startTimeUtc;
                }
                else
                {
                    runningBackupStatus.LastIncrementalBackup = _startTimeUtc;
                }

                totalSw.Stop();

                if (_logger.IsInfoEnabled)
                {
                    var fullBackupText = "a " + (_configuration.BackupType == BackupType.Backup ? " full backup" : " snapshot");
                    _logger.Info($"Successfully created {(_isFullBackup ? fullBackupText : "an incremental backup")} " +
                                 $"in {totalSw.ElapsedMilliseconds:#,#;;0} ms");
                }

                return(_backupResult);
            }
            catch (OperationCanceledException)
            {
                operationCanceled = TaskCancelToken.Token.IsCancellationRequested;
                throw;
            }
            catch (ObjectDisposedException)
            {
                // shutting down, probably
                operationCanceled = true;
                throw;
            }
            catch (Exception e)
            {
                const string message = "Error when performing periodic backup";

                runningBackupStatus.Error = new Error
                {
                    Exception = e.ToString(),
                    At        = DateTime.UtcNow
                };

                if (_logger.IsOperationsEnabled)
                {
                    _logger.Operations(message, e);
                }

                _database.NotificationCenter.Add(AlertRaised.Create(
                                                     _database.Name,
                                                     $"Periodic Backup task: '{_taskName}'",
                                                     message,
                                                     AlertType.PeriodicBackup,
                                                     NotificationSeverity.Error,
                                                     details: new ExceptionDetails(e)));

                throw;
            }
            finally
            {
                if (operationCanceled == false)
                {
                    // whether we succeeded or not,
                    // in periodic backup we need to update the last backup time to avoid
                    // starting a new backup right after this one
                    if (_isFullBackup)
                    {
                        runningBackupStatus.LastFullBackupInternal = _startTimeUtc;
                    }
                    else
                    {
                        runningBackupStatus.LastIncrementalBackupInternal = _startTimeUtc;
                    }

                    runningBackupStatus.NodeTag      = _database.ServerStore.NodeTag;
                    runningBackupStatus.DurationInMs = totalSw.ElapsedMilliseconds;
                    UpdateOperationId(runningBackupStatus);

                    if (_isOneTimeBackup == false)
                    {
                        runningBackupStatus.Version = ++_previousBackupStatus.Version;
                        // save the backup status
                        AddInfo("Saving backup status");
                        SaveBackupStatus(runningBackupStatus, _database, _logger, _backupResult);
                    }
                }
            }
        }
Пример #4
0
        public async Task <IOperationResult> RunPeriodicBackup(Action <IOperationProgress> onProgress)
        {
            AddInfo($"Started task: '{_configuration.Name}'", onProgress);

            var totalSw           = Stopwatch.StartNew();
            var operationCanceled = false;

            var runningBackupStatus = _periodicBackup.RunningBackupStatus = new PeriodicBackupStatus
            {
                TaskId                        = _configuration.TaskId,
                BackupType                    = _configuration.BackupType,
                LastEtag                      = _previousBackupStatus.LastEtag,
                LastFullBackup                = _previousBackupStatus.LastFullBackup,
                LastIncrementalBackup         = _previousBackupStatus.LastIncrementalBackup,
                LastFullBackupInternal        = _previousBackupStatus.LastFullBackupInternal,
                LastIncrementalBackupInternal = _previousBackupStatus.LastIncrementalBackupInternal,
                IsFull                        = _isFullBackup,
                LocalBackup                   = _previousBackupStatus.LocalBackup,
                LastOperationId               = _previousBackupStatus.LastOperationId
            };

            try
            {
                using (_database.DocumentsStorage.ContextPool.AllocateOperationContext(out DocumentsOperationContext context))
                    using (var tx = context.OpenReadTransaction())
                    {
                        var now = DateTime.Now.ToString(DateTimeFormat, CultureInfo.InvariantCulture);

                        if (runningBackupStatus.LocalBackup == null)
                        {
                            runningBackupStatus.LocalBackup = new LocalBackup();
                        }

                        if (_logger.IsInfoEnabled)
                        {
                            var fullBackupText = "a " + (_configuration.BackupType == BackupType.Backup ? "full backup" : "snapshot");
                            _logger.Info($"Creating {(_isFullBackup ? fullBackupText : "an incremental backup")}");
                        }

                        if (_isFullBackup == false)
                        {
                            // no-op if nothing has changed
                            var currentLastEtag = DocumentsStorage.ReadLastEtag(tx.InnerTransaction);
                            if (currentLastEtag == _previousBackupStatus.LastEtag)
                            {
                                var message = "Skipping incremental backup because " +
                                              $"last etag ({currentLastEtag:#,#;;0}) hasn't changed since last backup";

                                if (_logger.IsInfoEnabled)
                                {
                                    _logger.Info(message);
                                }

                                UpdateOperationId(runningBackupStatus);
                                runningBackupStatus.LastIncrementalBackup = _startTime;
                                DatabaseSmuggler.EnsureProcessed(_backupResult);
                                AddInfo(message, onProgress);

                                return(_backupResult);
                            }
                        }

                        GenerateFolderNameAndBackupDirectory(now, out var folderName, out var backupDirectory);
                        var startDocumentEtag = _isFullBackup == false ? _previousBackupStatus.LastEtag : null;
                        var fileName          = GetFileName(_isFullBackup, backupDirectory.FullPath, now, _configuration.BackupType, out string backupFilePath);
                        var lastEtag          = CreateLocalBackupOrSnapshot(runningBackupStatus, backupFilePath, startDocumentEtag, context, tx, onProgress);

                        runningBackupStatus.LocalBackup.BackupDirectory = _backupToLocalFolder ? backupDirectory.FullPath : null;
                        runningBackupStatus.LocalBackup.TempFolderUsed  = _backupToLocalFolder == false;
                        runningBackupStatus.IsFull = _isFullBackup;

                        try
                        {
                            await UploadToServer(backupFilePath, folderName, fileName, onProgress);
                        }
                        finally
                        {
                            runningBackupStatus.UploadToS3      = _backupResult.S3Backup;
                            runningBackupStatus.UploadToAzure   = _backupResult.AzureBackup;
                            runningBackupStatus.UploadToGlacier = _backupResult.GlacierBackup;
                            runningBackupStatus.UploadToFtp     = _backupResult.FtpBackup;

                            // if user did not specify local folder we delete the temporary file
                            if (_backupToLocalFolder == false)
                            {
                                IOExtensions.DeleteFile(backupFilePath);
                            }
                        }

                        UpdateOperationId(runningBackupStatus);
                        runningBackupStatus.LastEtag   = lastEtag;
                        runningBackupStatus.FolderName = folderName;
                        if (_isFullBackup)
                        {
                            runningBackupStatus.LastFullBackup = _periodicBackup.StartTime;
                        }
                        else
                        {
                            runningBackupStatus.LastIncrementalBackup = _periodicBackup.StartTime;
                        }
                    }

                totalSw.Stop();

                if (_logger.IsInfoEnabled)
                {
                    var fullBackupText = "a " + (_configuration.BackupType == BackupType.Backup ? " full backup" : " snapshot");
                    _logger.Info($"Successfully created {(_isFullBackup ? fullBackupText : "an incremental backup")} " +
                                 $"in {totalSw.ElapsedMilliseconds:#,#;;0} ms");
                }

                return(_backupResult);
            }
            catch (OperationCanceledException)
            {
                operationCanceled = TaskCancelToken.Token.IsCancellationRequested &&
                                    _databaseShutdownCancellationToken.IsCancellationRequested;
                throw;
            }
            catch (ObjectDisposedException)
            {
                // shutting down, probably
                operationCanceled = true;
                throw;
            }
            catch (Exception e)
            {
                const string message = "Error when performing periodic backup";

                runningBackupStatus.Error = new Error
                {
                    Exception = e.ToString(),
                    At        = DateTime.UtcNow
                };

                if (_logger.IsOperationsEnabled)
                {
                    _logger.Operations(message, e);
                }

                _database.NotificationCenter.Add(AlertRaised.Create(
                                                     _database.Name,
                                                     "Periodic Backup",
                                                     message,
                                                     AlertType.PeriodicBackup,
                                                     NotificationSeverity.Error,
                                                     details: new ExceptionDetails(e)));

                throw;
            }
            finally
            {
                if (operationCanceled == false)
                {
                    // whether we succeeded or not,
                    // we need to update the last backup time to avoid
                    // starting a new backup right after this one
                    if (_isFullBackup)
                    {
                        runningBackupStatus.LastFullBackupInternal = _startTime;
                    }
                    else
                    {
                        runningBackupStatus.LastIncrementalBackupInternal = _startTime;
                    }

                    runningBackupStatus.NodeTag      = _serverStore.NodeTag;
                    runningBackupStatus.DurationInMs = totalSw.ElapsedMilliseconds;
                    runningBackupStatus.Version      = ++_previousBackupStatus.Version;

                    _periodicBackup.BackupStatus = runningBackupStatus;

                    // save the backup status
                    await WriteStatus(runningBackupStatus, onProgress);
                }
            }
        }