source: bin/varnishd/cache/cache_vcl.c @ 097e64

Revision 097e64, 8.3 KB checked in by Poul-Henning Kamp <phk@…>, 2 years ago (diff)

Move another 144 bytes from sess to req

  • Property mode set to 100644
Line 
1/*-
2 * Copyright (c) 2006 Verdens Gang AS
3 * Copyright (c) 2006-2011 Varnish Software AS
4 * All rights reserved.
5 *
6 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
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 * Interface *to* compiled VCL code:  Loading, unloading, calling into etc.
30 *
31 * The interface *from* the compiled VCL code is in cache_vrt.c.
32 */
33
34#include "config.h"
35
36#include <dlfcn.h>
37#include <stdlib.h>
38
39#include "cache.h"
40
41#include "vcl.h"
42#include "vcli.h"
43#include "vcli_priv.h"
44
45struct vcls {
46        unsigned                magic;
47#define VVCLS_MAGIC             0x214188f2
48        VTAILQ_ENTRY(vcls)      list;
49        char                    *name;
50        void                    *dlh;
51        struct VCL_conf         conf[1];
52};
53
54/*
55 * XXX: Presently all modifications to this list happen from the
56 * CLI event-engine, so no locking is necessary
57 */
58static VTAILQ_HEAD(, vcls)      vcl_head =
59    VTAILQ_HEAD_INITIALIZER(vcl_head);
60
61
62static struct lock              vcl_mtx;
63static struct vcls              *vcl_active; /* protected by vcl_mtx */
64
65/*--------------------------------------------------------------------*/
66
67const char *
68VCL_Return_Name(unsigned method)
69{
70
71        switch (method) {
72#define VCL_RET_MAC(l, U, B) case VCL_RET_##U: return(#l);
73#include "tbl/vcl_returns.h"
74#undef VCL_RET_MAC
75        default:
76                return (NULL);
77        }
78}
79
80/*--------------------------------------------------------------------*/
81
82static void
83VCL_Get(struct VCL_conf **vcc)
84{
85        static int once = 0;
86
87        while (!once && vcl_active == NULL) {
88                (void)sleep(1);
89        }
90        once = 1;
91
92        Lck_Lock(&vcl_mtx);
93        AN(vcl_active);
94        *vcc = vcl_active->conf;
95        AN(*vcc);
96        AZ((*vcc)->discard);
97        (*vcc)->busy++;
98        Lck_Unlock(&vcl_mtx);
99}
100
101void
102VCL_Refresh(struct VCL_conf **vcc)
103{
104        if (*vcc == vcl_active->conf)
105                return;
106        if (*vcc != NULL)
107                VCL_Rel(vcc);   /* XXX: optimize locking */
108        VCL_Get(vcc);
109}
110
111void
112VCL_Rel(struct VCL_conf **vcc)
113{
114        struct VCL_conf *vc;
115
116        AN(*vcc);
117        vc = *vcc;
118        *vcc = NULL;
119
120        Lck_Lock(&vcl_mtx);
121        assert(vc->busy > 0);
122        vc->busy--;
123        /*
124         * We do not garbage collect discarded VCL's here, that happens
125         * in VCL_Poll() which is called from the CLI thread.
126         */
127        Lck_Unlock(&vcl_mtx);
128}
129
130/*--------------------------------------------------------------------*/
131
132static struct vcls *
133vcl_find(const char *name)
134{
135        struct vcls *vcl;
136
137        ASSERT_CLI();
138        VTAILQ_FOREACH(vcl, &vcl_head, list) {
139                if (vcl->conf->discard)
140                        continue;
141                if (!strcmp(vcl->name, name))
142                        return (vcl);
143        }
144        return (NULL);
145}
146
147static int
148VCL_Load(const char *fn, const char *name, struct cli *cli)
149{
150        struct vcls *vcl;
151        struct VCL_conf const *cnf;
152
153        ASSERT_CLI();
154        vcl = vcl_find(name);
155        if (vcl != NULL) {
156                VCLI_Out(cli, "Config '%s' already loaded", name);
157                return (1);
158        }
159
160        ALLOC_OBJ(vcl, VVCLS_MAGIC);
161        XXXAN(vcl);
162
163        vcl->dlh = dlopen(fn, RTLD_NOW | RTLD_LOCAL);
164
165        if (vcl->dlh == NULL) {
166                VCLI_Out(cli, "dlopen(%s): %s\n", fn, dlerror());
167                FREE_OBJ(vcl);
168                return (1);
169        }
170        cnf = dlsym(vcl->dlh, "VCL_conf");
171        if (cnf == NULL) {
172                VCLI_Out(cli, "Internal error: No VCL_conf symbol\n");
173                (void)dlclose(vcl->dlh);
174                FREE_OBJ(vcl);
175                return (1);
176        }
177        memcpy(vcl->conf, cnf, sizeof *cnf);
178
179        if (vcl->conf->magic != VCL_CONF_MAGIC) {
180                VCLI_Out(cli, "Wrong VCL_CONF_MAGIC\n");
181                (void)dlclose(vcl->dlh);
182                FREE_OBJ(vcl);
183                return (1);
184        }
185        if (vcl->conf->init_vcl(cli)) {
186                VCLI_Out(cli, "VCL \"%s\" Failed to initialize", name);
187                (void)dlclose(vcl->dlh);
188                FREE_OBJ(vcl);
189                return (1);
190        }
191        REPLACE(vcl->name, name);
192        VCLI_Out(cli, "Loaded \"%s\" as \"%s\"", fn , name);
193        VTAILQ_INSERT_TAIL(&vcl_head, vcl, list);
194        (void)vcl->conf->init_func(NULL);
195        Lck_Lock(&vcl_mtx);
196        if (vcl_active == NULL)
197                vcl_active = vcl;
198        Lck_Unlock(&vcl_mtx);
199        VSC_C_main->n_vcl++;
200        VSC_C_main->n_vcl_avail++;
201        return (0);
202}
203
204/*--------------------------------------------------------------------
205 * This function is polled from the CLI thread to dispose of any non-busy
206 * VCLs which have been discarded.
207 */
208
209static void
210VCL_Nuke(struct vcls *vcl)
211{
212
213        ASSERT_CLI();
214        assert(vcl != vcl_active);
215        assert(vcl->conf->discard);
216        assert(vcl->conf->busy == 0);
217        VTAILQ_REMOVE(&vcl_head, vcl, list);
218        (void)vcl->conf->fini_func(NULL);
219        vcl->conf->fini_vcl(NULL);
220        free(vcl->name);
221        (void)dlclose(vcl->dlh);
222        FREE_OBJ(vcl);
223        VSC_C_main->n_vcl--;
224        VSC_C_main->n_vcl_discard--;
225}
226
227/*--------------------------------------------------------------------*/
228
229void
230VCL_Poll(void)
231{
232        struct vcls *vcl, *vcl2;
233
234        ASSERT_CLI();
235        VTAILQ_FOREACH_SAFE(vcl, &vcl_head, list, vcl2)
236                if (vcl->conf->discard && vcl->conf->busy == 0)
237                        VCL_Nuke(vcl);
238}
239
240/*--------------------------------------------------------------------*/
241
242static void
243ccf_config_list(struct cli *cli, const char * const *av, void *priv)
244{
245        struct vcls *vcl;
246        const char *flg;
247
248        (void)av;
249        (void)priv;
250        ASSERT_CLI();
251        VTAILQ_FOREACH(vcl, &vcl_head, list) {
252                if (vcl == vcl_active) {
253                        flg = "active";
254                } else if (vcl->conf->discard) {
255                        flg = "discarded";
256                } else
257                        flg = "available";
258                VCLI_Out(cli, "%-10s %6u %s\n",
259                    flg,
260                    vcl->conf->busy,
261                    vcl->name);
262        }
263}
264
265static void
266ccf_config_load(struct cli *cli, const char * const *av, void *priv)
267{
268
269        (void)av;
270        (void)priv;
271        ASSERT_CLI();
272        if (VCL_Load(av[3], av[2], cli))
273                VCLI_SetResult(cli, CLIS_PARAM);
274        return;
275}
276
277static void
278ccf_config_discard(struct cli *cli, const char * const *av, void *priv)
279{
280        struct vcls *vcl;
281
282        ASSERT_CLI();
283        (void)av;
284        (void)priv;
285        vcl = vcl_find(av[2]);
286        if (vcl == NULL) {
287                VCLI_SetResult(cli, CLIS_PARAM);
288                VCLI_Out(cli, "VCL '%s' unknown", av[2]);
289                return;
290        }
291        Lck_Lock(&vcl_mtx);
292        if (vcl == vcl_active) {
293                Lck_Unlock(&vcl_mtx);
294                VCLI_SetResult(cli, CLIS_PARAM);
295                VCLI_Out(cli, "VCL %s is the active VCL", av[2]);
296                return;
297        }
298        VSC_C_main->n_vcl_discard++;
299        VSC_C_main->n_vcl_avail--;
300        vcl->conf->discard = 1;
301        Lck_Unlock(&vcl_mtx);
302        if (vcl->conf->busy == 0)
303                VCL_Nuke(vcl);
304}
305
306static void
307ccf_config_use(struct cli *cli, const char * const *av, void *priv)
308{
309        struct vcls *vcl;
310        int i;
311
312        (void)av;
313        (void)priv;
314        vcl = vcl_find(av[2]);
315        if (vcl == NULL) {
316                VCLI_Out(cli, "No VCL named '%s'", av[2]);
317                VCLI_SetResult(cli, CLIS_PARAM);
318                return;
319        }
320        Lck_Lock(&vcl_mtx);
321        vcl_active = vcl;
322        Lck_Unlock(&vcl_mtx);
323
324        /* Tickle this VCL's backends to take over health polling */
325        for(i = 1; i < vcl->conf->ndirector; i++)
326                VBE_UseHealth(vcl->conf->director[i]);
327}
328
329/*--------------------------------------------------------------------*/
330
331#define VCL_MET_MAC(func, upper, bitmap)                                \
332void                                                                    \
333VCL_##func##_method(struct sess *sp)                                    \
334{                                                                       \
335                                                                        \
336        sp->req->handling = 0;                                          \
337        sp->req->cur_method = VCL_MET_ ## upper;                                \
338        WSP(sp, SLT_VCL_call, "%s", #func);                             \
339        (void)sp->vcl->func##_func(sp);                                 \
340        WSP(sp, SLT_VCL_return, "%s", VCL_Return_Name(sp->req->handling));      \
341        sp->req->cur_method = 0;                                                \
342        assert((1U << sp->req->handling) & bitmap);                             \
343        assert(!((1U << sp->req->handling) & ~bitmap));                 \
344}
345
346#include "tbl/vcl_returns.h"
347#undef VCL_MET_MAC
348
349/*--------------------------------------------------------------------*/
350
351static struct cli_proto vcl_cmds[] = {
352        { CLI_VCL_LOAD,         "i", ccf_config_load },
353        { CLI_VCL_LIST,         "i", ccf_config_list },
354        { CLI_VCL_DISCARD,      "i", ccf_config_discard },
355        { CLI_VCL_USE,          "i", ccf_config_use },
356        { NULL }
357};
358
359void
360VCL_Init()
361{
362
363        CLI_AddFuncs(vcl_cmds);
364        Lck_New(&vcl_mtx, lck_vcl);
365}
Note: See TracBrowser for help on using the repository browser.