private void RemoveDatabase(Model.WorkQueue item)
		{
			using (IUpdateContext updateContext = PersistentStoreRegistry.GetDefaultStore().OpenUpdateContext(UpdateContextSyncMode.Flush))
			{
				// Setup the delete parameters
				DeleteFilesystemStudyStorageParameters parms = new DeleteFilesystemStudyStorageParameters();

				parms.ServerPartitionKey = item.ServerPartitionKey;
				parms.StudyStorageKey = item.StudyStorageKey;
				parms.StudyStatusEnum = StudyStatusEnum.Nearline; // TODO: Don't we set Nearline only if all the storage location are purged?

				// Get the Insert Instance broker and do the insert
				IDeleteFilesystemStudyStorage delete = updateContext.GetBroker<IDeleteFilesystemStudyStorage>();

				if (false == delete.Execute(parms))
				{
					Platform.Log(LogLevel.Error, "Unexpected error when trying to delete study: {0} on partition {1}",
								 StorageLocation.StudyInstanceUid, ServerPartition.Description);
				}
				else
				{
					// Unlock the study, too
					ILockStudy studyLock = updateContext.GetBroker<ILockStudy>();
					LockStudyParameters lockParms = new LockStudyParameters();
					lockParms.QueueStudyStateEnum = QueueStudyStateEnum.Idle;
					lockParms.StudyStorageKey = item.StudyStorageKey;
					studyLock.Execute(lockParms);

					updateContext.Commit();
				}
			}
		}
		protected override void OnExecute(CommandProcessor theProcessor, IUpdateContext updateContext)
		{
			ILockStudy lockStudyBroker = updateContext.GetBroker<ILockStudy>();
			LockStudyParameters lockParms = new LockStudyParameters();
			lockParms.StudyStorageKey = _studyStorageKey;
			if (_queueStudyState != null)
				lockParms.QueueStudyStateEnum = _queueStudyState;
			if (_writeLock.HasValue)
				lockParms.WriteLock = _writeLock.Value;
			if (_readLock.HasValue)
				lockParms.ReadLock = _readLock.Value;
			bool retVal = lockStudyBroker.Execute(lockParms);

			if (!retVal || !lockParms.Successful)
			{
				throw new ApplicationException(String.Format("Unable to lock the study: {0}", lockParms.FailureReason));
			}
		}
        public bool DeleteRestoreQueueItem(RestoreQueue item)
        {
        	using (IUpdateContext updateContext = PersistentStoreRegistry.GetDefaultStore().OpenUpdateContext(UpdateContextSyncMode.Flush))
			{
				ILockStudy lockStudyBroker = updateContext.GetBroker<ILockStudy>();
				LockStudyParameters parms = new LockStudyParameters
				                            	{
				                            		StudyStorageKey = item.StudyStorageKey,
				                            		QueueStudyStateEnum = QueueStudyStateEnum.Idle
				                            	};
				if (!lockStudyBroker.Execute(parms))
					return false;
				if (!parms.Successful)
					return false;

				bool retValue = _adaptor.Delete(updateContext, item.Key);

				updateContext.Commit();

				return retValue;
			}
        }
		private void ReinventoryFilesystem(Filesystem filesystem)
        {
            ServerPartition partition;

            DirectoryInfo filesystemDir = new DirectoryInfo(filesystem.FilesystemPath);

            foreach(DirectoryInfo partitionDir in filesystemDir.GetDirectories())
            {
                if (GetServerPartition(partitionDir.Name, out partition) == false)
                    continue;

                foreach(DirectoryInfo dateDir in partitionDir.GetDirectories())
                {
                    if (dateDir.FullName.EndsWith("Deleted", StringComparison.InvariantCultureIgnoreCase)
						|| dateDir.FullName.EndsWith(ServerPlatform.ReconcileStorageFolder, StringComparison.InvariantCultureIgnoreCase))
						continue;
                	List<FileInfo> fileList;

					foreach (DirectoryInfo studyDir in dateDir.GetDirectories())
					{
                        if (studyDir.FullName.EndsWith("Deleted", StringComparison.InvariantCultureIgnoreCase))
                            continue;
					    
						// Check for Cancel message
						if (CancelPending) return;

						String studyInstanceUid = studyDir.Name;

						StudyStorageLocation location;
						if (GetStudyStorageLocation(partition.Key, studyInstanceUid, out location))
						{
                            #region Study record exists in db

                            int integrityQueueCount;
                            int workQueueCount;
                            Study theStudy = GetStudyAndQueues(location, out integrityQueueCount, out workQueueCount);
                            if (theStudy != null)
                                continue;

                            if (integrityQueueCount != 0 && workQueueCount != 0)
                                continue;

                            fileList = LoadSopFiles(studyDir, false);

                            if (fileList.Count == 0)
                            {
                                Platform.Log(LogLevel.Warn, "Found empty study folder with StorageLocation, deleteing StorageLocation: {0}\\{1}",
                                             dateDir.Name, studyDir.Name);
                                studyDir.Delete(true);

                                RemoveStudyStorage(location);
                                continue;
                            }

                            // WriteLock the new study storage for study processing
                            if (!location.QueueStudyStateEnum.Equals(QueueStudyStateEnum.ProcessingScheduled))
                            {
                            	string failureReason;
								if (!ServerHelper.LockStudy(location.Key,QueueStudyStateEnum.ProcessingScheduled, out failureReason))
                                    Platform.Log(LogLevel.Error, "Unable to lock study {0} for Study Processing", location.StudyInstanceUid);
                            } 
                            #endregion
						}
						else
						{
                            #region Directory not in DB, 

                            fileList = LoadSopFiles(studyDir, true);

                            if (fileList.Count == 0)
                            {
                                Platform.Log(LogLevel.Warn, "Found empty study folder: {0}\\{1}", dateDir.Name, studyDir.Name);
                                continue;
                            }

							DicomFile file = LoadFileFromList(fileList);

                            if (file == null)
                            {
                                Platform.Log(LogLevel.Warn, "Found directory with no readable files: {0}\\{1}", dateDir.Name, studyDir.Name);
                                continue;
                            }

                            // Do a second check, using the study instance uid from a file in the directory.
                            // had an issue with trailing periods on uids causing us to not find the 
                            // study storage, and insert a new record into the database.
                            studyInstanceUid = file.DataSet[DicomTags.StudyInstanceUid].ToString();
                            if (GetStudyStorageLocation(partition.Key, studyInstanceUid, out location))
                            {
                                continue;
                            }

                            StudyStorage storage;
                            if (GetStudyStorage(partition, studyInstanceUid, out storage))
                            {
                                Platform.Log(LogLevel.Warn, "Study {0} on filesystem partition {1} is offline {2}", studyInstanceUid,
                                             partition.Description, studyDir.ToString());
                                continue;
                            }

                            Platform.Log(LogLevel.Info, "Reinventory inserting study storage location for {0} on partition {1}", studyInstanceUid,
                                         partition.Description);

                            // Insert StudyStorage
                            using (IUpdateContext update = _store.OpenUpdateContext(UpdateContextSyncMode.Flush))
                            {
                                IInsertStudyStorage studyInsert = update.GetBroker<IInsertStudyStorage>();
                                InsertStudyStorageParameters insertParms = new InsertStudyStorageParameters
                                                                           	{
                                                                           		ServerPartitionKey = partition.GetKey(),
                                                                           		StudyInstanceUid = studyInstanceUid,
                                                                           		Folder = dateDir.Name,
                                                                           		FilesystemKey = filesystem.GetKey(),
                                                                           		QueueStudyStateEnum =
                                                                           			QueueStudyStateEnum.Idle
                                                                           	};
                            	if (file.TransferSyntax.LosslessCompressed)
                                {
                                    insertParms.TransferSyntaxUid = file.TransferSyntax.UidString;
                                    insertParms.StudyStatusEnum = StudyStatusEnum.OnlineLossless;
                                }
                                else if (file.TransferSyntax.LossyCompressed)
                                {
                                    insertParms.TransferSyntaxUid = file.TransferSyntax.UidString;
                                    insertParms.StudyStatusEnum = StudyStatusEnum.OnlineLossy;
                                }
                                else
                                {
                                    insertParms.TransferSyntaxUid = file.TransferSyntax.UidString;
                                    insertParms.StudyStatusEnum = StudyStatusEnum.Online;
                                }

                                location = studyInsert.FindOne(insertParms);

                                // WriteLock the new study storage for study processing
                                ILockStudy lockStudy = update.GetBroker<ILockStudy>();
                                LockStudyParameters lockParms = new LockStudyParameters
                                                                	{
                                                                		StudyStorageKey = location.Key,
                                                                		QueueStudyStateEnum =
                                                                			QueueStudyStateEnum.ProcessingScheduled
                                                                	};
                            	if (!lockStudy.Execute(lockParms) || !lockParms.Successful)
                                    Platform.Log(LogLevel.Error, "Unable to lock study {0} for Study Processing", location.StudyInstanceUid);

                                update.Commit();
                            }		 
                            #endregion					
						}

					    string studyXml = location.GetStudyXmlPath();
						if (File.Exists(studyXml))
							FileUtils.Delete(studyXml);

                        string studyGZipXml = location.GetCompressedStudyXmlPath();
                        if (File.Exists(studyGZipXml))
                            FileUtils.Delete(studyGZipXml);


						foreach (FileInfo sopFile in fileList)
						{
							String sopInstanceUid = sopFile.Name.Replace(sopFile.Extension, string.Empty);

							using (ServerExecutionContext context = new ServerExecutionContext())
							{
								// Just use a read context here, in hopes of improving 
								// performance.  Every other place in the code should use
								// Update contexts when doing transactions.
								IInsertWorkQueue workQueueInsert =
									context.ReadContext.GetBroker<IInsertWorkQueue>();

								InsertWorkQueueParameters queueInsertParms =
									new InsertWorkQueueParameters
										{
											WorkQueueTypeEnum = WorkQueueTypeEnum.StudyProcess,
											StudyStorageKey = location.GetKey(),
											ServerPartitionKey = partition.GetKey(),
											SeriesInstanceUid = sopFile.Directory.Name,
											SopInstanceUid = sopInstanceUid,
											ScheduledTime = Platform.Time
										};

								if (workQueueInsert.FindOne(queueInsertParms) == null)
									Platform.Log(LogLevel.Error,
									             "Failure attempting to insert SOP Instance into WorkQueue during Reinventory.");
							}
						}
					}

                	// Cleanup the date directory, if its empty.
                	DirectoryUtility.DeleteIfEmpty(dateDir.FullName);
                }
            }
        }
Exemple #5
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();
                    }
                }
            }			
		}
        private void RestoreOnlineStudy(RestoreQueue queueItem, string zipFile, string destinationFolder)
		{
			try
			{
				using (ServerCommandProcessor processor = new ServerCommandProcessor("NAS Restore Online Study"))
				{
					using (ZipFile zip = new ZipFile(zipFile))
					{
						foreach (string file in zip.EntryFileNames)
						{
							processor.AddCommand(new ExtractZipFileAndReplaceCommand(zipFile, file, destinationFolder));
						}
					}

					// We rebuild the StudyXml, in case any settings or issues have happened since archival
					processor.AddCommand(new RebuildStudyXmlCommand(_location.StudyInstanceUid, destinationFolder));

					StudyStatusEnum status;

					if (_syntax.Encapsulated && _syntax.LosslessCompressed)
						status = StudyStatusEnum.OnlineLossless;
					else if (_syntax.Encapsulated && _syntax.LossyCompressed)
						status = StudyStatusEnum.OnlineLossy;
					else
						status = StudyStatusEnum.Online;

					processor.AddCommand(new UpdateStudyStateCommand(_location, status, _serverSyntax));

					// Apply the rules engine.
					ServerActionContext context =
						new ServerActionContext(null, _location.FilesystemKey, _nasArchive.ServerPartition,
												queueItem.StudyStorageKey) {CommandProcessor = processor};
					processor.AddCommand(
						new ApplyRulesCommand(destinationFolder, _location.StudyInstanceUid, context));

					if (!processor.Execute())
					{
						Platform.Log(LogLevel.Error, "Unexpected error processing restore request for {0} on archive {1}",
									 _location.StudyInstanceUid, _nasArchive.PartitionArchive.Description);
						queueItem.FailureDescription = processor.FailureReason;
						_nasArchive.UpdateRestoreQueue(queueItem, RestoreQueueStatusEnum.Failed, Platform.Time);
					}
					else
					{
						// Unlock the Queue Entry and set to complete
						using (IUpdateContext update = PersistentStoreRegistry.GetDefaultStore().OpenUpdateContext(UpdateContextSyncMode.Flush))
						{
							_nasArchive.UpdateRestoreQueue(update, queueItem, RestoreQueueStatusEnum.Completed, Platform.Time.AddSeconds(60));
							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} failed to unlock.", _location.StudyInstanceUid,
											 _nasArchive.ServerPartition.Description);
							}

							update.Commit();

							Platform.Log(LogLevel.Info, "Successfully restored study: {0} on archive {1}", _location.StudyInstanceUid,
										 _nasArchive.PartitionArchive.Description);

                            OnStudyRestored(_location);
						}
					}
				}
			}
			catch (Exception e)
			{
				Platform.Log(LogLevel.Error, e, "Unexpected exception processing restore request for {0} on archive {1}",
							 _location.StudyInstanceUid, _nasArchive.PartitionArchive.Description);
				queueItem.FailureDescription = e.Message;
				_nasArchive.UpdateRestoreQueue(queueItem, RestoreQueueStatusEnum.Failed, Platform.Time);
			}
		}
		public void RestoreNearlineStudy(RestoreQueue queueItem, string zipFile, string destinationFolder, string studyFolder)
		{
            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 restore request";
				_nasArchive.UpdateRestoreQueue(queueItem, RestoreQueueStatusEnum.Pending, scheduleTime);
				return;
			}

		    StudyStorageLocation restoredLocation = null;
			try
			{
				using (ServerCommandProcessor processor = 
                    new ServerCommandProcessor("NAS Restore Offline Study"))
				{
					processor.AddCommand(new CreateDirectoryCommand(destinationFolder));
					destinationFolder = Path.Combine(destinationFolder, studyFolder);
					processor.AddCommand(new CreateDirectoryCommand(destinationFolder));
					destinationFolder = Path.Combine(destinationFolder, _studyStorage.StudyInstanceUid);
					processor.AddCommand(new CreateDirectoryCommand(destinationFolder));
					processor.AddCommand(new ExtractZipCommand(zipFile, destinationFolder));

					// We rebuild the StudyXml, in case any settings or issues have happened since archival
					processor.AddCommand(new RebuildStudyXmlCommand(_studyStorage.StudyInstanceUid, destinationFolder));

                    // Apply the rules engine.
					ServerActionContext context =
						new ServerActionContext(null, fs.Filesystem.GetKey(), _nasArchive.ServerPartition,
						                        queueItem.StudyStorageKey) {CommandProcessor = processor};
					processor.AddCommand(
						new ApplyRulesCommand(destinationFolder, _studyStorage.StudyInstanceUid, context));

					// Do the actual insert into the DB
					InsertFilesystemStudyStorageCommand insertStorageCommand = new InsertFilesystemStudyStorageCommand(
													_nasArchive.PartitionArchive.ServerPartitionKey,
						                            _studyStorage.StudyInstanceUid,
						                            studyFolder,
						                            fs.Filesystem.GetKey(), _syntax);
					processor.AddCommand(insertStorageCommand);

					if (!processor.Execute())
					{
						Platform.Log(LogLevel.Error, "Unexpected error processing restore request for {0} on archive {1}",
						             _studyStorage.StudyInstanceUid, _nasArchive.PartitionArchive.Description);
						queueItem.FailureDescription = processor.FailureReason;
						_nasArchive.UpdateRestoreQueue(queueItem, RestoreQueueStatusEnum.Failed, Platform.Time);
					}
					else
					{
					    restoredLocation = insertStorageCommand.Location;

						// Unlock the Queue Entry
						using (
							IUpdateContext update = PersistentStoreRegistry.GetDefaultStore().OpenUpdateContext(UpdateContextSyncMode.Flush))
						{
							bool retVal = _nasArchive.UpdateRestoreQueue(update, queueItem, RestoreQueueStatusEnum.Completed, Platform.Time.AddSeconds(60));
							ILockStudy studyLock = update.GetBroker<ILockStudy>();
							LockStudyParameters parms = new LockStudyParameters
							                            	{
							                            		StudyStorageKey = queueItem.StudyStorageKey,
							                            		QueueStudyStateEnum = QueueStudyStateEnum.Idle
							                            	};
							retVal = retVal && studyLock.Execute(parms);
							if (!parms.Successful || !retVal)
							{
								string message =
									String.Format("Study {0} on partition {1} failed to unlock.", _studyStorage.StudyInstanceUid,
									              _nasArchive.ServerPartition.Description);
								Platform.Log(LogLevel.Info, message);
								throw new ApplicationException(message);
							}
							update.Commit();

							Platform.Log(LogLevel.Info, "Successfully restored study: {0} on archive {1}", _studyStorage.StudyInstanceUid,
										 _nasArchive.PartitionArchive.Description);

                            OnStudyRestored(restoredLocation);
						}
					}
				}
			}
            catch(StudyIntegrityValidationFailure ex)
            {
                Debug.Assert(restoredLocation != null);
                // study has been restored but it seems corrupted. Need to reprocess it.
                ReprocessStudy(restoredLocation, ex.Message);
            }
			catch (Exception e)
			{
				Platform.Log(LogLevel.Error, e, "Unexpected exception processing restore request for {0} on archive {1}",
							 _studyStorage.StudyInstanceUid, _nasArchive.PartitionArchive.Description);
				_nasArchive.UpdateRestoreQueue(queueItem, RestoreQueueStatusEnum.Failed, Platform.Time);
			}
		}
    	/// <summary>
        /// Process study migration candidates retrieved from the <see cref="Model.FilesystemQueue"/> table
        /// </summary>
        /// <param name="candidateList">The list of candidate studies for deleting.</param>
		private void ProcessStudyMigrateCandidates(IList<FilesystemQueue> candidateList)
        {
        	Platform.CheckForNullReference(candidateList, "candidateList");

        	if (candidateList.Count > 0)
        		Platform.Log(LogLevel.Debug, "Scheduling tier-migration for {0} eligible studies...", candidateList.Count);

			FilesystemProcessStatistics summaryStats = new FilesystemProcessStatistics("FilesystemTierMigrateInsert");
        	foreach (FilesystemQueue queueItem in candidateList)
        	{
				if (_bytesToRemove < 0 || CancelPending)
        		{
                    Platform.Log(LogLevel.Debug, "Estimated disk space has been reached.");
                    break;
        		}
				StudyProcessStatistics stats = new StudyProcessStatistics("TierMigrateStudy");
				stats.TotalTime.Start();

				stats.StudyStorageTime.Start();
        		// First, get the StudyStorage locations for the study, and calculate the disk usage.
				StudyStorageLocation location;
				if (!FilesystemMonitor.Instance.GetWritableStudyStorageLocation(queueItem.StudyStorageKey, out location))
					continue;
				stats.StudyStorageTime.End();

				stats.CalculateDirectorySizeTime.Start();
				// Get the disk usage
				float studySize = EstimateFolderSizeFromStudyXml(location);
				stats.CalculateDirectorySizeTime.End();
        		stats.DirectorySize = (ulong) studySize;

				stats.DbUpdateTime.Start();
        		using (
        			IUpdateContext update =
        				PersistentStoreRegistry.GetDefaultStore().OpenUpdateContext(UpdateContextSyncMode.Flush))
        		{
					ILockStudy lockstudy = update.GetBroker<ILockStudy>();
					LockStudyParameters lockParms = new LockStudyParameters
					                                	{
					                                		StudyStorageKey = location.Key,
					                                		QueueStudyStateEnum = QueueStudyStateEnum.MigrationScheduled
					                                	};
        			if (!lockstudy.Execute(lockParms) || !lockParms.Successful)
					{
						Platform.Log(LogLevel.Warn, "Unable to lock study for inserting Tier Migration. Reason:{0}. Skipping study ({1})",
                                     lockParms.FailureReason, location.StudyInstanceUid);
						continue;
					}

					IInsertWorkQueueFromFilesystemQueue broker = update.GetBroker<IInsertWorkQueueFromFilesystemQueue>();

					InsertWorkQueueFromFilesystemQueueParameters insertParms = new InsertWorkQueueFromFilesystemQueueParameters
                                                       	{
                                                       		StudyStorageKey = location.GetKey(),
                                                       		ServerPartitionKey = location.ServerPartitionKey,
                                                       		ScheduledTime = _scheduledTime,
                                                       		DeleteFilesystemQueue = true,
                                                       		WorkQueueTypeEnum = WorkQueueTypeEnum.MigrateStudy,
                                                       		FilesystemQueueTypeEnum =
                                                       			FilesystemQueueTypeEnum.TierMigrate
                                                       	};

        			Platform.Log(LogLevel.Debug, "Scheduling tier-migration for study {0} from {1} at {2}...",
        			             location.StudyInstanceUid, location.FilesystemTierEnum, _scheduledTime);
        			WorkQueue insertItem = broker.FindOne(insertParms);
					if (insertItem == null)
        			{
        				Platform.Log(LogLevel.Error,
        				             "Unexpected problem inserting 'MigrateStudy' record into WorkQueue for Study {0}",
        				             location.StudyInstanceUid);
        			}
        			else
        			{
        				update.Commit();
        				_bytesToRemove -= studySize;
        				_studiesMigrated++;

        				// spread out the scheduled migration entries based on the size
        				// assuming that the larger the study the longer it will take to migrate
        				// The assumed migration speed is arbitarily chosen.
        				double migrationSpeed = ServiceLockSettings.Default.TierMigrationSpeed*1024*1024; // MB / sec
        				TimeSpan estMigrateTime = TimeSpan.FromSeconds(studySize/migrationSpeed);
        				_scheduledTime = _scheduledTime.Add(estMigrateTime);
        			}
        		}
				stats.DbUpdateTime.End();
				stats.TotalTime.End();

        		summaryStats.AddSubStats(stats);
				StatisticsLogger.Log(LogLevel.Debug, stats);
			}

			summaryStats.CalculateAverage();
    		StatisticsLogger.Log(LogLevel.Info, false, summaryStats);
        }
		protected override void OnExecute(CommandProcessor theProcessor, IUpdateContext updateContext)
		{
			// Setup the delete parameters
			var parms = new DeleteFilesystemStudyStorageParameters();

			parms.ServerPartitionKey = _storage.ServerPartitionKey;
			parms.StudyStorageKey = _storage.GetKey();
			parms.StudyStatusEnum = StudyStatusEnum.Nearline; // TODO: Don't we set Nearline only if all the storage location are purged?
			
			// Get the Insert Instance broker and do the insert
			var delete = updateContext.GetBroker<IDeleteFilesystemStudyStorage>();

			if (false == delete.Execute(parms))
			{
				Platform.Log(LogLevel.Error, "Unexpected error when trying to delete study: {0} on partition {1}", _storage.StudyInstanceUid, _storage.ServerPartition.Description);
			}
			else
			{
				// Unlock the study, too
				var studyLock = updateContext.GetBroker<ILockStudy>();
				var lockParms = new LockStudyParameters();
				lockParms.QueueStudyStateEnum = QueueStudyStateEnum.Idle;
				lockParms.StudyStorageKey = _storage.GetKey();
				studyLock.Execute(lockParms);
			}
		}
		/// <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 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"))
                    {

						var archiveStudyCmd = new ArchiveStudyCommand(_storageLocation, _hsmArchive.HsmPath, executionContext.TempDirectory, _hsmArchive.PartitionArchive) 
								{ ForceCompress = HsmSettings.Default.CompressZipFiles };

						commandProcessor.AddCommand(archiveStudyCmd);
	                    commandProcessor.AddCommand(new UpdateArchiveQueueItemCommand(queueItem.GetKey(),_storageLocation.GetKey(), ArchiveQueueStatusEnum.Completed));
                        
                    	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, archiveStudyCmd.OutputZipFilePath);

                            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, archiveStudyCmd.OutputZipFilePath);

						// 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();
                    }
                }
            }			
		}
Exemple #11
0
        /// <summary>
        /// Resets the state of the study set by <see cref="LockStudy"/>.
        /// </summary>
        /// <param name="studyStorageKey"></param>
        /// <returns></returns>
        public static bool UnlockStudy(ServerEntityKey studyStorageKey)
        {
            using (IUpdateContext updateContext = PersistentStoreRegistry.GetDefaultStore().OpenUpdateContext(UpdateContextSyncMode.Flush))
            {
                ILockStudy lockStudyBroker = updateContext.GetBroker<ILockStudy>();
                LockStudyParameters lockStudyParams = new LockStudyParameters
                                                      	{
                                                      		StudyStorageKey = studyStorageKey,
                                                      		QueueStudyStateEnum = QueueStudyStateEnum.Idle
                                                      	};

            	if (!lockStudyBroker.Execute(lockStudyParams) || !lockStudyParams.Successful)
                    return false;

            	updateContext.Commit();
            	return true;
            }
        }
Exemple #12
0
        /// <summary>
        /// Sets the Queue Study State of the study.
        /// </summary>
        /// <param name="studyStorageKey">The <see cref="ServerEntityKey"/> of the <see cref="StudyStorage"/> record.</param>
        /// <param name="state">The state of the study to set</param>
        /// <param name="failureReason">A string value describing why the state could not be set.</param>
        /// <returns>True if the state of the study was successfully set. False otherwise.</returns>
        public static bool LockStudy(ServerEntityKey studyStorageKey, QueueStudyStateEnum state, out string failureReason)
        {
            using (IUpdateContext updateContext = PersistentStoreRegistry.GetDefaultStore().OpenUpdateContext(UpdateContextSyncMode.Flush))
            {
                ILockStudy lockStudyBroker = updateContext.GetBroker<ILockStudy>();
                LockStudyParameters lockStudyParams = new LockStudyParameters
                                                      	{
                                                      		StudyStorageKey = studyStorageKey,
                                                      		QueueStudyStateEnum = state
                                                      	};

            	if (!lockStudyBroker.Execute(lockStudyParams) || !lockStudyParams.Successful)
                {
                    failureReason = lockStudyParams.FailureReason;
                    return false;
                }
            	updateContext.Commit();
            	failureReason = null;
            	return true;
            }
        }
        private static void ReconcileStudy(string command,StudyIntegrityQueue item )
        {
            //Ignore the reconcile command if the item is null.
            if (item == null) return;

			// Preload the change description so its not done during the DB transaction
			XmlDocument changeDescription = new XmlDocument();
			changeDescription.LoadXml(command);

			// The Xml in the SIQ item was generated when the images were received and put into the SIQ.
			// We now add the user info to it so that it will be logged in the history
            ReconcileStudyWorkQueueData queueData = XmlUtils.Deserialize<ReconcileStudyWorkQueueData>(item.Details);
            queueData.TimeStamp = Platform.Time;
            queueData.UserId = ServerHelper.CurrentUserName;

			using (IUpdateContext context = PersistentStoreRegistry.GetDefaultStore().OpenUpdateContext(UpdateContextSyncMode.Flush))
			{
                
                LockStudyParameters lockParms = new LockStudyParameters
                                                	{
                                                		QueueStudyStateEnum = QueueStudyStateEnum.ReconcileScheduled,
                                                		StudyStorageKey = item.StudyStorageKey
                                                	};
				ILockStudy broker = context.GetBroker<ILockStudy>();
                broker.Execute(lockParms);
                if (!lockParms.Successful)
                {
                    throw new ApplicationException(lockParms.FailureReason);
                }

                
				//Add to Study History
				StudyHistoryeAdaptor historyAdaptor = new StudyHistoryeAdaptor();
				StudyHistoryUpdateColumns parameters = new StudyHistoryUpdateColumns
				                                       	{
				                                       		StudyData = item.StudyData,
				                                       		ChangeDescription = changeDescription,
				                                       		StudyStorageKey = item.StudyStorageKey,
				                                       		StudyHistoryTypeEnum = StudyHistoryTypeEnum.StudyReconciled
				                                       	};

				StudyHistory history = historyAdaptor.Add(context, parameters);

				//Create WorkQueue Entry
				WorkQueueAdaptor workQueueAdaptor = new WorkQueueAdaptor();
				WorkQueueUpdateColumns row = new WorkQueueUpdateColumns
				                             	{
				                             		Data = XmlUtils.SerializeAsXmlDoc(queueData),
				                             		ServerPartitionKey = item.ServerPartitionKey,
				                             		StudyStorageKey = item.StudyStorageKey,
				                             		StudyHistoryKey = history.GetKey(),
				                             		WorkQueueTypeEnum = WorkQueueTypeEnum.ReconcileStudy,
				                             		WorkQueueStatusEnum = WorkQueueStatusEnum.Pending,
				                             		ScheduledTime = Platform.Time,
				                             		ExpirationTime = Platform.Time.AddHours(1),
                                                    GroupID = item.GroupID
				                             	};
				WorkQueue newWorkQueueItem = workQueueAdaptor.Add(context, row);

				StudyIntegrityQueueUidAdaptor studyIntegrityQueueUidAdaptor = new StudyIntegrityQueueUidAdaptor();
				StudyIntegrityQueueUidSelectCriteria crit = new StudyIntegrityQueueUidSelectCriteria();
				crit.StudyIntegrityQueueKey.EqualTo(item.GetKey());
				IList<StudyIntegrityQueueUid> uidList = studyIntegrityQueueUidAdaptor.Get(context, crit);

				WorkQueueUidAdaptor workQueueUidAdaptor = new WorkQueueUidAdaptor();
				WorkQueueUidUpdateColumns update = new WorkQueueUidUpdateColumns();
				foreach (StudyIntegrityQueueUid uid in uidList)
				{
					update.WorkQueueKey = newWorkQueueItem.GetKey();
					update.SeriesInstanceUid = uid.SeriesInstanceUid;
					update.SopInstanceUid = uid.SopInstanceUid;
				    update.RelativePath = uid.RelativePath;
					workQueueUidAdaptor.Add(context, update);
				}

				//DeleteStudyIntegrityQueue Item
				StudyIntegrityQueueUidSelectCriteria criteria = new StudyIntegrityQueueUidSelectCriteria();
				criteria.StudyIntegrityQueueKey.EqualTo(item.GetKey());
				studyIntegrityQueueUidAdaptor.Delete(context, criteria);

				StudyIntegrityQueueAdaptor studyIntegrityQueueAdaptor = new StudyIntegrityQueueAdaptor();
				studyIntegrityQueueAdaptor.Delete(context, item.GetKey());

				context.Commit();
			}

		}
Exemple #14
0
		/// <summary>
		/// Delete a Study.
		/// </summary>
		public void DeleteStudy(ServerEntityKey studyKey, string reason)
        {
			StudySummary study = StudySummaryAssembler.CreateStudySummary(HttpContextData.Current.ReadContext, Study.Load(HttpContextData.Current.ReadContext, studyKey));
			if (study.IsReconcileRequired)
			{
				throw new ApplicationException(
					String.Format("Deleting the study is not allowed at this time : there are items to be reconciled."));

				// NOTE: another check will occur when the delete is actually processed
			}
			

			using (IUpdateContext ctx = PersistentStoreRegistry.GetDefaultStore().OpenUpdateContext(UpdateContextSyncMode.Flush))
			{
                LockStudyParameters lockParms = new LockStudyParameters
                                                	{
                                                		QueueStudyStateEnum = QueueStudyStateEnum.WebDeleteScheduled,
                                                		StudyStorageKey = study.TheStudyStorage.Key
                                                	};
				ILockStudy broker = ctx.GetBroker<ILockStudy>();
				broker.Execute(lockParms);
				if (!lockParms.Successful)
				{
				    throw new ApplicationException(String.Format("Unable to lock the study : {0}", lockParms.FailureReason));
				}
				

				InsertWorkQueueParameters insertParms = new InsertWorkQueueParameters
				                                        	{
				                                        		WorkQueueTypeEnum = WorkQueueTypeEnum.WebDeleteStudy,
				                                        		ServerPartitionKey = study.ThePartition.Key,
				                                        		StudyStorageKey = study.TheStudyStorage.Key,
				                                        		ScheduledTime = Platform.Time
				                                        	};

				WebDeleteStudyLevelQueueData extendedData = new WebDeleteStudyLevelQueueData
			                                                	{
			                                                		Level = DeletionLevel.Study,
			                                                		Reason = reason,
			                                                		UserId = ServerHelper.CurrentUserId,
			                                                		UserName = ServerHelper.CurrentUserName
			                                                	};
				insertParms.WorkQueueData = XmlUtils.SerializeAsXmlDoc(extendedData);
				IInsertWorkQueue insertWorkQueue = ctx.GetBroker<IInsertWorkQueue>();
				
                if (insertWorkQueue.FindOne(insertParms)==null)
                {
                    throw new ApplicationException("DeleteStudy failed");
                }


				ctx.Commit();
			}
        }
        /// <summary>
        /// Inserts a <see cref="WorkQueue"/> request to reprocess the study
        /// </summary>
        /// <param name="ctx"></param>
        /// <param name="reason"></param>
        /// <param name="location"></param>
        /// <param name="additionalPaths"></param>
        /// <param name="scheduleTime"></param>
        /// <returns></returns>
        /// <exception cref="InvalidStudyStateOperationException">Study is in a state that reprocessing is not allowed</exception>
        /// 
        public WorkQueue ReprocessStudy(IUpdateContext ctx, String reason, StudyStorageLocation location, List<FilesystemDynamicPath> additionalPaths, DateTime scheduleTime)
		{
			Platform.CheckForNullReference(location, "location");

            if (location.StudyStatusEnum.Equals(StudyStatusEnum.OnlineLossy))
            {
                if (location.IsLatestArchiveLossless)
                {
                    string message = String.Format("Study has been archived as lossless and is currently lossy. It must be restored first");
                    throw new InvalidStudyStateOperationException(message);
                }
            }

			Study study = location.LoadStudy(ctx);
            
			// Unlock first. 
			ILockStudy lockStudy = ctx.GetBroker<ILockStudy>();
			LockStudyParameters lockParms = new LockStudyParameters();
			lockParms.StudyStorageKey = location.Key;
			lockParms.QueueStudyStateEnum = QueueStudyStateEnum.Idle;
			if (!lockStudy.Execute(lockParms) || !lockParms.Successful)
			{
                // Note: according to the stored proc, setting study state to Idle always succeeds so
                // this will never happen
			    return null;
			}

            // Now relock into ReprocessScheduled state. If another process locks the study before this occurs,
            // 
			lockParms.QueueStudyStateEnum = QueueStudyStateEnum.ReprocessScheduled;
			if (!lockStudy.Execute(lockParms) || !lockParms.Successful)
			{
			    throw new InvalidStudyStateOperationException(lockParms.FailureReason);
			}

			InsertWorkQueueParameters columns = new InsertWorkQueueParameters();
			columns.ScheduledTime = scheduleTime;
			columns.ServerPartitionKey = location.ServerPartitionKey;
			columns.StudyStorageKey = location.Key;
			columns.WorkQueueTypeEnum = WorkQueueTypeEnum.ReprocessStudy;

			ReprocessStudyQueueData queueData = new ReprocessStudyQueueData();
			queueData.State = new ReprocessStudyState();
			queueData.State.ExecuteAtLeastOnce = false;
			queueData.ChangeLog = new ReprocessStudyChangeLog();
			queueData.ChangeLog.Reason = reason;
			queueData.ChangeLog.TimeStamp = Platform.Time;
			queueData.ChangeLog.User = (Thread.CurrentPrincipal is CustomPrincipal)
			                           	? (Thread.CurrentPrincipal as CustomPrincipal).Identity.Name
			                           	: String.Empty;

            if (additionalPaths != null)
                queueData.AdditionalFiles = additionalPaths.ConvertAll<string>(path => path.ToString());
            

			columns.WorkQueueData = XmlUtils.SerializeAsXmlDoc(queueData);
			IInsertWorkQueue insertBroker = ctx.GetBroker<IInsertWorkQueue>();
			WorkQueue reprocessEntry = insertBroker.FindOne(columns);
			if (reprocessEntry != null)
			{
				if (study != null)
				{
					Platform.Log(LogLevel.Info,
					             "Study Reprocess Scheduled for Study {0}, A#: {1}, Patient: {2}, ID={3}",
					             study.StudyInstanceUid, study.AccessionNumber, study.PatientsName, study.PatientId);
				}
				else
				{
					Platform.Log(LogLevel.Info, "Study Reprocess Scheduled for Study {0}.", location.StudyInstanceUid);
				}
			}

			return reprocessEntry;
		}
        /// <summary>
        /// Inserts work queue entry to process the duplicates.
        /// </summary>
        /// <param name="entryKey"><see cref="ServerEntityKey"/> of the <see cref="StudyIntegrityQueue"/> entry  that has <see cref="StudyIntegrityReasonEnum"/> equal to <see cref="StudyIntegrityReasonEnum.Duplicate"/> </param>
        /// <param name="action"></param>
        public void Process(ServerEntityKey entryKey, ProcessDuplicateAction action)
        {
            
            DuplicateSopReceivedQueue entry = DuplicateSopReceivedQueue.Load(HttpContextData.Current.ReadContext, entryKey);
            Platform.CheckTrue(entry.StudyIntegrityReasonEnum == StudyIntegrityReasonEnum.Duplicate, "Invalid type of entry");

            IList<StudyIntegrityQueueUid> uids = LoadDuplicateSopUid(entry);

            using(IUpdateContext context = PersistentStoreRegistry.GetDefaultStore().OpenUpdateContext(UpdateContextSyncMode.Flush))
            {
                ProcessDuplicateQueueEntryQueueData data = new ProcessDuplicateQueueEntryQueueData
                {
                    Action = action,
                    DuplicateSopFolder = entry.GetFolderPath(context),
                    UserName = ServerHelper.CurrentUserName,                                                              		
                }; 
                
                LockStudyParameters lockParms = new LockStudyParameters
                {
                    QueueStudyStateEnum = QueueStudyStateEnum.ReconcileScheduled,
                    StudyStorageKey = entry.StudyStorageKey
                };

                ILockStudy lockBbroker = context.GetBroker<ILockStudy>();
                lockBbroker.Execute(lockParms);
                if (!lockParms.Successful)
                {
                    throw new ApplicationException(lockParms.FailureReason);
                }

            	IWorkQueueProcessDuplicateSopBroker broker = context.GetBroker<IWorkQueueProcessDuplicateSopBroker>();
                WorkQueueProcessDuplicateSopUpdateColumns columns = new WorkQueueProcessDuplicateSopUpdateColumns
                                                                    	{
                                                                    		Data = XmlUtils.SerializeAsXmlDoc(data),
                                                                    		GroupID = entry.GroupID,
                                                                    		ScheduledTime = Platform.Time,
                                                                    		ExpirationTime =
                                                                    			Platform.Time.Add(TimeSpan.FromMinutes(15)),
                                                                    		ServerPartitionKey = entry.ServerPartitionKey,
                                                                    		WorkQueuePriorityEnum =
                                                                    			WorkQueuePriorityEnum.Medium,
                                                                    		StudyStorageKey = entry.StudyStorageKey,
                                                                    		WorkQueueStatusEnum = WorkQueueStatusEnum.Pending
                                                                    	};

            	WorkQueueProcessDuplicateSop processDuplicateWorkQueueEntry = broker.Insert(columns);

                IWorkQueueUidEntityBroker workQueueUidBroker = context.GetBroker<IWorkQueueUidEntityBroker>();
                IStudyIntegrityQueueUidEntityBroker duplicateUidBroke = context.GetBroker<IStudyIntegrityQueueUidEntityBroker>();
                foreach (StudyIntegrityQueueUid uid in uids)
                {
                    WorkQueueUidUpdateColumns uidColumns = new WorkQueueUidUpdateColumns
                                                           	{
                                                           		Duplicate = true,
                                                           		Extension = ServerPlatform.DuplicateFileExtension,
                                                           		SeriesInstanceUid = uid.SeriesInstanceUid,
                                                           		SopInstanceUid = uid.SopInstanceUid,
                                                           		RelativePath = uid.RelativePath,
                                                           		WorkQueueKey = processDuplicateWorkQueueEntry.GetKey()
                                                           	};

                	workQueueUidBroker.Insert(uidColumns);

                    duplicateUidBroke.Delete(uid.GetKey());
                }

                IDuplicateSopEntryEntityBroker duplicateEntryBroker =
                    context.GetBroker<IDuplicateSopEntryEntityBroker>();
                duplicateEntryBroker.Delete(entry.GetKey());


                context.Commit();
            }
        }
		/// <summary>
		/// Process StudyDelete Candidates retrieved from the <see cref="Model.FilesystemQueue"/> table
		/// </summary>
		/// <param name="candidateList">The list of candidate studies for deleting.</param>
		/// <param name="type">The type of compress.</param>
		private void ProcessCompressCandidates(IEnumerable<FilesystemQueue> candidateList, FilesystemQueueTypeEnum type)
		{
			DateTime scheduledTime = Platform.Time.AddSeconds(10);

			foreach (FilesystemQueue queueItem in candidateList)
			{
				// Check for Shutdown/Cancel
				if (CancelPending) break;

				// First, get the StudyStorage locations for the study, and calculate the disk usage.
				StudyStorageLocation location;
				if (!FilesystemMonitor.Instance.GetWritableStudyStorageLocation(queueItem.StudyStorageKey, out location))
					continue;

				// Get the disk usage
				StudyXml studyXml = LoadStudyXml(location);

				using (IUpdateContext update = PersistentStoreRegistry.GetDefaultStore().OpenUpdateContext(UpdateContextSyncMode.Flush))
				{
					ILockStudy lockstudy = update.GetBroker<ILockStudy>();
					LockStudyParameters lockParms = new LockStudyParameters();
					lockParms.StudyStorageKey = location.Key;
					lockParms.QueueStudyStateEnum = QueueStudyStateEnum.CompressScheduled;
					if (!lockstudy.Execute(lockParms) || !lockParms.Successful)
					{
						Platform.Log(LogLevel.Warn, "Unable to lock study for inserting Lossy Compress, skipping study ({0}",
									 location.StudyInstanceUid);
						continue;
					}

					scheduledTime = scheduledTime.AddSeconds(3);

					IInsertWorkQueueFromFilesystemQueue workQueueInsert = update.GetBroker<IInsertWorkQueueFromFilesystemQueue>();

					InsertWorkQueueFromFilesystemQueueParameters insertParms = new InsertWorkQueueFromFilesystemQueueParameters();
				    insertParms.WorkQueueTypeEnum = WorkQueueTypeEnum.CompressStudy;
					insertParms.FilesystemQueueTypeEnum = FilesystemQueueTypeEnum.LossyCompress;
					insertParms.StudyStorageKey = location.GetKey();
					insertParms.ServerPartitionKey = location.ServerPartitionKey;
					DateTime expirationTime = scheduledTime;
					insertParms.ScheduledTime = expirationTime;
					insertParms.DeleteFilesystemQueue = true;
					insertParms.Data = queueItem.QueueXml;
					insertParms.WorkQueueTypeEnum = WorkQueueTypeEnum.CompressStudy;
					insertParms.FilesystemQueueTypeEnum = type;
					
					try
					{
						WorkQueue entry = workQueueInsert.FindOne(insertParms);

						InsertWorkQueueUidFromStudyXml(studyXml,update,entry.GetKey());

						update.Commit();
						_studiesInserted++;
					}
					catch(Exception e) 
					{
						Platform.Log(LogLevel.Error, e, "Unexpected problem inserting 'CompressStudy' record into WorkQueue for Study {0}", location.StudyInstanceUid);
						// throw; -- would cause abort of inserts, go ahead and try everything
					}
				}
			}
		}
		/// <summary>
		/// Process StudyPurge <see cref="FilesystemQueue"/> entries.
		/// </summary>
		/// <param name="candidateList">The list of candidates for purging</param>
		private void ProcessStudyPurgeCandidates(IList<FilesystemQueue> candidateList)
		{
			if (candidateList.Count > 0)
				Platform.Log(LogLevel.Debug, "Scheduling purge study for {0} eligible studies...", candidateList.Count);

			FilesystemProcessStatistics summaryStats = new FilesystemProcessStatistics("FilesystemPurgeInsert");

			foreach (FilesystemQueue queueItem in candidateList)
			{
				if (_bytesToRemove < 0 || CancelPending)
					break;

				StudyProcessStatistics stats = new StudyProcessStatistics("PurgeStudy");
				stats.TotalTime.Start();

				stats.StudyStorageTime.Start();
				// First, get the StudyStorage locations for the study, and calculate the disk usage.
				StudyStorageLocation location;
				if (!FilesystemMonitor.Instance.GetWritableStudyStorageLocation(queueItem.StudyStorageKey, out location))
					continue;
				stats.StudyStorageTime.End();

				stats.CalculateDirectorySizeTime.Start();
				// Get the disk usage
				float studySize = EstimateFolderSizeFromStudyXml(location);
				stats.CalculateDirectorySizeTime.End();
				stats.DirectorySize = (ulong) studySize;

				stats.DbUpdateTime.Start();
				// Update the DB
				using (
					IUpdateContext update = PersistentStoreRegistry.GetDefaultStore().OpenUpdateContext(UpdateContextSyncMode.Flush))
				{
					ILockStudy lockstudy = update.GetBroker<ILockStudy>();
					LockStudyParameters lockParms = new LockStudyParameters();
					lockParms.StudyStorageKey = location.Key;
					lockParms.QueueStudyStateEnum = QueueStudyStateEnum.PurgeScheduled;
					if (!lockstudy.Execute(lockParms) || !lockParms.Successful)
					{
						Platform.Log(LogLevel.Warn, "Unable to lock study for inserting Study Purge, skipping study ({0}",
						             location.StudyInstanceUid);
						continue;
					}

                    IInsertWorkQueueFromFilesystemQueue insertBroker = update.GetBroker<IInsertWorkQueueFromFilesystemQueue>();

					InsertWorkQueueFromFilesystemQueueParameters insertParms = new InsertWorkQueueFromFilesystemQueueParameters();
					insertParms.StudyStorageKey = location.GetKey();
					insertParms.ServerPartitionKey = location.ServerPartitionKey;
					insertParms.ScheduledTime = _scheduledTime;
					insertParms.DeleteFilesystemQueue = true;
					insertParms.WorkQueueTypeEnum = WorkQueueTypeEnum.PurgeStudy;
					insertParms.FilesystemQueueTypeEnum = FilesystemQueueTypeEnum.PurgeStudy;
					
                    WorkQueue insertItem = insertBroker.FindOne(insertParms);
					if (insertItem == null)
					{
						Platform.Log(LogLevel.Error, "Unexpected problem inserting 'PurgeStudy' record into WorkQueue for Study {0}",
						             location.StudyInstanceUid);
					}
					else
					{
						update.Commit();
						_bytesToRemove -= studySize;
						_studiesPurged++;
						_scheduledTime = _scheduledTime.AddSeconds(2);
					}
					
				}
				stats.DbUpdateTime.End();
				stats.TotalTime.End();

				summaryStats.AddSubStats(stats);
				StatisticsLogger.Log(LogLevel.Debug, stats);
			}
			summaryStats.CalculateAverage();
			StatisticsLogger.Log(LogLevel.Info, false, summaryStats);
		}