哈希表&哈希算法

简单用如下的例子介绍哈希表数据结构,以及相关操作。

1、数据结构

/*哈希头节点*/
typedef struct _hash_head
{
	unsigned  elem;     /* The number of elements currently in the table */
	unsigned  size;     /* The size of the hash table */

	struct hlist_head *head;    /* The hash table */
	
	spinlock_t lock ;
} hash_head_t;

hash_head_t *g_hash_head = NULL;

/*存储的数据结构:源IP+目的IP*/
typedef  struct ip_addr_pair
{
	__be32 src_ip;
	__be32 dst_ip;
	atomic_t count;

	struct hlist_node hash_list;
} ip_addr_pair_t;

2、初始化

主要是分配哈希头节点存储空间,以及每个哈希节点的空间分配及初始化。

int hash_init(void)
{
	struct hlist_head *hash = NULL;
	unsigned int i, hash_size = nf_conntrack_max;

	g_hash_head = kmalloc(sizeof(hash_head_t), GFP_KERNEL);
	if (NULL  == g_hash_head)
	{
		printk("Failed to malloc hash head in hash init.\n");
		return ERROR;
	}

	hash = vmalloc(hash_size * sizeof(struct hlist_head));
	if (NULL == hash)
	{
		kfree(g_hash_head);
		printk("Failed to malloc hash table in hash init.\n");
		return ERROR;
	}

	if (NULL != hash)
	{
		for (i = 0; i < hash_size; i++)
		{
			INIT_HLIST_HEAD(&hash[i]);
		}
	}

	g_hash_head->head = hash;
	g_hash_head->elem = 0;
	g_hash_head->size = hash_size;

	spin_lock_init(&g_hash_head->lock);

	return OK;
}

3、卸载清空

void hash_exit(void)
{
	unsigned i = 0;
	ip_addr_pair_t *entry = NULL;
	hash_head_t *head = g_hash_head;
	struct hlist_node *node, *next;

	spin_lock_bh(&head->lock);
	for(i = 0; i < head->size; i++)
	{
		hlist_for_each_entry_safe(entry, node, next, &head->head[i], hash_list)
		{
			__hlist_del(&entry->hash_list);

			head->elem--;
			kfree(entry);
			entry = NULL;
		}
	}
	spin_unlock_bh(&head->lock);

	if (g_hash_head)
	{
		vfree(g_hash_head->head);
		g_hash_head->head = NULL;

		kfree(g_hash_head);
		g_hash_head = NULL;
	}
}

4、哈希函数

static unsigned hash_fn(const void *key_param, int key_len)
{
	unsigned a = 0;
	unsigned b = 0;
	unsigned len;
	uint8_t *key = (uint8_t *) key_param;

	/* Set up the internal state */
	len = (unsigned) key_len;
	a = len;

	if (len >= 4)
	{
		b = key[0] + (key[1] << 8) + (key[2] << 16) + (key[3] << 24);
	}

	while (len >= 8)
	{
		a += b;
		key += 4;
		a += ~(a << 15);
		len -= 4;
		a ^=  (a >> 10);
		b = key[0];
		a +=  (a << 3);
		b += key[1] << 8;
		a ^=  (a >> 6);
		b += key[2] << 16;
		a += ~(a << 11);
		b += key[3] << 24;
		a ^=  (a >> 16);
	}

	if (len >= 4)
	{
		a += b;
		a += ~(a << 15);
		len -= 4;
		a ^=  (a >> 10);
		a +=  (a << 3);
		a ^=  (a >> 6);
		a += ~(a << 11);
		a ^=  (a >> 16);
	}


	/* All the case statements fall through */
	switch (len)
	{
	case 3 :
		a += key[2] << 16;
	case 2 :
		a ^= key[1] << 8;
	case 1 :
		a += key[0];
	default:
		break;
	}

	return a;
}

5、元素比较函数

static bool addrPair_hash_cmp(ip_addr_pair_t *pAddrPair, ip_addr_pair_key_t *key)
{
	return ((pAddrPair->src_ip == key->src_ip) && (pAddrPair->dst_ip == key->dst_ip));
}

6、哈希添加

int hash_add(ip_addr_pair_key_t *key, uint32_t mark)
{
	unsigned hash = 0;
	unsigned hash_index = 0;
	ip_addr_pair_t *entry, *pAddrPair = NULL;
	hash_head_t *head = g_hash_head;
	struct hlist_node *node = NULL;

	if(elem_up_limit())
		return OVER_MAX;

	hash = hash_fn((void *)key, sizeof(ip_addr_pair_key_t));
	hash_index = hash % head->size;

	spin_lock_bh(&head->lock);
	hlist_for_each_entry(entry, node, &head->head[hash_index], hash_list)
	{
		if (addrPair_hash_cmp(entry, key))
		{
			atomic_inc(&entry->count);
			spin_unlock_bh(&head->lock);

			return OK;
		}
	}

	pAddrPair = kmalloc(sizeof(ip_addr_pair_t), GFP_KERNEL);
	if(NULL == pAddrPair)
	{
		spin_unlock_bh(&head->lock);
		printk("Failed kmalloc pAddrPair.\n");
		return ALLOC_FAIL;
	}

	pAddrPair->src_ip = key->src_ip;
	pAddrPair->dst_ip = key->dst_ip;

	atomic_set(&pAddrPair->count, 1);

	hlist_add_head(&pAddrPair->hash_list, &head->head[hash_index]);
	head->elem++;

	spin_unlock_bh(&head->lock);

	return OK;
}

7、哈希查询

ip_addr_pair_t *hash_get(ip_addr_pair_key_t *key)
{
	unsigned hash = 0;
	unsigned hash_index = 0;
	struct hlist_node *node = NULL;
	ip_addr_pair_t *entry = NULL;
	hash_head_t *head = g_hash_head;

	hash = hash_fn((void *)key, sizeof(ip_addr_pair_key_t));
	hash_index = hash % head->size;

	spin_lock_bh(&head->lock);
	hlist_for_each_entry(entry, node, &head->head[hash_index], hash_list)
	{
		if (addrPair_hash_cmp(entry, key))
		{
			spin_unlock_bh(&head->lock);
			return entry;
		}
	}
	spin_unlock_bh(&head->lock);

	return NULL;
}

8、哈希删除

int hash_remove(ip_addr_pair_key_t *key)
{
	unsigned hash = 0;
	unsigned hash_index = 0;
	struct hlist_node *node = NULL;
	ip_addr_pair_t *entry = NULL;
	hash_head_t *head = g_hash_head;

	hash = hash_fn((void *)key, sizeof(ip_addr_pair_key_t));
	hash_index = hash % head->size;

	spin_lock_bh(&head->lock);
	hlist_for_each_entry(entry, node, &head->head[hash_index], hash_list)
	{
		if (addrPair_hash_cmp(entry, key))
		{
			if(atomic_read(&entry->count) > 1)
			{
				atomic_dec(&entry->count);

				spin_unlock_bh(&head->lock);
				return COUNT_NOZERO;
			}
			else
			{
				__hlist_del(&entry->hash_list);
				head->elem--;
				
				spin_unlock_bh(&head->lock);
				return OK;
			}
		}
	}
	spin_unlock_bh(&head->lock);

	return NO_EXIST;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值