diff --git a/debian/changelog b/debian/changelog index 883059781..7079b7055 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,6 +2,7 @@ cm4all-beng-proxy (18.2) unstable; urgency=low * spawn: do not log "failed to kill: No such process" * lb/translation: store ANALYTICS_ID and GENERATOR in the cache + * lb/translation: dynamic cache allocation -- diff --git a/src/lb/TranslationCache.cxx b/src/lb/TranslationCache.cxx index c2709ff9f..fe29fc63e 100644 --- a/src/lb/TranslationCache.cxx +++ b/src/lb/TranslationCache.cxx @@ -134,8 +134,9 @@ class LbTranslationCacheKeyIterator { } }; -LbTranslationCache::Item::Item(const TranslateResponse &response) noexcept - :status(response.status), +LbTranslationCache::Item::Item(const char *_key, const TranslateResponse &response) noexcept + :key(_key), + status(response.status), https_only(response.https_only) { if (response.redirect != nullptr) @@ -163,11 +164,7 @@ LbTranslationCache::Item::Item(const TranslateResponse &response) noexcept CacheStats LbTranslationCache::GetStats() const noexcept { - size_t size = 0; - - cache.ForEach([&size](const std::string &key, const Item &item){ - size += key.length() + item.GetAllocatedMemory(); - }); + const std::size_t size = cache.GetTotalSize(); stats.allocator = { .brutto_size = size, @@ -180,7 +177,7 @@ LbTranslationCache::GetStats() const noexcept void LbTranslationCache::Clear() noexcept { - cache.Clear(); + cache.clear(); seen_vary.Clear(); } @@ -232,15 +229,14 @@ LbTranslationCache::Invalidate(const TranslationInvalidateRequest &request) noex return; if (request.site != nullptr) - per_site.remove_and_dispose_key_if(request.site, [this, &request](const Item &item){ - const auto &key = cache.KeyOf(item); - return MatchKey(key.c_str(), request) && MatchItem(item, request); + per_site.remove_and_dispose_key_if(request.site, [&request](const Item &item){ + return MatchKey(item.key.c_str(), request) && MatchItem(item, request); }, [this](Item *item){ cache.RemoveItem(*item); }); else - cache.RemoveIf([&request](const std::string &key, const Item &item){ - return MatchKey(key.c_str(), request) && MatchItem(item, request); + cache.RemoveIf([&request](const Item &item){ + return MatchKey(item.key.c_str(), request) && MatchItem(item, request); }); } @@ -275,7 +271,7 @@ LbTranslationCache::Put(const IncomingHttpRequest &request, const Vary vary(response); - if (!vary && !cache.IsEmpty()) { + if (!vary && !cache.empty()) { logger(4, "VARY disappeared, clearing cache"); Clear(); } @@ -288,7 +284,8 @@ LbTranslationCache::Put(const IncomingHttpRequest &request, logger(4, "store '", key, "'"); ++stats.stores; - auto &item = cache.PutOrReplace(std::string_view{key}, response); - if (!item.site.empty()) - per_site.insert(item); + auto *item = new Item(key, response); + if (!item->site.empty()) + per_site.insert(*item); + cache.Put(*item); } diff --git a/src/lb/TranslationCache.hxx b/src/lb/TranslationCache.hxx index ddc1c31f1..97db5a072 100644 --- a/src/lb/TranslationCache.hxx +++ b/src/lb/TranslationCache.hxx @@ -6,7 +6,8 @@ #include "stats/CacheStats.hxx" #include "io/Logger.hxx" -#include "util/StaticCache.hxx" +#include "util/DeleteDisposer.hxx" +#include "util/IntrusiveCache.hxx" #include "util/IntrusiveList.hxx" #include @@ -24,28 +25,46 @@ class LbTranslationCache final { public: struct Item { + IntrusiveCacheHook cache_hook; IntrusiveHashSetHook per_site_hook; + std::string key; + HttpStatus status = {}; uint16_t https_only = 0; std::string redirect, message, pool, canonical_host, site, analytics_id, generator; [[nodiscard]] - explicit Item(const TranslateResponse &response) noexcept; + explicit Item(const char *_key, const TranslateResponse &response) noexcept; [[gnu::pure]] size_t GetAllocatedMemory() const noexcept { - return sizeof(*this) + redirect.length() + message.length() + + return sizeof(*this) + key.length() + + redirect.length() + message.length() + pool.length() + canonical_host.length() + site.length() + analytics_id.length() + generator.length(); } + struct GetKey { + [[gnu::pure]] + std::string_view operator()(const Item &item) const noexcept { + return item.key; + } + }; + struct GetSite { [[gnu::pure]] std::string_view operator()(const Item &item) const noexcept { return item.site; } }; + + struct SizeOf { + [[gnu::pure]] + std::size_t operator()(const Item &item) const noexcept { + return item.GetAllocatedMemory(); + } + }; }; struct Vary { @@ -88,8 +107,17 @@ private: std::equal_to>, IntrusiveHashSetMemberHookTraits<&Item::per_site_hook>> per_site; - using Cache = StaticCache, std::equal_to>; + using Cache = + IntrusiveCache, + std::equal_to, + Item::SizeOf, + DeleteDisposer>, + IntrusiveCacheMemberHookTraits<&Item::cache_hook>>; + Cache cache; Vary seen_vary; @@ -98,8 +126,8 @@ private: public: [[nodiscard]] - LbTranslationCache() noexcept - :logger("tcache") {} + explicit LbTranslationCache(std::size_t max_size) noexcept + :logger("tcache"), cache(max_size) {} [[gnu::pure]] CacheStats GetStats() const noexcept; diff --git a/src/lb/TranslationHandler.cxx b/src/lb/TranslationHandler.cxx index 7afc7965b..0cfac0162 100644 --- a/src/lb/TranslationHandler.cxx +++ b/src/lb/TranslationHandler.cxx @@ -154,7 +154,8 @@ LbTranslationHandler::PutCache(const IncomingHttpRequest &request, return; if (!cache) - cache.reset(new LbTranslationCache()); + // TODO configurable cache size + cache.reset(new LbTranslationCache(256 * std::size_t{1024 * 1024})); cache->Put(request, listener_tag, response); }