vinyl-cache/bin/vinyld/storage/storage_synth.c
0
/*-
1
 * Copyright 2025 UPLEX - Nils Goroll Systemoptimierung
2
 * All rights reserved.
3
 *
4
 * Author: Nils Goroll <slink@uplex.de>
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
 * Special-purpose stevedore for use with transient synth objects as those
30
 * created from vcl_synth {}: Does not copy, only references on-workspace
31
 * data
32
 */
33
34
/*lint --e{801} */
35
36
#include "config.h"
37
38
#include <stdlib.h>
39
40
#include "cache/cache_int.h"
41
42
#include "cache/cache_obj.h"
43
#include "cache/cache_objhead.h"
44
45
#include "storage/storage.h"
46
#include "storage/storage_simple.h"
47
#include "storage/storage_vai.h"
48
49
#include "VSC_ssy.h"
50
51
#include "vend.h"
52
53
struct ssy_st {
54
        unsigned                        magic;
55
#define SSY_ST_MAGIC                    0x236918b3
56
        VSTAILQ_ENTRY(ssy_st)           list;
57
        struct vscarab                  scarab;
58
};
59
60
//lint -emacro({413}, SSY_ST_SIZE)
61
#define SSY_ST_SIZE(cap) (offsetof(struct ssy_st, scarab) + VSCARAB_SIZE(cap))
62
63
struct ssy {
64
        unsigned                        magic;
65
#define SSY_MAGIC                       0xfb41f362
66
        unsigned                        flags;
67
#define SSY_F_LEN                       1
68
        struct ws                       *ws;
69
        VSTAILQ_HEAD(,ssy_st)           head;
70
        // getattr needs to return *pointer* to len as big endian
71
        uint8_t                         len_be[sizeof(uint64_t)];
72
};
73
74
static struct VSC_ssy *stats = NULL;
75
static struct vsc_seg *vsc_seg = NULL;
76
static unsigned refcnt = 0;
77
78
static void v_matchproto_(objfree_f)
79 2127
ssy_objfree(struct worker *wrk, struct objcore *oc)
80
{
81
82 2127
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
83
        // object is on workspace, nothing to free here
84 2127
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
85 2127
        memset(oc->stobj, 0, sizeof *oc->stobj);
86 2127
        wrk->stats->n_object--;
87 2127
}
88
89
static struct ssy_st *
90 4004
ssy_st_alloc(struct ssy *ssy)
91
{
92
        struct ssy_st *st;
93 4004
        const size_t cap = 8;                   // XXX GOOD?
94 4004
        const size_t sz = SSY_ST_SIZE(cap);
95
96 4004
        CHECK_OBJ_NOTNULL(ssy, SSY_MAGIC);
97 4004
        st = WS_Alloc(ssy->ws, sz);
98 4004
        if (st == NULL)
99 0
                return (st);
100 4004
        INIT_OBJ(st, SSY_ST_MAGIC);
101 4004
        VSCARAB_INIT(&st->scarab, cap);
102 4004
        VSTAILQ_INSERT_TAIL(&ssy->head, st, list);
103 4004
        return (st);
104 4004
}
105
106
/*
107
 * deliberate API violation: does not return space, but a VSCARAB
108
 *
109
 * XXX own stevedore method?
110
 */
111
static int v_matchproto_(objgetspace_f)
112 3896
ssy_getspace(struct worker *wrk, struct objcore *oc, ssize_t *sz,
113
    uint8_t **ptr)
114
{
115
        struct ssy *ssy;
116
        struct ssy_st *st;
117
118 3896
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
119 3896
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
120 3896
        CAST_OBJ_NOTNULL(ssy, oc->stobj->priv, SSY_MAGIC);
121 3896
        (void) sz;
122
123 3896
        st = VSTAILQ_LAST(&ssy->head, ssy_st, list);
124 3896
        CHECK_OBJ_NOTNULL(st, SSY_ST_MAGIC);
125 3896
        CHECK_OBJ_NOTNULL(&st->scarab, VSCARAB_MAGIC);
126
127 3896
        if (st->scarab.used == st->scarab.capacity)
128 1876
                st = ssy_st_alloc(ssy);
129 3896
        if (st == NULL) {
130 0
                stats->c_getspace_fail++;
131 0
                return (0);
132
        }
133 3896
        *ptr = (void*)(&st->scarab);
134 3896
        stats->c_getspace_success++;
135 3896
        return (1);
136 3896
}
137
138
/*
139
 * VAI for ssy is really simple because we never block, hence need no
140
 * notification
141
 */
142
143
struct ssy_hdl {
144
        struct vai_hdl_preamble preamble;
145
#define SSY_HDL_MAGIC           0x07a0be62
146
        //struct ssy            *ssy;
147
        struct ssy_st           *st;
148
        struct viov             *viov;
149
};
150
151
static int
152 3804
ssy_ai_lease(struct worker *wrk, vai_hdl vhdl, struct vscarab *dst)
153
{
154
        struct ssy_hdl *hdl;
155
        struct viov *dviov;
156 3804
        int r = 0;
157
158 3804
        (void) wrk;
159 3804
        CAST_VAI_HDL_NOTNULL(hdl, vhdl, SSY_HDL_MAGIC);
160 3804
        VSCARAB_CHECK_NOTNULL(dst);
161
162 3804
        if (hdl->st == NULL) {
163 1896
                dst->flags |= VSCARAB_F_END;
164 1896
                return (r);
165
        }
166
167 1908
        CHECK_OBJ(hdl->st, SSY_ST_MAGIC);
168 1908
        VSCARAB_CHECK(&hdl->st->scarab);
169 1908
        AN(hdl->viov);
170
171 1908
        do {
172 27300
                VSCARAB_FOREACH_RESUME(hdl->viov, &hdl->st->scarab) {
173 23588
                        dviov = VSCARAB_GET(dst);
174 23588
                        if (dviov == NULL)
175 0
                                break;
176 23588
                        *dviov = *hdl->viov;
177 23588
                        dviov->lease = VAI_LEASE_NORET;
178 23588
                        r++;
179 23588
                }
180 3712
                if (hdl->viov == NULL) {
181 3712
                        hdl->st = VSTAILQ_NEXT(hdl->st, list);
182 3712
                        if (hdl->st == NULL)
183 1908
                                dst->flags |= VSCARAB_F_END;
184
                        else
185 1804
                                hdl->viov = &hdl->st->scarab.s[0];
186 3712
                }
187 3712
        } while (hdl->viov != NULL);
188
189 1908
        return (r);
190 3804
}
191
192
// just malloc
193
static int
194 0
ssy_ai_buffer(struct worker *wrk, vai_hdl vhdl, struct vscarab *scarab)
195
{
196
        struct ssy_hdl *hdl;
197
        struct viov *vio;
198
        void *p;
199 0
        int r = 0;
200
201 0
        (void) wrk;
202 0
        CAST_VAI_HDL_NOTNULL(hdl, vhdl, SSY_HDL_MAGIC);
203
204 0
        VSCARAB_FOREACH(vio, scarab)
205 0
                if (vio->iov.iov_len == 0 || vio->iov.iov_len > UINT_MAX)
206 0
                        return (-EINVAL);
207
208 0
        VSCARAB_FOREACH(vio, scarab) {
209 0
                p = malloc(vio->iov.iov_len);
210 0
                AN(p);
211 0
                vio->iov.iov_base = p;
212 0
                vio->lease = ptr2lease(p);
213 0
                r++;
214 0
        }
215 0
        return (r);
216 0
}
217
218
// just free buffers
219
static void v_matchproto_(vai_return_f)
220 1908
ssy_ai_return(struct worker *wrk, vai_hdl vhdl, struct vscaret *scaret)
221
{
222
        struct ssy_hdl *hdl;
223
        viov_lease_t *p;
224
225 1908
        (void) wrk;
226 1908
        CAST_VAI_HDL_NOTNULL(hdl, vhdl, SSY_HDL_MAGIC);
227 1908
        VSCARET_CHECK_NOTNULL(scaret);
228 25496
        VSCARET_FOREACH(p, scaret) {
229 23588
                 if (*p != VAI_LEASE_NORET)
230 0
                        free (lease2ptr(*p));
231 23588
        }
232 1908
}
233
234
static void v_matchproto_(vai_fini_f)
235 1908
ssy_ai_fini(struct worker *wrk, vai_hdl *vai_hdlp)
236
{
237
        struct ssy_hdl *hdl;
238
239 1908
        (void)wrk;
240 1908
        AN(vai_hdlp);
241 1908
        CAST_VAI_HDL_NOTNULL(hdl, *vai_hdlp, SSY_HDL_MAGIC);
242 1908
        *vai_hdlp = NULL;
243 1908
}
244
245
static void * v_matchproto_(objsetattr_f)
246 0
ssy_setattr(struct worker *wrk, struct objcore *oc, enum obj_attr attr,
247
    ssize_t len, const void *ptr)
248
{
249
        static uint64_t ignored;
250
251 0
        (void)wrk;
252 0
        (void)oc;
253 0
        assert(attr == OA_LEN);
254 0
        (void)len;
255 0
        (void)ptr;
256 0
        return (&ignored);
257
}
258
259
static const void * v_matchproto_(objgetattr_f)
260 6376
ssy_getattr(struct worker *wrk, struct objcore *oc, enum obj_attr attr,
261
   ssize_t *len)
262
{
263
        struct ssy *ssy;
264
        struct ssy_st *st;
265
        struct viov *viov;
266
        static const uint8_t flags = 0;
267 6376
        uint64_t l = 0;
268
269 6376
        (void)wrk;
270 6376
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
271
272 6376
        if (attr == OA_FLAGS) {
273 2120
                AZ(len);
274 2120
                return (&flags);
275
        }
276
277 4256
        if (attr != OA_LEN)
278 2116
                return (NULL);
279
280 2140
        AN(len);
281 2140
        CAST_OBJ_NOTNULL(ssy, oc->stobj->priv, SSY_MAGIC);
282 2140
        assert(attr == OA_LEN);
283
284 2140
        if ((ssy->flags & SSY_F_LEN) == 0) {
285 6116
                VSTAILQ_FOREACH(st, &ssy->head, list) {
286 28520
                        VSCARAB_FOREACH(viov, &st->scarab)
287 24524
                                l += viov->iov.iov_len;
288 3996
                }
289 2120
                vbe64enc(ssy->len_be, l);
290 2120
                ssy->flags |= SSY_F_LEN;
291 2120
        }
292 2140
        *len = sizeof ssy->len_be;
293 2140
        return (ssy->len_be);
294 6376
}
295
296
static vai_hdl v_matchproto_(vai_init_f)
297 1908
ssy_ai_init(struct worker *wrk, struct objcore *oc, struct ws *ws,
298
    vai_notify_cb *notify, void *notify_priv)
299
{
300
        struct ssy_hdl *hdl;
301
        struct ssy *ssy;
302
303 1908
        (void)wrk;
304 1908
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
305 1908
        CAST_OBJ_NOTNULL(ssy, oc->stobj->priv, SSY_MAGIC);
306 1908
        (void)notify;
307 1908
        (void)notify_priv;
308
309 1908
        if (ws == NULL)
310 1908
                ws = ssy->ws;
311 1908
        hdl = WS_Alloc(ws, sizeof *hdl);
312 1908
        if (hdl == NULL)
313 0
                return (NULL);
314
315 1908
        INIT_VAI_HDL(hdl, SSY_HDL_MAGIC);
316 1908
        hdl->st = VSTAILQ_FIRST(&ssy->head);
317 1908
        CHECK_OBJ(hdl->st, SSY_ST_MAGIC);
318 1908
        VSCARAB_CHECK(&hdl->st->scarab);
319 1908
        hdl->viov = &hdl->st->scarab.s[0];
320
321 1908
        AN(hdl);
322 1908
        hdl->preamble.vai_lease = ssy_ai_lease;
323 1908
        hdl->preamble.vai_buffer = ssy_ai_buffer;
324 1908
        hdl->preamble.vai_return = ssy_ai_return;
325 1908
        hdl->preamble.vai_fini = ssy_ai_fini;
326 1908
        return (hdl);
327 1908
}
328
329
static const struct obj_methods ssy_methods = {
330
        .objfree        = ssy_objfree,
331
        .objiterator    = SML_iterator,
332
        .objgetspace    = ssy_getspace,
333
        .objextend      = NULL,         // don't call, asserts in cache_obj.c
334
        .objtrimstore   = NULL,
335
        .objbocdone     = NULL,
336
        .objslim        = NULL,
337
        .objgetattr     = ssy_getattr,  // only OA_LEN, OA_FLAGS, others not
338
        .objsetattr     = ssy_setattr,  // only OA_LEN, ignores value
339
        .objtouch       = NULL,
340
        .vai_init       = ssy_ai_init
341
};
342
343
static int v_matchproto_(storage_allocobj_f)
344 2136
ssy_allocobj(struct worker *wrk, const struct stevedore *stv,
345
    struct objcore *oc, unsigned wsl)
346
{
347
        struct req *req;
348
        struct ssy *ssy;
349
350 2136
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
351 2136
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
352 2136
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
353
354 2136
        req = THR_GetRequest();
355
356 2136
        if (wsl != 0 || req == NULL)
357 4
                goto wrong_ctx;
358
359 2132
        CHECK_OBJ(req, REQ_MAGIC);
360 2132
        if (oc != req->objcore)
361 4
                goto wrong_ctx;
362
363 2128
        ssy = WS_Alloc(req->ws, sizeof *ssy);
364 2128
        if (ssy == NULL)
365 0
                goto err;
366 2128
        INIT_OBJ(ssy, SSY_MAGIC);
367 2128
        ssy->ws = req->ws;
368 2128
        VSTAILQ_INIT(&ssy->head);
369 2128
        if (ssy_st_alloc(ssy) == NULL)
370 0
                goto err;
371 2128
        oc->stobj->stevedore = stv;
372 2128
        oc->stobj->priv = ssy;
373 2128
        stats->c_allocobj_success++;
374 2128
        return (1);
375
    wrong_ctx:
376 8
        VSLb(wrk->vsl, SLT_Error,
377
            "synth storage can only be used for resp.storage in vcl_synth {}");
378
    err:
379 8
        stats->c_allocobj_fail++;
380 8
        return (0);
381 2136
}
382
383
static void v_matchproto_(storage_close_f)
384 7688
ssy_close(const struct stevedore *st, int warn)
385
{
386
387 7688
        (void)st;
388
389 7688
        ASSERT_CLI();
390 7688
        if (warn)
391 3844
                return;
392 3844
        AN(refcnt);
393 3844
        if (--refcnt > 0)
394 0
                return;
395
396 3844
        VSC_ssy_Destroy(&vsc_seg);
397 3844
        AZ(vsc_seg);
398 3844
        stats = NULL;
399 7688
}
400
401
static void v_matchproto_(storage_open_f)
402 3880
ssy_open(struct stevedore *st)
403
{
404
405 3880
        (void)st;
406 3880
        ASSERT_CLI();
407 3880
        if (refcnt++ > 0)
408 0
                return;
409
410 3880
        stats = VSC_ssy_New(NULL, &vsc_seg, "synth");
411 3880
        AN(stats);
412 3880
}
413
414
const struct stevedore ssy_stevedore = {
415
        .magic          =       STEVEDORE_MAGIC,
416
        .name           =       "synth",
417
        .vclname        =       "storage.synth",
418
        .ident          =       "synth",
419
        .open           =       ssy_open,
420
        .close          =       ssy_close,
421
        .allocobj       =       ssy_allocobj,
422
        .methods        =       &ssy_methods
423
};