CppCommon 1.0.5.0
C++ Common Library
Loading...
Searching...
No Matches
filecache.cpp
Go to the documentation of this file.
1
9#include "cache/filecache.h"
10
11namespace CppCommon {
12
13bool FileCache::emplace(std::string&& key, std::string&& value, const Timespan& timeout)
14{
15 std::unique_lock<std::shared_mutex> locker(_lock);
16
17 // Try to find and remove the previous key
18 remove_internal(key);
19
20 // Update the cache entry
21 if (timeout.total() > 0)
22 {
23 Timestamp current = UtcTimestamp();
24 _timestamp = (current <= _timestamp) ? _timestamp + 1 : current;
25 _entries_by_key.insert(std::make_pair(key, MemCacheEntry(std::move(value), _timestamp, timeout)));
26 _entries_by_timestamp.insert(std::make_pair(_timestamp, key));
27 }
28 else
29 _entries_by_key.emplace(std::make_pair(std::move(key), MemCacheEntry(std::move(value))));
30
31 return true;
32}
33
34bool FileCache::insert(const std::string& key, const std::string& value, const Timespan& timeout)
35{
36 std::unique_lock<std::shared_mutex> locker(_lock);
37
38 // Try to find and remove the previous key
39 remove_internal(key);
40
41 // Update the cache entry
42 if (timeout.total() > 0)
43 {
44 Timestamp current = UtcTimestamp();
45 _timestamp = (current <= _timestamp) ? _timestamp + 1 : current;
46 _entries_by_key.insert(std::make_pair(key, MemCacheEntry(value, _timestamp, timeout)));
47 _entries_by_timestamp.insert(std::make_pair(_timestamp, key));
48 }
49 else
50 _entries_by_key.insert(std::make_pair(key, MemCacheEntry(value)));
51
52 return true;
53}
54
55std::pair<bool, std::string_view> FileCache::find(const std::string& key)
56{
57 std::shared_lock<std::shared_mutex> locker(_lock);
58
59 // Try to find the given key
60 auto it = _entries_by_key.find(key);
61 if (it == _entries_by_key.end())
62 return std::make_pair(false, std::string_view());
63
64 return std::make_pair(true, std::string_view(it->second.value));
65}
66
67std::pair<bool, std::string_view> FileCache::find(const std::string& key, Timestamp& timeout)
68{
69 std::shared_lock<std::shared_mutex> locker(_lock);
70
71 // Try to find the given key
72 auto it = _entries_by_key.find(key);
73 if (it == _entries_by_key.end())
74 return std::make_pair(false, std::string_view());
75
76 timeout = it->second.timestamp + it->second.timespan;
77 return std::make_pair(true, std::string_view(it->second.value));
78}
79
80bool FileCache::remove(const std::string& key)
81{
82 std::unique_lock<std::shared_mutex> locker(_lock);
83
84 return remove_internal(key);
85}
86
87bool FileCache::remove_internal(const std::string& key)
88{
89 // Try to find the given key
90 auto it = _entries_by_key.find(key);
91 if (it == _entries_by_key.end())
92 return false;
93
94 // Try to erase cache entry by timestamp
95 if (it->second.timestamp.total() > 0)
96 _entries_by_timestamp.erase(it->second.timestamp);
97
98 // Erase cache entry
99 _entries_by_key.erase(it);
100
101 return true;
102}
103
104bool FileCache::insert_path(const CppCommon::Path& path, const std::string& prefix, const Timespan& timeout, const InsertHandler& handler)
105{
106 // Try to find and remove the previous path
107 remove_path_internal(path);
108
109 // Insert the cache path
110 if (!insert_path_internal(path, prefix, timeout, handler))
111 return false;
112
113 std::unique_lock<std::shared_mutex> locker(_lock);
114
115 // Update the cache path
116 if (timeout.total() > 0)
117 {
118 Timestamp current = UtcTimestamp();
119 _timestamp = (current <= _timestamp) ? _timestamp + 1 : current;
120 _paths_by_key.insert(std::make_pair(path, FileCacheEntry(prefix, handler, _timestamp, timeout)));
121 _paths_by_timestamp.insert(std::make_pair(_timestamp, path));
122 }
123 else
124 _paths_by_key.insert(std::make_pair(path, FileCacheEntry(prefix, handler)));
125
126 return true;
127}
128
129bool FileCache::insert_path_internal(const CppCommon::Path& path, const std::string& prefix, const Timespan& timeout, const InsertHandler& handler)
130{
131 try
132 {
133 const std::string key_prefix = (prefix.empty() || (prefix == "/")) ? "/" : (prefix + "/");
134
135 // Iterate through all directory entries
136 for (const auto& item : CppCommon::Directory(path))
137 {
138 const CppCommon::Path entry = item.IsSymlink() ? Symlink(item).target() : item;
139 const std::string key = key_prefix + CppCommon::Encoding::URLDecode(item.filename().string());
140
141 if (entry.IsDirectory())
142 {
143 // Recursively insert sub-directory
144 if (!insert_path_internal(entry, key, timeout, handler))
145 return false;
146 }
147 else
148 {
149 try
150 {
151 // Load the cache file content
152 auto content = CppCommon::File::ReadAllBytes(entry);
153 std::string value(content.begin(), content.end());
154 if (!handler(*this, key, value, timeout))
155 return false;
156 }
157 catch (const CppCommon::FileSystemException&) { return false; }
158 }
159 }
160
161 return true;
162 }
163 catch (const CppCommon::FileSystemException&) { return false; }
164}
165
167{
168 std::shared_lock<std::shared_mutex> locker(_lock);
169
170 // Try to find the given path
171 auto it = _paths_by_key.find(path);
172 if (it == _paths_by_key.end())
173 return false;
174
175 return true;
176}
177
179{
180 std::shared_lock<std::shared_mutex> locker(_lock);
181
182 // Try to find the given path
183 auto it = _paths_by_key.find(path);
184 if (it == _paths_by_key.end())
185 return false;
186
187 timeout = it->second.timestamp + it->second.timespan;
188 return true;
189}
190
192{
193 return remove_path_internal(path);
194}
195
196bool FileCache::remove_path_internal(const CppCommon::Path& path)
197{
198 std::unique_lock<std::shared_mutex> locker(_lock);
199
200 // Try to find the given path
201 auto it = _paths_by_key.find(path);
202 if (it == _paths_by_key.end())
203 return false;
204
205 // Try to erase cache path by timestamp
206 if (it->second.timestamp.total() > 0)
207 _paths_by_timestamp.erase(it->second.timestamp);
208
209 // Erase cache path
210 _paths_by_key.erase(it);
211
212 return true;
213}
214
216{
217 std::unique_lock<std::shared_mutex> locker(_lock);
218
219 // Clear all cache entries
220 _entries_by_key.clear();
221 _entries_by_timestamp.clear();
222 _paths_by_key.clear();
223 _paths_by_timestamp.clear();
224}
225
227{
228 std::unique_lock<std::shared_mutex> locker(_lock);
229
230 // Watchdog for cache entries
231 auto it_entry_by_timestamp = _entries_by_timestamp.begin();
232 while (it_entry_by_timestamp != _entries_by_timestamp.end())
233 {
234 // Check for the cache entry timeout
235 auto it_entry_by_key = _entries_by_key.find(it_entry_by_timestamp->second);
236 if ((it_entry_by_key->second.timestamp + it_entry_by_key->second.timespan) <= utc)
237 {
238 // Erase the cache entry with timeout
239 _entries_by_key.erase(it_entry_by_key);
240 _entries_by_timestamp.erase(it_entry_by_timestamp);
241 it_entry_by_timestamp = _entries_by_timestamp.begin();
242 continue;
243 }
244 else
245 break;
246 }
247
248 // Watchdog for cache paths
249 auto it_path_by_timestamp = _paths_by_timestamp.begin();
250 while (it_path_by_timestamp != _paths_by_timestamp.end())
251 {
252 // Check for the cache entry timeout
253 auto& it_path_by_key = _paths_by_key[it_path_by_timestamp->second];
254 if ((it_path_by_key.timestamp + it_path_by_key.timespan) <= utc)
255 {
256 // Update the cache path with timeout
257 auto path = it_path_by_timestamp->second;
258 auto prefix = it_path_by_key.prefix;
259 auto timespan = it_path_by_key.timespan;
260 auto handler = it_path_by_key.handler;
261 _paths_by_timestamp.erase(it_path_by_timestamp);
262 locker.unlock();
263 insert_path(path, prefix, timespan, handler);
264 locker.lock();
265 it_path_by_timestamp = _paths_by_timestamp.begin();
266 continue;
267 }
268 else
269 break;
270 }
271}
272
273void FileCache::swap(FileCache& cache) noexcept
274{
275 std::unique_lock<std::shared_mutex> locker1(_lock);
276 std::unique_lock<std::shared_mutex> locker2(cache._lock);
277
278 using std::swap;
279 swap(_timestamp, cache._timestamp);
280 swap(_entries_by_key, cache._entries_by_key);
281 swap(_entries_by_timestamp, cache._entries_by_timestamp);
282 swap(_paths_by_key, cache._paths_by_key);
283 swap(_paths_by_timestamp, cache._paths_by_timestamp);
284}
285
286} // namespace CppCommon
Filesystem directory.
Definition directory.h:25
static std::string URLDecode(std::string_view str)
URL decode string.
Definition encoding.cpp:499
bool insert(const std::string &key, const std::string &value, const Timespan &timeout=Timespan(0))
Insert a new cache value with the given timeout into the file cache.
Definition filecache.cpp:34
void watchdog(const UtcTimestamp &utc=UtcTimestamp())
Watchdog the file cache.
std::pair< bool, std::string_view > find(const std::string &key)
Try to find the cache value by the given key.
Definition filecache.cpp:55
friend void swap(FileCache &cache1, FileCache &cache2) noexcept
Definition filecache.inl:23
bool remove(const std::string &key)
Remove the cache value with the given key from the file cache.
Definition filecache.cpp:80
bool remove_path(const CppCommon::Path &path)
Remove the cache path from the file cache.
bool emplace(std::string &&key, std::string &&value, const Timespan &timeout=Timespan(0))
Emplace a new cache value with the given timeout into the file cache.
Definition filecache.cpp:13
bool insert_path(const CppCommon::Path &path, const std::string &prefix="/", const Timespan &timeout=Timespan(0), const InsertHandler &handler=[](FileCache &cache, const std::string &key, const std::string &value, const Timespan &timeout){ return cache.insert(key, value, timeout);})
Insert a new cache path with the given timeout into the file cache.
bool find_path(const CppCommon::Path &path)
Try to find the cache path.
void clear()
Clear the memory cache.
std::function< bool(FileCache &cache, const std::string &key, const std::string &value, const Timespan &timeout)> InsertHandler
File cache insert handler type.
Definition filecache.h:39
std::vector< uint8_t > ReadAllBytes()
Read all bytes.
Definition reader.cpp:15
File system exception.
Definition exceptions.h:19
Filesystem path.
Definition path.h:90
bool IsSymlink() const
Is the path points to symbolic link?
Definition path.h:219
bool IsDirectory() const
Is the path points to directory?
Definition path.h:217
int64_t total() const noexcept
Get total value of the current timespan (total nanoseconds)
Definition timespan.h:151
File cache definition.
C++ Common project definitions.
void swap(FileCache &cache1, FileCache &cache2) noexcept
Definition filecache.inl:23