通过启动时的-o hash_algorithm可以配置memcached的hash算法,支持两种算法:jenkins, murmur3,默认是jenkins。
hash源码里面有几点比较有意思,直接在代码里标明。
大端序部分与小端序部分基本一致,就不再标明。
jenkins_hash.c
#if HASH_LITTLE_ENDIAN == 1
uint32_t jenkins_hash(
const void *key, /* the key to hash */
size_t length) /* length of the key */
{
// 由于a,b,c都是4byte的,因此下面每次循环最大处理12byte
uint32_t a,b,c; /* internal state */
// union里面有个const变量,不用马上初始化,通过i直接操作,免除了数据强转
union { const void *ptr; size_t i; } u; /* needed for Mac Powerbook G4 */
/* Set up the internal state */
// 0xdeadbeef是一个魔术数,标记软件崩溃或死锁,但这里好像并没有特别的意义,反汇编的时候方便查找?后面+0似乎也没有意义,知道的博友还望告知一下,不胜感激!
a = b = c = 0xdeadbeef + ((uint32_t)length) + 0;
u.ptr = key;
// 此处的HASH_LITTLE_ENDIAN是多余的,其值必然为1。u.i&0x3是检查地址低两位是否是00,如果是的话可以认为是4字节内存对齐的,可以一次处理4byte。
if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) {
const uint32_t *k = key; /* read 32-bit chunks */
#ifdef VALGRIND
const uint8_t *k8;
#endif /* ifdef VALGRIND */
/*------ all but last block: aligned reads and affect 32 bits of (a,b,c) */
while (length > 12)
{
a += k[0];
b += k[1];
c += k[2];
mix(a,b,c);
length -= 12;
k += 3;
}
/*----------------------------- handle the last (probably partial) block */
/*
* "k[2]&0xffffff" actually reads beyond the end of the string, but
* then masks off the part it's not allowed to read. Because the
* string is aligned, the masked-off tail is in the same word as the
* rest of the string. Every machine with memory protection I've seen
* does it on word boundaries, so is OK with this. But VALGRIND will
* still catch it and complain. The masking trick does make the hash
* noticably faster for short strings (like English words).
*/
#ifndef VALGRIND
switch(length)
{
case 12: c+=k[2]; b+=k[1]; a+=k[0]; break;
case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break;
case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break;
case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break;
case 8 : b+=k[1]; a+=k[0]; break;
case 7 : b+=k[1]&0xffffff; a+=k[0]; break;
case 6 : b+=k[1]&0xffff; a+=k[0]; break;
case 5 : b+=k[1]&0xff; a+=k[0]; break;
case 4 : a+=k[0]; break;
case 3 : a+=k[0]&0xffffff; break;
case 2 : a+=k[0]&0xffff; break;
case 1 : a+=k[0]&0xff; break;
case 0 : return c; /* zero length strings require no mixing */
}
#else /* make valgrind happy */
k8 = (