[td-225] update the hash func

This commit is contained in:
Haojun Liao 2020-07-31 17:27:12 +08:00
parent 99e15e0d6d
commit 6f3f7f7ff9
3 changed files with 72 additions and 185 deletions

View File

@ -41,17 +41,17 @@ typedef struct SHashNode {
typedef enum SHashLockTypeE { typedef enum SHashLockTypeE {
HASH_NO_LOCK = 0, HASH_NO_LOCK = 0,
HASH_GLOBAL_LOCK = 1, // HASH_GLOBAL_LOCK = 1,
HASH_ENTRY_LOCK = 2, HASH_ENTRY_LOCK = 1,
} SHashLockTypeE; } SHashLockTypeE;
typedef struct SHashLock { //typedef struct SHashLock {
#if defined(LINUX) //#if defined(LINUX)
pthread_rwlock_t *lock; // pthread_rwlock_t *lock;
#else //#else
pthread_mutex_t *lock; // pthread_mutex_t *lock;
#endif //#endif
} SHashLock; //} SHashLock;
typedef struct SHashEntry { typedef struct SHashEntry {
int32_t num; // number of elements in current entry int32_t num; // number of elements in current entry
@ -66,8 +66,8 @@ typedef struct SHashObj {
_hash_fn_t hashFp; // hash function _hash_fn_t hashFp; // hash function
_hash_free_fn_t freeFp; // hash node free callback function _hash_free_fn_t freeFp; // hash node free callback function
SHashLock lock; SRWLatch lock; // read-write spin lock
SHashLockTypeE lockType; // lock type SHashLockTypeE type; // lock type
bool enableUpdate; // enable update bool enableUpdate; // enable update
SArray *pMemBlock; // memory block allocated for SHashEntry SArray *pMemBlock; // memory block allocated for SHashEntry
} SHashObj; } SHashObj;

View File

@ -21,64 +21,35 @@
#define HASH_NEED_RESIZE(_h) ((_h)->size >= (_h)->capacity * HASH_DEFAULT_LOAD_FACTOR) #define HASH_NEED_RESIZE(_h) ((_h)->size >= (_h)->capacity * HASH_DEFAULT_LOAD_FACTOR)
static FORCE_INLINE void __wr_lock(void *lock) { static FORCE_INLINE void __wr_lock(void *lock, int32_t type) {
if (lock == NULL) { if (type == HASH_NO_LOCK) {
return;
}
taosWLockLatch(lock);
}
static FORCE_INLINE void __rd_lock(void *lock, int32_t type) {
if (type == HASH_NO_LOCK) {
return; return;
} }
#if defined(LINUX) taosRLockLatch(lock);
pthread_rwlock_wrlock(lock);
#else
pthread_mutex_lock(lock);
#endif
} }
static FORCE_INLINE void __rd_lock(void *lock) { static FORCE_INLINE void __rd_unlock(void *lock, int32_t type) {
if (lock == NULL) { if (type == HASH_NO_LOCK) {
return; return;
} }
#if defined(LINUX) taosRUnLockLatch(lock);
pthread_rwlock_rdlock(lock);
#else
pthread_mutex_lock(lock);
#endif
} }
static FORCE_INLINE void __unlock(void *lock) { static FORCE_INLINE void __wr_unlock(void *lock, int32_t type) {
if (lock == NULL) { if (type == HASH_NO_LOCK) {
return; return;
} }
#if defined(LINUX) taosWUnLockLatch(lock);
pthread_rwlock_unlock(lock);
#else
pthread_mutex_unlock(lock);
#endif
}
static FORCE_INLINE int32_t __lock_init(void *lock) {
if (lock == NULL) {
return 0;
}
#if defined(LINUX)
return pthread_rwlock_init(lock, NULL);
#else
return pthread_mutex_init(lock, NULL);
#endif
}
static FORCE_INLINE void __lock_destroy(void *lock) {
if (lock == NULL) {
return;
}
#if defined(LINUX)
pthread_rwlock_destroy(lock);
#else
pthread_mutex_destroy(lock);
#endif
} }
static FORCE_INLINE int32_t taosHashCapacity(int32_t length) { static FORCE_INLINE int32_t taosHashCapacity(int32_t length) {
@ -97,32 +68,38 @@ static FORCE_INLINE int32_t taosHashCapacity(int32_t length) {
* @param hashVal hash value by hash function * @param hashVal hash value by hash function
* @return * @return
*/ */
FORCE_INLINE SHashNode *doGetNodeFromHashTable(SHashObj *pHashObj, const void *key, uint32_t keyLen, uint32_t hashVal) {
int32_t slot = HASH_INDEX(hashVal, pHashObj->capacity);
SHashEntry *pe = pHashObj->hashList[slot];
// no data, return directly
int32_t num = atomic_load_32(&pe->num);
if (num == 0) {
return NULL;
}
if (pHashObj->lockType == HASH_ENTRY_LOCK) {
taosRLockLatch(&pe->latch);
}
static FORCE_INLINE SHashNode* doSearchEntryList(SHashEntry* pe, const void* key, size_t keyLen, uint32_t hashVal) {
SHashNode* pNode = pe->head.next; SHashNode* pNode = pe->head.next;
while (pNode) { while (pNode) {
if ((pNode->keyLen == keyLen) && (memcmp(pNode->key, key, keyLen) == 0)) { if ((pNode->keyLen == keyLen) && (memcmp(pNode->key, key, keyLen) == 0)) {
assert(pNode->hashVal == hashVal); assert(pNode->hashVal == hashVal);
break; break;
} }
pNode = pNode->next; pNode = pNode->next;
} }
if (pHashObj->lockType == HASH_ENTRY_LOCK) { return pNode;
}
static FORCE_INLINE SHashNode *doGetNodeFromHashTable(SHashObj *pHashObj, const void *key, uint32_t keyLen, uint32_t hashVal) {
int32_t slot = HASH_INDEX(hashVal, pHashObj->capacity);
SHashEntry *pe = pHashObj->hashList[slot];
// no data, return directly
if (atomic_load_32(&pe->num) == 0) {
return NULL;
}
if (pHashObj->type == HASH_ENTRY_LOCK) {
taosRLockLatch(&pe->latch);
}
SHashNode* pNode = doSearchEntryList(pe, key, keyLen, hashVal);
if (pHashObj->type == HASH_ENTRY_LOCK) {
taosRUnLockLatch(&pe->latch); taosRUnLockLatch(&pe->latch);
} }
@ -195,7 +172,7 @@ SHashObj *taosHashInit(size_t capacity, _hash_fn_t fn, bool update, SHashLockTyp
assert((pHashObj->capacity & (pHashObj->capacity - 1)) == 0); assert((pHashObj->capacity & (pHashObj->capacity - 1)) == 0);
pHashObj->hashFp = fn; pHashObj->hashFp = fn;
pHashObj->lockType = type; pHashObj->type = type;
pHashObj->enableUpdate = update; pHashObj->enableUpdate = update;
pHashObj->hashList = (SHashEntry **)calloc(pHashObj->capacity, sizeof(void*)); pHashObj->hashList = (SHashEntry **)calloc(pHashObj->capacity, sizeof(void*));
@ -215,22 +192,6 @@ SHashObj *taosHashInit(size_t capacity, _hash_fn_t fn, bool update, SHashLockTyp
taosArrayPush(pHashObj->pMemBlock, &p); taosArrayPush(pHashObj->pMemBlock, &p);
} }
if (pHashObj->lockType != HASH_NO_LOCK) {
#if defined(LINUX)
pHashObj->lock.lock = calloc(1, sizeof(pthread_rwlock_t));
#else
pHashObj->lock.lock = calloc(1, sizeof(pthread_mutex_t));
#endif
}
if (__lock_init(pHashObj->lock.lock) != 0) {
free(pHashObj->hashList);
free(pHashObj);
uError("failed to init lock, reason:%s", strerror(errno));
return NULL;
}
return pHashObj; return pHashObj;
} }
@ -247,17 +208,17 @@ int32_t taosHashPut(SHashObj *pHashObj, const void *key, size_t keyLen, void *da
// need the resize process, write lock applied // need the resize process, write lock applied
if (HASH_NEED_RESIZE(pHashObj)) { if (HASH_NEED_RESIZE(pHashObj)) {
__wr_lock(pHashObj->lock.lock); __wr_lock(&pHashObj->lock, pHashObj->type);
taosHashTableResize(pHashObj); taosHashTableResize(pHashObj);
__unlock(pHashObj->lock.lock); __wr_unlock(&pHashObj->lock, pHashObj->type);
} }
__rd_lock(pHashObj->lock.lock); __rd_lock(&pHashObj->lock, pHashObj->type);
int32_t slot = HASH_INDEX(hashVal, pHashObj->capacity); int32_t slot = HASH_INDEX(hashVal, pHashObj->capacity);
SHashEntry *pe = pHashObj->hashList[slot]; SHashEntry *pe = pHashObj->hashList[slot];
if (pHashObj->lockType == HASH_ENTRY_LOCK) { if (pHashObj->type == HASH_ENTRY_LOCK) {
taosWLockLatch(&pe->latch); taosWLockLatch(&pe->latch);
} }
@ -275,12 +236,12 @@ int32_t taosHashPut(SHashObj *pHashObj, const void *key, size_t keyLen, void *da
// no data in hash table with the specified key, add it into hash table // no data in hash table with the specified key, add it into hash table
pushfrontNode(pe, pNewNode); pushfrontNode(pe, pNewNode);
if (pHashObj->lockType == HASH_ENTRY_LOCK) { if (pHashObj->type == HASH_ENTRY_LOCK) {
taosWUnLockLatch(&pe->latch); taosWUnLockLatch(&pe->latch);
} }
// enable resize // enable resize
__unlock(pHashObj->lock.lock); __rd_unlock(&pHashObj->lock, pHashObj->type);
atomic_add_fetch_64(&pHashObj->size, 1); atomic_add_fetch_64(&pHashObj->size, 1);
return 0; return 0;
@ -290,12 +251,12 @@ int32_t taosHashPut(SHashObj *pHashObj, const void *key, size_t keyLen, void *da
doUpdateHashNode(pNode, pNewNode); doUpdateHashNode(pNode, pNewNode);
} }
if (pHashObj->lockType == HASH_ENTRY_LOCK) { if (pHashObj->type == HASH_ENTRY_LOCK) {
taosWUnLockLatch(&pe->latch); taosWUnLockLatch(&pe->latch);
} }
// enable resize // enable resize
__unlock(pHashObj->lock.lock); __rd_unlock(&pHashObj->lock, pHashObj->type);
tfree(pNewNode->data) tfree(pNewNode->data)
tfree(pNewNode); tfree(pNewNode);
@ -312,11 +273,11 @@ void *taosHashGet(SHashObj *pHashObj, const void *key, size_t keyLen) {
uint32_t hashVal = (*pHashObj->hashFp)(key, keyLen); uint32_t hashVal = (*pHashObj->hashFp)(key, keyLen);
// only add the read lock to disable the resize process // only add the read lock to disable the resize process
__rd_lock(pHashObj->lock.lock); __rd_lock(&pHashObj->lock, pHashObj->type);
SHashNode *pNode = doGetNodeFromHashTable(pHashObj, key, keyLen, hashVal); SHashNode *pNode = doGetNodeFromHashTable(pHashObj, key, keyLen, hashVal);
__unlock(pHashObj->lock.lock); __rd_unlock(&pHashObj->lock, pHashObj->type);
if (pNode) { if (pNode) {
assert(pNode->hashVal == hashVal); assert(pNode->hashVal == hashVal);
@ -327,70 +288,7 @@ void *taosHashGet(SHashObj *pHashObj, const void *key, size_t keyLen) {
} }
int32_t taosHashRemove(SHashObj *pHashObj, const void *key, size_t keyLen) { int32_t taosHashRemove(SHashObj *pHashObj, const void *key, size_t keyLen) {
if (pHashObj->size <= 0) { return taosHashRemoveNode(pHashObj, key, keyLen, NULL, 0);
return -1;
}
uint32_t hashVal = (*pHashObj->hashFp)(key, keyLen);
// disable the resize process
__rd_lock(pHashObj->lock.lock);
int32_t slot = HASH_INDEX(hashVal, pHashObj->capacity);
SHashEntry *pe = pHashObj->hashList[slot];
// no data, return directly
if (pe->num == 0) {
__unlock(pHashObj->lock.lock);
return -1;
}
if (pHashObj->lockType == HASH_ENTRY_LOCK) {
taosWLockLatch(&pe->latch);
}
SHashNode* pNode = pe->head.next;
while (pNode) {
if ((pNode->keyLen == keyLen) && (memcmp(pNode->key, key, keyLen) == 0)) {
assert(pNode->hashVal == hashVal);
break;
}
pNode = pNode->next;
}
if (pNode != NULL) {
assert(pNode->prev != NULL);
SHashNode *pNext = pNode->next;
pNode->prev->next = pNext;
if (pNext != NULL) {
pNext->prev = pNode->prev;
}
pe->num -= 1;
}
if (pHashObj->lockType == HASH_ENTRY_LOCK) {
taosWUnLockLatch(&pe->latch);
}
__unlock(pHashObj->lock.lock);
if (pNode != NULL) {
atomic_sub_fetch_64(&pHashObj->size, 1);
pNode->next = NULL;
pNode->prev = NULL;
tfree(pNode->data);
tfree(pNode);
return 0;
} else {
return -1;
}
} }
int32_t taosHashRemoveNode(SHashObj *pHashObj, const void *key, size_t keyLen, void* data, size_t dsize) { int32_t taosHashRemoveNode(SHashObj *pHashObj, const void *key, size_t keyLen, void* data, size_t dsize) {
@ -401,31 +299,22 @@ int32_t taosHashRemoveNode(SHashObj *pHashObj, const void *key, size_t keyLen, v
uint32_t hashVal = (*pHashObj->hashFp)(key, keyLen); uint32_t hashVal = (*pHashObj->hashFp)(key, keyLen);
// disable the resize process // disable the resize process
__rd_lock(pHashObj->lock.lock); __rd_lock(&pHashObj->lock, pHashObj->type);
int32_t slot = HASH_INDEX(hashVal, pHashObj->capacity); int32_t slot = HASH_INDEX(hashVal, pHashObj->capacity);
SHashEntry *pe = pHashObj->hashList[slot]; SHashEntry *pe = pHashObj->hashList[slot];
// no data, return directly // no data, return directly
if (pe->num == 0) { if (pe->num == 0) {
__unlock(pHashObj->lock.lock); __rd_unlock(&pHashObj->lock, pHashObj->type);
return -1; return -1;
} }
if (pHashObj->lockType == HASH_ENTRY_LOCK) { if (pHashObj->type == HASH_ENTRY_LOCK) {
taosWLockLatch(&pe->latch); taosWLockLatch(&pe->latch);
} }
SHashNode* pNode = pe->head.next; SHashNode* pNode = doSearchEntryList(pe, key, keyLen, hashVal);
while (pNode) {
if ((pNode->keyLen == keyLen) && (memcmp(pNode->key, key, keyLen) == 0)) {
assert(pNode->hashVal == hashVal);
break;
}
pNode = pNode->next;
}
if (pNode != NULL) { if (pNode != NULL) {
assert(pNode->prev != NULL); assert(pNode->prev != NULL);
@ -435,14 +324,15 @@ int32_t taosHashRemoveNode(SHashObj *pHashObj, const void *key, size_t keyLen, v
if (pNext != NULL) { if (pNext != NULL) {
pNext->prev = pNode->prev; pNext->prev = pNode->prev;
} }
pe->num -= 1;
} }
if (pHashObj->lockType == HASH_ENTRY_LOCK) { if (pHashObj->type == HASH_ENTRY_LOCK) {
pe->num -= 1;
taosWUnLockLatch(&pe->latch); taosWUnLockLatch(&pe->latch);
} }
__unlock(pHashObj->lock.lock); __rd_unlock(&pHashObj->lock, pHashObj->type);
atomic_sub_fetch_64(&pHashObj->size, 1); atomic_sub_fetch_64(&pHashObj->size, 1);
@ -470,7 +360,7 @@ void taosHashCleanup(SHashObj *pHashObj) {
SHashNode *pNode, *pNext; SHashNode *pNode, *pNext;
__wr_lock(pHashObj->lock.lock); __wr_lock(&pHashObj->lock, pHashObj->type);
if (pHashObj->hashList) { if (pHashObj->hashList) {
for (int32_t i = 0; i < pHashObj->capacity; ++i) { for (int32_t i = 0; i < pHashObj->capacity; ++i) {
@ -496,10 +386,7 @@ void taosHashCleanup(SHashObj *pHashObj) {
free(pHashObj->hashList); free(pHashObj->hashList);
} }
__unlock(pHashObj->lock.lock); __wr_unlock(&pHashObj->lock, pHashObj->type);
__lock_destroy(pHashObj->lock.lock);
tfree(pHashObj->lock.lock);
// destroy mem block // destroy mem block
size_t memBlock = taosArrayGetSize(pHashObj->pMemBlock); size_t memBlock = taosArrayGetSize(pHashObj->pMemBlock);

View File

@ -289,7 +289,7 @@ void *taosCachePut(SCacheObj *pCacheObj, const void *key, size_t keyLen, const v
pCacheObj->name, key, pNode1->data, pNode1->addedTime, pNode1->expireTime, pCacheObj->name, key, pNode1->data, pNode1->addedTime, pNode1->expireTime,
(int32_t)taosHashGetSize(pCacheObj->pHashTable), pCacheObj->totalSize, (int64_t)dataSize); (int32_t)taosHashGetSize(pCacheObj->pHashTable), pCacheObj->totalSize, (int64_t)dataSize);
return pNode1; return pNode1->data;
} else { } else {
// failed, try again // failed, try again