DPDK中的cuckoo hash算法

本文详细分析了DPDK中Cuckoo Hash的实现,包括Cuckoo Hash的工作原理,如何处理哈希冲突,以及在DPDK库中的具体代码实现。还介绍了Bloom Filter的基本概念和在特定场景的应用。同时,概述了DPDK哈希表的创建、查找、删除和插入操作的关键步骤,强调了哈希表中的关键成员变量的作用。
摘要由CSDN通过智能技术生成

现在用到的cuckoo hash算法比较多,下面具体分析在dpdk代码中cuckoo实现,在lib/librte_hash/下有其他若干种hash就不一一介绍了,比较简单,先文字介绍下bloom filter和cuckoo hash。

bloom filter:“似于bitmap这样的hashset,所以空间利用率很高。其独特的地方在于它使用多个哈希函数来避免哈希碰撞”,“带来的问题:一个是误报(false positives),在查询时能提供“一定不存在”,但只能提供“可能存在”,因为存在其它元素被映射到部分相同bit位上,导致该位置1,那么一个不存在的元素可能会被误报成存在;另一个是漏报(false nagatives),同样道理,如果删除了某个元素,导致该映射bit位被置0,那么本来存在的元素会被漏报成不存在。由于后者问题严重得多,所以bloom filter必须确保“definitely no”从而容忍“probably yes”,不允许元素的删除。”

在一些场景中比如区块链中交易和区块数据的快速判断,使用数组只存储key不存储数据,根据交易和区块的sha256哈希值快速判断当前需要同步给对等节点的交易数据和区块数据是否已同步过,这样虽然可能存在漏报,即交易a和交易c映射的bit置为1后,同步a,c,后面来了交易b,然后映射后的位置bit都为1误以为已经同步过,故不同步,当然这些不成问题,会由其他的对等节点同步。截取bitcoin/src/bloom.h中CBloomFilter类部分声明:

 44 class CBloomFilter
 45 {
 46 private:
 47     std::vector<unsigned char> vData;
 48     bool isFull;
 49     bool isEmpty;
 50     unsigned int nHashFuncs;
 51     unsigned int nTweak;
 52     unsigned char nFlags;

cuckoo hash:“哈希函数是成对的,每一个元素都有两个,分别映射到两个位置,一个是记录的位置,另一个是备用位置。这个备用位置是处理碰撞时用的。cuckoo hashing处理碰撞的方法,就是把原来占用位置的这个元素踢走,被踢出去的元素有一个备用位置可以安置,如果备用位置上还有元素,再把它踢走,如此往复。直到被踢的次数达到一个上限,才确认哈希表已满,并执行rehash操作。” 下面开始真正分析源码中的实现。

先来看看cuckoo中key的比较函数,求key的hash函数原型和hash表结构:

 66 /** Signature of key that is stored internally. */
 67 typedef uint32_t hash_sig_t;
 68 
 69 /** Type of function that can be used for calculating the hash value. */
 70 typedef uint32_t (*rte_hash_function)(const void *key, uint32_t key_len, uint32_t init_val);
 72
 73 /** Type of function used to compare the hash key. */
 74 typedef int (*rte_hash_cmp_eq_t)(const void *key1, const void *key2, size_t key_len);

183 /** A hash table structure. */
184 struct rte_hash {
185     char name[RTE_HASH_NAMESIZE];   /**< Name of the hash. */
186     uint32_t entries;               /**< Total table entries. */
187     uint32_t num_buckets;           /**< Number of buckets in table. */
188     uint32_t key_len;               /**< Length of hash key. */
189     rte_hash_function hash_func;    /**< Function used to calculate hash. */
190     uint32_t hash_func_init_val;    /**< Init value used by hash_func. */
191     rte_hash_cmp_eq_t rte_hash_custom_cmp_eq;
192     /**< Custom function used to compare keys. */
193     enum cmp_jump_table_case cmp_jump_table_idx;
194     /**< Indicates which compare function to use. */
195     uint32_t bucket_bitmask;        /**< Bitmask for getting bucket index
196                         from hash signature. */
197     uint32_t key_entry_size;         /**< Size of each key entry. */
198 
199     struct rte_ring *free_slots;    /**< Ring that stores all indexes
200                         of the free slots in the key table */
201     void *key_store;                /**< Table storing all keys and data */
202     struct rte_hash_bucket *buckets;    /**< Table with buckets storing all the
203                             hash values and key indexes
204                             to the key table*/
212 } __rte_cache_aligned;

165 /* Structure that stores key-value pair */
166 struct rte_hash_key {
167     union {
168         uintptr_t idata;
169         void *pdata;
170     };
171     /* Variable key size */
172     char key[0];
173 } __attribute__((aligned(KEY_ALIGNMENT)));

154 /* Structure storing both primary and secondary hashes */
155 struct rte_hash_signatures {
156     union {
157         struct {
158             hash_sig_t current;
159             hash_sig_t alt;
160         };
161         uint64_t sig;
162     };
163 };

175 /** Bucket structure */
176 struct rte_hash_bucket {
177     struct rte_hash_signatures signatures[RTE_HASH_BUCKET_ENTRIES];
178     /* Includes dummy key index that always contains index 0 */
179     uint32_t key_idx[RTE_HASH_BUCKET_ENTRIES + 1];
180     uint8_t flag[RTE_HASH_BUCKET_ENTRIES];
181 } __rte_cache_aligned;

其中rte_hash_custom_cmp_eq和cmp_jump_table_idx是用于指定哪种类型的key比较函数,用户也可以自己实现,其他字段会在下面使用到的地方作说明,这里仅考虑单线程操作hash表,即线程a不会去操作线程b的hash表[设计错误],也不会出现线程a和b操作hash表[有锁费性能,尽量充分理解业务选择适合的方案]。截取部分如下:

 72  * based on the key size and custom function.
 73  */
 74 enum cmp_jump_table_case {
 75     KEY_CUSTOM = 0,
 76     KEY_16_BYTES,
 77     KEY_32_BYTES,
 78     //more
 86 };
 87 
 88 /*
 89  * Table storing all different key compare functions
 90  * (multi-process supported)
 91  */
 92 const rte_hash_cmp_eq_t cmp_jump_table[NUM_KEY_CMP_CASES] = {
 93     NULL,
 94     rte_hash_k16_cmp_eq,
 95     rte_hash_k32_cmp_eq,
 96     //more 
 97 };

 34 /* Functions to compare multiple of 16 byte keys (up to 128 bytes) */
 35 static int
 36 rte_hash_k16_cmp_eq(const void *key1, const void *key2,
 37             size_t key_len __rte_unused)
 38 {
 39     uint64_t x0, x1, y0, y1;
 40 
 41     asm volatile(
 42         "ldp %x[x1], %x[x0], [%x[p1]]"
 43         : [x1]&#
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值