source: bin/varnishd/cache_hash.c @ f5176a

Revision f5176a, 6.6 KB checked in by Poul-Henning Kamp <phk@…>, 7 years ago (diff)

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@1398 d4fa192b-c00b-0410-8231-f00ffab90ce4

  • Property mode set to 100644
Line 
1/*-
2 * Copyright (c) 2006 Verdens Gang AS
3 * Copyright (c) 2006 Linpro AS
4 * All rights reserved.
5 *
6 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * $Id$
30 *
31 * This is the central hash-table code, it relies on a chosen hash
32 * implementation only for the actual hashing, all the housekeeping
33 * happens here.
34 *
35 * We have two kinds of structures, objecthead and object.  An objecthead
36 * corresponds to a given (Host:, URL) tupple, and the objects hung from
37 * the objecthead may represent various variations (ie: Vary: header,
38 * different TTL etc) instances of that web-entity.
39 *
40 * Each objecthead has a mutex which locks both its own fields, the
41 * list of objects and fields in the objects.
42 *
43 * The hash implementation must supply a reference count facility on
44 * the objecthead, and return with a reference held after a lookup.
45 *
46 * Lookups in the hash implementation returns with a ref held and each
47 * object hung from the objhead holds a ref as well.
48 *
49 * Objects have refcounts which are locked by the objecthead mutex.
50 *
51 * New objects are always marked busy, and they can go from busy to
52 * not busy only once.
53 */
54
55#include <stdio.h>
56#include <stdlib.h>
57#include <string.h>
58#include <sys/types.h>
59#include <fcntl.h>
60
61#include "shmlog.h"
62#include "heritage.h"
63#include "cache.h"
64
65static struct hash_slinger      *hash;
66
67/* Precreate an objhead and object for later use */
68void
69HSH_Prealloc(struct sess *sp)
70{
71        struct worker *w;
72
73        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
74        w = sp->wrk;
75
76        if (w->nobjhead == NULL) {
77                w->nobjhead = calloc(sizeof *w->nobjhead, 1);
78                XXXAN(w->nobjhead);
79                w->nobjhead->magic = OBJHEAD_MAGIC;
80                TAILQ_INIT(&w->nobjhead->objects);
81                MTX_INIT(&w->nobjhead->mtx);
82                VSL_stats->n_objecthead++;
83        } else
84                CHECK_OBJ_NOTNULL(w->nobjhead, OBJHEAD_MAGIC);
85        if (w->nobj == NULL) {
86                w->nobj = calloc(sizeof *w->nobj, 1);
87                XXXAN(w->nobj);
88                w->nobj->magic = OBJECT_MAGIC;
89                w->nobj->http.magic = HTTP_MAGIC;
90                w->nobj->busy = 1;
91                w->nobj->refcnt = 1;
92                TAILQ_INIT(&w->nobj->store);
93                TAILQ_INIT(&w->nobj->waitinglist);
94                VSL_stats->n_object++;
95        } else
96                CHECK_OBJ_NOTNULL(w->nobj, OBJECT_MAGIC);
97}
98
99void
100HSH_Freestore(struct object *o)
101{
102        struct storage *st, *stn;
103
104        TAILQ_FOREACH_SAFE(st, &o->store, list, stn) {
105                CHECK_OBJ_NOTNULL(st, STORAGE_MAGIC);
106                TAILQ_REMOVE(&o->store, st, list);
107                st->stevedore->free(st);
108        }
109}
110
111struct object *
112HSH_Lookup(struct sess *sp)
113{
114        struct worker *w;
115        struct http *h;
116        struct objhead *oh;
117        struct object *o;
118
119        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
120        CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC);
121        CHECK_OBJ_NOTNULL(sp->http, HTTP_MAGIC);
122        AN(hash);
123        w = sp->wrk;
124        h = sp->http;
125
126        HSH_Prealloc(sp);
127        if (sp->obj != NULL) {
128                CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);
129                o = sp->obj;
130                oh = o->objhead;
131                CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC);
132                LOCK(&oh->mtx);
133                goto were_back;
134        }
135VSLR(SLT_Debug, sp->fd, sp->hash_b, sp->hash_e);
136
137        oh = hash->lookup(sp->hash_b, sp->hash_e, w->nobjhead);
138        CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC);
139        if (oh == w->nobjhead)
140                w->nobjhead = NULL;
141        LOCK(&oh->mtx);
142        TAILQ_FOREACH(o, &oh->objects, list) {
143                o->refcnt++;
144                if (o->busy) {
145                        TAILQ_INSERT_TAIL(&o->waitinglist, sp, list);
146                        sp->obj = o;
147                        UNLOCK(&oh->mtx);
148                        return (NULL);
149                }
150        were_back:
151                /* XXX: check Vary: */
152                if (!o->cacheable) {
153                        /* ignore */
154                } else if (o->ttl == 0) {
155                        /* Object banned but not reaped yet */
156                } else if (o->ttl <= sp->t_req.tv_sec) {
157                        /* Object expired */
158                } else if (BAN_CheckObject(o, h->hd[HTTP_HDR_URL].b)) {
159                        o->ttl = 0;
160                        VSL(SLT_ExpBan, 0, "%u was banned", o->xid);
161                        EXP_TTLchange(o);
162                } else
163                        break;
164                o->refcnt--;
165        }
166        if (o != NULL) {
167                UNLOCK(&oh->mtx);
168                (void)hash->deref(oh);
169                return (o);
170        }
171
172        /* Insert (precreated) object in objecthead */
173        o = w->nobj;
174        w->nobj = NULL;
175        o->objhead = oh;
176        TAILQ_INSERT_TAIL(&oh->objects, o, list);
177        /* NB: do not deref objhead the new object inherits our reference */
178        UNLOCK(&oh->mtx);
179        BAN_NewObj(o);
180        return (o);
181}
182
183void
184HSH_Unbusy(struct object *o)
185{
186        struct objhead *oh;
187        struct sess *sp;
188
189        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
190        assert(o->busy);
191        assert(o->refcnt > 0);
192        if (o->cacheable)
193                EXP_Insert(o);
194        oh = o->objhead;
195        if (oh != NULL) {
196                CHECK_OBJ(oh, OBJHEAD_MAGIC);
197                LOCK(&oh->mtx);
198        }
199        o->busy = 0;
200        if (oh != NULL)
201                UNLOCK(&oh->mtx);
202        while (1) {
203                sp = TAILQ_FIRST(&o->waitinglist);
204                if (sp == NULL)
205                        break;
206                TAILQ_REMOVE(&o->waitinglist, sp, list);
207                WRK_QueueSession(sp);
208        }
209}
210
211void
212HSH_Ref(struct object *o)
213{
214        struct objhead *oh;
215
216        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
217        oh = o->objhead;
218        if (oh != NULL) {
219                CHECK_OBJ(oh, OBJHEAD_MAGIC);
220                LOCK(&oh->mtx);
221        }
222        assert(o->refcnt > 0);
223        o->refcnt++;
224        if (oh != NULL)
225                UNLOCK(&oh->mtx);
226}
227
228void
229HSH_Deref(struct object *o)
230{
231        struct objhead *oh;
232        unsigned r;
233
234        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
235        oh = o->objhead;
236        if (oh != NULL) {
237                CHECK_OBJ(oh, OBJHEAD_MAGIC);
238
239                /* drop ref on object */
240                LOCK(&oh->mtx);
241        }
242        assert(o->refcnt > 0);
243        r = --o->refcnt;
244        if (oh != NULL) {
245                if (!r)
246                        TAILQ_REMOVE(&oh->objects, o, list);
247                UNLOCK(&oh->mtx);
248        }
249
250        /* If still referenced, done */
251        if (r != 0)
252                return;
253
254        if (o->http.s != NULL)
255                free(o->http.s);
256
257        HSH_Freestore(o);
258        free(o);
259        VSL_stats->n_object--;
260
261        if (oh == NULL)
262                return;
263        /* Drop our ref on the objhead */
264        if (hash->deref(oh))
265                return;
266        assert(TAILQ_EMPTY(&oh->objects));
267        MTX_DESTROY(&oh->mtx);
268        VSL_stats->n_objecthead--;
269        free(oh);
270}
271
272void
273HSH_Init(void)
274{
275
276        hash = heritage.hash;
277        if (hash->start != NULL)
278                hash->start();
279}
Note: See TracBrowser for help on using the repository browser.