Commit 98ccaa95 authored by Poul-Henning Kamp's avatar Poul-Henning Kamp

Retire saint-mode.

If there is a need, we'll bring it back as a VMOD.
parent 94a24450
......@@ -530,7 +530,6 @@ struct busyobj {
struct http *beresp;
struct objcore *fetch_objcore;
struct object *fetch_obj;
uint8_t digest[DIGEST_LEN];
struct exp exp;
struct http_conn htc;
......@@ -759,7 +758,7 @@ void VBE_DiscardHealth(const struct director *vdi);
struct vbc *VDI_GetFd(const struct director *, struct busyobj *);
int VDI_Healthy(const struct director *, const uint8_t *digest);
int VDI_Healthy(const struct director *);
void VDI_CloseFd(struct vbc **vbp);
void VDI_RecycleFd(struct vbc **vbp);
void VDI_AddHostHeader(struct http *to, const struct vbc *vbc);
......
......@@ -42,7 +42,6 @@
#include "cache_backend.h"
#include "vrt.h"
#include "vtcp.h"
#include "vtim.h"
static struct mempool *vbcpool;
......@@ -220,35 +219,6 @@ vbe_NewConn(void)
return (vc);
}
/*--------------------------------------------------------------------
* Add backend trouble item
*/
void
VBE_AddTrouble(const struct busyobj *bo, double expires)
{
struct trouble *tp;
struct vbc *vbc;
struct backend *be;
CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
vbc = bo->vbc;
if (vbc == NULL)
return;
CHECK_OBJ_NOTNULL(vbc, VBC_MAGIC);
be = vbc->backend;
CHECK_OBJ_NOTNULL(be, BACKEND_MAGIC);
ALLOC_OBJ(tp, TROUBLE_MAGIC);
if (tp == NULL)
return;
memcpy(tp->digest, bo->digest, sizeof tp->digest);
tp->timeout = expires;
Lck_Lock(&vbc->backend->mtx);
VTAILQ_INSERT_HEAD(&be->troublelist, tp, list);
be->n_trouble++;
Lck_Unlock(&vbc->backend->mtx);
}
/*--------------------------------------------------------------------
* It evaluates if a backend is healthy _for_a_specific_object_.
* That means that it relies on req->objcore->objhead. This is mainly for
......@@ -261,17 +231,10 @@ VBE_AddTrouble(const struct busyobj *bo, double expires)
*/
static unsigned int
vbe_Healthy(const struct vdi_simple *vs, const uint8_t *digest)
vbe_Healthy(const struct vdi_simple *vs)
{
struct trouble *tr;
struct trouble *tr2;
unsigned retval;
unsigned int threshold;
struct backend *backend;
VTAILQ_HEAD(, trouble) troublelist;
double now;
AN(digest);
CHECK_OBJ_NOTNULL(vs, VDI_SIMPLE_MAGIC);
backend = vs->backend;
CHECK_OBJ_NOTNULL(backend, BACKEND_MAGIC);
......@@ -282,48 +245,7 @@ vbe_Healthy(const struct vdi_simple *vs, const uint8_t *digest)
if (backend->admin_health == ah_sick)
return (0);
/* VRT/VCC sets threshold to UINT_MAX to mark that it's not
* specified by VCL (thus use param).
*/
threshold = vs->vrt->saintmode_threshold;
if (threshold == UINT_MAX)
threshold = cache_param->saintmode_threshold;
if (backend->admin_health == ah_healthy)
threshold = UINT_MAX;
/* Saintmode is disabled, or list is empty */
if (threshold == 0 || backend->n_trouble == 0)
return (1);
now = VTIM_real();
retval = 1;
VTAILQ_INIT(&troublelist);
Lck_Lock(&backend->mtx);
VTAILQ_FOREACH_SAFE(tr, &backend->troublelist, list, tr2) {
CHECK_OBJ_NOTNULL(tr, TROUBLE_MAGIC);
if (tr->timeout < now) {
VTAILQ_REMOVE(&backend->troublelist, tr, list);
VTAILQ_INSERT_HEAD(&troublelist, tr, list);
backend->n_trouble--;
continue;
}
if (!memcmp(tr->digest, digest, sizeof tr->digest)) {
retval = 0;
break;
}
}
if (threshold <= backend->n_trouble)
retval = 0;
Lck_Unlock(&backend->mtx);
VTAILQ_FOREACH_SAFE(tr, &troublelist, list, tr2)
FREE_OBJ(tr);
return (retval);
return (1);
}
/*--------------------------------------------------------------------
......@@ -379,7 +301,7 @@ vbe_GetVbe(struct busyobj *bo, struct vdi_simple *vs)
VBE_ReleaseConn(vc);
}
if (!vbe_Healthy(vs, bo->digest)) {
if (!vbe_Healthy(vs)) {
VSC_C_main->backend_unhealthy++;
return (NULL);
}
......@@ -469,13 +391,13 @@ vdi_simple_getfd(const struct director *d, struct busyobj *bo)
}
static unsigned
vdi_simple_healthy(const struct director *d, const uint8_t *digest)
vdi_simple_healthy(const struct director *d)
{
struct vdi_simple *vs;
CHECK_OBJ_NOTNULL(d, DIRECTOR_MAGIC);
CAST_OBJ_NOTNULL(vs, d->priv, VDI_SIMPLE_MAGIC);
return (vbe_Healthy(vs, digest));
return (vbe_Healthy(vs));
}
static void
......
......@@ -77,7 +77,7 @@ struct vrt_backend_probe;
typedef struct vbc *vdi_getfd_f(const struct director *, struct busyobj *);
typedef void vdi_fini_f(const struct director *);
typedef unsigned vdi_healthy(const struct director *, const uint8_t *digest);
typedef unsigned vdi_healthy(const struct director *);
struct director {
unsigned magic;
......@@ -90,18 +90,6 @@ struct director {
void *priv;
};
/*--------------------------------------------------------------------
* List of objectheads that have recently been rejected by VCL.
*/
struct trouble {
unsigned magic;
#define TROUBLE_MAGIC 0x4211ab21
uint8_t digest[DIGEST_LEN];
double timeout;
VTAILQ_ENTRY(trouble) list;
};
/*--------------------------------------------------------------------
* An instance of a backend from a VCL program.
*/
......@@ -137,9 +125,6 @@ struct backend {
unsigned healthy;
enum admin_health admin_health;
unsigned n_trouble;
VTAILQ_HEAD(, trouble) troublelist;
struct VSC_C_vbe *vsc;
};
......@@ -166,7 +151,6 @@ struct vbc {
/* cache_backend.c */
void VBE_ReleaseConn(struct vbc *vc);
void VBE_AddTrouble(const struct busyobj *, double expires);
/* cache_backend_cfg.c */
void VBE_DropRefConn(struct backend *);
......
......@@ -209,8 +209,6 @@ VBE_AddBackend(struct cli *cli, const struct vrt_backend *vb)
VTAILQ_INIT(&b->connlist);
VTAILQ_INIT(&b->troublelist);
/*
* This backend may live longer than the VCL that instantiated it
* so we cannot simply reference the VCL's copy of things.
......
......@@ -144,8 +144,6 @@ VBO_GetBusyObj(struct worker *wrk, struct req *req)
WS_Init(bo->ws, "bo", p, bo->end - p);
memcpy(bo->digest, req->digest, sizeof bo->digest);
bo->do_stream = 1;
bo->director = req->director;
......
......@@ -123,9 +123,9 @@ VDI_GetFd(const struct director *d, struct busyobj *bo)
*/
int
VDI_Healthy(const struct director *d, const uint8_t *digest)
VDI_Healthy(const struct director *d)
{
CHECK_OBJ_NOTNULL(d, DIRECTOR_MAGIC);
return (d->healthy(d, digest));
return (d->healthy(d));
}
......@@ -102,8 +102,6 @@ cnt_stream(struct worker *wrk, struct req *req)
CHECK_OBJ_NOTNULL(req->obj, OBJECT_MAGIC);
CHECK_OBJ_NOTNULL(req->vcl, VCL_CONF_MAGIC);
// req->res_mode = 0;
AZ(bo->do_esi);
if (wrk->handling == VCL_RET_RESTART) {
......
......@@ -380,20 +380,6 @@ VRT_BOOL_string(unsigned val)
return (val ? "true" : "false");
}
/*--------------------------------------------------------------------
* Add an objecthead to the saintmode list for the (hopefully) relevant
* backend.
*/
void
VRT_l_beresp_saintmode(const struct vrt_ctx *ctx, double a)
{
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
if (a > 0.)
VBE_AddTrouble(ctx->bo, a + VTIM_real());
}
/*--------------------------------------------------------------------*/
void
......
......@@ -336,7 +336,7 @@ VRT_r_req_backend_healthy(const struct vrt_ctx *ctx)
if (ctx->req->director == NULL)
return (0);
CHECK_OBJ_NOTNULL(ctx->req->director, DIRECTOR_MAGIC);
return (VDI_Healthy(ctx->req->director, ctx->req->digest));
return (VDI_Healthy(ctx->req->director));
}
/*--------------------------------------------------------------------*/
......@@ -368,7 +368,7 @@ VRT_r_bereq_backend_healthy(const struct vrt_ctx *ctx)
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(ctx->bo, BUSYOBJ_MAGIC);
CHECK_OBJ_NOTNULL(ctx->bo->director, DIRECTOR_MAGIC);
return (VDI_Healthy(ctx->bo->director, ctx->bo->digest));
return (VDI_Healthy(ctx->bo->director));
}
/*--------------------------------------------------------------------*/
......
varnishtest "Test that saintmode_threshold correctly marks a backend as sick"
feature OldSaintMode
server s1 {
rxreq
txresp
rxreq
txresp
rxreq
txresp
rxreq
txresp
rxreq
txresp -hdr "X-Saint: yes"
accept
rxreq
txresp -hdr "X-Saint: yes"
accept
rxreq
txresp -hdr "X-Saint: yes"
accept
rxreq
txresp -hdr "X-Saint: yes"
} -start
varnish v1 -arg "-p saintmode_threshold=2" -vcl+backend {
sub vcl_recv {
set req.grace = 1h;
}
sub vcl_backend_response {
if (beresp.http.X-Saint == "yes") {
set beresp.saintmode = 20s;
set beresp.uncacheable = true;
set beresp.ttl = 0s;
return(deliver);
}
set beresp.grace = 1h;
set beresp.ttl = 1s;
}
sub vcl_deliver {
if (resp.http.X-saint == "yes") {
return (restart);
}
set resp.http.X-Restarts = req.restarts;
}
} -start
client c1 {
txreq -url "/one"
rxresp
expect resp.status == 200
expect resp.http.X-Saint != "yes"
expect resp.http.X-Restarts == "0"
txreq -url "/two"
rxresp
expect resp.status == 200
expect resp.http.X-Saint != "yes"
expect resp.http.X-Restarts == "0"
txreq -url "/three"
rxresp
expect resp.status == 200
expect resp.http.X-Saint != "yes"
expect resp.http.X-Restarts == "0"
txreq -url "/four"
rxresp
expect resp.status == 200
expect resp.http.X-Saint != "yes"
expect resp.http.X-Restarts == "0"
delay 2
txreq -url "/one"
rxresp
expect resp.status == 200
expect resp.http.X-Saint != "yes"
expect resp.http.X-Restarts == "1"
txreq -url "/two"
rxresp
expect resp.status == 200
expect resp.http.X-Saint != "yes"
expect resp.http.X-Restarts == "1"
# The saintmode_threshold should kick in now
# so expect no more restarts
txreq -url "/three"
rxresp
expect resp.status == 200
expect resp.http.X-Saint != "yes"
expect resp.http.X-Restarts == "0"
txreq -url "/four"
rxresp
expect resp.status == 200
expect resp.http.X-Saint != "yes"
expect resp.http.X-Restarts == "0"
} -run
varnishtest "Test that saintmode_threshold in VCL"
feature OldSaintMode
server s1 {
rxreq
txresp
rxreq
txresp
rxreq
txresp
rxreq
txresp
rxreq
txresp -hdr "X-Saint: yes"
accept
rxreq
txresp -hdr "X-Saint: yes"
accept
rxreq
txresp -hdr "X-Saint: yes"
accept
rxreq
txresp -hdr "X-Saint: yes"
} -start
varnish v1 -arg "-p saintmode_threshold=10" -vcl {
backend foo {
.host = "${s1_addr}";
.port = "${s1_port}";
.saintmode_threshold = 2;
}
sub vcl_recv {
set req.backend = foo;
set req.grace = 1h;
}
sub vcl_backend_response {
if (beresp.http.X-Saint == "yes") {
set beresp.saintmode = 20s;
set beresp.uncacheable = true;
set beresp.ttl = 0s;
return(deliver);
}
set beresp.grace = 1h;
set beresp.ttl = 1s;
}
sub vcl_deliver {
if (resp.http.X-saint == "yes") {
return (restart);
}
set resp.http.X-Restarts = req.restarts;
}
} -start
client c1 {
txreq -url "/one"
rxresp
expect resp.status == 200
expect resp.http.X-Saint != "yes"
expect resp.http.X-Restarts == "0"
txreq -url "/two"
rxresp
expect resp.status == 200
expect resp.http.X-Saint != "yes"
expect resp.http.X-Restarts == "0"
txreq -url "/three"
rxresp
expect resp.status == 200
expect resp.http.X-Saint != "yes"
expect resp.http.X-Restarts == "0"
txreq -url "/four"
rxresp
expect resp.status == 200
expect resp.http.X-Saint != "yes"
expect resp.http.X-Restarts == "0"
delay 2
txreq -url "/one"
rxresp
expect resp.status == 200
expect resp.http.X-Saint != "yes"
expect resp.http.X-Restarts == "1"
txreq -url "/two"
rxresp
expect resp.status == 200
expect resp.http.X-Saint != "yes"
expect resp.http.X-Restarts == "1"
txreq -url "/three"
rxresp
expect resp.status == 200
expect resp.http.X-Saint != "yes"
expect resp.http.X-Restarts == "0"
txreq -url "/four"
rxresp
expect resp.status == 200
expect resp.http.X-Saint != "yes"
expect resp.http.X-Restarts == "0"
} -run
varnishtest "Test fallback director with saint mode"
server s1 {
rxreq
txresp -hdr "Foo: 1"
} -start
server s2 {
rxreq
txresp -hdr "Foo: 2" -bodylen 1
} -start
varnish v1 -vcl+backend {
import directors from "${topbuild}/lib/libvmod_directors/.libs/libvmod_directors.so" ;
sub vcl_init {
new f1 = directors.fallback();
f1.add_backend(s1);
f1.add_backend(s2);
}
sub vcl_recv {
set req.backend = f1.backend();
}
sub vcl_backend_response {
if (beresp.http.foo == "1") {
set beresp.uncacheable = true;
set beresp.saintmode = 1h;
set beresp.status = 606;
return(deliver);
}
}
sub vcl_deliver {
if (resp.status == 606) {
return(restart);
}
}
} -start
client c1 {
txreq
rxresp
expect resp.http.foo == "2"
} -run
varnishtest "Check saint mode with sick pages"
feature OldSaintMode
server s1 {
timeout 10
rxreq
expect req.url == "/"
txresp -status 200 -hdr "foo: 1"
rxreq
expect req.url == "/"
txresp -status 200 -hdr "foo: 2"
accept
rxreq
expect req.url == "/"
txresp -status 200 -hdr "foo: 3"
} -start
varnish v1 -vcl+backend {
sub vcl_backend_response {
set beresp.ttl = 1s;
set beresp.grace = 10m;
if (beresp.http.foo == "2")
{
set beresp.saintmode = 2s;
set beresp.status = 606;
set beresp.uncacheable = true;
set beresp.ttl = 0s;
return (deliver);
}
return(deliver);
}
sub vcl_deliver {
if (resp.status == 606) {
return (restart);
}
}
} -start
client c1 {
txreq -url "/"
rxresp
expect resp.status == 200
expect resp.http.foo == 1
} -run
delay 2
client c2 {
txreq -url "/"
rxresp
expect resp.status == 200
expect resp.http.foo == 1
} -run
delay 2
client c3 {
txreq -url "/"
rxresp
expect resp.status == 200
expect resp.http.foo == 3
} -run
......@@ -133,7 +133,6 @@ struct vrt_backend {
double first_byte_timeout;
double between_bytes_timeout;
unsigned max_connections;
unsigned saintmode_threshold;
const struct vrt_backend_probe *probe;
};
......
......@@ -282,11 +282,6 @@ sp_variables = [
( 'backend_response',),
( 'backend_response',),
),
('beresp.saintmode',
'DURATION',
( ),
( 'backend_response',),
),
('beresp.status',
'INT',
( 'backend_response',),
......
......@@ -50,7 +50,6 @@
#include "config.h"
#include <limits.h>
#include <stdlib.h>
#include <string.h>
......@@ -300,7 +299,6 @@ vcc_ParseHostDef(struct vcc *tl, int serial, const char *vgcname)
struct token *t_host = NULL;
struct token *t_port = NULL;
struct token *t_hosthdr = NULL;
unsigned saint = UINT_MAX;
struct fld_spec *fs;
struct vsb *vsb;
unsigned u;
......@@ -317,7 +315,6 @@ vcc_ParseHostDef(struct vcc *tl, int serial, const char *vgcname)
"?between_bytes_timeout",
"?probe",
"?max_connections",
"?saintmode_threshold",
NULL);
SkipToken(tl, '{');
......@@ -391,21 +388,6 @@ vcc_ParseHostDef(struct vcc *tl, int serial, const char *vgcname)
ERRCHK(tl);
SkipToken(tl, ';');
Fb(tl, 0, "\t.max_connections = %u,\n", u);
} else if (vcc_IdIs(t_field, "saintmode_threshold")) {
u = vcc_UintVal(tl);
/* UINT_MAX == magic number to mark as unset, so
* not allowed here.
*/
if (u == UINT_MAX) {
VSB_printf(tl->sb,
"Value outside allowed range: ");
vcc_ErrToken(tl, tl->t);
VSB_printf(tl->sb, " at\n");
vcc_ErrWhere(tl, tl->t);
}
ERRCHK(tl);
saint = u;
SkipToken(tl, ';');
} else if (vcc_IdIs(t_field, "probe") && tl->t->tok == '{') {
Fb(tl, 0, "\t.probe = &vgc_probe__%d,\n", tl->nprobe);
vcc_ParseProbeSpec(tl);
......@@ -452,8 +434,6 @@ vcc_ParseHostDef(struct vcc *tl, int serial, const char *vgcname)
EncToken(tl->fb, t_host);
Fb(tl, 0, ",\n");
Fb(tl, 0, "\t.saintmode_threshold = %d,\n",saint);
/* Close the struct */
Fb(tl, 0, "};\n");
......
......@@ -45,12 +45,12 @@ struct vmod_directors_fallback {
};
static unsigned __match_proto__(vdi_healthy)
vmod_rr_healthy(const struct director *dir, const uint8_t *digest)
vmod_rr_healthy(const struct director *dir)
{
struct vmod_directors_fallback *rr;
CAST_OBJ_NOTNULL(rr, dir->priv, VMOD_DIRECTORS_FALLBACK_MAGIC);
return (vdir_any_healthy(rr->vd, digest));
return (vdir_any_healthy(rr->vd));
}
static struct vbc * __match_proto__(vdi_getfd_f)
......@@ -65,7 +65,7 @@ vmod_rr_getfd(const struct director *dir, struct busyobj *bo)
for (u = 0; u < rr->vd->n_backend; u++) {
be = rr->vd->backend[u];
CHECK_OBJ_NOTNULL(be, DIRECTOR_MAGIC);
if (be->healthy(be, bo->digest))
if (be->healthy(be))
break;
}
vdir_unlock(rr->vd);
......
......@@ -119,6 +119,6 @@ vmod_hash_backend(const struct vrt_ctx *ctx, struct vmod_directors_hash *rr,
r = vbe32dec(sha256);
r = scalbn(r, -32);
assert(r >= 0 && r <= 1.0);
be = vdir_pick_be(rr->vd, ctx->bo, r, rr->nloops);
be = vdir_pick_be(rr->vd, r, rr->nloops);
return (be);
}
......@@ -50,12 +50,12 @@ struct vmod_directors_random {
};
static unsigned __match_proto__(vdi_healthy)
vmod_rr_healthy(const struct director *dir, const uint8_t *digest)
vmod_rr_healthy(const struct director *dir)
{
struct vmod_directors_random *rr;
CAST_OBJ_NOTNULL(rr, dir->priv, VMOD_DIRECTORS_RANDOM_MAGIC);
return (vdir_any_healthy(rr->vd, digest));
return (vdir_any_healthy(rr->vd));
}
static struct vbc * __match_proto__(vdi_getfd_f)
......@@ -68,7 +68,7 @@ vmod_rr_getfd(const struct director *dir, struct busyobj *bo)
CAST_OBJ_NOTNULL(rr, dir->priv, VMOD_DIRECTORS_RANDOM_MAGIC);
r = scalbn(random(), -31);
assert(r >= 0 && r < 1.0);
be = vdir_pick_be(rr->vd, bo, r, rr->nloops);
be = vdir_pick_be(rr->vd, r, rr->nloops);
if (be == NULL)
return (NULL);
return (be->getfd(be, bo));
......
......@@ -46,12 +46,12 @@ struct vmod_directors_round_robin {
};
static unsigned __match_proto__(vdi_healthy)
vmod_rr_healthy(const struct director *dir, const uint8_t *digest)
vmod_rr_healthy(const struct director *dir)
{
struct vmod_directors_round_robin *rr;
CAST_OBJ_NOTNULL(rr, dir->priv, VMOD_DIRECTORS_ROUND_ROBIN_MAGIC);
return (vdir_any_healthy(rr->vd, digest));
return (vdir_any_healthy(rr->vd));
}
static struct vbc * __match_proto__(vdi_getfd_f)
......@@ -68,7 +68,7 @@ vmod_rr_getfd(const struct director *dir, struct busyobj *bo)
be = rr->vd->backend[rr->nxt];
rr->nxt++;
CHECK_OBJ_NOTNULL(be, DIRECTOR_MAGIC);
if (be->healthy(be, bo->digest))
if (be->healthy(be))
break;
}
vdir_unlock(rr->vd);
......
......@@ -128,7 +128,7 @@ vdir_add_backend(struct vdir *vd, VCL_BACKEND be, double weight)
}
unsigned
vdir_any_healthy(struct vdir *vd, const uint8_t *digest)
vdir_any_healthy(struct vdir *vd)
{
unsigned retval = 0;
VCL_BACKEND be;
......@@ -139,7 +139,7 @@ vdir_any_healthy(struct vdir *vd, const uint8_t *digest)
for (u = 0; u < vd->n_backend; u++) {
be = vd->backend[u];
CHECK_OBJ_NOTNULL(be, DIRECTOR_MAGIC);
if (be->healthy(be, digest)) {
if (be->healthy(be)) {
retval = 1;
break;
}
......@@ -169,8 +169,7 @@ vdir_pick_by_weight(const struct vdir *vd, double w,
}
VCL_BACKEND
vdir_pick_be(struct vdir *vd, const struct busyobj *bo, double w,
unsigned nloops)
vdir_pick_be(struct vdir *vd, double w, unsigned nloops)
{
struct vbitmap *vbm = NULL;
unsigned u, v, l;
......@@ -186,7 +185,7 @@ vdir_pick_be(struct vdir *vd, const struct busyobj *bo, double w,
u = vdir_pick_by_weight(vd, w * tw, vbm);
be = vd->backend[u];
CHECK_OBJ_NOTNULL(be, DIRECTOR_MAGIC);
if (be->healthy(be, bo->digest))
if (be->healthy(be))
break;
if (l == 0) {
vbm = vd->vbm;
......
......@@ -47,6 +47,5 @@ void vdir_delete(struct vdir **vdp);
void vdir_lock(struct vdir *vd);
void vdir_unlock(struct vdir *vd);
unsigned vdir_add_backend(struct vdir *vd, VCL_BACKEND be, double weight);
unsigned vdir_any_healthy(struct vdir *vd, const uint8_t *digest);
VCL_BACKEND vdir_pick_be(struct vdir *vd, const struct busyobj *, double w,
unsigned nloops);
unsigned vdir_any_healthy(struct vdir *vd);
VCL_BACKEND vdir_pick_be(struct vdir *vd, double w, unsigned nloops);
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