mirror of
https://git.haproxy.org/git/haproxy.git/
synced 2025-08-09 16:47:18 +02:00
MEDIUM: cache: store sha1 for hashing the cache key
The cache was relying on the txn->uri for creating its key, which was a big problem when there was no log activated. This patch does a sha1 of the host + uri, and stores it in the txn. When a object is stored, the eb32node uses the first 32 bits of the hash as a key, and the whole hash is stored in the cache entry. During a lookup, the truncated hash is used, and when it matches an entry we check the real sha1.
This commit is contained in:
parent
7fc96d5a01
commit
f528fff46b
@ -319,6 +319,7 @@ struct http_txn {
|
|||||||
/* 1 unused byte here */
|
/* 1 unused byte here */
|
||||||
short status; /* HTTP status from the server, negative if from proxy */
|
short status; /* HTTP status from the server, negative if from proxy */
|
||||||
|
|
||||||
|
char cache_hash[20]; /* Store the cache hash */
|
||||||
char *uri; /* first line if log needed, NULL otherwise */
|
char *uri; /* first line if log needed, NULL otherwise */
|
||||||
char *cli_cookie; /* cookie presented by the client, in capture mode */
|
char *cli_cookie; /* cookie presented by the client, in capture mode */
|
||||||
char *srv_cookie; /* cookie presented by the server, in capture mode */
|
char *srv_cookie; /* cookie presented by the server, in capture mode */
|
||||||
|
60
src/cache.c
60
src/cache.c
@ -11,6 +11,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <eb32tree.h>
|
#include <eb32tree.h>
|
||||||
|
#include <import/sha1.h>
|
||||||
|
|
||||||
#include <types/action.h>
|
#include <types/action.h>
|
||||||
#include <types/cli.h>
|
#include <types/cli.h>
|
||||||
@ -63,6 +64,7 @@ struct cache_entry {
|
|||||||
unsigned int latest_validation; /* latest validation date */
|
unsigned int latest_validation; /* latest validation date */
|
||||||
unsigned int expire; /* expiration date */
|
unsigned int expire; /* expiration date */
|
||||||
struct eb32_node eb; /* ebtree node used to hold the cache object */
|
struct eb32_node eb; /* ebtree node used to hold the cache object */
|
||||||
|
char hash[20];
|
||||||
unsigned char data[0];
|
unsigned char data[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -71,16 +73,21 @@ struct cache_entry {
|
|||||||
static struct list caches = LIST_HEAD_INIT(caches);
|
static struct list caches = LIST_HEAD_INIT(caches);
|
||||||
static struct cache *tmp_cache_config = NULL;
|
static struct cache *tmp_cache_config = NULL;
|
||||||
|
|
||||||
struct cache_entry *entry_exist(struct cache *cache, struct cache_entry *new_entry)
|
struct cache_entry *entry_exist(struct cache *cache, char *hash)
|
||||||
{
|
{
|
||||||
struct eb32_node *node;
|
struct eb32_node *node;
|
||||||
struct cache_entry *entry;
|
struct cache_entry *entry;
|
||||||
|
|
||||||
node = eb32_lookup(&cache->entries, new_entry->eb.key);
|
node = eb32_lookup(&cache->entries, (*(unsigned int *)hash));
|
||||||
if (!node)
|
if (!node)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
entry = eb32_entry(node, struct cache_entry, eb);
|
entry = eb32_entry(node, struct cache_entry, eb);
|
||||||
|
|
||||||
|
/* if that's not the right node */
|
||||||
|
if (memcmp(entry->hash, hash, sizeof(entry->hash)))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
if (entry->expire > now.tv_sec) {
|
if (entry->expire > now.tv_sec) {
|
||||||
return entry;
|
return entry;
|
||||||
} else {
|
} else {
|
||||||
@ -443,11 +450,12 @@ enum act_return http_action_store_cache(struct act_rule *rule, struct proxy *px,
|
|||||||
cache_ctx->first_block = first;
|
cache_ctx->first_block = first;
|
||||||
object = (struct cache_entry *)first->data;
|
object = (struct cache_entry *)first->data;
|
||||||
|
|
||||||
object->eb.key = hash_djb2(txn->uri, strlen(txn->uri));
|
object->eb.key = (*(unsigned int *)&txn->cache_hash);
|
||||||
|
memcpy(object->hash, txn->cache_hash, sizeof(object->hash));
|
||||||
/* Insert the node later on caching success */
|
/* Insert the node later on caching success */
|
||||||
|
|
||||||
shctx_lock(shctx);
|
shctx_lock(shctx);
|
||||||
if (entry_exist((struct cache *)rule->arg.act.p[0], object)) {
|
if (entry_exist((struct cache *)rule->arg.act.p[0], txn->cache_hash)) {
|
||||||
shctx_unlock(shctx);
|
shctx_unlock(shctx);
|
||||||
if (filter->ctx) {
|
if (filter->ctx) {
|
||||||
object->eb.key = 0;
|
object->eb.key = 0;
|
||||||
@ -592,19 +600,53 @@ enum act_parse_ret parse_cache_store(const char **args, int *orig_arg, struct pr
|
|||||||
return ACT_RET_PRS_ERR;
|
return ACT_RET_PRS_ERR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This produces a sha1 hash of the concatenation of the first
|
||||||
|
* occurrence of the Host header followed by the path component if it
|
||||||
|
* begins with a slash ('/'). */
|
||||||
|
int sha1_hosturi(struct http_txn *txn)
|
||||||
|
{
|
||||||
|
struct hdr_ctx ctx;
|
||||||
|
|
||||||
|
blk_SHA_CTX sha1_ctx;
|
||||||
|
struct chunk *trash;
|
||||||
|
char *path;
|
||||||
|
char *end;
|
||||||
|
trash = get_trash_chunk();
|
||||||
|
|
||||||
|
/* retrive the host */
|
||||||
|
ctx.idx = 0;
|
||||||
|
if (!http_find_header2("Host", 4, txn->req.chn->buf->p, &txn->hdr_idx, &ctx))
|
||||||
|
return 0;
|
||||||
|
chunk_strncat(trash, ctx.line + ctx.val, ctx.vlen);
|
||||||
|
|
||||||
|
/* now retrieve the path */
|
||||||
|
end = txn->req.chn->buf->p + txn->req.sl.rq.u + txn->req.sl.rq.u_l;
|
||||||
|
path = http_get_path(txn);
|
||||||
|
if (!path)
|
||||||
|
return 0;
|
||||||
|
chunk_strncat(trash, path, end - path);
|
||||||
|
|
||||||
|
/* hash everything */
|
||||||
|
blk_SHA1_Init(&sha1_ctx);
|
||||||
|
blk_SHA1_Update(&sha1_ctx, trash->str, trash->len);
|
||||||
|
blk_SHA1_Final((unsigned char *)txn->cache_hash, &sha1_ctx);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
enum act_return http_action_req_cache_use(struct act_rule *rule, struct proxy *px,
|
enum act_return http_action_req_cache_use(struct act_rule *rule, struct proxy *px,
|
||||||
struct session *sess, struct stream *s, int flags)
|
struct session *sess, struct stream *s, int flags)
|
||||||
{
|
{
|
||||||
|
|
||||||
struct cache_entry search_entry;
|
|
||||||
struct cache_entry *res;
|
struct cache_entry *res;
|
||||||
|
|
||||||
struct cache *cache = (struct cache *)rule->arg.act.p[0];
|
struct cache *cache = (struct cache *)rule->arg.act.p[0];
|
||||||
|
|
||||||
search_entry.eb.key = hash_djb2(s->txn->uri, strlen(s->txn->uri));
|
sha1_hosturi(s->txn);
|
||||||
|
|
||||||
shctx_lock(shctx_ptr(cache));
|
shctx_lock(shctx_ptr(cache));
|
||||||
res = entry_exist(cache, &search_entry);
|
res = entry_exist(cache, s->txn->cache_hash);
|
||||||
if (res) {
|
if (res) {
|
||||||
struct appctx *appctx;
|
struct appctx *appctx;
|
||||||
shctx_row_inc_hot(shctx_ptr(cache), block_ptr(res));
|
shctx_row_inc_hot(shctx_ptr(cache), block_ptr(res));
|
||||||
@ -900,7 +942,7 @@ static int cli_io_handler_show_cache(struct appctx *appctx)
|
|||||||
}
|
}
|
||||||
|
|
||||||
entry = container_of(node, struct cache_entry, eb);
|
entry = container_of(node, struct cache_entry, eb);
|
||||||
chunk_appendf(&trash, "%p (size: %u (%u blocks), refcount:%u, expire: %d)\n", entry, block_ptr(entry)->len, block_ptr(entry)->block_count, block_ptr(entry)->refcount, entry->expire - (int)now.tv_sec);
|
chunk_appendf(&trash, "%p hash:%u size:%u (%u blocks), refcount:%u, expire:%d\n", entry, (*(unsigned int *)entry->hash), block_ptr(entry)->len, block_ptr(entry)->block_count, block_ptr(entry)->refcount, entry->expire - (int)now.tv_sec);
|
||||||
|
|
||||||
next_key = node->key + 1;
|
next_key = node->key + 1;
|
||||||
appctx->ctx.cli.i0 = next_key;
|
appctx->ctx.cli.i0 = next_key;
|
||||||
|
Loading…
Reference in New Issue
Block a user