Fixing merge
[awesomized/libmemcached] / libmemcached / memcached_hash.c
1 #include "common.h"
2
3 /* Defines */
4 static uint64_t FNV_64_INIT= 0xcbf29ce484222325LL;
5 static uint64_t FNV_64_PRIME= 0x100000001b3LL;
6
7 static uint32_t FNV_32_INIT= 2166136261UL;
8 static uint32_t FNV_32_PRIME= 16777619;
9
10 /* Prototypes */
11 static uint32_t internal_generate_hash(char *key, size_t key_length);
12 static uint32_t internal_generate_md5(char *key, size_t key_length);
13 static uint32_t internal_generate_ketama_md5(char *key, size_t key_length);
14
15 uint32_t generate_hash(memcached_st *ptr, char *key, size_t key_length)
16 {
17 uint32_t hash= 1; /* Just here to remove compile warning */
18 uint32_t x= 0;
19
20
21 WATCHPOINT_ASSERT(ptr->number_of_hosts);
22
23 if (ptr->number_of_hosts == 1)
24 return 0;
25
26 switch (ptr->hash)
27 {
28 case MEMCACHED_HASH_DEFAULT:
29 hash= internal_generate_hash(key, key_length);
30 break;
31 case MEMCACHED_HASH_MD5:
32 hash= internal_generate_md5(key, key_length);
33 break;
34 case MEMCACHED_HASH_CRC:
35 hash= ((hash_crc32(key, key_length) >> 16) & 0x7fff);
36 if (hash == 0)
37 hash= 1;
38 break;
39 /* FNV hash'es lifted from Dustin Sallings work */
40 case MEMCACHED_HASH_FNV1_64:
41 {
42 /* Thanks to pierre@demartines.com for the pointer */
43 uint64_t temp_hash;
44
45 temp_hash= FNV_64_INIT;
46 for (x= 0; x < key_length; x++)
47 {
48 temp_hash *= FNV_64_PRIME;
49 temp_hash ^= key[x];
50 }
51 hash= (uint32_t)temp_hash;
52 }
53 break;
54 case MEMCACHED_HASH_FNV1A_64:
55 {
56 hash= FNV_64_INIT;
57 for (x= 0; x < key_length; x++)
58 {
59 hash ^= key[x];
60 hash *= FNV_64_PRIME;
61 }
62 }
63 break;
64 case MEMCACHED_HASH_FNV1_32:
65 {
66 hash= FNV_32_INIT;
67 for (x= 0; x < key_length; x++)
68 {
69 hash *= FNV_32_PRIME;
70 hash ^= key[x];
71 }
72 }
73 break;
74 case MEMCACHED_HASH_FNV1A_32:
75 {
76 hash= FNV_32_INIT;
77 for (x= 0; x < key_length; x++)
78 {
79 hash ^= key[x];
80 hash *= FNV_32_PRIME;
81 }
82 }
83 break;
84 case MEMCACHED_HASH_KETAMA:
85 {
86 hash= internal_generate_ketama_md5(key, key_length);
87 break;
88 }
89 case MEMCACHED_HASH_HSIEH:
90 {
91 hash= hsieh_hash(key, key_length);
92 break;
93 }
94 case MEMCACHED_HASH_MURMUR:
95 {
96 hash= murmur_hash(key, key_length);
97 break;
98 }
99 }
100
101 WATCHPOINT_ASSERT(hash);
102 return hash;
103 }
104
105 unsigned int dispatch_host(memcached_st *ptr, uint32_t hash)
106 {
107 switch (ptr->distribution)
108 {
109 case MEMCACHED_DISTRIBUTION_CONSISTENT:
110 case MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA:
111 {
112 int num= ptr->number_of_hosts * MEMCACHED_POINTS_PER_SERVER;
113
114 hash= hash;
115 struct continuum_item *begin, *end, *left, *right, *middle;
116 begin= left= ptr->continuum;
117 end= right= ptr->continuum + (num - 1);
118
119 while (1)
120 {
121 struct continuum_item *rmiddle;
122
123 middle = left + (right - left) / 2;
124
125 if (middle==end)
126 return begin->index;
127
128 if (middle==begin)
129 return end->index;
130
131 rmiddle = middle+1;
132
133 if (hash<rmiddle->value && hash>=middle->value)
134 return middle->index;
135
136 if (middle->value < hash)
137 left = middle + 1;
138 else if (middle->value > hash)
139 right = middle - 1;
140
141 if (left>right)
142 return left->index;
143 }
144 }
145 break;
146 case MEMCACHED_DISTRIBUTION_CONSISTENT_WHEEL:
147 {
148 unsigned int server_key;
149
150 server_key= hash % MEMCACHED_WHEEL_SIZE;
151
152 return ptr->wheel[server_key];
153 }
154 case MEMCACHED_DISTRIBUTION_MODULA:
155 return hash % ptr->number_of_hosts;
156 default:
157 WATCHPOINT_ASSERT(0); /* We have added a distribution without extending the logic */
158 return hash % ptr->number_of_hosts;
159 }
160
161 if (ptr->distribution == MEMCACHED_DISTRIBUTION_MODULA)
162 {
163 return hash % ptr->number_of_hosts;
164 }
165 else if (ptr->distribution == MEMCACHED_DISTRIBUTION_CONSISTENT)
166 {
167 unsigned int server_key;
168
169 server_key= hash % MEMCACHED_WHEEL_SIZE;
170
171 return ptr->wheel[server_key];
172 }
173 else if (ptr->distribution == MEMCACHED_DISTRIBUTION_CONSISTENT_KETAMA)
174 {
175 int num = ptr->number_of_hosts * MEMCACHED_POINTS_PER_SERVER;
176
177 hash = hash;
178 struct continuum_item *begin, *end, *left, *right, *middle;
179 begin = left = ptr->continuum;
180 end = right = ptr->continuum + (num - 1);
181 while(1)
182 {
183 middle = left + (right - left) / 2;
184 if(middle==end)
185 {
186 return begin->index;
187 }
188 if(middle==begin)
189 {
190 return end->index;
191 }
192 struct continuum_item *rmiddle = middle+1;
193 if(hash<rmiddle->value && hash>=middle->value)
194 return middle->index;
195
196 if(middle->value < hash) {
197 left = middle + 1;
198 }else if(middle->value > hash) {
199 right = middle - 1;
200 }
201
202 if (left>right)
203 return left->index;
204 }
205 }
206 else
207 {
208 WATCHPOINT_ASSERT(0);
209 }
210 }
211
212 unsigned int memcached_generate_hash(memcached_st *ptr, char *key, size_t key_length)
213 {
214 uint32_t hash= 1; /* Just here to remove compile warning */
215
216 WATCHPOINT_ASSERT(ptr->number_of_hosts);
217
218 if (ptr->number_of_hosts == 1)
219 return 0;
220
221 hash = generate_hash(ptr, key, key_length);
222
223 WATCHPOINT_ASSERT(hash);
224 return dispatch_host(ptr, hash);
225 }
226
227 static uint32_t internal_generate_hash(char *key, size_t key_length)
228 {
229 char *ptr= key;
230 uint32_t value= 0;
231
232 while (--key_length)
233 {
234 value += *ptr++;
235 value += (value << 10);
236 value ^= (value >> 6);
237 }
238 value += (value << 3);
239 value ^= (value >> 11);
240 value += (value << 15);
241
242 return value == 0 ? 1 : value;
243 }
244
245 static uint32_t internal_generate_md5(char *key, size_t key_length)
246 {
247 unsigned char results[16];
248
249 md5_signature((unsigned char*)key, (unsigned int)key_length, results);
250
251 return (uint32_t)(( results[3] << 24 )
252 | ( results[2] << 16 )
253 | ( results[1] << 8 )
254 | results[0] );
255 }
256
257 static uint32_t internal_generate_ketama_md5(char *key, size_t key_length)
258 {
259 unsigned char results[16];
260
261 md5_signature((unsigned char*)key, (unsigned int)key_length, results);
262
263 return ((uint32_t) (results[3] & 0xFF) << 24)
264 | ((uint32_t) (results[2] & 0xFF) << 16)
265 | ((uint32_t) (results[1] & 0xFF) << 8)
266 | (results[0] & 0xFF);
267 }