blob: 3b5a175065dda4fa82fe8ac311f626c6d82737f1 [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
2 * Copyright (c) 2015 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15/*
16 Copyright (c) 2006 Eliot Dresselhaus
17
18 Permission is hereby granted, free of charge, to any person obtaining
19 a copy of this software and associated documentation files (the
20 "Software"), to deal in the Software without restriction, including
21 without limitation the rights to use, copy, modify, merge, publish,
22 distribute, sublicense, and/or sell copies of the Software, and to
23 permit persons to whom the Software is furnished to do so, subject to
24 the following conditions:
25
26 The above copyright notice and this permission notice shall be
27 included in all copies or substantial portions of the Software.
28
29 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
32 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
33 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
34 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
35 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36*/
37
38#include <vppinfra/qhash.h>
39
40#define QHASH_ALL_VALID ((1 << QHASH_KEYS_PER_BUCKET) - 1)
41
42void *
Dave Barachc3799992016-08-15 11:12:27 -040043_qhash_resize (void *v, uword length, uword elt_bytes)
Ed Warnickecb9cada2015-12-08 15:45:58 -070044{
Dave Barachc3799992016-08-15 11:12:27 -040045 qhash_t *h;
Ed Warnickecb9cada2015-12-08 15:45:58 -070046 uword l;
47
48 l = clib_max (max_log2 (length), 2 + QHASH_LOG2_KEYS_PER_BUCKET);
49
50 /* Round up if less than 1/2 full. */
51 l += ((f64) length / (f64) (1 << l)) < .5;
52
Dave Barachc3799992016-08-15 11:12:27 -040053 v = _vec_resize (0, 1 << l, elt_bytes << l, sizeof (h[0]),
Ed Warnickecb9cada2015-12-08 15:45:58 -070054 /* align */ sizeof (uword));
55
56 h = qhash_header (v);
57 h->n_elts = 0;
58 h->log2_hash_size = l;
Dave Barachc3799992016-08-15 11:12:27 -040059 h->hash_keys =
60 clib_mem_alloc_aligned_no_fail (sizeof (h->hash_keys[0]) << l,
61 CLIB_CACHE_LINE_BYTES);
Ed Warnickecb9cada2015-12-08 15:45:58 -070062 vec_resize (h->hash_key_valid_bitmap,
63 1 << (l - QHASH_LOG2_KEYS_PER_BUCKET));
Dave Barachb7b92992018-10-17 10:38:51 -040064 clib_memset (v, ~0, elt_bytes << l);
Ed Warnickecb9cada2015-12-08 15:45:58 -070065
66 return v;
67}
68
69static u8 min_log2_table[256];
70
71static inline uword
72qhash_min_log2 (uword x)
73{
74 ASSERT (is_pow2 (x));
75 ASSERT (x < 256);
76 return min_log2_table[x];
77}
78
Dave Barachc3799992016-08-15 11:12:27 -040079static void
80qhash_min_log2_init ()
Ed Warnickecb9cada2015-12-08 15:45:58 -070081{
82 int i;
83 for (i = 0; i < 256; i++)
84 min_log2_table[i] = min_log2 (i);
85}
86
87always_inline uword
88qhash_get_valid_elt_mask (qhash_t * h, uword i)
Dave Barachc3799992016-08-15 11:12:27 -040089{
90 return h->hash_key_valid_bitmap[i / QHASH_KEYS_PER_BUCKET];
91}
Ed Warnickecb9cada2015-12-08 15:45:58 -070092
93always_inline void
94qhash_set_valid_elt_mask (qhash_t * h, uword i, uword mask)
Dave Barachc3799992016-08-15 11:12:27 -040095{
96 h->hash_key_valid_bitmap[i / QHASH_KEYS_PER_BUCKET] = mask;
97}
Ed Warnickecb9cada2015-12-08 15:45:58 -070098
99always_inline uword
Dave Barachc3799992016-08-15 11:12:27 -0400100qhash_search_bucket (uword * hash_keys, uword search_key, uword m)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700101{
102 uword t;
103#define _(i) ((hash_keys[i] == search_key) << i)
Dave Barachc3799992016-08-15 11:12:27 -0400104 t = (_(0) | _(1) | _(2) | _(3));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700105 if (QHASH_KEYS_PER_BUCKET > 4)
Dave Barachc3799992016-08-15 11:12:27 -0400106 t |= (_(4) | _(5) | _(6) | _(7));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700107 if (QHASH_KEYS_PER_BUCKET > 8)
Dave Barachc3799992016-08-15 11:12:27 -0400108 t |= (_(8) | _(9) | _(10) | _(11) | _(12) | _(13) | _(14) | _(15));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700109#undef _
110 return m & t;
111}
112
113/* Lookup multiple keys in the same hash table. */
114void
Dave Barachc3799992016-08-15 11:12:27 -0400115qhash_get_multiple (void *v,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700116 uword * search_keys,
Dave Barachc3799992016-08-15 11:12:27 -0400117 uword n_search_keys, u32 * result_indices)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700118{
Dave Barachc3799992016-08-15 11:12:27 -0400119 qhash_t *h = qhash_header (v);
120 uword *k, *hash_keys;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700121 uword n_left, bucket_mask;
Dave Barachc3799992016-08-15 11:12:27 -0400122 u32 *r;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700123
Dave Barachc3799992016-08-15 11:12:27 -0400124 if (!v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700125 {
Dave Barachb7b92992018-10-17 10:38:51 -0400126 clib_memset (result_indices, ~0,
127 sizeof (result_indices[0]) * n_search_keys);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700128 return;
129 }
130
Dave Barachc3799992016-08-15 11:12:27 -0400131 bucket_mask = pow2_mask (h->log2_hash_size) & ~(QHASH_KEYS_PER_BUCKET - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700132
133 k = search_keys;
134 n_left = n_search_keys;
135 hash_keys = h->hash_keys;
136 r = result_indices;
137
138 while (n_left >= 2)
139 {
140 u32 a0, b0, c0, bi0, valid0, match0;
141 u32 a1, b1, c1, bi1, valid1, match1;
Dave Barachc3799992016-08-15 11:12:27 -0400142 uword k0, k1, *h0, *h1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700143
144 k0 = k[0];
145 k1 = k[1];
146 n_left -= 2;
147 k += 2;
148
149 a0 = a1 = h->hash_seeds[0];
150 b0 = b1 = h->hash_seeds[1];
151 c0 = c1 = h->hash_seeds[2];
152 a0 ^= k0;
153 a1 ^= k1;
154#if uword_bits == 64
155 b0 ^= k0 >> 32;
156 b1 ^= k1 >> 32;
157#endif
Dave Barachc3799992016-08-15 11:12:27 -0400158
Ed Warnickecb9cada2015-12-08 15:45:58 -0700159 hash_mix32_step_1 (a0, b0, c0);
160 hash_mix32_step_1 (a1, b1, c1);
161 hash_mix32_step_2 (a0, b0, c0);
162 hash_mix32_step_2 (a1, b1, c1);
163 hash_mix32_step_3 (a0, b0, c0);
164 hash_mix32_step_3 (a1, b1, c1);
165
166 bi0 = c0 & bucket_mask;
167 bi1 = c1 & bucket_mask;
168
169 h0 = hash_keys + bi0;
170 h1 = hash_keys + bi1;
171
172 /* Search two buckets. */
173 valid0 = qhash_get_valid_elt_mask (h, bi0);
174 valid1 = qhash_get_valid_elt_mask (h, bi1);
175
176 match0 = qhash_search_bucket (h0, k0, valid0);
177 match1 = qhash_search_bucket (h1, k1, valid1);
178
179 bi0 += qhash_min_log2 (match0);
180 bi1 += qhash_min_log2 (match1);
181
182 r[0] = match0 ? bi0 : ~0;
183 r[1] = match1 ? bi1 : ~0;
184 r += 2;
185
186 /* Full buckets trigger search of overflow hash. */
Dave Barachc3799992016-08-15 11:12:27 -0400187 if (PREDICT_FALSE (!match0 && valid0 == QHASH_ALL_VALID))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700188 {
Dave Barachc3799992016-08-15 11:12:27 -0400189 uword *p = hash_get (h->overflow_hash, k0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700190 r[-2] = p ? p[0] : ~0;
191 }
192
193 /* Full buckets trigger search of overflow hash. */
Dave Barachc3799992016-08-15 11:12:27 -0400194 if (PREDICT_FALSE (!match1 && valid1 == QHASH_ALL_VALID))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700195 {
Dave Barachc3799992016-08-15 11:12:27 -0400196 uword *p = hash_get (h->overflow_hash, k1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700197 r[-1] = p ? p[0] : ~0;
198 }
199 }
200
201 while (n_left >= 1)
202 {
203 u32 a0, b0, c0, bi0, valid0, match0;
Dave Barachc3799992016-08-15 11:12:27 -0400204 uword k0, *h0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700205
206 k0 = k[0];
207 n_left -= 1;
208 k += 1;
209
210 a0 = h->hash_seeds[0];
211 b0 = h->hash_seeds[1];
212 c0 = h->hash_seeds[2];
213 a0 ^= k0;
214#if uword_bits == 64
215 b0 ^= k0 >> 32;
216#endif
217
218 hash_mix32 (a0, b0, c0);
219
220 bi0 = c0 & bucket_mask;
221
222 h0 = hash_keys + bi0;
223
224 /* Search one bucket. */
225 valid0 = qhash_get_valid_elt_mask (h, bi0);
226 match0 = qhash_search_bucket (h0, k0, valid0);
227
228 bi0 += qhash_min_log2 (match0);
229
230 r[0] = match0 ? bi0 : ~0;
231 r += 1;
232
233 /* Full buckets trigger search of overflow hash. */
Dave Barachc3799992016-08-15 11:12:27 -0400234 if (PREDICT_FALSE (!match0 && valid0 == QHASH_ALL_VALID))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700235 {
Dave Barachc3799992016-08-15 11:12:27 -0400236 uword *p = hash_get (h->overflow_hash, k0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700237 r[-1] = p ? p[0] : ~0;
238 }
239 }
240}
241
242/* Lookup multiple keys in the same hash table.
243 Returns index of first matching key. */
244u32
Dave Barachc3799992016-08-15 11:12:27 -0400245qhash_get_first_match (void *v,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700246 uword * search_keys,
Dave Barachc3799992016-08-15 11:12:27 -0400247 uword n_search_keys, uword * matching_key)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700248{
Dave Barachc3799992016-08-15 11:12:27 -0400249 qhash_t *h = qhash_header (v);
250 uword *k, *hash_keys;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700251 uword n_left, match_mask, bucket_mask;
252
Dave Barachc3799992016-08-15 11:12:27 -0400253 if (!v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700254 return ~0;
255
256 match_mask = 0;
Dave Barachc3799992016-08-15 11:12:27 -0400257 bucket_mask = pow2_mask (h->log2_hash_size) & ~(QHASH_KEYS_PER_BUCKET - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700258
259 k = search_keys;
260 n_left = n_search_keys;
261 hash_keys = h->hash_keys;
262 while (n_left >= 2)
263 {
264 u32 a0, b0, c0, bi0, valid0;
265 u32 a1, b1, c1, bi1, valid1;
Dave Barachc3799992016-08-15 11:12:27 -0400266 uword k0, k1, *h0, *h1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700267
268 k0 = k[0];
269 k1 = k[1];
270 n_left -= 2;
271 k += 2;
272
273 a0 = a1 = h->hash_seeds[0];
274 b0 = b1 = h->hash_seeds[1];
275 c0 = c1 = h->hash_seeds[2];
276 a0 ^= k0;
277 a1 ^= k1;
278#if uword_bits == 64
279 b0 ^= k0 >> 32;
280 b1 ^= k1 >> 32;
281#endif
Dave Barachc3799992016-08-15 11:12:27 -0400282
Ed Warnickecb9cada2015-12-08 15:45:58 -0700283 hash_mix32_step_1 (a0, b0, c0);
284 hash_mix32_step_1 (a1, b1, c1);
285 hash_mix32_step_2 (a0, b0, c0);
286 hash_mix32_step_2 (a1, b1, c1);
287 hash_mix32_step_3 (a0, b0, c0);
288 hash_mix32_step_3 (a1, b1, c1);
289
290 bi0 = c0 & bucket_mask;
291 bi1 = c1 & bucket_mask;
292
293 h0 = hash_keys + bi0;
294 h1 = hash_keys + bi1;
295
296 /* Search two buckets. */
297 valid0 = qhash_get_valid_elt_mask (h, bi0);
298 valid1 = qhash_get_valid_elt_mask (h, bi1);
299 match_mask = qhash_search_bucket (h0, k0, valid0);
300 match_mask |= (qhash_search_bucket (h1, k1, valid1)
301 << QHASH_KEYS_PER_BUCKET);
302 if (match_mask)
303 {
304 uword bi, is_match1;
305
306 bi = qhash_min_log2 (match_mask);
307 is_match1 = bi >= QHASH_KEYS_PER_BUCKET;
308
309 bi += ((is_match1 ? bi1 : bi0)
310 - (is_match1 << QHASH_LOG2_KEYS_PER_BUCKET));
311 *matching_key = (k - 2 - search_keys) + is_match1;
312 return bi;
313 }
314
315 /* Full buckets trigger search of overflow hash. */
316 if (PREDICT_FALSE (valid0 == QHASH_ALL_VALID
317 || valid1 == QHASH_ALL_VALID))
318 {
Dave Barachc3799992016-08-15 11:12:27 -0400319 uword *p = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700320 uword ki = k - 2 - search_keys;
321
322 if (valid0 == QHASH_ALL_VALID)
323 p = hash_get (h->overflow_hash, k0);
324
Dave Barachc3799992016-08-15 11:12:27 -0400325 if (!p && valid1 == QHASH_ALL_VALID)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700326 {
327 p = hash_get (h->overflow_hash, k1);
328 ki++;
329 }
330
331 if (p)
332 {
333 *matching_key = ki;
334 return p[0];
335 }
336 }
337 }
338
339 while (n_left >= 1)
340 {
341 u32 a0, b0, c0, bi0, valid0;
Dave Barachc3799992016-08-15 11:12:27 -0400342 uword k0, *h0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700343
344 k0 = k[0];
345 n_left -= 1;
346 k += 1;
347
348 a0 = h->hash_seeds[0];
349 b0 = h->hash_seeds[1];
350 c0 = h->hash_seeds[2];
351 a0 ^= k0;
352#if uword_bits == 64
353 b0 ^= k0 >> 32;
354#endif
355
356 hash_mix32 (a0, b0, c0);
357
358 bi0 = c0 & bucket_mask;
359
360 h0 = hash_keys + bi0;
361
362 /* Search one bucket. */
363 valid0 = qhash_get_valid_elt_mask (h, bi0);
364 match_mask = qhash_search_bucket (h0, k0, valid0);
365 if (match_mask)
366 {
367 uword bi;
368 bi = bi0 + qhash_min_log2 (match_mask);
369 *matching_key = (k - 1 - search_keys);
370 return bi;
371 }
372
373 /* Full buckets trigger search of overflow hash. */
374 if (PREDICT_FALSE (valid0 == QHASH_ALL_VALID))
375 {
Dave Barachc3799992016-08-15 11:12:27 -0400376 uword *p = hash_get (h->overflow_hash, k0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700377 if (p)
378 {
379 *matching_key = (k - 1 - search_keys);
380 return p[0];
381 }
382 }
383 }
384
385 return ~0;
386}
387
388static void *
Dave Barachc3799992016-08-15 11:12:27 -0400389qhash_set_overflow (void *v, uword elt_bytes,
390 uword key, uword bi, uword * n_elts, u32 * result)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700391{
Dave Barachc3799992016-08-15 11:12:27 -0400392 qhash_t *h = qhash_header (v);
393 uword *p = hash_get (h->overflow_hash, key);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700394 uword i;
395
396 bi /= QHASH_KEYS_PER_BUCKET;
397
398 if (p)
399 i = p[0];
400 else
401 {
402 uword l = vec_len (h->overflow_free_indices);
403 if (l > 0)
404 {
405 i = h->overflow_free_indices[l - 1];
406 _vec_len (h->overflow_free_indices) = l - 1;
407 }
408 else
409 i = (1 << h->log2_hash_size) + hash_elts (h->overflow_hash);
410 hash_set (h->overflow_hash, key, i);
411 vec_validate (h->overflow_counts, bi);
412 h->overflow_counts[bi] += 1;
413 *n_elts += 1;
414
415 l = vec_len (v);
416 if (i >= l)
417 {
418 uword dl = round_pow2 (1 + i - l, 8);
Dave Barachc3799992016-08-15 11:12:27 -0400419 v = _vec_resize (v, dl, (l + dl) * elt_bytes, sizeof (h[0]),
Ed Warnickecb9cada2015-12-08 15:45:58 -0700420 /* align */ sizeof (uword));
Dave Barachb7b92992018-10-17 10:38:51 -0400421 clib_memset (v + l * elt_bytes, ~0, dl * elt_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700422 }
423 }
424
425 *result = i;
426
427 return v;
428}
429
430static uword
Dave Barachc3799992016-08-15 11:12:27 -0400431qhash_unset_overflow (void *v, uword key, uword bi, uword * n_elts)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700432{
Dave Barachc3799992016-08-15 11:12:27 -0400433 qhash_t *h = qhash_header (v);
434 uword *p = hash_get (h->overflow_hash, key);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700435 uword result;
436
437 bi /= QHASH_KEYS_PER_BUCKET;
438
439 if (p)
440 {
441 result = p[0];
442 hash_unset (h->overflow_hash, key);
443 ASSERT (bi < vec_len (h->overflow_counts));
444 ASSERT (h->overflow_counts[bi] > 0);
445 ASSERT (*n_elts > 0);
446 vec_add1 (h->overflow_free_indices, result);
447 h->overflow_counts[bi] -= 1;
448 *n_elts -= 1;
449 }
450 else
451 result = ~0;
452
453 return result;
454}
455
456always_inline uword
457qhash_find_free (uword i, uword valid_mask)
Dave Barachc3799992016-08-15 11:12:27 -0400458{
459 return first_set (~valid_mask & pow2_mask (QHASH_KEYS_PER_BUCKET));
460}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700461
462void *
Dave Barachc3799992016-08-15 11:12:27 -0400463_qhash_set_multiple (void *v,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700464 uword elt_bytes,
465 uword * search_keys,
Dave Barachc3799992016-08-15 11:12:27 -0400466 uword n_search_keys, u32 * result_indices)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700467{
Dave Barachc3799992016-08-15 11:12:27 -0400468 qhash_t *h = qhash_header (v);
469 uword *k, *hash_keys;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700470 uword n_left, n_elts, bucket_mask;
Dave Barachc3799992016-08-15 11:12:27 -0400471 u32 *r;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700472
473 if (vec_len (v) < n_search_keys)
474 v = _qhash_resize (v, n_search_keys, elt_bytes);
475
476 if (qhash_min_log2 (2) != 1)
477 {
478 qhash_min_log2_init ();
479 ASSERT (qhash_min_log2 (2) == 1);
480 }
481
482 ASSERT (v != 0);
483
Dave Barachc3799992016-08-15 11:12:27 -0400484 bucket_mask = pow2_mask (h->log2_hash_size) & ~(QHASH_KEYS_PER_BUCKET - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700485
486 hash_keys = h->hash_keys;
487 k = search_keys;
488 r = result_indices;
489 n_left = n_search_keys;
490 n_elts = h->n_elts;
491
492 while (n_left >= 2)
493 {
494 u32 a0, b0, c0, bi0, match0, valid0, free0;
495 u32 a1, b1, c1, bi1, match1, valid1, free1;
Dave Barachc3799992016-08-15 11:12:27 -0400496 uword k0, *h0;
497 uword k1, *h1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700498
499 k0 = k[0];
500 k1 = k[1];
501
502 /* Keys must be unique. */
503 ASSERT (k0 != k1);
504
505 n_left -= 2;
506 k += 2;
Dave Barachc3799992016-08-15 11:12:27 -0400507
Ed Warnickecb9cada2015-12-08 15:45:58 -0700508 a0 = a1 = h->hash_seeds[0];
509 b0 = b1 = h->hash_seeds[1];
510 c0 = c1 = h->hash_seeds[2];
511 a0 ^= k0;
512 a1 ^= k1;
513#if uword_bits == 64
514 b0 ^= k0 >> 32;
515 b1 ^= k1 >> 32;
516#endif
517
518 hash_mix32_step_1 (a0, b0, c0);
519 hash_mix32_step_1 (a1, b1, c1);
520 hash_mix32_step_2 (a0, b0, c0);
521 hash_mix32_step_2 (a1, b1, c1);
522 hash_mix32_step_3 (a0, b0, c0);
523 hash_mix32_step_3 (a1, b1, c1);
524
525 bi0 = c0 & bucket_mask;
526 bi1 = c1 & bucket_mask;
527
528 h0 = hash_keys + bi0;
529 h1 = hash_keys + bi1;
530
531 /* Search two buckets. */
532 valid0 = qhash_get_valid_elt_mask (h, bi0);
533 valid1 = qhash_get_valid_elt_mask (h, bi1);
534
535 match0 = qhash_search_bucket (h0, k0, valid0);
536 match1 = qhash_search_bucket (h1, k1, valid1);
537
538 /* Find first free element starting at hash offset into bucket. */
539 free0 = qhash_find_free (c0 & (QHASH_KEYS_PER_BUCKET - 1), valid0);
540
541 valid1 = valid1 | (bi0 == bi1 ? free0 : 0);
542 free1 = qhash_find_free (c1 & (QHASH_KEYS_PER_BUCKET - 1), valid1);
543
544 n_elts += (match0 == 0) + (match1 == 0);
545
546 match0 = match0 ? match0 : free0;
547 match1 = match1 ? match1 : free1;
548
549 valid0 |= match0;
550 valid1 |= match1;
551
552 h0 += qhash_min_log2 (match0);
553 h1 += qhash_min_log2 (match1);
554
Dave Barachc3799992016-08-15 11:12:27 -0400555 if (PREDICT_FALSE (!match0 || !match1))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700556 goto slow_path2;
557
558 h0[0] = k0;
559 h1[0] = k1;
560 r[0] = h0 - hash_keys;
561 r[1] = h1 - hash_keys;
562 r += 2;
563 qhash_set_valid_elt_mask (h, bi0, valid0);
564 qhash_set_valid_elt_mask (h, bi1, valid1);
565 continue;
566
567 slow_path2:
Dave Barachc3799992016-08-15 11:12:27 -0400568 if (!match0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700569 {
570 n_elts -= 1;
571 v = qhash_set_overflow (v, elt_bytes, k0, bi0, &n_elts, &r[0]);
572 }
573 else
574 {
575 h0[0] = k0;
576 r[0] = h0 - hash_keys;
577 qhash_set_valid_elt_mask (h, bi0, valid0);
578 }
Dave Barachc3799992016-08-15 11:12:27 -0400579 if (!match1)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700580 {
581 n_elts -= 1;
582 v = qhash_set_overflow (v, elt_bytes, k1, bi1, &n_elts, &r[1]);
583 }
584 else
585 {
586 h1[0] = k1;
587 r[1] = h1 - hash_keys;
588 qhash_set_valid_elt_mask (h, bi1, valid1);
589 }
590 r += 2;
591 }
592
593 while (n_left >= 1)
594 {
595 u32 a0, b0, c0, bi0, match0, valid0, free0;
Dave Barachc3799992016-08-15 11:12:27 -0400596 uword k0, *h0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700597
598 k0 = k[0];
599 n_left -= 1;
600 k += 1;
Dave Barachc3799992016-08-15 11:12:27 -0400601
Ed Warnickecb9cada2015-12-08 15:45:58 -0700602 a0 = h->hash_seeds[0];
603 b0 = h->hash_seeds[1];
604 c0 = h->hash_seeds[2];
605 a0 ^= k0;
606#if uword_bits == 64
607 b0 ^= k0 >> 32;
608#endif
609
610 hash_mix32 (a0, b0, c0);
611
612 bi0 = c0 & bucket_mask;
613
614 h0 = hash_keys + bi0;
615
616 valid0 = qhash_get_valid_elt_mask (h, bi0);
617
618 /* Find first free element starting at hash offset into bucket. */
619 free0 = qhash_find_free (c0 & (QHASH_KEYS_PER_BUCKET - 1), valid0);
620
621 match0 = qhash_search_bucket (h0, k0, valid0);
622
623 n_elts += (match0 == 0);
624
625 match0 = match0 ? match0 : free0;
626
627 valid0 |= match0;
628
629 h0 += qhash_min_log2 (match0);
630
Dave Barachc3799992016-08-15 11:12:27 -0400631 if (PREDICT_FALSE (!match0))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700632 goto slow_path1;
633
634 h0[0] = k0;
635 r[0] = h0 - hash_keys;
636 r += 1;
637 qhash_set_valid_elt_mask (h, bi0, valid0);
638 continue;
639
640 slow_path1:
641 n_elts -= 1;
642 v = qhash_set_overflow (v, elt_bytes, k0, bi0, &n_elts, &r[0]);
643 r += 1;
644 }
645
646 h = qhash_header (v);
647 h->n_elts = n_elts;
648
649 return v;
650}
651
652static uword
Dave Barachc3799992016-08-15 11:12:27 -0400653unset_slow_path (void *v, uword elt_bytes,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700654 uword k0, uword bi0, uword valid0, uword match0,
655 uword * n_elts)
656{
Dave Barachc3799992016-08-15 11:12:27 -0400657 qhash_t *h = qhash_header (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700658 uword i, j = 0, k, l, t = ~0;
Dave Barachc3799992016-08-15 11:12:27 -0400659 hash_pair_t *p, *found;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700660
Dave Barachc3799992016-08-15 11:12:27 -0400661 if (!match0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700662 {
663 if (valid0 == QHASH_ALL_VALID)
664 t = qhash_unset_overflow (v, k0, bi0, n_elts);
665 return t;
666 }
667
668 i = bi0 / QHASH_KEYS_PER_BUCKET;
669 t = bi0 + qhash_min_log2 (match0);
670
671 if (valid0 == QHASH_ALL_VALID
Dave Barachc3799992016-08-15 11:12:27 -0400672 && i < vec_len (h->overflow_counts) && h->overflow_counts[i] > 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700673 {
674 found = 0;
Dave Barachc3799992016-08-15 11:12:27 -0400675 /* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700676 hash_foreach_pair (p, h->overflow_hash, ({
677 j = qhash_hash_mix (h, p->key) / QHASH_KEYS_PER_BUCKET;
678 if (j == i)
679 {
680 found = p;
681 break;
682 }
683 }));
Dave Barachc3799992016-08-15 11:12:27 -0400684 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700685 ASSERT (found != 0);
686 ASSERT (j == i);
687
688 l = found->value[0];
689 k = found->key;
690 hash_unset3 (h->overflow_hash, k, &j);
691 vec_add1 (h->overflow_free_indices, j);
692 h->overflow_counts[i] -= 1;
693
694 qhash_set_valid_elt_mask (h, bi0, valid0);
695
696 h->hash_keys[t] = k;
Dave Barachc3799992016-08-15 11:12:27 -0400697 clib_memswap (v + t * elt_bytes, v + l * elt_bytes, elt_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700698 t = l;
699 }
700 else
701 qhash_set_valid_elt_mask (h, bi0, valid0 ^ match0);
702
703 return t;
704}
705
706void
Dave Barachc3799992016-08-15 11:12:27 -0400707_qhash_unset_multiple (void *v,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700708 uword elt_bytes,
709 uword * search_keys,
Dave Barachc3799992016-08-15 11:12:27 -0400710 uword n_search_keys, u32 * result_indices)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700711{
Dave Barachc3799992016-08-15 11:12:27 -0400712 qhash_t *h = qhash_header (v);
713 uword *k, *hash_keys;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700714 uword n_left, n_elts, bucket_mask;
Dave Barachc3799992016-08-15 11:12:27 -0400715 u32 *r;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700716
Dave Barachc3799992016-08-15 11:12:27 -0400717 if (!v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700718 {
719 uword i;
720 for (i = 0; i < n_search_keys; i++)
721 result_indices[i] = ~0;
722 }
723
Dave Barachc3799992016-08-15 11:12:27 -0400724 bucket_mask = pow2_mask (h->log2_hash_size) & ~(QHASH_KEYS_PER_BUCKET - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700725
726 hash_keys = h->hash_keys;
727 k = search_keys;
728 r = result_indices;
729 n_left = n_search_keys;
730 n_elts = h->n_elts;
731
732 while (n_left >= 2)
733 {
734 u32 a0, b0, c0, bi0, match0, valid0;
735 u32 a1, b1, c1, bi1, match1, valid1;
Dave Barachc3799992016-08-15 11:12:27 -0400736 uword k0, *h0;
737 uword k1, *h1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700738
739 k0 = k[0];
740 k1 = k[1];
741
742 /* Keys must be unique. */
743 ASSERT (k0 != k1);
744
745 n_left -= 2;
746 k += 2;
Dave Barachc3799992016-08-15 11:12:27 -0400747
Ed Warnickecb9cada2015-12-08 15:45:58 -0700748 a0 = a1 = h->hash_seeds[0];
749 b0 = b1 = h->hash_seeds[1];
750 c0 = c1 = h->hash_seeds[2];
751 a0 ^= k0;
752 a1 ^= k1;
753#if uword_bits == 64
754 b0 ^= k0 >> 32;
755 b1 ^= k1 >> 32;
756#endif
757
758 hash_mix32_step_1 (a0, b0, c0);
759 hash_mix32_step_1 (a1, b1, c1);
760 hash_mix32_step_2 (a0, b0, c0);
761 hash_mix32_step_2 (a1, b1, c1);
762 hash_mix32_step_3 (a0, b0, c0);
763 hash_mix32_step_3 (a1, b1, c1);
764
765 bi0 = c0 & bucket_mask;
766 bi1 = c1 & bucket_mask;
767
768 h0 = hash_keys + bi0;
769 h1 = hash_keys + bi1;
770
771 /* Search two buckets. */
772 valid0 = qhash_get_valid_elt_mask (h, bi0);
773 valid1 = qhash_get_valid_elt_mask (h, bi1);
774
775 match0 = qhash_search_bucket (h0, k0, valid0);
776 match1 = qhash_search_bucket (h1, k1, valid1);
777
778 n_elts -= (match0 != 0) + (match1 != 0);
779
780 if (PREDICT_FALSE (valid0 == QHASH_ALL_VALID
781 || valid1 == QHASH_ALL_VALID))
782 goto slow_path2;
783
784 valid0 ^= match0;
785 qhash_set_valid_elt_mask (h, bi0, valid0);
786
787 valid1 = bi0 == bi1 ? valid0 : valid1;
788 valid1 ^= match1;
789
790 qhash_set_valid_elt_mask (h, bi1, valid1);
791
792 r[0] = match0 ? bi0 + qhash_min_log2 (match0) : ~0;
793 r[1] = match1 ? bi1 + qhash_min_log2 (match1) : ~0;
794 r += 2;
795 continue;
796
797 slow_path2:
Dave Barachc3799992016-08-15 11:12:27 -0400798 r[0] = unset_slow_path (v, elt_bytes, k0, bi0, valid0, match0, &n_elts);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700799 if (bi0 == bi1)
800 {
801 /* Search again in same bucket to test new overflow element. */
802 valid1 = qhash_get_valid_elt_mask (h, bi0);
Dave Barachc3799992016-08-15 11:12:27 -0400803 if (!match1)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700804 {
805 match1 = qhash_search_bucket (h1, k1, valid1);
806 n_elts -= (match1 != 0);
807 }
808 }
Dave Barachc3799992016-08-15 11:12:27 -0400809 r[1] = unset_slow_path (v, elt_bytes, k1, bi1, valid1, match1, &n_elts);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700810 r += 2;
811 }
812
813 while (n_left >= 1)
814 {
815 u32 a0, b0, c0, bi0, match0, valid0;
Dave Barachc3799992016-08-15 11:12:27 -0400816 uword k0, *h0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700817
818 k0 = k[0];
819 n_left -= 1;
820 k += 1;
Dave Barachc3799992016-08-15 11:12:27 -0400821
Ed Warnickecb9cada2015-12-08 15:45:58 -0700822 a0 = h->hash_seeds[0];
823 b0 = h->hash_seeds[1];
824 c0 = h->hash_seeds[2];
825 a0 ^= k0;
826#if uword_bits == 64
827 b0 ^= k0 >> 32;
828#endif
829
830 hash_mix32 (a0, b0, c0);
831
832 bi0 = c0 & bucket_mask;
833
834 h0 = hash_keys + bi0;
835
836 valid0 = qhash_get_valid_elt_mask (h, bi0);
837
838 match0 = qhash_search_bucket (h0, k0, valid0);
839 n_elts -= (match0 != 0);
840 qhash_set_valid_elt_mask (h, bi0, valid0 ^ match0);
841
842 r[0] = match0 ? bi0 + qhash_min_log2 (match0) : ~0;
843 r += 1;
844
845 if (PREDICT_FALSE (valid0 == QHASH_ALL_VALID))
846 r[-1] = unset_slow_path (v, elt_bytes, k0, bi0, valid0, match0,
847 &n_elts);
848 }
849
850 h->n_elts = n_elts;
851}
Dave Barachc3799992016-08-15 11:12:27 -0400852
853/*
854 * fd.io coding-style-patch-verification: ON
855 *
856 * Local Variables:
857 * eval: (c-set-style "gnu")
858 * End:
859 */