|
Ian Kent |
b04561 |
autofs-5.0.4 - make hash table scale to thousands of entries
|
|
Ian Kent |
b04561 |
|
|
Ian Kent |
b04561 |
From: Valerie Aurora Henson <vaurora@redhat.com>
|
|
Ian Kent |
b04561 |
|
|
Ian Kent |
b04561 |
Originally written by Paul Wankadia <junyer@google.com>.
|
|
Ian Kent |
b04561 |
|
|
Ian Kent |
b04561 |
The autofs cache lookup performs poorly for large maps.
|
|
Ian Kent |
b04561 |
|
|
Ian Kent |
b04561 |
The additive hashing algorithm used by autofs results in a clustering
|
|
Ian Kent |
b04561 |
of hash values around the average hash chain size. It is biased toward
|
|
Ian Kent |
b04561 |
a small range of hash indexes which becomes worse as the hash table size
|
|
Ian Kent |
b04561 |
increases.
|
|
Ian Kent |
b04561 |
|
|
Ian Kent |
b04561 |
Simple testing shows that the "One-at-a-time" hash function (implemented
|
|
Ian Kent |
b04561 |
by this patch) gives a much better distribution of hash indexes as table
|
|
Ian Kent |
b04561 |
size increases.
|
|
Ian Kent |
b04561 |
|
|
Ian Kent |
b04561 |
The only change made to the original patch is to make the hash table size
|
|
Ian Kent |
b04561 |
configurable with a default somewhat larger than it is currently.
|
|
Ian Kent |
b04561 |
---
|
|
Ian Kent |
b04561 |
|
|
Ian Kent |
b04561 |
CHANGELOG | 2 ++
|
|
Ian Kent |
b04561 |
include/automount.h | 2 +-
|
|
Ian Kent |
b04561 |
include/defaults.h | 3 +++
|
|
Ian Kent |
b04561 |
lib/cache.c | 47 +++++++++++++++++++++++-----------------
|
|
Ian Kent |
b04561 |
lib/defaults.c | 16 +++++++++++++-
|
|
Ian Kent |
b04561 |
redhat/autofs.sysconfig.in | 6 +++++
|
|
Ian Kent |
b04561 |
samples/autofs.conf.default.in | 6 +++++
|
|
Ian Kent |
b04561 |
7 files changed, 60 insertions(+), 22 deletions(-)
|
|
Ian Kent |
b04561 |
|
|
Ian Kent |
b04561 |
|
|
Ian Kent |
b04561 |
diff --git a/CHANGELOG b/CHANGELOG
|
|
Ian Kent |
b04561 |
index 0fb7db5..912c088 100644
|
|
Ian Kent |
b04561 |
--- a/CHANGELOG
|
|
Ian Kent |
b04561 |
+++ b/CHANGELOG
|
|
Ian Kent |
b04561 |
@@ -5,6 +5,8 @@
|
|
Ian Kent |
b04561 |
- fix negative caching for non-existent map keys.
|
|
Ian Kent |
b04561 |
- use CLOEXEC flag.
|
|
Ian Kent |
b04561 |
- fix select(2) fd limit.
|
|
Ian Kent |
b04561 |
+- make hash table scale to thousands of entries (Paul Wankadia,
|
|
Ian Kent |
b04561 |
+ Valerie Aurora Henson).
|
|
Ian Kent |
b04561 |
|
|
Ian Kent |
b04561 |
4/11/2008 autofs-5.0.4
|
|
Ian Kent |
b04561 |
-----------------------
|
|
Ian Kent |
b04561 |
diff --git a/include/automount.h b/include/automount.h
|
|
Ian Kent |
b04561 |
index a55ddbc..fa24885 100644
|
|
Ian Kent |
b04561 |
--- a/include/automount.h
|
|
Ian Kent |
b04561 |
+++ b/include/automount.h
|
|
Ian Kent |
b04561 |
@@ -128,7 +128,7 @@ struct autofs_point;
|
|
Ian Kent |
b04561 |
#define CHE_DUPLICATE 0x0020
|
|
Ian Kent |
b04561 |
#define CHE_UNAVAIL 0x0040
|
|
Ian Kent |
b04561 |
|
|
Ian Kent |
b04561 |
-#define HASHSIZE 77
|
|
Ian Kent |
b04561 |
+#define NULL_MAP_HASHSIZE 64
|
|
Ian Kent |
b04561 |
#define NEGATIVE_TIMEOUT 10
|
|
Ian Kent |
b04561 |
#define UMOUNT_RETRIES 8
|
|
Ian Kent |
b04561 |
#define EXPIRE_RETRIES 3
|
|
Ian Kent |
b04561 |
diff --git a/include/defaults.h b/include/defaults.h
|
|
Ian Kent |
b04561 |
index 12534ec..9a2430f 100644
|
|
Ian Kent |
b04561 |
--- a/include/defaults.h
|
|
Ian Kent |
b04561 |
+++ b/include/defaults.h
|
|
Ian Kent |
b04561 |
@@ -40,6 +40,8 @@
|
|
Ian Kent |
b04561 |
#define DEFAULT_APPEND_OPTIONS 1
|
|
Ian Kent |
b04561 |
#define DEFAULT_AUTH_CONF_FILE AUTOFS_MAP_DIR "/autofs_ldap_auth.conf"
|
|
Ian Kent |
b04561 |
|
|
Ian Kent |
b04561 |
+#define DEFAULT_MAP_HASH_TABLE_SIZE 1024
|
|
Ian Kent |
b04561 |
+
|
|
Ian Kent |
b04561 |
struct ldap_schema;
|
|
Ian Kent |
b04561 |
struct ldap_searchdn;
|
|
Ian Kent |
b04561 |
|
|
Ian Kent |
b04561 |
@@ -62,6 +64,7 @@ void defaults_free_searchdns(struct ldap_searchdn *);
|
|
Ian Kent |
b04561 |
unsigned int defaults_get_append_options(void);
|
|
Ian Kent |
b04561 |
unsigned int defaults_get_umount_wait(void);
|
|
Ian Kent |
b04561 |
const char *defaults_get_auth_conf_file(void);
|
|
Ian Kent |
b04561 |
+unsigned int defaults_get_map_hash_table_size(void);
|
|
Ian Kent |
b04561 |
|
|
Ian Kent |
b04561 |
#endif
|
|
Ian Kent |
b04561 |
|
|
Ian Kent |
b04561 |
diff --git a/lib/cache.c b/lib/cache.c
|
|
Ian Kent |
b04561 |
index 4a00367..edb3192 100644
|
|
Ian Kent |
b04561 |
--- a/lib/cache.c
|
|
Ian Kent |
b04561 |
+++ b/lib/cache.c
|
|
Ian Kent |
b04561 |
@@ -190,7 +190,7 @@ struct mapent_cache *cache_init(struct autofs_point *ap, struct map_source *map)
|
|
Ian Kent |
b04561 |
if (!mc)
|
|
Ian Kent |
b04561 |
return NULL;
|
|
Ian Kent |
b04561 |
|
|
Ian Kent |
b04561 |
- mc->size = HASHSIZE;
|
|
Ian Kent |
b04561 |
+ mc->size = defaults_get_map_hash_table_size();
|
|
Ian Kent |
b04561 |
|
|
Ian Kent |
b04561 |
mc->hash = malloc(mc->size * sizeof(struct entry *));
|
|
Ian Kent |
b04561 |
if (!mc->hash) {
|
|
Ian Kent |
b04561 |
@@ -241,7 +241,7 @@ struct mapent_cache *cache_init_null_cache(struct master *master)
|
|
Ian Kent |
b04561 |
if (!mc)
|
|
Ian Kent |
b04561 |
return NULL;
|
|
Ian Kent |
b04561 |
|
|
Ian Kent |
b04561 |
- mc->size = HASHSIZE;
|
|
Ian Kent |
b04561 |
+ mc->size = NULL_MAP_HASHSIZE;
|
|
Ian Kent |
b04561 |
|
|
Ian Kent |
b04561 |
mc->hash = malloc(mc->size * sizeof(struct entry *));
|
|
Ian Kent |
b04561 |
if (!mc->hash) {
|
|
Ian Kent |
b04561 |
@@ -279,29 +279,36 @@ struct mapent_cache *cache_init_null_cache(struct master *master)
|
|
Ian Kent |
b04561 |
return mc;
|
|
Ian Kent |
b04561 |
}
|
|
Ian Kent |
b04561 |
|
|
Ian Kent |
b04561 |
-static unsigned int hash(const char *key)
|
|
Ian Kent |
b04561 |
+static u_int32_t hash(const char *key, unsigned int size)
|
|
Ian Kent |
b04561 |
{
|
|
Ian Kent |
b04561 |
- unsigned long hashval;
|
|
Ian Kent |
b04561 |
+ u_int32_t hashval;
|
|
Ian Kent |
b04561 |
char *s = (char *) key;
|
|
Ian Kent |
b04561 |
|
|
Ian Kent |
b04561 |
- for (hashval = 0; *s != '\0';)
|
|
Ian Kent |
b04561 |
- hashval += *s++;
|
|
Ian Kent |
b04561 |
+ for (hashval = 0; *s != '\0';) {
|
|
Ian Kent |
b04561 |
+ hashval += (unsigned char) *s++;
|
|
Ian Kent |
b04561 |
+ hashval += (hashval << 10);
|
|
Ian Kent |
b04561 |
+ hashval ^= (hashval >> 6);
|
|
Ian Kent |
b04561 |
+ }
|
|
Ian Kent |
b04561 |
+
|
|
Ian Kent |
b04561 |
+ hashval += (hashval << 3);
|
|
Ian Kent |
b04561 |
+ hashval ^= (hashval >> 11);
|
|
Ian Kent |
b04561 |
+ hashval += (hashval << 15);
|
|
Ian Kent |
b04561 |
|
|
Ian Kent |
b04561 |
- return hashval % HASHSIZE;
|
|
Ian Kent |
b04561 |
+ return hashval % size;
|
|
Ian Kent |
b04561 |
}
|
|
Ian Kent |
b04561 |
|
|
Ian Kent |
b04561 |
-static unsigned int ino_hash(dev_t dev, ino_t ino)
|
|
Ian Kent |
b04561 |
+static u_int32_t ino_hash(dev_t dev, ino_t ino, unsigned int size)
|
|
Ian Kent |
b04561 |
{
|
|
Ian Kent |
b04561 |
- unsigned long hashval;
|
|
Ian Kent |
b04561 |
+ u_int32_t hashval;
|
|
Ian Kent |
b04561 |
|
|
Ian Kent |
b04561 |
hashval = dev + ino;
|
|
Ian Kent |
b04561 |
|
|
Ian Kent |
b04561 |
- return hashval % HASHSIZE;
|
|
Ian Kent |
b04561 |
+ return hashval % size;
|
|
Ian Kent |
b04561 |
}
|
|
Ian Kent |
b04561 |
|
|
Ian Kent |
b04561 |
int cache_set_ino_index(struct mapent_cache *mc, const char *key, dev_t dev, ino_t ino)
|
|
Ian Kent |
b04561 |
{
|
|
Ian Kent |
b04561 |
- unsigned int ino_index = ino_hash(dev, ino);
|
|
Ian Kent |
b04561 |
+ u_int32_t ino_index = ino_hash(dev, ino, mc->size);
|
|
Ian Kent |
b04561 |
struct mapent *me;
|
|
Ian Kent |
b04561 |
|
|
Ian Kent |
b04561 |
me = cache_lookup_distinct(mc, key);
|
|
Ian Kent |
b04561 |
@@ -323,10 +330,10 @@ struct mapent *cache_lookup_ino(struct mapent_cache *mc, dev_t dev, ino_t ino)
|
|
Ian Kent |
b04561 |
{
|
|
Ian Kent |
b04561 |
struct mapent *me = NULL;
|
|
Ian Kent |
b04561 |
struct list_head *head, *p;
|
|
Ian Kent |
b04561 |
- unsigned int ino_index;
|
|
Ian Kent |
b04561 |
+ u_int32_t ino_index;
|
|
Ian Kent |
b04561 |
|
|
Ian Kent |
b04561 |
ino_index_lock(mc);
|
|
Ian Kent |
b04561 |
- ino_index = ino_hash(dev, ino);
|
|
Ian Kent |
b04561 |
+ ino_index = ino_hash(dev, ino, mc->size);
|
|
Ian Kent |
b04561 |
head = &mc->ino_index[ino_index];
|
|
Ian Kent |
b04561 |
|
|
Ian Kent |
b04561 |
list_for_each(p, head) {
|
|
Ian Kent |
b04561 |
@@ -369,7 +376,7 @@ struct mapent *cache_lookup_first(struct mapent_cache *mc)
|
|
Ian Kent |
b04561 |
struct mapent *cache_lookup_next(struct mapent_cache *mc, struct mapent *me)
|
|
Ian Kent |
b04561 |
{
|
|
Ian Kent |
b04561 |
struct mapent *this;
|
|
Ian Kent |
b04561 |
- unsigned long hashval;
|
|
Ian Kent |
b04561 |
+ u_int32_t hashval;
|
|
Ian Kent |
b04561 |
unsigned int i;
|
|
Ian Kent |
b04561 |
|
|
Ian Kent |
b04561 |
if (!me)
|
|
Ian Kent |
b04561 |
@@ -385,7 +392,7 @@ struct mapent *cache_lookup_next(struct mapent_cache *mc, struct mapent *me)
|
|
Ian Kent |
b04561 |
return this;
|
|
Ian Kent |
b04561 |
}
|
|
Ian Kent |
b04561 |
|
|
Ian Kent |
b04561 |
- hashval = hash(me->key) + 1;
|
|
Ian Kent |
b04561 |
+ hashval = hash(me->key, mc->size) + 1;
|
|
Ian Kent |
b04561 |
if (hashval < mc->size) {
|
|
Ian Kent |
b04561 |
for (i = (unsigned int) hashval; i < mc->size; i++) {
|
|
Ian Kent |
b04561 |
this = mc->hash[i];
|
|
Ian Kent |
b04561 |
@@ -433,7 +440,7 @@ struct mapent *cache_lookup(struct mapent_cache *mc, const char *key)
|
|
Ian Kent |
b04561 |
if (!key)
|
|
Ian Kent |
b04561 |
return NULL;
|
|
Ian Kent |
b04561 |
|
|
Ian Kent |
b04561 |
- for (me = mc->hash[hash(key)]; me != NULL; me = me->next) {
|
|
Ian Kent |
b04561 |
+ for (me = mc->hash[hash(key, mc->size)]; me != NULL; me = me->next) {
|
|
Ian Kent |
b04561 |
if (strcmp(key, me->key) == 0)
|
|
Ian Kent |
b04561 |
goto done;
|
|
Ian Kent |
b04561 |
}
|
|
Ian Kent |
b04561 |
@@ -446,7 +453,7 @@ struct mapent *cache_lookup(struct mapent_cache *mc, const char *key)
|
|
Ian Kent |
b04561 |
goto done;
|
|
Ian Kent |
b04561 |
}
|
|
Ian Kent |
b04561 |
|
|
Ian Kent |
b04561 |
- for (me = mc->hash[hash("*")]; me != NULL; me = me->next)
|
|
Ian Kent |
b04561 |
+ for (me = mc->hash[hash("*", mc->size)]; me != NULL; me = me->next)
|
|
Ian Kent |
b04561 |
if (strcmp("*", me->key) == 0)
|
|
Ian Kent |
b04561 |
goto done;
|
|
Ian Kent |
b04561 |
}
|
|
Ian Kent |
b04561 |
@@ -462,7 +469,7 @@ struct mapent *cache_lookup_distinct(struct mapent_cache *mc, const char *key)
|
|
Ian Kent |
b04561 |
if (!key)
|
|
Ian Kent |
b04561 |
return NULL;
|
|
Ian Kent |
b04561 |
|
|
Ian Kent |
b04561 |
- for (me = mc->hash[hash(key)]; me != NULL; me = me->next) {
|
|
Ian Kent |
b04561 |
+ for (me = mc->hash[hash(key, mc->size)]; me != NULL; me = me->next) {
|
|
Ian Kent |
b04561 |
if (strcmp(key, me->key) == 0)
|
|
Ian Kent |
b04561 |
return me;
|
|
Ian Kent |
b04561 |
}
|
|
Ian Kent |
b04561 |
@@ -530,7 +537,7 @@ int cache_add(struct mapent_cache *mc, struct map_source *ms, const char *key, c
|
|
Ian Kent |
b04561 |
{
|
|
Ian Kent |
b04561 |
struct mapent *me, *existing = NULL;
|
|
Ian Kent |
b04561 |
char *pkey, *pent;
|
|
Ian Kent |
b04561 |
- unsigned int hashval = hash(key);
|
|
Ian Kent |
b04561 |
+ u_int32_t hashval = hash(key, mc->size);
|
|
Ian Kent |
b04561 |
int status;
|
|
Ian Kent |
b04561 |
|
|
Ian Kent |
b04561 |
me = (struct mapent *) malloc(sizeof(struct mapent));
|
|
Ian Kent |
b04561 |
@@ -750,7 +757,7 @@ int cache_update(struct mapent_cache *mc, struct map_source *ms, const char *key
|
|
Ian Kent |
b04561 |
int cache_delete(struct mapent_cache *mc, const char *key)
|
|
Ian Kent |
b04561 |
{
|
|
Ian Kent |
b04561 |
struct mapent *me = NULL, *pred;
|
|
Ian Kent |
b04561 |
- unsigned int hashval = hash(key);
|
|
Ian Kent |
b04561 |
+ u_int32_t hashval = hash(key, mc->size);
|
|
Ian Kent |
b04561 |
int status, ret = CHE_OK;
|
|
Ian Kent |
b04561 |
char *this;
|
|
Ian Kent |
b04561 |
|
|
Ian Kent |
b04561 |
diff --git a/lib/defaults.c b/lib/defaults.c
|
|
Ian Kent |
b04561 |
index ff653e3..0d39716 100644
|
|
Ian Kent |
b04561 |
--- a/lib/defaults.c
|
|
Ian Kent |
b04561 |
+++ b/lib/defaults.c
|
|
Ian Kent |
b04561 |
@@ -49,6 +49,8 @@
|
|
Ian Kent |
b04561 |
#define ENV_UMOUNT_WAIT "UMOUNT_WAIT"
|
|
Ian Kent |
b04561 |
#define ENV_AUTH_CONF_FILE "AUTH_CONF_FILE"
|
|
Ian Kent |
b04561 |
|
|
Ian Kent |
b04561 |
+#define ENV_MAP_HASH_TABLE_SIZE "MAP_HASH_TABLE_SIZE"
|
|
Ian Kent |
b04561 |
+
|
|
Ian Kent |
b04561 |
static const char *default_master_map_name = DEFAULT_MASTER_MAP_NAME;
|
|
Ian Kent |
b04561 |
static const char *default_auth_conf_file = DEFAULT_AUTH_CONF_FILE;
|
|
Ian Kent |
b04561 |
|
|
Ian Kent |
b04561 |
@@ -323,7 +325,8 @@ unsigned int defaults_read_config(unsigned int to_syslog)
|
|
Ian Kent |
b04561 |
check_set_config_value(key, ENV_NAME_VALUE_ATTR, value, to_syslog) ||
|
|
Ian Kent |
b04561 |
check_set_config_value(key, ENV_APPEND_OPTIONS, value, to_syslog) ||
|
|
Ian Kent |
b04561 |
check_set_config_value(key, ENV_UMOUNT_WAIT, value, to_syslog) ||
|
|
Ian Kent |
b04561 |
- check_set_config_value(key, ENV_AUTH_CONF_FILE, value, to_syslog))
|
|
Ian Kent |
b04561 |
+ check_set_config_value(key, ENV_AUTH_CONF_FILE, value, to_syslog) ||
|
|
Ian Kent |
b04561 |
+ check_set_config_value(key, ENV_MAP_HASH_TABLE_SIZE, value, to_syslog))
|
|
Ian Kent |
b04561 |
;
|
|
Ian Kent |
b04561 |
}
|
|
Ian Kent |
b04561 |
|
|
Ian Kent |
b04561 |
@@ -672,3 +675,14 @@ const char *defaults_get_auth_conf_file(void)
|
|
Ian Kent |
b04561 |
return (const char *) cf;
|
|
Ian Kent |
b04561 |
}
|
|
Ian Kent |
b04561 |
|
|
Ian Kent |
b04561 |
+unsigned int defaults_get_map_hash_table_size(void)
|
|
Ian Kent |
b04561 |
+{
|
|
Ian Kent |
b04561 |
+ long size;
|
|
Ian Kent |
b04561 |
+
|
|
Ian Kent |
b04561 |
+ size = get_env_number(ENV_MAP_HASH_TABLE_SIZE);
|
|
Ian Kent |
b04561 |
+ if (size < 0)
|
|
Ian Kent |
b04561 |
+ size = DEFAULT_MAP_HASH_TABLE_SIZE;
|
|
Ian Kent |
b04561 |
+
|
|
Ian Kent |
b04561 |
+ return (unsigned int) size;
|
|
Ian Kent |
b04561 |
+}
|
|
Ian Kent |
b04561 |
+
|
|
Ian Kent |
b04561 |
diff --git a/redhat/autofs.sysconfig.in b/redhat/autofs.sysconfig.in
|
|
Ian Kent |
b04561 |
index 8256888..fe36f45 100644
|
|
Ian Kent |
b04561 |
--- a/redhat/autofs.sysconfig.in
|
|
Ian Kent |
b04561 |
+++ b/redhat/autofs.sysconfig.in
|
|
Ian Kent |
b04561 |
@@ -89,6 +89,12 @@ BROWSE_MODE="no"
|
|
Ian Kent |
b04561 |
#
|
|
Ian Kent |
b04561 |
#AUTH_CONF_FILE="@@autofsmapdir@@/autofs_ldap_auth.conf"
|
|
Ian Kent |
b04561 |
#
|
|
Ian Kent |
b04561 |
+# MAP_HASH_TABLE_SIZE - set the map cache hash table size.
|
|
Ian Kent |
b04561 |
+# Should be a power of 2 with a ratio roughly
|
|
Ian Kent |
b04561 |
+# between 1:10 and 1:20 for each map.
|
|
Ian Kent |
b04561 |
+#
|
|
Ian Kent |
b04561 |
+#MAP_HASH_TABLE_SIZE=1024
|
|
Ian Kent |
b04561 |
+#
|
|
Ian Kent |
b04561 |
# General global options
|
|
Ian Kent |
b04561 |
#
|
|
Ian Kent |
b04561 |
# If the kernel supports using the autofs miscellanous device
|
|
Ian Kent |
b04561 |
diff --git a/samples/autofs.conf.default.in b/samples/autofs.conf.default.in
|
|
Ian Kent |
b04561 |
index 844a6f3..4496738 100644
|
|
Ian Kent |
b04561 |
--- a/samples/autofs.conf.default.in
|
|
Ian Kent |
b04561 |
+++ b/samples/autofs.conf.default.in
|
|
Ian Kent |
b04561 |
@@ -89,6 +89,12 @@ BROWSE_MODE="no"
|
|
Ian Kent |
b04561 |
#
|
|
Ian Kent |
b04561 |
#AUTH_CONF_FILE="@@autofsmapdir@@/autofs_ldap_auth.conf"
|
|
Ian Kent |
b04561 |
#
|
|
Ian Kent |
b04561 |
+# MAP_HASH_TABLE_SIZE - set the map cache hash table size.
|
|
Ian Kent |
b04561 |
+# Should be a power of 2 with a ratio roughly
|
|
Ian Kent |
b04561 |
+# between 1:10 and 1:20 for each map.
|
|
Ian Kent |
b04561 |
+#
|
|
Ian Kent |
b04561 |
+#MAP_HASH_TABLE_SIZE=1024
|
|
Ian Kent |
b04561 |
+#
|
|
Ian Kent |
b04561 |
# General global options
|
|
Ian Kent |
b04561 |
#
|
|
Ian Kent |
b04561 |
# If the kernel supports using the autofs miscellanous device
|