Skip to content

Commit

Permalink
lb/TranslationCache: use class IntrusiveCache instead of StaticCache
Browse files Browse the repository at this point in the history
The StaticCache class has a huge memory usage even when it's empty and
is badly tuned for large installations.  Let's use the new
IntrusiveCache class which allocates items dynamically, preparing for
making the cache size configurable.
  • Loading branch information
MaxKellermann committed Sep 2, 2024
1 parent 4c58109 commit 7df23b8
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 25 deletions.
1 change: 1 addition & 0 deletions debian/changelog
Original file line number Diff line number Diff line change
Expand Up @@ -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

--

Expand Down
31 changes: 14 additions & 17 deletions src/lb/TranslationCache.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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,
Expand All @@ -180,7 +177,7 @@ LbTranslationCache::GetStats() const noexcept
void
LbTranslationCache::Clear() noexcept
{
cache.Clear();
cache.clear();
seen_vary.Clear();
}

Expand Down Expand Up @@ -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);
});
}

Expand Down Expand Up @@ -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();
}
Expand All @@ -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);
}
42 changes: 35 additions & 7 deletions src/lb/TranslationCache.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -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 <string>
Expand All @@ -24,28 +25,46 @@ class LbTranslationCache final {

public:
struct Item {
IntrusiveCacheHook cache_hook;
IntrusiveHashSetHook<IntrusiveHookMode::AUTO_UNLINK> 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 {
Expand Down Expand Up @@ -88,8 +107,17 @@ private:
std::equal_to<std::string_view>>,
IntrusiveHashSetMemberHookTraits<&Item::per_site_hook>> per_site;

using Cache = StaticCache<std::string, Item, 65536, N_BUCKETS,
std::hash<std::string_view>, std::equal_to<std::string_view>>;
using Cache =
IntrusiveCache<Item,
N_BUCKETS,
IntrusiveCacheOperators<Item,
Item::GetKey,
std::hash<std::string_view>,
std::equal_to<std::string_view>,
Item::SizeOf,
DeleteDisposer>,
IntrusiveCacheMemberHookTraits<&Item::cache_hook>>;

Cache cache;

Vary seen_vary;
Expand All @@ -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;
Expand Down
3 changes: 2 additions & 1 deletion src/lb/TranslationHandler.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

0 comments on commit 7df23b8

Please sign in to comment.