PACS System 0.1.0
PACS DICOM system library
Loading...
Searching...
No Matches
kcenon::pacs::workflow::auto_prefetch_service Class Reference

#include <auto_prefetch_service.h>

Collaboration diagram for kcenon::pacs::workflow::auto_prefetch_service:
Collaboration graph

Public Member Functions

 auto_prefetch_service (storage::index_database &database, const prefetch_service_config &config={})
 Construct auto prefetch service.
 
 auto_prefetch_service (storage::index_database &database, std::shared_ptr< kcenon::thread::thread_pool > thread_pool, const prefetch_service_config &config={})
 Construct auto prefetch service with thread pool.
 
 auto_prefetch_service (storage::index_database &database, std::shared_ptr< kcenon::common::interfaces::IExecutor > executor, const prefetch_service_config &config={})
 Construct auto prefetch service with IExecutor (recommended)
 
 ~auto_prefetch_service ()
 Destructor - ensures graceful shutdown.
 
 auto_prefetch_service (const auto_prefetch_service &)=delete
 Non-copyable.
 
auto_prefetch_serviceoperator= (const auto_prefetch_service &)=delete
 
 auto_prefetch_service (auto_prefetch_service &&)=delete
 Non-movable.
 
auto_prefetch_serviceoperator= (auto_prefetch_service &&)=delete
 
void enable ()
 Enable the prefetch service.
 
void start ()
 Start the prefetch service (alias for enable)
 
void disable (bool wait_for_completion=true)
 Disable/stop the prefetch service.
 
void stop (bool wait_for_completion=true)
 Stop the prefetch service (alias for disable)
 
auto is_enabled () const noexcept -> bool
 Check if the service is enabled/running.
 
auto is_running () const noexcept -> bool
 Check if the service is running (alias for is_enabled)
 
auto prefetch_priors (const std::string &patient_id, std::chrono::days lookback=std::chrono::days{365}) -> prefetch_result
 Manually prefetch prior studies for a patient.
 
void trigger_for_worklist (const std::vector< storage::worklist_item > &worklist_items)
 Trigger prefetch for worklist items.
 
void trigger_cycle ()
 Trigger next cycle immediately.
 
auto run_prefetch_cycle () -> prefetch_result
 Run a prefetch cycle manually.
 
void on_worklist_query (const std::vector< storage::worklist_item > &worklist_items)
 Handle worklist query event.
 
auto get_last_result () const -> std::optional< prefetch_result >
 Get the result of the last prefetch cycle.
 
auto get_cumulative_stats () const -> prefetch_result
 Get cumulative statistics since service started.
 
auto time_until_next_cycle () const -> std::optional< std::chrono::seconds >
 Get the time until the next scheduled prefetch cycle.
 
auto cycles_completed () const noexcept -> std::size_t
 Get the number of cycles completed.
 
auto pending_requests () const noexcept -> std::size_t
 Get the number of pending prefetch requests.
 
void set_prefetch_interval (std::chrono::seconds interval)
 Update the prefetch interval.
 
auto get_prefetch_interval () const noexcept -> std::chrono::seconds
 Get the current prefetch interval.
 
void set_prefetch_criteria (const prefetch_criteria &criteria)
 Update the prefetch criteria.
 
auto get_prefetch_criteria () const noexcept -> const prefetch_criteria &
 Get the current prefetch criteria.
 
void set_cycle_complete_callback (prefetch_service_config::cycle_complete_callback callback)
 Set the cycle complete callback.
 
void set_error_callback (prefetch_service_config::error_callback callback)
 Set the error callback.
 

Private Member Functions

void run_loop ()
 Background thread main loop.
 
auto execute_cycle () -> prefetch_result
 Execute a single prefetch cycle.
 
auto process_request (const prefetch_request &request) -> prefetch_result
 Process a single prefetch request.
 
auto query_prior_studies (const remote_pacs_config &pacs_config, const std::string &patient_id, std::chrono::days lookback) -> std::vector< prior_study_info >
 Query remote PACS for prior studies.
 
auto filter_studies (const std::vector< prior_study_info > &studies, const prefetch_request &request) -> std::vector< prior_study_info >
 Filter prior studies based on criteria.
 
auto study_exists_locally (const std::string &study_uid) -> bool
 Check if study already exists locally.
 
auto prefetch_study (const remote_pacs_config &pacs_config, const prior_study_info &study) -> bool
 Prefetch a single study via C-MOVE.
 
void update_stats (const prefetch_result &result)
 Update cumulative statistics.
 
void queue_request (const prefetch_request &request)
 Add request to queue (deduplicated)
 
auto dequeue_request () -> std::optional< prefetch_request >
 Get next request from queue.
 

Private Attributes

storage::index_databasedatabase_
 Reference to PACS index database.
 
std::shared_ptr< kcenon::thread::thread_pool > thread_pool_
 Thread pool for parallel prefetches (optional, legacy)
 
std::shared_ptr< kcenon::common::interfaces::IExecutor > executor_
 IExecutor for task execution (recommended, Issue #487)
 
prefetch_service_config config_
 Service configuration.
 
std::thread worker_thread_
 Background worker thread.
 
std::mutex mutex_
 Mutex for thread synchronization.
 
std::condition_variable cv_
 Condition variable for sleep/wake.
 
std::atomic< bool > stop_requested_ {false}
 Flag to signal shutdown.
 
std::atomic< bool > enabled_ {false}
 Flag indicating service is enabled.
 
std::atomic< bool > cycle_in_progress_ {false}
 Flag indicating a cycle is in progress.
 
std::queue< prefetch_requestrequest_queue_
 Queue of pending prefetch requests.
 
std::set< std::string > queued_patients_
 Set of patient IDs currently in queue (for deduplication)
 
std::mutex queue_mutex_
 Mutex for request queue.
 
std::optional< prefetch_resultlast_result_
 Last prefetch result.
 
prefetch_result cumulative_stats_
 Cumulative statistics.
 
std::atomic< std::size_t > cycles_count_ {0}
 Number of completed cycles.
 
std::chrono::steady_clock::time_point next_cycle_time_
 Time of next scheduled cycle.
 

Detailed Description

Definition at line 203 of file auto_prefetch_service.h.

Constructor & Destructor Documentation

◆ auto_prefetch_service() [1/5]

kcenon::pacs::workflow::auto_prefetch_service::auto_prefetch_service ( storage::index_database & database,
const prefetch_service_config & config = {} )
explicit

Construct auto prefetch service.

Parameters
databaseReference to the PACS index database for checking existing studies and receiving worklist events
configService configuration

Definition at line 33 of file auto_prefetch_service.cpp.

36 : database_(database)
37 , config_(config) {
39 start();
40 }
41}
storage::index_database & database_
Reference to PACS index database.
prefetch_service_config config_
Service configuration.
void start()
Start the prefetch service (alias for enable)
bool auto_start
Whether to start automatically on construction.
bool enabled
Enable/disable the prefetch service.

References kcenon::pacs::workflow::prefetch_service_config::auto_start, config_, and kcenon::pacs::workflow::prefetch_service_config::enabled.

◆ auto_prefetch_service() [2/5]

kcenon::pacs::workflow::auto_prefetch_service::auto_prefetch_service ( storage::index_database & database,
std::shared_ptr< kcenon::thread::thread_pool > thread_pool,
const prefetch_service_config & config = {} )

Construct auto prefetch service with thread pool.

Parameters
databaseReference to the PACS index database
thread_poolThread pool for parallel prefetch operations
configService configuration

Definition at line 43 of file auto_prefetch_service.cpp.

47 : database_(database)
48 , thread_pool_(std::move(thread_pool))
49 , config_(config) {
51 start();
52 }
53}
std::shared_ptr< kcenon::thread::thread_pool > thread_pool_
Thread pool for parallel prefetches (optional, legacy)

References kcenon::pacs::workflow::prefetch_service_config::auto_start, config_, and kcenon::pacs::workflow::prefetch_service_config::enabled.

◆ auto_prefetch_service() [3/5]

kcenon::pacs::workflow::auto_prefetch_service::auto_prefetch_service ( storage::index_database & database,
std::shared_ptr< kcenon::common::interfaces::IExecutor > executor,
const prefetch_service_config & config = {} )

Construct auto prefetch service with IExecutor (recommended)

This constructor accepts the standardized IExecutor interface from common_system, enabling better testability and decoupling from specific thread pool implementations.

Parameters
databaseReference to the PACS index database
executorIExecutor for task execution (from common_system)
configService configuration
See also
Issue #487 - IExecutor integration

Definition at line 55 of file auto_prefetch_service.cpp.

59 : database_(database)
60 , executor_(std::move(executor))
61 , config_(config) {
63 start();
64 }
65}
std::shared_ptr< kcenon::common::interfaces::IExecutor > executor_
IExecutor for task execution (recommended, Issue #487)

References kcenon::pacs::workflow::prefetch_service_config::auto_start, config_, and kcenon::pacs::workflow::prefetch_service_config::enabled.

◆ ~auto_prefetch_service()

kcenon::pacs::workflow::auto_prefetch_service::~auto_prefetch_service ( )

Destructor - ensures graceful shutdown.

Definition at line 67 of file auto_prefetch_service.cpp.

67 {
68 stop(true);
69}
void stop(bool wait_for_completion=true)
Stop the prefetch service (alias for disable)

References stop().

Here is the call graph for this function:

◆ auto_prefetch_service() [4/5]

kcenon::pacs::workflow::auto_prefetch_service::auto_prefetch_service ( const auto_prefetch_service & )
delete

Non-copyable.

◆ auto_prefetch_service() [5/5]

kcenon::pacs::workflow::auto_prefetch_service::auto_prefetch_service ( auto_prefetch_service && )
delete

Non-movable.

Member Function Documentation

◆ cycles_completed()

auto kcenon::pacs::workflow::auto_prefetch_service::cycles_completed ( ) const -> std::size_t
nodiscardnoexcept

Get the number of cycles completed.

Returns
Total number of completed prefetch cycles

Definition at line 228 of file auto_prefetch_service.cpp.

228 {
229 return cycles_count_.load();
230}
std::atomic< std::size_t > cycles_count_
Number of completed cycles.

References cycles_count_.

◆ dequeue_request()

auto kcenon::pacs::workflow::auto_prefetch_service::dequeue_request ( ) -> std::optional<prefetch_request>
nodiscardprivate

Get next request from queue.

Returns
Optional containing next request, or nullopt if empty

Definition at line 807 of file auto_prefetch_service.cpp.

808 {
809 std::lock_guard<std::mutex> lock(queue_mutex_);
810
811 if (request_queue_.empty()) {
812 return std::nullopt;
813 }
814
815 auto request = std::move(request_queue_.front());
816 request_queue_.pop();
817 queued_patients_.erase(request.patient_id);
818
819 return request;
820}
std::set< std::string > queued_patients_
Set of patient IDs currently in queue (for deduplication)
std::queue< prefetch_request > request_queue_
Queue of pending prefetch requests.
std::mutex queue_mutex_
Mutex for request queue.

◆ disable()

void kcenon::pacs::workflow::auto_prefetch_service::disable ( bool wait_for_completion = true)

Disable/stop the prefetch service.

Gracefully stops the service, waiting for any in-progress prefetch operations to complete.

Parameters
wait_for_completionIf true, waits for current operations

Definition at line 97 of file auto_prefetch_service.cpp.

97 {
98 stop(wait_for_completion);
99}

References stop().

Here is the call graph for this function:

◆ enable()

void kcenon::pacs::workflow::auto_prefetch_service::enable ( )

Enable the prefetch service.

Starts the background prefetch thread and begins monitoring worklist queries for prefetch candidates.

Definition at line 75 of file auto_prefetch_service.cpp.

75 {
76 start();
77}

References start().

Here is the call graph for this function:

◆ execute_cycle()

auto kcenon::pacs::workflow::auto_prefetch_service::execute_cycle ( ) -> prefetch_result
nodiscardprivate

Execute a single prefetch cycle.

Returns
Prefetch result

Definition at line 334 of file auto_prefetch_service.cpp.

334 {
335 prefetch_result cycle_result;
336 cycle_result.timestamp = std::chrono::system_clock::now();
337 auto cycle_start = std::chrono::steady_clock::now();
338
339 // Process all pending requests
340 while (auto request = dequeue_request()) {
341 if (stop_requested_.load()) {
342 break;
343 }
344
345 auto result = process_request(*request);
346 cycle_result += result;
347 }
348
349 cycle_result.duration = std::chrono::duration_cast<std::chrono::milliseconds>(
350 std::chrono::steady_clock::now() - cycle_start);
351
353 "Prefetch cycle completed patients={} studies_prefetched={} studies_failed={} duration_ms={}",
354 cycle_result.patients_processed,
355 cycle_result.studies_prefetched,
356 cycle_result.studies_failed,
357 cycle_result.duration.count());
358
359 // Record metrics
361 "prefetch_cycle_duration_ms",
362 static_cast<double>(cycle_result.duration.count()));
364 "prefetch_studies_total",
365 static_cast<int64_t>(cycle_result.studies_prefetched));
367 "prefetch_failures_total",
368 static_cast<int64_t>(cycle_result.studies_failed));
369
370 return cycle_result;
371}
static void info(kcenon::pacs::compat::format_string< Args... > fmt, Args &&... args)
Log an info-level message.
static void record_histogram(std::string_view name, double value)
Record a histogram sample.
static void increment_counter(std::string_view name, std::int64_t value=1)
Increment a counter metric.
auto process_request(const prefetch_request &request) -> prefetch_result
Process a single prefetch request.
std::atomic< bool > stop_requested_
Flag to signal shutdown.
auto dequeue_request() -> std::optional< prefetch_request >
Get next request from queue.

References kcenon::pacs::workflow::prefetch_result::duration, kcenon::pacs::integration::monitoring_adapter::increment_counter(), kcenon::pacs::integration::logger_adapter::info(), kcenon::pacs::workflow::prefetch_result::patients_processed, kcenon::pacs::integration::monitoring_adapter::record_histogram(), kcenon::pacs::workflow::prefetch_result::studies_failed, kcenon::pacs::workflow::prefetch_result::studies_prefetched, and kcenon::pacs::workflow::prefetch_result::timestamp.

Referenced by run_loop().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ filter_studies()

auto kcenon::pacs::workflow::auto_prefetch_service::filter_studies ( const std::vector< prior_study_info > & studies,
const prefetch_request & request ) -> std::vector<prior_study_info>
nodiscardprivate

Filter prior studies based on criteria.

Parameters
studiesList of candidate studies
requestOriginal prefetch request
Returns
Filtered list of studies to prefetch

Definition at line 606 of file auto_prefetch_service.cpp.

608 {
609
610 std::vector<prior_study_info> filtered;
611
612 for (const auto& study : studies) {
613 // Apply modality filters
614 bool modality_match = true;
615
616 // Check include list (if not empty, study must match)
617 if (!config_.criteria.include_modalities.empty()) {
618 modality_match = false;
619 for (const auto& mod : study.modalities) {
620 if (config_.criteria.include_modalities.count(mod) > 0) {
621 modality_match = true;
622 break;
623 }
624 }
625 }
626
627 // Check exclude list
628 if (modality_match && !config_.criteria.exclude_modalities.empty()) {
629 for (const auto& mod : study.modalities) {
630 if (config_.criteria.exclude_modalities.count(mod) > 0) {
631 modality_match = false;
632 break;
633 }
634 }
635 }
636
637 if (!modality_match) {
638 continue;
639 }
640
641 // Apply body part filter
642 if (!config_.criteria.include_body_parts.empty()) {
644 study.body_part_examined) == 0) {
645 continue;
646 }
647 }
648
649 filtered.push_back(study);
650 }
651
652 // Sort by preference if enabled
655 std::ranges::sort(filtered, [&](const auto& a, const auto& b) {
656 int score_a = 0;
657 int score_b = 0;
658
660 if (a.modalities.count(request.scheduled_modality) > 0) {
661 score_a += 10;
662 }
663 if (b.modalities.count(request.scheduled_modality) > 0) {
664 score_b += 10;
665 }
666 }
667
669 if (a.body_part_examined == request.scheduled_body_part) {
670 score_a += 5;
671 }
672 if (b.body_part_examined == request.scheduled_body_part) {
673 score_b += 5;
674 }
675 }
676
677 // Higher score first, then by date (newer first)
678 if (score_a != score_b) {
679 return score_a > score_b;
680 }
681 return a.study_date > b.study_date;
682 });
683 }
684
685 // Limit results
687 filtered.size() > config_.criteria.max_studies_per_patient) {
689 }
690
691 return filtered;
692}
bool prefer_same_body_part
Prefer same body part as scheduled procedure.
bool prefer_same_modality
Prefer same modality as scheduled procedure.
std::set< std::string > exclude_modalities
Modalities to exclude.
std::set< std::string > include_modalities
Modalities to include (empty = all modalities)
std::size_t max_studies_per_patient
Maximum number of prior studies to prefetch per patient.
std::set< std::string > include_body_parts
Only prefetch studies with specific body parts.
prefetch_criteria criteria
Selection criteria for prior studies.

◆ get_cumulative_stats()

auto kcenon::pacs::workflow::auto_prefetch_service::get_cumulative_stats ( ) const -> prefetch_result
nodiscard

Get cumulative statistics since service started.

Returns
Cumulative prefetch statistics

Definition at line 207 of file auto_prefetch_service.cpp.

207 {
208 std::lock_guard<std::mutex> lock(mutex_);
209 return cumulative_stats_;
210}
prefetch_result cumulative_stats_
Cumulative statistics.
std::mutex mutex_
Mutex for thread synchronization.

References cumulative_stats_, and mutex_.

◆ get_last_result()

auto kcenon::pacs::workflow::auto_prefetch_service::get_last_result ( ) const -> std::optional<prefetch_result>
nodiscard

Get the result of the last prefetch cycle.

Returns
Last prefetch result, or nullopt if no cycle has run

Definition at line 201 of file auto_prefetch_service.cpp.

202 {
203 std::lock_guard<std::mutex> lock(mutex_);
204 return last_result_;
205}
std::optional< prefetch_result > last_result_
Last prefetch result.

References last_result_, and mutex_.

◆ get_prefetch_criteria()

auto kcenon::pacs::workflow::auto_prefetch_service::get_prefetch_criteria ( ) const -> const prefetch_criteria&
nodiscardnoexcept

Get the current prefetch criteria.

Returns
Current selection criteria

Definition at line 259 of file auto_prefetch_service.cpp.

260 {
261 std::lock_guard<std::mutex> lock(mutex_);
262 return config_.criteria;
263}

References config_, kcenon::pacs::workflow::prefetch_service_config::criteria, and mutex_.

◆ get_prefetch_interval()

auto kcenon::pacs::workflow::auto_prefetch_service::get_prefetch_interval ( ) const -> std::chrono::seconds
nodiscardnoexcept

Get the current prefetch interval.

Returns
Current interval between prefetch cycles

Definition at line 247 of file auto_prefetch_service.cpp.

248 {
249 std::lock_guard<std::mutex> lock(mutex_);
251}
std::chrono::seconds prefetch_interval
Interval between prefetch cycles (default: 5 minutes)

References config_, mutex_, and kcenon::pacs::workflow::prefetch_service_config::prefetch_interval.

◆ is_enabled()

auto kcenon::pacs::workflow::auto_prefetch_service::is_enabled ( ) const -> bool
nodiscardnoexcept

Check if the service is enabled/running.

Returns
true if the service is actively prefetching

Definition at line 120 of file auto_prefetch_service.cpp.

120 {
121 return enabled_.load();
122}
std::atomic< bool > enabled_
Flag indicating service is enabled.

References enabled_.

Referenced by is_running().

Here is the caller graph for this function:

◆ is_running()

auto kcenon::pacs::workflow::auto_prefetch_service::is_running ( ) const -> bool
nodiscardnoexcept

Check if the service is running (alias for is_enabled)

Returns
true if the service is actively prefetching

Definition at line 124 of file auto_prefetch_service.cpp.

124 {
125 return is_enabled();
126}
auto is_enabled() const noexcept -> bool
Check if the service is enabled/running.

References is_enabled().

Here is the call graph for this function:

◆ on_worklist_query()

void kcenon::pacs::workflow::auto_prefetch_service::on_worklist_query ( const std::vector< storage::worklist_item > & worklist_items)

Handle worklist query event.

Called when a worklist query is processed. Extracts patient information and queues prefetch requests for each unique patient.

Parameters
worklist_itemsThe worklist items returned by the query

Definition at line 170 of file auto_prefetch_service.cpp.

171 {
172
173 for (const auto& item : worklist_items) {
174 if (item.patient_id.empty()) {
175 continue;
176 }
177
178 prefetch_request request;
179 request.patient_id = item.patient_id;
180 request.patient_name = item.patient_name;
181 request.scheduled_modality = item.modality;
182 request.scheduled_study_uid = item.study_uid;
183 request.request_time = std::chrono::system_clock::now();
184
185 queue_request(request);
186 }
187
188 // Wake up worker if there are new requests
189 cv_.notify_one();
190
192 "Queued prefetch requests from worklist worklist_items={} queue_size={}",
193 worklist_items.size(),
195}
static void debug(kcenon::pacs::compat::format_string< Args... > fmt, Args &&... args)
Log a debug-level message.
std::condition_variable cv_
Condition variable for sleep/wake.
void queue_request(const prefetch_request &request)
Add request to queue (deduplicated)
auto pending_requests() const noexcept -> std::size_t
Get the number of pending prefetch requests.
constexpr dicom_tag item
Item.

References cv_, kcenon::pacs::integration::logger_adapter::debug(), kcenon::pacs::workflow::prefetch_request::patient_id, kcenon::pacs::workflow::prefetch_request::patient_name, pending_requests(), queue_request(), kcenon::pacs::workflow::prefetch_request::request_time, kcenon::pacs::workflow::prefetch_request::scheduled_modality, and kcenon::pacs::workflow::prefetch_request::scheduled_study_uid.

Referenced by trigger_for_worklist().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ operator=() [1/2]

auto_prefetch_service & kcenon::pacs::workflow::auto_prefetch_service::operator= ( auto_prefetch_service && )
delete

◆ operator=() [2/2]

auto_prefetch_service & kcenon::pacs::workflow::auto_prefetch_service::operator= ( const auto_prefetch_service & )
delete

◆ pending_requests()

auto kcenon::pacs::workflow::auto_prefetch_service::pending_requests ( ) const -> std::size_t
nodiscardnoexcept

Get the number of pending prefetch requests.

Returns
Number of patients waiting to be prefetched

Definition at line 232 of file auto_prefetch_service.cpp.

232 {
233 std::lock_guard<std::mutex> lock(queue_mutex_);
234 return request_queue_.size();
235}

References queue_mutex_, and request_queue_.

Referenced by on_worklist_query().

Here is the caller graph for this function:

◆ prefetch_priors()

auto kcenon::pacs::workflow::auto_prefetch_service::prefetch_priors ( const std::string & patient_id,
std::chrono::days lookback = std::chrono::days{365} ) -> prefetch_result
nodiscard

Manually prefetch prior studies for a patient.

Immediately triggers a prefetch operation for the specified patient, regardless of whether the service is enabled or the patient is in the worklist.

Parameters
patient_idThe patient ID to prefetch priors for
lookbackLookback period (default: use config value)
Returns
Result with count of prefetched studies, or error

Definition at line 132 of file auto_prefetch_service.cpp.

134 {
135
136 prefetch_request request;
137 request.patient_id = patient_id;
138 request.request_time = std::chrono::system_clock::now();
139
140 // Override criteria lookback if specified
141 auto saved_lookback = config_.criteria.lookback_period;
143
144 auto result = process_request(request);
145
146 config_.criteria.lookback_period = saved_lookback;
147
148 return result;
149}
constexpr dicom_tag patient_id
Patient ID.
std::chrono::days lookback_period
Lookback period for prior studies (default: 365 days)

References kcenon::pacs::workflow::prefetch_request::patient_id, and kcenon::pacs::workflow::prefetch_request::request_time.

◆ prefetch_study()

auto kcenon::pacs::workflow::auto_prefetch_service::prefetch_study ( const remote_pacs_config & pacs_config,
const prior_study_info & study ) -> bool
nodiscardprivate

Prefetch a single study via C-MOVE.

Parameters
pacs_configRemote PACS configuration
studyStudy information
Returns
true if prefetch was successful

Definition at line 701 of file auto_prefetch_service.cpp.

703 {
704
706 "Prefetching study study_uid={} patient_id={} remote_pacs={}",
707 study.study_instance_uid,
708 study.patient_id,
709 pacs_config.ae_title);
710
711 try {
712 // Configure association for C-MOVE
713 network::association_config assoc_config;
714 assoc_config.calling_ae_title = pacs_config.local_ae_title;
715 assoc_config.called_ae_title = pacs_config.ae_title;
716 assoc_config.proposed_contexts.push_back({
717 1,
719 {"1.2.840.10008.1.2.1", "1.2.840.10008.1.2"}
720 });
721
722 // Connect to remote PACS
723 auto connect_result = network::association::connect(
724 pacs_config.host,
725 pacs_config.port,
726 assoc_config,
727 std::chrono::duration_cast<network::association::duration>(
728 pacs_config.connection_timeout));
729
730 if (connect_result.is_err()) {
732 "Failed to connect to remote PACS for C-MOVE remote_pacs={} error={}",
733 pacs_config.ae_title,
734 connect_result.error().message);
735 return false;
736 }
737
738 auto assoc = std::move(connect_result.value());
739
740 // Configure retrieve SCU with our local AE as move destination
741 services::retrieve_scu_config retrieve_config;
742 retrieve_config.mode = services::retrieve_mode::c_move;
743 retrieve_config.model = services::query_model::study_root;
744 retrieve_config.level = services::query_level::study;
745 retrieve_config.move_destination = pacs_config.local_ae_title;
746 retrieve_config.timeout = std::chrono::duration_cast<std::chrono::milliseconds>(
747 pacs_config.association_timeout);
748
749 services::retrieve_scu scu(retrieve_config);
750 auto move_result = scu.retrieve_study(
751 assoc, study.study_instance_uid);
752
753 // Release association
754 (void)assoc.release();
755
756 if (move_result.is_ok() && move_result.value().is_success()) {
758 "Successfully prefetched study study_uid={} completed={} remote_pacs={}",
759 study.study_instance_uid,
760 move_result.value().completed,
761 pacs_config.ae_title);
762 return true;
763 }
764
765 if (move_result.is_err()) {
767 "C-MOVE failed study_uid={} remote_pacs={} error={}",
768 study.study_instance_uid,
769 pacs_config.ae_title,
770 move_result.error().message);
771 } else if (move_result.value().has_failures()) {
773 "C-MOVE completed with failures study_uid={} completed={} failed={} remote_pacs={}",
774 study.study_instance_uid,
775 move_result.value().completed,
776 move_result.value().failed,
777 pacs_config.ae_title);
778 }
779
780 return false;
781 } catch (const std::exception& e) {
783 "Exception during prefetch study_uid={} remote_pacs={} error={}",
784 study.study_instance_uid,
785 pacs_config.ae_title,
786 e.what());
787 return false;
788 }
789}
static void error(kcenon::pacs::compat::format_string< Args... > fmt, Args &&... args)
Log an error-level message.
static Result< association > connect(const std::string &host, uint16_t port, const association_config &config, duration timeout=default_timeout)
Initiate an SCU association to a remote SCP.
@ c_move
Request SCP to send to third party (requires move destination)
constexpr std::string_view study_root_move_sop_class_uid
Study Root Query/Retrieve Information Model - MOVE.
@ study
Study level - query study information.
@ study_root
Study Root Query/Retrieve Information Model.

References kcenon::pacs::services::c_move, kcenon::pacs::network::association_config::called_ae_title, kcenon::pacs::network::association_config::calling_ae_title, kcenon::pacs::network::association::connect(), kcenon::pacs::integration::logger_adapter::debug(), kcenon::pacs::integration::logger_adapter::error(), kcenon::pacs::integration::logger_adapter::info(), kcenon::pacs::services::retrieve_scu_config::level, kcenon::pacs::services::retrieve_scu_config::mode, kcenon::pacs::services::retrieve_scu_config::model, kcenon::pacs::services::retrieve_scu_config::move_destination, kcenon::pacs::network::association_config::proposed_contexts, kcenon::pacs::services::retrieve_scu::retrieve_study(), kcenon::pacs::services::study, kcenon::pacs::services::study_root, kcenon::pacs::services::study_root_move_sop_class_uid, and kcenon::pacs::services::retrieve_scu_config::timeout.

Here is the call graph for this function:

◆ process_request()

auto kcenon::pacs::workflow::auto_prefetch_service::process_request ( const prefetch_request & request) -> prefetch_result
nodiscardprivate

Process a single prefetch request.

Parameters
requestThe prefetch request to process
Returns
Prefetch result for this request

Definition at line 373 of file auto_prefetch_service.cpp.

374 {
375
376 prefetch_result result;
377 result.patients_processed = 1;
378 result.timestamp = std::chrono::system_clock::now();
379 auto start_time = std::chrono::steady_clock::now();
380
382 "Processing prefetch request patient_id={} scheduled_modality={}",
383 request.patient_id,
384 request.scheduled_modality);
385
386 // Query each remote PACS for prior studies
387 for (const auto& pacs : config_.remote_pacs) {
388 if (!pacs.is_valid()) {
389 continue;
390 }
391
392 // Query for prior studies
394 pacs,
395 request.patient_id,
397
398 // Filter based on criteria
399 auto filtered_studies = filter_studies(prior_studies, request);
400
401 // Prefetch each study
402 for (const auto& study : filtered_studies) {
403 // Skip if already present locally
404 if (study_exists_locally(study.study_instance_uid)) {
405 ++result.studies_already_present;
406 continue;
407 }
408
409 // Skip the scheduled study itself
410 if (study.study_instance_uid == request.scheduled_study_uid) {
411 continue;
412 }
413
414 // Attempt prefetch
415 bool success = prefetch_study(pacs, study);
416
417 if (success) {
418 ++result.studies_prefetched;
419 result.series_prefetched += study.number_of_series;
420 result.instances_prefetched += study.number_of_instances;
421
424 request.patient_id, study, true, "");
425 }
426 } else {
427 ++result.studies_failed;
428
431 request.patient_id,
432 study.study_instance_uid,
433 "Failed to prefetch study");
434 }
435 }
436
437 // Check rate limiting
439 auto elapsed = std::chrono::steady_clock::now() - start_time;
440 auto elapsed_minutes =
441 std::chrono::duration_cast<std::chrono::minutes>(elapsed)
442 .count();
443 if (elapsed_minutes < 1) {
444 auto prefetched_this_minute =
445 result.studies_prefetched + result.studies_failed;
446 if (prefetched_this_minute >= config_.rate_limit_per_minute) {
447 // Wait until the next minute
448 std::this_thread::sleep_for(
449 std::chrono::seconds(60) - elapsed);
450 }
451 }
452 }
453 }
454 }
455
456 result.duration = std::chrono::duration_cast<std::chrono::milliseconds>(
457 std::chrono::steady_clock::now() - start_time);
458
459 return result;
460}
auto query_prior_studies(const remote_pacs_config &pacs_config, const std::string &patient_id, std::chrono::days lookback) -> std::vector< prior_study_info >
Query remote PACS for prior studies.
auto filter_studies(const std::vector< prior_study_info > &studies, const prefetch_request &request) -> std::vector< prior_study_info >
Filter prior studies based on criteria.
auto study_exists_locally(const std::string &study_uid) -> bool
Check if study already exists locally.
auto prefetch_study(const remote_pacs_config &pacs_config, const prior_study_info &study) -> bool
Prefetch a single study via C-MOVE.
@ prior_studies
Fetch prior studies for patient.
std::size_t rate_limit_per_minute
Rate limit: maximum prefetches per minute (0 = unlimited)
std::vector< remote_pacs_config > remote_pacs
Remote PACS configurations (can prefetch from multiple sources)

References kcenon::pacs::integration::logger_adapter::debug(), kcenon::pacs::workflow::prefetch_result::duration, kcenon::pacs::workflow::prefetch_result::instances_prefetched, kcenon::pacs::workflow::prefetch_result::patients_processed, kcenon::pacs::workflow::prefetch_result::series_prefetched, kcenon::pacs::workflow::prefetch_result::studies_already_present, kcenon::pacs::workflow::prefetch_result::studies_failed, kcenon::pacs::workflow::prefetch_result::studies_prefetched, and kcenon::pacs::workflow::prefetch_result::timestamp.

Here is the call graph for this function:

◆ query_prior_studies()

auto kcenon::pacs::workflow::auto_prefetch_service::query_prior_studies ( const remote_pacs_config & pacs_config,
const std::string & patient_id,
std::chrono::days lookback ) -> std::vector<prior_study_info>
nodiscardprivate

Query remote PACS for prior studies.

Parameters
pacs_configRemote PACS configuration
patient_idPatient ID to query
lookbackLookback period
Returns
Vector of prior study information

Definition at line 462 of file auto_prefetch_service.cpp.

465 {
466
467 std::vector<prior_study_info> results;
468
469 // Calculate date range
470 auto now = std::chrono::system_clock::now();
471 auto from_time = now - lookback;
472
473 // Format dates as YYYYMMDD
474 auto format_date = [](std::chrono::system_clock::time_point tp) {
475 auto time_t = std::chrono::system_clock::to_time_t(tp);
476 std::tm tm = *std::localtime(&time_t);
477 char buffer[9];
478 std::strftime(buffer, sizeof(buffer), "%Y%m%d", &tm);
479 return std::string(buffer);
480 };
481
482 std::string from_date = format_date(from_time);
483 std::string to_date = format_date(now);
484
486 "Querying prior studies remote_pacs={} patient_id={} from_date={} to_date={}",
487 pacs_config.ae_title,
488 patient_id,
489 from_date,
490 to_date);
491
492 try {
493 // Configure association for C-FIND
494 network::association_config assoc_config;
495 assoc_config.calling_ae_title = pacs_config.local_ae_title;
496 assoc_config.called_ae_title = pacs_config.ae_title;
497 assoc_config.proposed_contexts.push_back({
498 1,
500 {"1.2.840.10008.1.2.1", "1.2.840.10008.1.2"}
501 });
502
503 // Connect to remote PACS
504 auto connect_result = network::association::connect(
505 pacs_config.host,
506 pacs_config.port,
507 assoc_config,
508 std::chrono::duration_cast<network::association::duration>(
509 pacs_config.connection_timeout));
510
511 if (connect_result.is_err()) {
513 "Failed to connect to remote PACS for C-FIND remote_pacs={} error={}",
514 pacs_config.ae_title,
515 connect_result.error().message);
516 return results;
517 }
518
519 auto assoc = std::move(connect_result.value());
520
521 // Build query keys
522 services::study_query_keys keys;
523 keys.patient_id = patient_id;
524 keys.study_date = from_date + "-" + to_date;
525
526 // Execute C-FIND query
527 services::query_scu_config query_config;
528 query_config.model = services::query_model::study_root;
529 query_config.level = services::query_level::study;
530 query_config.timeout = std::chrono::duration_cast<std::chrono::milliseconds>(
531 pacs_config.association_timeout);
532
533 services::query_scu scu(query_config);
534 auto find_result = scu.find_studies(assoc, keys);
535
536 if (find_result.is_ok() && find_result.value().is_success()) {
537 for (const auto& dataset : find_result.value().matches) {
538 prior_study_info info;
539 info.study_instance_uid =
540 dataset.get_string(core::tags::study_instance_uid);
541 info.patient_id = patient_id;
542 info.patient_name =
543 dataset.get_string(core::tags::patient_name);
544 info.study_date =
545 dataset.get_string(core::tags::study_date);
546 info.study_description =
547 dataset.get_string(core::tags::study_description);
548
549 // Parse modalities in study (backslash-separated)
550 auto modalities_str =
551 dataset.get_string(core::tags::modalities_in_study);
552 if (!modalities_str.empty()) {
553 std::istringstream ss(modalities_str);
554 std::string mod;
555 while (std::getline(ss, mod, '\\')) {
556 if (!mod.empty()) {
557 info.modalities.insert(mod);
558 }
559 }
560 }
561
562 // Parse numeric fields
563 auto num_series_str = dataset.get_string(
565 if (!num_series_str.empty()) {
566 try {
567 info.number_of_series = std::stoull(num_series_str);
568 } catch (...) {}
569 }
570
571 auto num_instances_str = dataset.get_string(
573 if (!num_instances_str.empty()) {
574 try {
575 info.number_of_instances = std::stoull(num_instances_str);
576 } catch (...) {}
577 }
578
579 results.push_back(std::move(info));
580 }
581
583 "C-FIND query returned matches={} remote_pacs={} patient_id={}",
584 results.size(),
585 pacs_config.ae_title,
586 patient_id);
587 } else if (find_result.is_err()) {
589 "C-FIND query failed remote_pacs={} error={}",
590 pacs_config.ae_title,
591 find_result.error().message);
592 }
593
594 // Release association
595 (void)assoc.release();
596 } catch (const std::exception& e) {
598 "Exception querying prior studies remote_pacs={} error={}",
599 pacs_config.ae_title,
600 e.what());
601 }
602
603 return results;
604}
constexpr dicom_tag number_of_study_related_series
Number of Study Related Series.
constexpr dicom_tag modalities_in_study
Modalities in Study.
constexpr dicom_tag study_description
Study Description.
constexpr dicom_tag number_of_study_related_instances
Number of Study Related Instances.
constexpr dicom_tag study_instance_uid
Study Instance UID.
constexpr dicom_tag patient_name
Patient's Name.
constexpr dicom_tag study_date
Study Date.
constexpr std::string_view study_root_find_sop_class_uid
Study Root Query/Retrieve Information Model - FIND.
Definition query_scp.h:42

References kcenon::pacs::network::association_config::called_ae_title, kcenon::pacs::network::association_config::calling_ae_title, kcenon::pacs::network::association::connect(), kcenon::pacs::integration::logger_adapter::debug(), kcenon::pacs::integration::logger_adapter::error(), kcenon::pacs::services::query_scu::find_studies(), kcenon::pacs::services::query_scu_config::level, kcenon::pacs::core::tags::modalities_in_study, kcenon::pacs::services::query_scu_config::model, kcenon::pacs::core::tags::number_of_study_related_instances, kcenon::pacs::core::tags::number_of_study_related_series, kcenon::pacs::services::study_query_keys::patient_id, kcenon::pacs::core::tags::patient_name, kcenon::pacs::network::association_config::proposed_contexts, kcenon::pacs::services::study, kcenon::pacs::core::tags::study_date, kcenon::pacs::services::study_query_keys::study_date, kcenon::pacs::core::tags::study_description, kcenon::pacs::core::tags::study_instance_uid, kcenon::pacs::services::study_root, kcenon::pacs::services::study_root_find_sop_class_uid, and kcenon::pacs::services::query_scu_config::timeout.

Here is the call graph for this function:

◆ queue_request()

void kcenon::pacs::workflow::auto_prefetch_service::queue_request ( const prefetch_request & request)
private

Add request to queue (deduplicated)

Parameters
requestThe prefetch request to queue

Definition at line 795 of file auto_prefetch_service.cpp.

795 {
796 std::lock_guard<std::mutex> lock(queue_mutex_);
797
798 // Deduplicate by patient ID
799 if (queued_patients_.count(request.patient_id) > 0) {
800 return;
801 }
802
803 request_queue_.push(request);
804 queued_patients_.insert(request.patient_id);
805}

References kcenon::pacs::workflow::prefetch_request::patient_id, queue_mutex_, queued_patients_, and request_queue_.

Referenced by on_worklist_query().

Here is the caller graph for this function:

◆ run_loop()

void kcenon::pacs::workflow::auto_prefetch_service::run_loop ( )
private

Background thread main loop.

Definition at line 281 of file auto_prefetch_service.cpp.

281 {
282 integration::logger_adapter::debug("Prefetch service worker thread started");
283
284 while (!stop_requested_.load()) {
285 std::unique_lock<std::mutex> lock(mutex_);
286
287 // Wait until next cycle time or until woken up
288 auto wait_until = next_cycle_time_;
289 cv_.wait_until(lock, wait_until, [this]() {
290 return stop_requested_.load() ||
291 std::chrono::steady_clock::now() >= next_cycle_time_ ||
292 !request_queue_.empty();
293 });
294
295 if (stop_requested_.load()) {
296 break;
297 }
298
299 // Check if we should run a cycle
300 auto now = std::chrono::steady_clock::now();
301 bool should_run_cycle = (now >= next_cycle_time_) ||
302 (!request_queue_.empty());
303
304 if (should_run_cycle) {
305 lock.unlock();
306
307 cycle_in_progress_.store(true);
308 auto result = execute_cycle();
309 cycle_in_progress_.store(false);
310
311 lock.lock();
312
313 // Update last result
314 last_result_ = result;
315 update_stats(result);
317
318 // Schedule next cycle
319 next_cycle_time_ = std::chrono::steady_clock::now() +
321
322 // Invoke callback
324 lock.unlock();
326 lock.lock();
327 }
328 }
329 }
330
331 integration::logger_adapter::debug("Prefetch service worker thread stopped");
332}
std::atomic< bool > cycle_in_progress_
Flag indicating a cycle is in progress.
void update_stats(const prefetch_result &result)
Update cumulative statistics.
auto execute_cycle() -> prefetch_result
Execute a single prefetch cycle.
std::chrono::steady_clock::time_point next_cycle_time_
Time of next scheduled cycle.

References config_, cv_, cycle_in_progress_, cycles_count_, kcenon::pacs::integration::logger_adapter::debug(), execute_cycle(), last_result_, mutex_, next_cycle_time_, kcenon::pacs::workflow::prefetch_service_config::on_cycle_complete, kcenon::pacs::workflow::prefetch_service_config::prefetch_interval, request_queue_, stop_requested_, and update_stats().

Referenced by start().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ run_prefetch_cycle()

auto kcenon::pacs::workflow::auto_prefetch_service::run_prefetch_cycle ( ) -> prefetch_result
nodiscard

Run a prefetch cycle manually.

Executes a complete prefetch cycle for all queued patients. Can be called whether the service is enabled or not.

Returns
Prefetch result with statistics

Definition at line 162 of file auto_prefetch_service.cpp.

162 {
163 return execute_cycle();
164}

◆ set_cycle_complete_callback()

void kcenon::pacs::workflow::auto_prefetch_service::set_cycle_complete_callback ( prefetch_service_config::cycle_complete_callback callback)

Set the cycle complete callback.

Parameters
callbackFunction called after each prefetch cycle

Definition at line 265 of file auto_prefetch_service.cpp.

266 {
267 std::lock_guard<std::mutex> lock(mutex_);
268 config_.on_cycle_complete = std::move(callback);
269}

References config_, mutex_, and kcenon::pacs::workflow::prefetch_service_config::on_cycle_complete.

◆ set_error_callback()

void kcenon::pacs::workflow::auto_prefetch_service::set_error_callback ( prefetch_service_config::error_callback callback)

Set the error callback.

Parameters
callbackFunction called when a prefetch fails

Definition at line 271 of file auto_prefetch_service.cpp.

272 {
273 std::lock_guard<std::mutex> lock(mutex_);
274 config_.on_prefetch_error = std::move(callback);
275}

References config_, mutex_, and kcenon::pacs::workflow::prefetch_service_config::on_prefetch_error.

◆ set_prefetch_criteria()

void kcenon::pacs::workflow::auto_prefetch_service::set_prefetch_criteria ( const prefetch_criteria & criteria)

Update the prefetch criteria.

Parameters
criteriaNew selection criteria for prior studies

Definition at line 253 of file auto_prefetch_service.cpp.

254 {
255 std::lock_guard<std::mutex> lock(mutex_);
256 config_.criteria = criteria;
257}

References config_, kcenon::pacs::workflow::prefetch_service_config::criteria, and mutex_.

◆ set_prefetch_interval()

void kcenon::pacs::workflow::auto_prefetch_service::set_prefetch_interval ( std::chrono::seconds interval)

Update the prefetch interval.

Parameters
intervalNew interval between prefetch cycles
Note
Takes effect at the next cycle

Definition at line 241 of file auto_prefetch_service.cpp.

242 {
243 std::lock_guard<std::mutex> lock(mutex_);
244 config_.prefetch_interval = interval;
245}

References config_, mutex_, and kcenon::pacs::workflow::prefetch_service_config::prefetch_interval.

◆ start()

void kcenon::pacs::workflow::auto_prefetch_service::start ( )

Start the prefetch service (alias for enable)

Definition at line 79 of file auto_prefetch_service.cpp.

79 {
80 if (enabled_.exchange(true)) {
81 return; // Already enabled
82 }
83
84 stop_requested_.store(false);
85 next_cycle_time_ = std::chrono::steady_clock::now();
86
87 worker_thread_ = std::thread([this]() {
88 run_loop();
89 });
90
92 "Auto prefetch service started interval_seconds={} max_concurrent={}",
95}
std::thread worker_thread_
Background worker thread.
std::size_t max_concurrent_prefetches
Maximum concurrent prefetch operations.

References config_, enabled_, kcenon::pacs::integration::logger_adapter::info(), kcenon::pacs::workflow::prefetch_service_config::max_concurrent_prefetches, next_cycle_time_, kcenon::pacs::workflow::prefetch_service_config::prefetch_interval, run_loop(), stop_requested_, and worker_thread_.

Referenced by enable().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ stop()

void kcenon::pacs::workflow::auto_prefetch_service::stop ( bool wait_for_completion = true)

Stop the prefetch service (alias for disable)

Parameters
wait_for_completionIf true, waits for current operations

Definition at line 101 of file auto_prefetch_service.cpp.

101 {
102 if (!enabled_.exchange(false)) {
103 return; // Already disabled
104 }
105
106 stop_requested_.store(true);
107
108 // Wake up the worker thread
109 cv_.notify_all();
110
111 if (wait_for_completion && worker_thread_.joinable()) {
112 worker_thread_.join();
113 } else if (worker_thread_.joinable()) {
114 worker_thread_.detach();
115 }
116
117 integration::logger_adapter::info("Auto prefetch service stopped");
118}

References cv_, enabled_, kcenon::pacs::integration::logger_adapter::info(), stop_requested_, and worker_thread_.

Referenced by disable(), and ~auto_prefetch_service().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ study_exists_locally()

auto kcenon::pacs::workflow::auto_prefetch_service::study_exists_locally ( const std::string & study_uid) -> bool
nodiscardprivate

Check if study already exists locally.

Parameters
study_uidStudy Instance UID
Returns
true if study is already in local storage

Definition at line 694 of file auto_prefetch_service.cpp.

695 {
696 // Query local database to check if study exists
697 auto study_record = database_.find_study(study_uid);
698 return study_record.has_value();
699}
auto find_study(std::string_view study_uid) const -> std::optional< study_record >
Find a study by Study Instance UID.

◆ time_until_next_cycle()

auto kcenon::pacs::workflow::auto_prefetch_service::time_until_next_cycle ( ) const -> std::optional<std::chrono::seconds>
nodiscard

Get the time until the next scheduled prefetch cycle.

Returns
Duration until next cycle, or nullopt if not scheduled

Definition at line 212 of file auto_prefetch_service.cpp.

213 {
214 if (!enabled_.load()) {
215 return std::nullopt;
216 }
217
218 std::lock_guard<std::mutex> lock(mutex_);
219 auto now = std::chrono::steady_clock::now();
220 if (next_cycle_time_ <= now) {
221 return std::chrono::seconds{0};
222 }
223
224 return std::chrono::duration_cast<std::chrono::seconds>(
225 next_cycle_time_ - now);
226}

References enabled_, mutex_, and next_cycle_time_.

◆ trigger_cycle()

void kcenon::pacs::workflow::auto_prefetch_service::trigger_cycle ( )

Trigger next cycle immediately.

Wakes up the background thread to run a prefetch cycle immediately, without waiting for the scheduled interval.

Definition at line 156 of file auto_prefetch_service.cpp.

156 {
157 std::lock_guard<std::mutex> lock(mutex_);
158 next_cycle_time_ = std::chrono::steady_clock::now();
159 cv_.notify_one();
160}

References cv_, mutex_, and next_cycle_time_.

◆ trigger_for_worklist()

void kcenon::pacs::workflow::auto_prefetch_service::trigger_for_worklist ( const std::vector< storage::worklist_item > & worklist_items)

Trigger prefetch for worklist items.

Queues prefetch requests for all patients in the provided worklist items. Useful for batch prefetching.

Parameters
worklist_itemsVector of worklist items to prefetch for

Definition at line 151 of file auto_prefetch_service.cpp.

152 {
153 on_worklist_query(worklist_items);
154}
void on_worklist_query(const std::vector< storage::worklist_item > &worklist_items)
Handle worklist query event.

References on_worklist_query().

Here is the call graph for this function:

◆ update_stats()

void kcenon::pacs::workflow::auto_prefetch_service::update_stats ( const prefetch_result & result)
private

Update cumulative statistics.

Parameters
resultResult from latest operation

Definition at line 791 of file auto_prefetch_service.cpp.

791 {
792 cumulative_stats_ += result;
793}

References cumulative_stats_.

Referenced by run_loop().

Here is the caller graph for this function:

Member Data Documentation

◆ config_

◆ cumulative_stats_

prefetch_result kcenon::pacs::workflow::auto_prefetch_service::cumulative_stats_
private

Cumulative statistics.

Definition at line 606 of file auto_prefetch_service.h.

Referenced by get_cumulative_stats(), and update_stats().

◆ cv_

std::condition_variable kcenon::pacs::workflow::auto_prefetch_service::cv_
private

Condition variable for sleep/wake.

Definition at line 582 of file auto_prefetch_service.h.

Referenced by on_worklist_query(), run_loop(), stop(), and trigger_cycle().

◆ cycle_in_progress_

std::atomic<bool> kcenon::pacs::workflow::auto_prefetch_service::cycle_in_progress_ {false}
private

Flag indicating a cycle is in progress.

Definition at line 591 of file auto_prefetch_service.h.

591{false};

Referenced by run_loop().

◆ cycles_count_

std::atomic<std::size_t> kcenon::pacs::workflow::auto_prefetch_service::cycles_count_ {0}
private

Number of completed cycles.

Definition at line 609 of file auto_prefetch_service.h.

609{0};

Referenced by cycles_completed(), and run_loop().

◆ database_

storage::index_database& kcenon::pacs::workflow::auto_prefetch_service::database_
private

Reference to PACS index database.

Definition at line 564 of file auto_prefetch_service.h.

◆ enabled_

std::atomic<bool> kcenon::pacs::workflow::auto_prefetch_service::enabled_ {false}
private

Flag indicating service is enabled.

Definition at line 588 of file auto_prefetch_service.h.

588{false};

Referenced by is_enabled(), start(), stop(), and time_until_next_cycle().

◆ executor_

std::shared_ptr<kcenon::common::interfaces::IExecutor> kcenon::pacs::workflow::auto_prefetch_service::executor_
private

IExecutor for task execution (recommended, Issue #487)

Definition at line 570 of file auto_prefetch_service.h.

◆ last_result_

std::optional<prefetch_result> kcenon::pacs::workflow::auto_prefetch_service::last_result_
private

Last prefetch result.

Definition at line 603 of file auto_prefetch_service.h.

Referenced by get_last_result(), and run_loop().

◆ mutex_

std::mutex kcenon::pacs::workflow::auto_prefetch_service::mutex_
mutableprivate

◆ next_cycle_time_

std::chrono::steady_clock::time_point kcenon::pacs::workflow::auto_prefetch_service::next_cycle_time_
private

Time of next scheduled cycle.

Definition at line 612 of file auto_prefetch_service.h.

Referenced by run_loop(), start(), time_until_next_cycle(), and trigger_cycle().

◆ queue_mutex_

std::mutex kcenon::pacs::workflow::auto_prefetch_service::queue_mutex_
mutableprivate

Mutex for request queue.

Definition at line 600 of file auto_prefetch_service.h.

Referenced by pending_requests(), and queue_request().

◆ queued_patients_

std::set<std::string> kcenon::pacs::workflow::auto_prefetch_service::queued_patients_
private

Set of patient IDs currently in queue (for deduplication)

Definition at line 597 of file auto_prefetch_service.h.

Referenced by queue_request().

◆ request_queue_

std::queue<prefetch_request> kcenon::pacs::workflow::auto_prefetch_service::request_queue_
private

Queue of pending prefetch requests.

Definition at line 594 of file auto_prefetch_service.h.

Referenced by pending_requests(), queue_request(), and run_loop().

◆ stop_requested_

std::atomic<bool> kcenon::pacs::workflow::auto_prefetch_service::stop_requested_ {false}
private

Flag to signal shutdown.

Definition at line 585 of file auto_prefetch_service.h.

585{false};

Referenced by run_loop(), start(), and stop().

◆ thread_pool_

std::shared_ptr<kcenon::thread::thread_pool> kcenon::pacs::workflow::auto_prefetch_service::thread_pool_
private

Thread pool for parallel prefetches (optional, legacy)

Definition at line 567 of file auto_prefetch_service.h.

◆ worker_thread_

std::thread kcenon::pacs::workflow::auto_prefetch_service::worker_thread_
private

Background worker thread.

Definition at line 576 of file auto_prefetch_service.h.

Referenced by start(), and stop().


The documentation for this class was generated from the following files: