PACS System 0.1.0
PACS DICOM system library
Loading...
Searching...
No Matches
hsm_migration_service.cpp
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
11
12#include <algorithm>
13
14namespace kcenon::pacs::storage {
15
16// ============================================================================
17// Construction
18// ============================================================================
19
21 hsm_storage& storage, const migration_service_config& config)
22 : storage_(storage), config_(config) {
23 if (config_.auto_start) {
24 start();
25 }
26}
27
29 hsm_storage& storage,
30 std::shared_ptr<kcenon::thread::thread_pool> thread_pool,
31 const migration_service_config& config)
32 : storage_(storage),
33 thread_pool_(std::move(thread_pool)),
34 config_(config) {
35 if (config_.auto_start) {
36 start();
37 }
38}
39
43
44// ============================================================================
45// Lifecycle Management
46// ============================================================================
47
49 std::lock_guard lock(mutex_);
50
51 if (running_.load()) {
52 return; // Already running
53 }
54
55 stop_requested_.store(false);
56 running_.store(true);
57
58 // Set next cycle time
60 std::chrono::steady_clock::now() + config_.migration_interval;
61
62 // Start worker thread
63 worker_thread_ = std::thread([this]() { run_loop(); });
64}
65
66void hsm_migration_service::stop(bool wait_for_completion) {
67 {
68 std::lock_guard lock(mutex_);
69
70 if (!running_.load()) {
71 return; // Not running
72 }
73
74 stop_requested_.store(true);
75 }
76
77 // Wake up the worker thread
78 cv_.notify_all();
79
80 // Wait for thread to finish
81 if (worker_thread_.joinable()) {
82 if (wait_for_completion) {
83 worker_thread_.join();
84 } else {
85 worker_thread_.detach();
86 }
87 }
88
89 running_.store(false);
90}
91
92auto hsm_migration_service::is_running() const noexcept -> bool {
93 return running_.load();
94}
95
96// ============================================================================
97// Manual Operations
98// ============================================================================
99
101 return execute_cycle();
102}
103
105 std::lock_guard lock(mutex_);
106
107 if (!running_.load()) {
108 return;
109 }
110
111 // Set next cycle time to now to trigger immediate execution
112 next_cycle_time_ = std::chrono::steady_clock::now();
113
114 // Wake up the worker thread
115 cv_.notify_all();
116}
117
118// ============================================================================
119// Statistics and Monitoring
120// ============================================================================
121
123 -> std::optional<migration_result> {
124 std::lock_guard lock(mutex_);
125 return last_result_;
126}
127
129 std::lock_guard lock(mutex_);
130 return cumulative_stats_;
131}
132
134 -> std::optional<std::chrono::seconds> {
135 std::lock_guard lock(mutex_);
136
137 if (!running_.load()) {
138 return std::nullopt;
139 }
140
141 auto now = std::chrono::steady_clock::now();
142 if (next_cycle_time_ <= now) {
143 return std::chrono::seconds{0};
144 }
145
146 return std::chrono::duration_cast<std::chrono::seconds>(next_cycle_time_ -
147 now);
148}
149
150auto hsm_migration_service::cycles_completed() const noexcept -> std::size_t {
151 return cycles_count_.load();
152}
153
154// ============================================================================
155// Configuration
156// ============================================================================
157
159 std::chrono::seconds interval) {
160 std::lock_guard lock(mutex_);
161 config_.migration_interval = interval;
162}
163
165 -> std::chrono::seconds {
167}
168
171 std::lock_guard lock(mutex_);
172 config_.on_cycle_complete = std::move(callback);
173}
174
177 std::lock_guard lock(mutex_);
178 config_.on_migration_error = std::move(callback);
179}
180
181// ============================================================================
182// Internal Methods
183// ============================================================================
184
186 while (!stop_requested_.load()) {
187 std::unique_lock lock(mutex_);
188
189 // Wait until next cycle time or stop requested
190 cv_.wait_until(lock, next_cycle_time_, [this]() {
191 return stop_requested_.load() ||
192 std::chrono::steady_clock::now() >= next_cycle_time_;
193 });
194
195 if (stop_requested_.load()) {
196 break;
197 }
198
199 // Release lock during migration
200 lock.unlock();
201
202 // Execute migration cycle
203 auto result = execute_cycle();
204
205 // Update statistics
206 update_stats(result);
207
208 // Store result
209 lock.lock();
210 last_result_ = result;
212
213 // Schedule next cycle
215 std::chrono::steady_clock::now() + config_.migration_interval;
216
217 // Call progress callback (outside of lock)
218 auto callback = config_.on_cycle_complete;
219 lock.unlock();
220
221 if (callback) {
222 callback(result);
223 }
224 }
225}
226
228 cycle_in_progress_.store(true);
229
230 auto result = storage_.run_migration_cycle();
231
232 // Call error callbacks for failures
233 if (!result.failed_uids.empty() && config_.on_migration_error) {
234 for (const auto& uid : result.failed_uids) {
235 config_.on_migration_error(uid, "Migration failed");
236 }
237 }
238
239 cycle_in_progress_.store(false);
240
241 return result;
242}
243
245 std::lock_guard lock(mutex_);
246
251
252 // Append failed UIDs (keep last N)
253 constexpr std::size_t kMaxFailedUids = 100;
254 for (const auto& uid : result.failed_uids) {
255 if (cumulative_stats_.failed_uids.size() >= kMaxFailedUids) {
258 }
260 }
261}
262
263} // namespace kcenon::pacs::storage
~hsm_migration_service()
Destructor - ensures graceful shutdown.
void update_stats(const migration_result &result)
Update cumulative statistics.
void set_progress_callback(migration_service_config::progress_callback callback)
Set the progress callback.
void stop(bool wait_for_completion=true)
Stop the background migration service.
auto get_last_result() const -> std::optional< migration_result >
Get the result of the last migration cycle.
void set_migration_interval(std::chrono::seconds interval)
Update the migration interval.
std::atomic< bool > stop_requested_
Flag to signal shutdown.
std::mutex mutex_
Mutex for thread synchronization.
hsm_migration_service(hsm_storage &storage, const migration_service_config &config={})
Construct migration service.
std::chrono::steady_clock::time_point next_cycle_time_
Time of next scheduled cycle.
std::thread worker_thread_
Background worker thread.
auto cycles_completed() const noexcept -> std::size_t
Get the number of cycles completed.
auto run_migration_cycle() -> migration_result
Manually trigger a migration cycle.
std::atomic< bool > running_
Flag indicating service is running.
auto is_running() const noexcept -> bool
Check if the service is running.
void trigger_cycle()
Trigger next cycle immediately.
void set_error_callback(migration_service_config::error_callback callback)
Set the error callback.
std::atomic< std::size_t > cycles_count_
Number of completed cycles.
auto execute_cycle() -> migration_result
Execute a single migration cycle.
auto get_cumulative_stats() const -> migration_result
Get total statistics since service started.
std::optional< migration_result > last_result_
Last migration result.
auto time_until_next_cycle() const -> std::optional< std::chrono::seconds >
Get the time until the next scheduled migration.
auto get_migration_interval() const noexcept -> std::chrono::seconds
Get the current migration interval.
migration_result cumulative_stats_
Cumulative statistics.
migration_service_config config_
Service configuration.
void start()
Start the background migration service.
std::condition_variable cv_
Condition variable for sleep/wake.
Background migration service for Hierarchical Storage Management.
Result of a migration operation.
Definition hsm_types.h:230
std::chrono::milliseconds duration
Duration of the migration operation.
Definition hsm_types.h:238
std::size_t bytes_migrated
Total bytes migrated.
Definition hsm_types.h:235
std::size_t instances_migrated
Number of instances successfully migrated.
Definition hsm_types.h:232
std::size_t instances_skipped
Number of instances that were skipped (not eligible)
Definition hsm_types.h:244
std::vector< std::string > failed_uids
SOP Instance UIDs that failed to migrate.
Definition hsm_types.h:241
Configuration for the migration service.
bool auto_start
Whether to start automatically on construction.
std::function< void(const migration_result &result)> progress_callback
Callback for migration progress updates.
std::function< void(const std::string &uid, const std::string &error)> error_callback
Callback for migration errors.
std::chrono::seconds migration_interval
Interval between migration cycles.
std::string_view uid