r217 - in trunk/varnish-cache: include lib/libvarnish lib/libvcl

phk at projects.linpro.no phk at projects.linpro.no
Wed Jun 21 10:09:02 CEST 2006


Author: phk
Date: 2006-06-21 10:09:02 +0200 (Wed, 21 Jun 2006)
New Revision: 217

Added:
   trunk/varnish-cache/include/binary_heap.h
   trunk/varnish-cache/lib/libvarnish/binary_heap.c
Modified:
   trunk/varnish-cache/include/Makefile.am
   trunk/varnish-cache/lib/libvarnish/Makefile.am
   trunk/varnish-cache/lib/libvcl/vcl_fixed_token.c
Log:
Add a binary heap implementation for keeping track of objects expiry time.



Modified: trunk/varnish-cache/include/Makefile.am
===================================================================
--- trunk/varnish-cache/include/Makefile.am	2006-06-20 19:49:28 UTC (rev 216)
+++ trunk/varnish-cache/include/Makefile.am	2006-06-21 08:09:02 UTC (rev 217)
@@ -1,6 +1,7 @@
 # $Id$
 
 include_HEADERS = \
+	binary_heap.h \
 	compat.h \
 	hash.h \
 	libvarnish.h \

Added: trunk/varnish-cache/include/binary_heap.h
===================================================================
--- trunk/varnish-cache/include/binary_heap.h	2006-06-20 19:49:28 UTC (rev 216)
+++ trunk/varnish-cache/include/binary_heap.h	2006-06-21 08:09:02 UTC (rev 217)
@@ -0,0 +1,49 @@
+/*
+ * $Id$
+ *
+ * Binary Heap API (see: http://en.wikipedia.org/wiki/Binary_heap)
+ *
+ * XXX: doesn't scale back the array of pointers when items are deleted.
+ */
+
+/* Public Interface --------------------------------------------------*/
+
+struct binheap;
+
+typedef int binheap_cmp_t(void *priv, void *a, void *b);
+	/*
+	 * Comparison function.
+ 	 * Should return true if item 'a' should be closer to the root
+	 * than item 'b'
+	 */
+
+typedef void binheap_update_t(void *priv, void *a, unsigned newidx);
+	/*
+	 * Update function (optional)
+	 * When items move in the tree, this function gets called to
+	 * notify the item of its new index.
+	 * Only needed if deleting non-root items.
+	 */
+
+struct binheap *binheap_new(void *priv, binheap_cmp_t, binheap_update_t);
+	/*
+	 * Create Binary tree
+	 * 'priv' is passed to cmp and update functions.
+ 	 */
+
+void binheap_insert(struct binheap *, void *);
+	/*
+	 * Insert an item
+	 */
+
+void binheap_delete(struct binheap *, unsigned idx);
+	/*
+	 * Delete an item
+	 * The root item has 'idx' zero
+	 */
+
+void *binheap_root(struct binheap *);
+	/*
+	 * Return the root item
+	 */
+

Modified: trunk/varnish-cache/lib/libvarnish/Makefile.am
===================================================================
--- trunk/varnish-cache/lib/libvarnish/Makefile.am	2006-06-20 19:49:28 UTC (rev 216)
+++ trunk/varnish-cache/lib/libvarnish/Makefile.am	2006-06-21 08:09:02 UTC (rev 217)
@@ -6,5 +6,6 @@
 
 libvarnish_la_SOURCES = \
 	argv.c \
+	binary_heap.c \
 	cli.c \
 	time.c

Added: trunk/varnish-cache/lib/libvarnish/binary_heap.c
===================================================================
--- trunk/varnish-cache/lib/libvarnish/binary_heap.c	2006-06-20 19:49:28 UTC (rev 216)
+++ trunk/varnish-cache/lib/libvarnish/binary_heap.c	2006-06-21 08:09:02 UTC (rev 217)
@@ -0,0 +1,260 @@
+/*
+ * $Id$
+ *
+ * Implementation of a binary heap API
+ *
+ * We use a malloc(3)/realloc(3) array to store the pointers using the
+ * classical FORTRAN strategy.
+ *
+ * XXX: the array is not scaled back when items are deleted.
+ */
+
+#include <assert.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "binary_heap.h"
+
+/* Private definitions -----------------------------------------------*/
+
+#define MIN_LENGTH		16
+
+struct binheap {
+	unsigned		magic;
+#define BINHEAP_MAGIC		0xf581581aU	/* from /dev/random */
+	void			*priv;
+	binheap_cmp_t		*cmp;
+	binheap_update_t	*update;
+	void			**array;
+	unsigned		length;
+	unsigned		next;
+	unsigned		granularity;
+};
+
+#define PARENT(u)	(((u) - 1) / 2)
+#define CHILD(u,n)	((u) * 2 + (n))
+
+/* Implementation ----------------------------------------------------*/
+
+static void
+binheap_update(struct binheap *bh, unsigned u)
+{
+	assert(bh->magic == BINHEAP_MAGIC);
+	assert(u < bh->next);
+	if (bh->update == NULL)
+		return;
+	bh->update(bh->priv, bh->array[u], u);
+}
+
+struct binheap *
+binheap_new(void *priv, binheap_cmp_t *cmp_f, binheap_update_t *update_f)
+{
+	struct binheap *bh;
+
+	bh = calloc(sizeof *bh, 1);
+	if (bh == NULL)
+		return (bh);
+	bh->priv = priv;
+	bh->cmp = cmp_f;
+	bh->update = update_f;
+	bh->next = 0;
+	bh->length = MIN_LENGTH;
+	bh->array = calloc(sizeof *bh->array, bh->length);
+	assert(bh->array != NULL);
+	bh->granularity = getpagesize() / sizeof *bh->array;
+	bh->magic = BINHEAP_MAGIC;
+	return (bh);
+}
+
+static void
+binhead_swap(struct binheap *bh, unsigned u, unsigned v)
+{
+	void *p;
+
+	assert(bh->magic == BINHEAP_MAGIC);
+	assert(u < bh->next);
+	assert(v < bh->next);
+	p = bh->array[u];
+	bh->array[u] = bh->array[v];
+	bh->array[v] = p;
+	binheap_update(bh, u);
+	binheap_update(bh, v);
+}
+
+static unsigned
+binheap_trickleup(struct binheap *bh, unsigned u)
+{
+	unsigned v;
+
+	assert(bh->magic == BINHEAP_MAGIC);
+	while (u > 0) {
+		v = PARENT(u);
+		if (bh->cmp(bh->priv, bh->array[u], bh->array[v])) {
+			binhead_swap(bh, u, v);
+			u = v;
+		} else
+			break;
+	}
+	return (u);
+}
+
+static void
+binheap_trickledown(struct binheap *bh, unsigned u)
+{
+	unsigned v1, v2;
+
+	assert(bh->magic == BINHEAP_MAGIC);
+	while (1) {
+		v1 = CHILD(u, 1);
+		if (v1 >= bh->next)
+			return;
+		v2 = CHILD(u, 2);
+		if (v2 >= bh->next) {
+			if (!bh->cmp(bh->priv, bh->array[u], bh->array[v1]))
+				binhead_swap(bh, u, v1);
+			return;
+		}
+		if (bh->cmp(bh->priv, bh->array[v1], bh->array[v2])) {
+			if (!bh->cmp(bh->priv, bh->array[u], bh->array[v1])) {
+				binhead_swap(bh, u, v1);
+				u = v1;
+				continue;
+			}
+		} else {
+			if (!bh->cmp(bh->priv, bh->array[u], bh->array[v2])) {
+				binhead_swap(bh, u, v2);
+				u = v2;
+				continue;
+			}
+		}
+		return;
+	}
+}
+
+void
+binheap_insert(struct binheap *bh, void *p)
+{
+	unsigned u;
+
+	assert(bh->magic == BINHEAP_MAGIC);
+	assert(bh->length >= bh->next);
+	if (bh->length == bh->next) {
+		if (bh->length >= bh->granularity * 32)
+			bh->length += bh->granularity * 32;
+		else if (bh->length > bh->granularity)
+			bh->length += bh->granularity;
+		else
+			bh->length += bh->length;
+		bh->array = realloc(bh->array, bh->length * sizeof *bh->array);
+		assert(bh->array != NULL);
+	}
+	u = bh->next++;
+	bh->array[u] = p;
+	binheap_update(bh, u);
+	binheap_trickleup(bh, u);
+}
+
+void *
+binheap_root(struct binheap *bh)
+{
+
+	assert(bh->magic == BINHEAP_MAGIC);
+	if(bh->next == 0)
+		return (NULL);
+	return (bh->array[0]);
+}
+
+void
+binheap_delete(struct binheap *bh, unsigned idx)
+{
+
+	assert(bh->magic == BINHEAP_MAGIC);
+	assert(bh->next > 0);
+	assert(idx < bh->next);
+	if (idx == --bh->next)
+		return;
+	bh->array[idx] = bh->array[bh->next];
+	binheap_update(bh, idx);
+	binheap_trickledown(bh, idx);
+	/* XXX: free part of array ? */
+}
+
+
+#ifdef TEST_DRIVER
+/* Test driver -------------------------------------------------------*/
+
+#include <stdio.h>
+
+static int
+cmp(void *priv, void *a, void *b)
+{
+
+	return (*(unsigned *)a < *(unsigned *)b);
+}
+
+void
+update(void *priv, void *a, unsigned u)
+{
+	printf("%p is now %u\n", a, u);
+}
+
+static void
+dump(struct binheap *bh, const char *what, unsigned ptr)
+{
+	FILE *f;
+	unsigned u, *up;
+
+	printf("dump\n");
+	f = popen("dot -Tps >> /tmp/_.ps", "w");
+	assert(f != NULL);
+	fprintf(f, "digraph binheap {\n");
+	fprintf(f, "size=\"7,10\"\n");
+	fprintf(f, "ptr [label=\"%s\"]\n", what);
+	fprintf(f, "ptr -> node_%u\n", ptr);
+	for (u = 0; u < bh->next; u++) {
+		up = bh->array[u];
+		fprintf(f, "node_%u [label=\"%u\"];\n", u, *up);
+		if (u > 0)
+			fprintf(f, "node_%u -> node_%u\n", PARENT(u), u);
+	}
+	fprintf(f, "}\n");
+	pclose(f);
+}
+
+#define N 31
+int
+main(int argc, char **argv)
+{
+	struct binheap *bh;
+	unsigned l[N], u, *up, lu;
+
+	srandomdev();
+	u = random();
+	printf("Seed %u\n", u);
+	srandom(u);
+	system("echo %! > /tmp/_.ps");
+	bh = binheap_new(NULL, cmp, update);
+	for (u = 0; u < N; u++) {
+		l[u] = random() % 1000;
+		binheap_insert(bh, &l[u]);
+		if (1)
+			dump(bh, "Insert", 0);
+	}
+	printf("Inserts done\n");
+	lu = 0;
+	while(1) {
+		up = binheap_root(bh);
+		if (up == NULL)
+			break;
+		assert(*up >= lu);
+		lu = *up;
+		u = random() % bh->next;
+		binheap_delete(bh, u);
+		if (1)
+			dump(bh, "Delete", u);
+	}
+	printf("Deletes done\n");
+
+	return (0);
+}
+#endif

Modified: trunk/varnish-cache/lib/libvcl/vcl_fixed_token.c
===================================================================
--- trunk/varnish-cache/lib/libvcl/vcl_fixed_token.c	2006-06-20 19:49:28 UTC (rev 216)
+++ trunk/varnish-cache/lib/libvcl/vcl_fixed_token.c	2006-06-21 08:09:02 UTC (rev 217)
@@ -473,7 +473,7 @@
 	fputs("char *VRT_GetReq(struct sess *);\n", f);
 	fputs("void VRT_handling(struct sess *sp, unsigned hand);\n", f);
 	fputs("int VRT_obj_valid(struct sess *);\n", f);
-	fputs("int VRT_obj_cachable(struct sess *);\n", f);
+	fputs("int VRT_obj_cacheable(struct sess *);\n", f);
 	fputs("\n", f);
 	fputs("void VRT_set_backend_hostname(struct backend *, const char *);\n", f);
 	fputs("void VRT_set_backend_portname(struct backend *, const char *);\n", f);




More information about the varnish-commit mailing list