From c3ebe6cfed4a3bcd9dea60cdde0a15a7e752a90d Mon Sep 17 00:00:00 2001 From: phk Date: Thu, 7 Feb 2008 09:54:42 +0000 Subject: [PATCH] Make the random director work, and remove the old code. git-svn-id: svn+ssh://projects.linpro.no/svn/varnish/trunk@2442 d4fa192b-c00b-0410-8231-f00ffab90ce4 --- varnish-cache/bin/varnishd/Makefile.am | 4 +- .../bin/varnishd/cache_backend_random.c | 530 ------------------ .../bin/varnishd/cache_backend_round_robin.c | 492 ---------------- .../bin/varnishd/cache_backend_simple.c | 349 ------------ varnish-cache/bin/varnishd/cache_dir_random.c | 139 +++++ 5 files changed, 140 insertions(+), 1374 deletions(-) delete mode 100644 varnish-cache/bin/varnishd/cache_backend_random.c delete mode 100644 varnish-cache/bin/varnishd/cache_backend_round_robin.c delete mode 100644 varnish-cache/bin/varnishd/cache_backend_simple.c create mode 100644 varnish-cache/bin/varnishd/cache_dir_random.c diff --git a/varnish-cache/bin/varnishd/Makefile.am b/varnish-cache/bin/varnishd/Makefile.am index 7303da0f..4e4bbede 100644 --- a/varnish-cache/bin/varnishd/Makefile.am +++ b/varnish-cache/bin/varnishd/Makefile.am @@ -12,12 +12,10 @@ varnishd_SOURCES = \ cache_acceptor_poll.c \ cache_acceptor_kqueue.c \ cache_backend.c \ - cache_backend_random.c \ - cache_backend_round_robin.c \ - cache_backend_simple.c \ cache_ban.c \ cache_center.c \ cache_cli.c \ + cache_dir_random.c \ cache_dir_simple.c \ cache_expire.c \ cache_fetch.c \ diff --git a/varnish-cache/bin/varnishd/cache_backend_random.c b/varnish-cache/bin/varnishd/cache_backend_random.c deleted file mode 100644 index c4586e58..00000000 --- a/varnish-cache/bin/varnishd/cache_backend_random.c +++ /dev/null @@ -1,530 +0,0 @@ -/*- - * Copyright (c) 2006 Verdens Gang AS - * Copyright (c) 2006-2008 Linpro AS - * All rights reserved. - * - * Author: Cecilie Fritzvold - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id$ - * - */ - -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "shmlog.h" -#include "cache.h" -#include "vrt.h" - - -#if 0 -struct ber { - unsigned magic; -#define BER_MAGIC 0x645b03f4 - struct brspec *blist; - int count; -#if 0 - /* Store a hash of the backend info given in - * vcl for comparison when a new vcl file is - * uploaded. Not in use yet. - */ - unsigned hash; -#endif -}; - -struct brspec { - unsigned magic; -#define BRSPEC_MAGIC 0x5aa072a7 - struct brspec *next; - double limit; - char *hostname; - char *portname; - struct addrinfo *addr; - struct addrinfo *last_addr; - double dnsttl; - double dnstime; - unsigned dnsseq; - VTAILQ_HEAD(, vbe_conn) connlist; - int health; -}; - -/*-------------------------------------------------------------------- - * Try to get a socket connected to one of the addresses on the list. - * We start from the cached "last good" address and try all items on - * the list exactly once. - * If a new DNS lookup is made while we try, we start over and try the - * new list exactly once. - */ - -static int -ber_conn_try_list(const struct sess *sp, struct brspec *bs) -{ - struct addrinfo *ai, *from; - int s, loops; - unsigned myseq; - - CHECK_OBJ_NOTNULL(bs, BRSPEC_MAGIC); - if (bs->addr == NULL) - return (-1); - AN(bs->last_addr); - - /* Called with lock held */ - myseq = bs->dnsseq; - loops = 0; - ai = from = bs->last_addr; - while (1) { - - /* NB: releases/acquires lock */ - s = VBE_TryConnect(sp, ai); - - if (s >= 0) { - /* Update cached "last good" if still valid */ - if (myseq == bs->dnsseq) - bs->last_addr = ai; - return (s); - } - - if (myseq != bs->dnsseq) { - /* A DNS-lookup happended, try again from start */ - loops = 0; - from = bs->last_addr; - ai = from; - } else { - /* Try next one */ - ai = ai->ai_next; - if (ai == NULL) { - loops++; - ai = bs->addr; - } - } - if (loops == 1 && ai == from) - return (-1); - } -} - -/*--------------------------------------------------------------------*/ - -static const char * -ber_dns_lookup(struct backend *bp, struct brspec *bs) -{ - struct addrinfo *res, hint, *old; - int error; - - CHECK_OBJ_NOTNULL(bp, BACKEND_MAGIC); - CHECK_OBJ_NOTNULL(bs, BRSPEC_MAGIC); - - bs->dnstime = TIM_mono(); - - /* Let go of lock while we do sleepable stuff */ - UNLOCK(&bp->mtx); - - memset(&hint, 0, sizeof hint); - hint.ai_family = PF_UNSPEC; - hint.ai_socktype = SOCK_STREAM; - res = NULL; - error = getaddrinfo(bs->hostname, - bs->portname == NULL ? "http" : bs->portname, - &hint, &res); - LOCK(&bp->mtx); - if (error) { - if (res != NULL) - freeaddrinfo(res); - return(gai_strerror(error)); - } - bs->dnsseq++; - old = bs->addr; - bs->last_addr = res; - bs->addr = res; - if (old != NULL) - freeaddrinfo(old); - return (NULL); -} - -/*--------------------------------------------------------------------*/ - -static int -ber_conn_try(const struct sess *sp, struct backend *bp, struct brspec *bs) -{ - int s; - - LOCK(&bp->mtx); - - s = ber_conn_try_list(sp, bs); - if (s >= 0) { - bp->refcount++; - UNLOCK(&bp->mtx); - return (s); - } - - if (bs->dnstime + bs->dnsttl >= TIM_mono()) { - UNLOCK(&bp->mtx); - return (-1); - } - - (void)ber_dns_lookup(bp, bs); - - /* And try the entire list */ - s = ber_conn_try_list(sp, bs); - if (s >= 0) { - bp->refcount++; - UNLOCK(&bp->mtx); - return (s); - } - - UNLOCK(&bp->mtx); - return (-1); - -} - - -/* Get a backend connection ------------------------------------------ - * - * Get the next backend in the round-robin list, and connect to this. - * - * Try all cached backend connections for this backend, and use the - * first one that is looks like it is still connected. - * If that fails to get us a connection, create a new one, reusing a - * connection from the freelist, if possible. - * - * This function is slightly complicated by optimizations on bermtx. - */ - -static struct vbe_conn * -ber_nextfd(const struct sess *sp) -{ - struct vbe_conn *vc; - struct backend *bp; - int reuse = 0; - struct ber *ber; - struct brspec *bs; - int min_health = -10; - int num = 0; - double r = 0; - - CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); - CHECK_OBJ_NOTNULL(sp->backend, BACKEND_MAGIC); - bp = sp->backend; - CAST_OBJ_NOTNULL(ber, bp->priv, BER_MAGIC); - - r = (double)rand() / ((double)(RAND_MAX)+1.0); - bs = ber->blist; - CHECK_OBJ_NOTNULL(bs, BRSPEC_MAGIC); - while (r > bs->limit) { - bs = bs->next; - CHECK_OBJ_NOTNULL(bs, BRSPEC_MAGIC); - } - - /* If health is low (bad), use round-robin to find - * a server with better health (if possible). - */ - while (bs->health < min_health) { - bs = bs->next; - num++; - if (num > ber->count) { - min_health *= 10; - num = 0; - } - } - - while (1) { - LOCK(&bp->mtx); - vc = VTAILQ_FIRST(&bs->connlist); - if (vc != NULL) { - bp->refcount++; - assert(vc->backend == bp); - assert(vc->fd >= 0); - VTAILQ_REMOVE(&bs->connlist, vc, list); - } - UNLOCK(&bp->mtx); - if (vc == NULL) - break; - - if (VBE_CheckFd(vc->fd)) { - /* XXX locking of stats */ - VSL_stats->backend_reuse += reuse; - VSL_stats->backend_conn++; - return (vc); - } - VBE_ClosedFd(sp->wrk, vc); - } - - vc = VBE_NewConn(); - assert(vc->fd == -1); - AZ(vc->backend); - vc->fd = ber_conn_try(sp, bp, bs); - if (vc->fd < 0) { - VBE_ReleaseConn(vc); - VSL_stats->backend_fail++; - return (NULL); - } - vc->backend = bp; - vc->priv = bs; - VSL_stats->backend_conn++; - return (vc); - -} - -static struct vbe_conn * -ber_GetFd(const struct sess *sp) -{ - struct vbe_conn *vc; - unsigned n; - for (n = 1; n < 5; n++) { - vc = ber_nextfd(sp); - if (vc == NULL) { - AZ(usleep(100000 * n)); - continue; - } - assert(vc->fd >= 0); - assert(vc->backend == sp->backend); - WSL(sp->wrk, SLT_BackendXID, vc->fd, "%u", sp->xid); - WSP(sp, SLT_Backend, "%d %s", vc->fd, sp->backend->vcl_name); - return (vc); - } - return (NULL); -} - -/*--------------------------------------------------------------------*/ - -static void -ber_ClosedFd(struct worker *w, struct vbe_conn *vc) -{ - CHECK_OBJ_NOTNULL(vc, VBE_CONN_MAGIC); - CHECK_OBJ_NOTNULL(vc->backend, BACKEND_MAGIC); - assert(vc->fd >= 0); - WSL(w, SLT_BackendClose, vc->fd, "%s", vc->backend->vcl_name); - AZ(close(vc->fd)); - vc->fd = -1; - VBE_DropRef(vc->backend); - vc->backend = NULL; - VBE_ReleaseConn(vc); -} - -/*--------------------------------------------------------------------*/ - -static void -ber_RecycleFd(struct worker *w, struct vbe_conn *vc) -{ - struct brspec *bs; - - CHECK_OBJ_NOTNULL(vc, VBE_CONN_MAGIC); - CHECK_OBJ_NOTNULL(vc->backend, BACKEND_MAGIC); - CAST_OBJ_NOTNULL(bs, vc->priv, BRSPEC_MAGIC); - - assert(vc->fd >= 0); - WSL(w, SLT_BackendReuse, vc->fd, "%s", vc->backend->vcl_name); - LOCK(&vc->backend->mtx); - VSL_stats->backend_recycle++; - VTAILQ_INSERT_HEAD(&bs->connlist, vc, list); - VBE_DropRefLocked(vc->backend); -} - -/*--------------------------------------------------------------------*/ - -static void -ber_Cleanup(const struct backend *b) -{ - struct ber *ber; - struct vbe_conn *vbe; - struct brspec *bs, *bstmp; - - assert(b->refcount == 0); - CAST_OBJ_NOTNULL(ber, b->priv, BER_MAGIC); - - bs = ber->blist; - - do { - free(bs->portname); - free(bs->hostname); - freeaddrinfo(bs->addr); - while (1) { - vbe = VTAILQ_FIRST(&bs->connlist); - if (vbe == NULL) - break; - VTAILQ_REMOVE(&bs->connlist, vbe, list); - if (vbe->fd >= 0) - AZ(close(vbe->fd)); - free(vbe); - } - bstmp = bs; - bs = bs->next; - free(bstmp); - } while (bs != ber->blist); - - free(ber); -} - -/*--------------------------------------------------------------------*/ - -/* Will return the hostname of the first backend in the list */ -static const char * -ber_GetHostname(const struct backend *b) -{ - struct ber *ber; - - CHECK_OBJ_NOTNULL(b, BACKEND_MAGIC); - CAST_OBJ_NOTNULL(ber, b->priv, BER_MAGIC); - return (ber->blist->hostname); -} - -/*--------------------------------------------------------------------*/ - -/* This should maybe be divided into two separate functions. One for - * increasing/decreasing health, and one for "pulling" the health - * towards neutral (0) as time passes - */ -static void -ber_UpdateHealth(const struct sess *sp, const struct vbe_conn *vc, int add) -{ - struct brspec *bs, *first; - struct ber *ber; - - if (vc != NULL) { - CAST_OBJ_NOTNULL(bs, vc->priv, BRSPEC_MAGIC); - - if (bs->health + add >= -10000 || bs->health + add <= 10000) - bs->health += add; - } else { - CAST_OBJ_NOTNULL(ber, sp->backend->priv, BRSPEC_MAGIC); - first = ber->blist; - bs = first; - do { - bs = bs->next; - bs->health = (int)((double)bs->health / 2); - } while (bs != first); - } -} - -/*--------------------------------------------------------------------*/ - -struct backend_method backend_method_random = { - .name = "random", - .getfd = ber_GetFd, - .close = ber_ClosedFd, - .recycle = ber_RecycleFd, - .gethostname = ber_GetHostname, - .updatehealth = ber_UpdateHealth, - .cleanup = ber_Cleanup, -}; - -#endif - -/*--------------------------------------------------------------------*/ - -void -VRT_init_dir_random(struct cli *cli, struct director **bp, const struct vrt_dir_random *t) -{ - (void)cli; - (void)bp; - (void)t; - - -#if 0 - struct backend *b; - - if (VBE_AddBackend(&backend_method_random, t->ident, bp)) - return; /* reuse existing backend */ - - bp = *bp; - AN(t->name); - REPLACE(b->vcl_name, t->name); - struct backend *b; - struct ber *ber; - struct vrt_backend_entry *be; - struct brspec *bs = NULL; - struct brspec *bs_prev = NULL; - struct brspec *bs_first = NULL; - double limit = 0; - double default_weight; - - /* - * Scan existing backends to see if we can recycle one of them. - */ - - /* - * XXX: Do this by comparing a hash generated from this new - * XXX: backend with the earlier computed hashes from existing - * XXX: backends ? Should the hash be a parameter to this function, - * XXX: or computed here? - */ - - b = VBE_NewBackend(&backend_method_random); - - ber = calloc(sizeof *ber, 1); - XXXAN(ber); - ber->magic = BER_MAGIC; - ber->count = t->count; - - b->priv = ber; - - AN(t->name); - b->vcl_name = strdup(t->name); - XXXAN(b->vcl_name); - - default_weight = 1.0 / (double)t->count; - - be = t->bentry; - while (be != NULL) { - bs = calloc(sizeof *bs, 1); - XXXAN(bs); - bs->magic = BRSPEC_MAGIC; - AN(be->port); - bs->portname = strdup(be->port); - XXXAN(bs->portname); - - AN(be->host); - bs->hostname = strdup(be->host); - XXXAN(bs->hostname); - - if (!(t->weighted)) - be->weight = default_weight; - - limit += be->weight; - bs->limit = limit; - - bs->dnsttl = 300; - bs->health = 0; - - if (bs_first == NULL) - bs_first = bs; - - bs->next = bs_prev; - bs_prev = bs; - be = be->next; - } - XXXAN(bs_first); - bs_first->next = bs; - ber->blist = bs; - - *bp = b; -#endif -} - diff --git a/varnish-cache/bin/varnishd/cache_backend_round_robin.c b/varnish-cache/bin/varnishd/cache_backend_round_robin.c deleted file mode 100644 index c701e8cf..00000000 --- a/varnish-cache/bin/varnishd/cache_backend_round_robin.c +++ /dev/null @@ -1,492 +0,0 @@ -/*- - * Copyright (c) 2006 Verdens Gang AS - * Copyright (c) 2006-2008 Linpro AS - * All rights reserved. - * - * Author: Cecilie Fritzvold - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id$ - * - */ - -#if 0 - -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "shmlog.h" -#include "cache.h" -#include "vrt.h" - - -struct brr { - unsigned magic; -#define BRR_MAGIC 0x66f05894 - struct bspec *blist; - int count; -#if 0 - /* Store a hash of the backend info given in - * vcl for comparison when a new vcl file is - * uploaded. Not in use yet. - */ - unsigned hash; -#endif -}; - -struct bspec { - unsigned magic; -#define BSPEC_MAGIC 0x761d69c2 - struct bspec *next; - char *hostname; - char *portname; - struct addrinfo *addr; - struct addrinfo *last_addr; - double dnsttl; - double dnstime; - unsigned dnsseq; - VTAILQ_HEAD(, vbe_conn) connlist; - int health; -}; - -/*-------------------------------------------------------------------- - * Try to get a socket connected to one of the addresses on the list. - * We start from the cached "last good" address and try all items on - * the list exactly once. - * If a new DNS lookup is made while we try, we start over and try the - * new list exactly once. - */ - -static int -brr_conn_try_list(const struct sess *sp, struct bspec *bs) -{ - struct addrinfo *ai, *from; - int s, loops; - unsigned myseq; - - CHECK_OBJ_NOTNULL(bs, BSPEC_MAGIC); - if (bs->addr == NULL) - return (-1); - AN(bs->last_addr); - - /* Called with lock held */ - myseq = bs->dnsseq; - loops = 0; - ai = from = bs->last_addr; - while (1) { - - /* NB: releases/acquires lock */ - s = VBE_TryConnect(sp, ai); - - if (s >= 0) { - /* Update cached "last good" if still valid */ - if (myseq == bs->dnsseq) - bs->last_addr = ai; - return (s); - } - - if (myseq != bs->dnsseq) { - /* A DNS-lookup happended, try again from start */ - loops = 0; - from = bs->last_addr; - ai = from; - } else { - /* Try next one */ - ai = ai->ai_next; - if (ai == NULL) { - loops++; - ai = bs->addr; - } - } - if (loops == 1 && ai == from) - return (-1); - } -} - -/*--------------------------------------------------------------------*/ - -static const char * -brr_dns_lookup(struct backend *bp, struct bspec *bs) -{ - struct addrinfo *res, hint, *old; - int error; - - CHECK_OBJ_NOTNULL(bp, BACKEND_MAGIC); - CHECK_OBJ_NOTNULL(bs, BSPEC_MAGIC); - - bs->dnstime = TIM_mono(); - - /* Let go of lock while we do sleepable stuff */ - UNLOCK(&bp->mtx); - - memset(&hint, 0, sizeof hint); - hint.ai_family = PF_UNSPEC; - hint.ai_socktype = SOCK_STREAM; - res = NULL; - error = getaddrinfo(bs->hostname, - bs->portname == NULL ? "http" : bs->portname, - &hint, &res); - LOCK(&bp->mtx); - if (error) { - if (res != NULL) - freeaddrinfo(res); - return(gai_strerror(error)); - } - bs->dnsseq++; - old = bs->addr; - bs->last_addr = res; - bs->addr = res; - if (old != NULL) - freeaddrinfo(old); - return (NULL); -} - -/*--------------------------------------------------------------------*/ - -static int -brr_conn_try(const struct sess *sp, struct backend *bp, struct bspec *bs) -{ - int s; - - LOCK(&bp->mtx); - - s = brr_conn_try_list(sp, bs); - if (s >= 0) { - bp->refcount++; - UNLOCK(&bp->mtx); - return (s); - } - - if (bs->dnstime + bs->dnsttl >= TIM_mono()) { - UNLOCK(&bp->mtx); - return (-1); - } - - (void)brr_dns_lookup(bp, bs); - - /* And try the entire list */ - s = brr_conn_try_list(sp, bs); - if (s >= 0) { - bp->refcount++; - UNLOCK(&bp->mtx); - return (s); - } - - UNLOCK(&bp->mtx); - return (-1); -} - - -/* Get a backend connection ------------------------------------------ - * - * Get the next backend in the round-robin list, and connect to this. - * - * Try all cached backend connections for this backend, and use the - * first one that is looks like it is still connected. - * If that fails to get us a connection, create a new one, reusing a - * connection from the freelist, if possible. - * - * This function is slightly complicated by optimizations on brrmtx. - */ - -static struct vbe_conn * -brr_nextfd(const struct sess *sp) -{ - struct vbe_conn *vc; - struct backend *bp; - int reuse = 0; - struct brr *brr; - struct bspec *bs; - int min_health = -10; - int num = 0; - - CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); - CHECK_OBJ_NOTNULL(sp->backend, BACKEND_MAGIC); - bp = sp->backend; - CAST_OBJ_NOTNULL(brr, bp->priv, BRR_MAGIC); - - do { - bs = brr->blist = brr->blist->next; - num++; - if (num > brr->count) { - min_health *= 10; - num = 0; - } - } while (bs->health < min_health); - - while (1) { - LOCK(&bp->mtx); - vc = VTAILQ_FIRST(&bs->connlist); - if (vc != NULL) { - bp->refcount++; - assert(vc->backend == bp); - assert(vc->fd >= 0); - VTAILQ_REMOVE(&bs->connlist, vc, list); - } - UNLOCK(&bp->mtx); - if (vc == NULL) - break; - - if (VBE_CheckFd(vc->fd)) { - /* XXX locking of stats */ - VSL_stats->backend_reuse += reuse; - VSL_stats->backend_conn++; - return (vc); - } - VBE_ClosedFd(sp->wrk, vc); - } - - vc = VBE_NewConn(); - assert(vc->fd == -1); - AZ(vc->backend); - vc->fd = brr_conn_try(sp, bp, bs); - if (vc->fd < 0) { - VBE_ReleaseConn(vc); - VSL_stats->backend_fail++; - return (NULL); - } - vc->backend = bp; - vc->priv = bs; - VSL_stats->backend_conn++; - return (vc); -} - -static struct vbe_conn * -brr_GetFd(const struct sess *sp) -{ - struct vbe_conn *vc; - unsigned n; - for (n = 1; n < 5; n++) { - vc = brr_nextfd(sp); - if (vc == NULL) { - AZ(usleep(100000 * n)); - continue; - } - assert(vc->fd >= 0); - assert(vc->backend == sp->backend); - WSL(sp->wrk, SLT_BackendXID, vc->fd, "%u", sp->xid); - WSP(sp, SLT_Backend, "%d %s", vc->fd, sp->backend->vcl_name); - return (vc); - } - return (NULL); -} - -/*--------------------------------------------------------------------*/ - -static void -brr_ClosedFd(struct worker *w, struct vbe_conn *vc) -{ - CHECK_OBJ_NOTNULL(vc, VBE_CONN_MAGIC); - CHECK_OBJ_NOTNULL(vc->backend, BACKEND_MAGIC); - assert(vc->fd >= 0); - WSL(w, SLT_BackendClose, vc->fd, "%s", vc->backend->vcl_name); - AZ(close(vc->fd)); - vc->fd = -1; - VBE_DropRef(vc->backend); - vc->backend = NULL; - VBE_ReleaseConn(vc); -} - -/*--------------------------------------------------------------------*/ - -static void -brr_RecycleFd(struct worker *w, struct vbe_conn *vc) -{ - struct bspec *bs; - - CHECK_OBJ_NOTNULL(vc, VBE_CONN_MAGIC); - CHECK_OBJ_NOTNULL(vc->backend, BACKEND_MAGIC); - CAST_OBJ_NOTNULL(bs, vc->priv, BSPEC_MAGIC); - - assert(vc->fd >= 0); - WSL(w, SLT_BackendReuse, vc->fd, "%s", vc->backend->vcl_name); - LOCK(&vc->backend->mtx); - VSL_stats->backend_recycle++; - VTAILQ_INSERT_HEAD(&bs->connlist, vc, list); - VBE_DropRefLocked(vc->backend); -} - -/*--------------------------------------------------------------------*/ - -static void -brr_Cleanup(const struct backend *b) -{ - struct brr *brr; - struct vbe_conn *vbe; - struct bspec *bs, *bstmp; - - assert(b->refcount == 0); - CAST_OBJ_NOTNULL(brr, b->priv, BRR_MAGIC); - - bs = brr->blist; - - do { - free(bs->portname); - free(bs->hostname); - freeaddrinfo(bs->addr); - while (1) { - vbe = VTAILQ_FIRST(&bs->connlist); - if (vbe == NULL) - break; - VTAILQ_REMOVE(&bs->connlist, vbe, list); - if (vbe->fd >= 0) - AZ(close(vbe->fd)); - free(vbe); - } - bstmp = bs; - bs = bs->next; - free(bstmp); - } while (bs != brr->blist); - - free(brr); -} - -/*--------------------------------------------------------------------*/ - -/* Will return the hostname of the first backend in the list */ -static const char * -brr_GetHostname(const struct backend *b) -{ - struct brr *brr; - - CHECK_OBJ_NOTNULL(b, BACKEND_MAGIC); - CAST_OBJ_NOTNULL(brr, b->priv, BRR_MAGIC); - return (brr->blist->hostname); -} - -/*--------------------------------------------------------------------*/ - -/* This should maybe be divided into two separate functions. One for - * increasing/decreasing health, and one for "pulling" the health - * towards neutral (0) as time passes - */ -static void -brr_UpdateHealth(const struct sess *sp, const struct vbe_conn *vc, int add) -{ - struct bspec *bs, *first; - struct brr *brr; - - if (vc != NULL) { - - CAST_OBJ_NOTNULL(bs, vc->priv, BSPEC_MAGIC); - - if (bs->health + add >= -10000 || bs->health + add <= 10000) - bs->health += add; - } else { - CAST_OBJ_NOTNULL(brr, sp->backend->priv, BSPEC_MAGIC); - first = brr->blist; - bs = first; - do { - bs = bs->next; - bs->health = (int)((double)bs->health / 2); - } while (bs != first); - } -} - -/*--------------------------------------------------------------------*/ - -struct backend_method backend_method_round_robin = { - .name = "round_robin", - .getfd = brr_GetFd, - .close = brr_ClosedFd, - .recycle = brr_RecycleFd, - .gethostname = brr_GetHostname, - .updatehealth = brr_UpdateHealth, - .cleanup = brr_Cleanup, -}; - -/*--------------------------------------------------------------------*/ - -void -VRT_init_round_robin_backend(struct backend **bp, const struct vrt_round_robin_backend *t) -{ - struct backend *b; - struct brr *brr; - struct vrt_backend_entry *be; - struct bspec *bs = NULL; - struct bspec *bs_prev = NULL; - struct bspec *bs_first = NULL; - - /* - * Scan existing backends to see if we can recycle one of them. - */ - /* - * XXX: Do this by comparing a hash generated from this new - * XXX: backend with the earlier computed hashes from existing - * XXX: backends ? Should the hash be a parameter to this function, - * XXX: or computed here? - */ - - - b = VBE_NewBackend(&backend_method_round_robin); - - brr = calloc(sizeof *brr, 1); - XXXAN(brr); - brr->magic = BRR_MAGIC; - brr->count = t->count; - - b->priv = brr; - - AN(t->name); - b->vcl_name = strdup(t->name); - XXXAN(b->vcl_name); - - be = t->bentry; - while (be != NULL) { - bs = calloc(sizeof *bs, 1); - XXXAN(bs); - bs->magic = BSPEC_MAGIC; - AN(be->port); - bs->portname = strdup(be->port); - XXXAN(bs->portname); - - AN(be->host); - bs->hostname = strdup(be->host); - XXXAN(bs->hostname); - - bs->dnsttl = 300; - bs->health = 0; - - if (bs_first == NULL) - bs_first = bs; - - bs->next = bs_prev; - bs_prev = bs; - be = be->next; - } - - XXXAN(bs_first); - bs_first->next = bs; - brr->blist = bs; - - *bp = b; -} - -#endif diff --git a/varnish-cache/bin/varnishd/cache_backend_simple.c b/varnish-cache/bin/varnishd/cache_backend_simple.c deleted file mode 100644 index 60a6a83c..00000000 --- a/varnish-cache/bin/varnishd/cache_backend_simple.c +++ /dev/null @@ -1,349 +0,0 @@ -/*- - * Copyright (c) 2006 Verdens Gang AS - * Copyright (c) 2006-2008 Linpro AS - * All rights reserved. - * - * Author: Poul-Henning Kamp - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Id$ - * - */ - -#include -#include - -#include -#include -#include -#include -#include -#include - -#include "shmlog.h" -#include "cache.h" -#include "vrt.h" - -#if 0 - -struct bes { - unsigned magic; -#define BES_MAGIC 0x015e17ac - char *hostname; - char *portname; - struct addrinfo *addr; - struct addrinfo *last_addr; - double dnsttl; - double dnstime; - unsigned dnsseq; - VTAILQ_HEAD(, vbe_conn) connlist; -}; - -/*-------------------------------------------------------------------- - * Try to get a socket connected to one of the addresses on the list. - * We start from the cached "last good" address and try all items on - * the list exactly once. - * If a new DNS lookup is made while we try, we start over and try the - * new list exactly once. - */ - -static int -bes_conn_try_list(const struct sess *sp, struct bes *bes) -{ - struct addrinfo *ai, *from; - int s, loops; - unsigned myseq; - - CHECK_OBJ_NOTNULL(bes, BES_MAGIC); - if (bes->addr == NULL) - return (-1); - AN(bes->last_addr); - - /* Called with lock held */ - myseq = bes->dnsseq; - loops = 0; - ai = from = bes->last_addr; - while (1) { - - /* NB: releases/acquires lock */ - s = VBE_TryConnect(sp, ai); - - if (s >= 0) { - /* Update cached "last good" if still valid */ - if (myseq == bes->dnsseq) - bes->last_addr = ai; - return (s); - } - - if (myseq != bes->dnsseq) { - /* A DNS-lookup happended, try again from start */ - loops = 0; - from = bes->last_addr; - ai = from; - } else { - /* Try next one */ - ai = ai->ai_next; - if (ai == NULL) { - loops++; - ai = bes->addr; - } - } - if (loops == 1 && ai == from) - return (-1); - } -} - -/*--------------------------------------------------------------------*/ - -static const char * -bes_dns_lookup(struct backend *bp) -{ - struct addrinfo *res, hint, *old; - struct bes *bes; - int error; - - CHECK_OBJ_NOTNULL(bp, BACKEND_MAGIC); - CAST_OBJ_NOTNULL(bes, bp->priv, BES_MAGIC); - - bes->dnstime = TIM_mono(); - - /* Let go of lock while we do sleepable stuff */ - UNLOCK(&bp->mtx); - - memset(&hint, 0, sizeof hint); - hint.ai_family = PF_UNSPEC; - hint.ai_socktype = SOCK_STREAM; - res = NULL; - error = getaddrinfo(bes->hostname, - bes->portname == NULL ? "http" : bes->portname, - &hint, &res); - LOCK(&bp->mtx); - if (error) { - if (res != NULL) - freeaddrinfo(res); - return(gai_strerror(error)); - } - bes->dnsseq++; - old = bes->addr; - bes->last_addr = res; - bes->addr = res; - if (old != NULL) - freeaddrinfo(old); - return (NULL); -} - -/*--------------------------------------------------------------------*/ - -static int -bes_conn_try(const struct sess *sp, struct backend *bp) -{ - int s; - struct bes *bes; - - CAST_OBJ_NOTNULL(bes, bp->priv, BES_MAGIC); - - LOCK(&bp->mtx); - - s = bes_conn_try_list(sp, bes); - if (s >= 0) { - bp->refcount++; - UNLOCK(&bp->mtx); - return (s); - } - - if (bes->dnstime + bes->dnsttl >= TIM_mono()) { - UNLOCK(&bp->mtx); - return (-1); - } - - (void)bes_dns_lookup(bp); - - /* And try the entire list */ - s = bes_conn_try_list(sp, bes); - if (s >= 0) { - bp->refcount++; - UNLOCK(&bp->mtx); - return (s); - } - - UNLOCK(&bp->mtx); - return (-1); -} - -/* Get a backend connection ------------------------------------------ - * - * Try all cached backend connections for this backend, and use the - * first one that is looks like it is still connected. - * If that fails to get us a connection, create a new one, reusing a - * connection from the freelist, if possible. - * - * This function is slightly complicated by optimizations on besmtx. - */ - -static struct vbe_conn * -bes_nextfd(const struct sess *sp) -{ - struct vbe_conn *vc; - struct backend *bp; - int reuse = 0; - struct bes *bes; - - CHECK_OBJ_NOTNULL(sp, SESS_MAGIC); - CHECK_OBJ_NOTNULL(sp->backend, BACKEND_MAGIC); - bp = sp->backend; - CAST_OBJ_NOTNULL(bes, bp->priv, BES_MAGIC); - while (1) { - LOCK(&bp->mtx); - vc = VTAILQ_FIRST(&bes->connlist); - if (vc != NULL) { - bp->refcount++; - assert(vc->backend == bp); - assert(vc->fd >= 0); - VTAILQ_REMOVE(&bes->connlist, vc, list); - } - UNLOCK(&bp->mtx); - if (vc == NULL) - break; - - if (VBE_CheckFd(vc->fd)) { - /* XXX locking of stats */ - VSL_stats->backend_reuse += reuse; - VSL_stats->backend_conn++; - return (vc); - } - VBE_ClosedFd(sp->wrk, vc); - } - - vc = VBE_NewConn(); - assert(vc->fd == -1); - AZ(vc->backend); - vc->fd = bes_conn_try(sp, bp); - if (vc->fd < 0) { - VBE_ReleaseConn(vc); - VSL_stats->backend_fail++; - return (NULL); - } - vc->backend = bp; - VSL_stats->backend_conn++; - return (vc); -} - -/*--------------------------------------------------------------------*/ - -static struct vbe_conn * -bes_GetFd(const struct sess *sp) -{ - struct vbe_conn *vc; - unsigned n; - for (n = 1; n < 5; n++) { - vc = bes_nextfd(sp); - if (vc == NULL) { - AZ(usleep(100000 * n)); - continue; - } - assert(vc->fd >= 0); - assert(vc->backend == sp->backend); - WSL(sp->wrk, SLT_BackendXID, vc->fd, "%u", sp->xid); - WSP(sp, SLT_Backend, "%d %s", vc->fd, sp->backend->vcl_name); - return (vc); - } - return (NULL); -} - -/* Close a connection ------------------------------------------------*/ - -static void -bes_ClosedFd(struct worker *w, struct vbe_conn *vc) -{ - int i; - - CHECK_OBJ_NOTNULL(vc, VBE_CONN_MAGIC); - CHECK_OBJ_NOTNULL(vc->backend, BACKEND_MAGIC); - assert(vc->fd >= 0); - WSL(w, SLT_BackendClose, vc->fd, "%s", vc->backend->vcl_name); - i = close(vc->fd); - assert(i == 0 || errno == ECONNRESET || errno == ENOTCONN); - vc->fd = -1; - VBE_DropRef(vc->backend); - vc->backend = NULL; - VBE_ReleaseConn(vc); -} - -/* Recycle a connection ----------------------------------------------*/ - -static void -bes_RecycleFd(struct worker *w, struct vbe_conn *vc) -{ - struct bes *bes; - - CHECK_OBJ_NOTNULL(vc, VBE_CONN_MAGIC); - CHECK_OBJ_NOTNULL(vc->backend, BACKEND_MAGIC); - CAST_OBJ_NOTNULL(bes, vc->backend->priv, BES_MAGIC); - - assert(vc->fd >= 0); - WSL(w, SLT_BackendReuse, vc->fd, "%s", vc->backend->vcl_name); - LOCK(&vc->backend->mtx); - VSL_stats->backend_recycle++; - VTAILQ_INSERT_HEAD(&bes->connlist, vc, list); - VBE_DropRefLocked(vc->backend); -} - -/*--------------------------------------------------------------------*/ - -static void -bes_Cleanup(const struct backend *b) -{ - struct bes *bes; - struct vbe_conn *vbe; - - assert(b->refcount == 0); - CAST_OBJ_NOTNULL(bes, b->priv, BES_MAGIC); - free(bes->portname); - free(bes->hostname); - freeaddrinfo(bes->addr); - while (1) { - vbe = VTAILQ_FIRST(&bes->connlist); - if (vbe == NULL) - break; - VTAILQ_REMOVE(&bes->connlist, vbe, list); - if (vbe->fd >= 0) - AZ(close(vbe->fd)); - FREE_OBJ(vbe); - } - FREE_OBJ(bes); -} - -/*--------------------------------------------------------------------*/ - -static const char * -bes_GetHostname(const struct backend *b) -{ - struct bes *bes; - - CHECK_OBJ_NOTNULL(b, BACKEND_MAGIC); - CAST_OBJ_NOTNULL(bes, b->priv, BES_MAGIC); - return (bes->hostname); -} - - -#endif diff --git a/varnish-cache/bin/varnishd/cache_dir_random.c b/varnish-cache/bin/varnishd/cache_dir_random.c new file mode 100644 index 00000000..99042319 --- /dev/null +++ b/varnish-cache/bin/varnishd/cache_dir_random.c @@ -0,0 +1,139 @@ +/*- + * Copyright (c) 2006 Verdens Gang AS + * Copyright (c) 2006-2008 Linpro AS + * All rights reserved. + * + * Author: Poul-Henning Kamp + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id$ + * + */ + +#include +#include + +#include +#include +#include +#include + +#include "shmlog.h" +#include "cache.h" +#include "vrt.h" + +/*--------------------------------------------------------------------*/ + +struct vdi_random_host { + struct backend *backend; + unsigned weight; +}; + +struct vdi_random { + unsigned magic; +#define VDI_RANDOM_MAGIC 0x476d25b7 + struct director dir; + struct backend *backend; + unsigned nhosts; + struct vdi_random_host *hosts; +}; + + +static struct backend * +vdi_random_choose(struct sess *sp) +{ + struct vdi_random *vs; + uint32_t r; + struct vdi_random_host *vh; + + CHECK_OBJ_NOTNULL(sp->director, DIRECTOR_MAGIC); + CAST_OBJ_NOTNULL(vs, sp->director->priv, VDI_RANDOM_MAGIC); + r = random(); + r &= 0x7fffffff; + + for (vh = vs->hosts; ; vh++) + if (r < vh->weight) + return (vh->backend); + assert(0 != __LINE__); + return (NULL); +} + +static void +vdi_random_fini(struct director *d) +{ + struct vdi_random *vs; + + CHECK_OBJ_NOTNULL(d, DIRECTOR_MAGIC); + CAST_OBJ_NOTNULL(vs, d->priv, VDI_RANDOM_MAGIC); + + VBE_DropRef(vs->backend); + free(vs->hosts); + free(vs); +} + +void +VRT_init_dir_random(struct cli *cli, struct director **bp, const struct vrt_dir_random *t) +{ + struct vdi_random *vs; + const struct vrt_dir_random_entry *te; + struct vdi_random_host *vh; + double s, a, b; + unsigned v; + int i; + + (void)cli; + + vs = calloc(sizeof *vs, 1); + XXXAN(vs); + vs->hosts = calloc(sizeof *vh, t->nmember); + XXXAN(vs->hosts); + + vs->magic = VDI_RANDOM_MAGIC; + vs->dir.magic = DIRECTOR_MAGIC; + vs->dir.priv = vs; + vs->dir.name = "random"; + vs->dir.choose = vdi_random_choose; + vs->dir.fini = vdi_random_fini; + + s = 0; + vh = vs->hosts; + te = t->members; + for (i = 0; i < t->nmember; i++, vh++, te++) { + s += te->weight; + vh->backend = VBE_AddBackend(cli, te->host); + } + + /* Normalize weights */ + i = 0; + a = 0.0; + for (te = t->members; te->host != NULL; te++, i++) { + /* First normalize the specified weight in FP */ + b = te->weight / s; + /* Then accumulate to eliminate rounding errors */ + a += b; + /* Convert to unsigned in random() range */ + v = (unsigned)((1U<<31) * a); + vs->hosts[i].weight = v; + } + *bp = &vs->dir; +} -- 2.39.5