source: bin/varnishd/cache_hash.c @ 24c315

Revision 24c315, 16.2 KB checked in by Poul-Henning Kamp <phk@…>, 5 years ago (diff)

Add a debug facility for substituting digests with hand-created
digests with edge-bit conditions and run the critbit through them.

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

  • Property mode set to 100644
Line 
1/*-
2 * Copyright (c) 2006 Verdens Gang AS
3 * Copyright (c) 2006-2009 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 * $Id$
30 *
31 * This is the central hash-table code, it relies on a chosen hash
32 * implementation only for the actual hashing, all the housekeeping
33 * happens here.
34 *
35 * We have two kinds of structures, objecthead and object.  An objecthead
36 * corresponds to a given (Host:, URL) tupple, and the objects hung from
37 * the objecthead may represent various variations (ie: Vary: header,
38 * different TTL etc) instances of that web-entity.
39 *
40 * Each objecthead has a mutex which locks both its own fields, the
41 * list of objects and fields in the objects.
42 *
43 * The hash implementation must supply a reference count facility on
44 * the objecthead, and return with a reference held after a lookup.
45 *
46 * Lookups in the hash implementation returns with a ref held and each
47 * object hung from the objhead holds a ref as well.
48 *
49 * Objects have refcounts which are locked by the objecthead mutex.
50 *
51 * New objects are always marked busy, and they can go from busy to
52 * not busy only once.
53 */
54
55#include "config.h"
56
57#include <stdio.h>
58#include <stdlib.h>
59#include <math.h>
60#include <string.h>
61#include <limits.h>
62#include <sys/types.h>
63#include <fcntl.h>
64
65#include "shmlog.h"
66#include "cache.h"
67#include "stevedore.h"
68#include "hash_slinger.h"
69#include "vsha256.h"
70
71static const struct hash_slinger *hash;
72unsigned        save_hash;
73
74double
75HSH_Grace(double g)
76{
77        if (isnan(g))
78                return (double)(params->default_grace);
79        return (g);
80}
81
82struct object *
83HSH_NewObject(struct sess *sp, int transient)
84{
85        struct object *o;
86        struct storage *st;
87        void *p;
88
89        if (transient) {
90                p = malloc(sizeof *o + params->obj_workspace);
91                XXXAN(p);
92                o = p;
93                p = o + 1;
94                memset(o, 0, sizeof *o);
95                o->magic = OBJECT_MAGIC;
96                WS_Init(o->ws_o, "obj", p, params->obj_workspace);
97        } else {
98                st = STV_alloc(sp, params->obj_workspace);
99                XXXAN(st);
100                assert(st->space > sizeof *o);
101                o = (void *)st->ptr; /* XXX: align ? */
102                st->len = sizeof *o;
103                memset(o, 0, sizeof *o);
104                o->magic = OBJECT_MAGIC;
105                o->objstore = st;
106                WS_Init(o->ws_o, "obj",
107                    st->ptr + st->len, st->space - st->len);
108                st->len = st->space;
109        }
110        WS_Assert(o->ws_o);
111        http_Setup(o->http, o->ws_o);
112        o->http->magic = HTTP_MAGIC;
113        o->refcnt = 1;
114        o->grace = NAN;
115        o->entered = NAN;
116        VTAILQ_INIT(&o->store);
117        VTAILQ_INIT(&o->esibits);
118        sp->wrk->stats->n_object++;
119        return (o);
120}
121
122/* Precreate an objhead and object for later use */
123void
124HSH_Prealloc(const struct sess *sp)
125{
126        struct worker *w;
127        struct objhead *oh;
128        struct objcore *oc;
129
130        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
131        CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC);
132        w = sp->wrk;
133
134        if (w->nobjcore == NULL) {
135                ALLOC_OBJ(oc, OBJCORE_MAGIC);
136                XXXAN(oc);
137                w->nobjcore = oc;
138                oc->flags |= OC_F_BUSY;
139        }
140        CHECK_OBJ_NOTNULL(w->nobjcore, OBJCORE_MAGIC);
141
142        if (w->nobjhead == NULL) {
143                ALLOC_OBJ(oh, OBJHEAD_MAGIC);
144                XXXAN(oh);
145                oh->refcnt = 1;
146                VTAILQ_INIT(&oh->objcs);
147                VTAILQ_INIT(&oh->waitinglist);
148                Lck_New(&oh->mtx);
149                w->nobjhead = oh;
150                w->stats->n_objecthead++;
151        }
152        CHECK_OBJ_NOTNULL(w->nobjhead, OBJHEAD_MAGIC);
153
154}
155
156void
157HSH_Cleanup(struct worker *w)
158{
159
160        if (w->nobjcore != NULL) {
161                FREE_OBJ(w->nobjcore);
162                w->nobjcore = NULL;
163        }
164        if (w->nobjhead != NULL) {
165                Lck_Delete(&w->nobjhead->mtx);
166                FREE_OBJ(w->nobjhead);
167                w->nobjhead = NULL;
168                w->stats->n_objecthead--;
169        }
170}
171
172void
173HSH_DeleteObjHead(const struct worker *w, struct objhead *oh)
174{
175
176        AZ(oh->refcnt);
177        assert(VTAILQ_EMPTY(&oh->objcs));
178        Lck_Delete(&oh->mtx);
179        w->stats->n_objecthead--;
180        free(oh->hash);
181        FREE_OBJ(oh);
182}
183
184void
185HSH_Freestore(struct object *o)
186{
187        struct storage *st, *stn;
188
189        VTAILQ_FOREACH_SAFE(st, &o->store, list, stn) {
190                CHECK_OBJ_NOTNULL(st, STORAGE_MAGIC);
191                VTAILQ_REMOVE(&o->store, st, list);
192                STV_free(st);
193        }
194}
195
196void
197HSH_Copy(const struct sess *sp, struct objhead *oh)
198{
199        unsigned u, v;
200        char *b;
201
202        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
203        CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC);
204        if (!save_hash)
205                return;
206
207        oh->hash = malloc(sp->lhashptr);
208        XXXAN(oh->hash);
209        b = oh->hash;
210        for (u = 0; u < sp->ihashptr; u += 2) {
211                v = pdiff(sp->hashptr[u], sp->hashptr[u + 1]);
212                memcpy(b, sp->hashptr[u], v);
213                b += v;
214                *b++ = '#';
215        }
216        *b++ = '\0';
217        assert(b <= oh->hash + sp->lhashptr);
218}
219
220void
221HSH_Prepare(struct sess *sp, unsigned nhashcount)
222{
223        char *p;
224        unsigned u;
225
226        SHA256_Init(sp->wrk->sha256ctx);
227        if (!save_hash)
228                return;
229
230        /* Allocate the pointers we need, align properly. */
231        sp->lhashptr = 1;       /* space for NUL */
232        sp->ihashptr = 0;
233        sp->nhashptr = nhashcount * 2;
234        p = WS_Alloc(sp->http->ws, sizeof(const char *) * (sp->nhashptr + 1));
235        XXXAN(p);
236        /* Align pointer properly (?) */
237        u = (uintptr_t)p;
238        u &= sizeof(const char *) - 1;
239        if (u)
240                p += sizeof(const char *) - u;
241        sp->hashptr = (void*)p;
242}
243
244void
245HSH_AddString(struct sess *sp, const char *str)
246{
247        int l;
248
249        if (str == NULL)
250                str = "";
251        l = strlen(str);
252
253        SHA256_Update(sp->wrk->sha256ctx, str, l);
254        SHA256_Update(sp->wrk->sha256ctx, "#", 1);
255
256        if (params->log_hash)
257                WSP(sp, SLT_Hash, "%s", str);
258
259        if (!save_hash)
260                return;
261
262        /*
263        * XXX: handle this by bouncing sp->vcl->nhashcount when it fails
264        * XXX: and dispose of this request either by reallocating the
265        * XXX: hashptr (if possible) or restarting/error the request
266        */
267        xxxassert(sp->ihashptr < sp->nhashptr);
268
269        sp->hashptr[sp->ihashptr] = str;
270        sp->hashptr[sp->ihashptr + 1] = str + l;
271        sp->ihashptr += 2;
272        sp->lhashptr += l + 1;
273}
274
275/**********************************************************************
276 * This is a debugging hack to enable testing of boundary conditions
277 * in the hash algorithm.
278 * We trap the first 9 different digests and translate them to different
279 * digests with edge bit conditions
280 */
281
282static struct hsh_magiclist {
283        unsigned char was[SHA256_LEN];
284        unsigned char now[SHA256_LEN];
285} hsh_magiclist[] = {
286        { .now = {      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
287                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
288                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
289                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
290        { .now = {      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
291                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
292                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
293                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } },
294        { .now = {      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
295                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
296                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
297                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02 } },
298        { .now = {      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
299                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
300                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
301                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40 } },
302        { .now = {      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
303                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
304                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
305                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80 } },
306        { .now = {      0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
307                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
308                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
309                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
310        { .now = {      0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
311                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
312                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
313                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
314        { .now = {      0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
315                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
316                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
317                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
318        { .now = {      0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
319                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
320                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
321                        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
322};
323
324#define HSH_NMAGIC (sizeof hsh_magiclist / sizeof hsh_magiclist[0])
325
326static void
327hsh_testmagic(void *result)
328{
329        int i, j;
330        static int nused;
331
332        for (i = 0; i < nused; i++)
333                if (!memcmp(hsh_magiclist[i].was, result, SHA256_LEN))
334                        break;
335        if (i == nused && i < HSH_NMAGIC) 
336                memcpy(hsh_magiclist[nused++].was, result, SHA256_LEN);
337        if (i == nused)
338                return;
339        fprintf(stderr, "HASHMAGIC: <");
340        for (j = 0; j < SHA256_LEN; j++)
341                fprintf(stderr, "%02x", ((unsigned char*)result)[j]);
342        fprintf(stderr, "> -> <");
343        memcpy(result, hsh_magiclist[i].now, SHA256_LEN);
344        for (j = 0; j < SHA256_LEN; j++)
345                fprintf(stderr, "%02x", ((unsigned char*)result)[j]);
346        fprintf(stderr, ">\n");
347}
348
349/**********************************************************************/
350
351
352struct objcore *
353HSH_Lookup(struct sess *sp, struct objhead **poh)
354{
355        struct worker *w;
356        struct objhead *oh;
357        struct objcore *oc;
358        struct objcore *busy_oc, *grace_oc;
359        struct object *o;
360
361        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
362        CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC);
363        CHECK_OBJ_NOTNULL(sp->http, HTTP_MAGIC);
364        AN(hash);
365        w = sp->wrk;
366
367        HSH_Prealloc(sp);
368        SHA256_Final(sp->wrk->nobjhead->digest, sp->wrk->sha256ctx);
369        if (params->diag_bitmap & 0x80000000)
370                hsh_testmagic(sp->wrk->nobjhead->digest);
371       
372        if (sp->objhead != NULL) {
373                CHECK_OBJ_NOTNULL(sp->objhead, OBJHEAD_MAGIC);
374                oh = sp->objhead;
375                sp->objhead = NULL;
376                CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC);
377                Lck_Lock(&oh->mtx);
378        } else {
379                AN(w->nobjhead);
380                oh = hash->lookup(sp, w->nobjhead);
381                CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC);
382                if (oh == w->nobjhead)
383                        w->nobjhead = NULL;
384                Lck_Lock(&oh->mtx);
385        }
386
387        busy_oc = NULL;
388        grace_oc = NULL;
389        VTAILQ_FOREACH(oc, &oh->objcs, list) {
390                /* Must be at least our own ref + the objcore we examine */
391                assert(oh->refcnt > 1);
392                CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
393
394                if (oc->flags & OC_F_BUSY) {
395                        busy_oc = oc;
396                        continue;
397                }
398
399                o = oc->obj;
400                CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
401               
402                if (!o->cacheable)
403                        continue;
404                if (o->ttl == 0)
405                        continue;
406                if (BAN_CheckObject(o, sp)) 
407                        continue;
408                if (o->vary != NULL && !VRY_Match(sp, o->vary))
409                        continue;
410
411                /* If still valid, use it */
412                if (o->ttl >= sp->t_req)
413                        break;
414
415                /* Remember any matching objects inside their grace period */
416                if (o->ttl + HSH_Grace(o->grace) >= sp->t_req)
417                        grace_oc = oc;
418        }
419
420        /*
421         * If we have seen a busy object, and have an object in grace,
422         * use it, if req.grace is also satisified.
423         * XXX: Interesting footnote:  The busy object might be for a
424         * XXX: different "Vary:" than we sought.  We have no way of knowing
425         * XXX: this until the object is unbusy'ed, so in practice we
426         * XXX: serialize fetch of all Vary's if grace is possible.
427         */
428        if (oc == NULL && grace_oc != NULL && busy_oc != NULL) {
429                o = grace_oc->obj;
430                CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
431                if (o->ttl + HSH_Grace(sp->grace) >= sp->t_req)
432                        oc = grace_oc;
433        }
434
435        if (oc != NULL) {
436                o = oc->obj;
437                CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
438
439                /* We found an object we like */
440                o->refcnt++;
441                if (o->hits < INT_MAX)
442                        o->hits++;
443                assert(oh->refcnt > 1);
444                Lck_Unlock(&oh->mtx);
445                assert(hash->deref(oh));
446                *poh = oh;
447                return (oc);
448        }
449
450        if (busy_oc != NULL) {
451                /* There are one or more busy objects, wait for them */
452                if (sp->esis == 0)
453                        VTAILQ_INSERT_TAIL(&oh->waitinglist, sp, list);
454                if (params->diag_bitmap & 0x20)
455                        WSP(sp, SLT_Debug,
456                                "on waiting list <%s>", oh->hash);
457                sp->objhead = oh;
458                sp->wrk = NULL;
459                Lck_Unlock(&oh->mtx);
460                return (NULL);
461        }
462
463        /* Insert (precreated) objcore in objecthead */
464        oc = w->nobjcore;
465        w->nobjcore = NULL;
466        AN(oc->flags & OC_F_BUSY);
467
468        /* XXX: Should this not be ..._HEAD now ? */
469        VTAILQ_INSERT_TAIL(&oh->objcs, oc, list);
470        /* NB: do not deref objhead the new object inherits our reference */
471        Lck_Unlock(&oh->mtx);
472        *poh = oh;
473        return (oc);
474}
475
476static void
477hsh_rush(struct objhead *oh)
478{
479        unsigned u;
480        struct sess *sp;
481
482        CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC);
483        Lck_AssertHeld(&oh->mtx);
484        for (u = 0; u < params->rush_exponent; u++) {
485                sp = VTAILQ_FIRST(&oh->waitinglist);
486                if (sp == NULL)
487                        return;
488                CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
489                AZ(sp->wrk);
490                VTAILQ_REMOVE(&oh->waitinglist, sp, list);
491                DSL(0x20, SLT_Debug, sp->id, "off waiting list");
492                WRK_QueueSession(sp);
493        }
494}
495
496void
497HSH_Drop(struct sess *sp)
498{
499        struct object *o;
500
501        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
502        o = sp->obj;
503        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
504        assert(o->refcnt > 0);
505        if (o->objcore != NULL) {       /* Pass has no objcore */
506                AN(ObjIsBusy(o));
507                o->ttl = 0;
508        }
509        o->cacheable = 0;
510        if (o->objcore != NULL)         /* Pass has no objcore */
511                HSH_Unbusy(sp);
512        HSH_Deref(sp->wrk, &sp->obj);
513}
514
515void
516HSH_Unbusy(const struct sess *sp)
517{
518        struct object *o;
519        struct objhead *oh;
520
521        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
522        o = sp->obj;
523        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
524        AN(ObjIsBusy(o));
525        assert(o->objcore->obj == o);
526        assert(o->refcnt > 0);
527        if (o->ws_o->overflow)
528                VSL_stats->n_objoverflow++;
529        if (params->diag_bitmap & 0x40)
530                WSP(sp, SLT_Debug,
531                    "Object %u workspace free %u", o->xid, WS_Free(o->ws_o));
532
533        oh = o->objhead;
534        if (oh != NULL) {
535                CHECK_OBJ(oh, OBJHEAD_MAGIC);
536                Lck_Lock(&oh->mtx);
537        }
538        o->objcore->flags &= ~OC_F_BUSY;
539        if (oh != NULL) {
540                hsh_rush(oh);
541                Lck_Unlock(&oh->mtx);
542        }
543}
544
545void
546HSH_Ref(struct object *o)
547{
548        struct objhead *oh;
549
550        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
551        oh = o->objhead;
552        CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC);
553        Lck_Lock(&oh->mtx);
554        assert(o->refcnt > 0);
555        o->refcnt++;
556        Lck_Unlock(&oh->mtx);
557}
558
559void
560HSH_DerefObjCore(struct sess *sp)
561{
562        struct objhead *oh;
563        struct objcore *oc;
564
565        CHECK_OBJ_NOTNULL(sp->objhead, OBJHEAD_MAGIC);
566        CHECK_OBJ_NOTNULL(sp->objcore, OBJCORE_MAGIC);
567
568        oh = sp->objhead;
569        sp->objhead = NULL;
570        oc = sp->objcore;
571        sp->objcore = NULL;
572
573        Lck_Lock(&oh->mtx);
574        VTAILQ_REMOVE(&oh->objcs, oc, list);
575        Lck_Unlock(&oh->mtx);
576        assert(oh->refcnt > 0);
577        if (hash->deref(oh))
578                return;
579        HSH_DeleteObjHead(sp->wrk, oh);
580}
581
582void
583HSH_Deref(const struct worker *w, struct object **oo)
584{
585        struct object *o;
586        struct objhead *oh;
587        struct objcore *oc;
588        unsigned r;
589
590        AN(oo);
591        o = *oo;
592        *oo = NULL;
593        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
594        oh = o->objhead;
595        if (oh == NULL) {
596                oc = NULL;
597                assert(o->refcnt > 0);
598                r = --o->refcnt;
599        } else {
600                CHECK_OBJ_NOTNULL(oh, OBJHEAD_MAGIC);
601
602                oc = o->objcore;
603                CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
604               
605                Lck_Lock(&oh->mtx);
606                assert(o->refcnt > 0);
607                r = --o->refcnt;
608                if (!r)
609                        VTAILQ_REMOVE(&oh->objcs, oc, list);
610                else
611                        hsh_rush(oh);
612                Lck_Unlock(&oh->mtx);
613        }
614
615        /* If still referenced, done */
616        if (r != 0)
617                return;
618
619        BAN_DestroyObj(o);
620        AZ(o->ban);
621        DSL(0x40, SLT_Debug, 0, "Object %u workspace min free %u",
622            o->xid, WS_Free(o->ws_o));
623
624        if (o->vary != NULL)
625                free(o->vary);
626
627        ESI_Destroy(o);
628        HSH_Freestore(o);
629        if (o->objstore != NULL)
630                STV_free(o->objstore);
631        else
632                FREE_OBJ(o);
633        o = NULL;
634        w->stats->n_object--;
635
636        if (oh == NULL) {
637                AZ(oc);
638                return;
639        }
640        AN(oc);
641        FREE_OBJ(oc);
642        /* Drop our ref on the objhead */
643        assert(oh->refcnt > 0);
644        if (hash->deref(oh))
645                return;
646        HSH_DeleteObjHead(w, oh);
647}
648
649
650void
651HSH_Init(void)
652{
653
654        assert(DIGEST_LEN == SHA256_LEN);       /* avoid #include pollution */
655        save_hash = params->save_hash;
656        hash = heritage.hash;
657        if (hash->start != NULL)
658                hash->start();
659}
660
661const struct choice hsh_choice[] = {
662        { "classic",            &hcl_slinger },
663        { "simple",             &hsl_slinger },
664        { "simple_list",        &hsl_slinger }, /* backwards compat */
665        { "critbit",            &hcb_slinger },
666        { NULL,                 NULL }
667};
Note: See TracBrowser for help on using the repository browser.