3 Star 18 Fork 2

阿宝 / threadfpm

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
hash.h 10.14 KB
一键复制 编辑 原始数据 按行查看 历史
阿宝 提交于 2022-05-12 16:31 . Optimize perf and fix bugs.
#ifndef _HASH_H
#define _HASH_H
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <php.h>
#include <zend_types.h>
typedef unsigned long int ulong;
typedef struct string_t {
unsigned int len;
char str[1];
} string_t;
typedef enum {
NULL_T=0,
BOOL_T,
LONG_T,
DOUBLE_T,
STR_T,
HT_T,
SERI_T,
TS_HT_T
} type_t;
typedef struct value_t {
type_t type;
int expire;
union {
zend_bool b;
long int l;
double d;
string_t *str;
void *ptr;
};
} value_t;
typedef struct bucket_t {
ulong h; /* Used for numeric indexing */
value_t value;
struct bucket_t *pListNext;
struct bucket_t *pListLast;
struct bucket_t *pNext;
struct bucket_t *pLast;
uint nKeyLength;
char arKey[1];
} bucket_t;
typedef void (*hash_dtor_func_t)(value_t *pDest);
typedef struct hash_table_t {
uint nTableSize;
uint nTableMask;
uint nNumOfElements;
ulong nNextFreeElement;
bucket_t *pListHead;
bucket_t *pListTail;
bucket_t **arBuckets;
hash_dtor_func_t pDestructor;
} hash_table_t;
void hash_table_value_free(value_t *value);
/* startup/shutdown */
int _hash_table_init(hash_table_t *ht, uint nSize, hash_dtor_func_t pDestructor);
void hash_table_destroy(hash_table_t *ht);
void hash_table_clean(hash_table_t *ht);
#define hash_table_init(ht, nSize) _hash_table_init((ht), (nSize), hash_table_value_free)
#define hash_table_init_ex(ht, nSize, pDestructor) _hash_table_init((ht), (nSize), (pDestructor))
#define HASH_TABLE_ADD 1
#define HASH_TABLE_UPDATE 2
#define HASH_TABLE_NEXT_INSERT 4
/* additions/updates/changes */
int _hash_table_add_or_update(hash_table_t *ht, const char *arKey, uint nKeyLength, value_t *pData, int flag);
#define hash_table_update(ht, arKey, nKeyLength, pData, pDest) \
_hash_table_add_or_update(ht, arKey, nKeyLength, pData, HASH_TABLE_UPDATE)
#define hash_table_add(ht, arKey, nKeyLength, pData, pDest) \
_hash_table_add_or_update(ht, arKey, nKeyLength, pData, HASH_TABLE_ADD)
int _hash_table_quick_add_or_update(hash_table_t *ht, const char *arKey, uint nKeyLength, ulong h, value_t *pData, int flag);
#define hash_table_quick_update(ht, arKey, nKeyLength, h, pData, pDest) \
_hash_table_quick_add_or_update(ht, arKey, nKeyLength, h, pData, HASH_TABLE_UPDATE)
#define hash_table_quick_add(ht, arKey, nKeyLength, h, pData, pDest) \
_hash_table_quick_add_or_update(ht, arKey, nKeyLength, h, pData, HASH_TABLE_ADD)
int _hash_table_index_update_or_next_insert(hash_table_t *ht, ulong h, value_t *pData, int flag);
#define hash_table_index_update(ht, h, pData, pDest) \
_hash_table_index_update_or_next_insert(ht, h, pData, HASH_TABLE_UPDATE)
#define hash_table_next_index_insert(ht, pData, pDest) \
_hash_table_index_update_or_next_insert(ht, 0, pData, HASH_TABLE_NEXT_INSERT)
#define HASH_TABLE_APPLY_KEEP 1
#define HASH_TABLE_APPLY_REMOVE 2
#define HASH_TABLE_APPLY_STOP 4
typedef int (*hash_apply_func_t)(bucket_t *pDest);
typedef int (*hash_apply_func_arg_t)(bucket_t *pDest, void *argument);
typedef int (*hash_apply_func_args_t)(bucket_t *pDest, int num_args, va_list args);
void hash_table_apply(hash_table_t *ht, hash_apply_func_t apply_func);
void hash_table_apply_with_argument(hash_table_t *ht, hash_apply_func_arg_t apply_func, void *);
void hash_table_apply_with_arguments(hash_table_t *ht, hash_apply_func_args_t apply_func, int, ...);
#define HASH_TABLE_DEL_KEY 1
#define HASH_TABLE_DEL_KEY_QUICK 2
#define HASH_TABLE_DEL_INDEX 4
/* Deletes */
int hash_table_del_key_or_index(hash_table_t *ht, const char *arKey, uint nKeyLength, ulong h, int flag);
#define hash_table_del(ht, arKey, nKeyLength) \
hash_table_del_key_or_index(ht, arKey, nKeyLength, 0, HASH_TABLE_DEL_KEY)
#define hash_table_quick_del(ht, arKey, nKeyLength, h) \
hash_table_del_key_or_index(ht, arKey, nKeyLength, h, HASH_TABLE_DEL_KEY_QUICK)
#define hash_table_index_del(ht, h) \
hash_table_del_key_or_index(ht, NULL, 0, h, HASH_TABLE_DEL_INDEX)
#define zend_get_hash_value(s,l) hash_table_func(s,l)
/* Data retreival */
int hash_table_find(const hash_table_t *ht, const char *arKey, uint nKeyLength, value_t *pData);
int hash_table_quick_find(const hash_table_t *ht, const char *arKey, uint nKeyLength, ulong h, value_t *pData);
int hash_table_index_find(const hash_table_t *ht, ulong h, value_t *pData);
/* Misc */
int hash_table_exists(const hash_table_t *ht, const char *arKey, uint nKeyLength);
int hash_table_quick_exists(const hash_table_t *ht, const char *arKey, uint nKeyLength, ulong h);
int hash_table_index_exists(const hash_table_t *ht, ulong h);
ulong hash_table_next_free_element(const hash_table_t *ht);
int hash_table_num_elements(const hash_table_t *ht);
void hash_table_reindex(hash_table_t *ht, zend_bool only_integer_keys);
ulong hash_table_func(const char *arKey, uint nKeyLength);
static zend_always_inline void hash_table_bucket_delete(hash_table_t *ht, bucket_t *p) {
if (p->pLast) {
p->pLast->pNext = p->pNext;
} else {
ht->arBuckets[p->h & ht->nTableMask] = p->pNext;
}
if (p->pNext) {
p->pNext->pLast = p->pLast;
}
if (p->pListLast != NULL) {
p->pListLast->pListNext = p->pListNext;
} else {
/* Deleting the head of the list */
ht->pListHead = p->pListNext;
}
if (p->pListNext != NULL) {
p->pListNext->pListLast = p->pListLast;
} else {
/* Deleting the tail of the list */
ht->pListTail = p->pListLast;
}
ht->nNumOfElements--;
if (ht->pDestructor) {
ht->pDestructor(&p->value);
}
free(p);
}
typedef int (*hash_compare_func_t)(const bucket_t *a, const bucket_t *b);
int compare_key(const bucket_t *a, const bucket_t *b);
int compare_value(const bucket_t *a, const bucket_t *b);
int hash_table_minmax(const hash_table_t *ht, hash_compare_func_t compar, int flag, bucket_t **ret);
int hash_table_sort(hash_table_t *ht, hash_compare_func_t compar, int reverse);
// ===========================================================================================================
#include <pthread.h>
#include <time.h>
#include <zend_exceptions.h>
#if defined(LOCK_TIMEOUT) && LOCK_TIMEOUT <= 0
#undef LOCK_TIMEOUT
#endif
#ifdef LOCK_TIMEOUT
typedef struct _tskey_hash_table_t {
hash_table_t ht;
pthread_mutex_t lock;
} tskey_hash_table_t;
#endif
typedef struct ts_hash_table_t {
hash_table_t ht;
int expire;
volatile unsigned short rd_count;
volatile unsigned short ref_count; // reference count
pthread_mutex_t wlock;
pthread_mutex_t rlock;
int fds[2];
#ifdef LOCK_TIMEOUT
tskey_hash_table_t *tsht;
ulong h;
#endif
} ts_hash_table_t;
static zend_always_inline int _ts_hash_table_init(ts_hash_table_t *ts_ht, uint nSize, hash_dtor_func_t pDestructor) {
ts_ht->rd_count = 0;
ts_ht->ref_count = 1;
ts_ht->fds[0] = 0;
ts_ht->fds[1] = 0;
ts_ht->expire = 0;
#ifdef LOCK_TIMEOUT
ts_ht->tsht = NULL;
ts_ht->h = hash_table_func((const char*) &ts_ht, sizeof(void*));
#endif
pthread_mutex_init(&ts_ht->rlock, NULL);
pthread_mutex_init(&ts_ht->wlock, NULL);
return _hash_table_init(&ts_ht->ht, nSize, pDestructor);
}
#define ts_hash_table_init(ht, nSize) _ts_hash_table_init((ht), (nSize), hash_table_value_free)
#define ts_hash_table_init_ex(ht, nSize, pDestructor) _ts_hash_table_init((ht), (nSize), (pDestructor))
static zend_always_inline void ts_hash_table_lock(ts_hash_table_t *ts_ht) {
pthread_mutex_lock(&ts_ht->rlock);
}
static zend_always_inline void ts_hash_table_unlock(ts_hash_table_t *ts_ht) {
pthread_mutex_unlock(&ts_ht->rlock);
}
#ifdef LOCK_TIMEOUT
extern pthread_key_t tskey;
void ts_table_table_tid_destroy(void *hh);
long int ts_table_table_tid_inc(ts_hash_table_t *hh);
long int ts_table_table_tid_dec_ex(tskey_hash_table_t *tsht, ts_hash_table_t *hh);
#define ts_table_table_tid_dec(ht) ts_table_table_tid_dec_ex(pthread_getspecific(tskey), ht)
const char *gettimeofstr();
void ts_hash_table_deadlock(const char *msg);
#endif
static zend_always_inline void ts_hash_table_wr_lock(ts_hash_table_t *ts_ht) {
#ifndef LOCK_TIMEOUT
pthread_mutex_lock(&ts_ht->wlock);
#else
// printf("%p lock\n", ts_ht);
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
ts.tv_sec += LOCK_TIMEOUT;
if(pthread_mutex_timedlock(&ts_ht->wlock, &ts)) {
if(ts_table_table_tid_inc(ts_ht) == 1) {
ts_hash_table_deadlock("Deadlock caused by shared variables");
} else {
ts_hash_table_deadlock("Repeated locking of shared variables");
}
pthread_mutex_lock(&ts_ht->wlock);
} else {
ts_table_table_tid_inc(ts_ht);
}
ts_ht->tsht = pthread_getspecific(tskey);
#endif
}
static zend_always_inline void ts_hash_table_wr_unlock(ts_hash_table_t *ts_ht) {
#ifndef LOCK_TIMEOUT
pthread_mutex_unlock(&ts_ht->wlock);
#else
long int i = ts_table_table_tid_dec(ts_ht);
if(i == 0) {
ts_ht->tsht = NULL;
// printf("%p unlock\n", ts_ht);
pthread_mutex_unlock(&ts_ht->wlock);
} else if(i < 0) {
i = ts_table_table_tid_dec_ex(ts_ht->tsht, ts_ht);
if(i == 0) {
ts_ht->tsht = NULL;
// printf("%p unlock\n", ts_ht);
pthread_mutex_unlock(&ts_ht->wlock);
} else if(i < 0) {
ts_hash_table_deadlock("Shared variable unlocking exception");
}
}
#endif
}
static zend_always_inline void ts_hash_table_rd_lock(ts_hash_table_t *ts_ht) {
pthread_mutex_lock(&ts_ht->rlock);
if((++ts_ht->rd_count) == 1) ts_hash_table_wr_lock(ts_ht);
pthread_mutex_unlock(&ts_ht->rlock);
}
static zend_always_inline void ts_hash_table_rd_unlock(ts_hash_table_t *ts_ht) {
pthread_mutex_lock(&ts_ht->rlock);
if((--ts_ht->rd_count) == 0) ts_hash_table_wr_unlock(ts_ht);
pthread_mutex_unlock(&ts_ht->rlock);
}
static zend_always_inline void ts_hash_table_ref(ts_hash_table_t *ts_ht) {
ts_hash_table_lock(ts_ht);
ts_ht->ref_count++;
ts_hash_table_unlock(ts_ht);
}
#define ts_hash_table_unref(ts_ht) ts_hash_table_destroy(ts_ht)
static zend_always_inline void ts_hash_table_destroy_ex(ts_hash_table_t *ts_ht, int is_free) {
ts_hash_table_lock(ts_ht);
if(--ts_ht->ref_count == 0) {
ts_hash_table_unlock(ts_ht);
if(ts_ht->fds[0] > 0) close(ts_ht->fds[0]);
if(ts_ht->fds[1] > 0) close(ts_ht->fds[1]);
pthread_mutex_destroy(&ts_ht->rlock);
pthread_mutex_destroy(&ts_ht->wlock);
hash_table_destroy(&ts_ht->ht);
if(is_free) free(ts_ht);
} else ts_hash_table_unlock(ts_ht);
}
#define ts_hash_table_destroy(ts_ht) ts_hash_table_destroy_ex(ts_ht, 1)
#endif /* _HASH_H */
C
1
https://gitee.com/talent518/threadfpm.git
git@gitee.com:talent518/threadfpm.git
talent518
threadfpm
threadfpm
main

搜索帮助