hash table实现内存控制和超时删除

test.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include "hash.h"

//编写hash函数
unsigned int hash_func(unsigned int bucktes, ip_port_t *ipp)
{
    uint32_t key = (ipp->saddr ^ ipp->daddr ^ ipp->dport) % bucktes;
    printf("get buckets saddr:%x daddr:%x dport:%x --> key:%u\n", ipp->saddr, ipp->daddr, ipp->dport, key);
    ipp->key = key;
    return 1;
}

int main(int argc, char *argv[])
{
    ip_port_t ipp_arry[] = {
        {0, 0x7509A8C0, 0x710CA8C0, 0x59, 0 },
        {0, 0x7509A8C1, 0x710CA8C2, 0x58, 0 },
        {0, 0x7509A8C2, 0x710CA8C3, 0x57, 0 },
        {0, 0x7509A8C3, 0x710CA8C4, 0x56, 0 },
        {0, 0x7509A8C4, 0x710CA8C5, 0x55, 0 },
        {0, 0x7509A8C5, 0x710CA8C6, 0x54, 0 },
        {0, 0x7509A8C6, 0x710CA8C7, 0x53, 0 },
        {0, 0x7509A8C7, 0x710CA8C8, 0x52, 0 },
        {0, 0x7509A8C8, 0x710CA8C9, 0x51, 0 }
    };

    hash_t *hash = hash_init(MAX_BUCKETS_SIZE);

    int i = 0;
    int size = sizeof(ipp_arry) / sizeof(ipp_arry[0]);
    for (i = 0; i < size - 4; i++)
    {
        hash_func(MAX_BUCKETS_SIZE, &ipp_arry[i]);
        hash_add_entry(hash, &ipp_arry[i]);
    }

    printf("......................add end...............\n");
    hash_node_t *hn = NULL;
    for (i = 0; i < size - 4; i++)
    {
        hn = (hash_node_t *)hash_lookup_entry(hash, &ipp_arry[i]);
        if (hn) {
            printf("find [%d]:%x,%x,%x,%x\n", i, hn->saddr, hn->daddr, hn->dport, hn->timeout);
        }
        else {
            printf("[%d]:no node \n", i);
        }
    }
    for (i = 0; i < size; i++)
    {
        hash_del_entry(hash, &ipp_arry[i]);
    }
    printf("......................free end...............\n");
    for (i = 0; i < size; i++)
    {
        hn = (hash_node_t *)hash_lookup_entry(hash, &ipp_arry[i]);
        if (hn) {
            printf("after free find [%d]:%x,%x,%x,%x\n", i, hn->saddr, hn->daddr, hn->dport, hn->timeout);
        }
        else {
            printf("after free [%d]:no node \n", i);
        }
    }

    for (i = 0; i < size ; i++)
    {
        hash_func(MAX_BUCKETS_SIZE, &ipp_arry[i]);
        ipp_arry[i].timeout = time(NULL);
        printf("add entry [%d] timeout:%lu\n", i, ipp_arry[i].timeout);
        hash_add_entry(hash, &ipp_arry[i]);
        sleep(1);
    }

    printf("......................add end 2...............\n");
    hn = NULL;
    for (i = 0; i < size; i++)
    {
        hn = (hash_node_t *)hash_lookup_entry(hash, &ipp_arry[i]);
        if (hn) {
            printf("find 2 [%d]:%x,%x,%x,%lu\n", i, hn->saddr, hn->daddr, hn->dport, hn->timeout);
        }
        else {
            printf("[%d]:no node \n", i);
        }
    }

    ip_port_t ipp;
    while(hash->timeout_nodes)
    {
        time_t tm_now = time(NULL);
        if(tm_now - hash->timeout_nodes->timeout > 5) {
            printf("goto delete timeout now:%lu - %lu\n", tm_now, hash->timeout_nodes->timeout);
            ipp.saddr = hash->timeout_nodes->saddr;
            ipp.daddr = hash->timeout_nodes->daddr;
            ipp.dport = hash->timeout_nodes->dport;
            hash_func(MAX_BUCKETS_SIZE, &ipp);
            hash_del_entry(hash, &ipp);
        }
        sleep(1);
    }
    printf("......................delete timeout end...............\n");

    for (i = 0; i < size; i++)
    {
        hn = (hash_node_t *)hash_lookup_entry(hash, &ipp_arry[i]);
        if (hn) {
            printf("find 3 [%d]:%x,%x,%x,%lu\n", i, hn->saddr, hn->daddr, hn->dport, hn->timeout);
        }
        else {
            printf("[%d]:no node \n", i);
        }
    }

    return 0;
}

hash.h

#pragma once
#ifndef _HASH_H_
#define _HASH_H_

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <time.h>

#define MAX_BUCKETS_SIZE    1024

typedef struct ip_port {
    uint32_t key;//
    uint32_t saddr;//
    uint32_t daddr;//
    uint16_t dport;//
    time_t   timeout;//
}ip_port_t;

typedef struct hash_node {
    uint32_t saddr;//
    uint32_t daddr;//
    uint16_t dport;//
    time_t   timeout;//

    struct hash_node *prev;
    struct hash_node *next;

    struct hash_node *timeout_prev;
    struct hash_node *timeout_next;
}hash_node_t;

typedef struct hash {
    unsigned int buckets;//桶的个数(大小)
    hash_node_t **nodes;//hash表中存放的链表地址
    hash_node_t * free_nodes;
    hash_node_t * timeout_nodes;
    hash_node_t * timeout_tail;
}hash_t;

/*返回的是hash表指针,创建hash表*/
hash_t *hash_init(unsigned int);
void *hash_lookup_entry(hash_t *, ip_port_t *); 

void hash_add_entry(hash_t *, ip_port_t *); 
void hash_del_entry(hash_t *, ip_port_t *); 

#endif /*_HASH_H_*/

hash.c

#include "hash.h"


hash_node_t * hash_get_free_nodes(hash_t *hash);
void hash_add_free_nodes(hash_t *hash, hash_node_t *node);
void hash_add_timeout_nodes(hash_t *hash, hash_node_t *node);
void hash_del_timeout_nodes(hash_t *hash, hash_node_t *node);

hash_t *hash_init(unsigned int buckets)
{
    hash_t *hash = (hash_t *)malloc(sizeof(hash_t));
    memset(hash, 0x00, sizeof(hash_t));
    hash->buckets = buckets;
    unsigned int size = buckets * sizeof(hash_node_t *); 
    hash->nodes = (hash_node_t **)malloc(size);
    memset(hash->nodes,0x00, size);
    return hash;
}

void* hash_lookup_entry(hash_t *hash, ip_port_t *ipp)
{
    hash_node_t *node = hash->nodes[ipp->key];
    if (node == NULL) return NULL;
    
    while (node != NULL ) { 
        if (node->saddr == ipp->saddr && node->daddr == ipp->daddr && node->dport == ipp->dport)
            return node;

        node = node->next;
    }   
    return NULL;
}

void hash_add_entry(hash_t *hash, ip_port_t *ipp)
{
    if (hash_lookup_entry(hash, ipp)) {
        printf("duplicate hash key\n");
        return;
    }   
    
    hash_node_t *node;
    node = hash_get_free_nodes(hash);
    if (node == NULL) {
        node = (hash_node_t*)malloc(sizeof(hash_node_t));
        if (node == NULL) {
            printf("error: add entry malloc node!\n");
            exit(-1);
        }   
        printf("add entry malloc node=========================\n");
    }   
    else {
        printf("add entry get free node=========================\n");
    }   

    node->next = NULL;
    node->prev = NULL;
    node->timeout_next = NULL;
    node->timeout_prev = NULL;

    node->saddr = ipp->saddr;
    node->daddr = ipp->daddr;
    node->dport = ipp->dport;
    node->timeout = ipp->timeout;

    hash_node_t **bucket = &(hash->nodes[ipp->key]);
    if (*bucket == NULL) {
        *bucket = node;
    }
    else {
        node->next = *bucket;   //first is next
        (*bucket)->prev = node;
        *bucket = node;
    }

    //add to timeout nodes
    hash_add_timeout_nodes(hash, node);
}

void hash_del_entry(hash_t *hash, ip_port_t *ipp)
{
    hash_node_t *node = hash_lookup_entry(hash, ipp);
    if (node == NULL)
        return;

    if (node->prev) {
        node->prev->next = node->next;
    }
    else {
        hash_node_t **bucket = &(hash->nodes[ipp->key]);
        *bucket = node->next;
    }
    if (node->next) {
        node->next->prev = node->prev;
    }

    //del from timeout nodes
    hash_del_timeout_nodes(hash, node);

    //add to free nodes
    hash_add_free_nodes(hash, node);
}

void hash_add_free_nodes(hash_t *hash, hash_node_t *node)
{
    node->next = NULL;
    node->prev = NULL;
    if (hash->free_nodes == NULL) {
        hash->free_nodes = node;
    }
    else {
        node->next = hash->free_nodes;  //first is next
        hash->free_nodes->prev = node;
        hash->free_nodes = node;
    }
}

hash_node_t * hash_get_free_nodes(hash_t *hash)
{
    hash_node_t *node = hash->free_nodes;
    if (node == NULL)
        return NULL;

    if (node->next) {
        node->next->prev = NULL;
    }
    hash->free_nodes = node->next;
    node->next = NULL;

    return node;
}

void hash_add_timeout_nodes(hash_t *hash, hash_node_t *node)
{
    if (hash->timeout_nodes == NULL) {
        hash->timeout_nodes = hash->timeout_tail = node;
    }
    else {
        hash->timeout_tail->timeout_next = node;
        node->timeout_prev = hash->timeout_tail;

        hash->timeout_tail = node;
    }
}

void hash_del_timeout_nodes(hash_t *hash, hash_node_t *node)
{
    if (node->timeout_prev) {
        node->timeout_prev->timeout_next = node->timeout_next;
    }
    else {
        hash->timeout_nodes = node->timeout_next;
    }

    if (node->timeout_next) {
        node->timeout_next->timeout_prev = node->timeout_prev;
    }
    else {
        hash->timeout_tail = node->timeout_prev;
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值