cache
This commit is contained in:
parent
1360f6b265
commit
9df1fed6ab
|
@ -13,17 +13,16 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _TD_UTIL_CACHE_H
|
#ifndef _TD_UTIL_CACHE_H_
|
||||||
#define _TD_UTIL_CACHE_H
|
#define _TD_UTIL_CACHE_H_
|
||||||
|
|
||||||
|
#include "thash.h"
|
||||||
|
#include "tlockfree.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "os.h"
|
|
||||||
#include "tlockfree.h"
|
|
||||||
#include "thash.h"
|
|
||||||
|
|
||||||
#if defined(_TD_ARM_32)
|
#if defined(_TD_ARM_32)
|
||||||
#define TSDB_CACHE_PTR_KEY TSDB_DATA_TYPE_INT
|
#define TSDB_CACHE_PTR_KEY TSDB_DATA_TYPE_INT
|
||||||
#define TSDB_CACHE_PTR_TYPE int32_t
|
#define TSDB_CACHE_PTR_TYPE int32_t
|
||||||
|
@ -101,7 +100,8 @@ typedef struct {
|
||||||
* @param fn free resource callback function
|
* @param fn free resource callback function
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
SCacheObj *taosCacheInit(int32_t keyType, int64_t refreshTimeInSeconds, bool extendLifespan, __cache_free_fn_t fn, const char *cacheName);
|
SCacheObj *taosCacheInit(int32_t keyType, int64_t refreshTimeInSeconds, bool extendLifespan, __cache_free_fn_t fn,
|
||||||
|
const char *cacheName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* add data into cache
|
* add data into cache
|
||||||
|
@ -113,7 +113,8 @@ SCacheObj *taosCacheInit(int32_t keyType, int64_t refreshTimeInSeconds, bool ext
|
||||||
* @param keepTime survival time in second
|
* @param keepTime survival time in second
|
||||||
* @return cached element
|
* @return cached element
|
||||||
*/
|
*/
|
||||||
void *taosCachePut(SCacheObj *pCacheObj, const void *key, size_t keyLen, const void *pData, size_t dataSize, int durationMS);
|
void *taosCachePut(SCacheObj *pCacheObj, const void *key, size_t keyLen, const void *pData, size_t dataSize,
|
||||||
|
int32_t durationMS);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get data from cache
|
* get data from cache
|
||||||
|
@ -188,4 +189,4 @@ void taosStopCacheRefreshWorker();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /*_TD_UTIL_CACHE_H*/
|
#endif /*_TD_UTIL_CACHE_H_*/
|
||||||
|
|
|
@ -14,11 +14,10 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define _DEFAULT_SOURCE
|
#define _DEFAULT_SOURCE
|
||||||
#include "os.h"
|
#include "tcache.h"
|
||||||
#include "tlog.h"
|
#include "tlog.h"
|
||||||
#include "ttimer.h"
|
#include "ttimer.h"
|
||||||
#include "tutil.h"
|
#include "tutil.h"
|
||||||
#include "tcache.h"
|
|
||||||
|
|
||||||
static FORCE_INLINE void __cache_wr_lock(SCacheObj *pCacheObj) {
|
static FORCE_INLINE void __cache_wr_lock(SCacheObj *pCacheObj) {
|
||||||
#if defined(LINUX)
|
#if defined(LINUX)
|
||||||
|
@ -102,7 +101,8 @@ pthread_t doRegisterCacheObj(SCacheObj* pCacheObj) {
|
||||||
* @param lifespan total survial expiredTime from now
|
* @param lifespan total survial expiredTime from now
|
||||||
* @return SCacheDataNode
|
* @return SCacheDataNode
|
||||||
*/
|
*/
|
||||||
static SCacheDataNode *taosCreateCacheNode(const char *key, size_t keyLen, const char *pData, size_t size, uint64_t duration);
|
static SCacheDataNode *taosCreateCacheNode(const char *key, size_t keyLen, const char *pData, size_t size,
|
||||||
|
uint64_t duration);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* addedTime object node into trash, and this object is closed for referencing if it is addedTime to trash
|
* addedTime object node into trash, and this object is closed for referencing if it is addedTime to trash
|
||||||
|
@ -181,7 +181,8 @@ static FORCE_INLINE void doDestroyTrashcanElem(SCacheObj* pCacheObj, STrashElem
|
||||||
free(pElem);
|
free(pElem);
|
||||||
}
|
}
|
||||||
|
|
||||||
SCacheObj *taosCacheInit(int32_t keyType, int64_t refreshTimeInSeconds, bool extendLifespan, __cache_free_fn_t fn, const char* cacheName) {
|
SCacheObj *taosCacheInit(int32_t keyType, int64_t refreshTimeInSeconds, bool extendLifespan, __cache_free_fn_t fn,
|
||||||
|
const char *cacheName) {
|
||||||
const int32_t SLEEP_DURATION = 500; // 500 ms
|
const int32_t SLEEP_DURATION = 500; // 500 ms
|
||||||
|
|
||||||
if (refreshTimeInSeconds <= 0) {
|
if (refreshTimeInSeconds <= 0) {
|
||||||
|
@ -220,7 +221,8 @@ SCacheObj *taosCacheInit(int32_t keyType, int64_t refreshTimeInSeconds, bool ext
|
||||||
return pCacheObj;
|
return pCacheObj;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *taosCachePut(SCacheObj *pCacheObj, const void *key, size_t keyLen, const void *pData, size_t dataSize, int durationMS) {
|
void *taosCachePut(SCacheObj *pCacheObj, const void *key, size_t keyLen, const void *pData, size_t dataSize,
|
||||||
|
int32_t durationMS) {
|
||||||
if (pCacheObj == NULL || pCacheObj->pHashTable == NULL || pCacheObj->deleting == 1) {
|
if (pCacheObj == NULL || pCacheObj->pHashTable == NULL || pCacheObj->deleting == 1) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -311,7 +313,8 @@ void *taosCacheAcquireByKey(SCacheObj *pCacheObj, const void *key, size_t keyLen
|
||||||
|
|
||||||
if (pData != NULL) {
|
if (pData != NULL) {
|
||||||
atomic_add_fetch_32(&pCacheObj->statistics.hitCount, 1);
|
atomic_add_fetch_32(&pCacheObj->statistics.hitCount, 1);
|
||||||
uDebug("cache:%s, key:%p, %p is retrieved from cache, refcnt:%d", pCacheObj->name, key, pData, T_REF_VAL_GET(ptNode));
|
uDebug("cache:%s, key:%p, %p is retrieved from cache, refcnt:%d", pCacheObj->name, key, pData,
|
||||||
|
T_REF_VAL_GET(ptNode));
|
||||||
} else {
|
} else {
|
||||||
atomic_add_fetch_32(&pCacheObj->statistics.missCount, 1);
|
atomic_add_fetch_32(&pCacheObj->statistics.missCount, 1);
|
||||||
uDebug("cache:%s, key:%p, not in cache, retrieved failed", pCacheObj->name, key);
|
uDebug("cache:%s, key:%p, not in cache, retrieved failed", pCacheObj->name, key);
|
||||||
|
@ -371,7 +374,6 @@ void taosCacheRelease(SCacheObj *pCacheObj, void **data, bool _remove) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// The operation of removal from hash table and addition to trashcan is not an atomic operation,
|
// The operation of removal from hash table and addition to trashcan is not an atomic operation,
|
||||||
// therefore the check for the empty of both the hash table and the trashcan has a race condition.
|
// therefore the check for the empty of both the hash table and the trashcan has a race condition.
|
||||||
// It happens when there is only one object in the cache, and two threads which has referenced this object
|
// It happens when there is only one object in the cache, and two threads which has referenced this object
|
||||||
|
@ -403,8 +405,8 @@ void taosCacheRelease(SCacheObj *pCacheObj, void **data, bool _remove) {
|
||||||
uDebug("cache:%s, key:%p, %p is released, refcnt:%d, in trashcan:%d", pCacheObj->name, key, d, ref - 1, inTrashcan);
|
uDebug("cache:%s, key:%p, %p is released, refcnt:%d, in trashcan:%d", pCacheObj->name, key, d, ref - 1, inTrashcan);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If it is not referenced by other users, remove it immediately. Otherwise move this node to trashcan wait for all users
|
* If it is not referenced by other users, remove it immediately. Otherwise move this node to trashcan wait for all
|
||||||
* releasing this resources.
|
* users releasing this resources.
|
||||||
*
|
*
|
||||||
* NOTE: previous ref is 0, and current ref is still 0, remove it. If previous is not 0, there is another thread
|
* NOTE: previous ref is 0, and current ref is still 0, remove it. If previous is not 0, there is another thread
|
||||||
* that tries to do the same thing.
|
* that tries to do the same thing.
|
||||||
|
@ -434,15 +436,18 @@ void taosCacheRelease(SCacheObj *pCacheObj, void **data, bool _remove) {
|
||||||
// when reaches here.
|
// when reaches here.
|
||||||
SCacheDataNode *p = NULL;
|
SCacheDataNode *p = NULL;
|
||||||
int32_t ret = taosHashRemove(pCacheObj->pHashTable, pNode->key, pNode->keySize);
|
int32_t ret = taosHashRemove(pCacheObj->pHashTable, pNode->key, pNode->keySize);
|
||||||
// int32_t ret = taosHashRemoveWithData(pCacheObj->pHashTable, pNode->key, pNode->keySize, &p, sizeof(void *));
|
// int32_t ret = taosHashRemoveWithData(pCacheObj->pHashTable, pNode->key, pNode->keySize, &p, sizeof(void
|
||||||
|
// *));
|
||||||
ref = T_REF_DEC(pNode);
|
ref = T_REF_DEC(pNode);
|
||||||
|
|
||||||
// successfully remove from hash table, if failed, this node must have been move to trash already, do nothing.
|
// successfully remove from hash table, if failed, this node must have been move to trash already, do nothing.
|
||||||
// note that the remove operation can be executed only once.
|
// note that the remove operation can be executed only once.
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
if (p != pNode) {
|
if (p != pNode) {
|
||||||
uDebug( "cache:%s, key:%p, successfully removed a new entry:%p, refcnt:%d, prev entry:%p has been removed by "
|
uDebug(
|
||||||
"others already", pCacheObj->name, pNode->key, p->data, T_REF_VAL_GET(p), pNode->data);
|
"cache:%s, key:%p, successfully removed a new entry:%p, refcnt:%d, prev entry:%p has been removed by "
|
||||||
|
"others already",
|
||||||
|
pCacheObj->name, pNode->key, p->data, T_REF_VAL_GET(p), pNode->data);
|
||||||
|
|
||||||
assert(p->pTNodeHeader == NULL);
|
assert(p->pTNodeHeader == NULL);
|
||||||
taosAddToTrashcan(pCacheObj, p);
|
taosAddToTrashcan(pCacheObj, p);
|
||||||
|
@ -468,8 +473,8 @@ void taosCacheRelease(SCacheObj *pCacheObj, void **data, bool _remove) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
uDebug("cache:%s, key:%p, %p has been removed from hash table by others already, refcnt:%d",
|
uDebug("cache:%s, key:%p, %p has been removed from hash table by others already, refcnt:%d", pCacheObj->name,
|
||||||
pCacheObj->name, pNode->key, pNode->data, ref);
|
pNode->key, pNode->data, ref);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -481,7 +486,8 @@ void taosCacheRelease(SCacheObj *pCacheObj, void **data, bool _remove) {
|
||||||
// int32_t ref = T_REF_VAL_GET(pNode);
|
// int32_t ref = T_REF_VAL_GET(pNode);
|
||||||
//
|
//
|
||||||
// if (ref == 1 && inTrashcan) {
|
// if (ref == 1 && inTrashcan) {
|
||||||
// // If it is the last ref, remove it from trashcan linked-list first, and then destroy it.Otherwise, it may be
|
// // If it is the last ref, remove it from trashcan linked-list first, and then destroy it.Otherwise, it may
|
||||||
|
// be
|
||||||
// // destroyed by refresh worker if decrease ref count before removing it from linked-list.
|
// // destroyed by refresh worker if decrease ref count before removing it from linked-list.
|
||||||
// assert(pNode->pTNodeHeader->pData == pNode);
|
// assert(pNode->pTNodeHeader->pData == pNode);
|
||||||
//
|
//
|
||||||
|
@ -610,7 +616,8 @@ void taosTrashcanEmpty(SCacheObj *pCacheObj, bool force) {
|
||||||
if (pCacheObj->numOfElemsInTrash == 0) {
|
if (pCacheObj->numOfElemsInTrash == 0) {
|
||||||
if (pCacheObj->pTrash != NULL) {
|
if (pCacheObj->pTrash != NULL) {
|
||||||
pCacheObj->pTrash = NULL;
|
pCacheObj->pTrash = NULL;
|
||||||
uError("cache:%s, key:inconsistency data in cache, numOfElem in trashcan:%d", pCacheObj->name, pCacheObj->numOfElemsInTrash);
|
uError("cache:%s, key:inconsistency data in cache, numOfElem in trashcan:%d", pCacheObj->name,
|
||||||
|
pCacheObj->numOfElemsInTrash);
|
||||||
}
|
}
|
||||||
|
|
||||||
__cache_unlock(pCacheObj);
|
__cache_unlock(pCacheObj);
|
||||||
|
@ -627,8 +634,8 @@ void taosTrashcanEmpty(SCacheObj *pCacheObj, bool force) {
|
||||||
assert(pElem->next != pElem && pElem->prev != pElem);
|
assert(pElem->next != pElem && pElem->prev != pElem);
|
||||||
|
|
||||||
if (force || (T_REF_VAL_GET(pElem->pData) == 0)) {
|
if (force || (T_REF_VAL_GET(pElem->pData) == 0)) {
|
||||||
uDebug("cache:%s, key:%p, %p removed from trashcan. numOfElem in trashcan:%d", pCacheObj->name, pElem->pData->key, pElem->pData->data,
|
uDebug("cache:%s, key:%p, %p removed from trashcan. numOfElem in trashcan:%d", pCacheObj->name, pElem->pData->key,
|
||||||
pCacheObj->numOfElemsInTrash - 1);
|
pElem->pData->data, pCacheObj->numOfElemsInTrash - 1);
|
||||||
|
|
||||||
doRemoveElemInTrashcan(pCacheObj, pElem);
|
doRemoveElemInTrashcan(pCacheObj, pElem);
|
||||||
doDestroyTrashcanElem(pCacheObj, pElem);
|
doDestroyTrashcanElem(pCacheObj, pElem);
|
||||||
|
@ -777,6 +784,4 @@ void taosCacheRefresh(SCacheObj *pCacheObj, __cache_trav_fn_t fp, void* param1)
|
||||||
doCacheRefresh(pCacheObj, now, fp, param1);
|
doCacheRefresh(pCacheObj, now, fp, param1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void taosStopCacheRefreshWorker(void) {
|
void taosStopCacheRefreshWorker(void) { stopRefreshWorker = true; }
|
||||||
stopRefreshWorker = true;
|
|
||||||
}
|
|
Loading…
Reference in New Issue