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 50398
#include "cache/cache_int.h"
36 50567
37 11235
#include "cache/cache_obj.h"
38 7589
#include "cache/cache_objhead.h"
39 50567
40
#include "storage/storage.h"
41
#include "storage/storage_simple.h"
42
#include "storage/storage_vai.h"
43
44
#include "vtim.h"
45 64029
46 131785
/* 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 73364
/*-------------------------------------------------------------------*/
53
54
static struct storage *
55
objallocwithnuke(struct worker *, const struct stevedore *, ssize_t size,
56
    int flags);
57
58
static struct storage *
59 66319
sml_stv_alloc(const struct stevedore *stv, ssize_t size, int flags)
60
{
61
        struct storage *st;
62
63 66319
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
64 66319
        AN(stv->sml_alloc);
65
66 66319
        if (!(flags & LESS_MEM_ALLOCED_IS_OK)) {
67 13379
                if (size > cache_param->fetch_maxchunksize)
68 0
                        return (NULL);
69
                else
70 13379
                        return (stv->sml_alloc(stv, size));
71
        }
72
73 52940
        if (size > cache_param->fetch_maxchunksize)
74 0
                size = cache_param->fetch_maxchunksize;
75
76 52940
        assert(size <= UINT_MAX);       /* field limit in struct storage */
77
78 55775
        for (;;) {
79
                /* try to allocate from it */
80 55775
                assert(size > 0);
81 55775
                st = stv->sml_alloc(stv, size);
82 55775
                if (st != NULL)
83 52709
                        break;
84
85 3066
                if (size <= cache_param->fetch_chunksize)
86 231
                        break;
87
88 2835
                size /= 2;
89
        }
90 52940
        CHECK_OBJ_ORNULL(st, STORAGE_MAGIC);
91 52940
        return (st);
92 66319
}
93
94
static void
95 83063
sml_stv_free(const struct stevedore *stv, struct storage *st)
96
{
97
98 83063
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
99 83063
        CHECK_OBJ_NOTNULL(st, STORAGE_MAGIC);
100 83063
        if (stv->sml_free != NULL)
101 83063
                stv->sml_free(st);
102 83063
}
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 55923
SML_MkObject(const struct stevedore *stv, struct objcore *oc, void *ptr)
114
{
115
        struct object *o;
116
117 55923
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
118 55923
        AN(stv->methods);
119 55923
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
120
121 55923
        assert(PAOK(ptr));
122
123 55923
        o = ptr;
124 55923
        INIT_OBJ(o, OBJECT_MAGIC);
125
126 55923
        VTAILQ_INIT(&o->list);
127
128 55923
        oc->stobj->stevedore = stv;
129 55923
        oc->stobj->priv = o;
130 55923
        oc->stobj->priv2 = 0;
131 55923
        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 55713
SML_allocobj(struct worker *wrk, const struct stevedore *stv,
141
    struct objcore *oc, unsigned wsl)
142
{
143
        struct object *o;
144 55713
        struct storage *st = NULL;
145
        unsigned ltot;
146
147 55713
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
148 55713
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
149 55713
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
150
151 55713
        AN(stv->sml_alloc);
152
153 55713
        ltot = sizeof(*o) + PRNDUP(wsl);
154
155 55713
        do {
156 55776
                st = stv->sml_alloc(stv, ltot);
157 55776
                if (st != NULL && st->space < ltot) {
158 0
                        stv->sml_free(st);
159 0
                        st = NULL;
160 0
                }
161 55776
        } while (st == NULL && LRU_NukeOne(wrk, stv->lru));
162 55713
        if (st == NULL)
163 189
                return (0);
164
165 55524
        CHECK_OBJ(st, STORAGE_MAGIC);
166 55524
        o = SML_MkObject(stv, oc, st->ptr);
167 55524
        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
168 55524
        st->len = sizeof(*o);
169 55524
        o->objstore = st;
170 55524
        return (1);
171 55713
}
172
173
void * v_matchproto_(storage_allocbuf_t)
174 6174
SML_AllocBuf(struct worker *wrk, const struct stevedore *stv, size_t size,
175
    uintptr_t *ppriv)
176
{
177
        struct storage *st;
178
179 6174
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
180 6174
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
181 6174
        AN(ppriv);
182
183 6174
        if (size > UINT_MAX)
184 0
                return (NULL);
185 6174
        st = objallocwithnuke(wrk, stv, size, 0);
186 6174
        if (st == NULL)
187 0
                return (NULL);
188 6174
        assert(st->space >= size);
189 6174
        st->flags = STORAGE_F_BUFFER;
190 6174
        st->len = size;
191 6174
        *ppriv = (uintptr_t)st;
192 6174
        return (st->ptr);
193 6174
}
194
195
void v_matchproto_(storage_freebuf_t)
196 6174
SML_FreeBuf(struct worker *wrk, const struct stevedore *stv, uintptr_t priv)
197
{
198
        struct storage *st;
199
200 6174
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
201 6174
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
202
203 6174
        CAST_OBJ_NOTNULL(st, (void *)priv, STORAGE_MAGIC);
204 6174
        assert(st->flags == STORAGE_F_BUFFER);
205 6174
        sml_stv_free(stv, st);
206 6174
}
207
208
/*---------------------------------------------------------------------
209
 */
210
211
static struct object *
212 3312976
sml_getobj(struct worker *wrk, struct objcore *oc)
213
{
214
        const struct stevedore *stv;
215
        struct object *o;
216
217 3312976
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
218 3312976
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
219 3312976
        stv = oc->stobj->stevedore;
220 3312976
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
221 3312976
        if (stv->sml_getobj != NULL)
222 5376
                return (stv->sml_getobj(wrk, oc));
223 3307600
        if (oc->stobj->priv == NULL)
224 0
                return (NULL);
225 3307600
        CAST_OBJ_NOTNULL(o, oc->stobj->priv, OBJECT_MAGIC);
226 3307600
        return (o);
227 3312976
}
228
229
static void v_matchproto_(objslim_f)
230 56541
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 56541
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
237
238 56541
        stv = oc->stobj->stevedore;
239 56541
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
240 56541
        o = sml_getobj(wrk, oc);
241 56541
        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 84298
        VTAILQ_FOREACH_SAFE(st, &o->list, list, stn) {
253 27757
                CHECK_OBJ_NOTNULL(st, STORAGE_MAGIC);
254 27757
                VTAILQ_REMOVE(&o->list, st, list);
255 27757
                sml_stv_free(stv, st);
256 27757
        }
257
}
258
259
static void
260 56234
sml_bocfini(const struct stevedore *stv, struct boc *boc)
261
{
262
        struct storage *st;
263
264 56234
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
265 56234
        CHECK_OBJ_NOTNULL(boc, BOC_MAGIC);
266
267 56234
        if (boc->stevedore_priv == NULL ||
268 31416
            boc->stevedore_priv == trim_once)
269 51864
                return;
270
271
        /* Free any leftovers from Trim */
272 4370
        TAKE_OBJ_NOTNULL(st, &boc->stevedore_priv, STORAGE_MAGIC);
273 4370
        sml_stv_free(stv, st);
274 56234
}
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 34198
sml_objfree(struct worker *wrk, struct objcore *oc)
283
{
284
        const struct stevedore *stv;
285
        struct storage *st;
286
        struct object *o;
287
288 34198
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
289 34198
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
290 34198
        stv = oc->stobj->stevedore;
291 34198
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
292 34198
        CAST_OBJ_NOTNULL(o, oc->stobj->priv, OBJECT_MAGIC);
293
294 34198
        sml_slim(wrk, oc);
295 34198
        st = o->objstore;
296 34198
        CHECK_OBJ_NOTNULL(st, STORAGE_MAGIC);
297 34198
        FINI_OBJ(o);
298
299 34198
        if (oc->boc != NULL)
300 483
                sml_bocfini(stv, oc->boc);
301 33715
        else if (stv->lru != NULL)
302 33714
                LRU_Remove(oc);
303
304 34198
        sml_stv_free(stv, st);
305
306 34198
        memset(oc->stobj, 0, sizeof oc->stobj);
307
308 34198
        wrk->stats->n_object--;
309 34198
}
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 31145
sml_ai_viov_fill(struct viov *viov, struct storage *st)
335
{
336 31145
        viov->iov.iov_base = TRUST_ME(st->ptr);
337 31145
        viov->iov.iov_len = st->len;
338 31145
        viov->lease = ptr2lease(st);
339 31145
        VAI_ASSERT_LEASE(viov->lease);
340 31145
}
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 336
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 336
        int r = 0;
380
381 336
        (void) wrk;
382 336
        CAST_VAI_HDL_NOTNULL(hdl, vhdl, SML_HDL_MAGIC);
383 336
        stv = hdl->stv;
384 336
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
385
386 672
        VSCARAB_FOREACH(vio, scarab)
387 336
                if (vio->iov.iov_len > UINT_MAX)
388 0
                        return (-EINVAL);
389
390 672
        VSCARAB_FOREACH(vio, scarab) {
391 336
                st = objallocwithnuke(wrk, stv, vio->iov.iov_len, 0);
392 336
                if (st == NULL)
393 0
                        break;
394 336
                assert(st->space >= vio->iov.iov_len);
395 336
                st->flags = STORAGE_F_BUFFER;
396 336
                st->len = st->space;
397
398 336
                sml_ai_viov_fill(vio, st);
399 336
                r++;
400 336
        }
401 336
        if (r == 0) {
402 0
                sml_ai_later(wrk, hdl);
403 0
                r = -EAGAIN;
404 0
        }
405 336
        return (r);
406 336
}
407
408
static int
409 52692
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 52692
        int r = 0;
415
416 52692
        (void) wrk;
417 52692
        CAST_VAI_HDL_NOTNULL(hdl, vhdl, SML_HDL_MAGIC);
418 52692
        VSCARAB_CHECK_NOTNULL(scarab);
419
420 52692
        AZ(hdl->st_off);
421 52692
        st = hdl->st;
422 83502
        while (st != NULL && (viov = VSCARAB_GET(scarab)) != NULL) {
423 30810
                CHECK_OBJ(st, STORAGE_MAGIC);
424 30810
                sml_ai_viov_fill(viov, st);
425 30810
                r++;
426 30810
                st = VTAILQ_PREV(st, storagehead, list);
427
        }
428 52692
        hdl->st = st;
429 52692
        if (st == NULL)
430 52669
                scarab->flags |= VSCARAB_F_END;
431 52692
        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 104303
sml_ai_lease_boc(struct worker *wrk, vai_hdl vhdl, struct vscarab *scarab)
448
{
449 104303
        enum boc_state_e state = BOS_INVALID;
450
        struct storage *next;
451
        struct sml_hdl *hdl;
452
        struct viov *viov;
453 104303
        int r = 0;
454
455 104303
        CAST_VAI_HDL_NOTNULL(hdl, vhdl, SML_HDL_MAGIC);
456 104303
        VSCARAB_CHECK_NOTNULL(scarab);
457 104303
        assert(hdl->boc == hdl->oc->boc);
458
459 104303
        if (hdl->avail == hdl->returned) {
460 198792
                hdl->avail = ObjVAIGetExtend(wrk, hdl->oc, hdl->returned,
461 99396
                    &state, &hdl->qe);
462 99396
                assert(state >= BOS_STREAM);
463 99396
                if (state == BOS_FAILED) {
464 357
                        hdl->last = NULL;
465 357
                        return (-EPIPE);
466
                }
467 99039
                else if (state == BOS_FINISHED)
468 16482
                        (void)0;
469 82557
                else if (hdl->avail == hdl->returned) {
470
                        // ObjVAIGetExtend() has scheduled a notification
471 40575
                        if (hdl->boc->transit_buffer > 0)
472 5513
                                return (-ENOBUFS);
473
                        else
474 35062
                                return (-EAGAIN);
475
                }
476
                else
477 41982
                        assert(state < BOS_FINISHED);
478 58464
        }
479 63371
        Lck_Lock(&hdl->boc->mtx);
480 63371
        if (hdl->st == NULL && hdl->last != NULL)
481 19023
                hdl->st = VTAILQ_PREV(hdl->last, storagehead, list);
482 63371
        if (hdl->last != NULL && state < BOS_FINISHED) {
483 3294
                viov = VSCARAB_GET(scarab);
484 3294
                AN(viov);
485 3294
                viov->iov = IOV_NIL;
486 3294
                viov->lease = ptr2lease(hdl->last);
487 3294
                r++;
488 3294
        }
489 63371
        if (hdl->last != NULL)
490 19023
                hdl->last = NULL;
491 63371
        if (hdl->st == NULL && hdl->returned == 0)
492 16958
                hdl->st = VTAILQ_LAST(&hdl->obj->list, storagehead);
493 63371
        if (hdl->st == NULL)
494 15704
                assert(hdl->avail == hdl->returned);
495
496 113899
        while (hdl->avail > hdl->returned && (viov = VSCARAB_GET(scarab)) != NULL) {
497 50528
                CHECK_OBJ_NOTNULL(hdl->st, STORAGE_MAGIC); // ObjVAIGetExtend ensures
498 50528
                assert(hdl->boc == hdl->oc->boc);
499 50528
                assert(hdl->st_off <= hdl->st->space);
500 50528
                size_t av = hdl->avail - hdl->returned;
501 50528
                size_t l = hdl->st->space - hdl->st_off;
502 50528
                AN(l);
503 50528
                if (l > av)
504 23818
                        l = av;
505 50528
                viov->iov.iov_base = TRUST_ME(hdl->st->ptr + hdl->st_off);
506 50528
                viov->iov.iov_len = l;
507 50528
                if (hdl->st_off + l == hdl->st->space) {
508 26711
                        next = VTAILQ_PREV(hdl->st, storagehead, list);
509 26711
                        AZ(hdl->last);
510 26711
                        if (next == NULL) {
511 19293
                                hdl->last = hdl->st;
512 19293
                                viov->lease = VAI_LEASE_NORET;
513 19293
                        }
514
                        else {
515 7418
                                CHECK_OBJ(next, STORAGE_MAGIC);
516 7418
                                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 26711
                        hdl->st_off = 0;
524 26711
                        hdl->st = next;
525 26711
                }
526
                else {
527 23817
                        viov->lease = VAI_LEASE_NORET;
528 23817
                        hdl->st_off += l;
529
                }
530 50528
                hdl->returned += l;
531 50528
                VAI_ASSERT_LEASE(viov->lease);
532 50528
                r++;
533
        }
534
535 63371
        Lck_Unlock(&hdl->boc->mtx);
536 63371
        if (state != BOS_FINISHED && hdl->avail == hdl->returned) {
537 93920
                hdl->avail = ObjVAIGetExtend(wrk, hdl->oc, hdl->returned,
538 46960
                    &state, &hdl->qe);
539 46960
        }
540 63371
        if (state == BOS_FINISHED && hdl->avail == hdl->returned)
541 16485
                scarab->flags |= VSCARAB_F_END;
542 63371
        return (r);
543 104303
}
544
545
// return only buffers, used if object is not streaming
546
static void v_matchproto_(vai_return_f)
547 42462
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 42462
        (void) wrk;
554 42462
        CAST_VAI_HDL_NOTNULL(hdl, vhdl, SML_HDL_MAGIC);
555
556 87581
        VSCARET_FOREACH(p, scaret) {
557 45119
                if (*p == VAI_LEASE_NORET)
558 13160
                        continue;
559 31959
                CAST_OBJ_NOTNULL(st, lease2ptr(*p), STORAGE_MAGIC);
560 31959
                if ((st->flags & STORAGE_F_BUFFER) == 0)
561 31623
                        continue;
562 336
                sml_stv_free(hdl->stv, st);
563 336
        }
564 42462
        VSCARET_INIT(scaret, scaret->capacity);
565 42462
}
566
567
// generic return for buffers and object leases, used when streaming
568
static void v_matchproto_(vai_return_f)
569 26398
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 26398
        (void) wrk;
576 26398
        CAST_VAI_HDL_NOTNULL(hdl, vhdl, SML_HDL_MAGIC);
577 26398
        VSCARET_CHECK_NOTNULL(scaret);
578 26398
        if (scaret->used == 0)
579 0
                return;
580
581
        // callback is only registered if needed
582 26398
        assert(hdl->boc != NULL && (hdl->oc->flags & OC_F_TRANSIENT) != 0);
583
584
        // filter noret and last
585 26398
        VSCARET_LOCAL(todo, scaret->used);
586 66931
        VSCARET_FOREACH(p, scaret) {
587 40533
                if (*p == VAI_LEASE_NORET)
588 30640
                        continue;
589 9893
                CAST_OBJ_NOTNULL(st, lease2ptr(*p), STORAGE_MAGIC);
590 9893
                VSCARET_ADD(todo, *p);
591 9893
        }
592 26398
        VSCARET_INIT(scaret, scaret->capacity);
593
594 26398
        Lck_Lock(&hdl->boc->mtx);
595 36291
        VSCARET_FOREACH(p, todo) {
596 9893
                CAST_OBJ_NOTNULL(st, lease2ptr(*p), STORAGE_MAGIC);
597 9893
                if ((st->flags & STORAGE_F_BUFFER) != 0)
598 0
                        continue;
599 9893
                VTAILQ_REMOVE(&hdl->obj->list, st, list);
600 9893
                if (st == hdl->boc->stevedore_priv)
601 0
                        hdl->boc->stevedore_priv = trim_once;
602 9893
        }
603 26398
        Lck_Unlock(&hdl->boc->mtx);
604
605 36292
        VSCARET_FOREACH(p, todo) {
606 9894
                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 9894
                sml_stv_free(hdl->stv, st);
612 9894
        }
613 26398
}
614
615
// call the notify_cb to allow VDPs to use -EAGAIN also
616
static void v_matchproto_(vai_return_f)
617 2687
sml_ai_notify(struct worker *wrk, vai_hdl vhdl)
618
{
619
        struct sml_hdl *hdl;
620
621 2687
        (void) wrk;
622 2687
        CAST_VAI_HDL_NOTNULL(hdl, vhdl, SML_HDL_MAGIC);
623 2687
        CHECK_OBJ(&hdl->qe, VAI_Q_MAGIC);
624 2687
        hdl->qe.cb(vhdl, hdl->qe.priv);
625 2687
}
626
627
static void v_matchproto_(vai_fini_f)
628 44113
sml_ai_fini(struct worker *wrk, vai_hdl *vai_hdlp)
629
{
630
        struct sml_hdl *hdl;
631
632 44113
        AN(vai_hdlp);
633 44113
        CAST_VAI_HDL_NOTNULL(hdl, *vai_hdlp, SML_HDL_MAGIC);
634 44113
        *vai_hdlp = NULL;
635
636 44113
        if (hdl->boc != NULL) {
637 17070
                ObjVAICancel(wrk, hdl->boc, &hdl->qe);
638 17070
                HSH_DerefBoc(wrk, hdl->oc);
639 17070
                hdl->boc = NULL;
640 17070
        }
641
642 44113
        if (hdl->ws != NULL)
643 672
                WS_Release(hdl->ws, 0);
644
        else
645 43441
                free(hdl);
646 44113
}
647
648
static vai_hdl v_matchproto_(vai_init_f)
649 44118
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 44118
        const size_t sz = sizeof *hdl;
654
655 44118
        if (ws != NULL && WS_ReserveSize(ws, (unsigned)sz))
656 672
                hdl = WS_Reservation(ws);
657
        else {
658 43446
                hdl = malloc(sz);
659 43446
                ws = NULL;
660
        }
661
662 44118
        AN(hdl);
663 44118
        INIT_VAI_HDL(hdl, SML_HDL_MAGIC);
664 44118
        hdl->preamble.vai_lease = sml_ai_lease_simple;
665 44118
        hdl->preamble.vai_buffer = sml_ai_buffer;
666 44118
        hdl->preamble.vai_return = sml_ai_return_buffers;
667 44118
        hdl->preamble.vai_notify = sml_ai_notify;
668 44118
        hdl->preamble.vai_fini = sml_ai_fini;
669 44118
        hdl->ws = ws;
670
671 44118
        hdl->oc = oc;
672 44118
        hdl->obj = sml_getobj(wrk, oc);
673 44118
        CHECK_OBJ_NOTNULL(hdl->obj, OBJECT_MAGIC);
674 44118
        hdl->stv = oc->stobj->stevedore;
675 44118
        CHECK_OBJ_NOTNULL(hdl->stv, STEVEDORE_MAGIC);
676
677
678 44118
        hdl->qe.magic = VAI_Q_MAGIC;
679 44118
        hdl->qe.cb = notify;
680 44118
        hdl->qe.hdl = hdl;
681 44118
        hdl->qe.priv = notify_priv;
682
683 44118
        hdl->boc = HSH_RefBoc(oc);
684 44118
        if (hdl->boc == NULL) {
685 27050
                hdl->st = VTAILQ_LAST(&hdl->obj->list, storagehead);
686 27050
                CHECK_OBJ_ORNULL(hdl->st, STORAGE_MAGIC);
687 27050
                return (hdl);
688
        }
689
        /* we only initialize notifications if we have a boc, so
690
         * any wrong attempt triggers magic checks.
691
         */
692 17068
        hdl->preamble.vai_lease = sml_ai_lease_boc;
693 17068
        if ((hdl->oc->flags & OC_F_TRANSIENT) != 0)
694 7727
                hdl->preamble.vai_return = sml_ai_return;
695 17068
        return (hdl);
696 44118
}
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 52665
sml_notify_init(struct sml_notify *sn)
711
{
712
713 52665
        INIT_OBJ(sn, SML_NOTIFY_MAGIC);
714 52665
        PTOK(pthread_mutex_init(&sn->mtx, NULL));
715 52665
        PTOK(pthread_cond_init(&sn->cond, NULL));
716 52665
}
717
718
static void
719 52666
sml_notify_fini(struct sml_notify *sn)
720
{
721
722 52666
        CHECK_OBJ_NOTNULL(sn, SML_NOTIFY_MAGIC);
723 52666
        PTOK(pthread_mutex_destroy(&sn->mtx));
724 52666
        PTOK(pthread_cond_destroy(&sn->cond));
725 52666
}
726
727
static void v_matchproto_(vai_notify_cb)
728 43685
sml_notify(vai_hdl hdl, void *priv)
729
{
730
        struct sml_notify *sn;
731
732 43685
        (void) hdl;
733 43685
        CAST_OBJ_NOTNULL(sn, priv, SML_NOTIFY_MAGIC);
734 43685
        PTOK(pthread_mutex_lock(&sn->mtx));
735 43685
        sn->hasmore = 1;
736 43685
        PTOK(pthread_cond_signal(&sn->cond));
737 43685
        PTOK(pthread_mutex_unlock(&sn->mtx));
738
739 43685
}
740
741
static void
742 40216
sml_notify_wait(struct sml_notify *sn)
743
{
744
745 40216
        CHECK_OBJ_NOTNULL(sn, SML_NOTIFY_MAGIC);
746 40216
        PTOK(pthread_mutex_lock(&sn->mtx));
747 60796
        while (sn->hasmore == 0)
748 20580
                PTOK(pthread_cond_wait(&sn->cond, &sn->mtx));
749 40216
        AN(sn->hasmore);
750 40216
        sn->hasmore = 0;
751 40216
        PTOK(pthread_mutex_unlock(&sn->mtx));
752 40216
}
753
754
int v_matchproto_(objiterator_f)
755 52673
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 52673
        VSCARAB_LOCAL(scarab, 16);
765 52673
        VSCARET_LOCAL(scaret, 16);
766
767 52673
        (void) final; // phase out?
768 52673
        sml_notify_init(&sn);
769 52673
        hdl = ObjVAIinit(wrk, oc, NULL, sml_notify, &sn);
770 52673
        AN(hdl);
771
772 52673
        r = u = 0;
773
774 52673
        do {
775 127815
                do {
776 174747
                        nn = ObjVAIlease(wrk, hdl, scarab);
777 174747
                        if (nn <= 0 || scarab->flags & VSCARAB_F_END)
778 127790
                                break;
779 46957
                } 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 127815
                uu = u;
786 127815
                last = VSCARAB_LAST(scarab);
787 323241
                VSCARAB_FOREACH(vio, scarab) {
788 196664
                        islast = vio == last;
789 196664
                        AZ(u & OBJ_ITER_END);
790 196664
                        if (islast && scarab->flags & VSCARAB_F_END)
791 35706
                                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 196664
                        uu = u;
796 196664
                        if ((islast && nn < 0) || scaret->used == scaret->capacity - 1)
797 38582
                                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 196664
                        if (vio->iov.iov_base == IOV_NIL.iov_base)
802 3294
                                r = 0;
803
                        else
804 193370
                                r = func(priv, uu, vio->iov.iov_base, vio->iov.iov_len);
805 196664
                        if (r != 0)
806 1236
                                break;
807
808
                        // sufficient space ensured by capacity check above
809 195428
                        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 195428
                        if ((uu & OBJ_ITER_FLUSH) && scaret->used > 0)
819 38252
                                ObjVAIreturn(wrk, hdl, scaret);
820 195428
                }
821
822
                // return leases which we did not use if error (break)
823 129817
                VSCARAB_FOREACH_RESUME(vio, scarab) {
824 2004
                        if (scaret->used == scaret->capacity)
825 0
                                ObjVAIreturn(wrk, hdl, scaret);
826 2004
                        VSCARET_ADD(scaret, vio->lease);
827 2004
                }
828
829
                // we have now completed the scarab
830 127813
                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 127813
                if (r == 0 && (nn == -ENOBUFS || nn == -EAGAIN) &&
840 126587
                    (uu & OBJ_ITER_FLUSH) == 0) {
841 2002
                        r = func(priv, OBJ_ITER_FLUSH, NULL, 0);
842 2002
                        if (scaret->used > 0)
843 0
                                ObjVAIreturn(wrk, hdl, scaret);
844 2002
                }
845
846 127813
                if (r == 0 && (nn == -ENOBUFS || nn == -EAGAIN)) {
847 40231
                        assert(scaret->used <= 1);
848 40231
                        sml_notify_wait(&sn);
849 40231
                }
850 87582
                else if (r == 0 && nn < 0)
851 357
                        r = -1;
852 127813
        } while (nn != 0 && r == 0);
853
854 52671
        if ((u & OBJ_ITER_END) == 0) {
855 16960
                r2 = func(priv, OBJ_ITER_END, NULL, 0);
856 16960
                if (r == 0)
857 16170
                        r = r2;
858 16960
        }
859
860 52671
        if (scaret->used > 0)
861 36141
                ObjVAIreturn(wrk, hdl, scaret);
862
863 52671
        ObjVAIfini(wrk, &hdl);
864 52671
        sml_notify_fini(&sn);
865
866 52671
        return (r);
867
}
868
869
/*--------------------------------------------------------------------
870
 */
871
872
static struct storage *
873 61865
objallocwithnuke(struct worker *wrk, const struct stevedore *stv, ssize_t size,
874
    int flags)
875
{
876 61865
        struct storage *st = NULL;
877
878 61865
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
879 61865
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
880
881 61865
        if (size > cache_param->fetch_maxchunksize) {
882 42
                if (!(flags & LESS_MEM_ALLOCED_IS_OK))
883 0
                        return (NULL);
884 42
                size = cache_param->fetch_maxchunksize;
885 42
        }
886
887 61865
        assert(size <= UINT_MAX);       /* field limit in struct storage */
888
889 61865
        do {
890
                /* try to allocate from it */
891 62033
                st = sml_stv_alloc(stv, size, flags);
892 62033
                if (st != NULL)
893 61760
                        break;
894
895
                /* no luck; try to free some space and keep trying */
896 273
                if (stv->lru == NULL)
897 0
                        break;
898 273
        } while (LRU_NukeOne(wrk, stv->lru));
899
900 61865
        CHECK_OBJ_ORNULL(st, STORAGE_MAGIC);
901 61865
        return (st);
902 61865
}
903
904
static int v_matchproto_(objgetspace_f)
905 1255456
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 1255456
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
912 1255456
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
913 1255456
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
914 1255456
        AN(sz);
915 1255456
        AN(ptr);
916 1255456
        if (*sz == 0)
917 1190347
                *sz = cache_param->fetch_chunksize;
918 1255456
        assert(*sz > 0);
919 1255456
        if (oc->boc->transit_buffer > 0)
920 9555
                *sz = vmin_t(ssize_t, *sz, oc->boc->transit_buffer);
921
922 1255456
        o = sml_getobj(wrk, oc);
923 1255456
        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
924 1255456
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
925
926 1255456
        st = VTAILQ_FIRST(&o->list);
927 1255456
        if (st != NULL && st->len < st->space) {
928 1202642
                *sz = st->space - st->len;
929 1202642
                *ptr = st->ptr + st->len;
930 1202642
                assert (*sz > 0);
931 1202642
                return (1);
932
        }
933
934 52814
        st = objallocwithnuke(wrk, oc->stobj->stevedore, *sz,
935
            LESS_MEM_ALLOCED_IS_OK);
936 52814
        if (st == NULL)
937 105
                return (0);
938
939 52709
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
940 52709
        Lck_Lock(&oc->boc->mtx);
941 52709
        VTAILQ_INSERT_HEAD(&o->list, st, list);
942 52709
        Lck_Unlock(&oc->boc->mtx);
943
944 52709
        *sz = st->space - st->len;
945 52709
        assert (*sz > 0);
946 52709
        *ptr = st->ptr + st->len;
947 52709
        return (1);
948 1255456
}
949
950
static void v_matchproto_(objextend_f)
951 1221441
sml_extend(struct worker *wrk, struct objcore *oc, ssize_t l)
952
{
953
        struct object *o;
954
        struct storage *st;
955
956 1221441
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
957 1221441
        assert(l > 0);
958
959 1221441
        o = sml_getobj(wrk, oc);
960 1221441
        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
961 1221441
        st = VTAILQ_FIRST(&o->list);
962 1221441
        CHECK_OBJ_NOTNULL(st, STORAGE_MAGIC);
963 1221441
        assert(st->len + l <= st->space);
964 1221441
        st->len += l;
965 1221441
}
966
967
static void v_matchproto_(objtrimstore_f)
968 31436
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 31436
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
975 31436
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
976 31436
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
977
978 31436
        stv = oc->stobj->stevedore;
979 31436
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
980
981 31436
        if (oc->boc->stevedore_priv != NULL)
982 0
                WRONG("sml_trimstore already called");
983 31436
        oc->boc->stevedore_priv = trim_once;
984
985 31436
        o = sml_getobj(wrk, oc);
986 31436
        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
987 31436
        st = VTAILQ_FIRST(&o->list);
988
989 31436
        if (st == NULL)
990 0
                return;
991
992 31436
        if (st->len == 0) {
993 84
                Lck_Lock(&oc->boc->mtx);
994 84
                VTAILQ_REMOVE(&o->list, st, list);
995 84
                Lck_Unlock(&oc->boc->mtx);
996
                /* sml_bocdone frees this */
997 84
                oc->boc->stevedore_priv = st;
998 84
                return;
999
        }
1000
1001 31352
        if (stv->sml_free == NULL)
1002 0
                return;
1003
1004 31352
        if (st->space - st->len < 512)
1005 27068
                return;
1006
1007 4284
        st1 = sml_stv_alloc(stv, st->len, 0);
1008 4284
        if (st1 == NULL)
1009 0
                return;
1010 4284
        assert(st1->space >= st->len);
1011
1012 4284
        vmemcpy(st1->ptr, st->ptr, st->len);
1013 4284
        st1->len = st->len;
1014 4284
        Lck_Lock(&oc->boc->mtx);
1015 4284
        VTAILQ_REMOVE(&o->list, st, list);
1016 4284
        VTAILQ_INSERT_HEAD(&o->list, st1, list);
1017 4284
        Lck_Unlock(&oc->boc->mtx);
1018
        /* sml_bocdone frees this */
1019 4284
        oc->boc->stevedore_priv = st;
1020 31436
}
1021
1022
static void v_matchproto_(objbocdone_f)
1023 55751
sml_bocdone(struct worker *wrk, struct objcore *oc, struct boc *boc)
1024
{
1025
        const struct stevedore *stv;
1026
1027 55751
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
1028 55751
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
1029 55751
        CHECK_OBJ_NOTNULL(boc, BOC_MAGIC);
1030 55751
        stv = oc->stobj->stevedore;
1031 55751
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
1032
1033 55751
        sml_bocfini(stv, boc);
1034
1035 55751
        if (stv->lru != NULL) {
1036 55016
                if (isnan(wrk->lastused))
1037 0
                        wrk->lastused = VTIM_real();
1038 55016
                LRU_Add(oc, wrk->lastused);     // approx timestamp is OK
1039 55016
        }
1040 55751
}
1041
1042
static const void * v_matchproto_(objgetattr_f)
1043 476255
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 476255
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
1050
1051 476255
        if (len == NULL)
1052 292973
                len = &dummy;
1053 476255
        o = sml_getobj(wrk, oc);
1054 476255
        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
1055
1056 476255
        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 476255
}
1088
1089
static void * v_matchproto_(objsetattr_f)
1090 227977
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 227977
        void *retval = NULL;
1095
        struct storage *st;
1096
1097 227977
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
1098
1099 227977
        o = sml_getobj(wrk, oc);
1100 227977
        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
1101 227977
        st = o->objstore;
1102
1103 227977
        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 227977
        if (retval != NULL && ptr != NULL)
1158 8358
                vmemcpy(retval, ptr, len);
1159 227979
        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 84
sml_panic_st(struct vsb *vsb, const char *hd, const struct storage *st)
1178
{
1179 168
        VSB_printf(vsb, "%s = %p {priv=%p, ptr=%p, len=%u, space=%u},\n",
1180 84
            hd, st, st->priv, st->ptr, st->len, st->space);
1181 84
}
1182
1183
void
1184 42
SML_panic(struct vsb *vsb, const struct objcore *oc)
1185
{
1186
        struct object *o;
1187
        struct storage *st;
1188
1189 42
        VSB_printf(vsb, "Simple = %p,\n", oc->stobj->priv);
1190 42
        if (oc->stobj->priv == NULL)
1191 0
                return;
1192 42
        o = oc->stobj->priv;
1193 42
        PAN_CheckMagic(vsb, o, OBJECT_MAGIC);
1194 42
        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 84
        VTAILQ_FOREACH(st, &o->list, list) {
1213 42
                sml_panic_st(vsb, "Body", st);
1214 42
        }
1215
}