Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions doc/admin-guide/files/records.yaml.en.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2390,6 +2390,19 @@ Cache Control
Establishes a guaranteed maximum lifetime boundary for object freshness.
Setting this to ``0`` disables the feature.

.. ts:cv:: CONFIG proxy.config.http.cache.try_compat_key_read INT 0
:reloadable:

When enabled (``1``), |TS| will try to lookup the cached object using the
previous cache key generation algorithm, but will always write new objects
using the newest key generation. This might be temporarily necessary
if a large cache was created by the previous version of ATS but the new
version changed the way cache keys are generated. If this is turned on,
a metric called `proxy.process.http.cache.compat_key_reads` will be
incremented any time the compat cache lookup successfully finds the object.
You can monitor this metric and know when its safe to turn this feature off
as the cache wraps around.

.. ts:cv:: CONFIG proxy.config.http.cache.range.lookup INT 1
:overridable:

Expand Down
12 changes: 12 additions & 0 deletions include/proxy/hdrs/URL.h
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,7 @@ void url_called_set(URLImpl *url);
char *url_string_get_buf(URLImpl *url, char *dstbuf, int dstbuf_size, int *length);

void url_CryptoHash_get(const URLImpl *url, CryptoHash *hash, bool ignore_query = false, cache_generation_t generation = -1);
void url_CryptoHash_get_92(const URLImpl *url, CryptoHash *hash, bool ignore_query = false, cache_generation_t generation = -1);
void url_host_CryptoHash_get(URLImpl *url, CryptoHash *hash);

constexpr bool USE_STRICT_URI_PARSING = true;
Expand Down Expand Up @@ -278,6 +279,7 @@ class URL : public HdrHeapSDKHandle
char *string_get_ref(int *length = nullptr, unsigned normalization_flags = URLNormalize::NONE) const;
char *string_get_buf(char *dstbuf, int dsbuf_size, int *length = nullptr) const;
void hash_get(CryptoHash *hash, bool ignore_query = false, cache_generation_t generation = -1) const;
void hash_get92(CryptoHash *hash, bool ignore_query = false, cache_generation_t generation = -1) const;
void host_hash_get(CryptoHash *hash) const;

const char *scheme_get(int *length);
Expand Down Expand Up @@ -496,6 +498,16 @@ URL::hash_get(CryptoHash *hash, bool ignore_query, cache_generation_t generation
url_CryptoHash_get(m_url_impl, hash, ignore_query, generation);
}

/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/

inline void
URL::hash_get92(CryptoHash *hash, bool ignore_query, cache_generation_t generation) const
{
ink_assert(valid());
url_CryptoHash_get_92(m_url_impl, hash, ignore_query, generation);
}

/*-------------------------------------------------------------------------
-------------------------------------------------------------------------*/

Expand Down
3 changes: 3 additions & 0 deletions include/proxy/http/HttpConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@ struct HttpStatsBlock {
Metrics::Counter::AtomicType *origin_server_speed_bytes_per_sec_400M;
Metrics::Counter::AtomicType *origin_server_speed_bytes_per_sec_800M;
Metrics::Counter::AtomicType *origin_server_speed_bytes_per_sec_1G;
Metrics::Counter::AtomicType *cache_compat_key_reads;
};

enum CacheOpenWriteFailAction_t {
Expand Down Expand Up @@ -817,6 +818,8 @@ struct HttpConfigParams : public ConfigInfo {
MgmtByte http_host_sni_policy = 0;
MgmtByte scheme_proto_mismatch_policy = 2;

MgmtByte cache_try_compat_key_read = 0;

// noncopyable
/////////////////////////////////////
// operator = and copy constructor //
Expand Down
8 changes: 8 additions & 0 deletions include/proxy/http/HttpSM.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,12 @@ class PostDataBuffers
~PostDataBuffers();
};

enum class CompatibilityCacheLookup {
COMPAT_CACHE_LOOKUP_NORMAL = 0,
COMPAT_CACHE_LOOKUP_92,
COMPAT_CACHE_LAST,
};

class HttpSM : public Continuation, public PluginUserArgs<TS_USER_ARGS_TXN>
{
friend class HttpTransact;
Expand Down Expand Up @@ -533,6 +539,8 @@ class HttpSM : public Continuation, public PluginUserArgs<TS_USER_ARGS_TXN>
const char *plugin_tag = nullptr;
int64_t plugin_id = 0;

CompatibilityCacheLookup compatibility_cache_lookup = CompatibilityCacheLookup::COMPAT_CACHE_LOOKUP_NORMAL;

private:
HttpTunnel tunnel;

Expand Down
18 changes: 18 additions & 0 deletions src/iocore/cache/P_CacheInternal.h
Original file line number Diff line number Diff line change
Expand Up @@ -470,6 +470,11 @@ struct Cache {
static void generate_key(CryptoHash *hash, CacheURL *url);
static void generate_key(HttpCacheKey *hash, CacheURL *url, bool ignore_query = false, cache_generation_t generation = -1);

// These generate functions are used for backward compatibility with caches created with ATS9.2
// see `proxy.config.http.cache.try_compat_key_read`
static void generate_key92(CryptoHash *hash, CacheURL *url);
static void generate_key92(HttpCacheKey *hash, CacheURL *url, bool ignore_query = false, cache_generation_t generation = -1);

void vol_initialized(bool result);

int open_done();
Expand All @@ -495,6 +500,19 @@ Cache::generate_key(HttpCacheKey *key, CacheURL *url, bool ignore_query, cache_g
url->hash_get(&key->hash, ignore_query, generation);
}

inline void
Cache::generate_key92(CryptoHash *hash, CacheURL *url)
{
url->hash_get92(hash);
}

inline void
Cache::generate_key92(HttpCacheKey *key, CacheURL *url, bool ignore_query, cache_generation_t generation)
{
key->hostname = url->host_get(&key->hostlen);
url->hash_get92(&key->hash, ignore_query, generation);
}

inline unsigned int
cache_hash(const CryptoHash &hash)
{
Expand Down
117 changes: 117 additions & 0 deletions src/proxy/hdrs/URL.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1877,6 +1877,123 @@ url_CryptoHash_get(const URLImpl *url, CryptoHash *hash, bool ignore_query, cach
}
}

static inline void
url_CryptoHash_get_general_92(const URLImpl *url, CryptoContext &ctx, CryptoHash &hash, bool ignore_query,
cache_generation_t generation)
{
char buffer[BUFSIZE];
char *p, *e;
const char *strs[13], *ends[13];
const char *t;
in_port_t port;
int i, s;

strs[0] = url->m_ptr_scheme;
strs[1] = "://";
strs[2] = url->m_ptr_user;
strs[3] = ":";
strs[4] = url->m_ptr_password;
strs[5] = "@";
strs[6] = url->m_ptr_host;
strs[7] = "/";
strs[8] = url->m_ptr_path;

ends[0] = strs[0] + url->m_len_scheme;
ends[1] = strs[1] + 3;
ends[2] = strs[2] + url->m_len_user;
ends[3] = strs[3] + 1;
ends[4] = strs[4] + url->m_len_password;
ends[5] = strs[5] + 1;
ends[6] = strs[6] + url->m_len_host;
ends[7] = strs[7] + 1;
ends[8] = strs[8] + url->m_len_path;

strs[9] = ";";
strs[10] = url->m_ptr_params;
strs[11] = "?";

// Special case for the query paramters, allowing us to ignore them if requested
if (!ignore_query) {
strs[12] = url->m_ptr_query;
ends[12] = strs[12] + url->m_len_query;
} else {
strs[12] = nullptr;
ends[12] = nullptr;
}

ends[9] = strs[9] + 1;
ends[10] = strs[10] + url->m_len_params;
ends[11] = strs[11] + 1;

p = buffer;
e = buffer + BUFSIZE;

for (i = 0; i < 13; i++) {
if (strs[i]) {
t = strs[i];
s = 0;

while (t < ends[i]) {
if ((i == 0) || (i == 6)) { // scheme and host
unescape_str_tolower(p, e, t, ends[i], s);
} else if (i == 8 || i == 10 || i == 12) { // path, params, query
// Don't unescape the parts of the URI that are processed by the
// origin since it may behave differently based upon whether these are
// escaped or not. Therefore differently encoded strings should be
// cached separately via differentiated hashes.
int path_len = ends[i] - t;
int min_len = std::min(path_len, static_cast<int>(e - p));
memcpy(p, t, min_len);
p += min_len;
t += min_len;
} else {
unescape_str(p, e, t, ends[i], s);
}

if (p == e) {
ctx.update(buffer, BUFSIZE);
p = buffer;
}
}
}
}

if (p != buffer) {
ctx.update(buffer, p - buffer);
}
int buffer_len = static_cast<int>(p - buffer);
port = url_canonicalize_port(url->m_url_type, url->m_port);

ctx.update(&port, sizeof(port));
if (generation != -1) {
ctx.update(&generation, sizeof(generation));
Dbg(dbg_ctl_url_cachekey, "Final url string for cache hash key %.*s%d%d", buffer_len, buffer, port,
static_cast<int>(generation));
} else {
Dbg(dbg_ctl_url_cachekey, "Final url string for cache hash key %.*s%d", buffer_len, buffer, port);
}
ctx.finalize(hash);
}

void
url_CryptoHash_get_92(const URLImpl *url, CryptoHash *hash, bool ignore_query, cache_generation_t generation)
{
URLHashContext ctx;
if ((url_hash_method != 0) && (url->m_url_type == URL_TYPE_HTTP) &&
((url->m_len_user + url->m_len_password + url->m_len_params + (ignore_query ? 0 : url->m_len_query)) == 0) &&
(3 + 1 + 1 + 1 + 1 + 1 + 2 + url->m_len_scheme + url->m_len_host + url->m_len_path < BUFSIZE) &&
(memchr(url->m_ptr_host, '%', url->m_len_host) == nullptr) && (memchr(url->m_ptr_path, '%', url->m_len_path) == nullptr)) {
url_CryptoHash_get_fast(url, ctx, hash, generation);
#ifdef DEBUG
CryptoHash hash_general;
url_CryptoHash_get_general_92(url, ctx, hash_general, ignore_query, generation);
ink_assert(*hash == hash_general);
#endif
} else {
url_CryptoHash_get_general_92(url, ctx, *hash, ignore_query, generation);
}
}

#undef BUFSIZE

/*-------------------------------------------------------------------------
Expand Down
5 changes: 4 additions & 1 deletion src/proxy/http/HttpConfig.cc
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,7 @@ register_stat_callbacks()
Metrics::Counter::createPtr("proxy.process.http.origin_server_speed_bytes_per_sec_800M");
http_rsb.origin_server_speed_bytes_per_sec_1G =
Metrics::Counter::createPtr("proxy.process.http.origin_server_speed_bytes_per_sec_1G");
http_rsb.cache_compat_key_reads = Metrics::Counter::createPtr("proxy.process.http.cache.compat_key_reads");

Metrics::Derived::derive({
// Total bytes of client request body + headers
Expand Down Expand Up @@ -1108,7 +1109,7 @@ HttpConfig::startup()
HttpEstablishStaticConfigLongLong(c.post_copy_size, "proxy.config.http.post_copy_size");
HttpEstablishStaticConfigStringAlloc(c.redirect_actions_string, "proxy.config.http.redirect.actions");
HttpEstablishStaticConfigByte(c.http_host_sni_policy, "proxy.config.http.host_sni_policy");

HttpEstablishStaticConfigByte(c.cache_try_compat_key_read, "proxy.config.http.cache.try_compat_key_read");
HttpEstablishStaticConfigStringAlloc(c.oride.ssl_client_sni_policy, "proxy.config.ssl.client.sni_policy");
HttpEstablishStaticConfigStringAlloc(c.oride.ssl_client_alpn_protocols, "proxy.config.ssl.client.alpn_protocols");
HttpEstablishStaticConfigByte(c.scheme_proto_mismatch_policy, "proxy.config.ssl.client.scheme_proto_mismatch_policy");
Expand Down Expand Up @@ -1409,6 +1410,8 @@ HttpConfig::reconfigure()
params->oride.plugin_vc_default_buffer_index = m_master.oride.plugin_vc_default_buffer_index;
params->oride.plugin_vc_default_buffer_water_mark = m_master.oride.plugin_vc_default_buffer_water_mark;

params->cache_try_compat_key_read = m_master.cache_try_compat_key_read;

m_id = configProcessor.set(m_id, params);
}

Expand Down
19 changes: 18 additions & 1 deletion src/proxy/http/HttpSM.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@

*/

#include "proxy/http/HttpConfig.h"
#include "tsutil/Metrics.h"
#include "tsutil/ts_bw_format.h"
#include "proxy/ProxyTransaction.h"
#include "proxy/http/HttpSM.h"
Expand Down Expand Up @@ -2587,6 +2589,10 @@ HttpSM::state_cache_open_read(int event, void *data)
t_state.cache_info.hit_miss_code = SQUID_HIT_DISK;
}

if (compatibility_cache_lookup == CompatibilityCacheLookup::COMPAT_CACHE_LOOKUP_92) {
Metrics::Counter::increment(http_rsb.cache_compat_key_reads);
}

ink_assert(t_state.cache_info.object_read != nullptr);
call_transact_and_set_next_state(HttpTransact::HandleCacheOpenRead);
break;
Expand All @@ -2603,6 +2609,13 @@ HttpSM::state_cache_open_read(int event, void *data)
if (cache_sm.get_last_error() == -ECACHE_DOC_BUSY) {
t_state.cache_lookup_result = HttpTransact::CACHE_LOOKUP_DOC_BUSY;
} else {
if (t_state.http_config_param->cache_try_compat_key_read &&
compatibility_cache_lookup == CompatibilityCacheLookup::COMPAT_CACHE_LOOKUP_NORMAL) {
// do the retry
compatibility_cache_lookup = CompatibilityCacheLookup::COMPAT_CACHE_LOOKUP_92;
do_cache_lookup_and_read();
return 0;
}
t_state.cache_lookup_result = HttpTransact::CACHE_LOOKUP_MISS;
}

Expand Down Expand Up @@ -5000,7 +5013,11 @@ HttpSM::do_cache_lookup_and_read()
SMDbg(dbg_ctl_http_seq, "Issuing cache lookup for URL %s", c_url->string_get(&t_state.arena));

HttpCacheKey key;
Cache::generate_key(&key, c_url, t_state.txn_conf->cache_ignore_query, t_state.txn_conf->cache_generation_number);
if (compatibility_cache_lookup == CompatibilityCacheLookup::COMPAT_CACHE_LOOKUP_92) {
Cache::generate_key92(&key, c_url, t_state.txn_conf->cache_ignore_query, t_state.txn_conf->cache_generation_number);
} else {
Cache::generate_key(&key, c_url, t_state.txn_conf->cache_ignore_query, t_state.txn_conf->cache_generation_number);
}

t_state.hdr_info.cache_request.copy(&t_state.hdr_info.client_request);
HttpTransactHeaders::normalize_accept_encoding(t_state.txn_conf, &t_state.hdr_info.cache_request);
Expand Down
7 changes: 7 additions & 0 deletions src/records/RecordsConfig.cc
Original file line number Diff line number Diff line change
Expand Up @@ -638,6 +638,13 @@ static const RecordElement RecordsConfig[] =
{RECT_CONFIG, "proxy.config.http.cache.guaranteed_max_lifetime", RECD_INT, "31536000", RECU_DYNAMIC, RR_NULL, RECC_NULL, nullptr, RECA_NULL}
,

// ###################
// # Cache Compat #
// ###################
{RECT_CONFIG, "proxy.config.http.cache.try_compat_key_read", RECD_INT, "0", RECU_NULL, RR_NULL, RECC_INT, "[0-1]", RECA_NULL}
,


// ###################
// # Error Reporting #
// ###################
Expand Down