目录

Cuckoo Hashing 的引入

多线程支持

代码


 Cuckoo Hashing的应用及性能优化-阿里云开发者社区

Cuckoo Hashing 的引入

1、Dense Hash Table就是普通的用线性探查解决冲突的哈希表。当插入F时,通过哈希函数将F映射到表中所指位置,发现该位置已存有D了,向后扫描探查,直到碰到一个空位,再将F插入。而查询一个G时,则需要从对应的位置开始向后找,直到找到G(命中),或找到空位(G不在表中)。这种结构对内存的利用不佳,如果想让哈希表尽量存满(k, v)对,那么插入/查询的性能将会严重下降。

2、Chain Hash Table是利用拉链法解决冲突的哈希表,它的特点是空间利用率比较高,除了顺序存下所有(k, v)对之外仅需要一个索引来记录链表头,但由于链表的空间不连续,导致查询性能一般。

3、Cuckoo Hash Table是本次引入的数据结构,它用了两个哈希函数来解决冲突。Cuckoo查询操作的理论复杂度为最差O(1),优于Dense的期望查询复杂度O(1)和Chain的O(1+α),而Cuckoo的插入复杂度为均摊O(1)。我们引入Cuckoo是希望它在实际应用中,能够在较高的空间利用率下,仍然维持不错的查询性能。

多线程支持

1、如果设置了“多个写者”的标志(RTE_HASH_EXTRA_FLAGS_MULTI_WRITER_ADD),则允许多个线程写入表。键的添加、删除和表重置受到保护。如果仅设置此标志,无法保护“读者”免受正在进行的写入操作的影响。

2、如果设置了读/写并发(RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY),则多线程读/写操作是安全的(即,应用程序不需要“停止读者访问哈希表,一直等待写者完成更新为止”。读者和写者可以同时在表上进行操作 )。该库使用读写锁提供并发。

3、除了这两个标志值外,如果还设置了事务性内存标志(RTE_HASH_EXTRA_FLAGS_TRANS_MEM_SUPPORT),那么如果硬件支持,读写锁将使用硬件事务性内存(例如Intel®TSX)来保证线程安全。如果平台支持Intel®TSX,建议设置事务性内存标志,因为这将加快并发表操作。否则,由于软件锁定机制相关的开销,并发操作将变慢。

4、如果设置了无锁读/写并发(RTE_HASH_EXTRA_FLAGS_RW_CONCURRENCY_LF),则将提供不使用读写锁的读/写并发。对于不支持事务性内存的平台(例如,当前基于ARM的平台),建议设置此标志以实现更高的性能可伸缩性。如果设置了此标志,则默认设置(RTE_HASH_EXTRA_FLAGS_NO_FREE_ON_DEL)标志。

5、如果设置了“在删除时不释放”(RTE_HASH_EXTRA_FLAGS_NO_FREE_ON_DEL)标志,则在调用delete()时不会释放哈希表中条目的位置。当设置无锁读/写并发标志时,默认情况下启用此标志。在所有读者都停止引用该位置之后,应用程序应释放该位置。在需要时,应用程序可以利用RCU机制来确定读者何时停止引用该位置

代码

#include <stdio.h>
#include <rte_eal.h>
#include <rte_hash.h>
#include <rte_jhash.h>
#include <rte_malloc.h>

#define HASH_KEY_COUNT 20

struct net_key {
	uint32_t sip;
	uint32_t dip;
	uint16_t sport;
	uint16_t dport;
	char proto;
};

static struct rte_hash *create_hash_table(const char *name) {

	struct rte_hash_parameters *params = rte_malloc("rte_hash_parameters", sizeof(struct rte_hash_parameters), 0);
	if (!params) return NULL;

	memset(params, 0, sizeof(struct rte_hash_parameters));
	params->name = name;
	params->entries = 8192;	//哈希表长度
	params->key_len = sizeof(struct net_key);
	params->hash_func = rte_jhash;
	params->hash_func_init_val = 0;	//一般设置为0
	params->socket_id = rte_socket_id();
	
	
	struct rte_hash *hash = rte_hash_create(params);

	return hash;
}

static void print_key(struct net_key *key) {
	printf("sip:%x, dip:%x, sport:%x, dport:%x, proto:%d\n", 
			key->sip, key->dip, key->sport, key->dport, key->proto);
}

int main(int argc, char *argv[]) {

	rte_eal_init(argc, argv);
/*
 * 哈希插入的方法:(其中的hash是自己计算出来再插入的)
 * key
 * key hash
 * key data
 * key hash data
 */

	struct rte_hash *hash = create_hash_table("hash_table");

	int i = 0;
	for(i = 0; i < HASH_KEY_COUNT; i++) {
		struct net_key nk = {0};
		nk.sip = 0x11111111 + i;
		nk.dip = 0x22222222 + i;
		nk.sport = 0x3333 + i;
		nk.dport = 0x4444 + i;
		nk.proto = i % 2;

		if (i % 4 == 0) {
			//插入key, 该key不需要申请动态内存
			rte_hash_add_key(hash, &nk);
		} else if (i %4 == 1) {
			//插入key+hash
			hash_sig_t hash_value = rte_hash_hash(hash, &nk);
			rte_hash_add_key_with_hash(hash, &nk, hash_value);
		} else if (i % 4 == 2) {
			//插入key data, data地址不能为局部的,避免失效
			uint32_t *tmp = rte_malloc("tmp", sizeof(uint32_t), 0);
			*tmp = i;
			rte_hash_add_key_data(hash, &nk, tmp);
		} else if (i % 4 == 3) {
			//插入key hash data
			hash_sig_t hash_value = rte_hash_hash(hash, &nk);
			uint32_t *tmp = rte_malloc("tmp", sizeof(uint32_t), 0);
			*tmp = i;
			rte_hash_add_key_with_hash_data(hash, &nk, hash_value, tmp);
		}
	}

	for (i = 0; i < HASH_KEY_COUNT; i++) {
		struct net_key nk = {0};
		nk.sip = 0x11111111 + i;
		nk.dip = 0x22222222 + i;
		nk.sport = 0x3333 + i;
		nk.dport = 0x4444 + i;
		nk.proto = i % 2;

		int idx = rte_hash_lookup(hash, &nk);
		printf("hash look up-->sip:%x idx:%d\n", nk.sip, idx);

		//rte_hash_del_key(hash, &nk);
	}

	struct net_key *key = NULL;
	void *value = NULL;
	uint32_t next = 0;

	//遍历所有哈希节点
	while(rte_hash_iterate(hash, (const void**)&key, &value, &next) >= 0) {
		if (value != NULL) {
			printf("value: %d \t", *(uint32_t*)value);
		} 
		print_key(key);
	}
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.
  • 69.
  • 70.
  • 71.
  • 72.
  • 73.
  • 74.
  • 75.
  • 76.
  • 77.
  • 78.
  • 79.
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86.
  • 87.
  • 88.
  • 89.
  • 90.
  • 91.
  • 92.
  • 93.
  • 94.
  • 95.
  • 96.
  • 97.
  • 98.
  • 99.
  • 100.
  • 101.
  • 102.
  • 103.
  • 104.
  • 105.
  • 106.
  • 107.
  • 108.
  • 109.