source: bin/varnishd/cache_hash.c @ 42b9d90

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

Add a bit of garbage collection to yesterdays change: Passed objects need
to have their storage properly reclaimed, including the actual content
of a obj.pass=1 cache entry, once we have sent the content to the original
requestor.

git-svn-id:  http://www.varnish-cache.org/svn/trunk/varnish-cache@1278 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 sess *sp;
189
190        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
191        assert(o->busy);
192        assert(o->refcnt > 0);
193        if (o->cacheable)
194                EXP_Insert(o);
195        LOCK(&o->objhead->mtx);
196        o->busy = 0;
197        UNLOCK(&o->objhead->mtx);
198        while (1) {
199                sp = TAILQ_FIRST(&o->waitinglist);
200                if (sp == NULL)
201                        break;
202                TAILQ_REMOVE(&o->waitinglist, sp, list);
203                WRK_QueueSession(sp);
204        }
205}
206
207void
208HSH_Ref(struct object *o)
209{
210        struct objhead *oh;
211
212        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
213        oh = o->objhead;
214        if (oh != NULL) {
215                CHECK_OBJ(oh, OBJHEAD_MAGIC);
216                LOCK(&oh->mtx);
217        }
218        assert(o->refcnt > 0);
219        o->refcnt++;
220        if (oh != NULL)
221                UNLOCK(&oh->mtx);
222}
223
224void
225HSH_Deref(struct object *o)
226{
227        struct objhead *oh;
228        unsigned r;
229
230        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
231        oh = o->objhead;
232        if (oh != NULL) {
233                CHECK_OBJ(oh, OBJHEAD_MAGIC);
234
235                /* drop ref on object */
236                LOCK(&oh->mtx);
237        }
238        assert(o->refcnt > 0);
239        r = --o->refcnt;
240        if (oh != NULL) {
241                if (!r)
242                        TAILQ_REMOVE(&oh->objects, o, list);
243                UNLOCK(&oh->mtx);
244        }
245
246        /* If still referenced, done */
247        if (r != 0)
248                return;
249
250        if (o->http.s != NULL)
251                free(o->http.s);
252
253        HSH_Freestore(o);
254        free(o);
255        VSL_stats->n_object--;
256
257        if (oh == NULL)
258                return;
259        /* Drop our ref on the objhead */
260        if (hash->deref(oh))
261                return;
262        assert(TAILQ_EMPTY(&oh->objects));
263        MTX_DESTROY(&oh->mtx);
264        VSL_stats->n_objecthead--;
265        free(oh);
266}
267
268void
269HSH_Init(void)
270{
271
272        hash = heritage.hash;
273        if (hash->start != NULL)
274                hash->start();
275}
Note: See TracBrowser for help on using the repository browser.