[master] 8d47bfc8d vdir: centralize health info, fix total_weight
Nils Goroll
nils.goroll at uplex.de
Wed Mar 6 15:26:07 UTC 2019
commit 8d47bfc8d16c8deb980ace67dc8bbace67405c99
Author: Nils Goroll <nils.goroll at uplex.de>
Date: Wed Mar 6 15:40:23 2019 +0100
vdir: centralize health info, fix total_weight
Whenever we gather health information about our backends, we should also
update the other metrics:
- director changed time
- total weight
- number of healthy backends (added)
This also adds back sensible use of (struct vdir).total_weight, which
was maintained by add_backend / remove_backend, but not used anywhere
and useless anyway because, for the hash and random directors, the total
weight of the _healthy_ directors is required.
This also fixes the weight output for backend.list to be relative to the
healthy backends.
Ref #2896
diff --git a/lib/libvmod_directors/fall_back.c b/lib/libvmod_directors/fall_back.c
index f00a6f11e..88efb699b 100644
--- a/lib/libvmod_directors/fall_back.c
+++ b/lib/libvmod_directors/fall_back.c
@@ -37,6 +37,7 @@
#include "vdir.h"
#include "vsb.h"
+#include "vbm.h"
struct vmod_directors_fallback {
unsigned magic;
@@ -63,10 +64,9 @@ vmod_fallback_list(VRT_CTX, VCL_BACKEND dir, struct vsb *vsb, int pflag,
{
struct vmod_directors_fallback *fb;
struct vdir *vd;
- VCL_TIME c, changed = 0;
VCL_BACKEND be;
VCL_BOOL h;
- unsigned u, nh = 0;
+ unsigned u, nh;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(dir, DIRECTOR_MAGIC);
@@ -87,17 +87,13 @@ vmod_fallback_list(VRT_CTX, VCL_BACKEND dir, struct vsb *vsb, int pflag,
}
vdir_rdlock(vd);
- for (u = 0; u < vd->n_backend; u++) {
+ vdir_update_health(ctx, vd);
+ for (u = 0; pflag && u < vd->n_backend; u++) {
be = vd->backend[u];
CHECK_OBJ_NOTNULL(be, DIRECTOR_MAGIC);
- c = 0;
- h = VRT_Healthy(ctx, be, &c);
- if (h)
- nh++;
- if (c > changed)
- changed = c;
- if ((pflag) == 0)
- continue;
+
+ h = vbit_test(vd->healthy, u);
+
if (jflag) {
if (u)
VSB_cat(vsb, ",\n");
@@ -116,10 +112,9 @@ vmod_fallback_list(VRT_CTX, VCL_BACKEND dir, struct vsb *vsb, int pflag,
VSB_cat(vsb, "\n");
}
}
+ nh = vd->n_healthy;
vdir_unlock(vd);
- VRT_SetChanged(vd->dir, changed);
-
if (jflag && (pflag)) {
VSB_cat(vsb, "\n");
VSB_indent(vsb, -2);
@@ -131,18 +126,11 @@ vmod_fallback_list(VRT_CTX, VCL_BACKEND dir, struct vsb *vsb, int pflag,
if (pflag)
return;
- /*
- * for health state, the api-correct thing would be to call our own
- * healthy function, but that would just re-iterate the backends for no
- * real benefit
- */
-
if (jflag)
VSB_printf(vsb, "[%u, %u, \"%s\"]", nh, u,
nh ? "healthy" : "sick");
else
VSB_printf(vsb, "%u/%u\t%s", nh, u, nh ? "healthy" : "sick");
-
}
static VCL_BACKEND v_matchproto_(vdi_resolve_f)
diff --git a/lib/libvmod_directors/vdir.c b/lib/libvmod_directors/vdir.c
index bb6bacec6..1caab2e3c 100644
--- a/lib/libvmod_directors/vdir.c
+++ b/lib/libvmod_directors/vdir.c
@@ -47,6 +47,9 @@ vdir_expand(struct vdir *vd, unsigned n)
AN(vd->backend);
vd->weight = realloc(vd->weight, n * sizeof *vd->weight);
AN(vd->weight);
+ if (n > vd->healthy->nbits)
+ vbit_expand(vd->healthy, n);
+ AN(vd->healthy);
vd->l_backend = n;
}
@@ -127,7 +130,6 @@ vdir_add_backend(VRT_CTX, struct vdir *vd, VCL_BACKEND be, double weight)
u = vd->n_backend++;
vd->backend[u] = be;
vd->weight[u] = weight;
- vd->total_weight += weight;
vdir_unlock(vd);
}
@@ -152,7 +154,6 @@ vdir_remove_backend(VRT_CTX, struct vdir *vd, VCL_BACKEND be, unsigned *cur)
vdir_unlock(vd);
return;
}
- vd->total_weight -= vd->weight[u];
n = (vd->n_backend - u) - 1;
memmove(&vd->backend[u], &vd->backend[u+1], n * sizeof(vd->backend[0]));
memmove(&vd->weight[u], &vd->weight[u+1], n * sizeof(vd->weight[0]));
@@ -198,10 +199,9 @@ void
vdir_list(VRT_CTX, struct vdir *vd, struct vsb *vsb, int pflag, int jflag,
int weight)
{
- VCL_TIME c, changed = 0;
VCL_BACKEND be;
VCL_BOOL h;
- unsigned u, nh = 0;
+ unsigned u, nh;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(vd, VDIR_MAGIC);
@@ -221,23 +221,19 @@ vdir_list(VRT_CTX, struct vdir *vd, struct vsb *vsb, int pflag, int jflag,
}
vdir_rdlock(vd);
- for (u = 0; u < vd->n_backend; u++) {
+ vdir_update_health(ctx, vd);
+ for (u = 0; pflag && u < vd->n_backend; u++) {
be = vd->backend[u];
CHECK_OBJ_NOTNULL(be, DIRECTOR_MAGIC);
- c = 0;
- h = VRT_Healthy(ctx, be, &c);
- if (h)
- nh++;
- if (c > changed)
- changed = c;
- if ((pflag) == 0)
- continue;
+
+ h = vbit_test(vd->healthy, u);
+
if (jflag) {
if (u)
VSB_cat(vsb, ",\n");
if (weight)
VSB_printf(vsb, "\"%s\": [%f, \"%s\"]",
- be->vcl_name, vd->weight[u],
+ be->vcl_name, h ? vd->weight[u] : 0.0,
h ? "healthy" : "sick");
else
VSB_printf(vsb, "\"%s\": \"%s\"",
@@ -245,7 +241,7 @@ vdir_list(VRT_CTX, struct vdir *vd, struct vsb *vsb, int pflag, int jflag,
} else {
VSB_cat(vsb, "\t");
VSB_cat(vsb, be->vcl_name);
- if (weight)
+ if (h && weight)
VSB_printf(vsb, "\t%.2f%%\t",
100 * vd->weight[u] / vd->total_weight);
else
@@ -254,10 +250,9 @@ vdir_list(VRT_CTX, struct vdir *vd, struct vsb *vsb, int pflag, int jflag,
VSB_cat(vsb, "\n");
}
}
+ nh = vd->n_healthy;
vdir_unlock(vd);
- VRT_SetChanged(vd->dir, changed);
-
if (jflag && (pflag)) {
VSB_cat(vsb, "\n");
VSB_indent(vsb, -2);
@@ -269,12 +264,6 @@ vdir_list(VRT_CTX, struct vdir *vd, struct vsb *vsb, int pflag, int jflag,
if (pflag)
return;
- /*
- * for health state, the api-correct thing would be to call our own
- * healthy function, but that would just re-iterate the backends for no
- * real benefit
- */
-
if (jflag)
VSB_printf(vsb, "[%u, %u, \"%s\"]", nh, u,
nh ? "healthy" : "sick");
@@ -282,6 +271,55 @@ vdir_list(VRT_CTX, struct vdir *vd, struct vsb *vsb, int pflag, int jflag,
VSB_printf(vsb, "%u/%u\t%s", nh, u, nh ? "healthy" : "sick");
}
+/*
+ * iterate backends and update
+ * - healthy bitmap
+ * - number of healthy backends
+ * - total_weight
+ * - last change time of the VCL_BACKEND
+ *
+ * must be called under the vdir lock (read or write).
+ *
+ * A write lock is required if consistency between the individual attributes is
+ * a must, e.g. when total_weight is required to be the exact sum of the weights
+ *
+ * The read lock is safe because add_backend expands the healthy bitmap and all
+ * other members are atomic and may be used if consistency is not required.
+ */
+void
+vdir_update_health(VRT_CTX, struct vdir *vd)
+{
+ VCL_TIME c, changed = 0;
+ VCL_BOOL h;
+ VCL_BACKEND be;
+ unsigned u, nh = 0;
+ double tw = 0.0;
+ struct vbitmap *healthy = vd->healthy;
+
+ healthy = vd->healthy;
+ for (u = 0; u < vd->n_backend; u++) {
+ be = vd->backend[u];
+ CHECK_OBJ_NOTNULL(be, DIRECTOR_MAGIC);
+ c = 0;
+ h = VRT_Healthy(ctx, vd->backend[u], &c);
+ if (h) {
+ nh++;
+ tw += vd->weight[u];
+ }
+ if (c > changed)
+ changed = c;
+ if (h != vbit_test(healthy, u)) {
+ if (h)
+ vbit_set(healthy, u);
+ else
+ vbit_clr(healthy, u);
+ }
+ }
+ VRT_SetChanged(vd->dir, changed);
+ vd->total_weight = tw;
+ vd->n_healthy = nh;
+}
+
static unsigned
vdir_pick_by_weight(const struct vdir *vd, double w)
{
@@ -304,22 +342,14 @@ VCL_BACKEND
vdir_pick_be(VRT_CTX, struct vdir *vd, double w)
{
unsigned u;
- double tw = 0.0;
VCL_BACKEND be = NULL;
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
CHECK_OBJ_NOTNULL(vd, VDIR_MAGIC);
vdir_wrlock(vd);
- for (u = 0; u < vd->n_backend; u++) {
- if (VRT_Healthy(ctx, vd->backend[u], NULL)) {
- vbit_set(vd->healthy, u);
- tw += vd->weight[u];
- } else {
- vbit_clr(vd->healthy, u);
- }
- }
- if (tw > 0.0) {
- u = vdir_pick_by_weight(vd, w * tw);
+ vdir_update_health(ctx, vd);
+ if (vd->total_weight > 0.0) {
+ u = vdir_pick_by_weight(vd, w * vd->total_weight);
assert(u < vd->n_backend);
be = vd->backend[u];
CHECK_OBJ_NOTNULL(be, DIRECTOR_MAGIC);
diff --git a/lib/libvmod_directors/vdir.h b/lib/libvmod_directors/vdir.h
index 786f233e2..287d88fae 100644
--- a/lib/libvmod_directors/vdir.h
+++ b/lib/libvmod_directors/vdir.h
@@ -39,6 +39,7 @@ struct vdir {
double total_weight;
VCL_BACKEND dir;
struct vbitmap *healthy;
+ unsigned n_healthy;
};
void vdir_new(VRT_CTX, struct vdir **vdp, const char *vcl_name,
@@ -51,4 +52,5 @@ void vdir_add_backend(VRT_CTX, struct vdir *, VCL_BACKEND, double weight);
void vdir_remove_backend(VRT_CTX, struct vdir *, VCL_BACKEND, unsigned *cur);
VCL_BOOL vdir_any_healthy(VRT_CTX, struct vdir *, VCL_TIME *);
void vdir_list(VRT_CTX, struct vdir *, struct vsb *, int, int, int);
+void vdir_update_health(VRT_CTX, struct vdir *);
VCL_BACKEND vdir_pick_be(VRT_CTX, struct vdir *, double w);
More information about the varnish-commit
mailing list