/// <summary>
		/// Load the first instance from the first series of the StudyXml file for a study.
		/// </summary>
		/// <param name="location">The storage location of the study.</param>
		/// <returns></returns>
		protected static DicomFile LoadInstance(StudyStorageLocation location)
		{
			string studyXml = Path.Combine(location.GetStudyPath(), location.StudyInstanceUid + ".xml");

			if (!File.Exists(studyXml))
			{
				return null;
			}

			FileStream stream = FileStreamOpener.OpenForRead(studyXml, FileMode.Open);
			var theDoc = new XmlDocument();
			StudyXmlIo.Read(theDoc, stream);
			stream.Close();
			stream.Dispose();
			var xml = new StudyXml();
			xml.SetMemento(theDoc);
            
			IEnumerator<SeriesXml> seriesEnumerator = xml.GetEnumerator();
			if (seriesEnumerator.MoveNext())
			{
				SeriesXml seriesXml = seriesEnumerator.Current;
				IEnumerator<InstanceXml> instanceEnumerator = seriesXml.GetEnumerator();
				if (instanceEnumerator.MoveNext())
				{
					InstanceXml instance = instanceEnumerator.Current;
					var file = new DicomFile("file.dcm",new DicomAttributeCollection(), instance.Collection)
						{TransferSyntax = instance.TransferSyntax};
					return file;
				}
			}

			return null;
		}
コード例 #2
0
        public SaveXmlCommand(StudyXml stream, StudyStorageLocation storageLocation)
            : base("Insert into Study XML", true)
        {
            Platform.CheckForNullReference(stream, "StudyStream object");
            Platform.CheckForNullReference(storageLocation, "Study Storage Location");

            _stream = stream;
            _xmlPath = Path.Combine(storageLocation.GetStudyPath(), storageLocation.StudyInstanceUid + ".xml");
            _gzPath = _xmlPath + ".gz";
        }
コード例 #3
0
        private static StudyXml GetStudyXml(StudyStorageLocation storageLocation)
        {
            StudyXml studyXml     = new StudyXml();
            string   studyXmlPath = Path.Combine(storageLocation.GetStudyPath(), storageLocation.StudyInstanceUid + ".xml");

            using (Stream stream = FileStreamOpener.OpenForRead(studyXmlPath, FileMode.Open))
            {
                XmlDocument doc = new XmlDocument();
                StudyXmlIo.Read(doc, stream);
                studyXml.SetMemento(doc);
                stream.Close();
            }
            return(studyXml);
        }
コード例 #4
0
        protected override void OnExecute(CommandProcessor theProcessor)
        {
            if (_map == null)
            {
                return;// nothing to save
            }
            _path = Path.Combine(_studyLocation.GetStudyPath(), "UidMap.xml");
            if (RequiresRollback)
            {
                Backup();
            }

            _map.Save(_path);
        }
コード例 #5
0
        public void OnStudyDeleting()
        {
            if (!Enabled)
            {
                return;
            }

            StudyStorageLocation        storage  = _context.StorageLocation;
            IList <ArchiveStudyStorage> archives = StudyStorageLocation.GetArchiveLocations(storage.GetKey());

            if (archives != null && archives.Count > 0)
            {
                _archives = new DeletedStudyArchiveInfoCollection();
                foreach (ArchiveStudyStorage archive in archives)
                {
                    DeletedStudyArchiveInfo archiveInfo = new DeletedStudyArchiveInfo();
                    archiveInfo.ArchiveTime = archive.ArchiveTime;
                    archiveInfo.ArchiveXml  = archive.ArchiveXml;

                    archiveInfo.PartitionArchiveRef = PartitionArchive.Load(archive.PartitionArchiveKey).GetKey().Key;
                    archiveInfo.TransferSyntaxUid   = archive.ServerTransferSyntax.Uid;
                    _archives.Add(archiveInfo);
                }
            }



            // only backup if study is manually deleted
            if (_context.WorkQueueItem.WorkQueueTypeEnum == WorkQueueTypeEnum.WebDeleteStudy)
            {
                using (var processor = new ServerCommandProcessor("Backup deleted study"))
                {
                    string path = _context.Filesystem.ResolveAbsolutePath(BackupSubPath);

                    Platform.Log(LogLevel.Info, "Saving a copy of the study to {0}...", path);

                    var mkdir = new CreateDirectoryCommand(path);
                    processor.AddCommand(mkdir);

                    var zip = new ZipStudyFolderCommand(storage.GetStudyPath(), BackupFullPath);
                    processor.AddCommand(zip);

                    if (!processor.Execute())
                    {
                        throw new ApplicationException(String.Format("Unable to backup study: {0}", processor.FailureReason));
                    }
                }
            }
        }
コード例 #6
0
        /// <summary>
        /// Estimate the folder size for a study
        /// </summary>
        /// <remarks>
        /// This routine loads the StudyXml file and traverses through each series
        /// for the study.  It then looks at the size of the first image in the series,
        /// and assumes the series size is equal to the first image size times the number
        /// of images within the series.  If the file sizes vary within the series, this
        /// algorithm will fall down a bit.
        /// </remarks>
        /// <param name="location">The StudyStorageLocation object for the study.</param>
        /// <returns></returns>
        protected float EstimateFolderSizeFromStudyXml(StudyStorageLocation location)
        {
            float  folderSize  = 0.0f;
            string studyFolder = location.GetStudyPath();

            string file = Path.Combine(studyFolder, location.StudyInstanceUid + ".xml");

            var finfo1 = new FileInfo(file);

            if (finfo1.Exists)
            {
                folderSize += finfo1.Length;
            }

            file = Path.Combine(studyFolder, location.StudyInstanceUid + ".xml.gz");

            var finfo2 = new FileInfo(file);

            if (finfo2.Exists)
            {
                folderSize += finfo2.Length;
            }

            StudyXml study = LoadStudyXml(location);

            foreach (SeriesXml series in study)
            {
                string seriesFolder = Path.Combine(studyFolder, series.SeriesInstanceUid);

                foreach (InstanceXml instance in series)
                {
                    if (instance.FileSize != 0)
                    {
                        folderSize += instance.FileSize;
                    }
                    else
                    {
                        file = Path.Combine(seriesFolder, String.Format("{0}.dcm", instance.SopInstanceUid));
                        var finfo = new FileInfo(file);
                        if (finfo.Exists)
                        {
                            folderSize += finfo.Length;
                        }
                    }
                }
            }

            return(folderSize);
        }
コード例 #7
0
        /// <summary>
        /// Computes and returns the absolute path specified by this <see cref="FilesystemDynamicPath"/> for the <see cref="StudyStorageLocation"/>.
        /// Note: The path may or may not be valid.
        /// </summary>
        /// <param name="studyStorage"></param>
        /// <returns></returns>
        public string ConvertToAbsolutePath(StudyStorageLocation studyStorage)
        {
            switch (_type)
            {
            case PathType.Absolute: return(_path);

            case PathType.RelativeToReconcileFolder:
                var basePath = studyStorage.GetReconcileRootPath();
                return(Path.Combine(basePath, _path));

            case PathType.RelativeToStudyFolder:
                basePath = studyStorage.GetStudyPath();
                return(Path.Combine(basePath, _path));

            default:
                return(_path);
            }
        }
コード例 #8
0
ファイル: BaseScp.cs プロジェクト: hksonngan/Xian
        /// <summary>
        /// Helper method to load a <see cref="StudyXml"/> instance for a given study location.
        /// </summary>
        /// <param name="location"></param>
        /// <returns></returns>
        public static StudyXml LoadStudyXml(StudyStorageLocation location)
        {
            String streamFile = Path.Combine(location.GetStudyPath(), location.StudyInstanceUid + ".xml");

            StudyXml theXml = new StudyXml();

            if (File.Exists(streamFile))
            {
                // allocate the random number generator here, in case we need it below
                Random rand = new Random();

                // Go into a retry loop, to handle if the study is being processed right now
                for (int i = 0; ; i++)
                {
                    try
                    {
                        using (Stream fileStream = FileStreamOpener.OpenForRead(streamFile, FileMode.Open))
                        {
                            XmlDocument theDoc = new XmlDocument();

                            StudyXmlIo.Read(theDoc, fileStream);

                            theXml.SetMemento(theDoc);

                            fileStream.Close();

                            return(theXml);
                        }
                    }
                    catch (IOException)
                    {
                        if (i < 5)
                        {
                            Thread.Sleep(rand.Next(5, 50)); // Sleep 5-50 milliseconds
                            continue;
                        }

                        throw;
                    }
                }
            }

            return(theXml);
        }
コード例 #9
0
        protected void StudyStorageView_DataBound(object sender, EventArgs e)
        {
            StudyStorageLocation ssl = (StudyStorageViewControl.DataItem) as StudyStorageLocation;

            if (ssl != null)
            {
                Label statusLabel = StudyStorageViewControl.FindControl("Status") as Label;
                if (statusLabel != null)
                {
                    statusLabel.Text = ServerEnumDescription.GetLocalizedDescription(ssl.StudyStatusEnum);
                }
                Label queueStateLable = StudyStorageViewControl.FindControl("QueueState") as Label;
                if (queueStateLable != null)
                {
                    queueStateLable.Text = ServerEnumDescription.GetLocalizedDescription(ssl.QueueStudyStateEnum);
                }
                Label studyFolder = StudyStorageViewControl.FindControl("StudyFolder") as Label;
                if (studyFolder != null)
                {
                    studyFolder.Text = ssl.GetStudyPath();
                }
                Label transferSyntaxUID = StudyStorageViewControl.FindControl("TransferSyntaxUID") as Label;
                if (transferSyntaxUID != null)
                {
                    transferSyntaxUID.Text = TransferSyntax.GetTransferSyntax(ssl.TransferSyntaxUid).Name;
                }
                Label tier = StudyStorageViewControl.FindControl("Tier") as Label;
                if (tier != null)
                {
                    tier.Text = ServerEnumDescription.GetLocalizedDescription(ssl.FilesystemTierEnum);
                }

                Label studySize = StudyStorageViewControl.FindControl("StudySize") as Label;
                if (studySize != null)
                {
                    ulong sizeInBytes = (ulong)(ssl.Study.StudySizeInKB * 1024);
                    studySize.Text = ByteCountFormatter.Format(sizeInBytes);
                }
            }
        }
コード例 #10
0
        /// <summary>
        /// Load a <see cref="StudyXml"/> file for a given <see cref="StudyStorageLocation"/>
        /// </summary>
        /// <param name="location">The location a study is stored.</param>
        /// <returns>The <see cref="StudyXml"/> instance for <paramref name="location"/></returns>
        protected virtual StudyXml LoadStudyXml(StudyStorageLocation location)
        {
            StudyXml theXml = new StudyXml();

            String streamFile = Path.Combine(location.GetStudyPath(), location.StudyInstanceUid + ".xml");

            if (File.Exists(streamFile))
            {
                using (Stream fileStream = FileStreamOpener.OpenForRead(streamFile, FileMode.Open))
                {
                    XmlDocument theDoc = new XmlDocument();

                    StudyXmlIo.Read(theDoc, fileStream);

                    theXml.SetMemento(theDoc);

                    fileStream.Close();
                }
            }

            return(theXml);
        }
コード例 #11
0
        /// <summary>
        /// Load the first instance from the first series of the StudyXml file for a study.
        /// </summary>
        /// <param name="location">The storage location of the study.</param>
        /// <returns></returns>
        protected static DicomFile LoadInstance(StudyStorageLocation location)
        {
            string studyXml = Path.Combine(location.GetStudyPath(), location.StudyInstanceUid + ".xml");

            if (!File.Exists(studyXml))
            {
                return(null);
            }

            FileStream stream     = FileStreamOpener.OpenForRead(studyXml, FileMode.Open);
            var        theMemento = new StudyXmlMemento();

            StudyXmlIo.Read(theMemento, stream);
            stream.Close();
            stream.Dispose();
            var xml = new StudyXml();

            xml.SetMemento(theMemento);

            IEnumerator <SeriesXml> seriesEnumerator = xml.GetEnumerator();

            if (seriesEnumerator.MoveNext())
            {
                SeriesXml seriesXml = seriesEnumerator.Current;
                IEnumerator <InstanceXml> instanceEnumerator = seriesXml.GetEnumerator();
                if (instanceEnumerator.MoveNext())
                {
                    InstanceXml instance = instanceEnumerator.Current;
                    var         file     = new DicomFile("file.dcm", new DicomAttributeCollection(), instance.Collection)
                    {
                        TransferSyntax = instance.TransferSyntax
                    };
                    return(file);
                }
            }

            return(null);
        }
コード例 #12
0
        protected static StudyXml LoadStudyXml(StudyStorageLocation location)
        {
            // This method should be combined with StudyStorageLocation.LoadStudyXml()
            StudyXml theXml = new StudyXml(location.StudyInstanceUid);

            String streamFile = Path.Combine(location.GetStudyPath(), location.StudyInstanceUid + ".xml");

            if (File.Exists(streamFile))
            {
                using (Stream fileStream = FileStreamOpener.OpenForRead(streamFile, FileMode.Open))
                {
                    var theMemento = new StudyXmlMemento();

                    StudyXmlIo.Read(theMemento, fileStream);

                    theXml.SetMemento(theMemento);

                    fileStream.Close();
                }
            }

            return(theXml);
        }
コード例 #13
0
        private void Initialize()
        {
            using (IPersistenceContext readContext = PersistentStoreRegistry.GetDefaultStore().OpenReadContext())
            {
                _backupDir = ServerExecutionContext.Current.BackupDirectory;

                _oldStudyPath        = _oldStudyLocation.GetStudyPath();
                _oldStudyInstanceUid = _oldStudyLocation.StudyInstanceUid;
                _oldStudyFolder      = _oldStudyLocation.StudyFolder;
                _newStudyInstanceUid = _oldStudyInstanceUid;

                _study          = _oldStudyLocation.LoadStudy(readContext);
                _totalSopCount  = _study.NumberOfStudyRelatedInstances;
                _curPatient     = _study.LoadPatient(readContext);
                _oldPatientInfo = new PatientInfo
                {
                    Name              = _curPatient.PatientsName,
                    PatientId         = _curPatient.PatientId,
                    IssuerOfPatientId = _curPatient.IssuerOfPatientId
                };

                _newPatientInfo = new PatientInfo(_oldPatientInfo);
                Debug.Assert(_newPatientInfo.Equals(_oldPatientInfo));

                foreach (BaseImageLevelUpdateCommand command in _commands)
                {
                    ImageLevelUpdateEntry imageLevelUpdate = command.UpdateEntry;
                    if (imageLevelUpdate == null)
                    {
                        continue;
                    }

                    if (imageLevelUpdate.TagPath.Tag.TagValue == DicomTags.StudyInstanceUid)
                    {
                        _newStudyInstanceUid = imageLevelUpdate.GetStringValue();
                    }
                    else if (imageLevelUpdate.TagPath.Tag.TagValue == DicomTags.PatientId)
                    {
                        _newPatientInfo.PatientId = imageLevelUpdate.GetStringValue();
                    }
                    else if (imageLevelUpdate.TagPath.Tag.TagValue == DicomTags.IssuerOfPatientId)
                    {
                        _newPatientInfo.IssuerOfPatientId = imageLevelUpdate.GetStringValue();
                    }
                    else if (imageLevelUpdate.TagPath.Tag.TagValue == DicomTags.PatientsName)
                    {
                        _newPatientInfo.Name = imageLevelUpdate.GetStringValue();
                    }
                }

                Platform.CheckForNullReference(_newStudyInstanceUid, "_newStudyInstanceUid");

                NewStudyPath = Path.Combine(_oldStudyLocation.FilesystemPath, _partition.PartitionFolder);
                NewStudyPath = Path.Combine(NewStudyPath, _oldStudyFolder);
                NewStudyPath = Path.Combine(NewStudyPath, _newStudyInstanceUid);

                _newPatient = FindPatient(_newPatientInfo, readContext);
                _patientInfoIsNotChanged = _newPatientInfo.Equals(_oldPatientInfo);

                Statistics.InstanceCount = _study.NumberOfStudyRelatedInstances;
                Statistics.StudySize     = (ulong)_oldStudyLocation.LoadStudyXml().GetStudySize();

                // The study path will be changed. We will need to delete the original folder at the end.
                // May be too simple to test if two paths are the same. But let's assume it is good enough for 99% of the time.
                _deleteOriginalFolder = NewStudyPath != _oldStudyPath;
                _initialized          = true;
            }
        }
コード例 #14
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
                                               	};

            	string 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

                CopyDirectoryCommand 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);
            
        }
コード例 #15
0
		/// <summary>
		/// Do the restore.
		/// </summary>
		/// <param name="queueItem">The queue item to restore.</param>
		public void Run(RestoreQueue queueItem)
		{
            using (RestoreProcessorContext context = new RestoreProcessorContext(queueItem))
            {
                try
                {
                    // Load up related classes.
                    using (IReadContext readContext = _nasArchive.PersistentStore.OpenReadContext())
                    {
                        _archiveStudyStorage = ArchiveStudyStorage.Load(readContext, queueItem.ArchiveStudyStorageKey);
                        _serverSyntax = ServerTransferSyntax.Load(readContext, _archiveStudyStorage.ServerTransferSyntaxKey);
                        _syntax = TransferSyntax.GetTransferSyntax(_serverSyntax.Uid);

                        StudyStorageLocationQueryParameters parms = new StudyStorageLocationQueryParameters
                                                                    	{StudyStorageKey = queueItem.StudyStorageKey};
                    	IQueryStudyStorageLocation broker = readContext.GetBroker<IQueryStudyStorageLocation>();
                        _location = broker.FindOne(parms);
                        if (_location == null)
                        {
                            _studyStorage = StudyStorage.Load(readContext, queueItem.StudyStorageKey);
							if (_studyStorage==null)
							{
								DateTime scheduleTime = Platform.Time.AddMinutes(5);
								Platform.Log(LogLevel.Error, "Unable to find storage location, rescheduling restore request to {0}",
											 scheduleTime);
								queueItem.FailureDescription = "Unable to find storage location, rescheduling request.";
								_nasArchive.UpdateRestoreQueue(queueItem, RestoreQueueStatusEnum.Pending, scheduleTime);
								return;
							}
                        }
                    }

					if (_location == null)
						Platform.Log(LogLevel.Info, "Starting restore of nearline study: {0}", _studyStorage.StudyInstanceUid);
					else
                        Platform.Log(LogLevel.Info, "Starting restore of online study: {0}", _location.StudyInstanceUid);

                    // If restoring a Nearline study, select a filesystem
                    string destinationFolder;
                    if (_location == null)
                    {
                        ServerFilesystemInfo fs = _nasArchive.Selector.SelectFilesystem();
                        if (fs == null)
                        {
                            DateTime scheduleTime = Platform.Time.AddMinutes(5);
                            Platform.Log(LogLevel.Error, "No writeable filesystem for restore, rescheduling restore request to {0}",
                                         scheduleTime);
                            queueItem.FailureDescription = "No writeable filesystem for restore, rescheduling request.";
                            _nasArchive.UpdateRestoreQueue(queueItem, RestoreQueueStatusEnum.Pending, scheduleTime);
                            return;
                        }
                        destinationFolder = Path.Combine(fs.Filesystem.FilesystemPath, _nasArchive.ServerPartition.PartitionFolder);
                    }
                    else
                        destinationFolder = _location.GetStudyPath();


                    // Get the zip file path from the xml data in the ArchiveStudyStorage entry
                    // Also store the "StudyFolder" for use below
                    string studyFolder = String.Empty;
                    string filename = String.Empty;
                    string studyInstanceUid = String.Empty;
                    XmlElement element = _archiveStudyStorage.ArchiveXml.DocumentElement;
					if (element!=null)
						foreach (XmlElement node in element.ChildNodes)
							if (node.Name.Equals("StudyFolder"))
								studyFolder = node.InnerText;
							else if (node.Name.Equals("Filename"))
								filename = node.InnerText;
							else if (node.Name.Equals("Uid"))
								studyInstanceUid = node.InnerText;

                    string zipFile = Path.Combine(_nasArchive.NasPath, studyFolder);
                    zipFile = Path.Combine(zipFile, studyInstanceUid);
                    zipFile = Path.Combine(zipFile, filename);


                    // Do a test read of the zip file.  If it succeeds, the file is available, if it 
                    // fails, we just set back to pending and recheck.
                    try
                    {
                        FileStream stream = File.OpenRead(zipFile);
                        // Read a byte, just in case that makes a difference.
                        stream.ReadByte();
                        stream.Close();
                        stream.Dispose();
                    }
                    catch (Exception ex)
                    {
                        DateTime scheduledTime = Platform.Time.AddSeconds(NasSettings.Default.ReadFailRescheduleDelaySeconds);
                        Platform.Log(LogLevel.Error, ex, "Archive {0} for Study  {1} is unreadable, rescheduling restore to {2}",
                                     zipFile, _studyStorage == null ? (_location == null ? string.Empty : _location.StudyInstanceUid) : _studyStorage.StudyInstanceUid,
                                     scheduledTime);
                        // Just reschedule in "Restoring" state, the file is unreadable.
                        _nasArchive.UpdateRestoreQueue(queueItem, RestoreQueueStatusEnum.Restoring,
                                                       scheduledTime);
                        return;
                    }

                    if (_location == null)
                        RestoreNearlineStudy(queueItem, zipFile, destinationFolder, studyFolder);
                    else
                        RestoreOnlineStudy(queueItem, zipFile, destinationFolder);
                }
                catch (Exception e)
                {
                    Platform.Log(LogLevel.Error, e, "Unexpected exception processing restore request for {0} on archive {1}",
                        _studyStorage == null ? (_location == null ? string.Empty : _location.StudyInstanceUid) : _studyStorage.StudyInstanceUid,
                        _nasArchive.PartitionArchive.Description);
                    queueItem.FailureDescription = e.Message;
                    _nasArchive.UpdateRestoreQueue(queueItem, RestoreQueueStatusEnum.Failed, Platform.Time);
                }
            }
			
		}
コード例 #16
0
        /// <summary>
        /// Do the restore.
        /// </summary>
        /// <param name="queueItem">The queue item to restore.</param>
        public void Run(RestoreQueue queueItem)
        {
            using (var context = new RestoreProcessorContext(queueItem))
            {
                try
                {
                    // Load up related classes.
                    using (IReadContext readContext = _hsmArchive.PersistentStore.OpenReadContext())
                    {
                        _archiveStudyStorage = ArchiveStudyStorage.Load(readContext, queueItem.ArchiveStudyStorageKey);
                        _serverSyntax        = ServerTransferSyntax.Load(readContext, _archiveStudyStorage.ServerTransferSyntaxKey);
                        _syntax = TransferSyntax.GetTransferSyntax(_serverSyntax.Uid);

                        var parms = new StudyStorageLocationQueryParameters
                        {
                            StudyStorageKey = queueItem.StudyStorageKey
                        };
                        var broker = readContext.GetBroker <IQueryStudyStorageLocation>();
                        _location = broker.FindOne(parms);
                        if (_location == null)
                        {
                            _studyStorage = StudyStorage.Load(readContext, queueItem.StudyStorageKey);
                            if (_studyStorage == null)
                            {
                                DateTime scheduleTime = Platform.Time.AddMinutes(5);
                                Platform.Log(LogLevel.Error, "Unable to find storage location, rescheduling restore request to {0}",
                                             scheduleTime);
                                queueItem.FailureDescription = "Unable to find storage location, rescheduling request.";
                                _hsmArchive.UpdateRestoreQueue(queueItem, RestoreQueueStatusEnum.Pending, scheduleTime);
                                return;
                            }
                        }
                    }

                    if (_location == null)
                    {
                        Platform.Log(LogLevel.Info, "Starting restore of nearline study: {0}",
                                     _studyStorage.StudyInstanceUid);

                        // Get the zip file path from the xml data in the ArchiveStudyStorage entry
                        // Also store the "StudyFolder" for use below
                        string studyFolder;
                        string zipFile = GetZipFileName(out studyFolder);

                        // Do a test read of the zip file.  If it succeeds, the file is available, if it
                        // fails, we just set back to pending and recheck.
                        if (!CanReadZip(zipFile, queueItem))
                        {
                            return;
                        }

                        RestoreNearlineStudy(queueItem, zipFile, studyFolder);
                    }
                    else
                    {
                        Platform.Log(LogLevel.Info, "Starting restore of online study: {0}", _location.StudyInstanceUid);

                        // Get the zip file path from the xml data in the ArchiveStudyStorage entry
                        // Also store the "StudyFolder" for use below
                        string studyFolder;
                        string zipFile = GetZipFileName(out studyFolder);

                        // Do a test read of the zip file.  If it succeeds, the file is available, if it
                        // fails, we just set back to pending and recheck.
                        if (!CanReadZip(zipFile, queueItem))
                        {
                            return;
                        }

                        RestoreOnlineStudy(queueItem, zipFile, _location.GetStudyPath());
                    }
                }
                catch (Exception e)
                {
                    Platform.Log(LogLevel.Error, e, "Unexpected exception processing restore request for {0} on archive {1}",
                                 _studyStorage == null ? (_location == null ? string.Empty : _location.StudyInstanceUid) : _studyStorage.StudyInstanceUid,
                                 _hsmArchive.PartitionArchive.Description);
                    queueItem.FailureDescription = e.Message;
                    _hsmArchive.UpdateRestoreQueue(queueItem, RestoreQueueStatusEnum.Failed, Platform.Time);
                }
            }
        }
コード例 #17
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);
        }
コード例 #18
0
ファイル: UidMapXml.cs プロジェクト: hksonngan/Xian
 /// <summary>
 /// Loads the <see cref="Series"/> and instance mappings for the specified study.
 /// </summary>
 /// <param name="location"></param>
 public void Load(StudyStorageLocation location)
 {
     Load(Path.Combine(location.GetStudyPath(), "UidMap.xml"));
 }
コード例 #19
0
		/// <summary>
		/// Do the restore.
		/// </summary>
		/// <param name="queueItem">The queue item to restore.</param>
		public void Run(RestoreQueue queueItem)
		{
            using (var context = new RestoreProcessorContext(queueItem))
            {
                try
                {
                    // Load up related classes.
                    using (IReadContext readContext = _hsmArchive.PersistentStore.OpenReadContext())
                    {
                        _archiveStudyStorage = ArchiveStudyStorage.Load(readContext, queueItem.ArchiveStudyStorageKey);
                        _serverSyntax = ServerTransferSyntax.Load(readContext, _archiveStudyStorage.ServerTransferSyntaxKey);
                        _syntax = TransferSyntax.GetTransferSyntax(_serverSyntax.Uid);

                        var parms = new StudyStorageLocationQueryParameters
                                                                    	{StudyStorageKey = queueItem.StudyStorageKey};
                    	var broker = readContext.GetBroker<IQueryStudyStorageLocation>();
                        _location = broker.FindOne(parms);
                        if (_location == null)
                        {
                            _studyStorage = StudyStorage.Load(readContext, queueItem.StudyStorageKey);
							if (_studyStorage==null)
							{
								DateTime scheduleTime = Platform.Time.AddMinutes(5);
								Platform.Log(LogLevel.Error, "Unable to find storage location, rescheduling restore request to {0}",
											 scheduleTime);
								queueItem.FailureDescription = "Unable to find storage location, rescheduling request.";
								_hsmArchive.UpdateRestoreQueue(queueItem, RestoreQueueStatusEnum.Pending, scheduleTime);
								return;
							}
                        }
                    }

                    if (_location == null)
                    {
                        Platform.Log(LogLevel.Info, "Starting restore of nearline study: {0}",
                                     _studyStorage.StudyInstanceUid);

                        // Get the zip file path from the xml data in the ArchiveStudyStorage entry
                        // Also store the "StudyFolder" for use below
                        string studyFolder;
                        string zipFile = GetZipFileName(out studyFolder);

                        // Do a test read of the zip file.  If it succeeds, the file is available, if it 
                        // fails, we just set back to pending and recheck.
                        if (!CanReadZip(zipFile, queueItem))
                            return;

                        RestoreNearlineStudy(queueItem, zipFile, studyFolder);
                    }
                    else
                    {
                        Platform.Log(LogLevel.Info, "Starting restore of online study: {0}", _location.StudyInstanceUid);

                         // Get the zip file path from the xml data in the ArchiveStudyStorage entry
                         // Also store the "StudyFolder" for use below
                         string studyFolder;
                         string zipFile = GetZipFileName(out studyFolder);

                         // Do a test read of the zip file.  If it succeeds, the file is available, if it 
                         // fails, we just set back to pending and recheck.
                         if (!CanReadZip(zipFile, queueItem))
                             return;

                        RestoreOnlineStudy(queueItem, zipFile, _location.GetStudyPath());
                    }       
                }
                catch (Exception e)
                {
                    Platform.Log(LogLevel.Error, e, "Unexpected exception processing restore request for {0} on archive {1}",
                        _studyStorage == null ? (_location == null ? string.Empty : _location.StudyInstanceUid) : _studyStorage.StudyInstanceUid,
                        _hsmArchive.PartitionArchive.Description);
                    queueItem.FailureDescription = e.Message;
                    _hsmArchive.UpdateRestoreQueue(queueItem, RestoreQueueStatusEnum.Failed, Platform.Time);
                }
            }
			
		}
コード例 #20
0
		/// <summary>
		/// Load a <see cref="StudyXml"/> file for a given <see cref="StudyStorageLocation"/>
		/// </summary>
		/// <param name="location">The location a study is stored.</param>
		/// <returns>The <see cref="StudyXml"/> instance for <paramref name="location"/></returns>
		protected virtual StudyXml LoadStudyXml(StudyStorageLocation location)
		{
			StudyXml theXml = new StudyXml();

			String streamFile = Path.Combine(location.GetStudyPath(), location.StudyInstanceUid + ".xml");
			if (File.Exists(streamFile))
			{
				using (Stream fileStream = FileStreamOpener.OpenForRead(streamFile, FileMode.Open))
				{
					var theMemento = new StudyXmlMemento();

					StudyXmlIo.Read(theMemento, fileStream);

					theXml.SetMemento(theMemento);

					fileStream.Close();
				}
			}

			return theXml;
		}
コード例 #21
0
        /// <summary>
        /// Do the restore.
        /// </summary>
        /// <param name="queueItem">The queue item to restore.</param>
        public void Run(RestoreQueue queueItem)
        {
            using (RestoreProcessorContext context = new RestoreProcessorContext(queueItem))
            {
                try
                {
                    // Load up related classes.
                    using (IReadContext readContext = _nasArchive.PersistentStore.OpenReadContext())
                    {
                        _archiveStudyStorage = ArchiveStudyStorage.Load(readContext, queueItem.ArchiveStudyStorageKey);
                        _serverSyntax        = ServerTransferSyntax.Load(readContext, _archiveStudyStorage.ServerTransferSyntaxKey);
                        _syntax = TransferSyntax.GetTransferSyntax(_serverSyntax.Uid);

                        StudyStorageLocationQueryParameters parms = new StudyStorageLocationQueryParameters
                        {
                            StudyStorageKey = queueItem.StudyStorageKey
                        };
                        IQueryStudyStorageLocation broker = readContext.GetBroker <IQueryStudyStorageLocation>();
                        _location = broker.FindOne(parms);
                        if (_location == null)
                        {
                            _studyStorage = StudyStorage.Load(readContext, queueItem.StudyStorageKey);
                            if (_studyStorage == null)
                            {
                                DateTime scheduleTime = Platform.Time.AddMinutes(5);
                                Platform.Log(LogLevel.Error, "Unable to find storage location, rescheduling restore request to {0}",
                                             scheduleTime);
                                queueItem.FailureDescription = "Unable to find storage location, rescheduling request.";
                                _nasArchive.UpdateRestoreQueue(queueItem, RestoreQueueStatusEnum.Pending, scheduleTime);
                                return;
                            }
                        }
                    }

                    if (_location == null)
                    {
                        Platform.Log(LogLevel.Info, "Starting restore of nearline study: {0}", _studyStorage.StudyInstanceUid);
                    }
                    else
                    {
                        Platform.Log(LogLevel.Info, "Starting restore of online study: {0}", _location.StudyInstanceUid);
                    }

                    // If restoring a Nearline study, select a filesystem
                    string destinationFolder;
                    if (_location == null)
                    {
                        ServerFilesystemInfo fs = _nasArchive.Selector.SelectFilesystem();
                        if (fs == null)
                        {
                            DateTime scheduleTime = Platform.Time.AddMinutes(5);
                            Platform.Log(LogLevel.Error, "No writeable filesystem for restore, rescheduling restore request to {0}",
                                         scheduleTime);
                            queueItem.FailureDescription = "No writeable filesystem for restore, rescheduling request.";
                            _nasArchive.UpdateRestoreQueue(queueItem, RestoreQueueStatusEnum.Pending, scheduleTime);
                            return;
                        }
                        destinationFolder = Path.Combine(fs.Filesystem.FilesystemPath, _nasArchive.ServerPartition.PartitionFolder);
                    }
                    else
                    {
                        destinationFolder = _location.GetStudyPath();
                    }


                    // Get the zip file path from the xml data in the ArchiveStudyStorage entry
                    // Also store the "StudyFolder" for use below
                    string     studyFolder      = String.Empty;
                    string     filename         = String.Empty;
                    string     studyInstanceUid = String.Empty;
                    XmlElement element          = _archiveStudyStorage.ArchiveXml.DocumentElement;
                    if (element != null)
                    {
                        foreach (XmlElement node in element.ChildNodes)
                        {
                            if (node.Name.Equals("StudyFolder"))
                            {
                                studyFolder = node.InnerText;
                            }
                            else if (node.Name.Equals("Filename"))
                            {
                                filename = node.InnerText;
                            }
                            else if (node.Name.Equals("Uid"))
                            {
                                studyInstanceUid = node.InnerText;
                            }
                        }
                    }

                    string zipFile = Path.Combine(_nasArchive.NasPath, studyFolder);
                    zipFile = Path.Combine(zipFile, studyInstanceUid);
                    zipFile = Path.Combine(zipFile, filename);


                    // Do a test read of the zip file.  If it succeeds, the file is available, if it
                    // fails, we just set back to pending and recheck.
                    try
                    {
                        FileStream stream = File.OpenRead(zipFile);
                        // Read a byte, just in case that makes a difference.
                        stream.ReadByte();
                        stream.Close();
                        stream.Dispose();
                    }
                    catch (Exception ex)
                    {
                        DateTime scheduledTime = Platform.Time.AddSeconds(NasSettings.Default.ReadFailRescheduleDelaySeconds);
                        Platform.Log(LogLevel.Error, ex, "Archive {0} for Study  {1} is unreadable, rescheduling restore to {2}",
                                     zipFile, _studyStorage == null ? (_location == null ? string.Empty : _location.StudyInstanceUid) : _studyStorage.StudyInstanceUid,
                                     scheduledTime);
                        // Just reschedule in "Restoring" state, the file is unreadable.
                        _nasArchive.UpdateRestoreQueue(queueItem, RestoreQueueStatusEnum.Restoring,
                                                       scheduledTime);
                        return;
                    }

                    if (_location == null)
                    {
                        RestoreNearlineStudy(queueItem, zipFile, destinationFolder, studyFolder);
                    }
                    else
                    {
                        RestoreOnlineStudy(queueItem, zipFile, destinationFolder);
                    }
                }
                catch (Exception e)
                {
                    Platform.Log(LogLevel.Error, e, "Unexpected exception processing restore request for {0} on archive {1}",
                                 _studyStorage == null ? (_location == null ? string.Empty : _location.StudyInstanceUid) : _studyStorage.StudyInstanceUid,
                                 _nasArchive.PartitionArchive.Description);
                    queueItem.FailureDescription = e.Message;
                    _nasArchive.UpdateRestoreQueue(queueItem, RestoreQueueStatusEnum.Failed, Platform.Time);
                }
            }
        }
コード例 #22
0
ファイル: ServerHelper.cs プロジェクト: m-berkani/ClearCanvas
        /// <summary>
        /// Helper method to return the path to the duplicate image (in the Reconcile folder)
        /// </summary>
        /// <param name="studyStorage"></param>
        /// <param name="sop"></param>
        /// <returns></returns>
        public static String GetDuplicateUidPath(StudyStorageLocation studyStorage, WorkQueueUid sop)
        {
            string dupPath = GetDuplicateGroupPath(studyStorage, sop);
            dupPath = string.IsNullOrEmpty(sop.RelativePath)
                        ? Path.Combine(dupPath,
                                       Path.Combine(studyStorage.StudyInstanceUid, sop.SopInstanceUid + "." + sop.Extension))
                        : Path.Combine(dupPath, sop.RelativePath);

            #region BACKWARD_COMPATIBILTY_CODE

            if (string.IsNullOrEmpty(sop.RelativePath) && !File.Exists(dupPath))
            {
                string basePath = Path.Combine(studyStorage.GetStudyPath(), sop.SeriesInstanceUid);
                basePath = Path.Combine(basePath, sop.SopInstanceUid);
                if (sop.Extension != null)
                    dupPath = basePath + "." + sop.Extension;
                else
                    dupPath = basePath + ".dcm";
            }

            #endregion

            return dupPath;
        }
コード例 #23
0
		/// <summary>
		/// Estimate the folder size for a study
		/// </summary>
		/// <remarks>
		/// This routine loads the StudyXml file and traverses through each series
		/// for the study.  It then looks at the size of the first image in the series,
		/// and assumes the series size is equal to the first image size times the number
		/// of images within the series.  If the file sizes vary within the series, this
		/// algorithm will fall down a bit.
		/// </remarks>
		/// <param name="location">The StudyStorageLocation object for the study.</param>
		/// <returns></returns>
		protected float EstimateFolderSizeFromStudyXml(StudyStorageLocation location)
		{
			float folderSize = 0.0f;
			string studyFolder = location.GetStudyPath();

			string file = Path.Combine(studyFolder, location.StudyInstanceUid + ".xml");
			if (File.Exists(file))
			{
				FileInfo finfo = new FileInfo(file);
				folderSize += finfo.Length;
			}
			file = Path.Combine(studyFolder, location.StudyInstanceUid + ".xml.gz");
			if (File.Exists(file))
			{
				FileInfo finfo = new FileInfo(file);
				folderSize += finfo.Length;
			}

			StudyXml study = LoadStudyXml(location);
			foreach (SeriesXml series in study)
			{
				string seriesFolder = Path.Combine(studyFolder, series.SeriesInstanceUid);

				foreach (InstanceXml instance in series)
				{
					if (instance.FileSize != 0)
					{
						folderSize += instance.FileSize;
					}
					else
					{
						file = Path.Combine(seriesFolder, String.Format("{0}.dcm", instance.SopInstanceUid));
						if (File.Exists(file))
						{
							FileInfo finfo = new FileInfo(file);
							folderSize += finfo.Length;
						}
					}
				}
			}

			return folderSize;
		}
コード例 #24
0
        /// <summary>
        /// Do the actual rebuild.  On error, will attempt to reprocess the study.
        /// </summary>
        public void RebuildXml()
        {
            string rootStudyPath = _location.GetStudyPath();

            try
            {
                using (ServerCommandProcessor processor = new ServerCommandProcessor("Rebuild XML"))
                {
                    var command = new RebuildStudyXmlCommand(_location.StudyInstanceUid, rootStudyPath);
                    processor.AddCommand(command);

                    var updateCommand = new UpdateStudySizeInDBCommand(_location, command);
                    processor.AddCommand(updateCommand);

                    if (!processor.Execute())
                    {
                        throw new ApplicationException(processor.FailureReason, processor.FailureException);
                    }

                    Study theStudy = _location.Study;
                    if (theStudy.NumberOfStudyRelatedInstances != command.StudyXml.NumberOfStudyRelatedInstances)
                    {
                        // We rebuilt, but the counts don't match.
                        throw new StudyIntegrityValidationFailure(ValidationErrors.InconsistentObjectCount,
                                                                  new ValidationStudyInfo(theStudy,
                                                                                          _location.ServerPartition),
                                                                  string.Format(
                                                                      "Database study count {0} does not match study xml {1}",
                                                                      theStudy.NumberOfStudyRelatedInstances,
                                                                      command.StudyXml.NumberOfStudyRelatedInstances));
                    }

                    Platform.Log(LogLevel.Info, "Completed reprocessing Study XML file for study {0}", _location.StudyInstanceUid);
                }
            }
            catch (Exception e)
            {
                Platform.Log(LogLevel.Error, e, "Unexpected error when rebuilding study XML for directory: {0}",
                             _location.FilesystemPath);
                StudyReprocessor reprocessor = new StudyReprocessor();
                try
                {
                    WorkQueue reprocessEntry = reprocessor.ReprocessStudy("Rebuild StudyXml", _location, Platform.Time);
                    if (reprocessEntry != null)
                    {
                        Platform.Log(LogLevel.Error, "Failure attempting to reprocess study: {0}",
                                     _location.StudyInstanceUid);
                    }
                    else
                    {
                        Platform.Log(LogLevel.Error, "Inserted reprocess request for study: {0}",
                                     _location.StudyInstanceUid);
                    }
                }
                catch (InvalidStudyStateOperationException ex)
                {
                    Platform.Log(LogLevel.Error, "Failure attempting to reprocess study {0}: {1}",
                                 _location.StudyInstanceUid, ex.Message);
                }
            }
        }
コード例 #25
0
        private void DoStudyLevelValidation(StudyStorageLocation storageLocation, StudyXml studyXml, Study study, ServerPartition partition)
        {
            int xmlNumInstances = studyXml.NumberOfStudyRelatedInstances;
            int xmlNumSeries = studyXml.NumberOfStudyRelatedSeries;

            if (study.NumberOfStudyRelatedInstances != xmlNumInstances)
            {
                throw new StudyIntegrityValidationFailure(
                    ValidationErrors.InconsistentObjectCount,
                    new ValidationStudyInfo(study, partition),
                    String.Format("Number of study related instances in the database ({0}) does not match number of images in the filesystem ({1})",
                                  study.NumberOfStudyRelatedInstances, xmlNumInstances));
            }

            if (study.NumberOfStudyRelatedSeries != xmlNumSeries)
            {
                throw new StudyIntegrityValidationFailure(ValidationErrors.InconsistentObjectCount,
                                                          new ValidationStudyInfo(study, partition),
                                                          String.Format("Number of study related series in the database ({0}) does not match number of series in the xml ({1})",
                                                                        study.NumberOfStudyRelatedSeries, xmlNumSeries));

            }


            long dirFileCount = DirectoryUtility.Count(storageLocation.GetStudyPath(),
                                                       "*" + ServerPlatform.DicomFileExtension, true, null);

            if (xmlNumInstances != dirFileCount)
            {
                throw new StudyIntegrityValidationFailure(ValidationErrors.InconsistentObjectCount,
                                                          new ValidationStudyInfo(study, partition),
                                                          String.Format("Number of instance in xml ({0}) does not match number of images in the filesystem ({1})",
                                                                        xmlNumInstances, dirFileCount));
            }
        }
コード例 #26
0
        /// <summary>
        /// Load a <see cref="StudyXml"/> file for a given <see cref="StudyStorageLocation"/>
        /// </summary>
        /// <param name="location">The location a study is stored.</param>
        /// <returns>The <see cref="StudyXml"/> instance for <paramref name="location"/></returns>
        protected virtual StudyXml LoadStudyXml(StudyStorageLocation location)
        {
            StudyXml theXml = new StudyXml();

            StudyXmlLoadTime.Add(
                delegate
                    {
                        String streamFile = Path.Combine(location.GetStudyPath(), location.StudyInstanceUid + ".xml");
                        if (File.Exists(streamFile))
                        {
                            using (Stream fileStream = FileStreamOpener.OpenForRead(streamFile, FileMode.Open))
                            {
                                XmlDocument theDoc = new XmlDocument();

                                StudyXmlIo.Read(theDoc, fileStream);

                                theXml.SetMemento(theDoc);

                                fileStream.Close();
                            }
                        }
                    }
                );

           return theXml;
        }
コード例 #27
0
        /// <summary>
        /// Computes and returns the absolute path specified by this <see cref="FilesystemDynamicPath"/> for the <see cref="StudyStorageLocation"/>.
        /// Note: The path may or may not be valid.
        /// </summary>
        /// <param name="studyStorage"></param>
        /// <returns></returns>
        public string ConvertToAbsolutePath(StudyStorageLocation studyStorage)
        {
            switch (_type)
            {
                case PathType.Absolute: return _path;

                case PathType.RelativeToReconcileFolder:
                    var basePath = studyStorage.GetReconcileRootPath();
                    return Path.Combine(basePath, _path);

                case PathType.RelativeToStudyFolder:
                    basePath = studyStorage.GetStudyPath();
                    return Path.Combine(basePath, _path);

                default:
                    return _path;
            }
        }
コード例 #28
0
        private static WorkQueueDetails CreateProcessDuplicateWorkQueueItemDetails(Model.WorkQueue item)
        {
            var detail = new WorkQueueDetails();

            detail.Key = item.Key;
            detail.ScheduledDateTime = item.ScheduledTime;
            detail.ExpirationTime    = item.ExpirationTime;
            detail.InsertTime        = item.InsertTime;
            detail.FailureCount      = item.FailureCount;
            detail.Type               = item.WorkQueueTypeEnum;
            detail.Status             = item.WorkQueueStatusEnum;
            detail.Priority           = item.WorkQueuePriorityEnum;
            detail.FailureDescription = item.FailureDescription;
            detail.ServerDescription  = item.ProcessorID;

            StudyStorageLocation storage = WorkQueueController.GetLoadStorageLocation(item);

            detail.StorageLocationPath = storage.GetStudyPath();

            XmlDocument doc      = item.Data;
            XmlNodeList nodeList = doc.GetElementsByTagName("DuplicateSopFolder");

            detail.DuplicateStorageLocationPath = nodeList[0].InnerText;

            // Fetch UIDs
            var wqUidsAdaptor = new WorkQueueUidAdaptor();
            var uidCriteria   = new WorkQueueUidSelectCriteria();

            uidCriteria.WorkQueueKey.EqualTo(item.GetKey());
            IList <WorkQueueUid> uids = wqUidsAdaptor.Get(uidCriteria);

            var mapSeries = new Hashtable();

            foreach (WorkQueueUid uid in uids)
            {
                if (mapSeries.ContainsKey(uid.SeriesInstanceUid) == false)
                {
                    mapSeries.Add(uid.SeriesInstanceUid, uid.SopInstanceUid);
                }
            }

            detail.NumInstancesPending = uids.Count;
            detail.NumSeriesPending    = mapSeries.Count;


            // Fetch the study and patient info
            var          ssAdaptor = new StudyStorageAdaptor();
            StudyStorage storages  = ssAdaptor.Get(item.StudyStorageKey);

            var studyAdaptor  = new StudyAdaptor();
            var studycriteria = new StudySelectCriteria();

            studycriteria.StudyInstanceUid.EqualTo(storages.StudyInstanceUid);
            studycriteria.ServerPartitionKey.EqualTo(item.ServerPartitionKey);
            Study study = studyAdaptor.GetFirst(studycriteria);

            // Study may not be available until the images are processed.
            if (study != null)
            {
                var studyAssembler = new StudyDetailsAssembler();
                detail.Study = studyAssembler.CreateStudyDetail(study);
            }
            return(detail);
        }
コード例 #29
0
ファイル: UidMapXml.cs プロジェクト: nhannd/Xian
 /// <summary>
 /// Loads the <see cref="Series"/> and instance mappings for the specified study.
 /// </summary>
 /// <param name="location"></param>
 public void Load(StudyStorageLocation location)
 {
     Load(Path.Combine(location.GetStudyPath(), "UidMap.xml"));
 }
コード例 #30
0
        private static WorkQueueDetails CreateWebMoveStudyWorkQueueItemDetails(Model.WorkQueue item)
        {
            var          deviceAdaptor       = new DeviceDataAdapter();
            var          studyStorageAdaptor = new StudyStorageAdaptor();
            StudyStorage studyStorage        = studyStorageAdaptor.Get(item.StudyStorageKey);
            var          wqUidsAdaptor       = new WorkQueueUidAdaptor();
            var          studyAdaptor        = new StudyAdaptor();
            Device       dest = deviceAdaptor.Get(item.DeviceKey);

            var detail = new WebMoveStudyWorkQueueDetails();

            detail.Key = item.GetKey();

            detail.DestinationAE     = dest == null ? string.Empty : dest.AeTitle;
            detail.StudyInstanceUid  = studyStorage == null ? string.Empty : studyStorage.StudyInstanceUid;
            detail.ScheduledDateTime = item.ScheduledTime;
            detail.ExpirationTime    = item.ExpirationTime;
            detail.InsertTime        = item.InsertTime;
            detail.FailureCount      = item.FailureCount;
            detail.Type               = item.WorkQueueTypeEnum;
            detail.Status             = item.WorkQueueStatusEnum;
            detail.Priority           = item.WorkQueuePriorityEnum;
            detail.ServerDescription  = item.ProcessorID;
            detail.FailureDescription = item.FailureDescription;

            StudyStorageLocation storage = WorkQueueController.GetLoadStorageLocation(item);

            detail.StorageLocationPath = storage.GetStudyPath();

            // Fetch UIDs
            var uidCriteria = new WorkQueueUidSelectCriteria();

            uidCriteria.WorkQueueKey.EqualTo(item.GetKey());
            IList <WorkQueueUid> uids = wqUidsAdaptor.Get(uidCriteria);

            var mapSeries = new Hashtable();

            foreach (WorkQueueUid uid in uids)
            {
                if (mapSeries.ContainsKey(uid.SeriesInstanceUid) == false)
                {
                    mapSeries.Add(uid.SeriesInstanceUid, uid.SopInstanceUid);
                }
            }

            detail.NumInstancesPending = uids.Count;
            detail.NumSeriesPending    = mapSeries.Count;


            // Fetch the study and patient info
            if (studyStorage != null)
            {
                var studycriteria = new StudySelectCriteria();
                studycriteria.StudyInstanceUid.EqualTo(studyStorage.StudyInstanceUid);
                studycriteria.ServerPartitionKey.EqualTo(item.ServerPartitionKey);
                Study study = studyAdaptor.GetFirst(studycriteria);

                // Study may not be available until the images are processed.
                if (study != null)
                {
                    var studyAssembler = new StudyDetailsAssembler();
                    detail.Study = studyAssembler.CreateStudyDetail(study);
                }
            }

            return(detail);
        }
コード例 #31
0
        private static WorkQueueDetails CreateEditWorkQueueItemDetails(Model.WorkQueue item)
        {
            string studyPath;

            try
            {
                StudyStorageLocation storage = WorkQueueController.GetLoadStorageLocation(item);
                studyPath = storage.GetStudyPath();
            }
            catch (Exception)
            {
                studyPath = string.Empty;
            }
            var detail = new WorkQueueDetails
            {
                Key = item.Key,
                ScheduledDateTime = item.ScheduledTime,
                ExpirationTime    = item.ExpirationTime,
                InsertTime        = item.InsertTime,
                FailureCount      = item.FailureCount,
                Type                = item.WorkQueueTypeEnum,
                Status              = item.WorkQueueStatusEnum,
                Priority            = item.WorkQueuePriorityEnum,
                FailureDescription  = item.FailureDescription,
                ServerDescription   = item.ProcessorID,
                StorageLocationPath = studyPath
            };



            // Fetch UIDs
            var wqUidsAdaptor = new WorkQueueUidAdaptor();
            var uidCriteria   = new WorkQueueUidSelectCriteria();

            uidCriteria.WorkQueueKey.EqualTo(item.GetKey());
            IList <WorkQueueUid> uids = wqUidsAdaptor.Get(uidCriteria);

            var mapSeries = new Hashtable();

            foreach (WorkQueueUid uid in uids)
            {
                if (mapSeries.ContainsKey(uid.SeriesInstanceUid) == false)
                {
                    mapSeries.Add(uid.SeriesInstanceUid, uid.SopInstanceUid);
                }
            }

            detail.NumInstancesPending = uids.Count;
            detail.NumSeriesPending    = mapSeries.Count;


            // Fetch the study and patient info
            var          ssAdaptor = new StudyStorageAdaptor();
            StudyStorage storages  = ssAdaptor.Get(item.StudyStorageKey);

            var studyAdaptor  = new StudyAdaptor();
            var studycriteria = new StudySelectCriteria();

            studycriteria.StudyInstanceUid.EqualTo(storages.StudyInstanceUid);
            studycriteria.ServerPartitionKey.EqualTo(item.ServerPartitionKey);
            Study study = studyAdaptor.GetFirst(studycriteria);

            // Study may not be available until the images are processed.
            if (study != null)
            {
                var studyAssembler = new StudyDetailsAssembler();
                detail.Study = studyAssembler.CreateStudyDetail(study);
            }

            var parser = new EditStudyWorkQueueDataParser();
            EditStudyWorkQueueData data = parser.Parse(item.Data.DocumentElement);

            detail.EditUpdateItems = data.EditRequest.UpdateEntries.ToArray();

            return(detail);
        }
コード例 #32
0
        /// <summary>
        /// Archive the specified <see cref="ArchiveQueue"/> item.
        /// </summary>
        /// <param name="queueItem">The ArchiveQueue item to archive.</param>
        public void Run(ArchiveQueue queueItem)
        {
            using (ArchiveProcessorContext executionContext = new ArchiveProcessorContext(queueItem))
            {
                try
                {
                    if (!GetStudyStorageLocation(queueItem))
                    {
                        Platform.Log(LogLevel.Error,
                                     "Unable to find readable study storage location for archival queue request {0}.  Delaying request.",
                                     queueItem.Key);
                        queueItem.FailureDescription = "Unable to find readable study storage location for archival queue request.";
                        _hsmArchive.UpdateArchiveQueue(queueItem, ArchiveQueueStatusEnum.Pending, Platform.Time.AddMinutes(2));
                        return;
                    }

                    // First, check to see if we can lock the study, if not just reschedule the queue entry.
                    if (!_storageLocation.QueueStudyStateEnum.Equals(QueueStudyStateEnum.Idle))
                    {
                        Platform.Log(LogLevel.Info, "Study {0} on partition {1} is currently locked, delaying archival.", _storageLocation.StudyInstanceUid, _hsmArchive.ServerPartition.Description);
                        queueItem.FailureDescription = "Study is currently locked, delaying archival.";
                        _hsmArchive.UpdateArchiveQueue(queueItem, ArchiveQueueStatusEnum.Pending, Platform.Time.AddMinutes(2));
                        return;
                    }

                    StudyIntegrityValidator validator = new StudyIntegrityValidator();
                    validator.ValidateStudyState("Archive", _storageLocation, StudyIntegrityValidationModes.Default);

                    using (IUpdateContext update = PersistentStoreRegistry.GetDefaultStore().OpenUpdateContext(UpdateContextSyncMode.Flush))
                    {
                        ILockStudy          studyLock = update.GetBroker <ILockStudy>();
                        LockStudyParameters parms     = new LockStudyParameters
                        {
                            StudyStorageKey     = queueItem.StudyStorageKey,
                            QueueStudyStateEnum = QueueStudyStateEnum.ArchiveScheduled
                        };
                        bool retVal = studyLock.Execute(parms);
                        if (!parms.Successful || !retVal)
                        {
                            Platform.Log(LogLevel.Info, "Study {0} on partition {1} failed to lock, delaying archival.", _storageLocation.StudyInstanceUid, _hsmArchive.ServerPartition.Description);
                            queueItem.FailureDescription = "Study failed to lock, delaying archival.";
                            _hsmArchive.UpdateArchiveQueue(queueItem, ArchiveQueueStatusEnum.Pending, Platform.Time.AddMinutes(2));
                            return;
                        }
                        update.Commit();
                    }

                    string studyFolder = _storageLocation.GetStudyPath();

                    string studyXmlFile = _storageLocation.GetStudyXmlPath();

                    // Load the study Xml file, this is used to generate the list of dicom files to archive.
                    LoadStudyXml(studyXmlFile);

                    DicomFile file = LoadFileFromStudyXml();

                    string patientsName    = file.DataSet[DicomTags.PatientsName].GetString(0, string.Empty);
                    string patientId       = file.DataSet[DicomTags.PatientId].GetString(0, string.Empty);
                    string accessionNumber = file.DataSet[DicomTags.AccessionNumber].GetString(0, string.Empty);

                    Platform.Log(LogLevel.Info,
                                 "Starting archival of study {0} for Patient {1} (PatientId:{2} A#:{3}) on Partition {4} on archive {5}",
                                 _storageLocation.StudyInstanceUid, patientsName, patientId,
                                 accessionNumber, _hsmArchive.ServerPartition.Description,
                                 _hsmArchive.PartitionArchive.Description);

                    // Use the command processor to do the archival.
                    using (ServerCommandProcessor commandProcessor = new ServerCommandProcessor("Archive"))
                    {
                        _archiveXml = new XmlDocument();

                        // Create the study date folder
                        string zipFilename = Path.Combine(_hsmArchive.HsmPath, _storageLocation.StudyFolder);
                        commandProcessor.AddCommand(new CreateDirectoryCommand(zipFilename));

                        // Create a folder for the study
                        zipFilename = Path.Combine(zipFilename, _storageLocation.StudyInstanceUid);
                        commandProcessor.AddCommand(new CreateDirectoryCommand(zipFilename));

                        // Save the archive data in the study folder, based on a filename with a date / time stamp
                        string filename = String.Format("{0}.zip", Platform.Time.ToString("yyyy-MM-dd-HHmm"));
                        zipFilename = Path.Combine(zipFilename, filename);


                        // Create the Xml data to store in the ArchiveStudyStorage table telling
                        // where the archived study is located.
                        XmlElement hsmArchiveElement = _archiveXml.CreateElement("HsmArchive");
                        _archiveXml.AppendChild(hsmArchiveElement);
                        XmlElement studyFolderElement = _archiveXml.CreateElement("StudyFolder");
                        hsmArchiveElement.AppendChild(studyFolderElement);
                        studyFolderElement.InnerText = _storageLocation.StudyFolder;
                        XmlElement filenameElement = _archiveXml.CreateElement("Filename");
                        hsmArchiveElement.AppendChild(filenameElement);
                        filenameElement.InnerText = filename;
                        XmlElement studyInstanceUidElement = _archiveXml.CreateElement("Uid");
                        hsmArchiveElement.AppendChild(studyInstanceUidElement);
                        studyInstanceUidElement.InnerText = _storageLocation.StudyInstanceUid;


                        // Create the Zip file
                        commandProcessor.AddCommand(
                            new CreateStudyZipCommand(zipFilename, _studyXml, studyFolder, executionContext.TempDirectory));

                        // Update the database.
                        commandProcessor.AddCommand(new InsertArchiveStudyStorageCommand(queueItem.StudyStorageKey, queueItem.PartitionArchiveKey, queueItem.GetKey(), _storageLocation.ServerTransferSyntaxKey, _archiveXml));


                        StudyRulesEngine studyEngine =
                            new StudyRulesEngine(_storageLocation, _hsmArchive.ServerPartition, _studyXml);
                        studyEngine.Apply(ServerRuleApplyTimeEnum.StudyArchived, commandProcessor);


                        if (!commandProcessor.Execute())
                        {
                            Platform.Log(LogLevel.Error,
                                         "Unexpected failure archiving study ({0}) to archive {1}: {2}, zip filename: {3}",
                                         _storageLocation.StudyInstanceUid, _hsmArchive.PartitionArchive.Description,
                                         commandProcessor.FailureReason, zipFilename);

                            queueItem.FailureDescription = commandProcessor.FailureReason;
                            _hsmArchive.UpdateArchiveQueue(queueItem, ArchiveQueueStatusEnum.Failed, Platform.Time);
                        }
                        else
                        {
                            Platform.Log(LogLevel.Info, "Successfully archived study {0} on {1} to zip {2}",
                                         _storageLocation.StudyInstanceUid,
                                         _hsmArchive.PartitionArchive.Description, zipFilename);
                        }

                        // Log the current FilesystemQueue settings
                        _storageLocation.LogFilesystemQueue();
                    }
                }
                catch (StudyIntegrityValidationFailure ex)
                {
                    StringBuilder error = new StringBuilder();
                    error.AppendLine(String.Format("Partition  : {0}", ex.ValidationStudyInfo.ServerAE));
                    error.AppendLine(String.Format("Patient    : {0}", ex.ValidationStudyInfo.PatientsName));
                    error.AppendLine(String.Format("Study Uid  : {0}", ex.ValidationStudyInfo.StudyInstaneUid));
                    error.AppendLine(String.Format("Accession# : {0}", ex.ValidationStudyInfo.AccessionNumber));
                    error.AppendLine(String.Format("Study Date : {0}", ex.ValidationStudyInfo.StudyDate));

                    queueItem.FailureDescription = error.ToString();
                    _hsmArchive.UpdateArchiveQueue(queueItem, ArchiveQueueStatusEnum.Failed, Platform.Time);
                }
                catch (Exception e)
                {
                    String msg = String.Format("Unexpected exception archiving study: {0} on {1}: {2}",
                                               _storageLocation.StudyInstanceUid, _hsmArchive.PartitionArchive.Description, e.Message);

                    Platform.Log(LogLevel.Error, e, msg);
                    queueItem.FailureDescription = msg;
                    _hsmArchive.UpdateArchiveQueue(queueItem, ArchiveQueueStatusEnum.Failed, Platform.Time);
                }
                finally
                {
                    // Unlock the Queue Entry
                    using (IUpdateContext update = PersistentStoreRegistry.GetDefaultStore().OpenUpdateContext(UpdateContextSyncMode.Flush))
                    {
                        ILockStudy          studyLock = update.GetBroker <ILockStudy>();
                        LockStudyParameters parms     = new LockStudyParameters
                        {
                            StudyStorageKey     = queueItem.StudyStorageKey,
                            QueueStudyStateEnum = QueueStudyStateEnum.Idle
                        };
                        bool retVal = studyLock.Execute(parms);
                        if (!parms.Successful || !retVal)
                        {
                            Platform.Log(LogLevel.Info, "Study {0} on partition {1} is failed to unlock.", _storageLocation.StudyInstanceUid, _hsmArchive.ServerPartition.Description);
                        }
                        update.Commit();
                    }
                }
            }
        }