root/trunk/varnish-cache/bin/varnishd/cache_hash.c @ 4633

Revision 4633, 17.9 KB (checked in by phk, 6 months ago)

Remove invalid assert, the waitinglist is overloaded with the
critbit cooling-list, making this check invalid.

Spotted by: Justin Pasher

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