Example #1
0
        public void OnCancelation(CustomBackupAgent agent, Models.Backup backup, Exception exception)
        {
            IsRunning = false;

            var message = string.Format("Backup canceled: {0}", exception != null ? exception.Message : "Exception not informed");

            Report.AddErrorMessage(message);
            Error(message);
            //StatusInfo.Update(BackupStatusLevel.ERROR, message);

            backup.WasCanceled();
            _daoBackup.Update(backup);

            OnUpdate(new BackupOperationEvent {
                Status = BackupOperationStatus.Canceled, Message = message
            });
        }
Example #2
0
        private void Save(ISession session)
        {
            Assert.IsFalse(IsSaved);

            BatchProcessor               batchProcessor        = new BatchProcessor();
            BackupRepository             daoBackup             = new BackupRepository(session);
            BackupPlanFileRepository     daoBackupPlanFile     = new BackupPlanFileRepository(session);
            BackupedFileRepository       daoBackupedFile       = new BackupedFileRepository(session);
            BackupPlanPathNodeRepository daoBackupPlanPathNode = new BackupPlanPathNodeRepository(session);

#if false
            var FilesToTrack          = SuppliedFiles.Union(ChangeSet.DeletedFiles);
            var FilesToInsertOrUpdate =
                from f in FilesToTrack
                where
                // Keep it so we'll later add or update a `BackupedFile`.
                ((f.LastStatus == Models.BackupFileStatus.ADDED || f.LastStatus == Models.BackupFileStatus.MODIFIED))
                // Keep it if `LastStatus` is different from `PreviousLastStatus`.
                || ((f.LastStatus == Models.BackupFileStatus.REMOVED || f.LastStatus == Models.BackupFileStatus.DELETED) && (f.LastStatus != f.PreviousLastStatus))
                // Skip all UNCHANGED files.
                select f;
#else
            var FilesToTrack          = SuppliedFiles;
            var FilesToInsertOrUpdate =
                from f in FilesToTrack
                where
                // Keep it so we'll later add or update a `BackupedFile`.
                ((f.LastStatus == Models.BackupFileStatus.ADDED || f.LastStatus == Models.BackupFileStatus.MODIFIED))
                // Skip all UNCHANGED/DELETED/REMOVED files.
                select f;
#endif

            BlockPerfStats stats = new BlockPerfStats();

            using (ITransaction tx = session.BeginTransaction())
            {
                try
                {
                    // ------------------------------------------------------------------------------------

                    stats.Begin("STEP 1");

                    BackupPlanPathNodeCreator pathNodeCreator = new BackupPlanPathNodeCreator(daoBackupPlanPathNode, tx);

                    // 1 - Split path into its components and INSERT new path nodes if they don't exist yet.
                    foreach (Models.BackupPlanFile entry in FilesToInsertOrUpdate)
                    {
                        // Throw if the operation was canceled.
                        CancellationToken.ThrowIfCancellationRequested();

                        try
                        {
                            entry.PathNode = pathNodeCreator.CreateOrUpdatePathNodes(Backup.BackupPlan.StorageAccount, entry);
                        }
                        catch (Exception ex)
                        {
                            string message = string.Format("BUG: Failed to create/update {0} => {1}",
                                                           typeof(Models.BackupPlanPathNode).Name,
                                                           CustomJsonSerializer.SerializeObject(entry, 1));

                            Results.OnError(this, message);
                            logger.Log(LogLevel.Error, ex, message);

                            throw;
                        }

                        batchProcessor.ProcessBatch(session);
                    }

                    batchProcessor.ProcessBatch(session, true);
                    stats.End();

                    // ------------------------------------------------------------------------------------

                    stats.Begin("STEP 2");

                    // 2 - Insert/Update `BackupPlanFile`s as necessary.
                    foreach (Models.BackupPlanFile entry in FilesToInsertOrUpdate)
                    {
                        // Throw if the operation was canceled.
                        CancellationToken.ThrowIfCancellationRequested();

                        // IMPORTANT: It's important that we guarantee the referenced `BackupPlanFile` has a valid `Id`
                        // before we reference it elsewhere, otherwise NHibernate won't have a valid value to put on
                        // the `backup_plan_file_id` column.
                        try
                        {
                            daoBackupPlanFile.InsertOrUpdate(tx, entry);                             // Guarantee it's saved
                        }
                        catch (Exception ex)
                        {
                            string message = string.Format("BUG: Failed to insert/update {0} => {1}",
                                                           typeof(Models.BackupPlanFile).Name,
                                                           CustomJsonSerializer.SerializeObject(entry, 1));

                            Results.OnError(this, message);
                            logger.Log(LogLevel.Error, ex, message);

                            logger.Error("Dump of failed object: {0}", entry.DumpMe());
                            throw;
                        }

                        batchProcessor.ProcessBatch(session);
                    }

                    batchProcessor.ProcessBatch(session, true);
                    stats.End();

                    // ------------------------------------------------------------------------------------

                    stats.Begin("STEP 3");

                    // 3 - Insert/Update `BackupedFile`s as necessary and add them to the `Backup`.
                    //List<Models.BackupedFile> backupedFiles = new List<Models.BackupedFile>(FilesToInsertOrUpdate.Count());

                    foreach (Models.BackupPlanFile entry in FilesToInsertOrUpdate)
                    {
                        // Throw if the operation was canceled.
                        CancellationToken.ThrowIfCancellationRequested();

                        Models.BackupedFile backupedFile = daoBackupedFile.GetByBackupAndPath(Backup, entry.Path);
                        if (backupedFile == null)                         // If we're resuming, this should already exist.
                        {
                            // Create `BackupedFile`.
                            backupedFile = new Models.BackupedFile(Backup, entry);
                        }
                        backupedFile.FileSize          = entry.LastSize;
                        backupedFile.FileStatus        = entry.LastStatus;
                        backupedFile.FileLastWrittenAt = entry.LastWrittenAt;
                        backupedFile.FileLastChecksum  = entry.LastChecksum;
                        switch (entry.LastStatus)
                        {
                        default:
                            backupedFile.TransferStatus = default(TransferStatus);
                            break;

                        case Models.BackupFileStatus.REMOVED:
                        case Models.BackupFileStatus.DELETED:
                            backupedFile.TransferStatus = TransferStatus.COMPLETED;
                            break;
                        }
                        backupedFile.UpdatedAt = DateTime.UtcNow;

                        try
                        {
                            daoBackupedFile.InsertOrUpdate(tx, backupedFile);
                        }
                        catch (Exception ex)
                        {
                            logger.Log(LogLevel.Error, ex, "BUG: Failed to insert/update {0} => {1}",
                                       typeof(Models.BackupedFile).Name,
                                       CustomJsonSerializer.SerializeObject(backupedFile, 1));
                            throw;
                        }

                        //backupedFiles.Add(backupedFile);

                        batchProcessor.ProcessBatch(session);
                    }

                    batchProcessor.ProcessBatch(session, true);
                    stats.End();

                    // ------------------------------------------------------------------------------------

                    stats.Begin("STEP 4");

                    // 4 - Update all `BackupPlanFile`s that already exist for the backup plan associated with this backup operation.
                    {
                        var AllFilesFromPlanThatWerentUpdatedYet = AllFilesFromPlan.Values.Except(FilesToInsertOrUpdate);
                        foreach (Models.BackupPlanFile file in AllFilesFromPlanThatWerentUpdatedYet)
                        {
                            // Throw if the operation was canceled.
                            CancellationToken.ThrowIfCancellationRequested();

                            //Console.WriteLine("2: {0}", file.Path);
                            try
                            {
                                daoBackupPlanFile.Update(tx, file);
                            }
                            catch (Exception ex)
                            {
                                string message = string.Format("BUG: Failed to update {0} => {1} ",
                                                               typeof(Models.BackupPlanFile).Name,
                                                               CustomJsonSerializer.SerializeObject(file, 1));

                                Results.OnError(this, message);
                                logger.Log(LogLevel.Error, ex, message);

                                throw;
                            }

                            batchProcessor.ProcessBatch(session);
                        }
                    }

                    batchProcessor.ProcessBatch(session, true);
                    stats.End();

                    // ------------------------------------------------------------------------------------

                    stats.Begin("STEP 5");

                    // 5 - Insert/Update `Backup` and its `BackupedFile`s into the database, also saving
                    //     the `BackupPlanFile`s instances that may have been changed by step 2.
                    {
                        //foreach (var bf in backupedFiles)
                        //{
                        //	// Throw if the operation was canceled.
                        //	CancellationToken.ThrowIfCancellationRequested();
                        //
                        //	Backup.Files.Add(bf);
                        //
                        //	ProcessBatch(session);
                        //}

                        try
                        {
                            daoBackup.Update(tx, Backup);
                        }
                        catch (Exception ex)
                        {
                            string message = string.Format("BUG: Failed to update {0} => {1}",
                                                           typeof(Models.Backup).Name,
                                                           CustomJsonSerializer.SerializeObject(Backup, 1));

                            Results.OnError(this, message);
                            logger.Log(LogLevel.Error, ex, message);

                            throw;
                        }
                    }

                    batchProcessor.ProcessBatch(session, true);
                    stats.End();

                    // ------------------------------------------------------------------------------------

                    tx.Commit();
                }
                catch (OperationCanceledException)
                {
                    string message = "Operation cancelled";

                    Results.OnError(this, message);
                    logger.Warn(message);

                    tx.Rollback();                     // Rollback the transaction
                    throw;
                }
                catch (Exception ex)
                {
                    string message = string.Format("Caught Exception: {0}", ex.Message);

                    Results.OnError(this, message);
                    logger.Log(LogLevel.Error, ex, message);

                    tx.Rollback();                     // Rollback the transaction
                    throw;
                }
                finally
                {
                    // ...
                }
            }

            IsSaved = true;

            // 6 - Create versioned files and remove files that won't belong to this backup.
            TransferSet.Files = GetFilesToTransfer(Backup, SuppliedFiles);

            // Test to see if things are okay!
            {
                var transferCount = TransferSet.Files.Count();
                var filesCount    = ChangeSet.AddedFiles.Count() + ChangeSet.ModifiedFiles.Count();

                Assert.IsTrue(transferCount == filesCount, "TransferSet.Files must be equal (ChangeSet.AddedFiles + ChangeSet.ModifiedFiles)");
            }
        }