[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/


Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/