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