CppCommon  1.0.4.1
C++ Common Library
filecache.cpp
Go to the documentation of this file.
1 
9 #include "cache/filecache.h"
10 
11 namespace CppCommon {
12 
13 bool 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 
34 bool 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 
55 std::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 
67 std::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 
80 bool FileCache::remove(const std::string& key)
81 {
82  std::unique_lock<std::shared_mutex> locker(_lock);
83 
84  return remove_internal(key);
85 }
86 
87 bool 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 
104 bool 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 
129 bool 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 
178 bool FileCache::find_path(const CppCommon::Path& path, Timestamp& timeout)
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 
196 bool 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 
273 void 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:494
File cache.
Definition: filecache.h:36
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.
Definition: filecache.cpp:226
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
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.
Definition: filecache.cpp:191
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.
Definition: filecache.cpp:104
bool find_path(const CppCommon::Path &path)
Try to find the cache path.
Definition: filecache.cpp:166
void swap(FileCache &cache) noexcept
Swap two instances.
Definition: filecache.cpp:273
void clear()
Clear the memory cache.
Definition: filecache.cpp:215
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
UTC timestamp.
Definition: timestamp.h:248
File cache definition.
C++ Common project definitions.
Definition: token_bucket.h:15
void swap(FileCache &cache1, FileCache &cache2) noexcept
Definition: filecache.inl:23