vinyl-cache/bin/vinyld/storage/storage_simple.c
0
/*-
1
 * Copyright (c) 2007-2015 Varnish Software AS
2
 * All rights reserved.
3
 *
4
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
5
 *
6
 * SPDX-License-Identifier: BSD-2-Clause
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
 */
30
31
#include "config.h"
32
33
#include <stdlib.h>
34
35 9288
#include "cache/cache_int.h"
36 9320
37 2132
#include "cache/cache_obj.h"
38 1445
#include "cache/cache_objhead.h"
39 9320
40
#include "storage/storage.h"
41
#include "storage/storage_simple.h"
42
#include "storage/storage_vai.h"
43
44
#include "vtim.h"
45 12200
46 24458
/* Flags for allocating memory in sml_stv_alloc */
47
#define LESS_MEM_ALLOCED_IS_OK  1
48
49
// marker pointer for sml_trimstore
50
static void *trim_once = &trim_once;
51
52 12397
/*-------------------------------------------------------------------*/
53
54
static struct storage *
55
objallocwithnuke(struct worker *, const struct stevedore *, ssize_t size,
56
    int flags);
57
58
static struct storage *
59 12134
sml_stv_alloc(const struct stevedore *stv, ssize_t size, int flags)
60
{
61
        struct storage *st;
62
63 12134
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
64 12134
        AN(stv->sml_alloc);
65
66 12134
        if (!(flags & LESS_MEM_ALLOCED_IS_OK)) {
67 2538
                if (size > cache_param->fetch_maxchunksize)
68 0
                        return (NULL);
69
                else
70 2538
                        return (stv->sml_alloc(stv, size));
71
        }
72
73 9596
        if (size > cache_param->fetch_maxchunksize)
74 0
                size = cache_param->fetch_maxchunksize;
75
76 9596
        assert(size <= UINT_MAX);       /* field limit in struct storage */
77
78 10136
        for (;;) {
79
                /* try to allocate from it */
80 10136
                assert(size > 0);
81 10136
                st = stv->sml_alloc(stv, size);
82 10136
                if (st != NULL)
83 9552
                        break;
84
85 584
                if (size <= cache_param->fetch_chunksize)
86 44
                        break;
87
88 540
                size /= 2;
89
        }
90 9596
        CHECK_OBJ_ORNULL(st, STORAGE_MAGIC);
91 9596
        return (st);
92 12134
}
93
94
static void
95 14335
sml_stv_free(const struct stevedore *stv, struct storage *st)
96
{
97
98 14335
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
99 14335
        CHECK_OBJ_NOTNULL(st, STORAGE_MAGIC);
100 14335
        if (stv->sml_free != NULL)
101 14335
                stv->sml_free(st);
102 14335
}
103
104
/*--------------------------------------------------------------------
105
 * This function is called by stevedores ->allocobj() method, which
106
 * very often will be SML_allocobj() below, to convert a slab
107
 * of storage into object which the stevedore can then register in its
108
 * internal state, before returning it to STV_NewObject().
109
 * As you probably guessed: All this for persistence.
110
 */
111
112
struct object *
113 9824
SML_MkObject(const struct stevedore *stv, struct objcore *oc, void *ptr)
114
{
115
        struct object *o;
116
117 9824
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
118 9824
        AN(stv->methods);
119 9824
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
120
121 9824
        assert(PAOK(ptr));
122
123 9824
        o = ptr;
124 9824
        INIT_OBJ(o, OBJECT_MAGIC);
125
126 9824
        VTAILQ_INIT(&o->list);
127
128 9824
        oc->stobj->stevedore = stv;
129 9824
        oc->stobj->priv = o;
130 9824
        oc->stobj->priv2 = 0;
131 9824
        return (o);
132
}
133
134
/*--------------------------------------------------------------------
135
 * This is the default ->allocobj() which all stevedores who do not
136
 * implement persistent storage can rely on.
137
 */
138
139
int v_matchproto_(storage_allocobj_f)
140 9776
SML_allocobj(struct worker *wrk, const struct stevedore *stv,
141
    struct objcore *oc, unsigned wsl)
142
{
143
        struct object *o;
144 9776
        struct storage *st = NULL;
145
        unsigned ltot;
146
147 9776
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
148 9776
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
149 9776
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
150
151 9776
        AN(stv->sml_alloc);
152
153 9776
        ltot = sizeof(*o) + PRNDUP(wsl);
154
155 9776
        do {
156 9788
                st = stv->sml_alloc(stv, ltot);
157 9788
                if (st != NULL && st->space < ltot) {
158 0
                        stv->sml_free(st);
159 0
                        st = NULL;
160 0
                }
161 9788
        } while (st == NULL && LRU_NukeOne(wrk, stv->lru));
162 9776
        if (st == NULL)
163 36
                return (0);
164
165 9740
        CHECK_OBJ(st, STORAGE_MAGIC);
166 9740
        o = SML_MkObject(stv, oc, st->ptr);
167 9740
        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
168 9740
        st->len = sizeof(*o);
169 9740
        o->objstore = st;
170 9740
        return (1);
171 9776
}
172
173
void * v_matchproto_(storage_allocbuf_t)
174 1176
SML_AllocBuf(struct worker *wrk, const struct stevedore *stv, size_t size,
175
    uintptr_t *ppriv)
176
{
177
        struct storage *st;
178
179 1176
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
180 1176
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
181 1176
        AN(ppriv);
182
183 1176
        if (size > UINT_MAX)
184 0
                return (NULL);
185 1176
        st = objallocwithnuke(wrk, stv, size, 0);
186 1176
        if (st == NULL)
187 0
                return (NULL);
188 1176
        assert(st->space >= size);
189 1176
        st->flags = STORAGE_F_BUFFER;
190 1176
        st->len = size;
191 1176
        *ppriv = (uintptr_t)st;
192 1176
        return (st->ptr);
193 1176
}
194
195
void v_matchproto_(storage_freebuf_t)
196 1176
SML_FreeBuf(struct worker *wrk, const struct stevedore *stv, uintptr_t priv)
197
{
198
        struct storage *st;
199
200 1176
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
201 1176
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
202
203 1176
        CAST_OBJ_NOTNULL(st, (void *)priv, STORAGE_MAGIC);
204 1176
        assert(st->flags == STORAGE_F_BUFFER);
205 1176
        sml_stv_free(stv, st);
206 1176
}
207
208
/*---------------------------------------------------------------------
209
 */
210
211
static struct object *
212 625506
sml_getobj(struct worker *wrk, struct objcore *oc)
213
{
214
        const struct stevedore *stv;
215
        struct object *o;
216
217 625506
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
218 625506
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
219 625506
        stv = oc->stobj->stevedore;
220 625506
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
221 625506
        if (stv->sml_getobj != NULL)
222 1156
                return (stv->sml_getobj(wrk, oc));
223 624350
        if (oc->stobj->priv == NULL)
224 0
                return (NULL);
225 624350
        CAST_OBJ_NOTNULL(o, oc->stobj->priv, OBJECT_MAGIC);
226 624350
        return (o);
227 625506
}
228
229
static void v_matchproto_(objslim_f)
230 9237
sml_slim(struct worker *wrk, struct objcore *oc)
231
{
232
        const struct stevedore *stv;
233
        struct object *o;
234
        struct storage *st, *stn;
235
236 9237
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
237
238 9237
        stv = oc->stobj->stevedore;
239 9237
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
240 9237
        o = sml_getobj(wrk, oc);
241 9237
        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
242
243
#define OBJ_AUXATTR(U, l)                                       \
244
        do {                                                    \
245
                if (o->aa_##l != NULL) {                        \
246
                        sml_stv_free(stv, o->aa_##l);           \
247
                        o->aa_##l = NULL;                       \
248
                }                                               \
249
        } while (0);
250
#include "tbl/obj_attr.h"
251
252 14005
        VTAILQ_FOREACH_SAFE(st, &o->list, list, stn) {
253 4768
                CHECK_OBJ_NOTNULL(st, STORAGE_MAGIC);
254 4768
                VTAILQ_REMOVE(&o->list, st, list);
255 4768
                sml_stv_free(stv, st);
256 4768
        }
257
}
258
259
static void
260 9888
sml_bocfini(const struct stevedore *stv, struct boc *boc)
261
{
262
        struct storage *st;
263
264 9888
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
265 9888
        CHECK_OBJ_NOTNULL(boc, BOC_MAGIC);
266
267 9888
        if (boc->stevedore_priv == NULL ||
268 5938
            boc->stevedore_priv == trim_once)
269 9058
                return;
270
271
        /* Free any leftovers from Trim */
272 830
        TAKE_OBJ_NOTNULL(st, &boc->stevedore_priv, STORAGE_MAGIC);
273 830
        sml_stv_free(stv, st);
274 9888
}
275
276
/*
277
 * called in two cases:
278
 * - oc->boc == NULL: cache object on LRU freed
279
 * - oc->boc != NULL: cache object replaced for backend error
280
 */
281
static void v_matchproto_(objfree_f)
282 5489
sml_objfree(struct worker *wrk, struct objcore *oc)
283
{
284
        const struct stevedore *stv;
285
        struct storage *st;
286
        struct object *o;
287
288 5489
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
289 5489
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
290 5489
        stv = oc->stobj->stevedore;
291 5489
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
292 5489
        CAST_OBJ_NOTNULL(o, oc->stobj->priv, OBJECT_MAGIC);
293
294 5489
        sml_slim(wrk, oc);
295 5489
        st = o->objstore;
296 5489
        CHECK_OBJ_NOTNULL(st, STORAGE_MAGIC);
297 5489
        FINI_OBJ(o);
298
299 5489
        if (oc->boc != NULL)
300 92
                sml_bocfini(stv, oc->boc);
301 5397
        else if (stv->lru != NULL)
302 5396
                LRU_Remove(oc);
303
304 5489
        sml_stv_free(stv, st);
305
306 5489
        memset(oc->stobj, 0, sizeof oc->stobj);
307
308 5489
        wrk->stats->n_object--;
309 5489
}
310
311
// kept for reviewers - XXX remove later
312
#undef VAI_DBG
313
314
struct sml_hdl {
315
        struct vai_hdl_preamble preamble;
316
#define SML_HDL_MAGIC           0x37dfd996
317
        struct vai_qe           qe;
318
        struct pool_task        task;   // unfortunate
319
        struct ws               *ws;    // NULL is malloc()
320
        struct objcore          *oc;
321
        struct object           *obj;
322
        const struct stevedore  *stv;
323
        struct boc              *boc;
324
325
        struct storage          *st;    // updated by _lease()
326
327
        // only for _lease_boc()
328
        uint64_t                st_off; // already returned fragment of current st
329
        uint64_t                avail, returned;
330
        struct storage          *last;  // to resume, held back by _return()
331
};
332
333
static inline void
334 5909
sml_ai_viov_fill(struct viov *viov, struct storage *st)
335
{
336 5909
        viov->iov.iov_base = TRUST_ME(st->ptr);
337 5909
        viov->iov.iov_len = st->len;
338 5909
        viov->lease = ptr2lease(st);
339 5909
        VAI_ASSERT_LEASE(viov->lease);
340 5909
}
341
342
// sml has no mechanism to notify "I got free space again now"
343
// (we could add that, but because storage.h is used in mgt, a first attempt
344
//  looks at least like this would cause some include spill for vai_q_head or
345
//  something similar)
346
//
347
// So anyway, to get ahead we just implement a pretty stupid "call the notify
348
// some time later" on a thread
349
static void
350 0
sml_ai_later_task(struct worker *wrk, void *priv)
351
{
352
        struct sml_hdl *hdl;
353 0
        const vtim_dur dur = 0.0042;
354
355 0
        (void)wrk;
356 0
        VTIM_sleep(dur);
357 0
        CAST_VAI_HDL_NOTNULL(hdl, priv, SML_HDL_MAGIC);
358 0
        memset(&hdl->task, 0, sizeof hdl->task);
359 0
        hdl->qe.cb(hdl, hdl->qe.priv);
360 0
}
361
static void
362 0
sml_ai_later(struct worker *wrk, struct sml_hdl *hdl)
363
{
364 0
        AZ(hdl->task.func);
365 0
        AZ(hdl->task.priv);
366 0
        hdl->task.func = sml_ai_later_task;
367 0
        hdl->task.priv = hdl;
368 0
        AZ(Pool_Task(wrk->pool, &hdl->task, TASK_QUEUE_BG));
369 0
}
370
371
372
static int
373 64
sml_ai_buffer(struct worker *wrk, vai_hdl vhdl, struct vscarab *scarab)
374
{
375
        const struct stevedore *stv;
376
        struct sml_hdl *hdl;
377
        struct storage *st;
378
        struct viov *vio;
379 64
        int r = 0;
380
381 64
        (void) wrk;
382 64
        CAST_VAI_HDL_NOTNULL(hdl, vhdl, SML_HDL_MAGIC);
383 64
        stv = hdl->stv;
384 64
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
385
386 128
        VSCARAB_FOREACH(vio, scarab)
387 64
                if (vio->iov.iov_len > UINT_MAX)
388 0
                        return (-EINVAL);
389
390 128
        VSCARAB_FOREACH(vio, scarab) {
391 64
                st = objallocwithnuke(wrk, stv, vio->iov.iov_len, 0);
392 64
                if (st == NULL)
393 0
                        break;
394 64
                assert(st->space >= vio->iov.iov_len);
395 64
                st->flags = STORAGE_F_BUFFER;
396 64
                st->len = st->space;
397
398 64
                sml_ai_viov_fill(vio, st);
399 64
                r++;
400 64
        }
401 64
        if (r == 0) {
402 0
                sml_ai_later(wrk, hdl);
403 0
                r = -EAGAIN;
404 0
        }
405 64
        return (r);
406 64
}
407
408
static int
409 9993
sml_ai_lease_simple(struct worker *wrk, vai_hdl vhdl, struct vscarab *scarab)
410
{
411
        struct storage *st;
412
        struct sml_hdl *hdl;
413
        struct viov *viov;
414 9993
        int r = 0;
415
416 9993
        (void) wrk;
417 9993
        CAST_VAI_HDL_NOTNULL(hdl, vhdl, SML_HDL_MAGIC);
418 9993
        VSCARAB_CHECK_NOTNULL(scarab);
419
420 9993
        AZ(hdl->st_off);
421 9993
        st = hdl->st;
422 15838
        while (st != NULL && (viov = VSCARAB_GET(scarab)) != NULL) {
423 5845
                CHECK_OBJ(st, STORAGE_MAGIC);
424 5845
                sml_ai_viov_fill(viov, st);
425 5845
                r++;
426 5845
                st = VTAILQ_PREV(st, storagehead, list);
427
        }
428 9993
        hdl->st = st;
429 9993
        if (st == NULL)
430 9989
                scarab->flags |= VSCARAB_F_END;
431 9993
        return (r);
432
}
433
434
/*
435
 * on leases while streaming (with a boc):
436
 *
437
 * SML uses the lease return facility to implement the "free behind" for
438
 * OC_F_TRANSIENT objects. When streaming, we also return leases on
439
 * fragments of sts, but we must only "free behind" when we are done with the
440
 * last fragment.
441
 *
442
 * So we use a magic lease to signal "this is only a fragment", which we ignore
443
 * on returns
444
 */
445
446
static int
447 20896
sml_ai_lease_boc(struct worker *wrk, vai_hdl vhdl, struct vscarab *scarab)
448
{
449 20896
        enum boc_state_e state = BOS_INVALID;
450
        struct storage *next;
451
        struct sml_hdl *hdl;
452
        struct viov *viov;
453 20896
        int r = 0;
454
455 20896
        CAST_VAI_HDL_NOTNULL(hdl, vhdl, SML_HDL_MAGIC);
456 20896
        VSCARAB_CHECK_NOTNULL(scarab);
457 20896
        assert(hdl->boc == hdl->oc->boc);
458
459 20896
        if (hdl->avail == hdl->returned) {
460 40004
                hdl->avail = ObjVAIGetExtend(wrk, hdl->oc, hdl->returned,
461 20002
                    &state, &hdl->qe);
462 20002
                assert(state >= BOS_STREAM);
463 20002
                if (state == BOS_FAILED) {
464 68
                        hdl->last = NULL;
465 68
                        return (-EPIPE);
466
                }
467 19934
                else if (state == BOS_FINISHED)
468 3140
                        (void)0;
469 16794
                else if (hdl->avail == hdl->returned) {
470
                        // ObjVAIGetExtend() has scheduled a notification
471 8298
                        if (hdl->boc->transit_buffer > 0)
472 1036
                                return (-ENOBUFS);
473
                        else
474 7262
                                return (-EAGAIN);
475
                }
476
                else
477 8496
                        assert(state < BOS_FINISHED);
478 11636
        }
479 12530
        Lck_Lock(&hdl->boc->mtx);
480 12530
        if (hdl->st == NULL && hdl->last != NULL)
481 3629
                hdl->st = VTAILQ_PREV(hdl->last, storagehead, list);
482 12530
        if (hdl->last != NULL && state < BOS_FINISHED) {
483 643
                viov = VSCARAB_GET(scarab);
484 643
                AN(viov);
485 643
                viov->iov = IOV_NIL;
486 643
                viov->lease = ptr2lease(hdl->last);
487 643
                r++;
488 643
        }
489 12530
        if (hdl->last != NULL)
490 3629
                hdl->last = NULL;
491 12530
        if (hdl->st == NULL && hdl->returned == 0)
492 3224
                hdl->st = VTAILQ_LAST(&hdl->obj->list, storagehead);
493 12530
        if (hdl->st == NULL)
494 2982
                assert(hdl->avail == hdl->returned);
495
496 22626
        while (hdl->avail > hdl->returned && (viov = VSCARAB_GET(scarab)) != NULL) {
497 10096
                CHECK_OBJ_NOTNULL(hdl->st, STORAGE_MAGIC); // ObjVAIGetExtend ensures
498 10096
                assert(hdl->boc == hdl->oc->boc);
499 10096
                assert(hdl->st_off <= hdl->st->space);
500 10096
                size_t av = hdl->avail - hdl->returned;
501 10096
                size_t l = hdl->st->space - hdl->st_off;
502 10096
                AN(l);
503 10096
                if (l > av)
504 4954
                        l = av;
505 10096
                viov->iov.iov_base = TRUST_ME(hdl->st->ptr + hdl->st_off);
506 10096
                viov->iov.iov_len = l;
507 10096
                if (hdl->st_off + l == hdl->st->space) {
508 5144
                        next = VTAILQ_PREV(hdl->st, storagehead, list);
509 5144
                        AZ(hdl->last);
510 5144
                        if (next == NULL) {
511 3682
                                hdl->last = hdl->st;
512 3682
                                viov->lease = VAI_LEASE_NORET;
513 3682
                        }
514
                        else {
515 1462
                                CHECK_OBJ(next, STORAGE_MAGIC);
516 1462
                                viov->lease = ptr2lease(hdl->st);
517
                        }
518
#ifdef VAI_DBG
519
                        if (wrk->vsl)
520
                                VSLb(wrk->vsl, SLT_Debug, "off %zu + l %zu == space st %p next st %p stvprv %p",
521
                                    hdl->st_off, l, hdl->st, next, hdl->boc->stevedore_priv);
522
#endif
523 5144
                        hdl->st_off = 0;
524 5144
                        hdl->st = next;
525 5144
                }
526
                else {
527 4952
                        viov->lease = VAI_LEASE_NORET;
528 4952
                        hdl->st_off += l;
529
                }
530 10096
                hdl->returned += l;
531 10096
                VAI_ASSERT_LEASE(viov->lease);
532 10096
                r++;
533
        }
534
535 12530
        Lck_Unlock(&hdl->boc->mtx);
536 12530
        if (state != BOS_FINISHED && hdl->avail == hdl->returned) {
537 18820
                hdl->avail = ObjVAIGetExtend(wrk, hdl->oc, hdl->returned,
538 9410
                    &state, &hdl->qe);
539 9410
        }
540 12530
        if (state == BOS_FINISHED && hdl->avail == hdl->returned)
541 3140
                scarab->flags |= VSCARAB_F_END;
542 12530
        return (r);
543 20896
}
544
545
// return only buffers, used if object is not streaming
546
static void v_matchproto_(vai_return_f)
547 8076
sml_ai_return_buffers(struct worker *wrk, vai_hdl vhdl, struct vscaret *scaret)
548
{
549
        struct storage *st;
550
        struct sml_hdl *hdl;
551
        viov_lease_t *p;
552
553 8076
        (void) wrk;
554 8076
        CAST_VAI_HDL_NOTNULL(hdl, vhdl, SML_HDL_MAGIC);
555
556 16659
        VSCARET_FOREACH(p, scaret) {
557 8583
                if (*p == VAI_LEASE_NORET)
558 2514
                        continue;
559 6069
                CAST_OBJ_NOTNULL(st, lease2ptr(*p), STORAGE_MAGIC);
560 6069
                if ((st->flags & STORAGE_F_BUFFER) == 0)
561 6005
                        continue;
562 64
                sml_stv_free(hdl->stv, st);
563 64
        }
564 8076
        VSCARET_INIT(scaret, scaret->capacity);
565 8076
}
566
567
// generic return for buffers and object leases, used when streaming
568
static void v_matchproto_(vai_return_f)
569 5585
sml_ai_return(struct worker *wrk, vai_hdl vhdl, struct vscaret *scaret)
570
{
571
        struct storage *st;
572
        struct sml_hdl *hdl;
573
        viov_lease_t *p;
574
575 5585
        (void) wrk;
576 5585
        CAST_VAI_HDL_NOTNULL(hdl, vhdl, SML_HDL_MAGIC);
577 5585
        VSCARET_CHECK_NOTNULL(scaret);
578 5585
        if (scaret->used == 0)
579 0
                return;
580
581
        // callback is only registered if needed
582 5585
        assert(hdl->boc != NULL && (hdl->oc->flags & OC_F_TRANSIENT) != 0);
583
584
        // filter noret and last
585 5585
        VSCARET_LOCAL(todo, scaret->used);
586 13790
        VSCARET_FOREACH(p, scaret) {
587 8205
                if (*p == VAI_LEASE_NORET)
588 6260
                        continue;
589 1945
                CAST_OBJ_NOTNULL(st, lease2ptr(*p), STORAGE_MAGIC);
590 1945
                VSCARET_ADD(todo, *p);
591 1945
        }
592 5585
        VSCARET_INIT(scaret, scaret->capacity);
593
594 5585
        Lck_Lock(&hdl->boc->mtx);
595 7530
        VSCARET_FOREACH(p, todo) {
596 1945
                CAST_OBJ_NOTNULL(st, lease2ptr(*p), STORAGE_MAGIC);
597 1945
                if ((st->flags & STORAGE_F_BUFFER) != 0)
598 0
                        continue;
599 1945
                VTAILQ_REMOVE(&hdl->obj->list, st, list);
600 1945
                if (st == hdl->boc->stevedore_priv)
601 0
                        hdl->boc->stevedore_priv = trim_once;
602 1945
        }
603 5585
        Lck_Unlock(&hdl->boc->mtx);
604
605 7530
        VSCARET_FOREACH(p, todo) {
606 1945
                CAST_OBJ_NOTNULL(st, lease2ptr(*p), STORAGE_MAGIC);
607
#ifdef VAI_DBG
608
                if (wrk->vsl != NULL)
609
                        VSLb(wrk->vsl, SLT_Debug, "ret %p", st);
610
#endif
611 1945
                sml_stv_free(hdl->stv, st);
612 1945
        }
613 5585
}
614
615
// call the notify_cb to allow VDPs to use -EAGAIN also
616
static void v_matchproto_(vai_return_f)
617 512
sml_ai_notify(struct worker *wrk, vai_hdl vhdl)
618
{
619
        struct sml_hdl *hdl;
620
621 512
        (void) wrk;
622 512
        CAST_VAI_HDL_NOTNULL(hdl, vhdl, SML_HDL_MAGIC);
623 512
        CHECK_OBJ(&hdl->qe, VAI_Q_MAGIC);
624 512
        hdl->qe.cb(vhdl, hdl->qe.priv);
625 512
}
626
627
static void v_matchproto_(vai_fini_f)
628 8373
sml_ai_fini(struct worker *wrk, vai_hdl *vai_hdlp)
629
{
630
        struct sml_hdl *hdl;
631
632 8373
        AN(vai_hdlp);
633 8373
        CAST_VAI_HDL_NOTNULL(hdl, *vai_hdlp, SML_HDL_MAGIC);
634 8373
        *vai_hdlp = NULL;
635
636 8373
        if (hdl->boc != NULL) {
637 3248
                ObjVAICancel(wrk, hdl->boc, &hdl->qe);
638 3248
                HSH_DerefBoc(wrk, hdl->oc);
639 3248
                hdl->boc = NULL;
640 3248
        }
641
642 8373
        if (hdl->ws != NULL)
643 128
                WS_Release(hdl->ws, 0);
644
        else
645 8245
                free(hdl);
646 8373
}
647
648
static vai_hdl v_matchproto_(vai_init_f)
649 8372
sml_ai_init(struct worker *wrk, struct objcore *oc, struct ws *ws,
650
    vai_notify_cb *notify, void *notify_priv)
651
{
652
        struct sml_hdl *hdl;
653 8372
        const size_t sz = sizeof *hdl;
654
655 8372
        if (ws != NULL && WS_ReserveSize(ws, (unsigned)sz))
656 128
                hdl = WS_Reservation(ws);
657
        else {
658 8244
                hdl = malloc(sz);
659 8244
                ws = NULL;
660
        }
661
662 8372
        AN(hdl);
663 8372
        INIT_VAI_HDL(hdl, SML_HDL_MAGIC);
664 8372
        hdl->preamble.vai_lease = sml_ai_lease_simple;
665 8372
        hdl->preamble.vai_buffer = sml_ai_buffer;
666 8372
        hdl->preamble.vai_return = sml_ai_return_buffers;
667 8372
        hdl->preamble.vai_notify = sml_ai_notify;
668 8372
        hdl->preamble.vai_fini = sml_ai_fini;
669 8372
        hdl->ws = ws;
670
671 8372
        hdl->oc = oc;
672 8372
        hdl->obj = sml_getobj(wrk, oc);
673 8372
        CHECK_OBJ_NOTNULL(hdl->obj, OBJECT_MAGIC);
674 8372
        hdl->stv = oc->stobj->stevedore;
675 8372
        CHECK_OBJ_NOTNULL(hdl->stv, STEVEDORE_MAGIC);
676
677
678 8372
        hdl->qe.magic = VAI_Q_MAGIC;
679 8372
        hdl->qe.cb = notify;
680 8372
        hdl->qe.hdl = hdl;
681 8372
        hdl->qe.priv = notify_priv;
682
683 8372
        hdl->boc = HSH_RefBoc(oc);
684 8372
        if (hdl->boc == NULL) {
685 5125
                hdl->st = VTAILQ_LAST(&hdl->obj->list, storagehead);
686 5125
                CHECK_OBJ_ORNULL(hdl->st, STORAGE_MAGIC);
687 5125
                return (hdl);
688
        }
689
        /* we only initialize notifications if we have a boc, so
690
         * any wrong attempt triggers magic checks.
691
         */
692 3247
        hdl->preamble.vai_lease = sml_ai_lease_boc;
693 3247
        if ((hdl->oc->flags & OC_F_TRANSIENT) != 0)
694 1463
                hdl->preamble.vai_return = sml_ai_return;
695 3247
        return (hdl);
696 8372
}
697
698
/*
699
 * trivial notification to allow the iterator to simply block
700
 */
701
struct sml_notify {
702
        unsigned                magic;
703
#define SML_NOTIFY_MAGIC        0x4589af31
704
        unsigned                hasmore;
705
        pthread_mutex_t         mtx;
706
        pthread_cond_t          cond;
707
};
708
709
static void
710 10150
sml_notify_init(struct sml_notify *sn)
711
{
712
713 10150
        INIT_OBJ(sn, SML_NOTIFY_MAGIC);
714 10150
        PTOK(pthread_mutex_init(&sn->mtx, NULL));
715 10150
        PTOK(pthread_cond_init(&sn->cond, NULL));
716 10150
}
717
718
static void
719 10153
sml_notify_fini(struct sml_notify *sn)
720
{
721
722 10153
        CHECK_OBJ_NOTNULL(sn, SML_NOTIFY_MAGIC);
723 10153
        PTOK(pthread_mutex_destroy(&sn->mtx));
724 10153
        PTOK(pthread_cond_destroy(&sn->cond));
725 10153
}
726
727
static void v_matchproto_(vai_notify_cb)
728 8833
sml_notify(vai_hdl hdl, void *priv)
729
{
730
        struct sml_notify *sn;
731
732 8833
        (void) hdl;
733 8833
        CAST_OBJ_NOTNULL(sn, priv, SML_NOTIFY_MAGIC);
734 8833
        PTOK(pthread_mutex_lock(&sn->mtx));
735 8833
        sn->hasmore = 1;
736 8833
        PTOK(pthread_cond_signal(&sn->cond));
737 8833
        PTOK(pthread_mutex_unlock(&sn->mtx));
738
739 8833
}
740
741
static void
742 8230
sml_notify_wait(struct sml_notify *sn)
743
{
744
745 8230
        CHECK_OBJ_NOTNULL(sn, SML_NOTIFY_MAGIC);
746 8230
        PTOK(pthread_mutex_lock(&sn->mtx));
747 12129
        while (sn->hasmore == 0)
748 3899
                PTOK(pthread_cond_wait(&sn->cond, &sn->mtx));
749 8230
        AN(sn->hasmore);
750 8230
        sn->hasmore = 0;
751 8230
        PTOK(pthread_mutex_unlock(&sn->mtx));
752 8230
}
753
754
int v_matchproto_(objiterator_f)
755 10153
SML_iterator(struct worker *wrk, struct objcore *oc,
756
    void *priv, objiterate_f *func, int final)
757
{
758
        struct sml_notify sn;
759
        struct viov *vio, *last;
760
        unsigned u, uu;
761
        vai_hdl hdl;
762
        int nn, r, r2, islast;
763
764 10153
        VSCARAB_LOCAL(scarab, 16);
765 10153
        VSCARET_LOCAL(scaret, 16);
766
767 10153
        (void) final; // phase out?
768 10153
        sml_notify_init(&sn);
769 10153
        hdl = ObjVAIinit(wrk, oc, NULL, sml_notify, &sn);
770 10153
        AN(hdl);
771
772 10153
        r = u = 0;
773
774 10153
        do {
775 25175
                do {
776 34581
                        nn = ObjVAIlease(wrk, hdl, scarab);
777 34581
                        if (nn <= 0 || scarab->flags & VSCARAB_F_END)
778 25170
                                break;
779 9411
                } while (scarab->used < scarab->capacity);
780
781
                /*
782
                 * nn is the wait/return action or 0
783
                 * nn tells us if to flush
784
                 */
785 25175
                uu = u;
786 25175
                last = VSCARAB_LAST(scarab);
787 64859
                VSCARAB_FOREACH(vio, scarab) {
788 39908
                        islast = vio == last;
789 39908
                        AZ(u & OBJ_ITER_END);
790 39908
                        if (islast && scarab->flags & VSCARAB_F_END)
791 6929
                                u |= OBJ_ITER_END;
792
793
                        // flush if it is the scarab's last IOV and we will block next
794
                        // or if we need space in the return leases array
795 39908
                        uu = u;
796 39908
                        if ((islast && nn < 0) || scaret->used == scaret->capacity - 1)
797 7919
                                uu |= OBJ_ITER_FLUSH;
798
799
                        // null iov with the only purpose to return the resume ptr lease
800
                        // exception needed because assert(len > 0) in VDP_bytes()
801 39908
                        if (vio->iov.iov_base == IOV_NIL.iov_base)
802 643
                                r = 0;
803
                        else
804 39265
                                r = func(priv, uu, vio->iov.iov_base, vio->iov.iov_len);
805 39908
                        if (r != 0)
806 224
                                break;
807
808
                        // sufficient space ensured by capacity check above
809 39684
                        VSCARET_ADD(scaret, vio->lease);
810
811
#ifdef VAI_DBG
812
                        if (wrk->vsl)
813
                                VSLb(wrk->vsl, SLT_Debug, "len %zu scaret %u uu %u",
814
                                    vio->iov.iov_len, scaret->used, uu);
815
#endif
816
817
                        // whenever we have flushed, return leases
818 39684
                        if ((uu & OBJ_ITER_FLUSH) && scaret->used > 0)
819 7857
                                ObjVAIreturn(wrk, hdl, scaret);
820 39684
                }
821
822
                // return leases which we did not use if error (break)
823 25547
                VSCARAB_FOREACH_RESUME(vio, scarab) {
824 372
                        if (scaret->used == scaret->capacity)
825 0
                                ObjVAIreturn(wrk, hdl, scaret);
826 372
                        VSCARET_ADD(scaret, vio->lease);
827 372
                }
828
829
                // we have now completed the scarab
830 25175
                VSCARAB_INIT(scarab, scarab->capacity);
831
832
#ifdef VAI_DBG
833
                if (wrk->vsl)
834
                        VSLb(wrk->vsl, SLT_Debug, "r %d nn %d uu %u",
835
                            r, nn, uu);
836
#endif
837
838
                // flush before blocking if we did not already
839 25175
                if (r == 0 && (nn == -ENOBUFS || nn == -EAGAIN) &&
840 24955
                    (uu & OBJ_ITER_FLUSH) == 0) {
841 382
                        r = func(priv, OBJ_ITER_FLUSH, NULL, 0);
842 382
                        if (scaret->used > 0)
843 0
                                ObjVAIreturn(wrk, hdl, scaret);
844 382
                }
845
846 25175
                if (r == 0 && (nn == -ENOBUFS || nn == -EAGAIN)) {
847 8235
                        assert(scaret->used <= 1);
848 8235
                        sml_notify_wait(&sn);
849 8235
                }
850 16940
                else if (r == 0 && nn < 0)
851 68
                        r = -1;
852 25175
        } while (nn != 0 && r == 0);
853
854 10153
        if ((u & OBJ_ITER_END) == 0) {
855 3224
                r2 = func(priv, OBJ_ITER_END, NULL, 0);
856 3224
                if (r == 0)
857 3073
                        r = r2;
858 3224
        }
859
860 10153
        if (scaret->used > 0)
861 7012
                ObjVAIreturn(wrk, hdl, scaret);
862
863 10153
        ObjVAIfini(wrk, &hdl);
864 10153
        sml_notify_fini(&sn);
865
866 10153
        return (r);
867
}
868
869
/*--------------------------------------------------------------------
870
 */
871
872
static struct storage *
873 11288
objallocwithnuke(struct worker *wrk, const struct stevedore *stv, ssize_t size,
874
    int flags)
875
{
876 11288
        struct storage *st = NULL;
877
878 11288
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
879 11288
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
880
881 11288
        if (size > cache_param->fetch_maxchunksize) {
882 8
                if (!(flags & LESS_MEM_ALLOCED_IS_OK))
883 0
                        return (NULL);
884 8
                size = cache_param->fetch_maxchunksize;
885 8
        }
886
887 11288
        assert(size <= UINT_MAX);       /* field limit in struct storage */
888
889 11288
        do {
890
                /* try to allocate from it */
891 11320
                st = sml_stv_alloc(stv, size, flags);
892 11320
                if (st != NULL)
893 11268
                        break;
894
895
                /* no luck; try to free some space and keep trying */
896 52
                if (stv->lru == NULL)
897 0
                        break;
898 52
        } while (LRU_NukeOne(wrk, stv->lru));
899
900 11288
        CHECK_OBJ_ORNULL(st, STORAGE_MAGIC);
901 11288
        return (st);
902 11288
}
903
904
static int v_matchproto_(objgetspace_f)
905 238414
sml_getspace(struct worker *wrk, struct objcore *oc, ssize_t *sz,
906
    uint8_t **ptr)
907
{
908
        struct object *o;
909
        struct storage *st;
910
911 238414
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
912 238414
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
913 238414
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
914 238414
        AN(sz);
915 238414
        AN(ptr);
916 238414
        if (*sz == 0)
917 225918
                *sz = cache_param->fetch_chunksize;
918 238414
        assert(*sz > 0);
919 238414
        if (oc->boc->transit_buffer > 0)
920 1820
                *sz = vmin_t(ssize_t, *sz, oc->boc->transit_buffer);
921
922 238414
        o = sml_getobj(wrk, oc);
923 238414
        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
924 238414
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
925
926 238414
        st = VTAILQ_FIRST(&o->list);
927 238414
        if (st != NULL && st->len < st->space) {
928 228842
                *sz = st->space - st->len;
929 228842
                *ptr = st->ptr + st->len;
930 228842
                assert (*sz > 0);
931 228842
                return (1);
932
        }
933
934 9572
        st = objallocwithnuke(wrk, oc->stobj->stevedore, *sz,
935
            LESS_MEM_ALLOCED_IS_OK);
936 9572
        if (st == NULL)
937 20
                return (0);
938
939 9552
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
940 9552
        Lck_Lock(&oc->boc->mtx);
941 9552
        VTAILQ_INSERT_HEAD(&o->list, st, list);
942 9552
        Lck_Unlock(&oc->boc->mtx);
943
944 9552
        *sz = st->space - st->len;
945 9552
        assert (*sz > 0);
946 9552
        *ptr = st->ptr + st->len;
947 9552
        return (1);
948 238414
}
949
950
static void v_matchproto_(objextend_f)
951 232771
sml_extend(struct worker *wrk, struct objcore *oc, ssize_t l)
952
{
953
        struct object *o;
954
        struct storage *st;
955
956 232771
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
957 232771
        assert(l > 0);
958
959 232771
        o = sml_getobj(wrk, oc);
960 232771
        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
961 232771
        st = VTAILQ_FIRST(&o->list);
962 232771
        CHECK_OBJ_NOTNULL(st, STORAGE_MAGIC);
963 232771
        assert(st->len + l <= st->space);
964 232771
        st->len += l;
965 232771
}
966
967
static void v_matchproto_(objtrimstore_f)
968 5942
sml_trimstore(struct worker *wrk, struct objcore *oc)
969
{
970
        const struct stevedore *stv;
971
        struct storage *st, *st1;
972
        struct object *o;
973
974 5942
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
975 5942
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
976 5942
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
977
978 5942
        stv = oc->stobj->stevedore;
979 5942
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
980
981 5942
        if (oc->boc->stevedore_priv != NULL)
982 0
                WRONG("sml_trimstore already called");
983 5942
        oc->boc->stevedore_priv = trim_once;
984
985 5942
        if (stv->sml_free == NULL)
986 0
                return;
987
988 5942
        o = sml_getobj(wrk, oc);
989 5942
        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
990 5942
        st = VTAILQ_FIRST(&o->list);
991
992 5942
        if (st == NULL)
993 0
                return;
994
995 5942
        if (st->len == 0) {
996 16
                Lck_Lock(&oc->boc->mtx);
997 16
                VTAILQ_REMOVE(&o->list, st, list);
998 16
                Lck_Unlock(&oc->boc->mtx);
999
                /* sml_bocdone frees this */
1000 16
                oc->boc->stevedore_priv = st;
1001 16
                return;
1002
        }
1003
1004 5926
        if (st->space - st->len < 512)
1005 5112
                return;
1006
1007 814
        st1 = sml_stv_alloc(stv, st->len, 0);
1008 814
        if (st1 == NULL)
1009 0
                return;
1010 814
        assert(st1->space >= st->len);
1011
1012 814
        memcpy(st1->ptr, st->ptr, st->len);
1013 814
        st1->len = st->len;
1014 814
        Lck_Lock(&oc->boc->mtx);
1015 814
        VTAILQ_REMOVE(&o->list, st, list);
1016 814
        VTAILQ_INSERT_HEAD(&o->list, st1, list);
1017 814
        Lck_Unlock(&oc->boc->mtx);
1018
        /* sml_bocdone frees this */
1019 814
        oc->boc->stevedore_priv = st;
1020 5942
}
1021
1022
static void v_matchproto_(objbocdone_f)
1023 9795
sml_bocdone(struct worker *wrk, struct objcore *oc, struct boc *boc)
1024
{
1025
        const struct stevedore *stv;
1026
1027 9795
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
1028 9795
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
1029 9795
        CHECK_OBJ_NOTNULL(boc, BOC_MAGIC);
1030 9795
        stv = oc->stobj->stevedore;
1031 9795
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
1032
1033 9795
        sml_bocfini(stv, boc);
1034
1035 9795
        if (stv->lru != NULL) {
1036 9643
                if (isnan(wrk->lastused))
1037 0
                        wrk->lastused = VTIM_real();
1038 9643
                LRU_Add(oc, wrk->lastused);     // approx timestamp is OK
1039 9643
        }
1040 9795
}
1041
1042
static const void * v_matchproto_(objgetattr_f)
1043 88676
sml_getattr(struct worker *wrk, struct objcore *oc, enum obj_attr attr,
1044
   ssize_t *len)
1045
{
1046
        struct object *o;
1047
        ssize_t dummy;
1048
1049 88676
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
1050
1051 88676
        if (len == NULL)
1052 54625
                len = &dummy;
1053 88676
        o = sml_getobj(wrk, oc);
1054 88676
        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
1055
1056 88676
        switch (attr) {
1057
                /* Fixed size attributes */
1058
#define OBJ_FIXATTR(U, l, s)                                            \
1059
        case OA_##U:                                                    \
1060
                *len = sizeof o->fa_##l;                                \
1061
                return (o->fa_##l);
1062
#include "tbl/obj_attr.h"
1063
1064
                /* Variable size attributes */
1065
#define OBJ_VARATTR(U, l)                                               \
1066
        case OA_##U:                                                    \
1067
                if (o->va_##l == NULL)                                  \
1068
                        return (NULL);                                  \
1069
                *len = o->va_##l##_len;                                 \
1070
                return (o->va_##l);
1071
#include "tbl/obj_attr.h"
1072
1073
                /* Auxiliary attributes */
1074
#define OBJ_AUXATTR(U, l)                                               \
1075
        case OA_##U:                                                    \
1076
                if (o->aa_##l == NULL)                                  \
1077
                        return (NULL);                                  \
1078
                CHECK_OBJ_NOTNULL(o->aa_##l, STORAGE_MAGIC);            \
1079
                *len = o->aa_##l->len;                                  \
1080
                return (o->aa_##l->ptr);
1081
#include "tbl/obj_attr.h"
1082
1083
        default:
1084
                break;
1085
        }
1086 0
        WRONG("Unsupported OBJ_ATTR");
1087 88676
}
1088
1089
static void * v_matchproto_(objsetattr_f)
1090 42159
sml_setattr(struct worker *wrk, struct objcore *oc, enum obj_attr attr,
1091
    ssize_t len, const void *ptr)
1092
{
1093
        struct object *o;
1094 42159
        void *retval = NULL;
1095
        struct storage *st;
1096
1097 42159
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
1098
1099 42159
        o = sml_getobj(wrk, oc);
1100 42159
        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
1101 42159
        st = o->objstore;
1102
1103 42159
        switch (attr) {
1104
                /* Fixed size attributes */
1105
#define OBJ_FIXATTR(U, l, s)                                            \
1106
        case OA_##U:                                                    \
1107
                assert(len == sizeof o->fa_##l);                        \
1108
                retval = o->fa_##l;                                     \
1109
                break;
1110
#include "tbl/obj_attr.h"
1111
1112
                /* Variable size attributes */
1113
#define OBJ_VARATTR(U, l)                                               \
1114
        case OA_##U:                                                    \
1115
                if (o->va_##l##_len > 0) {                              \
1116
                        AN(o->va_##l);                                  \
1117
                        assert(len == o->va_##l##_len);                 \
1118
                        retval = o->va_##l;                             \
1119
                } else if (len > 0) {                                   \
1120
                        assert(len <= UINT_MAX);                        \
1121
                        assert(st->len + len <= st->space);             \
1122
                        o->va_##l = st->ptr + st->len;                  \
1123
                        st->len += len;                                 \
1124
                        o->va_##l##_len = len;                          \
1125
                        retval = o->va_##l;                             \
1126
                }                                                       \
1127
                break;
1128
#include "tbl/obj_attr.h"
1129
1130
                /* Auxiliary attributes */
1131
#define OBJ_AUXATTR(U, l)                                               \
1132
        case OA_##U:                                                    \
1133
                if (o->aa_##l != NULL) {                                \
1134
                        CHECK_OBJ_NOTNULL(o->aa_##l, STORAGE_MAGIC);    \
1135
                        assert(len == o->aa_##l->len);                  \
1136
                        retval = o->aa_##l->ptr;                        \
1137
                        break;                                          \
1138
                }                                                       \
1139
                if (len == 0)                                           \
1140
                        break;                                          \
1141
                o->aa_##l = objallocwithnuke(wrk, oc->stobj->stevedore, \
1142
                    len, 0);                                            \
1143
                if (o->aa_##l == NULL)                                  \
1144
                        break;                                          \
1145
                CHECK_OBJ_NOTNULL(o->aa_##l, STORAGE_MAGIC);            \
1146
                assert(len <= o->aa_##l->space);                        \
1147
                o->aa_##l->len = len;                                   \
1148
                retval = o->aa_##l->ptr;                                \
1149
                break;
1150
#include "tbl/obj_attr.h"
1151
1152
        default:
1153 0
                WRONG("Unsupported OBJ_ATTR");
1154
                break;
1155
        }
1156
1157 42159
        if (retval != NULL && ptr != NULL)
1158 1584
                memcpy(retval, ptr, len);
1159 42159
        return (retval);
1160
}
1161
1162
const struct obj_methods SML_methods = {
1163
        .objfree        = sml_objfree,
1164
        .objiterator    = SML_iterator,
1165
        .objgetspace    = sml_getspace,
1166
        .objextend      = sml_extend,
1167
        .objtrimstore   = sml_trimstore,
1168
        .objbocdone     = sml_bocdone,
1169
        .objslim        = sml_slim,
1170
        .objgetattr     = sml_getattr,
1171
        .objsetattr     = sml_setattr,
1172
        .objtouch       = LRU_Touch,
1173
        .vai_init       = sml_ai_init
1174
};
1175
1176
static void
1177 16
sml_panic_st(struct vsb *vsb, const char *hd, const struct storage *st)
1178
{
1179 32
        VSB_printf(vsb, "%s = %p {priv=%p, ptr=%p, len=%u, space=%u},\n",
1180 16
            hd, st, st->priv, st->ptr, st->len, st->space);
1181 16
}
1182
1183
void
1184 8
SML_panic(struct vsb *vsb, const struct objcore *oc)
1185
{
1186
        struct object *o;
1187
        struct storage *st;
1188
1189 8
        VSB_printf(vsb, "Simple = %p,\n", oc->stobj->priv);
1190 8
        if (oc->stobj->priv == NULL)
1191 0
                return;
1192 8
        o = oc->stobj->priv;
1193 8
        PAN_CheckMagic(vsb, o, OBJECT_MAGIC);
1194 8
        sml_panic_st(vsb, "Obj", o->objstore);
1195
1196
#define OBJ_FIXATTR(U, l, sz) \
1197
        VSB_printf(vsb, "%s = ", #U); \
1198
        VSB_quote(vsb, (const void*)o->fa_##l, sz, VSB_QUOTE_HEX); \
1199
        VSB_printf(vsb, ",\n");
1200
1201
#define OBJ_VARATTR(U, l) \
1202
        VSB_printf(vsb, "%s = {len=%u, ptr=%p},\n", \
1203
            #U, o->va_##l##_len, o->va_##l);
1204
1205
#define OBJ_AUXATTR(U, l)                                               \
1206
        do {                                                            \
1207
                if (o->aa_##l != NULL) sml_panic_st(vsb, #U, o->aa_##l);\
1208
        } while(0);
1209
1210
#include "tbl/obj_attr.h"
1211
1212 16
        VTAILQ_FOREACH(st, &o->list, list) {
1213 8
                sml_panic_st(vsb, "Body", st);
1214 8
        }
1215
}