InfiniSQL  v0.1.2-alpha
Massive Scale Transaction Processing
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
spooky.cc
Go to the documentation of this file.
1 // Spooky Hash
2 // A 128-bit noncryptographic hash, for checksums and table lookup
3 // By Bob Jenkins. Public domain.
4 // Oct 31 2010: published framework, disclaimer ShortHash isn't right
5 // Nov 7 2010: disabled ShortHash
6 // Oct 31 2011: replace End, ShortMix, ShortEnd, enable ShortHash again
7 // April 10 2012: buffer overflow on platforms without unaligned reads
8 
17 #include <memory.h>
18 #include "spooky.h"
19 #line 22 "spooky.cc"
20 
21 #define ALLOW_UNALIGNED_READS 1
22 
23 //
24 // short hash ... it could be used on any message,
25 // but it's used by Spooky just for short messages.
26 //
28  const void *message,
29  size_t length,
30  uint64 *hash1,
31  uint64 *hash2)
32 {
33  uint64 buf[2*sc_numVars];
34  union
35  {
36  const uint8 *p8;
37  uint32 *p32;
38  uint64 *p64;
39  size_t i;
40  } u;
41 
42  u.p8 = (const uint8 *)message;
43 
44  if (!ALLOW_UNALIGNED_READS && (u.i & 0x7))
45  {
46  memcpy(buf, message, length);
47  u.p64 = buf;
48  }
49 
50  size_t remainder = length%32;
51  uint64 a=*hash1;
52  uint64 b=*hash2;
53  uint64 c=sc_const;
54  uint64 d=sc_const;
55 
56  if (length > 15)
57  {
58  const uint64 *end = u.p64 + (length/32)*4;
59 
60  // handle all complete sets of 32 bytes
61  for (; u.p64 < end; u.p64 += 4)
62  {
63  c += u.p64[0];
64  d += u.p64[1];
65  ShortMix(a,b,c,d);
66  a += u.p64[2];
67  b += u.p64[3];
68  }
69 
70  //Handle the case of 16+ remaining bytes.
71  if (remainder >= 16)
72  {
73  c += u.p64[0];
74  d += u.p64[1];
75  ShortMix(a,b,c,d);
76  u.p64 += 2;
77  remainder -= 16;
78  }
79  }
80 
81  // Handle the last 0..15 bytes, and its length
82  d = ((uint64)length) << 56;
83 
84  switch (remainder)
85  {
86  case 15:
87  d += ((uint64)u.p8[14]) << 48;
88 
89  case 14:
90  d += ((uint64)u.p8[13]) << 40;
91 
92  case 13:
93  d += ((uint64)u.p8[12]) << 32;
94 
95  case 12:
96  d += u.p32[2];
97  c += u.p64[0];
98  break;
99 
100  case 11:
101  d += ((uint64)u.p8[10]) << 16;
102 
103  case 10:
104  d += ((uint64)u.p8[9]) << 8;
105 
106  case 9:
107  d += (uint64)u.p8[8];
108 
109  case 8:
110  c += u.p64[0];
111  break;
112 
113  case 7:
114  c += ((uint64)u.p8[6]) << 48;
115 
116  case 6:
117  c += ((uint64)u.p8[5]) << 40;
118 
119  case 5:
120  c += ((uint64)u.p8[4]) << 32;
121 
122  case 4:
123  c += u.p32[0];
124  break;
125 
126  case 3:
127  c += ((uint64)u.p8[2]) << 16;
128 
129  case 2:
130  c += ((uint64)u.p8[1]) << 8;
131 
132  case 1:
133  c += (uint64)u.p8[0];
134  break;
135 
136  case 0:
137  c += sc_const;
138  d += sc_const;
139  }
140 
141  ShortEnd(a,b,c,d);
142  *hash1 = a;
143  *hash2 = b;
144 }
145 
146 
147 
148 
149 // do the whole hash in one call
151  const void *message,
152  size_t length,
153  uint64 *hash1,
154  uint64 *hash2)
155 {
156  if (length < sc_bufSize)
157  {
158  Short(message, length, hash1, hash2);
159  return;
160  }
161 
162  uint64 h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11;
163  uint64 buf[sc_numVars];
164  uint64 *end;
165  union
166  {
167  const uint8 *p8;
168  uint64 *p64;
169  size_t i;
170  } u;
171  size_t remainder;
172 
173  h0=h3=h6=h9 = *hash1;
174  h1=h4=h7=h10 = *hash2;
175  h2=h5=h8=h11 = sc_const;
176 
177  u.p8 = (const uint8 *)message;
178  end = u.p64 + (length/sc_blockSize)*sc_numVars;
179 
180  // handle all whole sc_blockSize blocks of bytes
181  if (ALLOW_UNALIGNED_READS || ((u.i & 0x7) == 0))
182  {
183  while (u.p64 < end)
184  {
185  Mix(u.p64, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
186  u.p64 += sc_numVars;
187  }
188  }
189  else
190  {
191  while (u.p64 < end)
192  {
193  memcpy(buf, u.p64, sc_blockSize);
194  Mix(buf, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
195  u.p64 += sc_numVars;
196  }
197  }
198 
199  // handle the last partial block of sc_blockSize bytes
200  remainder = (length - ((const uint8 *)end-(const uint8 *)message));
201  memcpy(buf, end, remainder);
202  memset(((uint8 *)buf)+remainder, 0, sc_blockSize-remainder);
203  ((uint8 *)buf)[sc_blockSize-1] = remainder;
204  Mix(buf, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
205 
206  // do some final mixing
207  End(h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
208  *hash1 = h0;
209  *hash2 = h1;
210 }
211 
212 
213 
214 // init spooky state
215 void SpookyHash::Init(uint64 seed1, uint64 seed2)
216 {
217  m_length = 0;
218  m_remainder = 0;
219  m_state[0] = seed1;
220  m_state[1] = seed2;
221 }
222 
223 
224 // add a message fragment to the state
225 void SpookyHash::Update(const void *message, size_t length)
226 {
227  uint64 h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11;
228  size_t newLength = length + m_remainder;
229  uint8 remainder;
230  union
231  {
232  const uint8 *p8;
233  uint64 *p64;
234  size_t i;
235  } u;
236  const uint64 *end;
237 
238  // Is this message fragment too short? If it is, stuff it away.
239  if (newLength < sc_bufSize)
240  {
241  memcpy(&((uint8 *)m_data)[m_remainder], message, length);
242  m_length = length + m_length;
243  m_remainder = (uint8)newLength;
244  return;
245  }
246 
247  // init the variables
248  if (m_length < sc_bufSize)
249  {
250  h0=h3=h6=h9 = m_state[0];
251  h1=h4=h7=h10 = m_state[1];
252  h2=h5=h8=h11 = sc_const;
253  }
254  else
255  {
256  h0 = m_state[0];
257  h1 = m_state[1];
258  h2 = m_state[2];
259  h3 = m_state[3];
260  h4 = m_state[4];
261  h5 = m_state[5];
262  h6 = m_state[6];
263  h7 = m_state[7];
264  h8 = m_state[8];
265  h9 = m_state[9];
266  h10 = m_state[10];
267  h11 = m_state[11];
268  }
269 
270  m_length = length + m_length;
271 
272  // if we've got anything stuffed away, use it now
273  if (m_remainder)
274  {
275  uint8 prefix = sc_bufSize-m_remainder;
276  memcpy(&(((uint8 *)m_data)[m_remainder]), message, prefix);
277  u.p64 = m_data;
278  Mix(u.p64, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
279  Mix(&u.p64[sc_numVars], h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
280  u.p8 = ((const uint8 *)message) + prefix;
281  length -= prefix;
282  }
283  else
284  {
285  u.p8 = (const uint8 *)message;
286  }
287 
288  // handle all whole blocks of sc_blockSize bytes
289  end = u.p64 + (length/sc_blockSize)*sc_numVars;
290  remainder = (uint8)(length-((const uint8 *)end-u.p8));
291 
292  if (ALLOW_UNALIGNED_READS || (u.i & 0x7) == 0)
293  {
294  while (u.p64 < end)
295  {
296  Mix(u.p64, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
297  u.p64 += sc_numVars;
298  }
299  }
300  else
301  {
302  while (u.p64 < end)
303  {
304  memcpy(m_data, u.p8, sc_blockSize);
305  Mix(m_data, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
306  u.p64 += sc_numVars;
307  }
308  }
309 
310  // stuff away the last few bytes
311  m_remainder = remainder;
312  memcpy(m_data, end, remainder);
313 
314  // stuff away the variables
315  m_state[0] = h0;
316  m_state[1] = h1;
317  m_state[2] = h2;
318  m_state[3] = h3;
319  m_state[4] = h4;
320  m_state[5] = h5;
321  m_state[6] = h6;
322  m_state[7] = h7;
323  m_state[8] = h8;
324  m_state[9] = h9;
325  m_state[10] = h10;
326  m_state[11] = h11;
327 }
328 
329 
330 // report the hash for the concatenation of all message fragments so far
331 void SpookyHash::Final(uint64 *hash1, uint64 *hash2)
332 {
333  // init the variables
334  if (m_length < sc_bufSize)
335  {
336  Short(m_data, m_length, hash1, hash2);
337  return;
338  }
339 
340  const uint64 *data = (const uint64 *)m_data;
341  uint8 remainder = m_remainder;
342 
343  uint64 h0 = m_state[0];
344  uint64 h1 = m_state[1];
345  uint64 h2 = m_state[2];
346  uint64 h3 = m_state[3];
347  uint64 h4 = m_state[4];
348  uint64 h5 = m_state[5];
349  uint64 h6 = m_state[6];
350  uint64 h7 = m_state[7];
351  uint64 h8 = m_state[8];
352  uint64 h9 = m_state[9];
353  uint64 h10 = m_state[10];
354  uint64 h11 = m_state[11];
355 
356  if (remainder >= sc_blockSize)
357  {
358  // m_data can contain two blocks; handle any whole first block
359  Mix(data, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
360  data += sc_numVars;
361  remainder -= sc_blockSize;
362  }
363 
364  // mix in the last partial block, and the length mod sc_blockSize
365  memset(&((uint8 *)data)[remainder], 0, (sc_blockSize-remainder));
366 
367  ((uint8 *)data)[sc_blockSize-1] = remainder;
368  Mix(data, h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
369 
370  // do some final mixing
371  End(h0,h1,h2,h3,h4,h5,h6,h7,h8,h9,h10,h11);
372 
373  *hash1 = h0;
374  *hash2 = h1;
375 }
376