diff --git a/doc/configuration.txt b/doc/configuration.txt index c430ec3b8..0b4844b18 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -2548,6 +2548,14 @@ hash-type poorly with numeric-only input or when the total server weight is a multiple of 33, unless the avalanche modifier is also used. + wt6 this function was designed for haproxy while testing other + functions in the past. It is not as smooth as the other ones, but + is much less sensible to the input data set or to the number of + servers. It can make sense as an alternative to sdbm+avalanche or + djb2+avalanche for consistent hashing or when hashing on numeric + data such as a source IP address or a visitor identifier in a URL + parameter. + indicates an optional method applied after hashing the key : avalanche This directive indicates that the result from the hash diff --git a/include/common/hash.h b/include/common/hash.h index f6875c9ac..379bf898c 100644 --- a/include/common/hash.h +++ b/include/common/hash.h @@ -23,6 +23,7 @@ #define _COMMON_HASH_H_ unsigned long hash_djb2(const char *key, int len); +unsigned long hash_wt6(const char *key, int len); unsigned long hash_sdbm(const char *key, int len); #endif /* _COMMON_HASH_H_ */ diff --git a/include/types/backend.h b/include/types/backend.h index 57d17bdf2..6325be2bf 100644 --- a/include/types/backend.h +++ b/include/types/backend.h @@ -114,6 +114,7 @@ /* BE_LB_HFCN_* is the hash function, to be used with BE_LB_HASH_FUNC */ #define BE_LB_HFCN_SDBM 0x000000 /* sdbm hash */ #define BE_LB_HFCN_DJB2 0x400000 /* djb2 hash */ +#define BE_LB_HFCN_WT6 0x800000 /* wt6 hash */ #define BE_LB_HASH_FUNC 0xC00000 /* get/clear hash function */ diff --git a/src/backend.c b/src/backend.c index e044430e0..7689cea67 100644 --- a/src/backend.c +++ b/src/backend.c @@ -61,6 +61,9 @@ static unsigned long gen_hash(const struct proxy* px, const char* key, unsigned case BE_LB_HFCN_DJB2: hash = hash_djb2(key, len); break; + case BE_LB_HFCN_WT6: + hash = hash_wt6(key, len); + break; case BE_LB_HFCN_SDBM: /* this is the default hash function */ default: diff --git a/src/cfgparse.c b/src/cfgparse.c index bb79a34a1..28507dd06 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -4128,9 +4128,11 @@ stats_error_parsing: } else if (!strcmp(args[2], "djb2")) { curproxy->lbprm.algo |= BE_LB_HFCN_DJB2; + } else if (!strcmp(args[2], "wt6")) { + curproxy->lbprm.algo |= BE_LB_HFCN_WT6; } else { - Alert("parsing [%s:%d] : '%s' only supports 'sdbm' and 'djb2' hash functions.\n", file, linenum, args[0]); + Alert("parsing [%s:%d] : '%s' only supports 'sdbm', 'djb2' or 'wt6' hash functions.\n", file, linenum, args[0]); err_code |= ERR_ALERT | ERR_FATAL; goto out; } diff --git a/src/hash.c b/src/hash.c index 8da3003b9..034685efd 100644 --- a/src/hash.c +++ b/src/hash.c @@ -17,6 +17,33 @@ #include +unsigned long hash_wt6(const char *key, int len) +{ + unsigned h0 = 0xa53c965aUL; + unsigned h1 = 0x5ca6953aUL; + unsigned step0 = 6; + unsigned step1 = 18; + + for (; len > 0; len--) { + unsigned int t; + + t = ((unsigned int)*key); + key++; + + h0 = ~(h0 ^ t); + h1 = ~(h1 + t); + + t = (h1 << step0) | (h1 >> (32-step0)); + h1 = (h0 << step1) | (h0 >> (32-step1)); + h0 = t; + + t = ((h0 >> 16) ^ h1) & 0xffff; + step0 = t & 0x1F; + step1 = t >> 11; + } + return h0 ^ h1; +} + unsigned long hash_djb2(const char *key, int len) { unsigned long hash = 5381;