101 lines
2.4 KiB
C++
101 lines
2.4 KiB
C++
#ifndef REPERTORY_INCLUDE_UTILS_TTL_CACHE_HPP_
|
|
#define REPERTORY_INCLUDE_UTILS_TTL_CACHE_HPP_
|
|
|
|
#include "utils/config.hpp"
|
|
|
|
namespace repertory::utils {
|
|
template <typename data_t, template <typename> class atomic_t = std::atomic>
|
|
class ttl_cache final {
|
|
public:
|
|
using clock = std::chrono::steady_clock;
|
|
using duration = std::chrono::milliseconds;
|
|
using entry_t = atomic_t<data_t>;
|
|
using entry_ptr_t = std::shared_ptr<entry_t>;
|
|
|
|
static constexpr const auto default_expiration{duration(60000U)};
|
|
|
|
private:
|
|
struct entry final {
|
|
entry_ptr_t data;
|
|
clock::time_point expires_at;
|
|
};
|
|
|
|
public:
|
|
ttl_cache(duration ttl = default_expiration) : ttl_{ttl} {}
|
|
|
|
private:
|
|
duration ttl_;
|
|
|
|
private:
|
|
mutable std::mutex mutex_;
|
|
std::unordered_map<std::string, entry> entries_;
|
|
|
|
public:
|
|
void clear() {
|
|
mutex_lock lock(mutex_);
|
|
entries_.clear();
|
|
}
|
|
|
|
void erase(const std::string &api_path) {
|
|
mutex_lock lock(mutex_);
|
|
entries_.erase(api_path);
|
|
}
|
|
|
|
[[nodiscard]] auto contains(const std::string &api_path) -> bool {
|
|
mutex_lock lock(mutex_);
|
|
return entries_.contains(api_path);
|
|
}
|
|
|
|
[[nodiscard]] auto get(const std::string &api_path) -> entry_ptr_t {
|
|
mutex_lock lock(mutex_);
|
|
auto iter = entries_.find(api_path);
|
|
if (iter == entries_.end()) {
|
|
return nullptr;
|
|
}
|
|
|
|
iter->second.expires_at = clock::now() + ttl_;
|
|
return iter->second.data;
|
|
}
|
|
|
|
void purge_expired() {
|
|
mutex_lock lock(mutex_);
|
|
auto now = clock::now();
|
|
for (auto iter = entries_.begin(); iter != entries_.end();) {
|
|
if (iter->second.expires_at <= now) {
|
|
iter = entries_.erase(iter);
|
|
continue;
|
|
}
|
|
|
|
++iter;
|
|
}
|
|
}
|
|
|
|
[[nodiscard]] auto get_ttl() const -> duration {
|
|
mutex_lock lock(mutex_);
|
|
return ttl_;
|
|
}
|
|
|
|
void set(const std::string &api_path, const data_t &data) {
|
|
mutex_lock lock(mutex_);
|
|
if (entries_.contains(api_path)) {
|
|
auto &entry = entries_.at(api_path);
|
|
entry.data->store(data);
|
|
entry.expires_at = clock::now() + ttl_;
|
|
return;
|
|
}
|
|
|
|
entries_.emplace(api_path, entry{
|
|
.data = std::make_shared<entry_t>(data),
|
|
.expires_at = clock::now() + ttl_,
|
|
});
|
|
}
|
|
|
|
void set_ttl(duration ttl) {
|
|
mutex_lock lock(mutex_);
|
|
ttl_ = ttl;
|
|
}
|
|
};
|
|
} // namespace repertory::utils
|
|
|
|
#endif // REPERTORY_INCLUDE_UTILS_TTL_CACHE_HPP_
|