varnish-cache/bin/varnishd/storage/storage_simple.c
1
/*-
2
 * Copyright (c) 2007-2015 Varnish Software AS
3
 * All rights reserved.
4
 *
5
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions
9
 * are met:
10
 * 1. Redistributions of source code must retain the above copyright
11
 *    notice, this list of conditions and the following disclaimer.
12
 * 2. Redistributions in binary form must reproduce the above copyright
13
 *    notice, this list of conditions and the following disclaimer in the
14
 *    documentation and/or other materials provided with the distribution.
15
 *
16
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
20
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
 * SUCH DAMAGE.
27
 *
28
 */
29
30
#include "config.h"
31
32
#include "cache/cache_varnishd.h"
33
34
#include "cache/cache_obj.h"
35
#include "cache/cache_objhead.h"
36
37
#include "storage/storage.h"
38
#include "storage/storage_simple.h"
39
40
#include "vtim.h"
41
42
/* Flags for allocating memory in sml_stv_alloc */
43
#define LESS_MEM_ALLOCED_IS_OK  1
44
45
/*-------------------------------------------------------------------*/
46
47
static struct storage *
48 3734
sml_stv_alloc(const struct stevedore *stv, size_t size, int flags)
49
{
50
        struct storage *st;
51
52 3734
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
53 3734
        AN(stv->sml_alloc);
54
55 3734
        if (!(flags & LESS_MEM_ALLOCED_IS_OK)) {
56 460
                if (size > cache_param->fetch_maxchunksize)
57 0
                        return (NULL);
58
                else
59 460
                        return (stv->sml_alloc(stv, size));
60
        }
61
62 3274
        if (size > cache_param->fetch_maxchunksize)
63 0
                size = cache_param->fetch_maxchunksize;
64
65 3274
        assert(size <= UINT_MAX);       /* field limit in struct storage */
66
67
        for (;;) {
68
                /* try to allocate from it */
69 3662
                assert(size > 0);
70 3468
                st = stv->sml_alloc(stv, size);
71 3468
                if (st != NULL)
72 3256
                        break;
73
74 212
                if (size <= cache_param->fetch_chunksize)
75 18
                        break;
76
77 194
                size >>= 1;
78
        }
79 3274
        CHECK_OBJ_ORNULL(st, STORAGE_MAGIC);
80 3274
        return (st);
81
}
82
83
static void
84 4600
sml_stv_free(const struct stevedore *stv, struct storage *st)
85
{
86
87 4600
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
88 4600
        CHECK_OBJ_NOTNULL(st, STORAGE_MAGIC);
89 4600
        if (stv->sml_free != NULL)
90 4600
                stv->sml_free(st);
91 4600
}
92
93
/*--------------------------------------------------------------------
94
 * This function is called by stevedores ->allocobj() method, which
95
 * very often will be SML_allocobj() below, to convert a slab
96
 * of storage into object which the stevedore can then register in its
97
 * internal state, before returning it to STV_NewObject().
98
 * As you probably guessed: All this for persistence.
99
 */
100
101
struct object *
102 3898
SML_MkObject(const struct stevedore *stv, struct objcore *oc, void *ptr)
103
{
104
        struct object *o;
105
106 3898
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
107 3898
        AN(stv->methods);
108 3898
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
109
110 3898
        assert(PAOK(ptr));
111
112 3898
        o = ptr;
113 3898
        INIT_OBJ(o, OBJECT_MAGIC);
114
115 3898
        VTAILQ_INIT(&o->list);
116
117 3898
        oc->stobj->stevedore = stv;
118 3898
        oc->stobj->priv = o;
119 3898
        oc->stobj->priv2 = 0;
120 3898
        return (o);
121
}
122
123
/*--------------------------------------------------------------------
124
 * This is the default ->allocobj() which all stevedores who do not
125
 * implement persistent storage can rely on.
126
 */
127
128
int v_matchproto_(storage_allocobj_f)
129 3864
SML_allocobj(struct worker *wrk, const struct stevedore *stv,
130
    struct objcore *oc, unsigned wsl)
131
{
132
        struct object *o;
133 3864
        struct storage *st = NULL;
134
        unsigned ltot;
135
136 3864
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
137 3864
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
138 3864
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
139
140 3864
        AN(stv->sml_alloc);
141
142 3864
        ltot = sizeof(struct object) + PRNDUP(wsl);
143
144
        do {
145 3870
                st = stv->sml_alloc(stv, ltot);
146 3870
                if (st != NULL && st->space < ltot) {
147 0
                        stv->sml_free(st);
148 0
                        st = NULL;
149
                }
150 3870
        } while (st == NULL && LRU_NukeOne(wrk, stv->lru));
151 3864
        if (st == NULL)
152 10
                return (0);
153
154 3854
        CHECK_OBJ_NOTNULL(st, STORAGE_MAGIC);
155 3854
        o = SML_MkObject(stv, oc, st->ptr);
156 3854
        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
157 3854
        st->len = sizeof(*o);
158 3854
        o->objstore = st;
159 3854
        return (1);
160
}
161
162
/*---------------------------------------------------------------------
163
 */
164
165
static struct object *
166 277667
sml_getobj(struct worker *wrk, struct objcore *oc)
167
{
168
        const struct stevedore *stv;
169
        struct object *o;
170
171 277667
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
172 277667
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
173 277667
        stv = oc->stobj->stevedore;
174 277667
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
175 277667
        if (stv->sml_getobj != NULL)
176 550
                return (stv->sml_getobj(wrk, oc));
177 277117
        if (oc->stobj->priv == NULL)
178 0
                return (NULL);
179 277117
        CAST_OBJ_NOTNULL(o, oc->stobj->priv, OBJECT_MAGIC);
180 277117
        return (o);
181
}
182
183
static void v_matchproto_(objslim_f)
184 3928
sml_slim(struct worker *wrk, struct objcore *oc)
185
{
186
        const struct stevedore *stv;
187
        struct object *o;
188
        struct storage *st, *stn;
189
190 3928
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
191
192 3928
        stv = oc->stobj->stevedore;
193 3928
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
194 3928
        o = sml_getobj(wrk, oc);
195 3928
        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
196
197
#define OBJ_AUXATTR(U, l)                                               \
198
        if (o->aa_##l != NULL) {                                        \
199
                sml_stv_free(stv, o->aa_##l);                           \
200
                o->aa_##l = NULL;                                       \
201
        }
202
#include "tbl/obj_attr.h"
203
204 5205
        VTAILQ_FOREACH_SAFE(st, &o->list, list, stn) {
205 1277
                CHECK_OBJ_NOTNULL(st, STORAGE_MAGIC);
206 1277
                VTAILQ_REMOVE(&o->list, st, list);
207 1277
                sml_stv_free(stv, st);
208
        }
209 3928
}
210
211
static void v_matchproto_(objfree_f)
212 2220
sml_objfree(struct worker *wrk, struct objcore *oc)
213
{
214
        struct object *o;
215
216 2220
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
217 2220
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
218 2220
        sml_slim(wrk, oc);
219 2220
        CAST_OBJ_NOTNULL(o, oc->stobj->priv, OBJECT_MAGIC);
220 2220
        o->magic = 0;
221
222 2220
        if (oc->boc == NULL && oc->stobj->stevedore->lru != NULL)
223 2180
                LRU_Remove(oc);
224
225 2220
        sml_stv_free(oc->stobj->stevedore, o->objstore);
226
227 2220
        memset(oc->stobj, 0, sizeof oc->stobj);
228
229 2220
        wrk->stats->n_object--;
230 2220
}
231
232
static int v_matchproto_(objiterate_f)
233 3364
sml_iterator(struct worker *wrk, struct objcore *oc,
234
    void *priv, objiterate_f *func, int final)
235
{
236
        struct boc *boc;
237
        struct object *obj;
238
        struct storage *st;
239 3364
        struct storage *checkpoint = NULL;
240
        const struct stevedore *stv;
241 3364
        ssize_t checkpoint_len = 0;
242 3364
        ssize_t len = 0;
243 3364
        int ret = 0;
244
        ssize_t ol;
245
        ssize_t nl;
246
        ssize_t sl;
247
        void *p;
248
        ssize_t l;
249
        unsigned u;
250
251 3364
        obj = sml_getobj(wrk, oc);
252 3364
        CHECK_OBJ_NOTNULL(obj, OBJECT_MAGIC);
253 3364
        stv = oc->stobj->stevedore;
254 3364
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
255
256 3364
        boc = HSH_RefBoc(oc);
257
258 3364
        if (boc == NULL) {
259 4244
                VTAILQ_FOREACH_SAFE(st, &obj->list, list, checkpoint) {
260 2247
                        u = 0;
261 2247
                        if (VTAILQ_NEXT(st, list) == NULL)
262 2037
                                u |= OBJ_ITER_FINAL;
263 2247
                        if (final)
264 679
                                u |= OBJ_ITER_FLUSH;
265 2247
                        if (ret == 0 && st->len > 0)
266 2247
                                ret = func(priv, u, st->ptr, st->len);
267 2247
                        if (final) {
268 679
                                VTAILQ_REMOVE(&obj->list, st, list);
269 679
                                sml_stv_free(stv, st);
270 1568
                        } else if (ret)
271 40
                                break;
272
                }
273 2037
                return (ret);
274
        }
275
276 1327
        p = NULL;
277 1327
        l = 0;
278
279
        while (1) {
280 4551
                ol = len;
281 2939
                nl = ObjWaitExtend(wrk, oc, ol);
282 2939
                if (boc->state == BOS_FAILED) {
283 22
                        ret = -1;
284 22
                        break;
285
                }
286 2917
                if (nl == ol) {
287 1295
                        if (boc->state == BOS_FINISHED)
288 1295
                                break;
289 0
                        continue;
290
                }
291 1622
                Lck_Lock(&boc->mtx);
292 1622
                AZ(VTAILQ_EMPTY(&obj->list));
293 1622
                if (checkpoint == NULL) {
294 1432
                        st = VTAILQ_FIRST(&obj->list);
295 1432
                        sl = 0;
296
                } else {
297 190
                        st = checkpoint;
298 190
                        sl = checkpoint_len;
299 190
                        ol -= checkpoint_len;
300
                }
301 3490
                while (st != NULL) {
302 1868
                        if (st->len > ol) {
303 1622
                                p = st->ptr + ol;
304 1622
                                l = st->len - ol;
305 1622
                                len += l;
306 1622
                                break;
307
                        }
308 246
                        ol -= st->len;
309 246
                        assert(ol >= 0);
310 246
                        nl -= st->len;
311 246
                        assert(nl > 0);
312 246
                        sl += st->len;
313 246
                        st = VTAILQ_NEXT(st, list);
314 246
                        if (VTAILQ_NEXT(st, list) != NULL) {
315 168
                                if (final && checkpoint != NULL) {
316 122
                                        VTAILQ_REMOVE(&obj->list,
317
                                            checkpoint, list);
318 122
                                        sml_stv_free(stv, checkpoint);
319
                                }
320 168
                                checkpoint = st;
321 168
                                checkpoint_len = sl;
322
                        }
323
                }
324 1622
                CHECK_OBJ_NOTNULL(obj, OBJECT_MAGIC);
325 1622
                CHECK_OBJ_NOTNULL(st, STORAGE_MAGIC);
326 1622
                st = VTAILQ_NEXT(st, list);
327 1622
                if (st != NULL && st->len == 0)
328 7
                        st = NULL;
329 1622
                Lck_Unlock(&boc->mtx);
330 1622
                assert(l > 0 || boc->state == BOS_FINISHED);
331 1622
                u = 0;
332 1622
                if (st == NULL || final)
333 1581
                        u |= OBJ_ITER_FLUSH;
334 1622
                ret = func(priv, u, p, l);
335 1622
                if (ret)
336 10
                        break;
337
        }
338 1327
        HSH_DerefBoc(wrk, oc);
339 1327
        return (ret);
340
}
341
342
/*--------------------------------------------------------------------
343
 */
344
345
static struct storage *
346 3450
objallocwithnuke(struct worker *wrk, const struct stevedore *stv, size_t size,
347
    int flags)
348
{
349 3450
        struct storage *st = NULL;
350
351 3450
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
352 3450
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
353
354 3450
        if (size > cache_param->fetch_maxchunksize) {
355 0
                if (!(flags & LESS_MEM_ALLOCED_IS_OK))
356 0
                        return (NULL);
357 0
                size = cache_param->fetch_maxchunksize;
358
        }
359
360 3450
        assert(size <= UINT_MAX);       /* field limit in struct storage */
361
362
        do {
363
                /* try to allocate from it */
364 3460
                st = sml_stv_alloc(stv, size, flags);
365 3460
                if (st != NULL)
366 3440
                        break;
367
368
                /* no luck; try to free some space and keep trying */
369 20
                if (stv->lru == NULL)
370 0
                        break;
371 20
        } while (LRU_NukeOne(wrk, stv->lru));
372
373 3450
        CHECK_OBJ_ORNULL(st, STORAGE_MAGIC);
374 3450
        return (st);
375
}
376
377
static int v_matchproto_(objgetspace_f)
378 112574
sml_getspace(struct worker *wrk, struct objcore *oc, ssize_t *sz,
379
    uint8_t **ptr)
380
{
381
        struct object *o;
382
        struct storage *st;
383
384 112574
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
385 112574
        AN(sz);
386 112574
        AN(ptr);
387 112574
        assert(*sz > 0);
388
389 112574
        o = sml_getobj(wrk, oc);
390 112574
        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
391 112574
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
392
393 112574
        st = VTAILQ_LAST(&o->list, storagehead);
394 112574
        if (st != NULL && st->len < st->space) {
395 109309
                *sz = st->space - st->len;
396 109309
                *ptr = st->ptr + st->len;
397 109309
                assert (*sz > 0);
398 109309
                return (1);
399
        }
400
401 3265
        st = objallocwithnuke(wrk, oc->stobj->stevedore, *sz,
402
            LESS_MEM_ALLOCED_IS_OK);
403 3266
        if (st == NULL)
404 10
                return (0);
405
406 3256
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
407 3256
        Lck_Lock(&oc->boc->mtx);
408 3256
        VTAILQ_INSERT_TAIL(&o->list, st, list);
409 3256
        Lck_Unlock(&oc->boc->mtx);
410
411 3256
        *sz = st->space - st->len;
412 3256
        assert (*sz > 0);
413 3256
        *ptr = st->ptr + st->len;
414 3256
        return (1);
415
}
416
417
static void v_matchproto_(objextend_f)
418 110193
sml_extend(struct worker *wrk, struct objcore *oc, ssize_t l)
419
{
420
        struct object *o;
421
        struct storage *st;
422
423 110193
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
424 110193
        assert(l > 0);
425
426 110193
        o = sml_getobj(wrk, oc);
427 110193
        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
428 110193
        st = VTAILQ_LAST(&o->list, storagehead);
429 110193
        CHECK_OBJ_NOTNULL(st, STORAGE_MAGIC);
430 110193
        assert(st->len + l <= st->space);
431 110193
        st->len += l;
432 110193
}
433
434
static void v_matchproto_(objtrimstore_f)
435 1792
sml_trimstore(struct worker *wrk, struct objcore *oc)
436
{
437
        const struct stevedore *stv;
438
        struct storage *st, *st1;
439
        struct object *o;
440
441 1792
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
442 1792
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
443 1792
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
444
445 1792
        stv = oc->stobj->stevedore;
446 1792
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
447
448 1792
        if (stv->sml_free == NULL)
449 6
                return;
450
451 1786
        o = sml_getobj(wrk, oc);
452 1786
        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
453 1786
        st = VTAILQ_LAST(&o->list, storagehead);
454
455 1786
        if (st == NULL)
456 0
                return;
457
458 1786
        if (st->len == 0) {
459 10
                Lck_Lock(&oc->boc->mtx);
460 10
                VTAILQ_REMOVE(&o->list, st, list);
461 10
                Lck_Unlock(&oc->boc->mtx);
462 10
                sml_stv_free(stv, st);
463 10
                return;
464
        }
465
466 1776
        if (st->space - st->len < 512)
467 1502
                return;
468
469 274
        st1 = sml_stv_alloc(stv, st->len, 0);
470 274
        if (st1 == NULL)
471 0
                return;
472 274
        assert(st1->space >= st->len);
473
474 274
        memcpy(st1->ptr, st->ptr, st->len);
475 274
        st1->len = st->len;
476 274
        Lck_Lock(&oc->boc->mtx);
477 274
        VTAILQ_REMOVE(&o->list, st, list);
478 274
        VTAILQ_INSERT_TAIL(&o->list, st1, list);
479 274
        Lck_Unlock(&oc->boc->mtx);
480
        /* sml_bocdone frees this */
481 274
        AZ(oc->boc->stevedore_priv);
482 274
        oc->boc->stevedore_priv = st;
483
}
484
485
static void v_matchproto_(objbocdone_f)
486 3890
sml_bocdone(struct worker *wrk, struct objcore *oc, struct boc *boc)
487
{
488
        const struct stevedore *stv;
489
        struct storage *st;
490
491 3890
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
492 3890
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
493 3890
        CHECK_OBJ_NOTNULL(boc, BOC_MAGIC);
494 3890
        stv = oc->stobj->stevedore;
495 3890
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
496
497 3890
        if (boc->stevedore_priv != NULL) {
498
                /* Free any leftovers from Trim */
499 274
                CAST_OBJ_NOTNULL(st, boc->stevedore_priv, STORAGE_MAGIC);
500 274
                boc->stevedore_priv = 0;
501 274
                CHECK_OBJ_NOTNULL(st, STORAGE_MAGIC);
502 274
                sml_stv_free(stv, st);
503
        }
504
505 3890
        if (stv->lru != NULL) {
506 3814
                if (isnan(wrk->lastused))
507 0
                        wrk->lastused = VTIM_real();
508 3814
                LRU_Add(oc, wrk->lastused);     // approx timestamp is OK
509
        }
510 3890
}
511
512
static const void * v_matchproto_(objgetattr_f)
513 30498
sml_getattr(struct worker *wrk, struct objcore *oc, enum obj_attr attr,
514
   ssize_t *len)
515
{
516
        struct object *o;
517
        ssize_t dummy;
518
519 30498
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
520
521 30498
        if (len == NULL)
522 20006
                len = &dummy;
523 30498
        o = sml_getobj(wrk, oc);
524 30497
        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
525
526 30497
        switch (attr) {
527
                /* Fixed size attributes */
528
#define OBJ_FIXATTR(U, l, s)                                            \
529
        case OA_##U:                                                    \
530
                *len = sizeof o->fa_##l;                                \
531
                return (o->fa_##l);
532
#include "tbl/obj_attr.h"
533
534
                /* Variable size attributes */
535
#define OBJ_VARATTR(U, l)                                               \
536
        case OA_##U:                                                    \
537
                if (o->va_##l == NULL)                                  \
538
                        return (NULL);                                  \
539
                *len = o->va_##l##_len;                                 \
540
                return (o->va_##l);
541
#include "tbl/obj_attr.h"
542
543
                /* Auxiliary attributes */
544
#define OBJ_AUXATTR(U, l)                                               \
545
        case OA_##U:                                                    \
546
                if (o->aa_##l == NULL)                                  \
547
                        return (NULL);                                  \
548
                CHECK_OBJ_NOTNULL(o->aa_##l, STORAGE_MAGIC);            \
549
                *len = o->aa_##l->len;                                  \
550
                return (o->aa_##l->ptr);
551
#include "tbl/obj_attr.h"
552
553
        default:
554 0
                break;
555
        }
556 0
        WRONG("Unsupported OBJ_ATTR");
557
}
558
559
static void * v_matchproto_(objsetattr_f)
560 15334
sml_setattr(struct worker *wrk, struct objcore *oc, enum obj_attr attr,
561
    ssize_t len, const void *ptr)
562
{
563
        struct object *o;
564 15334
        void *retval = NULL;
565
        struct storage *st;
566
567 15334
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
568
569 15334
        o = sml_getobj(wrk, oc);
570 15332
        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
571 15332
        st = o->objstore;
572
573 15332
        switch (attr) {
574
                /* Fixed size attributes */
575
#define OBJ_FIXATTR(U, l, s)                                            \
576
        case OA_##U:                                                    \
577
                assert(len == sizeof o->fa_##l);                        \
578
                retval = o->fa_##l;                                     \
579
                break;
580
#include "tbl/obj_attr.h"
581
582
                /* Variable size attributes */
583
#define OBJ_VARATTR(U, l)                                               \
584
        case OA_##U:                                                    \
585
                if (o->va_##l##_len > 0) {                              \
586
                        AN(o->va_##l);                                  \
587
                        assert(len == o->va_##l##_len);                 \
588
                        retval = o->va_##l;                             \
589
                } else if (len > 0) {                                   \
590
                        assert(len <= UINT_MAX);                        \
591
                        assert(st->len + len <= st->space);             \
592
                        o->va_##l = st->ptr + st->len;                  \
593
                        st->len += len;                                 \
594
                        o->va_##l##_len = len;                          \
595
                        retval = o->va_##l;                             \
596
                }                                                       \
597
                break;
598
#include "tbl/obj_attr.h"
599
600
                /* Auxiliary attributes */
601
#define OBJ_AUXATTR(U, l)                                               \
602
        case OA_##U:                                                    \
603
                if (o->aa_##l != NULL) {                                \
604
                        CHECK_OBJ_NOTNULL(o->aa_##l, STORAGE_MAGIC);    \
605
                        assert(len == o->aa_##l->len);                  \
606
                        retval = o->aa_##l->ptr;                        \
607
                        break;                                          \
608
                }                                                       \
609
                if (len == 0)                                           \
610
                        break;                                          \
611
                o->aa_##l = objallocwithnuke(wrk, oc->stobj->stevedore, \
612
                    len, 0);                                            \
613
                if (o->aa_##l == NULL)                                  \
614
                        break;                                          \
615
                CHECK_OBJ_NOTNULL(o->aa_##l, STORAGE_MAGIC);            \
616
                assert(len <= o->aa_##l->space);                        \
617
                o->aa_##l->len = len;                                   \
618
                retval = o->aa_##l->ptr;                                \
619
                break;
620
#include "tbl/obj_attr.h"
621
622
        default:
623 0
                WRONG("Unsupported OBJ_ATTR");
624
                break;
625
        }
626
627 15332
        if (retval != NULL && ptr != NULL)
628 626
                memcpy(retval, ptr, len);
629 15332
        return (retval);
630
}
631
632
const struct obj_methods SML_methods = {
633
        .objfree        = sml_objfree,
634
        .objiterator    = sml_iterator,
635
        .objgetspace    = sml_getspace,
636
        .objextend      = sml_extend,
637
        .objtrimstore   = sml_trimstore,
638
        .objbocdone     = sml_bocdone,
639
        .objslim        = sml_slim,
640
        .objgetattr     = sml_getattr,
641
        .objsetattr     = sml_setattr,
642
        .objtouch       = LRU_Touch,
643
};
644
645
static void
646 4
sml_panic_st(struct vsb *vsb, const char *hd, const struct storage *st)
647
{
648 4
        VSB_printf(vsb, "%s = %p {priv=%p, ptr=%p, len=%u, space=%u},\n",
649
            hd, st, st->priv, st->ptr, st->len, st->space);
650 4
}
651
652
void
653 2
SML_panic(struct vsb *vsb, const struct objcore *oc)
654
{
655
        struct object *o;
656
        struct storage *st;
657
658 2
        VSB_printf(vsb, "Simple = %p,\n", oc->stobj->priv);
659 2
        if (oc->stobj->priv == NULL)
660 0
                return;
661 2
        CAST_OBJ_NOTNULL(o, oc->stobj->priv, OBJECT_MAGIC);
662 2
        sml_panic_st(vsb, "Obj", o->objstore);
663
664
#define OBJ_FIXATTR(U, l, sz) \
665
        VSB_printf(vsb, "%s = ", #U); \
666
        VSB_quote(vsb, (const void*)o->fa_##l, sz, VSB_QUOTE_HEX); \
667
        VSB_printf(vsb, ",\n");
668
669
#define OBJ_VARATTR(U, l) \
670
        VSB_printf(vsb, "%s = {len=%u, ptr=%p},\n", \
671
            #U, o->va_##l##_len, o->va_##l);
672
673
#define OBJ_AUXATTR(U, l) \
674
        if (o->aa_##l != NULL) sml_panic_st(vsb, #U, o->aa_##l);
675
676
#include "tbl/obj_attr.h"
677
678 4
        VTAILQ_FOREACH(st, &o->list, list) {
679 2
                sml_panic_st(vsb, "Body", st);
680
        }
681
}