blob: f4e38c4a1d7509c4ea9dd3b06d7a4598a614d6ef [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));
64 memset (v, ~0, elt_bytes << l);
65
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 {
126 memset (result_indices, ~0, sizeof (result_indices[0]) * n_search_keys);
127 return;
128 }
129
Dave Barachc3799992016-08-15 11:12:27 -0400130 bucket_mask = pow2_mask (h->log2_hash_size) & ~(QHASH_KEYS_PER_BUCKET - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700131
132 k = search_keys;
133 n_left = n_search_keys;
134 hash_keys = h->hash_keys;
135 r = result_indices;
136
137 while (n_left >= 2)
138 {
139 u32 a0, b0, c0, bi0, valid0, match0;
140 u32 a1, b1, c1, bi1, valid1, match1;
Dave Barachc3799992016-08-15 11:12:27 -0400141 uword k0, k1, *h0, *h1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700142
143 k0 = k[0];
144 k1 = k[1];
145 n_left -= 2;
146 k += 2;
147
148 a0 = a1 = h->hash_seeds[0];
149 b0 = b1 = h->hash_seeds[1];
150 c0 = c1 = h->hash_seeds[2];
151 a0 ^= k0;
152 a1 ^= k1;
153#if uword_bits == 64
154 b0 ^= k0 >> 32;
155 b1 ^= k1 >> 32;
156#endif
Dave Barachc3799992016-08-15 11:12:27 -0400157
Ed Warnickecb9cada2015-12-08 15:45:58 -0700158 hash_mix32_step_1 (a0, b0, c0);
159 hash_mix32_step_1 (a1, b1, c1);
160 hash_mix32_step_2 (a0, b0, c0);
161 hash_mix32_step_2 (a1, b1, c1);
162 hash_mix32_step_3 (a0, b0, c0);
163 hash_mix32_step_3 (a1, b1, c1);
164
165 bi0 = c0 & bucket_mask;
166 bi1 = c1 & bucket_mask;
167
168 h0 = hash_keys + bi0;
169 h1 = hash_keys + bi1;
170
171 /* Search two buckets. */
172 valid0 = qhash_get_valid_elt_mask (h, bi0);
173 valid1 = qhash_get_valid_elt_mask (h, bi1);
174
175 match0 = qhash_search_bucket (h0, k0, valid0);
176 match1 = qhash_search_bucket (h1, k1, valid1);
177
178 bi0 += qhash_min_log2 (match0);
179 bi1 += qhash_min_log2 (match1);
180
181 r[0] = match0 ? bi0 : ~0;
182 r[1] = match1 ? bi1 : ~0;
183 r += 2;
184
185 /* Full buckets trigger search of overflow hash. */
Dave Barachc3799992016-08-15 11:12:27 -0400186 if (PREDICT_FALSE (!match0 && valid0 == QHASH_ALL_VALID))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700187 {
Dave Barachc3799992016-08-15 11:12:27 -0400188 uword *p = hash_get (h->overflow_hash, k0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700189 r[-2] = p ? p[0] : ~0;
190 }
191
192 /* Full buckets trigger search of overflow hash. */
Dave Barachc3799992016-08-15 11:12:27 -0400193 if (PREDICT_FALSE (!match1 && valid1 == QHASH_ALL_VALID))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700194 {
Dave Barachc3799992016-08-15 11:12:27 -0400195 uword *p = hash_get (h->overflow_hash, k1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700196 r[-1] = p ? p[0] : ~0;
197 }
198 }
199
200 while (n_left >= 1)
201 {
202 u32 a0, b0, c0, bi0, valid0, match0;
Dave Barachc3799992016-08-15 11:12:27 -0400203 uword k0, *h0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700204
205 k0 = k[0];
206 n_left -= 1;
207 k += 1;
208
209 a0 = h->hash_seeds[0];
210 b0 = h->hash_seeds[1];
211 c0 = h->hash_seeds[2];
212 a0 ^= k0;
213#if uword_bits == 64
214 b0 ^= k0 >> 32;
215#endif
216
217 hash_mix32 (a0, b0, c0);
218
219 bi0 = c0 & bucket_mask;
220
221 h0 = hash_keys + bi0;
222
223 /* Search one bucket. */
224 valid0 = qhash_get_valid_elt_mask (h, bi0);
225 match0 = qhash_search_bucket (h0, k0, valid0);
226
227 bi0 += qhash_min_log2 (match0);
228
229 r[0] = match0 ? bi0 : ~0;
230 r += 1;
231
232 /* Full buckets trigger search of overflow hash. */
Dave Barachc3799992016-08-15 11:12:27 -0400233 if (PREDICT_FALSE (!match0 && valid0 == QHASH_ALL_VALID))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700234 {
Dave Barachc3799992016-08-15 11:12:27 -0400235 uword *p = hash_get (h->overflow_hash, k0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700236 r[-1] = p ? p[0] : ~0;
237 }
238 }
239}
240
241/* Lookup multiple keys in the same hash table.
242 Returns index of first matching key. */
243u32
Dave Barachc3799992016-08-15 11:12:27 -0400244qhash_get_first_match (void *v,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700245 uword * search_keys,
Dave Barachc3799992016-08-15 11:12:27 -0400246 uword n_search_keys, uword * matching_key)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700247{
Dave Barachc3799992016-08-15 11:12:27 -0400248 qhash_t *h = qhash_header (v);
249 uword *k, *hash_keys;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700250 uword n_left, match_mask, bucket_mask;
251
Dave Barachc3799992016-08-15 11:12:27 -0400252 if (!v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700253 return ~0;
254
255 match_mask = 0;
Dave Barachc3799992016-08-15 11:12:27 -0400256 bucket_mask = pow2_mask (h->log2_hash_size) & ~(QHASH_KEYS_PER_BUCKET - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700257
258 k = search_keys;
259 n_left = n_search_keys;
260 hash_keys = h->hash_keys;
261 while (n_left >= 2)
262 {
263 u32 a0, b0, c0, bi0, valid0;
264 u32 a1, b1, c1, bi1, valid1;
Dave Barachc3799992016-08-15 11:12:27 -0400265 uword k0, k1, *h0, *h1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700266
267 k0 = k[0];
268 k1 = k[1];
269 n_left -= 2;
270 k += 2;
271
272 a0 = a1 = h->hash_seeds[0];
273 b0 = b1 = h->hash_seeds[1];
274 c0 = c1 = h->hash_seeds[2];
275 a0 ^= k0;
276 a1 ^= k1;
277#if uword_bits == 64
278 b0 ^= k0 >> 32;
279 b1 ^= k1 >> 32;
280#endif
Dave Barachc3799992016-08-15 11:12:27 -0400281
Ed Warnickecb9cada2015-12-08 15:45:58 -0700282 hash_mix32_step_1 (a0, b0, c0);
283 hash_mix32_step_1 (a1, b1, c1);
284 hash_mix32_step_2 (a0, b0, c0);
285 hash_mix32_step_2 (a1, b1, c1);
286 hash_mix32_step_3 (a0, b0, c0);
287 hash_mix32_step_3 (a1, b1, c1);
288
289 bi0 = c0 & bucket_mask;
290 bi1 = c1 & bucket_mask;
291
292 h0 = hash_keys + bi0;
293 h1 = hash_keys + bi1;
294
295 /* Search two buckets. */
296 valid0 = qhash_get_valid_elt_mask (h, bi0);
297 valid1 = qhash_get_valid_elt_mask (h, bi1);
298 match_mask = qhash_search_bucket (h0, k0, valid0);
299 match_mask |= (qhash_search_bucket (h1, k1, valid1)
300 << QHASH_KEYS_PER_BUCKET);
301 if (match_mask)
302 {
303 uword bi, is_match1;
304
305 bi = qhash_min_log2 (match_mask);
306 is_match1 = bi >= QHASH_KEYS_PER_BUCKET;
307
308 bi += ((is_match1 ? bi1 : bi0)
309 - (is_match1 << QHASH_LOG2_KEYS_PER_BUCKET));
310 *matching_key = (k - 2 - search_keys) + is_match1;
311 return bi;
312 }
313
314 /* Full buckets trigger search of overflow hash. */
315 if (PREDICT_FALSE (valid0 == QHASH_ALL_VALID
316 || valid1 == QHASH_ALL_VALID))
317 {
Dave Barachc3799992016-08-15 11:12:27 -0400318 uword *p = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700319 uword ki = k - 2 - search_keys;
320
321 if (valid0 == QHASH_ALL_VALID)
322 p = hash_get (h->overflow_hash, k0);
323
Dave Barachc3799992016-08-15 11:12:27 -0400324 if (!p && valid1 == QHASH_ALL_VALID)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700325 {
326 p = hash_get (h->overflow_hash, k1);
327 ki++;
328 }
329
330 if (p)
331 {
332 *matching_key = ki;
333 return p[0];
334 }
335 }
336 }
337
338 while (n_left >= 1)
339 {
340 u32 a0, b0, c0, bi0, valid0;
Dave Barachc3799992016-08-15 11:12:27 -0400341 uword k0, *h0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700342
343 k0 = k[0];
344 n_left -= 1;
345 k += 1;
346
347 a0 = h->hash_seeds[0];
348 b0 = h->hash_seeds[1];
349 c0 = h->hash_seeds[2];
350 a0 ^= k0;
351#if uword_bits == 64
352 b0 ^= k0 >> 32;
353#endif
354
355 hash_mix32 (a0, b0, c0);
356
357 bi0 = c0 & bucket_mask;
358
359 h0 = hash_keys + bi0;
360
361 /* Search one bucket. */
362 valid0 = qhash_get_valid_elt_mask (h, bi0);
363 match_mask = qhash_search_bucket (h0, k0, valid0);
364 if (match_mask)
365 {
366 uword bi;
367 bi = bi0 + qhash_min_log2 (match_mask);
368 *matching_key = (k - 1 - search_keys);
369 return bi;
370 }
371
372 /* Full buckets trigger search of overflow hash. */
373 if (PREDICT_FALSE (valid0 == QHASH_ALL_VALID))
374 {
Dave Barachc3799992016-08-15 11:12:27 -0400375 uword *p = hash_get (h->overflow_hash, k0);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700376 if (p)
377 {
378 *matching_key = (k - 1 - search_keys);
379 return p[0];
380 }
381 }
382 }
383
384 return ~0;
385}
386
387static void *
Dave Barachc3799992016-08-15 11:12:27 -0400388qhash_set_overflow (void *v, uword elt_bytes,
389 uword key, uword bi, uword * n_elts, u32 * result)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700390{
Dave Barachc3799992016-08-15 11:12:27 -0400391 qhash_t *h = qhash_header (v);
392 uword *p = hash_get (h->overflow_hash, key);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700393 uword i;
394
395 bi /= QHASH_KEYS_PER_BUCKET;
396
397 if (p)
398 i = p[0];
399 else
400 {
401 uword l = vec_len (h->overflow_free_indices);
402 if (l > 0)
403 {
404 i = h->overflow_free_indices[l - 1];
405 _vec_len (h->overflow_free_indices) = l - 1;
406 }
407 else
408 i = (1 << h->log2_hash_size) + hash_elts (h->overflow_hash);
409 hash_set (h->overflow_hash, key, i);
410 vec_validate (h->overflow_counts, bi);
411 h->overflow_counts[bi] += 1;
412 *n_elts += 1;
413
414 l = vec_len (v);
415 if (i >= l)
416 {
417 uword dl = round_pow2 (1 + i - l, 8);
Dave Barachc3799992016-08-15 11:12:27 -0400418 v = _vec_resize (v, dl, (l + dl) * elt_bytes, sizeof (h[0]),
Ed Warnickecb9cada2015-12-08 15:45:58 -0700419 /* align */ sizeof (uword));
Dave Barachc3799992016-08-15 11:12:27 -0400420 memset (v + l * elt_bytes, ~0, dl * elt_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700421 }
422 }
423
424 *result = i;
425
426 return v;
427}
428
429static uword
Dave Barachc3799992016-08-15 11:12:27 -0400430qhash_unset_overflow (void *v, uword key, uword bi, uword * n_elts)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700431{
Dave Barachc3799992016-08-15 11:12:27 -0400432 qhash_t *h = qhash_header (v);
433 uword *p = hash_get (h->overflow_hash, key);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700434 uword result;
435
436 bi /= QHASH_KEYS_PER_BUCKET;
437
438 if (p)
439 {
440 result = p[0];
441 hash_unset (h->overflow_hash, key);
442 ASSERT (bi < vec_len (h->overflow_counts));
443 ASSERT (h->overflow_counts[bi] > 0);
444 ASSERT (*n_elts > 0);
445 vec_add1 (h->overflow_free_indices, result);
446 h->overflow_counts[bi] -= 1;
447 *n_elts -= 1;
448 }
449 else
450 result = ~0;
451
452 return result;
453}
454
455always_inline uword
456qhash_find_free (uword i, uword valid_mask)
Dave Barachc3799992016-08-15 11:12:27 -0400457{
458 return first_set (~valid_mask & pow2_mask (QHASH_KEYS_PER_BUCKET));
459}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700460
461void *
Dave Barachc3799992016-08-15 11:12:27 -0400462_qhash_set_multiple (void *v,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700463 uword elt_bytes,
464 uword * search_keys,
Dave Barachc3799992016-08-15 11:12:27 -0400465 uword n_search_keys, u32 * result_indices)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700466{
Dave Barachc3799992016-08-15 11:12:27 -0400467 qhash_t *h = qhash_header (v);
468 uword *k, *hash_keys;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700469 uword n_left, n_elts, bucket_mask;
Dave Barachc3799992016-08-15 11:12:27 -0400470 u32 *r;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700471
472 if (vec_len (v) < n_search_keys)
473 v = _qhash_resize (v, n_search_keys, elt_bytes);
474
475 if (qhash_min_log2 (2) != 1)
476 {
477 qhash_min_log2_init ();
478 ASSERT (qhash_min_log2 (2) == 1);
479 }
480
481 ASSERT (v != 0);
482
Dave Barachc3799992016-08-15 11:12:27 -0400483 bucket_mask = pow2_mask (h->log2_hash_size) & ~(QHASH_KEYS_PER_BUCKET - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700484
485 hash_keys = h->hash_keys;
486 k = search_keys;
487 r = result_indices;
488 n_left = n_search_keys;
489 n_elts = h->n_elts;
490
491 while (n_left >= 2)
492 {
493 u32 a0, b0, c0, bi0, match0, valid0, free0;
494 u32 a1, b1, c1, bi1, match1, valid1, free1;
Dave Barachc3799992016-08-15 11:12:27 -0400495 uword k0, *h0;
496 uword k1, *h1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700497
498 k0 = k[0];
499 k1 = k[1];
500
501 /* Keys must be unique. */
502 ASSERT (k0 != k1);
503
504 n_left -= 2;
505 k += 2;
Dave Barachc3799992016-08-15 11:12:27 -0400506
Ed Warnickecb9cada2015-12-08 15:45:58 -0700507 a0 = a1 = h->hash_seeds[0];
508 b0 = b1 = h->hash_seeds[1];
509 c0 = c1 = h->hash_seeds[2];
510 a0 ^= k0;
511 a1 ^= k1;
512#if uword_bits == 64
513 b0 ^= k0 >> 32;
514 b1 ^= k1 >> 32;
515#endif
516
517 hash_mix32_step_1 (a0, b0, c0);
518 hash_mix32_step_1 (a1, b1, c1);
519 hash_mix32_step_2 (a0, b0, c0);
520 hash_mix32_step_2 (a1, b1, c1);
521 hash_mix32_step_3 (a0, b0, c0);
522 hash_mix32_step_3 (a1, b1, c1);
523
524 bi0 = c0 & bucket_mask;
525 bi1 = c1 & bucket_mask;
526
527 h0 = hash_keys + bi0;
528 h1 = hash_keys + bi1;
529
530 /* Search two buckets. */
531 valid0 = qhash_get_valid_elt_mask (h, bi0);
532 valid1 = qhash_get_valid_elt_mask (h, bi1);
533
534 match0 = qhash_search_bucket (h0, k0, valid0);
535 match1 = qhash_search_bucket (h1, k1, valid1);
536
537 /* Find first free element starting at hash offset into bucket. */
538 free0 = qhash_find_free (c0 & (QHASH_KEYS_PER_BUCKET - 1), valid0);
539
540 valid1 = valid1 | (bi0 == bi1 ? free0 : 0);
541 free1 = qhash_find_free (c1 & (QHASH_KEYS_PER_BUCKET - 1), valid1);
542
543 n_elts += (match0 == 0) + (match1 == 0);
544
545 match0 = match0 ? match0 : free0;
546 match1 = match1 ? match1 : free1;
547
548 valid0 |= match0;
549 valid1 |= match1;
550
551 h0 += qhash_min_log2 (match0);
552 h1 += qhash_min_log2 (match1);
553
Dave Barachc3799992016-08-15 11:12:27 -0400554 if (PREDICT_FALSE (!match0 || !match1))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700555 goto slow_path2;
556
557 h0[0] = k0;
558 h1[0] = k1;
559 r[0] = h0 - hash_keys;
560 r[1] = h1 - hash_keys;
561 r += 2;
562 qhash_set_valid_elt_mask (h, bi0, valid0);
563 qhash_set_valid_elt_mask (h, bi1, valid1);
564 continue;
565
566 slow_path2:
Dave Barachc3799992016-08-15 11:12:27 -0400567 if (!match0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700568 {
569 n_elts -= 1;
570 v = qhash_set_overflow (v, elt_bytes, k0, bi0, &n_elts, &r[0]);
571 }
572 else
573 {
574 h0[0] = k0;
575 r[0] = h0 - hash_keys;
576 qhash_set_valid_elt_mask (h, bi0, valid0);
577 }
Dave Barachc3799992016-08-15 11:12:27 -0400578 if (!match1)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700579 {
580 n_elts -= 1;
581 v = qhash_set_overflow (v, elt_bytes, k1, bi1, &n_elts, &r[1]);
582 }
583 else
584 {
585 h1[0] = k1;
586 r[1] = h1 - hash_keys;
587 qhash_set_valid_elt_mask (h, bi1, valid1);
588 }
589 r += 2;
590 }
591
592 while (n_left >= 1)
593 {
594 u32 a0, b0, c0, bi0, match0, valid0, free0;
Dave Barachc3799992016-08-15 11:12:27 -0400595 uword k0, *h0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700596
597 k0 = k[0];
598 n_left -= 1;
599 k += 1;
Dave Barachc3799992016-08-15 11:12:27 -0400600
Ed Warnickecb9cada2015-12-08 15:45:58 -0700601 a0 = h->hash_seeds[0];
602 b0 = h->hash_seeds[1];
603 c0 = h->hash_seeds[2];
604 a0 ^= k0;
605#if uword_bits == 64
606 b0 ^= k0 >> 32;
607#endif
608
609 hash_mix32 (a0, b0, c0);
610
611 bi0 = c0 & bucket_mask;
612
613 h0 = hash_keys + bi0;
614
615 valid0 = qhash_get_valid_elt_mask (h, bi0);
616
617 /* Find first free element starting at hash offset into bucket. */
618 free0 = qhash_find_free (c0 & (QHASH_KEYS_PER_BUCKET - 1), valid0);
619
620 match0 = qhash_search_bucket (h0, k0, valid0);
621
622 n_elts += (match0 == 0);
623
624 match0 = match0 ? match0 : free0;
625
626 valid0 |= match0;
627
628 h0 += qhash_min_log2 (match0);
629
Dave Barachc3799992016-08-15 11:12:27 -0400630 if (PREDICT_FALSE (!match0))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700631 goto slow_path1;
632
633 h0[0] = k0;
634 r[0] = h0 - hash_keys;
635 r += 1;
636 qhash_set_valid_elt_mask (h, bi0, valid0);
637 continue;
638
639 slow_path1:
640 n_elts -= 1;
641 v = qhash_set_overflow (v, elt_bytes, k0, bi0, &n_elts, &r[0]);
642 r += 1;
643 }
644
645 h = qhash_header (v);
646 h->n_elts = n_elts;
647
648 return v;
649}
650
651static uword
Dave Barachc3799992016-08-15 11:12:27 -0400652unset_slow_path (void *v, uword elt_bytes,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700653 uword k0, uword bi0, uword valid0, uword match0,
654 uword * n_elts)
655{
Dave Barachc3799992016-08-15 11:12:27 -0400656 qhash_t *h = qhash_header (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700657 uword i, j = 0, k, l, t = ~0;
Dave Barachc3799992016-08-15 11:12:27 -0400658 hash_pair_t *p, *found;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700659
Dave Barachc3799992016-08-15 11:12:27 -0400660 if (!match0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700661 {
662 if (valid0 == QHASH_ALL_VALID)
663 t = qhash_unset_overflow (v, k0, bi0, n_elts);
664 return t;
665 }
666
667 i = bi0 / QHASH_KEYS_PER_BUCKET;
668 t = bi0 + qhash_min_log2 (match0);
669
670 if (valid0 == QHASH_ALL_VALID
Dave Barachc3799992016-08-15 11:12:27 -0400671 && i < vec_len (h->overflow_counts) && h->overflow_counts[i] > 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700672 {
673 found = 0;
Dave Barachc3799992016-08-15 11:12:27 -0400674 /* *INDENT-OFF* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700675 hash_foreach_pair (p, h->overflow_hash, ({
676 j = qhash_hash_mix (h, p->key) / QHASH_KEYS_PER_BUCKET;
677 if (j == i)
678 {
679 found = p;
680 break;
681 }
682 }));
Dave Barachc3799992016-08-15 11:12:27 -0400683 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -0700684 ASSERT (found != 0);
685 ASSERT (j == i);
686
687 l = found->value[0];
688 k = found->key;
689 hash_unset3 (h->overflow_hash, k, &j);
690 vec_add1 (h->overflow_free_indices, j);
691 h->overflow_counts[i] -= 1;
692
693 qhash_set_valid_elt_mask (h, bi0, valid0);
694
695 h->hash_keys[t] = k;
Dave Barachc3799992016-08-15 11:12:27 -0400696 clib_memswap (v + t * elt_bytes, v + l * elt_bytes, elt_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700697 t = l;
698 }
699 else
700 qhash_set_valid_elt_mask (h, bi0, valid0 ^ match0);
701
702 return t;
703}
704
705void
Dave Barachc3799992016-08-15 11:12:27 -0400706_qhash_unset_multiple (void *v,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700707 uword elt_bytes,
708 uword * search_keys,
Dave Barachc3799992016-08-15 11:12:27 -0400709 uword n_search_keys, u32 * result_indices)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700710{
Dave Barachc3799992016-08-15 11:12:27 -0400711 qhash_t *h = qhash_header (v);
712 uword *k, *hash_keys;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700713 uword n_left, n_elts, bucket_mask;
Dave Barachc3799992016-08-15 11:12:27 -0400714 u32 *r;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700715
Dave Barachc3799992016-08-15 11:12:27 -0400716 if (!v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700717 {
718 uword i;
719 for (i = 0; i < n_search_keys; i++)
720 result_indices[i] = ~0;
721 }
722
Dave Barachc3799992016-08-15 11:12:27 -0400723 bucket_mask = pow2_mask (h->log2_hash_size) & ~(QHASH_KEYS_PER_BUCKET - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700724
725 hash_keys = h->hash_keys;
726 k = search_keys;
727 r = result_indices;
728 n_left = n_search_keys;
729 n_elts = h->n_elts;
730
731 while (n_left >= 2)
732 {
733 u32 a0, b0, c0, bi0, match0, valid0;
734 u32 a1, b1, c1, bi1, match1, valid1;
Dave Barachc3799992016-08-15 11:12:27 -0400735 uword k0, *h0;
736 uword k1, *h1;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700737
738 k0 = k[0];
739 k1 = k[1];
740
741 /* Keys must be unique. */
742 ASSERT (k0 != k1);
743
744 n_left -= 2;
745 k += 2;
Dave Barachc3799992016-08-15 11:12:27 -0400746
Ed Warnickecb9cada2015-12-08 15:45:58 -0700747 a0 = a1 = h->hash_seeds[0];
748 b0 = b1 = h->hash_seeds[1];
749 c0 = c1 = h->hash_seeds[2];
750 a0 ^= k0;
751 a1 ^= k1;
752#if uword_bits == 64
753 b0 ^= k0 >> 32;
754 b1 ^= k1 >> 32;
755#endif
756
757 hash_mix32_step_1 (a0, b0, c0);
758 hash_mix32_step_1 (a1, b1, c1);
759 hash_mix32_step_2 (a0, b0, c0);
760 hash_mix32_step_2 (a1, b1, c1);
761 hash_mix32_step_3 (a0, b0, c0);
762 hash_mix32_step_3 (a1, b1, c1);
763
764 bi0 = c0 & bucket_mask;
765 bi1 = c1 & bucket_mask;
766
767 h0 = hash_keys + bi0;
768 h1 = hash_keys + bi1;
769
770 /* Search two buckets. */
771 valid0 = qhash_get_valid_elt_mask (h, bi0);
772 valid1 = qhash_get_valid_elt_mask (h, bi1);
773
774 match0 = qhash_search_bucket (h0, k0, valid0);
775 match1 = qhash_search_bucket (h1, k1, valid1);
776
777 n_elts -= (match0 != 0) + (match1 != 0);
778
779 if (PREDICT_FALSE (valid0 == QHASH_ALL_VALID
780 || valid1 == QHASH_ALL_VALID))
781 goto slow_path2;
782
783 valid0 ^= match0;
784 qhash_set_valid_elt_mask (h, bi0, valid0);
785
786 valid1 = bi0 == bi1 ? valid0 : valid1;
787 valid1 ^= match1;
788
789 qhash_set_valid_elt_mask (h, bi1, valid1);
790
791 r[0] = match0 ? bi0 + qhash_min_log2 (match0) : ~0;
792 r[1] = match1 ? bi1 + qhash_min_log2 (match1) : ~0;
793 r += 2;
794 continue;
795
796 slow_path2:
Dave Barachc3799992016-08-15 11:12:27 -0400797 r[0] = unset_slow_path (v, elt_bytes, k0, bi0, valid0, match0, &n_elts);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700798 if (bi0 == bi1)
799 {
800 /* Search again in same bucket to test new overflow element. */
801 valid1 = qhash_get_valid_elt_mask (h, bi0);
Dave Barachc3799992016-08-15 11:12:27 -0400802 if (!match1)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700803 {
804 match1 = qhash_search_bucket (h1, k1, valid1);
805 n_elts -= (match1 != 0);
806 }
807 }
Dave Barachc3799992016-08-15 11:12:27 -0400808 r[1] = unset_slow_path (v, elt_bytes, k1, bi1, valid1, match1, &n_elts);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700809 r += 2;
810 }
811
812 while (n_left >= 1)
813 {
814 u32 a0, b0, c0, bi0, match0, valid0;
Dave Barachc3799992016-08-15 11:12:27 -0400815 uword k0, *h0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700816
817 k0 = k[0];
818 n_left -= 1;
819 k += 1;
Dave Barachc3799992016-08-15 11:12:27 -0400820
Ed Warnickecb9cada2015-12-08 15:45:58 -0700821 a0 = h->hash_seeds[0];
822 b0 = h->hash_seeds[1];
823 c0 = h->hash_seeds[2];
824 a0 ^= k0;
825#if uword_bits == 64
826 b0 ^= k0 >> 32;
827#endif
828
829 hash_mix32 (a0, b0, c0);
830
831 bi0 = c0 & bucket_mask;
832
833 h0 = hash_keys + bi0;
834
835 valid0 = qhash_get_valid_elt_mask (h, bi0);
836
837 match0 = qhash_search_bucket (h0, k0, valid0);
838 n_elts -= (match0 != 0);
839 qhash_set_valid_elt_mask (h, bi0, valid0 ^ match0);
840
841 r[0] = match0 ? bi0 + qhash_min_log2 (match0) : ~0;
842 r += 1;
843
844 if (PREDICT_FALSE (valid0 == QHASH_ALL_VALID))
845 r[-1] = unset_slow_path (v, elt_bytes, k0, bi0, valid0, match0,
846 &n_elts);
847 }
848
849 h->n_elts = n_elts;
850}
Dave Barachc3799992016-08-15 11:12:27 -0400851
852/*
853 * fd.io coding-style-patch-verification: ON
854 *
855 * Local Variables:
856 * eval: (c-set-style "gnu")
857 * End:
858 */