예제 #1
0
        /// <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;
                }
            }
        }
예제 #3
0
파일: WorkQueue.cs 프로젝트: hksonngan/Xian
        /// <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;
        }
예제 #5
0
        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);
        }
예제 #6
0
        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();
            }
        }
예제 #7
0
        /// <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);
            }
        }
예제 #8
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);
            }
        }
예제 #9
0
        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();
            }
        }
예제 #10
0
        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);
        }
예제 #13
0
        /// <summary>
        /// Migrates the study to new tier
        /// </summary>
        /// <param name="storage"></param>
        /// <param name="newFilesystem"></param>
        private void DoMigrateStudy(StudyStorageLocation storage, ServerFilesystemInfo newFilesystem)
        {
            Platform.CheckForNullReference(storage, "storage");
            Platform.CheckForNullReference(newFilesystem, "newFilesystem");

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            string originalPath = storage.GetStudyPath();

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

            UpdateAverageStatistics(stat);
        }