PACS System 0.1.0
PACS DICOM system library
Loading...
Searching...
No Matches
auto_prefetch_service.h
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2021-2025, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
19#pragma once
20
21#include "prefetch_config.h"
23
24#include <atomic>
25#include <chrono>
26#include <condition_variable>
27#include <functional>
28#include <memory>
29#include <mutex>
30#include <optional>
31#include <queue>
32#include <set>
33#include <string>
34#include <thread>
35#include <vector>
36
37// Forward declarations for kcenon ecosystem
38namespace kcenon::thread {
39class thread_pool;
40} // namespace kcenon::thread
41
42namespace kcenon::logger {
43class logger;
44} // namespace kcenon::logger
45
47class IExecutor;
48} // namespace kcenon::common::interfaces
49
50// Forward declarations for PACS modules
51namespace kcenon::pacs::network {
52class association;
53} // namespace kcenon::pacs::network
54
55namespace kcenon::pacs::storage {
56class index_database;
57} // namespace kcenon::pacs::storage
58
59namespace kcenon::pacs::core {
60class dicom_dataset;
61} // namespace kcenon::pacs::core
62
64
73 std::string patient_id;
74
76 std::string patient_name;
77
79 std::string scheduled_modality;
80
83
86
88 std::chrono::system_clock::time_point request_time;
89
91 std::size_t retry_count{0};
92};
93
204public:
205 // =========================================================================
206 // Construction
207 // =========================================================================
208
216 explicit auto_prefetch_service(
217 storage::index_database& database,
218 const prefetch_service_config& config = {});
219
228 storage::index_database& database,
229 std::shared_ptr<kcenon::thread::thread_pool> thread_pool,
230 const prefetch_service_config& config = {});
231
246 storage::index_database& database,
247 std::shared_ptr<kcenon::common::interfaces::IExecutor> executor,
248 const prefetch_service_config& config = {});
249
254
258
262
263 // =========================================================================
264 // Lifecycle Management
265 // =========================================================================
266
273 void enable();
274
278 void start();
279
288 void disable(bool wait_for_completion = true);
289
295 void stop(bool wait_for_completion = true);
296
302 [[nodiscard]] auto is_enabled() const noexcept -> bool;
303
309 [[nodiscard]] auto is_running() const noexcept -> bool;
310
311 // =========================================================================
312 // Manual Operations
313 // =========================================================================
314
326 [[nodiscard]] auto prefetch_priors(
327 const std::string& patient_id,
328 std::chrono::days lookback = std::chrono::days{365})
330
340 const std::vector<storage::worklist_item>& worklist_items);
341
348 void trigger_cycle();
349
358 [[nodiscard]] auto run_prefetch_cycle() -> prefetch_result;
359
360 // =========================================================================
361 // Worklist Event Handler
362 // =========================================================================
363
373 const std::vector<storage::worklist_item>& worklist_items);
374
375 // =========================================================================
376 // Statistics and Monitoring
377 // =========================================================================
378
384 [[nodiscard]] auto get_last_result() const
385 -> std::optional<prefetch_result>;
386
392 [[nodiscard]] auto get_cumulative_stats() const -> prefetch_result;
393
399 [[nodiscard]] auto time_until_next_cycle() const
400 -> std::optional<std::chrono::seconds>;
401
407 [[nodiscard]] auto cycles_completed() const noexcept -> std::size_t;
408
414 [[nodiscard]] auto pending_requests() const noexcept -> std::size_t;
415
416 // =========================================================================
417 // Configuration
418 // =========================================================================
419
427 void set_prefetch_interval(std::chrono::seconds interval);
428
434 [[nodiscard]] auto get_prefetch_interval() const noexcept
435 -> std::chrono::seconds;
436
442 void set_prefetch_criteria(const prefetch_criteria& criteria);
443
449 [[nodiscard]] auto get_prefetch_criteria() const noexcept
450 -> const prefetch_criteria&;
451
458 prefetch_service_config::cycle_complete_callback callback);
459
466 prefetch_service_config::error_callback callback);
467
468private:
469 // =========================================================================
470 // Internal Methods
471 // =========================================================================
472
476 void run_loop();
477
482 [[nodiscard]] auto execute_cycle() -> prefetch_result;
483
490 [[nodiscard]] auto process_request(const prefetch_request& request)
492
501 [[nodiscard]] auto query_prior_studies(
502 const remote_pacs_config& pacs_config,
503 const std::string& patient_id,
504 std::chrono::days lookback) -> std::vector<prior_study_info>;
505
513 [[nodiscard]] auto filter_studies(
514 const std::vector<prior_study_info>& studies,
515 const prefetch_request& request) -> std::vector<prior_study_info>;
516
523 [[nodiscard]] auto study_exists_locally(const std::string& study_uid)
524 -> bool;
525
533 [[nodiscard]] auto prefetch_study(
534 const remote_pacs_config& pacs_config,
535 const prior_study_info& study) -> bool;
536
542 void update_stats(const prefetch_result& result);
543
549 void queue_request(const prefetch_request& request);
550
556 [[nodiscard]] auto dequeue_request()
557 -> std::optional<prefetch_request>;
558
559 // =========================================================================
560 // Member Variables
561 // =========================================================================
562
564 storage::index_database& database_;
565
567 std::shared_ptr<kcenon::thread::thread_pool> thread_pool_;
568
570 std::shared_ptr<kcenon::common::interfaces::IExecutor> executor_;
571
574
576 std::thread worker_thread_;
577
579 mutable std::mutex mutex_;
580
582 std::condition_variable cv_;
583
585 std::atomic<bool> stop_requested_{false};
586
588 std::atomic<bool> enabled_{false};
589
591 std::atomic<bool> cycle_in_progress_{false};
592
594 std::queue<prefetch_request> request_queue_;
595
597 std::set<std::string> queued_patients_;
598
600 mutable std::mutex queue_mutex_;
601
603 std::optional<prefetch_result> last_result_;
604
607
609 std::atomic<std::size_t> cycles_count_{0};
610
612 std::chrono::steady_clock::time_point next_cycle_time_;
613};
614
615} // namespace kcenon::pacs::workflow
std::set< std::string > queued_patients_
Set of patient IDs currently in queue (for deduplication)
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.
void on_worklist_query(const std::vector< storage::worklist_item > &worklist_items)
Handle worklist query event.
std::optional< prefetch_result > last_result_
Last prefetch result.
std::condition_variable cv_
Condition variable for sleep/wake.
auto cycles_completed() const noexcept -> std::size_t
Get the number of cycles completed.
storage::index_database & database_
Reference to PACS index database.
void set_prefetch_criteria(const prefetch_criteria &criteria)
Update the prefetch criteria.
void disable(bool wait_for_completion=true)
Disable/stop the prefetch service.
auto is_running() const noexcept -> bool
Check if the service is running (alias for is_enabled)
std::atomic< bool > enabled_
Flag indicating service is enabled.
auto_prefetch_service & operator=(const auto_prefetch_service &)=delete
std::queue< prefetch_request > request_queue_
Queue of pending prefetch requests.
auto_prefetch_service(storage::index_database &database, const prefetch_service_config &config={})
Construct auto prefetch service.
std::atomic< bool > cycle_in_progress_
Flag indicating a cycle is in progress.
void set_error_callback(prefetch_service_config::error_callback callback)
Set the error callback.
auto_prefetch_service & operator=(auto_prefetch_service &&)=delete
void trigger_cycle()
Trigger next cycle immediately.
void update_stats(const prefetch_result &result)
Update cumulative statistics.
auto execute_cycle() -> prefetch_result
Execute a single prefetch cycle.
std::thread worker_thread_
Background worker thread.
prefetch_result cumulative_stats_
Cumulative statistics.
auto is_enabled() const noexcept -> bool
Check if the service is enabled/running.
std::chrono::steady_clock::time_point next_cycle_time_
Time of next scheduled cycle.
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.
std::atomic< std::size_t > cycles_count_
Number of completed cycles.
std::shared_ptr< kcenon::common::interfaces::IExecutor > executor_
IExecutor for task execution (recommended, Issue #487)
prefetch_service_config config_
Service configuration.
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_prefetch_service()
Destructor - ensures graceful shutdown.
auto process_request(const prefetch_request &request) -> prefetch_result
Process a single prefetch request.
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.
std::mutex queue_mutex_
Mutex for request queue.
auto time_until_next_cycle() const -> std::optional< std::chrono::seconds >
Get the time until the next scheduled prefetch cycle.
std::shared_ptr< kcenon::thread::thread_pool > thread_pool_
Thread pool for parallel prefetches (optional, legacy)
std::atomic< bool > stop_requested_
Flag to signal shutdown.
auto_prefetch_service(const auto_prefetch_service &)=delete
Non-copyable.
auto run_prefetch_cycle() -> prefetch_result
Run a prefetch cycle manually.
auto get_prefetch_interval() const noexcept -> std::chrono::seconds
Get the current prefetch interval.
void set_prefetch_interval(std::chrono::seconds interval)
Update the prefetch interval.
void stop(bool wait_for_completion=true)
Stop the prefetch service (alias for disable)
void trigger_for_worklist(const std::vector< storage::worklist_item > &worklist_items)
Trigger prefetch for worklist items.
std::mutex mutex_
Mutex for thread synchronization.
void start()
Start the prefetch service (alias for enable)
void queue_request(const prefetch_request &request)
Add request to queue (deduplicated)
auto study_exists_locally(const std::string &study_uid) -> bool
Check if study already exists locally.
auto pending_requests() const noexcept -> std::size_t
Get the number of pending prefetch requests.
auto dequeue_request() -> std::optional< prefetch_request >
Get next request from queue.
void set_cycle_complete_callback(prefetch_service_config::cycle_complete_callback callback)
Set the cycle complete callback.
auto prefetch_study(const remote_pacs_config &pacs_config, const prior_study_info &study) -> bool
Prefetch a single study via C-MOVE.
auto get_prefetch_criteria() const noexcept -> const prefetch_criteria &
Get the current prefetch criteria.
auto_prefetch_service(auto_prefetch_service &&)=delete
Non-movable.
std::shared_mutex mutex
Mutex for thread-safe access.
Configuration for automatic prefetch service.
Prefetch request for a single patient.
std::string scheduled_body_part
Scheduled body part (for preference matching)
std::string scheduled_study_uid
Study Instance UID of scheduled study (to avoid prefetching)
std::string scheduled_modality
Scheduled modality (for preference matching)
std::chrono::system_clock::time_point request_time
Request timestamp.
std::size_t retry_count
Number of retry attempts.
Configuration for the auto prefetch service.
Remote PACS connection configuration.
Modality Worklist (MWL) record data structures.