vinyl-cache/bin/vinyld/storage/storage_debug.c
0
/*-
1
 * Copyright 2021,2023 UPLEX - Nils Goroll Systemoptimierung
2
 * All rights reserved.
3
 *
4
 * Author: Nils Goroll <nils.goroll@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
 * debug helper storage based on malloc
30
 */
31
32
#include "config.h"
33
34
#include "cache/cache_int.h"
35
#include "cache/cache_obj.h"
36
#include "common/heritage.h"
37
38
#include <stdio.h>
39
#include <stdlib.h>
40
41
#include "storage/storage.h"
42
#include "storage/storage_simple.h"
43
44
#include "vtim.h"
45
#include "vnum.h"
46
47
/*
48
 * if smd was to have its own configuration, we would have to wrap all function
49
 * pointers from the actual storage implementation (sma). To avoid these
50
 * complications, we limit to one smd instance and use statics.
51
 */
52
static vtim_dur dopen = 0.0;
53
static unsigned count = 0;
54
static ssize_t max_size = 0;
55
56
/* returns one byte less than requested */
57
static int v_matchproto_(objgetspace_f)
58 16
smd_lsp_getspace(struct worker *wrk, struct objcore *oc, ssize_t *sz,
59
    uint8_t **ptr)
60
{
61 16
        AN(sz);
62 16
        if (*sz > 2)
63 8
                (*sz)--;
64 16
        return (SML_methods.objgetspace(wrk, oc, sz, ptr));
65
}
66
67
/*
68
 * returns max_size at most, then fails
69
 *
70
 * relies on the actual storage implementation to not use priv2
71
 */
72
static int v_matchproto_(objgetspace_f)
73 32
smd_max_getspace(struct worker *wrk, struct objcore *oc, ssize_t *sz,
74
    uint8_t **ptr)
75
{
76
        ssize_t used;
77
        int r;
78
79 32
        AN(sz);
80 32
        used = (ssize_t)oc->stobj->priv2;
81
82 32
        VSLb(wrk->vsl, SLT_Debug, "-sdebug getspace: %zd/%zd", used, max_size);
83
84 32
        if (used >= max_size) {
85 12
                VSLb(wrk->vsl, SLT_Storage, "-sdebug: max_size=%zd reached", max_size);
86 12
                return (0);
87
        }
88
89 20
        assert(used < max_size);
90 20
        *sz = vmin_t(ssize_t, *sz, max_size - used);
91
92 20
        r = SML_methods.objgetspace(wrk, oc, sz, ptr);
93 20
        return (r);
94 32
}
95
96
static void v_matchproto_(objextend_f)
97 20
smd_max_extend(struct worker *wrk, struct objcore *oc, ssize_t l)
98
{
99
100 20
        assert(l > 0);
101 20
        oc->stobj->priv2 += (uint64_t)l;
102 20
        VSLb(wrk->vsl, SLT_Debug, "-sdebug extend: %zd/%zd", (ssize_t)oc->stobj->priv2, max_size);
103 20
        SML_methods.objextend(wrk, oc, l);
104 20
}
105
106
/* full storage can't get space, can't alloc objects */
107
static int v_matchproto_(objgetspace_f)
108 0
smd_full_getspace(struct worker *wrk, struct objcore *oc, ssize_t *sz,
109
    uint8_t **ptr)
110
{
111 0
        (void)wrk;
112 0
        (void)oc;
113 0
        (void)sz;
114 0
        (void)ptr;
115
116 0
        return (0);
117
}
118
static int v_matchproto_(storage_allocobj_f)
119 4
smd_full_allocobj(struct worker *wrk, const struct stevedore *stv,
120
    struct objcore *oc, unsigned len)
121
{
122 4
        (void)wrk;
123 4
        (void)stv;
124 4
        (void)oc;
125 4
        (void)len;
126
127 4
        return (0);
128
}
129
static void * v_matchproto_(storage_allocbuf_t)
130 0
smd_full_allocbuf(struct worker *wrk, const struct stevedore *stv, size_t size,
131
    uintptr_t *ppriv)
132
{
133 0
        (void)wrk;
134 0
        (void)stv;
135 0
        (void)size;
136 0
        (void)ppriv;
137 0
        return (NULL);
138
}
139
140
#define dur_arg(a, s, d)                                        \
141
        (! vstrncmp((a), (s), vstrlen(s))                               \
142
         && (d = VNUM_duration(a + vstrlen(s))) != nan(""))
143
144
static int
145 36
bytes_arg(char *a, const char *s, ssize_t *sz)
146
{
147
        const char *err;
148
        uintmax_t bytes;
149
150 36
        AN(sz);
151 36
        if (vstrncmp(a, s, vstrlen(s)))
152 16
                return (0);
153 20
        a += vstrlen(s);
154 20
        err = VNUM_2bytes(a, &bytes, 0);
155 20
        if (err != NULL)
156 4
                ARGV_ERR("%s\n", err);
157 16
        assert(bytes <= SSIZE_MAX);
158 16
        *sz = (ssize_t)bytes;
159
160 16
        return (1);
161 32
}
162
163
164 35
static void smd_open(struct stevedore *stv)
165
{
166 35
        sma_stevedore.open(stv);
167 35
        fprintf(stderr, "-sdebug open delay %fs\n", dopen);
168 35
        if (dopen > 0.0)
169 8
                VTIM_sleep(dopen);
170 35
}
171
172
static void v_matchproto_(storage_init_f)
173 48
smd_init(struct stevedore *parent, int aac, char * const *aav)
174
{
175
        struct obj_methods *methods;
176 48
        objgetspace_f *getspace = NULL;
177 48
        storage_allocobj_f *allocobj = NULL;
178
        const char *ident;
179 48
        int i, ac = 0;
180
        size_t nac;
181 48
        vtim_dur d, dinit = 0.0;
182
        char **av;      //lint !e429
183
        char *a;
184
185 48
        if (count++ > 0)
186 4
                ARGV_ERR("Only one -s%s instance supported\n", smd_stevedore.name);
187
188 44
        ident = parent->ident;
189 44
        vmemcpy(parent, &sma_stevedore, sizeof *parent);
190 44
        parent->ident = ident;
191 44
        parent->name = smd_stevedore.name;
192
193 44
        methods = malloc(sizeof *methods);
194 44
        AN(methods);
195 44
        vmemcpy(methods, &SML_methods, sizeof *methods);
196 44
        parent->methods = methods;
197
198 44
        assert(aac >= 0);
199 44
        nac = aac;
200 44
        nac++;
201 44
        av = calloc(nac, sizeof *av);
202 44
        AN(av);
203 84
        for (i = 0; i < aac; i++) {
204 44
                a = aav[i];
205 44
                if (a != NULL) {
206 44
                        if (! vstrcmp(a, "full")) {
207 4
                                if (getspace != NULL) {
208 0
                                        ARGV_ERR("-s%s conflicting options\n",
209
                                            smd_stevedore.name);
210 0
                                }
211 4
                                getspace = smd_full_getspace;
212 4
                                AZ(allocobj);
213 4
                                allocobj = smd_full_allocobj;
214 4
                                parent->allocbuf = smd_full_allocbuf;
215 4
                                continue;
216
                        }
217 40
                        if (! vstrcmp(a, "lessspace")) {
218 8
                                if (getspace != NULL) {
219 0
                                        ARGV_ERR("-s%s conflicting options\n",
220
                                            smd_stevedore.name);
221 0
                                }
222 8
                                getspace = smd_lsp_getspace;
223 8
                                continue;
224
                        }
225 32
                        if (bytes_arg(a, "maxspace=", &max_size)) {
226 16
                                if (getspace != NULL) {
227 4
                                        ARGV_ERR("-s%s conflicting options\n",
228
                                            smd_stevedore.name);
229 0
                                }
230 12
                                getspace = smd_max_getspace;
231 12
                                methods->objextend = smd_max_extend;
232 12
                                continue;
233
                        }
234 16
                        if (dur_arg(a, "dinit=", d)) {
235 8
                                dinit = d;
236 8
                                continue;
237
                        }
238 8
                        if (dur_arg(a, "dopen=", d)) {
239 8
                                dopen = d;
240 8
                                continue;
241
                        }
242 0
                }
243 0
                av[ac] = a;
244 0
                ac++;
245 0
        }
246 40
        assert(ac >= 0);
247 40
        assert(ac < (int)nac);
248 40
        AZ(av[ac]);
249
250 40
        if (getspace != NULL)
251 20
                methods->objgetspace = getspace;
252 40
        if (allocobj != NULL)
253 4
                parent->allocobj = allocobj;
254
255 40
        sma_stevedore.init(parent, ac, av);
256 40
        free(av);
257 40
        fprintf(stderr, "-sdebug init delay %fs\n", dinit);
258 40
        fprintf(stderr, "-sdebug open delay in init %fs\n", dopen);
259 40
        if (dinit > 0.0) {
260 8
                VTIM_sleep(dinit);
261 8
        }
262 40
        parent->open = smd_open;
263 40
}
264
265
const struct stevedore smd_stevedore = {
266
        .magic          =       STEVEDORE_MAGIC,
267
        .name           =       "debug",
268
        .init           =       smd_init,
269
        // other callbacks initialized in smd_init()
270
};