diff --git a/cmake/define.inc b/cmake/define.inc index e43e570979..5f17ee1216 100755 --- a/cmake/define.inc +++ b/cmake/define.inc @@ -11,9 +11,9 @@ ENDIF () IF (TD_VPEER) ADD_DEFINITIONS(-D_VPEER) - ADD_DEFINITIONS(-DTSDB_REPLICA_MAX_NUM=3) + #ADD_DEFINITIONS(-DTSDB_REPLICA_MAX_NUM=3) ELSE () - ADD_DEFINITIONS(-DTSDB_REPLICA_MAX_NUM=1) + #ADD_DEFINITIONS(-DTSDB_REPLICA_MAX_NUM=1) ENDIF () IF (TD_ACCOUNT) diff --git a/src/dnode/inc/dnodeMClient.h b/src/dnode/inc/dnodeMClient.h index cab9ea9be4..ba63894631 100644 --- a/src/dnode/inc/dnodeMClient.h +++ b/src/dnode/inc/dnodeMClient.h @@ -24,6 +24,7 @@ int32_t dnodeInitMClient(); void dnodeCleanupMClient(); void dnodeSendMsgToMnode(SRpcMsg *rpcMsg); uint32_t dnodeGetMnodeMasteIp(); +void * dnodeGetMpeerInfos(); #ifdef __cplusplus } diff --git a/src/dnode/src/dnodeMClient.c b/src/dnode/src/dnodeMClient.c index 5630872318..5dd015313a 100644 --- a/src/dnode/src/dnodeMClient.c +++ b/src/dnode/src/dnodeMClient.c @@ -15,33 +15,45 @@ #define _DEFAULT_SOURCE #include "os.h" +#include "cJSON.h" #include "taosmsg.h" #include "tlog.h" #include "trpc.h" #include "tutil.h" +#include "tsync.h" #include "dnode.h" #include "dnodeMClient.h" #include "dnodeModule.h" #include "dnodeMgmt.h" +#define MPEER_CONTENT_LEN 2000 + static bool dnodeReadMnodeIpList(); static void dnodeSaveMnodeIpList(); static void dnodeProcessRspFromMnode(SRpcMsg *pMsg); static void dnodeProcessStatusRsp(SRpcMsg *pMsg); static void (*tsDnodeProcessMgmtRspFp[TSDB_MSG_TYPE_MAX])(SRpcMsg *); static void *tsDnodeMClientRpc = NULL; -static SRpcIpSet tsDnodeMnodeIpList = {0}; +static SRpcIpSet tsMnodeIpList = {0}; +static SDMNodeInfos tsMnodeInfos = {0}; int32_t dnodeInitMClient() { if (!dnodeReadMnodeIpList()) { - dTrace("failed to read mnode iplist, set it from cfg file"); - memset(&tsDnodeMnodeIpList, 0, sizeof(SRpcIpSet)); - tsDnodeMnodeIpList.port = tsMnodeDnodePort; - tsDnodeMnodeIpList.numOfIps = 1; - tsDnodeMnodeIpList.ip[0] = inet_addr(tsMasterIp); + memset(&tsMnodeIpList, 0, sizeof(SRpcIpSet)); + memset(&tsMnodeInfos, 0, sizeof(SDMNodeInfos)); + tsMnodeIpList.port = tsMnodeDnodePort; + tsMnodeIpList.numOfIps = 1; + tsMnodeIpList.ip[0] = inet_addr(tsMasterIp); if (tsSecondIp[0]) { - tsDnodeMnodeIpList.numOfIps = 2; - tsDnodeMnodeIpList.ip[1] = inet_addr(tsSecondIp); + tsMnodeIpList.numOfIps = 2; + tsMnodeIpList.ip[1] = inet_addr(tsSecondIp); + } + } else { + tsMnodeIpList.inUse = tsMnodeInfos.inUse; + tsMnodeIpList.numOfIps = tsMnodeInfos.nodeNum; + tsMnodeIpList.port = tsMnodeInfos.nodeInfos[0].nodePort; + for (int32_t i = 0; i < tsMnodeInfos.nodeNum; i++) { + tsMnodeIpList.ip[i] = tsMnodeInfos.nodeInfos[i].nodeIp; } } @@ -96,23 +108,31 @@ static void dnodeProcessStatusRsp(SRpcMsg *pMsg) { } SDMStatusRsp *pStatusRsp = pMsg->pCont; - if (pStatusRsp->ipList.numOfIps <= 0) { - dError("status msg is invalid, num of ips is %d", pStatusRsp->ipList.numOfIps); + SDMNodeInfos *mpeers = &pStatusRsp->mpeers; + if (mpeers->nodeNum <= 0) { + dError("status msg is invalid, num of ips is %d", mpeers->nodeNum); return; } - pStatusRsp->ipList.port = htons(pStatusRsp->ipList.port); - for (int32_t i = 0; i < pStatusRsp->ipList.numOfIps; ++i) { - pStatusRsp->ipList.ip[i] = htonl(pStatusRsp->ipList.ip[i]); + SRpcIpSet mgmtIpSet = {0}; + mgmtIpSet.inUse = mpeers->inUse; + mgmtIpSet.numOfIps = mpeers->nodeNum; + mgmtIpSet.port = htons(mpeers->nodeInfos[0].nodePort); + for (int32_t i = 0; i < mpeers->nodeNum; i++) { + mgmtIpSet.ip[i] = htonl(mpeers->nodeInfos[i].nodeIp); } - //dTrace("status msg is received, result:%s", tstrerror(pMsg->code)); - - if (memcmp(&(pStatusRsp->ipList), &tsDnodeMnodeIpList, sizeof(SRpcIpSet)) != 0) { - dPrint("mnode ip list is changed, numOfIps:%d inUse:%d", pStatusRsp->ipList.numOfIps, pStatusRsp->ipList.inUse); - memcpy(&tsDnodeMnodeIpList, &pStatusRsp->ipList, sizeof(SRpcIpSet)); - for (int32_t i = 0; i < tsDnodeMnodeIpList.numOfIps; ++i) { - dPrint("mnode index:%d ip:%s", i, taosIpStr(tsDnodeMnodeIpList.ip[i])); + if (memcmp(&mgmtIpSet, &tsMnodeIpList, sizeof(SRpcIpSet)) != 0) { + memcpy(&tsMnodeIpList, &mgmtIpSet, sizeof(SRpcIpSet)); + memcpy(&tsMnodeInfos, mpeers, sizeof(SDMNodeInfos)); + dPrint("mnode ip list is changed, numOfIps:%d inUse:%d", tsMnodeInfos.nodeNum, tsMnodeInfos.inUse); + for (int32_t i = 0; i < mpeers->nodeNum; i++) { + tsMnodeInfos.nodeInfos[i].nodeId = htonl(mpeers->nodeInfos[i].nodeId); + tsMnodeInfos.nodeInfos[i].nodeIp = htonl(mpeers->nodeInfos[i].nodeIp); + tsMnodeInfos.nodeInfos[i].nodePort = htons(mpeers->nodeInfos[i].nodePort); + dPrint("mnode:%d, ip:%s:%u name:%s", tsMnodeInfos.nodeInfos[i].nodeId, + taosIpStr(tsMnodeInfos.nodeInfos[i].nodeId), tsMnodeInfos.nodeInfos[i].nodePort, + tsMnodeInfos.nodeInfos[i].nodeName); } dnodeSaveMnodeIpList(); } @@ -129,70 +149,149 @@ static void dnodeProcessStatusRsp(SRpcMsg *pMsg) { void dnodeSendMsgToMnode(SRpcMsg *rpcMsg) { if (tsDnodeMClientRpc) { - rpcSendRequest(tsDnodeMClientRpc, &tsDnodeMnodeIpList, rpcMsg); + rpcSendRequest(tsDnodeMClientRpc, &tsMnodeIpList, rpcMsg); } } static bool dnodeReadMnodeIpList() { char ipFile[TSDB_FILENAME_LEN] = {0}; - sprintf(ipFile, "%s/iplist", tsDnodeDir); - + sprintf(ipFile, "%s/mgmtIpList.json", tsDnodeDir); FILE *fp = fopen(ipFile, "r"); - if (!fp) return false; - - char option[32] = {0}; - int32_t value = 0; - int32_t num = 0; - - num = fscanf(fp, "%s %d", option, &value); - if (num != 2) return false; - if (strcmp(option, "inUse") != 0) return false; - tsDnodeMnodeIpList.inUse = (int8_t)value;; - - num = fscanf(fp, "%s %d", option, &value); - if (num != 2) return false; - if (strcmp(option, "numOfIps") != 0) return false; - tsDnodeMnodeIpList.numOfIps = (int8_t)value; - - num = fscanf(fp, "%s %d", option, &value); - if (num != 2) return false; - if (strcmp(option, "port") != 0) return false; - tsDnodeMnodeIpList.port = (uint16_t)value; - - for (int32_t i = 0; i < tsDnodeMnodeIpList.numOfIps; i++) { - num = fscanf(fp, "%s %d", option, &value); - if (num != 2) return false; - if (strncmp(option, "ip", 2) != 0) return false; - tsDnodeMnodeIpList.ip[i] = (uint32_t)value; + if (!fp) { + dTrace("failed to read mnode mgmtIpList.json, file not exist"); + return false; } - fclose(fp); - dPrint("read mnode iplist successed"); - for (int32_t i = 0; i < tsDnodeMnodeIpList.numOfIps; i++) { - dPrint("mnode index:%d ip:%s", i, taosIpStr(tsDnodeMnodeIpList.ip[i])); - } + bool ret = false; + int maxLen = 2000; + char *content = calloc(1, maxLen + 1); + int len = fread(content, 1, maxLen, fp); + if (len <= 0) { + free(content); + fclose(fp); + dError("failed to read mnode mgmtIpList.json, content is null"); + return false; + } - return true; + cJSON* root = cJSON_Parse(content); + if (root == NULL) { + dError("failed to read mnode mgmtIpList.json, invalid json format"); + goto PARSE_OVER; + } + + cJSON* inUse = cJSON_GetObjectItem(root, "inUse"); + if (!inUse || inUse->type != cJSON_Number) { + dError("failed to read mnode mgmtIpList.json, inUse not found"); + goto PARSE_OVER; + } + tsMnodeInfos.inUse = inUse->valueint; + + cJSON* nodeNum = cJSON_GetObjectItem(root, "nodeNum"); + if (!nodeNum || nodeNum->type != cJSON_Number) { + dError("failed to read mnode mgmtIpList.json, nodeNum not found"); + goto PARSE_OVER; + } + tsMnodeInfos.nodeNum = nodeNum->valueint; + + cJSON* nodeInfos = cJSON_GetObjectItem(root, "nodeInfos"); + if (!nodeInfos || nodeInfos->type != cJSON_Array) { + dError("failed to read mnode mgmtIpList.json, nodeInfos not found"); + goto PARSE_OVER; + } + + int size = cJSON_GetArraySize(nodeInfos); + if (size != tsMnodeInfos.nodeNum) { + dError("failed to read mnode mgmtIpList.json, nodeInfos size not matched"); + goto PARSE_OVER; + } + + for (int i = 0; i < size; ++i) { + cJSON* nodeInfo = cJSON_GetArrayItem(nodeInfos, i); + if (nodeInfo == NULL) continue; + + cJSON *nodeId = cJSON_GetObjectItem(nodeInfo, "nodeId"); + if (!nodeId || nodeId->type != cJSON_Number) { + dError("failed to read mnode mgmtIpList.json, nodeId not found"); + goto PARSE_OVER; + } + tsMnodeInfos.nodeInfos[i].nodeId = nodeId->valueint; + + cJSON *nodeIp = cJSON_GetObjectItem(nodeInfo, "nodeIp"); + if (!nodeIp || nodeIp->type != cJSON_String || nodeIp->valuestring == NULL) { + dError("failed to read mnode mgmtIpList.json, nodeIp not found"); + goto PARSE_OVER; + } + tsMnodeInfos.nodeInfos[i].nodeIp = inet_addr(nodeIp->valuestring); + + cJSON *nodePort = cJSON_GetObjectItem(nodeInfo, "nodePort"); + if (!nodePort || nodePort->type != cJSON_Number) { + dError("failed to read mnode mgmtIpList.json, nodePort not found"); + goto PARSE_OVER; + } + tsMnodeInfos.nodeInfos[i].nodePort = (uint16_t)nodePort->valueint; + + cJSON *nodeName = cJSON_GetObjectItem(nodeInfo, "nodeName"); + if (!nodeIp || nodeName->type != cJSON_String || nodeName->valuestring == NULL) { + dError("failed to read mnode mgmtIpList.json, nodeName not found"); + goto PARSE_OVER; + } + strncpy(tsMnodeInfos.nodeInfos[i].nodeName, nodeName->valuestring, TSDB_NODE_NAME_LEN); + } + + ret = true; + + dPrint("read mnode iplist successed, numOfIps:%d inUse:%d", tsMnodeInfos.nodeNum, tsMnodeInfos.inUse); + for (int32_t i = 0; i < tsMnodeInfos.nodeNum; i++) { + dPrint("mnode:%d, ip:%s:%u name:%s", tsMnodeInfos.nodeInfos[i].nodeId, + taosIpStr(tsMnodeInfos.nodeInfos[i].nodeId), tsMnodeInfos.nodeInfos[i].nodePort, + tsMnodeInfos.nodeInfos[i].nodeName); + } + +PARSE_OVER: + free(content); + cJSON_Delete(root); + fclose(fp); + return ret; } static void dnodeSaveMnodeIpList() { char ipFile[TSDB_FILENAME_LEN] = {0}; - sprintf(ipFile, "%s/iplist", tsDnodeDir); - + sprintf(ipFile, "%s/mgmtIpList.json", tsDnodeDir); FILE *fp = fopen(ipFile, "w"); if (!fp) return; - fprintf(fp, "inUse %d\n", tsDnodeMnodeIpList.inUse); - fprintf(fp, "numOfIps %d\n", tsDnodeMnodeIpList.numOfIps); - fprintf(fp, "port %u\n", tsDnodeMnodeIpList.port); - for (int32_t i = 0; i < tsDnodeMnodeIpList.numOfIps; i++) { - fprintf(fp, "ip%d %u\n", i, tsDnodeMnodeIpList.ip[i]); + int32_t len = 0; + int32_t maxLen = 2000; + char * content = calloc(1, maxLen + 1); + + len += snprintf(content + len, maxLen - len, "{\n"); + len += snprintf(content + len, maxLen - len, " \"inUse\": %d,\n", tsMnodeInfos.inUse); + len += snprintf(content + len, maxLen - len, " \"nodeNum\": %d,\n", tsMnodeInfos.nodeNum); + len += snprintf(content + len, maxLen - len, " \"nodeInfos\": [{\n"); + for (int32_t i = 0; i < tsMnodeInfos.nodeNum; i++) { + len += snprintf(content + len, maxLen - len, " \"nodeId\": %d,\n", tsMnodeInfos.nodeInfos[i].nodeId); + len += snprintf(content + len, maxLen - len, " \"nodeIp\": \"%s\",\n", taosIpStr(tsMnodeInfos.nodeInfos[i].nodeIp)); + len += snprintf(content + len, maxLen - len, " \"nodePort\": %u,\n", tsMnodeInfos.nodeInfos[i].nodePort); + len += snprintf(content + len, maxLen - len, " \"nodeName\": \"%s\"\n", tsMnodeInfos.nodeInfos[i].nodeName); + if (i < tsMnodeInfos.nodeNum -1) { + len += snprintf(content + len, maxLen - len, " },{\n"); + } else { + len += snprintf(content + len, maxLen - len, " }]\n"); + } } - + len += snprintf(content + len, maxLen - len, "}\n"); + + fwrite(content, 1, len, fp); fclose(fp); + free(content); + dPrint("save mnode iplist successed"); } uint32_t dnodeGetMnodeMasteIp() { - return tsDnodeMnodeIpList.ip[0]; + return tsMnodeIpList.ip[tsMnodeIpList.inUse]; +} + +void* dnodeGetMpeerInfos() { + return &tsMnodeInfos; } \ No newline at end of file diff --git a/src/dnode/src/dnodeMgmt.c b/src/dnode/src/dnodeMgmt.c index da80206e4c..0ec769c0af 100644 --- a/src/dnode/src/dnodeMgmt.c +++ b/src/dnode/src/dnodeMgmt.c @@ -45,7 +45,7 @@ static void *tsDnodeTmr = NULL; static void *tsStatusTimer = NULL; static uint32_t tsRebootTime; static int32_t tsDnodeId = 0; -static char tsDnodeName[TSDB_DNODE_NAME_LEN]; +static char tsDnodeName[TSDB_NODE_NAME_LEN]; int32_t dnodeInitMgmt() { dnodeReadDnodeId(); diff --git a/src/inc/mnode.h b/src/inc/mnode.h index dec9292209..f2c072453f 100644 --- a/src/inc/mnode.h +++ b/src/inc/mnode.h @@ -41,28 +41,21 @@ struct _vg_obj; struct _db_obj; struct _acct_obj; struct _user_obj; +struct _mnode_obj; -typedef struct { +typedef struct _mnode_obj { int32_t mnodeId; - uint32_t privateIp; - uint32_t publicIp; + int32_t dnodeId; int64_t createdTime; - int64_t lostTime; - uint64_t dbVersion; - uint32_t rack; - uint16_t idc; - uint16_t slot; - int8_t role; - int8_t status; - int8_t numOfMnodes; - int32_t numOfDnodes; - char mnodeName[TSDB_DNODE_NAME_LEN + 1]; - int8_t reserved[15]; + int8_t reserved[14]; int8_t updateEnd[1]; int32_t refCount; - int syncFd; - void *hbTimer; - void *pSync; + int8_t role; + int8_t status; + uint16_t port; + uint32_t privateIp; + uint32_t publicIp; + char mnodeName[TSDB_NODE_NAME_LEN + 1]; } SMnodeObj; typedef struct _dnode_obj { @@ -81,7 +74,7 @@ typedef struct _dnode_obj { int8_t alternativeRole; // from dnode status msg, 0-any, 1-mgmt, 2-dnode int8_t status; // set in balance function int32_t customScore; // config by user - char dnodeName[TSDB_DNODE_NAME_LEN + 1]; + char dnodeName[TSDB_NODE_NAME_LEN + 1]; int8_t reserved[15]; int8_t updateEnd[1]; int32_t refCount; diff --git a/src/mnode/inc/mgmtMnode.h b/src/inc/mpeer.h similarity index 51% rename from src/mnode/inc/mgmtMnode.h rename to src/inc/mpeer.h index ad9688c0ee..157ea40119 100644 --- a/src/mnode/inc/mgmtMnode.h +++ b/src/inc/mpeer.h @@ -13,35 +13,37 @@ * along with this program. If not, see . */ -#ifndef TDENGINE_MGMT_MNODE_H -#define TDENGINE_MGMT_MNODE_H +#ifndef TDENGINE_MPEER_H +#define TDENGINE_MPEER_H #ifdef __cplusplus extern "C" { #endif -enum _TSDB_MN_STATUS { - TSDB_MN_STATUS_OFFLINE, - TSDB_MN_STATUS_UNSYNCED, - TSDB_MN_STATUS_SYNCING, - TSDB_MN_STATUS_SERVING +struct _mnode_obj; + +enum _TAOS_MN_STATUS { + TAOS_MN_STATUS_OFFLINE, + TAOS_MN_STATUS_DROPPING, + TAOS_MN_STATUS_READY }; -enum _TSDB_MN_ROLE { - TSDB_MN_ROLE_UNDECIDED, - TSDB_MN_ROLE_SLAVE, - TSDB_MN_ROLE_MASTER -}; +int32_t mpeerInit(); +void mpeerCleanup(); +int32_t mpeerGetMnodesNum(); +void * mpeerGetNextMnode(void *pNode, struct _mnode_obj **pMnode); +void mpeerReleaseMnode(struct _mnode_obj *pMnode); -int32_t mgmtInitMnodes(); -void mgmtCleanupMnodes(); +bool mpeerInServerStatus(); +bool mpeerIsMaster(); +bool mpeerCheckRedirect(); -bool mgmtInServerStatus(); -bool mgmtIsMaster(); +void mpeerGetPrivateIpList(SRpcIpSet *ipSet); +void mpeerGetPublicIpList(SRpcIpSet *ipSet); +void mpeerGetMpeerInfos(void *mpeers); -bool mgmtCheckRedirect(void *handle); -void mgmtGetMnodePrivateIpList(SRpcIpSet *ipSet); -void mgmtGetMnodePublicIpList(SRpcIpSet *ipSet); +char * mpeerGetMnodeStatusStr(int32_t status); +char * mpeerGetMnodeRoleStr(int32_t role); #ifdef __cplusplus } diff --git a/src/inc/taosdef.h b/src/inc/taosdef.h index de5aa1dc12..2b15e7a4c6 100644 --- a/src/inc/taosdef.h +++ b/src/inc/taosdef.h @@ -176,7 +176,7 @@ void tsDataSwap(void *pLeft, void *pRight, int32_t type, int32_t size); #define TSDB_MAX_COLUMNS 256 #define TSDB_MIN_COLUMNS 2 //PRIMARY COLUMN(timestamp) + other columns -#define TSDB_DNODE_NAME_LEN 64 +#define TSDB_NODE_NAME_LEN 64 #define TSDB_TABLE_NAME_LEN 192 #define TSDB_DB_NAME_LEN 32 #define TSDB_COL_NAME_LEN 64 @@ -233,7 +233,7 @@ void tsDataSwap(void *pLeft, void *pRight, int32_t type, int32_t size); /* * this is defined in CMakeList.txt */ -//#define TSDB_REPLICA_MAX_NUM 3 +#define TSDB_REPLICA_MAX_NUM 3 #define TSDB_TBNAME_COLUMN_INDEX (-1) #define TSDB_MULTI_METERMETA_MAX_NUM 100000 // maximum batch size allowed to load metermeta diff --git a/src/inc/taosmsg.h b/src/inc/taosmsg.h index c580bdecdc..b8412a2c63 100644 --- a/src/inc/taosmsg.h +++ b/src/inc/taosmsg.h @@ -577,7 +577,7 @@ typedef struct { typedef struct { uint32_t version; int32_t dnodeId; - char dnodeName[TSDB_DNODE_NAME_LEN]; + char dnodeName[TSDB_NODE_NAME_LEN + 1]; uint32_t privateIp; uint32_t publicIp; uint32_t lastReboot; // time stamp for last reboot @@ -591,7 +591,20 @@ typedef struct { } SDMStatusMsg; typedef struct { - SRpcIpSet ipList; + int32_t nodeId; + uint32_t nodeIp; + uint16_t nodePort; + char nodeName[TSDB_NODE_NAME_LEN + 1]; +} SDMNodeInfo; + +typedef struct { + int8_t inUse; + int8_t nodeNum; + SDMNodeInfo nodeInfos[TSDB_MAX_MPEERS]; +} SDMNodeInfos; + +typedef struct { + SDMNodeInfos mpeers; SDnodeState dnodeState; SVnodeAccess vnodeAccess[]; } SDMStatusRsp; diff --git a/src/mnode/CMakeLists.txt b/src/mnode/CMakeLists.txt index b830695f52..2e975f089c 100644 --- a/src/mnode/CMakeLists.txt +++ b/src/mnode/CMakeLists.txt @@ -13,5 +13,5 @@ IF ((TD_LINUX_64) OR (TD_LINUX_32 AND TD_ARM)) AUX_SOURCE_DIRECTORY(src SRC) ADD_LIBRARY(mnode ${SRC}) - TARGET_LINK_LIBRARIES(mnode trpc tutil pthread) + #TARGET_LINK_LIBRARIES(mnode trpc tutil pthread) ENDIF () \ No newline at end of file diff --git a/src/mnode/inc/mgmtSdb.h b/src/mnode/inc/mgmtSdb.h index ecf6887b42..83afa2a081 100644 --- a/src/mnode/inc/mgmtSdb.h +++ b/src/mnode/inc/mgmtSdb.h @@ -21,21 +21,31 @@ extern "C" { #endif typedef enum { - SDB_KEY_TYPE_STRING, - SDB_KEY_TYPE_AUTO + SDB_TABLE_MNODE = 0, + SDB_TABLE_DNODE = 1, + SDB_TABLE_ACCOUNT = 2, + SDB_TABLE_USER = 3, + SDB_TABLE_DB = 4, + SDB_TABLE_VGROUP = 5, + SDB_TABLE_STABLE = 6, + SDB_TABLE_CTABLE = 7, + SDB_TABLE_MAX = 8 +} ESdbTable; + +typedef enum { + SDB_KEY_STRING, + SDB_KEY_AUTO } ESdbKeyType; typedef enum { - SDB_OPER_TYPE_GLOBAL, - SDB_OPER_TYPE_LOCAL + SDB_OPER_GLOBAL, + SDB_OPER_LOCAL } ESdbOperType; typedef struct { ESdbOperType type; void * table; void * pObj; - int64_t version; - int32_t maxRowSize; int32_t rowSize; void * rowData; } SSdbOperDesc; @@ -45,6 +55,7 @@ typedef struct { int32_t hashSessions; int32_t maxRowSize; int32_t refCountPos; + ESdbTable tableId; ESdbKeyType keyType; int32_t (*insertFp)(SSdbOperDesc *pOper); int32_t (*deleteFp)(SSdbOperDesc *pOper); @@ -52,8 +63,12 @@ typedef struct { int32_t (*encodeFp)(SSdbOperDesc *pOper); int32_t (*decodeFp)(SSdbOperDesc *pDesc); int32_t (*destroyFp)(SSdbOperDesc *pDesc); + int32_t (*updateAllFp)(); } SSdbTableDesc; +int32_t sdbInit(); +void sdbCleanUp(); + void * sdbOpenTable(SSdbTableDesc *desc); void sdbCloseTable(void *handle); diff --git a/src/mnode/src/mgmtDb.c b/src/mnode/src/mgmtDb.c index 9ecc2c6458..946ec29d8c 100644 --- a/src/mnode/src/mgmtDb.c +++ b/src/mnode/src/mgmtDb.c @@ -24,8 +24,8 @@ #include "mgmtDb.h" #include "tcluster.h" #include "tgrant.h" +#include "mpeer.h" #include "mgmtShell.h" -#include "mgmtMnode.h" #include "mgmtProfile.h" #include "mgmtSdb.h" #include "mgmtTable.h" @@ -88,14 +88,9 @@ static int32_t mgmtDbActionUpdate(SSdbOperDesc *pOper) { static int32_t mgmtDbActionEncode(SSdbOperDesc *pOper) { SDbObj *pDb = pOper->pObj; - - if (pOper->maxRowSize < tsDbUpdateSize) { - return -1; - } else { - memcpy(pOper->rowData, pDb, tsDbUpdateSize); - pOper->rowSize = tsDbUpdateSize; - return TSDB_CODE_SUCCESS; - } + memcpy(pOper->rowData, pDb, tsDbUpdateSize); + pOper->rowSize = tsDbUpdateSize; + return TSDB_CODE_SUCCESS; } static int32_t mgmtDbActionDecode(SSdbOperDesc *pOper) { @@ -107,22 +102,28 @@ static int32_t mgmtDbActionDecode(SSdbOperDesc *pOper) { return TSDB_CODE_SUCCESS; } +static int32_t mgmtDbActionUpdateAll() { + return 0; +} + int32_t mgmtInitDbs() { SDbObj tObj; tsDbUpdateSize = (int8_t *)tObj.updateEnd - (int8_t *)&tObj; SSdbTableDesc tableDesc = { + .tableId = SDB_TABLE_DB, .tableName = "dbs", .hashSessions = TSDB_MAX_DBS, .maxRowSize = tsDbUpdateSize, .refCountPos = (int8_t *)(&tObj.refCount) - (int8_t *)&tObj, - .keyType = SDB_KEY_TYPE_STRING, + .keyType = SDB_KEY_STRING, .insertFp = mgmtDbActionInsert, .deleteFp = mgmtDbActionDelete, .updateFp = mgmtDbActionUpdate, .encodeFp = mgmtDbActionEncode, .decodeFp = mgmtDbActionDecode, .destroyFp = mgmtDbActionDestroy, + .updateAllFp = mgmtDbActionUpdateAll }; tsDbSdb = sdbOpenTable(&tableDesc); @@ -136,7 +137,7 @@ int32_t mgmtInitDbs() { mgmtAddShellMsgHandle(TSDB_MSG_TYPE_CM_DROP_DB, mgmtProcessDropDbMsg); mgmtAddShellShowMetaHandle(TSDB_MGMT_TABLE_DB, mgmtGetDbMeta); mgmtAddShellShowRetrieveHandle(TSDB_MGMT_TABLE_DB, mgmtRetrieveDbs); - + mTrace("db data is initialized"); return 0; } @@ -310,7 +311,7 @@ static int32_t mgmtCreateDb(SAcctObj *pAcct, SCMCreateDbMsg *pCreate) { pDb->cfg = *pCreate; SSdbOperDesc oper = { - .type = SDB_OPER_TYPE_GLOBAL, + .type = SDB_OPER_GLOBAL, .table = tsDbSdb, .pObj = pDb, .rowSize = sizeof(SDbObj) @@ -663,7 +664,7 @@ static int32_t mgmtSetDbDropping(SDbObj *pDb) { pDb->status = true; SSdbOperDesc oper = { - .type = SDB_OPER_TYPE_GLOBAL, + .type = SDB_OPER_GLOBAL, .table = tsDbSdb, .pObj = pDb, .rowSize = tsDbUpdateSize @@ -678,8 +679,6 @@ static int32_t mgmtSetDbDropping(SDbObj *pDb) { } static void mgmtProcessCreateDbMsg(SQueuedMsg *pMsg) { - if (mgmtCheckRedirect(pMsg->thandle)) return; - SCMCreateDbMsg *pCreate = pMsg->pCont; pCreate->maxSessions = htonl(pCreate->maxSessions); pCreate->cacheBlockSize = htonl(pCreate->cacheBlockSize); @@ -750,7 +749,7 @@ static int32_t mgmtAlterDb(SDbObj *pDb, SCMAlterDbMsg *pAlter) { if (memcmp(&newCfg, &pDb->cfg, sizeof(SDbCfg)) != 0) { pDb->cfg = newCfg; SSdbOperDesc oper = { - .type = SDB_OPER_TYPE_GLOBAL, + .type = SDB_OPER_GLOBAL, .table = tsDbSdb, .pObj = pDb, .rowSize = tsDbUpdateSize @@ -808,7 +807,7 @@ static void mgmtDropDb(SQueuedMsg *pMsg) { mPrint("db:%s, drop db from sdb", pDb->name); SSdbOperDesc oper = { - .type = SDB_OPER_TYPE_GLOBAL, + .type = SDB_OPER_GLOBAL, .table = tsDbSdb, .pObj = pDb }; diff --git a/src/mnode/src/mgmtDnode.c b/src/mnode/src/mgmtDnode.c index 2f4abc5cfe..51ac4e842d 100644 --- a/src/mnode/src/mgmtDnode.c +++ b/src/mnode/src/mgmtDnode.c @@ -19,8 +19,8 @@ #include "tbalance.h" #include "tcluster.h" #include "mnode.h" +#include "mpeer.h" #include "mgmtDClient.h" -#include "mgmtMnode.h" #include "mgmtShell.h" #include "mgmtDServer.h" #include "mgmtUser.h" @@ -141,8 +141,6 @@ static void clusterProcessCfgDnodeMsgRsp(SRpcMsg *rpcMsg) { } void clusterProcessDnodeStatusMsg(SRpcMsg *rpcMsg) { - if (mgmtCheckRedirect(rpcMsg->handle)) return; - SDMStatusMsg *pStatus = rpcMsg->pCont; pStatus->dnodeId = htonl(pStatus->dnodeId); pStatus->privateIp = htonl(pStatus->privateIp); @@ -221,7 +219,7 @@ void clusterProcessDnodeStatusMsg(SRpcMsg *rpcMsg) { return; } - mgmtGetMnodePrivateIpList(&pRsp->ipList); + mpeerGetMpeerInfos(&pRsp->mpeers); pRsp->dnodeState.dnodeId = htonl(pDnode->dnodeId); pRsp->dnodeState.moduleStatus = htonl(pDnode->moduleStatus); diff --git a/src/mnode/src/mgmtMain.c b/src/mnode/src/mgmtMain.c index e04630d745..a074060f52 100644 --- a/src/mnode/src/mgmtMain.c +++ b/src/mnode/src/mgmtMain.c @@ -22,11 +22,11 @@ #include "taccount.h" #include "tbalance.h" #include "tcluster.h" +#include "tgrant.h" +#include "mpeer.h" #include "mgmtDb.h" #include "mgmtDClient.h" #include "mgmtDServer.h" -#include "tgrant.h" -#include "mgmtMnode.h" #include "mgmtSdb.h" #include "mgmtVgroup.h" #include "mgmtUser.h" @@ -105,7 +105,12 @@ int32_t mgmtStartSystem() { } if (mgmtInitTables() < 0) { - mError("failed to init meters"); + mError("failed to init tables"); + return -1; + } + + if (sdbInit() < 0) { + mError("failed to init sdb"); return -1; } @@ -117,8 +122,8 @@ int32_t mgmtStartSystem() { return -1; } - if (mgmtInitMnodes() < 0) { - mError("failed to init mnodes"); + if (mpeerInit() < 0) { + mError("failed to init mpeers"); return -1; } @@ -135,7 +140,7 @@ int32_t mgmtStartSystem() { void mgmtStopSystem() { - if (mgmtIsMaster()) { + if (mpeerIsMaster()) { mTrace("it is a master mgmt node, it could not be stopped"); return; } @@ -147,7 +152,7 @@ void mgmtStopSystem() { void mgmtCleanUpSystem() { mPrint("starting to clean up mgmt"); grantCleanUp(); - mgmtCleanupMnodes(); + mpeerCleanup(); balanceCleanUp(); mgmtCleanUpShell(); mgmtCleanupDClient(); @@ -158,6 +163,7 @@ void mgmtCleanUpSystem() { clusterCleanUp(); mgmtCleanUpUsers(); acctCleanUp(); + sdbCleanUp(); taosTmrCleanUp(tsMgmtTmr); mPrint("mgmt is cleaned up"); } diff --git a/src/mnode/src/mgmtMnode.c b/src/mnode/src/mgmtMnode.c index 1e2a4e9066..82da454793 100644 --- a/src/mnode/src/mgmtMnode.c +++ b/src/mnode/src/mgmtMnode.c @@ -17,43 +17,36 @@ #include "os.h" #include "taoserror.h" #include "trpc.h" -#include "mgmtMnode.h" +#include "tsync.h" +#include "mpeer.h" #include "mgmtSdb.h" #include "mgmtShell.h" #include "mgmtUser.h" -#ifndef _MPEER - -static SMnodeObj tsMnodeObj = {0}; +extern int32_t mpeerInitMnodes(); +extern void mpeerCleanupMnodes(); static int32_t mgmtGetMnodeMeta(STableMetaMsg *pMeta, SShowObj *pShow, void *pConn); static int32_t mgmtRetrieveMnodes(SShowObj *pShow, char *data, int32_t rows, void *pConn); -int32_t mgmtInitMnodes() { - mgmtAddShellShowMetaHandle(TSDB_MGMT_TABLE_MNODE, mgmtGetMnodeMeta); - mgmtAddShellShowRetrieveHandle(TSDB_MGMT_TABLE_MNODE, mgmtRetrieveMnodes); +#ifndef _MPEER +static SMnodeObj tsMnodeObj = {0}; + +int32_t mpeerInitMnodes() { tsMnodeObj.mnodeId = 1; + tsMnodeObj.dnodeId = 1; tsMnodeObj.privateIp = inet_addr(tsPrivateIp); tsMnodeObj.publicIp = inet_addr(tsPublicIp); tsMnodeObj.createdTime = taosGetTimestampMs(); - tsMnodeObj.role = TSDB_MN_ROLE_MASTER; - tsMnodeObj.status = TSDB_MN_STATUS_SERVING; - tsMnodeObj.numOfMnodes = 1; - sprintf(tsMnodeObj.mnodeName, "%d", tsMnodeObj.mnodeId); - + tsMnodeObj.role = TAOS_SYNC_ROLE_MASTER; + tsMnodeObj.status = TAOS_MN_STATUS_READY; + tsMnodeObj.port = tsMnodeDnodePort; + sprintf(tsMnodeObj.mnodeName, "m%d", tsMnodeObj.mnodeId); + return TSDB_CODE_SUCCESS; } -void mgmtCleanupMnodes() {} -bool mgmtInServerStatus() { return tsMnodeObj.status == TSDB_MN_STATUS_SERVING; } -bool mgmtIsMaster() { return tsMnodeObj.role == TSDB_MN_ROLE_MASTER; } -bool mgmtCheckRedirect(void *thandle) { return false; } - -static int32_t mgmtGetMnodesNum() { - return 1; -} - -static void *mgmtGetNextMnode(void *pNode, SMnodeObj **pMnode) { +void *mpeerGetNextMnode(void *pNode, SMnodeObj **pMnode) { if (*pMnode == NULL) { *pMnode = &tsMnodeObj; } else { @@ -63,22 +56,74 @@ static void *mgmtGetNextMnode(void *pNode, SMnodeObj **pMnode) { return *pMnode; } -char *taosGetMnodeStatusStr(int32_t mnodeStatus) { - switch (mnodeStatus) { - case TSDB_MN_STATUS_OFFLINE: return "offline"; - case TSDB_MN_STATUS_UNSYNCED: return "unsynced"; - case TSDB_MN_STATUS_SYNCING: return "syncing"; - case TSDB_MN_STATUS_SERVING: return "serving"; - default: return "undefined"; +void mpeerGetPrivateIpList(SRpcIpSet *ipSet) { + ipSet->inUse = 0; + ipSet->port = htons(tsMnodeDnodePort); + ipSet->numOfIps = 1; + ipSet->ip[0] = htonl(tsMnodeObj.privateIp); +} + +void mpeerGetPublicIpList(SRpcIpSet *ipSet) { + ipSet->inUse = 0; + ipSet->port = htons(tsMnodeDnodePort); + ipSet->numOfIps = 1; + ipSet->ip[0] = htonl(tsMnodeObj.publicIp); +} + +void mpeerGetMpeerInfos(void *param) { + SDMNodeInfos *mpeers = param; + mpeers->nodeNum = 1; + mpeers->nodeInfos[0].nodeId = htonl(tsMnodeObj.mnodeId); + mpeers->nodeInfos[0].nodeIp = htonl(tsMnodeObj.privateIp); + mpeers->nodeInfos[0].nodePort = htons(tsMnodeObj.port); + strcpy(mpeers->nodeInfos[0].nodeName, tsMnodeObj.mnodeName); +} + +void mpeerCleanupDnodes() {} +int32_t mpeerGetMnodesNum() { return 1; } +void mpeerReleaseMnode(struct _mnode_obj *pMnode) {} +bool mpeerInServerStatus() { return tsMnodeObj.status == TAOS_MN_STATUS_READY; } +bool mpeerIsMaster() { return tsMnodeObj.role == TAOS_SYNC_ROLE_MASTER; } +bool mpeerCheckRedirect() { return false; } + +#endif + +int32_t mpeerInit() { + mgmtAddShellShowMetaHandle(TSDB_MGMT_TABLE_MNODE, mgmtGetMnodeMeta); + mgmtAddShellShowRetrieveHandle(TSDB_MGMT_TABLE_MNODE, mgmtRetrieveMnodes); + + return mpeerInitMnodes(); +} + +void mpeerCleanup() { + mpeerCleanupDnodes(); +} + +char *mpeerGetMnodeStatusStr(int32_t status) { + switch (status) { + case TAOS_MN_STATUS_OFFLINE: + return "offline"; + case TAOS_MN_STATUS_DROPPING: + return "dropping"; + case TAOS_MN_STATUS_READY: + return "ready"; + default: + return "undefined"; } } -char *taosGetMnodeRoleStr(int32_t mnodeRole) { - switch (mnodeRole) { - case TSDB_MN_ROLE_UNDECIDED: return "undicided"; - case TSDB_MN_ROLE_SLAVE: return "slave"; - case TSDB_MN_ROLE_MASTER: return "master"; - default: return "undefined"; +char *mpeerGetMnodeRoleStr(int32_t role) { + switch (role) { + case TAOS_SYNC_ROLE_OFFLINE: + return "offline"; + case TAOS_SYNC_ROLE_UNSYNCED: + return "unsynced"; + case TAOS_SYNC_ROLE_SLAVE: + return "slave"; + case TAOS_SYNC_ROLE_MASTER: + return "master"; + default: + return "undefined"; } } @@ -135,7 +180,7 @@ static int32_t mgmtGetMnodeMeta(STableMetaMsg *pMeta, SShowObj *pShow, void *pCo pShow->offset[i] = pShow->offset[i - 1] + pShow->bytes[i - 1]; } - pShow->numOfRows = mgmtGetMnodesNum(); + pShow->numOfRows = mpeerGetMnodesNum(); pShow->rowSize = pShow->offset[cols - 1] + pShow->bytes[cols - 1]; pShow->pNode = NULL; mgmtReleaseUser(pUser); @@ -151,7 +196,7 @@ static int32_t mgmtRetrieveMnodes(SShowObj *pShow, char *data, int32_t rows, voi char ipstr[32]; while (numOfRows < rows) { - pShow->pNode = mgmtGetNextMnode(pShow->pNode, (SMnodeObj **)&pMnode); + pShow->pNode = mpeerGetNextMnode(pShow->pNode, &pMnode); if (pMnode == NULL) break; cols = 0; @@ -175,11 +220,11 @@ static int32_t mgmtRetrieveMnodes(SShowObj *pShow, char *data, int32_t rows, voi cols++; pWrite = data + pShow->offset[cols] * rows + pShow->bytes[cols] * numOfRows; - strcpy(pWrite, taosGetMnodeStatusStr(pMnode->status)); + strcpy(pWrite, mpeerGetMnodeStatusStr(pMnode->status)); cols++; pWrite = data + pShow->offset[cols] * rows + pShow->bytes[cols] * numOfRows; - strcpy(pWrite, taosGetMnodeRoleStr(pMnode->role)); + strcpy(pWrite, mpeerGetMnodeRoleStr(pMnode->role)); cols++; numOfRows++; @@ -188,20 +233,4 @@ static int32_t mgmtRetrieveMnodes(SShowObj *pShow, char *data, int32_t rows, voi pShow->numOfReads += numOfRows; return numOfRows; -} - -void mgmtGetMnodePrivateIpList(SRpcIpSet *ipSet) { - ipSet->inUse = 0; - ipSet->port = htons(tsMnodeDnodePort); - ipSet->numOfIps = 1; - ipSet->ip[0] = htonl(tsMnodeObj.privateIp); -} - -void mgmtGetMnodePublicIpList(SRpcIpSet *ipSet) { - ipSet->inUse = 0; - ipSet->port = htons(tsMnodeDnodePort); - ipSet->numOfIps = 1; - ipSet->ip[0] = htonl(tsMnodeObj.publicIp); -} - -#endif \ No newline at end of file +} \ No newline at end of file diff --git a/src/mnode/src/mgmtProfile.c b/src/mnode/src/mgmtProfile.c index 2b22fae47a..f7dec4656b 100644 --- a/src/mnode/src/mgmtProfile.c +++ b/src/mnode/src/mgmtProfile.c @@ -19,7 +19,7 @@ #include "taccount.h" #include "tcluster.h" #include "mgmtDb.h" -#include "mgmtMnode.h" +#include "mpeer.h" #include "mgmtProfile.h" #include "mgmtShell.h" #include "mgmtTable.h" @@ -681,8 +681,7 @@ int32_t mgmtRetrieveConns(SShowObj *pShow, char *data, int32_t rows, void *pConn void mgmtProcessKillQueryMsg(SQueuedMsg *pMsg) { SRpcMsg rpcRsp = {.handle = pMsg->thandle, .pCont = NULL, .contLen = 0, .code = 0, .msgType = 0}; - if (mgmtCheckRedirect(pMsg->thandle)) return; - + SUserObj *pUser = mgmtGetUserFromConn(pMsg->thandle, NULL); if (pUser == NULL) { rpcRsp.code = TSDB_CODE_INVALID_USER; @@ -705,8 +704,7 @@ void mgmtProcessKillQueryMsg(SQueuedMsg *pMsg) { void mgmtProcessKillStreamMsg(SQueuedMsg *pMsg) { SRpcMsg rpcRsp = {.handle = pMsg->thandle, .pCont = NULL, .contLen = 0, .code = 0, .msgType = 0}; - if (mgmtCheckRedirect(pMsg->thandle)) return; - + SUserObj *pUser = mgmtGetUserFromConn(pMsg->thandle, NULL); if (pUser == NULL) { rpcRsp.code = TSDB_CODE_INVALID_USER; @@ -729,8 +727,7 @@ void mgmtProcessKillStreamMsg(SQueuedMsg *pMsg) { void mgmtProcessKillConnectionMsg(SQueuedMsg *pMsg) { SRpcMsg rpcRsp = {.handle = pMsg->thandle, .pCont = NULL, .contLen = 0, .code = 0, .msgType = 0}; - if (mgmtCheckRedirect(pMsg->thandle)) return; - + SUserObj *pUser = mgmtGetUserFromConn(pMsg->thandle, NULL); if (pUser == NULL) { rpcRsp.code = TSDB_CODE_INVALID_USER; diff --git a/src/mnode/src/mgmtSdb.c b/src/mnode/src/mgmtSdb.c index f3fc7d07f5..bc0d1b81f2 100644 --- a/src/mnode/src/mgmtSdb.c +++ b/src/mnode/src/mgmtSdb.c @@ -22,37 +22,30 @@ #include "tlog.h" #include "trpc.h" #include "tutil.h" +#include "twal.h" +#include "tsync.h" #include "hashint.h" #include "hashstr.h" - #include "mgmtSdb.h" -#define abs(x) (((x) < 0) ? -(x) : (x)) -#define SDB_MAX_PEERS 4 -#define SDB_DELIMITER 0xFFF00F00 -#define SDB_ENDCOMMIT 0xAFFFAAAF - typedef struct { - uint64_t swVersion; - int16_t sdbFileVersion; - char reserved[2]; - TSCKSUM checkSum; -} SSdbHeader; + int32_t code; + int64_t version; + void * sync; + void * wal; + sem_t sem; + pthread_mutex_t mutex; +} SSdbSync; typedef struct _SSdbTable { - SSdbHeader header; - char tableName[TSDB_DB_NAME_LEN]; - char fileName[TSDB_FILENAME_LEN]; + char tableName[TSDB_DB_NAME_LEN + 1]; + ESdbTable tableId; ESdbKeyType keyType; - int32_t tableId; int32_t hashSessions; int32_t maxRowSize; int32_t refCountPos; int32_t autoIndex; - int32_t fd; int64_t numOfRows; - int64_t version; - int64_t fileSize; void * iHandle; int32_t (*insertFp)(SSdbOperDesc *pDesc); int32_t (*deleteFp)(SSdbOperDesc *pOper); @@ -60,363 +53,154 @@ typedef struct _SSdbTable { int32_t (*decodeFp)(SSdbOperDesc *pOper); int32_t (*encodeFp)(SSdbOperDesc *pOper); int32_t (*destroyFp)(SSdbOperDesc *pOper); + int32_t (*updateAllFp)(); pthread_mutex_t mutex; } SSdbTable; typedef struct { - int64_t version; - int64_t offset; int32_t rowSize; void * row; } SRowMeta; -typedef struct { - int32_t delimiter; - int32_t rowSize; - int64_t version; - char data[]; -} SRowHead; - typedef enum { - SDB_FORWARD_TYPE_INSERT, - SDB_FORWARD_TYPE_DELETE, - SDB_FORWARD_TYPE_UPDATE -} ESdbForwardType; + SDB_ACTION_INSERT, + SDB_ACTION_DELETE, + SDB_ACTION_UPDATE +} ESdbActionType; -typedef struct { - ESdbForwardType type; - int32_t tableId; - int64_t version; - int32_t rowSize; - void * rowData; -} SForwardMsg; - -extern char version[]; -const int16_t sdbFileVersion = 2; -int32_t (*mpeerForwardRequestFp)(SForwardMsg *forwardMsg) = NULL; - -static SSdbTable *sdbTableList[10] = {0}; -static int32_t sdbNumOfTables = 0; -static uint64_t sdbVersion = 0; +static SSdbTable *tsSdbTableList[SDB_TABLE_MAX] = {0}; +static int32_t tsSdbNumOfTables = 0; +static SSdbSync * tsSdbSync; static void *(*sdbInitIndexFp[])(int32_t maxRows, int32_t dataSize) = {sdbOpenStrHash, sdbOpenIntHash}; static void *(*sdbAddIndexFp[])(void *handle, void *key, void *data) = {sdbAddStrHash, sdbAddIntHash}; -static void (*sdbDeleteIndexFp[])(void *handle, void *key) = {sdbDeleteStrHash, sdbDeleteIntHash}; +static void (*sdbDeleteIndexFp[])(void *handle, void *key) = {sdbDeleteStrHash, sdbDeleteIntHash}; static void *(*sdbGetIndexFp[])(void *handle, void *key) = {sdbGetStrHashData, sdbGetIntHashData}; -static void (*sdbCleanUpIndexFp[])(void *handle) = {sdbCloseStrHash, sdbCloseIntHash}; +static void (*sdbCleanUpIndexFp[])(void *handle) = {sdbCloseStrHash, sdbCloseIntHash}; static void *(*sdbFetchRowFp[])(void *handle, void *ptr, void **ppRow) = {sdbFetchStrHashData, sdbFetchIntHashData}; +static int sdbProcessWrite(void *param, void *data, int type); -uint64_t sdbGetVersion() { return sdbVersion; } -int64_t sdbGetId(void *handle) { return ((SSdbTable *)handle)->version; } -int64_t sdbGetNumOfRows(void *handle) { return ((SSdbTable *)handle)->numOfRows; } +uint64_t sdbGetVersion() { return tsSdbSync->version; } +int64_t sdbGetId(void *handle) { return ((SSdbTable *)handle)->autoIndex; } +int64_t sdbGetNumOfRows(void *handle) { return ((SSdbTable *)handle)->numOfRows; } + +static char *sdbGetActionStr(int32_t action) { + switch (action) { + case SDB_ACTION_INSERT: + return "insert"; + case SDB_ACTION_DELETE: + return "delete"; + case SDB_ACTION_UPDATE: + return "update"; + } + return "invalid"; +} static char *sdbGetkeyStr(SSdbTable *pTable, void *row) { static char str[16]; switch (pTable->keyType) { - case SDB_KEY_TYPE_STRING: + case SDB_KEY_STRING: return (char *)row; - case SDB_KEY_TYPE_AUTO: + case SDB_KEY_AUTO: sprintf(str, "%d", *(int32_t *)row); return str; default: - return "unknown"; + return "invalid"; } } -static int32_t sdbForwardDbReqToPeer(SForwardMsg *forwardMsg) { - if (mpeerForwardRequestFp) { - return mpeerForwardRequestFp(forwardMsg); - } else { - return 0; - } +static void *sdbGetTableFromId(int32_t tableId) { + return tsSdbTableList[tableId]; } -static void sdbFinishCommit(SSdbTable *pTable) { - uint32_t sdbEcommit = SDB_ENDCOMMIT; - off_t offset = lseek(pTable->fd, 0, SEEK_END); - assert(offset == pTable->fileSize); - twrite(pTable->fd, &sdbEcommit, sizeof(sdbEcommit)); - pTable->fileSize += sizeof(sdbEcommit); -} +// static void mpeerConfirmForward(void *ahandle, void *param, int32_t code) { +// sem_post(&tsSdbSync->sem); +// mPrint("mpeerConfirmForward"); +// } -static int32_t sdbOpenSdbFile(SSdbTable *pTable) { - struct stat fstat, ofstat; - uint64_t size; - char * dirc = NULL; - char * basec = NULL; - union { - char cversion[64]; - uint64_t iversion; - } swVersion; - - memcpy(swVersion.cversion, version, sizeof(uint64_t)); - - // check sdb.db and .sdb.db status - char fn[TSDB_FILENAME_LEN] = "\0"; - dirc = strdup(pTable->fileName); - basec = strdup(pTable->fileName); - sprintf(fn, "%s/.%s", dirname(dirc), basename(basec)); - tfree(dirc); - tfree(basec); - if (stat(fn, &ofstat) == 0) { // .sdb.db file exists - if (stat(pTable->fileName, &fstat) == 0) { - remove(fn); - } else { - remove(pTable->fileName); - rename(fn, pTable->fileName); - } - } - - pTable->fd = open(pTable->fileName, O_RDWR | O_CREAT, S_IRWXU | S_IRWXG | S_IRWXO); - if (pTable->fd < 0) { - sdbError("table:%s, failed to open file:%s", pTable->tableName, pTable->fileName); - return -1; - } - - pTable->fileSize = 0; - stat(pTable->fileName, &fstat); - size = sizeof(pTable->header); - - if (fstat.st_size == 0) { - pTable->header.swVersion = swVersion.iversion; - pTable->header.sdbFileVersion = sdbFileVersion; - if (taosCalcChecksumAppend(0, (uint8_t *)(&pTable->header), size) < 0) { - sdbError("table:%s, failed to get file header checksum, file:%s", pTable->tableName, pTable->fileName); - tclose(pTable->fd); - return -1; - } - twrite(pTable->fd, &(pTable->header), size); - pTable->fileSize += size; - sdbFinishCommit(pTable); - } else { - uint32_t sdbEcommit = 0; - off_t offset = lseek(pTable->fd, -(sizeof(sdbEcommit)), SEEK_END); - while (offset > 0) { - read(pTable->fd, &sdbEcommit, sizeof(sdbEcommit)); - if (sdbEcommit == SDB_ENDCOMMIT) { - ftruncate(pTable->fd, offset + sizeof(sdbEcommit)); - break; - } - offset = lseek(pTable->fd, -(sizeof(sdbEcommit) + 1), SEEK_CUR); - } - lseek(pTable->fd, 0, SEEK_SET); - - ssize_t tsize = read(pTable->fd, &(pTable->header), size); - if (tsize < size) { - sdbError("table:%s, failed to read sdb file header, file:%s", pTable->tableName, pTable->fileName); - tclose(pTable->fd); - return -1; - } - - if (pTable->header.swVersion != swVersion.iversion) { - sdbWarn("table:%s, sdb file:%s version not match software version", pTable->tableName, pTable->fileName); - } - - if (!taosCheckChecksumWhole((uint8_t *)(&pTable->header), size)) { - sdbError("table:%s, sdb file header is broken since checksum mismatch, file:%s", pTable->tableName, pTable->fileName); - tclose(pTable->fd); - return -1; - } - - pTable->fileSize += size; - // skip end commit symbol - lseek(pTable->fd, sizeof(sdbEcommit), SEEK_CUR); - pTable->fileSize += sizeof(sdbEcommit); - } - - pTable->numOfRows = 0; - - return pTable->fd; -} - -static int32_t sdbInitTableByFile(SSdbTable *pTable) { - sdbTrace("table:%s, open sdb file:%s for read", pTable->tableName, pTable->fileName); - if (sdbOpenSdbFile(pTable) < 0) { - sdbError("table:%s, failed to open sdb file:%s for read", pTable->tableName, pTable->fileName); - return -1; - } +static int32_t sdbForwardDbReqToPeer(SWalHead *pHead) { + // int32_t code = syncForwardToPeer(NULL, pHead, NULL); + // if (code < 0) { + // return code; + // } - int32_t total_size = sizeof(SRowHead) + pTable->maxRowSize + sizeof(TSCKSUM); - SRowHead *rowHead = (SRowHead *)malloc(total_size); - if (rowHead == NULL) { - sdbError("table:%s, failed to allocate row head memory, sdb:%s", pTable->tableName, pTable->tableName); + // sem_wait(&tsSdbSync->sem); + // return tsSdbSync->code; + return TSDB_CODE_SUCCESS; +} + +int32_t sdbInit() { + tsSdbSync = calloc(1, sizeof(SSdbSync)); + sem_init(&tsSdbSync->sem, 0, 0); + pthread_mutex_init(&tsSdbSync->mutex, NULL); + + SWalCfg walCfg = {.commitLog = 2, .wals = 2, .keep = 1}; + tsSdbSync->wal = walOpen(tsMnodeDir, &walCfg); + if (tsSdbSync->wal == NULL) { + sdbError("failed to open sdb in %s", tsMnodeDir); return -1; } - int32_t numOfChanged = 0; - int32_t maxAutoIndex = 0; - while (1) { - memset(rowHead, 0, total_size); + sdbTrace("open sdb file for read"); + walRestore(tsSdbSync->wal, tsSdbSync, sdbProcessWrite); - int32_t bytes = read(pTable->fd, rowHead, sizeof(SRowHead)); - if (bytes < 0) { - sdbError("table:%s, failed to read sdb file:%s", pTable->tableName, pTable->fileName); - tfree(rowHead); - return -1; + int32_t totalRows = 0; + int32_t numOfTables = 0; + for (int32_t tableId = SDB_TABLE_DNODE; tableId < SDB_TABLE_MAX; ++tableId) { + SSdbTable *pTable = sdbGetTableFromId(tableId); + if (pTable == NULL) continue; + if (pTable->updateAllFp) { + (*pTable->updateAllFp)(); } - if (bytes == 0) break; - - if (bytes < sizeof(SRowHead) || rowHead->delimiter != SDB_DELIMITER) { - pTable->fileSize++; - lseek(pTable->fd, -(bytes - 1), SEEK_CUR); - continue; - } - - if (rowHead->rowSize < 0 || rowHead->rowSize > pTable->maxRowSize) { - sdbError("table:%s, error row size in sdb filesize:%d, version:%d rowSize:%d maxRowSize:%d", pTable->tableName, - pTable->fileSize, rowHead->version, rowHead->rowSize, pTable->maxRowSize); - pTable->fileSize += sizeof(SRowHead); - continue; - } - - bytes = read(pTable->fd, rowHead->data, rowHead->rowSize + sizeof(TSCKSUM)); - if (bytes < rowHead->rowSize + sizeof(TSCKSUM)) { - // TODO: Here may cause pTable->fileSize not end of the file - sdbError("table:%s, failed to read sdb file, version:%d rowSize:%d", pTable->tableName, rowHead->version, - rowHead->rowSize); - break; - } - - int32_t real_size = sizeof(SRowHead) + rowHead->rowSize + sizeof(TSCKSUM); - if (!taosCheckChecksumWhole((uint8_t *)rowHead, real_size)) { - sdbError("table:%s, error sdb checksum, version:%d, skip", pTable->tableName, rowHead->version); - pTable->fileSize += real_size; - continue; - } - - if (pTable->keyType == SDB_KEY_TYPE_AUTO) { - maxAutoIndex = MAX(maxAutoIndex, *(int32_t *) rowHead->data); - } - - pTable->version = MAX(pTable->version, abs(rowHead->version)); - - void *pMetaRow = sdbGetRow(pTable, rowHead->data); - if (pMetaRow == NULL) { - if (rowHead->version < 0) { - sdbError("table:%s, error sdb negative version:%d, record:%s, skip", pTable->tableName, rowHead->version, - sdbGetkeyStr(pTable, rowHead->data)); - } else { - SRowMeta rowMeta; - rowMeta.version = rowHead->version; - rowMeta.offset = pTable->fileSize; - rowMeta.rowSize = rowHead->rowSize; - SSdbOperDesc oper = { - .table = pTable, - .rowData = rowHead->data, - .rowSize = rowHead->rowSize - }; - int32_t code = (*pTable->decodeFp)(&oper); - if (code == TSDB_CODE_SUCCESS) { - rowMeta.row = oper.pObj; - (*sdbAddIndexFp[pTable->keyType])(pTable->iHandle, rowMeta.row, &rowMeta); - pTable->numOfRows++; - sdbTrace("table:%s, version:%" PRId64 " numOfRows:%d, read new record:%s", - pTable->tableName, pTable->version, pTable->numOfRows, sdbGetkeyStr(pTable, rowHead->data)); - } else { - sdbTrace("table:%s, version:%" PRId64 " numOfRows:%d, failed to decode record:%s", - pTable->tableName, pTable->version, pTable->numOfRows, sdbGetkeyStr(pTable, rowHead->data)); - } - } - } else { - if (rowHead->version < 0) { - (*sdbDeleteIndexFp[pTable->keyType])(pTable->iHandle, rowHead->data); - pTable->numOfRows--; - sdbTrace("table:%s, version:%" PRId64 " numOfRows:%d, read deleted record:%s", - pTable->tableName, pTable->version, pTable->numOfRows, sdbGetkeyStr(pTable, rowHead->data)); - } else { - SRowMeta rowMeta; - rowMeta.version = rowHead->version; - rowMeta.offset = pTable->fileSize; - rowMeta.rowSize = rowHead->rowSize; - SSdbOperDesc oper = { - .table = pTable, - .rowData = rowHead->data, - .rowSize = rowHead->rowSize, - .pObj = pMetaRow - }; - (*sdbDeleteIndexFp[pTable->keyType])(pTable->iHandle, rowHead->data); - - int32_t code = (*pTable->decodeFp)(&oper); - if (code == TSDB_CODE_SUCCESS) { - rowMeta.row = oper.pObj; - (*sdbAddIndexFp[pTable->keyType])(pTable->iHandle, rowMeta.row, &rowMeta); - sdbTrace("table:%s, version:%" PRId64 " numOfRows:%d, read updated record:%s", - pTable->tableName, pTable->version, pTable->numOfRows, sdbGetkeyStr(pTable, rowHead->data)); - } else { - sdbTrace("table:%s, version:%" PRId64 " numOfRows:%d, failed to decode record:%s", - pTable->tableName, pTable->version, pTable->numOfRows, sdbGetkeyStr(pTable, rowHead->data)); - } - } - numOfChanged++; - } - - pTable->fileSize += real_size; - pTable->fileSize += 4; - lseek(pTable->fd, 4, SEEK_CUR); + totalRows += pTable->numOfRows; + numOfTables++; + sdbTrace("table:%s, is initialized, numOfRows:%d", pTable->tableName, pTable->numOfRows); } - void *pNode = NULL; - while (1) { - SRowMeta * pMeta; - pNode = (*sdbFetchRowFp[pTable->keyType])(pTable->iHandle, pNode, (void **)&pMeta); - if (pMeta == NULL) break; - - SSdbOperDesc oper = { - .pObj = pMeta->row, - .table = pTable, - .version = pMeta->version, - }; - - sdbIncRef(pTable, oper.pObj); - int32_t code = (*pTable->insertFp)(&oper); - if (code != TSDB_CODE_SUCCESS) { - sdbError("table:%s, failed to insert record:%s", pTable->tableName, sdbGetkeyStr(pTable, rowHead->data)); - } - } - - sdbVersion += pTable->version; - - if (pTable->keyType == SDB_KEY_TYPE_AUTO) { - pTable->autoIndex = maxAutoIndex; - } - - tfree(rowHead); - return 0; + sdbTrace("sdb is initialized, version:%d totalRows:%d numOfTables:%d", tsSdbSync->version, totalRows, numOfTables); + return TSDB_CODE_SUCCESS; } -void *sdbOpenTable(SSdbTableDesc *pDesc) { - SSdbTable *pTable = (SSdbTable *)calloc(1, sizeof(SSdbTable)); - if (pTable == NULL) return NULL; - - pTable->keyType = pDesc->keyType; - pTable->hashSessions = pDesc->hashSessions; - pTable->maxRowSize = pDesc->maxRowSize; - pTable->refCountPos = pDesc->refCountPos; - pTable->insertFp = pDesc->insertFp; - pTable->deleteFp = pDesc->deleteFp; - pTable->updateFp = pDesc->updateFp; - pTable->encodeFp = pDesc->encodeFp; - pTable->decodeFp = pDesc->decodeFp; - pTable->destroyFp = pDesc->destroyFp; - strcpy(pTable->tableName, pDesc->tableName); - sprintf(pTable->fileName, "%s/%s.db", tsMnodeDir, pTable->tableName); - - if (sdbInitIndexFp[pTable->keyType] != NULL) { - pTable->iHandle = (*sdbInitIndexFp[pTable->keyType])(pTable->maxRowSize, sizeof(SRowMeta)); +void sdbCleanUp() { + if (tsSdbSync) { + sem_destroy(&tsSdbSync->sem); + pthread_mutex_destroy(&tsSdbSync->mutex); + walClose(tsSdbSync->wal); + free(tsSdbSync); + tsSdbSync = NULL; } +} - pthread_mutex_init(&pTable->mutex, NULL); +void sdbIncRef(void *handle, void *pRow) { + if (pRow) { + SSdbTable *pTable = handle; + int32_t * pRefCount = (int32_t *)(pRow + pTable->refCountPos); + atomic_add_fetch_32(pRefCount, 1); + if (0 && strcmp(pTable->tableName, "dnodes") == 0) { + sdbTrace("table:%s, add ref to record:%s:%s:%d", pTable->tableName, pTable->tableName, sdbGetkeyStr(pTable, pRow), + *pRefCount); + } + } +} - if (sdbInitTableByFile(pTable) < 0) return NULL; - - pTable->tableId = sdbNumOfTables++; - sdbTableList[pTable->tableId] = pTable; - - sdbTrace("table:%s, is initialized, sdbversion:%" PRId64 " version:%" PRId64 " numOfRows:%d numOfTables:%d", - pTable->tableName, sdbVersion, pTable->version, pTable->numOfRows, sdbNumOfTables); - - return pTable; +void sdbDecRef(void *handle, void *pRow) { + if (pRow) { + SSdbTable *pTable = handle; + int32_t * pRefCount = (int32_t *)(pRow + pTable->refCountPos); + int32_t refCount = atomic_sub_fetch_32(pRefCount, 1); + if (0 && strcmp(pTable->tableName, "dnodes") == 0) { + sdbTrace("table:%s, def ref of record:%s:%s:%d", pTable->tableName, pTable->tableName, sdbGetkeyStr(pTable, pRow), + *pRefCount); + } + int8_t *updateEnd = pRow + pTable->refCountPos - 1; + if (refCount <= 0 && *updateEnd) { + sdbTrace("table:%s, record:%s:%s:%d is destroyed", pTable->tableName, pTable->tableName, + sdbGetkeyStr(pTable, pRow), *pRefCount); + SSdbOperDesc oper = {.pObj = pRow}; + (*pTable->destroyFp)(&oper); + } + } } static SRowMeta *sdbGetRowMeta(void *handle, void *key) { @@ -430,34 +214,6 @@ static SRowMeta *sdbGetRowMeta(void *handle, void *key) { return pMeta; } -void sdbIncRef(void *handle, void *pRow) { - if (pRow) { - SSdbTable *pTable = handle; - int32_t *pRefCount = (int32_t *)(pRow + pTable->refCountPos); - atomic_add_fetch_32(pRefCount, 1); - if (0 && strcmp(pTable->tableName, "dnodes") == 0) { - sdbTrace("table:%s, add ref to record:%s:%s:%d", pTable->tableName, pTable->tableName, sdbGetkeyStr(pTable, pRow), *pRefCount); - } - } -} - -void sdbDecRef(void *handle, void *pRow) { - if (pRow) { - SSdbTable *pTable = handle; - int32_t *pRefCount = (int32_t *)(pRow + pTable->refCountPos); - int32_t refCount = atomic_sub_fetch_32(pRefCount, 1); - if (0 && strcmp(pTable->tableName, "dnodes") == 0) { - sdbTrace("table:%s, def ref of record:%s:%s:%d", pTable->tableName, pTable->tableName, sdbGetkeyStr(pTable, pRow), *pRefCount); - } - int8_t* updateEnd = pRow + pTable->refCountPos - 1; - if (refCount <= 0 && *updateEnd) { - sdbTrace("table:%s, record:%s:%s:%d is destroyed", pTable->tableName, pTable->tableName, sdbGetkeyStr(pTable, pRow), *pRefCount); - SSdbOperDesc oper = {.pObj = pRow}; - (*pTable->destroyFp)(&oper); - } - } -} - void *sdbGetRow(void *handle, void *key) { SSdbTable *pTable = (SSdbTable *)handle; SRowMeta * pMeta; @@ -476,100 +232,205 @@ void *sdbGetRow(void *handle, void *key) { return pMeta->row; } -int32_t sdbInsertRow(SSdbOperDesc *pOper) { - SSdbTable *pTable = (SSdbTable *)pOper->table; - if (pTable == NULL) { - sdbError("sdb tables is null"); +static int32_t sdbInsertLocal(SSdbTable *pTable, SSdbOperDesc *pOper) { + SRowMeta rowMeta; + rowMeta.rowSize = pOper->rowSize; + rowMeta.row = pOper->pObj; + + pthread_mutex_lock(&pTable->mutex); + (*sdbAddIndexFp[pTable->keyType])(pTable->iHandle, pOper->pObj, &rowMeta); + sdbIncRef(pTable, pOper->pObj); + pTable->numOfRows++; + pthread_mutex_unlock(&pTable->mutex); + + sdbTrace("table:%s, insert record:%s, numOfRows:%d", pTable->tableName, sdbGetkeyStr(pTable, pOper->pObj), + pTable->numOfRows); + + (*pTable->insertFp)(pOper); + return TSDB_CODE_SUCCESS; +} + +static int32_t sdbDeleteLocal(SSdbTable *pTable, SSdbOperDesc *pOper) { + pthread_mutex_lock(&pTable->mutex); + (*sdbDeleteIndexFp[pTable->keyType])(pTable->iHandle, pOper->pObj); + pTable->numOfRows--; + pthread_mutex_unlock(&pTable->mutex); + + sdbTrace("table:%s, delete record:%s, numOfRows:%d", pTable->tableName, sdbGetkeyStr(pTable, pOper->pObj), + pTable->numOfRows); + + (*pTable->deleteFp)(pOper); + int8_t *updateEnd = pOper->pObj + pTable->refCountPos - 1; + *updateEnd = 1; + sdbDecRef(pTable, pOper->pObj); + + return TSDB_CODE_SUCCESS; +} + +static int32_t sdbUpdateLocal(SSdbTable *pTable, SSdbOperDesc *pOper) { + sdbTrace("table:%s, update record:%s, numOfRows:%d", pTable->tableName, sdbGetkeyStr(pTable, pOper->pObj), + pTable->numOfRows); + + (*pTable->updateFp)(pOper); + return TSDB_CODE_SUCCESS; +} + +static int32_t sdbProcessWriteFromApp(SSdbTable *pTable, SWalHead *pHead, int32_t action) { + int32_t code = 0; + + pthread_mutex_lock(&tsSdbSync->mutex); + tsSdbSync->version++; + pHead->version = tsSdbSync->version; + + code = sdbForwardDbReqToPeer(pHead); + if (code != TSDB_CODE_SUCCESS) { + pthread_mutex_unlock(&tsSdbSync->mutex); + sdbError("table:%s, failed to forward %s record:%s from file, version:%" PRId64 ", reason:%s", pTable->tableName, + sdbGetActionStr(action), sdbGetkeyStr(pTable, pHead->cont), pHead->version, tstrerror(code)); + return code; + } + + code = walWrite(tsSdbSync->wal, pHead); + pthread_mutex_unlock(&tsSdbSync->mutex); + + if (code < 0) { + sdbError("table:%s, failed to %s record:%s to file, version:%" PRId64 ", reason:%s", pTable->tableName, + sdbGetActionStr(action), sdbGetkeyStr(pTable, pHead->cont), pHead->version, tstrerror(code)); + } else { + sdbTrace("table:%s, success to %s record:%s to file, version:%" PRId64, pTable->tableName, sdbGetActionStr(action), + sdbGetkeyStr(pTable, pHead->cont), pHead->version); + } + + walFsync(tsSdbSync->wal); + free(pHead); + + return code; +} + +static int32_t sdbProcessWriteFromWal(SSdbTable *pTable, SWalHead *pHead, int32_t action) { + pthread_mutex_lock(&tsSdbSync->mutex); + if (pHead->version <= tsSdbSync->version) { + pthread_mutex_unlock(&tsSdbSync->mutex); + return TSDB_CODE_SUCCESS; + } else if (pHead->version != tsSdbSync->version + 1) { + pthread_mutex_unlock(&tsSdbSync->mutex); + sdbError("table:%s, failed to restore %s record:%s from file, version:%" PRId64 " too large, sdb version:%" PRId64, + pTable->tableName, sdbGetActionStr(action), sdbGetkeyStr(pTable, pHead->cont), pHead->version, + tsSdbSync->version); return TSDB_CODE_OTHERS; } + tsSdbSync->version = pHead->version; + sdbTrace("table:%s, success to restore %s record:%s from file, version:%" PRId64, pTable->tableName, + sdbGetActionStr(action), sdbGetkeyStr(pTable, pHead->cont), pHead->version); + + int32_t code = -1; + if (action == SDB_ACTION_INSERT) { + SSdbOperDesc oper = { + .rowSize = pHead->len, + .rowData = pHead->cont, + .table = pTable, + }; + code = (*pTable->decodeFp)(&oper); + if (code < 0) { + sdbTrace("table:%s, failed to decode %s record:%s from file, version:%" PRId64, pTable->tableName, + sdbGetActionStr(action), sdbGetkeyStr(pTable, pHead->cont), pHead->version); + pthread_mutex_unlock(&tsSdbSync->mutex); + return code; + } + + code = sdbInsertLocal(pTable, &oper); + } else if (action == SDB_ACTION_DELETE) { + SRowMeta *rowMeta = sdbGetRowMeta(pTable, pHead->cont); + assert(rowMeta != NULL && rowMeta->row != NULL); + + SSdbOperDesc oper = { + .table = pTable, + .pObj = rowMeta->row, + }; + + code = sdbDeleteLocal(pTable, &oper); + } else if (action == SDB_ACTION_UPDATE) { + SRowMeta *rowMeta = sdbGetRowMeta(pTable, pHead->cont); + assert(rowMeta != NULL && rowMeta->row != NULL); + + SSdbOperDesc oper1 = { + .table = pTable, + .pObj = rowMeta->row, + }; + sdbDeleteLocal(pTable, &oper1); + + SSdbOperDesc oper2 = { + .rowSize = pHead->len, + .rowData = pHead->cont, + .table = pTable, + }; + code = (*pTable->decodeFp)(&oper2); + if (code < 0) { + sdbTrace("table:%s, failed to decode %s record:%s from file, version:%" PRId64, pTable->tableName, + sdbGetActionStr(action), sdbGetkeyStr(pTable, pHead->cont), pHead->version); + pthread_mutex_unlock(&tsSdbSync->mutex); + return code; + } + code = sdbInsertLocal(pTable, &oper2); + } + + pthread_mutex_unlock(&tsSdbSync->mutex); + return code; +} + +static int sdbProcessWrite(void *param, void *data, int type) { + SWalHead *pHead = data; + int32_t tableId = pHead->msgType / 10; + int32_t action = pHead->msgType % 10; + + SSdbTable *pTable = sdbGetTableFromId(tableId); + assert(pTable != NULL); + + if (pHead->version == 0) { + return sdbProcessWriteFromApp(pTable, pHead, action); + } else { + return sdbProcessWriteFromWal(pTable, pHead, action); + } +} + +int32_t sdbInsertRow(SSdbOperDesc *pOper) { + SSdbTable *pTable = (SSdbTable *)pOper->table; + if (pTable == NULL) return -1; + if (sdbGetRow(pTable, pOper->pObj)) { sdbError("table:%s, failed to insert record:%s, already exist", pTable->tableName, sdbGetkeyStr(pTable, pOper->pObj)); sdbDecRef(pTable, pOper->pObj); return TSDB_CODE_ALREADY_THERE; } - pOper->maxRowSize = pTable->maxRowSize; - pthread_mutex_lock(&pTable->mutex); - - if (pOper->type == SDB_OPER_TYPE_GLOBAL) { - SForwardMsg forward = { - .type = SDB_FORWARD_TYPE_INSERT, - .tableId = pTable->tableId, - .version = pTable->version + 1, - .rowSize = pOper->rowSize, - .rowData = pOper->rowData, - }; - - if (sdbForwardDbReqToPeer(&forward) != 0) { - sdbError("table:%s, failed to forward record:%s version:%" PRId64 " sdbversion:%" PRId64, - pTable->tableName, sdbGetkeyStr(pTable, pOper->pObj), pOper->version, sdbVersion); - pthread_mutex_unlock(&pTable->mutex); - return TSDB_CODE_OTHERS; - } - } - - int32_t total_size = sizeof(SRowHead) + pTable->maxRowSize + sizeof(TSCKSUM); - SRowHead *rowHead = (SRowHead *)calloc(1, total_size); - if (rowHead == NULL) { - pthread_mutex_unlock(&pTable->mutex); - sdbError("table:%s, failed to allocate row head memory for record:%s version:%" PRId64 " sdbversion:%" PRId64, - pTable->tableName, sdbGetkeyStr(pTable, pOper->pObj), pOper->version, sdbVersion); - return -1; - } - - if (pTable->keyType == SDB_KEY_TYPE_AUTO) { + if (pTable->keyType == SDB_KEY_AUTO) { + pthread_mutex_lock(&pTable->mutex); *((uint32_t *)pOper->pObj) = ++pTable->autoIndex; // let vgId increase from 2 if (pTable->autoIndex == 1 && strcmp(pTable->tableName, "vgroups") == 0) { *((uint32_t *)pOper->pObj) = ++pTable->autoIndex; } - } - pTable->version++; - sdbVersion++; - - pOper->rowData = rowHead->data; - (*pTable->encodeFp)(pOper); - rowHead->rowSize = pOper->rowSize; - rowHead->delimiter = SDB_DELIMITER; - rowHead->version = pTable->version; - assert(rowHead->rowSize > 0 && rowHead->rowSize <= pTable->maxRowSize); - - int32_t real_size = sizeof(SRowHead) + rowHead->rowSize + sizeof(TSCKSUM); - if (taosCalcChecksumAppend(0, (uint8_t *)rowHead, real_size) < 0) { - sdbError("table:%s, failed to get checksum while inserting", pTable->tableName); - pTable->version--; - sdbVersion--; pthread_mutex_unlock(&pTable->mutex); - tfree(rowHead); - return -1; } - twrite(pTable->fd, rowHead, real_size); - pTable->fileSize += real_size; - sdbFinishCommit(pTable); - tfree(rowHead); - - // update in SDB layer - SRowMeta rowMeta; - rowMeta.version = pTable->version; - rowMeta.offset = pTable->fileSize; - rowMeta.rowSize = pOper->rowSize; - rowMeta.row = pOper->pObj; - (*sdbAddIndexFp[pTable->keyType])(pTable->iHandle, pOper->pObj, &rowMeta); - sdbIncRef(pTable, pOper->pObj); + if (pOper->type == SDB_OPER_GLOBAL) { + int32_t size = sizeof(SWalHead) + pTable->maxRowSize; + SWalHead *pHead = calloc(1, size); + pHead->version = 0; + pHead->len = pOper->rowSize; + pHead->msgType = pTable->tableId * 10 + SDB_ACTION_INSERT; - pTable->numOfRows++; + pOper->rowData = pHead->cont; + (*pTable->encodeFp)(pOper); + pHead->len = pOper->rowSize; + + int32_t code = sdbProcessWrite(tsSdbSync, pHead, pHead->msgType); + if (code < 0) return code; + } - pthread_mutex_unlock(&pTable->mutex); - - sdbTrace("table:%s, sdbversion:%" PRId64 " version:%" PRId64 " numOfRows:%d, insert record:%s, rowSize:%d fileSize:%" PRId64, - pTable->tableName, sdbVersion, pTable->version, pTable->numOfRows, sdbGetkeyStr(pTable, pOper->pObj), pOper->rowSize, pTable->fileSize); - - (*pTable->insertFp)(pOper); - - return 0; + return sdbInsertLocal(pTable, pOper); } // row here can be object or null-terminated string @@ -586,204 +447,61 @@ int32_t sdbDeleteRow(SSdbOperDesc *pOper) { void * pMetaRow = pMeta->row; assert(pMetaRow != NULL); - pthread_mutex_lock(&pTable->mutex); + if (pOper->type == SDB_OPER_GLOBAL) { + int32_t rowSize = 0; + switch (pTable->keyType) { + case SDB_KEY_STRING: + rowSize = strlen((char *)pOper->pObj) + 1; + break; + case SDB_KEY_AUTO: + rowSize = sizeof(uint64_t); + break; + default: + return -1; + } - if (pOper->type == SDB_OPER_TYPE_GLOBAL) { - SForwardMsg forward = { - .type = SDB_FORWARD_TYPE_DELETE, - .tableId = pTable->tableId, - .version = pTable->version + 1, - .rowSize = pMeta->rowSize, - .rowData = pMeta->row, - }; + int32_t size = sizeof(SWalHead) + rowSize; + SWalHead *pHead = calloc(1, size); + pHead->version = 0; + pHead->len = rowSize; + pHead->msgType = pTable->tableId * 10 + SDB_ACTION_DELETE; + memcpy(pHead->cont, pOper->pObj, rowSize); - if (sdbForwardDbReqToPeer(&forward) != 0) { - sdbError("table:%s, failed to delete record", pTable->tableName); - pthread_mutex_unlock(&pTable->mutex); - return -1; - } - } - - int32_t total_size = sizeof(SRowHead) + pMeta->rowSize + sizeof(TSCKSUM); - SRowHead *rowHead = (SRowHead *)calloc(1, total_size); - if (rowHead == NULL) { - sdbError("failed to allocate row head memory, sdb:%s", pTable->tableName); - pthread_mutex_unlock(&pTable->mutex); - return -1; - } - - pTable->version++; - sdbVersion++; - - int32_t rowSize = 0; - switch (pTable->keyType) { - case SDB_KEY_TYPE_STRING: - rowSize = strlen((char *)pOper->pObj) + 1; - break; - case SDB_KEY_TYPE_AUTO: - rowSize = sizeof(uint64_t); - break; - default: - return -1; - } - - rowHead->delimiter = SDB_DELIMITER; - rowHead->rowSize = rowSize; - rowHead->version = -(pTable->version); - memcpy(rowHead->data, pOper->pObj, rowSize); - int32_t real_size = sizeof(SRowHead) + rowHead->rowSize + sizeof(TSCKSUM); - if (taosCalcChecksumAppend(0, (uint8_t *)rowHead, real_size) < 0) { - sdbError("failed to get checksum while inserting, sdb:%s", pTable->tableName); - pTable->version--; - sdbVersion--; - pthread_mutex_unlock(&pTable->mutex); - tfree(rowHead); - return -1; - } - - twrite(pTable->fd, rowHead, real_size); - pTable->fileSize += real_size; - sdbFinishCommit(pTable); - - tfree(rowHead); - - - sdbTrace("table:%s, sdbversion:%" PRId64 " version:%" PRId64 " numOfRows:%d, delete record:%s, rowSize:%d fileSize:%" PRId64, - pTable->tableName, sdbVersion, pTable->version, pTable->numOfRows, sdbGetkeyStr(pTable, pOper->pObj), pOper->rowSize, pTable->fileSize); - - // Delete from current layer - (*sdbDeleteIndexFp[pTable->keyType])(pTable->iHandle, pOper->pObj); - - pTable->numOfRows--; - - pthread_mutex_unlock(&pTable->mutex); - - (*pTable->deleteFp)(pOper); - int8_t* updateEnd = pOper->pObj + pTable->refCountPos - 1; - *updateEnd = 1; - sdbDecRef(pTable, pOper->pObj); - return 0; + int32_t code = sdbProcessWrite(tsSdbSync, pHead, pHead->msgType); + if (code < 0) return code; + } + + return sdbDeleteLocal(pTable, pOper); } -// row here can be the object or the string info (encoded string) int32_t sdbUpdateRow(SSdbOperDesc *pOper) { SSdbTable *pTable = (SSdbTable *)pOper->table; if (pTable == NULL) return -1; SRowMeta *pMeta = sdbGetRowMeta(pTable, pOper->pObj); if (pMeta == NULL) { - sdbError("table:%s, failed to update record:%s, record is not there, sdbversion:%" PRId64 " version:%" PRId64, - pTable->tableName, sdbGetkeyStr(pTable, pOper->pObj), sdbVersion, pTable->version); + sdbTrace("table:%s, record is not there, delete failed", pTable->tableName); return -1; } - void *pMetaRow = pMeta->row; + void * pMetaRow = pMeta->row; assert(pMetaRow != NULL); - pthread_mutex_lock(&pTable->mutex); + if (pOper->type == SDB_OPER_GLOBAL) { + int32_t size = sizeof(SWalHead) + pTable->maxRowSize; + SWalHead *pHead = calloc(1, size); + pHead->version = 0; + pHead->msgType = pTable->tableId * 10 + SDB_ACTION_UPDATE; - if (pOper->type == SDB_OPER_TYPE_GLOBAL) { - SForwardMsg forward = { - .type = SDB_FORWARD_TYPE_UPDATE, - .tableId = pTable->tableId, - .version = pTable->version + 1, - .rowSize = pOper->rowSize, - .rowData = pOper->rowData, - }; - if (sdbForwardDbReqToPeer(&forward) != 0) { - sdbError("table:%s, failed to update record", pTable->tableName); - pthread_mutex_unlock(&pTable->mutex); - return -1; - } - } + pOper->rowData = pHead->cont; + (*pTable->encodeFp)(pOper); + pHead->len = pOper->rowSize; - int32_t total_size = sizeof(SRowHead) + pTable->maxRowSize + sizeof(TSCKSUM); - SRowHead *rowHead = (SRowHead *)calloc(1, total_size); - if (rowHead == NULL) { - pthread_mutex_unlock(&pTable->mutex); - sdbError("table:%s, failed to allocate row head memory", pTable->tableName); - return -1; + int32_t code = sdbProcessWrite(tsSdbSync, pHead, pHead->msgType); + if (code < 0) return code; } - if (pMetaRow != pOper->pObj) { - memcpy(rowHead->data, pOper->rowData, pOper->rowSize); - rowHead->rowSize = pOper->rowSize; - } else { - SSdbOperDesc oper = { - .table = pTable, - .rowData = rowHead->data, - .maxRowSize = pTable->maxRowSize, - .pObj = pOper->pObj - }; - (*pTable->encodeFp)(&oper); - rowHead->rowSize = oper.rowSize; - } - - pTable->version++; - sdbVersion++; - - int32_t real_size = sizeof(SRowHead) + rowHead->rowSize + sizeof(TSCKSUM); - rowHead->delimiter = SDB_DELIMITER; - rowHead->version = pTable->version; - if (taosCalcChecksumAppend(0, (uint8_t *)rowHead, real_size) < 0) { - sdbError("table:%s, failed to get checksum, version:%d", pTable->tableName, rowHead->version); - pTable->version--; - sdbVersion--; - pthread_mutex_unlock(&pTable->mutex); - tfree(rowHead); - return -1; - } - - twrite(pTable->fd, rowHead, real_size); - pTable->fileSize += real_size; - sdbFinishCommit(pTable); - - sdbTrace("table:%s, sdbversion:%" PRId64 " version:%" PRId64 " numOfRows:%d, update record:%s, rowSize:%d fileSize:%" PRId64, - pTable->tableName, sdbVersion, pTable->version, pTable->numOfRows, sdbGetkeyStr(pTable, pOper->pObj), pOper->rowSize, pTable->fileSize); - - pMeta->version = pTable->version; - pMeta->offset = pTable->fileSize; - pMeta->rowSize = rowHead->rowSize; - - pthread_mutex_unlock(&pTable->mutex); - - (*pTable->updateFp)(pOper); // update in upper layer - - tfree(rowHead); - - return 0; -} - -void sdbCloseTable(void *handle) { - SSdbTable *pTable = (SSdbTable *)handle; - void * pNode = NULL; - - if (pTable == NULL) return; - - while (1) { - SRowMeta * pMeta; - pNode = (*sdbFetchRowFp[pTable->keyType])(pTable->iHandle, pNode, (void **)&pMeta); - if (pMeta == NULL) break; - - SSdbOperDesc oper = { - .pObj = pMeta->row, - .table = pTable, - .version = pMeta->version, - }; - - (*pTable->destroyFp)(&oper); - } - - if (sdbCleanUpIndexFp[pTable->keyType]) (*sdbCleanUpIndexFp[pTable->keyType])(pTable->iHandle); - - if (pTable->fd) tclose(pTable->fd); - - pthread_mutex_destroy(&pTable->mutex); - - sdbNumOfTables--; - sdbTrace("table:%s, is closed, version:%" PRId64 " numOfTables:%d", pTable->tableName, pTable->version, sdbNumOfTables); - - tfree(pTable); + return sdbUpdateLocal(pTable, pOper); } void *sdbFetchRow(void *handle, void *pNode, void **ppRow) { @@ -801,3 +519,63 @@ void *sdbFetchRow(void *handle, void *pNode, void **ppRow) { return pNode; } + +void *sdbOpenTable(SSdbTableDesc *pDesc) { + SSdbTable *pTable = (SSdbTable *)calloc(1, sizeof(SSdbTable)); + if (pTable == NULL) return NULL; + + strcpy(pTable->tableName, pDesc->tableName); + pTable->keyType = pDesc->keyType; + pTable->tableId = pDesc->tableId; + pTable->hashSessions = pDesc->hashSessions; + pTable->maxRowSize = pDesc->maxRowSize; + pTable->refCountPos = pDesc->refCountPos; + pTable->insertFp = pDesc->insertFp; + pTable->deleteFp = pDesc->deleteFp; + pTable->updateFp = pDesc->updateFp; + pTable->encodeFp = pDesc->encodeFp; + pTable->decodeFp = pDesc->decodeFp; + pTable->destroyFp = pDesc->destroyFp; + pTable->updateAllFp = pDesc->updateAllFp; + + if (sdbInitIndexFp[pTable->keyType] != NULL) { + pTable->iHandle = (*sdbInitIndexFp[pTable->keyType])(pTable->maxRowSize, sizeof(SRowMeta)); + } + + pthread_mutex_init(&pTable->mutex, NULL); + + tsSdbNumOfTables++; + tsSdbTableList[pTable->tableId] = pTable; + return pTable; +} + +void sdbCloseTable(void *handle) { + SSdbTable *pTable = (SSdbTable *)handle; + if (pTable == NULL) return; + + tsSdbNumOfTables--; + tsSdbTableList[pTable->tableId] = NULL; + + void *pNode = NULL; + while (1) { + SRowMeta *pMeta; + pNode = (*sdbFetchRowFp[pTable->keyType])(pTable->iHandle, pNode, (void **)&pMeta); + if (pMeta == NULL) break; + + SSdbOperDesc oper = { + .pObj = pMeta->row, + .table = pTable, + }; + + (*pTable->destroyFp)(&oper); + } + + if (sdbCleanUpIndexFp[pTable->keyType]) { + (*sdbCleanUpIndexFp[pTable->keyType])(pTable->iHandle); + } + + pthread_mutex_destroy(&pTable->mutex); + + sdbTrace("table:%s, is closed, numOfTables:%d", pTable->tableName, tsSdbNumOfTables); + free(pTable); +} diff --git a/src/mnode/src/mgmtShell.c b/src/mnode/src/mgmtShell.c index 880c6d0c10..dbd7627d3f 100644 --- a/src/mnode/src/mgmtShell.c +++ b/src/mnode/src/mgmtShell.c @@ -27,7 +27,7 @@ #include "mgmtDb.h" #include "tcluster.h" #include "tgrant.h" -#include "mgmtMnode.h" +#include "mpeer.h" #include "mgmtProfile.h" #include "mgmtSdb.h" #include "mgmtShell.h" @@ -142,14 +142,14 @@ static void mgmtProcessMsgFromShell(SRpcMsg *rpcMsg) { return; } - if (mgmtCheckRedirect(rpcMsg->handle)) { + if (mpeerCheckRedirect()) { // rpcSendRedirectRsp(rpcMsg->handle, mgmtGetMnodeIpListForRedirect()); mgmtSendSimpleResp(rpcMsg->handle, TSDB_CODE_NO_MASTER); rpcFreeCont(rpcMsg->pCont); return; } - if (!mgmtInServerStatus()) { + if (!mpeerInServerStatus()) { mgmtProcessMsgWhileNotReady(rpcMsg); rpcFreeCont(rpcMsg->pCont); return; @@ -337,9 +337,9 @@ static void mgmtProcessHeartBeatMsg(SQueuedMsg *pMsg) { } if (pMsg->usePublicIp) { - mgmtGetMnodePublicIpList(&pHBRsp->ipList); + mpeerGetPublicIpList(&pHBRsp->ipList); } else { - mgmtGetMnodePrivateIpList(&pHBRsp->ipList); + mpeerGetPrivateIpList(&pHBRsp->ipList); } /* @@ -423,9 +423,9 @@ static void mgmtProcessConnectMsg(SQueuedMsg *pMsg) { pConnectRsp->superAuth = pUser->superAuth; if (pMsg->usePublicIp) { - mgmtGetMnodePublicIpList(&pConnectRsp->ipList); + mpeerGetPublicIpList(&pConnectRsp->ipList); } else { - mgmtGetMnodePrivateIpList(&pConnectRsp->ipList); + mpeerGetPrivateIpList(&pConnectRsp->ipList); } connect_over: diff --git a/src/mnode/src/mgmtTable.c b/src/mnode/src/mgmtTable.c index b536bb5ac9..ef38702a96 100644 --- a/src/mnode/src/mgmtTable.c +++ b/src/mnode/src/mgmtTable.c @@ -35,7 +35,7 @@ #include "tcluster.h" #include "mgmtDServer.h" #include "tgrant.h" -#include "mgmtMnode.h" +#include "mpeer.h" #include "mgmtProfile.h" #include "mgmtSdb.h" #include "mgmtShell.h" @@ -174,6 +174,7 @@ static int32_t mgmtChildTableActionUpdate(SSdbOperDesc *pOper) { } static int32_t mgmtChildTableActionEncode(SSdbOperDesc *pOper) { + const int32_t maxRowSize = sizeof(SChildTableObj) + sizeof(SSchema) * TSDB_MAX_COLUMNS; SChildTableObj *pTable = pOper->pObj; assert(pTable != NULL && pOper->rowData != NULL); @@ -182,7 +183,7 @@ static int32_t mgmtChildTableActionEncode(SSdbOperDesc *pOper) { pOper->rowSize = tsChildTableUpdateSize; } else { int32_t schemaSize = pTable->numOfColumns * sizeof(SSchema); - if (pOper->maxRowSize < tsChildTableUpdateSize + schemaSize) { + if (maxRowSize < tsChildTableUpdateSize + schemaSize) { return TSDB_CODE_INVALID_MSG_LEN; } memcpy(pOper->rowData, pTable, tsChildTableUpdateSize); @@ -224,35 +225,11 @@ static int32_t mgmtChildTableActionDecode(SSdbOperDesc *pOper) { return TSDB_CODE_SUCCESS; } -static int32_t mgmtInitChildTables() { +static int32_t mgmtChildTableActionUpdateAll() { void *pNode = NULL; void *pLastNode = NULL; SChildTableObj *pTable = NULL; - SChildTableObj tObj; - tsChildTableUpdateSize = (int8_t *)tObj.updateEnd - (int8_t *)&tObj; - - SSdbTableDesc tableDesc = { - .tableName = "ctables", - .hashSessions = tsMaxTables, - .maxRowSize = sizeof(SChildTableObj) + sizeof(SSchema) * TSDB_MAX_COLUMNS, - .refCountPos = (int8_t *)(&tObj.refCount) - (int8_t *)&tObj, - .keyType = SDB_KEY_TYPE_STRING, - .insertFp = mgmtChildTableActionInsert, - .deleteFp = mgmtChildTableActionDelete, - .updateFp = mgmtChildTableActionUpdate, - .encodeFp = mgmtChildTableActionEncode, - .decodeFp = mgmtChildTableActionDecode, - .destroyFp = mgmtChildTableActionDestroy, - }; - - tsChildTableSdb = sdbOpenTable(&tableDesc); - if (tsChildTableSdb == NULL) { - mError("failed to init child table data"); - return -1; - } - - pNode = NULL; while (1) { pLastNode = pNode; mgmtDecTableRef(pTable); @@ -263,7 +240,7 @@ static int32_t mgmtInitChildTables() { if (pDb == NULL) { mError("ctable:%s, failed to get db, discard it", pTable->info.tableId); SSdbOperDesc desc = {0}; - desc.type = SDB_OPER_TYPE_LOCAL; + desc.type = SDB_OPER_LOCAL; desc.pObj = pTable; desc.table = tsChildTableSdb; sdbDeleteRow(&desc); @@ -277,7 +254,7 @@ static int32_t mgmtInitChildTables() { mError("ctable:%s, failed to get vgroup:%d sid:%d, discard it", pTable->info.tableId, pTable->vgId, pTable->sid); pTable->vgId = 0; SSdbOperDesc desc = {0}; - desc.type = SDB_OPER_TYPE_LOCAL; + desc.type = SDB_OPER_LOCAL; desc.pObj = pTable; desc.table = tsChildTableSdb; sdbDeleteRow(&desc); @@ -291,7 +268,7 @@ static int32_t mgmtInitChildTables() { pTable->info.tableId, pDb->name, pTable->vgId, pVgroup->dbName, pTable->sid); pTable->vgId = 0; SSdbOperDesc desc = {0}; - desc.type = SDB_OPER_TYPE_LOCAL; + desc.type = SDB_OPER_LOCAL; desc.pObj = pTable; desc.table = tsChildTableSdb; sdbDeleteRow(&desc); @@ -303,7 +280,7 @@ static int32_t mgmtInitChildTables() { mError("ctable:%s, vgroup:%d tableList is null", pTable->info.tableId, pTable->vgId); pTable->vgId = 0; SSdbOperDesc desc = {0}; - desc.type = SDB_OPER_TYPE_LOCAL; + desc.type = SDB_OPER_LOCAL; desc.pObj = pTable; desc.table = tsChildTableSdb; sdbDeleteRow(&desc); @@ -317,7 +294,7 @@ static int32_t mgmtInitChildTables() { mError("ctable:%s, stable:%s not exist", pTable->info.tableId, pTable->superTableId); pTable->vgId = 0; SSdbOperDesc desc = {0}; - desc.type = SDB_OPER_TYPE_LOCAL; + desc.type = SDB_OPER_LOCAL; desc.pObj = pTable; desc.table = tsChildTableSdb; sdbDeleteRow(&desc); @@ -328,6 +305,35 @@ static int32_t mgmtInitChildTables() { } } + return 0; +} + +static int32_t mgmtInitChildTables() { + SChildTableObj tObj; + tsChildTableUpdateSize = (int8_t *)tObj.updateEnd - (int8_t *)&tObj; + + SSdbTableDesc tableDesc = { + .tableId = SDB_TABLE_CTABLE, + .tableName = "ctables", + .hashSessions = tsMaxTables, + .maxRowSize = sizeof(SChildTableObj) + sizeof(SSchema) * TSDB_MAX_COLUMNS, + .refCountPos = (int8_t *)(&tObj.refCount) - (int8_t *)&tObj, + .keyType = SDB_KEY_STRING, + .insertFp = mgmtChildTableActionInsert, + .deleteFp = mgmtChildTableActionDelete, + .updateFp = mgmtChildTableActionUpdate, + .encodeFp = mgmtChildTableActionEncode, + .decodeFp = mgmtChildTableActionDecode, + .destroyFp = mgmtChildTableActionDestroy, + .updateAllFp = mgmtChildTableActionUpdateAll + }; + + tsChildTableSdb = sdbOpenTable(&tableDesc); + if (tsChildTableSdb == NULL) { + mError("failed to init child table data"); + return -1; + } + mTrace("child table is initialized"); return 0; } @@ -374,12 +380,14 @@ static int32_t mgmtSuperTableActionUpdate(SSdbOperDesc *pOper) { } static int32_t mgmtSuperTableActionEncode(SSdbOperDesc *pOper) { + const int32_t maxRowSize = sizeof(SChildTableObj) + sizeof(SSchema) * TSDB_MAX_COLUMNS; + SSuperTableObj *pStable = pOper->pObj; assert(pOper->pObj != NULL && pOper->rowData != NULL); int32_t schemaSize = sizeof(SSchema) * (pStable->numOfColumns + pStable->numOfTags); - if (pOper->maxRowSize < tsSuperTableUpdateSize + schemaSize) { + if (maxRowSize < tsSuperTableUpdateSize + schemaSize) { return TSDB_CODE_INVALID_MSG_LEN; } @@ -411,22 +419,28 @@ static int32_t mgmtSuperTableActionDecode(SSdbOperDesc *pOper) { return TSDB_CODE_SUCCESS; } +static int32_t mgmtSuperTableActionUpdateAll() { + return 0; +} + static int32_t mgmtInitSuperTables() { SSuperTableObj tObj; tsSuperTableUpdateSize = (int8_t *)tObj.updateEnd - (int8_t *)&tObj; SSdbTableDesc tableDesc = { + .tableId = SDB_TABLE_STABLE, .tableName = "stables", .hashSessions = TSDB_MAX_SUPER_TABLES, .maxRowSize = tsSuperTableUpdateSize + sizeof(SSchema) * TSDB_MAX_COLUMNS, .refCountPos = (int8_t *)(&tObj.refCount) - (int8_t *)&tObj, - .keyType = SDB_KEY_TYPE_STRING, + .keyType = SDB_KEY_STRING, .insertFp = mgmtSuperTableActionInsert, .deleteFp = mgmtSuperTableActionDelete, .updateFp = mgmtSuperTableActionUpdate, .encodeFp = mgmtSuperTableActionEncode, .decodeFp = mgmtSuperTableActionDecode, .destroyFp = mgmtSuperTableActionDestroy, + .updateAllFp = mgmtSuperTableActionUpdateAll }; tsSuperTableSdb = sdbOpenTable(&tableDesc); @@ -662,7 +676,7 @@ static void mgmtProcessCreateSuperTableMsg(SQueuedMsg *pMsg) { } SSdbOperDesc oper = { - .type = SDB_OPER_TYPE_GLOBAL, + .type = SDB_OPER_GLOBAL, .table = tsSuperTableSdb, .pObj = pStable, .rowSize = sizeof(SSuperTableObj) + schemaSize @@ -686,7 +700,7 @@ static void mgmtProcessDropSuperTableMsg(SQueuedMsg *pMsg) { mgmtSendSimpleResp(pMsg->thandle, TSDB_CODE_OTHERS); } else { SSdbOperDesc oper = { - .type = SDB_OPER_TYPE_GLOBAL, + .type = SDB_OPER_GLOBAL, .table = tsSuperTableSdb, .pObj = pStable }; @@ -737,7 +751,7 @@ static int32_t mgmtAddSuperTableTag(SSuperTableObj *pStable, SSchema schema[], i pStable->sversion++; SSdbOperDesc oper = { - .type = SDB_OPER_TYPE_GLOBAL, + .type = SDB_OPER_GLOBAL, .table = tsSuperTableSdb, .pObj = pStable, .rowSize = tsSuperTableUpdateSize @@ -768,7 +782,7 @@ static int32_t mgmtDropSuperTableTag(SSuperTableObj *pStable, char *tagName) { pStable->schema = realloc(pStable->schema, schemaSize); SSdbOperDesc oper = { - .type = SDB_OPER_TYPE_GLOBAL, + .type = SDB_OPER_GLOBAL, .table = tsSuperTableSdb, .pObj = pStable, .rowSize = tsSuperTableUpdateSize @@ -803,7 +817,7 @@ static int32_t mgmtModifySuperTableTagName(SSuperTableObj *pStable, char *oldTag strncpy(schema->name, newTagName, TSDB_COL_NAME_LEN); SSdbOperDesc oper = { - .type = SDB_OPER_TYPE_GLOBAL, + .type = SDB_OPER_GLOBAL, .table = tsSuperTableSdb, .pObj = pStable, .rowSize = tsSuperTableUpdateSize @@ -862,7 +876,7 @@ static int32_t mgmtAddSuperTableColumn(SDbObj *pDb, SSuperTableObj *pStable, SSc } SSdbOperDesc oper = { - .type = SDB_OPER_TYPE_GLOBAL, + .type = SDB_OPER_GLOBAL, .table = tsSuperTableSdb, .pObj = pStable, .rowSize = tsSuperTableUpdateSize @@ -899,7 +913,7 @@ static int32_t mgmtDropSuperTableColumn(SDbObj *pDb, SSuperTableObj *pStable, ch } SSdbOperDesc oper = { - .type = SDB_OPER_TYPE_GLOBAL, + .type = SDB_OPER_GLOBAL, .table = tsSuperTableSdb, .pObj = pStable, .rowSize = tsSuperTableUpdateSize @@ -1047,7 +1061,7 @@ void mgmtDropAllSuperTables(SDbObj *pDropDb) { if (strncmp(pDropDb->name, pTable->info.tableId, dbNameLen) == 0) { SSdbOperDesc oper = { - .type = SDB_OPER_TYPE_LOCAL, + .type = SDB_OPER_LOCAL, .table = tsSuperTableSdb, .pObj = pTable, }; @@ -1262,7 +1276,7 @@ static SChildTableObj* mgmtDoCreateChildTable(SCMCreateTableMsg *pCreate, SVgObj } SSdbOperDesc desc = {0}; - desc.type = SDB_OPER_TYPE_GLOBAL; + desc.type = SDB_OPER_GLOBAL; desc.pObj = pTable; desc.table = tsChildTableSdb; @@ -1416,7 +1430,7 @@ static int32_t mgmtAddNormalTableColumn(SDbObj *pDb, SChildTableObj *pTable, SSc } SSdbOperDesc oper = { - .type = SDB_OPER_TYPE_GLOBAL, + .type = SDB_OPER_GLOBAL, .table = tsChildTableSdb, .pObj = pTable, .rowSize = tsChildTableUpdateSize @@ -1450,7 +1464,7 @@ static int32_t mgmtDropNormalTableColumn(SDbObj *pDb, SChildTableObj *pTable, ch } SSdbOperDesc oper = { - .type = SDB_OPER_TYPE_GLOBAL, + .type = SDB_OPER_GLOBAL, .table = tsChildTableSdb, .pObj = pTable, .rowSize = tsChildTableUpdateSize @@ -1592,7 +1606,7 @@ void mgmtDropAllChildTables(SDbObj *pDropDb) { if (strncmp(pDropDb->name, pTable->info.tableId, dbNameLen) == 0) { SSdbOperDesc oper = { - .type = SDB_OPER_TYPE_LOCAL, + .type = SDB_OPER_LOCAL, .table = tsChildTableSdb, .pObj = pTable, }; @@ -1621,7 +1635,7 @@ static void mgmtDropAllChildTablesInStable(SSuperTableObj *pStable) { if (pTable->superTable == pStable) { SSdbOperDesc oper = { - .type = SDB_OPER_TYPE_LOCAL, + .type = SDB_OPER_LOCAL, .table = tsChildTableSdb, .pObj = pTable, }; @@ -1650,8 +1664,6 @@ static SChildTableObj* mgmtGetTableByPos(uint32_t dnodeId, int32_t vnode, int32_ } static void mgmtProcessTableCfgMsg(SRpcMsg *rpcMsg) { - if (mgmtCheckRedirect(rpcMsg->handle)) return; - SDMConfigTableMsg *pCfg = (SDMConfigTableMsg *) rpcMsg->pCont; pCfg->dnode = htonl(pCfg->dnode); pCfg->vnode = htonl(pCfg->vnode); @@ -1712,7 +1724,7 @@ static void mgmtProcessDropChildTableRsp(SRpcMsg *rpcMsg) { } SSdbOperDesc oper = { - .type = SDB_OPER_TYPE_GLOBAL, + .type = SDB_OPER_GLOBAL, .table = tsChildTableSdb, .pObj = pTable }; @@ -1755,7 +1767,7 @@ static void mgmtProcessCreateChildTableRsp(SRpcMsg *rpcMsg) { queueMsg->thandle, tstrerror(rpcMsg->code)); SSdbOperDesc oper = { - .type = SDB_OPER_TYPE_GLOBAL, + .type = SDB_OPER_GLOBAL, .table = tsChildTableSdb, .pObj = pTable }; diff --git a/src/mnode/src/mgmtUser.c b/src/mnode/src/mgmtUser.c index fe7d40e120..3a49e56331 100644 --- a/src/mnode/src/mgmtUser.c +++ b/src/mnode/src/mgmtUser.c @@ -20,7 +20,7 @@ #include "tutil.h" #include "taccount.h" #include "tgrant.h" -#include "mgmtMnode.h" +#include "mpeer.h" #include "mgmtSdb.h" #include "mgmtShell.h" #include "mgmtUser.h" @@ -70,14 +70,9 @@ static int32_t mgmtUserActionUpdate(SSdbOperDesc *pOper) { static int32_t mgmtUserActionEncode(SSdbOperDesc *pOper) { SUserObj *pUser = pOper->pObj; - - if (pOper->maxRowSize < tsUserUpdateSize) { - return -1; - } else { - memcpy(pOper->rowData, pUser, tsUserUpdateSize); - pOper->rowSize = tsUserUpdateSize; - return TSDB_CODE_SUCCESS; - } + memcpy(pOper->rowData, pUser, tsUserUpdateSize); + pOper->rowSize = tsUserUpdateSize; + return TSDB_CODE_SUCCESS; } static int32_t mgmtUserActionDecode(SSdbOperDesc *pOper) { @@ -89,22 +84,34 @@ static int32_t mgmtUserActionDecode(SSdbOperDesc *pOper) { return TSDB_CODE_SUCCESS; } +static int32_t mgmtUserActionUpdateAll() { + SAcctObj *pAcct = acctGetAcct("root"); + mgmtCreateUser(pAcct, "root", "taosdata"); + mgmtCreateUser(pAcct, "monitor", tsInternalPass); + mgmtCreateUser(pAcct, "_root", tsInternalPass); + acctReleaseAcct(pAcct); + + return 0; +} + int32_t mgmtInitUsers() { SUserObj tObj; tsUserUpdateSize = (int8_t *)tObj.updateEnd - (int8_t *)&tObj; SSdbTableDesc tableDesc = { + .tableId = SDB_TABLE_USER, .tableName = "users", .hashSessions = TSDB_MAX_USERS, .maxRowSize = tsUserUpdateSize, .refCountPos = (int8_t *)(&tObj.refCount) - (int8_t *)&tObj, - .keyType = SDB_KEY_TYPE_STRING, + .keyType = SDB_KEY_STRING, .insertFp = mgmtUserActionInsert, .deleteFp = mgmtUserActionDelete, .updateFp = mgmtUserActionUpdate, .encodeFp = mgmtUserActionEncode, .decodeFp = mgmtUserActionDecode, .destroyFp = mgmtUserActionDestroy, + .updateAllFp = mgmtUserActionUpdateAll }; tsUserSdb = sdbOpenTable(&tableDesc); @@ -113,12 +120,6 @@ int32_t mgmtInitUsers() { return -1; } - SAcctObj *pAcct = acctGetAcct("root"); - mgmtCreateUser(pAcct, "root", "taosdata"); - mgmtCreateUser(pAcct, "monitor", tsInternalPass); - mgmtCreateUser(pAcct, "_root", tsInternalPass); - acctReleaseAcct(pAcct); - mgmtAddShellMsgHandle(TSDB_MSG_TYPE_CM_CREATE_USER, mgmtProcessCreateUserMsg); mgmtAddShellMsgHandle(TSDB_MSG_TYPE_CM_ALTER_USER, mgmtProcessAlterUserMsg); mgmtAddShellMsgHandle(TSDB_MSG_TYPE_CM_DROP_USER, mgmtProcessDropUserMsg); @@ -143,7 +144,7 @@ void mgmtReleaseUser(SUserObj *pUser) { static int32_t mgmtUpdateUser(SUserObj *pUser) { SSdbOperDesc oper = { - .type = SDB_OPER_TYPE_GLOBAL, + .type = SDB_OPER_GLOBAL, .table = tsUserSdb, .pObj = pUser, .rowSize = tsUserUpdateSize @@ -191,7 +192,7 @@ int32_t mgmtCreateUser(SAcctObj *pAcct, char *name, char *pass) { } SSdbOperDesc oper = { - .type = SDB_OPER_TYPE_GLOBAL, + .type = SDB_OPER_GLOBAL, .table = tsUserSdb, .pObj = pUser, .rowSize = sizeof(SUserObj) @@ -208,7 +209,7 @@ int32_t mgmtCreateUser(SAcctObj *pAcct, char *name, char *pass) { static int32_t mgmtDropUser(SUserObj *pUser) { SSdbOperDesc oper = { - .type = SDB_OPER_TYPE_GLOBAL, + .type = SDB_OPER_GLOBAL, .table = tsUserSdb, .pObj = pUser }; @@ -314,8 +315,6 @@ SUserObj *mgmtGetUserFromConn(void *pConn, bool *usePublicIp) { } static void mgmtProcessCreateUserMsg(SQueuedMsg *pMsg) { - if (mgmtCheckRedirect(pMsg->thandle)) return; - int32_t code; SUserObj *pUser = pMsg->pUser; @@ -333,8 +332,6 @@ static void mgmtProcessCreateUserMsg(SQueuedMsg *pMsg) { } static void mgmtProcessAlterUserMsg(SQueuedMsg *pMsg) { - if (mgmtCheckRedirect(pMsg->thandle)) return; - int32_t code; SUserObj *pOperUser = pMsg->pUser; @@ -427,8 +424,6 @@ static void mgmtProcessAlterUserMsg(SQueuedMsg *pMsg) { } static void mgmtProcessDropUserMsg(SQueuedMsg *pMsg) { - if (mgmtCheckRedirect(pMsg->thandle)) return; - int32_t code; SUserObj *pOperUser = pMsg->pUser; @@ -488,7 +483,7 @@ void mgmtDropAllUsers(SAcctObj *pAcct) { if (strncmp(pUser->acct, pAcct->user, acctNameLen) == 0) { SSdbOperDesc oper = { - .type = SDB_OPER_TYPE_LOCAL, + .type = SDB_OPER_LOCAL, .table = tsUserSdb, .pObj = pUser, }; diff --git a/src/mnode/src/mgmtVgroup.c b/src/mnode/src/mgmtVgroup.c index 6b27fbbc83..19468dc547 100644 --- a/src/mnode/src/mgmtVgroup.c +++ b/src/mnode/src/mgmtVgroup.c @@ -24,7 +24,7 @@ #include "mgmtDb.h" #include "mgmtDClient.h" #include "mgmtDServer.h" -#include "mgmtMnode.h" +#include "mpeer.h" #include "mgmtProfile.h" #include "mgmtSdb.h" #include "mgmtShell.h" @@ -138,13 +138,9 @@ static int32_t mgmtVgroupActionUpdate(SSdbOperDesc *pOper) { static int32_t mgmtVgroupActionEncode(SSdbOperDesc *pOper) { SVgObj *pVgroup = pOper->pObj; - if (pOper->maxRowSize < tsVgUpdateSize) { - return -1; - } else { - memcpy(pOper->rowData, pVgroup, tsVgUpdateSize); - pOper->rowSize = tsVgUpdateSize; - return TSDB_CODE_SUCCESS; - } + memcpy(pOper->rowData, pVgroup, tsVgUpdateSize); + pOper->rowSize = tsVgUpdateSize; + return TSDB_CODE_SUCCESS; } static int32_t mgmtVgroupActionDecode(SSdbOperDesc *pOper) { @@ -156,22 +152,28 @@ static int32_t mgmtVgroupActionDecode(SSdbOperDesc *pOper) { return TSDB_CODE_SUCCESS; } +static int32_t mgmtVgroupActionUpdateAll() { + return 0; +} + int32_t mgmtInitVgroups() { SVgObj tObj; tsVgUpdateSize = (int8_t *)tObj.updateEnd - (int8_t *)&tObj; SSdbTableDesc tableDesc = { + .tableId = SDB_TABLE_VGROUP, .tableName = "vgroups", .hashSessions = TSDB_MAX_VGROUPS, .maxRowSize = tsVgUpdateSize, .refCountPos = (int8_t *)(&tObj.refCount) - (int8_t *)&tObj, - .keyType = SDB_KEY_TYPE_AUTO, + .keyType = SDB_KEY_AUTO, .insertFp = mgmtVgroupActionInsert, .deleteFp = mgmtVgroupActionDelete, .updateFp = mgmtVgroupActionUpdate, .encodeFp = mgmtVgroupActionEncode, .decodeFp = mgmtVgroupActionDecode, .destroyFp = mgmtVgroupActionDestroy, + .updateAllFp = mgmtVgroupActionUpdateAll, }; tsVgroupSdb = sdbOpenTable(&tableDesc); @@ -187,6 +189,7 @@ int32_t mgmtInitVgroups() { mgmtAddDServerMsgHandle(TSDB_MSG_TYPE_DM_CONFIG_VNODE, mgmtProcessVnodeCfgMsg); mTrace("vgroup is initialized"); + return 0; } @@ -200,7 +203,7 @@ SVgObj *mgmtGetVgroup(int32_t vgId) { void mgmtUpdateVgroup(SVgObj *pVgroup) { SSdbOperDesc oper = { - .type = SDB_OPER_TYPE_GLOBAL, + .type = SDB_OPER_GLOBAL, .table = tsVgroupSdb, .pObj = pVgroup, .rowSize = tsVgUpdateSize @@ -244,7 +247,7 @@ void mgmtCreateVgroup(SQueuedMsg *pMsg, SDbObj *pDb) { } SSdbOperDesc oper = { - .type = SDB_OPER_TYPE_GLOBAL, + .type = SDB_OPER_GLOBAL, .table = tsVgroupSdb, .pObj = pVgroup, .rowSize = sizeof(SVgObj) @@ -276,7 +279,7 @@ void mgmtDropVgroup(SVgObj *pVgroup, void *ahandle) { mTrace("vgroup:%d, replica:%d is deleting from sdb", pVgroup->vgId, pVgroup->numOfVnodes); mgmtSendDropVgroupMsg(pVgroup, NULL); SSdbOperDesc oper = { - .type = SDB_OPER_TYPE_GLOBAL, + .type = SDB_OPER_GLOBAL, .table = tsVgroupSdb, .pObj = pVgroup }; @@ -583,7 +586,7 @@ static void mgmtProcessCreateVnodeRsp(SRpcMsg *rpcMsg) { mgmtAddToShellQueue(newMsg); } else { SSdbOperDesc oper = { - .type = SDB_OPER_TYPE_GLOBAL, + .type = SDB_OPER_GLOBAL, .table = tsVgroupSdb, .pObj = pVgroup }; @@ -646,7 +649,7 @@ static void mgmtProcessDropVnodeRsp(SRpcMsg *rpcMsg) { if (queueMsg->received != queueMsg->expected) return; SSdbOperDesc oper = { - .type = SDB_OPER_TYPE_GLOBAL, + .type = SDB_OPER_GLOBAL, .table = tsVgroupSdb, .pObj = pVgroup }; @@ -663,8 +666,6 @@ static void mgmtProcessDropVnodeRsp(SRpcMsg *rpcMsg) { } static void mgmtProcessVnodeCfgMsg(SRpcMsg *rpcMsg) { - if (mgmtCheckRedirect(rpcMsg->handle)) return; - SDMConfigVnodeMsg *pCfg = (SDMConfigVnodeMsg *) rpcMsg->pCont; pCfg->dnodeId = htonl(pCfg->dnodeId); pCfg->vgId = htonl(pCfg->vgId); @@ -705,7 +706,7 @@ void mgmtDropAllVgroups(SDbObj *pDropDb) { if (strncmp(pDropDb->name, pVgroup->dbName, dbNameLen) == 0) { SSdbOperDesc oper = { - .type = SDB_OPER_TYPE_LOCAL, + .type = SDB_OPER_LOCAL, .table = tsVgroupSdb, .pObj = pVgroup, }; diff --git a/src/plugins/http/inc/cJSON.h b/src/plugins/http/inc/cJSON.h deleted file mode 100644 index 31c6d19e78..0000000000 --- a/src/plugins/http/inc/cJSON.h +++ /dev/null @@ -1,264 +0,0 @@ -/* - Copyright (c) 2009-2017 Dave Gamble and cJSON contributors - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. -*/ - -#ifndef cJSON__h -#define cJSON__h - -#ifdef __cplusplus -extern "C" -{ -#endif - -/* project version */ -#define CJSON_VERSION_MAJOR 1 -#define CJSON_VERSION_MINOR 5 -#define CJSON_VERSION_PATCH 9 - -#include -#include - -/* cJSON Types: */ -#define cJSON_Invalid (0) -#define cJSON_False (1 << 0) -#define cJSON_True (1 << 1) -#define cJSON_NULL (1 << 2) -#define cJSON_Number (1 << 3) -#define cJSON_String (1 << 4) -#define cJSON_Array (1 << 5) -#define cJSON_Object (1 << 6) -#define cJSON_Raw (1 << 7) /* raw json */ - -#define cJSON_IsReference 256 -#define cJSON_StringIsConst 512 - -/* The cJSON structure: */ -typedef struct cJSON -{ - /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ - struct cJSON *next; - struct cJSON *prev; - /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ - struct cJSON *child; - - /* The type of the item, as above. */ - int type; - - /* The item's string, if type==cJSON_String and type == cJSON_Raw */ - char *valuestring; - /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */ - int64_t valueint; - /* The item's number, if type==cJSON_Number */ - double valuedouble; - - /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ - char *string; -} cJSON; - -typedef struct cJSON_Hooks -{ - void *(*malloc_fn)(size_t sz); - void (*free_fn)(void *ptr); -} cJSON_Hooks; - -typedef int cJSON_bool; - -#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32)) -#define __WINDOWS__ -#endif -#ifdef __WINDOWS__ - -/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 2 define options: - -CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols -CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols (default) -CJSON_IMPORT_SYMBOLS - Define this if you want to dllimport symbol - -For *nix builds that support visibility attribute, you can define similar behavior by - -setting default visibility to hidden by adding --fvisibility=hidden (for gcc) -or --xldscope=hidden (for sun cc) -to CFLAGS - -then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does - -*/ - -/* export symbols by default, this is necessary for copy pasting the C and header file */ -#if !defined(CJSON_HIDE_SYMBOLS) && !defined(CJSON_IMPORT_SYMBOLS) && !defined(CJSON_EXPORT_SYMBOLS) -#define CJSON_EXPORT_SYMBOLS -#endif - -#if defined(CJSON_HIDE_SYMBOLS) -#define CJSON_PUBLIC(type) type __stdcall -#elif defined(CJSON_EXPORT_SYMBOLS) -#define CJSON_PUBLIC(type) __declspec(dllexport) type __stdcall -#elif defined(CJSON_IMPORT_SYMBOLS) -#define CJSON_PUBLIC(type) __declspec(dllimport) type __stdcall -#endif -#else /* !WIN32 */ -#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY) -#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type -#else -#define CJSON_PUBLIC(type) type -#endif -#endif - -/* Limits how deeply nested arrays/objects can be before cJSON rejects to parse them. - * This is to prevent stack overflows. */ -#ifndef CJSON_NESTING_LIMIT -#define CJSON_NESTING_LIMIT 1000 -#endif - -/* returns the version of cJSON as a string */ -CJSON_PUBLIC(const char*) cJSON_Version(void); - -/* Supply malloc, realloc and free functions to cJSON */ -CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks); - -/* Memory Management: the caller is always responsible to free the results from all variants of cJSON_Parse (with cJSON_Delete) and cJSON_Print (with stdlib free, cJSON_Hooks.free_fn, or cJSON_free as appropriate). The exception is cJSON_PrintPreallocated, where the caller has full responsibility of the buffer. */ -/* Supply a block of JSON, and this returns a cJSON object you can interrogate. */ -CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value); -/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ -/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error so will match cJSON_GetErrorPtr(). */ -CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated); - -/* Render a cJSON entity to text for transfer/storage. */ -CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item); -/* Render a cJSON entity to text for transfer/storage without any formatting. */ -CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item); -/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */ -CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt); -/* Render a cJSON entity to text using a buffer already allocated in memory with given length. Returns 1 on success and 0 on failure. */ -/* NOTE: cJSON is not always 100% accurate in estimating how much memory it will use, so to be safe allocate 5 bytes more than you actually need */ -CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format); -/* Delete a cJSON entity and all subentities. */ -CJSON_PUBLIC(void) cJSON_Delete(cJSON *c); - -/* Returns the number of items in an array (or object). */ -CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array); -/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */ -CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index); -/* Get item "string" from object. Case insensitive. */ -CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string); -CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string); -CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string); -/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ -CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void); - -/* These functions check the type of an item */ -CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item); -CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item); -CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item); -CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item); -CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item); -CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item); -CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item); -CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item); -CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item); -CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item); - -/* These calls create a cJSON item of the appropriate type. */ -CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void); -CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void); -CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void); -CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean); -CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num); -CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string); -/* raw json */ -CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw); -CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void); -CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void); - -/* These utilities create an Array of count items. */ -CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count); -CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count); -CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count); -CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count); - -/* Append item to the specified array/object. */ -CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item); -CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item); -/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object. - * WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before - * writing to `item->string` */ -CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item); -/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ -CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); -CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item); - -/* Remove/Detatch items from Arrays/Objects. */ -CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item); -CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which); -CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which); -CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string); -CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string); -CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string); -CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string); - -/* Update array items. */ -CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */ -CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement); -CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem); -CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); -CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object,const char *string,cJSON *newitem); - -/* Duplicate a cJSON item */ -CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse); -/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will -need to be released. With recurse!=0, it will duplicate any children connected to the item. -The item->next and ->prev pointers are always zero on return from Duplicate. */ -/* Recursively compare two cJSON items for equality. If either a or b is NULL or invalid, they will be considered unequal. - * case_sensitive determines if object keys are treated case sensitive (1) or case insensitive (0) */ -CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive); - - -CJSON_PUBLIC(void) cJSON_Minify(char *json); - -/* Macros for creating things quickly. */ -#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull()) -#define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue()) -#define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse()) -#define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b)) -#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n)) -#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s)) -#define cJSON_AddRawToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateRaw(s)) - -/* When assigning an integer value, it needs to be propagated to valuedouble too. */ -#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number)) -/* helper for the cJSON_SetNumberValue macro */ -CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number); -#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number)) - -/* Macro for iterating over an array or object */ -#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next) - -/* malloc/free objects using the malloc/free functions that have been set with cJSON_InitHooks */ -CJSON_PUBLIC(void *) cJSON_malloc(size_t size); -CJSON_PUBLIC(void) cJSON_free(void *object); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/plugins/http/inc/tgHandle.h b/src/plugins/http/inc/tgHandle.h index 5b8c49900f..5622694374 100644 --- a/src/plugins/http/inc/tgHandle.h +++ b/src/plugins/http/inc/tgHandle.h @@ -33,6 +33,7 @@ #define TG_PASS_URL_POS 3 void tgInitHandle(HttpServer *pServer); +void tgCleanupHandle(); bool tgProcessRquest(struct HttpContext *pContext); diff --git a/src/plugins/http/src/cJSON.c b/src/plugins/http/src/cJSON.c deleted file mode 100644 index fa836f9871..0000000000 --- a/src/plugins/http/src/cJSON.c +++ /dev/null @@ -1,2699 +0,0 @@ -/* - Copyright (c) 2009-2017 Dave Gamble and cJSON contributors - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. -*/ - -/* cJSON */ -/* JSON parser in C. */ - -#ifdef __GNUC__ -#pragma GCC visibility push(default) -#endif - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef __GNUC__ -#pragma GCC visibility pop -#endif - -#include "cJSON.h" - -/* define our own boolean type */ -#define true ((cJSON_bool)1) -#define false ((cJSON_bool)0) - -typedef struct { - const unsigned char *json; - size_t position; -} error; -static error global_error = { NULL, 0 }; - -CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) -{ - return (const char*) (global_error.json + global_error.position); -} - -/* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ -#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 5) || (CJSON_VERSION_PATCH != 9) - #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. -#endif - -CJSON_PUBLIC(const char*) cJSON_Version(void) -{ - static char version[15]; - sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH); - - return version; -} - -/* Case insensitive string comparison, doesn't consider two NULL pointers equal though */ -static int case_insensitive_strcmp(const unsigned char *string1, const unsigned char *string2) -{ - if ((string1 == NULL) || (string2 == NULL)) - { - return 1; - } - - if (string1 == string2) - { - return 0; - } - - for(; tolower(*string1) == tolower(*string2); (void)string1++, string2++) - { - if (*string1 == '\0') - { - return 0; - } - } - - return tolower(*string1) - tolower(*string2); -} - -typedef struct internal_hooks -{ - void *(*allocate)(size_t size); - void (*deallocate)(void *pointer); - void *(*reallocate)(void *pointer, size_t size); -} internal_hooks; - -static internal_hooks global_hooks = { malloc, free, realloc }; - -static unsigned char* cJSON_strdup(const unsigned char* string, const internal_hooks * const hooks) -{ - size_t length = 0; - unsigned char *copy = NULL; - - if (string == NULL) - { - return NULL; - } - - length = strlen((const char*)string) + sizeof(""); - if (!(copy = (unsigned char*)hooks->allocate(length))) - { - return NULL; - } - memcpy(copy, string, length); - - return copy; -} - -CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks) -{ - if (hooks == NULL) - { - /* Reset hooks */ - global_hooks.allocate = malloc; - global_hooks.deallocate = free; - global_hooks.reallocate = realloc; - return; - } - - global_hooks.allocate = malloc; - if (hooks->malloc_fn != NULL) - { - global_hooks.allocate = hooks->malloc_fn; - } - - global_hooks.deallocate = free; - if (hooks->free_fn != NULL) - { - global_hooks.deallocate = hooks->free_fn; - } - - /* use realloc only if both free and malloc are used */ - global_hooks.reallocate = NULL; - if ((global_hooks.allocate == malloc) && (global_hooks.deallocate == free)) - { - global_hooks.reallocate = realloc; - } -} - -/* Internal constructor. */ -static cJSON *cJSON_New_Item(const internal_hooks * const hooks) -{ - cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON)); - if (node) - { - memset(node, '\0', sizeof(cJSON)); - } - - return node; -} - -/* Delete a cJSON structure. */ -CJSON_PUBLIC(void) cJSON_Delete(cJSON *item) -{ - cJSON *next = NULL; - while (item != NULL) - { - next = item->next; - if (!(item->type & cJSON_IsReference) && (item->child != NULL)) - { - cJSON_Delete(item->child); - } - if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL)) - { - global_hooks.deallocate(item->valuestring); - } - if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)) - { - global_hooks.deallocate(item->string); - } - global_hooks.deallocate(item); - item = next; - } -} - -/* get the decimal point character of the current locale */ -static unsigned char get_decimal_point(void) -{ - struct lconv *lconv = localeconv(); - return (unsigned char) lconv->decimal_point[0]; -} - -typedef struct -{ - const unsigned char *content; - size_t length; - size_t offset; - size_t depth; /* How deeply nested (in arrays/objects) is the input at the current offset. */ - internal_hooks hooks; -} parse_buffer; - -/* check if the given size is left to read in a given parse buffer (starting with 1) */ -#define can_read(buffer, size) ((buffer != NULL) && (((buffer)->offset + size) <= (buffer)->length)) -#define cannot_read(buffer, size) (!can_read(buffer, size)) -/* check if the buffer can be accessed at the given index (starting with 0) */ -#define can_access_at_index(buffer, index) ((buffer != NULL) && (((buffer)->offset + index) < (buffer)->length)) -#define cannot_access_at_index(buffer, index) (!can_access_at_index(buffer, index)) -/* get a pointer to the buffer at the position */ -#define buffer_at_offset(buffer) ((buffer)->content + (buffer)->offset) - -/* Parse the input text to generate a number, and populate the result into item. */ -static cJSON_bool parse_number(cJSON * const item, parse_buffer * const input_buffer) -{ - double number = 0; - unsigned char *after_end = NULL; - unsigned char number_c_string[64]; - unsigned char decimal_point = get_decimal_point(); - size_t i = 0; - - if ((input_buffer == NULL) || (input_buffer->content == NULL)) - { - return false; - } - - /* copy the number into a temporary buffer and replace '.' with the decimal point - * of the current locale (for strtod) - * This also takes care of '\0' not necessarily being available for marking the end of the input */ - for (i = 0; (i < (sizeof(number_c_string) - 1)) && can_access_at_index(input_buffer, i); i++) - { - switch (buffer_at_offset(input_buffer)[i]) - { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case '+': - case '-': - case 'e': - case 'E': - number_c_string[i] = buffer_at_offset(input_buffer)[i]; - break; - - case '.': - number_c_string[i] = decimal_point; - break; - - default: - goto loop_end; - } - } -loop_end: - number_c_string[i] = '\0'; - - number = strtod((const char*)number_c_string, (char**)&after_end); - if (number_c_string == after_end) - { - return false; /* parse_error */ - } - - item->valuedouble = number; - - /* use saturation in case of overflow */ - if (number >= LLONG_MAX) - { - item->valueint = LLONG_MAX; - } - else if (number <= LLONG_MIN) - { - item->valueint = LLONG_MIN; - } - else - { - item->valueint = (int64_t)number; - } - - item->type = cJSON_Number; - - input_buffer->offset += (size_t)(after_end - number_c_string); - return true; -} - -/* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */ -CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number) -{ - if (number >= LLONG_MAX) - { - object->valueint = LLONG_MAX; - } - else if (number <= LLONG_MIN) - { - object->valueint = LLONG_MIN; - } - else - { - object->valueint = (int64_t)number; - } - - return object->valuedouble = number; -} - -typedef struct -{ - unsigned char *buffer; - size_t length; - size_t offset; - size_t depth; /* current nesting depth (for formatted printing) */ - cJSON_bool noalloc; - cJSON_bool format; /* is this print a formatted print */ - internal_hooks hooks; -} printbuffer; - -/* realloc printbuffer if necessary to have at least "needed" bytes more */ -static unsigned char* ensure(printbuffer * const p, size_t needed) -{ - unsigned char *newbuffer = NULL; - size_t newsize = 0; - - if ((p == NULL) || (p->buffer == NULL)) - { - return NULL; - } - - if ((p->length > 0) && (p->offset >= p->length)) - { - /* make sure that offset is valid */ - return NULL; - } - - if (needed > LLONG_MAX) - { - /* sizes bigger than LLONG_MAX are currently not supported */ - return NULL; - } - - needed += p->offset + 1; - if (needed <= p->length) - { - return p->buffer + p->offset; - } - - if (p->noalloc) { - return NULL; - } - - /* calculate new buffer size */ - if (needed > (LLONG_MAX / 2)) - { - /* overflow of int, use LLONG_MAX if possible */ - if (needed <= LLONG_MAX) - { - newsize = LLONG_MAX; - } - else - { - return NULL; - } - } - else - { - newsize = needed * 2; - } - - if (p->hooks.reallocate != NULL) - { - /* reallocate with realloc if available */ - newbuffer = (unsigned char*)p->hooks.reallocate(p->buffer, newsize); - if (newbuffer == NULL) - { - p->hooks.deallocate(p->buffer); - p->length = 0; - p->buffer = NULL; - - return NULL; - } - } - else - { - /* otherwise reallocate manually */ - newbuffer = (unsigned char*)p->hooks.allocate(newsize); - if (!newbuffer) - { - p->hooks.deallocate(p->buffer); - p->length = 0; - p->buffer = NULL; - - return NULL; - } - if (newbuffer) - { - memcpy(newbuffer, p->buffer, p->offset + 1); - } - p->hooks.deallocate(p->buffer); - } - p->length = newsize; - p->buffer = newbuffer; - - return newbuffer + p->offset; -} - -/* calculate the new length of the string in a printbuffer and update the offset */ -static void update_offset(printbuffer * const buffer) -{ - const unsigned char *buffer_pointer = NULL; - if ((buffer == NULL) || (buffer->buffer == NULL)) - { - return; - } - buffer_pointer = buffer->buffer + buffer->offset; - - buffer->offset += strlen((const char*)buffer_pointer); -} - -/* Render the number nicely from the given item into a string. */ -static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer) -{ - unsigned char *output_pointer = NULL; - double d = item->valuedouble; - int length = 0; - size_t i = 0; - unsigned char number_buffer[26]; /* temporary buffer to print the number into */ - unsigned char decimal_point = get_decimal_point(); - double test; - - if (output_buffer == NULL) - { - return false; - } - - /* This checks for NaN and Infinity */ - if ((d * 0) != 0) - { - length = sprintf((char*)number_buffer, "null"); - } - else - { - /* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */ - length = sprintf((char*)number_buffer, "%1.15g", d); - - /* Check whether the original double can be recovered */ - if ((sscanf((char*)number_buffer, "%lg", &test) != 1) || ((double)test != d)) - { - /* If not, print with 17 decimal places of precision */ - length = sprintf((char*)number_buffer, "%1.17g", d); - } - } - - /* sprintf failed or buffer overrun occured */ - if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1))) - { - return false; - } - - /* reserve appropriate space in the output */ - output_pointer = ensure(output_buffer, (size_t)length); - if (output_pointer == NULL) - { - return false; - } - - /* copy the printed number to the output and replace locale - * dependent decimal point with '.' */ - for (i = 0; i < ((size_t)length); i++) - { - if (number_buffer[i] == decimal_point) - { - output_pointer[i] = '.'; - continue; - } - - output_pointer[i] = number_buffer[i]; - } - output_pointer[i] = '\0'; - - output_buffer->offset += (size_t)length; - - return true; -} - -/* parse 4 digit hexadecimal number */ -static unsigned parse_hex4(const unsigned char * const input) -{ - unsigned int h = 0; - size_t i = 0; - - for (i = 0; i < 4; i++) - { - /* parse digit */ - if ((input[i] >= '0') && (input[i] <= '9')) - { - h += (unsigned int) input[i] - '0'; - } - else if ((input[i] >= 'A') && (input[i] <= 'F')) - { - h += (unsigned int) 10 + input[i] - 'A'; - } - else if ((input[i] >= 'a') && (input[i] <= 'f')) - { - h += (unsigned int) 10 + input[i] - 'a'; - } - else /* invalid */ - { - return 0; - } - - if (i < 3) - { - /* shift left to make place for the next nibble */ - h = h << 4; - } - } - - return h; -} - -/* converts a UTF-16 literal to UTF-8 - * A literal can be one or two sequences of the form \uXXXX */ -static unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer) -{ - uint64_t codepoint = 0; - unsigned int first_code = 0; - const unsigned char *first_sequence = input_pointer; - unsigned char utf8_length = 0; - unsigned char utf8_position = 0; - unsigned char sequence_length = 0; - unsigned char first_byte_mark = 0; - - if ((input_end - first_sequence) < 6) - { - /* input ends unexpectedly */ - goto fail; - } - - /* get the first utf16 sequence */ - first_code = parse_hex4(first_sequence + 2); - - /* check that the code is valid */ - if (((first_code >= 0xDC00) && (first_code <= 0xDFFF))) - { - goto fail; - } - - /* UTF16 surrogate pair */ - if ((first_code >= 0xD800) && (first_code <= 0xDBFF)) - { - const unsigned char *second_sequence = first_sequence + 6; - unsigned int second_code = 0; - sequence_length = 12; /* \uXXXX\uXXXX */ - - if ((input_end - second_sequence) < 6) - { - /* input ends unexpectedly */ - goto fail; - } - - if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u')) - { - /* missing second half of the surrogate pair */ - goto fail; - } - - /* get the second utf16 sequence */ - second_code = parse_hex4(second_sequence + 2); - /* check that the code is valid */ - if ((second_code < 0xDC00) || (second_code > 0xDFFF)) - { - /* invalid second half of the surrogate pair */ - goto fail; - } - - - /* calculate the unicode codepoint from the surrogate pair */ - codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF)); - } - else - { - sequence_length = 6; /* \uXXXX */ - codepoint = first_code; - } - - /* encode as UTF-8 - * takes at maximum 4 bytes to encode: - * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ - if (codepoint < 0x80) - { - /* normal ascii, encoding 0xxxxxxx */ - utf8_length = 1; - } - else if (codepoint < 0x800) - { - /* two bytes, encoding 110xxxxx 10xxxxxx */ - utf8_length = 2; - first_byte_mark = 0xC0; /* 11000000 */ - } - else if (codepoint < 0x10000) - { - /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */ - utf8_length = 3; - first_byte_mark = 0xE0; /* 11100000 */ - } - else if (codepoint <= 0x10FFFF) - { - /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */ - utf8_length = 4; - first_byte_mark = 0xF0; /* 11110000 */ - } - else - { - /* invalid unicode codepoint */ - goto fail; - } - - /* encode as utf8 */ - for (utf8_position = (unsigned char)(utf8_length - 1); utf8_position > 0; utf8_position--) - { - /* 10xxxxxx */ - (*output_pointer)[utf8_position] = (unsigned char)((codepoint | 0x80) & 0xBF); - codepoint >>= 6; - } - /* encode first byte */ - if (utf8_length > 1) - { - (*output_pointer)[0] = (unsigned char)((codepoint | first_byte_mark) & 0xFF); - } - else - { - (*output_pointer)[0] = (unsigned char)(codepoint & 0x7F); - } - - *output_pointer += utf8_length; - - return sequence_length; - -fail: - return 0; -} - -/* Parse the input text into an unescaped cinput, and populate item. */ -static cJSON_bool parse_string(cJSON * const item, parse_buffer * const input_buffer) -{ - const unsigned char *input_pointer = buffer_at_offset(input_buffer) + 1; - const unsigned char *input_end = buffer_at_offset(input_buffer) + 1; - unsigned char *output_pointer = NULL; - unsigned char *output = NULL; - - /* not a string */ - if (buffer_at_offset(input_buffer)[0] != '\"') - { - goto fail; - } - - { - /* calculate approximate size of the output (overestimate) */ - size_t allocation_length = 0; - size_t skipped_bytes = 0; - while (((size_t)(input_end - input_buffer->content) < input_buffer->length) && (*input_end != '\"')) - { - /* is escape sequence */ - if (input_end[0] == '\\') - { - if ((size_t)(input_end + 1 - input_buffer->content) >= input_buffer->length) - { - /* prevent buffer overflow when last input character is a backslash */ - goto fail; - } - skipped_bytes++; - input_end++; - } - input_end++; - } - if (((size_t)(input_end - input_buffer->content) >= input_buffer->length) || (*input_end != '\"')) - { - goto fail; /* string ended unexpectedly */ - } - - /* This is at most how much we need for the output */ - allocation_length = (size_t) (input_end - buffer_at_offset(input_buffer)) - skipped_bytes; - output = (unsigned char*)input_buffer->hooks.allocate(allocation_length + sizeof("")); - if (output == NULL) - { - goto fail; /* allocation failure */ - } - } - - output_pointer = output; - /* loop through the string literal */ - while (input_pointer < input_end) - { - if (*input_pointer != '\\') - { - *output_pointer++ = *input_pointer++; - } - /* escape sequence */ - else - { - unsigned char sequence_length = 2; - if ((input_end - input_pointer) < 1) - { - goto fail; - } - - switch (input_pointer[1]) - { - case 'b': - *output_pointer++ = '\b'; - break; - case 'f': - *output_pointer++ = '\f'; - break; - case 'n': - *output_pointer++ = '\n'; - break; - case 'r': - *output_pointer++ = '\r'; - break; - case 't': - *output_pointer++ = '\t'; - break; - case '\"': - case '\\': - case '/': - *output_pointer++ = input_pointer[1]; - break; - - /* UTF-16 literal */ - case 'u': - sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer); - if (sequence_length == 0) - { - /* failed to convert UTF16-literal to UTF-8 */ - goto fail; - } - break; - - default: - goto fail; - } - input_pointer += sequence_length; - } - } - - /* zero terminate the output */ - *output_pointer = '\0'; - - item->type = cJSON_String; - item->valuestring = (char*)output; - - input_buffer->offset = (size_t) (input_end - input_buffer->content); - input_buffer->offset++; - - return true; - -fail: - if (output != NULL) - { - input_buffer->hooks.deallocate(output); - } - - if (input_pointer != NULL) - { - input_buffer->offset = (size_t)(input_pointer - input_buffer->content); - } - - return false; -} - -/* Render the cstring provided to an escaped version that can be printed. */ -static cJSON_bool print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer) -{ - const unsigned char *input_pointer = NULL; - unsigned char *output = NULL; - unsigned char *output_pointer = NULL; - size_t output_length = 0; - /* numbers of additional characters needed for escaping */ - size_t escape_characters = 0; - - if (output_buffer == NULL) - { - return false; - } - - /* empty string */ - if (input == NULL) - { - output = ensure(output_buffer, sizeof("\"\"")); - if (output == NULL) - { - return false; - } - strcpy((char*)output, "\"\""); - - return true; - } - - /* set "flag" to 1 if something needs to be escaped */ - for (input_pointer = input; *input_pointer; input_pointer++) - { - switch (*input_pointer) - { - case '\"': - case '\\': - case '\b': - case '\f': - case '\n': - case '\r': - case '\t': - /* one character escape sequence */ - escape_characters++; - break; - default: - if (*input_pointer < 32) - { - /* UTF-16 escape sequence uXXXX */ - escape_characters += 5; - } - break; - } - } - output_length = (size_t)(input_pointer - input) + escape_characters; - - output = ensure(output_buffer, output_length + sizeof("\"\"")); - if (output == NULL) - { - return false; - } - - /* no characters have to be escaped */ - if (escape_characters == 0) - { - output[0] = '\"'; - memcpy(output + 1, input, output_length); - output[output_length + 1] = '\"'; - output[output_length + 2] = '\0'; - - return true; - } - - output[0] = '\"'; - output_pointer = output + 1; - /* copy the string */ - for (input_pointer = input; *input_pointer != '\0'; (void)input_pointer++, output_pointer++) - { - if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\')) - { - /* normal character, copy */ - *output_pointer = *input_pointer; - } - else - { - /* character needs to be escaped */ - *output_pointer++ = '\\'; - switch (*input_pointer) - { - case '\\': - *output_pointer = '\\'; - break; - case '\"': - *output_pointer = '\"'; - break; - case '\b': - *output_pointer = 'b'; - break; - case '\f': - *output_pointer = 'f'; - break; - case '\n': - *output_pointer = 'n'; - break; - case '\r': - *output_pointer = 'r'; - break; - case '\t': - *output_pointer = 't'; - break; - default: - /* escape and print as unicode codepoint */ - sprintf((char*)output_pointer, "u%04x", *input_pointer); - output_pointer += 4; - break; - } - } - } - output[output_length + 1] = '\"'; - output[output_length + 2] = '\0'; - - return true; -} - -/* Invoke print_string_ptr (which is useful) on an item. */ -static cJSON_bool print_string(const cJSON * const item, printbuffer * const p) -{ - return print_string_ptr((unsigned char*)item->valuestring, p); -} - -/* Predeclare these prototypes. */ -static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer); -static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer); -static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer); -static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer); -static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer); -static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer); - -/* Utility to jump whitespace and cr/lf */ -static parse_buffer *buffer_skip_whitespace(parse_buffer * const buffer) -{ - if ((buffer == NULL) || (buffer->content == NULL)) - { - return NULL; - } - - while (can_access_at_index(buffer, 0) && (buffer_at_offset(buffer)[0] <= 32)) - { - buffer->offset++; - } - - if (buffer->offset == buffer->length) - { - buffer->offset--; - } - - return buffer; -} - -/* Parse an object - create a new root, and populate. */ -CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated) -{ - parse_buffer buffer = { 0, 0, 0, 0, { 0, 0, 0 } }; - cJSON *item = NULL; - - /* reset error position */ - global_error.json = NULL; - global_error.position = 0; - - if (value == NULL) - { - goto fail; - } - - buffer.content = (const unsigned char*)value; - buffer.length = strlen((const char*)value) + sizeof(""); - buffer.offset = 0; - buffer.hooks = global_hooks; - - item = cJSON_New_Item(&global_hooks); - if (item == NULL) /* memory fail */ - { - goto fail; - } - - if (!parse_value(item, buffer_skip_whitespace(&buffer))) - { - /* parse failure. ep is set. */ - goto fail; - } - - /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ - if (require_null_terminated) - { - buffer_skip_whitespace(&buffer); - if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0') - { - goto fail; - } - } - if (return_parse_end) - { - *return_parse_end = (const char*)buffer_at_offset(&buffer); - } - - return item; - -fail: - if (item != NULL) - { - cJSON_Delete(item); - } - - if (value != NULL) - { - error local_error; - local_error.json = (const unsigned char*)value; - local_error.position = 0; - - if (buffer.offset < buffer.length) - { - local_error.position = buffer.offset; - } - else if (buffer.length > 0) - { - local_error.position = buffer.length - 1; - } - - if (return_parse_end != NULL) - { - *return_parse_end = (const char*)local_error.json + local_error.position; - } - - global_error = local_error; - } - - return NULL; -} - -/* Default options for cJSON_Parse */ -CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value) -{ - return cJSON_ParseWithOpts(value, 0, 0); -} - -#define cjson_min(a, b) ((a < b) ? a : b) - -static unsigned char *print(const cJSON * const item, cJSON_bool format, const internal_hooks * const hooks) -{ - printbuffer buffer[1]; - unsigned char *printed = NULL; - - memset(buffer, 0, sizeof(buffer)); - - /* create buffer */ - buffer->buffer = (unsigned char*) hooks->allocate(256); - buffer->format = format; - buffer->hooks = *hooks; - if (buffer->buffer == NULL) - { - goto fail; - } - - /* print the value */ - if (!print_value(item, buffer)) - { - goto fail; - } - update_offset(buffer); - - /* check if reallocate is available */ - if (hooks->reallocate != NULL) - { - printed = (unsigned char*) hooks->reallocate(buffer->buffer, buffer->length); - buffer->buffer = NULL; - if (printed == NULL) { - goto fail; - } - } - else /* otherwise copy the JSON over to a new buffer */ - { - printed = (unsigned char*) hooks->allocate(buffer->offset + 1); - if (printed == NULL) - { - goto fail; - } - memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1)); - printed[buffer->offset] = '\0'; /* just to be sure */ - - /* free the buffer */ - hooks->deallocate(buffer->buffer); - } - - return printed; - -fail: - if (buffer->buffer != NULL) - { - hooks->deallocate(buffer->buffer); - } - - if (printed != NULL) - { - hooks->deallocate(printed); - } - - return NULL; -} - -/* Render a cJSON item/entity/structure to text. */ -CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item) -{ - return (char*)print(item, true, &global_hooks); -} - -CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item) -{ - return (char*)print(item, false, &global_hooks); -} - -CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt) -{ - printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; - - if (prebuffer < 0) - { - return NULL; - } - - p.buffer = (unsigned char*)global_hooks.allocate((size_t)prebuffer); - if (!p.buffer) - { - return NULL; - } - - p.length = (size_t)prebuffer; - p.offset = 0; - p.noalloc = false; - p.format = fmt; - p.hooks = global_hooks; - - if (!print_value(item, &p)) - { - global_hooks.deallocate(p.buffer); - return NULL; - } - - return (char*)p.buffer; -} - -CJSON_PUBLIC(cJSON_bool) cJSON_PrintPreallocated(cJSON *item, char *buf, const int len, const cJSON_bool fmt) -{ - printbuffer p = { 0, 0, 0, 0, 0, 0, { 0, 0, 0 } }; - - if ((len < 0) || (buf == NULL)) - { - return false; - } - - p.buffer = (unsigned char*)buf; - p.length = (size_t)len; - p.offset = 0; - p.noalloc = true; - p.format = fmt; - p.hooks = global_hooks; - - return print_value(item, &p); -} - -/* Parser core - when encountering text, process appropriately. */ -static cJSON_bool parse_value(cJSON * const item, parse_buffer * const input_buffer) -{ - if ((input_buffer == NULL) || (input_buffer->content == NULL)) - { - return false; /* no input */ - } - - /* parse the different types of values */ - /* null */ - if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "null", 4) == 0)) - { - item->type = cJSON_NULL; - input_buffer->offset += 4; - return true; - } - /* false */ - if (can_read(input_buffer, 5) && (strncmp((const char*)buffer_at_offset(input_buffer), "false", 5) == 0)) - { - item->type = cJSON_False; - input_buffer->offset += 5; - return true; - } - /* true */ - if (can_read(input_buffer, 4) && (strncmp((const char*)buffer_at_offset(input_buffer), "true", 4) == 0)) - { - item->type = cJSON_True; - item->valueint = 1; - input_buffer->offset += 4; - return true; - } - /* string */ - if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"')) - { - return parse_string(item, input_buffer); - } - /* number */ - if (can_access_at_index(input_buffer, 0) && ((buffer_at_offset(input_buffer)[0] == '-') || ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9')))) - { - return parse_number(item, input_buffer); - } - /* array */ - if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '[')) - { - return parse_array(item, input_buffer); - } - /* object */ - if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{')) - { - return parse_object(item, input_buffer); - } - - - return false; -} - -/* Render a value to text. */ -static cJSON_bool print_value(const cJSON * const item, printbuffer * const output_buffer) -{ - unsigned char *output = NULL; - - if ((item == NULL) || (output_buffer == NULL)) - { - return false; - } - - switch ((item->type) & 0xFF) - { - case cJSON_NULL: - output = ensure(output_buffer, 5); - if (output == NULL) - { - return false; - } - strcpy((char*)output, "null"); - return true; - - case cJSON_False: - output = ensure(output_buffer, 6); - if (output == NULL) - { - return false; - } - strcpy((char*)output, "false"); - return true; - - case cJSON_True: - output = ensure(output_buffer, 5); - if (output == NULL) - { - return false; - } - strcpy((char*)output, "true"); - return true; - - case cJSON_Number: - return print_number(item, output_buffer); - - case cJSON_Raw: - { - size_t raw_length = 0; - if (item->valuestring == NULL) - { - if (!output_buffer->noalloc) - { - output_buffer->hooks.deallocate(output_buffer->buffer); - } - return false; - } - - raw_length = strlen(item->valuestring) + sizeof(""); - output = ensure(output_buffer, raw_length); - if (output == NULL) - { - return false; - } - memcpy(output, item->valuestring, raw_length); - return true; - } - - case cJSON_String: - return print_string(item, output_buffer); - - case cJSON_Array: - return print_array(item, output_buffer); - - case cJSON_Object: - return print_object(item, output_buffer); - - default: - return false; - } -} - -/* Build an array from input text. */ -static cJSON_bool parse_array(cJSON * const item, parse_buffer * const input_buffer) -{ - cJSON *head = NULL; /* head of the linked list */ - cJSON *current_item = NULL; - - if (input_buffer->depth >= CJSON_NESTING_LIMIT) - { - return false; /* to deeply nested */ - } - input_buffer->depth++; - - if (buffer_at_offset(input_buffer)[0] != '[') - { - /* not an array */ - goto fail; - } - - input_buffer->offset++; - buffer_skip_whitespace(input_buffer); - if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ']')) - { - /* empty array */ - goto success; - } - - /* check if we skipped to the end of the buffer */ - if (cannot_access_at_index(input_buffer, 0)) - { - input_buffer->offset--; - goto fail; - } - - /* step back to character in front of the first element */ - input_buffer->offset--; - /* loop through the comma separated array elements */ - do - { - /* allocate next item */ - cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); - if (new_item == NULL) - { - goto fail; /* allocation failure */ - } - - /* attach next item to list */ - if (head == NULL) - { - /* start the linked list */ - current_item = head = new_item; - } - else - { - /* add to the end and advance */ - current_item->next = new_item; - new_item->prev = current_item; - current_item = new_item; - } - - /* parse next value */ - input_buffer->offset++; - buffer_skip_whitespace(input_buffer); - if (!parse_value(current_item, input_buffer)) - { - goto fail; /* failed to parse value */ - } - buffer_skip_whitespace(input_buffer); - } - while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); - - if (cannot_access_at_index(input_buffer, 0) || buffer_at_offset(input_buffer)[0] != ']') - { - goto fail; /* expected end of array */ - } - -success: - input_buffer->depth--; - - item->type = cJSON_Array; - item->child = head; - - input_buffer->offset++; - - return true; - -fail: - if (head != NULL) - { - cJSON_Delete(head); - } - - return false; -} - -/* Render an array to text */ -static cJSON_bool print_array(const cJSON * const item, printbuffer * const output_buffer) -{ - unsigned char *output_pointer = NULL; - size_t length = 0; - cJSON *current_element = item->child; - - if (output_buffer == NULL) - { - return false; - } - - /* Compose the output array. */ - /* opening square bracket */ - output_pointer = ensure(output_buffer, 1); - if (output_pointer == NULL) - { - return false; - } - - *output_pointer = '['; - output_buffer->offset++; - output_buffer->depth++; - - while (current_element != NULL) - { - if (!print_value(current_element, output_buffer)) - { - return false; - } - update_offset(output_buffer); - if (current_element->next) - { - length = (size_t) (output_buffer->format ? 2 : 1); - output_pointer = ensure(output_buffer, length + 1); - if (output_pointer == NULL) - { - return false; - } - *output_pointer++ = ','; - if(output_buffer->format) - { - *output_pointer++ = ' '; - } - *output_pointer = '\0'; - output_buffer->offset += length; - } - current_element = current_element->next; - } - - output_pointer = ensure(output_buffer, 2); - if (output_pointer == NULL) - { - return false; - } - *output_pointer++ = ']'; - *output_pointer = '\0'; - output_buffer->depth--; - - return true; -} - -/* Build an object from the text. */ -static cJSON_bool parse_object(cJSON * const item, parse_buffer * const input_buffer) -{ - cJSON *head = NULL; /* linked list head */ - cJSON *current_item = NULL; - - if (input_buffer->depth >= CJSON_NESTING_LIMIT) - { - return false; /* to deeply nested */ - } - input_buffer->depth++; - - if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '{')) - { - goto fail; /* not an object */ - } - - input_buffer->offset++; - buffer_skip_whitespace(input_buffer); - if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '}')) - { - goto success; /* empty object */ - } - - /* check if we skipped to the end of the buffer */ - if (cannot_access_at_index(input_buffer, 0)) - { - input_buffer->offset--; - goto fail; - } - - /* step back to character in front of the first element */ - input_buffer->offset--; - /* loop through the comma separated array elements */ - do - { - /* allocate next item */ - cJSON *new_item = cJSON_New_Item(&(input_buffer->hooks)); - if (new_item == NULL) - { - goto fail; /* allocation failure */ - } - - /* attach next item to list */ - if (head == NULL) - { - /* start the linked list */ - current_item = head = new_item; - } - else - { - /* add to the end and advance */ - current_item->next = new_item; - new_item->prev = current_item; - current_item = new_item; - } - - /* parse the name of the child */ - input_buffer->offset++; - buffer_skip_whitespace(input_buffer); - if (!parse_string(current_item, input_buffer)) - { - goto fail; /* faile to parse name */ - } - buffer_skip_whitespace(input_buffer); - - /* swap valuestring and string, because we parsed the name */ - current_item->string = current_item->valuestring; - current_item->valuestring = NULL; - - if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != ':')) - { - goto fail; /* invalid object */ - } - - /* parse the value */ - input_buffer->offset++; - buffer_skip_whitespace(input_buffer); - if (!parse_value(current_item, input_buffer)) - { - goto fail; /* failed to parse value */ - } - buffer_skip_whitespace(input_buffer); - } - while (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == ',')); - - if (cannot_access_at_index(input_buffer, 0) || (buffer_at_offset(input_buffer)[0] != '}')) - { - goto fail; /* expected end of object */ - } - -success: - input_buffer->depth--; - - item->type = cJSON_Object; - item->child = head; - - input_buffer->offset++; - return true; - -fail: - if (head != NULL) - { - cJSON_Delete(head); - } - - return false; -} - -/* Render an object to text. */ -static cJSON_bool print_object(const cJSON * const item, printbuffer * const output_buffer) -{ - unsigned char *output_pointer = NULL; - size_t length = 0; - cJSON *current_item = item->child; - - if (output_buffer == NULL) - { - return false; - } - - /* Compose the output: */ - length = (size_t) (output_buffer->format ? 2 : 1); /* fmt: {\n */ - output_pointer = ensure(output_buffer, length + 1); - if (output_pointer == NULL) - { - return false; - } - - *output_pointer++ = '{'; - output_buffer->depth++; - if (output_buffer->format) - { - *output_pointer++ = '\n'; - } - output_buffer->offset += length; - - while (current_item) - { - if (output_buffer->format) - { - size_t i; - output_pointer = ensure(output_buffer, output_buffer->depth); - if (output_pointer == NULL) - { - return false; - } - for (i = 0; i < output_buffer->depth; i++) - { - *output_pointer++ = '\t'; - } - output_buffer->offset += output_buffer->depth; - } - - /* print key */ - if (!print_string_ptr((unsigned char*)current_item->string, output_buffer)) - { - return false; - } - update_offset(output_buffer); - - length = (size_t) (output_buffer->format ? 2 : 1); - output_pointer = ensure(output_buffer, length); - if (output_pointer == NULL) - { - return false; - } - *output_pointer++ = ':'; - if (output_buffer->format) - { - *output_pointer++ = '\t'; - } - output_buffer->offset += length; - - /* print value */ - if (!print_value(current_item, output_buffer)) - { - return false; - } - update_offset(output_buffer); - - /* print comma if not last */ - length = (size_t) ((output_buffer->format ? 1 : 0) + (current_item->next ? 1 : 0)); - output_pointer = ensure(output_buffer, length + 1); - if (output_pointer == NULL) - { - return false; - } - if (current_item->next) - { - *output_pointer++ = ','; - } - - if (output_buffer->format) - { - *output_pointer++ = '\n'; - } - *output_pointer = '\0'; - output_buffer->offset += length; - - current_item = current_item->next; - } - - output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2); - if (output_pointer == NULL) - { - return false; - } - if (output_buffer->format) - { - size_t i; - for (i = 0; i < (output_buffer->depth - 1); i++) - { - *output_pointer++ = '\t'; - } - } - *output_pointer++ = '}'; - *output_pointer = '\0'; - output_buffer->depth--; - - return true; -} - -/* Get Array size/item / object item. */ -CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array) -{ - cJSON *child = NULL; - size_t size = 0; - - if (array == NULL) - { - return 0; - } - - child = array->child; - - while(child != NULL) - { - size++; - child = child->next; - } - - /* FIXME: Can overflow here. Cannot be fixed without breaking the API */ - - return (int)size; -} - -static cJSON* get_array_item(const cJSON *array, size_t index) -{ - cJSON *current_child = NULL; - - if (array == NULL) - { - return NULL; - } - - current_child = array->child; - while ((current_child != NULL) && (index > 0)) - { - index--; - current_child = current_child->next; - } - - return current_child; -} - -CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index) -{ - if (index < 0) - { - return NULL; - } - - return get_array_item(array, (size_t)index); -} - -static cJSON *get_object_item(const cJSON * const object, const char * const name, const cJSON_bool case_sensitive) -{ - cJSON *current_element = NULL; - - if ((object == NULL) || (name == NULL)) - { - return NULL; - } - - current_element = object->child; - if (case_sensitive) - { - while ((current_element != NULL) && (strcmp(name, current_element->string) != 0)) - { - current_element = current_element->next; - } - } - else - { - while ((current_element != NULL) && (case_insensitive_strcmp((const unsigned char*)name, (const unsigned char*)(current_element->string)) != 0)) - { - current_element = current_element->next; - } - } - - return current_element; -} - -CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string) -{ - return get_object_item(object, string, false); -} - -CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string) -{ - return get_object_item(object, string, true); -} - -CJSON_PUBLIC(cJSON_bool) cJSON_HasObjectItem(const cJSON *object, const char *string) -{ - return cJSON_GetObjectItem(object, string) ? 1 : 0; -} - -/* Utility for array list handling. */ -static void suffix_object(cJSON *prev, cJSON *item) -{ - prev->next = item; - item->prev = prev; -} - -/* Utility for handling references. */ -static cJSON *create_reference(const cJSON *item, const internal_hooks * const hooks) -{ - cJSON *reference = NULL; - if (item == NULL) - { - return NULL; - } - - reference = cJSON_New_Item(hooks); - if (reference == NULL) - { - return NULL; - } - - memcpy(reference, item, sizeof(cJSON)); - reference->string = NULL; - reference->type |= cJSON_IsReference; - reference->next = reference->prev = NULL; - return reference; -} - -/* Add item to array/object. */ -CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item) -{ - cJSON *child = NULL; - - if ((item == NULL) || (array == NULL)) - { - return; - } - - child = array->child; - - if (child == NULL) - { - /* list is empty, start new one */ - array->child = item; - } - else - { - /* append to the end */ - while (child->next) - { - child = child->next; - } - suffix_object(child, item); - } -} - -CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) -{ - if (item == NULL) - { - return; - } - - /* call cJSON_AddItemToObjectCS for code reuse */ - cJSON_AddItemToObjectCS(object, (char*)cJSON_strdup((const unsigned char*)string, &global_hooks), item); - /* remove cJSON_StringIsConst flag */ - item->type &= ~cJSON_StringIsConst; -} - -#if defined (__clang__) || ((__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) - #pragma GCC diagnostic push -#endif -#ifdef __GNUC__ -#pragma GCC diagnostic ignored "-Wcast-qual" -#endif - -/* Add an item to an object with constant string as key */ -CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) -{ - if ((item == NULL) || (string == NULL)) - { - return; - } - if (!(item->type & cJSON_StringIsConst) && item->string) - { - global_hooks.deallocate(item->string); - } - item->string = (char*)string; - item->type |= cJSON_StringIsConst; - cJSON_AddItemToArray(object, item); -} -#if defined (__clang__) || ((__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5)))) - #pragma GCC diagnostic pop -#endif - -CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) -{ - if (array == NULL) - { - return; - } - - cJSON_AddItemToArray(array, create_reference(item, &global_hooks)); -} - -CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item) -{ - if ((object == NULL) || (string == NULL)) - { - return; - } - - cJSON_AddItemToObject(object, string, create_reference(item, &global_hooks)); -} - -CJSON_PUBLIC(cJSON *) cJSON_DetachItemViaPointer(cJSON *parent, cJSON * const item) -{ - if ((parent == NULL) || (item == NULL)) - { - return NULL; - } - - if (item->prev != NULL) - { - /* not the first element */ - item->prev->next = item->next; - } - if (item->next != NULL) - { - /* not the last element */ - item->next->prev = item->prev; - } - - if (item == parent->child) - { - /* first element */ - parent->child = item->next; - } - /* make sure the detached item doesn't point anywhere anymore */ - item->prev = NULL; - item->next = NULL; - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which) -{ - if (which < 0) - { - return NULL; - } - - return cJSON_DetachItemViaPointer(array, get_array_item(array, (size_t)which)); -} - -CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which) -{ - cJSON_Delete(cJSON_DetachItemFromArray(array, which)); -} - -CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string) -{ - cJSON *to_detach = cJSON_GetObjectItem(object, string); - - return cJSON_DetachItemViaPointer(object, to_detach); -} - -CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObjectCaseSensitive(cJSON *object, const char *string) -{ - cJSON *to_detach = cJSON_GetObjectItemCaseSensitive(object, string); - - return cJSON_DetachItemViaPointer(object, to_detach); -} - -CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string) -{ - cJSON_Delete(cJSON_DetachItemFromObject(object, string)); -} - -CJSON_PUBLIC(void) cJSON_DeleteItemFromObjectCaseSensitive(cJSON *object, const char *string) -{ - cJSON_Delete(cJSON_DetachItemFromObjectCaseSensitive(object, string)); -} - -/* Replace array/object items with new ones. */ -CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem) -{ - cJSON *after_inserted = NULL; - - if (which < 0) - { - return; - } - - after_inserted = get_array_item(array, (size_t)which); - if (after_inserted == NULL) - { - cJSON_AddItemToArray(array, newitem); - return; - } - - newitem->next = after_inserted; - newitem->prev = after_inserted->prev; - after_inserted->prev = newitem; - if (after_inserted == array->child) - { - array->child = newitem; - } - else - { - newitem->prev->next = newitem; - } -} - -CJSON_PUBLIC(cJSON_bool) cJSON_ReplaceItemViaPointer(cJSON * const parent, cJSON * const item, cJSON * replacement) -{ - if ((parent == NULL) || (replacement == NULL) || (item == NULL)) - { - return false; - } - - if (replacement == item) - { - return true; - } - - replacement->next = item->next; - replacement->prev = item->prev; - - if (replacement->next != NULL) - { - replacement->next->prev = replacement; - } - if (replacement->prev != NULL) - { - replacement->prev->next = replacement; - } - if (parent->child == item) - { - parent->child = replacement; - } - - item->next = NULL; - item->prev = NULL; - cJSON_Delete(item); - - return true; -} - -CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem) -{ - if (which < 0) - { - return; - } - - cJSON_ReplaceItemViaPointer(array, get_array_item(array, (size_t)which), newitem); -} - -static cJSON_bool replace_item_in_object(cJSON *object, const char *string, cJSON *replacement, cJSON_bool case_sensitive) -{ - if ((replacement == NULL) || (string == NULL)) - { - return false; - } - - /* replace the name in the replacement */ - if (!(replacement->type & cJSON_StringIsConst) && (replacement->string != NULL)) - { - cJSON_free(replacement->string); - } - replacement->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); - replacement->type &= ~cJSON_StringIsConst; - - cJSON_ReplaceItemViaPointer(object, get_object_item(object, string, case_sensitive), replacement); - - return true; -} - -CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem) -{ - replace_item_in_object(object, string, newitem, false); -} - -CJSON_PUBLIC(void) cJSON_ReplaceItemInObjectCaseSensitive(cJSON *object, const char *string, cJSON *newitem) -{ - replace_item_in_object(object, string, newitem, true); -} - -/* Create basic types: */ -CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if(item) - { - item->type = cJSON_NULL; - } - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if(item) - { - item->type = cJSON_True; - } - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if(item) - { - item->type = cJSON_False; - } - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool b) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if(item) - { - item->type = b ? cJSON_True : cJSON_False; - } - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if(item) - { - item->type = cJSON_Number; - item->valuedouble = num; - - /* use saturation in case of overflow */ - if (num >= LLONG_MAX) - { - item->valueint = LLONG_MAX; - } - else if (num <= LLONG_MIN) - { - item->valueint = LLONG_MIN; - } - else - { - item->valueint = (int64_t)num; - } - } - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if(item) - { - item->type = cJSON_String; - item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); - if(!item->valuestring) - { - cJSON_Delete(item); - return NULL; - } - } - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if(item) - { - item->type = cJSON_Raw; - item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks); - if(!item->valuestring) - { - cJSON_Delete(item); - return NULL; - } - } - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if(item) - { - item->type=cJSON_Array; - } - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if (item) - { - item->type = cJSON_Object; - } - - return item; -} - -/* Create Arrays: */ -CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count) -{ - size_t i = 0; - cJSON *n = NULL; - cJSON *p = NULL; - cJSON *a = NULL; - - if ((count < 0) || (numbers == NULL)) - { - return NULL; - } - - a = cJSON_CreateArray(); - for(i = 0; a && (i < (size_t)count); i++) - { - n = cJSON_CreateNumber(numbers[i]); - if (!n) - { - cJSON_Delete(a); - return NULL; - } - if(!i) - { - a->child = n; - } - else - { - suffix_object(p, n); - } - p = n; - } - - return a; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count) -{ - size_t i = 0; - cJSON *n = NULL; - cJSON *p = NULL; - cJSON *a = NULL; - - if ((count < 0) || (numbers == NULL)) - { - return NULL; - } - - a = cJSON_CreateArray(); - - for(i = 0; a && (i < (size_t)count); i++) - { - n = cJSON_CreateNumber((double)numbers[i]); - if(!n) - { - cJSON_Delete(a); - return NULL; - } - if(!i) - { - a->child = n; - } - else - { - suffix_object(p, n); - } - p = n; - } - - return a; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count) -{ - size_t i = 0; - cJSON *n = NULL; - cJSON *p = NULL; - cJSON *a = NULL; - - if ((count < 0) || (numbers == NULL)) - { - return NULL; - } - - a = cJSON_CreateArray(); - - for(i = 0;a && (i < (size_t)count); i++) - { - n = cJSON_CreateNumber(numbers[i]); - if(!n) - { - cJSON_Delete(a); - return NULL; - } - if(!i) - { - a->child = n; - } - else - { - suffix_object(p, n); - } - p = n; - } - - return a; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count) -{ - size_t i = 0; - cJSON *n = NULL; - cJSON *p = NULL; - cJSON *a = NULL; - - if ((count < 0) || (strings == NULL)) - { - return NULL; - } - - a = cJSON_CreateArray(); - - for (i = 0; a && (i < (size_t)count); i++) - { - n = cJSON_CreateString(strings[i]); - if(!n) - { - cJSON_Delete(a); - return NULL; - } - if(!i) - { - a->child = n; - } - else - { - suffix_object(p,n); - } - p = n; - } - - return a; -} - -/* Duplication */ -CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cJSON_bool recurse) -{ - cJSON *newitem = NULL; - cJSON *child = NULL; - cJSON *next = NULL; - cJSON *newchild = NULL; - - /* Bail on bad ptr */ - if (!item) - { - goto fail; - } - /* Create new item */ - newitem = cJSON_New_Item(&global_hooks); - if (!newitem) - { - goto fail; - } - /* Copy over all vars */ - newitem->type = item->type & (~cJSON_IsReference); - newitem->valueint = item->valueint; - newitem->valuedouble = item->valuedouble; - if (item->valuestring) - { - newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks); - if (!newitem->valuestring) - { - goto fail; - } - } - if (item->string) - { - newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks); - if (!newitem->string) - { - goto fail; - } - } - /* If non-recursive, then we're done! */ - if (!recurse) - { - return newitem; - } - /* Walk the ->next chain for the child. */ - child = item->child; - while (child != NULL) - { - newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */ - if (!newchild) - { - goto fail; - } - if (next != NULL) - { - /* If newitem->child already set, then crosswire ->prev and ->next and move on */ - next->next = newchild; - newchild->prev = next; - next = newchild; - } - else - { - /* Set newitem->child and move to it */ - newitem->child = newchild; - next = newchild; - } - child = child->next; - } - - return newitem; - -fail: - if (newitem != NULL) - { - cJSON_Delete(newitem); - } - - return NULL; -} - -CJSON_PUBLIC(void) cJSON_Minify(char *json) -{ - unsigned char *into = (unsigned char*)json; - - if (json == NULL) - { - return; - } - - while (*json) - { - if (*json == ' ') - { - json++; - } - else if (*json == '\t') - { - /* Whitespace characters. */ - json++; - } - else if (*json == '\r') - { - json++; - } - else if (*json=='\n') - { - json++; - } - else if ((*json == '/') && (json[1] == '/')) - { - /* double-slash comments, to end of line. */ - while (*json && (*json != '\n')) - { - json++; - } - } - else if ((*json == '/') && (json[1] == '*')) - { - /* multiline comments. */ - while (*json && !((*json == '*') && (json[1] == '/'))) - { - json++; - } - json += 2; - } - else if (*json == '\"') - { - /* string literals, which are \" sensitive. */ - *into++ = (unsigned char)*json++; - while (*json && (*json != '\"')) - { - if (*json == '\\') - { - *into++ = (unsigned char)*json++; - } - *into++ = (unsigned char)*json++; - } - *into++ = (unsigned char)*json++; - } - else - { - /* All other characters. */ - *into++ = (unsigned char)*json++; - } - } - - /* and null-terminate. */ - *into = '\0'; -} - -CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item) -{ - if (item == NULL) - { - return false; - } - - return (item->type & 0xFF) == cJSON_Invalid; -} - -CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item) -{ - if (item == NULL) - { - return false; - } - - return (item->type & 0xFF) == cJSON_False; -} - -CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item) -{ - if (item == NULL) - { - return false; - } - - return (item->type & 0xff) == cJSON_True; -} - - -CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item) -{ - if (item == NULL) - { - return false; - } - - return (item->type & (cJSON_True | cJSON_False)) != 0; -} -CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item) -{ - if (item == NULL) - { - return false; - } - - return (item->type & 0xFF) == cJSON_NULL; -} - -CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item) -{ - if (item == NULL) - { - return false; - } - - return (item->type & 0xFF) == cJSON_Number; -} - -CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item) -{ - if (item == NULL) - { - return false; - } - - return (item->type & 0xFF) == cJSON_String; -} - -CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item) -{ - if (item == NULL) - { - return false; - } - - return (item->type & 0xFF) == cJSON_Array; -} - -CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item) -{ - if (item == NULL) - { - return false; - } - - return (item->type & 0xFF) == cJSON_Object; -} - -CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item) -{ - if (item == NULL) - { - return false; - } - - return (item->type & 0xFF) == cJSON_Raw; -} - -CJSON_PUBLIC(cJSON_bool) cJSON_Compare(const cJSON * const a, const cJSON * const b, const cJSON_bool case_sensitive) -{ - if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF)) || cJSON_IsInvalid(a)) - { - return false; - } - - /* check if type is valid */ - switch (a->type & 0xFF) - { - case cJSON_False: - case cJSON_True: - case cJSON_NULL: - case cJSON_Number: - case cJSON_String: - case cJSON_Raw: - case cJSON_Array: - case cJSON_Object: - break; - - default: - return false; - } - - /* identical objects are equal */ - if (a == b) - { - return true; - } - - switch (a->type & 0xFF) - { - /* in these cases and equal type is enough */ - case cJSON_False: - case cJSON_True: - case cJSON_NULL: - return true; - - case cJSON_Number: - if (a->valuedouble == b->valuedouble) - { - return true; - } - return false; - - case cJSON_String: - case cJSON_Raw: - if ((a->valuestring == NULL) || (b->valuestring == NULL)) - { - return false; - } - if (strcmp(a->valuestring, b->valuestring) == 0) - { - return true; - } - - return false; - - case cJSON_Array: - { - cJSON *a_element = a->child; - cJSON *b_element = b->child; - - for (; (a_element != NULL) && (b_element != NULL);) - { - if (!cJSON_Compare(a_element, b_element, case_sensitive)) - { - return false; - } - - a_element = a_element->next; - b_element = b_element->next; - } - - /* one of the arrays is longer than the other */ - if (a_element != b_element) { - return false; - } - - return true; - } - - case cJSON_Object: - { - cJSON *a_element = NULL; - cJSON *b_element = NULL; - cJSON_ArrayForEach(a_element, a) - { - /* TODO This has O(n^2) runtime, which is horrible! */ - b_element = get_object_item(b, a_element->string, case_sensitive); - if (b_element == NULL) - { - return false; - } - - if (!cJSON_Compare(a_element, b_element, case_sensitive)) - { - return false; - } - } - - /* doing this twice, once on a and b to prevent true comparison if a subset of b - * TODO: Do this the proper way, this is just a fix for now */ - cJSON_ArrayForEach(b_element, b) - { - a_element = get_object_item(a, b_element->string, case_sensitive); - if (a_element == NULL) - { - return false; - } - - if (!cJSON_Compare(b_element, a_element, case_sensitive)) - { - return false; - } - } - - return true; - } - - default: - return false; - } -} - -CJSON_PUBLIC(void *) cJSON_malloc(size_t size) -{ - return global_hooks.allocate(size); -} - -CJSON_PUBLIC(void) cJSON_free(void *object) -{ - global_hooks.deallocate(object); -} diff --git a/src/plugins/http/src/httpSystem.c b/src/plugins/http/src/httpSystem.c index aa66af9825..46f31a12d6 100644 --- a/src/plugins/http/src/httpSystem.c +++ b/src/plugins/http/src/httpSystem.c @@ -122,12 +122,14 @@ void httpStopSystem() { if (httpServer != NULL) { httpServer->online = false; } + tgCleanupHandle(); } void httpCleanUpSystem() { httpPrint("http service cleanup"); httpStopSystem(); -#if 0 + +#if 1 if (httpServer == NULL) { return; } diff --git a/src/plugins/http/src/tgHandle.c b/src/plugins/http/src/tgHandle.c index c22a7bbdef..2be39743bd 100644 --- a/src/plugins/http/src/tgHandle.c +++ b/src/plugins/http/src/tgHandle.c @@ -116,6 +116,7 @@ void tgFreeSchemas() { } free(tgSchemas.schemas); tgSchemas.size = 0; + tgSchemas.schemas = NULL; } } @@ -290,6 +291,10 @@ void tgInitHandle(HttpServer *pServer) { httpAddMethod(pServer, &tgDecodeMethod); } +void tgCleanupHandle() { + tgFreeSchemas(); +} + bool tgGetUserFromUrl(HttpContext *pContext) { HttpParser *pParser = &pContext->parser; if (pParser->path[TG_USER_URL_POS].len > TSDB_USER_LEN - 1 || pParser->path[TG_USER_URL_POS].len <= 0) { diff --git a/tests/tsim/inc/cJSON.h b/src/util/inc/cJSON.h similarity index 100% rename from tests/tsim/inc/cJSON.h rename to src/util/inc/cJSON.h diff --git a/tests/tsim/src/cJSON.c b/src/util/src/cJSON.c similarity index 100% rename from tests/tsim/src/cJSON.c rename to src/util/src/cJSON.c