private void Execute(Models.Restore restore, LinkedList <CustomVersionedFile> files, bool isNewRestore) { // The `files` argument contains the filesystem paths and versions informed by the user for this restore. // // NOTE: The methods call ORDER is important! // SuppliedFiles = DoLoadOrCreateRestorePlanFiles(restore.RestorePlan, files); //throw new Exception("Simulating failure."); }
public override void OnStart(CustomRestoreAgent agent, Models.Restore restore) { base.OnStart(agent, restore); _daoRestore.Insert(restore); var message = string.Format("Restore started at {0}", StartedAt); Info(message); //StatusInfo.Update(BackupStatusLevel.OK, message); OnUpdate(new RestoreOperationEvent { Status = RestoreOperationStatus.Started, Message = message }); }
public void OnFailure(CustomRestoreAgent agent, Models.Restore restore, Exception exception) { IsRunning = false; var message = string.Format("Restore failed: {0}", exception != null ? exception.Message : "Canceled?"); Report.AddErrorMessage(message); Error(message); //StatusInfo.Update(RestoreStatusLevel.ERROR, message); restore.DidFail(); _daoRestore.Update(restore); OnUpdate(new RestoreOperationEvent { Status = RestoreOperationStatus.Failed, Message = message }); }
private PathScanResults <CustomVersionedFile> DoWork(Models.Restore restore, CancellationToken cancellationToken) { // Scan files. DefaultRestoreScanner scanner = new DefaultRestoreScanner(restore.RestorePlan, cancellationToken); #if DEBUG scanner.FileAdded += (object sender, CustomVersionedFile file) => { logger.Debug("ADDED: File {0} @ {1}", file.Path, file.Version); }; scanner.EntryScanFailed += (object sender, string path, string message, Exception ex) => { logger.Debug("FAILED: {0} - Reason: {1}", path, message); }; #endif scanner.Scan(); return(scanner.Results); }
public async Task <FileVersionerResults> DoRestore(Models.Restore restore, LinkedList <CustomVersionedFile> files, bool newRestore) { Assert.IsNotNull(restore); Assert.AreEqual(TransferStatus.RUNNING, restore.Status); Assert.IsNotNull(files); Results.Reset(); await ExecuteOnBackround(() => { RestoreRepository daoRestore = new RestoreRepository(); Restore = daoRestore.Get(restore.Id); RestorePlanFileRepository daoRestorePlanFile = new RestorePlanFileRepository(); AllFilesFromPlan = daoRestorePlanFile.GetAllByPlan(restore.RestorePlan).ToDictionary <Models.RestorePlanFile, string>(p => p.Path); Execute(restore, files, newRestore); Save(); }, CancellationToken); return(Results); }
public virtual void OnStart(CustomRestoreAgent agent, Models.Restore restore) { IsRunning = true; restore.DidStart(); }
protected async void DoRestore(CustomRestoreAgent agent, Models.Restore restore, RestoreOperationOptions options) { try { CurrentState = RestoreOperationState.STARTING; OnStart(agent, restore); // Mount all network mappings and abort if there is any network mapping failure. CurrentState = RestoreOperationState.MAPPING_NETWORK_DRIVES; Helper.MountAllNetworkDrives(); // Execute pre-actions CurrentState = RestoreOperationState.EXECUTING_PRE_ACTIONS; Helper.ExecutePreActions(); // // Scanning // CurrentState = RestoreOperationState.SCANNING_FILES; LinkedList <CustomVersionedFile> filesToProcess = null; { Task <PathScanResults <CustomVersionedFile> > filesToProcessTask = GetFilesToProcess(restore); { var message = string.Format("Scanning files started."); Info(message); //StatusInfo.Update(BackupStatusLevel.INFO, message); OnUpdate(new RestoreOperationEvent { Status = RestoreOperationStatus.ScanningFilesStarted, Message = message }); } try { await filesToProcessTask; } catch (Exception ex) { if (ex.IsCancellation()) { string message = string.Format("Scanning files was canceled."); Report.AddErrorMessage(message); logger.Warn(message); } else { string message = string.Format("Caught exception during scanning files: {0}", ex.Message); Report.AddErrorMessage(message); logger.Log(LogLevel.Error, ex, message); } if (filesToProcessTask.IsFaulted || filesToProcessTask.IsCanceled) { if (filesToProcessTask.IsCanceled) { OnCancelation(agent, restore, ex); // filesToProcessTask.Exception } else { OnFailure(agent, restore, ex); // filesToProcessTask.Exception } return; } } filesToProcess = filesToProcessTask.Result.Files; { foreach (var entry in filesToProcessTask.Result.FailedFiles) { Report.AddErrorMessage(entry.Value); } if (filesToProcessTask.Result.FailedFiles.Count > 0) { StringBuilder sb = new StringBuilder(); sb.AppendLine("Scanning failed for the following drives/files/directories:"); foreach (var entry in filesToProcessTask.Result.FailedFiles) { sb.AppendLine(string.Format(" Path: {0} - Reason: {1}", entry.Key, entry.Value)); } Warn(sb.ToString()); } var message = string.Format("Scanning files finished."); Info(message); //StatusInfo.Update(BackupStatusLevel.INFO, message); OnUpdate(new RestoreOperationEvent { Status = RestoreOperationStatus.ScanningFilesFinished, Message = message }); } } // // Versioning // CurrentState = RestoreOperationState.VERSIONING_FILES; { Task versionerTask = DoVersionFiles(restore, filesToProcess); { var message = string.Format("Processing files started."); Info(message); //StatusInfo.Update(RestoreStatusLevel.INFO, message); OnUpdate(new RestoreOperationEvent { Status = RestoreOperationStatus.ProcessingFilesStarted, Message = message }); } try { await versionerTask; } catch (Exception ex) { if (ex.IsCancellation()) { string message = string.Format("Processing files was canceled."); Report.AddErrorMessage(message); logger.Warn(message); } else { string message = string.Format("Caught exception during processing files: {0}", ex.Message); Report.AddErrorMessage(message); logger.Log(LogLevel.Error, ex, message); } if (versionerTask.IsFaulted || versionerTask.IsCanceled) { Versioner.Undo(); if (versionerTask.IsCanceled) { OnCancelation(agent, restore, ex); // versionerTask.Exception } else { OnFailure(agent, restore, ex); // versionerTask.Exception } return; } } agent.Files = Versioner.FilesToTransfer; { var message = string.Format("Processing files finished."); Info(message); //StatusInfo.Update(BackupStatusLevel.INFO, message); OnUpdate(new RestoreOperationEvent { Status = RestoreOperationStatus.ProcessingFilesFinished, Message = message }); } { agent.Results.Stats.BytesTotal = agent.EstimatedTransferSize; var message = string.Format("Estimated restore size: {0} files, {1}", agent.Files.Count(), FileSizeUtils.FileSizeToString(agent.EstimatedTransferSize)); Info(message); } } // // Transfer files // CurrentState = RestoreOperationState.TRANSFERRING_FILES; { Task <TransferResults> transferTask = agent.Start(); Report.TransferResults = transferTask.Result; { var message = string.Format("Transfer files started."); Info(message); } try { await transferTask; } catch (Exception ex) { if (ex.IsCancellation()) { string message = string.Format("Transfer files was canceled."); Report.AddErrorMessage(message); logger.Warn(message); } else { string message = string.Format("Caught exception during transfer files: {0}", ex.Message); Report.AddErrorMessage(message); logger.Log(LogLevel.Error, ex, message); } if (transferTask.IsFaulted || transferTask.IsCanceled) { if (transferTask.IsCanceled) { OnCancelation(agent, restore, ex); // transferTask.Exception } else { OnFailure(agent, restore, ex); // transferTask.Exception } return; } } { var message = string.Format("Transfer files finished."); Info(message); } } CurrentState = RestoreOperationState.EXECUTING_POST_ACTIONS; Helper.ExecutePostActions(Report.TransferResults); CurrentState = RestoreOperationState.FINISHING; OnFinish(agent, restore); } catch (Exception ex) { OnFinish(agent, restore, ex); } }
protected abstract Task DoVersionFiles(Models.Restore restore, LinkedList <CustomVersionedFile> files);
protected abstract Task <PathScanResults <CustomVersionedFile> > GetFilesToProcess(Models.Restore restore);
protected void RegisterResultsEventHandlers(Models.Restore restore, TransferResults results) { RestoredFileRepository daoRestoredFile = new RestoredFileRepository(); BackupedFileRepository daoBackupedFile = new BackupedFileRepository(); results.Failed += (object sender, TransferFileProgressArgs args) => { Models.RestoredFile restoredFile = daoRestoredFile.GetByRestoreAndPath(restore, args.FilePath); restoredFile.TransferStatus = TransferStatus.FAILED; restoredFile.UpdatedAt = DateTime.UtcNow; daoRestoredFile.Update(restoredFile); var message = string.Format("Failed {0} - {1}", args.FilePath, args.Exception != null ? args.Exception.Message : "Unknown reason"); Warn(message); //StatusInfo.Update(BackupStatusLevel.ERROR, message); OnUpdate(new RestoreOperationEvent { Status = RestoreOperationStatus.Updated, Message = message, TransferStatus = TransferStatus.FAILED }); }; results.Canceled += (object sender, TransferFileProgressArgs args) => { Models.RestoredFile restoredFile = daoRestoredFile.GetByRestoreAndPath(restore, args.FilePath); restoredFile.TransferStatus = TransferStatus.CANCELED; restoredFile.UpdatedAt = DateTime.UtcNow; daoRestoredFile.Update(restoredFile); var message = string.Format("Canceled {0} - {1}", args.FilePath, args.Exception != null ? args.Exception.Message : "Unknown reason"); Warn(message); //StatusInfo.Update(BackupStatusLevel.ERROR, message); OnUpdate(new RestoreOperationEvent { Status = RestoreOperationStatus.Updated, Message = message, TransferStatus = TransferStatus.CANCELED }); }; results.Completed += (object sender, TransferFileProgressArgs args) => { Models.RestoredFile restoredFile = daoRestoredFile.GetByRestoreAndPath(restore, args.FilePath); restoredFile.TransferStatus = TransferStatus.COMPLETED; restoredFile.UpdatedAt = DateTime.UtcNow; daoRestoredFile.Update(restoredFile); // Only set original modified date if the restored file is the latest version whose transfer is completed, // otherwise, keep the date the OS/filesystem gave it. bool isLatestVersion = daoBackupedFile.IsLatestVersion(restoredFile.BackupedFile); if (isLatestVersion) { // Set original LastWriteTime so this file won't be erroneously included in the next Backup. FileManager.SafeSetFileLastWriteTimeUtc(restoredFile.File.Path, restoredFile.BackupedFile.FileLastWrittenAt); } else { // Keep the original LastWriteTime so this file will be included in the next backup. } var message = string.Format("Completed {0}", args.FilePath); Info(message); OnUpdate(new RestoreOperationEvent { Status = RestoreOperationStatus.Updated, Message = message, TransferStatus = TransferStatus.COMPLETED }); }; results.Started += (object sender, TransferFileProgressArgs args) => { Models.RestoredFile restoredFile = daoRestoredFile.GetByRestoreAndPath(restore, args.FilePath); restoredFile.TransferStatus = TransferStatus.RUNNING; restoredFile.UpdatedAt = DateTime.UtcNow; daoRestoredFile.Update(restoredFile); var message = string.Format("Started {0}", args.FilePath); Info(message); OnUpdate(new RestoreOperationEvent { Status = RestoreOperationStatus.Updated, Message = message }); }; results.Progress += (object sender, TransferFileProgressArgs args) => { #if DEBUG var message = string.Format("Progress {0}% {1} ({2}/{3} bytes)", args.PercentDone, args.FilePath, args.TransferredBytes, args.TotalBytes); //Info(message); #endif OnUpdate(new RestoreOperationEvent { Status = RestoreOperationStatus.Updated, Message = null }); }; }
protected override Task DoVersionFiles(Models.Restore restore, LinkedList <CustomVersionedFile> files) { return(Versioner.NewRestore(restore, files)); }
protected override Task <PathScanResults <CustomVersionedFile> > GetFilesToProcess(Models.Restore restore) { return(ExecuteOnBackround(() => { return DoWork(restore, CancellationTokenSource.Token); }, CancellationTokenSource.Token)); }
public NewRestoreOperation(Models.RestorePlan plan, RestoreOperationOptions options) : base(options) { Restore = new Models.Restore(plan); }
public async Task <FileVersionerResults> ResumeRestore(Models.Restore restore, LinkedList <CustomVersionedFile> files) { return(await DoRestore(restore, files, false)); }
// // Summary: // ... // private IEnumerable <CustomVersionedFile> GetFilesToTransfer(Models.Restore restore, LinkedList <Models.RestorePlanFile> files) { return(files.Select(p => p.VersionedFile)); }
private void OnControlPlanQuery(object sender, ServerCommandEventArgs e) { string planType = e.Command.GetArgumentValue <string>("planType"); Int32 planId = e.Command.GetArgumentValue <Int32>("planId"); ValidatePlanType(planType); bool isRunning = IsPlanRunning(planType, planId); bool needsResume = false; bool isFinished = false; bool isBackup = planType.Equals(PlanTypeEnum.BACKUP.ToString().ToLowerInvariant()); bool isRestore = planType.Equals(PlanTypeEnum.RESTORE.ToString().ToLowerInvariant()); // Report to GUI. Commands.GuiReportPlanStatus report = new Commands.GuiReportPlanStatus(); if (isBackup) { BackupRepository daoBackup = new BackupRepository(); Models.Backup latest = daoBackup.GetLatestByPlan(new Models.BackupPlan { Id = planId }); needsResume = latest != null && latest.NeedsResume(); isFinished = latest != null && latest.IsFinished(); if (isRunning) { report.StartedAt = latest.StartedAt; } else if (isFinished) { report.FinishedAt = latest.FinishedAt; } } else if (isRestore) { RestoreRepository daoRestore = new RestoreRepository(); Models.Restore latest = daoRestore.GetLatestByPlan(new Models.RestorePlan { Id = planId }); needsResume = latest != null && latest.NeedsResume(); isFinished = latest != null && latest.IsFinished(); if (isRunning) { report.StartedAt = latest.StartedAt; } else if (isFinished) { report.FinishedAt = latest.FinishedAt; } } bool isInterrupted = !isRunning && needsResume; Commands.OperationStatus status; // The condition order below is important because more than one flag might be true. if (isInterrupted) { status = Commands.OperationStatus.INTERRUPTED; } else if (needsResume) { status = Commands.OperationStatus.RESUMED; } else if (isRunning) { status = Commands.OperationStatus.STARTED; } else { status = Commands.OperationStatus.NOT_RUNNING; } report.Status = status; Handler.Send(e.Context, Commands.GuiReportOperationStatus(planType, planId, report)); }