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