varnish-cache/bin/varnishd/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 "cache/cache_varnishd.h"
34
35 106756
#include "cache/cache_obj.h"
36 86753
#include "cache/cache_objhead.h"
37 20554
38 14248
#include "storage/storage.h"
39 86759
#include "storage/storage_simple.h"
40
41
#include "vtim.h"
42
43
/* Flags for allocating memory in sml_stv_alloc */
44
#define LESS_MEM_ALLOCED_IS_OK  1
45 119265
46 223480
// marker pointer for sml_trimstore
47
static void *trim_once = &trim_once;
48
49
/*-------------------------------------------------------------------*/
50
51
static struct storage *
52 156539
objallocwithnuke(struct worker *, const struct stevedore *, ssize_t size,
53
    int flags);
54
55
static struct storage *
56 124084
sml_stv_alloc(const struct stevedore *stv, ssize_t size, int flags)
57
{
58
        struct storage *st;
59
60 124084
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
61 124084
        AN(stv->sml_alloc);
62
63 124084
        if (!(flags & LESS_MEM_ALLOCED_IS_OK)) {
64 13407
                if (size > cache_param->fetch_maxchunksize)
65 0
                        return (NULL);
66
                else
67 13407
                        return (stv->sml_alloc(stv, size));
68
        }
69
70 110677
        if (size > cache_param->fetch_maxchunksize)
71 0
                size = cache_param->fetch_maxchunksize;
72
73 110677
        assert(size <= UINT_MAX);       /* field limit in struct storage */
74
75 116077
        for (;;) {
76
                /* try to allocate from it */
77 116077
                assert(size > 0);
78 116077
                st = stv->sml_alloc(stv, size);
79 116077
                if (st != NULL)
80 110237
                        break;
81
82 5840
                if (size <= cache_param->fetch_chunksize)
83 440
                        break;
84
85 5400
                size /= 2;
86
        }
87 110677
        CHECK_OBJ_ORNULL(st, STORAGE_MAGIC);
88 110677
        return (st);
89 124084
}
90
91
static void
92 162451
sml_stv_free(const struct stevedore *stv, struct storage *st)
93
{
94
95 162451
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
96 162451
        CHECK_OBJ_NOTNULL(st, STORAGE_MAGIC);
97 162451
        if (stv->sml_free != NULL)
98 162450
                stv->sml_free(st);
99 162451
}
100
101
/*--------------------------------------------------------------------
102
 * This function is called by stevedores ->allocobj() method, which
103
 * very often will be SML_allocobj() below, to convert a slab
104
 * of storage into object which the stevedore can then register in its
105
 * internal state, before returning it to STV_NewObject().
106
 * As you probably guessed: All this for persistence.
107
 */
108
109
struct object *
110 111279
SML_MkObject(const struct stevedore *stv, struct objcore *oc, void *ptr)
111
{
112
        struct object *o;
113
114 111279
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
115 111279
        AN(stv->methods);
116 111279
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
117
118 111279
        assert(PAOK(ptr));
119
120 111279
        o = ptr;
121 111279
        INIT_OBJ(o, OBJECT_MAGIC);
122
123 111279
        VTAILQ_INIT(&o->list);
124
125 111279
        oc->stobj->stevedore = stv;
126 111279
        oc->stobj->priv = o;
127 111279
        oc->stobj->priv2 = 0;
128 111279
        return (o);
129
}
130
131
/*--------------------------------------------------------------------
132
 * This is the default ->allocobj() which all stevedores who do not
133
 * implement persistent storage can rely on.
134
 */
135
136
int v_matchproto_(storage_allocobj_f)
137 110839
SML_allocobj(struct worker *wrk, const struct stevedore *stv,
138
    struct objcore *oc, unsigned wsl)
139
{
140
        struct object *o;
141 110839
        struct storage *st = NULL;
142
        unsigned ltot;
143
144 110839
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
145 110839
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
146 110839
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
147
148 110839
        AN(stv->sml_alloc);
149
150 110839
        ltot = sizeof(*o) + PRNDUP(wsl);
151
152 110839
        do {
153 110960
                st = stv->sml_alloc(stv, ltot);
154 110960
                if (st != NULL && st->space < ltot) {
155 0
                        stv->sml_free(st);
156 0
                        st = NULL;
157 0
                }
158 110960
        } while (st == NULL && LRU_NukeOne(wrk, stv->lru));
159 110839
        if (st == NULL)
160 440
                return (0);
161
162 110399
        CHECK_OBJ_NOTNULL(st, STORAGE_MAGIC);
163 110399
        o = SML_MkObject(stv, oc, st->ptr);
164 110399
        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
165 110399
        st->len = sizeof(*o);
166 110399
        o->objstore = st;
167 110399
        return (1);
168 110839
}
169
170
void * v_matchproto_(storage_allocbuf_t)
171 880
SML_AllocBuf(struct worker *wrk, const struct stevedore *stv, size_t size,
172
    uintptr_t *ppriv)
173
{
174
        struct storage *st;
175
176 880
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
177 880
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
178 880
        AN(ppriv);
179
180 880
        if (size > UINT_MAX)
181 0
                return (NULL);
182 880
        st = objallocwithnuke(wrk, stv, size, 0);
183 880
        if (st == NULL)
184 0
                return (NULL);
185 880
        assert(st->space >= size);
186 880
        st->len = size;
187 880
        *ppriv = (uintptr_t)st;
188 880
        return (st->ptr);
189 880
}
190
191
void v_matchproto_(storage_freebuf_t)
192 880
SML_FreeBuf(struct worker *wrk, const struct stevedore *stv, uintptr_t priv)
193
{
194
        struct storage *st;
195
196 880
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
197 880
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
198
199 880
        CAST_OBJ_NOTNULL(st, (void *)priv, STORAGE_MAGIC);
200 880
        sml_stv_free(stv, st);
201 880
}
202
203
/*---------------------------------------------------------------------
204
 */
205
206
static struct object *
207 6150261
sml_getobj(struct worker *wrk, struct objcore *oc)
208
{
209
        const struct stevedore *stv;
210
        struct object *o;
211
212 6150261
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
213 6150261
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
214 6150261
        stv = oc->stobj->stevedore;
215 6150261
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
216 6150261
        if (stv->sml_getobj != NULL)
217 11600
                return (stv->sml_getobj(wrk, oc));
218 6138661
        if (oc->stobj->priv == NULL)
219 0
                return (NULL);
220 6138661
        CAST_OBJ_NOTNULL(o, oc->stobj->priv, OBJECT_MAGIC);
221 6138661
        return (o);
222 6150261
}
223
224
static void v_matchproto_(objslim_f)
225 125459
sml_slim(struct worker *wrk, struct objcore *oc)
226
{
227
        const struct stevedore *stv;
228
        struct object *o;
229
        struct storage *st, *stn;
230
231 125459
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
232
233 125459
        stv = oc->stobj->stevedore;
234 125459
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
235 125459
        o = sml_getobj(wrk, oc);
236 125459
        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
237
238
#define OBJ_AUXATTR(U, l)                                       \
239
        do {                                                    \
240
                if (o->aa_##l != NULL) {                        \
241
                        sml_stv_free(stv, o->aa_##l);           \
242
                        o->aa_##l = NULL;                       \
243
                }                                               \
244
        } while (0);
245
#include "tbl/obj_attr.h"
246
247 158217
        VTAILQ_FOREACH_SAFE(st, &o->list, list, stn) {
248 32758
                CHECK_OBJ_NOTNULL(st, STORAGE_MAGIC);
249 32758
                VTAILQ_REMOVE(&o->list, st, list);
250 32758
                sml_stv_free(stv, st);
251 32758
        }
252
}
253
254
static void
255 111957
sml_bocfini(const struct stevedore *stv, struct boc *boc)
256
{
257
        struct storage *st;
258
259 111957
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
260 111957
        CHECK_OBJ_NOTNULL(boc, BOC_MAGIC);
261
262 111957
        if (boc->stevedore_priv == NULL ||
263 74166
            boc->stevedore_priv == trim_once)
264 103871
                return;
265
266
        /* Free any leftovers from Trim */
267 8086
        TAKE_OBJ_NOTNULL(st, &boc->stevedore_priv, STORAGE_MAGIC);
268 8086
        sml_stv_free(stv, st);
269 111957
}
270
271
/*
272
 * called in two cases:
273
 * - oc->boc == NULL: cache object on LRU freed
274
 * - oc->boc != NULL: cache object replaced for backend error
275
 */
276
static void v_matchproto_(objfree_f)
277 70261
sml_objfree(struct worker *wrk, struct objcore *oc)
278
{
279
        const struct stevedore *stv;
280
        struct storage *st;
281
        struct object *o;
282
283 70261
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
284 70261
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
285 70261
        stv = oc->stobj->stevedore;
286 70261
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
287 70261
        CAST_OBJ_NOTNULL(o, oc->stobj->priv, OBJECT_MAGIC);
288
289 70261
        sml_slim(wrk, oc);
290 70261
        st = o->objstore;
291 70261
        CHECK_OBJ_NOTNULL(st, STORAGE_MAGIC);
292 70261
        FINI_OBJ(o);
293
294 70261
        if (oc->boc != NULL)
295 840
                sml_bocfini(stv, oc->boc);
296 69421
        else if (stv->lru != NULL)
297 69417
                LRU_Remove(oc);
298
299 70261
        sml_stv_free(stv, st);
300
301 70261
        memset(oc->stobj, 0, sizeof oc->stobj);
302
303 70261
        wrk->stats->n_object--;
304 70261
}
305
306
static int v_matchproto_(objiterator_f)
307 94989
sml_iterator(struct worker *wrk, struct objcore *oc,
308
    void *priv, objiterate_f *func, int final)
309
{
310
        struct boc *boc;
311
        enum boc_state_e state;
312
        struct object *obj;
313
        struct storage *st;
314 94989
        struct storage *checkpoint = NULL;
315
        const struct stevedore *stv;
316 94989
        ssize_t checkpoint_len = 0;
317 94989
        ssize_t len = 0;
318 94989
        int ret = 0, ret2;
319
        ssize_t ol;
320
        ssize_t nl;
321
        ssize_t sl;
322
        void *p;
323
        ssize_t l;
324
        unsigned u;
325
326 94989
        obj = sml_getobj(wrk, oc);
327 94989
        CHECK_OBJ_NOTNULL(obj, OBJECT_MAGIC);
328 94989
        stv = oc->stobj->stevedore;
329 94989
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
330
331 94989
        boc = HSH_RefBoc(oc);
332
333 94989
        if (boc == NULL) {
334 136345
                VTAILQ_FOREACH_REVERSE_SAFE(
335
                    st, &obj->list, storagehead, list, checkpoint) {
336
337 72273
                        u = 0;
338 72273
                        if (VTAILQ_PREV(st, storagehead, list) == NULL)
339 65269
                                u |= OBJ_ITER_END;
340 72273
                        if (final)
341 30158
                                u |= OBJ_ITER_FLUSH;
342 72273
                        if (ret == 0 && st->len > 0)
343 72270
                                ret = func(priv, u, st->ptr, st->len);
344 72281
                        if (final) {
345 30158
                                VTAILQ_REMOVE(&obj->list, st, list);
346 30158
                                sml_stv_free(stv, st);
347 72271
                        } else if (ret)
348 1240
                                break;
349 71031
                }
350 65312
                return (ret);
351
        }
352
353 29675
        p = NULL;
354 29675
        l = 0;
355
356 29675
        u = 0;
357 29675
        if (boc->fetched_so_far == 0) {
358 3387
                ret = func(priv, OBJ_ITER_FLUSH, NULL, 0);
359 3387
                if (ret)
360 0
                        return (ret);
361 3387
        }
362 86533
        while (1) {
363 86533
                ol = len;
364 86533
                nl = ObjWaitExtend(wrk, oc, ol, &state);
365 86533
                if (state == BOS_FAILED) {
366 560
                        ret = -1;
367 560
                        break;
368
                }
369 85973
                if (nl == ol) {
370 28407
                        assert(state == BOS_FINISHED);
371 28407
                        break;
372
                }
373 57566
                assert(nl > ol);
374 57566
                Lck_Lock(&boc->mtx);
375 57566
                AZ(VTAILQ_EMPTY(&obj->list));
376 57566
                if (checkpoint == NULL) {
377 35120
                        st = VTAILQ_LAST(&obj->list, storagehead);
378 35120
                        sl = 0;
379 35120
                } else {
380 22446
                        st = checkpoint;
381 22446
                        sl = checkpoint_len;
382 22446
                        ol -= checkpoint_len;
383
                }
384 79307
                while (st != NULL) {
385 79311
                        if (st->len > ol) {
386 57570
                                p = st->ptr + ol;
387 57570
                                l = st->len - ol;
388 57570
                                len += l;
389 57570
                                break;
390
                        }
391 21741
                        ol -= st->len;
392 21741
                        assert(ol >= 0);
393 21741
                        nl -= st->len;
394 21741
                        assert(nl > 0);
395 21741
                        sl += st->len;
396 21741
                        st = VTAILQ_PREV(st, storagehead, list);
397 21741
                        if (final && checkpoint != NULL) {
398 19840
                                if (checkpoint == boc->stevedore_priv)
399 0
                                        boc->stevedore_priv = trim_once;
400
                                else
401 19840
                                        VTAILQ_REMOVE(&obj->list, checkpoint, list);
402 19840
                                sml_stv_free(stv, checkpoint);
403 19840
                        }
404 21741
                        checkpoint = st;
405 21741
                        checkpoint_len = sl;
406
                }
407 57576
                CHECK_OBJ_NOTNULL(obj, OBJECT_MAGIC);
408 57576
                CHECK_OBJ_NOTNULL(st, STORAGE_MAGIC);
409 57576
                st = VTAILQ_PREV(st, storagehead, list);
410 57576
                if (st != NULL && st->len == 0)
411 10095
                        st = NULL;
412 57576
                Lck_Unlock(&boc->mtx);
413 57576
                assert(l > 0 || state == BOS_FINISHED);
414 57576
                u = 0;
415 57576
                if (st == NULL || final)
416 56856
                        u |= OBJ_ITER_FLUSH;
417 57576
                if (st == NULL && state == BOS_FINISHED)
418 290
                        u |= OBJ_ITER_END;
419 57576
                ret = func(priv, u, p, l);
420 57576
                if (ret)
421 718
                        break;
422
        }
423 29685
        HSH_DerefBoc(wrk, oc);
424 29685
        if ((u & OBJ_ITER_END) == 0) {
425 29394
                ret2 = func(priv, OBJ_ITER_END, NULL, 0);
426 29394
                if (ret == 0)
427 28116
                        ret = ret2;
428 29394
        }
429 29685
        return (ret);
430 94997
}
431
432
/*--------------------------------------------------------------------
433
 */
434
435
static struct storage *
436 115997
objallocwithnuke(struct worker *wrk, const struct stevedore *stv, ssize_t size,
437
    int flags)
438
{
439 115997
        struct storage *st = NULL;
440
441 115997
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
442 115997
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
443
444 115997
        if (size > cache_param->fetch_maxchunksize) {
445 80
                if (!(flags & LESS_MEM_ALLOCED_IS_OK))
446 0
                        return (NULL);
447 80
                size = cache_param->fetch_maxchunksize;
448 80
        }
449
450 115997
        assert(size <= UINT_MAX);       /* field limit in struct storage */
451
452 115997
        do {
453
                /* try to allocate from it */
454 116317
                st = sml_stv_alloc(stv, size, flags);
455 116317
                if (st != NULL)
456 115797
                        break;
457
458
                /* no luck; try to free some space and keep trying */
459 520
                if (stv->lru == NULL)
460 0
                        break;
461 520
        } while (LRU_NukeOne(wrk, stv->lru));
462
463 115997
        CHECK_OBJ_ORNULL(st, STORAGE_MAGIC);
464 115997
        return (st);
465 115997
}
466
467
static int v_matchproto_(objgetspace_f)
468 2318637
sml_getspace(struct worker *wrk, struct objcore *oc, ssize_t *sz,
469
    uint8_t **ptr)
470
{
471
        struct object *o;
472
        struct storage *st;
473
474 2318637
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
475 2318637
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
476 2318637
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
477 2318637
        AN(sz);
478 2318637
        AN(ptr);
479 2318637
        if (*sz == 0)
480 2175374
                *sz = cache_param->fetch_chunksize;
481 2318637
        assert(*sz > 0);
482 2318637
        if (oc->boc->transit_buffer > 0)
483 19237
                *sz = vmin_t(ssize_t, *sz, oc->boc->transit_buffer);
484
485 2318637
        o = sml_getobj(wrk, oc);
486 2318637
        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
487 2318637
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
488
489 2318637
        st = VTAILQ_FIRST(&o->list);
490 2318637
        if (st != NULL && st->len < st->space) {
491 2208201
                *sz = st->space - st->len;
492 2208201
                *ptr = st->ptr + st->len;
493 2208201
                assert (*sz > 0);
494 2208201
                return (1);
495
        }
496
497 110436
        st = objallocwithnuke(wrk, oc->stobj->stevedore, *sz,
498
            LESS_MEM_ALLOCED_IS_OK);
499 110436
        if (st == NULL)
500 200
                return (0);
501
502 110236
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
503 110236
        Lck_Lock(&oc->boc->mtx);
504 110236
        VTAILQ_INSERT_HEAD(&o->list, st, list);
505 110236
        Lck_Unlock(&oc->boc->mtx);
506
507 110236
        *sz = st->space - st->len;
508 110236
        assert (*sz > 0);
509 110236
        *ptr = st->ptr + st->len;
510 110236
        return (1);
511 2318637
}
512
513
static void v_matchproto_(objextend_f)
514 2260630
sml_extend(struct worker *wrk, struct objcore *oc, ssize_t l)
515
{
516
        struct object *o;
517
        struct storage *st;
518
519 2260630
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
520 2260630
        assert(l > 0);
521
522 2260630
        o = sml_getobj(wrk, oc);
523 2260630
        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
524 2260630
        st = VTAILQ_FIRST(&o->list);
525 2260630
        CHECK_OBJ_NOTNULL(st, STORAGE_MAGIC);
526 2260630
        assert(st->len + l <= st->space);
527 2260630
        st->len += l;
528 2260630
}
529
530
static void v_matchproto_(objtrimstore_f)
531 74163
sml_trimstore(struct worker *wrk, struct objcore *oc)
532
{
533
        const struct stevedore *stv;
534
        struct storage *st, *st1;
535
        struct object *o;
536
537 74163
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
538 74163
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
539 74163
        CHECK_OBJ_NOTNULL(oc->boc, BOC_MAGIC);
540
541 74163
        stv = oc->stobj->stevedore;
542 74163
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
543
544 74163
        if (oc->boc->stevedore_priv != NULL)
545 0
                WRONG("sml_trimstore already called");
546 74163
        oc->boc->stevedore_priv = trim_once;
547
548 74163
        if (stv->sml_free == NULL)
549 0
                return;
550
551 74163
        o = sml_getobj(wrk, oc);
552 74163
        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
553 74163
        st = VTAILQ_FIRST(&o->list);
554
555 74163
        if (st == NULL)
556 0
                return;
557
558 74163
        if (st->len == 0) {
559 320
                Lck_Lock(&oc->boc->mtx);
560 320
                VTAILQ_REMOVE(&o->list, st, list);
561 320
                Lck_Unlock(&oc->boc->mtx);
562
                /* sml_bocdone frees this */
563 320
                oc->boc->stevedore_priv = st;
564 320
                return;
565
        }
566
567 73843
        if (st->space - st->len < 512)
568 66079
                return;
569
570 7764
        st1 = sml_stv_alloc(stv, st->len, 0);
571 7764
        if (st1 == NULL)
572 0
                return;
573 7764
        assert(st1->space >= st->len);
574
575 7764
        memcpy(st1->ptr, st->ptr, st->len);
576 7764
        st1->len = st->len;
577 7764
        Lck_Lock(&oc->boc->mtx);
578 7764
        VTAILQ_REMOVE(&o->list, st, list);
579 7764
        VTAILQ_INSERT_HEAD(&o->list, st1, list);
580 7764
        Lck_Unlock(&oc->boc->mtx);
581
        /* sml_bocdone frees this */
582 7764
        oc->boc->stevedore_priv = st;
583 74163
}
584
585
static void v_matchproto_(objbocdone_f)
586 111119
sml_bocdone(struct worker *wrk, struct objcore *oc, struct boc *boc)
587
{
588
        const struct stevedore *stv;
589
590 111119
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
591 111119
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
592 111119
        CHECK_OBJ_NOTNULL(boc, BOC_MAGIC);
593 111119
        stv = oc->stobj->stevedore;
594 111119
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
595
596 111119
        sml_bocfini(stv, boc);
597
598 111119
        if (stv->lru != NULL) {
599 109558
                if (isnan(wrk->lastused))
600 0
                        wrk->lastused = VTIM_real();
601 109558
                LRU_Add(oc, wrk->lastused);     // approx timestamp is OK
602 109558
        }
603 111119
}
604
605
static const void * v_matchproto_(objgetattr_f)
606 862559
sml_getattr(struct worker *wrk, struct objcore *oc, enum obj_attr attr,
607
   ssize_t *len)
608
{
609
        struct object *o;
610
        ssize_t dummy;
611
612 862559
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
613
614 862559
        if (len == NULL)
615 529355
                len = &dummy;
616 862559
        o = sml_getobj(wrk, oc);
617 862559
        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
618
619 862559
        switch (attr) {
620
                /* Fixed size attributes */
621
#define OBJ_FIXATTR(U, l, s)                                            \
622
        case OA_##U:                                                    \
623
                *len = sizeof o->fa_##l;                                \
624
                return (o->fa_##l);
625
#include "tbl/obj_attr.h"
626
627
                /* Variable size attributes */
628
#define OBJ_VARATTR(U, l)                                               \
629
        case OA_##U:                                                    \
630
                if (o->va_##l == NULL)                                  \
631
                        return (NULL);                                  \
632
                *len = o->va_##l##_len;                                 \
633
                return (o->va_##l);
634
#include "tbl/obj_attr.h"
635
636
                /* Auxiliary attributes */
637
#define OBJ_AUXATTR(U, l)                                               \
638
        case OA_##U:                                                    \
639
                if (o->aa_##l == NULL)                                  \
640
                        return (NULL);                                  \
641
                CHECK_OBJ_NOTNULL(o->aa_##l, STORAGE_MAGIC);            \
642
                *len = o->aa_##l->len;                                  \
643
                return (o->aa_##l->ptr);
644
#include "tbl/obj_attr.h"
645
646
        default:
647
                break;
648
        }
649 0
        WRONG("Unsupported OBJ_ATTR");
650 862559
}
651
652
static void * v_matchproto_(objsetattr_f)
653 414667
sml_setattr(struct worker *wrk, struct objcore *oc, enum obj_attr attr,
654
    ssize_t len, const void *ptr)
655
{
656
        struct object *o;
657 414667
        void *retval = NULL;
658
        struct storage *st;
659
660 414667
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
661
662 414667
        o = sml_getobj(wrk, oc);
663 414667
        CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC);
664 414667
        st = o->objstore;
665
666 414667
        switch (attr) {
667
                /* Fixed size attributes */
668
#define OBJ_FIXATTR(U, l, s)                                            \
669
        case OA_##U:                                                    \
670
                assert(len == sizeof o->fa_##l);                        \
671
                retval = o->fa_##l;                                     \
672
                break;
673
#include "tbl/obj_attr.h"
674
675
                /* Variable size attributes */
676
#define OBJ_VARATTR(U, l)                                               \
677
        case OA_##U:                                                    \
678
                if (o->va_##l##_len > 0) {                              \
679
                        AN(o->va_##l);                                  \
680
                        assert(len == o->va_##l##_len);                 \
681
                        retval = o->va_##l;                             \
682
                } else if (len > 0) {                                   \
683
                        assert(len <= UINT_MAX);                        \
684
                        assert(st->len + len <= st->space);             \
685
                        o->va_##l = st->ptr + st->len;                  \
686
                        st->len += len;                                 \
687
                        o->va_##l##_len = len;                          \
688
                        retval = o->va_##l;                             \
689
                }                                                       \
690
                break;
691
#include "tbl/obj_attr.h"
692
693
                /* Auxiliary attributes */
694
#define OBJ_AUXATTR(U, l)                                               \
695
        case OA_##U:                                                    \
696
                if (o->aa_##l != NULL) {                                \
697
                        CHECK_OBJ_NOTNULL(o->aa_##l, STORAGE_MAGIC);    \
698
                        assert(len == o->aa_##l->len);                  \
699
                        retval = o->aa_##l->ptr;                        \
700
                        break;                                          \
701
                }                                                       \
702
                if (len == 0)                                           \
703
                        break;                                          \
704
                o->aa_##l = objallocwithnuke(wrk, oc->stobj->stevedore, \
705
                    len, 0);                                            \
706
                if (o->aa_##l == NULL)                                  \
707
                        break;                                          \
708
                CHECK_OBJ_NOTNULL(o->aa_##l, STORAGE_MAGIC);            \
709
                assert(len <= o->aa_##l->space);                        \
710
                o->aa_##l->len = len;                                   \
711
                retval = o->aa_##l->ptr;                                \
712
                break;
713
#include "tbl/obj_attr.h"
714
715
        default:
716 0
                WRONG("Unsupported OBJ_ATTR");
717
                break;
718
        }
719
720 414667
        if (retval != NULL && ptr != NULL)
721 14760
                memcpy(retval, ptr, len);
722 414673
        return (retval);
723
}
724
725
const struct obj_methods SML_methods = {
726
        .objfree        = sml_objfree,
727
        .objiterator    = sml_iterator,
728
        .objgetspace    = sml_getspace,
729
        .objextend      = sml_extend,
730
        .objtrimstore   = sml_trimstore,
731
        .objbocdone     = sml_bocdone,
732
        .objslim        = sml_slim,
733
        .objgetattr     = sml_getattr,
734
        .objsetattr     = sml_setattr,
735
        .objtouch       = LRU_Touch,
736
};
737
738
static void
739 120
sml_panic_st(struct vsb *vsb, const char *hd, const struct storage *st)
740
{
741 240
        VSB_printf(vsb, "%s = %p {priv=%p, ptr=%p, len=%u, space=%u},\n",
742 120
            hd, st, st->priv, st->ptr, st->len, st->space);
743 120
}
744
745
void
746 80
SML_panic(struct vsb *vsb, const struct objcore *oc)
747
{
748
        struct object *o;
749
        struct storage *st;
750
751 80
        VSB_printf(vsb, "Simple = %p,\n", oc->stobj->priv);
752 80
        if (oc->stobj->priv == NULL)
753 0
                return;
754 80
        o = oc->stobj->priv;
755 80
        PAN_CheckMagic(vsb, o, OBJECT_MAGIC);
756 80
        sml_panic_st(vsb, "Obj", o->objstore);
757
758
#define OBJ_FIXATTR(U, l, sz) \
759
        VSB_printf(vsb, "%s = ", #U); \
760
        VSB_quote(vsb, (const void*)o->fa_##l, sz, VSB_QUOTE_HEX); \
761
        VSB_printf(vsb, ",\n");
762
763
#define OBJ_VARATTR(U, l) \
764
        VSB_printf(vsb, "%s = {len=%u, ptr=%p},\n", \
765
            #U, o->va_##l##_len, o->va_##l);
766
767
#define OBJ_AUXATTR(U, l)                                               \
768
        do {                                                            \
769
                if (o->aa_##l != NULL) sml_panic_st(vsb, #U, o->aa_##l);\
770
        } while(0);
771
772
#include "tbl/obj_attr.h"
773
774 120
        VTAILQ_FOREACH(st, &o->list, list) {
775 40
                sml_panic_st(vsb, "Body", st);
776 40
        }
777
}