diff --git a/check_void_result.txt b/check_void_result.txt new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/include/libs/executor/storageapi.h b/include/libs/executor/storageapi.h index 2f4efebc5d75..830424c4a001 100644 --- a/include/libs/executor/storageapi.h +++ b/include/libs/executor/storageapi.h @@ -298,6 +298,12 @@ typedef struct SStoreMeta { bool* acquireRes); int32_t (*putCachedTableList)(void* pVnode, uint64_t suid, const void* pKey, int32_t keyLen, void* pPayload, int32_t payloadLen, double selectivityRatio); + int32_t (*getStableCachedTableList)(void* pVnode, tb_uid_t suid, + const uint8_t* pTagCondKey, int32_t tagCondKeyLen, + const uint8_t* pKey, int32_t keyLen, SArray* pList1, bool* acquireRes); + int32_t (*putStableCachedTableList)(void* pVnode, uint64_t suid, + const void* pTagCondKey, int32_t tagCondKeyLen, + const void* pKey, int32_t keyLen, SArray* pUidList, SArray* pTagColIds); int32_t (*metaGetCachedRefDbs)(void* pVnode, tb_uid_t suid, SArray* pList); int32_t (*metaPutRefDbsToCache)(void* pVnode, tb_uid_t suid, SArray* pList); diff --git a/include/os/osEnv.h b/include/os/osEnv.h index 85fdb7c38cd5..6acb8863e34d 100644 --- a/include/os/osEnv.h +++ b/include/os/osEnv.h @@ -43,6 +43,7 @@ extern char tsFMASupported; extern char tsAVX512Supported; extern char tsAVX512Enable; extern char tsTagFilterCache; +extern char tsStableTagFilterCache; extern char configDir[]; extern char tsDataDir[]; diff --git a/insert_res.txt b/insert_res.txt new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/source/common/src/tglobal.c b/source/common/src/tglobal.c index 50ffa167545a..244f377c0ae9 100644 --- a/source/common/src/tglobal.c +++ b/source/common/src/tglobal.c @@ -308,6 +308,7 @@ int32_t tsMaxInsertBatchRows = 1000000; float tsSelectivityRatio = 1.0; int32_t tsTagFilterResCacheSize = 1024 * 10; char tsTagFilterCache = 0; +char tsStableTagFilterCache = 0; int32_t tsBypassFlag = 0; @@ -733,6 +734,9 @@ static int32_t taosAddSystemCfg(SConfig *pCfg) { TAOS_CHECK_RETURN(cfgAddBool(pCfg, "AVX512Enable", tsAVX512Enable, CFG_SCOPE_BOTH, CFG_DYN_NONE, CFG_CATEGORY_LOCAL)); TAOS_CHECK_RETURN( cfgAddBool(pCfg, "tagFilterCache", tsTagFilterCache, CFG_SCOPE_BOTH, CFG_DYN_BOTH, CFG_CATEGORY_LOCAL)); + TAOS_CHECK_RETURN( + cfgAddBool(pCfg, "stableTagFilterCache", tsStableTagFilterCache, + CFG_SCOPE_SERVER, CFG_DYN_SERVER, CFG_CATEGORY_LOCAL)); TAOS_CHECK_RETURN( cfgAddInt64(pCfg, "openMax", tsOpenMax, 0, INT64_MAX, CFG_SCOPE_BOTH, CFG_DYN_NONE, CFG_CATEGORY_LOCAL)); @@ -1665,6 +1669,9 @@ static int32_t taosSetServerCfg(SConfig *pCfg) { TAOS_CHECK_GET_CFG_ITEM(pCfg, pItem, "tagFilterCache"); tsTagFilterCache = (bool)pItem->bval; + TAOS_CHECK_GET_CFG_ITEM(pCfg, pItem, "stableTagFilterCache"); + tsStableTagFilterCache = pItem->bval; + TAOS_CHECK_GET_CFG_ITEM(pCfg, pItem, "slowLogExceptDb"); TAOS_CHECK_RETURN(taosCheckCfgStrValueLen(pItem->name, pItem->str, TSDB_DB_NAME_LEN)); tstrncpy(tsSlowLogExceptDb, pItem->str, TSDB_DB_NAME_LEN); @@ -2810,7 +2817,8 @@ static int32_t taosCfgDynamicOptionsForServer(SConfig *pCfg, const char *name) { {"forceKillTrans", &tsForceKillTrans}, {"enableTLS", &tsEnableTLS}, {"rpcRecvLogThreshold", &tsRpcRecvLogThreshold}, - {"tagFilterCache", &tsTagFilterCache}}; + {"tagFilterCache", &tsTagFilterCache}, + {"stableTagFilterCache", &tsStableTagFilterCache}}; if ((code = taosCfgSetOption(debugOptions, tListLen(debugOptions), pItem, true)) != TSDB_CODE_SUCCESS) { code = taosCfgSetOption(options, tListLen(options), pItem, false); diff --git a/source/dnode/vnode/inc/vnode.h b/source/dnode/vnode/inc/vnode.h index 91009ba47ae2..0ae695bdd13a 100644 --- a/source/dnode/vnode/inc/vnode.h +++ b/source/dnode/vnode/inc/vnode.h @@ -141,6 +141,21 @@ int32_t metaGetCachedTableUidList(void *pVnode, tb_uid_t suid, const uint8_t *k bool *acquired); int32_t metaUidFilterCachePut(void *pVnode, uint64_t suid, const void *pKey, int32_t keyLen, void *pPayload, int32_t payloadLen, double selectivityRatio); +int32_t metaStableTagFilterCacheGet(void* pVnode, tb_uid_t suid, + const uint8_t* pTagCondKey, int32_t tagCondKeyLen, + const uint8_t* pKey, int32_t keyLen, SArray* pList, bool* acquired); +int32_t metaStableTagFilterCachePut(void* pVnode, uint64_t suid, + const void* pTagCondKey, int32_t tagCondKeyLen, + const void* pKey, int32_t keyLen, SArray* pUidList, SArray* pTagColIds); +int32_t metaStableTagFilterCacheDropSTable(SMeta* pMeta, tb_uid_t suid); +typedef enum { + STABLE_TAG_FILTER_CACHE_DROP_TABLE = 1, + STABLE_TAG_FILTER_CACHE_ADD_TABLE = 2, +} ETagFilterCacheAction; +int32_t metaStableTagFilterCacheUpdateUid( + SMeta* pMeta, const SMetaEntry* pDroppedTable, ETagFilterCacheAction action); +int32_t metaStableTagFilterCacheDropTag( + SMeta* pMeta, tb_uid_t suid, int16_t tagColId); tb_uid_t metaGetTableEntryUidByName(SMeta *pMeta, const char *name); int32_t metaGetCachedTbGroup(void *pVnode, tb_uid_t suid, const uint8_t *pKey, int32_t keyLen, SArray **pList); int32_t metaPutTbGroupToCache(void *pVnode, uint64_t suid, const void *pKey, int32_t keyLen, void *pPayload, diff --git a/source/dnode/vnode/src/meta/metaCache.c b/source/dnode/vnode/src/meta/metaCache.c index 1a9aa6574beb..a4042f530e07 100644 --- a/source/dnode/vnode/src/meta/metaCache.c +++ b/source/dnode/vnode/src/meta/metaCache.c @@ -44,6 +44,17 @@ typedef struct STagFilterResEntry { uint32_t hitTimes; // queried times for current super table } STagFilterResEntry; +typedef struct STagCondFilterEntry { + SArray* pColIds; // SArray + SHashObj* set; // SHashObj> + uint32_t hitTimes; // queried times for current tag filter condition +} STagCondFilterEntry; + +typedef struct STagConds { + SHashObj* set; // SHashObj + uint32_t hitTimes; // queried times for current super table +} STagConds; + struct SMetaCache { // child, normal, super, table entry cache struct SEntryCache { @@ -67,6 +78,14 @@ struct SMetaCache { SLRUCache* pUidResCache; } sTagFilterResCache; + // cache table list for tag filter conditions + // that match format "tag1 = v1 AND tag2 = v2 AND ..." + struct SStableTagFilterResCache { + TdThreadRwlock rwlock; + uint32_t accTimes; + SHashObj* pTableEntry; // HashObj + } sStableTagFilterResCache; + struct STbGroupResCache { TdThreadMutex lock; uint32_t accTimes; @@ -121,6 +140,19 @@ static void freeCacheEntryFp(void* param) { taosMemoryFreeClear(*p); } +static void freeTagFilterEntryFp(void* param) { + STagCondFilterEntry** p = param; + taosArrayDestroy((*p)->pColIds); + taosHashCleanup((*p)->set); + taosMemoryFreeClear(*p); +} + +static void freeTagCondsFp(void* param) { + STagConds** p = param; + taosHashCleanup((*p)->set); + taosMemoryFreeClear(*p); +} + static void freeRefDbFp(void* param) { SHashObj** p = param; taosHashCleanup(*p); @@ -170,6 +202,20 @@ int32_t metaCacheOpen(SMeta* pMeta) { taosHashSetFreeFp(pMeta->pCache->sTagFilterResCache.pTableEntry, freeCacheEntryFp); (void)taosThreadMutexInit(&pMeta->pCache->sTagFilterResCache.lock, NULL); + // open stable tag filter cache + pMeta->pCache->sStableTagFilterResCache.accTimes = 0; + pMeta->pCache->sStableTagFilterResCache.pTableEntry = + taosHashInit(1024, + taosGetDefaultHashFunction(TSDB_DATA_TYPE_VARCHAR), false, HASH_NO_LOCK); + if (pMeta->pCache->sStableTagFilterResCache.pTableEntry == NULL) { + TSDB_CHECK_CODE(code = terrno, lino, _exit); + } + taosHashSetFreeFp( + pMeta->pCache->sStableTagFilterResCache.pTableEntry, freeTagCondsFp); + + TAOS_UNUSED(taosThreadRwlockInit( + &pMeta->pCache->sStableTagFilterResCache.rwlock, NULL)); + // open group res cache pMeta->pCache->STbGroupResCache.pResCache = taosLRUCacheInit(5 * 1024 * 1024, -1, 0.5); if (pMeta->pCache->STbGroupResCache.pResCache == NULL) { @@ -230,6 +276,9 @@ void metaCacheClose(SMeta* pMeta) { (void)taosThreadMutexDestroy(&pMeta->pCache->sTagFilterResCache.lock); taosHashCleanup(pMeta->pCache->sTagFilterResCache.pTableEntry); + (void)taosThreadRwlockDestroy(&pMeta->pCache->sStableTagFilterResCache.rwlock); + taosHashCleanup(pMeta->pCache->sStableTagFilterResCache.pTableEntry); + taosHashClear(pMeta->pCache->STbGroupResCache.pTableEntry); taosLRUCacheCleanup(pMeta->pCache->STbGroupResCache.pResCache); (void)taosThreadMutexDestroy(&pMeta->pCache->STbGroupResCache.lock); @@ -578,6 +627,66 @@ int32_t metaGetCachedTableUidList(void* pVnode, tb_uid_t suid, const uint8_t* pK return TSDB_CODE_SUCCESS; } +int32_t metaStableTagFilterCacheGet(void* pVnode, tb_uid_t suid, + const uint8_t* pTagCondKey, int32_t tagCondKeyLen, + const uint8_t* pKey, int32_t keyLen, SArray* pList1, bool* acquireRes) { + + int32_t code = TSDB_CODE_SUCCESS; + int32_t lino = 0; + SMeta* pMeta = ((SVnode*)pVnode)->pMeta; + int32_t vgId = TD_VID(pMeta->pVnode); + *acquireRes = 0; + + // generate the composed key for LRU cache + SHashObj* pTableMap = pMeta->pCache->sStableTagFilterResCache.pTableEntry; + TdThreadRwlock* pRwlock = &pMeta->pCache->sStableTagFilterResCache.rwlock; + + code = taosThreadRwlockRdlock(pRwlock); + TSDB_CHECK_CODE(code, lino, _end); + pMeta->pCache->sStableTagFilterResCache.accTimes += 1; + + STagConds** pTagConds = + (STagConds**)taosHashGet(pTableMap, &suid, sizeof(tb_uid_t)); + TSDB_CHECK_NULL(pTagConds, code, lino, _end, TSDB_CODE_SUCCESS); + + STagCondFilterEntry** pFilterEntry = (STagCondFilterEntry**)taosHashGet( + (*pTagConds)->set, pTagCondKey, tagCondKeyLen); + TSDB_CHECK_NULL(pFilterEntry, code, lino, _end, TSDB_CODE_SUCCESS); + + SArray** pArray = (SArray**)taosHashGet((*pFilterEntry)->set, pKey, keyLen); + TSDB_CHECK_NULL(pArray, code, lino, _end, TSDB_CODE_SUCCESS); + + // set the result into the buffer + *acquireRes = 1; + TAOS_UNUSED(taosArrayAddBatch( + pList1, TARRAY_GET_ELEM(*pArray, 0), taosArrayGetSize(*pArray))); + + // do some bookmark work after acquiring the filter result from cache + (*pTagConds)->hitTimes += 1; + (*pFilterEntry)->hitTimes += 1; + uint32_t acc = pMeta->pCache->sTagFilterResCache.accTimes; + if ((*pTagConds)->hitTimes % 5000 == 1) { + metaInfo( + "vgId:%d, suid:%" PRIu64 ", table cache hit:%d, " + "total meta acc:%d, rate:%.2f%%, tag condition hit:%d", + vgId, suid, (*pTagConds)->hitTimes, acc, + (100 * (double)(*pTagConds)->hitTimes / acc), (*pFilterEntry)->hitTimes); + } + +_end: + if (TSDB_CODE_SUCCESS != code) { + metaError("vgId:%d, %s failed at %s:%d since %s", + vgId, __func__, __FILE__, lino, tstrerror(code)); + } + // unlock meta + code = taosThreadRwlockUnlock(pRwlock); + if (TSDB_CODE_SUCCESS != code) { + metaError("vgId:%d, %s unlock failed at %s:%d since %s", + vgId, __func__, __FILE__, lino, tstrerror(code)); + } + return code; +} + static void freeUidCachePayload(const void* key, size_t keyLen, void* value, void* ud) { (void)ud; if (value == NULL) { @@ -700,6 +809,330 @@ int32_t metaUidFilterCachePut(void* pVnode, uint64_t suid, const void* pKey, int return code; } +static void freeSArrayPtr(void* pp) { + SArray* pArray = *(SArray**)pp; + taosArrayDestroy(pArray); +} + +int32_t metaStableTagFilterCachePut( + void* pVnode, uint64_t suid, const void* pTagCondKey, int32_t tagCondKeyLen, + const void* pKey, int32_t keyLen, SArray* pUidList, SArray* pTagColIds) { + + int32_t code = TSDB_CODE_SUCCESS; + int32_t lino = 0; + SMeta* pMeta = ((SVnode*)pVnode)->pMeta; + int32_t vgId = TD_VID(pMeta->pVnode); + + SHashObj* pTableEntry = pMeta->pCache->sStableTagFilterResCache.pTableEntry; + TdThreadRwlock* pRwlock = &pMeta->pCache->sStableTagFilterResCache.rwlock; + + code = taosThreadRwlockWrlock(pRwlock); + TSDB_CHECK_CODE(code, lino, _end); + + STagConds** pTagConds = + (STagConds**)taosHashGet(pTableEntry, &suid, sizeof(uint64_t)); + if (pTagConds == NULL) { + // add new (suid -> tag conds) entry + STagConds* pEntry = (STagConds*)taosMemoryMalloc(sizeof(STagConds)); + TSDB_CHECK_NULL(pEntry, code, lino, _end, terrno); + + pEntry->hitTimes = 0; + pEntry->set = taosHashInit( + 1024, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), + false, HASH_NO_LOCK); + taosHashSetFreeFp(pEntry->set, freeTagFilterEntryFp); + TSDB_CHECK_NULL(pEntry->set, code, lino, _end, terrno); + + code = taosHashPut( + pTableEntry, &suid, sizeof(uint64_t), &pEntry, POINTER_BYTES); + TSDB_CHECK_CODE(code, lino, _end); + + pTagConds = (STagConds**)taosHashGet(pTableEntry, &suid, sizeof(uint64_t)); + TSDB_CHECK_NULL(pTagConds, code, lino, _end, terrno); + } + + STagCondFilterEntry** pFilterEntry = + (STagCondFilterEntry**)taosHashGet( + (*pTagConds)->set, pTagCondKey, tagCondKeyLen); + if (pFilterEntry == NULL) { + // add new (tag cond -> filter entry) entry + STagCondFilterEntry* pEntry = + (STagCondFilterEntry*)taosMemoryMalloc(sizeof(STagCondFilterEntry)); + TSDB_CHECK_NULL(pEntry, code, lino, _end, terrno); + + pEntry->hitTimes = 0; + pEntry->set = taosHashInit( + 1024, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), + false, HASH_NO_LOCK); + taosHashSetFreeFp(pEntry->set, freeSArrayPtr); + TSDB_CHECK_NULL(pEntry->set, code, lino, _end, terrno); + + code = taosHashPut( + (*pTagConds)->set, pTagCondKey, tagCondKeyLen, &pEntry, POINTER_BYTES); + TSDB_CHECK_CODE(code, lino, _end); + + pFilterEntry = (STagCondFilterEntry**)taosHashGet( + (*pTagConds)->set, pTagCondKey, tagCondKeyLen); + TSDB_CHECK_NULL(pFilterEntry, code, lino, _end, terrno); + (*pFilterEntry)->pColIds = taosArrayDup(pTagColIds, NULL); + } else { + // pColIds is already set, so we can destroy the new one + taosArrayDestroy(pTagColIds); + } + + // add to cache. + SArray* pPayload = taosArrayDup(pUidList, NULL); + code = taosHashPut( + (*pFilterEntry)->set, pKey, keyLen, &pPayload, POINTER_BYTES); + TSDB_CHECK_CODE(code, lino, _end); + +_end: + if (TSDB_CODE_SUCCESS != code) { + metaError("vgId:%d, %s failed at %s:%d since %s", + vgId, __func__, __FILE__, lino, tstrerror(code)); + } else { + metaDebug("vgId:%d, suid:%" PRIu64 " new tag filter cache added into cache," + " num stable:%d, tag conditions:%d", + vgId, suid, (int32_t)taosHashGetSize(pTableEntry), + pTagConds ? (int32_t)taosHashGetSize((*pTagConds)->set) : 0); + } + // unlock meta + code = taosThreadRwlockUnlock(pRwlock); + if (TSDB_CODE_SUCCESS != code) { + metaError("vgId:%d, %s unlock failed at %s:%d since %s", + vgId, __func__, __FILE__, lino, tstrerror(code)); + } + + return code; +} + +// drop all the cache entries for a super table +int32_t metaStableTagFilterCacheDropSTable( + SMeta* pMeta, tb_uid_t suid) { + if (pMeta == NULL) { + return TSDB_CODE_INVALID_PARA; + } + int32_t lino = 0; + int32_t code = TSDB_CODE_SUCCESS; + SHashObj* pTableEntry = pMeta->pCache->sStableTagFilterResCache.pTableEntry; + TdThreadRwlock* pRwlock = &pMeta->pCache->sStableTagFilterResCache.rwlock; + + code = taosThreadRwlockWrlock(pRwlock); + TSDB_CHECK_CODE(code, lino, _end); + code = taosHashRemove(pTableEntry, &suid, sizeof(tb_uid_t)); + TSDB_CHECK_CODE(code, lino, _end); + +_end: + if (TSDB_CODE_SUCCESS != code) { + metaError("vgId:%d, %s failed at %s:%d since %s", + TD_VID(pMeta->pVnode), __func__, __FILE__, lino, tstrerror(code)); + } else { + metaDebug( + "vgId:%d, suid:%" PRIu64 " stable tag filter cache dropped from cache", + TD_VID(pMeta->pVnode), suid); + } + code = taosThreadRwlockUnlock(pRwlock); + if (TSDB_CODE_SUCCESS != code) { + metaError("vgId:%d, %s unlock failed at %s:%d since %s", + TD_VID(pMeta->pVnode), __func__, __FILE__, lino, tstrerror(code)); + } + return code; +} + +static int32_t buildTagDataEntryKey( + const SArray* pColIds, STag* pTag, T_MD5_CTX* pContext) { + int32_t code = TSDB_CODE_SUCCESS; + int32_t keyLen = 0; + // get length first + for (int32_t i = 0; i < taosArrayGetSize(pColIds); i++) { + STagVal pTagValue = {.cid = *(col_id_t*)taosArrayGet(pColIds, i)}; + if (tTagGet(pTag, &pTagValue)) { + keyLen += sizeof(col_id_t); + if (IS_VAR_DATA_TYPE(pTagValue.type)) { + keyLen += pTagValue.nData; + } else { + keyLen += tDataTypes[pTagValue.type].bytes; + } + } else { + // tag value not found + code = TSDB_CODE_NOT_FOUND; + return code; + } + } + + char* pKey = taosMemoryCalloc(1, keyLen); + if (NULL == pKey) { + code = terrno; + return code; + } + + // build the key + char* pStart = pKey; + for (int32_t i = 0; i < taosArrayGetSize(pColIds); i++) { + STagVal pTagValue = {.cid = *(col_id_t*)taosArrayGet(pColIds, i)}; + if (tTagGet(pTag, &pTagValue)) { + // copy cid + memcpy(pStart, &pTagValue.cid, sizeof(col_id_t)); + pStart += sizeof(col_id_t); + // copy value + if (IS_VAR_DATA_TYPE(pTagValue.type)) { + int32_t varLen = pTagValue.nData; + memcpy(pStart, pTagValue.pData, varLen); + pStart += varLen; + } else { + int32_t typeLen = tDataTypes[pTagValue.type].bytes; + memcpy(pStart, &pTagValue.i64, typeLen); + pStart += typeLen; + } + } else { + // tag value not found + taosMemoryFree(pKey); + code = TSDB_CODE_NOT_FOUND; + return code; + } + } + + // update MD5 + tMD5Init(pContext); + tMD5Update(pContext, (uint8_t*)pKey, (uint32_t)keyLen); + tMD5Final(pContext); + + return code; +} + +// remove the dropped table uid from all cache entries +// pDroppedTable is the dropped child table meta entry +int32_t metaStableTagFilterCacheUpdateUid(SMeta* pMeta, + const SMetaEntry* pDroppedTable, ETagFilterCacheAction action) { + if (pMeta == NULL || pDroppedTable == NULL) { + return TSDB_CODE_INVALID_PARA; + } + int32_t lino = 0; + int32_t code = TSDB_CODE_SUCCESS; + SHashObj* pTableEntry = pMeta->pCache->sStableTagFilterResCache.pTableEntry; + TdThreadRwlock* pRwlock = &pMeta->pCache->sStableTagFilterResCache.rwlock; + + code = taosThreadRwlockWrlock(pRwlock); + TSDB_CHECK_CODE(code, lino, _end); + + tb_uid_t suid = pDroppedTable->ctbEntry.suid;; + STagConds** pTagConds = + (STagConds**)taosHashGet(pTableEntry, &suid, sizeof(tb_uid_t)); + if (pTagConds != NULL) { + STagCondFilterEntry** ppFilterEntry = NULL; + while (ppFilterEntry = taosHashIterate((*pTagConds)->set, ppFilterEntry)) { + STagCondFilterEntry* pFilterEntry = *ppFilterEntry; + // rebuild the tagCondKey and check existence + SArray* pColIds = pFilterEntry->pColIds; + // rebuild the tagCondFilterKey + int32_t keyLen = 0; + char* pKey = NULL; + T_MD5_CTX context = {0}; + code = buildTagDataEntryKey(pColIds, (STag*)pDroppedTable->ctbEntry.pTags, &context); + if (code != TSDB_CODE_SUCCESS) { + metaError("vgId:%d, suid:%" PRIu64 " failed to build tag condition key for dropped table uid:%" PRIu64 + " since %s", + TD_VID(pMeta->pVnode), suid, pDroppedTable->uid, tstrerror(code)); + goto _end; + } + + SArray** pArray = (SArray**)taosHashGet( + pFilterEntry->set, context.digest, tListLen(context.digest)); + if (pArray != NULL) { + // check and remove the dropped table uid from the array + // TODO(Tony Zhang): optimize this scan + if (action == STABLE_TAG_FILTER_CACHE_DROP_TABLE) { + for (int32_t i = 0; i < taosArrayGetSize(*pArray); i++) { + uint64_t uid = *(uint64_t*)taosArrayGet(*pArray, i); + if (uid == pDroppedTable->uid) { + taosArrayRemove(*pArray, i); + metaDebug("vgId:%d, suid:%" PRIu64 " removed dropped table uid:%" PRIu64 + " from stable tag filter cache", + TD_VID(pMeta->pVnode), suid, pDroppedTable->uid); + break; + } + } + } else { + // STABLE_TAG_FILTER_CACHE_ADD_TABLE + void* _tmp = taosArrayPush(*pArray, &pDroppedTable->uid); + } + } + } + } + +_end: + if (TSDB_CODE_SUCCESS != code) { + metaError("vgId:%d, %s failed at %s:%d since %s", + TD_VID(pMeta->pVnode), __func__, __FILE__, lino, tstrerror(code)); + } else { + metaDebug( + "vgId:%d, suid:%" PRIu64 " dropped table uid:%" PRIu64 + " removed from stable tag filter cache", + TD_VID(pMeta->pVnode), + pDroppedTable->ctbEntry.suid, pDroppedTable->uid); + } + code = taosThreadRwlockUnlock(pRwlock); + if (TSDB_CODE_SUCCESS != code) { + metaError("vgId:%d, %s unlock failed at %s:%d since %s", + TD_VID(pMeta->pVnode), __func__, __FILE__, lino, tstrerror(code)); + } + return code; +} + +int32_t metaStableTagFilterCacheDropTag(SMeta* pMeta, + tb_uid_t suid, col_id_t cid) { + if (pMeta == NULL) { + return TSDB_CODE_INVALID_PARA; + } + int32_t lino = 0; + int32_t code = TSDB_CODE_SUCCESS; + SHashObj* pTableEntry = pMeta->pCache->sStableTagFilterResCache.pTableEntry; + TdThreadRwlock* pRwlock = &pMeta->pCache->sStableTagFilterResCache.rwlock; + + code = taosThreadRwlockWrlock(pRwlock); + TSDB_CHECK_CODE(code, lino, _end); + + STagConds** pTagConds = + (STagConds**)taosHashGet(pTableEntry, &suid, sizeof(tb_uid_t)); + if (pTagConds != NULL) { + void* pIter = taosHashIterate((*pTagConds)->set, NULL); + while (pIter) { + STagCondFilterEntry* pFilterEntry = *(STagCondFilterEntry**)pIter; + bool found = false; + for (int32_t i = 0; i < taosArrayGetSize(pFilterEntry->pColIds); i++) { + col_id_t existCid = *(col_id_t*)taosArrayGet(pFilterEntry->pColIds, i); + if (existCid == cid) { + found = true; + break; + } + } + if (found) { + size_t keyLen = 0; + char *key = (char *)taosHashGetKey(pIter, &keyLen); + code = taosHashRemove((*pTagConds)->set, key, keyLen); + TSDB_CHECK_CODE(code, lino, _end); + } + pIter = taosHashIterate((*pTagConds)->set, pIter); + } + } +_end: + if (TSDB_CODE_SUCCESS != code) { + metaError("vgId:%d, %s failed at %s:%d since %s", + TD_VID(pMeta->pVnode), __func__, __FILE__, lino, tstrerror(code)); + } else { + metaDebug( + "vgId:%d, suid:%" PRIu64 " dropped tag cid:%d " + "from stable tag filter cache", + TD_VID(pMeta->pVnode), suid, cid); + } + code = taosThreadRwlockUnlock(pRwlock); + if (TSDB_CODE_SUCCESS != code) { + metaError("vgId:%d, %s unlock failed at %s:%d since %s", + TD_VID(pMeta->pVnode), __func__, __FILE__, lino, tstrerror(code)); + } + return code; +} + void metaCacheClear(SMeta* pMeta) { metaWLock(pMeta); metaCacheClose(pMeta); diff --git a/source/dnode/vnode/src/meta/metaEntry2.c b/source/dnode/vnode/src/meta/metaEntry2.c index 7b1f711de24e..c48b03c492ed 100644 --- a/source/dnode/vnode/src/meta/metaEntry2.c +++ b/source/dnode/vnode/src/meta/metaEntry2.c @@ -477,6 +477,13 @@ static int32_t metaUpdateSuperTableTagSchema(SMeta *pMeta, const SMetaHandlePara return code; } + // drop old tag from meta stable tag filter cache + code = metaStableTagFilterCacheDropTag(pMeta, pEntry->uid, pOldColumn->colId); + if (code) { + metaErr(TD_VID(pMeta->pVnode), code); + return code; + } + iOld++; } else { code = metaAddOrDropTagIndexOfSuperTable(pMeta, pParam, NULL, pNewColumn); @@ -496,6 +503,12 @@ static int32_t metaUpdateSuperTableTagSchema(SMeta *pMeta, const SMetaHandlePara metaErr(TD_VID(pMeta->pVnode), code); return code; } + // drop old tag from meta stable tag filter cache + code = metaStableTagFilterCacheDropTag(pMeta, pEntry->uid, pOldColumn->colId); + if (code) { + metaErr(TD_VID(pMeta->pVnode), code); + return code; + } } for (; iNew < pNewTagSchema->nCols; iNew++) { @@ -1343,6 +1356,12 @@ static int32_t metaHandleChildTableCreateImpl(SMeta *pMeta, const SMetaEntry *pE metaErr(TD_VID(pMeta->pVnode), ret); } + ret = metaStableTagFilterCacheUpdateUid( + pMeta, pEntry, STABLE_TAG_FILTER_CACHE_ADD_TABLE); + if (ret < 0) { + metaErr(TD_VID(pMeta->pVnode), ret); + } + ret = metaTbGroupCacheClear(pMeta, pSuperEntry->uid); if (ret < 0) { metaErr(TD_VID(pMeta->pVnode), ret); @@ -1476,6 +1495,12 @@ static int32_t metaHandleVirtualChildTableCreateImpl(SMeta *pMeta, const SMetaEn metaErr(TD_VID(pMeta->pVnode), ret); } + ret = metaStableTagFilterCacheUpdateUid( + pMeta, pEntry, STABLE_TAG_FILTER_CACHE_ADD_TABLE); + if (ret < 0) { + metaErr(TD_VID(pMeta->pVnode), ret); + } + ret = metaTbGroupCacheClear(pMeta, pSuperEntry->uid); if (ret < 0) { metaErr(TD_VID(pMeta->pVnode), ret); @@ -1630,6 +1655,12 @@ static int32_t metaHandleChildTableDropImpl(SMeta *pMeta, const SMetaHandleParam metaErr(TD_VID(pMeta->pVnode), ret); } + ret = metaStableTagFilterCacheUpdateUid( + pMeta, pChild, STABLE_TAG_FILTER_CACHE_DROP_TABLE); + if (ret < 0) { + metaErr(TD_VID(pMeta->pVnode), ret); + } + ret = metaTbGroupCacheClear(pMeta, pSuper->uid); if (ret < 0) { metaErr(TD_VID(pMeta->pVnode), ret); @@ -1817,6 +1848,12 @@ static int32_t metaHandleVirtualChildTableDropImpl(SMeta *pMeta, const SMetaHand metaErr(TD_VID(pMeta->pVnode), ret); } + ret = metaStableTagFilterCacheUpdateUid( + pMeta, pChild, STABLE_TAG_FILTER_CACHE_DROP_TABLE); + if (ret < 0) { + metaErr(TD_VID(pMeta->pVnode), ret); + } + ret = metaTbGroupCacheClear(pMeta, pSuper->uid); if (ret < 0) { metaErr(TD_VID(pMeta->pVnode), ret); @@ -2037,6 +2074,18 @@ static int32_t metaHandleVirtualChildTableUpdateImpl(SMeta *pMeta, const SMetaHa metaErr(TD_VID(pMeta->pVnode), code); } + // update stable tag filter cache: drop old then add new + code = metaStableTagFilterCacheUpdateUid( + pMeta, pOldEntry, STABLE_TAG_FILTER_CACHE_DROP_TABLE); + if (TSDB_CODE_SUCCESS != code) { + metaErr(TD_VID(pMeta->pVnode), code); + } + code = metaStableTagFilterCacheUpdateUid( + pMeta, pEntry, STABLE_TAG_FILTER_CACHE_ADD_TABLE); + if (TSDB_CODE_SUCCESS != code) { + metaErr(TD_VID(pMeta->pVnode), code); + } + if (metaTbGroupCacheClear(pMeta, pSuperEntry->uid) < 0) { metaErr(TD_VID(pMeta->pVnode), code); } @@ -2075,6 +2124,18 @@ static int32_t metaHandleChildTableUpdateImpl(SMeta *pMeta, const SMetaHandlePar metaErr(TD_VID(pMeta->pVnode), code); } + // update stable tag filter cache: drop old then add new + code = metaStableTagFilterCacheUpdateUid( + pMeta, pOldEntry, STABLE_TAG_FILTER_CACHE_DROP_TABLE); + if (TSDB_CODE_SUCCESS != code) { + metaErr(TD_VID(pMeta->pVnode), code); + } + code = metaStableTagFilterCacheUpdateUid( + pMeta, pEntry, STABLE_TAG_FILTER_CACHE_ADD_TABLE); + if (TSDB_CODE_SUCCESS != code) { + metaErr(TD_VID(pMeta->pVnode), code); + } + if (metaTbGroupCacheClear(pMeta, pSuperEntry->uid) < 0) { metaErr(TD_VID(pMeta->pVnode), code); } diff --git a/source/dnode/vnode/src/meta/metaTable.c b/source/dnode/vnode/src/meta/metaTable.c index 70a0c95e932e..b06bef0e7905 100644 --- a/source/dnode/vnode/src/meta/metaTable.c +++ b/source/dnode/vnode/src/meta/metaTable.c @@ -728,6 +728,13 @@ static int metaDropTableByUid(SMeta *pMeta, tb_uid_t uid, int *type, tb_uid_t *p metaError("vgId:%d, failed to clear uid cache:%s uid:%" PRId64 " since %s", TD_VID(pMeta->pVnode), e.name, e.ctbEntry.suid, tstrerror(ret)); } + ret = metaStableTagFilterCacheUpdateUid( + pMeta, &e, STABLE_TAG_FILTER_CACHE_DROP_TABLE); + if (ret < 0) { + metaError("vgId:%d, failed to update stable tag filter cache:%s " + "uid:%" PRId64 " since %s", TD_VID(pMeta->pVnode), e.name, + e.ctbEntry.suid, tstrerror(ret)); + } ret = metaTbGroupCacheClear(pMeta, e.ctbEntry.suid); if (ret < 0) { metaError("vgId:%d, failed to clear group cache:%s uid:%" PRId64 " since %s", TD_VID(pMeta->pVnode), e.name, @@ -767,6 +774,11 @@ static int metaDropTableByUid(SMeta *pMeta, tb_uid_t uid, int *type, tb_uid_t *p metaError("vgId:%d, failed to clear uid cache:%s uid:%" PRId64 " since %s", TD_VID(pMeta->pVnode), e.name, e.uid, tstrerror(ret)); } + ret = metaStableTagFilterCacheDropSTable(pMeta, uid); + if (ret < 0) { + metaError("vgId:%d, failed to clear stable tag filter cache:%s uid:%" PRId64 " since %s", TD_VID(pMeta->pVnode), e.name, + e.uid, tstrerror(ret)); + } ret = metaTbGroupCacheClear(pMeta, uid); if (ret < 0) { metaError("vgId:%d, failed to clear group cache:%s uid:%" PRId64 " since %s", TD_VID(pMeta->pVnode), e.name, diff --git a/source/dnode/vnode/src/vnd/vnodeApi.c b/source/dnode/vnode/src/vnd/vnodeApi.c index c6463564c39c..161fb78a7549 100644 --- a/source/dnode/vnode/src/vnd/vnodeApi.c +++ b/source/dnode/vnode/src/vnd/vnodeApi.c @@ -102,6 +102,8 @@ void initMetadataAPI(SStoreMeta* pMeta) { pMeta->getCachedTableList = metaGetCachedTableUidList; pMeta->putCachedTableList = metaUidFilterCachePut; + pMeta->getStableCachedTableList = metaStableTagFilterCacheGet; + pMeta->putStableCachedTableList = metaStableTagFilterCachePut; pMeta->metaGetCachedTbGroup = metaGetCachedTbGroup; pMeta->metaPutTbGroupToCache = metaPutTbGroupToCache; diff --git a/source/libs/executor/src/executil.c b/source/libs/executor/src/executil.c index 538a164aca23..f9ebf9e470e8 100644 --- a/source/libs/executor/src/executil.c +++ b/source/libs/executor/src/executil.c @@ -21,6 +21,7 @@ #include "querynodes.h" #include "taoserror.h" #include "tarray.h" +#include "tcompare.h" #include "tdatablock.h" #include "thash.h" #include "tmsg.h" @@ -693,6 +694,184 @@ void freeItem(void* p) { } } +static bool canOptimizeTagFilter(const SNode* pTagCond) { + if (NULL == pTagCond) return false; + if (nodeType(pTagCond) == QUERY_NODE_OPERATOR && + ((SOperatorNode*)pTagCond)->opType == OP_TYPE_EQUAL) { + return true; + } + if (nodeType(pTagCond) == QUERY_NODE_LOGIC_CONDITION && + ((SLogicConditionNode*)pTagCond)->condType == LOGIC_COND_TYPE_AND) { + SNode* pChild = NULL; + FOREACH(pChild, ((SLogicConditionNode*)pTagCond)->pParameterList) { + if (QUERY_NODE_OPERATOR != nodeType(pChild) || + ((SOperatorNode*)pChild)->opType != OP_TYPE_EQUAL) { + return false; + } + } + return true; + } + return false; +} + +typedef struct { + col_id_t colId; + SNode* pValueNode; +} STagDataEntry; + +static int compareTagDataEntry(const void* a, const void* b) { + STagDataEntry* p1 = (STagDataEntry*)a; + STagDataEntry* p2 = (STagDataEntry*)b; + + return compareInt16Val(&p1->colId, &p2->colId); +} + +static int32_t buildTagDataEntryKey(SArray* pIdWithValue, char** keyBuf, int32_t keyLen) { + *keyBuf = (char*)taosMemoryCalloc(1, keyLen); + if (NULL == *keyBuf) { + qError( + "failed to allocate memory for tag filter optimization key, size:%d", + keyLen); + return terrno; + } + char* pStart = *keyBuf; + for (int32_t i = 0; i < taosArrayGetSize(pIdWithValue); ++i) { + STagDataEntry* entry = (STagDataEntry*)taosArrayGet(pIdWithValue, i); + SValueNode* pValueNode = (SValueNode*)entry->pValueNode; + + (void)memcpy(pStart, &entry->colId, sizeof(col_id_t)); + pStart += sizeof(col_id_t); + + switch (pValueNode->node.resType.type) { + case TSDB_DATA_TYPE_BOOL: + (void)memcpy( + pStart, &pValueNode->datum.b, pValueNode->node.resType.bytes); + pStart += pValueNode->node.resType.bytes; + break; + case TSDB_DATA_TYPE_TINYINT: + case TSDB_DATA_TYPE_SMALLINT: + case TSDB_DATA_TYPE_INT: + case TSDB_DATA_TYPE_BIGINT: + case TSDB_DATA_TYPE_TIMESTAMP: + (void)memcpy( + pStart, &pValueNode->datum.i, pValueNode->node.resType.bytes); + pStart += pValueNode->node.resType.bytes; + break; + case TSDB_DATA_TYPE_UTINYINT: + case TSDB_DATA_TYPE_USMALLINT: + case TSDB_DATA_TYPE_UINT: + case TSDB_DATA_TYPE_UBIGINT: + (void)memcpy( + pStart, &pValueNode->datum.u, pValueNode->node.resType.bytes); + pStart += pValueNode->node.resType.bytes; + break; + case TSDB_DATA_TYPE_FLOAT: + case TSDB_DATA_TYPE_DOUBLE: + (void)memcpy( + pStart, &pValueNode->datum.d, pValueNode->node.resType.bytes); + pStart += pValueNode->node.resType.bytes; + break; + case TSDB_DATA_TYPE_VARCHAR: + case TSDB_DATA_TYPE_VARBINARY: + case TSDB_DATA_TYPE_NCHAR: + (void)memcpy(pStart, + varDataVal(pValueNode->datum.p), varDataLen(pValueNode->datum.p)); + pStart += varDataLen(pValueNode->datum.p); + break; + case TSDB_DATA_TYPE_JSON: { + int32_t jsonLen = getJsonValueLen(pValueNode->datum.p); + (void)memcpy(pStart, varDataVal(pValueNode->datum.p), jsonLen); + pStart += jsonLen; + break; + } + default: + qError("unsupported tag data type %d in tag filter optimization", + pValueNode->node.resType.type); + return TSDB_CODE_STREAM_INTERNAL_ERROR; + } + } + + return TSDB_CODE_SUCCESS; +} + +static void extractTagDataEntry( + SOperatorNode* pOpNode, SArray* pIdWithValue) { + SNode* pLeft = pOpNode->pLeft; + SNode* pRight = pOpNode->pRight; + SColumnNode* pColNode = nodeType(pLeft) == QUERY_NODE_COLUMN ? + (SColumnNode*)pLeft : (SColumnNode*)pRight; + SValueNode* pValueNode = nodeType(pLeft) == QUERY_NODE_VALUE ? + (SValueNode*)pLeft : (SValueNode*)pRight; + + STagDataEntry entry = {0}; + entry.colId = pColNode->colId; + entry.pValueNode = (SNode*)pValueNode; + void* _tmp = taosArrayPush(pIdWithValue, &entry); + STagDataEntry* pLastEntry = taosArrayGetLast(pIdWithValue); + ((SValueNode*)pLastEntry->pValueNode)->node.resType = pColNode->node.resType; +} + +static int32_t extractTagFilterTagDataEntries( + const SNode* pTagCond, SArray* pIdWithVal) { + if (NULL == pTagCond || NULL == pIdWithVal || + (nodeType(pTagCond) != QUERY_NODE_OPERATOR && + nodeType(pTagCond) != QUERY_NODE_LOGIC_CONDITION)) { + qError("invalid parameter to extract tag filter symbol"); + return TSDB_CODE_STREAM_INTERNAL_ERROR; + } + + if (nodeType(pTagCond) == QUERY_NODE_OPERATOR) { + extractTagDataEntry((SOperatorNode*)pTagCond, pIdWithVal); + } else if (nodeType(pTagCond) == QUERY_NODE_LOGIC_CONDITION) { + SNode* pChild = NULL; + FOREACH(pChild, ((SLogicConditionNode*)pTagCond)->pParameterList) { + extractTagDataEntry((SOperatorNode*)pChild, pIdWithVal); + } + } + + taosArraySort(pIdWithVal, compareTagDataEntry); + + return TSDB_CODE_SUCCESS; +} + +static int32_t genStableTagFilterDigest(const SNode* pTagCond, T_MD5_CTX* pContext) { + if (pTagCond == NULL) { + return TSDB_CODE_SUCCESS; + } + + char* payload = NULL; + int32_t len = 0; + int32_t code = TSDB_CODE_SUCCESS; + + SArray* pIdWithVal = taosArrayInit(TARRAY_MIN_SIZE, sizeof(STagDataEntry)); + code = extractTagFilterTagDataEntries(pTagCond, pIdWithVal); + if (TSDB_CODE_SUCCESS != code) { + qError("%s failed at line %d since %s", + __func__, __LINE__, tstrerror(code)); + taosArrayDestroy(pIdWithVal); + return code; + } + for (int32_t i = 0; i < taosArrayGetSize(pIdWithVal); ++i) { + STagDataEntry* pEntry = taosArrayGet(pIdWithVal, i); + len += sizeof(col_id_t) + + ((SValueNode*)pEntry->pValueNode)->node.resType.bytes; + } + code = buildTagDataEntryKey(pIdWithVal, &payload, len); + if (TSDB_CODE_SUCCESS != code) { + qError("%s failed at line %d since %s", + __func__, __LINE__, tstrerror(code)); + taosArrayDestroy(pIdWithVal); + return code; + } + + tMD5Init(pContext); + tMD5Update(pContext, (uint8_t*)payload, (uint32_t)len); + tMD5Final(pContext); + + taosMemoryFree(payload); + return code; +} + static int32_t genTagFilterDigest(const SNode* pTagCond, T_MD5_CTX* pContext) { if (pTagCond == NULL) { return TSDB_CODE_SUCCESS; @@ -1805,6 +1984,64 @@ static EDealRes replacePlaceHolderColumn(SNode** pNode, void* pContext) { return DEAL_RES_CONTINUE; } +static void extractTagColId(SOperatorNode* pOpNode, SArray* pColIdArray) { + SNode* pLeft = pOpNode->pLeft; + SNode* pRight = pOpNode->pRight; + SColumnNode* pColNode = nodeType(pLeft) == QUERY_NODE_COLUMN ? + (SColumnNode*)pLeft : (SColumnNode*)pRight; + + col_id_t colId = pColNode->colId; + void* _tmp = taosArrayPush(pColIdArray, &colId); +} + +static int32_t buildTagCondKey( + SNode* pTagCond, char** pTagCondKey, int32_t* tagCondKeyLen, SArray** pTagColIds) { + if (NULL == pTagCond || + (nodeType(pTagCond) != QUERY_NODE_OPERATOR && + nodeType(pTagCond) != QUERY_NODE_LOGIC_CONDITION)) { + qError("invalid parameter to extract tag filter symbol"); + return TSDB_CODE_STREAM_INTERNAL_ERROR; + } + int32_t code = TSDB_CODE_SUCCESS; + int32_t lino = 0; + *pTagColIds = taosArrayInit(4, sizeof(col_id_t)); + + if (nodeType(pTagCond) == QUERY_NODE_OPERATOR) { + extractTagColId((SOperatorNode*)pTagCond, *pTagColIds); + } else if (nodeType(pTagCond) == QUERY_NODE_LOGIC_CONDITION) { + SNode* pChild = NULL; + FOREACH(pChild, ((SLogicConditionNode*)pTagCond)->pParameterList) { + extractTagColId((SOperatorNode*)pChild, *pTagColIds); + } + } + + taosArraySort(*pTagColIds, compareUint16Val); + + // encode ordered colIds into key string, separated by ',' + *tagCondKeyLen = + (int32_t)(taosArrayGetSize(*pTagColIds) * (sizeof(col_id_t) + 1) - 1); + *pTagCondKey = (char*)taosMemoryCalloc(1, *tagCondKeyLen); + TSDB_CHECK_NULL(*pTagCondKey, code, lino, _end, terrno); + char* pStart = *pTagCondKey; + for (int32_t i = 0; i < taosArrayGetSize(*pTagColIds); ++i) { + col_id_t* pColId = (col_id_t*)taosArrayGet(*pTagColIds, i); + TSDB_CHECK_NULL(pColId, code, lino, _end, terrno); + memcpy(pStart, pColId, sizeof(col_id_t)); + pStart += sizeof(col_id_t); + if (i != taosArrayGetSize(*pTagColIds) - 1) { + *pStart = ','; + pStart += 1; + } + } + +_end: + if (TSDB_CODE_SUCCESS != code) { + qError("%s failed at line %d since %s", __func__, lino, tstrerror(code)); + terrno = code; + } + return code; +} + int32_t getTableList(void* pVnode, SScanPhysiNode* pScanNode, SNode* pTagCond, SNode* pTagIndexCond, STableListInfo* pListInfo, uint8_t* digest, const char* idstr, SStorageAPI* pStorageAPI, void* pStreamInfo) { int32_t code = TSDB_CODE_SUCCESS; @@ -1830,6 +2067,47 @@ int32_t getTableList(void* pVnode, SScanPhysiNode* pScanNode, SNode* pTagCond, S } else { T_MD5_CTX context = {0}; + if (pTagCond != NULL && + tsStableTagFilterCache && canOptimizeTagFilter(pTagCond)) { + qDebug("stable tag filter condition can be optimized"); + if (pStreamInfo != NULL && ((SStreamRuntimeFuncInfo*)pStreamInfo)->hasPlaceHolder) { + SNode* tmp = NULL; + code = nodesCloneNode((SNode*)pTagCond, &tmp); + QUERY_CHECK_CODE(code, lino, _error); + + PlaceHolderContext ctx = {.code = TSDB_CODE_SUCCESS, .pStreamRuntimeInfo = (SStreamRuntimeFuncInfo*)pStreamInfo}; + nodesRewriteExpr(&tmp, replacePlaceHolderColumn, (void*)&ctx); + if (TSDB_CODE_SUCCESS != ctx.code) { + nodesDestroyNode(tmp); + code = ctx.code; + goto _error; + } + code = genStableTagFilterDigest(tmp, &context); + nodesDestroyNode(tmp); + } else { + code = genStableTagFilterDigest(pTagCond, &context); + } + QUERY_CHECK_CODE(code, lino, _error); + + bool acquired = false; + char* pTagCondKey; + int32_t tagCondKeyLen; + SArray* pTagColIds = NULL; + code = buildTagCondKey(pTagCond, &pTagCondKey, &tagCondKeyLen, &pTagColIds); + QUERY_CHECK_CODE(code, lino, _error); + taosArrayDestroy(pTagColIds); + code = pStorageAPI->metaFn.getStableCachedTableList( + pVnode, pScanNode->suid, pTagCondKey, tagCondKeyLen, + context.digest, tListLen(context.digest), pUidList, &acquired); + QUERY_CHECK_CODE(code, lino, _error); + + if (acquired) { + digest[0] = 1; + memcpy(digest + 1, context.digest, tListLen(context.digest)); + qDebug("retrieve table uid list from cache, numOfTables:%d", (int32_t)taosArrayGetSize(pUidList)); + goto _end; + } + } if (tsTagFilterCache) { if (pStreamInfo != NULL && ((SStreamRuntimeFuncInfo*)pStreamInfo)->hasPlaceHolder) { SNode* tmp = NULL; @@ -1851,8 +2129,9 @@ int32_t getTableList(void* pVnode, SScanPhysiNode* pScanNode, SNode* pTagCond, S // try to retrieve the result from meta cache QUERY_CHECK_CODE(code, lino, _error); bool acquired = false; - code = pStorageAPI->metaFn.getCachedTableList(pVnode, pScanNode->suid, context.digest, tListLen(context.digest), - pUidList, &acquired); + code = pStorageAPI->metaFn.getCachedTableList( + pVnode, pScanNode->suid, context.digest, + tListLen(context.digest), pUidList, &acquired); QUERY_CHECK_CODE(code, lino, _error); if (acquired) { @@ -1886,7 +2165,9 @@ int32_t getTableList(void* pVnode, SScanPhysiNode* pScanNode, SNode* pTagCond, S } } - code = doFilterByTagCond(pListInfo, pUidList, pTagCond, pVnode, status, pStorageAPI, tsTagFilterCache, &listAdded, pStreamInfo); + code = doFilterByTagCond(pListInfo, pUidList, pTagCond, pVnode, status, + pStorageAPI, tsTagFilterCache || tsStableTagFilterCache, + &listAdded, pStreamInfo); QUERY_CHECK_CODE(code, lino, _end); // let's add the filter results into meta-cache @@ -1911,6 +2192,19 @@ int32_t getTableList(void* pVnode, SScanPhysiNode* pScanNode, SNode* pTagCond, S digest[0] = 1; memcpy(digest + 1, context.digest, tListLen(context.digest)); } + if (pTagCond != NULL && + tsStableTagFilterCache && canOptimizeTagFilter(pTagCond)) { + qDebug("tag filter condition can be optimized, cache separately"); + char* pTagCondKey; + int32_t tagCondKeyLen; + SArray* pTagColIds = NULL; + code = buildTagCondKey(pTagCond, &pTagCondKey, &tagCondKeyLen, &pTagColIds); + QUERY_CHECK_CODE(code, lino, _error); + code = pStorageAPI->metaFn.putStableCachedTableList( + pVnode, pScanNode->suid, pTagCondKey, tagCondKeyLen, + context.digest, tListLen(context.digest), pUidList, pTagColIds); + QUERY_CHECK_CODE(code, lino, _error); + } } _end: