aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cache.c80
1 files changed, 67 insertions, 13 deletions
diff --git a/cache.c b/cache.c
index 0ef110d..13f485e 100644
--- a/cache.c
+++ b/cache.c
@@ -17,9 +17,11 @@
#define MAX_CACHE_SIZE 10000
#define CACHE_CLEAN_INTERVAL 60
-struct node_attr {
+struct node {
struct stat stat;
time_t stat_valid;
+ char **dir;
+ time_t dir_valid;
time_t valid;
};
@@ -27,6 +29,7 @@ struct fuse_cache_dirhandle {
const char *path;
fuse_dirh_t h;
fuse_dirfil_t filler;
+ GPtrArray *dir;
};
static struct fuse_cache_operations *next_oper;
@@ -34,9 +37,16 @@ static GHashTable *cache;
static pthread_mutex_t cache_lock;
static time_t last_cleaned;
-static int cache_clean_entry(void *_key, struct node_attr *node, time_t *now)
+static void free_node(gpointer node_)
{
- (void) _key;
+ struct node *node = (struct node *) node_;
+ g_strfreev(node->dir);
+ g_free(node);
+}
+
+static int cache_clean_entry(void *key_, struct node *node, time_t *now)
+{
+ (void) key_;
if (*now > node->valid)
return TRUE;
else
@@ -53,9 +63,9 @@ static void cache_clean(void)
}
}
-static struct node_attr *cache_lookup(const char *path)
+static struct node *cache_lookup(const char *path)
{
- return (struct node_attr *) g_hash_table_lookup(cache, path);
+ return (struct node *) g_hash_table_lookup(cache, path);
}
static void cache_remove(const char *path)
@@ -76,12 +86,12 @@ static void cache_do_rename(const char *from, const char *to)
cache_remove(to);
}
-static struct node_attr *cache_get(const char *path)
+static struct node *cache_get(const char *path)
{
- struct node_attr *node = cache_lookup(path);
+ struct node *node = cache_lookup(path);
if (node == NULL) {
char *pathcopy = g_strdup(path);
- node = g_new0(struct node_attr, 1);
+ node = g_new0(struct node, 1);
g_hash_table_insert(cache, pathcopy, node);
}
return node;
@@ -89,7 +99,7 @@ static struct node_attr *cache_get(const char *path)
static void cache_add_attr(const char *path, const struct stat *stbuf)
{
- struct node_attr *node;
+ struct node *node;
time_t now;
pthread_mutex_lock(&cache_lock);
@@ -103,16 +113,33 @@ static void cache_add_attr(const char *path, const struct stat *stbuf)
pthread_mutex_unlock(&cache_lock);
}
+static void cache_add_dir(const char *path, char **dir)
+{
+ struct node *node;
+ time_t now;
+
+ pthread_mutex_lock(&cache_lock);
+ node = cache_get(path);
+ now = time(NULL);
+ g_strfreev(node->dir);
+ node->dir = dir;
+ node->dir_valid = time(NULL) + CACHE_TIMEOUT;
+ if (node->dir_valid > node->valid)
+ node->valid = node->dir_valid;
+ cache_clean();
+ pthread_mutex_unlock(&cache_lock);
+}
+
static int cache_getattr(const char *path, struct stat *stbuf)
{
- struct node_attr *node;
+ struct node *node;
int err;
pthread_mutex_lock(&cache_lock);
node = cache_lookup(path);
if (node != NULL) {
time_t now = time(NULL);
- if (node->valid - now >= 0) {
+ if (node->stat_valid - now >= 0) {
*stbuf = node->stat;
pthread_mutex_unlock(&cache_lock);
return 0;
@@ -131,6 +158,7 @@ static int cache_dirfill(fuse_cache_dirh_t ch, const char *name,
{
int err = ch->filler(ch->h, name, 0, 0);
if (!err) {
+ g_ptr_array_add(ch->dir, g_strdup(name));
char *fullpath = g_strdup_printf("%s/%s",
!ch->path[1] ? "" : ch->path, name);
cache_add_attr(fullpath, stbuf);
@@ -142,10 +170,36 @@ static int cache_dirfill(fuse_cache_dirh_t ch, const char *name,
static int cache_getdir(const char *path, fuse_dirh_t h, fuse_dirfil_t filler)
{
struct fuse_cache_dirhandle ch;
+ int err;
+ char **dir;
+ struct node *node;
+
+ pthread_mutex_lock(&cache_lock);
+ node = cache_lookup(path);
+ if (node != NULL && node->dir != NULL) {
+ time_t now = time(NULL);
+ if (node->dir_valid - now >= 0) {
+ for(dir = node->dir; *dir != NULL; dir++)
+ filler(h, *dir, 0, 0);
+ pthread_mutex_unlock(&cache_lock);
+ return 0;
+ }
+ }
+ pthread_mutex_unlock(&cache_lock);
+
ch.path = path;
ch.h = h;
ch.filler = filler;
- return next_oper->cache_getdir(path, &ch, cache_dirfill);
+ ch.dir = g_ptr_array_new();
+ err = next_oper->cache_getdir(path, &ch, cache_dirfill);
+ g_ptr_array_add(ch.dir, NULL);
+ dir = (char **) ch.dir->pdata;
+ if (!err)
+ cache_add_dir(path, dir);
+ else
+ g_strfreev(dir);
+ g_ptr_array_free(ch.dir, FALSE);
+ return err;
}
static int cache_unlink(const char *path)
@@ -235,7 +289,7 @@ struct fuse_operations *cache_init(struct fuse_cache_operations *oper)
cache_oper.listxattr = oper->oper.listxattr;
cache_oper.removexattr = oper->oper.removexattr;
pthread_mutex_init(&cache_lock, NULL);
- cache = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
+ cache = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, free_node);
if (cache == NULL) {
fprintf(stderr, "failed to create cache\n");
return NULL;