[vhffs-dev] [665] add a working cache |
[ Thread Index |
Date Index
| More vhffs.org/vhffs-dev Archives
]
Revision: 665
Author: gradator
Date: 2007-07-05 15:32:23 +0000 (Thu, 05 Jul 2007)
Log Message:
-----------
add a working cache
Modified Paths:
--------------
trunk/vhffs-tools/src/vhffsfs.c
trunk/vhffs-tools/src/vhffsfs_compil.sh
trunk/vhffs-tools/src/vhffsfs_run.sh
Modified: trunk/vhffs-tools/src/vhffsfs.c
===================================================================
--- trunk/vhffs-tools/src/vhffsfs.c 2007-07-05 11:35:33 UTC (rev 664)
+++ trunk/vhffs-tools/src/vhffsfs.c 2007-07-05 15:32:23 UTC (rev 665)
@@ -6,9 +6,12 @@
See the file COPYING.
*/
-#define _GNU_SOURCE
#define WITH_CACHE 1
+#define VHFFSFS_MAXCONNDB 5
+#define VHFFSFS_CONFIG "/etc/vhffsfs.conf"
+#define _GNU_SOURCE
+
#include <fuse.h>
#include <stdio.h>
#include <string.h>
@@ -30,27 +33,16 @@
#include <postgresql/libpq-fe.h>
#include "md5.h"
-#define VHFFSFS_MAXCONNDB 5
-#define VHFFSFS_CONFIG "/etc/vhffsfs.conf"
-
#ifdef WITH_CACHE
-#define VHFFSFS_CACHE_UID_HOMEDIR_TIMEOUT 3600
-#define VHFFSFS_CACHE_UID_GROUP_TIMEOUT 3600
+#define VHFFSFS_CACHE_QUERY_TIMEOUT 600
+#define VHFFSFS_CACHE_QUERY_FLUSH_EVERY 1800
typedef struct {
- gid_t gid;
- char *groupname;
- char *groupdir;
+ char *query;
+ PGresult *result;
time_t arrival;
-} vhffsfs_cache_uid_group;
-
-typedef struct {
- uid_t uid;
- pthread_mutex_t uid_lock;
- char *homedir;
- time_t homedir_arrival;
- GHashTable *groups;
-} vhffsfs_cache_uid;
+ int ref;
+} vhffsfs_cache_query;
#endif
struct vhffsfs {
@@ -69,7 +61,10 @@
mode_t minimumrightfile;
mode_t minimumrightdir;
#ifdef WITH_CACHE
- GHashTable *cache;
+ GHashTable *cachequeries;
+ GPtrArray* cachekeys;
+ pthread_mutex_t cachelock;
+ int cachethreadstarted;
#endif
};
@@ -89,50 +84,157 @@
return 0;
}
-// return context cache entry
-vhffsfs_cache_uid *vhffsfs_cache_uid_context() {
- uid_t uid = fuse_get_context()->uid;
- vhffsfs_cache_uid *vc = g_hash_table_lookup(vhffsfs.cache, &uid);
- if(!vc) {
- vc = malloc(sizeof(vhffsfs_cache_uid));
- memset(vc, 0, sizeof(vhffsfs_cache_uid));
- vc->uid = uid;
- vc->groups = g_hash_table_new(g_str_hash, g_str_equal);
- pthread_mutex_init(&vc->uid_lock, NULL);
- g_hash_table_insert(vhffsfs.cache, &vc->uid, vc);
+static inline void vhffsfs_cache_lock() {
+ pthread_mutex_lock(&vhffsfs.cachelock);
+}
+
+static inline void vhffsfs_cache_unlock() {
+ pthread_mutex_unlock(&vhffsfs.cachelock);
+}
+
+void vhffsfs_cache_add(char *query, PGresult *result) {
+ vhffsfs_cache_query *vcq;
+ vhffsfs_cache_lock();
+ vcq = g_hash_table_lookup(vhffsfs.cachequeries, query);
+ if(vcq) {
+ vhffsfs_cache_unlock();
+ return;
}
- return vc;
+ //printf("CACHE: ADDING: '%s'\n", query);
+ vcq = malloc(sizeof(vhffsfs_cache_query));
+ vcq->query = strdup(query);
+ vcq->result = result;
+ vcq->arrival = vhffsfs_cache_arrival();
+ vcq->ref = 1;
+ g_hash_table_insert(vhffsfs.cachequeries, vcq->query, vcq);
+ g_ptr_array_add(vhffsfs.cachekeys, vcq->query);
+ vhffsfs_cache_unlock();
}
-vhffsfs_cache_uid_group *vhffsfs_cache_uid_lookup_group(vhffsfs_cache_uid *vc, char *groupname) {
- vhffsfs_cache_uid_group *vcg = g_hash_table_lookup(vc->groups, groupname);
- if(vcg && vhffsfs_cache_timeout(vcg->arrival, VHFFSFS_CACHE_UID_GROUP_TIMEOUT)) {
- g_hash_table_remove(vc->groups, vcg->groupname);
- free(vcg->groupname);
- if(vcg->groupdir) free(vcg->groupdir);
- free(vcg);
- return NULL;
+void vhffsfs_cache_del(char *query) {
+ vhffsfs_cache_query *vcq;
+ vhffsfs_cache_lock();
+ vcq = g_hash_table_lookup(vhffsfs.cachequeries, query);
+ // non existing or still referenced
+ if(!vcq || vcq->ref > 0) {
+ vhffsfs_cache_unlock();
+ return;
}
- return vcg;
+ //printf("CACHE: DELETING: '%s'\n", query);
+ //g_ptr_array_remove_fast(vhffsfs.cachekeys, vcq->query);
+ g_ptr_array_remove_fast(vhffsfs.cachekeys, vcq->query);
+ g_hash_table_remove(vhffsfs.cachequeries, vcq->query);
+ free(vcq->query);
+ PQclear(vcq->result);
+ free(vcq);
+ vhffsfs_cache_unlock();
}
-vhffsfs_cache_uid_group *vhffsfs_cache_uid_fetch_group(vhffsfs_cache_uid *vc, char *groupname) {
- vhffsfs_cache_uid_group *vcg = vhffsfs_cache_uid_lookup_group(vc, groupname);
- if(vcg) return vcg;
- vcg = malloc(sizeof(vhffsfs_cache_uid_group));
- memset(vcg, 0, sizeof(vhffsfs_cache_uid_group));
- vcg->groupname = strdup(groupname);
- g_hash_table_insert(vc->groups, vcg->groupname, vcg);
- return vcg;
+PGresult *vhffsfs_cache_lookup(char *query) {
+ vhffsfs_cache_lock();
+ vhffsfs_cache_query *vcq = g_hash_table_lookup(vhffsfs.cachequeries, query);
+ if(vcq) {
+ // timeout
+ if(vhffsfs_cache_timeout(vcq->arrival, VHFFSFS_CACHE_QUERY_TIMEOUT)) {
+ //fprintf(stdout, "CACHE: TIMEOUT: '%s'\n", query);
+ vhffsfs_cache_unlock();
+ vhffsfs_cache_del(query);
+ return NULL;
+ }
+ // cache hit
+ //fprintf(stdout, "CACHE: HIT: '%s'\n", query);
+ vcq->ref++;
+ vhffsfs_cache_unlock();
+ return vcq->result;
+ }
+ // cache miss
+ //fprintf(stdout, "CACHE: MISS: '%s'\n", query);
+ vhffsfs_cache_unlock();
+ return NULL;
}
-static inline void vhffsfs_cache_uid_lock(vhffsfs_cache_uid *vc) {
- pthread_mutex_lock(&vc->uid_lock);
+void vhffsfs_cache_unref(char *query) {
+ vhffsfs_cache_lock();
+ vhffsfs_cache_query *vcq = g_hash_table_lookup(vhffsfs.cachequeries, query);
+ if(vcq && vcq->ref > 0) vcq->ref--;
+ else fprintf(stderr, "CACHE: CORRUPT: '%s'\n", query);
+ vhffsfs_cache_unlock();
}
-static inline void vhffsfs_cache_uid_unlock(vhffsfs_cache_uid *vc) {
- pthread_mutex_unlock(&vc->uid_lock);
+
+static void *vhffsfs_cache_flush(void *data_)
+{
+ (void) data_;
+
+ while(1) {
+ GPtrArray *keys;
+ int i;
+
+ sleep(VHFFSFS_CACHE_QUERY_FLUSH_EVERY);
+
+ keys = g_ptr_array_sized_new(4096);
+
+ //printf("FLUSH CACHE\n");
+
+ // copy keys
+ vhffsfs_cache_lock();
+ for(i = 0 ; i < vhffsfs.cachekeys->len ; i++) {
+ g_ptr_array_add(keys, strdup(vhffsfs.cachekeys->pdata[i]));
+ }
+ vhffsfs_cache_unlock();
+
+ // sleep a bit to not lock the cache too much
+ sleep(1);
+
+ for(i = 0 ; i < keys->len ; i++) {
+ char *query = keys->pdata[i];
+ vhffsfs_cache_query *vcq;
+
+ vhffsfs_cache_lock();
+ vcq = g_hash_table_lookup(vhffsfs.cachequeries, query);
+ if(vcq && vhffsfs_cache_timeout(vcq->arrival, VHFFSFS_CACHE_QUERY_TIMEOUT)) {
+ //fprintf(stdout, "CACHE: TIMEOUT: '%s'\n", query);
+ vhffsfs_cache_unlock();
+ vhffsfs_cache_del(query);
+ }
+ else vhffsfs_cache_unlock();
+
+ free(query);
+ //sleep a bit to not lock the cache too much
+ usleep(100000);
+ }
+
+ g_ptr_array_free(keys, TRUE);
+ }
+ return NULL;
}
+
+
+static int vhffsfs_start_cache_flush_thread(void)
+{
+ int err;
+ pthread_t thread_id;
+ sigset_t oldset;
+ sigset_t newset;
+
+ if(vhffsfs.cachethreadstarted) return 0;
+
+ sigemptyset(&newset);
+ sigaddset(&newset, SIGTERM);
+ sigaddset(&newset, SIGINT);
+ sigaddset(&newset, SIGHUP);
+ sigaddset(&newset, SIGQUIT);
+ pthread_sigmask(SIG_BLOCK, &newset, &oldset);
+ err = pthread_create(&thread_id, NULL, vhffsfs_cache_flush, NULL);
+ if(err) {
+ fprintf(stderr, "Failed to create thread: %s\n", strerror(err));
+ return -EIO;
+ }
+ pthread_detach(thread_id);
+ pthread_sigmask(SIG_SETMASK, &oldset, NULL);
+ vhffsfs.cachethreadstarted = 1;
+ return 0;
+}
#endif
@@ -141,6 +243,12 @@
int i;
PGresult *res;
+#ifdef WITH_CACHE
+ // try to fetch query from cache
+ res = vhffsfs_cache_lookup(query);
+ if(res) return res;
+#endif
+
do {
for(i = 0 ; i < VHFFSFS_MAXCONNDB && pthread_mutex_trylock(&vhffsfs.pg_lock[i]) ; i++);
// all slots used, sleep for 100ms and try again
@@ -154,12 +262,12 @@
vhffsfs.pg_conn[i] = PQconnectdb(vhffsfs.dbconninfo);
if(PQstatus(vhffsfs.pg_conn[i]) != CONNECTION_OK) {
- fprintf(stderr, "SLOT[%d]: Connection to database '%s' failed: %s\n", i, PQdb(vhffsfs.pg_conn[i]), PQerrorMessage(vhffsfs.pg_conn[i]));
+ fprintf(stderr, "SLOT[%d]: CONNECT FAILED '%s': %s\n", i, PQdb(vhffsfs.pg_conn[i]), PQerrorMessage(vhffsfs.pg_conn[i]));
PQfinish(vhffsfs.pg_conn[i]);
sleep(1);
}
else {
- fprintf(stdout, "SLOT[%d]: Connected to database '%s'\n", i, PQdb(vhffsfs.pg_conn[i]));
+ fprintf(stdout, "SLOT[%d]: CONNECT '%s'\n", i, PQdb(vhffsfs.pg_conn[i]));
}
}
@@ -171,49 +279,39 @@
res=NULL;
}
else {
- fprintf(stdout, "SLOT[%d]: QUERY: '%s'\n", i, query);
+ //fprintf(stdout, "SLOT[%d]: QUERY: '%s'\n", i, query);
+#ifdef WITH_CACHE
+ // fill cache
+ vhffsfs_cache_add(query, res);
+#endif
}
pthread_mutex_unlock(&vhffsfs.pg_lock[i]);
return res;
}
+static inline void vhffsfs_PGClear(char *query, PGresult *result) {
+#ifdef WITH_CACHE
+ vhffsfs_cache_unref(query);
+#endif
+#ifndef WITH_CACHE
+ PQclear(result);
+#endif
+}
char *vhffsfs_gethomedir() {
char query[128];
PGresult *res;
char *homedir=NULL;
-#ifdef WITH_CACHE
- // try to fetch homedir from cache
- vhffsfs_cache_uid *vc = vhffsfs_cache_uid_context();
- vhffsfs_cache_uid_lock(vc);
- if(vc->homedir && !vhffsfs_cache_timeout(vc->homedir_arrival, VHFFSFS_CACHE_UID_HOMEDIR_TIMEOUT)) {
- char *t = strdup(vc->homedir);
- vhffsfs_cache_uid_unlock(vc);
- return t;
- }
- vhffsfs_cache_uid_unlock(vc);
-#endif
-
snprintf(query, 128, "SELECT homedir FROM vhffs_users WHERE uid = %d", fuse_get_context()->uid);
res=vhffsfs_PGQuery(query);
if(!res) return NULL;
- if(PQnfields(res) == 1 && PQntuples(res) == 1) {
+ if(PQnfields(res) == 1 && PQntuples(res) == 1)
homedir = strdup(PQgetvalue(res, 0, 0));
-#ifdef WITH_CACHE
- // store homedir to cache
- vhffsfs_cache_uid_lock(vc);
- if(vc->homedir) free(vc->homedir);
- vc->homedir = strdup(homedir);
- vc->homedir_arrival = vhffsfs_cache_arrival();
- vhffsfs_cache_uid_unlock(vc);
-#endif
- }
-
- PQclear(res);
+ vhffsfs_PGClear(query, res);
return homedir;
}
@@ -225,58 +323,24 @@
char *groupname=NULL;
char *groupdir=NULL;
char *cur;
- gid_t gid=0;
// check if group match ^[a-z0-9]+$ to prevent SQL injections
for(cur = group ; *cur ; cur++)
if(! ( (*cur >= 'a' && *cur <= 'z') || (*cur >= '0' && *cur <= '9') ) ) return NULL;
-#ifdef WITH_CACHE
- // try to fetch groupdir from cache
- vhffsfs_cache_uid *vc;
- vhffsfs_cache_uid_group *vcg;
-
- vc = vhffsfs_cache_uid_context();
- vhffsfs_cache_uid_lock(vc);
- vcg = vhffsfs_cache_uid_lookup_group(vc, group);
- if(vcg) {
- char *t=NULL;
- if(vcg->groupdir) t = strdup(vcg->groupdir);
- vhffsfs_cache_uid_unlock(vc);
- return t;
- }
- vhffsfs_cache_uid_unlock(vc);
-#endif
-
- snprintf(query, 256, "SELECT g.gid,g.groupname FROM vhffs_users u, vhffs_groups g, vhffs_user_group ug WHERE u.uid = %d AND g.groupname = '%s' AND u.uid = ug.uid AND g.gid = ug.gid", fuse_get_context()->uid, group);
+ snprintf(query, 256, "SELECT g.groupname FROM vhffs_users u, vhffs_groups g, vhffs_user_group ug WHERE u.uid = %d AND g.groupname = '%s' AND u.uid = ug.uid AND g.gid = ug.gid", fuse_get_context()->uid, group);
res=vhffsfs_PGQuery(query);
if(!res) return NULL;
- if(PQnfields(res) == 2 && PQntuples(res) == 1) {
- gid = atoi(PQgetvalue(res, 0, 0));
- groupname = PQgetvalue(res, 0, 1);
- }
+ if(PQnfields(res) == 1 && PQntuples(res) == 1)
+ groupname = PQgetvalue(res, 0, 0);
if(groupname) {
groupdir = malloc(strlen(vhffsfs.grouppath)+strlen(groupname)+6);
sprintf(groupdir, "%s/%c/%c/%s", vhffsfs.grouppath, groupname[0], groupname[1], groupname);
}
-#ifdef WITH_CACHE
- // store groupdir to cache
- vhffsfs_cache_uid_lock(vc);
- vcg = vhffsfs_cache_uid_fetch_group(vc, group);
- vcg->gid = gid;
- if(vcg->groupdir) {
- free(vcg->groupdir);
- vcg->groupdir = NULL;
- }
- if(groupdir) vcg->groupdir = strdup(groupdir);
- vcg->arrival = vhffsfs_cache_arrival();
- vhffsfs_cache_uid_unlock(vc);
-#endif
-
- PQclear(res);
+ vhffsfs_PGClear(query, res);
return groupdir;
}
@@ -288,22 +352,6 @@
gid_t gid=0;
char *cur;
-#ifdef WITH_CACHE
- // try to fetch grouppid from cache
- vhffsfs_cache_uid *vc;
- vhffsfs_cache_uid_group *vcg;
-
- vc = vhffsfs_cache_uid_context();
- vhffsfs_cache_uid_lock(vc);
- vcg = vhffsfs_cache_uid_lookup_group(vc, group);
- if(vcg && vcg->gid) {
- gid = vcg->gid;
- vhffsfs_cache_uid_unlock(vc);
- return vcg->gid;
- }
- vhffsfs_cache_uid_unlock(vc);
-#endif
-
// check if group match ^[a-z0-9]+$ to prevent SQL injections
for(cur = group ; *cur ; cur++)
if(! ( (*cur >= 'a' && *cur <= 'z') || (*cur >= '0' && *cur <= '9') ) ) return 0;
@@ -315,7 +363,7 @@
if(PQnfields(res) == 1 && PQntuples(res) == 1)
gid = atoi(PQgetvalue(res, 0, 0));
- PQclear(res);
+ vhffsfs_PGClear(query, res);
return gid;
}
@@ -354,7 +402,7 @@
sprintf(webdir, "%s/%02x/%02x/%02x/%s", vhffsfs.webspath, digest[0], digest[1], digest[2], servername);
}
- PQclear(res);
+ vhffsfs_PGClear(query, res);
return webdir;
}
@@ -387,7 +435,7 @@
sprintf(repodir, "%s/%s", vhffsfs.repositoriespath, reponame);
}
- PQclear(res);
+ vhffsfs_PGClear(query, res);
return repodir;
}
@@ -418,27 +466,27 @@
}
}
- PQclear(res);
+ vhffsfs_PGClear(query, res);
return groups;
}
char **vhffsfs_getgroupservices(gid_t gid) {
- char query[256];
+ char query1[256], query2[256];
PGresult *res1,*res2;
char **services=NULL;
// fetch websites
- snprintf(query, 256, "SELECT servername FROM vhffs_httpd WHERE owner_gid = %d", gid);
- res1=vhffsfs_PGQuery(query);
+ snprintf(query1, 256, "SELECT servername FROM vhffs_httpd WHERE owner_gid = %d", gid);
+ res1=vhffsfs_PGQuery(query1);
if(!res1) return NULL;
// fetch repositories
- snprintf(query, 256, "SELECT name FROM vhffs_repository WHERE owner_gid = %d", gid);
- res2=vhffsfs_PGQuery(query);
+ snprintf(query2, 256, "SELECT name FROM vhffs_repository WHERE owner_gid = %d", gid);
+ res2=vhffsfs_PGQuery(query2);
if(!res2) {
- PQclear(res1);
+ vhffsfs_PGClear(query1, res1);
return NULL;
}
@@ -491,8 +539,8 @@
}
}
- PQclear(res1);
- PQclear(res2);
+ vhffsfs_PGClear(query1, res1);
+ vhffsfs_PGClear(query2, res2);
return services;
}
@@ -504,9 +552,9 @@
char *homedir;
char *rpath=NULL;
- printf("======= PATH: %s\n", path);
- printf("======= UID: %d\n", fuse_get_context()->uid);
- printf("======= GID: %d\n", fuse_get_context()->gid);
+ //printf("======= PATH: %s\n", path);
+ //printf("======= UID: %d\n", fuse_get_context()->uid);
+ //printf("======= GID: %d\n", fuse_get_context()->gid);
// path empty
if(*(path+0) == '\0') return NULL;
@@ -612,7 +660,7 @@
}
free(homedir);
- printf("======= RETURN: %s\n\n", rpath);
+ //printf("======= RETURN: %s\n\n", rpath);
return rpath;
}
@@ -640,6 +688,10 @@
static void *vhffsfs_init(void)
{
+#ifdef WITH_CACHE
+ // create cache flush thread
+ vhffsfs_start_cache_flush_thread();
+#endif
return NULL;
}
@@ -1296,7 +1348,10 @@
vhffsfs.minimumrightfile = 00400;
vhffsfs.minimumrightdir = 02700;
#ifdef WITH_CACHE
- vhffsfs.cache = g_hash_table_new(g_int_hash, g_int_equal);
+ vhffsfs.cachequeries = g_hash_table_new(g_str_hash, g_str_equal);
+ vhffsfs.cachekeys = g_ptr_array_sized_new(4096);
+ pthread_mutex_init(&vhffsfs.cachelock, NULL);
+ vhffsfs.cachethreadstarted = 0;
#endif
vhffsfs_readconfig(VHFFSFS_CONFIG);
Modified: trunk/vhffs-tools/src/vhffsfs_compil.sh
===================================================================
--- trunk/vhffs-tools/src/vhffsfs_compil.sh 2007-07-05 11:35:33 UTC (rev 664)
+++ trunk/vhffs-tools/src/vhffsfs_compil.sh 2007-07-05 15:32:23 UTC (rev 665)
@@ -1,2 +1 @@
-gcc -I/usr/include/fuse `pkg-config --cflags glib-2.0` -D_FILE_OFFSET_BITS=64 -D_REENTRANT -DFUSE_USE_VERSION=25 -Wall -ggdb -lfuse -lpthread -lpq `pkg-config --libs glib-2.0` vhffsfs.c md5c.c -o vhffsfs
-
+gcc -I/usr/include/fuse `pkg-config --cflags glib-2.0` -D_FILE_OFFSET_BITS=64 -D_REENTRANT -DFUSE_USE_VERSION=25 -Wall -O2 -lfuse -lpthread -lpq `pkg-config --libs glib-2.0` vhffsfs.c md5c.c -o vhffsfs
Modified: trunk/vhffs-tools/src/vhffsfs_run.sh
===================================================================
--- trunk/vhffs-tools/src/vhffsfs_run.sh 2007-07-05 11:35:33 UTC (rev 664)
+++ trunk/vhffs-tools/src/vhffsfs_run.sh 2007-07-05 15:32:23 UTC (rev 665)
@@ -1,2 +1 @@
-./vhffsfs -d -o allow_other,default_permissions,kernel_cache /mnt/fuse/
-
+./vhffsfs -o allow_other,default_permissions,kernel_cache /mnt/fuse/