From: phk Date: Mon, 6 Aug 2007 09:25:20 +0000 (+0000) Subject: Rewrite the req.hash implmentation: X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=83a51d5556f1085d77796f6dc4c5aad7f4dbbc83;p=varnish Rewrite the req.hash implmentation: Instead of assembling the entire hash-string in the workspace, use a scatter gather approach, hinted by the VCL compiler. This eliminates the workspace reservation which prevented regsub() from working in vcl_hash, and reduces the size of the necessary workspace a fair bit as well, at the cost of a little bit of complexity in the hash implmentations. Closes ticket 137 and possibly 141 git-svn-id: svn+ssh://projects.linpro.no/svn/varnish/trunk@1805 d4fa192b-c00b-0410-8231-f00ffab90ce4 --- diff --git a/varnish-cache/bin/varnishd/cache.h b/varnish-cache/bin/varnishd/cache.h index 20125a1d..7c7eeb17 100644 --- a/varnish-cache/bin/varnishd/cache.h +++ b/varnish-cache/bin/varnishd/cache.h @@ -315,8 +315,11 @@ struct sess { struct workreq workreq; struct acct acct; - char *hash_b; /* Start of hash string */ - char *hash_e; /* End of hash string */ + /* pointers to hash string components */ + unsigned nhashptr; + unsigned ihashptr; + unsigned lhashptr; + const char **hashptr; }; struct backend { @@ -390,6 +393,8 @@ int Fetch(struct sess *sp); /* cache_hash.c */ void HSH_Prealloc(struct sess *sp); +int HSH_Compare(struct sess *sp, const char *b, const char *e); +void HSH_Copy(struct sess *sp, char *b, const char *e); struct object *HSH_Lookup(struct sess *sp); void HSH_Unbusy(struct object *o); void HSH_Ref(struct object *o); diff --git a/varnish-cache/bin/varnishd/cache_center.c b/varnish-cache/bin/varnishd/cache_center.c index 4ff45140..2f0a7b8d 100644 --- a/varnish-cache/bin/varnishd/cache_center.c +++ b/varnish-cache/bin/varnishd/cache_center.c @@ -469,15 +469,26 @@ static int cnt_lookup(struct sess *sp) { struct object *o; + char *p; + uintptr_t u; CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); if (sp->obj == NULL) { - WS_Reserve(sp->http->ws, 0); - sp->hash_b = sp->http->ws->f; - sp->hash_e = sp->hash_b; + + /* Allocate the pointers we need, align properly. */ + sp->lhashptr = 1; /* space for NUL */ + sp->ihashptr = 0; + sp->nhashptr = sp->vcl->nhashcount * 2; + p = WS_Alloc(sp->http->ws, + sizeof(const char *) * (sp->nhashptr + 1)); + u = (uintptr_t)p; + u &= sizeof(const char *) - 1; + if (u) + p += sizeof(const char *) - u; + sp->hashptr = (void*)p; + VCL_hash_method(sp); /* XXX: no-op for now */ - WS_ReleaseP(sp->http->ws, sp->hash_e); /* XXX check error */ } @@ -494,9 +505,6 @@ cnt_lookup(struct sess *sp) return (1); } - WS_Return(sp->http->ws, sp->hash_b, sp->hash_e); - sp->hash_b = sp->hash_e = NULL; - sp->obj = o; /* If we inserted a new object it's a miss */ diff --git a/varnish-cache/bin/varnishd/cache_hash.c b/varnish-cache/bin/varnishd/cache_hash.c index 502f10f5..1453922a 100644 --- a/varnish-cache/bin/varnishd/cache_hash.c +++ b/varnish-cache/bin/varnishd/cache_hash.c @@ -109,6 +109,47 @@ HSH_Freestore(struct object *o) } } +int +HSH_Compare(struct sess *sp, const char *b, const char *e) +{ + int i; + unsigned u, v; + + i = sp->lhashptr - (e - b); + if (i) + return (i); + for (u = 0; u < sp->ihashptr; u += 2) { + v = sp->hashptr[u + 1] - sp->hashptr[u]; + i = memcmp(sp->hashptr[u], b, v); + if (i) + return (i); + b += v; + i = '#' - *b++; + if (i) + return (i); + } + assert(*b == '\0'); + b++; + assert(b == e); + return (0); +} + +void +HSH_Copy(struct sess *sp, char *b, const char *e) +{ + unsigned u, v; + + assert((e - b) >= sp->lhashptr); + for (u = 0; u < sp->ihashptr; u += 2) { + v = sp->hashptr[u + 1] - sp->hashptr[u]; + memcpy(b, sp->hashptr[u], v); + b += v; + *b++ = '#'; + } + *b++ = '\0'; + assert(b <= e); +} + struct object * HSH_Lookup(struct sess *sp) { @@ -133,9 +174,8 @@ HSH_Lookup(struct sess *sp) LOCK(&oh->mtx); goto were_back; } -VSLR(SLT_Debug, sp->fd, sp->hash_b, sp->hash_e); - oh = hash->lookup(sp->hash_b, sp->hash_e, w->nobjhead); + oh = hash->lookup(sp, w->nobjhead); CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC); if (oh == w->nobjhead) w->nobjhead = NULL; diff --git a/varnish-cache/bin/varnishd/cache_vrt.c b/varnish-cache/bin/varnishd/cache_vrt.c index d393c7cf..bb17e9bd 100644 --- a/varnish-cache/bin/varnishd/cache_vrt.c +++ b/varnish-cache/bin/varnishd/cache_vrt.c @@ -456,7 +456,9 @@ VRT_r_server_ip(struct sess *sp) return (sp->mysockaddr); } -/*--------------------------------------------------------------------*/ +/*-------------------------------------------------------------------- + * Add an element to the array/list of hash bits. + */ void VRT_l_req_hash(struct sess *sp, const char *str) @@ -466,10 +468,18 @@ VRT_l_req_hash(struct sess *sp, const char *str) if (str == NULL) str = ""; l = strlen(str); - xxxassert (sp->hash_e + l + 1 <= sp->http->ws->e); - memcpy(sp->hash_e, str, l); - sp->hash_e[l] = '#'; - sp->hash_e += l + 1; + + /* + * XXX: handle this by bouncing sp->vcl->nhashcount when it fails + * XXX: and dispose of this request either by reallocating the + * XXX: hashptr (if possible) or restarting/error the request + */ + xxxassert(sp->ihashptr < sp->nhashptr); + + sp->hashptr[sp->ihashptr] = str; + sp->hashptr[sp->ihashptr + 1] = str + l; + sp->ihashptr += 2; + sp->lhashptr += l + 1; } /*--------------------------------------------------------------------*/ diff --git a/varnish-cache/bin/varnishd/hash_classic.c b/varnish-cache/bin/varnishd/hash_classic.c index 19f03f9e..928a9f03 100644 --- a/varnish-cache/bin/varnishd/hash_classic.c +++ b/varnish-cache/bin/varnishd/hash_classic.c @@ -121,36 +121,44 @@ hcl_start(void) */ static struct objhead * -hcl_lookup(const char *b, const char *e, struct objhead *noh) +hcl_lookup(struct sess *sp, struct objhead *noh) { struct hcl_entry *he, *he2; struct hcl_hd *hp; - unsigned u1, digest, kl, r; + unsigned u1, digest, r; + unsigned u, v; int i; CHECK_OBJ_NOTNULL(noh, OBJHEAD_MAGIC); - digest = crc32_l(b, e - b); + digest = ~0U; + for (u = 0; u < sp->ihashptr; u += 2) { + v = sp->hashptr[u + 1] - sp->hashptr[u]; + digest = crc32(digest, sp->hashptr[u], v); + } + digest ^= ~0U; u1 = digest % hcl_nhash; hp = &hcl_head[u1]; - kl = e - b; he2 = NULL; for (r = 0; r < 2; r++ ) { LOCK(&hp->mtx); TAILQ_FOREACH(he, &hp->head, list) { CHECK_OBJ_NOTNULL(he, HCL_ENTRY_MAGIC); - if (kl < he->klen) + if (sp->lhashptr < he->klen) continue; - if (kl > he->klen) + if (sp->lhashptr > he->klen) break; if (he->digest < digest) continue; if (he->digest > digest) break; - if (memcmp(he->key, b, kl)) + i = HSH_Compare(sp, he->key, he->key + he->klen); + if (i < 0) continue; + if (i > 0) + break; he->refcnt++; noh = he->oh; UNLOCK(&hp->mtx); @@ -174,7 +182,7 @@ hcl_lookup(const char *b, const char *e, struct objhead *noh) } UNLOCK(&hp->mtx); - i = sizeof *he2 + kl; + i = sizeof *he2 + sp->lhashptr; he2 = calloc(i, 1); XXXAN(he2); he2->magic = HCL_ENTRY_MAGIC; @@ -182,11 +190,11 @@ hcl_lookup(const char *b, const char *e, struct objhead *noh) he2->digest = digest; he2->hash = u1; he2->head = hp; - he2->klen = kl; + he2->klen = sp->lhashptr; noh->hashpriv = he2; he2->key = (void*)(he2 + 1); - memcpy(he2->key, b, kl); + HSH_Copy(sp, he2->key, he2->key + sp->lhashptr); } assert(he2 == NULL); /* FlexeLint */ INCOMPL(); diff --git a/varnish-cache/bin/varnishd/hash_simple_list.c b/varnish-cache/bin/varnishd/hash_simple_list.c index 2454dbbd..d5158af3 100644 --- a/varnish-cache/bin/varnishd/hash_simple_list.c +++ b/varnish-cache/bin/varnishd/hash_simple_list.c @@ -73,26 +73,20 @@ hsl_start(void) */ static struct objhead * -hsl_lookup(const char *b, const char *e, struct objhead *nobj) +hsl_lookup(struct sess *sp, struct objhead *nobj) { struct hsl_entry *he, *he2; - int i, l; + int i; - l = e - b; LOCK(&hsl_mutex); TAILQ_FOREACH(he, &hsl_head, list) { - if (l > he->keylen) - continue; - if (l < he->keylen) - break;; - i = memcmp(b, he->key, l); + i = HSH_Compare(sp, he->key, he->key + he->keylen); if (i < 0) continue; if (i > 0) break; he->refcnt++; nobj = he->obj; - nobj->hashpriv = he; UNLOCK(&hsl_mutex); return (nobj); } @@ -100,13 +94,13 @@ hsl_lookup(const char *b, const char *e, struct objhead *nobj) UNLOCK(&hsl_mutex); return (NULL); } - he2 = calloc(sizeof *he2 + l, 1); + he2 = calloc(sizeof *he2 + sp->lhashptr, 1); XXXAN(he2); he2->obj = nobj; he2->refcnt = 1; he2->key = (void*)(he2 + 1); - he2->keylen = l; - memcpy(he2->key, b, l); + he2->keylen = sp->lhashptr; + HSH_Copy(sp, he2->key, he2->key + he2->keylen); nobj->hashpriv = he2; if (he != NULL) TAILQ_INSERT_BEFORE(he, he2, list); diff --git a/varnish-cache/bin/varnishd/hash_slinger.h b/varnish-cache/bin/varnishd/hash_slinger.h index 5673d9f0..38bc2710 100644 --- a/varnish-cache/bin/varnishd/hash_slinger.h +++ b/varnish-cache/bin/varnishd/hash_slinger.h @@ -29,9 +29,11 @@ * $Id$ */ +struct sess; + typedef int hash_init_f(const char *); typedef void hash_start_f(void); -typedef struct objhead *hash_lookup_f(const char *key1, const char *key2, struct objhead *nobj); +typedef struct objhead *hash_lookup_f(struct sess *sp, struct objhead *nobj); typedef int hash_deref_f(struct objhead *obj); struct hash_slinger {