Hi!

Here's an implementation which uses malloc instead of mmap (and hence
bypasses both the issues altogether); and a more rigorous testcase.

-- 
Regards,

Sanjoy Das.

http://playingwithpointers.com

Public Key at http://playingwithpointers.com/custom/public_key.txt
Index: varnish/varnish-cache/lib/libvmod_std/vmod.vcc
===================================================================
--- varnish.orig/varnish-cache/lib/libvmod_std/vmod.vcc	2010-11-15 14:09:04.000000000 +0530
+++ varnish/varnish-cache/lib/libvmod_std/vmod.vcc	2010-11-15 14:10:06.000000000 +0530
@@ -33,3 +33,4 @@
 Function REAL random(REAL, REAL)
 Function VOID log(STRING_LIST)
 Function VOID syslog(INT, STRING_LIST)
+Function STRING fileread(PRIV_CALL, STRING)
Index: varnish/varnish-cache/lib/libvmod_std/vmod_std.c
===================================================================
--- varnish.orig/varnish-cache/lib/libvmod_std/vmod_std.c	2010-11-15 14:09:09.000000000 +0530
+++ varnish/varnish-cache/lib/libvmod_std/vmod_std.c	2010-11-15 14:13:18.000000000 +0530
@@ -27,10 +27,17 @@
  */
 
 #include <ctype.h>
+#include <fcntl.h>
+#include <pthread.h>
 #include <stdarg.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <syslog.h>
+#include <unistd.h>
 #include <netinet/in.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
 #include "vrt.h"
 #include "../../bin/varnishd/cache.h"
 
@@ -161,3 +168,120 @@
 	if (p != NULL)
 		syslog(fac, "%s", buf);
 }
+
+VSLIST_HEAD(cached_file_list, cached_file);
+
+struct cached_file {
+	unsigned	magic;
+#define CACHED_FILE_MAGIC 0xa8e9d87a
+	char		*file_name;
+	char		*contents;
+	time_t		last_modification;
+	off_t		file_sz;
+	VSLIST_ENTRY(cached_file) next;
+};
+
+static void
+free_cached_files(void *file_list)
+{
+	struct cached_file *iter, *tmp;
+	struct cached_file_list *list = file_list;
+	VSLIST_FOREACH_SAFE(iter, list, next, tmp) {
+		CHECK_OBJ(iter, CACHED_FILE_MAGIC);
+		free(iter->file_name);
+		free(iter->contents);
+		FREE_OBJ(iter);
+	}
+	free(file_list);
+}
+
+pthread_rwlock_t filelist_lock = PTHREAD_RWLOCK_INITIALIZER;
+int filelist_update = 0;
+
+const char *
+vmod_fileread(struct sess *sp, struct vmod_priv *priv, const char *file_name)
+{
+	struct cached_file *iter = NULL;
+	struct stat buf;
+	struct cached_file_list *list;
+	int fd, aligned_sz, pagesize, my_filelist_update;
+
+	pagesize = getpagesize();
+
+	(void)sp;
+
+	AZ(pthread_rwlock_rdlock(&filelist_lock));
+
+	if (priv->free == NULL) {
+		AZ(pthread_rwlock_unlock(&filelist_lock));
+		/*
+		 * Another thread may already have initialized priv
+		 * here, making the repeat check necessary.
+		 */
+		AZ(pthread_rwlock_wrlock(&filelist_lock));
+		if (priv->free == NULL) {
+			priv->free = free_cached_files;
+			priv->priv = malloc(sizeof(struct cached_file_list));
+			list = priv->priv;
+			VSLIST_INIT(list);
+		}
+		AZ(pthread_rwlock_unlock(&filelist_lock));
+		AZ(pthread_rwlock_rdlock(&filelist_lock));
+	} else {
+		list = priv->priv;
+		VSLIST_FOREACH(iter, list, next) {
+			CHECK_OBJ(iter, CACHED_FILE_MAGIC);
+			if (strcmp(iter->file_name, file_name) == 0) {
+				/* This thread was holding a read lock. */
+				AZ(pthread_rwlock_unlock(&filelist_lock));
+				return iter->contents;
+			}
+		}
+	}
+
+	my_filelist_update = filelist_update;
+
+	/* This thread was holding a read lock. */
+	pthread_rwlock_unlock(&filelist_lock);
+
+	if ((fd = open(file_name, O_RDONLY)) == -1)
+		return "";
+
+	fstat(fd, &buf);
+
+	AZ(pthread_rwlock_wrlock(&filelist_lock));
+
+	if (my_filelist_update != filelist_update) {
+
+		/*
+		 * Small optimization: search through the linked list again
+		 * only if something has been changed.
+		 */
+		VSLIST_FOREACH(iter, list, next) {
+			CHECK_OBJ(iter, CACHED_FILE_MAGIC);
+			if (strcmp(iter->file_name, file_name) == 0) {
+				/* This thread was holding a write lock. */
+				AZ(pthread_rwlock_unlock(&filelist_lock));
+				return iter->contents;
+			}
+		}
+	}
+
+	ALLOC_OBJ(iter, CACHED_FILE_MAGIC);
+
+	iter->file_name = strdup(file_name);
+	iter->last_modification = buf.st_mtime;
+
+	iter->contents = malloc(buf.st_size + 1);
+	iter->file_sz = read(fd, iter->contents, buf.st_size);
+	assert(iter->file_sz == buf.st_size);
+	close(fd);
+
+	iter->contents[iter->file_sz] = '\0';
+
+	VSLIST_INSERT_HEAD(list, iter, next);
+
+	my_filelist_update++;
+	AZ(pthread_rwlock_unlock(&filelist_lock));
+	return iter->contents;
+}
Index: varnish/varnish-cache/bin/varnishtest/tests/m00004.vtc
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ varnish/varnish-cache/bin/varnishtest/tests/m00004.vtc	2010-11-15 14:14:15.000000000 +0530
@@ -0,0 +1,114 @@
+test "Test fileread for std VMOD"
+
+shell {
+	echo -n "File One" > "${tmpdir}/file_one"
+	echo -n "File Two" > "${tmpdir}/file_two"
+	echo -n "File Three" > "${tmpdir}/file_three"
+}
+
+server s1 {
+	loop 3 {
+		rxreq
+		txresp -hdr "foo: bar" -bodylen 4
+	}
+} -start
+
+varnish v1 -arg "-pvmod_dir=${topbuild}/lib/libvmod_std/.libs/" \
+	-vcl+backend {
+	import std;
+
+	sub vcl_deliver {
+		if (req.url == "/one") {
+			set resp.http.one = std.fileread("${tmpdir}/file_one");
+		} else if (req.url == "/two") {
+			set resp.http.two = std.fileread("${tmpdir}/file_two");
+		} else if (req.url == "/three") {
+			set resp.http.three = std.fileread("${tmpdir}/file_three");
+		}
+	}
+} -start
+
+client c1 {
+	loop 5 {
+		txreq -url "/one"
+		rxresp
+		expect resp.status == 200
+		expect resp.http.content-length == "4"
+		expect resp.http.foo == "bar"
+		expect resp.http.one == "File One"
+	}
+
+	loop 5 {
+		txreq -url "/two"
+		rxresp
+		expect resp.status == 200
+		expect resp.http.content-length == "4"
+		expect resp.http.foo == "bar"
+		expect resp.http.two == "File Two"
+
+		txreq -url "/three"
+		rxresp
+		expect resp.status == 200
+		expect resp.http.content-length == "4"
+		expect resp.http.foo == "bar"
+		expect resp.http.three == "File Three"
+	}
+}
+
+client c2 {
+	loop 5 {
+		txreq -url "/two"
+		rxresp
+		expect resp.status == 200
+		expect resp.http.content-length == "4"
+		expect resp.http.foo == "bar"
+		expect resp.http.two == "File Two"
+	}
+
+	loop 5 {
+		txreq -url "/one"
+		rxresp
+		expect resp.status == 200
+		expect resp.http.content-length == "4"
+		expect resp.http.foo == "bar"
+		expect resp.http.one == "File One"
+
+		txreq -url "/three"
+		rxresp
+		expect resp.status == 200
+		expect resp.http.content-length == "4"
+		expect resp.http.foo == "bar"
+		expect resp.http.three == "File Three"
+	}
+}
+
+client c3 {
+	loop 5 {
+		txreq -url "/three"
+		rxresp
+		expect resp.status == 200
+		expect resp.http.content-length == "4"
+		expect resp.http.foo == "bar"
+		expect resp.http.three == "File Three"
+	}
+
+	loop 5 {
+		txreq -url "/two"
+		rxresp
+		expect resp.status == 200
+		expect resp.http.content-length == "4"
+		expect resp.http.foo == "bar"
+		expect resp.http.two == "File Two"
+
+		txreq -url "/one"
+		rxresp
+		expect resp.status == 200
+		expect resp.http.content-length == "4"
+		expect resp.http.foo == "bar"
+		expect resp.http.one == "File One"
+	}
+}
+
+client c1 -run
+client c2 -run
+client c3 -run
_______________________________________________
varnish-dev mailing list
[email protected]
http://lists.varnish-cache.org/mailman/listinfo/varnish-dev

Reply via email to