vinyl-cache/bin/vinyld/storage/mgt_stevedore.c
0
/*-
1
 * Copyright (c) 2007-2011 Varnish Software AS
2
 * All rights reserved.
3
 *
4
 * Author: Dag-Erling Smørgav <des@des.no>
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
 * STEVEDORE: one who works at or is responsible for loading and
30
 * unloading ships in port.  Example: "on the wharves, stevedores were
31
 * unloading cargo from the far corners of the world." Origin: Spanish
32
 * estibador, from estibar to pack.  First Known Use: 1788
33
 */
34
35
#include "config.h"
36
37
#include <stdio.h>
38
#include <stdlib.h>
39
#include <string.h>
40
#include <unistd.h>
41
42
#include "mgt/mgt.h"
43
#include "common/heritage.h"
44
#include "vcli_serve.h"
45
46
#include "storage/storage.h"
47
48
VTAILQ_HEAD(stevedore_head, stevedore);
49
50
static struct stevedore_head proto_stevedores =
51
    VTAILQ_HEAD_INITIALIZER(proto_stevedores);
52
53
static struct stevedore_head pre_stevedores =
54
    VTAILQ_HEAD_INITIALIZER(pre_stevedores);
55
56
static struct stevedore_head stevedores =
57
    VTAILQ_HEAD_INITIALIZER(stevedores);
58
59
/* Name of special storages */
60
#define TRANSIENT_STORAGE       "Transient"     // passes
61
#define SYNTH_STORAGE           "Synth"         // vcl_synth resp.body
62
63
struct stevedore *stv_transient;
64
struct stevedore *stv_synth;
65
66
const char *mgt_stv_h2_rxbuf;
67
68
/*--------------------------------------------------------------------*/
69
70
int
71 138560
STV__iter(struct stevedore ** const pp)
72
{
73
74 138560
        AN(pp);
75 138560
        CHECK_OBJ_ORNULL(*pp, STEVEDORE_MAGIC);
76 138560
        if (*pp != NULL)
77 98020
                *pp = VTAILQ_NEXT(*pp, list);
78 40540
        else if (!VTAILQ_EMPTY(&stevedores))
79 30080
                *pp = VTAILQ_FIRST(&stevedores);
80
        else
81 10460
                *pp = VTAILQ_FIRST(&pre_stevedores);
82 138560
        return (*pp != NULL);
83
}
84
85
/*--------------------------------------------------------------------*/
86
87
static void v_matchproto_(cli_func_t)
88 16
stv_cli_list(struct cli *cli, const char * const *av, void *priv)
89
{
90
        struct stevedore *stv;
91
92 16
        ASSERT_MGT();
93 16
        (void)av;
94 16
        (void)priv;
95 16
        VCLI_Out(cli, "Storage devices:\n");
96 68
        STV_Foreach(stv)
97 52
                VCLI_Out(cli, "\tstorage.%s = %s\n", stv->ident, stv->name);
98 16
}
99
100
static void v_matchproto_(cli_func_t)
101 4
stv_cli_list_json(struct cli *cli, const char * const *av, void *priv)
102
{
103
        struct stevedore *stv;
104 4
        int n = 0;
105
106 4
        (void)priv;
107 4
        ASSERT_MGT();
108 4
        VCLI_JSON_begin(cli, 2, av);
109 4
        VCLI_Out(cli, ",\n");
110 16
        STV_Foreach(stv) {
111 12
                VCLI_Out(cli, "%s", n ? ",\n" : "");
112 12
                n++;
113 12
                VCLI_Out(cli, "{\n");
114 12
                VSB_indent(cli->sb, 2);
115 12
                VCLI_Out(cli, "\"name\": ");
116 12
                VCLI_JSON_str(cli, stv->ident);
117 12
                VCLI_Out(cli, ",\n");
118 12
                VCLI_Out(cli, "\"storage\": ");
119 12
                VCLI_JSON_str(cli, stv->name);
120 12
                VSB_indent(cli->sb, -2);
121 12
                VCLI_Out(cli, "\n}");
122
        }
123 4
        VCLI_JSON_end(cli);
124 4
}
125
126
/*--------------------------------------------------------------------*/
127
128
static struct cli_proto cli_stv[] = {
129
        { CLICMD_STORAGE_LIST,          "", stv_cli_list, stv_cli_list_json },
130
        { NULL}
131
};
132
133
/*--------------------------------------------------------------------
134
 */
135
136
#ifdef WITH_PERSISTENT_STORAGE
137
static void v_noreturn_ v_matchproto_(storage_init_f)
138 4
smp_fake_init(struct stevedore *parent, int ac, char * const *av)
139
{
140
141 4
        (void)parent;
142 4
        (void)ac;
143 4
        (void)av;
144 4
        ARGV_ERR(
145
            "-spersistent has been deprecated, please see:\n"
146
            "  https://vinyl-cache.org/docs/trunk/phk/persistent.html\n"
147
            "for details.\n"
148
        );
149 0
}
150
151
static const struct stevedore smp_fake_stevedore = {
152
        .magic = STEVEDORE_MAGIC,
153
        .name = "persistent",
154
        .init = smp_fake_init,
155
};
156
#endif
157
158
/*--------------------------------------------------------------------
159
 * Register a stevedore implementation by name.
160
 * VEXTs get to do this first, and since the list is searched front to
161
 * back a VEXT stevedore which inadvisably wants to steal "default" or
162
 * the name of another stevedore implementation can do so.
163
 */
164
165
void
166 27440
STV_Register(const struct stevedore *cstv, const char *altname)
167
{
168
        struct stevedore *stv;
169
170 27440
        CHECK_OBJ_NOTNULL(cstv, STEVEDORE_MAGIC);
171 27440
        ALLOC_OBJ(stv, STEVEDORE_MAGIC);
172 27440
        AN(stv);
173 27440
        *stv = *cstv;
174 27440
        if (altname != NULL)
175 3920
                stv->ident = altname;
176
        else
177 23520
                stv->ident = stv->name;
178 27440
        VTAILQ_INSERT_TAIL(&proto_stevedores, stv, list);
179 27440
}
180
181
static void
182 3920
STV_Register_The_Usual_Suspects(void)
183
{
184 3920
        STV_Register(&smf_stevedore, NULL);
185 3920
        STV_Register(&sma_stevedore, NULL);
186 3920
        STV_Register(&smd_stevedore, NULL);
187 3920
        STV_Register(&ssy_stevedore, NULL);
188
#ifdef WITH_PERSISTENT_STORAGE
189 3920
        STV_Register(&smp_stevedore, NULL);
190 3920
        STV_Register(&smp_fake_stevedore, NULL);
191
#endif
192
#if defined(HAVE_UMEM_H)
193
        STV_Register(&smu_stevedore, NULL);
194
        STV_Register(&smu_stevedore, "default");
195
#else
196 3920
        STV_Register(&sma_stevedore, "default");
197
#endif
198 3920
}
199
200
/*--------------------------------------------------------------------
201
 * Parse a stevedore argument on the form:
202
 *     [ name '=' ] strategy [ ',' arg ] *
203
 */
204
205
void
206 12212
STV_Config(const char *spec)
207
{
208
        char **av, buf[8];
209
        const char *ident;
210
        struct stevedore *stv;
211
        static unsigned seq = 0;
212
213 12212
        av = MGT_NamedArg(spec, &ident, "-s");
214 12212
        AN(av);
215
216 12212
        if (av[1] == NULL)
217 0
                ARGV_ERR("-s argument lacks strategy {malloc, file, ...}\n");
218
219
        /* Append strategy to ident string */
220 12212
        VSB_printf(vident, ",-s%s", av[1]);
221
222 12212
        if (ident == NULL) {
223 3964
                bprintf(buf, "s%u", seq++);
224 3964
                ident = strdup(buf);
225 3964
        }
226
227 24500
        VTAILQ_FOREACH(stv, &pre_stevedores, list)
228 12300
                if (!vstrcmp(stv->ident, ident))
229 12
                        ARGV_ERR("(-s %s) '%s' is already defined\n",
230
                            spec, ident);
231
232 12200
        ALLOC_OBJ(stv, STEVEDORE_MAGIC);
233 12200
        AN(stv);
234 12200
        stv->av = av;
235 12200
        stv->ident = ident;
236 12200
        stv->name = av[1];
237 12200
        VTAILQ_INSERT_TAIL(&pre_stevedores, stv, list);
238 12200
}
239
240
/*--------------------------------------------------------------------*/
241
242
void
243 4060
STV_Config_Final(void)
244
{
245 4060
        unsigned have_transient = 0, have_synth = 0;
246
        struct stevedore *stv;
247 4060
        ASSERT_MGT();
248
249 4060
        VCLS_AddFunc(mgt_cls, MCF_AUTH, cli_stv);
250 8220
        STV_Foreach(stv) {
251 4160
                if (!vstrcmp(stv->ident, TRANSIENT_STORAGE))
252 88
                        have_transient = 1;
253 4072
                else if (!vstrcmp(stv->ident, SYNTH_STORAGE))
254 4
                        have_synth = 1;
255
        }
256
257 4060
        if (! have_transient)
258 3972
                STV_Config(TRANSIENT_STORAGE "=default");
259 4060
        if (! have_synth)
260 4056
                STV_Config(SYNTH_STORAGE "=synth");
261 4060
}
262
263
/*--------------------------------------------------------------------
264
 * Initialize configured stevedores in the worker process
265
 */
266
267
void
268 3948
STV_Init(void)
269
{
270
        char **av;
271
        const char *ident;
272
        struct stevedore *stv;
273
        const struct stevedore *stv2;
274
        int ac;
275
276 3948
        STV_Register_The_Usual_Suspects();
277 15660
        while (!VTAILQ_EMPTY(&pre_stevedores)) {
278 11768
                stv = VTAILQ_FIRST(&pre_stevedores);
279 11768
                VTAILQ_REMOVE(&pre_stevedores, stv, list);
280 11768
                CHECK_OBJ_NOTNULL(stv, STEVEDORE_MAGIC);
281 11768
                AN(stv->av);
282 11768
                av = stv->av;
283 11768
                AN(stv->ident);
284 11768
                ident = stv->ident;
285
286 15944
                for (ac = 0; av[ac + 2] != NULL; ac++)
287 4176
                        continue;
288
289 69728
                VTAILQ_FOREACH(stv2, &proto_stevedores, list)
290 69700
                        if (!vstrcmp(stv2->ident, av[1]))
291 11740
                                break;
292 11768
                if (stv2 == NULL)
293 0
                        ARGV_ERR("Unknown stevedore method \"%s\"\n", av[1]);
294
295 11712
                CHECK_OBJ_NOTNULL(stv2, STEVEDORE_MAGIC);
296 11712
                *stv = *stv2;
297 11712
                AN(stv->name);
298
299 11712
                av += 2;
300
301 11712
                stv->ident = ident;
302 11712
                stv->av = av;
303
304 11712
                if (stv->init != NULL)
305 7824
                        stv->init(stv, ac, av);
306 3888
                else if (ac != 0)
307 0
                        ARGV_ERR("(-s %s) too many arguments\n", stv->name);
308
309 11712
                AN(stv->allocobj);
310 11712
                AN(stv->methods);
311
312 11712
                if (!vstrcmp(stv->ident, TRANSIENT_STORAGE)) {
313 3892
                        AZ(stv_transient);
314 3892
                        stv_transient = stv;
315 11712
                } else if (!vstrcmp(stv->ident, SYNTH_STORAGE)) {
316 3892
                        AZ(stv_synth);
317 3892
                        stv_synth = stv;
318 3892
                } else
319 3928
                        VTAILQ_INSERT_TAIL(&stevedores, stv, list);
320
                /* NB: Do not free av, stevedore gets to keep it */
321
        }
322 3892
        AN(stv_transient);
323 3892
        VTAILQ_INSERT_TAIL(&stevedores, stv_transient, list);
324 3892
        AN(stv_synth);
325 3892
        VTAILQ_INSERT_TAIL(&stevedores, stv_synth, list);
326 3892
}