[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