Motr  M0
hash_fnc.c
Go to the documentation of this file.
1 /* -*- C -*- */
2 /*
3  * Copyright (c) 2016-2020 Seagate Technology LLC and/or its Affiliates
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * For any questions about this software or licensing,
18  * please email opensource@seagate.com or cortx-questions@seagate.com.
19  *
20  */
21 
22 
28 #define M0_TRACE_SUBSYSTEM M0_TRACE_SUBSYS_LIB
29 #include "lib/trace.h"
30 #include "lib/memory.h"
31 #include "hash_fnc.h"
32 
33 static const uint64_t k0 = 0xc3a5c85c97cb3127ULL;
34 static const uint64_t k1 = 0xb492b66fbe98f273ULL;
35 static const uint64_t k2 = 0x9ae16a3b2f90404fULL;
36 static const uint64_t def_mul = 0x9ddfea08eb382d69ULL;
37 
38 static inline uint32_t swap_32(uint32_t x)
39 {
40  x = ((x << 8) & 0xFF00FF00) | ((x>> 8) & 0x00FF00FF);
41  x = (x >> 16) | (x << 16);
42  return x;
43 }
44 
45 static inline uint64_t swap_64(uint64_t x)
46 {
47  union {
48  uint64_t ll;
49  uint32_t l[2];
50  } w, r;
51 
52  w.ll = x;
53  r.l[0] = swap_32(w.l[1]);
54  r.l[1] = swap_32(w.l[0]);
55  return r.ll;
56 }
57 
58 static inline uint64_t fetch32(const unsigned char *val)
59 {
60  uint32_t res;
61 
62  memcpy(&res, val, sizeof(res));
63  return res;
64 }
65 
66 static inline uint64_t fetch64(const unsigned char *val)
67 {
68  uint64_t res;
69 
70  memcpy(&res, val, sizeof(res));
71  return res;
72 }
73 
74 static inline uint64_t rotate(uint64_t val, int shift)
75 {
76  return shift == 0 ? val : ((val >> shift) | (val << (64 - shift)));
77 }
78 
79 M0_UNUSED static inline uint32_t rotate32(uint32_t val, int shift)
80 {
81  return shift == 0 ? val : ((val >> shift) | (val << (32 - shift)));
82 }
83 
84 M0_INTERNAL uint64_t m0_hash_fnc_fnv1(const void *buffer, m0_bcount_t len)
85 {
86  const unsigned char *ptr = (const unsigned char*)buffer;
87  uint64_t val = 14695981039346656037UL;
88  m0_bcount_t i;
89 
90  if (buffer == NULL || len == 0)
91  return 0;
92  for (i = 0; i < len; i++)
93  val = (val * 1099511628211) ^ ptr[i];
94  return val;
95 }
96 
97 static inline uint64_t hash_len16(uint64_t u, uint64_t v, uint64_t mul)
98 {
99  uint64_t a = (u ^ v) * mul;
100  uint64_t b;
101 
102  a ^= (a >> 47);
103  b = (v ^ a) * mul;
104  b ^= (b >> 47);
105  b *= mul;
106  return b;
107 }
108 
109 static inline struct m0_uint128 weak_hash32_seeds_6(uint64_t w, uint64_t x,
110  uint64_t y, uint64_t z,
111  uint64_t a, uint64_t b)
112 {
113  uint64_t c;
114 
115  a += w;
116  b = rotate(b + a + z, 21);
117  c = a;
118  a += x;
119  a += y;
120  b += rotate(a, 44);
121  return M0_UINT128((uint64_t) (a + z), (uint64_t) (b + c));
122 }
123 
124 static inline struct m0_uint128 weak_hash32_seeds(const unsigned char* s,
125  uint64_t a, uint64_t b)
126 {
127  return weak_hash32_seeds_6(fetch64(s),
128  fetch64(s + 8),
129  fetch64(s + 16),
130  fetch64(s + 24),
131  a, b);
132 }
133 
134 static inline uint64_t shift_mix(uint64_t val)
135 {
136  return val ^ (val >> 47);
137 }
138 
139 static uint64_t hash_0to16(const unsigned char *buffer, m0_bcount_t len)
140 {
141  if (len >= 8) {
142  uint64_t mul = k2 + len * 2;
143  uint64_t a = fetch64(buffer) + k2;
144  uint64_t b = fetch64(buffer + len - 8);
145  uint64_t c = rotate(b, 37) * mul + a;
146  uint64_t d = (rotate(a, 25) + b) * mul;
147 
148  return hash_len16(c, d, mul);
149  }
150  if (len >= 4) {
151  uint64_t mul = k2 + len * 2;
152  uint64_t a = fetch32(buffer);
153 
154  return hash_len16(len + (a << 3),
155  fetch32(buffer + len - 4),
156  mul);
157  }
158  if (len > 0) {
159  uint8_t a = buffer[0];
160  uint8_t b = buffer[len >> 1];
161  uint8_t c = buffer[len - 1];
162  uint32_t y = a + (b << 8);
163  uint32_t z = len + (c << 2);
164 
165  return shift_mix(y * k2 ^ z * k0) * k2;
166  }
167  return k2;
168 }
169 
170 static uint64_t hash_17to32(const unsigned char *buffer, size_t len)
171 {
172  uint64_t mul = k2 + len * 2;
173  uint64_t a = fetch64(buffer) * k1;
174  uint64_t b = fetch64(buffer + 8);
175  uint64_t c = fetch64(buffer + len - 8) * mul;
176  uint64_t d = fetch64(buffer + len - 16) * k2;
177 
178  return hash_len16(rotate(a + b, 43) + rotate(c, 30) + d,
179  a + rotate(b + k2, 18) + c, mul);
180 }
181 
182 static uint64_t hash_33to64(const unsigned char *buffer, size_t len)
183 {
184  uint64_t mul = k2 + len * 2;
185  uint64_t a = fetch64(buffer) * k2;
186  uint64_t b = fetch64(buffer + 8);
187  uint64_t c = fetch64(buffer + len - 24);
188  uint64_t d = fetch64(buffer + len - 32);
189  uint64_t e = fetch64(buffer + 16) * k2;
190  uint64_t f = fetch64(buffer + 24) * 9;
191  uint64_t g = fetch64(buffer + len - 8);
192  uint64_t h = fetch64(buffer + len - 16) * mul;
193  uint64_t u = rotate(a + g, 43) + (rotate(b, 30) + c) * 9;
194  uint64_t v = ((a + g) ^ d) + f + 1;
195  uint64_t w = swap_64((u + v) * mul) + h;
196  uint64_t x = rotate(e + f, 42) + c;
197  uint64_t y = (swap_64((v + w) * mul) + g) * mul;
198  uint64_t z = e + f + c;
199 
200  a = swap_64((x + z) * mul + y) + b;
201  b = shift_mix((z + a) * mul + d + h) * mul;
202  return b + x;
203 }
204 
205 M0_INTERNAL uint64_t m0_hash_fnc_city(const void *buffer, m0_bcount_t len)
206 {
207  const unsigned char *ptr = (const unsigned char*)buffer;
208  uint64_t x;
209  uint64_t y;
210  uint64_t z;
211  uint64_t temp;
212  struct m0_uint128 v;
213  struct m0_uint128 w;
214 
215  if (buffer == NULL || len == 0)
216  return 0;
217  if (len <= 32) {
218  if (len <= 16)
219  return hash_0to16(buffer, len);
220  else
221  return hash_17to32(buffer, len);
222  }
223  else
224  if (len <= 64)
225  return hash_33to64(buffer, len);
226  /* Large buffer processing. */
227  x = fetch64(ptr + len - 40);
228  y = fetch64(ptr + len - 16) + fetch64(ptr + len - 56);
229  z = hash_len16(fetch64(ptr + len - 48) + len,
230  fetch64(ptr + len - 24), def_mul);
231 
232  v = weak_hash32_seeds(ptr + len - 64, len, z);
233  w = weak_hash32_seeds(ptr + len - 32, y + k1, x);
234  x = x * k1 + fetch64(ptr);
235 
236  len = (len - 1) & ~(m0_bcount_t)(63);
237  do {
238  x = rotate(x + y + v.u_hi + fetch64(ptr + 8), 37) * k1;
239  y = rotate(y + v.u_lo + fetch64(ptr + 48), 42) * k1;
240  x ^= w.u_lo;
241  y += v.u_hi + fetch64(ptr + 40);
242  z = rotate(z + w.u_hi, 33) * k1;
243  v = weak_hash32_seeds(ptr, v.u_lo * k1, x + w.u_hi);
244  w = weak_hash32_seeds(ptr + 32, z + w.u_lo,
245  y + fetch64(ptr + 16));
246  temp = z;
247  z = x;
248  x = temp;
249  ptr += 64;
250  len -= 64;
251  } while (len != 0);
252  return hash_len16(hash_len16(v.u_hi, w.u_hi, def_mul) +
253  shift_mix(y) * k1 + z,
254  hash_len16(v.u_lo, w.u_lo, def_mul) + x, def_mul);
255 }
256 
257 #undef M0_TRACE_SUBSYSTEM
258 
261 /*
262  * Local variables:
263  * c-indentation-style: "K&R"
264  * c-basic-offset: 8
265  * tab-width: 8
266  * fill-column: 80
267  * scroll-step: 1
268  * End:
269  */
270 /*
271  * vim: tabstop=8 shiftwidth=8 noexpandtab textwidth=80 nowrap
272  */
static void ptr(struct m0_addb2__context *ctx, const uint64_t *v, char *buf)
Definition: dump.c:440
static struct m0_uint128 weak_hash32_seeds(const unsigned char *s, uint64_t a, uint64_t b)
Definition: hash_fnc.c:124
static const uint64_t k1
Definition: hash_fnc.c:34
#define NULL
Definition: misc.h:38
Definition: idx_mock.c:52
static bool x
Definition: sm.c:168
static FILE * f
Definition: adieu.c:79
union @126 u
static uint64_t rotate(uint64_t val, int shift)
Definition: hash_fnc.c:74
uint64_t m0_bcount_t
Definition: types.h:77
static uint64_t swap_64(uint64_t x)
Definition: hash_fnc.c:45
static const uint64_t k0
Definition: hash_fnc.c:33
static uint64_t hash_len16(uint64_t u, uint64_t v, uint64_t mul)
Definition: hash_fnc.c:97
int i
Definition: dir.c:1033
static uint64_t shift_mix(uint64_t val)
Definition: hash_fnc.c:134
static uint64_t fetch32(const unsigned char *val)
Definition: hash_fnc.c:58
static struct m0_addb2_callback c
Definition: consumer.c:41
M0_INTERNAL uint64_t m0_hash_fnc_fnv1(const void *buffer, m0_bcount_t len)
Definition: hash_fnc.c:84
M0_INTERNAL uint64_t m0_hash_fnc_city(const void *buffer, m0_bcount_t len)
Definition: hash_fnc.c:205
uint64_t u_hi
Definition: types.h:36
static uint32_t swap_32(uint32_t x)
Definition: hash_fnc.c:38
static uint64_t hash_17to32(const unsigned char *buffer, size_t len)
Definition: hash_fnc.c:170
static uint64_t hash_0to16(const unsigned char *buffer, m0_bcount_t len)
Definition: hash_fnc.c:139
static uint64_t fetch64(const unsigned char *val)
Definition: hash_fnc.c:66
static struct m0_clink l[NR]
Definition: chan.c:37
static const uint64_t k2
Definition: hash_fnc.c:35
static const uint64_t def_mul
Definition: hash_fnc.c:36
static int r[NR]
Definition: thread.c:46
Definition: addb2.c:200
static uint64_t hash_33to64(const unsigned char *buffer, size_t len)
Definition: hash_fnc.c:182
static M0_UNUSED uint32_t rotate32(uint32_t val, int shift)
Definition: hash_fnc.c:79
#define M0_UINT128(hi, lo)
Definition: types.h:40
static struct m0_uint128 weak_hash32_seeds_6(uint64_t w, uint64_t x, uint64_t y, uint64_t z, uint64_t a, uint64_t b)
Definition: hash_fnc.c:109
uint64_t u_lo
Definition: types.h:37
static struct gen g[MAX_GEN]
Definition: beck.c:521
static struct m0_addb2_source * s
Definition: consumer.c:39
#define M0_UNUSED
Definition: misc.h:380