aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--lib/fuse.c196
2 files changed, 158 insertions, 43 deletions
diff --git a/ChangeLog b/ChangeLog
index 2cf7052..1a9e602 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2010-12-13 Miklos Szeredi <miklos@szeredi.hu>
+
+ * Highlevel lib: use dynamically resized hash table for looking up
+ by name and node ID.
+
2010-11-10 Miklos Szeredi <miklos@szeredi.hu>
* Add new write_buf() method to the highlevel API. Similarly to
diff --git a/lib/fuse.c b/lib/fuse.c
index 4d24aea..5b0a9ac 100644
--- a/lib/fuse.c
+++ b/lib/fuse.c
@@ -84,12 +84,17 @@ struct lock_queue_element {
pthread_cond_t cond;
};
+struct node_table {
+ struct node **array;
+ size_t use;
+ size_t size;
+ size_t split;
+};
+
struct fuse {
struct fuse_session *se;
- struct node **name_table;
- size_t name_table_size;
- struct node **id_table;
- size_t id_table_size;
+ struct node_table name_table;
+ struct node_table id_table;
fuse_ino_t ctr;
unsigned int generation;
unsigned int hidectr;
@@ -259,12 +264,23 @@ static void fuse_put_module(struct fuse_module *m)
pthread_mutex_unlock(&fuse_context_lock);
}
+static size_t id_hash(struct fuse *f, fuse_ino_t ino)
+{
+ uint64_t hash = ((uint32_t) ino * 2654435761) % f->id_table.size;
+ uint64_t oldhash = hash % (f->id_table.size / 2);
+
+ if (oldhash >= f->id_table.split)
+ return oldhash;
+ else
+ return hash;
+}
+
static struct node *get_node_nocheck(struct fuse *f, fuse_ino_t nodeid)
{
- size_t hash = nodeid % f->id_table_size;
+ size_t hash = id_hash(f, nodeid);
struct node *node;
- for (node = f->id_table[hash]; node != NULL; node = node->id_next)
+ for (node = f->id_table.array[hash]; node != NULL; node = node->id_next)
if (node->nodeid == nodeid)
return node;
@@ -290,33 +306,88 @@ static void free_node(struct node *node)
static void unhash_id(struct fuse *f, struct node *node)
{
- size_t hash = node->nodeid % f->id_table_size;
- struct node **nodep = &f->id_table[hash];
+ struct node **nodep = &f->id_table.array[id_hash(f, node->nodeid)];
for (; *nodep != NULL; nodep = &(*nodep)->id_next)
if (*nodep == node) {
*nodep = node->id_next;
+ f->id_table.use--;
return;
}
}
+static int node_table_resize(struct node_table *t)
+{
+ size_t newsize = t->size * 2;
+ void *newarray;
+
+ newarray = realloc(t->array, sizeof(struct node *) * newsize);
+ if (newarray == NULL)
+ return -1;
+
+ t->array = newarray;
+ memset(t->array + t->size, 0, t->size * sizeof(struct node *));
+ t->size = newsize;
+ t->split = 0;
+
+ return 0;
+}
+
+static void rehash_id(struct fuse *f)
+{
+ struct node_table *t = &f->id_table;
+ struct node **nodep;
+ struct node **next;
+ size_t hash;
+
+ if (t->split == t->size / 2)
+ return;
+
+ hash = t->split;
+ t->split++;
+ for (nodep = &t->array[hash]; *nodep != NULL; nodep = next) {
+ struct node *node = *nodep;
+ size_t newhash = id_hash(f, node->nodeid);
+
+ if (newhash != hash) {
+ next = nodep;
+ *nodep = node->id_next;
+ node->id_next = t->array[newhash];
+ t->array[newhash] = node;
+ } else {
+ next = &node->id_next;
+ }
+ }
+ if (t->split == t->size / 2)
+ node_table_resize(t);
+}
+
static void hash_id(struct fuse *f, struct node *node)
{
- size_t hash = node->nodeid % f->id_table_size;
- node->id_next = f->id_table[hash];
- f->id_table[hash] = node;
+ size_t hash = id_hash(f, node->nodeid);
+ node->id_next = f->id_table.array[hash];
+ f->id_table.array[hash] = node;
+ f->id_table.use++;
+
+ if (f->id_table.use >= f->id_table.size / 2)
+ rehash_id(f);
}
-static unsigned int name_hash(struct fuse *f, fuse_ino_t parent,
- const char *name)
+static size_t name_hash(struct fuse *f, fuse_ino_t parent,
+ const char *name)
{
- unsigned int hash = *name;
+ uint64_t hash = parent;
+ uint64_t oldhash;
- if (hash)
- for (name += 1; *name != '\0'; name++)
- hash = (hash << 5) - hash + *name;
+ for (; *name; name++)
+ hash = hash * 31 + (unsigned char) *name;
- return (hash + parent) % f->name_table_size;
+ hash %= f->name_table.size;
+ oldhash = hash % (f->name_table.size / 2);
+ if (oldhash >= f->name_table.split)
+ return oldhash;
+ else
+ return hash;
}
static void unref_node(struct fuse *f, struct node *node);
@@ -325,7 +396,7 @@ static void unhash_name(struct fuse *f, struct node *node)
{
if (node->name) {
size_t hash = name_hash(f, node->parent->nodeid, node->name);
- struct node **nodep = &f->name_table[hash];
+ struct node **nodep = &f->name_table.array[hash];
for (; *nodep != NULL; nodep = &(*nodep)->name_next)
if (*nodep == node) {
@@ -335,6 +406,7 @@ static void unhash_name(struct fuse *f, struct node *node)
free(node->name);
node->name = NULL;
node->parent = NULL;
+ f->name_table.use--;
return;
}
fprintf(stderr,
@@ -344,6 +416,35 @@ static void unhash_name(struct fuse *f, struct node *node)
}
}
+static void rehash_name(struct fuse *f)
+{
+ struct node_table *t = &f->name_table;
+ struct node **nodep;
+ struct node **next;
+ size_t hash;
+
+ if (t->split == t->size / 2)
+ return;
+
+ hash = t->split;
+ t->split++;
+ for (nodep = &t->array[hash]; *nodep != NULL; nodep = next) {
+ struct node *node = *nodep;
+ size_t newhash = name_hash(f, node->parent->nodeid, node->name);
+
+ if (newhash != hash) {
+ next = nodep;
+ *nodep = node->name_next;
+ node->name_next = t->array[newhash];
+ t->array[newhash] = node;
+ } else {
+ next = &node->name_next;
+ }
+ }
+ if (t->split == t->size / 2)
+ node_table_resize(t);
+}
+
static int hash_name(struct fuse *f, struct node *node, fuse_ino_t parentid,
const char *name)
{
@@ -355,8 +456,13 @@ static int hash_name(struct fuse *f, struct node *node, fuse_ino_t parentid,
parent->refctr ++;
node->parent = parent;
- node->name_next = f->name_table[hash];
- f->name_table[hash] = node;
+ node->name_next = f->name_table.array[hash];
+ f->name_table.array[hash] = node;
+ f->name_table.use++;
+
+ if (f->name_table.use >= f->name_table.size / 2)
+ rehash_name(f);
+
return 0;
}
@@ -397,7 +503,7 @@ static struct node *lookup_node(struct fuse *f, fuse_ino_t parent,
size_t hash = name_hash(f, parent, name);
struct node *node;
- for (node = f->name_table[hash]; node != NULL; node = node->name_next)
+ for (node = f->name_table.array[hash]; node != NULL; node = node->name_next)
if (node->parent->nodeid == parent &&
strcmp(node->name, name) == 0)
return node;
@@ -3802,6 +3908,20 @@ struct fuse_fs *fuse_fs_new(const struct fuse_operations *op, size_t op_size,
return fs;
}
+static int node_table_init(struct node_table *t)
+{
+ t->size = 8192;
+ t->array = (struct node **) calloc(1, sizeof(struct node *) * t->size);
+ if (t->array == NULL) {
+ fprintf(stderr, "fuse: memory allocation failed\n");
+ return -1;
+ }
+ t->use = 0;
+ t->split = 0;
+
+ return 0;
+}
+
struct fuse *fuse_new_common(struct fuse_chan *ch, struct fuse_args *args,
const struct fuse_operations *op,
size_t op_size, void *user_data, int compat)
@@ -3893,22 +4013,11 @@ struct fuse *fuse_new_common(struct fuse_chan *ch, struct fuse_args *args,
f->fs->debug = f->conf.debug;
f->ctr = 0;
f->generation = 0;
- /* FIXME: Dynamic hash table */
- f->name_table_size = 14057;
- f->name_table = (struct node **)
- calloc(1, sizeof(struct node *) * f->name_table_size);
- if (f->name_table == NULL) {
- fprintf(stderr, "fuse: memory allocation failed\n");
+ if (node_table_init(&f->name_table) == -1)
goto out_free_session;
- }
- f->id_table_size = 14057;
- f->id_table = (struct node **)
- calloc(1, sizeof(struct node *) * f->id_table_size);
- if (f->id_table == NULL) {
- fprintf(stderr, "fuse: memory allocation failed\n");
+ if (node_table_init(&f->id_table) == -1)
goto out_free_name_table;
- }
fuse_mutex_init(&f->lock);
@@ -3943,9 +4052,9 @@ out_free_root_name:
out_free_root:
free(root);
out_free_id_table:
- free(f->id_table);
+ free(f->id_table.array);
out_free_name_table:
- free(f->name_table);
+ free(f->name_table.array);
out_free_session:
fuse_session_destroy(f->se);
out_free_fs:
@@ -3982,10 +4091,10 @@ void fuse_destroy(struct fuse *f)
memset(c, 0, sizeof(*c));
c->ctx.fuse = f;
- for (i = 0; i < f->id_table_size; i++) {
+ for (i = 0; i < f->id_table.size; i++) {
struct node *node;
- for (node = f->id_table[i]; node != NULL;
+ for (node = f->id_table.array[i]; node != NULL;
node = node->id_next) {
if (node->is_hidden) {
char *path;
@@ -3997,17 +4106,18 @@ void fuse_destroy(struct fuse *f)
}
}
}
- for (i = 0; i < f->id_table_size; i++) {
+ for (i = 0; i < f->id_table.size; i++) {
struct node *node;
struct node *next;
- for (node = f->id_table[i]; node != NULL; node = next) {
+ for (node = f->id_table.array[i]; node != NULL; node = next) {
next = node->id_next;
free_node(node);
}
}
- free(f->id_table);
- free(f->name_table);
+
+ free(f->id_table.array);
+ free(f->name_table.array);
pthread_mutex_destroy(&f->lock);
fuse_session_destroy(f->se);
free(f->conf.modules);