/// <summary>
        /// Migrates the study to new tier
        /// </summary>
        /// <param name="storage"></param>
        /// <param name="newFilesystem"></param>
        private void DoMigrateStudy(StudyStorageLocation storage, ServerFilesystemInfo newFilesystem)
        {
            Platform.CheckForNullReference(storage, "storage");
            Platform.CheckForNullReference(newFilesystem, "newFilesystem");

            TierMigrationStatistics stat = new TierMigrationStatistics {StudyInstanceUid = storage.StudyInstanceUid};
        	stat.ProcessSpeed.Start();
    	    StudyXml studyXml = storage.LoadStudyXml();
            stat.StudySize = (ulong) studyXml.GetStudySize(); 

            Platform.Log(LogLevel.Info, "About to migrate study {0} from {1} to {2}", 
                    storage.StudyInstanceUid, storage.FilesystemTierEnum, newFilesystem.Filesystem.Description);
			
            string newPath = Path.Combine(newFilesystem.Filesystem.FilesystemPath, storage.PartitionFolder);
    	    DateTime startTime = Platform.Time;
            DateTime lastLog = Platform.Time;
    	    int fileCounter = 0;
    	    ulong bytesCopied = 0;
    	    long instanceCountInXml = studyXml.NumberOfStudyRelatedInstances;
            
            using (ServerCommandProcessor processor = new ServerCommandProcessor("Migrate Study"))
            {
                TierMigrationContext context = new TierMigrationContext
                                               	{
                                               		OriginalStudyLocation = storage,
                                               		Destination = newFilesystem
                                               	};

				// The multiple CreateDirectoryCommands are done so that rollback of the directories being created happens properly if either of the directories already exist.
				var origFolder = context.OriginalStudyLocation.GetStudyPath();
                processor.AddCommand(new CreateDirectoryCommand(newPath));

                newPath = Path.Combine(newPath, context.OriginalStudyLocation.StudyFolder);
                processor.AddCommand(new CreateDirectoryCommand(newPath));

                newPath = Path.Combine(newPath, context.OriginalStudyLocation.StudyInstanceUid);
                // don't create this directory so that it won't be backed up by MoveDirectoryCommand

				var copyDirCommand = new CopyDirectoryCommand(origFolder, newPath, 
                    delegate (string path)
                        {
                            // Update the progress. This is useful if the migration takes long time to complete.

                            FileInfo file = new FileInfo(path);
                            bytesCopied += (ulong)file.Length;
                            fileCounter++;
                            if (file.Extension != null && file.Extension.Equals(ServerPlatform.DicomFileExtension, StringComparison.InvariantCultureIgnoreCase))
                            {
                                TimeSpan elapsed = Platform.Time - lastLog;
                                TimeSpan totalElapsed = Platform.Time - startTime;
                                double speedInMBPerSecond = 0;
                                if (totalElapsed.TotalSeconds > 0)
                                {
                                    speedInMBPerSecond = (bytesCopied / 1024f / 1024f) / totalElapsed.TotalSeconds;
                                }

                                if (elapsed > TimeSpan.FromSeconds(WorkQueueSettings.Instance.TierMigrationProgressUpdateInSeconds))
                                {
                                    #region Log Progress

                                    StringBuilder stats = new StringBuilder();
                                    if (instanceCountInXml != 0)
                                    {
                                        float pct = (float)fileCounter / instanceCountInXml;
                                        stats.AppendFormat("{0} files moved [{1:0.0}MB] since {2} ({3:0}% completed). Speed={4:0.00}MB/s",
                                                    fileCounter, bytesCopied / 1024f / 1024f, startTime, pct * 100, speedInMBPerSecond);
                                    }
                                    else
                                    {
                                        stats.AppendFormat("{0} files moved [{1:0.0}MB] since {2}. Speed={3:0.00}MB/s",
                                                    fileCounter, bytesCopied / 1024f / 1024f, startTime, speedInMBPerSecond);

                                    }

                                    Platform.Log(LogLevel.Info, "Tier migration for study {0}: {1}", storage.StudyInstanceUid, stats.ToString());
                                    try
                                    {
                                        using (IUpdateContext ctx = PersistentStoreRegistry.GetDefaultStore().OpenUpdateContext(UpdateContextSyncMode.Flush))
                                        {
                                            IWorkQueueEntityBroker broker = ctx.GetBroker<IWorkQueueEntityBroker>();
                                            WorkQueueUpdateColumns parameters = new WorkQueueUpdateColumns
                                                                                	{FailureDescription = stats.ToString()};
                                        	broker.Update(WorkQueueItem.GetKey(), parameters);
                                            ctx.Commit();
                                        }
                                    }
                                    catch
                                    {
                                    	// can't log the progress so far... just ignore it
                                    }
                                    finally
                                    {
                                        lastLog = DateTime.Now;
                                    } 
                                    #endregion
                                }
                            }
                        });
                processor.AddCommand(copyDirCommand);

                DeleteDirectoryCommand delDirCommand = new DeleteDirectoryCommand(origFolder, false)
                                                       	{RequiresRollback = false};
            	processor.AddCommand(delDirCommand);
                
                TierMigrateDatabaseUpdateCommand updateDbCommand = new TierMigrateDatabaseUpdateCommand(context);
                processor.AddCommand(updateDbCommand);

                Platform.Log(LogLevel.Info, "Start migrating study {0}.. expecting {1} to be moved", storage.StudyInstanceUid, ByteCountFormatter.Format(stat.StudySize));
                if (!processor.Execute())
                {
                	if (processor.FailureException != null)
                        throw processor.FailureException;
                	throw new ApplicationException(processor.FailureReason);
                }

            	stat.DBUpdate = updateDbCommand.Statistics;
                stat.CopyFiles = copyDirCommand.CopySpeed;
                stat.DeleteDirTime = delDirCommand.Statistics;
            }

            stat.ProcessSpeed.SetData(bytesCopied);
            stat.ProcessSpeed.End();

            Platform.Log(LogLevel.Info, "Successfully migrated study {0} from {1} to {2} in {3} [ {4} files, {5} @ {6}, DB Update={7}, Remove Dir={8}]",
                            storage.StudyInstanceUid, 
                            storage.FilesystemTierEnum,
                            newFilesystem.Filesystem.FilesystemTierEnum,
                            TimeSpanFormatter.Format(stat.ProcessSpeed.ElapsedTime), 
                            fileCounter,
                            ByteCountFormatter.Format(bytesCopied), 
                            stat.CopyFiles.FormattedValue,
                            stat.DBUpdate.FormattedValue,
                            stat.DeleteDirTime.FormattedValue);

    	    string originalPath = storage.GetStudyPath();
            if (Directory.Exists(storage.GetStudyPath()))
            {
                Platform.Log(LogLevel.Info, "Original study folder could not be deleted. It must be cleaned up manually: {0}", originalPath);
                ServerPlatform.Alert(AlertCategory.Application, AlertLevel.Warning, WorkQueueItem.WorkQueueTypeEnum.ToString(), 1000, GetWorkQueueContextData(WorkQueueItem), TimeSpan.Zero,
                    "Study has been migrated to a new tier. Original study folder must be cleaned up manually: {0}", originalPath);
            }

            UpdateAverageStatistics(stat);
            
        }
Exemple #2
0
        /// <summary>
        /// Migrates the study to new tier
        /// </summary>
        /// <param name="storage"></param>
        /// <param name="newFilesystem"></param>
        private void DoMigrateStudy(StudyStorageLocation storage, ServerFilesystemInfo newFilesystem)
        {
            Platform.CheckForNullReference(storage, "storage");
            Platform.CheckForNullReference(newFilesystem, "newFilesystem");

            TierMigrationStatistics stat = new TierMigrationStatistics {
                StudyInstanceUid = storage.StudyInstanceUid
            };

            stat.ProcessSpeed.Start();
            StudyXml studyXml = storage.LoadStudyXml();

            stat.StudySize = (ulong)studyXml.GetStudySize();

            Platform.Log(LogLevel.Info, "About to migrate study {0} from {1} to {2}",
                         storage.StudyInstanceUid, storage.FilesystemTierEnum, newFilesystem.Filesystem.Description);

            string   newPath            = Path.Combine(newFilesystem.Filesystem.FilesystemPath, storage.PartitionFolder);
            DateTime startTime          = Platform.Time;
            DateTime lastLog            = Platform.Time;
            int      fileCounter        = 0;
            ulong    bytesCopied        = 0;
            long     instanceCountInXml = studyXml.NumberOfStudyRelatedInstances;

            using (ServerCommandProcessor processor = new ServerCommandProcessor("Migrate Study"))
            {
                TierMigrationContext context = new TierMigrationContext
                {
                    OriginalStudyLocation = storage,
                    Destination           = newFilesystem
                };

                // The multiple CreateDirectoryCommands are done so that rollback of the directories being created happens properly if either of the directories already exist.
                var origFolder = context.OriginalStudyLocation.GetStudyPath();
                processor.AddCommand(new CreateDirectoryCommand(newPath));

                newPath = Path.Combine(newPath, context.OriginalStudyLocation.StudyFolder);
                processor.AddCommand(new CreateDirectoryCommand(newPath));

                newPath = Path.Combine(newPath, context.OriginalStudyLocation.StudyInstanceUid);
                // don't create this directory so that it won't be backed up by MoveDirectoryCommand

                var copyDirCommand = new CopyDirectoryCommand(origFolder, newPath,
                                                              delegate(string path)
                {
                    // Update the progress. This is useful if the migration takes long time to complete.

                    FileInfo file = new FileInfo(path);
                    bytesCopied  += (ulong)file.Length;
                    fileCounter++;
                    if (file.Extension != null && file.Extension.Equals(ServerPlatform.DicomFileExtension, StringComparison.InvariantCultureIgnoreCase))
                    {
                        TimeSpan elapsed          = Platform.Time - lastLog;
                        TimeSpan totalElapsed     = Platform.Time - startTime;
                        double speedInMBPerSecond = 0;
                        if (totalElapsed.TotalSeconds > 0)
                        {
                            speedInMBPerSecond = (bytesCopied / 1024f / 1024f) / totalElapsed.TotalSeconds;
                        }

                        if (elapsed > TimeSpan.FromSeconds(WorkQueueSettings.Instance.TierMigrationProgressUpdateInSeconds))
                        {
                            #region Log Progress

                            StringBuilder stats = new StringBuilder();
                            if (instanceCountInXml != 0)
                            {
                                float pct = (float)fileCounter / instanceCountInXml;
                                stats.AppendFormat("{0} files moved [{1:0.0}MB] since {2} ({3:0}% completed). Speed={4:0.00}MB/s",
                                                   fileCounter, bytesCopied / 1024f / 1024f, startTime, pct * 100, speedInMBPerSecond);
                            }
                            else
                            {
                                stats.AppendFormat("{0} files moved [{1:0.0}MB] since {2}. Speed={3:0.00}MB/s",
                                                   fileCounter, bytesCopied / 1024f / 1024f, startTime, speedInMBPerSecond);
                            }

                            Platform.Log(LogLevel.Info, "Tier migration for study {0}: {1}", storage.StudyInstanceUid, stats.ToString());
                            try
                            {
                                using (IUpdateContext ctx = PersistentStoreRegistry.GetDefaultStore().OpenUpdateContext(UpdateContextSyncMode.Flush))
                                {
                                    IWorkQueueEntityBroker broker     = ctx.GetBroker <IWorkQueueEntityBroker>();
                                    WorkQueueUpdateColumns parameters = new WorkQueueUpdateColumns
                                    {
                                        FailureDescription = stats.ToString()
                                    };
                                    broker.Update(WorkQueueItem.GetKey(), parameters);
                                    ctx.Commit();
                                }
                            }
                            catch
                            {
                                // can't log the progress so far... just ignore it
                            }
                            finally
                            {
                                lastLog = DateTime.Now;
                            }
                            #endregion
                        }
                    }
                });
                processor.AddCommand(copyDirCommand);

                DeleteDirectoryCommand delDirCommand = new DeleteDirectoryCommand(origFolder, false)
                {
                    RequiresRollback = false
                };
                processor.AddCommand(delDirCommand);

                TierMigrateDatabaseUpdateCommand updateDbCommand = new TierMigrateDatabaseUpdateCommand(context);
                processor.AddCommand(updateDbCommand);

                Platform.Log(LogLevel.Info, "Start migrating study {0}.. expecting {1} to be moved", storage.StudyInstanceUid, ByteCountFormatter.Format(stat.StudySize));
                if (!processor.Execute())
                {
                    if (processor.FailureException != null)
                    {
                        throw processor.FailureException;
                    }
                    throw new ApplicationException(processor.FailureReason);
                }

                stat.DBUpdate      = updateDbCommand.Statistics;
                stat.CopyFiles     = copyDirCommand.CopySpeed;
                stat.DeleteDirTime = delDirCommand.Statistics;
            }

            stat.ProcessSpeed.SetData(bytesCopied);
            stat.ProcessSpeed.End();

            Platform.Log(LogLevel.Info, "Successfully migrated study {0} from {1} to {2} in {3} [ {4} files, {5} @ {6}, DB Update={7}, Remove Dir={8}]",
                         storage.StudyInstanceUid,
                         storage.FilesystemTierEnum,
                         newFilesystem.Filesystem.FilesystemTierEnum,
                         TimeSpanFormatter.Format(stat.ProcessSpeed.ElapsedTime),
                         fileCounter,
                         ByteCountFormatter.Format(bytesCopied),
                         stat.CopyFiles.FormattedValue,
                         stat.DBUpdate.FormattedValue,
                         stat.DeleteDirTime.FormattedValue);

            string originalPath = storage.GetStudyPath();

            if (Directory.Exists(storage.GetStudyPath()))
            {
                Platform.Log(LogLevel.Info, "Original study folder could not be deleted. It must be cleaned up manually: {0}", originalPath);
                ServerPlatform.Alert(AlertCategory.Application, AlertLevel.Warning, WorkQueueItem.WorkQueueTypeEnum.ToString(), 1000, GetWorkQueueContextData(WorkQueueItem), TimeSpan.Zero,
                                     "Study has been migrated to a new tier. Original study folder must be cleaned up manually: {0}", originalPath);
            }

            UpdateAverageStatistics(stat);
        }