[experimental-ims] 7bc0068 Overhaul the Vary matching code to make it faster, by assuming (but do not trusting) that all objects under an objhdr have the same Vary string.
Geoff Simmons
geoff at varnish-cache.org
Fri Jul 8 11:47:44 CEST 2011
commit 7bc0068d8f422c917042e35867e00a19f8956f46
Author: Poul-Henning Kamp <phk at FreeBSD.org>
Date: Tue Jun 21 11:55:07 2011 +0000
Overhaul the Vary matching code to make it faster, by assuming (but
do not trusting) that all objects under an objhdr have the same
Vary string.
Build a vary string for the request on the wrk->ws as we do the
comparison and use it as a cache for subsequent comparisons.
This will also be first step of sky's "pre-vary"
diff --git a/bin/varnishd/cache.h b/bin/varnishd/cache.h
index f8dedb1..22fa5ff 100644
--- a/bin/varnishd/cache.h
+++ b/bin/varnishd/cache.h
@@ -298,7 +298,11 @@ struct worker {
uint32_t *wlb, *wlp, *wle;
unsigned wlr;
+ /* Lookup stuff */
struct SHA256Context *sha256ctx;
+ uint8_t *vary_b;
+ uint8_t *vary_l;
+ uint8_t *vary_e;
struct http_conn htc[1];
struct ws ws[1];
@@ -880,7 +884,7 @@ void RES_StreamPoll(const struct sess *sp);
/* cache_vary.c */
struct vsb *VRY_Create(const struct sess *sp, const struct http *hp);
-int VRY_Match(const struct sess *sp, const unsigned char *vary);
+int VRY_Match(const struct sess *sp, const uint8_t *vary);
/* cache_vcl.c */
void VCL_Init(void);
diff --git a/bin/varnishd/cache_hash.c b/bin/varnishd/cache_hash.c
index 2a6dcc5..0324b57 100644
--- a/bin/varnishd/cache_hash.c
+++ b/bin/varnishd/cache_hash.c
@@ -330,6 +330,13 @@ HSH_Lookup(struct sess *sp, struct objhead **poh)
}
CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC);
+ AZ(sp->wrk->vary_b);
+ AZ(sp->wrk->vary_l);
+ AZ(sp->wrk->vary_e);
+ WS_Reserve(sp->wrk->ws, 0);
+ sp->wrk->vary_b = (void*)sp->wrk->ws->f;
+ sp->wrk->vary_e = (void*)sp->wrk->ws->r;
+ sp->wrk->vary_b[2] = '\0';
Lck_Lock(&oh->mtx);
assert(oh->refcnt > 0);
busy_oc = NULL;
@@ -374,6 +381,11 @@ HSH_Lookup(struct sess *sp, struct objhead **poh)
}
}
+ WS_ReleaseP(sp->wrk->ws, (void*)sp->wrk->vary_b);
+ sp->wrk->vary_b = NULL;
+ sp->wrk->vary_l = NULL;
+ sp->wrk->vary_e = NULL;
+
/*
* If we have seen a busy object or the backend is unhealthy, and
* we have an object in grace, use it, if req.grace is also
diff --git a/bin/varnishd/cache_vary.c b/bin/varnishd/cache_vary.c
index 8eab103..27abf74 100644
--- a/bin/varnishd/cache_vary.c
+++ b/bin/varnishd/cache_vary.c
@@ -58,6 +58,7 @@
#include <stdlib.h>
#include "cache.h"
+#include "vend.h"
#include "vct.h"
struct vsb *
@@ -131,63 +132,112 @@ VRY_Create(const struct sess *sp, const struct http *hp)
return(sb);
}
+/*
+ * Find length of a vary entry
+ */
+static unsigned
+vry_len(const uint8_t *p)
+{
+ unsigned l = vbe16dec(p);
+
+ return (2 + p[2] + 2 + (l == 0xffff ? 0 : l));
+}
+
+/*
+ * Compare two vary entries
+ */
+static int
+vry_cmp(const uint8_t * const *v1, uint8_t * const *v2)
+{
+ unsigned retval = 0;
+
+ if (!memcmp(*v1, *v2, vry_len(*v1))) {
+ /* Same same */
+ retval = 0;
+ } else if (memcmp((*v1) + 2, (*v2) + 2, (*v1)[2] + 2)) {
+ /* Different header */
+ retval = 1;
+ } else if (params->http_gzip_support &&
+ !strcasecmp(H_Accept_Encoding, (const char*)((*v1)+2))) {
+ /*
+ * If we do gzip processing, we do not vary on Accept-Encoding,
+ * because we want everybody to get the gzip'ed object, and
+ * varnish will gunzip as necessary. We implement the skip at
+ * check time, rather than create time, so that object in
+ * persistent storage can be used with either setting of
+ * http_gzip_support.
+ */
+ retval = 0;
+ } else {
+ /* Same header, different content */
+ retval = 2;
+ }
+ return (retval);
+}
+
int
VRY_Match(const struct sess *sp, const uint8_t *vary)
{
+ uint8_t *vsp = sp->wrk->vary_b;
char *h, *e;
- int i, l, lh;
-
- while (1) {
- l = vary[0] * 256 + vary[1];
- vary += 2;
- if (!*vary)
- break;
-
- if (params->http_gzip_support &&
- !strcasecmp(H_Accept_Encoding, (const char*)vary)) {
- /*
- * If we do gzip processing, we do not vary on
- * Accept-Encoding, because we want everybody to
- * get the gzip'ed object, and varnish will gunzip
- * as necessary. We implement the skip at check
- * time, rather than create time, so that object
- * in persistent storage can be used with either
- * setting of http_gzip_support.
- */
- vary += *vary + 2;
- if (l != 0xffff)
- vary += l;
- continue;
+ unsigned lh, ln;
+ int i, retval = 1, oflo = 0;
+
+ AN(vsp);
+ while (vary[2]) {
+ i = vry_cmp(&vary, &vsp);
+ if (i == 1) {
+ /* Build a new entry */
+
+ i = http_GetHdr(sp->http, (const char*)(vary+2), &h);
+ if (i) {
+ /* Trim trailing space */
+ e = strchr(h, '\0');
+ while (e > h && vct_issp(e[-1]))
+ e--;
+ lh = e - h;
+ assert(lh < 0xffff);
+ } else {
+ e = h = NULL;
+ lh = 0xffff;
+ }
+
+ /* Length of the entire new vary entry */
+ ln = 2 + vary[2] + 2 + (lh == 0xffff ? 0 : lh);
+ if (vsp + ln >= sp->wrk->vary_e) {
+ vsp = sp->wrk->vary_b;
+ oflo = 1;
+ }
+
+ /* We MUST have space for one entry */
+ assert(vsp + ln < sp->wrk->vary_e);
+
+ vbe16enc(vsp, (uint16_t)lh);
+ memcpy(vsp + 2, vary + 2, vary[2] + 2);
+ if (h != NULL && e != NULL)
+ memcpy(vsp + 2 + vsp[2] + 2, h, e - h);
+
+ i = vry_cmp(&vary, &vsp);
+ assert(i != 1); /* hdr must be the same now */
}
- /* Look for header */
- i = http_GetHdr(sp->http, (const char*)vary, &h);
- vary += *vary + 2;
-
- /* Fail if we have the header, but shouldn't */
- if (i && l == 0xffff)
- return (0);
- /* or if we don't when we should */
- if (l != 0xffff && !i)
- return (0);
-
- /* Nothing to match */
- if (!i)
- continue;
-
- /* Trim trailing space */
- e = strchr(h, '\0');
- while (e > h && vct_issp(e[-1]))
- e--;
-
- /* Fail if wrong length */
- lh = e - h;
- if (lh != l)
- return (0);
+ if (i != 0)
+ retval = 0;
+ vsp += vry_len(vsp);
+ vary += vry_len(vary);
+ }
+ if (vsp + 3 > sp->wrk->vary_e)
+ oflo = 1;
- /* or if wrong contents */
- if (memcmp(h, vary, l))
- return (0);
- vary += l;
+ if (oflo) {
+ /* XXX: Should log this */
+ vsp = sp->wrk->vary_b;
}
- return (1);
+ vsp[0] = 0xff;
+ vsp[1] = 0xff;
+ vsp[2] = 0;
+ if (oflo)
+ sp->wrk->vary_l = NULL;
+ else
+ sp->wrk->vary_l = vsp + 3;
+ return (retval);
}
More information about the varnish-commit
mailing list