This is an automated email from the ASF dual-hosted git repository.
zwoop pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git
The following commit(s) were added to refs/heads/master by this push:
new 42d86fea90 Improve seen list for the RAM cache (#10662)
42d86fea90 is described below
commit 42d86fea90085721d3f49e85c2589f8841cffd22
Author: Leif Hedstrom <[email protected]>
AuthorDate: Thu Apr 4 13:44:17 2024 -0600
Improve seen list for the RAM cache (#10662)
---
doc/admin-guide/files/records.yaml.en.rst | 11 ++++++++-
src/iocore/cache/RamCacheLRU.cc | 38 +++++++++++++++++++------------
src/records/RecordsConfig.cc | 2 +-
3 files changed, 35 insertions(+), 16 deletions(-)
diff --git a/doc/admin-guide/files/records.yaml.en.rst
b/doc/admin-guide/files/records.yaml.en.rst
index 6045e3d7f1..a1fdc5b7ae 100644
--- a/doc/admin-guide/files/records.yaml.en.rst
+++ b/doc/admin-guide/files/records.yaml.en.rst
@@ -2559,10 +2559,19 @@ RAM Cache
Enabling this option will filter inserts into the RAM cache to ensure that
they have been seen at least once. For the **LRU**, this provides scan
- resistance. Note that **CLFUS** already requires that a document have
history
+ resistance.
+
+ As of ATS v10.0.0 and later, this setting can take values in the range
``0`` to
+ ``9``. Values above ``1`` will only enable the seen filter after a certain
+ threshold of RAM cache usage has been reached. The threshold is determined
by
+ the value of this setting, with ``2`` being 50% filled, ``3`` being 67%
filled,
+ and so on.
+
+ Note that **CLFUS** already requires that a document have history
before it is inserted, so for **CLFUS**, setting this option means that a
document must be seen three times before it is added to the RAM cache.
+
.. ts:cv:: CONFIG proxy.config.cache.ram_cache.compress INT 0
The **CLFUS** RAM cache also supports an optional in-memory compression.
diff --git a/src/iocore/cache/RamCacheLRU.cc b/src/iocore/cache/RamCacheLRU.cc
index 3da2e7644a..01f2d09c66 100644
--- a/src/iocore/cache/RamCacheLRU.cc
+++ b/src/iocore/cache/RamCacheLRU.cc
@@ -22,6 +22,8 @@
*/
#include "P_Cache.h"
+#include <vector>
+#include <iterator>
struct RamCacheLRUEntry {
CryptoHash key;
@@ -47,7 +49,7 @@ struct RamCacheLRU : public RamCache {
void init(int64_t max_bytes, Stripe *stripe) override;
// private
- uint16_t *seen = nullptr;
+ std::vector<bool> *seen = nullptr;
Que(RamCacheLRUEntry, lru_link) lru;
DList(RamCacheLRUEntry, hash_link) *bucket = nullptr;
int nbuckets = 0;
@@ -84,13 +86,14 @@ RamCacheLRU::size() const
ClassAllocator<RamCacheLRUEntry> ramCacheLRUEntryAllocator("RamCacheLRUEntry");
-static const int bucket_sizes[] = {127, 251, 509, 1021,
2039, 4093, 8191, 16381,
- 32749, 65521, 131071, 262139,
524287, 1048573, 2097143, 4194301,
- 8388593, 16777213, 33554393, 67108859,
134217689, 268435399, 536870909};
+static const int bucket_sizes[] = {8191, 16381, 32749, 65521,
131071, 262139, 524287, 1048573, 2097143,
+ 4194301, 8388593, 16777213, 33554393,
67108859, 134217689, 268435399, 536870909, 1073741827};
void
RamCacheLRU::resize_hashtable()
{
+ ink_release_assert(ibuckets < static_cast<int>(std::size(bucket_sizes)));
+
int anbuckets = bucket_sizes[ibuckets];
DDbg(dbg_ctl_ram_cache, "resize hashtable %d", anbuckets);
int64_t s = anbuckets *
sizeof(DList(RamCacheLRUEntry, hash_link));
@@ -107,11 +110,12 @@ RamCacheLRU::resize_hashtable()
}
bucket = new_bucket;
nbuckets = anbuckets;
- ats_free(seen);
- int size = bucket_sizes[ibuckets] * sizeof(uint16_t);
+ delete seen;
if (cache_config_ram_cache_use_seen_filter) {
- seen = static_cast<uint16_t *>(ats_malloc(size));
- memset(seen, 0, size);
+ int size = bucket_sizes[ibuckets];
+
+ seen = new std::vector<bool>(size * 2); // Twice the size, to reduce
collision risks.
+ seen->assign(size * 2, false);
}
}
@@ -181,15 +185,21 @@ RamCacheLRU::put(CryptoHash *key, IOBufferData *data,
uint32_t len, bool, uint64
return 0;
}
uint32_t i = key->slice32(3) % nbuckets;
- if (cache_config_ram_cache_use_seen_filter) {
- uint16_t k = key->slice32(3) >> 16;
- uint16_t kk = seen[i];
- seen[i] = k;
- if ((kk != k)) {
+ if ((cache_config_ram_cache_use_seen_filter == 1) ||
+ // If proxy.config.cache.ram_cache.use_seen_filter is > 1, and the
cache is more than <n>% full, then use the seen filter.
+ // <n>% is calculated based on this setting, with 2 == 50%, 3 == 67%, 4
== 75%, up to 9 == 90%.
+ ((cache_config_ram_cache_use_seen_filter > 1) && (bytes >= max_bytes *
(1 - (1 / cache_config_ram_cache_use_seen_filter))))) {
+ uint32_t j = key->slice32(3) % (nbuckets * 2); // The seen filter bucket
size is 2x
+
+ if (!(*seen)[j]) {
DDbg(dbg_ctl_ram_cache, "put %X %" PRIu64 " len %d UNSEEN",
key->slice32(3), auxkey, len);
+ (*seen)[j] = true;
return 0;
+ } else {
+ (*seen)[j] = false; // Clear the seen filter slot for future entries.
}
}
+
RamCacheLRUEntry *e = bucket[i].head;
while (e) {
if (e->key == *key) {
@@ -223,7 +233,7 @@ RamCacheLRU::put(CryptoHash *key, IOBufferData *data,
uint32_t len, bool, uint64
}
}
DDbg(dbg_ctl_ram_cache, "put %X %" PRIu64 " INSERTED", key->slice32(3),
auxkey);
- if (objects > nbuckets) {
+ if (objects > nbuckets * 0.75) { // Resize when 75% "full"
++ibuckets;
resize_hashtable();
}
diff --git a/src/records/RecordsConfig.cc b/src/records/RecordsConfig.cc
index 9e3df88167..a9546a4917 100644
--- a/src/records/RecordsConfig.cc
+++ b/src/records/RecordsConfig.cc
@@ -809,7 +809,7 @@ static const RecordElement RecordsConfig[] =
,
{RECT_CONFIG, "proxy.config.cache.ram_cache.algorithm", RECD_INT, "1",
RECU_RESTART_TS, RR_NULL, RECC_INT, "[0-1]", RECA_NULL}
,
- {RECT_CONFIG, "proxy.config.cache.ram_cache.use_seen_filter", RECD_INT, "1",
RECU_RESTART_TS, RR_NULL, RECC_INT, "[0-1]", RECA_NULL}
+ {RECT_CONFIG, "proxy.config.cache.ram_cache.use_seen_filter", RECD_INT, "1",
RECU_RESTART_TS, RR_NULL, RECC_INT, "[0-9]", RECA_NULL}
,
{RECT_CONFIG, "proxy.config.cache.ram_cache.compress", RECD_INT, "0",
RECU_RESTART_TS, RR_NULL, RECC_INT, "[0-3]", RECA_NULL}
,