Merge branch '3.0' into feature/TD-13066-3.0
This commit is contained in:
commit
8b7ebd6f5f
|
@ -67,7 +67,13 @@ ELSE ()
|
||||||
IF (${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm64" OR ${CMAKE_SYSTEM_PROCESSOR} MATCHES "aarch64")
|
IF (${CMAKE_SYSTEM_PROCESSOR} MATCHES "arm64" OR ${CMAKE_SYSTEM_PROCESSOR} MATCHES "aarch64")
|
||||||
ADD_DEFINITIONS("-D_TD_ARM_")
|
ADD_DEFINITIONS("-D_TD_ARM_")
|
||||||
ELSE ()
|
ELSE ()
|
||||||
ADD_DEFINITIONS("-msse4.2 -mfma")
|
ADD_DEFINITIONS("-msse4.2")
|
||||||
|
IF("${FMA_SUPPORT}" MATCHES "true")
|
||||||
|
MESSAGE(STATUS "turn fma function support on")
|
||||||
|
ADD_DEFINITIONS("-mfma")
|
||||||
|
ELSE ()
|
||||||
|
MESSAGE(STATUS "turn fma function support off")
|
||||||
|
ENDIF()
|
||||||
ENDIF ()
|
ENDIF ()
|
||||||
|
|
||||||
ENDIF ()
|
ENDIF ()
|
||||||
|
|
|
@ -121,6 +121,10 @@ extern char tsCompressor[];
|
||||||
extern int32_t tsDiskCfgNum;
|
extern int32_t tsDiskCfgNum;
|
||||||
extern SDiskCfg tsDiskCfg[];
|
extern SDiskCfg tsDiskCfg[];
|
||||||
|
|
||||||
|
// internal
|
||||||
|
extern int32_t tsTransPullupMs;
|
||||||
|
extern int32_t tsMaRebalanceMs;
|
||||||
|
|
||||||
#define NEEDTO_COMPRESSS_MSG(size) (tsCompressMsgSize != -1 && (size) > tsCompressMsgSize)
|
#define NEEDTO_COMPRESSS_MSG(size) (tsCompressMsgSize != -1 && (size) > tsCompressMsgSize)
|
||||||
|
|
||||||
int32_t taosCreateLog(const char *logname, int32_t logFileNum, const char *cfgDir, const char **envCmd, const char *envFile,
|
int32_t taosCreateLog(const char *logname, int32_t logFileNum, const char *cfgDir, const char **envCmd, const char *envFile,
|
||||||
|
|
|
@ -47,7 +47,17 @@ typedef enum {
|
||||||
} SIndexOperOnColumn;
|
} SIndexOperOnColumn;
|
||||||
|
|
||||||
typedef enum { MUST = 0, SHOULD, NOT } EIndexOperatorType;
|
typedef enum { MUST = 0, SHOULD, NOT } EIndexOperatorType;
|
||||||
typedef enum { QUERY_TERM = 0, QUERY_PREFIX, QUERY_SUFFIX, QUERY_REGEX, QUERY_RANGE } EIndexQueryType;
|
typedef enum {
|
||||||
|
QUERY_TERM = 0,
|
||||||
|
QUERY_PREFIX,
|
||||||
|
QUERY_SUFFIX,
|
||||||
|
QUERY_REGEX,
|
||||||
|
QUERY_LESS_THAN,
|
||||||
|
QUERY_LESS_EQUAL,
|
||||||
|
QUERY_GREATER_THAN,
|
||||||
|
QUERY_GREATER_EQUAL,
|
||||||
|
QUERY_RANGE
|
||||||
|
} EIndexQueryType;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* create multi query
|
* create multi query
|
||||||
|
|
|
@ -264,7 +264,8 @@ int32_t* taosGetErrno();
|
||||||
#define TSDB_CODE_MND_TRANS_ALREADY_EXIST TAOS_DEF_ERROR_CODE(0, 0x03D0)
|
#define TSDB_CODE_MND_TRANS_ALREADY_EXIST TAOS_DEF_ERROR_CODE(0, 0x03D0)
|
||||||
#define TSDB_CODE_MND_TRANS_NOT_EXIST TAOS_DEF_ERROR_CODE(0, 0x03D1)
|
#define TSDB_CODE_MND_TRANS_NOT_EXIST TAOS_DEF_ERROR_CODE(0, 0x03D1)
|
||||||
#define TSDB_CODE_MND_TRANS_INVALID_STAGE TAOS_DEF_ERROR_CODE(0, 0x03D2)
|
#define TSDB_CODE_MND_TRANS_INVALID_STAGE TAOS_DEF_ERROR_CODE(0, 0x03D2)
|
||||||
#define TSDB_CODE_MND_TRANS_CAN_NOT_PARALLEL TAOS_DEF_ERROR_CODE(0, 0x03D4)
|
#define TSDB_CODE_MND_TRANS_CONFLICT TAOS_DEF_ERROR_CODE(0, 0x03D3)
|
||||||
|
#define TSDB_CODE_MND_TRANS_UNKNOW_ERROR TAOS_DEF_ERROR_CODE(0, 0x03D4)
|
||||||
|
|
||||||
// mnode-mq
|
// mnode-mq
|
||||||
#define TSDB_CODE_MND_TOPIC_ALREADY_EXIST TAOS_DEF_ERROR_CODE(0, 0x03E0)
|
#define TSDB_CODE_MND_TOPIC_ALREADY_EXIST TAOS_DEF_ERROR_CODE(0, 0x03E0)
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#ifndef _TD_UTIL_SKIPLIST2_H_
|
||||||
|
#define _TD_UTIL_SKIPLIST2_H_
|
||||||
|
|
||||||
|
#include "os.h"
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define SL_MAX_LEVEL 15
|
||||||
|
|
||||||
|
typedef struct SSkipList2 SSkipList2;
|
||||||
|
typedef struct SSLCursor SSLCursor;
|
||||||
|
typedef struct SSLCfg SSLCfg;
|
||||||
|
typedef struct SSLNode SSLNode;
|
||||||
|
|
||||||
|
typedef int32_t (*tslCmprFn)(const void *pKey1, int32_t nKey1, const void *pKey2, int32_t nKey2);
|
||||||
|
|
||||||
|
// SSkipList2
|
||||||
|
int32_t slOpen(const SSLCfg *pCfg, SSkipList2 **ppSl);
|
||||||
|
int32_t slClose(SSkipList2 *pSl);
|
||||||
|
int32_t slClear(SSkipList2 *pSl);
|
||||||
|
|
||||||
|
// SSLCursor
|
||||||
|
int32_t slcOpen(SSkipList2 *pSl, SSLCursor *pSlc);
|
||||||
|
int32_t slcClose(SSLCursor *pSlc);
|
||||||
|
int32_t slcMoveTo(SSLCursor *pSlc, const void *pKey, int32_t nKey);
|
||||||
|
int32_t slcMoveToNext(SSLCursor *pSlc);
|
||||||
|
int32_t slcMoveToPrev(SSLCursor *pSlc);
|
||||||
|
int32_t slcMoveToFirst(SSLCursor *pSlc);
|
||||||
|
int32_t slcMoveToLast(SSLCursor *pSlc);
|
||||||
|
int32_t slcPut(SSLCursor *pSlc, const void *pKey, int32_t nKey, const void *pData, int32_t nData);
|
||||||
|
int32_t slcGet(SSLCursor *pSlc, const void **ppKey, int32_t *nKey, const void **ppData, int32_t *nData);
|
||||||
|
int32_t slcDrop(SSLCursor *pSlc);
|
||||||
|
|
||||||
|
// struct
|
||||||
|
struct SSLCfg {
|
||||||
|
int8_t maxLevel;
|
||||||
|
int32_t nKey;
|
||||||
|
int32_t nData;
|
||||||
|
tslCmprFn cmprFn;
|
||||||
|
void *pPool;
|
||||||
|
void *(*xMalloc)(void *, int32_t size);
|
||||||
|
void (*xFree)(void *, void *);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SSLCursor {
|
||||||
|
SSkipList2 *pSl;
|
||||||
|
SSLNode **forwards[SL_MAX_LEVEL];
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /*_TD_UTIL_SKIPLIST2_H_*/
|
|
@ -169,6 +169,10 @@ uint32_t tsMaxRange = 500; // max range
|
||||||
uint32_t tsCurRange = 100; // range
|
uint32_t tsCurRange = 100; // range
|
||||||
char tsCompressor[32] = "ZSTD_COMPRESSOR"; // ZSTD_COMPRESSOR or GZIP_COMPRESSOR
|
char tsCompressor[32] = "ZSTD_COMPRESSOR"; // ZSTD_COMPRESSOR or GZIP_COMPRESSOR
|
||||||
|
|
||||||
|
// internal
|
||||||
|
int32_t tsTransPullupMs = 6000;
|
||||||
|
int32_t tsMaRebalanceMs = 2000;
|
||||||
|
|
||||||
void taosAddDataDir(int32_t index, char *v1, int32_t level, int32_t primary) {
|
void taosAddDataDir(int32_t index, char *v1, int32_t level, int32_t primary) {
|
||||||
tstrncpy(tsDiskCfg[index].dir, v1, TSDB_FILENAME_LEN);
|
tstrncpy(tsDiskCfg[index].dir, v1, TSDB_FILENAME_LEN);
|
||||||
tsDiskCfg[index].level = level;
|
tsDiskCfg[index].level = level;
|
||||||
|
|
|
@ -15,37 +15,83 @@
|
||||||
|
|
||||||
#define _DEFAULT_SOURCE
|
#define _DEFAULT_SOURCE
|
||||||
#include "tmsgcb.h"
|
#include "tmsgcb.h"
|
||||||
|
#include "taoserror.h"
|
||||||
|
|
||||||
static SMsgCb tsDefaultMsgCb;
|
static SMsgCb tsDefaultMsgCb;
|
||||||
|
|
||||||
void tmsgSetDefaultMsgCb(const SMsgCb* pMsgCb) { tsDefaultMsgCb = *pMsgCb; }
|
void tmsgSetDefaultMsgCb(const SMsgCb* pMsgCb) { tsDefaultMsgCb = *pMsgCb; }
|
||||||
|
|
||||||
int32_t tmsgPutToQueue(const SMsgCb* pMsgCb, EQueueType qtype, SRpcMsg* pReq) {
|
int32_t tmsgPutToQueue(const SMsgCb* pMsgCb, EQueueType qtype, SRpcMsg* pReq) {
|
||||||
return (*pMsgCb->queueFps[qtype])(pMsgCb->pWrapper, pReq);
|
PutToQueueFp fp = pMsgCb->queueFps[qtype];
|
||||||
|
if (fp != NULL) {
|
||||||
|
return (*fp)(pMsgCb->pWrapper, pReq);
|
||||||
|
} else {
|
||||||
|
terrno = TSDB_CODE_INVALID_PTR;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t tmsgGetQueueSize(const SMsgCb* pMsgCb, int32_t vgId, EQueueType qtype) {
|
int32_t tmsgGetQueueSize(const SMsgCb* pMsgCb, int32_t vgId, EQueueType qtype) {
|
||||||
return (*pMsgCb->qsizeFp)(pMsgCb->pWrapper, vgId, qtype);
|
GetQueueSizeFp fp = pMsgCb->qsizeFp;
|
||||||
|
if (fp != NULL) {
|
||||||
|
return (*fp)(pMsgCb->pWrapper, vgId, qtype);
|
||||||
|
} else {
|
||||||
|
terrno = TSDB_CODE_INVALID_PTR;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t tmsgSendReq(const SMsgCb* pMsgCb, const SEpSet* epSet, SRpcMsg* pReq) {
|
int32_t tmsgSendReq(const SMsgCb* pMsgCb, const SEpSet* epSet, SRpcMsg* pReq) {
|
||||||
return (*pMsgCb->sendReqFp)(pMsgCb->pWrapper, epSet, pReq);
|
SendReqFp fp = pMsgCb->sendReqFp;
|
||||||
|
if (fp != NULL) {
|
||||||
|
return (*fp)(pMsgCb->pWrapper, epSet, pReq);
|
||||||
|
} else {
|
||||||
|
terrno = TSDB_CODE_INVALID_PTR;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void tmsgSendRsp(const SRpcMsg* pRsp) { return (*tsDefaultMsgCb.sendRspFp)(tsDefaultMsgCb.pWrapper, pRsp); }
|
void tmsgSendRsp(const SRpcMsg* pRsp) {
|
||||||
|
SendRspFp fp = tsDefaultMsgCb.sendRspFp;
|
||||||
|
if (fp != NULL) {
|
||||||
|
return (*fp)(tsDefaultMsgCb.pWrapper, pRsp);
|
||||||
|
} else {
|
||||||
|
terrno = TSDB_CODE_INVALID_PTR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void tmsgSendRedirectRsp(const SRpcMsg* pRsp, const SEpSet* pNewEpSet) {
|
void tmsgSendRedirectRsp(const SRpcMsg* pRsp, const SEpSet* pNewEpSet) {
|
||||||
return (*tsDefaultMsgCb.sendRedirectRspFp)(tsDefaultMsgCb.pWrapper, pRsp, pNewEpSet);
|
SendRedirectRspFp fp = tsDefaultMsgCb.sendRedirectRspFp;
|
||||||
|
if (fp != NULL) {
|
||||||
|
(*fp)(tsDefaultMsgCb.pWrapper, pRsp, pNewEpSet);
|
||||||
|
} else {
|
||||||
|
terrno = TSDB_CODE_INVALID_PTR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void tmsgRegisterBrokenLinkArg(const SMsgCb* pMsgCb, SRpcMsg* pMsg) {
|
void tmsgRegisterBrokenLinkArg(const SMsgCb* pMsgCb, SRpcMsg* pMsg) {
|
||||||
(*pMsgCb->registerBrokenLinkArgFp)(pMsgCb->pWrapper, pMsg);
|
RegisterBrokenLinkArgFp fp = pMsgCb->registerBrokenLinkArgFp;
|
||||||
|
if (fp != NULL) {
|
||||||
|
(*fp)(pMsgCb->pWrapper, pMsg);
|
||||||
|
} else {
|
||||||
|
terrno = TSDB_CODE_INVALID_PTR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void tmsgReleaseHandle(void* handle, int8_t type) {
|
void tmsgReleaseHandle(void* handle, int8_t type) {
|
||||||
(*tsDefaultMsgCb.releaseHandleFp)(tsDefaultMsgCb.pWrapper, handle, type);
|
ReleaseHandleFp fp = tsDefaultMsgCb.releaseHandleFp;
|
||||||
|
if (fp != NULL) {
|
||||||
|
(*fp)(tsDefaultMsgCb.pWrapper, handle, type);
|
||||||
|
} else {
|
||||||
|
terrno = TSDB_CODE_INVALID_PTR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void tmsgReportStartup(const char* name, const char* desc) {
|
void tmsgReportStartup(const char* name, const char* desc) {
|
||||||
(*tsDefaultMsgCb.reportStartupFp)(tsDefaultMsgCb.pWrapper, name, desc);
|
ReportStartup fp = tsDefaultMsgCb.reportStartupFp;
|
||||||
|
if (fp != NULL && tsDefaultMsgCb.pWrapper != NULL) {
|
||||||
|
(*fp)(tsDefaultMsgCb.pWrapper, name, desc);
|
||||||
|
} else {
|
||||||
|
terrno = TSDB_CODE_INVALID_PTR;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -44,6 +44,8 @@ typedef void (*TransCbFp)(SMnode *pMnode, void *param, int32_t paramLen);
|
||||||
|
|
||||||
int32_t mndInitTrans(SMnode *pMnode);
|
int32_t mndInitTrans(SMnode *pMnode);
|
||||||
void mndCleanupTrans(SMnode *pMnode);
|
void mndCleanupTrans(SMnode *pMnode);
|
||||||
|
STrans *mndAcquireTrans(SMnode *pMnode, int32_t transId);
|
||||||
|
void mndReleaseTrans(SMnode *pMnode, STrans *pTrans);
|
||||||
|
|
||||||
STrans *mndTransCreate(SMnode *pMnode, ETrnPolicy policy, ETrnType type, const SRpcMsg *pReq);
|
STrans *mndTransCreate(SMnode *pMnode, ETrnPolicy policy, ETrnType type, const SRpcMsg *pReq);
|
||||||
void mndTransDrop(STrans *pTrans);
|
void mndTransDrop(STrans *pTrans);
|
||||||
|
|
|
@ -537,7 +537,7 @@ static int32_t mndTransActionUpdate(SSdb *pSdb, STrans *pOld, STrans *pNew) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static STrans *mndAcquireTrans(SMnode *pMnode, int32_t transId) {
|
STrans *mndAcquireTrans(SMnode *pMnode, int32_t transId) {
|
||||||
STrans *pTrans = sdbAcquire(pMnode->pSdb, SDB_TRANS, &transId);
|
STrans *pTrans = sdbAcquire(pMnode->pSdb, SDB_TRANS, &transId);
|
||||||
if (pTrans == NULL) {
|
if (pTrans == NULL) {
|
||||||
terrno = TSDB_CODE_MND_TRANS_NOT_EXIST;
|
terrno = TSDB_CODE_MND_TRANS_NOT_EXIST;
|
||||||
|
@ -545,7 +545,7 @@ static STrans *mndAcquireTrans(SMnode *pMnode, int32_t transId) {
|
||||||
return pTrans;
|
return pTrans;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mndReleaseTrans(SMnode *pMnode, STrans *pTrans) {
|
void mndReleaseTrans(SMnode *pMnode, STrans *pTrans) {
|
||||||
SSdb *pSdb = pMnode->pSdb;
|
SSdb *pSdb = pMnode->pSdb;
|
||||||
sdbRelease(pSdb, pTrans);
|
sdbRelease(pSdb, pTrans);
|
||||||
}
|
}
|
||||||
|
@ -710,12 +710,12 @@ static bool mndIsStbTrans(STrans *pTrans) {
|
||||||
return pTrans->type > TRN_TYPE_STB_SCOPE && pTrans->type < TRN_TYPE_STB_SCOPE_END;
|
return pTrans->type > TRN_TYPE_STB_SCOPE && pTrans->type < TRN_TYPE_STB_SCOPE_END;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool mndCheckTransCanParallel(SMnode *pMnode, STrans *pNewTrans) {
|
static bool mndCheckTransConflict(SMnode *pMnode, STrans *pNewTrans) {
|
||||||
STrans *pTrans = NULL;
|
STrans *pTrans = NULL;
|
||||||
void *pIter = NULL;
|
void *pIter = NULL;
|
||||||
bool canParallel = true;
|
bool conflict = false;
|
||||||
|
|
||||||
if (mndIsBasicTrans(pNewTrans)) return canParallel;
|
if (mndIsBasicTrans(pNewTrans)) return conflict;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
pIter = sdbFetch(pMnode->pSdb, SDB_TRANS, pIter, (void **)&pTrans);
|
pIter = sdbFetch(pMnode->pSdb, SDB_TRANS, pIter, (void **)&pTrans);
|
||||||
|
@ -724,7 +724,7 @@ static bool mndCheckTransCanParallel(SMnode *pMnode, STrans *pNewTrans) {
|
||||||
if (mndIsGlobalTrans(pNewTrans)) {
|
if (mndIsGlobalTrans(pNewTrans)) {
|
||||||
if (mndIsDbTrans(pTrans) || mndIsStbTrans(pTrans)) {
|
if (mndIsDbTrans(pTrans) || mndIsStbTrans(pTrans)) {
|
||||||
mError("trans:%d, can't execute since trans:%d in progress db:%s", pNewTrans->id, pTrans->id, pTrans->dbname);
|
mError("trans:%d, can't execute since trans:%d in progress db:%s", pNewTrans->id, pTrans->id, pTrans->dbname);
|
||||||
canParallel = false;
|
conflict = true;
|
||||||
} else {
|
} else {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -732,11 +732,11 @@ static bool mndCheckTransCanParallel(SMnode *pMnode, STrans *pNewTrans) {
|
||||||
else if (mndIsDbTrans(pNewTrans)) {
|
else if (mndIsDbTrans(pNewTrans)) {
|
||||||
if (mndIsGlobalTrans(pTrans)) {
|
if (mndIsGlobalTrans(pTrans)) {
|
||||||
mError("trans:%d, can't execute since trans:%d in progress", pNewTrans->id, pTrans->id);
|
mError("trans:%d, can't execute since trans:%d in progress", pNewTrans->id, pTrans->id);
|
||||||
canParallel = false;
|
conflict = true;
|
||||||
} else if (mndIsDbTrans(pTrans) || mndIsStbTrans(pTrans)) {
|
} else if (mndIsDbTrans(pTrans) || mndIsStbTrans(pTrans)) {
|
||||||
if (pNewTrans->dbUid == pTrans->dbUid) {
|
if (pNewTrans->dbUid == pTrans->dbUid) {
|
||||||
mError("trans:%d, can't execute since trans:%d in progress db:%s", pNewTrans->id, pTrans->id, pTrans->dbname);
|
mError("trans:%d, can't execute since trans:%d in progress db:%s", pNewTrans->id, pTrans->id, pTrans->dbname);
|
||||||
canParallel = false;
|
conflict = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
}
|
}
|
||||||
|
@ -745,11 +745,11 @@ static bool mndCheckTransCanParallel(SMnode *pMnode, STrans *pNewTrans) {
|
||||||
else if (mndIsStbTrans(pNewTrans)) {
|
else if (mndIsStbTrans(pNewTrans)) {
|
||||||
if (mndIsGlobalTrans(pTrans)) {
|
if (mndIsGlobalTrans(pTrans)) {
|
||||||
mError("trans:%d, can't execute since trans:%d in progress", pNewTrans->id, pTrans->id);
|
mError("trans:%d, can't execute since trans:%d in progress", pNewTrans->id, pTrans->id);
|
||||||
canParallel = false;
|
conflict = true;
|
||||||
} else if (mndIsDbTrans(pTrans)) {
|
} else if (mndIsDbTrans(pTrans)) {
|
||||||
if (pNewTrans->dbUid == pTrans->dbUid) {
|
if (pNewTrans->dbUid == pTrans->dbUid) {
|
||||||
mError("trans:%d, can't execute since trans:%d in progress db:%s", pNewTrans->id, pTrans->id, pTrans->dbname);
|
mError("trans:%d, can't execute since trans:%d in progress db:%s", pNewTrans->id, pTrans->id, pTrans->dbname);
|
||||||
canParallel = false;
|
conflict = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
}
|
}
|
||||||
|
@ -760,12 +760,12 @@ static bool mndCheckTransCanParallel(SMnode *pMnode, STrans *pNewTrans) {
|
||||||
|
|
||||||
sdbCancelFetch(pMnode->pSdb, pIter);
|
sdbCancelFetch(pMnode->pSdb, pIter);
|
||||||
sdbRelease(pMnode->pSdb, pTrans);
|
sdbRelease(pMnode->pSdb, pTrans);
|
||||||
return canParallel;
|
return conflict;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t mndTransPrepare(SMnode *pMnode, STrans *pTrans) {
|
int32_t mndTransPrepare(SMnode *pMnode, STrans *pTrans) {
|
||||||
if (!mndCheckTransCanParallel(pMnode, pTrans)) {
|
if (mndCheckTransConflict(pMnode, pTrans)) {
|
||||||
terrno = TSDB_CODE_MND_TRANS_CAN_NOT_PARALLEL;
|
terrno = TSDB_CODE_MND_TRANS_CONFLICT;
|
||||||
mError("trans:%d, failed to prepare since %s", pTrans->id, terrstr());
|
mError("trans:%d, failed to prepare since %s", pTrans->id, terrstr());
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -819,7 +819,8 @@ static int32_t mndTransRollback(SMnode *pMnode, STrans *pTrans) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mndTransSendRpcRsp(SMnode *pMnode, STrans *pTrans) {
|
static void mndTransSendRpcRsp(SMnode *pMnode, STrans *pTrans) {
|
||||||
bool sendRsp = false;
|
bool sendRsp = false;
|
||||||
|
int32_t code = pTrans->code;
|
||||||
|
|
||||||
if (pTrans->stage == TRN_STAGE_FINISHED) {
|
if (pTrans->stage == TRN_STAGE_FINISHED) {
|
||||||
sendRsp = true;
|
sendRsp = true;
|
||||||
|
@ -828,12 +829,12 @@ static void mndTransSendRpcRsp(SMnode *pMnode, STrans *pTrans) {
|
||||||
if (pTrans->policy == TRN_POLICY_ROLLBACK) {
|
if (pTrans->policy == TRN_POLICY_ROLLBACK) {
|
||||||
if (pTrans->stage == TRN_STAGE_UNDO_LOG || pTrans->stage == TRN_STAGE_UNDO_ACTION ||
|
if (pTrans->stage == TRN_STAGE_UNDO_LOG || pTrans->stage == TRN_STAGE_UNDO_ACTION ||
|
||||||
pTrans->stage == TRN_STAGE_ROLLBACK) {
|
pTrans->stage == TRN_STAGE_ROLLBACK) {
|
||||||
|
if (code == 0) code = TSDB_CODE_MND_TRANS_UNKNOW_ERROR;
|
||||||
sendRsp = true;
|
sendRsp = true;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
|
|
||||||
if (pTrans->policy == TRN_POLICY_RETRY) {
|
|
||||||
if (pTrans->stage == TRN_STAGE_REDO_ACTION && pTrans->failedTimes > 0) {
|
if (pTrans->stage == TRN_STAGE_REDO_ACTION && pTrans->failedTimes > 0) {
|
||||||
|
if (code == 0) code = TSDB_CODE_MND_TRANS_UNKNOW_ERROR;
|
||||||
sendRsp = true;
|
sendRsp = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -845,13 +846,13 @@ static void mndTransSendRpcRsp(SMnode *pMnode, STrans *pTrans) {
|
||||||
}
|
}
|
||||||
taosMemoryFree(pTrans->rpcRsp);
|
taosMemoryFree(pTrans->rpcRsp);
|
||||||
|
|
||||||
mDebug("trans:%d, send rsp, code:0x%04x stage:%d app:%p", pTrans->id, pTrans->code & 0xFFFF, pTrans->stage,
|
mDebug("trans:%d, send rsp, code:0x%04x stage:%d app:%p", pTrans->id, code & 0xFFFF, pTrans->stage,
|
||||||
pTrans->rpcAHandle);
|
pTrans->rpcAHandle);
|
||||||
SRpcMsg rspMsg = {
|
SRpcMsg rspMsg = {
|
||||||
.handle = pTrans->rpcHandle,
|
.handle = pTrans->rpcHandle,
|
||||||
.ahandle = pTrans->rpcAHandle,
|
.ahandle = pTrans->rpcAHandle,
|
||||||
.refId = pTrans->rpcRefId,
|
.refId = pTrans->rpcRefId,
|
||||||
.code = pTrans->code,
|
.code = code,
|
||||||
.pCont = rpcCont,
|
.pCont = rpcCont,
|
||||||
.contLen = pTrans->rpcRspLen,
|
.contLen = pTrans->rpcRspLen,
|
||||||
};
|
};
|
||||||
|
@ -918,27 +919,41 @@ static int32_t mndTransExecuteLogs(SMnode *pMnode, SArray *pArray) {
|
||||||
|
|
||||||
if (arraySize == 0) return 0;
|
if (arraySize == 0) return 0;
|
||||||
|
|
||||||
|
int32_t code = 0;
|
||||||
for (int32_t i = 0; i < arraySize; ++i) {
|
for (int32_t i = 0; i < arraySize; ++i) {
|
||||||
SSdbRaw *pRaw = taosArrayGetP(pArray, i);
|
SSdbRaw *pRaw = taosArrayGetP(pArray, i);
|
||||||
int32_t code = sdbWriteWithoutFree(pSdb, pRaw);
|
if (sdbWriteWithoutFree(pSdb, pRaw) != 0) {
|
||||||
if (code != 0) {
|
code = ((terrno != 0) ? terrno : -1);
|
||||||
return code;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
terrno = code;
|
||||||
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t mndTransExecuteRedoLogs(SMnode *pMnode, STrans *pTrans) {
|
static int32_t mndTransExecuteRedoLogs(SMnode *pMnode, STrans *pTrans) {
|
||||||
return mndTransExecuteLogs(pMnode, pTrans->redoLogs);
|
int32_t code = mndTransExecuteLogs(pMnode, pTrans->redoLogs);
|
||||||
|
if (code != 0) {
|
||||||
|
mError("failed to execute redoLogs since %s", terrstr());
|
||||||
|
}
|
||||||
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t mndTransExecuteUndoLogs(SMnode *pMnode, STrans *pTrans) {
|
static int32_t mndTransExecuteUndoLogs(SMnode *pMnode, STrans *pTrans) {
|
||||||
return mndTransExecuteLogs(pMnode, pTrans->undoLogs);
|
int32_t code = mndTransExecuteLogs(pMnode, pTrans->undoLogs);
|
||||||
|
if (code != 0) {
|
||||||
|
mError("failed to execute undoLogs since %s, return success", terrstr());
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0; // return success in any case
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t mndTransExecuteCommitLogs(SMnode *pMnode, STrans *pTrans) {
|
static int32_t mndTransExecuteCommitLogs(SMnode *pMnode, STrans *pTrans) {
|
||||||
return mndTransExecuteLogs(pMnode, pTrans->commitLogs);
|
int32_t code = mndTransExecuteLogs(pMnode, pTrans->commitLogs);
|
||||||
|
if (code != 0) {
|
||||||
|
mError("failed to execute commitLogs since %s", terrstr());
|
||||||
|
}
|
||||||
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mndTransResetActions(SMnode *pMnode, STrans *pTrans, SArray *pArray) {
|
static void mndTransResetActions(SMnode *pMnode, STrans *pTrans, SArray *pArray) {
|
||||||
|
@ -982,6 +997,7 @@ static int32_t mndTransSendActionMsg(SMnode *pMnode, STrans *pTrans, SArray *pAr
|
||||||
pAction->msgReceived = 0;
|
pAction->msgReceived = 0;
|
||||||
pAction->errCode = 0;
|
pAction->errCode = 0;
|
||||||
} else {
|
} else {
|
||||||
|
if (terrno == TSDB_CODE_INVALID_PTR) rpcFreeCont(rpcMsg.pCont);
|
||||||
mError("trans:%d, action:%d not send since %s", pTrans->id, action, terrstr());
|
mError("trans:%d, action:%d not send since %s", pTrans->id, action, terrstr());
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -1028,11 +1044,19 @@ static int32_t mndTransExecuteActions(SMnode *pMnode, STrans *pTrans, SArray *pA
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t mndTransExecuteRedoActions(SMnode *pMnode, STrans *pTrans) {
|
static int32_t mndTransExecuteRedoActions(SMnode *pMnode, STrans *pTrans) {
|
||||||
return mndTransExecuteActions(pMnode, pTrans, pTrans->redoActions);
|
int32_t code = mndTransExecuteActions(pMnode, pTrans, pTrans->redoActions);
|
||||||
|
if (code != 0) {
|
||||||
|
mError("failed to execute redoActions since %s", terrstr());
|
||||||
|
}
|
||||||
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t mndTransExecuteUndoActions(SMnode *pMnode, STrans *pTrans) {
|
static int32_t mndTransExecuteUndoActions(SMnode *pMnode, STrans *pTrans) {
|
||||||
return mndTransExecuteActions(pMnode, pTrans, pTrans->undoActions);
|
int32_t code = mndTransExecuteActions(pMnode, pTrans, pTrans->undoActions);
|
||||||
|
if (code != 0) {
|
||||||
|
mError("failed to execute undoActions since %s", terrstr());
|
||||||
|
}
|
||||||
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool mndTransPerformPrepareStage(SMnode *pMnode, STrans *pTrans) {
|
static bool mndTransPerformPrepareStage(SMnode *pMnode, STrans *pTrans) {
|
||||||
|
@ -1099,8 +1123,8 @@ static bool mndTransPerformCommitStage(SMnode *pMnode, STrans *pTrans) {
|
||||||
} else {
|
} else {
|
||||||
pTrans->code = terrno;
|
pTrans->code = terrno;
|
||||||
if (pTrans->policy == TRN_POLICY_ROLLBACK) {
|
if (pTrans->policy == TRN_POLICY_ROLLBACK) {
|
||||||
pTrans->stage = TRN_STAGE_REDO_ACTION;
|
pTrans->stage = TRN_STAGE_UNDO_ACTION;
|
||||||
mError("trans:%d, stage from commit to redoAction since %s, failedTimes:%d", pTrans->id, terrstr(),
|
mError("trans:%d, stage from commit to undoAction since %s, failedTimes:%d", pTrans->id, terrstr(),
|
||||||
pTrans->failedTimes);
|
pTrans->failedTimes);
|
||||||
continueExec = true;
|
continueExec = true;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1125,7 +1149,7 @@ static bool mndTransPerformCommitLogStage(SMnode *pMnode, STrans *pTrans) {
|
||||||
} else {
|
} else {
|
||||||
pTrans->code = terrno;
|
pTrans->code = terrno;
|
||||||
pTrans->failedTimes++;
|
pTrans->failedTimes++;
|
||||||
mError("trans:%d, stage keep on commitLog since %s", pTrans->id, terrstr());
|
mError("trans:%d, stage keep on commitLog since %s, failedTimes:%d", pTrans->id, terrstr(), pTrans->failedTimes);
|
||||||
continueExec = false;
|
continueExec = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1161,7 +1185,7 @@ static bool mndTransPerformUndoActionStage(SMnode *pMnode, STrans *pTrans) {
|
||||||
continueExec = false;
|
continueExec = false;
|
||||||
} else {
|
} else {
|
||||||
pTrans->failedTimes++;
|
pTrans->failedTimes++;
|
||||||
mError("trans:%d, stage keep on undoAction since %s", pTrans->id, terrstr());
|
mError("trans:%d, stage keep on undoAction since %s, failedTimes:%d", pTrans->id, terrstr(), pTrans->failedTimes);
|
||||||
continueExec = false;
|
continueExec = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1178,7 +1202,7 @@ static bool mndTransPerformRollbackStage(SMnode *pMnode, STrans *pTrans) {
|
||||||
continueExec = true;
|
continueExec = true;
|
||||||
} else {
|
} else {
|
||||||
pTrans->failedTimes++;
|
pTrans->failedTimes++;
|
||||||
mError("trans:%d, stage keep on rollback since %s", pTrans->id, terrstr());
|
mError("trans:%d, stage keep on rollback since %s, failedTimes:%d", pTrans->id, terrstr(), pTrans->failedTimes);
|
||||||
continueExec = false;
|
continueExec = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -275,9 +275,6 @@ static int32_t mndCreateUser(SMnode *pMnode, char *acct, SCreateUserReq *pCreate
|
||||||
}
|
}
|
||||||
sdbSetRawStatus(pRedoRaw, SDB_STATUS_READY);
|
sdbSetRawStatus(pRedoRaw, SDB_STATUS_READY);
|
||||||
|
|
||||||
char *param = strdup("====> test code to be deleted later <=====");
|
|
||||||
mndTransSetCb(pTrans, TEST_TRANS_START_FUNC, TEST_TRANS_STOP_FUNC, param, strlen(param) + 1);
|
|
||||||
|
|
||||||
if (mndTransPrepare(pMnode, pTrans) != 0) {
|
if (mndTransPrepare(pMnode, pTrans) != 0) {
|
||||||
mError("trans:%d, failed to prepare since %s", pTrans->id, terrstr());
|
mError("trans:%d, failed to prepare since %s", pTrans->id, terrstr());
|
||||||
mndTransDrop(pTrans);
|
mndTransDrop(pTrans);
|
||||||
|
|
|
@ -43,9 +43,6 @@
|
||||||
#include "mndUser.h"
|
#include "mndUser.h"
|
||||||
#include "mndVgroup.h"
|
#include "mndVgroup.h"
|
||||||
|
|
||||||
#define MQ_TIMER_MS 2000
|
|
||||||
#define TRNAS_TIMER_MS 6000
|
|
||||||
|
|
||||||
static void *mndBuildTimerMsg(int32_t *pContLen) {
|
static void *mndBuildTimerMsg(int32_t *pContLen) {
|
||||||
SMTimerReq timerReq = {0};
|
SMTimerReq timerReq = {0};
|
||||||
|
|
||||||
|
@ -68,7 +65,7 @@ static void mndPullupTrans(void *param, void *tmrId) {
|
||||||
tmsgPutToQueue(&pMnode->msgCb, WRITE_QUEUE, &rpcMsg);
|
tmsgPutToQueue(&pMnode->msgCb, WRITE_QUEUE, &rpcMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
taosTmrReset(mndPullupTrans, TRNAS_TIMER_MS, pMnode, pMnode->timer, &pMnode->transTimer);
|
taosTmrReset(mndPullupTrans, tsTransPullupMs, pMnode, pMnode->timer, &pMnode->transTimer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mndCalMqRebalance(void *param, void *tmrId) {
|
static void mndCalMqRebalance(void *param, void *tmrId) {
|
||||||
|
@ -84,7 +81,7 @@ static void mndCalMqRebalance(void *param, void *tmrId) {
|
||||||
tmsgPutToQueue(&pMnode->msgCb, READ_QUEUE, &rpcMsg);
|
tmsgPutToQueue(&pMnode->msgCb, READ_QUEUE, &rpcMsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
taosTmrReset(mndCalMqRebalance, MQ_TIMER_MS, pMnode, pMnode->timer, &pMnode->mqTimer);
|
taosTmrReset(mndCalMqRebalance, tsMaRebalanceMs, pMnode, pMnode->timer, &pMnode->mqTimer);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mndPullupTelem(void *param, void *tmrId) {
|
static void mndPullupTelem(void *param, void *tmrId) {
|
||||||
|
@ -106,12 +103,12 @@ static int32_t mndInitTimer(SMnode *pMnode) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (taosTmrReset(mndPullupTrans, TRNAS_TIMER_MS, pMnode, pMnode->timer, &pMnode->transTimer)) {
|
if (taosTmrReset(mndPullupTrans, tsTransPullupMs, pMnode, pMnode->timer, &pMnode->transTimer)) {
|
||||||
terrno = TSDB_CODE_OUT_OF_MEMORY;
|
terrno = TSDB_CODE_OUT_OF_MEMORY;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (taosTmrReset(mndCalMqRebalance, MQ_TIMER_MS, pMnode, pMnode->timer, &pMnode->mqTimer)) {
|
if (taosTmrReset(mndCalMqRebalance, tsMaRebalanceMs, pMnode, pMnode->timer, &pMnode->mqTimer)) {
|
||||||
terrno = TSDB_CODE_OUT_OF_MEMORY;
|
terrno = TSDB_CODE_OUT_OF_MEMORY;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ void reportStartup(SMgmtWrapper *pWrapper, const char *name, const char *desc) {
|
||||||
|
|
||||||
class MndTestTrans2 : public ::testing::Test {
|
class MndTestTrans2 : public ::testing::Test {
|
||||||
protected:
|
protected:
|
||||||
static void SetUpTestSuite() {
|
static void InitLog() {
|
||||||
dDebugFlag = 143;
|
dDebugFlag = 143;
|
||||||
vDebugFlag = 0;
|
vDebugFlag = 0;
|
||||||
mDebugFlag = 207;
|
mDebugFlag = 207;
|
||||||
|
@ -42,9 +42,9 @@ class MndTestTrans2 : public ::testing::Test {
|
||||||
if (taosInitLog("taosdlog", 1) != 0) {
|
if (taosInitLog("taosdlog", 1) != 0) {
|
||||||
printf("failed to init log file\n");
|
printf("failed to init log file\n");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
walInit();
|
static void InitMnode() {
|
||||||
|
|
||||||
static SMsgCb msgCb = {0};
|
static SMsgCb msgCb = {0};
|
||||||
msgCb.reportStartupFp = reportStartup;
|
msgCb.reportStartupFp = reportStartup;
|
||||||
msgCb.pWrapper = (SMgmtWrapper *)(&msgCb); // hack
|
msgCb.pWrapper = (SMgmtWrapper *)(&msgCb); // hack
|
||||||
|
@ -58,12 +58,22 @@ class MndTestTrans2 : public ::testing::Test {
|
||||||
strcpy(opt.replicas[0].fqdn, "localhost");
|
strcpy(opt.replicas[0].fqdn, "localhost");
|
||||||
opt.msgCb = msgCb;
|
opt.msgCb = msgCb;
|
||||||
|
|
||||||
|
tsTransPullupMs = 1000;
|
||||||
|
|
||||||
const char *mnodepath = "/tmp/mnode_test_trans";
|
const char *mnodepath = "/tmp/mnode_test_trans";
|
||||||
taosRemoveDir(mnodepath);
|
taosRemoveDir(mnodepath);
|
||||||
pMnode = mndOpen(mnodepath, &opt);
|
pMnode = mndOpen(mnodepath, &opt);
|
||||||
|
mndStart(pMnode);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void SetUpTestSuite() {
|
||||||
|
InitLog();
|
||||||
|
walInit();
|
||||||
|
InitMnode();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void TearDownTestSuite() {
|
static void TearDownTestSuite() {
|
||||||
|
mndStop(pMnode);
|
||||||
mndClose(pMnode);
|
mndClose(pMnode);
|
||||||
walCleanUp();
|
walCleanUp();
|
||||||
taosCloseLog();
|
taosCloseLog();
|
||||||
|
@ -76,11 +86,11 @@ class MndTestTrans2 : public ::testing::Test {
|
||||||
void SetUp() override {}
|
void SetUp() override {}
|
||||||
void TearDown() override {}
|
void TearDown() override {}
|
||||||
|
|
||||||
void CreateUser(const char *user) {
|
int32_t CreateUserLog(const char *acct, const char *user) {
|
||||||
SUserObj userObj = {0};
|
SUserObj userObj = {0};
|
||||||
taosEncryptPass_c((uint8_t *)"taosdata", strlen("taosdata"), userObj.pass);
|
taosEncryptPass_c((uint8_t *)"taosdata", strlen("taosdata"), userObj.pass);
|
||||||
tstrncpy(userObj.user, user, TSDB_USER_LEN);
|
tstrncpy(userObj.user, user, TSDB_USER_LEN);
|
||||||
tstrncpy(userObj.acct, "root", TSDB_USER_LEN);
|
tstrncpy(userObj.acct, acct, TSDB_USER_LEN);
|
||||||
userObj.createdTime = taosGetTimestampMs();
|
userObj.createdTime = taosGetTimestampMs();
|
||||||
userObj.updateTime = userObj.createdTime;
|
userObj.updateTime = userObj.createdTime;
|
||||||
userObj.superUser = 1;
|
userObj.superUser = 1;
|
||||||
|
@ -91,22 +101,208 @@ class MndTestTrans2 : public ::testing::Test {
|
||||||
mndTransAppendRedolog(pTrans, pRedoRaw);
|
mndTransAppendRedolog(pTrans, pRedoRaw);
|
||||||
sdbSetRawStatus(pRedoRaw, SDB_STATUS_READY);
|
sdbSetRawStatus(pRedoRaw, SDB_STATUS_READY);
|
||||||
|
|
||||||
char *param = strdup("====> test param <=====");
|
SSdbRaw *pUndoRaw = mndUserActionEncode(&userObj);
|
||||||
|
mndTransAppendUndolog(pTrans, pUndoRaw);
|
||||||
|
sdbSetRawStatus(pUndoRaw, SDB_STATUS_DROPPED);
|
||||||
|
|
||||||
|
char *param = strdup("====> test log <=====");
|
||||||
mndTransSetCb(pTrans, TEST_TRANS_START_FUNC, TEST_TRANS_STOP_FUNC, param, strlen(param) + 1);
|
mndTransSetCb(pTrans, TEST_TRANS_START_FUNC, TEST_TRANS_STOP_FUNC, param, strlen(param) + 1);
|
||||||
|
|
||||||
mndTransPrepare(pMnode, pTrans);
|
int32_t code = mndTransPrepare(pMnode, pTrans);
|
||||||
mndTransDrop(pTrans);
|
mndTransDrop(pTrans);
|
||||||
|
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t CreateUserAction(const char *acct, const char *user, bool hasUndoAction, ETrnPolicy policy) {
|
||||||
|
SUserObj userObj = {0};
|
||||||
|
taosEncryptPass_c((uint8_t *)"taosdata", strlen("taosdata"), userObj.pass);
|
||||||
|
tstrncpy(userObj.user, user, TSDB_USER_LEN);
|
||||||
|
tstrncpy(userObj.acct, acct, TSDB_USER_LEN);
|
||||||
|
userObj.createdTime = taosGetTimestampMs();
|
||||||
|
userObj.updateTime = userObj.createdTime;
|
||||||
|
userObj.superUser = 1;
|
||||||
|
|
||||||
|
SRpcMsg rpcMsg = {0};
|
||||||
|
STrans *pTrans = mndTransCreate(pMnode, policy, TRN_TYPE_CREATE_USER, &rpcMsg);
|
||||||
|
SSdbRaw *pRedoRaw = mndUserActionEncode(&userObj);
|
||||||
|
mndTransAppendRedolog(pTrans, pRedoRaw);
|
||||||
|
sdbSetRawStatus(pRedoRaw, SDB_STATUS_READY);
|
||||||
|
|
||||||
|
SSdbRaw *pUndoRaw = mndUserActionEncode(&userObj);
|
||||||
|
mndTransAppendUndolog(pTrans, pUndoRaw);
|
||||||
|
sdbSetRawStatus(pUndoRaw, SDB_STATUS_DROPPED);
|
||||||
|
|
||||||
|
char *param = strdup("====> test action <=====");
|
||||||
|
mndTransSetCb(pTrans, TEST_TRANS_START_FUNC, TEST_TRANS_STOP_FUNC, param, strlen(param) + 1);
|
||||||
|
|
||||||
|
{
|
||||||
|
STransAction action = {0};
|
||||||
|
action.epSet.inUse = 0;
|
||||||
|
action.epSet.numOfEps = 1;
|
||||||
|
action.epSet.eps[0].port = 9040;
|
||||||
|
strcpy(action.epSet.eps[0].fqdn, "localhost");
|
||||||
|
|
||||||
|
int32_t contLen = 1024;
|
||||||
|
void *pReq = taosMemoryCalloc(1, contLen);
|
||||||
|
strcpy((char *)pReq, "hello world redo");
|
||||||
|
action.pCont = pReq;
|
||||||
|
action.contLen = contLen;
|
||||||
|
action.msgType = TDMT_DND_CREATE_MNODE;
|
||||||
|
action.acceptableCode = TSDB_CODE_NODE_ALREADY_DEPLOYED;
|
||||||
|
mndTransAppendRedoAction(pTrans, &action);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasUndoAction) {
|
||||||
|
STransAction action = {0};
|
||||||
|
action.epSet.inUse = 0;
|
||||||
|
action.epSet.numOfEps = 1;
|
||||||
|
action.epSet.eps[0].port = 9040;
|
||||||
|
strcpy(action.epSet.eps[0].fqdn, "localhost");
|
||||||
|
|
||||||
|
int32_t contLen = 1024;
|
||||||
|
void *pReq = taosMemoryCalloc(1, contLen);
|
||||||
|
strcpy((char *)pReq, "hello world undo");
|
||||||
|
action.pCont = pReq;
|
||||||
|
action.contLen = contLen;
|
||||||
|
action.msgType = TDMT_DND_CREATE_MNODE;
|
||||||
|
action.acceptableCode = TSDB_CODE_NODE_ALREADY_DEPLOYED;
|
||||||
|
mndTransAppendUndoAction(pTrans, &action);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t code = mndTransPrepare(pMnode, pTrans);
|
||||||
|
mndTransDrop(pTrans);
|
||||||
|
|
||||||
|
return code;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
SMnode *MndTestTrans2::pMnode;
|
SMnode *MndTestTrans2::pMnode;
|
||||||
|
|
||||||
TEST_F(MndTestTrans2, 01_CbFunc) {
|
TEST_F(MndTestTrans2, 01_Log) {
|
||||||
|
const char *acct = "root";
|
||||||
|
const char *acct_invalid = "root1";
|
||||||
|
const char *user1 = "log1";
|
||||||
|
const char *user2 = "log2";
|
||||||
|
SUserObj *pUser1 = NULL;
|
||||||
|
SUserObj *pUser2 = NULL;
|
||||||
|
|
||||||
ASSERT_NE(pMnode, nullptr);
|
ASSERT_NE(pMnode, nullptr);
|
||||||
|
|
||||||
const char *user1 = "test1";
|
EXPECT_EQ(CreateUserLog(acct, user1), 0);
|
||||||
CreateUser(user1);
|
pUser1 = mndAcquireUser(pMnode, user1);
|
||||||
|
|
||||||
SUserObj *pUser1 = mndAcquireUser(pMnode, user1);
|
|
||||||
ASSERT_NE(pUser1, nullptr);
|
ASSERT_NE(pUser1, nullptr);
|
||||||
|
|
||||||
|
// failed to create user and rollback
|
||||||
|
EXPECT_EQ(CreateUserLog(acct_invalid, user2), 0);
|
||||||
|
pUser2 = mndAcquireUser(pMnode, user2);
|
||||||
|
ASSERT_EQ(pUser2, nullptr);
|
||||||
|
|
||||||
|
mndTransPullup(pMnode);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(MndTestTrans2, 02_Action) {
|
||||||
|
const char *acct = "root";
|
||||||
|
const char *acct_invalid = "root1";
|
||||||
|
const char *user1 = "action1";
|
||||||
|
const char *user2 = "action2";
|
||||||
|
SUserObj *pUser1 = NULL;
|
||||||
|
SUserObj *pUser2 = NULL;
|
||||||
|
STrans *pTrans = NULL;
|
||||||
|
int32_t transId = 0;
|
||||||
|
int32_t action = 0;
|
||||||
|
|
||||||
|
ASSERT_NE(pMnode, nullptr);
|
||||||
|
|
||||||
|
// failed to create user and rollback
|
||||||
|
EXPECT_EQ(CreateUserAction(acct, user1, false, TRN_POLICY_ROLLBACK), 0);
|
||||||
|
pUser1 = mndAcquireUser(pMnode, user1);
|
||||||
|
ASSERT_EQ(pUser1, nullptr);
|
||||||
|
mndReleaseUser(pMnode, pUser1);
|
||||||
|
|
||||||
|
// create user, and fake a response
|
||||||
|
{
|
||||||
|
EXPECT_EQ(CreateUserAction(acct, user1, true, TRN_POLICY_ROLLBACK), 0);
|
||||||
|
pUser1 = mndAcquireUser(pMnode, user1);
|
||||||
|
ASSERT_NE(pUser1, nullptr);
|
||||||
|
mndReleaseUser(pMnode, pUser1);
|
||||||
|
|
||||||
|
transId = 4;
|
||||||
|
pTrans = mndAcquireTrans(pMnode, transId);
|
||||||
|
EXPECT_EQ(pTrans->code, TSDB_CODE_INVALID_PTR);
|
||||||
|
EXPECT_EQ(pTrans->stage, TRN_STAGE_UNDO_ACTION);
|
||||||
|
EXPECT_EQ(pTrans->failedTimes, 1);
|
||||||
|
|
||||||
|
STransAction *pAction = (STransAction *)taosArrayGet(pTrans->undoActions, action);
|
||||||
|
pAction->msgSent = 1;
|
||||||
|
|
||||||
|
SNodeMsg rspMsg = {0};
|
||||||
|
rspMsg.pNode = pMnode;
|
||||||
|
int64_t signature = transId;
|
||||||
|
signature = (signature << 32);
|
||||||
|
signature += action;
|
||||||
|
rspMsg.rpcMsg.ahandle = (void *)signature;
|
||||||
|
mndTransProcessRsp(&rspMsg);
|
||||||
|
mndReleaseTrans(pMnode, pTrans);
|
||||||
|
|
||||||
|
pUser1 = mndAcquireUser(pMnode, user1);
|
||||||
|
ASSERT_EQ(pUser1, nullptr);
|
||||||
|
mndReleaseUser(pMnode, pUser1);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
EXPECT_EQ(CreateUserAction(acct, user1, false, TRN_POLICY_RETRY), 0);
|
||||||
|
pUser1 = mndAcquireUser(pMnode, user1);
|
||||||
|
ASSERT_NE(pUser1, nullptr);
|
||||||
|
mndReleaseUser(pMnode, pUser1);
|
||||||
|
|
||||||
|
{
|
||||||
|
transId = 5;
|
||||||
|
pTrans = mndAcquireTrans(pMnode, transId);
|
||||||
|
EXPECT_EQ(pTrans->code, TSDB_CODE_INVALID_PTR);
|
||||||
|
EXPECT_EQ(pTrans->stage, TRN_STAGE_REDO_ACTION);
|
||||||
|
EXPECT_EQ(pTrans->failedTimes, 1);
|
||||||
|
|
||||||
|
STransAction *pAction = (STransAction *)taosArrayGet(pTrans->redoActions, action);
|
||||||
|
pAction->msgSent = 1;
|
||||||
|
|
||||||
|
SNodeMsg rspMsg = {0};
|
||||||
|
rspMsg.pNode = pMnode;
|
||||||
|
int64_t signature = transId;
|
||||||
|
signature = (signature << 32);
|
||||||
|
signature += action;
|
||||||
|
rspMsg.rpcMsg.ahandle = (void *)signature;
|
||||||
|
rspMsg.rpcMsg.code = TSDB_CODE_RPC_NETWORK_UNAVAIL;
|
||||||
|
mndTransProcessRsp(&rspMsg);
|
||||||
|
mndReleaseTrans(pMnode, pTrans);
|
||||||
|
|
||||||
|
pUser1 = mndAcquireUser(pMnode, user1);
|
||||||
|
ASSERT_NE(pUser1, nullptr);
|
||||||
|
mndReleaseUser(pMnode, pUser1);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
transId = 5;
|
||||||
|
pTrans = mndAcquireTrans(pMnode, transId);
|
||||||
|
EXPECT_EQ(pTrans->code, TSDB_CODE_RPC_NETWORK_UNAVAIL);
|
||||||
|
EXPECT_EQ(pTrans->stage, TRN_STAGE_REDO_ACTION);
|
||||||
|
EXPECT_EQ(pTrans->failedTimes, 2);
|
||||||
|
|
||||||
|
STransAction *pAction = (STransAction *)taosArrayGet(pTrans->redoActions, action);
|
||||||
|
pAction->msgSent = 1;
|
||||||
|
|
||||||
|
SNodeMsg rspMsg = {0};
|
||||||
|
rspMsg.pNode = pMnode;
|
||||||
|
int64_t signature = transId;
|
||||||
|
signature = (signature << 32);
|
||||||
|
signature += action;
|
||||||
|
rspMsg.rpcMsg.ahandle = (void *)signature;
|
||||||
|
mndTransProcessRsp(&rspMsg);
|
||||||
|
mndReleaseTrans(pMnode, pTrans);
|
||||||
|
|
||||||
|
pUser1 = mndAcquireUser(pMnode, user1);
|
||||||
|
ASSERT_NE(pUser1, nullptr);
|
||||||
|
mndReleaseUser(pMnode, pUser1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,8 +103,6 @@ typedef struct {
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
|
|
||||||
// int metaCreateTable(SMeta* pMeta, STbCfg* pTbCfg, STbDdlH* pHandle);
|
|
||||||
int metaDropTable(SMeta* pMeta, tb_uid_t uid);
|
|
||||||
SMSmaCursor* metaOpenSmaCursor(SMeta* pMeta, tb_uid_t uid);
|
SMSmaCursor* metaOpenSmaCursor(SMeta* pMeta, tb_uid_t uid);
|
||||||
void metaCloseSmaCursor(SMSmaCursor* pSmaCur);
|
void metaCloseSmaCursor(SMSmaCursor* pSmaCur);
|
||||||
int64_t metaSmaCursorNext(SMSmaCursor* pSmaCur);
|
int64_t metaSmaCursorNext(SMSmaCursor* pSmaCur);
|
||||||
|
|
|
@ -46,13 +46,13 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct SVnodeInfo SVnodeInfo;
|
typedef struct SVnodeInfo SVnodeInfo;
|
||||||
typedef struct SMeta SMeta;
|
typedef struct SMeta SMeta;
|
||||||
typedef struct STsdb STsdb;
|
typedef struct STsdb STsdb;
|
||||||
typedef struct STQ STQ;
|
typedef struct STQ STQ;
|
||||||
typedef struct SVState SVState;
|
typedef struct SVState SVState;
|
||||||
typedef struct SVBufPool SVBufPool;
|
typedef struct SVBufPool SVBufPool;
|
||||||
typedef struct SQWorker SQHandle;
|
typedef struct SQWorker SQHandle;
|
||||||
|
|
||||||
#define VNODE_META_DIR "meta"
|
#define VNODE_META_DIR "meta"
|
||||||
#define VNODE_TSDB_DIR "tsdb"
|
#define VNODE_TSDB_DIR "tsdb"
|
||||||
|
@ -77,6 +77,7 @@ int metaCommit(SMeta* pMeta);
|
||||||
int metaCreateSTable(SMeta* pMeta, int64_t version, SVCreateStbReq* pReq);
|
int metaCreateSTable(SMeta* pMeta, int64_t version, SVCreateStbReq* pReq);
|
||||||
int metaDropSTable(SMeta* pMeta, int64_t verison, SVDropStbReq* pReq);
|
int metaDropSTable(SMeta* pMeta, int64_t verison, SVDropStbReq* pReq);
|
||||||
int metaCreateTable(SMeta* pMeta, int64_t version, SVCreateTbReq* pReq);
|
int metaCreateTable(SMeta* pMeta, int64_t version, SVCreateTbReq* pReq);
|
||||||
|
int metaDropTable(SMeta* pMeta, int64_t version, SVDropTbReq* pReq);
|
||||||
SSchemaWrapper* metaGetTableSchema(SMeta* pMeta, tb_uid_t uid, int32_t sver, bool isinline);
|
SSchemaWrapper* metaGetTableSchema(SMeta* pMeta, tb_uid_t uid, int32_t sver, bool isinline);
|
||||||
STSchema* metaGetTbTSchema(SMeta* pMeta, tb_uid_t uid, int32_t sver);
|
STSchema* metaGetTbTSchema(SMeta* pMeta, tb_uid_t uid, int32_t sver);
|
||||||
int metaGetTableEntryByName(SMetaReader* pReader, const char* name);
|
int metaGetTableEntryByName(SMetaReader* pReader, const char* name);
|
||||||
|
@ -100,7 +101,7 @@ int32_t tsdbCreateTSma(STsdb* pTsdb, char* pMsg);
|
||||||
int32_t tsdbInsertTSmaData(STsdb* pTsdb, int64_t indexUid, const char* msg);
|
int32_t tsdbInsertTSmaData(STsdb* pTsdb, int64_t indexUid, const char* msg);
|
||||||
int tsdbInsertData(STsdb* pTsdb, int64_t version, SSubmitReq* pMsg, SSubmitRsp* pRsp);
|
int tsdbInsertData(STsdb* pTsdb, int64_t version, SSubmitReq* pMsg, SSubmitRsp* pRsp);
|
||||||
tsdbReaderT* tsdbQueryTables(SVnode* pVnode, SQueryTableDataCond* pCond, STableGroupInfo* groupList, uint64_t qId,
|
tsdbReaderT* tsdbQueryTables(SVnode* pVnode, SQueryTableDataCond* pCond, STableGroupInfo* groupList, uint64_t qId,
|
||||||
uint64_t taskId);
|
uint64_t taskId);
|
||||||
tsdbReaderT tsdbQueryCacheLastT(STsdb* tsdb, SQueryTableDataCond* pCond, STableGroupInfo* groupList, uint64_t qId,
|
tsdbReaderT tsdbQueryCacheLastT(STsdb* tsdb, SQueryTableDataCond* pCond, STableGroupInfo* groupList, uint64_t qId,
|
||||||
void* pMemRef);
|
void* pMemRef);
|
||||||
int32_t tsdbGetTableGroupFromIdListT(STsdb* tsdb, SArray* pTableIdList, STableGroupInfo* pGroupInfo);
|
int32_t tsdbGetTableGroupFromIdListT(STsdb* tsdb, SArray* pTableIdList, STableGroupInfo* pGroupInfo);
|
||||||
|
@ -189,7 +190,6 @@ struct STbUidStore {
|
||||||
|
|
||||||
#define TD_VID(PVNODE) (PVNODE)->config.vgId
|
#define TD_VID(PVNODE) (PVNODE)->config.vgId
|
||||||
|
|
||||||
|
|
||||||
static FORCE_INLINE bool vnodeIsRollup(SVnode* pVnode) {
|
static FORCE_INLINE bool vnodeIsRollup(SVnode* pVnode) {
|
||||||
SRetention* pRetention = &(pVnode->config.tsdbCfg.retentions[0]);
|
SRetention* pRetention = &(pVnode->config.tsdbCfg.retentions[0]);
|
||||||
return (pRetention->freq > 0 && pRetention->keep > 0);
|
return (pRetention->freq > 0 && pRetention->keep > 0);
|
||||||
|
|
|
@ -289,7 +289,7 @@ int metaSaveTableToDB(SMeta *pMeta, STbCfg *pTbCfg, STbDdlH *pHandle) {
|
||||||
pVal = pBuf = buf;
|
pVal = pBuf = buf;
|
||||||
metaEncodeTbInfo(&pBuf, pTbCfg);
|
metaEncodeTbInfo(&pBuf, pTbCfg);
|
||||||
vLen = POINTER_DISTANCE(pBuf, buf);
|
vLen = POINTER_DISTANCE(pBuf, buf);
|
||||||
ret = tdbDbPut(pMetaDb->pTbDB, pKey, kLen, pVal, vLen, &pMetaDb->txn);
|
ret = tdbDbInsert(pMetaDb->pTbDB, pKey, kLen, pVal, vLen, &pMetaDb->txn);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -311,7 +311,7 @@ int metaSaveTableToDB(SMeta *pMeta, STbCfg *pTbCfg, STbDdlH *pHandle) {
|
||||||
pVal = pBuf = buf;
|
pVal = pBuf = buf;
|
||||||
metaEncodeSchemaEx(&pBuf, &schemaWrapper);
|
metaEncodeSchemaEx(&pBuf, &schemaWrapper);
|
||||||
vLen = POINTER_DISTANCE(pBuf, buf);
|
vLen = POINTER_DISTANCE(pBuf, buf);
|
||||||
ret = tdbDbPut(pMetaDb->pSchemaDB, pKey, kLen, pVal, vLen, &pMeta->pDB->txn);
|
ret = tdbDbInsert(pMetaDb->pSchemaDB, pKey, kLen, pVal, vLen, &pMeta->pDB->txn);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -325,7 +325,7 @@ int metaSaveTableToDB(SMeta *pMeta, STbCfg *pTbCfg, STbDdlH *pHandle) {
|
||||||
kLen = nameLen + 1 + sizeof(uid);
|
kLen = nameLen + 1 + sizeof(uid);
|
||||||
pVal = NULL;
|
pVal = NULL;
|
||||||
vLen = 0;
|
vLen = 0;
|
||||||
ret = tdbDbPut(pMetaDb->pNameIdx, pKey, kLen, pVal, vLen, &pMetaDb->txn);
|
ret = tdbDbInsert(pMetaDb->pNameIdx, pKey, kLen, pVal, vLen, &pMetaDb->txn);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -336,7 +336,7 @@ int metaSaveTableToDB(SMeta *pMeta, STbCfg *pTbCfg, STbDdlH *pHandle) {
|
||||||
kLen = sizeof(uid);
|
kLen = sizeof(uid);
|
||||||
pVal = NULL;
|
pVal = NULL;
|
||||||
vLen = 0;
|
vLen = 0;
|
||||||
ret = tdbDbPut(pMetaDb->pStbIdx, pKey, kLen, pVal, vLen, &pMetaDb->txn);
|
ret = tdbDbInsert(pMetaDb->pStbIdx, pKey, kLen, pVal, vLen, &pMetaDb->txn);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -347,7 +347,7 @@ int metaSaveTableToDB(SMeta *pMeta, STbCfg *pTbCfg, STbDdlH *pHandle) {
|
||||||
kLen = sizeof(ctbIdxKey);
|
kLen = sizeof(ctbIdxKey);
|
||||||
pVal = NULL;
|
pVal = NULL;
|
||||||
vLen = 0;
|
vLen = 0;
|
||||||
ret = tdbDbPut(pMetaDb->pCtbIdx, pKey, kLen, pVal, vLen, &pMetaDb->txn);
|
ret = tdbDbInsert(pMetaDb->pCtbIdx, pKey, kLen, pVal, vLen, &pMetaDb->txn);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -362,7 +362,7 @@ int metaSaveTableToDB(SMeta *pMeta, STbCfg *pTbCfg, STbDdlH *pHandle) {
|
||||||
kLen = sizeof(uid);
|
kLen = sizeof(uid);
|
||||||
pVal = NULL;
|
pVal = NULL;
|
||||||
vLen = 0;
|
vLen = 0;
|
||||||
ret = tdbDbPut(pMetaDb->pNtbIdx, pKey, kLen, pVal, vLen, &pMetaDb->txn);
|
ret = tdbDbInsert(pMetaDb->pNtbIdx, pKey, kLen, pVal, vLen, &pMetaDb->txn);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -530,7 +530,7 @@ int metaSaveSmaToDB(SMeta *pMeta, STSma *pSmaCfg) {
|
||||||
int32_t kLen = sizeof(pSmaCfg->indexUid);
|
int32_t kLen = sizeof(pSmaCfg->indexUid);
|
||||||
int32_t vLen = POINTER_DISTANCE(qBuf, pBuf);
|
int32_t vLen = POINTER_DISTANCE(qBuf, pBuf);
|
||||||
|
|
||||||
ret = tdbDbPut(pMeta->pDB->pSmaDB, key, kLen, val, vLen, &pMetaDb->txn);
|
ret = tdbDbInsert(pMeta->pDB->pSmaDB, key, kLen, val, vLen, &pMetaDb->txn);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
taosMemoryFreeClear(pBuf);
|
taosMemoryFreeClear(pBuf);
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -545,7 +545,7 @@ int metaSaveSmaToDB(SMeta *pMeta, STSma *pSmaCfg) {
|
||||||
val = NULL;
|
val = NULL;
|
||||||
vLen = 0;
|
vLen = 0;
|
||||||
|
|
||||||
ret = tdbDbPut(pMeta->pDB->pSmaIdx, key, kLen, val, vLen, &pMetaDb->txn);
|
ret = tdbDbInsert(pMeta->pDB->pSmaIdx, key, kLen, val, vLen, &pMetaDb->txn);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
taosMemoryFreeClear(pBuf);
|
taosMemoryFreeClear(pBuf);
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -72,44 +72,61 @@ _err:
|
||||||
}
|
}
|
||||||
|
|
||||||
int metaDropSTable(SMeta *pMeta, int64_t verison, SVDropStbReq *pReq) {
|
int metaDropSTable(SMeta *pMeta, int64_t verison, SVDropStbReq *pReq) {
|
||||||
SMetaReader mr = {0};
|
TDBC *pNameIdxc = NULL;
|
||||||
|
TDBC *pUidIdxc = NULL;
|
||||||
|
TDBC *pCtbIdxc = NULL;
|
||||||
|
SCtbIdxKey *pCtbIdxKey;
|
||||||
|
const void *pKey = NULL;
|
||||||
|
int nKey;
|
||||||
|
const void *pData = NULL;
|
||||||
|
int nData;
|
||||||
|
int c, ret;
|
||||||
|
|
||||||
// validate req
|
// prepare uid idx cursor
|
||||||
metaReaderInit(&mr, pMeta, 0);
|
tdbDbcOpen(pMeta->pUidIdx, &pUidIdxc, &pMeta->txn);
|
||||||
if (metaGetTableEntryByUid(&mr, pReq->suid) < 0) {
|
ret = tdbDbcMoveTo(pUidIdxc, &pReq->suid, sizeof(tb_uid_t), &c);
|
||||||
terrno = TSDB_CODE_VND_TABLE_NOT_EXIST;
|
if (ret < 0 || c != 0) {
|
||||||
|
terrno = TSDB_CODE_VND_TB_NOT_EXIST;
|
||||||
|
tdbDbcClose(pUidIdxc);
|
||||||
goto _err;
|
goto _err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// do drop
|
// prepare name idx cursor
|
||||||
// drop from pTbDb
|
tdbDbcOpen(pMeta->pNameIdx, &pNameIdxc, &pMeta->txn);
|
||||||
// drop from pSkmDb
|
ret = tdbDbcMoveTo(pNameIdxc, pReq->name, strlen(pReq->name) + 1, &c);
|
||||||
// drop from pUidIdx
|
if (ret < 0 || c != 0) {
|
||||||
// drop from pNameIdx
|
ASSERT(0);
|
||||||
// {
|
}
|
||||||
// TDBC *pDbc1 = NULL;
|
|
||||||
// void *pKey = NULL;
|
|
||||||
// void *pVal = NULL;
|
|
||||||
// int kLen = 0;
|
|
||||||
// int vLen = 0;
|
|
||||||
// int ret = 0;
|
|
||||||
|
|
||||||
// // drop from pCtbIdx
|
tdbDbcDelete(pUidIdxc);
|
||||||
// ret = tdbDbcOpen(pMeta->pCtbIdx, &pDbc1);
|
tdbDbcDelete(pNameIdxc);
|
||||||
// tdbDbcMoveTo(pDbc1, &pReq->suid, sizeof(pReq->suid), NULL /*cmpr*/, 0 /*TDB_FORWARD_SEARCH*/);
|
tdbDbcClose(pUidIdxc);
|
||||||
// tdbDbcGet(pDbc1, &pKey, &kLen, &pVal, vLen);
|
tdbDbcClose(pNameIdxc);
|
||||||
// tdbDbcDrop(pDbc1);
|
|
||||||
// // drop from pTagIdx
|
|
||||||
// // drop from pTtlIdx
|
|
||||||
// }
|
|
||||||
|
|
||||||
// clear and return
|
// loop to drop each child table
|
||||||
metaReaderClear(&mr);
|
tdbDbcOpen(pMeta->pCtbIdx, &pCtbIdxc, &pMeta->txn);
|
||||||
metaError("vgId:%d super table %s uid:%" PRId64 " is dropped", TD_VID(pMeta->pVnode), pReq->name, pReq->suid);
|
ret = tdbDbcMoveTo(pCtbIdxc, &(SCtbIdxKey){.suid = pReq->suid, .uid = INT64_MIN}, sizeof(SCtbIdxKey), &c);
|
||||||
|
if (ret < 0 || (c < 0 && tdbDbcMoveToNext(pCtbIdxc) < 0)) {
|
||||||
|
tdbDbcClose(pCtbIdxc);
|
||||||
|
goto _exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
tdbDbcGet(pCtbIdxc, &pKey, &nKey, NULL, NULL);
|
||||||
|
pCtbIdxKey = (SCtbIdxKey *)pKey;
|
||||||
|
|
||||||
|
if (pCtbIdxKey->suid > pReq->suid) break;
|
||||||
|
|
||||||
|
// drop the child table (TODO)
|
||||||
|
|
||||||
|
if (tdbDbcMoveToNext(pCtbIdxc) < 0) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
_exit:
|
||||||
|
metaDebug("vgId:%d super table %s uid:%" PRId64 " is dropped", TD_VID(pMeta->pVnode), pReq->name, pReq->suid);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
_err:
|
_err:
|
||||||
metaReaderClear(&mr);
|
|
||||||
metaError("vgId:%d failed to drop super table %s uid:%" PRId64 " since %s", TD_VID(pMeta->pVnode), pReq->name,
|
metaError("vgId:%d failed to drop super table %s uid:%" PRId64 " since %s", TD_VID(pMeta->pVnode), pReq->name,
|
||||||
pReq->suid, tstrerror(terrno));
|
pReq->suid, tstrerror(terrno));
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -166,18 +183,122 @@ _err:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int metaDropTable(SMeta *pMeta, tb_uid_t uid) {
|
int metaDropTable(SMeta *pMeta, int64_t version, SVDropTbReq *pReq) {
|
||||||
#if 0
|
TDBC *pTbDbc = NULL;
|
||||||
if (metaRemoveTableFromIdx(pMeta, uid) < 0) {
|
TDBC *pUidIdxc = NULL;
|
||||||
// TODO: handle error
|
TDBC *pNameIdxc = NULL;
|
||||||
|
const void *pData;
|
||||||
|
int nData;
|
||||||
|
tb_uid_t uid;
|
||||||
|
int64_t tver;
|
||||||
|
SMetaEntry me = {0};
|
||||||
|
SCoder coder = {0};
|
||||||
|
int8_t type;
|
||||||
|
int64_t ctime;
|
||||||
|
tb_uid_t suid;
|
||||||
|
int c, ret;
|
||||||
|
|
||||||
|
// search & delete the name idx
|
||||||
|
tdbDbcOpen(pMeta->pNameIdx, &pNameIdxc, &pMeta->txn);
|
||||||
|
ret = tdbDbcMoveTo(pNameIdxc, pReq->name, strlen(pReq->name) + 1, &c);
|
||||||
|
if (ret < 0 || c) {
|
||||||
|
tdbDbcClose(pNameIdxc);
|
||||||
|
terrno = TSDB_CODE_VND_TABLE_NOT_EXIST;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (metaRemoveTableFromIdx(pMeta, uid) < 0) {
|
ret = tdbDbcGet(pNameIdxc, NULL, NULL, &pData, &nData);
|
||||||
// TODO
|
if (ret < 0) {
|
||||||
|
ASSERT(0);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
uid = *(tb_uid_t *)pData;
|
||||||
|
|
||||||
|
tdbDbcDelete(pNameIdxc);
|
||||||
|
tdbDbcClose(pNameIdxc);
|
||||||
|
|
||||||
|
// search & delete uid idx
|
||||||
|
tdbDbcOpen(pMeta->pUidIdx, &pUidIdxc, &pMeta->txn);
|
||||||
|
ret = tdbDbcMoveTo(pUidIdxc, &uid, sizeof(uid), &c);
|
||||||
|
if (ret < 0 || c != 0) {
|
||||||
|
ASSERT(0);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = tdbDbcGet(pUidIdxc, NULL, NULL, &pData, &nData);
|
||||||
|
if (ret < 0) {
|
||||||
|
ASSERT(0);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
tver = *(int64_t *)pData;
|
||||||
|
tdbDbcDelete(pUidIdxc);
|
||||||
|
tdbDbcClose(pUidIdxc);
|
||||||
|
|
||||||
|
// search and get meta entry
|
||||||
|
tdbDbcOpen(pMeta->pTbDb, &pTbDbc, &pMeta->txn);
|
||||||
|
ret = tdbDbcMoveTo(pTbDbc, &(STbDbKey){.uid = uid, .version = tver}, sizeof(STbDbKey), &c);
|
||||||
|
if (ret < 0 || c != 0) {
|
||||||
|
ASSERT(0);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = tdbDbcGet(pTbDbc, NULL, NULL, &pData, &nData);
|
||||||
|
if (ret < 0) {
|
||||||
|
ASSERT(0);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// decode entry
|
||||||
|
void *pDataCopy = taosMemoryMalloc(nData); // remove the copy (todo)
|
||||||
|
memcpy(pDataCopy, pData, nData);
|
||||||
|
tCoderInit(&coder, TD_LITTLE_ENDIAN, pDataCopy, nData, TD_DECODER);
|
||||||
|
ret = metaDecodeEntry(&coder, &me);
|
||||||
|
if (ret < 0) {
|
||||||
|
ASSERT(0);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
type = me.type;
|
||||||
|
if (type == TSDB_CHILD_TABLE) {
|
||||||
|
ctime = me.ctbEntry.ctime;
|
||||||
|
suid = me.ctbEntry.suid;
|
||||||
|
} else if (type == TSDB_NORMAL_TABLE) {
|
||||||
|
ctime = me.ntbEntry.ctime;
|
||||||
|
suid = 0;
|
||||||
|
} else {
|
||||||
|
ASSERT(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
taosMemoryFree(pDataCopy);
|
||||||
|
tCoderClear(&coder);
|
||||||
|
tdbDbcClose(pTbDbc);
|
||||||
|
|
||||||
|
if (type == TSDB_CHILD_TABLE) {
|
||||||
|
// remove the pCtbIdx
|
||||||
|
TDBC *pCtbIdxc = NULL;
|
||||||
|
tdbDbcOpen(pMeta->pCtbIdx, &pCtbIdxc, &pMeta->txn);
|
||||||
|
|
||||||
|
ret = tdbDbcMoveTo(pCtbIdxc, &(SCtbIdxKey){.suid = suid, .uid = uid}, sizeof(SCtbIdxKey), &c);
|
||||||
|
if (ret < 0 || c != 0) {
|
||||||
|
ASSERT(0);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
tdbDbcDelete(pCtbIdxc);
|
||||||
|
tdbDbcClose(pCtbIdxc);
|
||||||
|
|
||||||
|
// remove tags from pTagIdx (todo)
|
||||||
|
} else if (type == TSDB_NORMAL_TABLE) {
|
||||||
|
// remove from pSkmDb
|
||||||
|
} else {
|
||||||
|
ASSERT(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove from ttl (todo)
|
||||||
|
if (ctime > 0) {
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -218,7 +339,7 @@ static int metaSaveToTbDb(SMeta *pMeta, const SMetaEntry *pME) {
|
||||||
tCoderClear(&coder);
|
tCoderClear(&coder);
|
||||||
|
|
||||||
// write to table.db
|
// write to table.db
|
||||||
if (tdbDbPut(pMeta->pTbDb, pKey, kLen, pVal, vLen, &pMeta->txn) < 0) {
|
if (tdbDbInsert(pMeta->pTbDb, pKey, kLen, pVal, vLen, &pMeta->txn) < 0) {
|
||||||
goto _err;
|
goto _err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -231,11 +352,11 @@ _err:
|
||||||
}
|
}
|
||||||
|
|
||||||
static int metaUpdateUidIdx(SMeta *pMeta, const SMetaEntry *pME) {
|
static int metaUpdateUidIdx(SMeta *pMeta, const SMetaEntry *pME) {
|
||||||
return tdbDbPut(pMeta->pUidIdx, &pME->uid, sizeof(tb_uid_t), &pME->version, sizeof(int64_t), &pMeta->txn);
|
return tdbDbInsert(pMeta->pUidIdx, &pME->uid, sizeof(tb_uid_t), &pME->version, sizeof(int64_t), &pMeta->txn);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int metaUpdateNameIdx(SMeta *pMeta, const SMetaEntry *pME) {
|
static int metaUpdateNameIdx(SMeta *pMeta, const SMetaEntry *pME) {
|
||||||
return tdbDbPut(pMeta->pNameIdx, pME->name, strlen(pME->name) + 1, &pME->uid, sizeof(tb_uid_t), &pMeta->txn);
|
return tdbDbInsert(pMeta->pNameIdx, pME->name, strlen(pME->name) + 1, &pME->uid, sizeof(tb_uid_t), &pMeta->txn);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int metaUpdateTtlIdx(SMeta *pMeta, const SMetaEntry *pME) {
|
static int metaUpdateTtlIdx(SMeta *pMeta, const SMetaEntry *pME) {
|
||||||
|
@ -258,12 +379,12 @@ static int metaUpdateTtlIdx(SMeta *pMeta, const SMetaEntry *pME) {
|
||||||
ttlKey.dtime = ctime + ttlDays * 24 * 60 * 60;
|
ttlKey.dtime = ctime + ttlDays * 24 * 60 * 60;
|
||||||
ttlKey.uid = pME->uid;
|
ttlKey.uid = pME->uid;
|
||||||
|
|
||||||
return tdbDbPut(pMeta->pTtlIdx, &ttlKey, sizeof(ttlKey), NULL, 0, &pMeta->txn);
|
return tdbDbInsert(pMeta->pTtlIdx, &ttlKey, sizeof(ttlKey), NULL, 0, &pMeta->txn);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int metaUpdateCtbIdx(SMeta *pMeta, const SMetaEntry *pME) {
|
static int metaUpdateCtbIdx(SMeta *pMeta, const SMetaEntry *pME) {
|
||||||
SCtbIdxKey ctbIdxKey = {.suid = pME->ctbEntry.suid, .uid = pME->uid};
|
SCtbIdxKey ctbIdxKey = {.suid = pME->ctbEntry.suid, .uid = pME->uid};
|
||||||
return tdbDbPut(pMeta->pCtbIdx, &ctbIdxKey, sizeof(ctbIdxKey), NULL, 0, &pMeta->txn);
|
return tdbDbInsert(pMeta->pCtbIdx, &ctbIdxKey, sizeof(ctbIdxKey), NULL, 0, &pMeta->txn);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int metaUpdateTagIdx(SMeta *pMeta, const SMetaEntry *pME) {
|
static int metaUpdateTagIdx(SMeta *pMeta, const SMetaEntry *pME) {
|
||||||
|
@ -304,7 +425,7 @@ static int metaSaveToSkmDb(SMeta *pMeta, const SMetaEntry *pME) {
|
||||||
tCoderInit(&coder, TD_LITTLE_ENDIAN, pVal, vLen, TD_ENCODER);
|
tCoderInit(&coder, TD_LITTLE_ENDIAN, pVal, vLen, TD_ENCODER);
|
||||||
tEncodeSSchemaWrapper(&coder, pSW);
|
tEncodeSSchemaWrapper(&coder, pSW);
|
||||||
|
|
||||||
if (tdbDbPut(pMeta->pSkmDb, &skmDbKey, sizeof(skmDbKey), pVal, vLen, &pMeta->txn) < 0) {
|
if (tdbDbInsert(pMeta->pSkmDb, &skmDbKey, sizeof(skmDbKey), pVal, vLen, &pMeta->txn) < 0) {
|
||||||
rcode = -1;
|
rcode = -1;
|
||||||
goto _exit;
|
goto _exit;
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,7 +97,7 @@ int32_t tsdbCloseDBF(SDBFile *pDBF) {
|
||||||
int32_t tsdbSaveSmaToDB(SDBFile *pDBF, void *pKey, int32_t keyLen, void *pVal, int32_t valLen, TXN *txn) {
|
int32_t tsdbSaveSmaToDB(SDBFile *pDBF, void *pKey, int32_t keyLen, void *pVal, int32_t valLen, TXN *txn) {
|
||||||
int32_t ret;
|
int32_t ret;
|
||||||
|
|
||||||
ret = tdbDbPut(pDBF->pDB, pKey, keyLen, pVal, valLen, txn);
|
ret = tdbDbInsert(pDBF->pDB, pKey, keyLen, pVal, valLen, txn);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
tsdbError("Failed to create insert sma data into db, ret = %d", ret);
|
tsdbError("Failed to create insert sma data into db, ret = %d", ret);
|
||||||
return -1;
|
return -1;
|
||||||
|
|
|
@ -445,14 +445,45 @@ static int vnodeProcessAlterTbReq(SVnode *pVnode, void *pReq, int32_t len, SRpcM
|
||||||
}
|
}
|
||||||
|
|
||||||
static int vnodeProcessDropTbReq(SVnode *pVnode, int64_t version, void *pReq, int32_t len, SRpcMsg *pRsp) {
|
static int vnodeProcessDropTbReq(SVnode *pVnode, int64_t version, void *pReq, int32_t len, SRpcMsg *pRsp) {
|
||||||
SVDropTbReq req = {0};
|
SVDropTbBatchReq req = {0};
|
||||||
SVDropTbReq rsp = {0};
|
SVDropTbBatchRsp rsp = {0};
|
||||||
|
SCoder coder = {0};
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
pRsp->msgType = TDMT_VND_CREATE_STB_RSP;
|
||||||
|
pRsp->pCont = NULL;
|
||||||
|
pRsp->contLen = 0;
|
||||||
|
pRsp->code = TSDB_CODE_SUCCESS;
|
||||||
|
|
||||||
// decode req
|
// decode req
|
||||||
|
tCoderInit(&coder, TD_LITTLE_ENDIAN, pReq, len, TD_DECODER);
|
||||||
|
ret = tDecodeSVDropTbBatchReq(&coder, &req);
|
||||||
|
if (ret < 0) {
|
||||||
|
terrno = TSDB_CODE_INVALID_MSG;
|
||||||
|
pRsp->code = terrno;
|
||||||
|
goto _exit;
|
||||||
|
}
|
||||||
|
|
||||||
// process req
|
// process req
|
||||||
|
rsp.pArray = taosArrayInit(sizeof(SVDropTbRsp), req.nReqs);
|
||||||
|
for (int iReq = 0; iReq < req.nReqs; iReq++) {
|
||||||
|
SVDropTbReq *pDropTbReq = req.pReqs + iReq;
|
||||||
|
SVDropTbRsp dropTbRsp = {0};
|
||||||
|
|
||||||
// return rsp
|
/* code */
|
||||||
|
ret = metaDropTable(pVnode->pMeta, version, pDropTbReq);
|
||||||
|
if (ret < 0) {
|
||||||
|
dropTbRsp.code = TSDB_CODE_SUCCESS;
|
||||||
|
} else {
|
||||||
|
dropTbRsp.code = terrno;
|
||||||
|
}
|
||||||
|
|
||||||
|
taosArrayPush(rsp.pArray, &dropTbRsp);
|
||||||
|
}
|
||||||
|
|
||||||
|
_exit:
|
||||||
|
tCoderClear(&coder);
|
||||||
|
// encode rsp (TODO)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -482,7 +513,7 @@ static int vnodeProcessSubmitReq(SVnode *pVnode, int64_t version, void *pReq, in
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t tsdbProcessSubmitReq(STsdb *pTsdb, int64_t version, void *pReq) {
|
int32_t tsdbProcessSubmitReq(STsdb *pTsdb, int64_t version, void *pReq) {
|
||||||
if(!pReq) {
|
if (!pReq) {
|
||||||
terrno = TSDB_CODE_INVALID_PTR;
|
terrno = TSDB_CODE_INVALID_PTR;
|
||||||
return TSDB_CODE_FAILED;
|
return TSDB_CODE_FAILED;
|
||||||
}
|
}
|
||||||
|
|
|
@ -4830,6 +4830,7 @@ static SArray* createSortInfo(SNodeList* pNodeList, SNodeList* pNodeListTarget);
|
||||||
static SArray* createIndexMap(SNodeList* pNodeList);
|
static SArray* createIndexMap(SNodeList* pNodeList);
|
||||||
static SArray* extractPartitionColInfo(SNodeList* pNodeList);
|
static SArray* extractPartitionColInfo(SNodeList* pNodeList);
|
||||||
static int32_t initQueryTableDataCond(SQueryTableDataCond* pCond, const STableScanPhysiNode* pTableScanNode);
|
static int32_t initQueryTableDataCond(SQueryTableDataCond* pCond, const STableScanPhysiNode* pTableScanNode);
|
||||||
|
static void setJoinColumnInfo(SColumnInfo* pInfo, const SColumnNode* pLeftNode);
|
||||||
|
|
||||||
static SInterval extractIntervalInfo(const STableScanPhysiNode* pTableScanNode) {
|
static SInterval extractIntervalInfo(const STableScanPhysiNode* pTableScanNode) {
|
||||||
SInterval interval = {
|
SInterval interval = {
|
||||||
|
@ -5624,25 +5625,29 @@ SOperatorInfo* createJoinOperatorInfo(SOperatorInfo** pDownstream, int32_t numOf
|
||||||
goto _error;
|
goto _error;
|
||||||
}
|
}
|
||||||
|
|
||||||
pOperator->resultInfo.capacity = 4096;
|
initResultSizeInfo(pOperator, 4096);
|
||||||
pOperator->resultInfo.threshold = 4096 * 0.75;
|
|
||||||
|
|
||||||
// initResultRowInf
|
pInfo->pRes = pResBlock;
|
||||||
// o(&pInfo->binfo.resultRowInfo, 8);
|
pOperator->name = "MergeJoinOperator";
|
||||||
pInfo->pRes = pResBlock;
|
|
||||||
|
|
||||||
pOperator->name = "JoinOperator";
|
|
||||||
pOperator->operatorType = QUERY_NODE_PHYSICAL_PLAN_JOIN;
|
pOperator->operatorType = QUERY_NODE_PHYSICAL_PLAN_JOIN;
|
||||||
pOperator->blocking = false;
|
pOperator->blocking = false;
|
||||||
pOperator->status = OP_NOT_OPENED;
|
pOperator->status = OP_NOT_OPENED;
|
||||||
pOperator->pExpr = pExprInfo;
|
pOperator->pExpr = pExprInfo;
|
||||||
pOperator->numOfOutput = numOfCols;
|
pOperator->numOfOutput = numOfCols;
|
||||||
pOperator->info = pInfo;
|
pOperator->info = pInfo;
|
||||||
pOperator->pTaskInfo = pTaskInfo;
|
pOperator->pTaskInfo = pTaskInfo;
|
||||||
|
|
||||||
|
SOperatorNode* pNode = (SOperatorNode*)pOnCondition;
|
||||||
|
setJoinColumnInfo(&pInfo->leftCol, (SColumnNode*)pNode->pLeft);
|
||||||
|
setJoinColumnInfo(&pInfo->rightCol, (SColumnNode*)pNode->pRight);
|
||||||
|
|
||||||
pOperator->fpSet =
|
pOperator->fpSet =
|
||||||
createOperatorFpSet(operatorDummyOpenFn, doMergeJoin, NULL, NULL, destroyBasicOperatorInfo, NULL, NULL, NULL);
|
createOperatorFpSet(operatorDummyOpenFn, doMergeJoin, NULL, NULL, destroyBasicOperatorInfo, NULL, NULL, NULL);
|
||||||
int32_t code = appendDownstream(pOperator, pDownstream, numOfDownstream);
|
int32_t code = appendDownstream(pOperator, pDownstream, numOfDownstream);
|
||||||
|
if (code != TSDB_CODE_SUCCESS) {
|
||||||
|
goto _error;
|
||||||
|
}
|
||||||
|
|
||||||
return pOperator;
|
return pOperator;
|
||||||
|
|
||||||
_error:
|
_error:
|
||||||
|
@ -5651,3 +5656,11 @@ _error:
|
||||||
pTaskInfo->code = TSDB_CODE_OUT_OF_MEMORY;
|
pTaskInfo->code = TSDB_CODE_OUT_OF_MEMORY;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setJoinColumnInfo(SColumnInfo* pColumn, const SColumnNode* pColumnNode) {
|
||||||
|
pColumn->slotId = pColumnNode->slotId;
|
||||||
|
pColumn->type = pColumnNode->node.resType.type;
|
||||||
|
pColumn->bytes = pColumnNode->node.resType.bytes;
|
||||||
|
pColumn->precision = pColumnNode->node.resType.precision;
|
||||||
|
pColumn->scale = pColumnNode->node.resType.scale;
|
||||||
|
}
|
||||||
|
|
|
@ -63,9 +63,14 @@ typedef struct SIFParam {
|
||||||
} SIFParam;
|
} SIFParam;
|
||||||
|
|
||||||
static int32_t sifGetFuncFromSql(EOperatorType src, EIndexQueryType *dst) {
|
static int32_t sifGetFuncFromSql(EOperatorType src, EIndexQueryType *dst) {
|
||||||
if (src == OP_TYPE_GREATER_THAN || src == OP_TYPE_GREATER_EQUAL || src == OP_TYPE_LOWER_THAN ||
|
if (src == OP_TYPE_GREATER_THAN) {
|
||||||
src == OP_TYPE_LOWER_EQUAL) {
|
*dst = QUERY_GREATER_THAN;
|
||||||
*dst = QUERY_RANGE;
|
} else if (src == OP_TYPE_GREATER_EQUAL) {
|
||||||
|
*dst = QUERY_GREATER_EQUAL;
|
||||||
|
} else if (src == OP_TYPE_LOWER_THAN) {
|
||||||
|
*dst = QUERY_LESS_THAN;
|
||||||
|
} else if (src == OP_TYPE_LOWER_EQUAL) {
|
||||||
|
*dst = QUERY_LESS_EQUAL;
|
||||||
} else if (src == OP_TYPE_EQUAL) {
|
} else if (src == OP_TYPE_EQUAL) {
|
||||||
*dst = QUERY_TERM;
|
*dst = QUERY_TERM;
|
||||||
} else if (src == OP_TYPE_LIKE || src == OP_TYPE_MATCH || src == OP_TYPE_NMATCH) {
|
} else if (src == OP_TYPE_LIKE || src == OP_TYPE_MATCH || src == OP_TYPE_NMATCH) {
|
||||||
|
@ -249,9 +254,6 @@ static int32_t sifExecFunction(SFunctionNode *node, SIFCtx *ctx, SIFParam *outpu
|
||||||
static int32_t sifDoIndex(SIFParam *left, SIFParam *right, int8_t operType, SIFParam *output) {
|
static int32_t sifDoIndex(SIFParam *left, SIFParam *right, int8_t operType, SIFParam *output) {
|
||||||
SIndexTerm *tm = indexTermCreate(left->suid, DEFAULT, operType, left->colValType, left->colName,
|
SIndexTerm *tm = indexTermCreate(left->suid, DEFAULT, operType, left->colValType, left->colName,
|
||||||
strlen(left->colName), right->condValue, strlen(right->condValue));
|
strlen(left->colName), right->condValue, strlen(right->condValue));
|
||||||
if (operType == OP_TYPE_LOWER_EQUAL || operType == OP_TYPE_GREATER_EQUAL || operType == OP_TYPE_GREATER_THAN ||
|
|
||||||
operType == OP_TYPE_LOWER_THAN) {
|
|
||||||
}
|
|
||||||
if (tm == NULL) {
|
if (tm == NULL) {
|
||||||
return TSDB_CODE_QRY_OUT_OF_MEMORY;
|
return TSDB_CODE_QRY_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,6 @@ typedef struct FstRange {
|
||||||
uint64_t end;
|
uint64_t end;
|
||||||
} FstRange;
|
} FstRange;
|
||||||
|
|
||||||
typedef enum { GE, GT, LE, LT } RangeType;
|
|
||||||
typedef enum { OneTransNext, OneTrans, AnyTrans, EmptyFinal } State;
|
typedef enum { OneTransNext, OneTrans, AnyTrans, EmptyFinal } State;
|
||||||
typedef enum { Ordered, OutOfOrdered, DuplicateKey } OrderType;
|
typedef enum { Ordered, OutOfOrdered, DuplicateKey } OrderType;
|
||||||
|
|
||||||
|
@ -174,9 +173,9 @@ Output fstStateFinalOutput(FstState* state, uint64_t version, FstSlice* date,
|
||||||
uint64_t fstStateFindInput(FstState* state, FstNode* node, uint8_t b, bool* null);
|
uint64_t fstStateFindInput(FstState* state, FstNode* node, uint8_t b, bool* null);
|
||||||
|
|
||||||
#define FST_STATE_ONE_TRNAS_NEXT(node) (node->state.state == OneTransNext)
|
#define FST_STATE_ONE_TRNAS_NEXT(node) (node->state.state == OneTransNext)
|
||||||
#define FST_STATE_ONE_TRNAS(node) (node->state.state == OneTrans)
|
#define FST_STATE_ONE_TRNAS(node) (node->state.state == OneTrans)
|
||||||
#define FST_STATE_ANY_TRANS(node) (node->state.state == AnyTrans)
|
#define FST_STATE_ANY_TRANS(node) (node->state.state == AnyTrans)
|
||||||
#define FST_STATE_EMPTY_FINAL(node) (node->state.state == EmptyFinal)
|
#define FST_STATE_EMPTY_FINAL(node) (node->state.state == EmptyFinal)
|
||||||
|
|
||||||
typedef struct FstLastTransition {
|
typedef struct FstLastTransition {
|
||||||
uint8_t inp;
|
uint8_t inp;
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
typedef enum { LT, LE, GT, GE } RangeType;
|
||||||
typedef enum { kTypeValue, kTypeDeletion } STermValueType;
|
typedef enum { kTypeValue, kTypeDeletion } STermValueType;
|
||||||
|
|
||||||
typedef struct SIndexStat {
|
typedef struct SIndexStat {
|
||||||
|
@ -86,7 +87,6 @@ typedef struct SIndexTerm {
|
||||||
int32_t nColName;
|
int32_t nColName;
|
||||||
char* colVal;
|
char* colVal;
|
||||||
int32_t nColVal;
|
int32_t nColVal;
|
||||||
int8_t qType; // just use for range
|
|
||||||
} SIndexTerm;
|
} SIndexTerm;
|
||||||
|
|
||||||
typedef struct SIndexTermQuery {
|
typedef struct SIndexTermQuery {
|
||||||
|
|
|
@ -262,7 +262,6 @@ SIndexTerm* indexTermCreate(int64_t suid, SIndexOperOnColumn oper, int8_t queryT
|
||||||
tm->colVal = (char*)taosMemoryCalloc(1, nColVal + 1);
|
tm->colVal = (char*)taosMemoryCalloc(1, nColVal + 1);
|
||||||
memcpy(tm->colVal, colVal, nColVal);
|
memcpy(tm->colVal, colVal, nColVal);
|
||||||
tm->nColVal = nColVal;
|
tm->nColVal = nColVal;
|
||||||
tm->qType = queryType;
|
|
||||||
|
|
||||||
return tm;
|
return tm;
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,10 +38,29 @@ static int32_t cacheSearchTerm(void* cache, CacheTerm* ct, SIdxTempResult* tr, S
|
||||||
static int32_t cacheSearchPrefix(void* cache, CacheTerm* ct, SIdxTempResult* tr, STermValueType* s);
|
static int32_t cacheSearchPrefix(void* cache, CacheTerm* ct, SIdxTempResult* tr, STermValueType* s);
|
||||||
static int32_t cacheSearchSuffix(void* cache, CacheTerm* ct, SIdxTempResult* tr, STermValueType* s);
|
static int32_t cacheSearchSuffix(void* cache, CacheTerm* ct, SIdxTempResult* tr, STermValueType* s);
|
||||||
static int32_t cacheSearchRegex(void* cache, CacheTerm* ct, SIdxTempResult* tr, STermValueType* s);
|
static int32_t cacheSearchRegex(void* cache, CacheTerm* ct, SIdxTempResult* tr, STermValueType* s);
|
||||||
|
static int32_t cacheSearchLessThan(void* cache, CacheTerm* ct, SIdxTempResult* tr, STermValueType* s);
|
||||||
|
static int32_t cacheSearchLessEqual(void* cache, CacheTerm* ct, SIdxTempResult* tr, STermValueType* s);
|
||||||
|
static int32_t cacheSearchGreaterThan(void* cache, CacheTerm* ct, SIdxTempResult* tr, STermValueType* s);
|
||||||
|
static int32_t cacheSearchGreaterEqual(void* cache, CacheTerm* ct, SIdxTempResult* tr, STermValueType* s);
|
||||||
static int32_t cacheSearchRange(void* cache, CacheTerm* ct, SIdxTempResult* tr, STermValueType* s);
|
static int32_t cacheSearchRange(void* cache, CacheTerm* ct, SIdxTempResult* tr, STermValueType* s);
|
||||||
|
/*comm func of compare, used in (LE/LT/GE/GT compare)*/
|
||||||
|
static int32_t cacheSearchCompareFunc(void* cache, CacheTerm* ct, SIdxTempResult* tr, STermValueType* s,
|
||||||
|
RangeType type);
|
||||||
|
|
||||||
|
typedef enum { MATCH, CONTINUE, BREAK } TExeCond;
|
||||||
|
typedef TExeCond (*_cache_range_compare)(void* a, void* b, int8_t type);
|
||||||
|
|
||||||
|
static TExeCond tCompareLessThan(void* a, void* b, int8_t type) { return MATCH; }
|
||||||
|
static TExeCond tCompareLessEqual(void* a, void* b, int8_t type) { return MATCH; }
|
||||||
|
static TExeCond tCompareGreaterThan(void* a, void* b, int8_t type) { return MATCH; }
|
||||||
|
static TExeCond tCompareGreaterEqual(void* a, void* b, int8_t type) { return MATCH; }
|
||||||
|
|
||||||
|
static TExeCond (*rangeCompare[])(void* a, void* b, int8_t type) = {tCompareLessThan, tCompareLessEqual,
|
||||||
|
tCompareGreaterThan, tCompareGreaterEqual};
|
||||||
|
|
||||||
static int32_t (*cacheSearch[])(void* cache, CacheTerm* ct, SIdxTempResult* tr, STermValueType* s) = {
|
static int32_t (*cacheSearch[])(void* cache, CacheTerm* ct, SIdxTempResult* tr, STermValueType* s) = {
|
||||||
cacheSearchTerm, cacheSearchPrefix, cacheSearchSuffix, cacheSearchRegex, cacheSearchRange};
|
cacheSearchTerm, cacheSearchPrefix, cacheSearchSuffix, cacheSearchRegex, cacheSearchLessThan,
|
||||||
|
cacheSearchLessEqual, cacheSearchGreaterThan, cacheSearchGreaterEqual, cacheSearchRange};
|
||||||
|
|
||||||
static void doMergeWork(SSchedMsg* msg);
|
static void doMergeWork(SSchedMsg* msg);
|
||||||
static bool indexCacheIteratorNext(Iterate* itera);
|
static bool indexCacheIteratorNext(Iterate* itera);
|
||||||
|
@ -88,6 +107,52 @@ static int32_t cacheSearchRegex(void* cache, CacheTerm* ct, SIdxTempResult* tr,
|
||||||
// impl later
|
// impl later
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
static int32_t cacheSearchCompareFunc(void* cache, CacheTerm* ct, SIdxTempResult* tr, STermValueType* s,
|
||||||
|
RangeType type) {
|
||||||
|
if (cache == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
_cache_range_compare cmpFn = rangeCompare[type];
|
||||||
|
|
||||||
|
MemTable* mem = cache;
|
||||||
|
char* key = indexCacheTermGet(ct);
|
||||||
|
|
||||||
|
SSkipListIterator* iter = tSkipListCreateIter(mem->mem);
|
||||||
|
while (tSkipListIterNext(iter)) {
|
||||||
|
SSkipListNode* node = tSkipListIterGet(iter);
|
||||||
|
if (node == NULL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
CacheTerm* c = (CacheTerm*)SL_GET_NODE_DATA(node);
|
||||||
|
TExeCond cond = cmpFn(c->colVal, ct->colVal, ct->colType);
|
||||||
|
if (cond == MATCH) {
|
||||||
|
if (c->operaType == ADD_VALUE) {
|
||||||
|
INDEX_MERGE_ADD_DEL(tr->deled, tr->added, c->uid)
|
||||||
|
// taosArrayPush(result, &c->uid);
|
||||||
|
*s = kTypeValue;
|
||||||
|
} else if (c->operaType == DEL_VALUE) {
|
||||||
|
INDEX_MERGE_ADD_DEL(tr->added, tr->deled, c->uid)
|
||||||
|
}
|
||||||
|
} else if (cond == CONTINUE) {
|
||||||
|
} else if (cond == BREAK) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tSkipListDestroyIter(iter);
|
||||||
|
return TSDB_CODE_SUCCESS;
|
||||||
|
}
|
||||||
|
static int32_t cacheSearchLessThan(void* cache, CacheTerm* ct, SIdxTempResult* tr, STermValueType* s) {
|
||||||
|
return cacheSearchCompareFunc(cache, ct, tr, s, LT);
|
||||||
|
}
|
||||||
|
static int32_t cacheSearchLessEqual(void* cache, CacheTerm* ct, SIdxTempResult* tr, STermValueType* s) {
|
||||||
|
return cacheSearchCompareFunc(cache, ct, tr, s, LE);
|
||||||
|
}
|
||||||
|
static int32_t cacheSearchGreaterThan(void* cache, CacheTerm* ct, SIdxTempResult* tr, STermValueType* s) {
|
||||||
|
return cacheSearchCompareFunc(cache, ct, tr, s, GT);
|
||||||
|
}
|
||||||
|
static int32_t cacheSearchGreaterEqual(void* cache, CacheTerm* ct, SIdxTempResult* tr, STermValueType* s) {
|
||||||
|
return cacheSearchCompareFunc(cache, ct, tr, s, GE);
|
||||||
|
}
|
||||||
static int32_t cacheSearchRange(void* cache, CacheTerm* ct, SIdxTempResult* tr, STermValueType* s) {
|
static int32_t cacheSearchRange(void* cache, CacheTerm* ct, SIdxTempResult* tr, STermValueType* s) {
|
||||||
// impl later
|
// impl later
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -64,10 +64,17 @@ static int32_t tfSearchTerm(void* reader, SIndexTerm* tem, SIdxTempResult* tr);
|
||||||
static int32_t tfSearchPrefix(void* reader, SIndexTerm* tem, SIdxTempResult* tr);
|
static int32_t tfSearchPrefix(void* reader, SIndexTerm* tem, SIdxTempResult* tr);
|
||||||
static int32_t tfSearchSuffix(void* reader, SIndexTerm* tem, SIdxTempResult* tr);
|
static int32_t tfSearchSuffix(void* reader, SIndexTerm* tem, SIdxTempResult* tr);
|
||||||
static int32_t tfSearchRegex(void* reader, SIndexTerm* tem, SIdxTempResult* tr);
|
static int32_t tfSearchRegex(void* reader, SIndexTerm* tem, SIdxTempResult* tr);
|
||||||
|
static int32_t tfSearchLessThan(void* reader, SIndexTerm* tem, SIdxTempResult* tr);
|
||||||
|
static int32_t tfSearchLessEqual(void* reader, SIndexTerm* tem, SIdxTempResult* tr);
|
||||||
|
static int32_t tfSearchGreaterThan(void* reader, SIndexTerm* tem, SIdxTempResult* tr);
|
||||||
|
static int32_t tfSearchGreaterEqual(void* reader, SIndexTerm* tem, SIdxTempResult* tr);
|
||||||
static int32_t tfSearchRange(void* reader, SIndexTerm* tem, SIdxTempResult* tr);
|
static int32_t tfSearchRange(void* reader, SIndexTerm* tem, SIdxTempResult* tr);
|
||||||
|
|
||||||
|
static int32_t tfSearchCompareFunc(void* reader, SIndexTerm* tem, SIdxTempResult* tr, RangeType ctype);
|
||||||
|
|
||||||
static int32_t (*tfSearch[])(void* reader, SIndexTerm* tem, SIdxTempResult* tr) = {
|
static int32_t (*tfSearch[])(void* reader, SIndexTerm* tem, SIdxTempResult* tr) = {
|
||||||
tfSearchTerm, tfSearchPrefix, tfSearchSuffix, tfSearchRegex, tfSearchRange};
|
tfSearchTerm, tfSearchPrefix, tfSearchSuffix, tfSearchRegex, tfSearchLessThan,
|
||||||
|
tfSearchLessEqual, tfSearchGreaterThan, tfSearchGreaterEqual, tfSearchRange};
|
||||||
|
|
||||||
TFileCache* tfileCacheCreate(const char* path) {
|
TFileCache* tfileCacheCreate(const char* path) {
|
||||||
TFileCache* tcache = taosMemoryCalloc(1, sizeof(TFileCache));
|
TFileCache* tcache = taosMemoryCalloc(1, sizeof(TFileCache));
|
||||||
|
@ -299,6 +306,47 @@ static int32_t tfSearchRegex(void* reader, SIndexTerm* tem, SIdxTempResult* tr)
|
||||||
fstSliceDestroy(&key);
|
fstSliceDestroy(&key);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int32_t tfSearchCompareFunc(void* reader, SIndexTerm* tem, SIdxTempResult* tr, RangeType type) {
|
||||||
|
bool hasJson = INDEX_TYPE_CONTAIN_EXTERN_TYPE(tem->colType, TSDB_DATA_TYPE_JSON);
|
||||||
|
int ret = 0;
|
||||||
|
char* p = tem->colVal;
|
||||||
|
uint64_t sz = tem->nColVal;
|
||||||
|
if (hasJson) {
|
||||||
|
p = indexPackJsonData(tem);
|
||||||
|
sz = strlen(p);
|
||||||
|
}
|
||||||
|
SArray* offsets = taosArrayInit(16, sizeof(uint64_t));
|
||||||
|
|
||||||
|
AutomationCtx* ctx = automCtxCreate((void*)p, AUTOMATION_ALWAYS);
|
||||||
|
FstStreamBuilder* sb = fstSearch(((TFileReader*)reader)->fst, ctx);
|
||||||
|
|
||||||
|
FstSlice h = fstSliceCreate((uint8_t*)p, sz);
|
||||||
|
fstStreamBuilderSetRange(sb, &h, type);
|
||||||
|
fstSliceDestroy(&h);
|
||||||
|
|
||||||
|
StreamWithState* st = streamBuilderIntoStream(sb);
|
||||||
|
StreamWithStateResult* rt = NULL;
|
||||||
|
while ((rt = streamWithStateNextWith(st, NULL)) != NULL) {
|
||||||
|
taosArrayPush(offsets, &(rt->out.out));
|
||||||
|
swsResultDestroy(rt);
|
||||||
|
}
|
||||||
|
streamWithStateDestroy(st);
|
||||||
|
fstStreamBuilderDestroy(sb);
|
||||||
|
return TSDB_CODE_SUCCESS;
|
||||||
|
}
|
||||||
|
static int32_t tfSearchLessThan(void* reader, SIndexTerm* tem, SIdxTempResult* tr) {
|
||||||
|
return tfSearchCompareFunc(reader, tem, tr, LT);
|
||||||
|
}
|
||||||
|
static int32_t tfSearchLessEqual(void* reader, SIndexTerm* tem, SIdxTempResult* tr) {
|
||||||
|
return tfSearchCompareFunc(reader, tem, tr, LE);
|
||||||
|
}
|
||||||
|
static int32_t tfSearchGreaterThan(void* reader, SIndexTerm* tem, SIdxTempResult* tr) {
|
||||||
|
return tfSearchCompareFunc(reader, tem, tr, GT);
|
||||||
|
}
|
||||||
|
static int32_t tfSearchGreaterEqual(void* reader, SIndexTerm* tem, SIdxTempResult* tr) {
|
||||||
|
return tfSearchCompareFunc(reader, tem, tr, GE);
|
||||||
|
}
|
||||||
static int32_t tfSearchRange(void* reader, SIndexTerm* tem, SIdxTempResult* tr) {
|
static int32_t tfSearchRange(void* reader, SIndexTerm* tem, SIdxTempResult* tr) {
|
||||||
bool hasJson = INDEX_TYPE_CONTAIN_EXTERN_TYPE(tem->colType, TSDB_DATA_TYPE_JSON);
|
bool hasJson = INDEX_TYPE_CONTAIN_EXTERN_TYPE(tem->colType, TSDB_DATA_TYPE_JSON);
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
|
@ -40,7 +40,9 @@ int tdbCommit(TENV *pEnv, TXN *pTxn);
|
||||||
int tdbDbOpen(const char *fname, int keyLen, int valLen, tdb_cmpr_fn_t keyCmprFn, TENV *pEnv, TDB **ppDb);
|
int tdbDbOpen(const char *fname, int keyLen, int valLen, tdb_cmpr_fn_t keyCmprFn, TENV *pEnv, TDB **ppDb);
|
||||||
int tdbDbClose(TDB *pDb);
|
int tdbDbClose(TDB *pDb);
|
||||||
int tdbDbDrop(TDB *pDb);
|
int tdbDbDrop(TDB *pDb);
|
||||||
int tdbDbPut(TDB *pDb, const void *pKey, int keyLen, const void *pVal, int valLen, TXN *pTxn);
|
int tdbDbInsert(TDB *pDb, const void *pKey, int keyLen, const void *pVal, int valLen, TXN *pTxn);
|
||||||
|
int tdbDbDelete(TDB *pDb, const void *pKey, int kLen, TXN *pTxn);
|
||||||
|
int tdbDbUpsert(TDB *pDb, const void *pKey, int kLen, const void *pVal, int vLen, TXN *pTxn);
|
||||||
int tdbDbGet(TDB *pDb, const void *pKey, int kLen, void **ppVal, int *vLen);
|
int tdbDbGet(TDB *pDb, const void *pKey, int kLen, void **ppVal, int *vLen);
|
||||||
int tdbDbPGet(TDB *pDb, const void *pKey, int kLen, void **ppKey, int *pkLen, void **ppVal, int *vLen);
|
int tdbDbPGet(TDB *pDb, const void *pKey, int kLen, void **ppKey, int *pkLen, void **ppVal, int *vLen);
|
||||||
|
|
||||||
|
@ -53,11 +55,9 @@ int tdbDbcMoveToLast(TDBC *pDbc);
|
||||||
int tdbDbcMoveToNext(TDBC *pDbc);
|
int tdbDbcMoveToNext(TDBC *pDbc);
|
||||||
int tdbDbcMoveToPrev(TDBC *pDbc);
|
int tdbDbcMoveToPrev(TDBC *pDbc);
|
||||||
int tdbDbcGet(TDBC *pDbc, const void **ppKey, int *pkLen, const void **ppVal, int *pvLen);
|
int tdbDbcGet(TDBC *pDbc, const void **ppKey, int *pkLen, const void **ppVal, int *pvLen);
|
||||||
|
int tdbDbcDelete(TDBC *pDbc);
|
||||||
int tdbDbcPut(TDBC *pDbc, const void *pKey, int keyLen, const void *pVal, int valLen);
|
|
||||||
int tdbDbcUpdate(TDBC *pDbc, const void *pKey, int kLen, const void *pVal, int vLen);
|
|
||||||
int tdbDbcDrop(TDBC *pDbc);
|
|
||||||
int tdbDbcNext(TDBC *pDbc, void **ppKey, int *kLen, void **ppVal, int *vLen);
|
int tdbDbcNext(TDBC *pDbc, void **ppKey, int *kLen, void **ppVal, int *vLen);
|
||||||
|
int tdbDbcUpsert(TDBC *pDbc, const void *pKey, int nKey, const void *pData, int nData, int insert);
|
||||||
|
|
||||||
// TXN
|
// TXN
|
||||||
#define TDB_TXN_WRITE 0x1
|
#define TDB_TXN_WRITE 0x1
|
||||||
|
|
|
@ -138,67 +138,90 @@ int tdbBtreeInsert(SBTree *pBt, const void *pKey, int kLen, const void *pVal, in
|
||||||
}
|
}
|
||||||
|
|
||||||
if (btc.idx == -1) {
|
if (btc.idx == -1) {
|
||||||
idx = 0;
|
btc.idx = 0;
|
||||||
} else {
|
} else {
|
||||||
if (c > 0) {
|
if (c > 0) {
|
||||||
idx = btc.idx + 1;
|
btc.idx++;
|
||||||
} else if (c < 0) {
|
} else if (c == 0) {
|
||||||
idx = btc.idx;
|
// dup key not allowed
|
||||||
} else {
|
|
||||||
// TDB does NOT allow same key
|
|
||||||
tdbBtcClose(&btc);
|
|
||||||
ASSERT(0);
|
ASSERT(0);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// make sure enough space to hold the cell
|
ret = tdbBtcUpsert(&btc, pKey, kLen, pVal, vLen, 1);
|
||||||
szBuf = kLen + vLen + 14;
|
|
||||||
pBuf = tdbRealloc(pBt->pBuf, pBt->pageSize > szBuf ? szBuf : pBt->pageSize);
|
|
||||||
if (pBuf == NULL) {
|
|
||||||
tdbBtcClose(&btc);
|
|
||||||
ASSERT(0);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
pBt->pBuf = pBuf;
|
|
||||||
pCell = (SCell *)pBt->pBuf;
|
|
||||||
|
|
||||||
// encode cell
|
|
||||||
ret = tdbBtreeEncodeCell(btc.pPage, pKey, kLen, pVal, vLen, pCell, &szCell);
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
tdbBtcClose(&btc);
|
|
||||||
ASSERT(0);
|
ASSERT(0);
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// mark the page dirty
|
|
||||||
ret = tdbPagerWrite(pBt->pPager, btc.pPage);
|
|
||||||
if (ret < 0) {
|
|
||||||
tdbBtcClose(&btc);
|
tdbBtcClose(&btc);
|
||||||
ASSERT(0);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// insert the cell
|
|
||||||
ret = tdbPageInsertCell(btc.pPage, idx, pCell, szCell, 0);
|
|
||||||
if (ret < 0) {
|
|
||||||
tdbBtcClose(&btc);
|
|
||||||
ASSERT(0);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check if need balance
|
|
||||||
if (btc.pPage->nOverflow > 0) {
|
|
||||||
ret = tdbBtreeBalance(&btc);
|
|
||||||
if (ret < 0) {
|
|
||||||
tdbBtcClose(&btc);
|
|
||||||
ASSERT(0);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tdbBtcClose(&btc);
|
tdbBtcClose(&btc);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tdbBtreeDelete(SBTree *pBt, const void *pKey, int kLen, TXN *pTxn) {
|
||||||
|
SBTC btc;
|
||||||
|
int c;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
tdbBtcOpen(&btc, pBt, pTxn);
|
||||||
|
|
||||||
|
// move the cursor
|
||||||
|
ret = tdbBtcMoveTo(&btc, pKey, kLen, &c);
|
||||||
|
if (ret < 0) {
|
||||||
|
tdbBtcClose(&btc);
|
||||||
|
ASSERT(0);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (btc.idx < 0 || c != 0) {
|
||||||
|
tdbBtcClose(&btc);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete the key
|
||||||
|
if (tdbBtcDelete(&btc) < 0) {
|
||||||
|
tdbBtcClose(&btc);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
tdbBtcClose(&btc);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tdbBtreeUpsert(SBTree *pBt, const void *pKey, int nKey, const void *pData, int nData, TXN *pTxn) {
|
||||||
|
SBTC btc;
|
||||||
|
int c;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
tdbBtcOpen(&btc, pBt, pTxn);
|
||||||
|
|
||||||
|
// move the cursor
|
||||||
|
ret = tdbBtcMoveTo(&btc, pKey, nKey, &c);
|
||||||
|
if (ret < 0) {
|
||||||
|
ASSERT(0);
|
||||||
|
tdbBtcClose(&btc);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (btc.idx == -1) {
|
||||||
|
btc.idx = 0;
|
||||||
|
c = 1;
|
||||||
|
} else {
|
||||||
|
if (c > 0) {
|
||||||
|
btc.idx = btc.idx + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = tdbBtcUpsert(&btc, pKey, nKey, pData, nData, c);
|
||||||
|
if (ret < 0) {
|
||||||
|
ASSERT(0);
|
||||||
|
tdbBtcClose(&btc);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
tdbBtcClose(&btc);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -552,14 +575,14 @@ static int tdbBtreeBalanceNonRoot(SBTree *pBt, SPage *pParent, int idx, TXN *pTx
|
||||||
SCell *pCell;
|
SCell *pCell;
|
||||||
int szLCell, szRCell;
|
int szLCell, szRCell;
|
||||||
|
|
||||||
|
// balance page (iNew) and (iNew-1)
|
||||||
for (;;) {
|
for (;;) {
|
||||||
pCell = tdbPageGetCell(pOlds[infoNews[iNew - 1].iPage], infoNews[iNew - 1].oIdx);
|
pCell = tdbPageGetCell(pOlds[infoNews[iNew - 1].iPage], infoNews[iNew - 1].oIdx);
|
||||||
|
|
||||||
if (childNotLeaf) {
|
szLCell = tdbBtreeCellSize(pOlds[infoNews[iNew - 1].iPage], pCell);
|
||||||
szLCell = szRCell = tdbBtreeCellSize(pOlds[infoNews[iNew - 1].iPage], pCell);
|
if (!childNotLeaf) {
|
||||||
|
szRCell = szLCell;
|
||||||
} else {
|
} else {
|
||||||
szLCell = tdbBtreeCellSize(pOlds[infoNews[iNew - 1].iPage], pCell);
|
|
||||||
|
|
||||||
int iPage = infoNews[iNew - 1].iPage;
|
int iPage = infoNews[iNew - 1].iPage;
|
||||||
int oIdx = infoNews[iNew - 1].oIdx + 1;
|
int oIdx = infoNews[iNew - 1].oIdx + 1;
|
||||||
SPage *pPage;
|
SPage *pPage;
|
||||||
|
@ -736,6 +759,13 @@ static int tdbBtreeBalanceNonRoot(SBTree *pBt, SPage *pParent, int idx, TXN *pTx
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (TDB_BTREE_PAGE_IS_ROOT(pParent) && TDB_PAGE_TOTAL_CELLS(pParent) == 0) {
|
||||||
|
i8 flags = TDB_BTREE_ROOT | TDB_BTREE_PAGE_IS_LEAF(pNews[0]);
|
||||||
|
// copy content to the parent page
|
||||||
|
tdbBtreeInitPage(pParent, &(SBtreeInitPageArg){.flags = flags, .pBt = pBt}, 0);
|
||||||
|
tdbPageCopy(pNews[0], pParent);
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < 3; i++) {
|
for (int i = 0; i < 3; i++) {
|
||||||
if (pDivCell[i]) {
|
if (pDivCell[i]) {
|
||||||
tdbOsFree(pDivCell[i]);
|
tdbOsFree(pDivCell[i]);
|
||||||
|
@ -1357,7 +1387,143 @@ int tdbBtcGet(SBTC *pBtc, const void **ppKey, int *kLen, const void **ppVal, int
|
||||||
|
|
||||||
if (ppVal) {
|
if (ppVal) {
|
||||||
*ppVal = (void *)pBtc->coder.pVal;
|
*ppVal = (void *)pBtc->coder.pVal;
|
||||||
*kLen = pBtc->coder.vLen;
|
*vLen = pBtc->coder.vLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tdbBtcDelete(SBTC *pBtc) {
|
||||||
|
int idx = pBtc->idx;
|
||||||
|
int nCells = TDB_PAGE_TOTAL_CELLS(pBtc->pPage);
|
||||||
|
SPager *pPager = pBtc->pBt->pPager;
|
||||||
|
const void *pKey;
|
||||||
|
i8 iPage;
|
||||||
|
SPage *pPage;
|
||||||
|
SPgno pgno;
|
||||||
|
SCell *pCell;
|
||||||
|
int szCell;
|
||||||
|
int nKey;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ASSERT(idx >= 0 && idx < nCells);
|
||||||
|
|
||||||
|
// drop the cell on the leaf
|
||||||
|
ret = tdbPagerWrite(pPager, pBtc->pPage);
|
||||||
|
if (ret < 0) {
|
||||||
|
ASSERT(0);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
tdbPageDropCell(pBtc->pPage, idx);
|
||||||
|
|
||||||
|
// update interior page or do balance
|
||||||
|
if (idx == nCells - 1) {
|
||||||
|
if (idx) {
|
||||||
|
pBtc->idx--;
|
||||||
|
tdbBtcGet(pBtc, &pKey, &nKey, NULL, NULL);
|
||||||
|
|
||||||
|
// loop to update the interial page
|
||||||
|
pgno = TDB_PAGE_PGNO(pBtc->pPage);
|
||||||
|
for (iPage = pBtc->iPage - 1; iPage >= 0; iPage--) {
|
||||||
|
pPage = pBtc->pgStack[iPage];
|
||||||
|
idx = pBtc->idxStack[iPage];
|
||||||
|
nCells = TDB_PAGE_TOTAL_CELLS(pPage);
|
||||||
|
|
||||||
|
if (idx < nCells) {
|
||||||
|
ret = tdbPagerWrite(pPager, pPage);
|
||||||
|
if (ret < 0) {
|
||||||
|
ASSERT(0);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// update the cell with new key
|
||||||
|
pCell = tdbOsMalloc(nKey + 9);
|
||||||
|
tdbBtreeEncodeCell(pPage, pKey, nKey, &pgno, sizeof(pgno), pCell, &szCell);
|
||||||
|
|
||||||
|
ret = tdbPageUpdateCell(pPage, idx, pCell, szCell);
|
||||||
|
if (ret < 0) {
|
||||||
|
tdbOsFree(pCell);
|
||||||
|
ASSERT(0);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
tdbOsFree(pCell);
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
pgno = TDB_PAGE_PGNO(pPage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// delete the leaf page and do balance
|
||||||
|
ASSERT(TDB_PAGE_TOTAL_CELLS(pBtc->pPage) == 0);
|
||||||
|
|
||||||
|
ret = tdbBtreeBalance(pBtc);
|
||||||
|
if (ret < 0) {
|
||||||
|
ASSERT(0);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tdbBtcUpsert(SBTC *pBtc, const void *pKey, int kLen, const void *pData, int nData, int insert) {
|
||||||
|
SCell *pCell;
|
||||||
|
int szCell;
|
||||||
|
int nCells = TDB_PAGE_TOTAL_CELLS(pBtc->pPage);
|
||||||
|
int szBuf;
|
||||||
|
void *pBuf;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ASSERT(pBtc->idx >= 0);
|
||||||
|
|
||||||
|
// alloc space
|
||||||
|
szBuf = kLen + nData + 14;
|
||||||
|
pBuf = tdbRealloc(pBtc->pBt->pBuf, pBtc->pBt->pageSize > szBuf ? szBuf : pBtc->pBt->pageSize);
|
||||||
|
if (pBuf == NULL) {
|
||||||
|
ASSERT(0);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
pBtc->pBt->pBuf = pBuf;
|
||||||
|
pCell = (SCell *)pBtc->pBt->pBuf;
|
||||||
|
|
||||||
|
// encode cell
|
||||||
|
ret = tdbBtreeEncodeCell(pBtc->pPage, pKey, kLen, pData, nData, pCell, &szCell);
|
||||||
|
if (ret < 0) {
|
||||||
|
ASSERT(0);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// mark dirty
|
||||||
|
ret = tdbPagerWrite(pBtc->pBt->pPager, pBtc->pPage);
|
||||||
|
if (ret < 0) {
|
||||||
|
ASSERT(0);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// insert or update
|
||||||
|
if (insert) {
|
||||||
|
ASSERT(pBtc->idx <= nCells);
|
||||||
|
|
||||||
|
ret = tdbPageInsertCell(pBtc->pPage, pBtc->idx, pCell, szCell, 0);
|
||||||
|
} else {
|
||||||
|
ASSERT(pBtc->idx < nCells);
|
||||||
|
|
||||||
|
ret = tdbPageUpdateCell(pBtc->pPage, pBtc->idx, pCell, szCell);
|
||||||
|
}
|
||||||
|
if (ret < 0) {
|
||||||
|
ASSERT(0);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check balance
|
||||||
|
if (pBtc->pPage->nOverflow > 0) {
|
||||||
|
ret = tdbBtreeBalance(pBtc);
|
||||||
|
if (ret < 0) {
|
||||||
|
ASSERT(0);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -75,10 +75,16 @@ int tdbDbDrop(TDB *pDb) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int tdbDbPut(TDB *pDb, const void *pKey, int keyLen, const void *pVal, int valLen, TXN *pTxn) {
|
int tdbDbInsert(TDB *pDb, const void *pKey, int keyLen, const void *pVal, int valLen, TXN *pTxn) {
|
||||||
return tdbBtreeInsert(pDb->pBt, pKey, keyLen, pVal, valLen, pTxn);
|
return tdbBtreeInsert(pDb->pBt, pKey, keyLen, pVal, valLen, pTxn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int tdbDbDelete(TDB *pDb, const void *pKey, int kLen, TXN *pTxn) { return tdbBtreeDelete(pDb->pBt, pKey, kLen, pTxn); }
|
||||||
|
|
||||||
|
int tdbDbUpsert(TDB *pDb, const void *pKey, int kLen, const void *pVal, int vLen, TXN *pTxn) {
|
||||||
|
return tdbBtreeUpsert(pDb->pBt, pKey, kLen, pVal, vLen, pTxn);
|
||||||
|
}
|
||||||
|
|
||||||
int tdbDbGet(TDB *pDb, const void *pKey, int kLen, void **ppVal, int *vLen) {
|
int tdbDbGet(TDB *pDb, const void *pKey, int kLen, void **ppVal, int *vLen) {
|
||||||
return tdbBtreeGet(pDb->pBt, pKey, kLen, ppVal, vLen);
|
return tdbBtreeGet(pDb->pBt, pKey, kLen, ppVal, vLen);
|
||||||
}
|
}
|
||||||
|
@ -117,28 +123,16 @@ int tdbDbcGet(TDBC *pDbc, const void **ppKey, int *pkLen, const void **ppVal, in
|
||||||
return tdbBtcGet(&pDbc->btc, ppKey, pkLen, ppVal, pvLen);
|
return tdbBtcGet(&pDbc->btc, ppKey, pkLen, ppVal, pvLen);
|
||||||
}
|
}
|
||||||
|
|
||||||
int tdbDbcPut(TDBC *pDbc, const void *pKey, int keyLen, const void *pVal, int valLen) {
|
int tdbDbcDelete(TDBC *pDbc) { return tdbBtcDelete(&pDbc->btc); }
|
||||||
// TODO
|
|
||||||
ASSERT(0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int tdbDbcUpdate(TDBC *pDbc, const void *pKey, int kLen, const void *pVal, int vLen) {
|
|
||||||
// TODO
|
|
||||||
ASSERT(0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int tdbDbcDrop(TDBC *pDbc) {
|
|
||||||
// TODO
|
|
||||||
ASSERT(0);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int tdbDbcNext(TDBC *pDbc, void **ppKey, int *kLen, void **ppVal, int *vLen) {
|
int tdbDbcNext(TDBC *pDbc, void **ppKey, int *kLen, void **ppVal, int *vLen) {
|
||||||
return tdbBtreeNext(&pDbc->btc, ppKey, kLen, ppVal, vLen);
|
return tdbBtreeNext(&pDbc->btc, ppKey, kLen, ppVal, vLen);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int tdbDbcUpsert(TDBC *pDbc, const void *pKey, int nKey, const void *pData, int nData, int insert) {
|
||||||
|
return tdbBtcUpsert(&pDbc->btc, pKey, nKey, pData, nData, insert);
|
||||||
|
}
|
||||||
|
|
||||||
int tdbDbcClose(TDBC *pDbc) {
|
int tdbDbcClose(TDBC *pDbc) {
|
||||||
if (pDbc) {
|
if (pDbc) {
|
||||||
tdbBtcClose(&pDbc->btc);
|
tdbBtcClose(&pDbc->btc);
|
||||||
|
|
|
@ -171,6 +171,11 @@ int tdbPageInsertCell(SPage *pPage, int idx, SCell *pCell, int szCell, u8 asOvfl
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int tdbPageUpdateCell(SPage *pPage, int idx, SCell *pCell, int szCell) {
|
||||||
|
tdbPageDropCell(pPage, idx);
|
||||||
|
return tdbPageInsertCell(pPage, idx, pCell, szCell, 0);
|
||||||
|
}
|
||||||
|
|
||||||
int tdbPageDropCell(SPage *pPage, int idx) {
|
int tdbPageDropCell(SPage *pPage, int idx) {
|
||||||
int lidx;
|
int lidx;
|
||||||
SCell *pCell;
|
SCell *pCell;
|
||||||
|
|
|
@ -128,6 +128,8 @@ struct SBTC {
|
||||||
int tdbBtreeOpen(int keyLen, int valLen, SPager *pFile, tdb_cmpr_fn_t kcmpr, SBTree **ppBt);
|
int tdbBtreeOpen(int keyLen, int valLen, SPager *pFile, tdb_cmpr_fn_t kcmpr, SBTree **ppBt);
|
||||||
int tdbBtreeClose(SBTree *pBt);
|
int tdbBtreeClose(SBTree *pBt);
|
||||||
int tdbBtreeInsert(SBTree *pBt, const void *pKey, int kLen, const void *pVal, int vLen, TXN *pTxn);
|
int tdbBtreeInsert(SBTree *pBt, const void *pKey, int kLen, const void *pVal, int vLen, TXN *pTxn);
|
||||||
|
int tdbBtreeDelete(SBTree *pBt, const void *pKey, int kLen, TXN *pTxn);
|
||||||
|
int tdbBtreeUpsert(SBTree *pBt, const void *pKey, int nKey, const void *pData, int nData, TXN *pTxn);
|
||||||
int tdbBtreeGet(SBTree *pBt, const void *pKey, int kLen, void **ppVal, int *vLen);
|
int tdbBtreeGet(SBTree *pBt, const void *pKey, int kLen, void **ppVal, int *vLen);
|
||||||
int tdbBtreePGet(SBTree *pBt, const void *pKey, int kLen, void **ppKey, int *pkLen, void **ppVal, int *vLen);
|
int tdbBtreePGet(SBTree *pBt, const void *pKey, int kLen, void **ppKey, int *pkLen, void **ppVal, int *vLen);
|
||||||
|
|
||||||
|
@ -141,6 +143,8 @@ int tdbBtcMoveToNext(SBTC *pBtc);
|
||||||
int tdbBtcMoveToPrev(SBTC *pBtc);
|
int tdbBtcMoveToPrev(SBTC *pBtc);
|
||||||
int tdbBtreeNext(SBTC *pBtc, void **ppKey, int *kLen, void **ppVal, int *vLen);
|
int tdbBtreeNext(SBTC *pBtc, void **ppKey, int *kLen, void **ppVal, int *vLen);
|
||||||
int tdbBtcGet(SBTC *pBtc, const void **ppKey, int *kLen, const void **ppVal, int *vLen);
|
int tdbBtcGet(SBTC *pBtc, const void **ppKey, int *kLen, const void **ppVal, int *vLen);
|
||||||
|
int tdbBtcDelete(SBTC *pBtc);
|
||||||
|
int tdbBtcUpsert(SBTC *pBtc, const void *pKey, int kLen, const void *pData, int nData, int insert);
|
||||||
|
|
||||||
// tdbPager.c ====================================
|
// tdbPager.c ====================================
|
||||||
|
|
||||||
|
@ -278,6 +282,7 @@ void tdbPageZero(SPage *pPage, u8 szAmHdr, int (*xCellSize)(const SPage *, SCell
|
||||||
void tdbPageInit(SPage *pPage, u8 szAmHdr, int (*xCellSize)(const SPage *, SCell *));
|
void tdbPageInit(SPage *pPage, u8 szAmHdr, int (*xCellSize)(const SPage *, SCell *));
|
||||||
int tdbPageInsertCell(SPage *pPage, int idx, SCell *pCell, int szCell, u8 asOvfl);
|
int tdbPageInsertCell(SPage *pPage, int idx, SCell *pCell, int szCell, u8 asOvfl);
|
||||||
int tdbPageDropCell(SPage *pPage, int idx);
|
int tdbPageDropCell(SPage *pPage, int idx);
|
||||||
|
int tdbPageUpdateCell(SPage *pPage, int idx, SCell *pCell, int szCell);
|
||||||
void tdbPageCopy(SPage *pFromPage, SPage *pToPage);
|
void tdbPageCopy(SPage *pFromPage, SPage *pToPage);
|
||||||
int tdbPageCapacity(int pageSize, int amHdrSize);
|
int tdbPageCapacity(int pageSize, int amHdrSize);
|
||||||
|
|
||||||
|
|
|
@ -115,12 +115,12 @@ static int tDefaultKeyCmpr(const void *pKey1, int keyLen1, const void *pKey2, in
|
||||||
return cret;
|
return cret;
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(tdb_test, simple_test) {
|
TEST(tdb_test, simple_insert1) {
|
||||||
int ret;
|
int ret;
|
||||||
TENV *pEnv;
|
TENV *pEnv;
|
||||||
TDB *pDb;
|
TDB *pDb;
|
||||||
tdb_cmpr_fn_t compFunc;
|
tdb_cmpr_fn_t compFunc;
|
||||||
int nData = 10000000;
|
int nData = 1000000;
|
||||||
TXN txn;
|
TXN txn;
|
||||||
|
|
||||||
taosRemoveDir("tdb");
|
taosRemoveDir("tdb");
|
||||||
|
@ -152,7 +152,7 @@ TEST(tdb_test, simple_test) {
|
||||||
for (int iData = 1; iData <= nData; iData++) {
|
for (int iData = 1; iData <= nData; iData++) {
|
||||||
sprintf(key, "key%d", iData);
|
sprintf(key, "key%d", iData);
|
||||||
sprintf(val, "value%d", iData);
|
sprintf(val, "value%d", iData);
|
||||||
ret = tdbDbPut(pDb, key, strlen(key), val, strlen(val), &txn);
|
ret = tdbDbInsert(pDb, key, strlen(key), val, strlen(val), &txn);
|
||||||
GTEST_ASSERT_EQ(ret, 0);
|
GTEST_ASSERT_EQ(ret, 0);
|
||||||
|
|
||||||
// if pool is full, commit the transaction and start a new one
|
// if pool is full, commit the transaction and start a new one
|
||||||
|
@ -202,6 +202,8 @@ TEST(tdb_test, simple_test) {
|
||||||
ret = tdbDbcOpen(pDb, &pDBC, NULL);
|
ret = tdbDbcOpen(pDb, &pDBC, NULL);
|
||||||
GTEST_ASSERT_EQ(ret, 0);
|
GTEST_ASSERT_EQ(ret, 0);
|
||||||
|
|
||||||
|
tdbDbcMoveToFirst(pDBC);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
ret = tdbDbcNext(pDBC, &pKey, &kLen, &pVal, &vLen);
|
ret = tdbDbcNext(pDBC, &pKey, &kLen, &pVal, &vLen);
|
||||||
if (ret < 0) break;
|
if (ret < 0) break;
|
||||||
|
@ -233,7 +235,7 @@ TEST(tdb_test, simple_test) {
|
||||||
GTEST_ASSERT_EQ(ret, 0);
|
GTEST_ASSERT_EQ(ret, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(tdb_test, simple_test2) {
|
TEST(tdb_test, simple_insert2) {
|
||||||
int ret;
|
int ret;
|
||||||
TENV *pEnv;
|
TENV *pEnv;
|
||||||
TDB *pDb;
|
TDB *pDb;
|
||||||
|
@ -269,7 +271,7 @@ TEST(tdb_test, simple_test2) {
|
||||||
for (int iData = 1; iData <= nData; iData++) {
|
for (int iData = 1; iData <= nData; iData++) {
|
||||||
sprintf(key, "key%d", iData);
|
sprintf(key, "key%d", iData);
|
||||||
sprintf(val, "value%d", iData);
|
sprintf(val, "value%d", iData);
|
||||||
ret = tdbDbPut(pDb, key, strlen(key), val, strlen(val), &txn);
|
ret = tdbDbInsert(pDb, key, strlen(key), val, strlen(val), &txn);
|
||||||
GTEST_ASSERT_EQ(ret, 0);
|
GTEST_ASSERT_EQ(ret, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,13 +285,15 @@ TEST(tdb_test, simple_test2) {
|
||||||
ret = tdbDbcOpen(pDb, &pDBC, NULL);
|
ret = tdbDbcOpen(pDb, &pDBC, NULL);
|
||||||
GTEST_ASSERT_EQ(ret, 0);
|
GTEST_ASSERT_EQ(ret, 0);
|
||||||
|
|
||||||
|
tdbDbcMoveToFirst(pDBC);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
ret = tdbDbcNext(pDBC, &pKey, &kLen, &pVal, &vLen);
|
ret = tdbDbcNext(pDBC, &pKey, &kLen, &pVal, &vLen);
|
||||||
if (ret < 0) break;
|
if (ret < 0) break;
|
||||||
|
|
||||||
std::cout.write((char *)pKey, kLen) /* << " " << kLen */ << " ";
|
// std::cout.write((char *)pKey, kLen) /* << " " << kLen */ << " ";
|
||||||
std::cout.write((char *)pVal, vLen) /* << " " << vLen */;
|
// std::cout.write((char *)pVal, vLen) /* << " " << vLen */;
|
||||||
std::cout << std::endl;
|
// std::cout << std::endl;
|
||||||
|
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
@ -316,4 +320,164 @@ TEST(tdb_test, simple_test2) {
|
||||||
// Close Env
|
// Close Env
|
||||||
ret = tdbEnvClose(pEnv);
|
ret = tdbEnvClose(pEnv);
|
||||||
GTEST_ASSERT_EQ(ret, 0);
|
GTEST_ASSERT_EQ(ret, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(tdb_test, simple_delete1) {
|
||||||
|
int ret;
|
||||||
|
TDB *pDb;
|
||||||
|
char key[128];
|
||||||
|
char data[128];
|
||||||
|
TXN txn;
|
||||||
|
TENV *pEnv;
|
||||||
|
SPoolMem *pPool;
|
||||||
|
void *pKey = NULL;
|
||||||
|
void *pData = NULL;
|
||||||
|
int nKey;
|
||||||
|
TDBC *pDbc;
|
||||||
|
int nData;
|
||||||
|
int nKV = 69;
|
||||||
|
|
||||||
|
taosRemoveDir("tdb");
|
||||||
|
|
||||||
|
pPool = openPool();
|
||||||
|
|
||||||
|
// open env
|
||||||
|
ret = tdbEnvOpen("tdb", 1024, 256, &pEnv);
|
||||||
|
GTEST_ASSERT_EQ(ret, 0);
|
||||||
|
|
||||||
|
// open database
|
||||||
|
ret = tdbDbOpen("db.db", -1, -1, tKeyCmpr, pEnv, &pDb);
|
||||||
|
GTEST_ASSERT_EQ(ret, 0);
|
||||||
|
|
||||||
|
tdbTxnOpen(&txn, 0, poolMalloc, poolFree, pPool, TDB_TXN_WRITE | TDB_TXN_READ_UNCOMMITTED);
|
||||||
|
tdbBegin(pEnv, &txn);
|
||||||
|
|
||||||
|
// loop to insert batch data
|
||||||
|
for (int iData = 0; iData < nKV; iData++) {
|
||||||
|
sprintf(key, "key%d", iData);
|
||||||
|
sprintf(data, "data%d", iData);
|
||||||
|
ret = tdbDbInsert(pDb, key, strlen(key), data, strlen(data), &txn);
|
||||||
|
GTEST_ASSERT_EQ(ret, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// query the data
|
||||||
|
for (int iData = 0; iData < nKV; iData++) {
|
||||||
|
sprintf(key, "key%d", iData);
|
||||||
|
sprintf(data, "data%d", iData);
|
||||||
|
|
||||||
|
ret = tdbDbGet(pDb, key, strlen(key), &pData, &nData);
|
||||||
|
GTEST_ASSERT_EQ(ret, 0);
|
||||||
|
GTEST_ASSERT_EQ(memcmp(data, pData, nData), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// loop to delete some data
|
||||||
|
for (int iData = nKV - 1; iData > 30; iData--) {
|
||||||
|
sprintf(key, "key%d", iData);
|
||||||
|
|
||||||
|
ret = tdbDbDelete(pDb, key, strlen(key), &txn);
|
||||||
|
GTEST_ASSERT_EQ(ret, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// query the data
|
||||||
|
for (int iData = 0; iData < nKV; iData++) {
|
||||||
|
sprintf(key, "key%d", iData);
|
||||||
|
|
||||||
|
ret = tdbDbGet(pDb, key, strlen(key), &pData, &nData);
|
||||||
|
if (iData <= 30) {
|
||||||
|
GTEST_ASSERT_EQ(ret, 0);
|
||||||
|
} else {
|
||||||
|
GTEST_ASSERT_EQ(ret, -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// loop to iterate the data
|
||||||
|
tdbDbcOpen(pDb, &pDbc, NULL);
|
||||||
|
|
||||||
|
ret = tdbDbcMoveToFirst(pDbc);
|
||||||
|
GTEST_ASSERT_EQ(ret, 0);
|
||||||
|
|
||||||
|
pKey = NULL;
|
||||||
|
pData = NULL;
|
||||||
|
for (;;) {
|
||||||
|
ret = tdbDbcNext(pDbc, &pKey, &nKey, &pData, &nData);
|
||||||
|
if (ret < 0) break;
|
||||||
|
|
||||||
|
std::cout.write((char *)pKey, nKey) /* << " " << kLen */ << " ";
|
||||||
|
std::cout.write((char *)pData, nData) /* << " " << vLen */;
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
tdbDbcClose(pDbc);
|
||||||
|
|
||||||
|
tdbCommit(pEnv, &txn);
|
||||||
|
|
||||||
|
closePool(pPool);
|
||||||
|
|
||||||
|
tdbDbClose(pDb);
|
||||||
|
tdbEnvClose(pEnv);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(tdb_test, simple_upsert1) {
|
||||||
|
int ret;
|
||||||
|
TENV *pEnv;
|
||||||
|
TDB *pDb;
|
||||||
|
int nData = 100000;
|
||||||
|
char key[64];
|
||||||
|
char data[64];
|
||||||
|
void *pData = NULL;
|
||||||
|
SPoolMem *pPool;
|
||||||
|
TXN txn;
|
||||||
|
|
||||||
|
taosRemoveDir("tdb");
|
||||||
|
|
||||||
|
// open env
|
||||||
|
ret = tdbEnvOpen("tdb", 4096, 64, &pEnv);
|
||||||
|
GTEST_ASSERT_EQ(ret, 0);
|
||||||
|
|
||||||
|
// open database
|
||||||
|
ret = tdbDbOpen("db.db", -1, -1, NULL, pEnv, &pDb);
|
||||||
|
GTEST_ASSERT_EQ(ret, 0);
|
||||||
|
|
||||||
|
pPool = openPool();
|
||||||
|
// insert some data
|
||||||
|
tdbTxnOpen(&txn, 0, poolMalloc, poolFree, pPool, TDB_TXN_WRITE | TDB_TXN_READ_UNCOMMITTED);
|
||||||
|
tdbBegin(pEnv, &txn);
|
||||||
|
|
||||||
|
for (int iData = 0; iData < nData; iData++) {
|
||||||
|
sprintf(key, "key%d", iData);
|
||||||
|
sprintf(data, "data%d", iData);
|
||||||
|
ret = tdbDbInsert(pDb, key, strlen(key), data, strlen(data), &txn);
|
||||||
|
GTEST_ASSERT_EQ(ret, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// query the data
|
||||||
|
for (int iData = 0; iData < nData; iData++) {
|
||||||
|
sprintf(key, "key%d", iData);
|
||||||
|
sprintf(data, "data%d", iData);
|
||||||
|
ret = tdbDbGet(pDb, key, strlen(key), &pData, &nData);
|
||||||
|
GTEST_ASSERT_EQ(ret, 0);
|
||||||
|
GTEST_ASSERT_EQ(memcmp(pData, data, nData), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// upsert some data
|
||||||
|
for (int iData = 0; iData < nData; iData++) {
|
||||||
|
sprintf(key, "key%d", iData);
|
||||||
|
sprintf(data, "data%d-u", iData);
|
||||||
|
ret = tdbDbUpsert(pDb, key, strlen(key), data, strlen(data), &txn);
|
||||||
|
GTEST_ASSERT_EQ(ret, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
tdbCommit(pEnv, &txn);
|
||||||
|
|
||||||
|
// query the data
|
||||||
|
for (int iData = 0; iData < nData; iData++) {
|
||||||
|
sprintf(key, "key%d", iData);
|
||||||
|
sprintf(data, "data%d-u", iData);
|
||||||
|
ret = tdbDbGet(pDb, key, strlen(key), &pData, &nData);
|
||||||
|
GTEST_ASSERT_EQ(ret, 0);
|
||||||
|
GTEST_ASSERT_EQ(memcmp(pData, data, nData), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
tdbDbClose(pDb);
|
||||||
|
tdbEnvClose(pEnv);
|
||||||
}
|
}
|
|
@ -271,7 +271,8 @@ TAOS_DEFINE_ERROR(TSDB_CODE_MND_INVALID_FUNC_RETRIEVE, "Invalid func retrieve
|
||||||
TAOS_DEFINE_ERROR(TSDB_CODE_MND_TRANS_ALREADY_EXIST, "Transaction already exists")
|
TAOS_DEFINE_ERROR(TSDB_CODE_MND_TRANS_ALREADY_EXIST, "Transaction already exists")
|
||||||
TAOS_DEFINE_ERROR(TSDB_CODE_MND_TRANS_NOT_EXIST, "Transaction not exists")
|
TAOS_DEFINE_ERROR(TSDB_CODE_MND_TRANS_NOT_EXIST, "Transaction not exists")
|
||||||
TAOS_DEFINE_ERROR(TSDB_CODE_MND_TRANS_INVALID_STAGE, "Invalid stage to kill")
|
TAOS_DEFINE_ERROR(TSDB_CODE_MND_TRANS_INVALID_STAGE, "Invalid stage to kill")
|
||||||
TAOS_DEFINE_ERROR(TSDB_CODE_MND_TRANS_CAN_NOT_PARALLEL, "Conflicting transaction not completed")
|
TAOS_DEFINE_ERROR(TSDB_CODE_MND_TRANS_CONFLICT, "Conflict transaction not completed")
|
||||||
|
TAOS_DEFINE_ERROR(TSDB_CODE_MND_TRANS_UNKNOW_ERROR, "Unknown transaction error")
|
||||||
|
|
||||||
// mnode-mq
|
// mnode-mq
|
||||||
TAOS_DEFINE_ERROR(TSDB_CODE_MND_TOPIC_ALREADY_EXIST, "Topic already exists")
|
TAOS_DEFINE_ERROR(TSDB_CODE_MND_TOPIC_ALREADY_EXIST, "Topic already exists")
|
||||||
|
|
|
@ -0,0 +1,175 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "tskiplist2.h"
|
||||||
|
|
||||||
|
struct SSLNode {
|
||||||
|
int8_t level;
|
||||||
|
SSLNode *forwards[];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SSkipList2 {
|
||||||
|
int8_t level;
|
||||||
|
uint32_t seed;
|
||||||
|
int32_t size;
|
||||||
|
const SSLCfg *pCfg;
|
||||||
|
SSLNode *pHead[];
|
||||||
|
};
|
||||||
|
|
||||||
|
static void *slMalloc(void *pPool, int32_t size);
|
||||||
|
static void slFree(void *pPool, void *p);
|
||||||
|
static int32_t slCmprFn(const void *pKey, int32_t nKey, const void *pData, int32_t nData);
|
||||||
|
|
||||||
|
const SSLCfg slDefaultCfg = {.maxLevel = SL_MAX_LEVEL,
|
||||||
|
.nKey = -1,
|
||||||
|
.nData = -1,
|
||||||
|
.cmprFn = slCmprFn,
|
||||||
|
.pPool = NULL,
|
||||||
|
.xMalloc = slMalloc,
|
||||||
|
.xFree = slFree};
|
||||||
|
|
||||||
|
int32_t slOpen(const SSLCfg *pCfg, SSkipList2 **ppSl) {
|
||||||
|
SSkipList2 *pSl = NULL;
|
||||||
|
int32_t size;
|
||||||
|
|
||||||
|
*ppSl = NULL;
|
||||||
|
if (pCfg == NULL) pCfg = &slDefaultCfg;
|
||||||
|
|
||||||
|
// check config (TODO)
|
||||||
|
|
||||||
|
// malloc handle
|
||||||
|
size = sizeof(*pSl) + sizeof(SSLNode *) * pCfg->maxLevel * 2;
|
||||||
|
pSl = pCfg->xMalloc(pCfg->pPool, size);
|
||||||
|
if (pSl == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
pSl->level = 0;
|
||||||
|
pSl->seed = taosRand();
|
||||||
|
pSl->size = 0;
|
||||||
|
pSl->pCfg = pCfg;
|
||||||
|
|
||||||
|
// init an empty skiplist
|
||||||
|
for (int32_t i = 0; i < pCfg->maxLevel * 2; i++) {
|
||||||
|
pSl->pHead[i] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
*ppSl = pSl;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t slClose(SSkipList2 *pSl) {
|
||||||
|
if (pSl) {
|
||||||
|
slClear(pSl);
|
||||||
|
if (pSl->pCfg->xFree) {
|
||||||
|
pSl->pCfg->xFree(pSl->pCfg->pPool, pSl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t slClear(SSkipList2 *pSl) {
|
||||||
|
// loop to clear sl
|
||||||
|
for (;;) {
|
||||||
|
// (TODO)
|
||||||
|
}
|
||||||
|
|
||||||
|
// init sl (TODO)
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t slcOpen(SSkipList2 *pSl, SSLCursor *pSlc) {
|
||||||
|
pSlc->pSl = pSl;
|
||||||
|
|
||||||
|
for (int i = 0; i < SL_MAX_LEVEL; i++) {
|
||||||
|
if (i < pSl->pCfg->maxLevel) {
|
||||||
|
} else {
|
||||||
|
pSlc->forwards[i] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t slcClose(SSLCursor *pSlc) {
|
||||||
|
// TODO
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t slcMoveTo(SSLCursor *pSlc, const void *pKey, int32_t nKey) {
|
||||||
|
// TODO
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t slcMoveToNext(SSLCursor *pSlc) {
|
||||||
|
// TODO
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t slcMoveToPrev(SSLCursor *pSlc) {
|
||||||
|
// TODO
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t slcMoveToFirst(SSLCursor *pSlc) {
|
||||||
|
// TODO
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t slcMoveToLast(SSLCursor *pSlc) {
|
||||||
|
// TODO
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t slcPut(SSLCursor *pSlc, const void *pKey, int32_t nKey, const void *pData, int32_t nData) {
|
||||||
|
// TODO
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t slcGet(SSLCursor *pSlc, const void **ppKey, int32_t *nKey, const void **ppData, int32_t *nData) {
|
||||||
|
// TODO
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t slcDrop(SSLCursor *pSlc) {
|
||||||
|
// TODO
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static FORCE_INLINE void *slMalloc(void *pPool, int32_t size) { return taosMemoryMalloc(size); }
|
||||||
|
|
||||||
|
static FORCE_INLINE void slFree(void *pPool, void *p) { taosMemoryFree(p); }
|
||||||
|
|
||||||
|
static int32_t slCmprFn(const void *pKey1, int32_t nKey1, const void *pKey2, int32_t nKey2) {
|
||||||
|
ASSERT(nKey1 >= 0 && nKey2 >= 0);
|
||||||
|
|
||||||
|
int32_t nKey = nKey1 > nKey2 ? nKey2 : nKey1;
|
||||||
|
int32_t c;
|
||||||
|
|
||||||
|
c = memcmp(pKey1, pKey2, nKey);
|
||||||
|
if (c == 0) {
|
||||||
|
if (nKey1 > nKey2) {
|
||||||
|
c = 1;
|
||||||
|
} else if (nKey1 < nKey2) {
|
||||||
|
c = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
|
@ -1 +1 @@
|
||||||
Subproject commit bf6c766986c61ff4fc80421fdea682a8fd4b5b32
|
Subproject commit 2f3dfddd4d9a869e706ba3cf98fb6d769404cd7c
|
Loading…
Reference in New Issue