[master] 3284aed Store VSC documentation in their own segments and only once, no matter how many instances of the VSC set there are.

Poul-Henning Kamp phk at FreeBSD.org
Fri Dec 22 21:38:06 UTC 2017


commit 3284aed8679a176ba0e30b91055f6b074b279fd5
Author: Poul-Henning Kamp <phk at FreeBSD.org>
Date:   Fri Dec 22 21:37:21 2017 +0000

    Store VSC documentation in their own segments and only once, no matter
    how many instances of the VSC set there are.

diff --git a/bin/varnishd/common/common_vsc.c b/bin/varnishd/common/common_vsc.c
index 1e8842d..3a719ed 100644
--- a/bin/varnishd/common/common_vsc.c
+++ b/bin/varnishd/common/common_vsc.c
@@ -53,11 +53,19 @@ struct vsc_seg {
 	unsigned		magic;
 #define VSC_SEG_MAGIC		0x9b355991
 
+	struct vsmw		*vsm;		// keep master/child sep.
 	const char		*nm;
 	VTAILQ_ENTRY(vsc_seg)	list;
 	void			*seg;
+
+	/* VSC segments */
 	struct vsc_head		*head;
 	void			*ptr;
+	struct vsc_seg		*doc;
+
+	/* DOC segments */
+	const unsigned char	*jp;
+	int			refs;
 };
 
 static VTAILQ_HEAD(,vsc_seg)	vsc_seglist =
@@ -66,41 +74,86 @@ static VTAILQ_HEAD(,vsc_seg)	vsc_seglist =
 vsc_callback_f *vsc_lock;
 vsc_callback_f *vsc_unlock;
 
+static struct vsc_seg *
+vrt_vsc_mksegv(const char *class, size_t payload, const char *fmt, va_list va)
+{
+	struct vsc_seg *vsg;
+	size_t co;
+
+	co = PRNDUP(sizeof(struct vsc_head));
+	ALLOC_OBJ(vsg, VSC_SEG_MAGIC);
+	AN(vsg);
+	vsg->seg = VSMW_Allocv(heritage.proc_vsmw, class,
+	    co + PRNDUP(payload), fmt, va);
+	AN(vsg->seg);
+	vsg->vsm = heritage.proc_vsmw;
+	vsg->head = (void*)vsg->seg;
+	vsg->head->body_offset = co;
+	vsg->ptr = (char*)vsg->seg + co;
+	return (vsg);
+}
+
+static struct vsc_seg *
+vrt_vsc_mksegf(const char *class, size_t payload, const char *fmt, ...)
+{
+	va_list ap;
+	struct vsc_seg *vsg;
+
+	va_start(ap, fmt);
+	vsg = vrt_vsc_mksegv(class, payload, fmt, ap);
+	va_end(ap);
+	return (vsg);
+}
+
 void *
 VRT_VSC_Alloc(struct vsc_seg **sg, const char *nm, size_t sd,
     const unsigned char *jp, size_t sj, const char *fmt, va_list va)
 {
-	char *p;
-	struct vsc_seg *vsg;
+	struct vsc_seg *vsg, *dvsg;
 	char buf[1024];
-	uint64_t co, jo;
+	uintptr_t jjp;
 
 	if (vsc_lock != NULL)
 		vsc_lock();
 
+	jjp = (uintptr_t)jp;
+
+	VTAILQ_FOREACH(dvsg, &vsc_seglist, list) {
+		if (dvsg->vsm != heritage.proc_vsmw)
+			continue;
+		if (dvsg->jp == NULL || dvsg->jp == jp)
+			break;
+	}
+	if (dvsg == NULL || dvsg->jp == NULL) {
+		/* Create a new documentation segment */
+		dvsg = vrt_vsc_mksegf(VSC_DOC_CLASS, sj,
+		    "%jx", (uintmax_t)jjp);
+		AN(dvsg);
+		dvsg->jp = jp;
+		dvsg->head->doc_id = jjp;
+		memcpy(dvsg->ptr, jp, sj);
+		VWMB();
+		dvsg->head->ready = 1;
+		VTAILQ_INSERT_HEAD(&vsc_seglist, dvsg, list);
+	}
+	AN(dvsg);
+	dvsg->refs++;
+
 	if (*fmt == '\0')
 		bprintf(buf, "%s", nm);
 	else
 		bprintf(buf, "%s.%s", nm, fmt);
 
-	co = PRNDUP(sizeof(struct vsc_head));
-	jo = co + PRNDUP(sd);
 	AN(heritage.proc_vsmw);
-	p = VSMW_Allocv(heritage.proc_vsmw, VSC_CLASS,
-	    jo + PRNDUP(sj), buf, va);
-	AN(p);
 
-	ALLOC_OBJ(vsg, VSC_SEG_MAGIC);
+	vsg = vrt_vsc_mksegv(VSC_CLASS, sd, buf, va);
 	AN(vsg);
-	vsg->seg = p;
-	vsg->head = (void*)p;
-	vsg->head->ctr_offset = co;
-	vsg->ptr = p + co;
+	vsg->nm = nm;
+	vsg->doc = dvsg;
+	vsg->head->doc_id = jjp;
 	VTAILQ_INSERT_TAIL(&vsc_seglist, vsg, list);
-	memcpy(p + jo, jp, sj);
 	VWMB();
-	vsg->head->json_offset = jo;
-	vsg->nm = nm;
+	vsg->head->ready = 1;
 	if (vsc_unlock != NULL)
 		vsc_unlock();
 	if (sg != NULL)
@@ -111,16 +164,27 @@ VRT_VSC_Alloc(struct vsc_seg **sg, const char *nm, size_t sd,
 void
 VRT_VSC_Destroy(const char *nm, struct vsc_seg *vsg)
 {
+	struct vsc_seg *dvsg;
 
 	if (vsc_lock != NULL)
 		vsc_lock();
 
 	AN(heritage.proc_vsmw);
 	CHECK_OBJ_NOTNULL(vsg, VSC_SEG_MAGIC);
+	AZ(vsg->jp);
+	CHECK_OBJ_NOTNULL(vsg->doc, VSC_SEG_MAGIC);
+	assert(vsg->vsm == heritage.proc_vsmw);
 	assert(vsg->nm == nm);
+
+	dvsg = vsg->doc;
 	VSMW_Free(heritage.proc_vsmw, &vsg->seg);
 	VTAILQ_REMOVE(&vsc_seglist, vsg, list);
 	FREE_OBJ(vsg);
+	if (--dvsg->refs == 0) {
+		VSMW_Free(heritage.proc_vsmw, &dvsg->seg);
+		VTAILQ_REMOVE(&vsc_seglist, dvsg, list);
+		FREE_OBJ(dvsg);
+	}
 	if (vsc_unlock != NULL)
 		vsc_unlock();
 }
diff --git a/include/vsc_priv.h b/include/vsc_priv.h
index e0d9f2e..88f55dd 100644
--- a/include/vsc_priv.h
+++ b/include/vsc_priv.h
@@ -37,8 +37,10 @@
 #define VSC_PRIV_H_INCLUDED
 
 #define VSC_CLASS		"Stat"
+#define VSC_DOC_CLASS		"StatDoc"
 
 struct vsc_head {
-	volatile uint64_t	json_offset;
-	uint64_t		ctr_offset;
+	volatile int		ready;
+	uint64_t		body_offset;
+	uintptr_t		doc_id;
 };
diff --git a/lib/libvarnishapi/vsc.c b/lib/libvarnishapi/vsc.c
index 92a4939..8f7c2df 100644
--- a/lib/libvarnishapi/vsc.c
+++ b/lib/libvarnishapi/vsc.c
@@ -69,8 +69,11 @@ struct vsc_seg {
 #define VSC_SEG_MAGIC		0x801177d4
 	VTAILQ_ENTRY(vsc_seg)	list;
 	struct vsm_fantom	fantom[1];
-	struct vjsn		*vj;
 	struct vsc_head		*head;
+	char			*body;
+
+	struct vjsn		*vj;
+
 	unsigned		npoints;
 	struct vsc_pt		*points;
 };
@@ -205,7 +208,7 @@ vsc_clean_point(struct vsc_pt *point)
 }
 
 static int
-vsc_fill_point(const struct vsc *vsc, struct vsc_seg *seg,
+vsc_fill_point(const struct vsc *vsc, const struct vsc_seg *seg,
     const struct vjsn_val *vv, struct vsb *vsb, struct vsc_pt *point)
 {
 	struct vjsn_val *vt;
@@ -285,9 +288,7 @@ vsc_fill_point(const struct vsc *vsc, struct vsc_seg *seg,
 	vt = vjsn_child(vv, "index");
 	AN(vt);
 
-	point->point.ptr = (volatile void*)
-	    ((volatile char*)seg->fantom->b +
-		seg->head->ctr_offset + atoi(vt->value));
+	point->point.ptr = (volatile void*)(seg->body + atoi(vt->value));
 	return (1);
 }
 
@@ -301,22 +302,24 @@ vsc_del_seg(const struct vsc *vsc, struct vsm *vsm, struct vsc_seg *sp)
 	AN(vsm);
 	CHECK_OBJ_NOTNULL(sp, VSC_SEG_MAGIC);
 	AZ(VSM_Unmap(vsm, sp->fantom));
-	vjsn_delete(&sp->vj);
-	pp = sp->points;
-	for (u = 0; u < sp->npoints; u++, pp++) {
-		if (vsc->fdestroy != NULL)
-			vsc->fdestroy(vsc->priv, &pp->point);
-		vsc_clean_point(pp);
+	if (sp->vj != NULL) {
+		vjsn_delete(&sp->vj);
+	} else {
+		pp = sp->points;
+		for (u = 0; u < sp->npoints; u++, pp++) {
+			if (vsc->fdestroy != NULL)
+				vsc->fdestroy(vsc->priv, &pp->point);
+			vsc_clean_point(pp);
+		}
+		free(sp->points);
 	}
-	free(sp->points);
 	FREE_OBJ(sp);
 }
 
 static struct vsc_seg *
 vsc_add_seg(const struct vsc *vsc, struct vsm *vsm, const struct vsm_fantom *fp)
 {
-	struct vsc_seg *sp;
-	const char *p;
+	struct vsc_seg *sp, *spd;
 	const char *e;
 	struct vjsn_val *vv, *vve;
 	struct vsb *vsb;
@@ -336,34 +339,43 @@ vsc_add_seg(const struct vsc *vsc, struct vsm *vsm, const struct vsm_fantom *fp)
 		FREE_OBJ(sp);
 		return (NULL);
 	}
-
 	sp->head = sp->fantom->b;
-	if (sp->head->json_offset == 0) {
+	if (sp->head->ready == 0) {
 		VRMB();
 		usleep(100000);
 	}
-	assert(sp->head->json_offset > 0);
-	p = (char*)sp->fantom->b + sp->head->json_offset;
-	assert (p < (char*)sp->fantom->e);
-	sp->vj = vjsn_parse(p, &e);
-	XXXAZ(e);
-	vve = vjsn_child(sp->vj->value, "elements");
-	AN(vve);
-	sp->npoints = strtoul(vve->value, NULL, 0);
-	sp->points = calloc(sp->npoints, sizeof *sp->points);
-	AN(sp->points);
-	vsb = VSB_new_auto();
-	AN(vsb);
-	vve = vjsn_child(sp->vj->value, "elem");
-	AN(vve);
-	pp = sp->points;
-	VTAILQ_FOREACH(vv, &vve->children, list) {
-		if (vsc_fill_point(vsc, sp, vv, vsb, pp) &&
-			vsc->fnew != NULL)
-			pp->point.priv = vsc->fnew(vsc->priv, &pp->point);
-		pp++;
+	assert(sp->head->ready > 0);
+	sp->body = (char*)sp->fantom->b + sp->head->body_offset;
+
+	if (!strcmp(fp->class, VSC_CLASS)) {
+		VTAILQ_FOREACH(spd, &vsc->segs, list)
+			if (spd->head->doc_id == sp->head->doc_id)
+				break;
+		AN(spd);
+		// XXX: Refcount ?
+		vve = vjsn_child(spd->vj->value, "elements");
+		AN(vve);
+		sp->npoints = strtoul(vve->value, NULL, 0);
+		sp->points = calloc(sp->npoints, sizeof *sp->points);
+		AN(sp->points);
+		vsb = VSB_new_auto();
+		AN(vsb);
+		vve = vjsn_child(spd->vj->value, "elem");
+		AN(vve);
+		pp = sp->points;
+		VTAILQ_FOREACH(vv, &vve->children, list) {
+			if (vsc_fill_point(vsc, sp, vv, vsb, pp) &&
+				vsc->fnew != NULL)
+				pp->point.priv =
+				    vsc->fnew(vsc->priv, &pp->point);
+			pp++;
+		}
+		VSB_destroy(&vsb);
+		return (sp);
 	}
-	VSB_destroy(&vsb);
+	assert(!strcmp(fp->class, VSC_DOC_CLASS));
+	sp->vj = vjsn_parse(sp->body, &e);
+	XXXAZ(e);
 	AN(sp->vj);
 	return (sp);
 }
@@ -398,8 +410,10 @@ VSC_Iter(struct vsc *vsc, struct vsm *vsm, VSC_iter_f *fiter, void *priv)
 	AN(vsm);
 	sp = VTAILQ_FIRST(&vsc->segs);
 	VSM_FOREACH(&ifantom, vsm) {
-		if (strcmp(ifantom.class, VSC_CLASS))
+		if (strcmp(ifantom.class, VSC_CLASS) &&
+		    strcmp(ifantom.class, VSC_DOC_CLASS))
 			continue;
+		sp2 = sp;
 		while (sp != NULL &&
 		    (strcmp(ifantom.ident, sp->fantom->ident) ||
 		    VSM_StillValid(vsm, sp->fantom) != VSM_valid)) {
@@ -408,19 +422,18 @@ VSC_Iter(struct vsc *vsc, struct vsm *vsm, VSC_iter_f *fiter, void *priv)
 			VTAILQ_REMOVE(&vsc->segs, sp2, list);
 			vsc_del_seg(vsc, vsm, sp2);
 		}
-		if (sp != NULL) {
-			if (fiter != NULL)
-				i = vsc_iter_seg(vsc, sp, fiter, priv);
-			sp = VTAILQ_NEXT(sp, list);
-		} else {
+		if (sp == NULL) {
 			sp = vsc_add_seg(vsc, vsm, &ifantom);
 			if (sp != NULL) {
 				VTAILQ_INSERT_TAIL(&vsc->segs, sp, list);
-				if (fiter != NULL)
-					i = vsc_iter_seg(vsc, sp, fiter, priv);
-				sp = NULL;
+				sp2 = NULL;
 			}
+		} else {
+			sp2 = VTAILQ_NEXT(sp, list);
 		}
+		if (sp != NULL && fiter != NULL)
+			i = vsc_iter_seg(vsc, sp, fiter, priv);
+		sp = sp2;
 		if (i)
 			break;
 	}


More information about the varnish-commit mailing list