Commit c12e7eb7 authored by Poul-Henning Kamp's avatar Poul-Henning Kamp

Implement runtime part of VCL controlled hashing.

The vcl_hash() is now used to control which fields go
into the hash algorithm, and the default is stil,
as previously, the URL + Host: header.

But now it is controlled by the vcl code, with the
default vcl_hash() being:

	sub vcl_hash {
		req.hash += req.url;
		req.hash += req.http.host;
		hash;
	}

Once I get a bit further, this will be changed to

	sub vcl_hash {
		req.hash += req.url;
		if (req.http.host) {
			req.hash += req.http.host;
		} else {
			req.hash += server.ip;
		}
		hash;
	}

So that we correctly hash HTTP requests without Host:
headers, that go to a machine with multiple IP numbers.

If you want to add fields to the hash, just write
a vcl_hash that does not end in "hash;":

	sub vcl_hash {
		req.hash += req.http.cookie;
	}

If you want to override the default vcl_hash, just
say so:

	sub vcl_hash {
		req.hash += req.url;
		hash;	// do not continue into default vcl_hash
	}




git-svn-id: http://www.varnish-cache.org/svn/trunk/varnish-cache@1398 d4fa192b-c00b-0410-8231-f00ffab90ce4
parent 2e3d4875
...@@ -291,6 +291,9 @@ struct sess { ...@@ -291,6 +291,9 @@ struct sess {
struct workreq workreq; struct workreq workreq;
struct acct acct; struct acct acct;
char *hash_b; /* Start of hash string */
char *hash_e; /* End of hash string */
}; };
struct backend { struct backend {
......
...@@ -437,9 +437,18 @@ cnt_lookup(struct sess *sp) ...@@ -437,9 +437,18 @@ cnt_lookup(struct sess *sp)
{ {
struct object *o; struct object *o;
VCL_hash_method(sp); /* XXX: no-op for now */ assert(sp->http->f > sp->http->s);
assert(sp->http->f >= sp->http->t);
if (sp->obj == NULL) {
sp->hash_b = sp->http->f;
sp->hash_e = sp->hash_b;
VCL_hash_method(sp); /* XXX: no-op for now */
/* XXX check error */
}
o = HSH_Lookup(sp); o = HSH_Lookup(sp);
if (o == NULL) { if (o == NULL) {
/* /*
* We hit a busy object, disembark worker thread and expect * We hit a busy object, disembark worker thread and expect
...@@ -451,6 +460,14 @@ cnt_lookup(struct sess *sp) ...@@ -451,6 +460,14 @@ cnt_lookup(struct sess *sp)
return (1); return (1);
} }
xxxassert (sp->hash_e == sp->http->f);
if (sp->hash_e == sp->http->f) {
/* Nobody alloc'ed after us, free again */
sp->http->f = sp->hash_b;
}
sp->hash_b = sp->hash_e = NULL;
sp->obj = o; sp->obj = o;
/* If we inserted a new object it's a miss */ /* If we inserted a new object it's a miss */
......
...@@ -115,7 +115,6 @@ HSH_Lookup(struct sess *sp) ...@@ -115,7 +115,6 @@ HSH_Lookup(struct sess *sp)
struct http *h; struct http *h;
struct objhead *oh; struct objhead *oh;
struct object *o; struct object *o;
char *url, *host;
CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC); CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC);
...@@ -125,9 +124,6 @@ HSH_Lookup(struct sess *sp) ...@@ -125,9 +124,6 @@ HSH_Lookup(struct sess *sp)
h = sp->http; h = sp->http;
HSH_Prealloc(sp); HSH_Prealloc(sp);
url = h->hd[HTTP_HDR_URL].b;
if (!http_GetHdr(h, H_Host, &host))
host = url;
if (sp->obj != NULL) { if (sp->obj != NULL) {
CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC); CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);
o = sp->obj; o = sp->obj;
...@@ -136,7 +132,9 @@ HSH_Lookup(struct sess *sp) ...@@ -136,7 +132,9 @@ HSH_Lookup(struct sess *sp)
LOCK(&oh->mtx); LOCK(&oh->mtx);
goto were_back; goto were_back;
} }
oh = hash->lookup(url, host, w->nobjhead); VSLR(SLT_Debug, sp->fd, sp->hash_b, sp->hash_e);
oh = hash->lookup(sp->hash_b, sp->hash_e, w->nobjhead);
CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC); CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC);
if (oh == w->nobjhead) if (oh == w->nobjhead)
w->nobjhead = NULL; w->nobjhead = NULL;
...@@ -157,7 +155,7 @@ HSH_Lookup(struct sess *sp) ...@@ -157,7 +155,7 @@ HSH_Lookup(struct sess *sp)
/* Object banned but not reaped yet */ /* Object banned but not reaped yet */
} else if (o->ttl <= sp->t_req.tv_sec) { } else if (o->ttl <= sp->t_req.tv_sec) {
/* Object expired */ /* Object expired */
} else if (BAN_CheckObject(o, url)) { } else if (BAN_CheckObject(o, h->hd[HTTP_HDR_URL].b)) {
o->ttl = 0; o->ttl = 0;
VSL(SLT_ExpBan, 0, "%u was banned", o->xid); VSL(SLT_ExpBan, 0, "%u was banned", o->xid);
EXP_TTLchange(o); EXP_TTLchange(o);
......
...@@ -540,6 +540,7 @@ http_header_complete(struct http *hp) ...@@ -540,6 +540,7 @@ http_header_complete(struct http *hp)
hp->t = p; hp->t = p;
assert(hp->t > hp->s); assert(hp->t > hp->s);
assert(hp->t <= hp->v); assert(hp->t <= hp->v);
hp->f = hp->v;
return (1); return (1);
} }
......
...@@ -273,3 +273,21 @@ VRT_r_server_ip(struct sess *sp) ...@@ -273,3 +273,21 @@ VRT_r_server_ip(struct sess *sp)
return ((struct sockaddr*)sp->mysockaddr); return ((struct sockaddr*)sp->mysockaddr);
} }
/*--------------------------------------------------------------------*/
void
VRT_l_req_hash(struct sess *sp, const char *str)
{
int l;
if (str == NULL)
str = "";
l = strlen(str);
xxxassert (sp->hash_e == sp->http->f);
xxxassert (sp->hash_e + l + 1 <= sp->http->e);
memcpy(sp->hash_e, str, l);
sp->hash_e[l] = '#';
sp->hash_e += l + 1;
sp->http->f += l + 1;
}
...@@ -121,22 +121,20 @@ hcl_start(void) ...@@ -121,22 +121,20 @@ hcl_start(void)
*/ */
static struct objhead * static struct objhead *
hcl_lookup(const char *key1, const char *key2, struct objhead *noh) hcl_lookup(const char *b, const char *e, struct objhead *noh)
{ {
struct hcl_entry *he, *he2; struct hcl_entry *he, *he2;
struct hcl_hd *hp; struct hcl_hd *hp;
unsigned u1, digest, kl1, kl2, kl, r; unsigned u1, digest, kl, r;
int i; int i;
CHECK_OBJ_NOTNULL(noh, OBJHEAD_MAGIC); CHECK_OBJ_NOTNULL(noh, OBJHEAD_MAGIC);
digest = crc32_2s(key1, key2); digest = crc32_l(b, e - b);
u1 = digest % hcl_nhash; u1 = digest % hcl_nhash;
hp = &hcl_head[u1]; hp = &hcl_head[u1];
kl1 = strlen(key1) + 1; /* Incl '/0' */ kl = e - b;
kl2 = strlen(key2);
kl = kl1 + kl2;
he2 = NULL; he2 = NULL;
for (r = 0; r < 2; r++ ) { for (r = 0; r < 2; r++ ) {
...@@ -151,9 +149,7 @@ hcl_lookup(const char *key1, const char *key2, struct objhead *noh) ...@@ -151,9 +149,7 @@ hcl_lookup(const char *key1, const char *key2, struct objhead *noh)
continue; continue;
if (he->digest > digest) if (he->digest > digest)
break; break;
if (memcmp(he->key, key1, kl1)) if (memcmp(he->key, b, kl))
continue;
if (memcmp(he->key + kl1, key2, kl2))
continue; continue;
he->refcnt++; he->refcnt++;
noh = he->oh; noh = he->oh;
...@@ -190,8 +186,7 @@ hcl_lookup(const char *key1, const char *key2, struct objhead *noh) ...@@ -190,8 +186,7 @@ hcl_lookup(const char *key1, const char *key2, struct objhead *noh)
noh->hashpriv = he2; noh->hashpriv = he2;
he2->key = (void*)(he2 + 1); he2->key = (void*)(he2 + 1);
memcpy(he2->key, key1, kl1); memcpy(he2->key, b, kl);
memcpy(he2->key + kl1, key2, kl2);
} }
assert(he2 == NULL); /* FlexeLint */ assert(he2 == NULL); /* FlexeLint */
INCOMPL(); INCOMPL();
......
...@@ -44,8 +44,8 @@ ...@@ -44,8 +44,8 @@
struct hsl_entry { struct hsl_entry {
TAILQ_ENTRY(hsl_entry) list; TAILQ_ENTRY(hsl_entry) list;
char *key1; char *key;
char *key2; int keylen;
struct objhead *obj; struct objhead *obj;
unsigned refcnt; unsigned refcnt;
}; };
...@@ -73,19 +73,19 @@ hsl_start(void) ...@@ -73,19 +73,19 @@ hsl_start(void)
*/ */
static struct objhead * static struct objhead *
hsl_lookup(const char *key1, const char *key2, struct objhead *nobj) hsl_lookup(const char *b, const char *e, struct objhead *nobj)
{ {
struct hsl_entry *he, *he2; struct hsl_entry *he, *he2;
int i; int i, l;
l = e - b;
LOCK(&hsl_mutex); LOCK(&hsl_mutex);
TAILQ_FOREACH(he, &hsl_head, list) { TAILQ_FOREACH(he, &hsl_head, list) {
i = strcmp(key1, he->key1); if (l > he->keylen)
if (i < 0)
continue; continue;
if (i > 0) if (l < he->keylen)
break; break;;
i = strcmp(key2, he->key2); i = memcmp(b, he->key, l);
if (i < 0) if (i < 0)
continue; continue;
if (i > 0) if (i > 0)
...@@ -100,14 +100,13 @@ hsl_lookup(const char *key1, const char *key2, struct objhead *nobj) ...@@ -100,14 +100,13 @@ hsl_lookup(const char *key1, const char *key2, struct objhead *nobj)
UNLOCK(&hsl_mutex); UNLOCK(&hsl_mutex);
return (NULL); return (NULL);
} }
he2 = calloc(sizeof *he2, 1); he2 = calloc(sizeof *he2 + l, 1);
XXXAN(he2); XXXAN(he2);
he2->obj = nobj; he2->obj = nobj;
he2->refcnt = 1; he2->refcnt = 1;
he2->key1 = strdup(key1); he2->key = (void*)(he2 + 1);
XXXAN(he2->key1); he2->keylen = l;
he2->key2 = strdup(key2); memcpy(he2->key, b, l);
XXXAN(he2->key2);
nobj->hashpriv = he2; nobj->hashpriv = he2;
if (he != NULL) if (he != NULL)
TAILQ_INSERT_BEFORE(he, he2, list); TAILQ_INSERT_BEFORE(he, he2, list);
...@@ -131,8 +130,6 @@ hsl_deref(struct objhead *obj) ...@@ -131,8 +130,6 @@ hsl_deref(struct objhead *obj)
he = obj->hashpriv; he = obj->hashpriv;
LOCK(&hsl_mutex); LOCK(&hsl_mutex);
if (--he->refcnt == 0) { if (--he->refcnt == 0) {
free(he->key1);
free(he->key2);
TAILQ_REMOVE(&hsl_head, he, list); TAILQ_REMOVE(&hsl_head, he, list);
free(he); free(he);
ret = 0; ret = 0;
......
...@@ -88,6 +88,16 @@ static const char *default_vcl = ...@@ -88,6 +88,16 @@ static const char *default_vcl =
"}\n" "}\n"
"\n" "\n"
"sub vcl_hash {\n" "sub vcl_hash {\n"
" set req.hash += req.url;\n"
#if 1
" set req.hash += req.http.host;\n"
#else
" if (req.http.host) {\n"
" set req.hash += req.http.host;\n"
" } else {\n"
" set req.hash += server.ip;\n"
" }\n"
#endif
" hash;\n" " hash;\n"
"}\n" "}\n"
"\n" "\n"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment