提交 af315a9c 编写于 作者: H hjxilinx

add hash iterator

上级 d1b298bc
...@@ -23,17 +23,18 @@ extern "C" { ...@@ -23,17 +23,18 @@ extern "C" {
#include "hashfunc.h" #include "hashfunc.h"
#define HASH_MAX_CAPACITY (1024 * 1024 * 16) #define HASH_MAX_CAPACITY (1024 * 1024 * 16)
#define HASH_VALUE_IN_TRASH (-1)
#define HASH_DEFAULT_LOAD_FACTOR (0.75) #define HASH_DEFAULT_LOAD_FACTOR (0.75)
#define HASH_INDEX(v, c) ((v) & ((c)-1)) #define HASH_INDEX(v, c) ((v) & ((c)-1))
typedef void (*_hash_free_fn_t)(void *param);
typedef struct SHashNode { typedef struct SHashNode {
char *key; // null-terminated string char *key;
union { union {
struct SHashNode * prev; struct SHashNode * prev;
struct SHashEntry *prev1; struct SHashEntry *prev1;
}; };
struct SHashNode *next; struct SHashNode *next;
uint32_t hashVal; // the hash value of key, if hashVal == HASH_VALUE_IN_TRASH, this node is moved to trash uint32_t hashVal; // the hash value of key, if hashVal == HASH_VALUE_IN_TRASH, this node is moved to trash
uint32_t keyLen; // length of the key uint32_t keyLen; // length of the key
...@@ -46,18 +47,27 @@ typedef struct SHashEntry { ...@@ -46,18 +47,27 @@ typedef struct SHashEntry {
} SHashEntry; } SHashEntry;
typedef struct SHashObj { typedef struct SHashObj {
SHashEntry **hashList; SHashEntry ** hashList;
size_t capacity; // number of slots size_t capacity; // number of slots
size_t size; // number of elements in hash table size_t size; // number of elements in hash table
_hash_fn_t hashFp; // hash function _hash_fn_t hashFp; // hash function
_hash_free_fn_t freeFp; // hash node free callback function
#if defined (LINUX)
pthread_rwlock_t* lock; #if defined(LINUX)
pthread_rwlock_t *lock;
#else #else
pthread_mutex_t* lock; pthread_mutex_t *lock;
#endif #endif
} SHashObj; } SHashObj;
typedef struct SHashMutableIterator {
SHashObj * pHashObj;
int32_t entryIndex;
SHashNode *pCur;
SHashNode *pNext; // current node can be deleted for mutable iterator, so keep the next one before return current
int32_t num; // already check number of elements in hash table
} SHashMutableIterator;
/** /**
* init the hash table * init the hash table
* *
...@@ -102,7 +112,7 @@ void *taosHashGet(SHashObj *pHashObj, const char *key, size_t keyLen); ...@@ -102,7 +112,7 @@ void *taosHashGet(SHashObj *pHashObj, const char *key, size_t keyLen);
* @param key * @param key
* @param keyLen * @param keyLen
*/ */
void taosHashRemove(SHashObj *pHashObj, const char *key, size_t keyLen); void taosHashRemove(SHashObj *pHashObj, const char *key, size_t keyLen);
/** /**
* clean up hash table * clean up hash table
...@@ -110,6 +120,41 @@ void taosHashRemove(SHashObj *pHashObj, const char *key, size_t keyLen); ...@@ -110,6 +120,41 @@ void taosHashRemove(SHashObj *pHashObj, const char *key, size_t keyLen);
*/ */
void taosHashCleanup(SHashObj *pHashObj); void taosHashCleanup(SHashObj *pHashObj);
/**
* Set the free callback function
* This function if set will be invoked right before freeing each hash node
* @param pHashObj
*/
void taosHashSetFreecb(SHashObj *pHashObj, _hash_free_fn_t freeFp);
/**
*
* @param pHashObj
* @return
*/
SHashMutableIterator* taosHashCreateIter(SHashObj *pHashObj);
/**
*
* @param iter
* @return
*/
bool taosHashIterNext(SHashMutableIterator *iter);
/**
*
* @param iter
* @return
*/
void *taosHashIterGet(SHashMutableIterator *iter);
/**
*
* @param iter
* @return
*/
void* taosHashDestroyIter(SHashMutableIterator* iter);
/** /**
* *
* @param pHashObj * @param pHashObj
......
...@@ -24,8 +24,8 @@ static FORCE_INLINE void __wr_lock(void *lock) { ...@@ -24,8 +24,8 @@ static FORCE_INLINE void __wr_lock(void *lock) {
if (lock == NULL) { if (lock == NULL) {
return; return;
} }
#if defined (LINUX) #if defined(LINUX)
pthread_rwlock_wrlock(lock); pthread_rwlock_wrlock(lock);
#else #else
pthread_mutex_lock(lock); pthread_mutex_lock(lock);
...@@ -36,8 +36,8 @@ static FORCE_INLINE void __rd_lock(void *lock) { ...@@ -36,8 +36,8 @@ static FORCE_INLINE void __rd_lock(void *lock) {
if (lock == NULL) { if (lock == NULL) {
return; return;
} }
#if defined (LINUX) #if defined(LINUX)
pthread_rwlock_rdlock(lock); pthread_rwlock_rdlock(lock);
#else #else
pthread_mutex_lock(lock); pthread_mutex_lock(lock);
...@@ -48,8 +48,8 @@ static FORCE_INLINE void __unlock(void *lock) { ...@@ -48,8 +48,8 @@ static FORCE_INLINE void __unlock(void *lock) {
if (lock == NULL) { if (lock == NULL) {
return; return;
} }
#if defined (LINUX) #if defined(LINUX)
pthread_rwlock_unlock(lock); pthread_rwlock_unlock(lock);
#else #else
pthread_mutex_unlock(lock); pthread_mutex_unlock(lock);
...@@ -60,8 +60,8 @@ static FORCE_INLINE int32_t __lock_init(void *lock) { ...@@ -60,8 +60,8 @@ static FORCE_INLINE int32_t __lock_init(void *lock) {
if (lock == NULL) { if (lock == NULL) {
return 0; return 0;
} }
#if defined (LINUX) #if defined(LINUX)
return pthread_rwlock_init(lock, NULL); return pthread_rwlock_init(lock, NULL);
#else #else
return pthread_mutex_init(lock, NULL); return pthread_mutex_init(lock, NULL);
...@@ -72,8 +72,8 @@ static FORCE_INLINE void __lock_destroy(void *lock) { ...@@ -72,8 +72,8 @@ static FORCE_INLINE void __lock_destroy(void *lock) {
if (lock == NULL) { if (lock == NULL) {
return; return;
} }
#if defined (LINUX) #if defined(LINUX)
pthread_rwlock_destroy(lock); pthread_rwlock_destroy(lock);
#else #else
pthread_mutex_destroy(lock); pthread_mutex_destroy(lock);
...@@ -107,7 +107,7 @@ static void doUpdateHashTable(SHashObj *pHashObj, SHashNode *pNode) { ...@@ -107,7 +107,7 @@ static void doUpdateHashTable(SHashObj *pHashObj, SHashNode *pNode) {
/** /**
* get SHashNode from hashlist, nodes from trash are not included. * get SHashNode from hashlist, nodes from trash are not included.
* @param pHashObj Cache objection * @param pHashObj Cache objection
* @param key key for hash * @param key key for hash
* @param keyLen key length * @param keyLen key length
* @return * @return
...@@ -155,24 +155,24 @@ static void taosHashTableResize(SHashObj *pHashObj) { ...@@ -155,24 +155,24 @@ static void taosHashTableResize(SHashObj *pHashObj) {
int32_t newSize = pHashObj->capacity << 1U; int32_t newSize = pHashObj->capacity << 1U;
if (newSize > HASH_MAX_CAPACITY) { if (newSize > HASH_MAX_CAPACITY) {
pTrace("current capacity:%d, maximum capacity:%d, no resize applied due to limitation is reached", pHashObj->capacity, pTrace("current capacity:%d, maximum capacity:%d, no resize applied due to limitation is reached",
HASH_MAX_CAPACITY); pHashObj->capacity, HASH_MAX_CAPACITY);
return; return;
} }
int64_t st = taosGetTimestampUs(); int64_t st = taosGetTimestampUs();
SHashEntry **pNewEntry = realloc(pHashObj->hashList, sizeof(SHashEntry*) * newSize); SHashEntry **pNewEntry = realloc(pHashObj->hashList, sizeof(SHashEntry *) * newSize);
if (pNewEntry == NULL) { if (pNewEntry == NULL) {
pTrace("cache resize failed due to out of memory, capacity remain:%d", pHashObj->capacity); pTrace("cache resize failed due to out of memory, capacity remain:%d", pHashObj->capacity);
return; return;
} }
pHashObj->hashList = pNewEntry; pHashObj->hashList = pNewEntry;
for(int32_t i = pHashObj->capacity; i < newSize; ++i) { for (int32_t i = pHashObj->capacity; i < newSize; ++i) {
pHashObj->hashList[i] = calloc(1, sizeof(SHashEntry)); pHashObj->hashList[i] = calloc(1, sizeof(SHashEntry));
} }
pHashObj->capacity = newSize; pHashObj->capacity = newSize;
for (int32_t i = 0; i < pHashObj->capacity; ++i) { for (int32_t i = 0; i < pHashObj->capacity; ++i) {
...@@ -182,7 +182,7 @@ static void taosHashTableResize(SHashObj *pHashObj) { ...@@ -182,7 +182,7 @@ static void taosHashTableResize(SHashObj *pHashObj) {
if (pNode != NULL) { if (pNode != NULL) {
assert(pNode->prev1 == pEntry && pEntry->num > 0); assert(pNode->prev1 == pEntry && pEntry->num > 0);
} }
while (pNode) { while (pNode) {
int32_t j = HASH_INDEX(pNode->hashVal, pHashObj->capacity); int32_t j = HASH_INDEX(pNode->hashVal, pHashObj->capacity);
if (j == i) { // this key resides in the same slot, no need to relocate it if (j == i) { // this key resides in the same slot, no need to relocate it
...@@ -192,13 +192,13 @@ static void taosHashTableResize(SHashObj *pHashObj) { ...@@ -192,13 +192,13 @@ static void taosHashTableResize(SHashObj *pHashObj) {
// remove from current slot // remove from current slot
assert(pNode->prev1 != NULL); assert(pNode->prev1 != NULL);
if (pNode->prev1 == pEntry) { // first node of the overflow linked list if (pNode->prev1 == pEntry) { // first node of the overflow linked list
pEntry->next = pNode->next; pEntry->next = pNode->next;
} else { } else {
pNode->prev->next = pNode->next; pNode->prev->next = pNode->next;
} }
pEntry->num--; pEntry->num--;
assert(pEntry->num >= 0); assert(pEntry->num >= 0);
...@@ -214,13 +214,13 @@ static void taosHashTableResize(SHashObj *pHashObj) { ...@@ -214,13 +214,13 @@ static void taosHashTableResize(SHashObj *pHashObj) {
if (pNewIndexEntry->next != NULL) { if (pNewIndexEntry->next != NULL) {
assert(pNewIndexEntry->next->prev1 == pNewIndexEntry); assert(pNewIndexEntry->next->prev1 == pNewIndexEntry);
pNewIndexEntry->next->prev = pNode; pNewIndexEntry->next->prev = pNode;
} }
pNode->next = pNewIndexEntry->next; pNode->next = pNewIndexEntry->next;
pNode->prev1 = pNewIndexEntry; pNode->prev1 = pNewIndexEntry;
pNewIndexEntry->next = pNode; pNewIndexEntry->next = pNode;
pNewIndexEntry->num++; pNewIndexEntry->num++;
...@@ -258,14 +258,14 @@ SHashObj *taosHashInit(size_t capacity, _hash_fn_t fn, bool threadsafe) { ...@@ -258,14 +258,14 @@ SHashObj *taosHashInit(size_t capacity, _hash_fn_t fn, bool threadsafe) {
pHashObj->hashFp = fn; pHashObj->hashFp = fn;
pHashObj->hashList = (SHashEntry **)calloc(pHashObj->capacity, sizeof(SHashEntry*)); pHashObj->hashList = (SHashEntry **)calloc(pHashObj->capacity, sizeof(SHashEntry *));
if (pHashObj->hashList == NULL) { if (pHashObj->hashList == NULL) {
free(pHashObj); free(pHashObj);
pError("failed to allocate memory, reason:%s", strerror(errno)); pError("failed to allocate memory, reason:%s", strerror(errno));
return NULL; return NULL;
} }
for(int32_t i = 0; i < pHashObj->capacity; ++i) { for (int32_t i = 0; i < pHashObj->capacity; ++i) {
pHashObj->hashList[i] = calloc(1, sizeof(SHashEntry)); pHashObj->hashList[i] = calloc(1, sizeof(SHashEntry));
} }
...@@ -276,7 +276,7 @@ SHashObj *taosHashInit(size_t capacity, _hash_fn_t fn, bool threadsafe) { ...@@ -276,7 +276,7 @@ SHashObj *taosHashInit(size_t capacity, _hash_fn_t fn, bool threadsafe) {
pHashObj->lock = calloc(1, sizeof(pthread_mutex_t)); pHashObj->lock = calloc(1, sizeof(pthread_mutex_t));
#endif #endif
} }
if (__lock_init(pHashObj->lock) != 0) { if (__lock_init(pHashObj->lock) != 0) {
free(pHashObj->hashList); free(pHashObj->hashList);
free(pHashObj); free(pHashObj);
...@@ -347,7 +347,7 @@ static void doAddToHashTable(SHashObj *pHashObj, SHashNode *pNode) { ...@@ -347,7 +347,7 @@ static void doAddToHashTable(SHashObj *pHashObj, SHashNode *pNode) {
int32_t index = HASH_INDEX(pNode->hashVal, pHashObj->capacity); int32_t index = HASH_INDEX(pNode->hashVal, pHashObj->capacity);
SHashEntry *pEntry = pHashObj->hashList[index]; SHashEntry *pEntry = pHashObj->hashList[index];
pNode->next = pEntry->next; pNode->next = pEntry->next;
if (pEntry->next) { if (pEntry->next) {
...@@ -356,7 +356,7 @@ static void doAddToHashTable(SHashObj *pHashObj, SHashNode *pNode) { ...@@ -356,7 +356,7 @@ static void doAddToHashTable(SHashObj *pHashObj, SHashNode *pNode) {
pEntry->next = pNode; pEntry->next = pNode;
pNode->prev1 = pEntry; pNode->prev1 = pEntry;
pEntry->num++; pEntry->num++;
pHashObj->size++; pHashObj->size++;
} }
...@@ -365,7 +365,7 @@ size_t taosHashGetSize(const SHashObj *pHashObj) { ...@@ -365,7 +365,7 @@ size_t taosHashGetSize(const SHashObj *pHashObj) {
if (pHashObj == NULL) { if (pHashObj == NULL) {
return 0; return 0;
} }
return pHashObj->size; return pHashObj->size;
} }
...@@ -430,7 +430,7 @@ void *taosHashGet(SHashObj *pHashObj, const char *key, size_t keyLen) { ...@@ -430,7 +430,7 @@ void *taosHashGet(SHashObj *pHashObj, const char *key, size_t keyLen) {
void taosHashRemove(SHashObj *pHashObj, const char *key, size_t keyLen) { void taosHashRemove(SHashObj *pHashObj, const char *key, size_t keyLen) {
__wr_lock(pHashObj->lock); __wr_lock(pHashObj->lock);
uint32_t val = 0; uint32_t val = 0;
SHashNode *pNode = doGetNodeFromHashTable(pHashObj, key, keyLen, &val); SHashNode *pNode = doGetNodeFromHashTable(pHashObj, key, keyLen, &val);
if (pNode == NULL) { if (pNode == NULL) {
__unlock(pHashObj->lock); __unlock(pHashObj->lock);
...@@ -446,13 +446,13 @@ void taosHashRemove(SHashObj *pHashObj, const char *key, size_t keyLen) { ...@@ -446,13 +446,13 @@ void taosHashRemove(SHashObj *pHashObj, const char *key, size_t keyLen) {
pNode->prev->next = pNext; pNode->prev->next = pNext;
} }
} }
if (pNext != NULL) { if (pNext != NULL) {
pNext->prev = pNode->prev; pNext->prev = pNode->prev;
} }
uint32_t index = HASH_INDEX(pNode->hashVal, pHashObj->capacity); uint32_t index = HASH_INDEX(pNode->hashVal, pHashObj->capacity);
SHashEntry *pEntry = pHashObj->hashList[index]; SHashEntry *pEntry = pHashObj->hashList[index];
pEntry->num--; pEntry->num--;
...@@ -483,10 +483,14 @@ void taosHashCleanup(SHashObj *pHashObj) { ...@@ -483,10 +483,14 @@ void taosHashCleanup(SHashObj *pHashObj) {
while (pNode) { while (pNode) {
pNext = pNode->next; pNext = pNode->next;
if (pHashObj->freeFp) {
pHashObj->freeFp(pNode->data);
}
free(pNode); free(pNode);
pNode = pNext; pNode = pNext;
} }
tfree(pEntry); tfree(pEntry);
} }
...@@ -496,24 +500,122 @@ void taosHashCleanup(SHashObj *pHashObj) { ...@@ -496,24 +500,122 @@ void taosHashCleanup(SHashObj *pHashObj) {
__unlock(pHashObj->lock); __unlock(pHashObj->lock);
__lock_destroy(pHashObj->lock); __lock_destroy(pHashObj->lock);
tfree(pHashObj->lock);
memset(pHashObj, 0, sizeof(SHashObj)); memset(pHashObj, 0, sizeof(SHashObj));
free(pHashObj); free(pHashObj);
} }
void taosHashSetFreecb(SHashObj *pHashObj, _hash_free_fn_t freeFp) {
if (pHashObj == NULL || freeFp == NULL) {
return;
}
pHashObj->freeFp = freeFp;
}
SHashMutableIterator *taosHashCreateIter(SHashObj *pHashObj) {
SHashMutableIterator *pIter = calloc(1, sizeof(SHashMutableIterator));
if (pIter == NULL) {
return NULL;
}
pIter->pHashObj = pHashObj;
}
static SHashNode *getNextHashNode(SHashMutableIterator *pIter) {
assert(pIter != NULL);
while (pIter->entryIndex < pIter->pHashObj->capacity) {
SHashEntry *pEntry = pIter->pHashObj->hashList[pIter->entryIndex];
if (pEntry->next == NULL) {
pIter->entryIndex++;
continue;
}
return pEntry->next;
}
return NULL;
}
bool taosHashIterNext(SHashMutableIterator *pIter) {
if (pIter == NULL) {
return false;
}
size_t size = taosHashGetSize(pIter->pHashObj);
if (size == 0 || pIter->num >= size) {
return false;
}
// check the first one
if (pIter->num == 0) {
assert(pIter->pCur == NULL && pIter->pNext == NULL);
while (1) {
SHashEntry *pEntry = pIter->pHashObj->hashList[pIter->entryIndex];
if (pEntry->next == NULL) {
pIter->entryIndex++;
continue;
}
pIter->pCur = pEntry->next;
if (pIter->pCur->next) {
pIter->pNext = pIter->pCur->next;
} else {
pIter->pNext = getNextHashNode(pIter);
}
break;
}
pIter->num++;
return true;
} else {
assert(pIter->pCur != NULL);
if (pIter->pNext) {
pIter->pCur = pIter->pNext;
} else { // no more data in the hash list
return false;
}
pIter->num++;
if (pIter->pCur->next) {
pIter->pNext = pIter->pCur->next;
} else {
pIter->pNext = getNextHashNode(pIter);
}
return true;
}
}
void *taosHashIterGet(SHashMutableIterator *iter) { return (iter == NULL) ? NULL : iter->pCur->data; }
void *taosHashDestroyIter(SHashMutableIterator *iter) {
if (iter == NULL) {
return NULL;
}
free(iter);
}
// for profile only // for profile only
int32_t taosHashGetMaxOverflowLinkLength(const SHashObj* pHashObj) { int32_t taosHashGetMaxOverflowLinkLength(const SHashObj *pHashObj) {
if (pHashObj == NULL || pHashObj->size == 0) { if (pHashObj == NULL || pHashObj->size == 0) {
return 0; return 0;
} }
int32_t num = 0; int32_t num = 0;
for(int32_t i = 0; i < pHashObj->size; ++i) { for (int32_t i = 0; i < pHashObj->size; ++i) {
SHashEntry *pEntry = pHashObj->hashList[i]; SHashEntry *pEntry = pHashObj->hashList[i];
if (num < pEntry->num) { if (num < pEntry->num) {
num = pEntry->num; num = pEntry->num;
} }
} }
return num; return num;
} }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册