#include "wimlib/list.h"
#include "wimlib/types.h"
+#include "wimlib/util.h"
struct wim_dentry;
* cases the inodes are linked by i_hlist_node. */
struct wim_inode_table {
struct hlist_head *array;
+ size_t filled;
size_t capacity;
struct hlist_head extra_inodes;
};
+/* Compute the index of the hash bucket to use for the given inode number and
+ * device number. */
+static inline size_t
+hash_inode(const struct wim_inode_table *table, u64 ino, u64 devno)
+{
+ return (hash_u64(ino) + devno) & (table->capacity - 1);
+}
+
extern int
init_inode_table(struct wim_inode_table *table, size_t capacity);
u64 ino, u64 devno, bool noshare,
struct wim_dentry **dentry_ret);
+extern void
+enlarge_inode_table(struct wim_inode_table *table);
+
extern void
inode_table_prepare_inode_list(struct wim_inode_table *table,
struct hlist_head *head);
size_t mask; /* capacity - 1; capacity is a power of 2 */
};
-static size_t
-next_power_of_2(size_t n)
-{
- if (n <= 1)
- return 1;
- return (size_t)1 << (1 + flsw(n - 1));
-}
-
struct blob_table *
new_blob_table(size_t capacity)
{
struct blob_table *table;
struct hlist_head *array;
- capacity = next_power_of_2(capacity);
+ capacity = roundup_pow_of_2(capacity);
table = MALLOC(sizeof(struct blob_table));
if (table == NULL)
}
/* Try adding this dentry to an existing inode. */
- pos = d_inode->i_ino % table->capacity;
+ pos = hash_inode(table, d_inode->i_ino, 0);
hlist_for_each_entry(inode, &table->array[pos], i_hlist_node) {
if (inode->i_ino != d_inode->i_ino) {
continue;
/* Keep this dentry's inode. */
hlist_add_head(&d_inode->i_hlist_node, &table->array[pos]);
+ if (++table->filled > table->capacity)
+ enlarge_inode_table(table);
return 0;
}
/* We use a hash table to map inode numbers to inodes. */
- ret = init_inode_table(¶ms.inode_table, 9001);
+ ret = init_inode_table(¶ms.inode_table, 64);
if (ret)
return ret;
*/
/*
- * Copyright (C) 2012, 2013, 2014 Eric Biggers
+ * Copyright (C) 2012-2016 Eric Biggers
*
* This file is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
# include "config.h"
#endif
+#include "wimlib/bitops.h"
#include "wimlib/dentry.h"
#include "wimlib/error.h"
#include "wimlib/inode.h"
int
init_inode_table(struct wim_inode_table *table, size_t capacity)
{
+ capacity = roundup_pow_of_2(capacity);
table->array = CALLOC(capacity, sizeof(table->array[0]));
if (!table->array)
return WIMLIB_ERR_NOMEM;
+ table->filled = 0;
table->capacity = capacity;
INIT_HLIST_HEAD(&table->extra_inodes);
return 0;
FREE(table->array);
}
+/* Double the capacity of the inode hash table. */
+void
+enlarge_inode_table(struct wim_inode_table *table)
+{
+ const size_t old_capacity = table->capacity;
+ const size_t new_capacity = old_capacity * 2;
+ struct hlist_head *old_array = table->array;
+ struct hlist_head *new_array;
+ struct wim_inode *inode;
+ struct hlist_node *tmp;
+
+ new_array = CALLOC(new_capacity, sizeof(struct hlist_head));
+ if (!new_array)
+ return;
+ table->array = new_array;
+ table->capacity = new_capacity;
+ for (size_t i = 0; i < old_capacity; i++) {
+ hlist_for_each_entry_safe(inode, tmp, &old_array[i], i_hlist_node) {
+ hlist_add_head(&inode->i_hlist_node,
+ &new_array[hash_inode(table, inode->i_ino,
+ inode->i_devno)]);
+ }
+ }
+ FREE(old_array);
+}
+
/*
* Allocate a new dentry, with hard link detection.
*
list = &table->extra_inodes;
} else {
/* Hard link detection */
- list = &table->array[hash_u64(hash_u64(ino) + hash_u64(devno))
- % table->capacity];
+ list = &table->array[hash_inode(table, ino, devno)];
hlist_for_each_entry(inode, list, i_hlist_node) {
if (inode->i_ino != ino || inode->i_devno != devno)
continue;
if (ret)
return ret;
inode = dentry->d_inode;
- hlist_add_head(&inode->i_hlist_node, list);
inode->i_ino = ino;
inode->i_devno = devno;
+ hlist_add_head(&inode->i_hlist_node, list);
+ if (list != &table->extra_inodes)
+ if (++table->filled > table->capacity)
+ enlarge_inode_table(table);
*dentry_ret = dentry;
return 0;
}