varnish-cache/bin/varnishd/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_varnishd.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 28
smd_lsp_getspace(struct worker *wrk, struct objcore *oc, ssize_t *sz,
59
    uint8_t **ptr)
60
{
61 28
        AN(sz);
62 28
        if (*sz > 2)
63 14
                (*sz)--;
64 28
        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 126
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 126
        AN(sz);
80 126
        used = (ssize_t)oc->stobj->priv2;
81
82 126
        VSLb(wrk->vsl, SLT_Debug, "-sdebug getspace: %zd/%zd", used, max_size);
83
84 126
        if (used >= max_size) {
85 42
                VSLb(wrk->vsl, SLT_Storage, "-sdebug: max_size=%zd reached", max_size);
86 42
                return (0);
87
        }
88
89 84
        assert(used < max_size);
90 84
        *sz = vmin_t(ssize_t, *sz, max_size - used);
91
92 84
        r = SML_methods.objgetspace(wrk, oc, sz, ptr);
93 84
        return (r);
94 126
}
95
96
static void v_matchproto_(objextend_f)
97 84
smd_max_extend(struct worker *wrk, struct objcore *oc, ssize_t l)
98
{
99
100 84
        assert(l > 0);
101 84
        oc->stobj->priv2 += (uint64_t)l;
102 84
        VSLb(wrk->vsl, SLT_Debug, "-sdebug extend: %zd/%zd", (ssize_t)oc->stobj->priv2, max_size);
103 84
        SML_methods.objextend(wrk, oc, l);
104 84
}
105
106
#define dur_arg(a, s, d)                                        \
107
        (! strncmp((a), (s), strlen(s))                         \
108
         && (d = VNUM_duration(a + strlen(s))) != nan(""))
109
110
static int
111 126
bytes_arg(char *a, const char *s, ssize_t *sz)
112
{
113
        const char *err;
114
        uintmax_t bytes;
115
116 126
        AN(sz);
117 126
        if (strncmp(a, s, strlen(s)))
118 56
                return (0);
119 70
        a += strlen(s);
120 70
        err = VNUM_2bytes(a, &bytes, 0);
121 70
        if (err != NULL)
122 14
                ARGV_ERR("%s\n", err);
123 56
        assert(bytes <= SSIZE_MAX);
124 56
        *sz = (ssize_t)bytes;
125
126 56
        return (1);
127 112
}
128
129
130 110
static void smd_open(struct stevedore *stv)
131
{
132 110
        sma_stevedore.open(stv);
133 110
        fprintf(stderr, "-sdebug open delay %fs\n", dopen);
134 110
        if (dopen > 0.0)
135 28
                VTIM_sleep(dopen);
136 110
}
137
138
static void v_matchproto_(storage_init_f)
139 154
smd_init(struct stevedore *parent, int aac, char * const *aav)
140
{
141
        struct obj_methods *methods;
142 154
        objgetspace_f *getspace = NULL;
143
        const char *ident;
144 154
        int i, ac = 0;
145
        size_t nac;
146 154
        vtim_dur d, dinit = 0.0;
147
        char **av;      //lint -e429
148
        char *a;
149
150 154
        if (count++ > 0)
151 14
                ARGV_ERR("Only one -s%s instance supported\n", smd_stevedore.name);
152
153 140
        ident = parent->ident;
154 140
        memcpy(parent, &sma_stevedore, sizeof *parent);
155 140
        parent->ident = ident;
156 140
        parent->name = smd_stevedore.name;
157
158 140
        methods = malloc(sizeof *methods);
159 140
        AN(methods);
160 140
        memcpy(methods, &SML_methods, sizeof *methods);
161 140
        parent->methods = methods;
162
163 140
        assert(aac >= 0);
164 140
        nac = aac;
165 140
        nac++;
166 140
        av = calloc(nac, sizeof *av);
167 140
        AN(av);
168 266
        for (i = 0; i < aac; i++) {
169 140
                a = aav[i];
170 140
                if (a != NULL) {
171 140
                        if (! strcmp(a, "lessspace")) {
172 28
                                if (getspace != NULL) {
173 0
                                        ARGV_ERR("-s%s conflicting options\n",
174
                                            smd_stevedore.name);
175 0
                                }
176 28
                                getspace = smd_lsp_getspace;
177 28
                                continue;
178
                        }
179 112
                        if (bytes_arg(a, "maxspace=", &max_size)) {
180 56
                                if (getspace != NULL) {
181 14
                                        ARGV_ERR("-s%s conflicting options\n",
182
                                            smd_stevedore.name);
183 0
                                }
184 42
                                getspace = smd_max_getspace;
185 42
                                methods->objextend = smd_max_extend;
186 42
                                continue;
187
                        }
188 56
                        if (dur_arg(a, "dinit=", d)) {
189 28
                                dinit = d;
190 28
                                continue;
191
                        }
192 28
                        if (dur_arg(a, "dopen=", d)) {
193 28
                                dopen = d;
194 28
                                continue;
195
                        }
196 0
                }
197 0
                av[ac] = a;
198 0
                ac++;
199 0
        }
200 126
        assert(ac >= 0);
201 126
        assert(ac < (int)nac);
202 126
        AZ(av[ac]);
203
204 126
        if (getspace != NULL)
205 56
                methods->objgetspace = getspace;
206
207 126
        sma_stevedore.init(parent, ac, av);
208 126
        free(av);
209 126
        fprintf(stderr, "-sdebug init delay %fs\n", dinit);
210 126
        fprintf(stderr, "-sdebug open delay in init %fs\n", dopen);
211 126
        if (dinit > 0.0) {
212 28
                VTIM_sleep(dinit);
213 28
        }
214 126
        parent->open = smd_open;
215 126
}
216
217
const struct stevedore smd_stevedore = {
218
        .magic          =       STEVEDORE_MAGIC,
219
        .name           =       "debug",
220
        .init           =       smd_init,
221
        // other callbacks initialized in smd_init()
222
};