blob: cfb8ceac69eb52e567809cea7d46a5d2374365be [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
2 Copyright (c) 2014 Cisco and/or its affiliates.
3
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at:
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15*/
16
Chris Luke16bcf7d2016-09-01 14:31:46 -040017/** @cond DOCUMENTATION_IS_IN_BIHASH_DOC_H */
Dave Barachdd3a57f2016-07-27 16:58:51 -040018
Dave Barachc3799992016-08-15 11:12:27 -040019/*
Ed Warnickecb9cada2015-12-08 15:45:58 -070020 * Note: to instantiate the template multiple times in a single file,
21 * #undef __included_bihash_template_h__...
22 */
23#ifndef __included_bihash_template_h__
24#define __included_bihash_template_h__
25
26#include <vppinfra/heap.h>
27#include <vppinfra/format.h>
28#include <vppinfra/pool.h>
Dave Barach30765e72018-02-23 07:45:36 -050029#include <vppinfra/cache.h>
Damjan Marion2a03efe2018-07-20 21:48:59 +020030#include <vppinfra/lock.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070031
32#ifndef BIHASH_TYPE
33#error BIHASH_TYPE not defined
34#endif
35
36#define _bv(a,b) a##b
37#define __bv(a,b) _bv(a,b)
38#define BV(a) __bv(a,BIHASH_TYPE)
39
40#define _bvt(a,b) a##b##_t
41#define __bvt(a,b) _bvt(a,b)
42#define BVT(a) __bvt(a,BIHASH_TYPE)
43
Dave Barachc3799992016-08-15 11:12:27 -040044typedef struct BV (clib_bihash_value)
45{
46 union
47 {
48 BVT (clib_bihash_kv) kvp[BIHASH_KVP_PER_PAGE];
49 struct BV (clib_bihash_value) * next_free;
Ed Warnickecb9cada2015-12-08 15:45:58 -070050 };
Dave Barachc3799992016-08-15 11:12:27 -040051} BVT (clib_bihash_value);
Ed Warnickecb9cada2015-12-08 15:45:58 -070052
Dave Barach508498f2018-07-19 12:11:16 -040053#define BIHASH_BUCKET_OFFSET_BITS 36
Dave Barach908a5ea2017-07-14 12:42:21 -040054
Dave Barachc3799992016-08-15 11:12:27 -040055typedef struct
56{
57 union
58 {
59 struct
60 {
Dave Barach508498f2018-07-19 12:11:16 -040061 u64 offset:BIHASH_BUCKET_OFFSET_BITS;
62 u64 lock:1;
Damjan Marion882fcfe2018-07-17 23:01:49 +020063 u64 linear_search:1;
64 u64 log2_pages:8;
65 i64 refcnt:16;
Ed Warnickecb9cada2015-12-08 15:45:58 -070066 };
67 u64 as_u64;
68 };
Dave Barach908a5ea2017-07-14 12:42:21 -040069} BVT (clib_bihash_bucket);
Ed Warnickecb9cada2015-12-08 15:45:58 -070070
Damjan Marion882fcfe2018-07-17 23:01:49 +020071STATIC_ASSERT_SIZEOF (BVT (clib_bihash_bucket), sizeof (u64));
Damjan Marion882fcfe2018-07-17 23:01:49 +020072
Dave Barachc3799992016-08-15 11:12:27 -040073typedef struct
74{
75 BVT (clib_bihash_value) * values;
Dave Barach908a5ea2017-07-14 12:42:21 -040076 BVT (clib_bihash_bucket) * buckets;
Dave Barach508498f2018-07-19 12:11:16 -040077 volatile u32 *alloc_lock;
Ed Warnickecb9cada2015-12-08 15:45:58 -070078
Dave Barachc3799992016-08-15 11:12:27 -040079 BVT (clib_bihash_value) ** working_copies;
Dave Barachba7ddfe2017-05-17 20:20:50 -040080 int *working_copy_lengths;
Dave Barach908a5ea2017-07-14 12:42:21 -040081 BVT (clib_bihash_bucket) saved_bucket;
Ed Warnickecb9cada2015-12-08 15:45:58 -070082
83 u32 nbuckets;
84 u32 log2_nbuckets;
Dave Barachc3799992016-08-15 11:12:27 -040085 u8 *name;
Ed Warnickecb9cada2015-12-08 15:45:58 -070086
Dave Barach908a5ea2017-07-14 12:42:21 -040087 u64 cache_hits;
88 u64 cache_misses;
89
Dave Barachc3799992016-08-15 11:12:27 -040090 BVT (clib_bihash_value) ** freelists;
Dave Barach97f5af02018-02-22 09:48:45 -050091
92 /*
Dave Barach30765e72018-02-23 07:45:36 -050093 * Backing store allocation. Since bihash manages its own
Dave Barach97f5af02018-02-22 09:48:45 -050094 * freelists, we simple dole out memory at alloc_arena_next.
95 */
96 uword alloc_arena;
97 uword alloc_arena_next;
98 uword alloc_arena_size;
Ed Warnickecb9cada2015-12-08 15:45:58 -070099
Vijayabhaskar Katamreddyfb8e61c2017-12-14 13:20:50 -0800100 /**
101 * A custom format function to print the Key and Value of bihash_key instead of default hexdump
102 */
103 format_function_t *fmt_fn;
104
Dave Barachc3799992016-08-15 11:12:27 -0400105} BVT (clib_bihash);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700106
Dave Barach508498f2018-07-19 12:11:16 -0400107static inline void BV (clib_bihash_alloc_lock) (BVT (clib_bihash) * h)
Dave Barach908a5ea2017-07-14 12:42:21 -0400108{
Dave Barach508498f2018-07-19 12:11:16 -0400109 while (__atomic_test_and_set (h->alloc_lock, __ATOMIC_ACQUIRE))
Damjan Marion2a03efe2018-07-20 21:48:59 +0200110 CLIB_PAUSE ();
Dave Barach908a5ea2017-07-14 12:42:21 -0400111}
112
Dave Barach508498f2018-07-19 12:11:16 -0400113static inline void BV (clib_bihash_alloc_unlock) (BVT (clib_bihash) * h)
Dave Barach908a5ea2017-07-14 12:42:21 -0400114{
Dave Barach508498f2018-07-19 12:11:16 -0400115 __atomic_clear (h->alloc_lock, __ATOMIC_RELEASE);
Dave Barach908a5ea2017-07-14 12:42:21 -0400116}
117
Dave Barach508498f2018-07-19 12:11:16 -0400118static inline void BV (clib_bihash_lock_bucket) (BVT (clib_bihash_bucket) * b)
Dave Barach908a5ea2017-07-14 12:42:21 -0400119{
Dave Barach508498f2018-07-19 12:11:16 -0400120 BVT (clib_bihash_bucket) unlocked_bucket, locked_bucket;
Dave Barach908a5ea2017-07-14 12:42:21 -0400121
Dave Barach508498f2018-07-19 12:11:16 -0400122 do
123 {
124 locked_bucket.as_u64 = unlocked_bucket.as_u64 = b->as_u64;
125 unlocked_bucket.lock = 0;
126 locked_bucket.lock = 1;
Damjan Marion2a03efe2018-07-20 21:48:59 +0200127 CLIB_PAUSE ();
Dave Barach508498f2018-07-19 12:11:16 -0400128 }
129 while (__atomic_compare_exchange_n (&b->as_u64, &unlocked_bucket.as_u64,
130 locked_bucket.as_u64, 1 /* weak */ ,
131 __ATOMIC_ACQUIRE,
132 __ATOMIC_ACQUIRE) == 0);
Dave Barach858c06f2017-07-21 10:44:27 -0400133}
134
135static inline void BV (clib_bihash_unlock_bucket)
136 (BVT (clib_bihash_bucket) * b)
137{
Dave Barach508498f2018-07-19 12:11:16 -0400138 CLIB_MEMORY_BARRIER ();
139 b->lock = 0;
Dave Barach908a5ea2017-07-14 12:42:21 -0400140}
141
142static inline void *BV (clib_bihash_get_value) (BVT (clib_bihash) * h,
Dave Barachc3799992016-08-15 11:12:27 -0400143 uword offset)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700144{
Dave Barach97f5af02018-02-22 09:48:45 -0500145 u8 *hp = (u8 *) h->alloc_arena;
Dave Barachc3799992016-08-15 11:12:27 -0400146 u8 *vp = hp + offset;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700147
148 return (void *) vp;
149}
150
Damjan Marion882fcfe2018-07-17 23:01:49 +0200151static inline int BV (clib_bihash_bucket_is_empty)
152 (BVT (clib_bihash_bucket) * b)
153{
Dave Barach508498f2018-07-19 12:11:16 -0400154 /* Note: applied to locked buckets, test offset */
155 return b->offset == 0;
Damjan Marion882fcfe2018-07-17 23:01:49 +0200156}
157
Dave Barach908a5ea2017-07-14 12:42:21 -0400158static inline uword BV (clib_bihash_get_offset) (BVT (clib_bihash) * h,
Dave Barachc3799992016-08-15 11:12:27 -0400159 void *v)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700160{
Dave Barachc3799992016-08-15 11:12:27 -0400161 u8 *hp, *vp;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700162
Dave Barach97f5af02018-02-22 09:48:45 -0500163 hp = (u8 *) h->alloc_arena;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700164 vp = (u8 *) v;
165
Ed Warnickecb9cada2015-12-08 15:45:58 -0700166 return vp - hp;
167}
168
Dave Barachc3799992016-08-15 11:12:27 -0400169void BV (clib_bihash_init)
170 (BVT (clib_bihash) * h, char *name, u32 nbuckets, uword memory_size);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700171
Vijayabhaskar Katamreddyfb8e61c2017-12-14 13:20:50 -0800172void BV (clib_bihash_set_kvp_format_fn) (BVT (clib_bihash) * h,
173 format_function_t * fmt_fn);
174
Dave Barachc3799992016-08-15 11:12:27 -0400175void BV (clib_bihash_free) (BVT (clib_bihash) * h);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700176
Dave Barachc3799992016-08-15 11:12:27 -0400177int BV (clib_bihash_add_del) (BVT (clib_bihash) * h,
178 BVT (clib_bihash_kv) * add_v, int is_add);
Matus Fabian828d27e2018-08-21 03:15:50 -0700179int BV (clib_bihash_add_or_overwrite_stale) (BVT (clib_bihash) * h,
180 BVT (clib_bihash_kv) * add_v,
181 int (*is_stale_cb) (BVT
182 (clib_bihash_kv)
183 *, void *),
184 void *arg);
Dave Barach908a5ea2017-07-14 12:42:21 -0400185int BV (clib_bihash_search) (BVT (clib_bihash) * h,
Dave Barachc3799992016-08-15 11:12:27 -0400186 BVT (clib_bihash_kv) * search_v,
187 BVT (clib_bihash_kv) * return_v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700188
Dave Barachc3799992016-08-15 11:12:27 -0400189void BV (clib_bihash_foreach_key_value_pair) (BVT (clib_bihash) * h,
190 void *callback, void *arg);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700191
Dave Barachc3799992016-08-15 11:12:27 -0400192format_function_t BV (format_bihash);
193format_function_t BV (format_bihash_kvp);
Dave Barach908a5ea2017-07-14 12:42:21 -0400194format_function_t BV (format_bihash_lru);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700195
Dave Barach30765e72018-02-23 07:45:36 -0500196static inline int BV (clib_bihash_search_inline_with_hash)
197 (BVT (clib_bihash) * h, u64 hash, BVT (clib_bihash_kv) * key_result)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700198{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700199 u32 bucket_index;
Dave Barachc3799992016-08-15 11:12:27 -0400200 BVT (clib_bihash_value) * v;
Dave Barach908a5ea2017-07-14 12:42:21 -0400201 BVT (clib_bihash_bucket) * b;
Dave Barach5e6b9582016-12-12 15:37:29 -0500202 int i, limit;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700203
Dave Barachc3799992016-08-15 11:12:27 -0400204 bucket_index = hash & (h->nbuckets - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700205 b = &h->buckets[bucket_index];
206
Damjan Marion882fcfe2018-07-17 23:01:49 +0200207 if (PREDICT_FALSE (BV (clib_bihash_bucket_is_empty) (b)))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700208 return -1;
209
Dave Barach508498f2018-07-19 12:11:16 -0400210 if (PREDICT_FALSE (b->lock))
Dave Barach908a5ea2017-07-14 12:42:21 -0400211 {
Dave Barach508498f2018-07-19 12:11:16 -0400212 volatile BVT (clib_bihash_bucket) * bv = b;
213 while (bv->lock)
Damjan Marion2a03efe2018-07-20 21:48:59 +0200214 CLIB_PAUSE ();
Dave Barach908a5ea2017-07-14 12:42:21 -0400215 }
216
Ed Warnickecb9cada2015-12-08 15:45:58 -0700217 hash >>= h->log2_nbuckets;
218
Dave Barachc3799992016-08-15 11:12:27 -0400219 v = BV (clib_bihash_get_value) (h, b->offset);
Dave Barachc3799992016-08-15 11:12:27 -0400220
Dave Barach5e6b9582016-12-12 15:37:29 -0500221 /* If the bucket has unresolvable collisions, use linear search */
222 limit = BIHASH_KVP_PER_PAGE;
223 v += (b->linear_search == 0) ? hash & ((1 << b->log2_pages) - 1) : 0;
224 if (PREDICT_FALSE (b->linear_search))
225 limit <<= b->log2_pages;
226
227 for (i = 0; i < limit; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700228 {
Dave Barach908a5ea2017-07-14 12:42:21 -0400229 if (BV (clib_bihash_key_compare) (v->kvp[i].key, key_result->key))
Dave Barachc3799992016-08-15 11:12:27 -0400230 {
Dave Barach908a5ea2017-07-14 12:42:21 -0400231 *key_result = v->kvp[i];
Dave Barachc3799992016-08-15 11:12:27 -0400232 return 0;
233 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700234 }
235 return -1;
236}
237
Dave Barach30765e72018-02-23 07:45:36 -0500238static inline int BV (clib_bihash_search_inline)
239 (BVT (clib_bihash) * h, BVT (clib_bihash_kv) * key_result)
240{
241 u64 hash;
242
243 hash = BV (clib_bihash_hash) (key_result);
244
245 return BV (clib_bihash_search_inline_with_hash) (h, hash, key_result);
246}
247
248static inline void BV (clib_bihash_prefetch_bucket)
249 (BVT (clib_bihash) * h, u64 hash)
250{
251 u32 bucket_index;
252 BVT (clib_bihash_bucket) * b;
253
254 bucket_index = hash & (h->nbuckets - 1);
255 b = &h->buckets[bucket_index];
256
257 CLIB_PREFETCH (b, CLIB_CACHE_LINE_BYTES, READ);
258}
259
260static inline void BV (clib_bihash_prefetch_data)
261 (BVT (clib_bihash) * h, u64 hash)
262{
263 u32 bucket_index;
264 BVT (clib_bihash_value) * v;
265 BVT (clib_bihash_bucket) * b;
266
267 bucket_index = hash & (h->nbuckets - 1);
268 b = &h->buckets[bucket_index];
269
Damjan Marion882fcfe2018-07-17 23:01:49 +0200270 if (PREDICT_FALSE (BV (clib_bihash_bucket_is_empty) (b)))
Dave Barach30765e72018-02-23 07:45:36 -0500271 return;
272
273 hash >>= h->log2_nbuckets;
274 v = BV (clib_bihash_get_value) (h, b->offset);
275
276 v += (b->linear_search == 0) ? hash & ((1 << b->log2_pages) - 1) : 0;
277
278 CLIB_PREFETCH (v, CLIB_CACHE_LINE_BYTES, READ);
279}
280
Andrew Yourtchenkoabcddcb2018-05-27 20:56:26 +0200281static inline int BV (clib_bihash_search_inline_2_with_hash)
Dave Barach908a5ea2017-07-14 12:42:21 -0400282 (BVT (clib_bihash) * h,
Andrew Yourtchenkoabcddcb2018-05-27 20:56:26 +0200283 u64 hash, BVT (clib_bihash_kv) * search_key, BVT (clib_bihash_kv) * valuep)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700284{
Ed Warnickecb9cada2015-12-08 15:45:58 -0700285 u32 bucket_index;
Dave Barachc3799992016-08-15 11:12:27 -0400286 BVT (clib_bihash_value) * v;
Dave Barach908a5ea2017-07-14 12:42:21 -0400287 BVT (clib_bihash_bucket) * b;
Dave Barach5e6b9582016-12-12 15:37:29 -0500288 int i, limit;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700289
Dave Barachc3799992016-08-15 11:12:27 -0400290 ASSERT (valuep);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700291
Dave Barachc3799992016-08-15 11:12:27 -0400292 bucket_index = hash & (h->nbuckets - 1);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700293 b = &h->buckets[bucket_index];
294
Damjan Marion882fcfe2018-07-17 23:01:49 +0200295 if (PREDICT_FALSE (BV (clib_bihash_bucket_is_empty) (b)))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700296 return -1;
297
Dave Barach508498f2018-07-19 12:11:16 -0400298 if (PREDICT_FALSE (b->lock))
Dave Barach908a5ea2017-07-14 12:42:21 -0400299 {
Dave Barach508498f2018-07-19 12:11:16 -0400300 volatile BVT (clib_bihash_bucket) * bv = b;
301 while (bv->lock)
Damjan Marion2a03efe2018-07-20 21:48:59 +0200302 CLIB_PAUSE ();
Dave Barach908a5ea2017-07-14 12:42:21 -0400303 }
304
Ed Warnickecb9cada2015-12-08 15:45:58 -0700305 hash >>= h->log2_nbuckets;
Dave Barachc3799992016-08-15 11:12:27 -0400306 v = BV (clib_bihash_get_value) (h, b->offset);
Dave Barachc3799992016-08-15 11:12:27 -0400307
Dave Barach5e6b9582016-12-12 15:37:29 -0500308 /* If the bucket has unresolvable collisions, use linear search */
309 limit = BIHASH_KVP_PER_PAGE;
310 v += (b->linear_search == 0) ? hash & ((1 << b->log2_pages) - 1) : 0;
311 if (PREDICT_FALSE (b->linear_search))
312 limit <<= b->log2_pages;
313
314 for (i = 0; i < limit; i++)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700315 {
Dave Barachc3799992016-08-15 11:12:27 -0400316 if (BV (clib_bihash_key_compare) (v->kvp[i].key, search_key->key))
317 {
318 *valuep = v->kvp[i];
319 return 0;
320 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700321 }
322 return -1;
323}
324
Andrew Yourtchenkoabcddcb2018-05-27 20:56:26 +0200325static inline int BV (clib_bihash_search_inline_2)
326 (BVT (clib_bihash) * h,
327 BVT (clib_bihash_kv) * search_key, BVT (clib_bihash_kv) * valuep)
328{
329 u64 hash;
330
331 hash = BV (clib_bihash_hash) (search_key);
332
333 return BV (clib_bihash_search_inline_2_with_hash) (h, hash, search_key,
334 valuep);
335}
336
337
Ed Warnickecb9cada2015-12-08 15:45:58 -0700338#endif /* __included_bihash_template_h__ */
Dave Barachdd3a57f2016-07-27 16:58:51 -0400339
Chris Luke16bcf7d2016-09-01 14:31:46 -0400340/** @endcond */
Dave Barachc3799992016-08-15 11:12:27 -0400341
342/*
343 * fd.io coding-style-patch-verification: ON
344 *
345 * Local Variables:
346 * eval: (c-set-style "gnu")
347 * End:
348 */