hash table

#define HASH_TABLE_SIZE 14976001
#define HASH_SEGMENT_SIZE 20
#define HASH_ENTRY_EXPIRE_TIME (60*60*24*30)   //30 days
#define HASH_AUDIT_BKT_NUM_PER_TIME (HASH_TABLE_SIZE/239) //every 5 days finish on audit cycle
#define HASH_AUDIT_INTERVAL (10*60) //do audit every 30 min


template <class T> class HashTable;


template <class T>
class HashEntry
{
friend class HashTable<T>;


private:
    string key;
    T value;
    time_t timestamp;
    HashEntry *next;


public:
    HashEntry():key(0), timestamp(0), next(NULL)
    {


    }
    HashEntry(const string &_key, const T &_val):key(_key), value(_val), next(NULL)
    {
        timestamp = time(NULL);
    }
    ~HashEntry()
    {


    }
};


template <class T>
class HashTable
{
private:
    HashEntry<T> **bucket;       //hash bucket
    uint32_t entry_num;          //current entry node number
    uint32_t bkt_cnt;            //hash bucket count
    uint32_t bkt_used;           //hash bucket used
    uint32_t cur_audit_bkt;      //current audit bucket index
    uint32_t purge_num; //entry number purged by audit
    pthread_rwlock_t *bkt_lock;  //rw lock


public:
    HashTable(uint32_t _size = HASH_TABLE_SIZE):entry_num(0), bkt_cnt(_size), bkt_used(0), cur_audit_bkt(0), purge_num(0)
    {
        init(bkt_cnt);
    }


    ~HashTable()
    {
        clear();
    }


    uint32_t get_entry_num()  { return __sync_fetch_and_add(&entry_num,0); }
    uint32_t get_bkt_count()  { return __sync_fetch_and_add(&bkt_cnt,0); }
    uint32_t get_bkt_used()  { return __sync_fetch_and_add(&bkt_used,0); }


    /*
     * Insert the pair of key and value
     *
     */
    bool insert(const char *key, const T &value)
    {
        if (NULL == key)
        {
            ASRT_RPT_XD(ASBAD_DATA, NULL_PTR, 0, "Invalid key!");
            return false;
        }


        return insert((const string&)key, value);
    }


    bool insert(const string &key, const T &value)
    {
        uint32_t idx = get_bkt_idx(key);


        wlock_bucket(idx);


        HashEntry<T>* entry = bucket[idx];
        if (NULL == entry)
        {
            __sync_add_and_fetch(&bkt_used,1);
        }


        while (entry)
        {
            /* If find the key, update the old value with the new one */
            if (entry->key == key)
            {
                memcpy(&entry->value, &value, sizeof(T));
                entry->timestamp = time(NULL);
                unlock_bucket(idx);
                return true;
            }


            entry = entry->next;
        }


        HashEntry<T>* new_entry = new HashEntry<T>(key, value);
        if (new_entry == NULL)
        {
            ASRT_RPT_XD(ASBAD_DATA, NULL_PTR, 0, "allocate memory failed! size=%d",sizeof(HashEntry<T>));
            return false;
        }


        new_entry->next = bucket[idx];
        bucket[idx] = new_entry;
        __sync_add_and_fetch(&entry_num,1);


        unlock_bucket(idx);


        return true;
    }


    /*
     * find one entry
     *
     */
    T* find(const char *key, time_t *time_stamp = NULL)
    {
        if (NULL == key)
        {
            ASRT_RPT_XD(ASBAD_DATA, NULL_PTR, 0, "Invalid key!");
            return NULL;
        }


        return find((const string&)key, time_stamp);
    }


    T* find(const string &key, time_t *time_stamp = NULL)
    {
        uint32_t idx = get_bkt_idx(key);


        rlock_bucket(idx);


        HashEntry<T>* entry = bucket[idx];
        while (entry)
        {
            if (entry->key == key)
            {
                if (NULL != time_stamp)
                {
                    *time_stamp = entry->timestamp;
                }
                entry->timestamp = time(NULL);
                unlock_bucket(idx);
                return &entry->value;
            }
            entry = entry->next;
        }


        unlock_bucket(idx);


        return NULL;
    }


    /*
     * update one entry
     *
     */
    bool update(const char *key, const T &value)
    {
        if (NULL == key)
        {
            ASRT_RPT_XD(ASBAD_DATA, NULL_PTR, 0, "Invalid key!");
            return false;
        }


        return update((const string&)key, value);
    }


    bool update(const string &key, const T &value)
    {
        uint32_t idx = get_bkt_idx(key);


        wlock_bucket(idx);


        HashEntry<T>* entry = bucket[idx];
        while (entry)
        {
            if (entry->key == key)
            {
                memcpy(&entry->value, &value, sizeof(T));
                entry->timestamp = time(NULL);
                unlock_bucket(idx);
                return true;
            }
            else
            {
                entry = entry->next;
            }
        }


        unlock_bucket(idx);


        return false;
    }


    /*
     * Delete hashEntry for given key
     *
     */
    bool del(const char *key)
    {
        if (NULL == key)
        {
            ASRT_RPT_XD(ASBAD_DATA, NULL_PTR, 0, "Invalid key!");
            return false;
        }


        return del((const string&)key);
    }


    bool del(const string &key)
    {
        uint32_t idx = get_bkt_idx(key);


        wlock_bucket(idx);


        HashEntry<T>* entry = bucket[idx];
        HashEntry<T>* pre_entry = NULL;
        while (entry)
        {
            if (entry->key == key)
            {
                if (pre_entry)
                {
                    pre_entry->next = entry->next;
                }
                else
                {
                    bucket[idx] = entry->next;
                    if (NULL == entry->next)
                    {
                        __sync_sub_and_fetch(&bkt_used,1);
                    }
                }


                delete entry;
                __sync_sub_and_fetch(&entry_num,1);
                unlock_bucket(idx);
                return true;
            }
            else
            {
                pre_entry = entry;
                entry = entry->next;
            }
        }


        unlock_bucket(idx);


        return false;
    }

private:


    /*
     * JS hash algorithm
     */
    uint64_t js_hash(const string &str)
    {
        uint64_t hash = 1315423911;


        for (uint8_t i = 0; i < str.length(); i++)
        {
            hash ^= ((hash << 5) + str[i] + (hash >> 2));
        }


        return hash;
    }


    void init(uint32_t _size)
    {
        uint32_t lock_size = ((bkt_cnt+HASH_SEGMENT_SIZE-1) / HASH_SEGMENT_SIZE);


        bucket = new HashEntry<T>*[_size];
        if (bucket == NULL)
        {
            ASRT_RPT_XD(ASBAD_DATA, NULL_PTR, 0, "allocate memory failed! size=%d",sizeof(HashEntry<T>*)*_size);
            return;
        }


        memset(bucket, 0, sizeof(HashEntry<T>*)*_size);


        bkt_lock = new pthread_rwlock_t[lock_size];
        if (bkt_lock == NULL)
        {
            ASRT_RPT_XD(ASBAD_DATA, NULL_PTR, 0, "allocate memory failed! size=%d",sizeof(pthread_rwlock_t)*lock_size);
            return;
        }
        for (uint32_t i = 0; i < lock_size; i++)
        {
            pthread_rwlock_init(&bkt_lock[i],NULL);
        }


    }


    void clear()
    {
        uint32_t lock_size = ((bkt_cnt+HASH_SEGMENT_SIZE-1) / HASH_SEGMENT_SIZE);


        for (uint32_t i = 0; i < bkt_cnt; i++)
        {
            HashEntry<T>* entry = bucket[i];
            while (entry)
            {
                HashEntry<T>* next = entry->next;
                delete entry;
                entry = next;
            }
        }


        delete [] bucket;


        for (uint32_t i = 0; i < lock_size; i++)
        {
            pthread_rwlock_destroy(&bkt_lock[i]);
        }


        delete [] bkt_lock;
    }


    uint32_t get_bkt_idx(const string &key)
    {
        uint64_t hash;
        uint32_t idx;


        hash = js_hash(key);
        idx = hash % bkt_cnt;


        return idx;
    }


    void wlock_bucket(uint32_t bkt_idx)
    {
        pthread_rwlock_wrlock(&bkt_lock[bkt_idx/HASH_SEGMENT_SIZE]);
    }


    void rlock_bucket(uint32_t bkt_idx)
    {
        pthread_rwlock_rdlock(&bkt_lock[bkt_idx/HASH_SEGMENT_SIZE]);
    }


    void unlock_bucket(uint32_t bkt_idx)
    {
        pthread_rwlock_unlock(&bkt_lock[bkt_idx/HASH_SEGMENT_SIZE]);
    }

};






#endif /* _SFED_HASHTABLE_H_ */


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值