Веб-сайт самохостера Lotigara

summaryrefslogtreecommitdiff
path: root/source/core/StarTtlCache.hpp
diff options
context:
space:
mode:
authorKae <80987908+Novaenia@users.noreply.github.com>2023-06-20 14:33:09 +1000
committerKae <80987908+Novaenia@users.noreply.github.com>2023-06-20 14:33:09 +1000
commit6352e8e3196f78388b6c771073f9e03eaa612673 (patch)
treee23772f79a7fbc41bc9108951e9e136857484bf4 /source/core/StarTtlCache.hpp
parent6741a057e5639280d85d0f88ba26f000baa58f61 (diff)
everything everywhere
all at once
Diffstat (limited to 'source/core/StarTtlCache.hpp')
-rw-r--r--source/core/StarTtlCache.hpp203
1 files changed, 203 insertions, 0 deletions
diff --git a/source/core/StarTtlCache.hpp b/source/core/StarTtlCache.hpp
new file mode 100644
index 0000000..c70741a
--- /dev/null
+++ b/source/core/StarTtlCache.hpp
@@ -0,0 +1,203 @@
+#ifndef STAR_TTL_CACHE_HPP
+#define STAR_TTL_CACHE_HPP
+
+#include "StarLruCache.hpp"
+#include "StarTime.hpp"
+#include "StarRandom.hpp"
+
+namespace Star {
+
+template <typename LruCacheType>
+class TtlCacheBase {
+public:
+ typedef typename LruCacheType::Key Key;
+ typedef typename LruCacheType::Value::second_type Value;
+
+ typedef function<Value(Key const&)> ProducerFunction;
+
+ TtlCacheBase(int64_t timeToLive = 10000, int timeSmear = 1000, size_t maxSize = NPos, bool ttlUpdateEnabled = true);
+
+ int64_t timeToLive() const;
+ void setTimeToLive(int64_t timeToLive);
+
+ int timeSmear() const;
+ void setTimeSmear(int timeSmear);
+
+ // If a max size is set, this cache also acts as an LRU cache with the given
+ // maximum size.
+ size_t maxSize() const;
+ void setMaxSize(size_t maxSize = NPos);
+
+ size_t currentSize() const;
+
+ List<Key> keys() const;
+ List<Value> values() const;
+
+ // If ttlUpdateEnabled is false, then the time to live for entries will not
+ // be updated on access.
+ bool ttlUpdateEnabled() const;
+ void setTtlUpdateEnabled(bool enabled);
+
+ // If the value is in the cache, returns it and updates the access time,
+ // otherwise returns nullptr.
+ Value* ptr(Key const& key);
+
+ // Put the given value into the cache.
+ void set(Key const& key, Value value);
+ // Removes the given value from the cache. If found and removed, returns
+ // true.
+ bool remove(Key const& key);
+
+ // Remove all key / value pairs matching a filter.
+ void removeWhere(function<bool(Key const&, Value&)> filter);
+
+ // If the value for the key is not found in the cache, produce it with the
+ // given producer. Producer should take the key as an argument and return
+ // the Value.
+ template <typename Producer>
+ Value& get(Key const& key, Producer producer);
+
+ void clear();
+
+ // Cleanup any cached entries that are older than their time to live, if the
+ // refreshFilter is given, things that match the refreshFilter instead have
+ // their ttl refreshed rather than being removed.
+ void cleanup(function<bool(Key const&, Value const&)> refreshFilter = {});
+
+private:
+ LruCacheType m_cache;
+ int64_t m_timeToLive;
+ int m_timeSmear;
+ bool m_ttlUpdateEnabled;
+};
+
+template <typename Key, typename Value, typename Compare = std::less<Key>, typename Allocator = BlockAllocator<pair<Key const, pair<int64_t, Value>>, 1024>>
+using TtlCache = TtlCacheBase<LruCache<Key, pair<int64_t, Value>, Compare, Allocator>>;
+
+template <typename Key, typename Value, typename Hash = Star::hash<Key>, typename Equals = std::equal_to<Key>, typename Allocator = BlockAllocator<pair<Key const, pair<int64_t, Value>>, 1024>>
+using HashTtlCache = TtlCacheBase<HashLruCache<Key, pair<int64_t, Value>, Hash, Equals, Allocator>>;
+
+template <typename LruCacheType>
+TtlCacheBase<LruCacheType>::TtlCacheBase(int64_t timeToLive, int timeSmear, size_t maxSize, bool ttlUpdateEnabled) {
+ m_cache.setMaxSize(maxSize);
+ m_timeToLive = timeToLive;
+ m_timeSmear = timeSmear;
+ m_ttlUpdateEnabled = ttlUpdateEnabled;
+}
+
+template <typename LruCacheType>
+int64_t TtlCacheBase<LruCacheType>::timeToLive() const {
+ return m_timeToLive;
+}
+
+template <typename LruCacheType>
+void TtlCacheBase<LruCacheType>::setTimeToLive(int64_t timeToLive) {
+ m_timeToLive = timeToLive;
+}
+
+template <typename LruCacheType>
+int TtlCacheBase<LruCacheType>::timeSmear() const {
+ return m_timeSmear;
+}
+
+template <typename LruCacheType>
+void TtlCacheBase<LruCacheType>::setTimeSmear(int timeSmear) {
+ m_timeSmear = timeSmear;
+}
+
+template <typename LruCacheType>
+bool TtlCacheBase<LruCacheType>::ttlUpdateEnabled() const {
+ return m_ttlUpdateEnabled;
+}
+
+template <typename LruCacheType>
+size_t TtlCacheBase<LruCacheType>::maxSize() const {
+ return m_cache.maxSize();
+}
+
+template <typename LruCacheType>
+void TtlCacheBase<LruCacheType>::setMaxSize(size_t maxSize) {
+ m_cache.setMaxSize(maxSize);
+}
+
+template <typename LruCacheType>
+size_t TtlCacheBase<LruCacheType>::currentSize() const {
+ return m_cache.currentSize();
+}
+
+template <typename LruCacheType>
+auto TtlCacheBase<LruCacheType>::keys() const -> List<Key> {
+ return m_cache.keys();
+}
+
+template <typename LruCacheType>
+auto TtlCacheBase<LruCacheType>::values() const -> List<Value> {
+ List<Value> values;
+ for (auto& p : m_cache.values())
+ values.append(move(p.second));
+ return values;
+}
+
+template <typename LruCacheType>
+void TtlCacheBase<LruCacheType>::setTtlUpdateEnabled(bool enabled) {
+ m_ttlUpdateEnabled = enabled;
+}
+
+template <typename LruCacheType>
+auto TtlCacheBase<LruCacheType>::ptr(Key const& key) -> Value * {
+ if (auto p = m_cache.ptr(key)) {
+ if (m_ttlUpdateEnabled)
+ p->first = Time::monotonicMilliseconds() + Random::randInt(-m_timeSmear, m_timeSmear);
+ return &p->second;
+ }
+ return nullptr;
+}
+
+template <typename LruCacheType>
+void TtlCacheBase<LruCacheType>::set(Key const& key, Value value) {
+ m_cache.set(key, make_pair(Time::monotonicMilliseconds() + Random::randInt(-m_timeSmear, m_timeSmear), value));
+}
+
+template <typename LruCacheType>
+bool TtlCacheBase<LruCacheType>::remove(Key const& key) {
+ return m_cache.remove(key);
+}
+
+template <typename LruCacheType>
+void TtlCacheBase<LruCacheType>::removeWhere(function<bool(Key const&, Value&)> filter) {
+ m_cache.removeWhere([&filter](auto const& key, auto& value) { return filter(key, value.second); });
+}
+
+template <typename LruCacheType>
+template <typename Producer>
+auto TtlCacheBase<LruCacheType>::get(Key const& key, Producer producer) -> Value & {
+ auto& value = m_cache.get(key, [producer](Key const& key) {
+ return pair<int64_t, Value>(0, producer(key));
+ });
+ if (value.first == 0 || m_ttlUpdateEnabled)
+ value.first = Time::monotonicMilliseconds() + Random::randInt(-m_timeSmear, m_timeSmear);
+ return value.second;
+}
+
+template <typename LruCacheType>
+void TtlCacheBase<LruCacheType>::clear() {
+ m_cache.clear();
+}
+
+template <typename LruCacheType>
+void TtlCacheBase<LruCacheType>::cleanup(function<bool(Key const&, Value const&)> refreshFilter) {
+ int64_t currentTime = Time::monotonicMilliseconds();
+ m_cache.removeWhere([&](auto const& key, auto& value) {
+ if (refreshFilter && refreshFilter(key, value.second)) {
+ value.first = currentTime;
+ } else {
+ if (currentTime - value.first > m_timeToLive)
+ return true;
+ }
+ return false;
+ });
+}
+
+}
+
+#endif