source: bin/varnishd/cache_hash.c @ 12a4d07

Revision 12a4d07, 17.9 KB checked in by Poul-Henning Kamp <phk@…>, 4 years ago (diff)

Make sure to release the waiting list, if we give up caching before
picking up the object body.

Fixes #667

git-svn-id:  http://www.varnish-cache.org/svn/trunk/varnish-cache@4631 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 "shmlog.h"
67#include "cache.h"
68#include "stevedore.h"
69#include "hash_slinger.h"
70#include "vsha256.h"
71#include "cache_backend.h"
72
73static const struct hash_slinger *hash;
74
75double
76HSH_Grace(double g)
77{
78        if (isnan(g))
79                return (double)(params->default_grace);
80        return (g);
81}
82
83/*
84 * XXX: this should vector through stevedore.c instead of calling the
85 * XXX: member function directly.
86 */
87
88void
89HSH_Object(const struct sess *sp)
90{
91        CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);
92        CHECK_OBJ_NOTNULL(sp->obj->objstore, STORAGE_MAGIC);
93        CHECK_OBJ_NOTNULL(sp->obj->objstore->stevedore, STEVEDORE_MAGIC);
94        AN(ObjIsBusy(sp->obj));
95        if (sp->obj->objstore->stevedore->object != NULL)
96                sp->obj->objstore->stevedore->object(sp);
97}
98
99/* Precreate an objhead and object for later use */
100void
101HSH_Prealloc(const struct sess *sp)
102{
103        struct worker *w;
104        struct objhead *oh;
105        struct objcore *oc;
106
107        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
108        CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC);
109        w = sp->wrk;
110
111        if (w->nobjcore == NULL) {
112                ALLOC_OBJ(oc, OBJCORE_MAGIC);
113                XXXAN(oc);
114                w->nobjcore = oc;
115                w->stats.n_objectcore++;
116                oc->flags |= OC_F_BUSY;
117        }
118        CHECK_OBJ_NOTNULL(w->nobjcore, OBJCORE_MAGIC);
119
120        if (w->nobjhead == NULL) {
121                ALLOC_OBJ(oh, OBJHEAD_MAGIC);
122                XXXAN(oh);
123                oh->refcnt = 1;
124                VTAILQ_INIT(&oh->objcs);
125                VTAILQ_INIT(&oh->waitinglist);
126                Lck_New(&oh->mtx);
127                w->nobjhead = oh;
128                w->stats.n_objecthead++;
129        }
130        CHECK_OBJ_NOTNULL(w->nobjhead, OBJHEAD_MAGIC);
131
132}
133
134void
135HSH_Cleanup(struct worker *w)
136{
137
138        if (w->nobjcore != NULL) {
139                FREE_OBJ(w->nobjcore);
140                w->stats.n_objectcore--;
141                w->nobjcore = NULL;
142        }
143        if (w->nobjhead != NULL) {
144                Lck_Delete(&w->nobjhead->mtx);
145                FREE_OBJ(w->nobjhead);
146                w->nobjhead = NULL;
147                w->stats.n_objecthead--;
148        }
149}
150
151void
152HSH_DeleteObjHead(struct worker *w, struct objhead *oh)
153{
154
155        AZ(oh->refcnt);
156        assert(VTAILQ_EMPTY(&oh->objcs));
157        assert(VTAILQ_EMPTY(&oh->waitinglist));
158        Lck_Delete(&oh->mtx);
159        w->stats.n_objecthead--;
160        FREE_OBJ(oh);
161}
162
163void
164HSH_Freestore(struct object *o)
165{
166        struct storage *st, *stn;
167
168        VTAILQ_FOREACH_SAFE(st, &o->store, list, stn) {
169                CHECK_OBJ_NOTNULL(st, STORAGE_MAGIC);
170                VTAILQ_REMOVE(&o->store, st, list);
171                STV_free(st);
172        }
173}
174
175void
176HSH_AddString(const struct sess *sp, const char *str)
177{
178        int l;
179
180        if (str == NULL)
181                str = "";
182        l = strlen(str);
183
184        SHA256_Update(sp->wrk->sha256ctx, str, l);
185        SHA256_Update(sp->wrk->sha256ctx, "#", 1);
186
187        if (params->log_hash)
188                WSP(sp, SLT_Hash, "%s", str);
189}
190
191/*---------------------------------------------------------------------
192 * This is a debugging hack to enable testing of boundary conditions
193 * in the hash algorithm.
194 * We trap the first 9 different digests and translate them to different
195 * digests with edge bit conditions
196 */
197
198static struct hsh_magiclist {
199        unsigned char was[SHA256_LEN];
200        unsigned char now[SHA256_LEN];
201} hsh_magiclist[] = {
202        { .now = {      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
203                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
204                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
205                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
206        { .now = {      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
207                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
208                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
209                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } },
210        { .now = {      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
211                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
212                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
213                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 } },
214        { .now = {      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
215                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
216                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
217                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40 } },
218        { .now = {      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
219                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
220                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
221                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 } },
222        { .now = {      0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
223                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
224                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
225                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
226        { .now = {      0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
227                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
228                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
229                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
230        { .now = {      0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
231                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
232                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
233                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
234        { .now = {      0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
235                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
236                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
237                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
238};
239
240#define HSH_NMAGIC (sizeof hsh_magiclist / sizeof hsh_magiclist[0])
241
242static void
243hsh_testmagic(void *result)
244{
245        int i, j;
246        static int nused = 0;
247
248        for (i = 0; i < nused; i++)
249                if (!memcmp(hsh_magiclist[i].was, result, SHA256_LEN))
250                        break;
251        if (i == nused && i < HSH_NMAGIC)
252                memcpy(hsh_magiclist[nused++].was, result, SHA256_LEN);
253        if (i == nused)
254                return;
255        assert(i < HSH_NMAGIC);
256        fprintf(stderr, "HASHMAGIC: <");
257        for (j = 0; j < SHA256_LEN; j++)
258                fprintf(stderr, "%02x", ((unsigned char*)result)[j]);
259        fprintf(stderr, "> -> <");
260        memcpy(result, hsh_magiclist[i].now, SHA256_LEN);
261        for (j = 0; j < SHA256_LEN; j++)
262                fprintf(stderr, "%02x", ((unsigned char*)result)[j]);
263        fprintf(stderr, ">\n");
264}
265
266/**********************************************************************
267 * Insert an object which magically appears out of nowhere or, more likely,
268 * comes off some persistent storage device.
269 */
270
271struct objcore *
272HSH_Insert(const struct sess *sp)
273{
274        struct worker *w;
275        struct objhead *oh;
276        struct objcore *oc;
277
278        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
279        CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC);
280        AN(hash);
281        w = sp->wrk;
282
283        HSH_Prealloc(sp);
284        if (params->diag_bitmap & 0x80000000)
285                hsh_testmagic(sp->wrk->nobjhead->digest);
286
287        AZ(sp->objhead);
288        AN(w->nobjhead);
289        oh = hash->lookup(sp, w->nobjhead);
290        CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC);
291        if (oh == w->nobjhead)
292                w->nobjhead = NULL;
293        Lck_Lock(&oh->mtx);
294        assert(oh->refcnt > 0);
295
296        /* Insert (precreated) objcore in objecthead */
297        oc = w->nobjcore;
298        w->nobjcore = NULL;
299        oc->refcnt = 1;
300        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
301        AZ(oc->flags & OC_F_BUSY);
302
303        /* XXX: Should this not be ..._HEAD now ? */
304        VTAILQ_INSERT_TAIL(&oh->objcs, oc, list);
305        /* NB: do not deref objhead the new object inherits our reference */
306        oc->objhead = oh;
307        Lck_Unlock(&oh->mtx);
308        sp->wrk->stats.n_vampireobject++;
309        return (oc);
310}
311
312
313struct objcore *
314HSH_Lookup(struct sess *sp, struct objhead **poh)
315{
316        struct worker *w;
317        struct objhead *oh;
318        struct objcore *oc;
319        struct objcore *busy_oc, *grace_oc;
320        struct object *o;
321
322        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
323        CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC);
324        CHECK_OBJ_NOTNULL(sp->http, HTTP_MAGIC);
325        CHECK_OBJ_NOTNULL(sp->director, DIRECTOR_MAGIC);
326        AN(hash);
327        w = sp->wrk;
328
329        HSH_Prealloc(sp);
330        memcpy(sp->wrk->nobjhead->digest, sp->digest, sizeof sp->digest);
331        if (params->diag_bitmap & 0x80000000)
332                hsh_testmagic(sp->wrk->nobjhead->digest);
333
334        if (sp->objhead != NULL) {
335                /*
336                 * This sess came off the waiting list, and brings a
337                 * oh refcnt with it.
338                 */
339                CHECK_OBJ_NOTNULL(sp->objhead, OBJHEAD_MAGIC);
340                oh = sp->objhead;
341                sp->objhead = NULL;
342        } else {
343                AN(w->nobjhead);
344                oh = hash->lookup(sp, w->nobjhead);
345                if (oh == w->nobjhead)
346                        w->nobjhead = NULL;
347        }
348
349        CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC);
350        Lck_Lock(&oh->mtx);
351        assert(oh->refcnt > 0);
352        busy_oc = NULL;
353        grace_oc = NULL;
354        VTAILQ_FOREACH(oc, &oh->objcs, list) {
355                /* Must be at least our own ref + the objcore we examine */
356                assert(oh->refcnt > 1);
357                assert(oc->objhead == oh);
358                CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
359
360                if (oc->flags & OC_F_PERSISTENT)
361                        SMP_Fixup(sp, oh, oc);
362
363                if (oc->flags & OC_F_BUSY) {
364                        busy_oc = oc;
365                        continue;
366                }
367
368                o = oc->obj;
369                CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
370
371                if (!o->cacheable)
372                        continue;
373                if (o->ttl == 0)
374                        continue;
375                if (BAN_CheckObject(o, sp))
376                        continue;
377                if (o->vary != NULL && !VRY_Match(sp, o->vary))
378                        continue;
379
380                /* If still valid, use it */
381                if (o->ttl >= sp->t_req)
382                        break;
383
384                /* Remember any matching objects inside their grace period */
385                if (o->ttl + HSH_Grace(o->grace) >= sp->t_req)
386                        grace_oc = oc;
387        }
388
389        /*
390         * If we have seen a busy object or the backend is unhealthy, and
391         * have an object in grace, use it, if req.grace is also
392         * satisified.
393         * XXX: Interesting footnote:  The busy object might be for a
394         * XXX: different "Vary:" than we sought.  We have no way of knowing
395         * XXX: this until the object is unbusy'ed, so in practice we
396         * XXX: serialize fetch of all Vary's if grace is possible.
397         */
398        if (oc == NULL                  /* We found no live object */
399            && grace_oc != NULL         /* There is a grace candidate */
400            && (busy_oc != NULL         /* Somebody else is already busy */
401            || !VBE_Healthy(sp->t_req, sp->director, (uintptr_t)oh))) {
402                                         /* Or it is impossible to fetch: */
403                o = grace_oc->obj;
404                CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
405                if (o->ttl + HSH_Grace(sp->grace) >= sp->t_req)
406                        oc = grace_oc;
407        }
408
409        if (oc != NULL) {
410                o = oc->obj;
411                CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
412                assert(oc->objhead == oh);
413
414                /* We found an object we like */
415                oc->refcnt++;
416                if (o->hits < INT_MAX)
417                        o->hits++;
418                assert(oh->refcnt > 1);
419                Lck_Unlock(&oh->mtx);
420                assert(hash->deref(oh));
421                *poh = oh;
422                return (oc);
423        }
424
425        if (busy_oc != NULL) {
426                /* There are one or more busy objects, wait for them */
427                if (sp->esis == 0)
428                        VTAILQ_INSERT_TAIL(&oh->waitinglist, sp, list);
429                if (params->diag_bitmap & 0x20)
430                        WSP(sp, SLT_Debug,
431                                "on waiting list <%p>", oh);
432                SES_Charge(sp);
433                /*
434                 * The objhead reference transfers to the sess, we get it
435                 * back when the sess comes off the waiting list and
436                 * calls us again
437                 */
438                sp->objhead = oh;
439                sp->wrk = NULL;
440                Lck_Unlock(&oh->mtx);
441                return (NULL);
442        }
443
444        /* Insert (precreated) objcore in objecthead */
445        oc = w->nobjcore;
446        w->nobjcore = NULL;
447        AN(oc->flags & OC_F_BUSY);
448        oc->refcnt = 1;
449
450        /* XXX: Should this not be ..._HEAD now ? */
451        VTAILQ_INSERT_TAIL(&oh->objcs, oc, list);
452        oc->objhead = oh;
453        /* NB: do not deref objhead the new object inherits our reference */
454        Lck_Unlock(&oh->mtx);
455        *poh = oh;
456        return (oc);
457}
458
459static void
460hsh_rush(struct objhead *oh)
461{
462        unsigned u;
463        struct sess *sp;
464
465        CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC);
466        Lck_AssertHeld(&oh->mtx);
467        for (u = 0; u < params->rush_exponent; u++) {
468                sp = VTAILQ_FIRST(&oh->waitinglist);
469                if (sp == NULL)
470                        return;
471                CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
472                AZ(sp->wrk);
473                VTAILQ_REMOVE(&oh->waitinglist, sp, list);
474                DSL(0x20, SLT_Debug, sp->id, "off waiting list");
475                if (WRK_QueueSession(sp)) {
476                        /*
477                         * We could not schedule the session, leave the
478                         * rest on the busy list.
479                         */
480                        VSL_stats->client_drop_late++;
481                        break;
482                }
483        }
484}
485
486/**********************************************************************
487 * Kill a busy object we don't need anyway.
488 * There may be sessions on the waiting list, so we cannot just blow
489 * it out of the water.
490 */
491
492void
493HSH_Drop(struct sess *sp)
494{
495        struct object *o;
496
497        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
498        o = sp->obj;
499        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
500        if (o->objcore != NULL) {       /* Pass has no objcore */
501                assert(o->objcore->refcnt > 0);
502                AN(ObjIsBusy(o));
503                o->ttl = 0;
504        }
505        o->cacheable = 0;
506        if (o->objcore != NULL)         /* Pass has no objcore */
507                HSH_Unbusy(sp);
508        HSH_Deref(sp->wrk, &sp->obj);
509}
510
511void
512HSH_Unbusy(const struct sess *sp)
513{
514        struct object *o;
515        struct objhead *oh;
516
517        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
518        o = sp->obj;
519        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
520        CHECK_OBJ_NOTNULL(o->objcore, OBJCORE_MAGIC);
521        oh = o->objcore->objhead;
522        CHECK_OBJ(oh, OBJHEAD_MAGIC);
523
524        AN(ObjIsBusy(o));
525        AN(o->ban);
526        assert(o->objcore->obj == o);
527        assert(o->objcore->refcnt > 0);
528        assert(oh->refcnt > 0);
529        if (o->ws_o->overflow)
530                sp->wrk->stats.n_objoverflow++;
531        if (params->diag_bitmap & 0x40)
532                WSP(sp, SLT_Debug,
533                    "Object %u workspace free %u", o->xid, WS_Free(o->ws_o));
534
535        Lck_Lock(&oh->mtx);
536        assert(oh->refcnt > 0);
537        o->objcore->flags &= ~OC_F_BUSY;
538        hsh_rush(oh);
539        AN(o->ban);
540        Lck_Unlock(&oh->mtx);
541}
542
543void
544HSH_Ref(struct object *o)
545{
546        struct objhead *oh;
547
548        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
549        CHECK_OBJ_NOTNULL(o->objcore, OBJCORE_MAGIC);
550        oh = o->objcore->objhead;
551        CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC);
552        Lck_Lock(&oh->mtx);
553        assert(o->objcore->refcnt > 0);
554        o->objcore->refcnt++;
555        Lck_Unlock(&oh->mtx);
556}
557
558void
559HSH_DerefObjCore(struct sess *sp)
560{
561        struct objhead *oh;
562        struct objcore *oc;
563
564        CHECK_OBJ_NOTNULL(sp->objhead, OBJHEAD_MAGIC);
565        CHECK_OBJ_NOTNULL(sp->objcore, OBJCORE_MAGIC);
566
567        oh = sp->objhead;
568        sp->objhead = NULL;
569        oc = sp->objcore;
570        sp->objcore = NULL;
571
572        Lck_Lock(&oh->mtx);
573        assert(oc->objhead == oh);
574        VTAILQ_REMOVE(&oh->objcs, oc, list);
575        if (oc->flags & OC_F_BUSY)
576                hsh_rush(oh);
577        Lck_Unlock(&oh->mtx);
578        oc->objhead = NULL;
579        assert(oh->refcnt > 0);
580        FREE_OBJ(oc);
581        sp->wrk->stats.n_objectcore--;
582        if (!hash->deref(oh))
583                HSH_DeleteObjHead(sp->wrk, oh);
584}
585
586/*******************************************************************
587 * This one is slightly tricky.  This is called from the BAN module
588 * to try to wash the object which holds the oldest ban.
589 * We compete against HSH_Deref() which comes in the opposite
590 * locking order, we need to hold the BAN mutex, to stop the
591 * BAN_DestroyObj() call in HSH_Deref(), so that the objhead
592 * will not be removed under us.
593 * NB: Do not call this function any other way or from any other
594 * NB: place in the code.  It will not work for you.
595 */
596
597void
598HSH_FindBan(struct sess *sp, struct objcore **oc)
599{
600        struct objcore *oc1, *oc2;
601        struct objhead *oh;
602
603        oc1 = *oc;
604        CHECK_OBJ_NOTNULL(oc1, OBJCORE_MAGIC);
605        oh = oc1->objhead;
606        CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC);
607        Lck_Lock(&oh->mtx);
608        VTAILQ_FOREACH(oc2, &oh->objcs, list)
609                if (oc1 == oc2)
610                        break;
611        if (oc2 != NULL && oc2->flags & OC_F_PERSISTENT)
612                SMP_Fixup(sp, oh, oc2);
613        if (oc2 != NULL)
614                oc2->refcnt++;
615        Lck_Unlock(&oh->mtx);
616        *oc = oc2;
617}
618
619void
620HSH_Deref(struct worker *w, struct object **oo)
621{
622        struct object *o;
623        struct objhead *oh;
624        struct objcore *oc;
625        unsigned r;
626
627        AN(oo);
628        o = *oo;
629        *oo = NULL;
630        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
631        oc = o->objcore;
632        if (oc == NULL) {
633                r = 0;
634                oh = NULL;
635        } else {
636                CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
637                oh = oc->objhead;
638                CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC);
639
640                Lck_Lock(&oh->mtx);
641                assert(oh->refcnt > 0);
642                assert(oc->refcnt > 0);
643                r = --oc->refcnt;
644                if (!r)
645                        VTAILQ_REMOVE(&oh->objcs, oc, list);
646                hsh_rush(oh);
647                Lck_Unlock(&oh->mtx);
648        }
649
650        /* If still referenced, done */
651        if (r != 0)
652                return;
653
654        if (oh != NULL)
655                BAN_DestroyObj(o);
656        AZ(o->ban);
657        DSL(0x40, SLT_Debug, 0, "Object %u workspace min free %u",
658            o->xid, WS_Free(o->ws_o));
659
660        if (o->esidata != NULL)
661                ESI_Destroy(o);
662        if (o->objcore != NULL && o->objcore->smp_seg != NULL) {
663                SMP_FreeObj(o);
664        } else {
665                HSH_Freestore(o);
666                if (o->objstore != NULL)
667                        STV_free(o->objstore);
668                else
669                        FREE_OBJ(o);
670        }
671        o = NULL;
672        w->stats.n_object--;
673
674        if (oc == NULL) {
675                AZ(oh);
676                return;
677        }
678        AN(oh);
679        FREE_OBJ(oc);
680        w->stats.n_objectcore--;
681        /* Drop our ref on the objhead */
682        assert(oh->refcnt > 0);
683        if (hash->deref(oh))
684                return;
685        HSH_DeleteObjHead(w, oh);
686}
687
688void
689HSH_Init(void)
690{
691
692        assert(DIGEST_LEN == SHA256_LEN);       /* avoid #include pollution */
693        hash = heritage.hash;
694        if (hash->start != NULL)
695                hash->start();
696}
697
698const struct choice hsh_choice[] = {
699        { "classic",            &hcl_slinger },
700        { "simple",             &hsl_slinger },
701        { "simple_list",        &hsl_slinger }, /* backwards compat */
702        { "critbit",            &hcb_slinger },
703        { NULL,                 NULL }
704};
Note: See TracBrowser for help on using the repository browser.