source: bin/varnishd/cache_hash.c @ ad6a8fd

Revision ad6a8fd, 6.7 KB checked in by Dag Erling Smørgrav <des@…>, 7 years ago (diff)

Don't try to lock the objhead mutex if we don't have an objhead. Doing so
caused the Varnish child to die immediately after sending its 503 response
if the backend didn't respond.

Reviewed by: phk

git-svn-id:  http://www.varnish-cache.org/svn/trunk@1376 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        char *url, *host;
119
120        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
121        CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC);
122        CHECK_OBJ_NOTNULL(sp->http, HTTP_MAGIC);
123        AN(hash);
124        w = sp->wrk;
125        h = sp->http;
126
127        HSH_Prealloc(sp);
128        url = h->hd[HTTP_HDR_URL].b;
129        if (!http_GetHdr(h, H_Host, &host))
130                host = url;
131        if (sp->obj != NULL) {
132                CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);
133                o = sp->obj;
134                oh = o->objhead;
135                CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC);
136                LOCK(&oh->mtx);
137                goto were_back;
138        }
139        oh = hash->lookup(url, host, w->nobjhead);
140        CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC);
141        if (oh == w->nobjhead)
142                w->nobjhead = NULL;
143        LOCK(&oh->mtx);
144        TAILQ_FOREACH(o, &oh->objects, list) {
145                o->refcnt++;
146                if (o->busy) {
147                        TAILQ_INSERT_TAIL(&o->waitinglist, sp, list);
148                        sp->obj = o;
149                        UNLOCK(&oh->mtx);
150                        return (NULL);
151                }
152        were_back:
153                /* XXX: check Vary: */
154                if (!o->cacheable) {
155                        /* ignore */
156                } else if (o->ttl == 0) {
157                        /* Object banned but not reaped yet */
158                } else if (o->ttl <= sp->t_req.tv_sec) {
159                        /* Object expired */
160                } else if (BAN_CheckObject(o, url)) {
161                        o->ttl = 0;
162                        VSL(SLT_ExpBan, 0, "%u was banned", o->xid);
163                        EXP_TTLchange(o);
164                } else
165                        break;
166                o->refcnt--;
167        }
168        if (o != NULL) {
169                UNLOCK(&oh->mtx);
170                (void)hash->deref(oh);
171                return (o);
172        }
173
174        /* Insert (precreated) object in objecthead */
175        o = w->nobj;
176        w->nobj = NULL;
177        o->objhead = oh;
178        TAILQ_INSERT_TAIL(&oh->objects, o, list);
179        /* NB: do not deref objhead the new object inherits our reference */
180        UNLOCK(&oh->mtx);
181        BAN_NewObj(o);
182        return (o);
183}
184
185void
186HSH_Unbusy(struct object *o)
187{
188        struct objhead *oh;
189        struct sess *sp;
190
191        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
192        assert(o->busy);
193        assert(o->refcnt > 0);
194        if (o->cacheable)
195                EXP_Insert(o);
196        oh = o->objhead;
197        if (oh != NULL) {
198                CHECK_OBJ(oh, OBJHEAD_MAGIC);
199                LOCK(&oh->mtx);
200        }
201        o->busy = 0;
202        if (oh != NULL)
203                UNLOCK(&oh->mtx);
204        while (1) {
205                sp = TAILQ_FIRST(&o->waitinglist);
206                if (sp == NULL)
207                        break;
208                TAILQ_REMOVE(&o->waitinglist, sp, list);
209                WRK_QueueSession(sp);
210        }
211}
212
213void
214HSH_Ref(struct object *o)
215{
216        struct objhead *oh;
217
218        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
219        oh = o->objhead;
220        if (oh != NULL) {
221                CHECK_OBJ(oh, OBJHEAD_MAGIC);
222                LOCK(&oh->mtx);
223        }
224        assert(o->refcnt > 0);
225        o->refcnt++;
226        if (oh != NULL)
227                UNLOCK(&oh->mtx);
228}
229
230void
231HSH_Deref(struct object *o)
232{
233        struct objhead *oh;
234        unsigned r;
235
236        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
237        oh = o->objhead;
238        if (oh != NULL) {
239                CHECK_OBJ(oh, OBJHEAD_MAGIC);
240
241                /* drop ref on object */
242                LOCK(&oh->mtx);
243        }
244        assert(o->refcnt > 0);
245        r = --o->refcnt;
246        if (oh != NULL) {
247                if (!r)
248                        TAILQ_REMOVE(&oh->objects, o, list);
249                UNLOCK(&oh->mtx);
250        }
251
252        /* If still referenced, done */
253        if (r != 0)
254                return;
255
256        if (o->http.s != NULL)
257                free(o->http.s);
258
259        HSH_Freestore(o);
260        free(o);
261        VSL_stats->n_object--;
262
263        if (oh == NULL)
264                return;
265        /* Drop our ref on the objhead */
266        if (hash->deref(oh))
267                return;
268        assert(TAILQ_EMPTY(&oh->objects));
269        MTX_DESTROY(&oh->mtx);
270        VSL_stats->n_objecthead--;
271        free(oh);
272}
273
274void
275HSH_Init(void)
276{
277
278        hash = heritage.hash;
279        if (hash->start != NULL)
280                hash->start();
281}
Note: See TracBrowser for help on using the repository browser.