Commit 31025b45 authored by Petter Knudsen's avatar Petter Knudsen

Added a round robin director. The round robin director can be created like this:

director batman round-robin {
	{ .backend = b1; }
	{ .backend = b2; }
	{ .backend = b3; }
}

sub vcl_recv {
	set req.backend = batman;
}

The backend will then be chosen in a round robin fashion.



git-svn-id: http://www.varnish-cache.org/svn/trunk@2943 d4fa192b-c00b-0410-8231-f00ffab90ce4
parent 8588af1c
......@@ -18,6 +18,7 @@ varnishd_SOURCES = \
cache_center.c \
cache_cli.c \
cache_dir_random.c \
cache_dir_round_robin.c \
cache_dir_simple.c \
cache_expire.c \
cache_fetch.c \
......
/*-
* Copyright (c) 2006 Verdens Gang AS
* Copyright (c) 2006-2008 Linpro AS
* All rights reserved.
*
* Author: Petter Knudsen <petter@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: cache_dir_round_robin.c 2906 2008-07-08 10:29:07Z phk $
*
*/
#include "config.h"
#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_round_robin_host {
struct backend *backend;
};
struct vdi_round_robin {
unsigned magic;
#define VDI_ROUND_ROBIN_MAGIC 0x2114a178
struct director dir;
struct backend *backend;
struct vdi_round_robin_host *hosts;
unsigned nhosts;
unsigned next_host;
};
static struct backend *
vdi_round_robin_choose(struct sess *sp)
{
struct vdi_round_robin *vs;
struct backend *backend;
CHECK_OBJ_NOTNULL(sp->director, DIRECTOR_MAGIC);
CAST_OBJ_NOTNULL(vs, sp->director->priv, VDI_ROUND_ROBIN_MAGIC);
backend = vs->hosts[ vs->next_host ].backend;
vs->next_host = (vs->next_host + 1) % vs->nhosts;
return (backend);
}
static void
vdi_round_robin_fini(struct director *d)
{
int i;
struct vdi_round_robin *vs;
struct vdi_round_robin_host *vh;
CHECK_OBJ_NOTNULL(d, DIRECTOR_MAGIC);
CAST_OBJ_NOTNULL(vs, d->priv, VDI_ROUND_ROBIN_MAGIC);
vh = vs->hosts;
for (i = 0; i < vs->nhosts; i++, vh++)
VBE_DropRef(vh->backend);
free(vs->hosts);
vs->dir.magic = 0;
vs->next_host = 0;
FREE_OBJ(vs);
}
void
VRT_init_dir_round_robin(struct cli *cli, struct director **bp, const struct vrt_dir_round_robin *t)
{
struct vdi_round_robin *vs;
const struct vrt_dir_round_robin_entry *te;
struct vdi_round_robin_host *vh;
int i;
(void)cli;
ALLOC_OBJ(vs, VDI_ROUND_ROBIN_MAGIC);
XXXAN(vs);
vs->hosts = calloc(sizeof *vh, t->nmember);
XXXAN(vs->hosts);
vs->dir.magic = DIRECTOR_MAGIC;
vs->dir.priv = vs;
vs->dir.name = "round_robin";
vs->dir.choose = vdi_round_robin_choose;
vs->dir.fini = vdi_round_robin_fini;
vh = vs->hosts;
te = t->members;
for (i = 0; i < t->nmember; i++, vh++, te++)
vh->backend = VBE_AddBackend(cli, te->host);
vs->nhosts = t->nmember;
vs->next_host = 0;
*bp = &vs->dir;
}
# $Id$
test "Test round robin director"
server s1 -listen 127.0.0.1:2000 {
rxreq
txresp -body "1"
} -start
server s2 -listen 127.0.0.1:3000 {
rxreq
txresp -body "22"
} -start
server s3 -listen 127.0.0.1:4000 {
rxreq
txresp -body "333"
} -start
server s4 -listen 127.0.0.1:5000 {
rxreq
txresp -body "4444"
} -start
varnish v1 -vcl+backend {
director batman round-robin {
{ .backend = s1; }
{ .backend = s2; }
{ .backend = s3; }
{ .backend = s4; }
}
sub vcl_recv {
set req.backend = batman;
}
} -start
client c1 {
timeout 3
txreq -url "/foo1"
rxresp
expect resp.http.content-length == 1
txreq -url "/foo2"
rxresp
expect resp.http.content-length == 2
txreq -url "/foo3"
rxresp
expect resp.http.content-length == 3
txreq -url "/foo4"
rxresp
expect resp.http.content-length == 4
} -run
server s1 -start
server s2 -start
client c2 {
timeout 3
txreq -url "/foo11"
rxresp
expect resp.http.content-length == 1
txreq -url "/foo22"
rxresp
expect resp.http.content-length == 2
} -run
......@@ -91,6 +91,21 @@ struct vrt_dir_random {
const struct vrt_dir_random_entry *members;
};
/*
* A director with round robin selection
*/
struct vrt_dir_round_robin_entry {
const struct vrt_backend *host;
};
struct vrt_dir_round_robin {
const char *name;
unsigned nmember;
const struct vrt_dir_round_robin_entry *members;
};
/*
* other stuff.
* XXX: document when bored
......@@ -147,6 +162,7 @@ void VRT_Rollback(struct sess *sp);
/* Backend related */
void VRT_init_dir_simple(struct cli *, struct director **, const struct vrt_dir_simple *);
void VRT_init_dir_random(struct cli *, struct director **, const struct vrt_dir_random *);
void VRT_init_dir_round_robin(struct cli *, struct director **, const struct vrt_dir_round_robin *);
void VRT_fini_dir(struct cli *, struct director *);
char *VRT_IP_string(const struct sess *sp, const struct sockaddr *sa);
......
......@@ -14,6 +14,7 @@ libvcl_la_SOURCES = \
vcc_backend.c \
vcc_compile.c \
vcc_dir_random.c \
vcc_dir_round_robin.c \
vcc_parse.c \
vcc_fixed_token.c \
vcc_obj.c \
......
......@@ -656,6 +656,7 @@ static const struct dirlist {
parsedirector_f *func;
} dirlist[] = {
{ "random", vcc_ParseRandomDirector },
{ "round-robin", vcc_ParseRoundRobinDirector },
{ NULL, NULL }
};
......
......@@ -178,6 +178,9 @@ void *TlAlloc(struct tokenlist *tl, unsigned len);
/* vcc_dir_random.c */
parsedirector_f vcc_ParseRandomDirector;
/* vcc_dir_round_robin.c */
parsedirector_f vcc_ParseRoundRobinDirector;
/* vcc_obj.c */
extern struct var vcc_vars[];
......
/*-
* Copyright (c) 2006 Verdens Gang AS
* Copyright (c) 2006-2008 Linpro AS
* All rights reserved.
*
* Author: Petter Knudsen <petter@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: vcc_dir_random.c 2900 2008-07-08 07:30:42Z phk $
*/
#include "config.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include "vsb.h"
#include "vcc_priv.h"
#include "vcc_compile.h"
#include "libvarnish.h"
/*--------------------------------------------------------------------
* Parse directors
*/
void
vcc_ParseRoundRobinDirector(struct tokenlist *tl, const struct token *t_policy, const struct token *t_dir)
{
struct token *t_field, *t_be;
int nbh, nelem;
struct fld_spec *fs;
fs = vcc_FldSpec(tl, "!backend", NULL);
Fc(tl, 0,
"\nstatic const struct vrt_dir_round_robin_entry vdrre_%.*s[] = {\n",
PF(t_dir));
for (nelem = 0; tl->t->tok != '}'; nelem++) { /* List of members */
t_be = tl->t;
vcc_ResetFldSpec(fs);
nbh = -1;
ExpectErr(tl, '{');
vcc_NextToken(tl);
Fc(tl, 0, "\t{");
while (tl->t->tok != '}') { /* Member fields */
vcc_IsField(tl, &t_field, fs);
ERRCHK(tl);
if (vcc_IdIs(t_field, "backend")) {
vcc_ParseBackendHost(tl, &nbh,
t_dir, t_policy, nelem);
Fc(tl, 0, " .host = &bh_%d,", nbh);
ERRCHK(tl);
} else {
ErrInternal(tl);
}
}
vcc_FieldsOk(tl, fs);
if (tl->err) {
vsb_printf(tl->sb,
"\nIn member host specfication starting at:\n");
vcc_ErrWhere(tl, t_be);
return;
}
Fc(tl, 0, " },\n");
vcc_NextToken(tl);
}
Fc(tl, 0, "};\n");
Fc(tl, 0,
"\nstatic const struct vrt_dir_round_robin vdrr_%.*s = {\n",
PF(t_dir));
Fc(tl, 0, "\t.name = \"%.*s\",\n", PF(t_dir));
Fc(tl, 0, "\t.nmember = %d,\n", nelem);
Fc(tl, 0, "\t.members = vdrre_%.*s,\n", PF(t_dir));
Fc(tl, 0, "};\n");
Fi(tl, 0,
"\tVRT_init_dir_round_robin(cli, &VGC_backend_%.*s , &vdrr_%.*s);\n",
PF(t_dir), PF(t_dir));
Ff(tl, 0, "\tVRT_fini_dir(cli, VGC_backend_%.*s);\n", PF(t_dir));
}
......@@ -430,6 +430,21 @@ vcl_output_lang_h(struct vsb *sb)
vsb_cat(sb, "};\n");
vsb_cat(sb, "\n");
vsb_cat(sb, "/*\n");
vsb_cat(sb, " * A director with round robin selection\n");
vsb_cat(sb, " */\n");
vsb_cat(sb, "\n");
vsb_cat(sb, "struct vrt_dir_round_robin_entry {\n");
vsb_cat(sb, " const struct vrt_backend *host;\n");
vsb_cat(sb, "};\n");
vsb_cat(sb, "\n");
vsb_cat(sb, "struct vrt_dir_round_robin {\n");
vsb_cat(sb, " const char *name;\n");
vsb_cat(sb, " unsigned nmember;\n");
vsb_cat(sb, " const struct vrt_dir_round_robin_entry *members;\n");
vsb_cat(sb, "};\n");
vsb_cat(sb, "\n");
vsb_cat(sb, "\n");
vsb_cat(sb, "/*\n");
vsb_cat(sb, " * other stuff.\n");
vsb_cat(sb, " * XXX: document when bored\n");
vsb_cat(sb, " */\n");
......@@ -485,6 +500,7 @@ vcl_output_lang_h(struct vsb *sb)
vsb_cat(sb, "/* Backend related */\n");
vsb_cat(sb, "void VRT_init_dir_simple(struct cli *, struct director **, const struct vrt_dir_simple *);\n");
vsb_cat(sb, "void VRT_init_dir_random(struct cli *, struct director **, const struct vrt_dir_random *);\n");
vsb_cat(sb, "void VRT_init_dir_round_robin(struct cli *, struct director **, const struct vrt_dir_round_robin *);\n");
vsb_cat(sb, "void VRT_fini_dir(struct cli *, struct director *);\n");
vsb_cat(sb, "\n");
vsb_cat(sb, "char *VRT_IP_string(const struct sess *sp, const struct sockaddr *sa);\n");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment