Skip to content

Commit

Permalink
cache: use struct StringWithHash
Browse files Browse the repository at this point in the history
This guarantess that hashes are only calculated once, and not twice
(lookup and store).  And it gives more control over how and when the
hash is calculated; since HttpCache has calculation hurts a lot, it is
now possible to use an optimized hash formula.
  • Loading branch information
MaxKellermann committed Jan 22, 2025
1 parent 41b2e18 commit ae56628
Show file tree
Hide file tree
Showing 16 changed files with 226 additions and 230 deletions.
17 changes: 9 additions & 8 deletions src/bp/Response.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ session_drop_widgets(RealmSession &session, const char *uri,
}

[[gnu::pure]]
static const char *
static StringWithHash
GetEncodingCacheKey(AllocatorPtr alloc,
const char *resource_tag,
std::string_view encoding,
Expand All @@ -122,15 +122,16 @@ GetEncodingCacheKey(AllocatorPtr alloc,
if EAGER_CACHE is enabled, and this code allows
putting EAGER_CACHE responses in the
EncodingCache */
return alloc.Concat(digest, "."sv, encoding);
return StringWithHash{alloc.ConcatView(digest, "."sv, encoding)};

if (resource_tag != nullptr)
if (const auto etag = response_headers.GetSloppy(etag_header);
etag.data() != nullptr)
return alloc.Concat(resource_tag, "|etag="sv, etag,
"."sv, encoding);
return StringWithHash{
alloc.ConcatView(resource_tag, "|etag="sv, etag, "."sv, encoding),
};

return nullptr;
return StringWithHash{{}, 0};
}

static void
Expand All @@ -143,9 +144,9 @@ MaybeCacheEncoded(EncodingCache *cache, AllocatorPtr alloc,
if (cache == nullptr)
return;

const char *key = GetEncodingCacheKey(alloc, resource_tag, encoding,
response_headers);
if (key == nullptr)
const auto key = GetEncodingCacheKey(alloc, resource_tag, encoding,
response_headers);
if (key.value.data() == nullptr)
return;

if (auto encoded = cache->Get(alloc.GetPool(), key)) {
Expand Down
6 changes: 3 additions & 3 deletions src/cache/Cache.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ Cache::RemoveItem(CacheItem &item) noexcept
}

CacheItem *
Cache::Get(const char *key) noexcept
Cache::Get(StringWithHash key) noexcept
{
auto i = items.find(key);
if (i == items.end())
Expand All @@ -112,7 +112,7 @@ Cache::Get(const char *key) noexcept
}

CacheItem *
Cache::GetMatch(const char *key,
Cache::GetMatch(StringWithHash key,
bool (*match)(const CacheItem *, void *),
void *ctx) noexcept
{
Expand Down Expand Up @@ -224,7 +224,7 @@ Cache::PutMatch(CacheItem &item,
}

void
Cache::Remove(const char *key) noexcept
Cache::Remove(StringWithHash key) noexcept
{
items.remove_and_dispose_key(key, ItemRemover{*this});
}
Expand Down
12 changes: 6 additions & 6 deletions src/cache/Cache.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ class Cache {
using ItemSet = IntrusiveHashSet<CacheItem, 65536,
IntrusiveHashSetOperators<CacheItem,
CacheItem::GetKeyFunction,
CacheItem::Hash,
CacheItem::Equal>,
std::hash<StringWithHash>,
std::equal_to<StringWithHash>>,
IntrusiveHashSetMemberHookTraits<&CacheItem::set_hook>>;

ItemSet items;
Expand Down Expand Up @@ -59,7 +59,7 @@ public:
std::chrono::system_clock::time_point SystemNow() const noexcept;

[[gnu::pure]]
CacheItem *Get(const char *key) noexcept;
CacheItem *Get(StringWithHash key) noexcept;

/**
* Find the first CacheItem for a key which matches with the
Expand All @@ -70,7 +70,7 @@ public:
* @param ctx a context pointer for the callback
*/
[[gnu::pure]]
CacheItem *GetMatch(const char *key,
CacheItem *GetMatch(StringWithHash key,
bool (*match)(const CacheItem *, void *),
void *ctx) noexcept;

Expand All @@ -97,14 +97,14 @@ public:
bool (*match)(const CacheItem *, void *),
void *ctx) noexcept;

void Remove(const char *key) noexcept;
void Remove(StringWithHash key) noexcept;

/**
* Removes all matching cache items.
*
* @return the number of items which were removed
*/
void RemoveKeyIf(const char *key,
void RemoveKeyIf(StringWithHash key,
std::predicate<const CacheItem &> auto pred) noexcept {
items.remove_and_dispose_key_if(key, pred, ItemRemover{*this});
}
Expand Down
25 changes: 2 additions & 23 deletions src/cache/Item.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,6 @@
// author: Max Kellermann <[email protected]>

#include "Item.hxx"
#include "util/djb_hash.hxx"
#include "util/StringAPI.hxx"

#include <cassert>

size_t
CacheItem::Hash::operator()(const char *_key) const noexcept
{
assert(_key != nullptr);

return djb_hash_string(_key);
}

bool
CacheItem::Equal::operator()(const char *a, const char *b) const noexcept
{
assert(a != nullptr);
assert(b != nullptr);

return StringIsEqual(a, b);
}

static constexpr std::chrono::steady_clock::time_point
ToSteady(std::chrono::steady_clock::time_point steady_now,
Expand All @@ -35,15 +14,15 @@ ToSteady(std::chrono::steady_clock::time_point steady_now,
: std::chrono::steady_clock::time_point();
}

CacheItem::CacheItem(const char *_key, std::size_t _size,
CacheItem::CacheItem(StringWithHash _key, std::size_t _size,
std::chrono::steady_clock::time_point now,
std::chrono::system_clock::time_point system_now,
std::chrono::system_clock::time_point _expires) noexcept
:CacheItem(_key, _size, ToSteady(now, system_now, _expires))
{
}

CacheItem::CacheItem(const char *_key, std::size_t _size,
CacheItem::CacheItem(StringWithHash _key, std::size_t _size,
std::chrono::steady_clock::time_point now,
std::chrono::seconds max_age) noexcept
:CacheItem(_key, _size, now + max_age)
Expand Down
23 changes: 7 additions & 16 deletions src/cache/Item.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#include "util/IntrusiveHashSet.hxx"
#include "util/IntrusiveList.hxx"
#include "util/SharedLease.hxx"
#include "util/StringWithHash.hxx"

#include <chrono>
#include <cstddef>
Expand All @@ -28,23 +29,23 @@ class CacheItem : public SharedAnchor {
/**
* The key under which this item is stored in the hash table.
*/
const char *const key;
const StringWithHash key;

std::chrono::steady_clock::time_point expires;

const size_t size;

public:
CacheItem(const char *_key, std::size_t _size,
CacheItem(StringWithHash _key, std::size_t _size,
std::chrono::steady_clock::time_point _expires) noexcept
:key(_key), expires(_expires), size(_size) {}

CacheItem(const char *_key, std::size_t _size,
CacheItem(StringWithHash _key, std::size_t _size,
std::chrono::steady_clock::time_point now,
std::chrono::system_clock::time_point system_now,
std::chrono::system_clock::time_point _expires) noexcept;

CacheItem(const char *_key, std::size_t _size,
CacheItem(StringWithHash _key, std::size_t _size,
std::chrono::steady_clock::time_point now,
std::chrono::seconds max_age) noexcept;

Expand All @@ -63,7 +64,7 @@ public:
Destroy();
}

const char *GetKey() const noexcept {
StringWithHash GetKey() const noexcept {
return key;
}

Expand All @@ -90,19 +91,9 @@ public:

virtual void Destroy() noexcept = 0;

struct Hash {
[[gnu::pure]]
size_t operator()(const char *key) const noexcept;
};

struct Equal {
[[gnu::pure]]
bool operator()(const char *a, const char *b) const noexcept;
};

struct GetKeyFunction {
[[gnu::pure]]
const char *operator()(const CacheItem &item) const noexcept {
StringWithHash operator()(const CacheItem &item) const noexcept {
return item.GetKey();
}
};
Expand Down
38 changes: 20 additions & 18 deletions src/http/cache/EncodingCache.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -32,21 +32,23 @@ class EncodingCacheItemKey {

public:
[[nodiscard]]
explicit EncodingCacheItemKey(const char *_key) noexcept
explicit EncodingCacheItemKey(std::string_view _key) noexcept
:key(_key) {}
};

struct EncodingCache::Item final : EncodingCacheItemKey, CacheItem, LeakDetector {
const std::string key;


const RubberAllocation allocation;

Item(const char *_key,
Item(StringWithHash _key,
std::chrono::steady_clock::time_point now,
std::chrono::system_clock::time_point system_now,
std::size_t _size, RubberAllocation &&_allocation) noexcept
:EncodingCacheItemKey(_key),
CacheItem(EncodingCacheItemKey::key.c_str(), _size, now, system_now,
:EncodingCacheItemKey(_key.value),
CacheItem(StringWithHash{EncodingCacheItemKey::key, _key.hash},
_size, now, system_now,
system_now + encoding_cache_default_expires),
allocation(std::move(_allocation)) {}

Expand All @@ -64,7 +66,7 @@ class EncodingCache::Store final

EncodingCache &cache;

const char *const key;
const StringWithHash key;

/**
* This event is initialized by the response callback, and limits
Expand All @@ -78,7 +80,7 @@ class EncodingCache::Store final
CancellablePointer rubber_cancel_ptr;

public:
Store(EncodingCache &_cache, const char *_key) noexcept
Store(EncodingCache &_cache, StringWithHash _key) noexcept
:cache(_cache), key(_key),
timeout_event(cache.GetEventLoop(), BIND_THIS_METHOD(OnTimeout)) {}

Expand Down Expand Up @@ -114,7 +116,7 @@ class EncodingCache::Store final
void OnTimeout() noexcept {
/* reading the response has taken too long already; don't store
this resource */
LogConcat(4, "EncodingCache", "timeout ", key);
LogConcat(4, "EncodingCache", "timeout ", key.value);
CancelStore();
}

Expand All @@ -140,7 +142,7 @@ EncodingCache::Store::RubberOutOfMemory() noexcept
{
rubber_cancel_ptr = nullptr;

LogConcat(4, "EncodingCache", "nocache oom ", key);
LogConcat(4, "EncodingCache", "nocache oom ", key.value);
++cache.stats.skips;
Destroy();
}
Expand All @@ -150,7 +152,7 @@ EncodingCache::Store::RubberTooLarge() noexcept
{
rubber_cancel_ptr = nullptr;

LogConcat(4, "EncodingCache", "nocache too large", key);
LogConcat(4, "EncodingCache", "nocache too large", key.value);
++cache.stats.skips;
Destroy();
}
Expand All @@ -160,22 +162,22 @@ EncodingCache::Store::RubberError(std::exception_ptr ep) noexcept
{
rubber_cancel_ptr = nullptr;

LogConcat(4, "EncodingCache", "body_error ", key, ": ", ep);
LogConcat(4, "EncodingCache", "body_error ", key.value, ": ", ep);
++cache.stats.skips;
Destroy();
}

UnusedIstreamPtr
EncodingCache::Get(struct pool &pool, const char *key) noexcept
EncodingCache::Get(struct pool &pool, StringWithHash key) noexcept
{
auto *item = (EncodingCache::Item *)cache.Get(key);
if (item == nullptr) {
LogConcat(6, "EncodingCache", "miss ", key);
LogConcat(6, "EncodingCache", "miss ", key.value);
++stats.misses;
return {};
}

LogConcat(5, "EncodingCache", "hit ", key);
LogConcat(5, "EncodingCache", "hit ", key.value);
++stats.hits;

return NewSharedLeaseIstream(pool,
Expand All @@ -186,7 +188,7 @@ EncodingCache::Get(struct pool &pool, const char *key) noexcept

UnusedIstreamPtr
EncodingCache::Put(struct pool &pool,
const char *key,
StringWithHash key,
UnusedIstreamPtr src) noexcept
{
if (!src)
Expand All @@ -195,12 +197,12 @@ EncodingCache::Put(struct pool &pool,
if (const auto available = src.GetAvailable(true);
available > cacheable_size_limit) {
/* too large for the cache */
LogConcat(4, "EncodingCache", "nocache too large", key);
LogConcat(4, "EncodingCache", "nocache too large", key.value);
++stats.skips;
return src;
}

LogConcat(4, "EncodingCache", "put ", key);
LogConcat(4, "EncodingCache", "put ", key.value);

/* tee the body: one goes to our client, and one goes into the
cache */
Expand All @@ -217,10 +219,10 @@ EncodingCache::Put(struct pool &pool,
}

void
EncodingCache::Add(const char *key,
EncodingCache::Add(StringWithHash key,
RubberAllocation &&a, std::size_t size) noexcept
{
LogConcat(4, "EncodingCache", "add ", key);
LogConcat(4, "EncodingCache", "add ", key.value);
++stats.stores;

auto item = new Item(key,
Expand Down
6 changes: 3 additions & 3 deletions src/http/cache/EncodingCache.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,13 @@ public:
Compress();
}

UnusedIstreamPtr Get(struct pool &pool, const char *key) noexcept;
UnusedIstreamPtr Get(struct pool &pool, StringWithHash key) noexcept;

UnusedIstreamPtr Put(struct pool &pool, const char *key,
UnusedIstreamPtr Put(struct pool &pool, StringWithHash key,
UnusedIstreamPtr src) noexcept;

private:
void Add(const char *key,
void Add(StringWithHash key,
RubberAllocation &&a, std::size_t size) noexcept;

void Compress() noexcept {
Expand Down
Loading

0 comments on commit ae56628

Please sign in to comment.