source: bin/varnishd/cache_hash.c @ 4324b6

Revision 4324b6, 19.9 KB checked in by Poul-Henning Kamp <phk@…>, 3 years ago (diff)

Reduce the arguments of HSH_DerefObjCore() to the minimum needed.

git-svn-id:  http://www.varnish-cache.org/svn/trunk/varnish-cache@5541 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, lck_objhdr);
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                        if (!sp->hash_ignore_busy)
369                                busy_oc = oc;
370                        continue;
371                }
372
373                o = oc->obj;
374                CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
375
376                if (!o->cacheable)
377                        continue;
378                if (o->ttl == 0)
379                        continue;
380                if (BAN_CheckObject(o, sp))
381                        continue;
382                if (o->vary != NULL && !VRY_Match(sp, o->vary))
383                        continue;
384
385                /* If still valid, use it */
386                if (o->ttl >= sp->t_req)
387                        break;
388
389                /* Remember any matching objects inside their grace period */
390                if (o->ttl + HSH_Grace(o->grace) >= sp->t_req)
391                        grace_oc = oc;
392        }
393
394        /*
395         * If we have seen a busy object or the backend is unhealthy, and
396         * have an object in grace, use it, if req.grace is also
397         * satisified.
398         * XXX: Interesting footnote:  The busy object might be for a
399         * XXX: different "Vary:" than we sought.  We have no way of knowing
400         * XXX: this until the object is unbusy'ed, so in practice we
401         * XXX: serialize fetch of all Vary's if grace is possible.
402         */
403        if (oc == NULL                  /* We found no live object */
404            && grace_oc != NULL         /* There is a grace candidate */
405            && (busy_oc != NULL         /* Somebody else is already busy */
406            || !VDI_Healthy(sp->t_req, sp->director, (uintptr_t)oh))) {
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 && !sp->hash_always_miss) {
415                o = oc->obj;
416                CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
417                assert(oc->objhead == oh);
418
419                /* We found an object we like */
420                oc->refcnt++;
421                if (o->hits < INT_MAX)
422                        o->hits++;
423                assert(oh->refcnt > 1);
424                Lck_Unlock(&oh->mtx);
425                assert(hash->deref(oh));
426                *poh = oh;
427                return (oc);
428        }
429
430        if (busy_oc != NULL) {
431                /* There are one or more busy objects, wait for them */
432                if (sp->esis == 0)
433                        VTAILQ_INSERT_TAIL(&oh->waitinglist, sp, list);
434                if (params->diag_bitmap & 0x20)
435                        WSP(sp, SLT_Debug,
436                                "on waiting list <%p>", oh);
437                SES_Charge(sp);
438                /*
439                 * The objhead reference transfers to the sess, we get it
440                 * back when the sess comes off the waiting list and
441                 * calls us again
442                 */
443                sp->objhead = oh;
444                sp->wrk = NULL;
445                Lck_Unlock(&oh->mtx);
446                return (NULL);
447        }
448
449        /* Insert (precreated) objcore in objecthead */
450        oc = w->nobjcore;
451        w->nobjcore = NULL;
452        AN(oc->flags & OC_F_BUSY);
453        oc->refcnt = 1;
454
455        VTAILQ_INSERT_HEAD(&oh->objcs, oc, list);
456        oc->objhead = oh;
457        /* NB: do not deref objhead the new object inherits our reference */
458        Lck_Unlock(&oh->mtx);
459        *poh = oh;
460        return (oc);
461}
462
463/**********************************************************************
464 */
465
466static void
467hsh_rush(struct objhead *oh)
468{
469        unsigned u;
470        struct sess *sp;
471
472        CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC);
473        Lck_AssertHeld(&oh->mtx);
474        for (u = 0; u < params->rush_exponent; u++) {
475                sp = VTAILQ_FIRST(&oh->waitinglist);
476                if (sp == NULL)
477                        return;
478                CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
479                AZ(sp->wrk);
480                VTAILQ_REMOVE(&oh->waitinglist, sp, list);
481                DSL(0x20, SLT_Debug, sp->id, "off waiting list");
482                if (WRK_QueueSession(sp)) {
483                        /*
484                         * We could not schedule the session, leave the
485                         * rest on the busy list.
486                         */
487                        VSC_main->client_drop_late++;
488                        break;
489                }
490        }
491}
492
493/**********************************************************************
494 * Purge an entire objhead
495 */
496
497void
498HSH_Purge(struct sess *sp, struct objhead *oh, double ttl, double grace)
499{
500        struct objcore *oc, **ocp;
501        unsigned spc, nobj, n;
502        struct object *o;
503
504        CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC);
505        spc = WS_Reserve(sp->wrk->ws, 0);
506        ocp = (void*)sp->wrk->ws->f;
507        Lck_Lock(&oh->mtx);
508        assert(oh->refcnt > 0);
509        nobj = 0;
510        VTAILQ_FOREACH(oc, &oh->objcs, list) {
511                CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
512                assert(oc->objhead == oh);
513                if (oc->flags & OC_F_BUSY) {
514                        /*
515                         * We cannot purge busy objects here, because their
516                         * owners have special rights to them, and may nuke
517                         * them without concern for the refcount, which by
518                         * definition always must be one, so they don't check.
519                         */
520                        continue;
521                }
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(struct objcore *oc)
611{
612        struct objhead *oh;
613
614        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
615        oh = oc->objhead;
616        CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC);
617        Lck_Lock(&oh->mtx);
618        assert(oc->refcnt > 0);
619        oc->refcnt++;
620        Lck_Unlock(&oh->mtx);
621}
622
623void
624HSH_DerefObjCore(struct worker *wrk, struct objcore *oc)
625{
626        struct objhead *oh;
627
628        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
629        oh = oc->objhead;
630        CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC);
631
632        Lck_Lock(&oh->mtx);
633        VTAILQ_REMOVE(&oh->objcs, oc, list);
634        if (oc->flags & OC_F_BUSY)
635                hsh_rush(oh);
636        Lck_Unlock(&oh->mtx);
637        oc->objhead = NULL;
638        assert(oh->refcnt > 0);
639        FREE_OBJ(oc);
640        wrk->stats.n_objectcore--;
641        if (!hash->deref(oh))
642                HSH_DeleteObjHead(wrk, oh);
643}
644
645/*******************************************************************
646 * This one is slightly tricky.  This is called from the BAN module
647 * to try to wash the object which holds the oldest ban.
648 * We compete against HSH_Deref() which comes in the opposite
649 * locking order, we need to hold the BAN mutex, to stop the
650 * BAN_DestroyObj() call in HSH_Deref(), so that the objhead
651 * will not be removed under us.
652 * NB: Do not call this function any other way or from any other
653 * NB: place in the code.  It will not work for you.
654 */
655
656void
657HSH_FindBan(struct sess *sp, struct objcore **oc)
658{
659        struct objcore *oc1, *oc2;
660        struct objhead *oh;
661
662        oc1 = *oc;
663        CHECK_OBJ_NOTNULL(oc1, OBJCORE_MAGIC);
664        oh = oc1->objhead;
665        CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC);
666        if (Lck_Trylock(&oh->mtx)) {
667                *oc = NULL;
668                return;
669        }
670        VTAILQ_FOREACH(oc2, &oh->objcs, list)
671                if (oc1 == oc2)
672                        break;
673        if (oc2 != NULL && oc2->flags & OC_F_PERSISTENT)
674                SMP_Fixup(sp, oh, oc2);
675        if (oc2 != NULL)
676                oc2->refcnt++;
677        Lck_Unlock(&oh->mtx);
678        *oc = oc2;
679}
680
681void
682HSH_Deref(struct worker *w, struct object **oo)
683{
684        struct object *o;
685        struct objhead *oh;
686        struct objcore *oc;
687        unsigned r;
688
689        AN(oo);
690        o = *oo;
691        *oo = NULL;
692        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
693        oc = o->objcore;
694        if (oc == NULL) {
695                r = 0;
696                oh = NULL;
697        } else {
698                CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
699                oh = oc->objhead;
700                CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC);
701
702                Lck_Lock(&oh->mtx);
703                assert(oh->refcnt > 0);
704                assert(oc->refcnt > 0);
705                r = --oc->refcnt;
706                if (!r)
707                        VTAILQ_REMOVE(&oh->objcs, oc, list);
708                hsh_rush(oh);
709                Lck_Unlock(&oh->mtx);
710        }
711
712        /* If still referenced, done */
713        if (r != 0)
714                return;
715
716        if (oh != NULL)
717                BAN_DestroyObj(o);
718        AZ(o->ban);
719        DSL(0x40, SLT_Debug, 0, "Object %u workspace min free %u",
720            o->xid, WS_Free(o->ws_o));
721
722        if (o->esidata != NULL)
723                ESI_Destroy(o);
724        if (o->objcore != NULL && o->objcore->smp_seg != NULL) {
725                SMP_FreeObj(o);
726        } else {
727                HSH_Freestore(o);
728                if (o->objstore != NULL)
729                        STV_free(o->objstore);
730                else
731                        FREE_OBJ(o);
732        }
733        o = NULL;
734        w->stats.n_object--;
735
736        if (oc == NULL) {
737                AZ(oh);
738                return;
739        }
740        AN(oh);
741        FREE_OBJ(oc);
742        w->stats.n_objectcore--;
743        /* Drop our ref on the objhead */
744        assert(oh->refcnt > 0);
745        if (hash->deref(oh))
746                return;
747        HSH_DeleteObjHead(w, oh);
748}
749
750void
751HSH_Init(void)
752{
753
754        assert(DIGEST_LEN == SHA256_LEN);       /* avoid #include pollution */
755        hash = heritage.hash;
756        if (hash->start != NULL)
757                hash->start();
758}
759
760static const struct choice hsh_choice[] = {
761        { "classic",            &hcl_slinger },
762        { "simple",             &hsl_slinger },
763        { "simple_list",        &hsl_slinger }, /* backwards compat */
764        { "critbit",            &hcb_slinger },
765        { NULL,                 NULL }
766};
767
768/*--------------------------------------------------------------------*/
769
770void
771HSH_config(const char *h_arg)
772{
773        char **av;
774        int ac;
775        const struct hash_slinger *hp;
776
777        ASSERT_MGT();
778        av = ParseArgv(h_arg, ARGV_COMMA);
779        AN(av);
780
781        if (av[0] != NULL)
782                ARGV_ERR("%s\n", av[0]);
783
784        if (av[1] == NULL)
785                ARGV_ERR("-h argument is empty\n");
786
787        for (ac = 0; av[ac + 2] != NULL; ac++)
788                continue;
789
790        hp = pick(hsh_choice, av[1], "hash");
791        CHECK_OBJ_NOTNULL(hp, SLINGER_MAGIC);
792        vsb_printf(vident, ",-h%s", av[1]);
793        heritage.hash = hp;
794        if (hp->init != NULL)
795                hp->init(ac, av + 2);
796        else if (ac > 0)
797                ARGV_ERR("Hash method \"%s\" takes no arguments\n",
798                    hp->name);
799}
800
Note: See TracBrowser for help on using the repository browser.