source: bin/varnishd/cache_hash.c @ 8105f4

Revision 8105f4, 20.0 KB checked in by Kristian Lyngstøl <kristian@…>, 4 years ago (diff)

Return(refresh) from VCL recv, allowing a controlled refresh of content
(for example from a script). Does not deal with Vary in any particular
fashion.

git-svn-id:  http://www.varnish-cache.org/svn/trunk/varnish-cache@5065 d4fa192b-c00b-0410-8231-f00ffab90ce4

  • Property mode set to 100644
Line 
1/*-
2 * Copyright (c) 2006 Verdens Gang AS
3 * Copyright (c) 2006-2010 Redpill 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 THE 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 * This is the central hash-table code, it relies on a chosen hash
30 * implementation only for the actual hashing, all the housekeeping
31 * happens here.
32 *
33 * We have two kinds of structures, objecthead and object.  An objecthead
34 * corresponds to a given (Host:, URL) tupple, and the objects hung from
35 * the objecthead may represent various variations (ie: Vary: header,
36 * different TTL etc) instances of that web-entity.
37 *
38 * Each objecthead has a mutex which locks both its own fields, the
39 * list of objects and fields in the objects.
40 *
41 * The hash implementation must supply a reference count facility on
42 * the objecthead, and return with a reference held after a lookup.
43 *
44 * Lookups in the hash implementation returns with a ref held and each
45 * object hung from the objhead holds a ref as well.
46 *
47 * Objects have refcounts which are locked by the objecthead mutex.
48 *
49 * New objects are always marked busy, and they can go from busy to
50 * not busy only once.
51 */
52
53#include "config.h"
54
55#include "svnid.h"
56SVNID("$Id$")
57
58#include <stdio.h>
59#include <stdlib.h>
60#include <math.h>
61#include <string.h>
62#include <limits.h>
63#include <sys/types.h>
64#include <fcntl.h>
65
66#include "cache.h"
67#include "stevedore.h"
68#include "hash_slinger.h"
69#include "vsha256.h"
70#include "cache_backend.h"
71
72static const struct hash_slinger *hash;
73
74double
75HSH_Grace(double g)
76{
77        if (isnan(g))
78                return (double)(params->default_grace);
79        return (g);
80}
81
82/*
83 * XXX: this should vector through stevedore.c instead of calling the
84 * XXX: member function directly.
85 */
86
87void
88HSH_Object(const struct sess *sp)
89{
90        CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);
91        CHECK_OBJ_NOTNULL(sp->obj->objstore, STORAGE_MAGIC);
92        CHECK_OBJ_NOTNULL(sp->obj->objstore->stevedore, STEVEDORE_MAGIC);
93        AN(ObjIsBusy(sp->obj));
94        if (sp->obj->objstore->stevedore->object != NULL)
95                sp->obj->objstore->stevedore->object(sp);
96}
97
98/* Precreate an objhead and object for later use */
99void
100HSH_Prealloc(const struct sess *sp)
101{
102        struct worker *w;
103        struct objhead *oh;
104        struct objcore *oc;
105
106        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
107        CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC);
108        w = sp->wrk;
109
110        if (w->nobjcore == NULL) {
111                ALLOC_OBJ(oc, OBJCORE_MAGIC);
112                XXXAN(oc);
113                w->nobjcore = oc;
114                w->stats.n_objectcore++;
115                oc->flags |= OC_F_BUSY;
116        }
117        CHECK_OBJ_NOTNULL(w->nobjcore, OBJCORE_MAGIC);
118
119        if (w->nobjhead == NULL) {
120                ALLOC_OBJ(oh, OBJHEAD_MAGIC);
121                XXXAN(oh);
122                oh->refcnt = 1;
123                VTAILQ_INIT(&oh->objcs);
124                VTAILQ_INIT(&oh->waitinglist);
125                Lck_New(&oh->mtx);
126                w->nobjhead = oh;
127                w->stats.n_objecthead++;
128        }
129        CHECK_OBJ_NOTNULL(w->nobjhead, OBJHEAD_MAGIC);
130
131}
132
133void
134HSH_Cleanup(struct worker *w)
135{
136
137        if (w->nobjcore != NULL) {
138                FREE_OBJ(w->nobjcore);
139                w->stats.n_objectcore--;
140                w->nobjcore = NULL;
141        }
142        if (w->nobjhead != NULL) {
143                Lck_Delete(&w->nobjhead->mtx);
144                FREE_OBJ(w->nobjhead);
145                w->nobjhead = NULL;
146                w->stats.n_objecthead--;
147        }
148        if (w->nhashpriv != NULL) {
149                free(w->nhashpriv);
150                w->nhashpriv = NULL;
151        }
152}
153
154void
155HSH_DeleteObjHead(struct worker *w, struct objhead *oh)
156{
157
158        AZ(oh->refcnt);
159        assert(VTAILQ_EMPTY(&oh->objcs));
160        Lck_Delete(&oh->mtx);
161        w->stats.n_objecthead--;
162        FREE_OBJ(oh);
163}
164
165void
166HSH_Freestore(struct object *o)
167{
168        struct storage *st, *stn;
169
170        VTAILQ_FOREACH_SAFE(st, &o->store, list, stn) {
171                CHECK_OBJ_NOTNULL(st, STORAGE_MAGIC);
172                VTAILQ_REMOVE(&o->store, st, list);
173                STV_free(st);
174        }
175}
176
177void
178HSH_AddString(const struct sess *sp, const char *str)
179{
180        int l;
181
182        if (str == NULL)
183                str = "";
184        l = strlen(str);
185
186        SHA256_Update(sp->wrk->sha256ctx, str, l);
187        SHA256_Update(sp->wrk->sha256ctx, "#", 1);
188
189        if (params->log_hash)
190                WSP(sp, SLT_Hash, "%s", str);
191}
192
193/*---------------------------------------------------------------------
194 * This is a debugging hack to enable testing of boundary conditions
195 * in the hash algorithm.
196 * We trap the first 9 different digests and translate them to different
197 * digests with edge bit conditions
198 */
199
200static struct hsh_magiclist {
201        unsigned char was[SHA256_LEN];
202        unsigned char now[SHA256_LEN];
203} hsh_magiclist[] = {
204        { .now = {      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
205                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
206                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
207                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
208        { .now = {      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
209                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
210                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
211                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } },
212        { .now = {      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
213                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
214                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
215                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 } },
216        { .now = {      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
217                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
218                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
219                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40 } },
220        { .now = {      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
221                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
222                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
223                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 } },
224        { .now = {      0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
225                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
226                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
227                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
228        { .now = {      0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
229                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
230                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
231                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
232        { .now = {      0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
233                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
234                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
235                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
236        { .now = {      0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
237                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
238                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
239                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
240};
241
242#define HSH_NMAGIC (sizeof hsh_magiclist / sizeof hsh_magiclist[0])
243
244static void
245hsh_testmagic(void *result)
246{
247        int i, j;
248        static int nused = 0;
249
250        for (i = 0; i < nused; i++)
251                if (!memcmp(hsh_magiclist[i].was, result, SHA256_LEN))
252                        break;
253        if (i == nused && i < HSH_NMAGIC)
254                memcpy(hsh_magiclist[nused++].was, result, SHA256_LEN);
255        if (i == nused)
256                return;
257        assert(i < HSH_NMAGIC);
258        fprintf(stderr, "HASHMAGIC: <");
259        for (j = 0; j < SHA256_LEN; j++)
260                fprintf(stderr, "%02x", ((unsigned char*)result)[j]);
261        fprintf(stderr, "> -> <");
262        memcpy(result, hsh_magiclist[i].now, SHA256_LEN);
263        for (j = 0; j < SHA256_LEN; j++)
264                fprintf(stderr, "%02x", ((unsigned char*)result)[j]);
265        fprintf(stderr, ">\n");
266}
267
268/**********************************************************************
269 * Insert an object which magically appears out of nowhere or, more likely,
270 * comes off some persistent storage device.
271 */
272
273struct objcore *
274HSH_Insert(const struct sess *sp)
275{
276        struct worker *w;
277        struct objhead *oh;
278        struct objcore *oc;
279
280        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
281        CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC);
282        AN(hash);
283        w = sp->wrk;
284
285        HSH_Prealloc(sp);
286        if (params->diag_bitmap & 0x80000000)
287                hsh_testmagic(sp->wrk->nobjhead->digest);
288
289        AZ(sp->objhead);
290        AN(w->nobjhead);
291        oh = hash->lookup(sp, w->nobjhead);
292        CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC);
293        if (oh == w->nobjhead)
294                w->nobjhead = NULL;
295        Lck_Lock(&oh->mtx);
296        assert(oh->refcnt > 0);
297
298        /* Insert (precreated) objcore in objecthead */
299        oc = w->nobjcore;
300        w->nobjcore = NULL;
301        oc->refcnt = 1;
302        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
303        AZ(oc->flags & OC_F_BUSY);
304
305        /* XXX: Should this not be ..._HEAD now ? */
306        VTAILQ_INSERT_TAIL(&oh->objcs, oc, list);
307        /* NB: do not deref objhead the new object inherits our reference */
308        oc->objhead = oh;
309        Lck_Unlock(&oh->mtx);
310        sp->wrk->stats.n_vampireobject++;
311        return (oc);
312}
313
314/**********************************************************************
315 */
316
317struct objcore *
318HSH_Lookup(struct sess *sp, struct objhead **poh)
319{
320        struct worker *w;
321        struct objhead *oh;
322        struct objcore *oc;
323        struct objcore *busy_oc, *grace_oc;
324        struct object *o;
325
326        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
327        CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC);
328        CHECK_OBJ_NOTNULL(sp->http, HTTP_MAGIC);
329        CHECK_OBJ_NOTNULL(sp->director, DIRECTOR_MAGIC);
330        AN(hash);
331        w = sp->wrk;
332
333        HSH_Prealloc(sp);
334        memcpy(sp->wrk->nobjhead->digest, sp->digest, sizeof sp->digest);
335        if (params->diag_bitmap & 0x80000000)
336                hsh_testmagic(sp->wrk->nobjhead->digest);
337
338        if (sp->objhead != NULL) {
339                /*
340                 * This sess came off the waiting list, and brings a
341                 * oh refcnt with it.
342                 */
343                CHECK_OBJ_NOTNULL(sp->objhead, OBJHEAD_MAGIC);
344                oh = sp->objhead;
345                sp->objhead = NULL;
346        } else {
347                AN(w->nobjhead);
348                oh = hash->lookup(sp, w->nobjhead);
349                if (oh == w->nobjhead)
350                        w->nobjhead = NULL;
351        }
352
353        CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC);
354        Lck_Lock(&oh->mtx);
355        assert(oh->refcnt > 0);
356        busy_oc = NULL;
357        grace_oc = NULL;
358        VTAILQ_FOREACH(oc, &oh->objcs, list) {
359                /* Must be at least our own ref + the objcore we examine */
360                assert(oh->refcnt > 1);
361                CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
362                assert(oc->objhead == oh);
363
364                if (oc->flags & OC_F_PERSISTENT)
365                        SMP_Fixup(sp, oh, oc);
366
367                if (oc->flags & OC_F_BUSY) {
368                        busy_oc = oc;
369                        continue;
370                }
371
372                o = oc->obj;
373                CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
374
375                if (!o->cacheable)
376                        continue;
377                if (o->ttl == 0)
378                        continue;
379                if (BAN_CheckObject(o, sp))
380                        continue;
381                if (o->vary != NULL && !VRY_Match(sp, o->vary))
382                        continue;
383
384                /* If still valid, use it */
385                if (o->ttl >= sp->t_req)
386                        break;
387
388                /* Remember any matching objects inside their grace period */
389                if (o->ttl + HSH_Grace(o->grace) >= sp->t_req)
390                        grace_oc = oc;
391        }
392
393        /*
394         * If we have seen a busy object or the backend is unhealthy, and
395         * have an object in grace, use it, if req.grace is also
396         * satisified.
397         * XXX: Interesting footnote:  The busy object might be for a
398         * XXX: different "Vary:" than we sought.  We have no way of knowing
399         * XXX: this until the object is unbusy'ed, so in practice we
400         * XXX: serialize fetch of all Vary's if grace is possible.
401         */
402        if (oc == NULL                  /* We found no live object */
403            && grace_oc != NULL         /* There is a grace candidate */
404            && (busy_oc != NULL         /* Somebody else is already busy */
405            || !VBE_Healthy(sp->t_req, sp->director, (uintptr_t)oh))
406            && sp->step != STP_REFRESH) {
407                                         /* Or it is impossible to fetch: */
408                o = grace_oc->obj;
409                CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
410                if (o->ttl + HSH_Grace(sp->grace) >= sp->t_req)
411                        oc = grace_oc;
412        }
413
414        if (oc != NULL) {
415                o = oc->obj;
416                CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
417                assert(oc->objhead == oh);
418                if (sp->step == STP_REFRESH) {
419                        if (o->ttl >= sp->t_req) {
420                                o->ttl = sp->t_req - 1;
421                                o->grace = HSH_Grace(sp->grace);
422                                EXP_Rearm(o);
423                        }
424                        o = NULL;
425                } else {
426                        /* We found an object we like */
427                        oc->refcnt++;
428                        if (o->hits < INT_MAX)
429                                o->hits++;
430                        assert(oh->refcnt > 1);
431                        Lck_Unlock(&oh->mtx);
432                        assert(hash->deref(oh));
433                        *poh = oh;
434                        return (oc);
435                }
436        }
437
438        if (busy_oc != NULL) {
439                /* There are one or more busy objects, wait for them */
440                if (sp->esis == 0)
441                        VTAILQ_INSERT_TAIL(&oh->waitinglist, sp, list);
442                if (params->diag_bitmap & 0x20)
443                        WSP(sp, SLT_Debug,
444                                "on waiting list <%p>", oh);
445                SES_Charge(sp);
446                /*
447                 * The objhead reference transfers to the sess, we get it
448                 * back when the sess comes off the waiting list and
449                 * calls us again
450                 */
451                sp->objhead = oh;
452                sp->wrk = NULL;
453                Lck_Unlock(&oh->mtx);
454                return (NULL);
455        }
456
457        /* Insert (precreated) objcore in objecthead */
458        oc = w->nobjcore;
459        w->nobjcore = NULL;
460        AN(oc->flags & OC_F_BUSY);
461        oc->refcnt = 1;
462
463        /* XXX: Should this not be ..._HEAD now ? */
464        VTAILQ_INSERT_TAIL(&oh->objcs, oc, list);
465        oc->objhead = oh;
466        /* NB: do not deref objhead the new object inherits our reference */
467        Lck_Unlock(&oh->mtx);
468        *poh = oh;
469        return (oc);
470}
471
472/**********************************************************************
473 */
474
475static void
476hsh_rush(struct objhead *oh)
477{
478        unsigned u;
479        struct sess *sp;
480
481        CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC);
482        Lck_AssertHeld(&oh->mtx);
483        for (u = 0; u < params->rush_exponent; u++) {
484                sp = VTAILQ_FIRST(&oh->waitinglist);
485                if (sp == NULL)
486                        return;
487                CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
488                AZ(sp->wrk);
489                VTAILQ_REMOVE(&oh->waitinglist, sp, list);
490                DSL(0x20, SLT_Debug, sp->id, "off waiting list");
491                if (WRK_QueueSession(sp)) {
492                        /*
493                         * We could not schedule the session, leave the
494                         * rest on the busy list.
495                         */
496                        VSC_main->client_drop_late++;
497                        break;
498                }
499        }
500}
501
502/**********************************************************************
503 * Purge an entire objhead
504 */
505
506void
507HSH_Purge(struct sess *sp, struct objhead *oh, double ttl, double grace)
508{
509        struct objcore *oc, **ocp;
510        unsigned spc, nobj, n;
511        struct object *o;
512
513        CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC);
514        spc = WS_Reserve(sp->wrk->ws, 0);
515        ocp = (void*)sp->wrk->ws->f;
516        Lck_Lock(&oh->mtx);
517        assert(oh->refcnt > 0);
518        nobj = 0;
519        VTAILQ_FOREACH(oc, &oh->objcs, list) {
520                CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
521                assert(oc->objhead == oh);
522
523                if (oc->flags & OC_F_PERSISTENT)
524                        SMP_Fixup(sp, oh, oc);
525
526                xxxassert(spc >= sizeof *ocp);
527                oc->refcnt++;
528                spc -= sizeof *ocp;
529                ocp[nobj++] = oc;
530        }
531        Lck_Unlock(&oh->mtx);
532
533        if (ttl <= 0)
534                ttl = -1;
535        for (n = 0; n < nobj; n++) {
536                oc = ocp[n];
537                CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
538                o = oc->obj;
539                if (o == NULL)
540                        continue;
541                CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
542                o->ttl = sp->t_req + ttl;
543                if (!isnan(grace))
544                        o->grace = grace;
545                EXP_Rearm(o);
546                HSH_Deref(sp->wrk, &o);
547        }
548        WS_Release(sp->wrk->ws, 0);
549}
550
551
552/**********************************************************************
553 * Kill a busy object we don't need anyway.
554 * There may be sessions on the waiting list, so we cannot just blow
555 * it out of the water.
556 */
557
558void
559HSH_Drop(struct sess *sp)
560{
561        struct object *o;
562
563        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
564        o = sp->obj;
565        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
566        if (o->objcore != NULL) {       /* Pass has no objcore */
567                assert(o->objcore->refcnt > 0);
568                AN(ObjIsBusy(o));
569                o->ttl = 0;
570        }
571        o->cacheable = 0;
572        if (o->objcore != NULL)         /* Pass has no objcore */
573                HSH_Unbusy(sp);
574        HSH_Deref(sp->wrk, &sp->obj);
575}
576
577void
578HSH_Unbusy(const struct sess *sp)
579{
580        struct object *o;
581        struct objhead *oh;
582
583        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
584        o = sp->obj;
585        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
586        CHECK_OBJ_NOTNULL(o->objcore, OBJCORE_MAGIC);
587        oh = o->objcore->objhead;
588        CHECK_OBJ(oh, OBJHEAD_MAGIC);
589
590        AN(ObjIsBusy(o));
591        AN(o->ban);
592        assert(o->objcore->obj == o);
593        assert(o->objcore->refcnt > 0);
594        assert(oh->refcnt > 0);
595        if (o->ws_o->overflow)
596                sp->wrk->stats.n_objoverflow++;
597        if (params->diag_bitmap & 0x40)
598                WSP(sp, SLT_Debug,
599                    "Object %u workspace free %u", o->xid, WS_Free(o->ws_o));
600
601        Lck_Lock(&oh->mtx);
602        assert(oh->refcnt > 0);
603        o->objcore->flags &= ~OC_F_BUSY;
604        hsh_rush(oh);
605        AN(o->ban);
606        Lck_Unlock(&oh->mtx);
607}
608
609void
610HSH_Ref(const struct object *o)
611{
612        struct objhead *oh;
613
614        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
615        CHECK_OBJ_NOTNULL(o->objcore, OBJCORE_MAGIC);
616        oh = o->objcore->objhead;
617        CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC);
618        Lck_Lock(&oh->mtx);
619        assert(o->objcore->refcnt > 0);
620        o->objcore->refcnt++;
621        Lck_Unlock(&oh->mtx);
622}
623
624void
625HSH_DerefObjCore(struct sess *sp)
626{
627        struct objhead *oh;
628        struct objcore *oc;
629
630        CHECK_OBJ_NOTNULL(sp->objhead, OBJHEAD_MAGIC);
631        CHECK_OBJ_NOTNULL(sp->objcore, OBJCORE_MAGIC);
632
633        oh = sp->objhead;
634        sp->objhead = NULL;
635        oc = sp->objcore;
636        sp->objcore = NULL;
637
638        Lck_Lock(&oh->mtx);
639        assert(oc->objhead == oh);
640        VTAILQ_REMOVE(&oh->objcs, oc, list);
641        if (oc->flags & OC_F_BUSY)
642                hsh_rush(oh);
643        Lck_Unlock(&oh->mtx);
644        oc->objhead = NULL;
645        assert(oh->refcnt > 0);
646        FREE_OBJ(oc);
647        sp->wrk->stats.n_objectcore--;
648        if (!hash->deref(oh))
649                HSH_DeleteObjHead(sp->wrk, oh);
650}
651
652/*******************************************************************
653 * This one is slightly tricky.  This is called from the BAN module
654 * to try to wash the object which holds the oldest ban.
655 * We compete against HSH_Deref() which comes in the opposite
656 * locking order, we need to hold the BAN mutex, to stop the
657 * BAN_DestroyObj() call in HSH_Deref(), so that the objhead
658 * will not be removed under us.
659 * NB: Do not call this function any other way or from any other
660 * NB: place in the code.  It will not work for you.
661 */
662
663void
664HSH_FindBan(struct sess *sp, struct objcore **oc)
665{
666        struct objcore *oc1, *oc2;
667        struct objhead *oh;
668
669        oc1 = *oc;
670        CHECK_OBJ_NOTNULL(oc1, OBJCORE_MAGIC);
671        oh = oc1->objhead;
672        CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC);
673        Lck_Lock(&oh->mtx);
674        VTAILQ_FOREACH(oc2, &oh->objcs, list)
675                if (oc1 == oc2)
676                        break;
677        if (oc2 != NULL && oc2->flags & OC_F_PERSISTENT)
678                SMP_Fixup(sp, oh, oc2);
679        if (oc2 != NULL)
680                oc2->refcnt++;
681        Lck_Unlock(&oh->mtx);
682        *oc = oc2;
683}
684
685void
686HSH_Deref(struct worker *w, struct object **oo)
687{
688        struct object *o;
689        struct objhead *oh;
690        struct objcore *oc;
691        unsigned r;
692
693        AN(oo);
694        o = *oo;
695        *oo = NULL;
696        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
697        oc = o->objcore;
698        if (oc == NULL) {
699                r = 0;
700                oh = NULL;
701        } else {
702                CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
703                oh = oc->objhead;
704                CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC);
705
706                Lck_Lock(&oh->mtx);
707                assert(oh->refcnt > 0);
708                assert(oc->refcnt > 0);
709                r = --oc->refcnt;
710                if (!r)
711                        VTAILQ_REMOVE(&oh->objcs, oc, list);
712                hsh_rush(oh);
713                Lck_Unlock(&oh->mtx);
714        }
715
716        /* If still referenced, done */
717        if (r != 0)
718                return;
719
720        if (oh != NULL)
721                BAN_DestroyObj(o);
722        AZ(o->ban);
723        DSL(0x40, SLT_Debug, 0, "Object %u workspace min free %u",
724            o->xid, WS_Free(o->ws_o));
725
726        if (o->esidata != NULL)
727                ESI_Destroy(o);
728        if (o->objcore != NULL && o->objcore->smp_seg != NULL) {
729                SMP_FreeObj(o);
730        } else {
731                HSH_Freestore(o);
732                if (o->objstore != NULL)
733                        STV_free(o->objstore);
734                else
735                        FREE_OBJ(o);
736        }
737        o = NULL;
738        w->stats.n_object--;
739
740        if (oc == NULL) {
741                AZ(oh);
742                return;
743        }
744        AN(oh);
745        FREE_OBJ(oc);
746        w->stats.n_objectcore--;
747        /* Drop our ref on the objhead */
748        assert(oh->refcnt > 0);
749        if (hash->deref(oh))
750                return;
751        HSH_DeleteObjHead(w, oh);
752}
753
754void
755HSH_Init(void)
756{
757
758        assert(DIGEST_LEN == SHA256_LEN);       /* avoid #include pollution */
759        hash = heritage.hash;
760        if (hash->start != NULL)
761                hash->start();
762}
763
764static const struct choice hsh_choice[] = {
765        { "classic",            &hcl_slinger },
766        { "simple",             &hsl_slinger },
767        { "simple_list",        &hsl_slinger }, /* backwards compat */
768        { "critbit",            &hcb_slinger },
769        { NULL,                 NULL }
770};
771
772/*--------------------------------------------------------------------*/
773
774void
775HSH_config(const char *h_arg)
776{
777        char **av;
778        int ac;
779        const struct hash_slinger *hp;
780
781        av = ParseArgv(h_arg, ARGV_COMMA);
782        AN(av);
783
784        if (av[0] != NULL)
785                ARGV_ERR("%s\n", av[0]);
786
787        if (av[1] == NULL)
788                ARGV_ERR("-h argument is empty\n");
789
790        for (ac = 0; av[ac + 2] != NULL; ac++)
791                continue;
792
793        hp = pick(hsh_choice, av[1], "hash");
794        CHECK_OBJ_NOTNULL(hp, SLINGER_MAGIC);
795        vsb_printf(vident, ",-h%s", av[1]);
796        heritage.hash = hp;
797        if (hp->init != NULL)
798                hp->init(ac, av + 2);
799        else if (ac > 0)
800                ARGV_ERR("Hash method \"%s\" takes no arguments\n",
801                    hp->name);
802}
803
Note: See TracBrowser for help on using the repository browser.