[master] 1bb10f4 Use reference counts to avoid duplicated files in std.fileread().
Poul-Henning Kamp
phk at varnish-cache.org
Wed May 11 11:01:12 CEST 2011
commit 1bb10f4b261f07ef4bada8aabc63dc84cf50a206
Author: Poul-Henning Kamp <phk at FreeBSD.org>
Date: Wed May 11 09:00:38 2011 +0000
Use reference counts to avoid duplicated files in std.fileread().
diff --git a/lib/libvmod_std/vmod_std_fileread.c b/lib/libvmod_std/vmod_std_fileread.c
index 3e2fcf4..1890b76 100644
--- a/lib/libvmod_std/vmod_std_fileread.c
+++ b/lib/libvmod_std/vmod_std_fileread.c
@@ -48,119 +48,75 @@
#include "vcc_if.h"
-VSLIST_HEAD(cached_file_list, cached_file);
-
-struct cached_file {
- unsigned magic;
+struct frfile {
+ unsigned magic;
#define CACHED_FILE_MAGIC 0xa8e9d87a
- char *file_name;
- char *contents;
- time_t last_modification;
- ssize_t file_sz;
- VSLIST_ENTRY(cached_file) next;
+ char *file_name;
+ char *contents;
+ int refcount;
+ VTAILQ_ENTRY(frfile) list;
};
+static VTAILQ_HEAD(, frfile) frlist = VTAILQ_HEAD_INITIALIZER(frlist);
+static pthread_mutex_t frmtx = PTHREAD_MUTEX_INITIALIZER;
+
static void
-free_cached_files(void *file_list)
+free_frfile(void *ptr)
{
- 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);
+ struct frfile *frf;
+
+ CAST_OBJ_NOTNULL(frf, ptr, CACHED_FILE_MAGIC);
+
+ AZ(pthread_mutex_lock(&frmtx));
+ if (--frf->refcount > 0)
+ frf = NULL;
+ else
+ VTAILQ_REMOVE(&frlist, frf, list);
+ AZ(pthread_mutex_unlock(&frmtx));
+ if (frf != NULL) {
+ free(frf->contents);
+ free(frf->file_name);
+ FREE_OBJ(frf);
}
- free(file_list);
}
-static pthread_rwlock_t filelist_lock = PTHREAD_RWLOCK_INITIALIZER;
-static 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, my_filelist_update;
+ struct frfile *frf;
+ char *s;
(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));
- AN(priv->priv);
- 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;
- }
- }
+ AN(priv);
+ if (priv->priv != NULL) {
+ CAST_OBJ_NOTNULL(frf, priv->priv, CACHED_FILE_MAGIC);
+ return (frf->contents);
}
-
- my_filelist_update = filelist_update;
-
- /* This thread was holding a read lock. */
- AZ(pthread_rwlock_unlock(&filelist_lock));
-
- if ((fd = open(file_name, O_RDONLY)) == -1)
- return "";
-
- AZ(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;
- }
+
+ AZ(pthread_mutex_lock(&frmtx));
+ VTAILQ_FOREACH(frf, &frlist, list) {
+ if (!strcmp(file_name, frf->file_name)) {
+ frf->refcount++;
+ break;
}
}
-
- ALLOC_OBJ(iter, CACHED_FILE_MAGIC);
- AN(iter);
-
- iter->file_name = strdup(file_name);
- iter->last_modification = buf.st_mtime;
-
- iter->contents = vreadfd(fd, &iter->file_sz);
- AN(iter->contents);
- assert(iter->file_sz == buf.st_size);
- AZ(close(fd));
-
- VSLIST_INSERT_HEAD(list, iter, next);
-
- filelist_update++;
-
- /* This thread was holding a write lock. */
- AZ(pthread_rwlock_unlock(&filelist_lock));
- return iter->contents;
+ AZ(pthread_mutex_unlock(&frmtx));
+ if (frf != NULL)
+ return (frf->contents);
+
+ s = vreadfile(NULL, file_name, NULL);
+ if (s != NULL) {
+ ALLOC_OBJ(frf, CACHED_FILE_MAGIC);
+ AN(frf);
+ frf->file_name = strdup(file_name);
+ AN(frf->file_name);
+ frf->refcount = 1;
+ frf->contents = s;
+ priv->free = free_frfile;
+ priv->priv = frf;
+ AZ(pthread_mutex_lock(&frmtx));
+ VTAILQ_INSERT_HEAD(&frlist, frf, list);
+ AZ(pthread_mutex_unlock(&frmtx));
+ }
+ return (s);
}
More information about the varnish-commit
mailing list