Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 130701790bf2d95e902edf16031ff596 > files > 285

autofs-5.0.1-0.rc2.164.el5_8.src.rpm

autofs-5.0.4 - make hash table scale to thousands of entries

From: Valerie Aurora Henson <vaurora@redhat.com>

Originally written by Paul Wankadia <junyer@google.com>.

The autofs cache lookup performs poorly for large maps.

The additive hashing algorithm used by autofs results in a clustering
of hash values around the average hash chain size. It is biased toward
a small range of hash indexes which becomes worse as the hash table size
increases.

Simple testing shows that the "One-at-a-time" hash function (implemented
by this patch) gives a much better distribution of hash indexes as table
size increases.

The only change made to the original patch is to make the hash table size
configurable with a default somewhat larger than it is currently.
---

 include/automount.h            |    2 -
 include/defaults.h             |    3 ++
 lib/cache.c                    |   47 +++++++++++++++++++++++------------------
 lib/defaults.c                 |   16 +++++++++++++
 redhat/autofs.sysconfig.in     |    6 +++++
 samples/autofs.conf.default.in |    6 +++++
 6 files changed, 58 insertions(+), 22 deletions(-)


--- autofs-5.0.1.orig/include/automount.h
+++ autofs-5.0.1/include/automount.h
@@ -124,7 +124,7 @@ struct autofs_point; 
 #define CHE_DUPLICATE	0x0020
 #define CHE_UNAVAIL	0x0040
 
-#define HASHSIZE		77
+#define NULL_MAP_HASHSIZE	64
 #define NEGATIVE_TIMEOUT	10
 #define UMOUNT_RETRIES		8
 #define EXPIRE_RETRIES		3
--- autofs-5.0.1.orig/include/defaults.h
+++ autofs-5.0.1/include/defaults.h
@@ -40,6 +40,8 @@
 #define DEFAULT_APPEND_OPTIONS		1
 #define DEFAULT_AUTH_CONF_FILE		AUTOFS_MAP_DIR "/autofs_ldap_auth.conf"
 
+#define DEFAULT_MAP_HASH_TABLE_SIZE	1024
+
 struct ldap_schema;
 struct ldap_searchdn;
 
@@ -62,6 +64,7 @@ void defaults_free_searchdns(struct ldap
 unsigned int defaults_get_append_options(void);
 unsigned int defaults_get_umount_wait(void);
 const char *defaults_get_auth_conf_file(void);
+unsigned int defaults_get_map_hash_table_size(void);
 
 #endif
 
--- autofs-5.0.1.orig/lib/cache.c
+++ autofs-5.0.1/lib/cache.c
@@ -177,7 +177,7 @@ struct mapent_cache *cache_init(struct a
 	if (!mc)
 		return NULL;
 
-	mc->size = HASHSIZE;
+	mc->size = defaults_get_map_hash_table_size();
 
 	mc->hash = malloc(mc->size * sizeof(struct entry *));
 	if (!mc->hash) {
@@ -228,7 +228,7 @@ struct mapent_cache *cache_init_null_cac
 	if (!mc)
 		return NULL;
 
-	mc->size = HASHSIZE;
+	mc->size = NULL_MAP_HASHSIZE;
 
 	mc->hash = malloc(mc->size * sizeof(struct entry *));
 	if (!mc->hash) {
@@ -266,29 +266,36 @@ struct mapent_cache *cache_init_null_cac
 	return mc;
 }
 
-static unsigned int hash(const char *key)
+static u_int32_t hash(const char *key, unsigned int size)
 {
-	unsigned long hashval;
+	u_int32_t hashval;
 	char *s = (char *) key;
 
-	for (hashval = 0; *s != '\0';)
-		hashval += *s++;
+	for (hashval = 0; *s != '\0';) {
+		hashval += (unsigned char) *s++;
+		hashval += (hashval << 10);
+		hashval ^= (hashval >> 6);
+	}
+
+	hashval += (hashval << 3);
+	hashval ^= (hashval >> 11);
+	hashval += (hashval << 15);
 
-	return hashval % HASHSIZE;
+	return hashval % size;
 }
 
-static unsigned int ino_hash(dev_t dev, ino_t ino)
+static u_int32_t ino_hash(dev_t dev, ino_t ino, unsigned int size)
 {
-	unsigned long hashval;
+	u_int32_t hashval;
 
 	hashval = dev + ino;
 
-	return hashval % HASHSIZE;
+	return hashval % size;
 }
 
 int cache_set_ino_index(struct mapent_cache *mc, const char *key, dev_t dev, ino_t ino)
 {
-	unsigned int ino_index = ino_hash(dev, ino);
+	u_int32_t ino_index = ino_hash(dev, ino, mc->size);
 	struct mapent *me;
 
 	me = cache_lookup_distinct(mc, key);
@@ -310,10 +317,10 @@ struct mapent *cache_lookup_ino(struct m
 {
 	struct mapent *me = NULL;
 	struct list_head *head, *p;
-	unsigned int ino_index;
+	u_int32_t ino_index;
 
 	ino_index_lock(mc);
-	ino_index = ino_hash(dev, ino);
+	ino_index = ino_hash(dev, ino, mc->size);
 	head = &mc->ino_index[ino_index];
 
 	list_for_each(p, head) {
@@ -356,7 +363,7 @@ struct mapent *cache_lookup_first(struct
 struct mapent *cache_lookup_next(struct mapent_cache *mc, struct mapent *me)
 {
 	struct mapent *this;
-	unsigned long hashval;
+	u_int32_t hashval;
 	unsigned int i;
 
 	if (!me)
@@ -372,7 +379,7 @@ struct mapent *cache_lookup_next(struct 
 		return this;
 	}
 
-	hashval = hash(me->key) + 1;
+	hashval = hash(me->key, mc->size) + 1;
 	if (hashval < mc->size) {
 		for (i = (unsigned int) hashval; i < mc->size; i++) {
 			this = mc->hash[i];
@@ -420,7 +427,7 @@ struct mapent *cache_lookup(struct mapen
 	if (!key)
 		return NULL;
 
-	for (me = mc->hash[hash(key)]; me != NULL; me = me->next) {
+	for (me = mc->hash[hash(key, mc->size)]; me != NULL; me = me->next) {
 		if (strcmp(key, me->key) == 0)
 			goto done;
 	}
@@ -433,7 +440,7 @@ struct mapent *cache_lookup(struct mapen
 			goto done;
 		}
 
-		for (me = mc->hash[hash("*")]; me != NULL; me = me->next)
+		for (me = mc->hash[hash("*", mc->size)]; me != NULL; me = me->next)
 			if (strcmp("*", me->key) == 0)
 				goto done;
 	}
@@ -449,7 +456,7 @@ struct mapent *cache_lookup_distinct(str
 	if (!key)
 		return NULL;
 
-	for (me = mc->hash[hash(key)]; me != NULL; me = me->next) {
+	for (me = mc->hash[hash(key, mc->size)]; me != NULL; me = me->next) {
 		if (strcmp(key, me->key) == 0)
 			return me;
 	}
@@ -517,7 +524,7 @@ int cache_add(struct mapent_cache *mc, s
 {
 	struct mapent *me, *existing = NULL;
 	char *pkey, *pent;
-	unsigned int hashval = hash(key);
+	u_int32_t hashval = hash(key, mc->size);
 	int status;
 
 	me = (struct mapent *) malloc(sizeof(struct mapent));
@@ -736,7 +743,7 @@ int cache_update(struct mapent_cache *mc
 int cache_delete(struct mapent_cache *mc, const char *key)
 {
 	struct mapent *me = NULL, *pred;
-	unsigned int hashval = hash(key);
+	u_int32_t hashval = hash(key, mc->size);
 	int status, ret = CHE_OK;
 	char *this;
 
--- autofs-5.0.1.orig/lib/defaults.c
+++ autofs-5.0.1/lib/defaults.c
@@ -48,6 +48,8 @@
 #define ENV_UMOUNT_WAIT			"UMOUNT_WAIT"
 #define ENV_AUTH_CONF_FILE		"AUTH_CONF_FILE"
 
+#define ENV_MAP_HASH_TABLE_SIZE		"MAP_HASH_TABLE_SIZE"
+
 static const char *default_master_map_name = DEFAULT_MASTER_MAP_NAME;
 static const char *default_auth_conf_file  = DEFAULT_AUTH_CONF_FILE;
 
@@ -322,7 +324,8 @@ unsigned int defaults_read_config(unsign
 		    check_set_config_value(key, ENV_NAME_VALUE_ATTR, value, to_syslog) ||
 		    check_set_config_value(key, ENV_APPEND_OPTIONS, value, to_syslog) ||
 		    check_set_config_value(key, ENV_UMOUNT_WAIT, value, to_syslog) ||
-		    check_set_config_value(key, ENV_AUTH_CONF_FILE, value, to_syslog))
+		    check_set_config_value(key, ENV_AUTH_CONF_FILE, value, to_syslog) ||
+		    check_set_config_value(key, ENV_MAP_HASH_TABLE_SIZE, value, to_syslog))
 			;
 	}
 
@@ -671,3 +674,14 @@ const char *defaults_get_auth_conf_file(
 	return (const char *) cf;
 }
 
+unsigned int defaults_get_map_hash_table_size(void)
+{
+	long size;
+
+	size = get_env_number(ENV_MAP_HASH_TABLE_SIZE);
+	if (size < 0)
+		size = DEFAULT_MAP_HASH_TABLE_SIZE;
+
+	return (unsigned int) size;
+}
+
--- autofs-5.0.1.orig/redhat/autofs.sysconfig.in
+++ autofs-5.0.1/redhat/autofs.sysconfig.in
@@ -89,6 +89,12 @@ BROWSE_MODE="no"
 #
 #AUTH_CONF_FILE="@@autofsmapdir@@/autofs_ldap_auth.conf"
 #
+# MAP_HASH_TABLE_SIZE - set the map cache hash table size.
+# 			Should be a power of 2 with a ratio roughly
+# 			between 1:10 and 1:20 for each map.
+#
+#MAP_HASH_TABLE_SIZE=1024
+#
 # General global options
 #
 #OPTIONS=""
--- autofs-5.0.1.orig/samples/autofs.conf.default.in
+++ autofs-5.0.1/samples/autofs.conf.default.in
@@ -89,6 +89,12 @@ BROWSE_MODE="no"
 #
 #AUTH_CONF_FILE="@@autofsmapdir@@/autofs_ldap_auth.conf"
 #
+# MAP_HASH_TABLE_SIZE - set the map cache hash table size.
+# 			Should be a power of 2 with a ratio roughly
+# 			between 1:10 and 1:20 for each map.
+#
+#MAP_HASH_TABLE_SIZE=1024
+#
 # General global options
 #
 #OPTIONS=""