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