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 1948
ssy_objfree(struct worker *wrk, struct objcore *oc)
80
{
81
82 1948
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
83
        // object is on workspace, nothing to free here
84 1948
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
85 1948
        memset(oc->stobj, 0, sizeof *oc->stobj);
86 1948
        wrk->stats->n_object--;
87 1948
}
88
89
static struct ssy_st *
90 3644
ssy_st_alloc(struct ssy *ssy)
91
{
92
        struct ssy_st *st;
93 3644
        const size_t cap = 8;                   // XXX GOOD?
94 3644
        const size_t sz = SSY_ST_SIZE(cap);
95
96 3644
        CHECK_OBJ_NOTNULL(ssy, SSY_MAGIC);
97 3644
        st = WS_Alloc(ssy->ws, sz);
98 3644
        if (st == NULL)
99 0
                return (st);
100 3644
        INIT_OBJ(st, SSY_ST_MAGIC);
101 3644
        VSCARAB_INIT(&st->scarab, cap);
102 3644
        VSTAILQ_INSERT_TAIL(&ssy->head, st, list);
103 3644
        return (st);
104 3644
}
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 3536
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 3536
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
119 3536
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
120 3536
        CAST_OBJ_NOTNULL(ssy, oc->stobj->priv, SSY_MAGIC);
121 3536
        (void) sz;
122
123 3536
        st = VSTAILQ_LAST(&ssy->head, ssy_st, list);
124 3536
        CHECK_OBJ_NOTNULL(st, SSY_ST_MAGIC);
125 3536
        CHECK_OBJ_NOTNULL(&st->scarab, VSCARAB_MAGIC);
126
127 3536
        if (st->scarab.used == st->scarab.capacity)
128 1696
                st = ssy_st_alloc(ssy);
129 3536
        if (st == NULL) {
130 0
                stats->c_getspace_fail++;
131 0
                return (0);
132
        }
133 3536
        *ptr = (void*)(&st->scarab);
134 3536
        stats->c_getspace_success++;
135 3536
        return (1);
136 3536
}
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 3445
ssy_ai_lease(struct worker *wrk, vai_hdl vhdl, struct vscarab *dst)
153
{
154
        struct ssy_hdl *hdl;
155
        struct viov *dviov;
156 3445
        int r = 0;
157
158 3445
        (void) wrk;
159 3445
        CAST_VAI_HDL_NOTNULL(hdl, vhdl, SSY_HDL_MAGIC);
160 3445
        VSCARAB_CHECK_NOTNULL(dst);
161
162 3445
        if (hdl->st == NULL) {
163 1717
                dst->flags |= VSCARAB_F_END;
164 1717
                return (r);
165
        }
166
167 1728
        CHECK_OBJ(hdl->st, SSY_ST_MAGIC);
168 1728
        VSCARAB_CHECK(&hdl->st->scarab);
169 1728
        AN(hdl->viov);
170
171 1728
        do {
172 24600
                VSCARAB_FOREACH_RESUME(hdl->viov, &hdl->st->scarab) {
173 21248
                        dviov = VSCARAB_GET(dst);
174 21248
                        if (dviov == NULL)
175 0
                                break;
176 21248
                        *dviov = *hdl->viov;
177 21248
                        dviov->lease = VAI_LEASE_NORET;
178 21248
                        r++;
179 21248
                }
180 3352
                if (hdl->viov == NULL) {
181 3352
                        hdl->st = VSTAILQ_NEXT(hdl->st, list);
182 3352
                        if (hdl->st == NULL)
183 1728
                                dst->flags |= VSCARAB_F_END;
184
                        else
185 1624
                                hdl->viov = &hdl->st->scarab.s[0];
186 3352
                }
187 3352
        } while (hdl->viov != NULL);
188
189 1728
        return (r);
190 3445
}
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 1728
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 1728
        (void) wrk;
226 1728
        CAST_VAI_HDL_NOTNULL(hdl, vhdl, SSY_HDL_MAGIC);
227 1728
        VSCARET_CHECK_NOTNULL(scaret);
228 22976
        VSCARET_FOREACH(p, scaret) {
229 21248
                 if (*p != VAI_LEASE_NORET)
230 0
                        free (lease2ptr(*p));
231 21248
        }
232 1728
}
233
234
static void v_matchproto_(vai_fini_f)
235 1728
ssy_ai_fini(struct worker *wrk, vai_hdl *vai_hdlp)
236
{
237
        struct ssy_hdl *hdl;
238
239 1728
        (void)wrk;
240 1728
        AN(vai_hdlp);
241 1728
        CAST_VAI_HDL_NOTNULL(hdl, *vai_hdlp, SSY_HDL_MAGIC);
242 1728
        *vai_hdlp = NULL;
243 1728
}
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 5836
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 5836
        uint64_t l = 0;
268
269 5836
        (void)wrk;
270 5836
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
271
272 5836
        if (attr == OA_FLAGS) {
273 1940
                AZ(len);
274 1940
                return (&flags);
275
        }
276
277 3896
        if (attr != OA_LEN)
278 1936
                return (NULL);
279
280 1960
        AN(len);
281 1960
        CAST_OBJ_NOTNULL(ssy, oc->stobj->priv, SSY_MAGIC);
282 1960
        assert(attr == OA_LEN);
283
284 1960
        if ((ssy->flags & SSY_F_LEN) == 0) {
285 5576
                VSTAILQ_FOREACH(st, &ssy->head, list) {
286 25820
                        VSCARAB_FOREACH(viov, &st->scarab)
287 22184
                                l += viov->iov.iov_len;
288 3636
                }
289 1940
                vbe64enc(ssy->len_be, l);
290 1940
                ssy->flags |= SSY_F_LEN;
291 1940
        }
292 1960
        *len = sizeof ssy->len_be;
293 1960
        return (ssy->len_be);
294 5836
}
295
296
static vai_hdl v_matchproto_(vai_init_f)
297 1728
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 1728
        (void)wrk;
304 1728
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
305 1728
        CAST_OBJ_NOTNULL(ssy, oc->stobj->priv, SSY_MAGIC);
306 1728
        (void)notify;
307 1728
        (void)notify_priv;
308
309 1728
        if (ws == NULL)
310 1728
                ws = ssy->ws;
311 1728
        hdl = WS_Alloc(ws, sizeof *hdl);
312 1728
        if (hdl == NULL)
313 0
                return (NULL);
314
315 1728
        INIT_VAI_HDL(hdl, SSY_HDL_MAGIC);
316 1728
        hdl->st = VSTAILQ_FIRST(&ssy->head);
317 1728
        CHECK_OBJ(hdl->st, SSY_ST_MAGIC);
318 1728
        VSCARAB_CHECK(&hdl->st->scarab);
319 1728
        hdl->viov = &hdl->st->scarab.s[0];
320
321 1728
        AN(hdl);
322 1728
        hdl->preamble.vai_lease = ssy_ai_lease;
323 1728
        hdl->preamble.vai_buffer = ssy_ai_buffer;
324 1728
        hdl->preamble.vai_return = ssy_ai_return;
325 1728
        hdl->preamble.vai_fini = ssy_ai_fini;
326 1728
        return (hdl);
327 1728
}
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 1958
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 1958
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
351 1958
        CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
352 1958
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
353
354 1958
        req = THR_GetRequest();
355
356 1958
        if (wsl != 0 || req == NULL)
357 4
                goto wrong_ctx;
358
359 1956
        CHECK_OBJ(req, REQ_MAGIC);
360 1956
        if (oc != req->objcore)
361 4
                goto wrong_ctx;
362
363 1952
        ssy = WS_Alloc(req->ws, sizeof *ssy);
364 1952
        if (ssy == NULL)
365 4
                goto err;
366 1948
        INIT_OBJ(ssy, SSY_MAGIC);
367 1948
        ssy->ws = req->ws;
368 1948
        VSTAILQ_INIT(&ssy->head);
369 1948
        if (ssy_st_alloc(ssy) == NULL)
370 0
                goto err;
371 1948
        oc->stobj->stevedore = stv;
372 1948
        oc->stobj->priv = ssy;
373 1948
        stats->c_allocobj_success++;
374 1948
        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 12
        stats->c_allocobj_fail++;
380 12
        return (0);
381 1960
}
382
383
static void v_matchproto_(storage_close_f)
384 7720
ssy_close(const struct stevedore *st, int warn)
385
{
386
387 7720
        (void)st;
388
389 7720
        ASSERT_CLI();
390 7720
        if (warn)
391 3860
                return;
392 3860
        AN(refcnt);
393 3860
        if (--refcnt > 0)
394 0
                return;
395
396 3860
        VSC_ssy_Destroy(&vsc_seg);
397 3860
        AZ(vsc_seg);
398 3860
        stats = NULL;
399 7720
}
400
401
static void v_matchproto_(storage_open_f)
402 3903
ssy_open(struct stevedore *st)
403
{
404
405 3903
        (void)st;
406 3903
        ASSERT_CLI();
407 3903
        if (refcnt++ > 0)
408 0
                return;
409
410 3903
        stats = VSC_ssy_New(NULL, &vsc_seg, "synth");
411 3903
        AN(stats);
412 3903
}
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
};