Commit 1bb10f4b authored by Poul-Henning Kamp's avatar Poul-Henning Kamp

Use reference counts to avoid duplicated files in std.fileread().

parent d30f2a6e
...@@ -48,119 +48,75 @@ ...@@ -48,119 +48,75 @@
#include "vcc_if.h" #include "vcc_if.h"
VSLIST_HEAD(cached_file_list, cached_file); struct frfile {
unsigned magic;
struct cached_file {
unsigned magic;
#define CACHED_FILE_MAGIC 0xa8e9d87a #define CACHED_FILE_MAGIC 0xa8e9d87a
char *file_name; char *file_name;
char *contents; char *contents;
time_t last_modification; int refcount;
ssize_t file_sz; VTAILQ_ENTRY(frfile) list;
VSLIST_ENTRY(cached_file) next;
}; };
static VTAILQ_HEAD(, frfile) frlist = VTAILQ_HEAD_INITIALIZER(frlist);
static pthread_mutex_t frmtx = PTHREAD_MUTEX_INITIALIZER;
static void static void
free_cached_files(void *file_list) free_frfile(void *ptr)
{ {
struct cached_file *iter, *tmp; struct frfile *frf;
struct cached_file_list *list = file_list;
VSLIST_FOREACH_SAFE(iter, list, next, tmp) { CAST_OBJ_NOTNULL(frf, ptr, CACHED_FILE_MAGIC);
CHECK_OBJ(iter, CACHED_FILE_MAGIC);
free(iter->file_name); AZ(pthread_mutex_lock(&frmtx));
free(iter->contents); if (--frf->refcount > 0)
FREE_OBJ(iter); 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 * const char *
vmod_fileread(struct sess *sp, struct vmod_priv *priv, const char *file_name) vmod_fileread(struct sess *sp, struct vmod_priv *priv, const char *file_name)
{ {
struct cached_file *iter = NULL; struct frfile *frf;
struct stat buf; char *s;
struct cached_file_list *list;
int fd, my_filelist_update;
(void)sp; (void)sp;
AN(priv);
AZ(pthread_rwlock_rdlock(&filelist_lock)); if (priv->priv != NULL) {
CAST_OBJ_NOTNULL(frf, priv->priv, CACHED_FILE_MAGIC);
if (priv->free == NULL) { return (frf->contents);
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;
}
}
} }
my_filelist_update = filelist_update; AZ(pthread_mutex_lock(&frmtx));
VTAILQ_FOREACH(frf, &frlist, list) {
/* This thread was holding a read lock. */ if (!strcmp(file_name, frf->file_name)) {
AZ(pthread_rwlock_unlock(&filelist_lock)); frf->refcount++;
break;
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_unlock(&frmtx));
ALLOC_OBJ(iter, CACHED_FILE_MAGIC); if (frf != NULL)
AN(iter); return (frf->contents);
iter->file_name = strdup(file_name); s = vreadfile(NULL, file_name, NULL);
iter->last_modification = buf.st_mtime; if (s != NULL) {
ALLOC_OBJ(frf, CACHED_FILE_MAGIC);
iter->contents = vreadfd(fd, &iter->file_sz); AN(frf);
AN(iter->contents); frf->file_name = strdup(file_name);
assert(iter->file_sz == buf.st_size); AN(frf->file_name);
AZ(close(fd)); frf->refcount = 1;
frf->contents = s;
VSLIST_INSERT_HEAD(list, iter, next); priv->free = free_frfile;
priv->priv = frf;
filelist_update++; AZ(pthread_mutex_lock(&frmtx));
VTAILQ_INSERT_HEAD(&frlist, frf, list);
/* This thread was holding a write lock. */ AZ(pthread_mutex_unlock(&frmtx));
AZ(pthread_rwlock_unlock(&filelist_lock)); }
return iter->contents; return (s);
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment