PACS System 0.1.0
PACS DICOM system library
Loading...
Searching...
No Matches
query_cache.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#include <mutex>
14#include <sstream>
15
17
18// ─────────────────────────────────────────────────────
19// query_cache Implementation
20// ─────────────────────────────────────────────────────
21
23 : config_(config)
24 , cache_(cache_config{
25 config.max_entries,
26 config.ttl,
27 config.enable_metrics,
28 config.cache_name}) {
29}
30
31std::optional<cached_query_result> query_cache::get(const key_type& key) {
32 return cache_.get(key);
33}
34
35void query_cache::put(const key_type& key, const cached_query_result& result) {
36 cache_.put(key, result);
37}
38
39void query_cache::put(const key_type& key, cached_query_result&& result) {
40 cache_.put(key, std::move(result));
41}
42
44 return cache_.invalidate(key);
45}
46
48 return cache_.invalidate_if(
49 [&prefix](const std::string& key, const cached_query_result&) {
50 return key.size() >= prefix.size() &&
51 key.compare(0, prefix.size(), prefix) == 0;
52 });
53}
54
56 // Keys are formatted as "LEVEL:params" or "AE/LEVEL:params"
57 // Match both formats
58 return cache_.invalidate_if(
59 [&query_level](const std::string& key, const cached_query_result&) {
60 // Direct match: "LEVEL:..."
61 if (key.starts_with(query_level + ":")) {
62 return true;
63 }
64 // AE prefix match: "AE/LEVEL:..."
65 auto slash_pos = key.find('/');
66 if (slash_pos != std::string::npos) {
67 auto level_start = slash_pos + 1;
68 auto colon_pos = key.find(':', level_start);
69 if (colon_pos != std::string::npos) {
70 auto key_level = key.substr(level_start, colon_pos - level_start);
71 return key_level == query_level;
72 }
73 }
74 return false;
75 });
76}
77
79 cache_.clear();
80}
81
83 return cache_.purge_expired();
84}
85
87 return cache_.size();
88}
89
90bool query_cache::empty() const {
91 return cache_.empty();
92}
93
95 return cache_.max_size();
96}
97
98const cache_stats& query_cache::stats() const noexcept {
99 return cache_.stats();
100}
101
102double query_cache::hit_rate() const noexcept {
103 return cache_.hit_rate();
104}
105
107 cache_.reset_stats();
108}
109
111 const std::string& query_level,
112 const std::vector<std::pair<std::string, std::string>>& params) {
113
114 // Sort parameters for consistent key generation
115 auto sorted_params = params;
116 std::sort(sorted_params.begin(), sorted_params.end(),
117 [](const auto& a, const auto& b) { return a.first < b.first; });
118
119 std::ostringstream oss;
120 oss << query_level << ":";
121
122 bool first = true;
123 for (const auto& [name, value] : sorted_params) {
124 if (!first) {
125 oss << ";";
126 }
127 first = false;
128 oss << name << "=" << value;
129 }
130
131 return oss.str();
132}
133
135 const std::string& calling_ae,
136 const std::string& query_level,
137 const std::vector<std::pair<std::string, std::string>>& params) {
138
139 return calling_ae + "/" + build_key(query_level, params);
140}
141
142// ─────────────────────────────────────────────────────
143// Global Query Cache
144// ─────────────────────────────────────────────────────
145
146namespace {
147
148std::once_flag g_cache_init_flag;
149std::unique_ptr<query_cache> g_query_cache;
150query_cache_config g_pending_config;
151bool g_config_pending = false;
152
153void init_global_cache() {
154 if (g_config_pending) {
155 g_query_cache = std::make_unique<query_cache>(g_pending_config);
156 } else {
157 g_query_cache = std::make_unique<query_cache>();
158 }
159}
160
161} // anonymous namespace
162
164 std::call_once(g_cache_init_flag, init_global_cache);
165 return *g_query_cache;
166}
167
169 // This is a simple check - if init already happened, return false
170 // Not perfectly thread-safe for the pending config, but configure
171 // should be called at startup before any access
172 if (g_query_cache) {
173 return false;
174 }
175 g_pending_config = config;
176 g_config_pending = true;
177 return true;
178}
179
180} // namespace kcenon::pacs::services::cache
DICOM query result cache with monitoring integration.
std::optional< cached_query_result > get(const key_type &key)
Retrieve a cached query result.
static std::string build_key(const std::string &query_level, const std::vector< std::pair< std::string, std::string > > &params)
Build a cache key from query parameters.
void reset_stats() noexcept
Reset cache statistics.
string_lru_cache< cached_query_result > cache_
bool empty() const
Check if the cache is empty.
size_type size() const
Get the current number of cached entries.
void clear()
Remove all entries from the cache.
double hit_rate() const noexcept
Get the cache hit rate.
size_type max_size() const noexcept
Get the maximum cache size.
const cache_stats & stats() const noexcept
Get cache statistics.
bool invalidate(const key_type &key)
Remove a specific entry from the cache.
size_type purge_expired()
Remove all expired entries.
void put(const key_type &key, const cached_query_result &result)
Store a query result in the cache.
static std::string build_key_with_ae(const std::string &calling_ae, const std::string &query_level, const std::vector< std::pair< std::string, std::string > > &params)
Build a cache key with AE title prefix.
size_type invalidate_by_prefix(const std::string &prefix)
query_cache(const query_cache_config &config=query_cache_config{})
Construct a query cache with the given configuration.
size_type invalidate_by_query_level(const std::string &query_level)
Remove all entries for a specific query level.
query_cache & global_query_cache()
Get the global query cache instance.
bool configure_global_cache(const query_cache_config &config)
Configure the global query cache.
query_level
DICOM Query/Retrieve level enumeration.
Definition query_scp.h:63
DICOM query result cache with monitoring integration.
Configuration options for the LRU cache.
Statistics for cache performance monitoring.
double hit_rate() const noexcept
Calculate the cache hit rate.
Wrapper for cached query results.
Definition query_cache.h:75
Configuration for the query cache.
Definition query_cache.h:47
std::string_view name