r2442 - trunk/varnish-cache/bin/varnishd

phk at projects.linpro.no phk at projects.linpro.no
Thu Feb 7 10:54:44 CET 2008


Author: phk
Date: 2008-02-07 10:54:42 +0100 (Thu, 07 Feb 2008)
New Revision: 2442

Added:
   trunk/varnish-cache/bin/varnishd/cache_dir_random.c
Removed:
   trunk/varnish-cache/bin/varnishd/cache_backend_random.c
   trunk/varnish-cache/bin/varnishd/cache_backend_round_robin.c
   trunk/varnish-cache/bin/varnishd/cache_backend_simple.c
Modified:
   trunk/varnish-cache/bin/varnishd/Makefile.am
Log:
Make the random director work, and remove the old code.


Modified: trunk/varnish-cache/bin/varnishd/Makefile.am
===================================================================
--- trunk/varnish-cache/bin/varnishd/Makefile.am	2008-02-07 09:53:28 UTC (rev 2441)
+++ trunk/varnish-cache/bin/varnishd/Makefile.am	2008-02-07 09:54:42 UTC (rev 2442)
@@ -12,12 +12,10 @@
 	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 \

Deleted: trunk/varnish-cache/bin/varnishd/cache_backend_random.c
===================================================================
--- trunk/varnish-cache/bin/varnishd/cache_backend_random.c	2008-02-07 09:53:28 UTC (rev 2441)
+++ trunk/varnish-cache/bin/varnishd/cache_backend_random.c	2008-02-07 09:54:42 UTC (rev 2442)
@@ -1,530 +0,0 @@
-/*-
- * Copyright (c) 2006 Verdens Gang AS
- * Copyright (c) 2006-2008 Linpro AS
- * All rights reserved.
- *
- * Author: Cecilie Fritzvold <cecilihf at linpro.no>
- *
- * 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 <sys/types.h>
-#include <sys/socket.h>
-
-#include <netdb.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#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
-}
-

Deleted: trunk/varnish-cache/bin/varnishd/cache_backend_round_robin.c
===================================================================
--- trunk/varnish-cache/bin/varnishd/cache_backend_round_robin.c	2008-02-07 09:53:28 UTC (rev 2441)
+++ trunk/varnish-cache/bin/varnishd/cache_backend_round_robin.c	2008-02-07 09:54:42 UTC (rev 2442)
@@ -1,492 +0,0 @@
-/*-
- * Copyright (c) 2006 Verdens Gang AS
- * Copyright (c) 2006-2008 Linpro AS
- * All rights reserved.
- *
- * Author: Cecilie Fritzvold <cecilihf at linpro.no>
- *
- * 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 <sys/types.h>
-#include <sys/socket.h>
-
-#include <netdb.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#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

Deleted: trunk/varnish-cache/bin/varnishd/cache_backend_simple.c
===================================================================
--- trunk/varnish-cache/bin/varnishd/cache_backend_simple.c	2008-02-07 09:53:28 UTC (rev 2441)
+++ trunk/varnish-cache/bin/varnishd/cache_backend_simple.c	2008-02-07 09:54:42 UTC (rev 2442)
@@ -1,349 +0,0 @@
-/*-
- * Copyright (c) 2006 Verdens Gang AS
- * Copyright (c) 2006-2008 Linpro AS
- * All rights reserved.
- *
- * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
- *
- * 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 <sys/types.h>
-#include <sys/socket.h>
-
-#include <netdb.h>
-#include <errno.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#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

Added: trunk/varnish-cache/bin/varnishd/cache_dir_random.c
===================================================================
--- trunk/varnish-cache/bin/varnishd/cache_dir_random.c	                        (rev 0)
+++ trunk/varnish-cache/bin/varnishd/cache_dir_random.c	2008-02-07 09:54:42 UTC (rev 2442)
@@ -0,0 +1,139 @@
+/*-
+ * Copyright (c) 2006 Verdens Gang AS
+ * Copyright (c) 2006-2008 Linpro AS
+ * All rights reserved.
+ *
+ * Author: Poul-Henning Kamp <phk at phk.freebsd.dk>
+ *
+ * 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 <sys/types.h>
+#include <sys/socket.h>
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#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;
+}




More information about the varnish-commit mailing list