mirror of
https://github.com/taosdata/TDengine
synced 2026-05-24 10:09:01 +00:00
501 lines
16 KiB
C
501 lines
16 KiB
C
/*
|
|
* Copyright (c) 2024 TAOS Data, Inc.
|
|
*
|
|
* This program is free software: you can use, redistribute, and/or modify
|
|
* it under the terms of the GNU Affero General Public License, version 3
|
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
|
*
|
|
* You should have received a copy of the GNU Affero General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#define _DEFAULT_SOURCE
|
|
#include <inttypes.h>
|
|
#include "mndInstance.h"
|
|
#include "mndShow.h"
|
|
#include "tcompare.h"
|
|
#include "ttime.h"
|
|
|
|
#define MND_INSTANCE_VER_NUMBER 1
|
|
|
|
static SSdbRaw *mndInstanceEncode(const SInstanceObj *pInstance);
|
|
static SSdbRow *mndInstanceDecode(SSdbRaw *pRaw);
|
|
static int32_t mndInstanceInsert(SSdb *pSdb, SInstanceObj *pInstance);
|
|
static int32_t mndInstanceUpdate(SSdb *pSdb, SInstanceObj *pOld, SInstanceObj *pNew);
|
|
static int32_t mndInstanceDelete(SSdb *pSdb, SInstanceObj *pInstance);
|
|
static int32_t mndRetrieveInstance(SRpcMsg *pReq, SShowObj *pShow, SSDataBlock *pBlock, int32_t rows);
|
|
static int32_t mndProcessInstanceRegister(SRpcMsg *pReq);
|
|
static int32_t mndProcessInstanceList(SRpcMsg *pReq);
|
|
static int32_t mndProcessInstanceTimer(SRpcMsg *pReq);
|
|
|
|
static inline int32_t mndInstanceDataSize(void) {
|
|
return TSDB_INSTANCE_ID_LEN + TSDB_INSTANCE_TYPE_LEN + TSDB_INSTANCE_DESC_LEN + sizeof(int64_t) * 2 + sizeof(int32_t);
|
|
}
|
|
|
|
int32_t mndInitInstance(SMnode *pMnode) {
|
|
SSdbTable table = {
|
|
.sdbType = SDB_INSTANCE,
|
|
.keyType = SDB_KEY_BINARY,
|
|
.encodeFp = NULL,
|
|
.decodeFp = (SdbDecodeFp)mndInstanceDecode,
|
|
.insertFp = (SdbInsertFp)mndInstanceInsert,
|
|
.updateFp = (SdbUpdateFp)mndInstanceUpdate,
|
|
.deleteFp = (SdbDeleteFp)mndInstanceDelete,
|
|
};
|
|
|
|
TAOS_CHECK_RETURN(sdbSetTable(pMnode->pSdb, table));
|
|
|
|
mndAddShowRetrieveHandle(pMnode, TSDB_MGMT_TABLE_INSTANCE, mndRetrieveInstance);
|
|
mndSetMsgHandle(pMnode, TDMT_MND_REGISTER_INSTANCE, mndProcessInstanceRegister);
|
|
mndSetMsgHandle(pMnode, TDMT_MND_LIST_INSTANCES, mndProcessInstanceList);
|
|
mndSetMsgHandle(pMnode, TDMT_MND_INSTANCE_TIMER, mndProcessInstanceTimer);
|
|
|
|
return TSDB_CODE_SUCCESS;
|
|
}
|
|
|
|
void mndCleanupInstance(SMnode *pMnode) {
|
|
(void)pMnode;
|
|
}
|
|
|
|
SInstanceObj *mndInstanceAcquire(SMnode *pMnode, const char *id) {
|
|
if (id == NULL || id[0] == 0) {
|
|
terrno = TSDB_CODE_INVALID_PARA;
|
|
return NULL;
|
|
}
|
|
return sdbAcquire(pMnode->pSdb, SDB_INSTANCE, id);
|
|
}
|
|
|
|
void mndInstanceRelease(SMnode *pMnode, SInstanceObj *pInstance) {
|
|
if (pInstance == NULL) return;
|
|
sdbRelease(pMnode->pSdb, pInstance);
|
|
}
|
|
|
|
int32_t mndInstanceUpsert(SMnode *pMnode, const char *id, const char *type, const char *desc, int64_t regTime,
|
|
int32_t expire) {
|
|
if (id == NULL || id[0] == 0) {
|
|
return TSDB_CODE_INVALID_PARA;
|
|
}
|
|
|
|
SInstanceObj instance = {0};
|
|
tstrncpy(instance.id, id, sizeof(instance.id));
|
|
if (type != NULL) {
|
|
tstrncpy(instance.type, type, sizeof(instance.type));
|
|
}
|
|
if (desc != NULL) {
|
|
tstrncpy(instance.desc, desc, sizeof(instance.desc));
|
|
}
|
|
instance.lastRegTime = regTime;
|
|
instance.expire = expire;
|
|
|
|
SInstanceObj *pOld = mndInstanceAcquire(pMnode, id);
|
|
if (pOld != NULL) {
|
|
instance.firstRegTime = pOld->firstRegTime;
|
|
if (instance.type[0] == 0) {
|
|
tstrncpy(instance.type, pOld->type, sizeof(instance.type));
|
|
}
|
|
if (instance.desc[0] == 0) {
|
|
tstrncpy(instance.desc, pOld->desc, sizeof(instance.desc));
|
|
}
|
|
mndInstanceRelease(pMnode, pOld);
|
|
} else {
|
|
instance.firstRegTime = regTime;
|
|
}
|
|
|
|
SSdbRaw *pRaw = mndInstanceEncode(&instance);
|
|
if (pRaw == NULL) {
|
|
return terrno;
|
|
}
|
|
|
|
int32_t code = sdbSetRawStatus(pRaw, SDB_STATUS_READY);
|
|
if (code != TSDB_CODE_SUCCESS) {
|
|
sdbFreeRaw(pRaw);
|
|
return code;
|
|
}
|
|
|
|
code = sdbWrite(pMnode->pSdb, pRaw);
|
|
if (code != TSDB_CODE_SUCCESS) {
|
|
mError("instance:%s, failed to upsert into sdb since %s", id, tstrerror(code));
|
|
}
|
|
return code;
|
|
}
|
|
|
|
int32_t mndInstanceRemove(SMnode *pMnode, const char *id) {
|
|
if (id == NULL || id[0] == 0) {
|
|
return TSDB_CODE_INVALID_PARA;
|
|
}
|
|
|
|
SInstanceObj instance = {0};
|
|
tstrncpy(instance.id, id, sizeof(instance.id));
|
|
|
|
SSdbRaw *pRaw = mndInstanceEncode(&instance);
|
|
if (pRaw == NULL) {
|
|
return terrno;
|
|
}
|
|
|
|
int32_t code = sdbSetRawStatus(pRaw, SDB_STATUS_DROPPED);
|
|
if (code != TSDB_CODE_SUCCESS) {
|
|
sdbFreeRaw(pRaw);
|
|
return code;
|
|
}
|
|
|
|
code = sdbWrite(pMnode->pSdb, pRaw);
|
|
if (code != TSDB_CODE_SUCCESS) {
|
|
mError("instance:%s, failed to remove from sdb since %s", id, tstrerror(code));
|
|
}
|
|
return code;
|
|
}
|
|
|
|
static SSdbRaw *mndInstanceEncode(const SInstanceObj *pInstance) {
|
|
int32_t code = TSDB_CODE_SUCCESS;
|
|
int32_t lino = 0;
|
|
terrno = TSDB_CODE_SUCCESS;
|
|
|
|
SSdbRaw *pRaw = sdbAllocRaw(SDB_INSTANCE, MND_INSTANCE_VER_NUMBER, mndInstanceDataSize());
|
|
if (pRaw == NULL) {
|
|
return NULL;
|
|
}
|
|
|
|
int32_t dataPos = 0;
|
|
SDB_SET_BINARY(pRaw, dataPos, pInstance->id, TSDB_INSTANCE_ID_LEN, _OVER);
|
|
SDB_SET_BINARY(pRaw, dataPos, pInstance->type, TSDB_INSTANCE_TYPE_LEN, _OVER);
|
|
SDB_SET_BINARY(pRaw, dataPos, pInstance->desc, TSDB_INSTANCE_DESC_LEN, _OVER);
|
|
SDB_SET_INT64(pRaw, dataPos, pInstance->firstRegTime, _OVER);
|
|
SDB_SET_INT64(pRaw, dataPos, pInstance->lastRegTime, _OVER);
|
|
SDB_SET_INT32(pRaw, dataPos, pInstance->expire, _OVER);
|
|
SDB_SET_DATALEN(pRaw, dataPos, _OVER);
|
|
|
|
return pRaw;
|
|
|
|
_OVER:
|
|
sdbFreeRaw(pRaw);
|
|
terrno = code != TSDB_CODE_SUCCESS ? code : terrno;
|
|
return NULL;
|
|
}
|
|
|
|
static SSdbRow *mndInstanceDecode(SSdbRaw *pRaw) {
|
|
int32_t code = TSDB_CODE_SUCCESS;
|
|
int32_t lino = 0;
|
|
terrno = TSDB_CODE_SUCCESS;
|
|
|
|
int8_t sver = 0;
|
|
if (sdbGetRawSoftVer(pRaw, &sver) != 0) {
|
|
return NULL;
|
|
}
|
|
if (sver != MND_INSTANCE_VER_NUMBER) {
|
|
terrno = TSDB_CODE_SDB_INVALID_DATA_VER;
|
|
return NULL;
|
|
}
|
|
|
|
SSdbRow *pRow = sdbAllocRow(sizeof(SInstanceObj));
|
|
if (pRow == NULL) {
|
|
terrno = TSDB_CODE_OUT_OF_MEMORY;
|
|
return NULL;
|
|
}
|
|
|
|
SInstanceObj *pInstance = sdbGetRowObj(pRow);
|
|
int32_t dataPos = 0;
|
|
SDB_GET_BINARY(pRaw, dataPos, pInstance->id, TSDB_INSTANCE_ID_LEN, _OVER);
|
|
SDB_GET_BINARY(pRaw, dataPos, pInstance->type, TSDB_INSTANCE_TYPE_LEN, _OVER);
|
|
SDB_GET_BINARY(pRaw, dataPos, pInstance->desc, TSDB_INSTANCE_DESC_LEN, _OVER);
|
|
SDB_GET_INT64(pRaw, dataPos, &pInstance->firstRegTime, _OVER);
|
|
SDB_GET_INT64(pRaw, dataPos, &pInstance->lastRegTime, _OVER);
|
|
SDB_GET_INT32(pRaw, dataPos, &pInstance->expire, _OVER);
|
|
|
|
return pRow;
|
|
|
|
_OVER:
|
|
taosMemoryFreeClear(pRow);
|
|
if (code != TSDB_CODE_SUCCESS) terrno = code;
|
|
return NULL;
|
|
}
|
|
|
|
static int32_t mndInstanceInsert(SSdb *pSdb, SInstanceObj *pInstance) {
|
|
(void)pSdb;
|
|
(void)pInstance;
|
|
return TSDB_CODE_SUCCESS;
|
|
}
|
|
|
|
static int32_t mndInstanceUpdate(SSdb *pSdb, SInstanceObj *pOld, SInstanceObj *pNew) {
|
|
(void)pSdb;
|
|
if (pOld == NULL || pNew == NULL) {
|
|
return TSDB_CODE_INVALID_PARA;
|
|
}
|
|
memcpy(pOld, pNew, sizeof(SInstanceObj));
|
|
return TSDB_CODE_SUCCESS;
|
|
}
|
|
|
|
static int32_t mndInstanceDelete(SSdb *pSdb, SInstanceObj *pInstance) {
|
|
(void)pSdb;
|
|
(void)pInstance;
|
|
return TSDB_CODE_SUCCESS;
|
|
}
|
|
|
|
static int32_t mndProcessInstanceRegister(SRpcMsg *pReq) {
|
|
SMnode *pMnode = pReq->info.node;
|
|
SInstanceRegisterReq req = {0};
|
|
int32_t code = tDeserializeSInstanceRegisterReq(pReq->pCont, pReq->contLen, &req);
|
|
if (code != TSDB_CODE_SUCCESS) {
|
|
mError("instance register, failed to decode since %s", tstrerror(code));
|
|
return code;
|
|
}
|
|
|
|
if (req.id[0] == 0) {
|
|
mError("instance register, id is empty");
|
|
return TSDB_CODE_INVALID_PARA;
|
|
}
|
|
|
|
if (req.expire < 0) {
|
|
code = mndInstanceRemove(pMnode, req.id);
|
|
if (code == TSDB_CODE_SUCCESS) {
|
|
mInfo("instance:%s unregistered", req.id);
|
|
}
|
|
} else {
|
|
int64_t now = taosGetTimestampMs();
|
|
const char *type = req.type[0] ? req.type : NULL;
|
|
const char *desc = req.desc[0] ? req.desc : NULL;
|
|
code = mndInstanceUpsert(pMnode, req.id, type, desc, now, req.expire);
|
|
if (code == TSDB_CODE_SUCCESS) {
|
|
mDebug("instance:%s registered type:%s expire:%d", req.id, req.type, req.expire);
|
|
}
|
|
}
|
|
|
|
if (code != TSDB_CODE_SUCCESS) {
|
|
mError("instance:%s, failed to process register request since %s", req.id, tstrerror(code));
|
|
}
|
|
return code;
|
|
}
|
|
|
|
static int32_t mndProcessInstanceList(SRpcMsg *pReq) {
|
|
SMnode *pMnode = pReq->info.node;
|
|
SSdb *pSdb = pMnode->pSdb;
|
|
SInstanceListReq req = {0};
|
|
int32_t code = tDeserializeSInstanceListReq(pReq->pCont, pReq->contLen, &req);
|
|
if (code != TSDB_CODE_SUCCESS) {
|
|
mError("instance list, failed to decode since %s", tstrerror(code));
|
|
return code;
|
|
}
|
|
|
|
// Collect instance IDs (keep instances referenced until serialization)
|
|
int32_t capacity = 32;
|
|
int32_t count = 0;
|
|
SInstanceObj **instances = taosMemoryCalloc(capacity, sizeof(SInstanceObj *));
|
|
const char **ids = taosMemoryCalloc(capacity, sizeof(char *));
|
|
void *iter = NULL;
|
|
SInstanceObj *pInstance = NULL;
|
|
int64_t now = taosGetTimestampMs();
|
|
int32_t filterTypeLen = (req.filter_type[0] != 0) ? (int32_t)strlen(req.filter_type) : 0;
|
|
|
|
if (instances == NULL || ids == NULL) {
|
|
taosMemoryFree(instances);
|
|
taosMemoryFree(ids);
|
|
return TSDB_CODE_OUT_OF_MEMORY;
|
|
}
|
|
|
|
while (1) {
|
|
iter = sdbFetch(pSdb, SDB_INSTANCE, iter, (void **)&pInstance);
|
|
if (iter == NULL) {
|
|
break;
|
|
}
|
|
|
|
// Filter by type if specified
|
|
if (filterTypeLen > 0) {
|
|
int32_t typeLen = (int32_t)strlen(pInstance->type);
|
|
if (typeLen != filterTypeLen || strncasecmp(pInstance->type, req.filter_type, (size_t)filterTypeLen) != 0) {
|
|
sdbRelease(pSdb, pInstance);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// Filter by expiration
|
|
if (pInstance->expire > 0 && pInstance->lastRegTime > 0) {
|
|
int64_t delta = now - pInstance->lastRegTime;
|
|
if (delta > (int64_t)pInstance->expire * 1000) {
|
|
sdbRelease(pSdb, pInstance);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
// Add to list (keep reference)
|
|
if (count >= capacity) {
|
|
int32_t newCap = capacity * 2;
|
|
SInstanceObj **newInstances = taosMemoryRealloc(instances, newCap * sizeof(SInstanceObj *));
|
|
if (newInstances == NULL) {
|
|
code = TSDB_CODE_OUT_OF_MEMORY;
|
|
goto _cleanup;
|
|
}
|
|
const char **newIds = taosMemoryRealloc(ids, newCap * sizeof(char *));
|
|
if (newIds == NULL) {
|
|
// If memory was moved, free newInstances; otherwise, keep instances unchanged
|
|
if (newInstances != instances) {
|
|
// Release instance references in newInstances before freeing the memory
|
|
for (int32_t i = 0; i < count; i++) {
|
|
if (newInstances[i] != NULL) {
|
|
sdbRelease(pSdb, newInstances[i]);
|
|
}
|
|
}
|
|
taosMemoryFree(newInstances);
|
|
instances = NULL; // Avoid freeing invalid memory in _cleanup
|
|
}
|
|
code = TSDB_CODE_OUT_OF_MEMORY;
|
|
goto _cleanup;
|
|
}
|
|
instances = newInstances;
|
|
ids = newIds;
|
|
capacity = newCap;
|
|
}
|
|
|
|
instances[count] = pInstance;
|
|
ids[count] = pInstance->id;
|
|
count++;
|
|
}
|
|
|
|
// Serialize response
|
|
SInstanceListRsp rsp = {0};
|
|
rsp.count = count;
|
|
rsp.ids = (char **)ids;
|
|
int32_t contLen = tSerializeSInstanceListRsp(NULL, 0, &rsp);
|
|
if (contLen <= 0) {
|
|
code = terrno != 0 ? terrno : TSDB_CODE_TSC_INTERNAL_ERROR;
|
|
goto _cleanup;
|
|
}
|
|
|
|
pReq->info.rsp = rpcMallocCont(contLen);
|
|
if (pReq->info.rsp == NULL) {
|
|
code = TSDB_CODE_OUT_OF_MEMORY;
|
|
goto _cleanup;
|
|
}
|
|
|
|
if (tSerializeSInstanceListRsp(pReq->info.rsp, contLen, &rsp) < 0) {
|
|
code = terrno != 0 ? terrno : TSDB_CODE_TSC_INTERNAL_ERROR;
|
|
rpcFreeCont(pReq->info.rsp);
|
|
pReq->info.rsp = NULL;
|
|
goto _cleanup;
|
|
}
|
|
|
|
pReq->info.rspLen = contLen;
|
|
code = TSDB_CODE_SUCCESS;
|
|
|
|
_cleanup:
|
|
// Release all instances
|
|
if (instances != NULL) {
|
|
for (int32_t i = 0; i < count; i++) {
|
|
if (instances[i] != NULL) {
|
|
sdbRelease(pSdb, instances[i]);
|
|
}
|
|
}
|
|
taosMemoryFree(instances);
|
|
}
|
|
if (ids != NULL) {
|
|
taosMemoryFree(ids);
|
|
}
|
|
if (pInstance != NULL) {
|
|
sdbRelease(pSdb, pInstance);
|
|
}
|
|
|
|
if (code != TSDB_CODE_SUCCESS) {
|
|
mError("instance list, failed to process request since %s", tstrerror(code));
|
|
} else {
|
|
mDebug("instance list, returned %d instances", count);
|
|
}
|
|
|
|
return code;
|
|
}
|
|
|
|
static int32_t mndProcessInstanceTimer(SRpcMsg *pReq) {
|
|
SMnode *pMnode = pReq->info.node;
|
|
SSdb *pSdb = pMnode->pSdb;
|
|
void *iter = NULL;
|
|
SInstanceObj *pInstance = NULL;
|
|
int64_t now = taosGetTimestampMs();
|
|
|
|
while (1) {
|
|
iter = sdbFetch(pSdb, SDB_INSTANCE, iter, (void **)&pInstance);
|
|
if (iter == NULL) {
|
|
break;
|
|
}
|
|
|
|
bool expired =
|
|
(pInstance->expire > 0) && (now - pInstance->lastRegTime > ((int64_t)pInstance->expire * 1000));
|
|
if (expired) {
|
|
mInfo("instance:%s expired(last:%" PRId64 "ms, expire:%ds), removing", pInstance->id, pInstance->lastRegTime,
|
|
pInstance->expire);
|
|
(void)mndInstanceRemove(pMnode, pInstance->id);
|
|
}
|
|
|
|
sdbRelease(pSdb, pInstance);
|
|
}
|
|
|
|
return TSDB_CODE_SUCCESS;
|
|
}
|
|
|
|
static int32_t mndRetrieveInstance(SRpcMsg *pReq, SShowObj *pShow, SSDataBlock *pBlock, int32_t rows) {
|
|
SMnode *pMnode = pReq->info.node;
|
|
SSdb *pSdb = pMnode->pSdb;
|
|
|
|
int32_t numOfRows = 0;
|
|
SInstanceObj *pInstance = NULL;
|
|
int32_t code = TSDB_CODE_SUCCESS;
|
|
int32_t lino = 0;
|
|
|
|
while (numOfRows < rows) {
|
|
pShow->pIter = sdbFetch(pSdb, SDB_INSTANCE, pShow->pIter, (void **)&pInstance);
|
|
if (pShow->pIter == NULL) break;
|
|
|
|
if (pShow->filterTb[0] != 0) {
|
|
if (rawStrPatternMatch(pInstance->id, pShow->filterTb) != TSDB_PATTERN_MATCH) {
|
|
sdbRelease(pSdb, pInstance);
|
|
pInstance = NULL;
|
|
continue;
|
|
}
|
|
}
|
|
|
|
int32_t cols = 0;
|
|
|
|
SColumnInfoData *pColInfo = taosArrayGet(pBlock->pDataBlock, cols++);
|
|
|
|
char idBuf[TSDB_INSTANCE_ID_LEN + VARSTR_HEADER_SIZE] = {0};
|
|
STR_WITH_MAXSIZE_TO_VARSTR(idBuf, pInstance->id, sizeof(idBuf));
|
|
RETRIEVE_CHECK_GOTO(colDataSetVal(pColInfo, numOfRows, idBuf, false), pInstance, &lino, _OVER);
|
|
|
|
pColInfo = taosArrayGet(pBlock->pDataBlock, cols++);
|
|
char typeBuf[TSDB_INSTANCE_TYPE_LEN + VARSTR_HEADER_SIZE] = {0};
|
|
STR_WITH_MAXSIZE_TO_VARSTR(typeBuf, pInstance->type, sizeof(typeBuf));
|
|
RETRIEVE_CHECK_GOTO(colDataSetVal(pColInfo, numOfRows, typeBuf, false), pInstance, &lino, _OVER);
|
|
|
|
pColInfo = taosArrayGet(pBlock->pDataBlock, cols++);
|
|
char descBuf[TSDB_INSTANCE_DESC_LEN + VARSTR_HEADER_SIZE] = {0};
|
|
STR_WITH_MAXSIZE_TO_VARSTR(descBuf, pInstance->desc, sizeof(descBuf));
|
|
RETRIEVE_CHECK_GOTO(colDataSetVal(pColInfo, numOfRows, descBuf, false), pInstance, &lino, _OVER);
|
|
|
|
pColInfo = taosArrayGet(pBlock->pDataBlock, cols++);
|
|
RETRIEVE_CHECK_GOTO(colDataSetVal(pColInfo, numOfRows, (const char *)&pInstance->firstRegTime, false), pInstance,
|
|
&lino, _OVER);
|
|
|
|
pColInfo = taosArrayGet(pBlock->pDataBlock, cols++);
|
|
RETRIEVE_CHECK_GOTO(colDataSetVal(pColInfo, numOfRows, (const char *)&pInstance->lastRegTime, false), pInstance,
|
|
&lino, _OVER);
|
|
|
|
pColInfo = taosArrayGet(pBlock->pDataBlock, cols++);
|
|
RETRIEVE_CHECK_GOTO(colDataSetVal(pColInfo, numOfRows, (const char *)&pInstance->expire, false), pInstance, &lino,
|
|
_OVER);
|
|
|
|
numOfRows++;
|
|
sdbRelease(pSdb, pInstance);
|
|
pInstance = NULL;
|
|
}
|
|
|
|
_OVER:
|
|
pShow->numOfRows += numOfRows;
|
|
pBlock->info.rows += numOfRows;
|
|
|
|
if (code != TSDB_CODE_SUCCESS) {
|
|
mError("failed to retrieve instance rows at line:%d since %s", lino, tstrerror(code));
|
|
}
|
|
|
|
return numOfRows;
|
|
}
|
|
|