/// <summary> /// Find a <see cref="Study"/> with the specified study instance uid on the given partition. /// </summary> /// <param name="studyInstanceUid"></param> /// <param name="partition"></param> /// <returns></returns> /// static public Study Find(IPersistenceContext context, String studyInstanceUid, ServerPartition partition) { IStudyEntityBroker broker = context.GetBroker <IStudyEntityBroker>(); StudySelectCriteria criteria = new StudySelectCriteria(); criteria.ServerPartitionKey.EqualTo(partition.GetKey()); criteria.StudyInstanceUid.EqualTo(studyInstanceUid); Study study = broker.FindOne(criteria); return(study); }
/// <summary> /// Find a <see cref="Study"/> with the specified study instance uid on the given partition. /// </summary> /// <param name="studyInstanceUid"></param> /// <param name="partition"></param> /// <returns></returns> /// static public Study Find(IPersistenceContext context, String studyInstanceUid, ServerPartition partition) { IStudyEntityBroker broker = context.GetBroker<IStudyEntityBroker>(); StudySelectCriteria criteria = new StudySelectCriteria(); criteria.ServerPartitionKey.EqualTo(partition.GetKey()); criteria.StudyInstanceUid.EqualTo(studyInstanceUid); Study study = broker.FindOne(criteria); return study; }
/// <summary> /// Lookup the device entity in the database corresponding to the remote AE of the association. /// </summary> /// <param name="partition">The partition to look up the devices</param> /// <param name="association">The association</param> /// <param name="isNew">Indicates whether the device returned is created by the call.</param> /// <returns>The device record corresponding to the called AE of the association</returns> static public Device LookupDevice(ServerPartition partition, AssociationParameters association, out bool isNew) { isNew = false; Device device = null; using ( IUpdateContext updateContext = PersistentStoreRegistry.GetDefaultStore().OpenUpdateContext(UpdateContextSyncMode.Flush)) { var queryDevice = updateContext.GetBroker<IDeviceEntityBroker>(); // Setup the select parameters. var queryParameters = new DeviceSelectCriteria(); queryParameters.AeTitle.EqualTo(association.CallingAE); queryParameters.ServerPartitionKey.EqualTo(partition.GetKey()); var devices = queryDevice.Find(queryParameters); foreach (var d in devices) { if (string.Compare(d.AeTitle,association.CallingAE,false,CultureInfo.InvariantCulture) == 0) { device = d; break; } } if (device == null) { if (!partition.AcceptAnyDevice) { return null; } if (partition.AutoInsertDevice) { // Auto-insert a new entry in the table. var updateColumns = new DeviceUpdateColumns { AeTitle = association.CallingAE, Enabled = true, Description = String.Format("AE: {0}", association.CallingAE), Dhcp = false, IpAddress = association.RemoteEndPoint.Address.ToString(), ServerPartitionKey = partition.GetKey(), Port = partition.DefaultRemotePort, AllowQuery = true, AllowRetrieve = true, AllowStorage = true, ThrottleMaxConnections = ImageServerCommonConfiguration.Device.MaxConnections, DeviceTypeEnum = DeviceTypeEnum.Workstation }; var insert = updateContext.GetBroker<IDeviceEntityBroker>(); device = insert.Insert(updateColumns); updateContext.Commit(); isNew = true; } } if (device != null) { // For DHCP devices, we always update the remote ip address, if its changed from what is in the DB. if (device.Dhcp && !association.RemoteEndPoint.Address.ToString().Equals(device.IpAddress)) { var updateColumns = new DeviceUpdateColumns { IpAddress = association.RemoteEndPoint.Address.ToString(), LastAccessedTime = Platform.Time }; var update = updateContext.GetBroker<IDeviceEntityBroker>(); if (!update.Update(device.GetKey(), updateColumns)) Platform.Log(LogLevel.Error, "Unable to update IP Address for DHCP device {0} on partition '{1}'", device.AeTitle, partition.Description); else updateContext.Commit(); } else if (!isNew) { var updateColumns = new DeviceUpdateColumns {LastAccessedTime = Platform.Time}; var update = updateContext.GetBroker<IDeviceEntityBroker>(); if (!update.Update(device.GetKey(), updateColumns)) Platform.Log(LogLevel.Error, "Unable to update LastAccessedTime device {0} on partition '{1}'", device.AeTitle, partition.Description); else updateContext.Commit(); } } } return device; }
private static StudyStorageLocation FindStudyStorageLocation(IUpdateContext context, ServerPartition partition, string studyInstanceUid) { var procedure = context.GetBroker<IQueryStudyStorageLocation>(); var parms = new StudyStorageLocationQueryParameters { ServerPartitionKey = partition.GetKey(), StudyInstanceUid = studyInstanceUid }; return procedure.FindOne(parms); }
private IList<PartitionSopClass> LoadPartitionSopClassesFromDatabase(ServerPartition partition) { using (IReadContext context = PersistentStoreRegistry.GetDefaultStore().OpenReadContext()) { // Set the input parameters for query var inputParms = new PartitionSopClassQueryParameters {ServerPartitionKey = partition.GetKey()}; var broker = context.GetBroker<IQueryServerPartitionSopClasses>(); return broker.Find(inputParms); } }
/// <summary> /// Load <see cref="Device"/> information for a Move destination. /// </summary> /// <param name="read"></param> /// <param name="partition"></param> /// <param name="remoteAe"></param> /// <returns></returns> private static Device LoadRemoteHost(IPersistenceContext read, ServerPartition partition, string remoteAe) { var select = read.GetBroker<IDeviceEntityBroker>(); // Setup the select parameters. var selectParms = new DeviceSelectCriteria(); selectParms.AeTitle.EqualTo(remoteAe); selectParms.ServerPartitionKey.EqualTo(partition.GetKey()); var devices = select.Find(selectParms); foreach (var d in devices) { if (string.Compare(d.AeTitle, remoteAe, false, CultureInfo.InvariantCulture) == 0) { return d; } } return null; }
/// <summary> /// Reprocess a file systems /// </summary> /// <param name="partition"></param> private void ReprocessPartition(ServerPartition partition) { var engine = new ServerRulesEngine(ServerRuleApplyTimeEnum.StudyProcessed, partition.Key); engine.Load(); var postArchivalEngine = new ServerRulesEngine(ServerRuleApplyTimeEnum.StudyArchived, partition.Key); postArchivalEngine.Load(); var dataAccessEngine = new ServerRulesEngine(ServerRuleApplyTimeEnum.StudyProcessed, partition.Key); dataAccessEngine.AddIncludeType(ServerRuleTypeEnum.DataAccess); dataAccessEngine.Load(); var filesystems = FilesystemMonitor.Instance.GetFilesystems(); foreach (var f in filesystems) { var partitionDir = Path.Combine(f.Filesystem.FilesystemPath, partition.PartitionFolder); var filesystemDir = new DirectoryInfo(partitionDir); foreach (DirectoryInfo dateDir in filesystemDir.GetDirectories()) { if (dateDir.FullName.EndsWith("Deleted") || dateDir.FullName.EndsWith(ServerPlatform.ReconcileStorageFolder)) continue; foreach (DirectoryInfo studyDir in dateDir.GetDirectories()) { String studyInstanceUid = studyDir.Name; try { StudyStorageLocation location = LoadReadableStorageLocation(partition.GetKey(), studyInstanceUid); if (location == null) { foreach (DirectoryInfo seriesDir in studyDir.GetDirectories()) { FileInfo[] sopInstanceFiles = seriesDir.GetFiles("*.dcm"); DicomFile file = null; foreach (FileInfo sopFile in sopInstanceFiles) { if (!sopFile.FullName.EndsWith(ServerPlatform.DicomFileExtension)) continue; try { file = new DicomFile(sopFile.FullName); file.Load(DicomTags.StudyId, DicomReadOptions.DoNotStorePixelDataInDataSet | DicomReadOptions.Default); break; } catch (Exception e) { Platform.Log(LogLevel.Warn, e, "Unexpected failure loading file: {0}. Continuing to next file.", sopFile.FullName); file = null; } } if (file != null) { studyInstanceUid = file.DataSet[DicomTags.StudyInstanceUid].ToString(); break; } } location = LoadReadableStorageLocation(partition.GetKey(), studyInstanceUid); if (location == null) continue; } ProcessStudy(partition, location, engine, postArchivalEngine, dataAccessEngine); //_stats.NumStudies++; if (CancelPending) return; } catch (Exception e) { Platform.Log(LogLevel.Error, e, "Unexpected error while processing study: {0} on partition {1}.", studyInstanceUid, partition.Description); } } // Cleanup the directory, if its empty. DirectoryUtility.DeleteIfEmpty(dateDir.FullName); } } }
/// <summary> /// Reprocess a specific study. /// </summary> /// <param name="partition">The ServerPartition the study is on.</param> /// <param name="location">The storage location of the study to process.</param> /// <param name="engine">The rules engine to use when processing the study.</param> /// <param name="postArchivalEngine">The rules engine used for studies that have been archived.</param> /// <param name="dataAccessEngine">The rules engine strictly used for setting data acess.</param> protected static void ProcessStudy(ServerPartition partition, StudyStorageLocation location, ServerRulesEngine engine, ServerRulesEngine postArchivalEngine, ServerRulesEngine dataAccessEngine) { if (!location.QueueStudyStateEnum.Equals(QueueStudyStateEnum.Idle) || !location.AcquireWriteLock()) { Platform.Log(LogLevel.Error, "Unable to lock study {0}. The study is being processed. (Queue State: {1})", location.StudyInstanceUid,location.QueueStudyStateEnum.Description); } else { try { DicomFile msg = LoadInstance(location); if (msg == null) { Platform.Log(LogLevel.Error, "Unable to load file for study {0}", location.StudyInstanceUid); return; } bool archiveQueueExists; bool archiveStudyStorageExists; bool filesystemDeleteExists; using (IReadContext read = PersistentStoreRegistry.GetDefaultStore().OpenReadContext()) { // Check for existing archive queue entries var archiveQueueBroker = read.GetBroker<IArchiveQueueEntityBroker>(); var archiveQueueCriteria = new ArchiveQueueSelectCriteria(); archiveQueueCriteria.StudyStorageKey.EqualTo(location.Key); archiveQueueExists = archiveQueueBroker.Count(archiveQueueCriteria) > 0; var archiveStorageBroker = read.GetBroker<IArchiveStudyStorageEntityBroker>(); var archiveStudyStorageCriteria = new ArchiveStudyStorageSelectCriteria(); archiveStudyStorageCriteria.StudyStorageKey.EqualTo(location.Key); archiveStudyStorageExists = archiveStorageBroker.Count(archiveStudyStorageCriteria) > 0; var filesystemQueueBroker = read.GetBroker<IFilesystemQueueEntityBroker>(); var filesystemQueueCriteria = new FilesystemQueueSelectCriteria(); filesystemQueueCriteria.StudyStorageKey.EqualTo(location.Key); filesystemQueueCriteria.FilesystemQueueTypeEnum.EqualTo(FilesystemQueueTypeEnum.DeleteStudy); filesystemDeleteExists = filesystemQueueBroker.Count(filesystemQueueCriteria) > 0; } using (var commandProcessor = new ServerCommandProcessor("Study Rule Processor") { PrimaryServerPartitionKey = partition.GetKey(), PrimaryStudyKey = location.Study.GetKey() }) { var context = new ServerActionContext(msg, location.FilesystemKey, partition, location.Key, commandProcessor); // Check if the Study has been archived if (archiveStudyStorageExists && !archiveQueueExists && !filesystemDeleteExists) { // Add a command to delete the current filesystemQueue entries, so that they can // be reinserted by the rules engine. context.CommandProcessor.AddCommand(new DeleteFilesystemQueueCommand(location.Key, ServerRuleApplyTimeEnum.StudyArchived)); // How to deal with exiting FilesystemQueue entries is problematic here. If the study // has been migrated off tier 1, we probably don't want to modify the tier migration // entries. Compression entries may have been entered when the Study was initially // processed, we don't want to delete them, because they might still be valid. // We just re-run the rules engine at this point, and delete only the StudyPurge entries, // since those we know at least would only be applied for archived studies. var studyRulesEngine = new StudyRulesEngine(postArchivalEngine, location, location.ServerPartition, location.LoadStudyXml()); studyRulesEngine.Apply(ServerRuleApplyTimeEnum.StudyArchived, commandProcessor); // Post Archive doesn't allow data access rules. Force Data Access rules to be reapplied // to these studies also. dataAccessEngine.Execute(context); } else { // Add a command to delete the current filesystemQueue entries, so that they can // be reinserted by the rules engine. context.CommandProcessor.AddCommand(new DeleteFilesystemQueueCommand(location.Key,ServerRuleApplyTimeEnum.StudyProcessed)); // Execute the rules engine, insert commands to update the database into the command processor. // Due to ticket #11673, we create a new rules engine instance for each study, since the Study QC rules // don't work right now with a single rules engine. //TODO CR (Jan 2014) - Check if we can go back to caching the rules engine to reduce database hits on the rules var studyRulesEngine = new StudyRulesEngine(location, location.ServerPartition, location.LoadStudyXml()); studyRulesEngine.Apply(ServerRuleApplyTimeEnum.StudyProcessed, commandProcessor); } // Do the actual database updates. if (false == context.CommandProcessor.Execute()) { Platform.Log(LogLevel.Error, "Unexpected failure processing Study level rules for study {0}", location.StudyInstanceUid); } // Log the FilesystemQueue related entries location.LogFilesystemQueue(); } } finally { location.ReleaseWriteLock(); } } }