/// <summary> /// Returns number of Delete Study, Tier Migrate, and Study Purge work queue items /// that are still Pending or In Progress for the filesystem associated with the /// specified <see cref="ServiceLock"/>. /// </summary> /// <param name="item">The ServiceLock item.</param> /// <returns>The number of WorkQueue entries pending.</returns> private int CheckWorkQueueCount(Model.ServiceLock item) { using (ServerExecutionContext context = new ServerExecutionContext()) { IWorkQueueEntityBroker select = context.ReadContext.GetBroker <IWorkQueueEntityBroker>(); WorkQueueSelectCriteria criteria = new WorkQueueSelectCriteria(); criteria.WorkQueueTypeEnum.In(new[] { WorkQueueTypeEnum.DeleteStudy, WorkQueueTypeEnum.MigrateStudy, WorkQueueTypeEnum.PurgeStudy }); // Do Pending status, in case there's a Failure status entry, we don't want to // block on that. criteria.WorkQueueStatusEnum.In(new[] { WorkQueueStatusEnum.Pending, WorkQueueStatusEnum.InProgress }); FilesystemStudyStorageSelectCriteria filesystemCriteria = new FilesystemStudyStorageSelectCriteria(); filesystemCriteria.FilesystemKey.EqualTo(item.FilesystemKey); criteria.FilesystemStudyStorageRelatedEntityCondition.Exists(filesystemCriteria); int count = select.Count(criteria); return(count); } }
private void UpdateQueueData() { using (IUpdateContext ctx = PersistentStoreRegistry.GetDefaultStore().OpenUpdateContext(UpdateContextSyncMode.Flush)) { // make a copy of the current queue data with updated info ProcessDuplicateQueueEntryQueueData data = new ProcessDuplicateQueueEntryQueueData { Action = _processDuplicateEntry.QueueData.Action, DuplicateSopFolder = _processDuplicateEntry.QueueData.DuplicateSopFolder, UserName = _processDuplicateEntry.QueueData.UserName, State = new ProcessDuplicateQueueState { HistoryLogged = HistoryLogged, ExistingStudyUpdated = _processDuplicateEntry.QueueData.State.ExistingStudyUpdated } }; // update the queue data in db IWorkQueueEntityBroker broker = ctx.GetBroker <IWorkQueueEntityBroker>(); WorkQueueUpdateColumns parameters = new WorkQueueUpdateColumns { Data = XmlUtils.SerializeAsXmlDoc(data) }; if (broker.Update(WorkQueueItem.Key, parameters)) { ctx.Commit(); HistoryLogged = _processDuplicateEntry.QueueData.State.HistoryLogged = true; } } }
/// <summary> /// Delete the Work Queue record from the system. /// </summary> /// <param name="context"></param> /// <returns></returns> public bool Delete(IPersistenceContext context) { IWorkQueueUidEntityBroker workQueueUidBroker = context.GetBroker <IWorkQueueUidEntityBroker>(); WorkQueueUidSelectCriteria criteria = new WorkQueueUidSelectCriteria(); criteria.WorkQueueKey.EqualTo(GetKey()); workQueueUidBroker.Delete(criteria); IWorkQueueEntityBroker workQueueBroker = context.GetBroker <IWorkQueueEntityBroker>(); return(workQueueBroker.Delete(GetKey())); }
/// <summary> /// Finds all storage locations used for the study. /// </summary> protected void FindAllRelatedDirectories() { // Check the work queue for other entries IList <Model.WorkQueue> list; // NOTE: a local read context is used for lookup because we want to // release the lock on the rows asap. using (IReadContext ctx = PersistentStoreRegistry.GetDefaultStore().OpenReadContext()) { IWorkQueueEntityBroker broker = ctx.GetBroker <IWorkQueueEntityBroker>(); WorkQueueSelectCriteria criteria = new WorkQueueSelectCriteria(); criteria.StudyStorageKey.EqualTo(WorkQueueItem.StudyStorageKey); list = broker.Find(criteria); } List <DirectoryInfo> dirs = new List <DirectoryInfo>(); foreach (Model.WorkQueue item in list) { string path = GetWorkQueueSecondaryFolder(item); if (!string.IsNullOrEmpty(path)) { dirs.Add(new DirectoryInfo(path)); } } // NOTE: Under normal operation, the SIQ entries should be // empty at this point because the Delete Study button is disabled otherwise. // This block of code is still needed just in case this DeleteStudy work queue entry // is inserted through different means. IList <StudyIntegrityQueue> siqList; using (IReadContext ctx = PersistentStoreRegistry.GetDefaultStore().OpenReadContext()) { IStudyIntegrityQueueEntityBroker broker = ctx.GetBroker <IStudyIntegrityQueueEntityBroker>(); StudyIntegrityQueueSelectCriteria criteria = new StudyIntegrityQueueSelectCriteria(); criteria.StudyStorageKey.EqualTo(WorkQueueItem.StudyStorageKey); siqList = broker.Find(criteria); } foreach (StudyIntegrityQueue item in siqList) { string path = GetSIQItemStorageFolder(item); if (!string.IsNullOrEmpty(path)) { dirs.Add(new DirectoryInfo(path)); } } _relatedDirectories = dirs; }
private static bool CheckIfStudyIsInWorkQueue(ScanResultEntry scanResult) { using (IReadContext ctx = PersistentStoreRegistry.GetDefaultStore().OpenReadContext()) { IWorkQueueEntityBroker broker = ctx.GetBroker <IWorkQueueEntityBroker>(); WorkQueueSelectCriteria criteria = new WorkQueueSelectCriteria(); criteria.StudyStorageKey.EqualTo(scanResult.Storage.Key); var list = broker.Find(criteria); scanResult.IsInWorkQueue = list != null && list.Count > 0; } return(scanResult.IsInWorkQueue); }
private void AddWorkQueueData() { WebMoveWorkQueueEntryData data = new WebMoveWorkQueueEntryData { Timestamp = DateTime.Now, UserId = ServerHelper.CurrentUserName }; using (IUpdateContext update = PersistentStoreRegistry.GetDefaultStore().OpenUpdateContext(UpdateContextSyncMode.Flush)) { IWorkQueueEntityBroker broker = update.GetBroker <IWorkQueueEntityBroker>(); WorkQueueUpdateColumns cols = new WorkQueueUpdateColumns(); cols.Data = XmlUtils.SerializeAsXmlDoc(data); broker.Update(WorkQueueItem.Key, cols); update.Commit(); } }
/// <summary> /// Checks for the existinance of a SOP for a given Study in the <see cref="WorkQueue"/> for a <see cref="WorkQueueTypeEnum.ReconcileStudy"/>. /// </summary> /// <param name="studyStorageKey">The StudyStorage primary key</param> /// <param name="seriesInstanceUid">The Series Instance Uid of the Sop</param> /// <param name="sopInstanceUid">The Sop Instance to look for</param> /// <returns>true if an entry exists, false if it doesn't</returns> static public bool WorkQueueUidExists(ServerEntityKey studyStorageKey, string seriesInstanceUid, string sopInstanceUid) { Platform.CheckForNullReference(studyStorageKey, "studyStorageKey"); using (ServerExecutionContext scope = new ServerExecutionContext()) { IWorkQueueEntityBroker broker = scope.PersistenceContext.GetBroker <IWorkQueueEntityBroker>(); WorkQueueUidSelectCriteria uidSelectCriteria = new WorkQueueUidSelectCriteria(); uidSelectCriteria.SeriesInstanceUid.EqualTo(seriesInstanceUid); uidSelectCriteria.SopInstanceUid.EqualTo(sopInstanceUid); WorkQueueSelectCriteria selectCriteria = new WorkQueueSelectCriteria(); selectCriteria.StudyStorageKey.EqualTo(studyStorageKey); selectCriteria.WorkQueueTypeEnum.EqualTo(WorkQueueTypeEnum.ReconcileStudy); selectCriteria.WorkQueueUidRelatedEntityCondition.Exists(uidSelectCriteria); return(broker.Count(selectCriteria) > 0); } }
/// <summary> /// Finds a list of <see cref="WorkQueue"/> related to the specified <see cref="studyStorageKey"/>. /// </summary> /// <param name="studyStorageKey"></param> /// <param name="filter">A delegate that will be used to filter the returned list. Pass in Null to get the entire list.</param> /// <returns>A list of <see cref="WorkQueue"/></returns> static public IList <WorkQueue> FindWorkQueueEntries(ServerEntityKey studyStorageKey, Predicate <WorkQueue> filter) { Platform.CheckForNullReference(studyStorageKey, "studyStorageKey"); using (ServerExecutionContext scope = new ServerExecutionContext()) { IWorkQueueEntityBroker broker = scope.PersistenceContext.GetBroker <IWorkQueueEntityBroker>(); WorkQueueSelectCriteria criteria = new WorkQueueSelectCriteria(); criteria.StudyStorageKey.EqualTo(studyStorageKey); criteria.InsertTime.SortDesc(0); IList <WorkQueue> list = broker.Find(criteria); if (filter != null) { CollectionUtils.Remove(list, filter); } return(list); } }
private static void UpdateState(ServerEntityKey key, TierMigrationProcessingState state) { TierMigrationWorkQueueData data = new TierMigrationWorkQueueData { State = state }; using (IUpdateContext context = PersistentStoreRegistry.GetDefaultStore().OpenUpdateContext(UpdateContextSyncMode.Flush)) { IWorkQueueEntityBroker broker = context.GetBroker <IWorkQueueEntityBroker>(); WorkQueueUpdateColumns parms = new WorkQueueUpdateColumns { Data = XmlUtils.SerializeAsXmlDoc(data) }; if (!broker.Update(key, parms)) { throw new ApplicationException("Unable to update work queue state"); } context.Commit(); } }
private Study GetStudyAndQueues(StudyStorageLocation location, out int integrityQueueCount, out int workQueueCount) { using (IReadContext context = _store.OpenReadContext()) { IStudyIntegrityQueueEntityBroker integrityBroker = context.GetBroker <IStudyIntegrityQueueEntityBroker>(); StudyIntegrityQueueSelectCriteria integrityCriteria = new StudyIntegrityQueueSelectCriteria(); integrityCriteria.StudyStorageKey.EqualTo(location.Key); integrityQueueCount = integrityBroker.Count(integrityCriteria); IWorkQueueEntityBroker workBroker = context.GetBroker <IWorkQueueEntityBroker>(); WorkQueueSelectCriteria workCriteria = new WorkQueueSelectCriteria(); workCriteria.StudyStorageKey.EqualTo(location.Key); workQueueCount = workBroker.Count(workCriteria); IStudyEntityBroker procedure = context.GetBroker <IStudyEntityBroker>(); StudySelectCriteria criteria = new StudySelectCriteria(); criteria.StudyStorageKey.EqualTo(location.Key); return(procedure.FindOne(criteria)); } }
/// <summary> /// Reschedule a list of <see cref="WorkQueue"/> items /// </summary> /// <param name="items">List of <see cref="WorkQueue"/> items to be rescheduled</param> /// <param name="newScheduledTime">New schedule start date/time</param> /// <param name="expirationTime">New expiration date/time</param> /// <param name="priority">New priority</param> /// <returns>A value indicating whether all <see cref="WorkQueue"/> items in <paramref name="items"/> are updated successfully.</returns> /// <remarks> /// If one or more <see cref="WorkQueue"/> in <paramref name="items"/> cannot be rescheduled, all changes will be /// reverted and <b>false</b> will be returned. /// </remarks> public bool RescheduleWorkQueueItems(IList <WorkQueue> items, DateTime newScheduledTime, DateTime expirationTime, WorkQueuePriorityEnum priority) { if (items == null || items.Count == 0) { return(false); } WorkQueueUpdateColumns updatedColumns = new WorkQueueUpdateColumns(); updatedColumns.WorkQueuePriorityEnum = priority; updatedColumns.ScheduledTime = newScheduledTime; updatedColumns.ExpirationTime = expirationTime; updatedColumns.FailureCount = 0; updatedColumns.FailureDescription = String.Empty; updatedColumns.LastUpdatedTime = Platform.Time; bool result = false; IPersistentStore store = PersistentStoreRegistry.GetDefaultStore(); using (IUpdateContext ctx = store.OpenUpdateContext(UpdateContextSyncMode.Flush)) { IWorkQueueEntityBroker workQueueBroker = ctx.GetBroker <IWorkQueueEntityBroker>(); foreach (WorkQueue item in items) { result = workQueueBroker.Update(item.Key, updatedColumns); if (!result) { break; } } if (result) { ctx.Commit(); } } return(result); }
public bool ReprocessWorkQueueItem(WorkQueue item) { // #10620: Get a list of remaining WorkQueueUids which need to be reprocess // Note: currently only WorkQueueUIDs in failed StudyProcess will be reprocessed var remainingWorkQueueUidPaths = item.GetAllWorkQueueUidPaths(); IPersistentStore store = PersistentStoreRegistry.GetDefaultStore(); using (IUpdateContext ctx = store.OpenUpdateContext(UpdateContextSyncMode.Flush)) { // delete current workqueue IWorkQueueUidEntityBroker uidBroker = ctx.GetBroker <IWorkQueueUidEntityBroker>(); WorkQueueUidSelectCriteria criteria = new WorkQueueUidSelectCriteria(); criteria.WorkQueueKey.EqualTo(item.GetKey()); if (uidBroker.Delete(criteria) >= 0) { IWorkQueueEntityBroker workQueueBroker = ctx.GetBroker <IWorkQueueEntityBroker>(); if (workQueueBroker.Delete(item.GetKey())) { IList <StudyStorageLocation> locations = item.LoadStudyLocations(ctx); if (locations != null && locations.Count > 0) { StudyReprocessor reprocessor = new StudyReprocessor(); String reason = String.Format("User reprocesses failed {0}", item.WorkQueueTypeEnum); WorkQueue reprocessEntry = reprocessor.ReprocessStudy(ctx, reason, locations[0], remainingWorkQueueUidPaths, Platform.Time); if (reprocessEntry != null) { ctx.Commit(); } return(reprocessEntry != null); } } } } return(false); }
/// <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); }