cache_ban.c \
cache_center.c \
cache_cli.c \
+ cache_dir_simple.c \
cache_expire.c \
cache_fetch.c \
cache_hash.c \
struct workreq;
struct addrinfo;
struct esi_bit;
+struct vrt_backend;
/*--------------------------------------------------------------------*/
VTAILQ_ENTRY(sess) list;
+ struct director *director;
struct backend *backend;
struct bereq *bereq;
struct object *obj;
const char **hashptr;
};
+/* -------------------------------------------------------------------
+ * A director is a piece of code which selects one of possibly multiple
+ * backends to use.
+ */
+
+typedef struct backend *vdi_choose_f(struct sess *sp);
+typedef void vdi_fini_f(struct director *d);
+
+struct director {
+ unsigned magic;
+#define DIRECTOR_MAGIC 0x3336351d
+ const char *name;
+ vdi_choose_f *choose;
+ vdi_fini_f *fini;
+ void *priv;
+};
+
/* -------------------------------------------------------------------*/
/* Backend connection */
void *priv;
};
-
-/* Backend method */
-typedef struct vbe_conn *vbe_getfd_f(const struct sess *sp);
-typedef void vbe_close_f(struct worker *w, struct vbe_conn *vc);
-typedef void vbe_recycle_f(struct worker *w, struct vbe_conn *vc);
-typedef void vbe_init_f(void);
-typedef const char *vbe_gethostname_f(const struct backend *);
-typedef void vbe_cleanup_f(const struct backend *);
-typedef void vbe_updatehealth_f(const struct sess *sp, const struct vbe_conn *vc, int);
-
-struct backend_method {
- const char *name;
- vbe_getfd_f *getfd;
- vbe_close_f *close;
- vbe_recycle_f *recycle;
- vbe_cleanup_f *cleanup;
- vbe_gethostname_f *gethostname;
- vbe_updatehealth_f *updatehealth;
- vbe_init_f *init;
-};
-
-/* Backend indstance */
-struct backend {
- unsigned magic;
-#define BACKEND_MAGIC 0x64c4c7c6
- char *vcl_name;
-
- VTAILQ_ENTRY(backend) list;
- int refcount;
- pthread_mutex_t mtx;
-
- struct backend_method *method;
- const char *ident;
- void *priv;
-
- int health;
- double last_check;
- int minute_limit;
-};
-
/*
* NB: This list is not locked, it is only ever manipulated from the
* cachers CLI thread.
/* cache_backend.c */
void VBE_Init(void);
-struct vbe_conn *VBE_GetFd(const struct sess *sp);
+struct vbe_conn *VBE_GetFd(struct sess *sp);
void VBE_ClosedFd(struct worker *w, struct vbe_conn *vc);
void VBE_RecycleFd(struct worker *w, struct vbe_conn *vc);
struct bereq * VBE_new_bereq(void);
extern struct backendlist backendlist;
void VBE_DropRef(struct backend *);
void VBE_DropRefLocked(struct backend *);
-int VBE_AddBackend(struct backend_method *method, const char *ident, struct backend **be);
+struct backend *VBE_AddBackend(struct cli *cli, const struct vrt_backend *vb);
struct vbe_conn *VBE_NewConn(void);
void VBE_ReleaseConn(struct vbe_conn *);
void VBE_UpdateHealth(const struct sess *sp, const struct vbe_conn *, int);
int VBE_TryConnect(const struct sess *sp, const struct addrinfo *ai);
int VBE_CheckFd(int fd);
-/* cache_backend_simple.c */
-extern struct backend_method backend_method_simple;
-extern struct backend_method backend_method_random;
-extern struct backend_method backend_method_round_robin;
-
/* cache_ban.c */
void AddBan(const char *, int hash);
void BAN_Init(void);
*
*/
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "heritage.h"
#include "shmlog.h"
#include "cache.h"
+#include "vrt.h"
+#include "cli_priv.h"
+
+/* Backend indstance */
+struct backend {
+ unsigned magic;
+#define BACKEND_MAGIC 0x64c4c7c6
+ char *vcl_name;
+
+ struct vrt_backend vrt[1];
+
+ VTAILQ_ENTRY(backend) list;
+ int refcount;
+ pthread_mutex_t mtx;
+
+ const char *ident;
+ struct addrinfo *ai;
+ struct addrinfo *last_ai;
+
+ VTAILQ_HEAD(, vbe_conn) connlist;
+
+ int health;
+ double last_check;
+};
static VTAILQ_HEAD(,bereq) bereq_head = VTAILQ_HEAD_INITIALIZER(bereq_head);
static VTAILQ_HEAD(,vbe_conn) vbe_head = VTAILQ_HEAD_INITIALIZER(vbe_head);
VBE_DropRefLocked(struct backend *b)
{
int i;
+ struct vbe_conn *vbe, *vbe2;
CHECK_OBJ_NOTNULL(b, BACKEND_MAGIC);
i = --b->refcount;
- if (i == 0) {
- ASSERT_CLI(); /* XXX: ?? */
- VTAILQ_REMOVE(&backendlist, b, list);
- }
UNLOCK(&b->mtx);
if (i)
return;
+
+ ASSERT_CLI(); /* XXX: ?? */
+ VTAILQ_REMOVE(&backendlist, b, list);
+ VTAILQ_FOREACH_SAFE(vbe, &b->connlist, list, vbe2) {
+ VTAILQ_REMOVE(&b->connlist, vbe, list);
+ if (vbe->fd >= 0)
+ AZ(close(vbe->fd));
+ FREE_OBJ(vbe);
+ }
+ free(TRUST_ME(b->vrt->ident));
+ free(TRUST_ME(b->vrt->hostname));
+ free(TRUST_ME(b->vrt->portname));
b->magic = 0;
- b->method->cleanup(b);
- free(b->vcl_name);
free(b);
}
VBE_DropRefLocked(b);
}
+/*--------------------------------------------------------------------
+ * 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 backend *bp)
+{
+ struct addrinfo *ai, *from;
+ int s, loops;
+
+ CHECK_OBJ_NOTNULL(bp, BACKEND_MAGIC);
+ if (bp->last_ai == NULL)
+ return (-1);
+ AN(bp->ai);
+
+ /* Called with lock held */
+ loops = 0;
+ ai = from = bp->last_ai;
+ while (1) {
+
+ /* NB: releases/acquires backend lock */
+ s = VBE_TryConnect(sp, ai);
+
+ if (s >= 0) {
+ bp->last_ai = ai;
+ return (s);
+ }
+
+ /* Try next one */
+ ai = ai->ai_next;
+ if (ai == NULL) {
+ loops++;
+ ai = bp->ai;
+ }
+ if (loops == 1 && ai == from)
+ return (-1);
+ }
+}
+
+
+/*--------------------------------------------------------------------*/
+
+static int
+bes_conn_try(const struct sess *sp, struct backend *bp)
+{
+ int s;
+
+ LOCK(&bp->mtx);
+
+ s = bes_conn_try_list(sp, bp);
+ if (s >= 0) {
+ bp->refcount++;
+ UNLOCK(&bp->mtx);
+ return (s);
+ }
+ UNLOCK(&bp->mtx);
+ return (-1);
+}
+
/*--------------------------------------------------------------------*/
struct vbe_conn *
-VBE_GetFd(const struct sess *sp)
+VBE_GetFd(struct sess *sp)
{
+ struct backend *bp;
+ struct vbe_conn *vc;
CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
- CHECK_OBJ_NOTNULL(sp->backend, BACKEND_MAGIC);
- AN(sp->backend->method);
- AN(sp->backend->method->getfd);
- return(sp->backend->method->getfd(sp));
+ CHECK_OBJ_NOTNULL(sp->director, DIRECTOR_MAGIC);
+ bp = sp->director->choose(sp);
+ CHECK_OBJ_NOTNULL(bp, BACKEND_MAGIC);
+ sp->backend = bp;
+
+ while (1) {
+ LOCK(&bp->mtx);
+ vc = VTAILQ_FIRST(&bp->connlist);
+ if (vc != NULL) {
+ bp->refcount++;
+ assert(vc->backend == bp);
+ assert(vc->fd >= 0);
+ VTAILQ_REMOVE(&bp->connlist, vc, list);
+ }
+ UNLOCK(&bp->mtx);
+ if (vc == NULL)
+ break;
+ if (VBE_CheckFd(vc->fd)) {
+ /* XXX locking of stats */
+ VSL_stats->backend_reuse += 1;
+ 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);
}
/* Close a connection ------------------------------------------------*/
VBE_ClosedFd(struct worker *w, struct vbe_conn *vc)
{
struct backend *b;
+ int i;
CHECK_OBJ_NOTNULL(vc, VBE_CONN_MAGIC);
CHECK_OBJ_NOTNULL(vc->backend, BACKEND_MAGIC);
b = vc->backend;
- AN(b->method);
- AN(b->method->close);
- b->method->close(w, vc);
+ 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);
CHECK_OBJ_NOTNULL(b, BACKEND_MAGIC);
}
void
VBE_RecycleFd(struct worker *w, struct vbe_conn *vc)
{
- struct backend *b;
+ struct backend *bp;
CHECK_OBJ_NOTNULL(vc, VBE_CONN_MAGIC);
CHECK_OBJ_NOTNULL(vc->backend, BACKEND_MAGIC);
- b = vc->backend;
- AN(b->method);
- AN(b->method->recycle);
- b->method->recycle(w, vc);
- CHECK_OBJ_NOTNULL(b, BACKEND_MAGIC);
+ assert(vc->fd >= 0);
+ bp = vc->backend;
+ WSL(w, SLT_BackendReuse, vc->fd, "%s", vc->backend->vcl_name);
+ LOCK(&vc->backend->mtx);
+ VSL_stats->backend_recycle++;
+ VTAILQ_INSERT_HEAD(&bp->connlist, vc, list);
+ VBE_DropRefLocked(vc->backend);
+ CHECK_OBJ_NOTNULL(bp, BACKEND_MAGIC);
}
/* Update health ----------------------------------------------------*/
void
VBE_UpdateHealth(const struct sess *sp, const struct vbe_conn *vc, int a)
{
+ (void)sp;
+ (void)vc;
+ (void)a;
+#if 0
+ INCOMPL();
struct backend *b;
if (vc != NULL) {
if(b->method->updatehealth != NULL)
b->method->updatehealth(sp, vc, a);
CHECK_OBJ_NOTNULL(b, BACKEND_MAGIC);
+#endif
}
-/*--------------------------------------------------------------------*/
+/*--------------------------------------------------------------------
+ * DNS lookup of backend host/port
+ */
static void
-VBE_AddBackendMethod(const struct backend_method *bem)
+vbe_dns_lookup(struct cli *cli, struct backend *bp)
{
-
- if (bem->init != NULL)
- bem->init();
+ int error;
+ struct addrinfo *res, hint, *old;
+
+ CHECK_OBJ_NOTNULL(bp, BACKEND_MAGIC);
+
+ memset(&hint, 0, sizeof hint);
+ hint.ai_family = PF_UNSPEC;
+ hint.ai_socktype = SOCK_STREAM;
+ res = NULL;
+ error = getaddrinfo(bp->vrt->hostname, bp->vrt->portname,
+ &hint, &res);
+ if (error) {
+ if (res != NULL)
+ freeaddrinfo(res);
+ /*
+ * We cannot point to the source code any more, it may
+ * be long gone from memory. We already checked over in
+ * the VCL compiler, so this is only relevant for refreshes.
+ * XXX: which we do when exactly ?
+ */
+ cli_out(cli, "DNS(/hosts) lookup failed for (%s/%s): %s",
+ bp->vrt->hostname, bp->vrt->portname, gai_strerror(error));
+ return;
+ }
+ LOCK(&bp->mtx);
+ old = bp->ai;
+ bp->ai = res;
+ bp->last_ai = res;
+ UNLOCK(&bp->mtx);
+ if (old != NULL)
+ freeaddrinfo(old);
}
/*--------------------------------------------------------------------
* and return zero.
*/
-int
-VBE_AddBackend(struct backend_method *method, const char *ident, struct backend **be)
+struct backend *
+VBE_AddBackend(struct cli *cli, const struct vrt_backend *vb)
{
struct backend *b;
+ AN(vb->hostname);
+ AN(vb->portname);
+ AN(vb->ident);
+ (void)cli;
ASSERT_CLI();
VTAILQ_FOREACH(b, &backendlist, list) {
CHECK_OBJ_NOTNULL(b, BACKEND_MAGIC);
- if (b->method != method)
- continue;
- if (strcmp(b->ident, ident))
+ if (strcmp(b->ident, vb->ident))
continue;
b->refcount++;
- *be = b;
- return (1);
+ return (b);
}
b = calloc(sizeof *b, 1);
XXXAN(b);
b->magic = BACKEND_MAGIC;
- b->method = method;
- b->ident = strdup(ident);
- XXXAN(b->ident);
+ VTAILQ_INIT(&b->connlist);
+
+ memcpy(b->vrt, vb, sizeof *vb);
+ /*
+ * This backend may live longer than the VCL that instantiated it
+ * so we cannot simply reference the VCL's copy of the strings.
+ */
+ b->vrt->ident = strdup(vb->ident);
+ XXXAN(b->vrt->ident);
+ b->vrt->hostname = strdup(vb->hostname);
+ XXXAN(b->vrt->hostname);
+ b->vrt->portname = strdup(vb->portname);
+ XXXAN(b->vrt->portname);
MTX_INIT(&b->mtx);
b->refcount = 1;
+ vbe_dns_lookup(cli, b);
+
b->last_check = TIM_mono();
- b->minute_limit = 1;
+
+ vbe_dns_lookup(cli, b);
VTAILQ_INSERT_TAIL(&backendlist, b, list);
- *be = b;
- return (0);
+ return (b);
}
+
/*--------------------------------------------------------------------*/
void
-VBE_Init(void)
+VRT_fini_dir(struct cli *cli, struct director *b)
{
- MTX_INIT(&VBE_mtx);
- VBE_AddBackendMethod(&backend_method_simple);
- VBE_AddBackendMethod(&backend_method_random);
+ ASSERT_CLI();
#if 0
- VBE_AddBackendMethod(&backend_method_round_robin);
+ VBE_DropRef(b);
+#else
+ (void)b;
+ (void)cli;
#endif
}
+/*--------------------------------------------------------------------*/
+
+void
+VBE_Init(void)
+{
+
+ MTX_INIT(&VBE_mtx);
+}
#include "vrt.h"
+#if 0
struct ber {
unsigned magic;
#define BER_MAGIC 0x645b03f4
.cleanup = ber_Cleanup,
};
+#endif
+
/*--------------------------------------------------------------------*/
void
-VRT_init_random_backend(struct backend **bp, const struct vrt_dir_random *t)
+VRT_init_dir_random(struct cli *cli, struct director **bp, const struct vrt_dir_random *t)
{
- struct backend *b;
+ (void)cli;
(void)bp;
(void)t;
+
+
+#if 0
+ struct backend *b;
if (VBE_AddBackend(&backend_method_random, t->ident, bp))
return; /* reuse existing backend */
- b = *bp;
+ bp = *bp;
AN(t->name);
REPLACE(b->vcl_name, t->name);
-#if 0
struct backend *b;
struct ber *ber;
struct vrt_backend_entry *be;
#include "cache.h"
#include "vrt.h"
+#if 0
+
struct bes {
unsigned magic;
#define BES_MAGIC 0x015e17ac
return (bes->hostname);
}
-/*--------------------------------------------------------------------*/
-struct backend_method backend_method_simple = {
- .name = "simple",
- .getfd = bes_GetFd,
- .close = bes_ClosedFd,
- .recycle = bes_RecycleFd,
- .gethostname = bes_GetHostname,
- .cleanup = bes_Cleanup,
-};
-
-/*--------------------------------------------------------------------*/
-
-void
-VRT_init_simple_backend(struct backend **bp, const struct vrt_simple_backend *t)
-{
- struct backend *b;
- struct bes *bes;
- const char *p;
-
- if (VBE_AddBackend(&backend_method_simple, t->ident, bp))
- return; /* ref to existing backend */
-
- b = *bp;
- AN(t->name);
- REPLACE(b->vcl_name, t->name);
-
- bes = calloc(sizeof *bes, 1);
- XXXAN(bes);
- bes->magic = BES_MAGIC;
-
- b->priv = bes;
-
- bes->dnsttl = 300;
-
- AN(t->host->portname);
- REPLACE(bes->portname, t->host->portname);
-
- AN(t->host->hostname);
- REPLACE(bes->hostname, t->host->hostname);
-
- /*
- * The VCL compiler already did a lookup, but we'll do another one
- * here, just in case...
- */
- LOCK(&b->mtx);
- p = bes_dns_lookup(b);
- UNLOCK(&b->mtx);
- if (p != NULL)
- printf("Warning: could not lookup backend %s (%s:%s): %s",
- b->vcl_name, bes->hostname, bes->portname, p);
-}
+#endif
AZ(sp->obj);
AZ(sp->bereq);
- sp->backend = NULL;
+ sp->director = NULL;
+ sp->backend = NULL; /*
+ * XXX: we may want to leave this
+ * behind to hint directors ?
+ */
+
if (sp->vcl != NULL) {
if (sp->wrk->vcl != NULL)
VCL_Rel(&sp->wrk->vcl);
CHECK_OBJ_NOTNULL(sp->vcl, VCL_CONF_MAGIC);
AN(sp->bereq);
- CHECK_OBJ_NOTNULL(sp->backend, BACKEND_MAGIC);
+ CHECK_OBJ_NOTNULL(sp->director, DIRECTOR_MAGIC);
i = Fetch(sp);
- CHECK_OBJ_NOTNULL(sp->backend, BACKEND_MAGIC);
+ CHECK_OBJ_NOTNULL(sp->director, DIRECTOR_MAGIC);
if (!i)
RFC2616_cache_policy(sp, sp->obj->http); /* XXX -> VCL */
sp->doclose = http_DoConnection(sp->http);
/* By default we use the first backend */
- AZ(sp->backend);
- sp->backend = sp->vcl->backend[0];
- CHECK_OBJ_NOTNULL(sp->backend, BACKEND_MAGIC);
+ AZ(sp->director);
+ sp->director = sp->vcl->director[0];
+ CHECK_OBJ_NOTNULL(sp->director, DIRECTOR_MAGIC);
/* XXX: Handle TRACE & OPTIONS of Max-Forwards = 0 */
CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC);
CHECK_OBJ_ORNULL(w->nobj, OBJECT_MAGIC);
CHECK_OBJ_ORNULL(w->nobjhead, OBJHEAD_MAGIC);
- CHECK_OBJ_ORNULL(sp->backend, BACKEND_MAGIC);
+ CHECK_OBJ_ORNULL(sp->director, DIRECTOR_MAGIC);
switch (sp->step) {
#ifdef DIAGNOSTICS
--- /dev/null
+/*-
+ * Copyright (c) 2006 Verdens Gang AS
+ * Copyright (c) 2006-2008 Linpro AS
+ * All rights reserved.
+ *
+ * Author: Poul-Henning Kamp <phk@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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "shmlog.h"
+#include "cache.h"
+#include "vrt.h"
+
+/*--------------------------------------------------------------------*/
+
+struct vdi_simple {
+ unsigned magic;
+#define VDI_SIMPLE_MAGIC 0x476d25b7
+ struct director dir;
+ struct backend *backend;
+};
+
+static struct backend *
+vdi_simple_choose(struct sess *sp)
+{
+ struct vdi_simple *vs;
+
+ CHECK_OBJ_NOTNULL(sp->director, DIRECTOR_MAGIC);
+ CAST_OBJ_NOTNULL(vs, sp->director->priv, VDI_SIMPLE_MAGIC);
+ return (vs->backend);
+}
+
+static void
+vdi_simple_fini(struct director *d)
+{
+ struct vdi_simple *vs;
+
+ CHECK_OBJ_NOTNULL(d, DIRECTOR_MAGIC);
+ CAST_OBJ_NOTNULL(vs, d->priv, VDI_SIMPLE_MAGIC);
+
+ VBE_DropRef(vs->backend);
+ free(vs);
+}
+
+void
+VRT_init_dir_simple(struct cli *cli, struct director **bp, const struct vrt_dir_simple *t)
+{
+ struct vdi_simple *vs;
+
+ (void)cli;
+
+ vs = calloc(sizeof *vs, 1);
+ XXXAN(vs);
+ vs->magic = VDI_SIMPLE_MAGIC;
+ vs->dir.magic = DIRECTOR_MAGIC;
+ vs->dir.priv = vs;
+ vs->dir.name = "simple";
+ vs->dir.choose = vdi_simple_choose;
+ vs->dir.fini = vdi_simple_fini;
+
+ vs->backend = VBE_AddBackend(cli, t->host);
+
+ *bp = &vs->dir;
+}
CHECK_OBJ_NOTNULL(sp->wrk, WORKER_MAGIC);
CHECK_OBJ_NOTNULL(sp->obj, OBJECT_MAGIC);
CHECK_OBJ_NOTNULL(sp->bereq, BEREQ_MAGIC);
- CHECK_OBJ_NOTNULL(sp->backend, BACKEND_MAGIC);
+ CHECK_OBJ_NOTNULL(sp->director, DIRECTOR_MAGIC);
assert(sp->obj->busy != 0);
w = sp->wrk;
bereq = sp->bereq;
/* XXX: This really ought to go into the default VCL */
if (!http_GetHdr(hp, H_Host, &b)) {
+#if 0
http_PrintfHeader(sp->wrk, sp->fd, hp, "Host: %s",
sp->backend->method->gethostname(sp->backend));
+#endif
+ INCOMPL();
}
sp->bereq = bereq;
}
SZOF(struct objhead);
SZOF(struct sess);
SZOF(struct vbe_conn);
- SZOF(struct backend);
CNT_Init();
fp(" },\n");
}
+#if 0
/* dump a struct backend */
static void
dump_backend(const struct backend *be)
be->vcl_name ? be->vcl_name : "(null)");
fp(" },\n");
}
+#endif
/* dump a struct sess */
static void
dump_sess(const struct sess *sp)
{
+#if 0
const struct backend *be = sp->backend;
+#endif
const struct object *obj = sp->obj;
fp("sp = %p {\n", sp);
fp(" err_code = %d, err_reason = %s,\n", sp->err_code,
sp->err_reason ? sp->err_reason : "(null)");
+#if 0
if (VALID_OBJ(be, BACKEND_MAGIC))
dump_backend(be);
+ INCOMPL():
+#endif
if (VALID_OBJ(obj, OBJECT_MAGIC))
dump_object(obj);
vcl_active = vcl;
UNLOCK(&vcl_mtx);
cli_out(cli, "Loaded \"%s\" as \"%s\"\n", fn , name);
- vcl->conf->init_func();
+ vcl->conf->init_func(cli);
return (0);
}
assert(vcl->conf->discard);
assert(vcl->conf->busy == 0);
VTAILQ_REMOVE(&vcl_head, vcl, list);
- vcl->conf->fini_func();
+ vcl->conf->fini_func(NULL);
free(vcl->name);
free(vcl);
}
/*--------------------------------------------------------------------*/
void
-VRT_l_req_backend(struct sess *sp, struct backend *be)
+VRT_l_req_backend(struct sess *sp, struct director *be)
{
CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
- sp->backend = be;
+ sp->director = be;
}
-struct backend *
+struct director *
VRT_r_req_backend(struct sess *sp)
{
CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
- return (sp->backend);
+ return (sp->director);
}
/*--------------------------------------------------------------------*/
int
VRT_r_backend_health(const struct sess *sp)
{
-
CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
+#if 0
CHECK_OBJ_NOTNULL(sp->backend, BACKEND_MAGIC);
return (sp->backend->health);
+#else
+ INCOMPL();
+ return (0);
+#endif
}
/*--------------------------------------------------------------------*/
return (strcmp(s1, s2));
}
-
-/*--------------------------------------------------------------------
- * Backend stuff
- */
-
-void
-VRT_fini_backend(struct backend *b)
-{
-
- ASSERT_CLI();
- VBE_DropRef(b);
-}
*/
struct sess;
+struct cli;
-typedef void vcl_init_f(void);
-typedef void vcl_fini_f(void);
+typedef void vcl_init_f(struct cli *);
+typedef void vcl_fini_f(struct cli *);
typedef int vcl_func_f(struct sess *sp);
struct VCL_conf {
unsigned magic;
#define VCL_CONF_MAGIC 0x7406c509 /* from /dev/random */
- struct backend **backend;
- unsigned nbackend;
+ struct director **director;
+ unsigned ndirector;
struct vrt_ref *ref;
unsigned nref;
unsigned busy;
struct sess;
struct vsb;
-struct backend;
+struct cli;
+struct director;
struct VCL_conf;
struct sockaddr;
-struct vrt_backend_host {
+/*
+ * A backend is a host+port somewhere on the network
+ */
+struct vrt_backend {
const char *portname;
const char *hostname;
const char *ident;
};
-struct vrt_simple_backend {
- const char *ident;
- const char *name;
- const struct vrt_backend_host *host;
-};
+/*
+ * A director with a predictable reply
+ */
-struct vrt_backend_entry {
- const char *port;
- const char *host;
- double weight;
- struct vrt_backend_entry *next;
+struct vrt_dir_simple {
+ const char *ident;
+ const char *name;
+ const struct vrt_backend *host;
};
-struct vrt_round_robin_backend {
- const char *name;
- unsigned count;
- struct vrt_backend_entry *bentry;
-};
+/*
+ * A director with an unpredictable reply
+ */
struct vrt_dir_random_entry {
- const struct vrt_backend_host *host;
- double weight;
+ const struct vrt_backend *host;
+ double weight;
};
struct vrt_dir_random {
- const char *ident;
- const char *name;
- unsigned nmember;
+ const char *ident;
+ const char *name;
+ unsigned nmember;
const struct vrt_dir_random_entry *members;
};
-struct vrt_random_backend {
- const char *name;
- unsigned weighted;
- unsigned count;
- struct vrt_backend_entry *bentry;
-};
-
+/*
+ * other stuff.
+ * XXX: document when bored
+ */
struct vrt_ref {
unsigned source;
void VRT_Rollback(struct sess *sp);
/* Backend related */
-void VRT_init_simple_backend(struct backend **, const struct vrt_simple_backend *);
-void VRT_init_round_robin_backend(struct backend **, const struct vrt_round_robin_backend *);
-void VRT_init_random_backend(struct backend **, const struct vrt_dir_random *);
-void VRT_fini_backend(struct backend *);
+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_fini_dir(struct cli *, struct director *);
char *VRT_IP_string(const struct sess *sp, const struct sockaddr *sa);
char *VRT_int_string(const struct sess *sp, int);
const char * VRT_r_req_proto(const struct sess *);
void VRT_l_req_proto(const struct sess *, const char *, ...);
void VRT_l_req_hash(struct sess *, const char *);
-struct backend * VRT_r_req_backend(struct sess *);
-void VRT_l_req_backend(struct sess *, struct backend *);
+struct director * VRT_r_req_backend(struct sess *);
+void VRT_l_req_backend(struct sess *, struct director *);
int VRT_r_req_restarts(const struct sess *);
double VRT_r_req_grace(struct sess *);
void VRT_l_req_grace(struct sess *, double);
*/
static void
-vcc_EmitBeIdent(struct vsb *v, const struct token *first, const struct token *last)
+vcc_EmitBeIdent(struct vsb *v, const struct token *qual, int serial, const struct token *first, const struct token *last)
{
vsb_printf(v, "\t.ident =");
+ if (qual != NULL) {
+ vsb_printf(v, "\n\t \"%.*s \"", PF(qual));
+ qual = VTAILQ_NEXT(qual, list);
+ vsb_printf(v, "\n\t \"%.*s \"", PF(qual));
+ vsb_printf(v, "\n\t \":: %d :: \"", serial);
+ }
while (first != last) {
if (first->dec != NULL)
vsb_printf(v, "\n\t \"\\\"\" %.*s \"\\\" \"",
* be_element:
* '.' name '=' value ';'
*
- * The struct vrt_backend_host is emitted to Fh().
+ * The struct vrt_backend is emitted to Fh().
*/
static void
-vcc_ParseBackendHost(struct tokenlist *tl, int *nbh)
+vcc_ParseBackendHost(struct tokenlist *tl, int *nbh, const struct token *qual, int serial)
{
struct token *t_field;
struct token *t_first;
vcc_NextToken(tl);
*nbh = tl->nbackend_host++;
- Fh(tl, 0, "\nstatic const struct vrt_backend_host bh_%d = {\n", *nbh);
+ Fh(tl, 0, "\nstatic const struct vrt_backend bh_%d = {\n", *nbh);
/* Check for old syntax */
if (tl->t->tok == ID && vcc_IdIs(tl->t, "set")) {
EncToken(tl->fh, t_host);
Fh(tl, 0, ",\n");
- /* Check that the hostname makes sense */
+ /* Check that the portname makes sense */
if (t_port != NULL) {
ep = CheckHostPort(t_host->dec, t_port->dec);
if (ep != NULL) {
Fh(tl, 0, "\t.portname = ");
EncToken(tl->fh, t_port);
Fh(tl, 0, ",\n");
+ } else {
+ Fh(tl, 0, "\t.portname = \"80\",\n");
}
ExpectErr(tl, '}');
- vcc_EmitBeIdent(tl->fh, t_first, tl->t);
+ vcc_EmitBeIdent(tl->fh, qual, serial, t_first, tl->t);
Fh(tl, 0, "};\n");
vcc_NextToken(tl);
}
h->name = tl->t;
vcc_NextToken(tl);
- vcc_ParseBackendHost(tl, &nbh);
+ vcc_ParseBackendHost(tl, &nbh, NULL, 0);
ERRCHK(tl);
h->hnum = nbh;
VTAILQ_INSERT_TAIL(&tl->hosts, h, list);
/* In the compiled vcl we use these macros to refer to backends */
- Fh(tl, 1, "\n#define VGC_backend_%.*s (VCL_conf.backend[%d])\n",
+ Fh(tl, 1, "\n#define VGC_backend_%.*s (VCL_conf.director[%d])\n",
PF(h->name), tl->nbackend);
vcc_AddDef(tl, h->name, R_BACKEND);
- Fi(tl, 0, "\tVRT_init_simple_backend(&VGC_backend_%.*s , &sbe_%.*s);\n",
+ Fi(tl, 0,
+ "\tVRT_init_dir_simple(cli, &VGC_backend_%.*s , &sbe_%.*s);\n",
PF(h->name), PF(h->name));
- Ff(tl, 0, "\tVRT_fini_backend(VGC_backend_%.*s);\n", PF(h->name));
+ Ff(tl, 0, "\tVRT_fini_dir(cli, VGC_backend_%.*s);\n", PF(h->name));
- Fc(tl, 0, "\nstatic const struct vrt_simple_backend sbe_%.*s = {\n",
+ Fc(tl, 0, "\nstatic const struct vrt_dir_simple sbe_%.*s = {\n",
PF(h->name));
Fc(tl, 0, "\t.name = \"%.*s\",\n", PF(h->name));
Fc(tl, 0, "\t.host = &bh_%d,\n", nbh);
- vcc_EmitBeIdent(tl->fc, t_first, tl->t);
+ vcc_EmitBeIdent(tl->fc, NULL, 0, t_first, tl->t);
Fc(tl, 0, "};\n");
tl->nbackend++;
int nbh, nelem;
struct fld_spec *fs;
- Fh(tl, 1, "\n#define VGC_backend_%.*s (VCL_conf.backend[%d])\n",
+ Fh(tl, 1, "\n#define VGC_backend_%.*s (VCL_conf.director[%d])\n",
PF(t_dir), tl->nbackend);
vcc_AddDef(tl, t_dir, R_BACKEND);
vcc_IsField(tl, &t_field, fs);
ERRCHK(tl);
if (vcc_IdIs(t_field, "backend")) {
- vcc_ParseBackendHost(tl, &nbh);
+ vcc_ParseBackendHost(tl, &nbh, t_dir, nelem);
Fc(tl, 0, " .host = &bh_%d,", nbh);
ERRCHK(tl);
} else if (vcc_IdIs(t_field, "weight")) {
Fc(tl, 0, "\t.name = \"%.*s\",\n", PF(t_dir));
Fc(tl, 0, "\t.nmember = %d,\n", nelem);
Fc(tl, 0, "\t.members = vdre_%.*s,\n", PF(t_dir));
- vcc_EmitBeIdent(tl->fc, t_first, tl->t);
+ vcc_EmitBeIdent(tl->fc, NULL, 0, t_first, tl->t);
Fc(tl, 0, "};\n");
vcc_NextToken(tl);
- Fi(tl, 0, "\tVRT_init_random_backend(&VGC_backend_%.*s , &vdr_%.*s);\n",
+ Fi(tl, 0,
+ "\tVRT_init_dir_random(cli, &VGC_backend_%.*s , &vdr_%.*s);\n",
PF(t_dir), PF(t_dir));
- Ff(tl, 0, "\tVRT_fini_backend(VGC_backend_%.*s);\n", PF(t_dir));
+ Ff(tl, 0, "\tVRT_fini_dir(cli, VGC_backend_%.*s);\n", PF(t_dir));
}
/*--------------------------------------------------------------------
EmitInitFunc(const struct tokenlist *tl)
{
- Fc(tl, 0, "\nstatic void\nVGC_Init(void)\n{\n\n");
+ Fc(tl, 0, "\nstatic void\nVGC_Init(struct cli *cli)\n{\n\n");
vsb_finish(tl->fi);
/* XXX: check vsb_overflowed ? */
vsb_cat(tl->fc, vsb_data(tl->fi));
EmitFiniFunc(const struct tokenlist *tl)
{
- Fc(tl, 0, "\nstatic void\nVGC_Fini(void)\n{\n\n");
+ Fc(tl, 0, "\nstatic void\nVGC_Fini(struct cli *cli)\n{\n\n");
vsb_finish(tl->ff);
/* XXX: check vsb_overflowed ? */
vsb_cat(tl->fc, vsb_data(tl->ff));
}
Fc(tl, 0, "};\n");
- Fc(tl, 0, "\nstatic struct backend\t*backends[%d];\n", tl->nbackend);
+ Fc(tl, 0, "\nstatic struct director\t*directors[%d];\n", tl->nbackend);
Fc(tl, 0, "\nconst struct VCL_conf VCL_conf = {\n");
Fc(tl, 0, "\t.magic = VCL_CONF_MAGIC,\n");
Fc(tl, 0, "\t.init_func = VGC_Init,\n");
Fc(tl, 0, "\t.fini_func = VGC_Fini,\n");
- Fc(tl, 0, "\t.nbackend = %d,\n", tl->nbackend);
- Fc(tl, 0, "\t.backend = backends,\n");
+ Fc(tl, 0, "\t.ndirector = %d,\n", tl->nbackend);
+ Fc(tl, 0, "\t.director = directors,\n");
Fc(tl, 0, "\t.ref = VGC_ref,\n");
Fc(tl, 0, "\t.nref = VGC_NREFS,\n");
Fc(tl, 0, "\t.nsrc = %u,\n", tl->nsources);
vsb_cat(sb, " */\n");
vsb_cat(sb, "\n");
vsb_cat(sb, "struct sess;\n");
+ vsb_cat(sb, "struct cli;\n");
vsb_cat(sb, "\n");
- vsb_cat(sb, "typedef void vcl_init_f(void);\n");
- vsb_cat(sb, "typedef void vcl_fini_f(void);\n");
+ vsb_cat(sb, "typedef void vcl_init_f(struct cli *);\n");
+ vsb_cat(sb, "typedef void vcl_fini_f(struct cli *);\n");
vsb_cat(sb, "typedef int vcl_func_f(struct sess *sp);\n");
vsb_cat(sb, "\n");
vsb_cat(sb, "struct VCL_conf {\n");
vsb_cat(sb, " unsigned magic;\n");
vsb_cat(sb, "#define VCL_CONF_MAGIC 0x7406c509 /* from /dev/random */\n");
vsb_cat(sb, "\n");
- vsb_cat(sb, " struct backend **backend;\n");
- vsb_cat(sb, " unsigned nbackend;\n");
+ vsb_cat(sb, " struct director **director;\n");
+ vsb_cat(sb, " unsigned ndirector;\n");
vsb_cat(sb, " struct vrt_ref *ref;\n");
vsb_cat(sb, " unsigned nref;\n");
vsb_cat(sb, " unsigned busy;\n");
vsb_cat(sb, "\n");
vsb_cat(sb, "struct sess;\n");
vsb_cat(sb, "struct vsb;\n");
- vsb_cat(sb, "struct backend;\n");
+ vsb_cat(sb, "struct cli;\n");
+ vsb_cat(sb, "struct director;\n");
vsb_cat(sb, "struct VCL_conf;\n");
vsb_cat(sb, "struct sockaddr;\n");
vsb_cat(sb, "\n");
- vsb_cat(sb, "struct vrt_backend_host {\n");
+ vsb_cat(sb, "/*\n");
+ vsb_cat(sb, " * A backend is a host+port somewhere on the network\n");
+ vsb_cat(sb, " */\n");
+ vsb_cat(sb, "struct vrt_backend {\n");
vsb_cat(sb, " const char *portname;\n");
vsb_cat(sb, " const char *hostname;\n");
vsb_cat(sb, " const char *ident;\n");
vsb_cat(sb, "};\n");
vsb_cat(sb, "\n");
- vsb_cat(sb, "struct vrt_simple_backend {\n");
- vsb_cat(sb, " const char *ident;\n");
- vsb_cat(sb, " const char *name;\n");
- vsb_cat(sb, " const struct vrt_backend_host *host;\n");
- vsb_cat(sb, "};\n");
+ vsb_cat(sb, "/*\n");
+ vsb_cat(sb, " * A director with a predictable reply\n");
+ vsb_cat(sb, " */\n");
vsb_cat(sb, "\n");
- vsb_cat(sb, "struct vrt_backend_entry {\n");
- vsb_cat(sb, " const char *port;\n");
- vsb_cat(sb, " const char *host;\n");
- vsb_cat(sb, " double weight;\n");
- vsb_cat(sb, " struct vrt_backend_entry *next;\n");
+ vsb_cat(sb, "struct vrt_dir_simple {\n");
+ vsb_cat(sb, " const char *ident;\n");
+ vsb_cat(sb, " const char *name;\n");
+ vsb_cat(sb, " const struct vrt_backend *host;\n");
vsb_cat(sb, "};\n");
vsb_cat(sb, "\n");
- vsb_cat(sb, "struct vrt_round_robin_backend {\n");
- vsb_cat(sb, " const char *name;\n");
- vsb_cat(sb, " unsigned count;\n");
- vsb_cat(sb, " struct vrt_backend_entry *bentry;\n");
- vsb_cat(sb, "};\n");
+ vsb_cat(sb, "/*\n");
+ vsb_cat(sb, " * A director with an unpredictable reply\n");
+ vsb_cat(sb, " */\n");
vsb_cat(sb, "\n");
vsb_cat(sb, "struct vrt_dir_random_entry {\n");
- vsb_cat(sb, " const struct vrt_backend_host *host;\n");
- vsb_cat(sb, " double weight;\n");
+ vsb_cat(sb, " const struct vrt_backend *host;\n");
+ vsb_cat(sb, " double weight;\n");
vsb_cat(sb, "};\n");
vsb_cat(sb, "\n");
vsb_cat(sb, "struct vrt_dir_random {\n");
- vsb_cat(sb, " const char *ident;\n");
- vsb_cat(sb, " const char *name;\n");
- vsb_cat(sb, " unsigned nmember;\n");
+ vsb_cat(sb, " const char *ident;\n");
+ vsb_cat(sb, " const char *name;\n");
+ vsb_cat(sb, " unsigned nmember;\n");
vsb_cat(sb, " const struct vrt_dir_random_entry *members;\n");
vsb_cat(sb, "};\n");
vsb_cat(sb, "\n");
- vsb_cat(sb, "struct vrt_random_backend {\n");
- vsb_cat(sb, " const char *name;\n");
- vsb_cat(sb, " unsigned weighted;\n");
- vsb_cat(sb, " unsigned count;\n");
- vsb_cat(sb, " struct vrt_backend_entry *bentry;\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");
vsb_cat(sb, "\n");
vsb_cat(sb, "struct vrt_ref {\n");
vsb_cat(sb, " unsigned source;\n");
vsb_cat(sb, "void VRT_Rollback(struct sess *sp);\n");
vsb_cat(sb, "\n");
vsb_cat(sb, "/* Backend related */\n");
- vsb_cat(sb, "void VRT_init_simple_backend(struct backend **, const struct vrt_simple_backend *);\n");
- vsb_cat(sb, "void VRT_init_round_robin_backend(struct backend **, const struct vrt_round_robin_backend *);\n");
- vsb_cat(sb, "void VRT_init_random_backend(struct backend **, const struct vrt_dir_random *);\n");
- vsb_cat(sb, "void VRT_fini_backend(struct backend *);\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_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");
vsb_cat(sb, "char *VRT_int_string(const struct sess *sp, int);\n");
vsb_cat(sb, "const char * VRT_r_req_proto(const struct sess *);\n");
vsb_cat(sb, "void VRT_l_req_proto(const struct sess *, const char *, ...);\n");
vsb_cat(sb, "void VRT_l_req_hash(struct sess *, const char *);\n");
- vsb_cat(sb, "struct backend * VRT_r_req_backend(struct sess *);\n");
- vsb_cat(sb, "void VRT_l_req_backend(struct sess *, struct backend *);\n");
+ vsb_cat(sb, "struct director * VRT_r_req_backend(struct sess *);\n");
+ vsb_cat(sb, "void VRT_l_req_backend(struct sess *, struct director *);\n");
vsb_cat(sb, "int VRT_r_req_restarts(const struct sess *);\n");
vsb_cat(sb, "double VRT_r_req_grace(struct sess *);\n");
vsb_cat(sb, "void VRT_l_req_grace(struct sess *, double);\n");
set fo [open ../../include/vcl.h w]
warns $fo
puts $fo {struct sess;
+struct cli;
-typedef void vcl_init_f(void);
-typedef void vcl_fini_f(void);
+typedef void vcl_init_f(struct cli *);
+typedef void vcl_fini_f(struct cli *);
typedef int vcl_func_f(struct sess *sp);
}
puts $fo "struct VCL_conf {"
puts $fo { unsigned magic;
#define VCL_CONF_MAGIC 0x7406c509 /* from /dev/random */
- struct backend **backend;
- unsigned nbackend;
+ struct director **director;
+ unsigned ndirector;
struct vrt_ref *ref;
unsigned nref;
unsigned busy;
set tt(IP) "struct sockaddr *"
set tt(STRING) "const char *"
set tt(BOOL) "unsigned"
-set tt(BACKEND) "struct backend *"
+set tt(BACKEND) "struct director *"
set tt(TIME) "double"
set tt(RTIME) "double"
set tt(INT) "int"