source: bin/varnishd/cache_hash.c @ fe7b3f

Revision fe7b3f, 16.3 KB checked in by Kristian Lyngstøl <kristian@…>, 5 years ago (diff)

Use a graced object if a backend is unhealthy

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