get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/patches/52130/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 52130,
    "url": "http://patches.dpdk.org/api/patches/52130/?format=api",
    "web_url": "http://patches.dpdk.org/project/dpdk/patch/20190402194455.9269-2-dharmik.thakkar@arm.com/",
    "project": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/projects/1/?format=api",
        "name": "DPDK",
        "link_name": "dpdk",
        "list_id": "dev.dpdk.org",
        "list_email": "dev@dpdk.org",
        "web_url": "http://core.dpdk.org",
        "scm_url": "git://dpdk.org/dpdk",
        "webscm_url": "http://git.dpdk.org/dpdk",
        "list_archive_url": "https://inbox.dpdk.org/dev",
        "list_archive_url_format": "https://inbox.dpdk.org/dev/{}",
        "commit_url_format": ""
    },
    "msgid": "<20190402194455.9269-2-dharmik.thakkar@arm.com>",
    "list_archive_url": "https://inbox.dpdk.org/dev/20190402194455.9269-2-dharmik.thakkar@arm.com",
    "date": "2019-04-02T19:44:54",
    "name": "[v5,1/2] hash: add lock free support for extendable bucket",
    "commit_ref": null,
    "pull_url": null,
    "state": "accepted",
    "archived": true,
    "hash": "e219d10af1fa9dafd85af9a09f229e51a69dfaf8",
    "submitter": {
        "id": 1108,
        "url": "http://patches.dpdk.org/api/people/1108/?format=api",
        "name": "Dharmik Thakkar",
        "email": "dharmik.thakkar@arm.com"
    },
    "delegate": {
        "id": 1,
        "url": "http://patches.dpdk.org/api/users/1/?format=api",
        "username": "tmonjalo",
        "first_name": "Thomas",
        "last_name": "Monjalon",
        "email": "thomas@monjalon.net"
    },
    "mbox": "http://patches.dpdk.org/project/dpdk/patch/20190402194455.9269-2-dharmik.thakkar@arm.com/mbox/",
    "series": [
        {
            "id": 4070,
            "url": "http://patches.dpdk.org/api/series/4070/?format=api",
            "web_url": "http://patches.dpdk.org/project/dpdk/list/?series=4070",
            "date": "2019-04-02T19:44:53",
            "name": "hash: add lock free support for ext bkt",
            "version": 5,
            "mbox": "http://patches.dpdk.org/series/4070/mbox/"
        }
    ],
    "comments": "http://patches.dpdk.org/api/patches/52130/comments/",
    "check": "success",
    "checks": "http://patches.dpdk.org/api/patches/52130/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "<dev-bounces@dpdk.org>",
        "X-Original-To": "patchwork@dpdk.org",
        "Delivered-To": "patchwork@dpdk.org",
        "Received": [
            "from [92.243.14.124] (localhost [127.0.0.1])\n\tby dpdk.org (Postfix) with ESMTP id 5A5F71B12B;\n\tTue,  2 Apr 2019 21:45:17 +0200 (CEST)",
            "from foss.arm.com (foss.arm.com [217.140.101.70])\n\tby dpdk.org (Postfix) with ESMTP id 47E517D52\n\tfor <dev@dpdk.org>; Tue,  2 Apr 2019 21:45:13 +0200 (CEST)",
            "from usa-sjc-imap-foss1.foss.arm.com (unknown [10.72.51.249])\n\tby usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id B0A3D15AD;\n\tTue,  2 Apr 2019 12:45:12 -0700 (PDT)",
            "from dp6132.austin.arm.com (dp6132.austin.arm.com [10.118.12.38])\n\tby usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id\n\t417303F68F; Tue,  2 Apr 2019 12:45:12 -0700 (PDT)"
        ],
        "From": "Dharmik Thakkar <dharmik.thakkar@arm.com>",
        "To": "Yipeng Wang <yipeng1.wang@intel.com>,\n\tSameh Gobriel <sameh.gobriel@intel.com>,\n\tBruce Richardson <bruce.richardson@intel.com>,\n\tPablo de Lara <pablo.de.lara.guarch@intel.com>,\n\tJohn McNamara <john.mcnamara@intel.com>,\n\tMarko Kovacevic <marko.kovacevic@intel.com>",
        "Cc": "dev@dpdk.org, honnappa.nagarahalli@arm.com,\n\tDharmik Thakkar <dharmik.thakkar@arm.com>",
        "Date": "Tue,  2 Apr 2019 19:44:54 +0000",
        "Message-Id": "<20190402194455.9269-2-dharmik.thakkar@arm.com>",
        "X-Mailer": "git-send-email 2.17.1",
        "In-Reply-To": "<20190402194455.9269-1-dharmik.thakkar@arm.com>",
        "References": "<20190401230830.17931-1-dharmik.thakkar@arm.com>\n\t<20190402194455.9269-1-dharmik.thakkar@arm.com>",
        "Subject": "[dpdk-dev] [PATCH v5 1/2] hash: add lock free support for\n\textendable bucket",
        "X-BeenThere": "dev@dpdk.org",
        "X-Mailman-Version": "2.1.15",
        "Precedence": "list",
        "List-Id": "DPDK patches and discussions <dev.dpdk.org>",
        "List-Unsubscribe": "<https://mails.dpdk.org/options/dev>,\n\t<mailto:dev-request@dpdk.org?subject=unsubscribe>",
        "List-Archive": "<http://mails.dpdk.org/archives/dev/>",
        "List-Post": "<mailto:dev@dpdk.org>",
        "List-Help": "<mailto:dev-request@dpdk.org?subject=help>",
        "List-Subscribe": "<https://mails.dpdk.org/listinfo/dev>,\n\t<mailto:dev-request@dpdk.org?subject=subscribe>",
        "Errors-To": "dev-bounces@dpdk.org",
        "Sender": "\"dev\" <dev-bounces@dpdk.org>"
    },
    "content": "This patch enables lock-free read-write concurrency support for\nextendable bucket feature.\n\nSuggested-by: Honnappa Nagarahalli <honnappa.nagarahalli@arm.com>\nSigned-off-by: Dharmik Thakkar <dharmik.thakkar@arm.com>\nReviewed-by: Ruifeng Wang <ruifeng.wang@arm.com>\nReviewed-by: Gavin Hu <gavin.hu@arm.com>\nReviewed-by: Honnappa Nagarahalli <honnappa.nagarahalli@arm.com>\nAcked-by: Yipeng Wang <yipeng1.wang@intel.com>\n---\n doc/guides/prog_guide/hash_lib.rst |   6 +-\n lib/librte_hash/rte_cuckoo_hash.c  | 157 ++++++++++++++++++++---------\n lib/librte_hash/rte_cuckoo_hash.h  |   7 ++\n 3 files changed, 117 insertions(+), 53 deletions(-)",
    "diff": "diff --git a/doc/guides/prog_guide/hash_lib.rst b/doc/guides/prog_guide/hash_lib.rst\nindex 85a6edfa8b16..d06c7de2ead1 100644\n--- a/doc/guides/prog_guide/hash_lib.rst\n+++ b/doc/guides/prog_guide/hash_lib.rst\n@@ -108,9 +108,9 @@ Extendable Bucket Functionality support\n An extra flag is used to enable this functionality (flag is not set by default). When the (RTE_HASH_EXTRA_FLAGS_EXT_TABLE) is set and\n in the very unlikely case due to excessive hash collisions that a key has failed to be inserted, the hash table bucket is extended with a linked\n list to insert these failed keys. This feature is important for the workloads (e.g. telco workloads) that need to insert up to 100% of the\n-hash table size and can't tolerate any key insertion failure (even if very few). Currently the extendable bucket is not supported\n-with the lock-free concurrency implementation (RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF).\n-\n+hash table size and can't tolerate any key insertion failure (even if very few).\n+Please note that with the 'lock free read/write concurrency' flag enabled, users need to call 'rte_hash_free_key_with_position' API in order to free the empty buckets and\n+deleted keys, to maintain the 100% capacity guarantee.\n \n Implementation Details (non Extendable Bucket Case)\n ---------------------------------------------------\ndiff --git a/lib/librte_hash/rte_cuckoo_hash.c b/lib/librte_hash/rte_cuckoo_hash.c\nindex c01489ba5193..8213dbf5f782 100644\n--- a/lib/librte_hash/rte_cuckoo_hash.c\n+++ b/lib/librte_hash/rte_cuckoo_hash.c\n@@ -140,6 +140,7 @@ rte_hash_create(const struct rte_hash_parameters *params)\n \tunsigned int readwrite_concur_support = 0;\n \tunsigned int writer_takes_lock = 0;\n \tunsigned int no_free_on_del = 0;\n+\tuint32_t *ext_bkt_to_free = NULL;\n \tuint32_t *tbl_chng_cnt = NULL;\n \tunsigned int readwrite_concur_lf_support = 0;\n \n@@ -170,15 +171,6 @@ rte_hash_create(const struct rte_hash_parameters *params)\n \t\treturn NULL;\n \t}\n \n-\tif ((params->extra_flag & RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF) &&\n-\t    (params->extra_flag & RTE_HASH_EXTRA_FLAGS_EXT_TABLE)) {\n-\t\trte_errno = EINVAL;\n-\t\tRTE_LOG(ERR, HASH, \"rte_hash_create: extendable bucket \"\n-\t\t\t\"feature not supported with rw concurrency \"\n-\t\t\t\"lock free\\n\");\n-\t\treturn NULL;\n-\t}\n-\n \t/* Check extra flags field to check extra options. */\n \tif (params->extra_flag & RTE_HASH_EXTRA_FLAGS_TRANS_MEM_SUPPORT)\n \t\thw_trans_mem_support = 1;\n@@ -302,6 +294,16 @@ rte_hash_create(const struct rte_hash_parameters *params)\n \t\t */\n \t\tfor (i = 1; i <= num_buckets; i++)\n \t\t\trte_ring_sp_enqueue(r_ext, (void *)((uintptr_t) i));\n+\n+\t\tif (readwrite_concur_lf_support) {\n+\t\t\text_bkt_to_free = rte_zmalloc(NULL, sizeof(uint32_t) *\n+\t\t\t\t\t\t\t\tnum_key_slots, 0);\n+\t\t\tif (ext_bkt_to_free == NULL) {\n+\t\t\t\tRTE_LOG(ERR, HASH, \"ext bkt to free memory allocation \"\n+\t\t\t\t\t\t\t\t\"failed\\n\");\n+\t\t\t\tgoto err_unlock;\n+\t\t\t}\n+\t\t}\n \t}\n \n \tconst uint32_t key_entry_size =\n@@ -393,6 +395,7 @@ rte_hash_create(const struct rte_hash_parameters *params)\n \t\tdefault_hash_func : params->hash_func;\n \th->key_store = k;\n \th->free_slots = r;\n+\th->ext_bkt_to_free = ext_bkt_to_free;\n \th->tbl_chng_cnt = tbl_chng_cnt;\n \t*h->tbl_chng_cnt = 0;\n \th->hw_trans_mem_support = hw_trans_mem_support;\n@@ -443,6 +446,7 @@ rte_hash_create(const struct rte_hash_parameters *params)\n \trte_free(buckets_ext);\n \trte_free(k);\n \trte_free(tbl_chng_cnt);\n+\trte_free(ext_bkt_to_free);\n \treturn NULL;\n }\n \n@@ -484,6 +488,7 @@ rte_hash_free(struct rte_hash *h)\n \trte_free(h->buckets);\n \trte_free(h->buckets_ext);\n \trte_free(h->tbl_chng_cnt);\n+\trte_free(h->ext_bkt_to_free);\n \trte_free(h);\n \trte_free(te);\n }\n@@ -799,7 +804,7 @@ rte_hash_cuckoo_move_insert_mw(const struct rte_hash *h,\n \t\t\t__atomic_store_n(h->tbl_chng_cnt,\n \t\t\t\t\t *h->tbl_chng_cnt + 1,\n \t\t\t\t\t __ATOMIC_RELEASE);\n-\t\t\t/* The stores to sig_alt and sig_current should not\n+\t\t\t/* The store to sig_current should not\n \t\t\t * move above the store to tbl_chng_cnt.\n \t\t\t */\n \t\t\t__atomic_thread_fence(__ATOMIC_RELEASE);\n@@ -831,7 +836,7 @@ rte_hash_cuckoo_move_insert_mw(const struct rte_hash *h,\n \t\t__atomic_store_n(h->tbl_chng_cnt,\n \t\t\t\t *h->tbl_chng_cnt + 1,\n \t\t\t\t __ATOMIC_RELEASE);\n-\t\t/* The stores to sig_alt and sig_current should not\n+\t\t/* The store to sig_current should not\n \t\t * move above the store to tbl_chng_cnt.\n \t\t */\n \t\t__atomic_thread_fence(__ATOMIC_RELEASE);\n@@ -1054,7 +1059,12 @@ __rte_hash_add_key_with_hash(const struct rte_hash *h, const void *key,\n \t\t\t/* Check if slot is available */\n \t\t\tif (likely(cur_bkt->key_idx[i] == EMPTY_SLOT)) {\n \t\t\t\tcur_bkt->sig_current[i] = short_sig;\n-\t\t\t\tcur_bkt->key_idx[i] = new_idx;\n+\t\t\t\t/* Store to signature should not leak after\n+\t\t\t\t * the store to key_idx\n+\t\t\t\t */\n+\t\t\t\t__atomic_store_n(&cur_bkt->key_idx[i],\n+\t\t\t\t\t\t new_idx,\n+\t\t\t\t\t\t __ATOMIC_RELEASE);\n \t\t\t\t__hash_rw_writer_unlock(h);\n \t\t\t\treturn new_idx - 1;\n \t\t\t}\n@@ -1072,7 +1082,12 @@ __rte_hash_add_key_with_hash(const struct rte_hash *h, const void *key,\n \tbkt_id = (uint32_t)((uintptr_t)ext_bkt_id) - 1;\n \t/* Use the first location of the new bucket */\n \t(h->buckets_ext[bkt_id]).sig_current[0] = short_sig;\n-\t(h->buckets_ext[bkt_id]).key_idx[0] = new_idx;\n+\t/* Store to signature should not leak after\n+\t * the store to key_idx\n+\t */\n+\t__atomic_store_n(&(h->buckets_ext[bkt_id]).key_idx[0],\n+\t\t\t new_idx,\n+\t\t\t __ATOMIC_RELEASE);\n \t/* Link the new bucket to sec bucket linked list */\n \tlast = rte_hash_get_last_bkt(sec_bkt);\n \tlast->next = &h->buckets_ext[bkt_id];\n@@ -1366,7 +1381,8 @@ remove_entry(const struct rte_hash *h, struct rte_hash_bucket *bkt, unsigned i)\n  * empty slot.\n  */\n static inline void\n-__rte_hash_compact_ll(struct rte_hash_bucket *cur_bkt, int pos) {\n+__rte_hash_compact_ll(const struct rte_hash *h,\n+\t\t\tstruct rte_hash_bucket *cur_bkt, int pos) {\n \tint i;\n \tstruct rte_hash_bucket *last_bkt;\n \n@@ -1377,10 +1393,27 @@ __rte_hash_compact_ll(struct rte_hash_bucket *cur_bkt, int pos) {\n \n \tfor (i = RTE_HASH_BUCKET_ENTRIES - 1; i >= 0; i--) {\n \t\tif (last_bkt->key_idx[i] != EMPTY_SLOT) {\n-\t\t\tcur_bkt->key_idx[pos] = last_bkt->key_idx[i];\n \t\t\tcur_bkt->sig_current[pos] = last_bkt->sig_current[i];\n+\t\t\t__atomic_store_n(&cur_bkt->key_idx[pos],\n+\t\t\t\t\t last_bkt->key_idx[i],\n+\t\t\t\t\t __ATOMIC_RELEASE);\n+\t\t\tif (h->readwrite_concur_lf_support) {\n+\t\t\t\t/* Inform the readers that the table has changed\n+\t\t\t\t * Since there is one writer, load acquire on\n+\t\t\t\t * tbl_chng_cnt is not required.\n+\t\t\t\t */\n+\t\t\t\t__atomic_store_n(h->tbl_chng_cnt,\n+\t\t\t\t\t *h->tbl_chng_cnt + 1,\n+\t\t\t\t\t __ATOMIC_RELEASE);\n+\t\t\t\t/* The store to sig_current should\n+\t\t\t\t * not move above the store to tbl_chng_cnt.\n+\t\t\t\t */\n+\t\t\t\t__atomic_thread_fence(__ATOMIC_RELEASE);\n+\t\t\t}\n \t\t\tlast_bkt->sig_current[i] = NULL_SIGNATURE;\n-\t\t\tlast_bkt->key_idx[i] = EMPTY_SLOT;\n+\t\t\t__atomic_store_n(&last_bkt->key_idx[i],\n+\t\t\t\t\t EMPTY_SLOT,\n+\t\t\t\t\t __ATOMIC_RELEASE);\n \t\t\treturn;\n \t\t}\n \t}\n@@ -1449,7 +1482,7 @@ __rte_hash_del_key_with_hash(const struct rte_hash *h, const void *key,\n \t/* look for key in primary bucket */\n \tret = search_and_remove(h, key, prim_bkt, short_sig, &pos);\n \tif (ret != -1) {\n-\t\t__rte_hash_compact_ll(prim_bkt, pos);\n+\t\t__rte_hash_compact_ll(h, prim_bkt, pos);\n \t\tlast_bkt = prim_bkt->next;\n \t\tprev_bkt = prim_bkt;\n \t\tgoto return_bkt;\n@@ -1461,7 +1494,7 @@ __rte_hash_del_key_with_hash(const struct rte_hash *h, const void *key,\n \tFOR_EACH_BUCKET(cur_bkt, sec_bkt) {\n \t\tret = search_and_remove(h, key, cur_bkt, short_sig, &pos);\n \t\tif (ret != -1) {\n-\t\t\t__rte_hash_compact_ll(cur_bkt, pos);\n+\t\t\t__rte_hash_compact_ll(h, cur_bkt, pos);\n \t\t\tlast_bkt = sec_bkt->next;\n \t\t\tprev_bkt = sec_bkt;\n \t\t\tgoto return_bkt;\n@@ -1488,11 +1521,24 @@ __rte_hash_del_key_with_hash(const struct rte_hash *h, const void *key,\n \t}\n \t/* found empty bucket and recycle */\n \tif (i == RTE_HASH_BUCKET_ENTRIES) {\n-\t\tprev_bkt->next = last_bkt->next = NULL;\n+\t\tprev_bkt->next = NULL;\n \t\tuint32_t index = last_bkt - h->buckets_ext + 1;\n-\t\trte_ring_sp_enqueue(h->free_ext_bkts, (void *)(uintptr_t)index);\n+\t\t/* Recycle the empty bkt if\n+\t\t * no_free_on_del is disabled.\n+\t\t */\n+\t\tif (h->no_free_on_del)\n+\t\t\t/* Store index of an empty ext bkt to be recycled\n+\t\t\t * on calling rte_hash_del_xxx APIs.\n+\t\t\t * When lock free read-write concurrency is enabled,\n+\t\t\t * an empty ext bkt cannot be put into free list\n+\t\t\t * immediately (as readers might be using it still).\n+\t\t\t * Hence freeing of the ext bkt is piggy-backed to\n+\t\t\t * freeing of the key index.\n+\t\t\t */\n+\t\t\th->ext_bkt_to_free[ret] = index;\n+\t\telse\n+\t\t\trte_ring_sp_enqueue(h->free_ext_bkts, (void *)(uintptr_t)index);\n \t}\n-\n \t__hash_rw_writer_unlock(h);\n \treturn ret;\n }\n@@ -1545,6 +1591,14 @@ rte_hash_free_key_with_position(const struct rte_hash *h,\n \t/* Out of bounds */\n \tif (position >= total_entries)\n \t\treturn -EINVAL;\n+\tif (h->ext_table_support && h->readwrite_concur_lf_support) {\n+\t\tuint32_t index = h->ext_bkt_to_free[position];\n+\t\tif (index) {\n+\t\t\t/* Recycle empty ext bkt to free list. */\n+\t\t\trte_ring_sp_enqueue(h->free_ext_bkts, (void *)(uintptr_t)index);\n+\t\t\th->ext_bkt_to_free[position] = 0;\n+\t\t}\n+\t}\n \n \tif (h->use_local_cache) {\n \t\tlcore_id = rte_lcore_id();\n@@ -1855,6 +1909,9 @@ __rte_hash_lookup_bulk_lf(const struct rte_hash *h, const void **keys,\n \t\trte_prefetch0(secondary_bkt[i]);\n \t}\n \n+\tfor (i = 0; i < num_keys; i++)\n+\t\tpositions[i] = -ENOENT;\n+\n \tdo {\n \t\t/* Load the table change counter before the lookup\n \t\t * starts. Acquire semantics will make sure that\n@@ -1899,7 +1956,6 @@ __rte_hash_lookup_bulk_lf(const struct rte_hash *h, const void **keys,\n \n \t\t/* Compare keys, first hits in primary first */\n \t\tfor (i = 0; i < num_keys; i++) {\n-\t\t\tpositions[i] = -ENOENT;\n \t\t\twhile (prim_hitmask[i]) {\n \t\t\t\tuint32_t hit_index =\n \t\t\t\t\t\t__builtin_ctzl(prim_hitmask[i])\n@@ -1972,6 +2028,35 @@ __rte_hash_lookup_bulk_lf(const struct rte_hash *h, const void **keys,\n \t\t\tcontinue;\n \t\t}\n \n+\t\t/* all found, do not need to go through ext bkt */\n+\t\tif (hits == ((1ULL << num_keys) - 1)) {\n+\t\t\tif (hit_mask != NULL)\n+\t\t\t\t*hit_mask = hits;\n+\t\t\treturn;\n+\t\t}\n+\t\t/* need to check ext buckets for match */\n+\t\tif (h->ext_table_support) {\n+\t\t\tfor (i = 0; i < num_keys; i++) {\n+\t\t\t\tif ((hits & (1ULL << i)) != 0)\n+\t\t\t\t\tcontinue;\n+\t\t\t\tnext_bkt = secondary_bkt[i]->next;\n+\t\t\t\tFOR_EACH_BUCKET(cur_bkt, next_bkt) {\n+\t\t\t\t\tif (data != NULL)\n+\t\t\t\t\t\tret = search_one_bucket_lf(h,\n+\t\t\t\t\t\t\tkeys[i], sig[i],\n+\t\t\t\t\t\t\t&data[i], cur_bkt);\n+\t\t\t\t\telse\n+\t\t\t\t\t\tret = search_one_bucket_lf(h,\n+\t\t\t\t\t\t\t\tkeys[i], sig[i],\n+\t\t\t\t\t\t\t\tNULL, cur_bkt);\n+\t\t\t\t\tif (ret != -1) {\n+\t\t\t\t\t\tpositions[i] = ret;\n+\t\t\t\t\t\thits |= 1ULL << i;\n+\t\t\t\t\t\tbreak;\n+\t\t\t\t\t}\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n \t\t/* The loads of sig_current in compare_signatures\n \t\t * should not move below the load from tbl_chng_cnt.\n \t\t */\n@@ -1988,34 +2073,6 @@ __rte_hash_lookup_bulk_lf(const struct rte_hash *h, const void **keys,\n \t\t\t\t\t__ATOMIC_ACQUIRE);\n \t} while (cnt_b != cnt_a);\n \n-\t/* all found, do not need to go through ext bkt */\n-\tif ((hits == ((1ULL << num_keys) - 1)) || !h->ext_table_support) {\n-\t\tif (hit_mask != NULL)\n-\t\t\t*hit_mask = hits;\n-\t\t__hash_rw_reader_unlock(h);\n-\t\treturn;\n-\t}\n-\n-\t/* need to check ext buckets for match */\n-\tfor (i = 0; i < num_keys; i++) {\n-\t\tif ((hits & (1ULL << i)) != 0)\n-\t\t\tcontinue;\n-\t\tnext_bkt = secondary_bkt[i]->next;\n-\t\tFOR_EACH_BUCKET(cur_bkt, next_bkt) {\n-\t\t\tif (data != NULL)\n-\t\t\t\tret = search_one_bucket_lf(h, keys[i],\n-\t\t\t\t\t\tsig[i], &data[i], cur_bkt);\n-\t\t\telse\n-\t\t\t\tret = search_one_bucket_lf(h, keys[i],\n-\t\t\t\t\t\tsig[i], NULL, cur_bkt);\n-\t\t\tif (ret != -1) {\n-\t\t\t\tpositions[i] = ret;\n-\t\t\t\thits |= 1ULL << i;\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t}\n-\t}\n-\n \tif (hit_mask != NULL)\n \t\t*hit_mask = hits;\n }\ndiff --git a/lib/librte_hash/rte_cuckoo_hash.h b/lib/librte_hash/rte_cuckoo_hash.h\nindex eacdaa8d4684..48c85c890712 100644\n--- a/lib/librte_hash/rte_cuckoo_hash.h\n+++ b/lib/librte_hash/rte_cuckoo_hash.h\n@@ -210,6 +210,13 @@ struct rte_hash {\n \trte_rwlock_t *readwrite_lock; /**< Read-write lock thread-safety. */\n \tstruct rte_hash_bucket *buckets_ext; /**< Extra buckets array */\n \tstruct rte_ring *free_ext_bkts; /**< Ring of indexes of free buckets */\n+\t/* Stores index of an empty ext bkt to be recycled on calling\n+\t * rte_hash_del_xxx APIs. When lock free read-write concurrency is\n+\t * enabled, an empty ext bkt cannot be put into free list immediately\n+\t * (as readers might be using it still). Hence freeing of the ext bkt\n+\t * is piggy-backed to freeing of the key index.\n+\t */\n+\tuint32_t *ext_bkt_to_free;\n \tuint32_t *tbl_chng_cnt;\n \t/**< Indicates if the hash table changed from last read. */\n } __rte_cache_aligned;\n",
    "prefixes": [
        "v5",
        "1/2"
    ]
}