Exemplo n.º 1
0
        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));
            }
        }
Exemplo n.º 2
0
        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();
                }
            }
        }
        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);
            }
        }
Exemplo n.º 4
0
        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);
            }
        }
Exemplo n.º 5
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();
            }
        }
Exemplo n.º 6
0
        /// <summary>
        /// Releases a lock acquired via <see cref="AcquireReadLock"/>
        /// </summary>
        /// <returns>
        /// <b>true</b> if the study is successfully unlocked.
        /// </returns>
        /// <remarks>
        /// This method is non-blocking. Caller must check the return value to ensure the study has been
        /// successfully unlocked.
        /// </remarks>
        public bool ReleaseReadLock()
        {
            IUpdateContext context =
                PersistentStoreRegistry.GetDefaultStore().OpenUpdateContext(UpdateContextSyncMode.Flush);

            using (context)
            {
                var lockStudyBroker = context.GetBroker <ILockStudy>();
                var parms           = new LockStudyParameters {
                    StudyStorageKey = GetKey(), ReadLock = false
                };
                if (!lockStudyBroker.Execute(parms))
                {
                    return(false);
                }

                context.Commit();
                return(parms.Successful);
            }
        }
Exemplo n.º 7
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);
            }
        }
        /// <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();
            }
        }
        private void RestoreOnlineStudy(RestoreQueue queueItem, string zipFile, string destinationFolder)
        {
            try
            {
                using (var processor = new ServerCommandProcessor("HSM Restore Online Study"))
                {
                    var zipService = Platform.GetService <IZipService>();
                    using (var zipWriter = zipService.OpenWrite(zipFile))
                    {
                        foreach (string file in zipWriter.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.
                    var context =
                        new ServerActionContext(null, _location.FilesystemKey, _hsmArchive.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, _hsmArchive.PartitionArchive.Description);
                        queueItem.FailureDescription = processor.FailureReason;
                        _hsmArchive.UpdateRestoreQueue(queueItem, RestoreQueueStatusEnum.Failed, Platform.Time);
                    }
                    else
                    {
                        // Unlock the Queue Entry and set to complete
                        using (IUpdateContext update = PersistentStoreRegistry.GetDefaultStore().OpenUpdateContext(UpdateContextSyncMode.Flush))
                        {
                            _hsmArchive.UpdateRestoreQueue(update, queueItem, RestoreQueueStatusEnum.Completed, Platform.Time.AddSeconds(60));
                            var studyLock = update.GetBroker <ILockStudy>();
                            var 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,
                                             _hsmArchive.ServerPartition.Description);
                            }

                            update.Commit();

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

                            _location = ReloadStorageLocation();
                            OnStudyRestored(_location);
                        }
                    }
                }
            }
            catch (StudyIntegrityValidationFailure ex)
            {
                // study has been restored but it seems corrupted. Need to reprocess it.
                ReprocessStudy(_location, ex.Message);
            }
            catch (Exception e)
            {
                Platform.Log(LogLevel.Error, e, "Unexpected exception processing restore request for {0} on archive {1}",
                             _location.StudyInstanceUid, _hsmArchive.PartitionArchive.Description);
                queueItem.FailureDescription = e.Message;
                _hsmArchive.UpdateRestoreQueue(queueItem, RestoreQueueStatusEnum.Failed, Platform.Time);
            }
        }
Exemplo n.º 10
0
        public void RestoreNearlineStudy(RestoreQueue queueItem, string zipFile, string studyFolder)
        {
            ServerFilesystemInfo fs = _hsmArchive.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";
                _hsmArchive.UpdateRestoreQueue(queueItem, RestoreQueueStatusEnum.Pending, scheduleTime);
                return;
            }

            string destinationFolder = Path.Combine(fs.Filesystem.FilesystemPath, _hsmArchive.ServerPartition.PartitionFolder);

            StudyStorageLocation restoredLocation = null;

            try
            {
                using (var processor = new ServerCommandProcessor("HSM 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.
                    var context =
                        new ServerActionContext(null, fs.Filesystem.GetKey(), _hsmArchive.ServerPartition,
                                                queueItem.StudyStorageKey)
                    {
                        CommandProcessor = processor
                    };
                    processor.AddCommand(
                        new ApplyRulesCommand(destinationFolder, _studyStorage.StudyInstanceUid, context));

                    // Do the actual insert into the DB
                    var insertStorageCommand = new InsertFilesystemStudyStorageCommand(
                        _hsmArchive.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, _hsmArchive.PartitionArchive.Description);
                        queueItem.FailureDescription = processor.FailureReason;
                        _hsmArchive.UpdateRestoreQueue(queueItem, RestoreQueueStatusEnum.Failed, Platform.Time);
                    }
                    else
                    {
                        restoredLocation = insertStorageCommand.Location;

                        // Unlock the Queue Entry
                        using (
                            IUpdateContext update = PersistentStoreRegistry.GetDefaultStore().OpenUpdateContext(UpdateContextSyncMode.Flush))
                        {
                            bool retVal    = _hsmArchive.UpdateRestoreQueue(update, queueItem, RestoreQueueStatusEnum.Completed, Platform.Time.AddSeconds(60));
                            var  studyLock = update.GetBroker <ILockStudy>();
                            var  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,
                                                  _hsmArchive.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,
                                         _hsmArchive.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, _hsmArchive.PartitionArchive.Description);
                _hsmArchive.UpdateRestoreQueue(queueItem, RestoreQueueStatusEnum.Failed, Platform.Time);
            }
        }
        /// <summary>
        /// Process StudyCompress 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 candidate (lossy or lossless)</param>
        private void ProcessCompressCandidates(IEnumerable <FilesystemQueue> candidateList, FilesystemQueueTypeEnum type)
        {
            using (ServerExecutionContext context = new ServerExecutionContext())
            {
                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;
                    }

                    StudyXml studyXml;
                    try
                    {
                        studyXml = LoadStudyXml(location);
                    }
                    catch (Exception e)
                    {
                        Platform.Log(LogLevel.Error, e, "Skipping compress candidate, unexpected exception loading StudyXml file for {0}",
                                     location.GetStudyPath());
                        continue;
                    }

                    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 Lossless Compress. Reason:{0}. Skipping study ({1})",
                                         lockParms.FailureReason, location.StudyInstanceUid);
                            continue;
                        }

                        scheduledTime = scheduledTime.AddSeconds(3);

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

                        InsertWorkQueueFromFilesystemQueueParameters insertParms = new InsertWorkQueueFromFilesystemQueueParameters();
                        insertParms.WorkQueueTypeEnum       = WorkQueueTypeEnum.CompressStudy;
                        insertParms.FilesystemQueueTypeEnum = FilesystemQueueTypeEnum.LosslessCompress;
                        insertParms.StudyStorageKey         = location.GetKey();
                        insertParms.ServerPartitionKey      = location.ServerPartitionKey;
                        DateTime expirationTime = scheduledTime;
                        insertParms.ScheduledTime         = expirationTime;
                        insertParms.DeleteFilesystemQueue = true;
                        insertParms.Data = queueItem.QueueXml;
                        insertParms.FilesystemQueueTypeEnum = type;
                        insertParms.WorkQueueTypeEnum       = WorkQueueTypeEnum.CompressStudy;

                        try
                        {
                            WorkQueue entry = workQueueInsert.FindOne(insertParms);

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

                            update.Commit();
                            _studiesInserted++;
                        }
                        catch (Exception e)
                        {
                            Platform.Log(LogLevel.Error, e,
                                         "Skipping compress record, unexpected problem inserting 'CompressStudy' record into WorkQueue for Study {0}",
                                         location.StudyInstanceUid);
                            // throw; -- would cause abort of inserts, go ahead and try everything
                        }
                    }
                }
            }
        }
Exemplo n.º 12
0
        /// <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);
        }
Exemplo n.º 13
0
        /// <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);
        }
Exemplo n.º 14
0
        /// <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);
        }
Exemplo n.º 15
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 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();
                    }
                }
            }
        }
Exemplo n.º 16
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();
                    }
                }
            }
        }
Exemplo n.º 17
0
        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);
                }
            }
        }
Exemplo n.º 18
0
        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();
            }
        }