source: bin/varnishd/cache/cache_backend.c @ e9e3e2

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

Eliminate a lot of arguments to http_ functions which used to convey
the VSL coords which are now a property of struct http.

  • 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 * Handle backend connections and backend request structures.
30 *
31 */
32
33#include "config.h"
34
35#include <poll.h>
36#include <stdlib.h>
37#include <stddef.h>
38#include <stdio.h>
39
40#include "cache.h"
41
42#include "cache_backend.h"
43#include "vrt.h"
44#include "vtcp.h"
45
46static struct mempool   *vbcpool;
47
48static unsigned         vbcps = sizeof(struct vbc);
49
50/*--------------------------------------------------------------------
51 * The "simple" director really isn't, since thats where all the actual
52 * connections happen.  Nontheless, pretend it is simple by sequestering
53 * the directoricity of it under this line.
54 */
55
56struct vdi_simple {
57        unsigned                magic;
58#define VDI_SIMPLE_MAGIC        0x476d25b7
59        struct director         dir;
60        struct backend          *backend;
61        const struct vrt_backend *vrt;
62};
63
64/*--------------------------------------------------------------------
65 * Create default Host: header for backend request
66 */
67void
68VDI_AddHostHeader(struct http *hp, const struct vbc *vbc)
69{
70
71        CHECK_OBJ_NOTNULL(vbc, VBC_MAGIC);
72        CHECK_OBJ_NOTNULL(vbc->vdis, VDI_SIMPLE_MAGIC);
73        http_PrintfHeader(hp,
74            "Host: %s", vbc->vdis->vrt->hosthdr);
75}
76
77/*--------------------------------------------------------------------*/
78
79/* Private interface from backend_cfg.c */
80void
81VBE_ReleaseConn(struct vbc *vc)
82{
83
84        CHECK_OBJ_NOTNULL(vc, VBC_MAGIC);
85        assert(vc->backend == NULL);
86        assert(vc->fd < 0);
87        MPL_Free(vbcpool, vc);
88}
89
90#define FIND_TMO(tmx, dst, sp, be)                                      \
91        do {                                                            \
92                CHECK_OBJ_NOTNULL(sp->wrk->busyobj, BUSYOBJ_MAGIC);     \
93                dst = sp->wrk->busyobj->tmx;                            \
94                if (dst == 0.0)                                         \
95                        dst = be->tmx;                                  \
96                if (dst == 0.0)                                         \
97                        dst = cache_param->tmx;                         \
98        } while (0)
99
100/*--------------------------------------------------------------------
101 * Attempt to connect to a given addrinfo entry.
102 *
103 * Must be called with locked backend, but will release the backend
104 * lock during the slow/sleeping stuff, so that other worker threads
105 * can have a go, while we ponder.
106 *
107 */
108
109static int
110vbe_TryConnect(const struct sess *sp, int pf, const struct sockaddr_storage *sa,
111    socklen_t salen, const struct vdi_simple *vs)
112{
113        int s, i, tmo;
114        double tmod;
115
116        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
117        CHECK_OBJ_NOTNULL(vs, VDI_SIMPLE_MAGIC);
118
119        s = socket(pf, SOCK_STREAM, 0);
120        if (s < 0)
121                return (s);
122
123        FIND_TMO(connect_timeout, tmod, sp, vs->vrt);
124
125        tmo = (int)(tmod * 1000.0);
126
127        i = VTCP_connect(s, sa, salen, tmo);
128
129        if (i != 0) {
130                AZ(close(s));
131                return (-1);
132        }
133
134        return (s);
135}
136
137/*--------------------------------------------------------------------*/
138
139static void
140bes_conn_try(const struct sess *sp, struct vbc *vc, const struct vdi_simple *vs)
141{
142        int s;
143        struct backend *bp = vs->backend;
144        char abuf1[VTCP_ADDRBUFSIZE];
145        char pbuf1[VTCP_PORTBUFSIZE];
146
147        CHECK_OBJ_NOTNULL(vs, VDI_SIMPLE_MAGIC);
148
149        Lck_Lock(&bp->mtx);
150        bp->refcount++;
151        bp->n_conn++;           /* It mostly works */
152        Lck_Unlock(&bp->mtx);
153
154        s = -1;
155        assert(bp->ipv6 != NULL || bp->ipv4 != NULL);
156
157        /* release lock during stuff that can take a long time */
158
159        if (cache_param->prefer_ipv6 && bp->ipv6 != NULL) {
160                s = vbe_TryConnect(sp, PF_INET6, bp->ipv6, bp->ipv6len, vs);
161                vc->addr = bp->ipv6;
162                vc->addrlen = bp->ipv6len;
163        }
164        if (s == -1 && bp->ipv4 != NULL) {
165                s = vbe_TryConnect(sp, PF_INET, bp->ipv4, bp->ipv4len, vs);
166                vc->addr = bp->ipv4;
167                vc->addrlen = bp->ipv4len;
168        }
169        if (s == -1 && !cache_param->prefer_ipv6 && bp->ipv6 != NULL) {
170                s = vbe_TryConnect(sp, PF_INET6, bp->ipv6, bp->ipv6len, vs);
171                vc->addr = bp->ipv6;
172                vc->addrlen = bp->ipv6len;
173        }
174
175        vc->fd = s;
176        if (s < 0) {
177                Lck_Lock(&bp->mtx);
178                bp->n_conn--;
179                bp->refcount--;         /* Only keep ref on success */
180                Lck_Unlock(&bp->mtx);
181                vc->addr = NULL;
182                vc->addrlen = 0;
183        } else {
184                vc->vsl_id = s | VSL_BACKENDMARKER;
185                VTCP_myname(s, abuf1, sizeof abuf1, pbuf1, sizeof pbuf1);
186                WSL(sp->wrk->vsl, SLT_BackendOpen, vc->vsl_id, "%s %s %s ",
187                    vs->backend->display_name, abuf1, pbuf1);
188        }
189
190}
191
192/*--------------------------------------------------------------------
193 * Check that there is still something at the far end of a given socket.
194 * We poll the fd with instant timeout, if there are any events we can't
195 * use it (backends are not allowed to pipeline).
196 */
197
198static int
199vbe_CheckFd(int fd)
200{
201        struct pollfd pfd;
202
203        pfd.fd = fd;
204        pfd.events = POLLIN;
205        pfd.revents = 0;
206        return(poll(&pfd, 1, 0) == 0);
207}
208
209/*--------------------------------------------------------------------
210 * Manage a pool of vbc structures.
211 * XXX: as an experiment, make this caching controled by a parameter
212 * XXX: so we can see if it has any effect.
213 */
214
215static struct vbc *
216vbe_NewConn(void)
217{
218        struct vbc *vc;
219
220        vc = MPL_Get(vbcpool, NULL);
221        XXXAN(vc);
222        vc->magic = VBC_MAGIC;
223        vc->fd = -1;
224        return (vc);
225}
226
227/*--------------------------------------------------------------------
228 * It evaluates if a backend is healthy _for_a_specific_object_.
229 * That means that it relies on sp->req->objcore->objhead. This is mainly for
230 * saint-mode, but also takes backend->healthy into account. If
231 * cache_param->saintmode_threshold is 0, this is basically just a test of
232 * backend->healthy.
233 *
234 * The threshold has to be evaluated _after_ the timeout check, otherwise
235 * items would never time out once the threshold is reached.
236 */
237
238static unsigned int
239vbe_Healthy(const struct vdi_simple *vs, const struct sess *sp)
240{
241        struct trouble *tr;
242        struct trouble *tr2;
243        struct trouble *old;
244        unsigned i = 0, retval;
245        unsigned int threshold;
246        struct backend *backend;
247        uintptr_t target;
248        double now;
249
250        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
251        CHECK_OBJ_NOTNULL(vs, VDI_SIMPLE_MAGIC);
252        backend = vs->backend;
253        CHECK_OBJ_NOTNULL(backend, BACKEND_MAGIC);
254
255        if (backend->admin_health == ah_probe && !backend->healthy)
256                return (0);
257
258        if (backend->admin_health == ah_sick)
259                return (0);
260
261        /* VRT/VCC sets threshold to UINT_MAX to mark that it's not
262         * specified by VCL (thus use param).
263         */
264        if (vs->vrt->saintmode_threshold == UINT_MAX)
265                threshold = cache_param->saintmode_threshold;
266        else
267                threshold = vs->vrt->saintmode_threshold;
268
269        if (backend->admin_health == ah_healthy)
270                threshold = UINT_MAX;
271
272        /* Saintmode is disabled */
273        if (threshold == 0)
274                return (1);
275
276        if (sp->req->objcore == NULL)
277                return (1);
278
279        now = sp->t_req;
280        target = (uintptr_t)(sp->req->objcore->objhead);
281
282        old = NULL;
283        retval = 1;
284        Lck_Lock(&backend->mtx);
285        VTAILQ_FOREACH_SAFE(tr, &backend->troublelist, list, tr2) {
286                CHECK_OBJ_NOTNULL(tr, TROUBLE_MAGIC);
287
288                if (tr->timeout < now) {
289                        VTAILQ_REMOVE(&backend->troublelist, tr, list);
290                        old = tr;
291                        retval = 1;
292                        break;
293                }
294
295                if (tr->target == target) {
296                        retval = 0;
297                        break;
298                }
299
300                /* If the threshold is at 1, a single entry on the list
301                 * will disable the backend. Since 0 is disable, ++i
302                 * instead of i++ to allow this behavior.
303                 */
304                if (++i >= threshold) {
305                        retval = 0;
306                        break;
307                }
308        }
309        Lck_Unlock(&backend->mtx);
310
311        if (old != NULL)
312                FREE_OBJ(old);
313
314        return (retval);
315}
316
317/*--------------------------------------------------------------------
318 * Get a connection to a particular backend.
319 */
320
321static struct vbc *
322vbe_GetVbe(const struct sess *sp, struct vdi_simple *vs)
323{
324        struct vbc *vc;
325        struct backend *bp;
326
327        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
328        CHECK_OBJ_NOTNULL(vs, VDI_SIMPLE_MAGIC);
329        bp = vs->backend;
330        CHECK_OBJ_NOTNULL(bp, BACKEND_MAGIC);
331
332        /* first look for vbc's we can recycle */
333        while (1) {
334                Lck_Lock(&bp->mtx);
335                vc = VTAILQ_FIRST(&bp->connlist);
336                if (vc != NULL) {
337                        bp->refcount++;
338                        assert(vc->backend == bp);
339                        assert(vc->fd >= 0);
340                        AN(vc->addr);
341                        VTAILQ_REMOVE(&bp->connlist, vc, list);
342                }
343                Lck_Unlock(&bp->mtx);
344                if (vc == NULL)
345                        break;
346                if (vbe_CheckFd(vc->fd)) {
347                        /* XXX locking of stats */
348                        VSC_C_main->backend_reuse += 1;
349                        WSP(sp, SLT_Backend, "%d %s %s",
350                            vc->fd, sp->req->director->vcl_name,
351                            bp->display_name);
352                        vc->vdis = vs;
353                        vc->recycled = 1;
354                        return (vc);
355                }
356                VSC_C_main->backend_toolate++;
357                WSL(sp->wrk->vsl, SLT_BackendClose, vc->vsl_id, "%s",
358                   bp->display_name);
359
360                /* Checkpoint log to flush all info related to this connection
361                   before the OS reuses the FD */
362                WSL_Flush(sp->wrk->vsl, 0);
363
364                VTCP_close(&vc->fd);
365                VBE_DropRefConn(bp);
366                vc->backend = NULL;
367                VBE_ReleaseConn(vc);
368        }
369
370        if (!vbe_Healthy(vs, sp)) {
371                VSC_C_main->backend_unhealthy++;
372                return (NULL);
373        }
374
375        if (vs->vrt->max_connections > 0 &&
376            bp->n_conn >= vs->vrt->max_connections) {
377                VSC_C_main->backend_busy++;
378                return (NULL);
379        }
380
381        vc = vbe_NewConn();
382        assert(vc->fd == -1);
383        AZ(vc->backend);
384        bes_conn_try(sp, vc, vs);
385        if (vc->fd < 0) {
386                VBE_ReleaseConn(vc);
387                VSC_C_main->backend_fail++;
388                return (NULL);
389        }
390        vc->backend = bp;
391        VSC_C_main->backend_conn++;
392        WSP(sp, SLT_Backend, "%d %s %s",
393            vc->fd, sp->req->director->vcl_name, bp->display_name);
394        vc->vdis = vs;
395        return (vc);
396}
397
398/*--------------------------------------------------------------------
399 * Returns the backend if and only if the this is a simple director.
400 * XXX: Needs a better name and possibly needs a better general approach.
401 * XXX: This is mainly used by the DNS director to fetch the actual backend
402 * XXX: so it can compare DNS lookups with the actual IP.
403 */
404
405struct backend *
406vdi_get_backend_if_simple(const struct director *d)
407{
408        CHECK_OBJ_NOTNULL(d, DIRECTOR_MAGIC);
409        struct vdi_simple *vs, *vs2;
410
411        vs2 = d->priv;
412        if (vs2->magic != VDI_SIMPLE_MAGIC)
413                return (NULL);
414        CAST_OBJ_NOTNULL(vs, d->priv, VDI_SIMPLE_MAGIC);
415        return (vs->backend);
416}
417
418/*--------------------------------------------------------------------
419 *
420 */
421
422void
423VBE_UseHealth(const struct director *vdi)
424{
425        struct vdi_simple *vs;
426
427        ASSERT_CLI();
428
429        if (strcmp(vdi->name, "simple"))
430                return;
431        CAST_OBJ_NOTNULL(vs, vdi->priv, VDI_SIMPLE_MAGIC);
432        if (vs->vrt->probe == NULL)
433                return;
434        VBP_Use(vs->backend, vs->vrt->probe);
435}
436
437/*--------------------------------------------------------------------
438 *
439 */
440
441static struct vbc * __match_proto__(vdi_getfd_f)
442vdi_simple_getfd(const struct director *d, struct sess *sp)
443{
444        struct vdi_simple *vs;
445        struct vbc *vc;
446
447        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
448        CHECK_OBJ_NOTNULL(d, DIRECTOR_MAGIC);
449        CAST_OBJ_NOTNULL(vs, d->priv, VDI_SIMPLE_MAGIC);
450        vc = vbe_GetVbe(sp, vs);
451        if (vc != NULL) {
452                FIND_TMO(first_byte_timeout,
453                    vc->first_byte_timeout, sp, vs->vrt);
454                FIND_TMO(between_bytes_timeout,
455                    vc->between_bytes_timeout, sp, vs->vrt);
456        }
457        return (vc);
458}
459
460static unsigned
461vdi_simple_healthy(const struct director *d, const struct sess *sp)
462{
463        struct vdi_simple *vs;
464
465        CHECK_OBJ_NOTNULL(d, DIRECTOR_MAGIC);
466        CAST_OBJ_NOTNULL(vs, d->priv, VDI_SIMPLE_MAGIC);
467        return (vbe_Healthy(vs, sp));
468}
469
470static void
471vdi_simple_fini(const struct director *d)
472{
473        struct vdi_simple *vs;
474
475        ASSERT_CLI();
476        CHECK_OBJ_NOTNULL(d, DIRECTOR_MAGIC);
477        CAST_OBJ_NOTNULL(vs, d->priv, VDI_SIMPLE_MAGIC);
478
479        if (vs->vrt->probe != NULL)
480                VBP_Remove(vs->backend, vs->vrt->probe);
481        VBE_DropRefVcl(vs->backend);
482        free(vs->dir.vcl_name);
483        vs->dir.magic = 0;
484        FREE_OBJ(vs);
485}
486
487void
488VRT_init_dir_simple(struct cli *cli, struct director **bp, int idx,
489    const void *priv)
490{
491        const struct vrt_backend *t;
492        struct vdi_simple *vs;
493
494        ASSERT_CLI();
495        (void)cli;
496        t = priv;
497
498        ALLOC_OBJ(vs, VDI_SIMPLE_MAGIC);
499        XXXAN(vs);
500        vs->dir.magic = DIRECTOR_MAGIC;
501        vs->dir.priv = vs;
502        vs->dir.name = "simple";
503        REPLACE(vs->dir.vcl_name, t->vcl_name);
504        vs->dir.getfd = vdi_simple_getfd;
505        vs->dir.fini = vdi_simple_fini;
506        vs->dir.healthy = vdi_simple_healthy;
507
508        vs->vrt = t;
509
510        vs->backend = VBE_AddBackend(cli, t);
511        if (vs->vrt->probe != NULL)
512                VBP_Insert(vs->backend, vs->vrt->probe, vs->vrt->hosthdr);
513
514        bp[idx] = &vs->dir;
515}
516
517void
518VDI_Init(void)
519{
520
521        vbcpool = MPL_New("vbc", &cache_param->vbc_pool, &vbcps);
522        AN(vbcpool);
523}
Note: See TracBrowser for help on using the repository browser.