From 966a5e180b21c375dea3465ab291bcde23064ae1 Mon Sep 17 00:00:00 2001 From: Shengliang Guan Date: Tue, 15 Dec 2020 16:03:52 +0800 Subject: [PATCH 01/38] rename some files --- src/sync/CMakeLists.txt | 6 ++-- src/sync/inc/{taosTcpPool.h => syncTcp.h} | 15 ++++---- .../src/{tarbitrator.c => syncArbitrator.c} | 22 ++++++------ src/sync/src/syncMain.c | 24 ++++++------- src/sync/src/{taosTcpPool.c => syncTcp.c} | 36 +++++++++---------- 5 files changed, 50 insertions(+), 53 deletions(-) rename src/sync/inc/{taosTcpPool.h => syncTcp.h} (77%) rename src/sync/src/{tarbitrator.c => syncArbitrator.c} (90%) rename src/sync/src/{taosTcpPool.c => syncTcp.c} (89%) diff --git a/src/sync/CMakeLists.txt b/src/sync/CMakeLists.txt index 60271c771c..aa38a56f38 100644 --- a/src/sync/CMakeLists.txt +++ b/src/sync/CMakeLists.txt @@ -5,12 +5,12 @@ INCLUDE_DIRECTORIES(inc) AUX_SOURCE_DIRECTORY(src SRC) IF (TD_LINUX) - LIST(REMOVE_ITEM SRC src/tarbitrator.c) + LIST(REMOVE_ITEM SRC src/syncArbitrator.c) ADD_LIBRARY(sync ${SRC}) TARGET_LINK_LIBRARIES(sync tutil pthread common) - LIST(APPEND BIN_SRC src/tarbitrator.c) - LIST(APPEND BIN_SRC src/taosTcpPool.c) + LIST(APPEND BIN_SRC src/syncArbitrator.c) + LIST(APPEND BIN_SRC src/syncTcp.c) ADD_EXECUTABLE(tarbitrator ${BIN_SRC}) TARGET_LINK_LIBRARIES(tarbitrator sync common osdetail tutil) diff --git a/src/sync/inc/taosTcpPool.h b/src/sync/inc/syncTcp.h similarity index 77% rename from src/sync/inc/taosTcpPool.h rename to src/sync/inc/syncTcp.h index 41043b0cd4..7db51f2a71 100644 --- a/src/sync/inc/taosTcpPool.h +++ b/src/sync/inc/syncTcp.h @@ -13,16 +13,13 @@ * along with this program. If not, see . */ -#ifndef TDENGINE_TCP_POOL_H -#define TDENGINE_TCP_POOL_H +#ifndef TDENGINE_SYNC_TCP_POOL_H +#define TDENGINE_SYNC_TCP_POOL_H #ifdef __cplusplus extern "C" { #endif -typedef void *ttpool_h; -typedef void *tthread_h; - typedef struct { int32_t numOfThreads; uint32_t serverIp; @@ -33,10 +30,10 @@ typedef struct { void (*processIncomingConn)(int32_t fd, uint32_t ip); } SPoolInfo; -ttpool_h taosOpenTcpThreadPool(SPoolInfo *pInfo); -void taosCloseTcpThreadPool(ttpool_h); -void * taosAllocateTcpConn(void *, void *ahandle, int32_t connFd); -void taosFreeTcpConn(void *); +void *syncOpenTcpThreadPool(SPoolInfo *pInfo); +void syncCloseTcpThreadPool(void *); +void *syncAllocateTcpConn(void *, void *ahandle, int32_t connFd); +void syncFreeTcpConn(void *); #ifdef __cplusplus } diff --git a/src/sync/src/tarbitrator.c b/src/sync/src/syncArbitrator.c similarity index 90% rename from src/sync/src/tarbitrator.c rename to src/sync/src/syncArbitrator.c index 4016042de2..971fac26aa 100644 --- a/src/sync/src/tarbitrator.c +++ b/src/sync/src/syncArbitrator.c @@ -22,17 +22,17 @@ #include "tsocket.h" #include "tglobal.h" #include "taoserror.h" -#include "taosTcpPool.h" #include "twal.h" #include "tsync.h" #include "syncInt.h" +#include "syncTcp.h" -static void arbSignalHandler(int32_t signum, siginfo_t *sigInfo, void *context); -static void arbProcessIncommingConnection(int32_t connFd, uint32_t sourceIp); -static void arbProcessBrokenLink(void *param); -static int32_t arbProcessPeerMsg(void *param, void *buffer); -static tsem_t tsArbSem; -static ttpool_h tsArbTcpPool; +static void arbSignalHandler(int32_t signum, siginfo_t *sigInfo, void *context); +static void arbProcessIncommingConnection(int32_t connFd, uint32_t sourceIp); +static void arbProcessBrokenLink(void *param); +static int32_t arbProcessPeerMsg(void *param, void *buffer); +static tsem_t tsArbSem; +static void * tsArbTcpPool; typedef struct { char id[TSDB_EP_LEN + 24]; @@ -90,7 +90,7 @@ int32_t main(int32_t argc, char *argv[]) { info.processBrokenLink = arbProcessBrokenLink; info.processIncomingMsg = arbProcessPeerMsg; info.processIncomingConn = arbProcessIncommingConnection; - tsArbTcpPool = taosOpenTcpThreadPool(&info); + tsArbTcpPool = syncOpenTcpThreadPool(&info); if (tsArbTcpPool == NULL) { sDebug("failed to open TCP thread pool, exit..."); @@ -101,8 +101,8 @@ int32_t main(int32_t argc, char *argv[]) { tsem_wait(&tsArbSem); - taosCloseTcpThreadPool(tsArbTcpPool); - sInfo("TAOS arbitrator is shut down\n"); + syncCloseTcpThreadPool(tsArbTcpPool); + sInfo("TAOS arbitrator is shut down"); closelog(); return 0; @@ -138,7 +138,7 @@ static void arbProcessIncommingConnection(int32_t connFd, uint32_t sourceIp) { sDebug("%s, arbitrator request is accepted", pNode->id); pNode->nodeFd = connFd; - pNode->pConn = taosAllocateTcpConn(tsArbTcpPool, pNode, connFd); + pNode->pConn = syncAllocateTcpConn(tsArbTcpPool, pNode, connFd); return; } diff --git a/src/sync/src/syncMain.c b/src/sync/src/syncMain.c index aae5dab3cd..847dbc2f5d 100644 --- a/src/sync/src/syncMain.c +++ b/src/sync/src/syncMain.c @@ -23,10 +23,10 @@ #include "tsocket.h" #include "tglobal.h" #include "taoserror.h" -#include "taosTcpPool.h" #include "tqueue.h" #include "twal.h" #include "tsync.h" +#include "syncTcp.h" #include "syncInt.h" // global configurable @@ -39,10 +39,10 @@ int32_t tsSyncTimer = 1; int32_t tsSyncNum; // number of sync in process in whole system char tsNodeFqdn[TSDB_FQDN_LEN]; -static ttpool_h tsTcpPool; -static void * tsSyncTmrCtrl = NULL; -static void * tsVgIdHash; -static int32_t tsSyncRefId = -1; +static void * tsTcpPool; +static void * tsSyncTmrCtrl = NULL; +static void * tsVgIdHash; +static int32_t tsSyncRefId = -1; // local functions static void syncProcessSyncRequest(char *pMsg, SSyncPeer *pPeer); @@ -117,7 +117,7 @@ int32_t syncInit() { info.processIncomingMsg = syncProcessPeerMsg; info.processIncomingConn = syncProcessIncommingConnection; - tsTcpPool = taosOpenTcpThreadPool(&info); + tsTcpPool = syncOpenTcpThreadPool(&info); if (tsTcpPool == NULL) { sError("failed to init tcpPool"); return -1; @@ -126,7 +126,7 @@ int32_t syncInit() { tsSyncTmrCtrl = taosTmrInit(1000, 50, 10000, "SYNC"); if (tsSyncTmrCtrl == NULL) { sError("failed to init tmrCtrl"); - taosCloseTcpThreadPool(tsTcpPool); + syncCloseTcpThreadPool(tsTcpPool); tsTcpPool = NULL; return -1; } @@ -135,7 +135,7 @@ int32_t syncInit() { if (tsVgIdHash == NULL) { sError("failed to init tsVgIdHash"); taosTmrCleanUp(tsSyncTmrCtrl); - taosCloseTcpThreadPool(tsTcpPool); + syncCloseTcpThreadPool(tsTcpPool); tsTcpPool = NULL; tsSyncTmrCtrl = NULL; return -1; @@ -155,7 +155,7 @@ int32_t syncInit() { void syncCleanUp() { if (tsTcpPool) { - taosCloseTcpThreadPool(tsTcpPool); + syncCloseTcpThreadPool(tsTcpPool); tsTcpPool = NULL; } @@ -509,7 +509,7 @@ static void syncClosePeerConn(SSyncPeer *pPeer) { taosClose(pPeer->syncFd); if (pPeer->peerFd >= 0) { pPeer->peerFd = -1; - taosFreeTcpConn(pPeer->pConn); + syncFreeTcpConn(pPeer->pConn); } } @@ -1065,7 +1065,7 @@ static void syncSetupPeerConnection(SSyncPeer *pPeer) { sDebug("%s, connection to peer server is setup, pfd:%d sfd:%d tranId:%u", pPeer->id, connFd, pPeer->syncFd, firstPkt.tranId); pPeer->peerFd = connFd; pPeer->role = TAOS_SYNC_ROLE_UNSYNCED; - pPeer->pConn = taosAllocateTcpConn(tsTcpPool, pPeer, connFd); + pPeer->pConn = syncAllocateTcpConn(tsTcpPool, pPeer, connFd); syncAddPeerRef(pPeer); } else { sDebug("%s, failed to setup peer connection to server since %s, try later", pPeer->id, strerror(errno)); @@ -1159,7 +1159,7 @@ static void syncProcessIncommingConnection(int32_t connFd, uint32_t sourceIp) { sDebug("%s, TCP connection is up, pfd:%d sfd:%d, old pfd:%d", pPeer->id, connFd, pPeer->syncFd, pPeer->peerFd); syncClosePeerConn(pPeer); pPeer->peerFd = connFd; - pPeer->pConn = taosAllocateTcpConn(tsTcpPool, pPeer, connFd); + pPeer->pConn = syncAllocateTcpConn(tsTcpPool, pPeer, connFd); syncAddPeerRef(pPeer); sDebug("%s, ready to exchange data", pPeer->id); syncSendPeersStatusMsgToPeer(pPeer, 1, SYNC_STATUS_EXCHANGE_DATA, syncGenTranId()); diff --git a/src/sync/src/taosTcpPool.c b/src/sync/src/syncTcp.c similarity index 89% rename from src/sync/src/taosTcpPool.c rename to src/sync/src/syncTcp.c index eb05cf7c6f..7bfdc4e440 100644 --- a/src/sync/src/taosTcpPool.c +++ b/src/sync/src/syncTcp.c @@ -19,10 +19,10 @@ #include "tutil.h" #include "tsocket.h" #include "taoserror.h" -#include "taosTcpPool.h" #include "twal.h" #include "tsync.h" #include "syncInt.h" +#include "syncTcp.h" typedef struct SThreadObj { pthread_t thread; @@ -47,12 +47,12 @@ typedef struct { int32_t closedByApp; } SConnObj; -static void *taosAcceptPeerTcpConnection(void *argv); -static void *taosProcessTcpData(void *param); -static void taosStopPoolThread(SThreadObj *pThread); -static SThreadObj *taosGetTcpThread(SPoolObj *pPool); +static void *syncAcceptPeerTcpConnection(void *argv); +static void *syncProcessTcpData(void *param); +static void syncStopPoolThread(SThreadObj *pThread); +static SThreadObj *syncGetTcpThread(SPoolObj *pPool); -void *taosOpenTcpThreadPool(SPoolInfo *pInfo) { +void *syncOpenTcpThreadPool(SPoolInfo *pInfo) { pthread_attr_t thattr; SPoolObj *pPool = calloc(sizeof(SPoolObj), 1); @@ -80,7 +80,7 @@ void *taosOpenTcpThreadPool(SPoolInfo *pInfo) { pthread_attr_init(&thattr); pthread_attr_setdetachstate(&thattr, PTHREAD_CREATE_JOINABLE); - if (pthread_create(&(pPool->thread), &thattr, (void *)taosAcceptPeerTcpConnection, pPool) != 0) { + if (pthread_create(&(pPool->thread), &thattr, (void *)syncAcceptPeerTcpConnection, pPool) != 0) { sError("failed to create accept thread for TCP server since %s", strerror(errno)); close(pPool->acceptFd); tfree(pPool->pThread); @@ -94,7 +94,7 @@ void *taosOpenTcpThreadPool(SPoolInfo *pInfo) { return pPool; } -void taosCloseTcpThreadPool(void *param) { +void syncCloseTcpThreadPool(void *param) { SPoolObj * pPool = param; SThreadObj *pThread; @@ -103,7 +103,7 @@ void taosCloseTcpThreadPool(void *param) { for (int32_t i = 0; i < pPool->info.numOfThreads; ++i) { pThread = pPool->pThread[i]; - if (pThread) taosStopPoolThread(pThread); + if (pThread) syncStopPoolThread(pThread); } sDebug("%p TCP pool is closed", pPool); @@ -112,7 +112,7 @@ void taosCloseTcpThreadPool(void *param) { tfree(pPool); } -void *taosAllocateTcpConn(void *param, void *pPeer, int32_t connFd) { +void *syncAllocateTcpConn(void *param, void *pPeer, int32_t connFd) { struct epoll_event event; SPoolObj *pPool = param; @@ -122,7 +122,7 @@ void *taosAllocateTcpConn(void *param, void *pPeer, int32_t connFd) { return NULL; } - SThreadObj *pThread = taosGetTcpThread(pPool); + SThreadObj *pThread = syncGetTcpThread(pPool); if (pThread == NULL) { tfree(pConn); return NULL; @@ -149,7 +149,7 @@ void *taosAllocateTcpConn(void *param, void *pPeer, int32_t connFd) { return pConn; } -void taosFreeTcpConn(void *param) { +void syncFreeTcpConn(void *param) { SConnObj * pConn = param; SThreadObj *pThread = pConn->pThread; @@ -175,7 +175,7 @@ static void taosProcessBrokenLink(SConnObj *pConn) { #define maxEvents 10 -static void *taosProcessTcpData(void *param) { +static void *syncProcessTcpData(void *param) { SThreadObj *pThread = (SThreadObj *)param; SPoolObj * pPool = pThread->pPool; SPoolInfo * pInfo = &pPool->info; @@ -222,7 +222,7 @@ static void *taosProcessTcpData(void *param) { if (pConn->closedByApp == 0) { if ((*pInfo->processIncomingMsg)(pConn->ahandle, buffer) < 0) { - taosFreeTcpConn(pConn); + syncFreeTcpConn(pConn); continue; } } @@ -239,7 +239,7 @@ static void *taosProcessTcpData(void *param) { return NULL; } -static void *taosAcceptPeerTcpConnection(void *argv) { +static void *syncAcceptPeerTcpConnection(void *argv) { SPoolObj * pPool = (SPoolObj *)argv; SPoolInfo *pInfo = &pPool->info; @@ -268,7 +268,7 @@ static void *taosAcceptPeerTcpConnection(void *argv) { return NULL; } -static SThreadObj *taosGetTcpThread(SPoolObj *pPool) { +static SThreadObj *syncGetTcpThread(SPoolObj *pPool) { SThreadObj *pThread = pPool->pThread[pPool->nextId]; if (pThread) return pThread; @@ -286,7 +286,7 @@ static SThreadObj *taosGetTcpThread(SPoolObj *pPool) { pthread_attr_t thattr; pthread_attr_init(&thattr); pthread_attr_setdetachstate(&thattr, PTHREAD_CREATE_JOINABLE); - int32_t ret = pthread_create(&(pThread->thread), &thattr, (void *)taosProcessTcpData, pThread); + int32_t ret = pthread_create(&(pThread->thread), &thattr, (void *)syncProcessTcpData, pThread); pthread_attr_destroy(&thattr); if (ret != 0) { @@ -303,7 +303,7 @@ static SThreadObj *taosGetTcpThread(SPoolObj *pPool) { return pThread; } -static void taosStopPoolThread(SThreadObj *pThread) { +static void syncStopPoolThread(SThreadObj *pThread) { pthread_t thread = pThread->thread; if (!taosCheckPthreadValid(thread)) { return; From e8d9017dc765c8139921d0dd9fa0ad04d1c1c09c Mon Sep 17 00:00:00 2001 From: Shengliang Guan Date: Tue, 15 Dec 2020 17:11:02 +0800 Subject: [PATCH 02/38] TD-2428 --- src/sync/inc/syncInt.h | 22 +++++---- src/sync/src/syncArbitrator.c | 16 +++---- src/sync/src/syncMain.c | 87 ++++++++++++++++++----------------- src/sync/src/syncRestore.c | 8 ++-- src/sync/src/syncRetrieve.c | 30 ++++++------ src/sync/test/syncServer.c | 4 +- 6 files changed, 87 insertions(+), 80 deletions(-) diff --git a/src/sync/inc/syncInt.h b/src/sync/inc/syncInt.h index 2be25447c4..c00015552f 100644 --- a/src/sync/inc/syncInt.h +++ b/src/sync/inc/syncInt.h @@ -43,6 +43,7 @@ typedef enum { #define SYNC_FWD_TIMER 300 #define SYNC_ROLE_TIMER 10000 #define SYNC_WAIT_AFTER_CHOOSE_MASTER 3 +#define SYNC_PROTOCOL_VERSION 0 #define nodeRole pNode->peerInfo[pNode->selfIndex]->role #define nodeVersion pNode->peerInfo[pNode->selfIndex]->version @@ -51,27 +52,27 @@ typedef enum { #pragma pack(push, 1) typedef struct { - char type; // msg type - char pversion; // protocol version - char reserved[6]; // not used + int8_t type; // msg type + int8_t protocol; // protocol version + int8_t reserved[6]; // not used int32_t vgId; // vg ID int32_t len; // content length, does not include head - // char cont[]; // message content starts from here } SSyncHead; typedef struct { - SSyncHead syncHead; + SSyncHead head; uint16_t port; uint16_t tranId; char fqdn[TSDB_FQDN_LEN]; int32_t sourceId; // only for arbitrator -} SFirstPkt; +} SSyncMsg; typedef struct { - int8_t sync; - int8_t reserved; - uint16_t tranId; -} SFirstPktRsp; + SSyncHead head; + int8_t sync; + int8_t reserved; + uint16_t tranId; +} SSyncRsp; typedef struct { int8_t role; @@ -101,6 +102,7 @@ typedef struct { } SFileAck; typedef struct { + SSyncHead head; uint64_t version; int32_t code; } SFwdRsp; diff --git a/src/sync/src/syncArbitrator.c b/src/sync/src/syncArbitrator.c index 971fac26aa..1cb2b8f302 100644 --- a/src/sync/src/syncArbitrator.c +++ b/src/sync/src/syncArbitrator.c @@ -113,9 +113,9 @@ static void arbProcessIncommingConnection(int32_t connFd, uint32_t sourceIp) { tinet_ntoa(ipstr, sourceIp); sDebug("peer TCP connection from ip:%s", ipstr); - SFirstPkt firstPkt; - if (taosReadMsg(connFd, &firstPkt, sizeof(firstPkt)) != sizeof(firstPkt)) { - sError("failed to read peer first pkt from ip:%s since %s", ipstr, strerror(errno)); + SSyncMsg msg; + if (taosReadMsg(connFd, &msg, sizeof(SSyncMsg)) != sizeof(SSyncMsg)) { + sError("failed to read peer sync msg from ip:%s since %s", ipstr, strerror(errno)); taosCloseSocket(connFd); return; } @@ -127,9 +127,9 @@ static void arbProcessIncommingConnection(int32_t connFd, uint32_t sourceIp) { return; } - firstPkt.fqdn[sizeof(firstPkt.fqdn) - 1] = 0; - snprintf(pNode->id, sizeof(pNode->id), "vgId:%d, peer:%s:%d", firstPkt.sourceId, firstPkt.fqdn, firstPkt.port); - if (firstPkt.syncHead.vgId) { + msg.fqdn[TSDB_FQDN_LEN - 1] = 0; + snprintf(pNode->id, sizeof(pNode->id), "vgId:%d, peer:%s:%d", msg.sourceId, msg.fqdn, msg.port); + if (msg.head.vgId) { sDebug("%s, vgId in head is not zero, close the connection", pNode->id); tfree(pNode); taosCloseSocket(connFd); @@ -156,8 +156,8 @@ static int32_t arbProcessPeerMsg(void *param, void *buffer) { int32_t bytes = 0; char * cont = (char *)buffer; - int32_t hlen = taosReadMsg(pNode->nodeFd, &head, sizeof(head)); - if (hlen != sizeof(head)) { + int32_t hlen = taosReadMsg(pNode->nodeFd, &head, sizeof(SSyncHead)); + if (hlen != sizeof(SSyncHead)) { sDebug("%s, failed to read msg, hlen:%d", pNode->id, hlen); return -1; } diff --git a/src/sync/src/syncMain.c b/src/sync/src/syncMain.c index 847dbc2f5d..5e3355e68f 100644 --- a/src/sync/src/syncMain.c +++ b/src/sync/src/syncMain.c @@ -384,18 +384,16 @@ void syncConfirmForward(int64_t rid, uint64_t version, int32_t code) { SSyncPeer *pPeer = pNode->pMaster; if (pPeer && pNode->quorum > 1) { - char msg[sizeof(SSyncHead) + sizeof(SFwdRsp)] = {0}; + SFwdRsp fwdRsp = {0}; - SSyncHead *pHead = (SSyncHead *)msg; - pHead->type = TAOS_SMSG_FORWARD_RSP; - pHead->len = sizeof(SFwdRsp); + fwdRsp.head.type = TAOS_SMSG_FORWARD_RSP; + fwdRsp.head.protocol = SYNC_PROTOCOL_VERSION; + fwdRsp.head.vgId = pNode->vgId; + fwdRsp.head.len = sizeof(SFwdRsp) - sizeof(SSyncHead); + fwdRsp.version = version; + fwdRsp.code = code; - SFwdRsp *pFwdRsp = (SFwdRsp *)(msg + sizeof(SSyncHead)); - pFwdRsp->version = version; - pFwdRsp->code = code; - - int32_t msgLen = sizeof(SSyncHead) + sizeof(SFwdRsp); - if (taosWriteMsg(pPeer->peerFd, msg, msgLen) == msgLen) { + if (taosWriteMsg(pPeer->peerFd, &fwdRsp, sizeof(SFwdRsp)) == sizeof(SFwdRsp)) { sTrace("%s, forward-rsp is sent, code:%x hver:%" PRIu64, pPeer->id, code, version); } else { sDebug("%s, failed to send forward ack, restart", pPeer->id); @@ -865,20 +863,22 @@ static void syncRecoverFromMaster(SSyncPeer *pPeer) { sDebug("%s, try to sync", pPeer->id); - SFirstPkt firstPkt; - memset(&firstPkt, 0, sizeof(firstPkt)); - firstPkt.syncHead.type = TAOS_SMSG_SYNC_REQ; - firstPkt.syncHead.vgId = pNode->vgId; - firstPkt.syncHead.len = sizeof(firstPkt) - sizeof(SSyncHead); - firstPkt.tranId = syncGenTranId(); - tstrncpy(firstPkt.fqdn, tsNodeFqdn, sizeof(firstPkt.fqdn)); - firstPkt.port = tsSyncPort; + SSyncMsg msg; + memset(&msg, 0, sizeof(SSyncMsg)); + msg.head.type = TAOS_SMSG_SYNC_REQ; + msg.head.protocol = SYNC_PROTOCOL_VERSION; + msg.head.vgId = pNode->vgId; + msg.head.len = sizeof(SSyncMsg) - sizeof(SSyncHead); + msg.port = tsSyncPort; + msg.tranId = syncGenTranId(); + tstrncpy(msg.fqdn, tsNodeFqdn, TSDB_FQDN_LEN); + taosTmrReset(syncNotStarted, tsSyncTimer * 1000, pPeer, tsSyncTmrCtrl, &pPeer->timer); - if (taosWriteMsg(pPeer->peerFd, &firstPkt, sizeof(firstPkt)) != sizeof(firstPkt)) { + if (taosWriteMsg(pPeer->peerFd, &msg, sizeof(SSyncMsg)) != sizeof(SSyncMsg)) { sError("%s, failed to send sync-req to peer", pPeer->id); } else { - sInfo("%s, sync-req is sent to peer, tranId:%u, sstatus:%s", pPeer->id, firstPkt.tranId, syncStatus[nodeSStatus]); + sInfo("%s, sync-req is sent to peer, tranId:%u, sstatus:%s", pPeer->id, msg.tranId, syncStatus[nodeSStatus]); } } @@ -958,7 +958,7 @@ static int32_t syncReadPeerMsg(SSyncPeer *pPeer, SSyncHead *pHead, char *cont) { // head.len = htonl(head.len); if (pHead->len < 0) { - sError("%s, invalid pkt length, hlen:%d", pPeer->id, pHead->len); + sError("%s, invalid msg length, hlen:%d", pPeer->id, pHead->len); return -1; } @@ -1052,17 +1052,19 @@ static void syncSetupPeerConnection(SSyncPeer *pPeer) { return; } - SFirstPkt firstPkt; - memset(&firstPkt, 0, sizeof(firstPkt)); - firstPkt.syncHead.vgId = pPeer->nodeId ? pNode->vgId : 0; - firstPkt.syncHead.type = TAOS_SMSG_STATUS; - tstrncpy(firstPkt.fqdn, tsNodeFqdn, sizeof(firstPkt.fqdn)); - firstPkt.port = tsSyncPort; - firstPkt.tranId = syncGenTranId(); - firstPkt.sourceId = pNode->vgId; // tell arbitrator its vgId + SSyncMsg msg; + memset(&msg, 0, sizeof(SSyncMsg)); + msg.head.type = TAOS_SMSG_STATUS; + msg.head.protocol = SYNC_PROTOCOL_VERSION; + msg.head.vgId = pPeer->nodeId ? pNode->vgId : 0; + msg.head.len = sizeof(SSyncMsg) - sizeof(SSyncHead); + msg.port = tsSyncPort; + msg.tranId = syncGenTranId(); + msg.sourceId = pNode->vgId; // tell arbitrator its vgId + tstrncpy(msg.fqdn, tsNodeFqdn, TSDB_FQDN_LEN); - if (taosWriteMsg(connFd, &firstPkt, sizeof(firstPkt)) == sizeof(firstPkt)) { - sDebug("%s, connection to peer server is setup, pfd:%d sfd:%d tranId:%u", pPeer->id, connFd, pPeer->syncFd, firstPkt.tranId); + if (taosWriteMsg(connFd, &msg, sizeof(SSyncMsg)) == sizeof(SSyncMsg)) { + sDebug("%s, connection to peer server is setup, pfd:%d sfd:%d tranId:%u", pPeer->id, connFd, pPeer->syncFd, msg.tranId); pPeer->peerFd = connFd; pPeer->role = TAOS_SYNC_ROLE_UNSYNCED; pPeer->pConn = syncAllocateTcpConn(tsTcpPool, pPeer, connFd); @@ -1116,14 +1118,14 @@ static void syncProcessIncommingConnection(int32_t connFd, uint32_t sourceIp) { tinet_ntoa(ipstr, sourceIp); sDebug("peer TCP connection from ip:%s", ipstr); - SFirstPkt firstPkt; - if (taosReadMsg(connFd, &firstPkt, sizeof(firstPkt)) != sizeof(firstPkt)) { - sError("failed to read peer first pkt from ip:%s since %s", ipstr, strerror(errno)); + SSyncMsg msg; + if (taosReadMsg(connFd, &msg, sizeof(SSyncMsg)) != sizeof(SSyncMsg)) { + sError("failed to read peer sync msg from ip:%s since %s", ipstr, strerror(errno)); taosCloseSocket(connFd); return; } - int32_t vgId = firstPkt.syncHead.vgId; + int32_t vgId = msg.head.vgId; SSyncNode **ppNode = taosHashGet(tsVgIdHash, &vgId, sizeof(int32_t)); if (ppNode == NULL || *ppNode == NULL) { sError("vgId:%d, vgId could not be found", vgId); @@ -1131,7 +1133,7 @@ static void syncProcessIncommingConnection(int32_t connFd, uint32_t sourceIp) { return; } - sDebug("vgId:%d, firstPkt is received, tranId:%u", vgId, firstPkt.tranId); + sDebug("vgId:%d, sync msg is received, tranId:%u", vgId, msg.tranId); SSyncNode *pNode = *ppNode; pthread_mutex_lock(&pNode->mutex); @@ -1139,20 +1141,20 @@ static void syncProcessIncommingConnection(int32_t connFd, uint32_t sourceIp) { SSyncPeer *pPeer; for (i = 0; i < pNode->replica; ++i) { pPeer = pNode->peerInfo[i]; - if (pPeer && (strcmp(pPeer->fqdn, firstPkt.fqdn) == 0) && (pPeer->port == firstPkt.port)) break; + if (pPeer && (strcmp(pPeer->fqdn, msg.fqdn) == 0) && (pPeer->port == msg.port)) break; } pPeer = (i < pNode->replica) ? pNode->peerInfo[i] : NULL; if (pPeer == NULL) { - sError("vgId:%d, peer:%s:%u not configured", pNode->vgId, firstPkt.fqdn, firstPkt.port); + sError("vgId:%d, peer:%s:%u not configured", pNode->vgId, msg.fqdn, msg.port); taosCloseSocket(connFd); // syncSendVpeerCfgMsg(sync); } else { // first packet tells what kind of link - if (firstPkt.syncHead.type == TAOS_SMSG_SYNC_DATA) { + if (msg.head.type == TAOS_SMSG_SYNC_DATA) { pPeer->syncFd = connFd; nodeSStatus = TAOS_SYNC_STATUS_START; - sInfo("%s, sync-data pkt from master is received, tranId:%u, set sstatus:%s", pPeer->id, firstPkt.tranId, + sInfo("%s, sync-data msg from master is received, tranId:%u, set sstatus:%s", pPeer->id, msg.tranId, syncStatus[nodeSStatus]); syncCreateRestoreDataThread(pPeer); } else { @@ -1334,13 +1336,14 @@ static int32_t syncForwardToPeerImpl(SSyncNode *pNode, void *data, void *mhandle if (pNode->replica == 1 || nodeRole != TAOS_SYNC_ROLE_MASTER) return 0; - // only pkt from RPC or CQ can be forwarded + // only msg from RPC or CQ can be forwarded if (qtype != TAOS_QTYPE_RPC && qtype != TAOS_QTYPE_CQ) return 0; // a hacker way to improve the performance pSyncHead = (SSyncHead *)(((char *)pWalHead) - sizeof(SSyncHead)); pSyncHead->type = TAOS_SMSG_FORWARD; - pSyncHead->pversion = 0; + pSyncHead->protocol = SYNC_PROTOCOL_VERSION; + pSyncHead->vgId = pNode->vgId; pSyncHead->len = sizeof(SWalHead) + pWalHead->len; fwdLen = pSyncHead->len + sizeof(SSyncHead); // include the WAL and SYNC head diff --git a/src/sync/src/syncRestore.c b/src/sync/src/syncRestore.c index 4247468bca..850a9b78b7 100644 --- a/src/sync/src/syncRestore.c +++ b/src/sync/src/syncRestore.c @@ -289,12 +289,12 @@ static int32_t syncRestoreDataStepByStep(SSyncPeer *pPeer) { uint64_t fversion = 0; sInfo("%s, start to restore, sstatus:%s", pPeer->id, syncStatus[pPeer->sstatus]); - SFirstPktRsp firstPktRsp = {.sync = 1, .tranId = syncGenTranId()}; - if (taosWriteMsg(pPeer->syncFd, &firstPktRsp, sizeof(SFirstPktRsp)) != sizeof(SFirstPktRsp)) { - sError("%s, failed to send sync firstPkt rsp since %s", pPeer->id, strerror(errno)); + SSyncRsp rsp = {.sync = 1, .tranId = syncGenTranId()}; + if (taosWriteMsg(pPeer->syncFd, &rsp, sizeof(SSyncRsp)) != sizeof(SSyncRsp)) { + sError("%s, failed to send sync rsp since %s", pPeer->id, strerror(errno)); return -1; } - sDebug("%s, send firstPktRsp to peer, tranId:%u", pPeer->id, firstPktRsp.tranId); + sDebug("%s, send sync rsp to peer, tranId:%u", pPeer->id, rsp.tranId); sInfo("%s, start to restore file, set sstatus:%s", pPeer->id, syncStatus[nodeSStatus]); int32_t code = syncRestoreFile(pPeer, &fversion); diff --git a/src/sync/src/syncRetrieve.c b/src/sync/src/syncRetrieve.c index 82e3700c7a..981716d561 100644 --- a/src/sync/src/syncRetrieve.c +++ b/src/sync/src/syncRetrieve.c @@ -405,27 +405,29 @@ static int32_t syncRetrieveWal(SSyncPeer *pPeer) { static int32_t syncRetrieveFirstPkt(SSyncPeer *pPeer) { SSyncNode *pNode = pPeer->pSyncNode; - SFirstPkt firstPkt; - memset(&firstPkt, 0, sizeof(firstPkt)); - firstPkt.syncHead.type = TAOS_SMSG_SYNC_DATA; - firstPkt.syncHead.vgId = pNode->vgId; - firstPkt.tranId = syncGenTranId(); - tstrncpy(firstPkt.fqdn, tsNodeFqdn, sizeof(firstPkt.fqdn)); - firstPkt.port = tsSyncPort; + SSyncMsg msg; + memset(&msg, 0, sizeof(SSyncMsg)); + msg.head.type = TAOS_SMSG_SYNC_DATA; + msg.head.protocol = SYNC_PROTOCOL_VERSION; + msg.head.vgId = pNode->vgId; + msg.head.len = sizeof(SSyncMsg) - sizeof(SSyncHead); + msg.port = tsSyncPort; + msg.tranId = syncGenTranId(); + tstrncpy(msg.fqdn, tsNodeFqdn, TSDB_FQDN_LEN); - if (taosWriteMsg(pPeer->syncFd, &firstPkt, sizeof(firstPkt)) != sizeof(firstPkt)) { - sError("%s, failed to send sync firstPkt since %s, tranId:%u", pPeer->id, strerror(errno), firstPkt.tranId); + if (taosWriteMsg(pPeer->syncFd, &msg, sizeof(SSyncMsg)) != sizeof(SSyncMsg)) { + sError("%s, failed to send sync-data msg since %s, tranId:%u", pPeer->id, strerror(errno), msg.tranId); return -1; } - sDebug("%s, send sync-data pkt to peer, tranId:%u", pPeer->id, firstPkt.tranId); + sDebug("%s, send sync-data msg to peer, tranId:%u", pPeer->id, msg.tranId); - SFirstPktRsp firstPktRsp; - if (taosReadMsg(pPeer->syncFd, &firstPktRsp, sizeof(SFirstPktRsp)) != sizeof(SFirstPktRsp)) { - sError("%s, failed to read sync firstPkt rsp since %s, tranId:%u", pPeer->id, strerror(errno), firstPkt.tranId); + SSyncRsp rsp; + if (taosReadMsg(pPeer->syncFd, &rsp, sizeof(SSyncRsp)) != sizeof(SSyncRsp)) { + sError("%s, failed to read sync-data rsp since %s, tranId:%u", pPeer->id, strerror(errno), msg.tranId); return -1; } - sDebug("%s, recv firstPktRsp from peer, tranId:%u", pPeer->id, firstPkt.tranId); + sDebug("%s, recv sync-data rsp from peer, tranId:%u rsp-tranId:%u", pPeer->id, msg.tranId, rsp.tranId); return 0; } diff --git a/src/sync/test/syncServer.c b/src/sync/test/syncServer.c index 5a64a0a36a..161105d86c 100644 --- a/src/sync/test/syncServer.c +++ b/src/sync/test/syncServer.c @@ -100,7 +100,7 @@ int processRpcMsg(void *item) { pHead->msgType = pMsg->msgType; pHead->len = pMsg->contLen; - uDebug("ver:%" PRIu64 ", pkt from client processed", pHead->version); + uDebug("ver:%" PRIu64 ", rsp from client processed", pHead->version); writeIntoWal(pHead); syncForwardToPeer(syncHandle, pHead, item, TAOS_QTYPE_RPC); @@ -275,7 +275,7 @@ int getWalInfo(int32_t vgId, char *name, int64_t *index) { int writeToCache(int32_t vgId, void *data, int type) { SWalHead *pHead = data; - uDebug("pkt from peer is received, ver:%" PRIu64 " len:%d type:%d", pHead->version, pHead->len, type); + uDebug("rsp from peer is received, ver:%" PRIu64 " len:%d type:%d", pHead->version, pHead->len, type); int msgSize = pHead->len + sizeof(SWalHead); void *pMsg = taosAllocateQitem(msgSize); From 2cc2a9cdc05860d78422e7cc64bf663d88a7e070 Mon Sep 17 00:00:00 2001 From: liuyq-617 Date: Tue, 15 Dec 2020 17:54:03 +0800 Subject: [PATCH 03/38] fix jenkins error --- tests/Jenkinsfile | 248 ++++++++++++---------------------------------- 1 file changed, 64 insertions(+), 184 deletions(-) diff --git a/tests/Jenkinsfile b/tests/Jenkinsfile index e343de789e..550a0d29ed 100644 --- a/tests/Jenkinsfile +++ b/tests/Jenkinsfile @@ -1,3 +1,32 @@ +import hudson.model.Result +import jenkins.model.CauseOfInterruption +properties([pipelineTriggers([githubPush()])]) +node { + git url: 'https://github.com/taosdata/TDengine.git' +} + + +def abortPreviousBuilds() { + def currentJobName = env.JOB_NAME + def currentBuildNumber = env.BUILD_NUMBER.toInteger() + def jobs = Jenkins.instance.getItemByFullName(currentJobName) + def builds = jobs.getBuilds() + + for (build in builds) { + if (!build.isBuilding()) { + continue; + } + + if (currentBuildNumber == build.getNumber().toInteger()) { + continue; + } + + build.doKill() //doTerm(),doKill(),doTerm() + } +} +//停止之前相同的分支。。 +abortPreviousBuilds() + def pre_test(){ catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') { sh ''' @@ -5,15 +34,17 @@ def pre_test(){ ''' } sh ''' + cd ${WKC} - git reset --hard - git checkout ${BRANCH} - git pull - git submodule update + rm -rf * cd ${WK} git reset --hard - git checkout ${BRANCH} + git checkout develop git pull + cd ${WKC} + rm -rf * + mv ${WORKSPACE}/* . + cd ${WK} export TZ=Asia/Harbin date rm -rf ${WK}/debug @@ -22,23 +53,30 @@ def pre_test(){ cmake .. > /dev/null make > /dev/null make install > /dev/null + cd ${WKC}/tests ''' return 1 } pipeline { agent none + environment{ - BRANCH = 'develop' WK = '/var/lib/jenkins/workspace/TDinternal' WKC= '/var/lib/jenkins/workspace/TDinternal/community' } - + stages { + + stage('Parallel test stage') { + //only pr triggering the build. + when { + changeRequest() + } parallel { - stage('pytest') { - agent{label '184'} - steps { + stage('python') { + agent{label 'pytest'} + steps { pre_test() sh ''' cd ${WKC}/tests @@ -47,15 +85,9 @@ pipeline { } } stage('test_b1') { - agent{label 'master'} - steps { + agent{label 'b1'} + steps { pre_test() - catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') { - sh ''' - cd ${WKC}/tests/pytest - python3 concurrent_inquiry.py -c 1 - ''' - } sh ''' cd ${WKC}/tests ./test-all.sh b1 @@ -64,12 +96,9 @@ pipeline { } stage('test_crash_gen') { - agent{label "185"} + agent{label "b2"} steps { pre_test() - sh ''' - cd ${WKC}/tests/pytest - ''' catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') { sh ''' cd ${WKC}/tests/pytest @@ -83,6 +112,7 @@ pipeline { ''' } sh ''' + date cd ${WKC}/tests ./test-all.sh b2 date @@ -91,177 +121,27 @@ pipeline { } stage('test_valgrind') { - agent{label "186"} + agent{label "b3"} steps { pre_test() + catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') { + sh ''' + cd ${WKC}/tests/pytest + ./valgrind-test.sh 2>&1 > mem-error-out.log + ./handle_val_log.sh + ''' + } sh ''' - cd ${WKC}/tests/pytest - ./valgrind-test.sh 2>&1 > mem-error-out.log - ./handle_val_log.sh - date cd ${WKC}/tests ./test-all.sh b3 date''' } } - stage('connector'){ - agent{label "release"} - steps{ - sh''' - cd ${WORKSPACE} - git checkout develop - ''' - catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') { - sh ''' - cd ${WORKSPACE}/tests/gotest - bash batchtest.sh - ''' - } - catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') { - sh ''' - cd ${WORKSPACE}/tests/examples/python/PYTHONConnectorChecker - python3 PythonChecker.py - ''' - } - catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') { - sh ''' - cd ${WORKSPACE}/tests/examples/JDBC/JDBCDemo/ - mvn clean package assembly:single >/dev/null - java -jar target/jdbcChecker-SNAPSHOT-jar-with-dependencies.jar -host 127.0.0.1 - ''' - } - catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') { - sh ''' - cd ${JENKINS_HOME}/workspace/C#NET/src/CheckC# - dotnet run - ''' - } - - } - } - stage('arm64_build'){ - agent{label 'arm64'} - steps{ - sh ''' - cd ${WK} - git fetch - git checkout develop - git pull - cd ${WKC} - git fetch - git checkout develop - git pull - git submodule update - cd ${WKC}/packaging - ./release.sh -v cluster -c aarch64 -n 2.0.0.0 -m 2.0.0.0 - - ''' - } - } - stage('arm32_build'){ - agent{label 'arm32'} - steps{ - catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') { - sh ''' - cd ${WK} - git fetch - git checkout develop - git pull - cd ${WKC} - git fetch - git checkout develop - git pull - git submodule update - cd ${WKC}/packaging - ./release.sh -v cluster -c aarch32 -n 2.0.0.0 -m 2.0.0.0 - - ''' - } - - } - } - } + } - } - post { - success { - emailext ( - subject: "SUCCESSFUL: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]'", - body: ''' - - - - - - - - - - - - -

- 构建信息 -
-
    -
    -
  • 构建名称>>分支:${PROJECT_NAME}
  • -
  • 构建结果: Successful
  • -
  • 构建编号:${BUILD_NUMBER}
  • -
  • 触发用户:${CAUSE}
  • -
  • 变更概要:${CHANGES}
  • -
  • 构建地址:${BUILD_URL}
  • -
  • 构建日志:${BUILD_URL}console
  • -
  • 变更集:${JELLY_SCRIPT}
  • -
    -
-
- - ''', - to: "yqliu@taosdata.com,pxiao@taosdata.com", - from: "support@taosdata.com" - ) - } - failure { - emailext ( - subject: "FAILED: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]'", - body: ''' - - - - - - - - - - - - -

- 构建信息 -
-
    -
    -
  • 构建名称>>分支:${PROJECT_NAME}
  • -
  • 构建结果: Successful
  • -
  • 构建编号:${BUILD_NUMBER}
  • -
  • 触发用户:${CAUSE}
  • -
  • 变更概要:${CHANGES}
  • -
  • 构建地址:${BUILD_URL}
  • -
  • 构建日志:${BUILD_URL}console
  • -
  • 变更集:${JELLY_SCRIPT}
  • -
    -
-
- - ''', - to: "yqliu@taosdata.com,pxiao@taosdata.com", - from: "support@taosdata.com" - ) - } - } -} \ No newline at end of file + } + +} From 6df4569e466454a125e8c2ed4527e8ea4a63e709 Mon Sep 17 00:00:00 2001 From: Shuduo Sang Date: Wed, 16 Dec 2020 10:46:27 +0800 Subject: [PATCH 04/38] [TECO-39]: update documents to align with 2.0.10.0. --- .../webdocs/markdowndocs/TAOS SQL-ch.md | 20 +++++++- .../webdocs/markdowndocs/administrator-ch.md | 48 ++++++++++++------- .../webdocs/markdowndocs/cluster-ch.md | 10 ++++ 3 files changed, 59 insertions(+), 19 deletions(-) diff --git a/documentation20/webdocs/markdowndocs/TAOS SQL-ch.md b/documentation20/webdocs/markdowndocs/TAOS SQL-ch.md index adba39ec1f..8ed497fe21 100644 --- a/documentation20/webdocs/markdowndocs/TAOS SQL-ch.md +++ b/documentation20/webdocs/markdowndocs/TAOS SQL-ch.md @@ -79,7 +79,7 @@ TDengine缺省的时间戳是毫秒精度,但通过修改配置参数enableMic - **使用数据库** - + ```mysql USE db_name; ``` @@ -1039,3 +1039,21 @@ SELECT AVG(current),MAX(current),LEASTSQUARES(current, start_val, step_val), PER - 标签最多允许128个,可以0个,标签总长度不超过16k个字符 - SQL语句最大长度65480个字符,但可通过系统配置参数maxSQLLength修改,最长可配置为1M - 库的数目,超级表的数目、表的数目,系统不做限制,仅受系统资源限制 + + + +## TAOS SQL其他约定 + +**group by的限制** + +TAOS SQL支持对标签、tbname进行group by操作,也支持普通列进行group by,前提是:仅限一列且该列的唯一值小于10万个。 + +**join操作的限制** + +TAOS SQL支持表之间按主键时间戳来join两张表的列,暂不支持两个表之间聚合后的四则运算。 + +**is not null与不为空的表达式适用范围** + +is not null支持所有类型的列。不为空的表达式为 <>"",仅对非数值类型的列适用。 + + diff --git a/documentation20/webdocs/markdowndocs/administrator-ch.md b/documentation20/webdocs/markdowndocs/administrator-ch.md index 7f40009e3c..2c470a270d 100644 --- a/documentation20/webdocs/markdowndocs/administrator-ch.md +++ b/documentation20/webdocs/markdowndocs/administrator-ch.md @@ -80,6 +80,12 @@ TDengine集群的节点数必须大于等于副本数,否则创建表时将报 TDengine系统后台服务由taosd提供,可以在配置文件taos.cfg里修改配置参数,以满足不同场景的需求。配置文件的缺省位置在/etc/taos目录,可以通过taosd命令行执行参数-c指定配置文件目录。比如taosd -c /home/user来指定配置文件位于/home/user这个目录。 +另外可以使用 “-C” 显示当前服务器配置参数: + +``` +taosd -C +``` + 下面仅仅列出一些重要的配置参数,更多的参数请看配置文件里的说明。各个参数的详细介绍及作用请看前述章节,而且这些参数的缺省配置都是工作的,一般无需设置。**注意:配置修改后,需要重启*taosd*服务才能生效。** - firstEp: taosd启动时,主动连接的集群中首个dnode的end point, 默认值为localhost:6030。 @@ -97,6 +103,7 @@ TDengine系统后台服务由taosd提供,可以在配置文件taos.cfg里修 - telemetryReporting: 是否允许 TDengine 采集和上报基本使用信息,0表示不允许,1表示允许。 默认值:1。 - stream: 是否启用连续查询(流计算功能),0表示不允许,1表示允许。 默认值:1。 - queryBufferSize: 为所有并发查询占用保留的内存大小。计算规则可以根据实际应用可能的最大并发数和表的数字相乘,再乘 170 。单位为字节。 +- ratioOfQueryCores: 设置查询线程的最大数量。最小值0 表示只有1个查询线程;最大值2表示最大建立2倍CPU核数的查询线程。默认为1,表示最大和CPU核数相等的查询线程。该值可以为小数,即0.5表示最大建立CPU核数一半的查询线程。 **注意:**对于端口,TDengine会使用从serverPort起13个连续的TCP和UDP端口号,请务必在防火墙打开。因此如果是缺省配置,需要打开从6030都6042共13个端口,而且必须TCP和UDP都打开。 @@ -152,7 +159,13 @@ ALTER DNODE ## 客户端配置 -TDengine系统的前台交互客户端应用程序为taos,它与taosd共享同一个配置文件taos.cfg。运行taos时,使用参数-c指定配置文件目录,如taos -c /home/cfg,表示使用/home/cfg/目录下的taos.cfg配置文件中的参数,缺省目录是/etc/taos。本节主要说明 taos 客户端应用在配置文件 taos.cfg 文件中使用到的参数。 +TDengine系统的前台交互客户端应用程序为taos,以及应用驱动,它与taosd共享同一个配置文件taos.cfg。运行taos时,使用参数-c指定配置文件目录,如taos -c /home/cfg,表示使用/home/cfg/目录下的taos.cfg配置文件中的参数,缺省目录是/etc/taos。更多taos的使用方法请见[Shell命令行程序](https://www.taosdata.com/cn/documentation/administrator/#_TDengine_Shell命令行程序)。本节主要说明 taos 客户端应用在配置文件 taos.cfg 文件中使用到的参数。 + +**2.0.10.0 之后版本支持命令行以下参数显示当前客户端参数的配置** + +```bash +taos -C 或 taos --dump-config +``` 客户端配置参数 @@ -215,15 +228,15 @@ TDengine系统的前台交互客户端应用程序为taos,它与taosd共享同 均是合法的设置东八区时区的格式。 时区的设置对于查询和写入SQL语句中非Unix时间戳的内容(时间戳字符串、关键词now的解析)产生影响。例如: - ``` + ```sql SELECT count(*) FROM table_name WHERE TS<'2019-04-11 12:01:08'; ``` 在东八区,SQL语句等效于 - ``` + ```sql SELECT count(*) FROM table_name WHERE TS<1554955268000; ``` 在UTC时区,SQL语句等效于 - ``` + ```sql SELECT count(*) FROM table_name WHERE TS<1554984068000; ``` 为了避免使用字符串时间格式带来的不确定性,也可以直接使用Unix时间戳。此外,还可以在SQL语句中使用带有时区的时间戳字符串,例如:RFC3339格式的时间戳字符串,2013-04-12T15:52:01.123+08:00或者ISO-8601格式时间戳字符串2013-04-12T15:52:01.123+0800。上述两个字符串转化为Unix时间戳不受系统所在时区的影响。 @@ -239,31 +252,31 @@ TDengine系统的前台交互客户端应用程序为taos,它与taosd共享同 系统管理员可以在CLI界面里添加、删除用户,也可以修改密码。CLI里SQL语法如下: -``` +```sql CREATE USER PASS <'password'>; ``` 创建用户,并指定用户名和密码,密码需要用单引号引起来,单引号为英文半角 -``` +```sql DROP USER ; ``` 删除用户,限root用户使用 -``` +```sql ALTER USER PASS <'password'>; ``` 修改用户密码, 为避免被转换为小写,密码需要用单引号引用,单引号为英文半角 -``` +```sql ALTER USER PRIVILEGE ; ``` 修改用户权限为:super/write/read,不需要添加单引号 -``` +```mysql SHOW USERS; ``` @@ -316,12 +329,11 @@ taos> DESCRIBE d1001 ``` 那么可以用如下命令导入数据 -``` +```mysql taos> insert into d1001 file '~/data.csv'; Query OK, 9 row(s) affected (0.004763s) ``` - **taosdump工具导入** TDengine提供了方便的数据库导入导出工具taosdump。用户可以将taosdump从一个系统导出的数据,导入到其他系统中。具体使用方法,请参见博客:TDengine DUMP工具使用指南 @@ -334,7 +346,7 @@ TDengine提供了方便的数据库导入导出工具taosdump。用户可以将t 如果用户需要导出一个表或一个STable中的数据,可在shell中运行 -``` +```mysql select * from >> data.csv; ``` @@ -348,37 +360,37 @@ TDengine提供了方便的数据库导出工具taosdump。用户可以根据需 系统管理员可以从CLI查询系统的连接、正在进行的查询、流式计算,并且可以关闭连接、停止正在进行的查询和流式计算。CLI里SQL语法如下: -``` +```mysql SHOW CONNECTIONS; ``` 显示数据库的连接,其中一列显示ip:port, 为连接的IP地址和端口号。 -``` +```mysql KILL CONNECTION ; ``` 强制关闭数据库连接,其中的connection-id是SHOW CONNECTIONS中显示的第一列的数字。 -``` +```mysql SHOW QUERIES; ``` 显示数据查询,其中第一列显示的以冒号隔开的两个数字为query-id,为发起该query应用连接的connection-id和查询次数。 -``` +```mysql KILL QUERY ; ``` 强制关闭数据查询,其中query-id是SHOW QUERIES中显示的 connection-id:query-no字串,如“105:2”,拷贝粘贴即可。 -``` +```mysql SHOW STREAMS; ``` 显示流式计算,其中第一列显示的以冒号隔开的两个数字为stream-id, 为启动该stream应用连接的connection-id和发起stream的次数。 -``` +```mysql KILL STREAM ; ``` diff --git a/documentation20/webdocs/markdowndocs/cluster-ch.md b/documentation20/webdocs/markdowndocs/cluster-ch.md index db479417c5..60ac6e4c2e 100644 --- a/documentation20/webdocs/markdowndocs/cluster-ch.md +++ b/documentation20/webdocs/markdowndocs/cluster-ch.md @@ -137,6 +137,16 @@ DROP DNODE "fqdn:port"; 其中fqdn是被删除的节点的FQDN,port是其对外服务器的端口号 +**【注意】** + + - 一个数据节点一旦被drop之后,不能重新加入集群。需要将此节点重新部署(清空数据文件夹)。集群在完成drop dnode操作之前,会将该dnode的数据迁移走。 + + - 请注意 drop dnode 和 停止taosd进程是两个不同的概念,不要混淆:因为删除dnode之前要执行迁移数据的操作,因此被删除的dnode必须保持在线状态。待删除操作结束之后,才能停止taosd进程。 + + - 一个数据节点被drop之后,其他节点都会感知到这个dnodeID的删除操作,任何集群中的节点都不会再接收此dnodeID的请求。 + + - dnodeID的是集群自动分配的,不得人工指定。它在生成时递增的,不会重复。 + ### 查看数据节点 执行CLI程序taos,使用root账号登录进TDengine系统,执行: From 595df83f4de4973f1b5901fa75fbf0b86b9465bc Mon Sep 17 00:00:00 2001 From: stephenkgu Date: Wed, 16 Dec 2020 15:54:19 +0800 Subject: [PATCH 05/38] [TD-2263]: debug log epSet.fqdn when connect success --- src/client/src/tscServer.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/client/src/tscServer.c b/src/client/src/tscServer.c index d5c1e6130f..9f6ccef50d 100644 --- a/src/client/src/tscServer.c +++ b/src/client/src/tscServer.c @@ -2146,6 +2146,10 @@ int tscProcessConnectRsp(SSqlObj *pSql) { if (pConnect->epSet.numOfEps > 0) { tscEpSetHtons(&pConnect->epSet); tscUpdateMgmtEpSet(pSql, &pConnect->epSet); + + for (int i = 0; i < pConnect->epSet.numOfEps; ++i) { + tscDebug("%p epSet.fqdn[%d]: %s, pObj:%p", pSql, i, pConnect->epSet.fqdn[i], pObj); + } } strcpy(pObj->sversion, pConnect->serverVersion); From e5f3f270a17acfc76d1acf1201d2d7e9ba24c30a Mon Sep 17 00:00:00 2001 From: Shuduo Sang Date: Wed, 16 Dec 2020 17:12:15 +0800 Subject: [PATCH 06/38] refine getting started and connector page. --- .../markdowndocs/Getting Started-ch.md | 167 ++++++++++-------- .../webdocs/markdowndocs/connector-ch.md | 5 +- 2 files changed, 98 insertions(+), 74 deletions(-) diff --git a/documentation20/webdocs/markdowndocs/Getting Started-ch.md b/documentation20/webdocs/markdowndocs/Getting Started-ch.md index 9df501ea78..9f9d3a2ec2 100644 --- a/documentation20/webdocs/markdowndocs/Getting Started-ch.md +++ b/documentation20/webdocs/markdowndocs/Getting Started-ch.md @@ -2,37 +2,7 @@ ## 快捷安装 -TDengine软件分为服务器、客户端和报警模块三部分,目前2.0版服务器仅能在Linux系统上安装和运行,后续会支持Windows、mac OS等系统。 - -**应用驱动** - -如果应用在Windows和Linux上运行,可使用C/C++/C#/JAVA/Python/Go/Node.js接口连接服务器。如果应用在Mac上运行,目前可以使用RESTful接口连接服务器。 - -**CPU** - -CPU支持X64/ARM64/MIPS64/Alpha64,后续会支持ARM32、RISC-V等CPU架构。用户可根据需求选择通过[源码](https://www.taosdata.com/cn/getting-started/#通过源码安装)或者[安装包](https://www.taosdata.com/cn/getting-started/#通过安装包安装)来安装。 - -**服务器** - -目前TDengine服务器可以运行在以下平台上: - -| | **CentOS** **6/7/8** | **Ubuntu** **16/18/20** | **Other Linux** | **统信****UOS** | **银河****/****中标麒麟** | **凝思** **V60/V80** | -| -------------- | --------------------- | ------------------------ | --------------- | --------------- | ------------------------- | --------------------- | -| X64 | ● | ● | | ○ | ● | ● | -| 树莓派ARM32 | | ● | ● | | | | -| 龙芯MIPS64 | | | ● | | | | -| 鲲鹏 ARM64 | | ○ | ○ | | ● | | -| 申威 Alpha64 | | | ○ | ● | | | -| 飞腾ARM64 | | ○优麒麟 | | | | | -| 海光X64 | ● | ● | ● | ○ | ● | ● | -| 瑞芯微ARM64/32 | | | ○ | | | | -| 全志ARM64/32 | | | ○ | | | | -| 炬力ARM64/32 | | | ○ | | | | -| TI ARM32 | | | ○ | | | | - - 其中 ● 表示经过官方测试验证, ○ 表示非官方测试验证。 - - +TDengine软件分为服务器、客户端和报警模块三部分,目前2.0版服务器仅能在Linux系统上安装和运行,后续会支持Windows、mac OS等系统。客户端可以在Windows或Linux上安装和运行。任何OS的应用也可以选择RESTful接口连接服务器taosd。CPU支持X64/ARM64/MIPS64/Alpha64,后续会支持ARM32、RISC-V等CPU架构。用户可根据需求选择通过[源码](https://www.taosdata.com/cn/getting-started/#通过源码安装)或者[安装包](https://www.taosdata.com/cn/getting-started/#通过安装包安装)来安装。 ### 通过源码安装 @@ -44,28 +14,11 @@ CPU支持X64/ARM64/MIPS64/Alpha64,后续会支持ARM32、RISC-V等CPU架构。 ### 通过安装包安装 -服务器部分,我们提供三种安装包,您可以根据需要选择。TDengine的安装非常简单,从下载到安装成功仅仅只要几秒钟。 +TDengine的安装非常简单,从下载到安装成功仅仅只要几秒钟。服务端安装包包含客户端和连接器,我们提供三种安装包,您可以根据需要选择: -- TDengine-server-2.0.9.0-Linux-x64.rpm (4.2M) -- TDengine-server-2.0.9.0-Linux-x64.deb (2.7M) -- TDengine-server-2.0.9.0-Linux-x64.tar.gz (4.5M) - - -客户端部分,Linux安装包如下: - -- TDengine-client-2.0.9.0-Linux-x64.tar.gz(3.0M) -- TDengine-client-2.0.9.0-Windows-x64.exe(2.8M) -- TDengine-client-2.0.9.0-Windows-x86.exe(2.8M) - -报警模块的Linux安装包如下(请参考[报警模块的使用方法](https://github.com/taosdata/TDengine/blob/master/alert/README_cn.md)): - -- TDengine-alert-2.0.9.0-Linux-x64.tar.gz (8.1M) - -目前,TDengine 支持在使用[`systemd`](https://en.wikipedia.org/wiki/Systemd)做进程服务管理的linux系统上安装,用`which systemctl`命令来检测系统中是否存在`systemd`包: - -```cmd -which systemctl -``` +- TDengine-server-2.0.10.0-Linux-x64.rpm (4.2M) +- TDengine-server-2.0.10.0-Linux-x64.deb (2.7M) +- TDengine-server-2.0.10.0-Linux-x64.tar.gz (4.5M) 具体的安装过程,请参见TDengine多种安装包的安装和卸载。 @@ -73,13 +26,13 @@ which systemctl 安装成功后,用户可使用`systemctl`命令来启动TDengine的服务进程。 -```cmd -systemctl start taosd +```bash +$ systemctl start taosd ``` 检查服务是否正常工作。 -```cmd -systemctl status taosd +```bash +$ systemctl status taosd ``` 如果TDengine服务正常工作,那么您可以通过TDengine的命令行程序`taos`来访问并体验TDengine。 @@ -88,15 +41,24 @@ systemctl status taosd - systemctl命令需要 _root_ 权限来运行,如果您非 _root_ 用户,请在命令前添加 sudo - 为更好的获得产品反馈,改善产品,TDengine会采集基本的使用信息,但您可以修改系统配置文件taos.cfg里的配置参数telemetryReporting, 将其设为0,就可将其关闭。 +- TDengine采用FQDN(一般就是hostname)作为节点的ID,为保证正常运行,需要给运行taosd的服务器配置好hostname,在客户端应用运行的机器配置好DNS服务或hosts文件,保证FQDN能够解析。 -如果系统中不支持`systemd`,也可以用手动运行 /usr/local/taos/bin/taosd 方式启动 TDengine 服务。 +* TDengine 支持在使用[`systemd`](https://en.wikipedia.org/wiki/Systemd)做进程服务管理的linux系统上安装,用`which systemctl`命令来检测系统中是否存在`systemd`包: + + ```bash + $ which systemctl + ``` + + 如果系统中不支持systemd,也可以用手动运行 /usr/local/taos/bin/taosd 方式启动 TDengine 服务。 + + ## TDengine命令行程序 执行TDengine命令行程序,您只要在Linux终端执行`taos`即可。 -```cmd -taos +```bash +$ taos ``` 如果TDengine终端连接服务成功,将会打印出欢迎消息和版本信息。如果失败,则会打印错误消息出来(请参考[FAQ](https://www.taosdata.com/cn/faq/)来解决终端连接服务端失败的问题)。TDengine终端的提示符号如下: @@ -136,8 +98,8 @@ Query OK, 2 row(s) in set (0.001700s) 示例: -```cmd -taos -h 192.168.0.1 -s "use db; show tables;" +```bash +$ taos -h 192.168.0.1 -s "use db; show tables;" ``` ### 运行SQL命令脚本 @@ -159,8 +121,8 @@ taos> source ; 启动TDengine的服务,在Linux终端执行taosdemo -``` -> taosdemo +```bash +$ taosdemo ``` 该命令将在数据库test下面自动创建一张超级表meters,该超级表下有1万张表,表名为"t0" 到"t9999",每张表有10万条记录,每条记录有 (f1, f2, f3)三个字段,时间戳从"2017-07-14 10:40:00 000" 到"2017-07-14 10:41:39 999",每张表带有标签areaid和loc, areaid被设置为1到10, loc被设置为"beijing"或者“shanghai"。 @@ -171,33 +133,92 @@ taos> source ; - 查询超级表下记录总条数: -``` -taos>select count(*) from test.meters; +```mysql +taos> select count(*) from test.meters; ``` - 查询10亿条记录的平均值、最大值、最小值等: -``` -taos>select avg(f1), max(f2), min(f3) from test.meters; +```mysql +taos> select avg(f1), max(f2), min(f3) from test.meters; ``` - 查询loc="beijing"的记录总条数: -``` -taos>select count(*) from test.meters where loc="beijing"; +```mysql +taos> select count(*) from test.meters where loc="beijing"; ``` - 查询areaid=10的所有记录的平均值、最大值、最小值等: -``` -taos>select avg(f1), max(f2), min(f3) from test.meters where areaid=10; +```mysql +taos> select avg(f1), max(f2), min(f3) from test.meters where areaid=10; ``` - 对表t10按10s进行平均值、最大值和最小值聚合统计: -``` -taos>select avg(f1), max(f2), min(f3) from test.t10 interval(10s); +```mysql +taos> select avg(f1), max(f2), min(f3) from test.t10 interval(10s); ``` **Note:** taosdemo命令本身带有很多选项,配置表的数目、记录条数等等,请执行 `taosdemo --help`详细列出。您可以设置不同参数进行体验。 + + +## 客户端和报警模块 + +如果客户端和服务端运行在不同的电脑上,可以单独安装客户端。Linux和Windows安装包如下: + +- TDengine-client-2.0.10.0-Linux-x64.tar.gz(3.0M) +- TDengine-client-2.0.10.0-Windows-x64.exe(2.8M) +- TDengine-client-2.0.10.0-Windows-x86.exe(2.8M) + +报警模块的Linux安装包如下(请参考[报警模块的使用方法](https://github.com/taosdata/TDengine/blob/master/alert/README_cn.md)): + +- TDengine-alert-2.0.10.0-Linux-x64.tar.gz (8.1M) + + + +## **支持平台列表** + +### TDengine服务器支持的平台列表 + +| | **CentOS** **6/7/8** | **Ubuntu** **16/18/20** | **Other Linux** | **统信****UOS** | **银河****/****中标麒麟** | **凝思** **V60/V80** | +| -------------- | --------------------- | ------------------------ | --------------- | --------------- | ------------------------- | --------------------- | +| X64 | ● | ● | | ○ | ● | ● | +| 树莓派ARM32 | | ● | ● | | | | +| 龙芯MIPS64 | | | ● | | | | +| 鲲鹏 ARM64 | | ○ | ○ | | ● | | +| 申威 Alpha64 | | | ○ | ● | | | +| 飞腾ARM64 | | ○优麒麟 | | | | | +| 海光X64 | ● | ● | ● | ○ | ● | ● | +| 瑞芯微ARM64/32 | | | ○ | | | | +| 全志ARM64/32 | | | ○ | | | | +| 炬力ARM64/32 | | | ○ | | | | +| TI ARM32 | | | ○ | | | | + +注: ● 表示经过官方测试验证, ○ 表示非官方测试验证。 + + + +### TDengine客户端和连接器支持的平台列表 + +目前TDengine的连接器可支持的平台广泛,目前包括:X64/X86/ARM64/ARM32/MIPS/Alpha等硬件平台,以及Linux/Win64/Win32等开发环境。 + +对照矩阵如下: + +| **CPU** | **X64 64bit** | | | **X86 32bit** | **ARM64** | **ARM32** | **MIPS ** **龙芯** | **Alpha ** **申威** | **X64 ** **海光** | +| ----------- | --------------- | --------- | --------- | --------------- | --------- | --------- | ------------------- | -------------------- | ------------------ | +| **OS** | **Linux** | **Win64** | **Win32** | **Win32** | **Linux** | **Linux** | **Linux** | **Linux** | **Linux** | +| **C/C++** | ● | ● | ● | ○ | ● | ● | ● | ● | ● | +| **JDBC** | ● | ● | ● | ○ | ● | ● | ● | ● | ● | +| **Python** | ● | ● | ● | ○ | ● | ● | ● | -- | ● | +| **Go** | ● | ● | ● | ○ | ● | ● | ○ | -- | -- | +| **NodeJs** | ● | ● | ○ | ○ | ● | ● | ○ | -- | -- | +| **C#** | ○ | ● | ● | ○ | ○ | ○ | ○ | -- | -- | +| **RESTful** | ● | ● | ● | ● | ● | ● | ● | ● | ● | + +注: ● 表示经过官方测试验证, ○ 表示非官方测试验证。 + +请跳转到 [连接器 ](https://www.taosdata.com/cn/documentation/connector)查看更详细的信息。 + diff --git a/documentation20/webdocs/markdowndocs/connector-ch.md b/documentation20/webdocs/markdowndocs/connector-ch.md index 9017dfd663..c04dc9891e 100644 --- a/documentation20/webdocs/markdowndocs/connector-ch.md +++ b/documentation20/webdocs/markdowndocs/connector-ch.md @@ -19,7 +19,10 @@ TDengine提供了丰富的应用程序开发接口,其中包括C/C++、C# 、J 其中 ● 表示经过官方测试验证, ○ 表示非官方测试验证。 -注意:所有执行 SQL 语句的 API,例如 C/C++ Connector 中的 `tao_query`、`taos_query_a`、`taos_subscribe` 等,以及其它语言中与它们对应的API,每次都只能执行一条 SQL 语句,如果实际参数中包含了多条语句,它们的行为是未定义的。 +注意: + +* 所有执行 SQL 语句的 API,例如 C/C++ Connector 中的 `tao_query`、`taos_query_a`、`taos_subscribe` 等,以及其它语言中与它们对应的API,每次都只能执行一条 SQL 语句,如果实际参数中包含了多条语句,它们的行为是未定义的。 +* 升级到TDengine到2.0.8.0版本的用户,必须更新JDBC连接TDengine必须升级taos-jdbcdriver到2.0.12及以上。 ## C/C++ Connector From f546a5632219d13125c22e6248f8008c066c4152 Mon Sep 17 00:00:00 2001 From: Minglei Jin Date: Wed, 16 Dec 2020 17:59:02 +0800 Subject: [PATCH 07/38] coverity 280234: init walCfg --- src/wal/test/waltest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wal/test/waltest.c b/src/wal/test/waltest.c index 7a473ed18c..9a52a2ca83 100644 --- a/src/wal/test/waltest.c +++ b/src/wal/test/waltest.c @@ -76,7 +76,7 @@ int main(int argc, char *argv[]) { taosInitLog("wal.log", 100000, 10); - SWalCfg walCfg; + SWalCfg walCfg = {0}; walCfg.walLevel = level; walCfg.keep = keep; From 6d2d52bc284ca415e3d95fd364903388e5a3cd69 Mon Sep 17 00:00:00 2001 From: Shengliang Guan Date: Wed, 16 Dec 2020 19:45:04 +0800 Subject: [PATCH 08/38] TD-2428 --- src/inc/taoserror.h | 5 ++ src/inc/vnode.h | 2 +- src/mnode/inc/mnodeSdb.h | 2 +- src/sync/inc/syncInt.h | 79 +------------------- src/sync/inc/syncMsg.h | 138 ++++++++++++++++++++++++++++++++++ src/sync/src/syncMain.c | 143 +++++++++++------------------------- src/sync/src/syncMsg.c | 93 +++++++++++++++++++++++ src/sync/src/syncRetrieve.c | 9 +-- 8 files changed, 284 insertions(+), 187 deletions(-) create mode 100644 src/sync/inc/syncMsg.h create mode 100644 src/sync/src/syncMsg.c diff --git a/src/inc/taoserror.h b/src/inc/taoserror.h index c913b2cf2a..58e19ce52a 100644 --- a/src/inc/taoserror.h +++ b/src/inc/taoserror.h @@ -267,6 +267,11 @@ TAOS_DEFINE_ERROR(TSDB_CODE_SYN_NOT_ENABLED, 0, 0x0901, "Sync modul TAOS_DEFINE_ERROR(TSDB_CODE_SYN_INVALID_VERSION, 0, 0x0902, "Invalid Sync version") TAOS_DEFINE_ERROR(TSDB_CODE_SYN_CONFIRM_EXPIRED, 0, 0x0903, "Sync confirm expired") TAOS_DEFINE_ERROR(TSDB_CODE_SYN_TOO_MANY_FWDINFO, 0, 0x0904, "Too many sync fwd infos") +TAOS_DEFINE_ERROR(TSDB_CODE_SYN_MISMATCHED_PROTOCOL, 0, 0x0905, "Mismatched protocol") +TAOS_DEFINE_ERROR(TSDB_CODE_SYN_MISMATCHED_CLUSTERID, 0, 0x0906, "Mismatched clusterId") +TAOS_DEFINE_ERROR(TSDB_CODE_SYN_MISMATCHED_SIGNATURE, 0, 0x0907, "Mismatched signature") +TAOS_DEFINE_ERROR(TSDB_CODE_SYN_INVALID_CHECKSUM, 0, 0x0908, "Invalid msg checksum") +TAOS_DEFINE_ERROR(TSDB_CODE_SYN_INVALID_MSGLEN, 0, 0x0909, "Invalid msg length") // wal TAOS_DEFINE_ERROR(TSDB_CODE_WAL_APP_ERROR, 0, 0x1000, "Unexpected generic error in wal") diff --git a/src/inc/vnode.h b/src/inc/vnode.h index 95f1d27b59..cbe64484b1 100644 --- a/src/inc/vnode.h +++ b/src/inc/vnode.h @@ -48,7 +48,7 @@ typedef struct { void * pVnode; SRpcMsg rpcMsg; SRspRet rspRet; - char reserveForSync[16]; + char reserveForSync[24]; SWalHead pHead[]; } SVWriteMsg; diff --git a/src/mnode/inc/mnodeSdb.h b/src/mnode/inc/mnodeSdb.h index 31ea2da640..e4df562d81 100644 --- a/src/mnode/inc/mnodeSdb.h +++ b/src/mnode/inc/mnodeSdb.h @@ -59,7 +59,7 @@ typedef struct SSdbRow { SMnodeMsg *pMsg; int32_t (*fpReq)(SMnodeMsg *pMsg); int32_t (*fpRsp)(SMnodeMsg *pMsg, int32_t code); - char reserveForSync[16]; + char reserveForSync[24]; SWalHead pHead[]; } SSdbRow; diff --git a/src/sync/inc/syncInt.h b/src/sync/inc/syncInt.h index c00015552f..535251ba11 100644 --- a/src/sync/inc/syncInt.h +++ b/src/sync/inc/syncInt.h @@ -13,12 +13,14 @@ * along with this program. If not, see . */ -#ifndef TDENGINE_SYNCINT_H -#define TDENGINE_SYNCINT_H +#ifndef TDENGINE_SYNC_INT_H +#define TDENGINE_SYNC_INT_H #ifdef __cplusplus extern "C" { #endif +#include "syncMsg.h" +#include "twal.h" #define sFatal(...) { if (sDebugFlag & DEBUG_FATAL) { taosPrintLog("SYN FATAL ", sDebugFlag, __VA_ARGS__); }} #define sError(...) { if (sDebugFlag & DEBUG_ERROR) { taosPrintLog("SYN ERROR ", sDebugFlag, __VA_ARGS__); }} @@ -27,88 +29,16 @@ extern "C" { #define sDebug(...) { if (sDebugFlag & DEBUG_DEBUG) { taosPrintLog("SYN ", sDebugFlag, __VA_ARGS__); }} #define sTrace(...) { if (sDebugFlag & DEBUG_TRACE) { taosPrintLog("SYN ", sDebugFlag, __VA_ARGS__); }} -typedef enum { - TAOS_SMSG_SYNC_DATA = 1, - TAOS_SMSG_FORWARD = 2, - TAOS_SMSG_FORWARD_RSP = 3, - TAOS_SMSG_SYNC_REQ = 4, - TAOS_SMSG_SYNC_RSP = 5, - TAOS_SMSG_SYNC_MUST = 6, - TAOS_SMSG_STATUS = 7, - TAOS_SMSG_SYNC_DATA_RSP = 8, -} ESyncMsgType; - #define SYNC_MAX_SIZE (TSDB_MAX_WAL_SIZE + sizeof(SWalHead) + sizeof(SSyncHead) + 16) #define SYNC_RECV_BUFFER_SIZE (5*1024*1024) #define SYNC_FWD_TIMER 300 #define SYNC_ROLE_TIMER 10000 #define SYNC_WAIT_AFTER_CHOOSE_MASTER 3 -#define SYNC_PROTOCOL_VERSION 0 #define nodeRole pNode->peerInfo[pNode->selfIndex]->role #define nodeVersion pNode->peerInfo[pNode->selfIndex]->version #define nodeSStatus pNode->peerInfo[pNode->selfIndex]->sstatus -#pragma pack(push, 1) - -typedef struct { - int8_t type; // msg type - int8_t protocol; // protocol version - int8_t reserved[6]; // not used - int32_t vgId; // vg ID - int32_t len; // content length, does not include head -} SSyncHead; - -typedef struct { - SSyncHead head; - uint16_t port; - uint16_t tranId; - char fqdn[TSDB_FQDN_LEN]; - int32_t sourceId; // only for arbitrator -} SSyncMsg; - -typedef struct { - SSyncHead head; - int8_t sync; - int8_t reserved; - uint16_t tranId; -} SSyncRsp; - -typedef struct { - int8_t role; - uint64_t version; -} SPeerStatus; - -typedef struct { - int8_t role; - int8_t ack; - int8_t type; - int8_t reserved[3]; - uint16_t tranId; - uint64_t version; - SPeerStatus peersStatus[]; -} SPeersStatus; - -typedef struct { - char name[TSDB_FILENAME_LEN]; - uint32_t magic; - uint32_t index; - uint64_t fversion; - int64_t size; -} SFileInfo; - -typedef struct { - int8_t sync; -} SFileAck; - -typedef struct { - SSyncHead head; - uint64_t version; - int32_t code; -} SFwdRsp; - -#pragma pack(pop) - typedef struct { char * buffer; int32_t bufferSize; @@ -192,7 +122,6 @@ void syncRestartConnection(SSyncPeer *pPeer); void syncBroadcastStatus(SSyncNode *pNode); void syncAddPeerRef(SSyncPeer *pPeer); int32_t syncDecPeerRef(SSyncPeer *pPeer); -uint16_t syncGenTranId(); #ifdef __cplusplus } diff --git a/src/sync/inc/syncMsg.h b/src/sync/inc/syncMsg.h new file mode 100644 index 0000000000..9a7ff04de1 --- /dev/null +++ b/src/sync/inc/syncMsg.h @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#ifndef TDENGINE_SYNC_MSG_H +#define TDENGINE_SYNC_MSG_H + +#ifdef __cplusplus +extern "C" { +#endif +#include "tsync.h" + +typedef enum { + TAOS_SMSG_START = 0, + TAOS_SMSG_SYNC_DATA = 1, + TAOS_SMSG_SYNC_DATA_RSP = 2, + TAOS_SMSG_SYNC_FWD = 3, + TAOS_SMSG_SYNC_FWD_RSP = 4, + TAOS_SMSG_SYNC_REQ = 5, + TAOS_SMSG_SYNC_REQ_RSP = 6, + TAOS_SMSG_SYNC_MUST = 7, + TAOS_SMSG_SYNC_MUST_RSP = 8, + TAOS_SMSG_STATUS = 9, + TAOS_SMSG_STATUS_RSP = 10, + TAOS_SMSG_SETUP = 11, + TAOS_SMSG_SETUP_RSP = 12, + TAOS_SMSG_END = 13, +} ESyncMsgType; + +typedef enum { + SYNC_STATUS_BROADCAST, + SYNC_STATUS_BROADCAST_RSP, + SYNC_STATUS_SETUP_CONN, + SYNC_STATUS_SETUP_CONN_RSP, + SYNC_STATUS_EXCHANGE_DATA, + SYNC_STATUS_EXCHANGE_DATA_RSP, + SYNC_STATUS_CHECK_ROLE, + SYNC_STATUS_CHECK_ROLE_RSP +} ESyncStatusType; + +#pragma pack(push, 1) + +typedef struct { + int8_t type; // msg type + int8_t protocol; // protocol version + uint16_t signature; // fixed value + int32_t code; // + int32_t cId; // cluster Id + int32_t vgId; // vg ID + int32_t len; // content length, does not include head + uint32_t cksum; +} SSyncHead; + +typedef struct { + SSyncHead head; + uint16_t port; + uint16_t tranId; + int32_t sourceId; // only for arbitrator + char fqdn[TSDB_FQDN_LEN]; +} SSyncMsg; + +typedef struct { + SSyncHead head; + int8_t sync; + int8_t reserved; + uint16_t tranId; + int8_t reserverd[4]; +} SSyncRsp; + +typedef struct { + int8_t role; + uint64_t version; +} SPeerStatus; + +typedef struct { + SSyncHead head; + int8_t role; + int8_t ack; + int8_t type; + int8_t reserved[3]; + uint16_t tranId; + uint64_t version; + SPeerStatus peersStatus[TAOS_SYNC_MAX_REPLICA]; +} SPeersStatus; + +typedef struct { + SSyncHead head; + char name[TSDB_FILENAME_LEN]; + uint32_t magic; + uint32_t index; + uint64_t fversion; + int64_t size; +} SFileInfo; + +typedef struct { + SSyncHead head; + int8_t sync; +} SFileAck; + +typedef struct { + SSyncHead head; + uint64_t version; + int32_t code; +} SFwdRsp; + +#pragma pack(pop) + +#define SYNC_PROTOCOL_VERSION 0 +#define SYNC_SIGNATURE ((uint16_t)(0xCDEF)) + +extern char *statusType[]; + +uint16_t syncGenTranId(); +int32_t syncCheckHead(SSyncHead *pHead); + +void syncBuildSyncFwdMsg(SSyncHead *pHead, int32_t vgId, int32_t len); +void syncBuildSyncFwdRsp(SFwdRsp *pMsg, int32_t vgId, uint64_t version, int32_t code); +void syncBuildSyncReqMsg(SSyncMsg *pMsg, int32_t vgId); +void syncBuildSyncDataMsg(SSyncMsg *pMsg, int32_t vgId); +void syncBuildSyncSetupMsg(SSyncMsg *pMsg, int32_t vgId); +void syncBuildPeersStatus(SPeersStatus *pMsg, int32_t vgId); + +#ifdef __cplusplus +} +#endif + +#endif // TDENGINE_VNODEPEER_H diff --git a/src/sync/src/syncMain.c b/src/sync/src/syncMain.c index 5e3355e68f..bf0b6e95d4 100644 --- a/src/sync/src/syncMain.c +++ b/src/sync/src/syncMain.c @@ -80,32 +80,6 @@ char *syncStatus[] = { "invalid" }; -typedef enum { - SYNC_STATUS_BROADCAST, - SYNC_STATUS_BROADCAST_RSP, - SYNC_STATUS_SETUP_CONN, - SYNC_STATUS_SETUP_CONN_RSP, - SYNC_STATUS_EXCHANGE_DATA, - SYNC_STATUS_EXCHANGE_DATA_RSP, - SYNC_STATUS_CHECK_ROLE, - SYNC_STATUS_CHECK_ROLE_RSP -} ESyncStatusType; - -char *statusType[] = { - "broadcast", - "broadcast-rsp", - "setup-conn", - "setup-conn-rsp", - "exchange-data", - "exchange-data-rsp", - "check-role", - "check-role-rsp" -}; - -uint16_t syncGenTranId() { - return taosRand() & 0XFFFF; -} - int32_t syncInit() { SPoolInfo info = {0}; @@ -384,19 +358,13 @@ void syncConfirmForward(int64_t rid, uint64_t version, int32_t code) { SSyncPeer *pPeer = pNode->pMaster; if (pPeer && pNode->quorum > 1) { - SFwdRsp fwdRsp = {0}; + SFwdRsp rsp; + syncBuildSyncFwdRsp(&rsp, pNode->vgId, version, code); - fwdRsp.head.type = TAOS_SMSG_FORWARD_RSP; - fwdRsp.head.protocol = SYNC_PROTOCOL_VERSION; - fwdRsp.head.vgId = pNode->vgId; - fwdRsp.head.len = sizeof(SFwdRsp) - sizeof(SSyncHead); - fwdRsp.version = version; - fwdRsp.code = code; - - if (taosWriteMsg(pPeer->peerFd, &fwdRsp, sizeof(SFwdRsp)) == sizeof(SFwdRsp)) { - sTrace("%s, forward-rsp is sent, code:%x hver:%" PRIu64, pPeer->id, code, version); + if (taosWriteMsg(pPeer->peerFd, &rsp, sizeof(SFwdRsp)) == sizeof(SFwdRsp)) { + sTrace("%s, forward-rsp is sent, code:0x%x hver:%" PRIu64, pPeer->id, code, version); } else { - sDebug("%s, failed to send forward ack, restart", pPeer->id); + sDebug("%s, failed to send forward-rsp, restart", pPeer->id); syncRestartConnection(pPeer); } } @@ -864,14 +832,7 @@ static void syncRecoverFromMaster(SSyncPeer *pPeer) { sDebug("%s, try to sync", pPeer->id); SSyncMsg msg; - memset(&msg, 0, sizeof(SSyncMsg)); - msg.head.type = TAOS_SMSG_SYNC_REQ; - msg.head.protocol = SYNC_PROTOCOL_VERSION; - msg.head.vgId = pNode->vgId; - msg.head.len = sizeof(SSyncMsg) - sizeof(SSyncHead); - msg.port = tsSyncPort; - msg.tranId = syncGenTranId(); - tstrncpy(msg.fqdn, tsNodeFqdn, TSDB_FQDN_LEN); + syncBuildSyncReqMsg(&msg, pNode->vgId); taosTmrReset(syncNotStarted, tsSyncTimer * 1000, pPeer, tsSyncTmrCtrl, &pPeer->timer); @@ -882,9 +843,8 @@ static void syncRecoverFromMaster(SSyncPeer *pPeer) { } } -static void syncProcessFwdResponse(char *cont, SSyncPeer *pPeer) { +static void syncProcessFwdResponse(SFwdRsp *pFwdRsp, SSyncPeer *pPeer) { SSyncNode *pNode = pPeer->pSyncNode; - SFwdRsp * pFwdRsp = (SFwdRsp *)cont; SSyncFwds *pSyncFwds = pNode->pSyncFwds; SFwdInfo * pFwdInfo; @@ -914,7 +874,7 @@ static void syncProcessFwdResponse(char *cont, SSyncPeer *pPeer) { static void syncProcessForwardFromPeer(char *cont, SSyncPeer *pPeer) { SSyncNode *pNode = pPeer->pSyncNode; - SWalHead * pHead = (SWalHead *)cont; + SWalHead * pHead = (SWalHead *)(cont + sizeof(SSyncHead)); sTrace("%s, forward is received, hver:%" PRIu64 ", len:%d", pPeer->id, pHead->version, pHead->len); @@ -931,9 +891,8 @@ static void syncProcessForwardFromPeer(char *cont, SSyncPeer *pPeer) { } } -static void syncProcessPeersStatusMsg(char *cont, SSyncPeer *pPeer) { - SSyncNode * pNode = pPeer->pSyncNode; - SPeersStatus *pPeersStatus = (SPeersStatus *)cont; +static void syncProcessPeersStatusMsg(SPeersStatus *pPeersStatus, SSyncPeer *pPeer) { + SSyncNode *pNode = pPeer->pSyncNode; sDebug("%s, status is received, self:%s:%s:%" PRIu64 ", peer:%s:%" PRIu64 ", ack:%d tranId:%u type:%s pfd:%d", pPeer->id, syncRole[nodeRole], syncStatus[nodeSStatus], nodeVersion, syncRole[pPeersStatus->role], @@ -947,23 +906,22 @@ static void syncProcessPeersStatusMsg(char *cont, SSyncPeer *pPeer) { } } -static int32_t syncReadPeerMsg(SSyncPeer *pPeer, SSyncHead *pHead, char *cont) { +static int32_t syncReadPeerMsg(SSyncPeer *pPeer, SSyncHead *pHead) { if (pPeer->peerFd < 0) return -1; int32_t hlen = taosReadMsg(pPeer->peerFd, pHead, sizeof(SSyncHead)); if (hlen != sizeof(SSyncHead)) { - sDebug("%s, failed to read msg, hlen:%d", pPeer->id, hlen); + sDebug("%s, failed to read msg since %s, hlen:%d", pPeer->id, tstrerror(errno), hlen); return -1; } - // head.len = htonl(head.len); - if (pHead->len < 0) { - sError("%s, invalid msg length, hlen:%d", pPeer->id, pHead->len); + int32_t code = syncCheckHead(pHead); + if (code != 0) { + sError("%s, failed to check msg head since %s, type:%d", pPeer->id, tstrerror(code), pHead->type); return -1; } - assert(pHead->len <= TSDB_MAX_WAL_SIZE); - int32_t bytes = taosReadMsg(pPeer->peerFd, cont, pHead->len); + int32_t bytes = taosReadMsg(pPeer->peerFd, (char *)pHead + sizeof(SSyncHead), pHead->len); if (bytes != pHead->len) { sError("%s, failed to read, bytes:%d len:%d", pPeer->id, bytes, pHead->len); return -1; @@ -974,23 +932,22 @@ static int32_t syncReadPeerMsg(SSyncPeer *pPeer, SSyncHead *pHead, char *cont) { static int32_t syncProcessPeerMsg(void *param, void *buffer) { SSyncPeer *pPeer = param; - SSyncHead head; - char * cont = buffer; - + SSyncHead *pHead = buffer; SSyncNode *pNode = pPeer->pSyncNode; + pthread_mutex_lock(&pNode->mutex); - int32_t code = syncReadPeerMsg(pPeer, &head, cont); + int32_t code = syncReadPeerMsg(pPeer, pHead); if (code == 0) { - if (head.type == TAOS_SMSG_FORWARD) { - syncProcessForwardFromPeer(cont, pPeer); - } else if (head.type == TAOS_SMSG_FORWARD_RSP) { - syncProcessFwdResponse(cont, pPeer); - } else if (head.type == TAOS_SMSG_SYNC_REQ) { - syncProcessSyncRequest(cont, pPeer); - } else if (head.type == TAOS_SMSG_STATUS) { - syncProcessPeersStatusMsg(cont, pPeer); + if (pHead->type == TAOS_SMSG_SYNC_FWD) { + syncProcessForwardFromPeer(buffer, pPeer); + } else if (pHead->type == TAOS_SMSG_SYNC_FWD_RSP) { + syncProcessFwdResponse(buffer, pPeer); + } else if (pHead->type == TAOS_SMSG_SYNC_REQ) { + syncProcessSyncRequest(buffer, pPeer); + } else if (pHead->type == TAOS_SMSG_STATUS) { + syncProcessPeersStatusMsg(buffer, pPeer); } } @@ -999,36 +956,29 @@ static int32_t syncProcessPeerMsg(void *param, void *buffer) { return code; } -#define statusMsgLen sizeof(SSyncHead) + sizeof(SPeersStatus) + sizeof(SPeerStatus) * TAOS_SYNC_MAX_REPLICA - static void syncSendPeersStatusMsgToPeer(SSyncPeer *pPeer, char ack, int8_t type, uint16_t tranId) { - SSyncNode *pNode = pPeer->pSyncNode; - char msg[statusMsgLen] = {0}; - if (pPeer->peerFd < 0 || pPeer->ip == 0) return; - SSyncHead * pHead = (SSyncHead *)msg; - SPeersStatus *pPeersStatus = (SPeersStatus *)(msg + sizeof(SSyncHead)); + SSyncNode *pNode = pPeer->pSyncNode; + SPeersStatus msg = {0}; - pHead->type = TAOS_SMSG_STATUS; - pHead->len = statusMsgLen - sizeof(SSyncHead); + syncBuildPeersStatus(&msg, pNode->vgId); - pPeersStatus->version = nodeVersion; - pPeersStatus->role = nodeRole; - pPeersStatus->ack = ack; - pPeersStatus->type = type; - pPeersStatus->tranId = tranId; + msg.role = nodeRole; + msg.ack = ack; + msg.type = type; + msg.tranId = tranId; + msg.version = nodeVersion; for (int32_t i = 0; i < pNode->replica; ++i) { - pPeersStatus->peersStatus[i].role = pNode->peerInfo[i]->role; - pPeersStatus->peersStatus[i].version = pNode->peerInfo[i]->version; + msg.peersStatus[i].role = pNode->peerInfo[i]->role; + msg.peersStatus[i].version = pNode->peerInfo[i]->version; } - if (taosWriteMsg(pPeer->peerFd, msg, statusMsgLen) == statusMsgLen) { + if (taosWriteMsg(pPeer->peerFd, &msg, sizeof(SPeersStatus)) == sizeof(SPeersStatus)) { sDebug("%s, status is sent, self:%s:%s:%" PRIu64 ", peer:%s:%s:%" PRIu64 ", ack:%d tranId:%u type:%s pfd:%d", pPeer->id, syncRole[nodeRole], syncStatus[nodeSStatus], nodeVersion, syncRole[pPeer->role], - syncStatus[pPeer->sstatus], pPeer->version, pPeersStatus->ack, pPeersStatus->tranId, - statusType[pPeersStatus->type], pPeer->peerFd); + syncStatus[pPeer->sstatus], pPeer->version, ack, tranId, statusType[type], pPeer->peerFd); } else { sDebug("%s, failed to send status msg, restart", pPeer->id); syncRestartConnection(pPeer); @@ -1053,15 +1003,7 @@ static void syncSetupPeerConnection(SSyncPeer *pPeer) { } SSyncMsg msg; - memset(&msg, 0, sizeof(SSyncMsg)); - msg.head.type = TAOS_SMSG_STATUS; - msg.head.protocol = SYNC_PROTOCOL_VERSION; - msg.head.vgId = pPeer->nodeId ? pNode->vgId : 0; - msg.head.len = sizeof(SSyncMsg) - sizeof(SSyncHead); - msg.port = tsSyncPort; - msg.tranId = syncGenTranId(); - msg.sourceId = pNode->vgId; // tell arbitrator its vgId - tstrncpy(msg.fqdn, tsNodeFqdn, TSDB_FQDN_LEN); + syncBuildSyncSetupMsg(&msg, pPeer->nodeId ? pNode->vgId : 0); if (taosWriteMsg(connFd, &msg, sizeof(SSyncMsg)) == sizeof(SSyncMsg)) { sDebug("%s, connection to peer server is setup, pfd:%d sfd:%d tranId:%u", pPeer->id, connFd, pPeer->syncFd, msg.tranId); @@ -1341,10 +1283,7 @@ static int32_t syncForwardToPeerImpl(SSyncNode *pNode, void *data, void *mhandle // a hacker way to improve the performance pSyncHead = (SSyncHead *)(((char *)pWalHead) - sizeof(SSyncHead)); - pSyncHead->type = TAOS_SMSG_FORWARD; - pSyncHead->protocol = SYNC_PROTOCOL_VERSION; - pSyncHead->vgId = pNode->vgId; - pSyncHead->len = sizeof(SWalHead) + pWalHead->len; + syncBuildSyncFwdMsg(pSyncHead, pNode->vgId, sizeof(SWalHead) + pWalHead->len); fwdLen = pSyncHead->len + sizeof(SSyncHead); // include the WAL and SYNC head pthread_mutex_lock(&pNode->mutex); diff --git a/src/sync/src/syncMsg.c b/src/sync/src/syncMsg.c new file mode 100644 index 0000000000..dafefc77ba --- /dev/null +++ b/src/sync/src/syncMsg.c @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2019 TAOS Data, Inc. + * + * This program is free software: you can use, redistribute, and/or modify + * it under the terms of the GNU Affero General Public License, version 3 + * or later ("AGPL"), as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +#define _DEFAULT_SOURCE +#include "os.h" +#include "taoserror.h" +#include "tchecksum.h" +#include "syncInt.h" + +char *statusType[] = { + "broadcast", + "broadcast-rsp", + "setup-conn", + "setup-conn-rsp", + "exchange-data", + "exchange-data-rsp", + "check-role", + "check-role-rsp" +}; + +uint16_t syncGenTranId() { + return taosRand() & 0XFFFF; +} + +static void syncBuildHead(SSyncHead *pHead) { + pHead->protocol = SYNC_PROTOCOL_VERSION; + pHead->signature = SYNC_SIGNATURE; + pHead->code = 0; + pHead->cId = 0; + taosCalcChecksumAppend(0, (uint8_t *)pHead, sizeof(SSyncHead)); +} + +int32_t syncCheckHead(SSyncHead *pHead) { + if (pHead->protocol != SYNC_PROTOCOL_VERSION) return TSDB_CODE_SYN_MISMATCHED_PROTOCOL; + if (pHead->signature != SYNC_SIGNATURE) return TSDB_CODE_SYN_MISMATCHED_SIGNATURE; + if (pHead->cId != 0) return TSDB_CODE_SYN_MISMATCHED_CLUSTERID; + if (pHead->len <= 0 || pHead->len > TSDB_MAX_WAL_SIZE) return TSDB_CODE_SYN_INVALID_MSGLEN; + if (!taosCheckChecksumWhole((uint8_t *)pHead, sizeof(SSyncHead))) return TSDB_CODE_SYN_INVALID_CHECKSUM; + + return TSDB_CODE_SUCCESS; +} + +void syncBuildSyncFwdMsg(SSyncHead *pHead, int32_t vgId, int32_t len) { + pHead->type = TAOS_SMSG_SYNC_FWD; + pHead->vgId = vgId; + pHead->len = len; + syncBuildHead(pHead); +} + +void syncBuildSyncFwdRsp(SFwdRsp *pMsg, int32_t vgId, uint64_t version, int32_t code) { + pMsg->head.type = TAOS_SMSG_SYNC_FWD_RSP; + pMsg->head.vgId = vgId; + pMsg->head.len = sizeof(SFwdRsp) - sizeof(SSyncHead); + syncBuildHead(&pMsg->head); + + pMsg->version = version; + pMsg->code = code; +} + +static void syncBuildMsg(SSyncMsg *pMsg, int32_t vgId, ESyncMsgType type) { + pMsg->head.type = type; + pMsg->head.vgId = vgId; + pMsg->head.len = sizeof(SSyncMsg) - sizeof(SSyncHead); + syncBuildHead(&pMsg->head); + + pMsg->port = tsSyncPort; + pMsg->tranId = syncGenTranId(); + pMsg->sourceId = vgId; + tstrncpy(pMsg->fqdn, tsNodeFqdn, TSDB_FQDN_LEN); +} + +void syncBuildSyncReqMsg(SSyncMsg *pMsg, int32_t vgId) { syncBuildMsg(pMsg, vgId, TAOS_SMSG_SYNC_REQ); } +void syncBuildSyncDataMsg(SSyncMsg *pMsg, int32_t vgId) { syncBuildMsg(pMsg, vgId, TAOS_SMSG_SYNC_DATA); } +void syncBuildSyncSetupMsg(SSyncMsg *pMsg, int32_t vgId) { syncBuildMsg(pMsg, vgId, TAOS_SMSG_SETUP); } + +void syncBuildPeersStatus(SPeersStatus *pMsg, int32_t vgId) { + pMsg->head.type = TAOS_SMSG_STATUS; + pMsg->head.vgId = vgId; + pMsg->head.len = sizeof(SPeersStatus) - sizeof(SSyncHead); + syncBuildHead(&pMsg->head); +} diff --git a/src/sync/src/syncRetrieve.c b/src/sync/src/syncRetrieve.c index 981716d561..204f4f9036 100644 --- a/src/sync/src/syncRetrieve.c +++ b/src/sync/src/syncRetrieve.c @@ -406,14 +406,7 @@ static int32_t syncRetrieveFirstPkt(SSyncPeer *pPeer) { SSyncNode *pNode = pPeer->pSyncNode; SSyncMsg msg; - memset(&msg, 0, sizeof(SSyncMsg)); - msg.head.type = TAOS_SMSG_SYNC_DATA; - msg.head.protocol = SYNC_PROTOCOL_VERSION; - msg.head.vgId = pNode->vgId; - msg.head.len = sizeof(SSyncMsg) - sizeof(SSyncHead); - msg.port = tsSyncPort; - msg.tranId = syncGenTranId(); - tstrncpy(msg.fqdn, tsNodeFqdn, TSDB_FQDN_LEN); + syncBuildSyncDataMsg(&msg, pNode->vgId); if (taosWriteMsg(pPeer->syncFd, &msg, sizeof(SSyncMsg)) != sizeof(SSyncMsg)) { sError("%s, failed to send sync-data msg since %s, tranId:%u", pPeer->id, strerror(errno), msg.tranId); From fce7a9d299f140eca0a916b957d0d9f2b1d7eb6b Mon Sep 17 00:00:00 2001 From: dapan1121 Date: Wed, 16 Dec 2020 12:08:07 +0000 Subject: [PATCH 09/38] fix bug --- src/client/src/tscAsync.c | 6 +++++- src/kit/shell/inc/shell.h | 2 +- src/kit/shell/src/shellEngine.c | 15 +++++++++------ src/kit/shell/src/shellMain.c | 6 ++++-- 4 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/client/src/tscAsync.c b/src/client/src/tscAsync.c index 910a7b4112..97b962e53a 100644 --- a/src/client/src/tscAsync.c +++ b/src/client/src/tscAsync.c @@ -381,6 +381,7 @@ void tscQueueAsyncError(void(*fp), void *param, int32_t code) { taosScheduleTask(tscQhandle, &schedMsg); } + void tscQueueAsyncRes(SSqlObj *pSql) { if (pSql == NULL || pSql->signature != pSql) { tscDebug("%p SqlObj is freed, not add into queue async res", pSql); @@ -390,7 +391,10 @@ void tscQueueAsyncRes(SSqlObj *pSql) { tscError("%p add into queued async res, code:%s", pSql, tstrerror(pSql->res.code)); SSqlRes *pRes = &pSql->res; - assert(pSql->fp != NULL && pSql->fetchFp != NULL); + + if (pSql->fp == NULL || pSql->fetchFp == NULL){ + return; + } pSql->fp = pSql->fetchFp; (*pSql->fp)(pSql->param, pSql, pRes->code); diff --git a/src/kit/shell/inc/shell.h b/src/kit/shell/inc/shell.h index 7e5ebb0596..2415695617 100644 --- a/src/kit/shell/inc/shell.h +++ b/src/kit/shell/inc/shell.h @@ -86,6 +86,6 @@ extern void set_terminal_mode(); extern int get_old_terminal_mode(struct termios* tio); extern void reset_terminal_mode(); extern SShellArguments args; -extern TAOS_RES* result; +extern int64_t result; #endif diff --git a/src/kit/shell/src/shellEngine.c b/src/kit/shell/src/shellEngine.c index 7a9e242668..1a8325cc43 100644 --- a/src/kit/shell/src/shellEngine.c +++ b/src/kit/shell/src/shellEngine.c @@ -46,7 +46,7 @@ char CONTINUE_PROMPT[] = " -> "; int prompt_size = 6; #endif -TAOS_RES *result = NULL; +int64_t result = 0; SShellHistory history; #define DEFAULT_MAX_BINARY_DISPLAY_WIDTH 30 @@ -294,17 +294,20 @@ void shellRunCommandOnServer(TAOS *con, char command[]) { st = taosGetTimestampUs(); - TAOS_RES* pSql = taos_query_h(con, command, &result); + TAOS_RES* tmpSql = NULL; + TAOS_RES* pSql = taos_query_h(con, command, &tmpSql); if (taos_errno(pSql)) { taos_error(pSql, st); return; } + result = ((SSqlObj*)tmpSql)->self; + if (regex_match(command, "^\\s*use\\s+[a-zA-Z0-9_]+\\s*;\\s*$", REG_EXTENDED | REG_ICASE)) { fprintf(stdout, "Database changed.\n\n"); fflush(stdout); - atomic_store_ptr(&result, 0); + atomic_store_64(&result, 0); taos_free_result(pSql); return; } @@ -313,7 +316,7 @@ void shellRunCommandOnServer(TAOS *con, char command[]) { int error_no = 0; int numOfRows = shellDumpResult(pSql, fname, &error_no, printMode); if (numOfRows < 0) { - atomic_store_ptr(&result, 0); + atomic_store_64(&result, 0); taos_free_result(pSql); return; } @@ -336,7 +339,7 @@ void shellRunCommandOnServer(TAOS *con, char command[]) { wordfree(&full_path); } - atomic_store_ptr(&result, 0); + atomic_store_64(&result, 0); taos_free_result(pSql); } @@ -501,7 +504,7 @@ static int dumpResultToFile(const char* fname, TAOS_RES* tres) { row = taos_fetch_row(tres); } while( row != NULL); - result = NULL; + result = 0; fclose(fp); return numOfRows; diff --git a/src/kit/shell/src/shellMain.c b/src/kit/shell/src/shellMain.c index 4f0c5e3f99..7b812f5d5b 100644 --- a/src/kit/shell/src/shellMain.c +++ b/src/kit/shell/src/shellMain.c @@ -22,8 +22,10 @@ pthread_t pid; void shellQueryInterruptHandler(int signum) { #ifdef LINUX - void* pResHandle = atomic_val_compare_exchange_64(&result, result, 0); - taos_stop_query(pResHandle); + int64_t rid = atomic_val_compare_exchange_64(&result, result, 0); + SSqlObj* pSql = taosAcquireRef(tscObjRef, rid); + taos_stop_query(pSql); + taosReleaseRef(tscObjRef, rid); #else printf("\nReceive ctrl+c or other signal, quit shell.\n"); exit(0); From e0d113b1754a06dcaed4016f77d6da0b8cbfc7bc Mon Sep 17 00:00:00 2001 From: Shengliang Guan Date: Wed, 16 Dec 2020 20:17:33 +0800 Subject: [PATCH 10/38] TD-2428 --- src/inc/taoserror.h | 1 + src/sync/src/syncMain.c | 12 ++---------- src/sync/src/syncMsg.c | 1 + 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/inc/taoserror.h b/src/inc/taoserror.h index 58e19ce52a..7c7e7ec31a 100644 --- a/src/inc/taoserror.h +++ b/src/inc/taoserror.h @@ -272,6 +272,7 @@ TAOS_DEFINE_ERROR(TSDB_CODE_SYN_MISMATCHED_CLUSTERID, 0, 0x0906, "Mismatched TAOS_DEFINE_ERROR(TSDB_CODE_SYN_MISMATCHED_SIGNATURE, 0, 0x0907, "Mismatched signature") TAOS_DEFINE_ERROR(TSDB_CODE_SYN_INVALID_CHECKSUM, 0, 0x0908, "Invalid msg checksum") TAOS_DEFINE_ERROR(TSDB_CODE_SYN_INVALID_MSGLEN, 0, 0x0909, "Invalid msg length") +TAOS_DEFINE_ERROR(TSDB_CODE_SYN_INVALID_MSGTYPE, 0, 0x090A, "Invalid msg type") // wal TAOS_DEFINE_ERROR(TSDB_CODE_WAL_APP_ERROR, 0, 0x1000, "Unexpected generic error in wal") diff --git a/src/sync/src/syncMain.c b/src/sync/src/syncMain.c index bf0b6e95d4..e84de62368 100644 --- a/src/sync/src/syncMain.c +++ b/src/sync/src/syncMain.c @@ -851,25 +851,17 @@ static void syncProcessFwdResponse(SFwdRsp *pFwdRsp, SSyncPeer *pPeer) { sTrace("%s, forward-rsp is received, code:%x hver:%" PRIu64, pPeer->id, pFwdRsp->code, pFwdRsp->version); SFwdInfo *pFirst = pSyncFwds->fwdInfo + pSyncFwds->first; - bool found = false; if (pFirst->version <= pFwdRsp->version && pSyncFwds->fwds > 0) { // find the forwardInfo from first for (int32_t i = 0; i < pSyncFwds->fwds; ++i) { pFwdInfo = pSyncFwds->fwdInfo + (i + pSyncFwds->first) % tsMaxFwdInfo; if (pFwdRsp->version == pFwdInfo->version) { - found = true; syncProcessFwdAck(pNode, pFwdInfo, pFwdRsp->code); syncRemoveConfirmedFwdInfo(pNode); - break; + return; } } } - - if (!found) { - sTrace("%s, forward-rsp not found first:%d fwds:%d, code:%x hver:%" PRIu64, pPeer->id, pSyncFwds->first, - pSyncFwds->fwds, pFwdRsp->code, pFwdRsp->version); - syncProcessFwdAck(pNode, pFwdInfo, pFwdRsp->code); - } } static void syncProcessForwardFromPeer(char *cont, SSyncPeer *pPeer) { @@ -1192,7 +1184,7 @@ static void syncProcessFwdAck(SSyncNode *pNode, SFwdInfo *pFwdInfo, int32_t code } if (confirm && pFwdInfo->confirmed == 0) { - sTrace("vgId:%d, forward is confirmed, hver:%" PRIu64 " code:%x", pNode->vgId, pFwdInfo->version, pFwdInfo->code); + sTrace("vgId:%d, forward is confirmed, hver:%" PRIu64 " code:0x%x", pNode->vgId, pFwdInfo->version, pFwdInfo->code); (*pNode->confirmForward)(pNode->vgId, pFwdInfo->mhandle, pFwdInfo->code); pFwdInfo->confirmed = 1; } diff --git a/src/sync/src/syncMsg.c b/src/sync/src/syncMsg.c index dafefc77ba..7ca96e86ba 100644 --- a/src/sync/src/syncMsg.c +++ b/src/sync/src/syncMsg.c @@ -47,6 +47,7 @@ int32_t syncCheckHead(SSyncHead *pHead) { if (pHead->signature != SYNC_SIGNATURE) return TSDB_CODE_SYN_MISMATCHED_SIGNATURE; if (pHead->cId != 0) return TSDB_CODE_SYN_MISMATCHED_CLUSTERID; if (pHead->len <= 0 || pHead->len > TSDB_MAX_WAL_SIZE) return TSDB_CODE_SYN_INVALID_MSGLEN; + if (pHead->type <= TAOS_SMSG_START || pHead->type >= TAOS_SMSG_END) return TSDB_CODE_SYN_INVALID_MSGTYPE; if (!taosCheckChecksumWhole((uint8_t *)pHead, sizeof(SSyncHead))) return TSDB_CODE_SYN_INVALID_CHECKSUM; return TSDB_CODE_SUCCESS; From 99e31ce57e48410adf7b1e2fce582372578d83b9 Mon Sep 17 00:00:00 2001 From: Minglei Jin Date: Wed, 16 Dec 2020 18:03:07 +0800 Subject: [PATCH 11/38] coverity 278651: Skip walHead if len is out of range --- src/wal/src/walWrite.c | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/wal/src/walWrite.c b/src/wal/src/walWrite.c index 2253ad5c33..e67127d6e4 100644 --- a/src/wal/src/walWrite.c +++ b/src/wal/src/walWrite.c @@ -297,16 +297,14 @@ static int32_t walRestoreWalFile(SWal *pWal, void *pVnode, FWalWrite writeFp, ch } } - if (pHead->len > size - sizeof(SWalHead)) { - size = sizeof(SWalHead) + pHead->len; - buffer = realloc(buffer, size); - if (buffer == NULL) { - wError("vgId:%d, file:%s, failed to open for restore since %s", pWal->vgId, name, strerror(errno)); - code = TAOS_SYSTEM_ERROR(errno); + if (pHead->len < 0 || pHead->len > size - sizeof(SWalHead)) { + wError("vgId:%d, file:%s, wal head len out of range, hver:%" PRIu64 " len:%d offset:%" PRId64, pWal->vgId, name, + pHead->version, pHead->len, offset); + code = walSkipCorruptedRecord(pWal, pHead, tfd, &offset); + if (code != TSDB_CODE_SUCCESS) { + walFtruncate(pWal, tfd, offset); break; } - - pHead = buffer; } ret = tfRead(tfd, pHead->cont, pHead->len); From 456ef978cc7e5cf0a4dc2f2fc6f822886e90805f Mon Sep 17 00:00:00 2001 From: Shengliang Guan Date: Wed, 16 Dec 2020 23:28:12 +0800 Subject: [PATCH 12/38] TD-2428 --- src/sync/inc/syncMsg.h | 9 +++++++-- src/sync/src/syncMsg.c | 17 +++++++++++++++++ src/sync/src/syncRestore.c | 14 ++++++++++---- src/sync/src/syncRetrieve.c | 12 ++++++++++-- 4 files changed, 44 insertions(+), 8 deletions(-) diff --git a/src/sync/inc/syncMsg.h b/src/sync/inc/syncMsg.h index 9a7ff04de1..73f4223c88 100644 --- a/src/sync/inc/syncMsg.h +++ b/src/sync/inc/syncMsg.h @@ -35,7 +35,9 @@ typedef enum { TAOS_SMSG_STATUS_RSP = 10, TAOS_SMSG_SETUP = 11, TAOS_SMSG_SETUP_RSP = 12, - TAOS_SMSG_END = 13, + TAOS_SMSG_SYNC_FILE = 13, + TAOS_SMSG_SYNC_FILE_RSP = 14, + TAOS_SMSG_END = 15, } ESyncMsgType; typedef enum { @@ -116,7 +118,7 @@ typedef struct { #pragma pack(pop) -#define SYNC_PROTOCOL_VERSION 0 +#define SYNC_PROTOCOL_VERSION 1 #define SYNC_SIGNATURE ((uint16_t)(0xCDEF)) extern char *statusType[]; @@ -131,6 +133,9 @@ void syncBuildSyncDataMsg(SSyncMsg *pMsg, int32_t vgId); void syncBuildSyncSetupMsg(SSyncMsg *pMsg, int32_t vgId); void syncBuildPeersStatus(SPeersStatus *pMsg, int32_t vgId); +void syncBuildFileAck(SFileAck *pMsg, int32_t vgId); +void syncBuildFileInfo(SFileInfo *pMsg, int32_t vgId); + #ifdef __cplusplus } #endif diff --git a/src/sync/src/syncMsg.c b/src/sync/src/syncMsg.c index 7ca96e86ba..abb2ac896f 100644 --- a/src/sync/src/syncMsg.c +++ b/src/sync/src/syncMsg.c @@ -16,6 +16,7 @@ #define _DEFAULT_SOURCE #include "os.h" #include "taoserror.h" +#include "tglobal.h" #include "tchecksum.h" #include "syncInt.h" @@ -92,3 +93,19 @@ void syncBuildPeersStatus(SPeersStatus *pMsg, int32_t vgId) { pMsg->head.len = sizeof(SPeersStatus) - sizeof(SSyncHead); syncBuildHead(&pMsg->head); } + +void syncBuildFileAck(SFileAck *pMsg, int32_t vgId) { + memset(pMsg, 0, sizeof(SFileAck)); + pMsg->head.type = TAOS_SMSG_SYNC_FILE_RSP; + pMsg->head.vgId = vgId; + pMsg->head.len = sizeof(SFileAck) - sizeof(SSyncHead); + syncBuildHead(&pMsg->head); +} + +void syncBuildFileInfo(SFileInfo *pMsg, int32_t vgId) { + memset(pMsg, 0, sizeof(SFileInfo)); + pMsg->head.type = TAOS_SMSG_SYNC_FILE; + pMsg->head.vgId = vgId; + pMsg->head.len = sizeof(SFileInfo) - sizeof(SSyncHead); + syncBuildHead(&pMsg->head); +} \ No newline at end of file diff --git a/src/sync/src/syncRestore.c b/src/sync/src/syncRestore.c index 850a9b78b7..088215ecc7 100644 --- a/src/sync/src/syncRestore.c +++ b/src/sync/src/syncRestore.c @@ -69,7 +69,13 @@ static int32_t syncRestoreFile(SSyncPeer *pPeer, uint64_t *fversion) { minfo.index = -1; int32_t ret = taosReadMsg(pPeer->syncFd, &minfo, sizeof(SFileInfo)); if (ret != sizeof(SFileInfo) || minfo.index == -1) { - sError("%s, failed to read file info while restore file since %s", pPeer->id, strerror(errno)); + sError("%s, failed to read fileinfo while restore file since %s", pPeer->id, strerror(errno)); + break; + } + + ret = syncCheckHead((SSyncHead*)(&minfo)); + if (ret != 0) { + sError("%s, failed to check fileinfo while restore file since %s", pPeer->id, strerror(ret)); break; } @@ -94,12 +100,12 @@ static int32_t syncRestoreFile(SSyncPeer *pPeer, uint64_t *fversion) { &sinfo.fversion); // if file not there or magic is not the same, file shall be synced - memset(&fileAck, 0, sizeof(fileAck)); + syncBuildFileAck(&fileAck, pNode->vgId); fileAck.sync = (sinfo.magic != minfo.magic || sinfo.name[0] == 0) ? 1 : 0; // send file ack - ret = taosWriteMsg(pPeer->syncFd, &fileAck, sizeof(fileAck)); - if (ret != sizeof(fileAck)) { + ret = taosWriteMsg(pPeer->syncFd, &fileAck, sizeof(SFileAck)); + if (ret != sizeof(SFileAck)) { sError("%s, failed to write file:%s ack while restore file since %s", pPeer->id, minfo.name, strerror(errno)); break; } diff --git a/src/sync/src/syncRetrieve.c b/src/sync/src/syncRetrieve.c index 204f4f9036..a1022c6fa0 100644 --- a/src/sync/src/syncRetrieve.c +++ b/src/sync/src/syncRetrieve.c @@ -99,6 +99,7 @@ static int32_t syncRetrieveFile(SSyncPeer *pPeer) { while (1) { // retrieve file info + syncBuildFileInfo(&fileInfo, pNode->vgId); fileInfo.name[0] = 0; fileInfo.size = 0; fileInfo.magic = (*pNode->getFileInfo)(pNode->vgId, fileInfo.name, &fileInfo.index, TAOS_SYNC_MAX_INDEX, @@ -106,8 +107,8 @@ static int32_t syncRetrieveFile(SSyncPeer *pPeer) { sDebug("%s, file:%s info is sent, size:%" PRId64, pPeer->id, fileInfo.name, fileInfo.size); // send the file info - int32_t ret = taosWriteMsg(pPeer->syncFd, &(fileInfo), sizeof(fileInfo)); - if (ret != sizeof(fileInfo)) { + int32_t ret = taosWriteMsg(pPeer->syncFd, &(fileInfo), sizeof(SFileInfo)); + if (ret != sizeof(SFileInfo)) { code = -1; sError("%s, failed to write file:%s info while retrieve file since %s", pPeer->id, fileInfo.name, strerror(errno)); break; @@ -128,6 +129,13 @@ static int32_t syncRetrieveFile(SSyncPeer *pPeer) { break; } + ret = syncCheckHead((SSyncHead*)(&fileAck)); + if (ret != 0) { + code = -1; + sError("%s, failed to check file:%s ack while retrieve file since %s", pPeer->id, fileInfo.name, strerror(ret)); + break; + } + // set the peer sync version pPeer->sversion = fileInfo.fversion; From 1c7bd8d970c79043e840c5ac5db134bc4902116a Mon Sep 17 00:00:00 2001 From: Shengliang Guan Date: Wed, 16 Dec 2020 23:35:43 +0800 Subject: [PATCH 13/38] TD-2463 --- src/sync/src/syncMain.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/sync/src/syncMain.c b/src/sync/src/syncMain.c index e84de62368..078b02556c 100644 --- a/src/sync/src/syncMain.c +++ b/src/sync/src/syncMain.c @@ -310,6 +310,11 @@ int32_t syncReconfig(int64_t rid, const SSyncCfg *pNewCfg) { newPeers[i] = pNode->peerInfo[j]; } + if (newPeers[i] == NULL) { + sError("vgId:%d, failed to reconfig", pNode->vgId); + return TSDB_CODE_SYN_INVALID_CONFIG; + } + if ((strcmp(pNewNode->nodeFqdn, tsNodeFqdn) == 0) && (pNewNode->nodePort == tsSyncPort)) { pNode->selfIndex = i; } @@ -1059,6 +1064,13 @@ static void syncProcessIncommingConnection(int32_t connFd, uint32_t sourceIp) { return; } + int32_t code = syncCheckHead((SSyncHead *)(&msg)); + if (code != 0) { + sError("failed to check peer sync msg from ip:%s since %s", ipstr, strerror(code)); + taosCloseSocket(connFd); + return; + } + int32_t vgId = msg.head.vgId; SSyncNode **ppNode = taosHashGet(tsVgIdHash, &vgId, sizeof(int32_t)); if (ppNode == NULL || *ppNode == NULL) { @@ -1305,4 +1317,3 @@ static int32_t syncForwardToPeerImpl(SSyncNode *pNode, void *data, void *mhandle return code; } - From fa929caecc3472a05b3b828f4c21afc0af4b96bb Mon Sep 17 00:00:00 2001 From: Shuduo Sang Date: Thu, 17 Dec 2020 10:42:25 +0800 Subject: [PATCH 14/38] replace connector.png --- documentation20/webdocs/assets/connector.png | Bin 78340 -> 87029 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/documentation20/webdocs/assets/connector.png b/documentation20/webdocs/assets/connector.png index 1f8708ff199fd8054a150b5c4ffbaf640f071eb8..6030bd73f51123615eabacfa5d734918559ce3d9 100644 GIT binary patch literal 87029 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 z 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 Date: Thu, 17 Dec 2020 11:07:11 +0800 Subject: [PATCH 15/38] TD-2428 --- src/sync/src/syncRetrieve.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sync/src/syncRetrieve.c b/src/sync/src/syncRetrieve.c index a1022c6fa0..d579025ded 100644 --- a/src/sync/src/syncRetrieve.c +++ b/src/sync/src/syncRetrieve.c @@ -99,11 +99,11 @@ static int32_t syncRetrieveFile(SSyncPeer *pPeer) { while (1) { // retrieve file info - syncBuildFileInfo(&fileInfo, pNode->vgId); fileInfo.name[0] = 0; fileInfo.size = 0; fileInfo.magic = (*pNode->getFileInfo)(pNode->vgId, fileInfo.name, &fileInfo.index, TAOS_SYNC_MAX_INDEX, &fileInfo.size, &fileInfo.fversion); + syncBuildFileInfo(&fileInfo, pNode->vgId); sDebug("%s, file:%s info is sent, size:%" PRId64, pPeer->id, fileInfo.name, fileInfo.size); // send the file info From b157f711f44a0ae99c672c8732134546f3382829 Mon Sep 17 00:00:00 2001 From: dapan1121 Date: Thu, 17 Dec 2020 05:06:20 +0000 Subject: [PATCH 16/38] move signal handle to thread --- src/kit/shell/src/shellEngine.c | 17 +++++++++++++---- src/kit/shell/src/shellMain.c | 34 +++++++++++++++++++++++++++------ 2 files changed, 41 insertions(+), 10 deletions(-) diff --git a/src/kit/shell/src/shellEngine.c b/src/kit/shell/src/shellEngine.c index 1a8325cc43..627d06ac2e 100644 --- a/src/kit/shell/src/shellEngine.c +++ b/src/kit/shell/src/shellEngine.c @@ -260,6 +260,14 @@ int32_t shellRunCommand(TAOS* con, char* command) { } +void freeResultWithRid(int64_t rid) { + SSqlObj* pSql = taosAcquireRef(tscObjRef, rid); + if(pSql){ + taos_free_result(pSql); + taosReleaseRef(tscObjRef, rid); + } +} + void shellRunCommandOnServer(TAOS *con, char command[]) { int64_t st, et; wordexp_t full_path; @@ -301,14 +309,15 @@ void shellRunCommandOnServer(TAOS *con, char command[]) { return; } - result = ((SSqlObj*)tmpSql)->self; + atomic_store_64(&result, ((SSqlObj*)tmpSql)->self); + int64_t oresult = atomic_load_64(&result); if (regex_match(command, "^\\s*use\\s+[a-zA-Z0-9_]+\\s*;\\s*$", REG_EXTENDED | REG_ICASE)) { fprintf(stdout, "Database changed.\n\n"); fflush(stdout); atomic_store_64(&result, 0); - taos_free_result(pSql); + freeResultWithRid(oresult); return; } @@ -317,7 +326,7 @@ void shellRunCommandOnServer(TAOS *con, char command[]) { int numOfRows = shellDumpResult(pSql, fname, &error_no, printMode); if (numOfRows < 0) { atomic_store_64(&result, 0); - taos_free_result(pSql); + freeResultWithRid(oresult); return; } @@ -340,7 +349,7 @@ void shellRunCommandOnServer(TAOS *con, char command[]) { } atomic_store_64(&result, 0); - taos_free_result(pSql); + freeResultWithRid(oresult); } /* Function to do regular expression check */ diff --git a/src/kit/shell/src/shellMain.c b/src/kit/shell/src/shellMain.c index 7b812f5d5b..041ad71ccb 100644 --- a/src/kit/shell/src/shellMain.c +++ b/src/kit/shell/src/shellMain.c @@ -19,17 +19,31 @@ #include "tnettest.h" pthread_t pid; +static tsem_t cancelSem; void shellQueryInterruptHandler(int signum) { + tsem_post(&cancelSem); +} + +void *cancelHandler(void *arg) { + while(1) { + if (tsem_wait(&cancelSem) != 0) { + taosMsleep(10); + continue; + } + #ifdef LINUX - int64_t rid = atomic_val_compare_exchange_64(&result, result, 0); - SSqlObj* pSql = taosAcquireRef(tscObjRef, rid); - taos_stop_query(pSql); - taosReleaseRef(tscObjRef, rid); + int64_t rid = atomic_val_compare_exchange_64(&result, result, 0); + SSqlObj* pSql = taosAcquireRef(tscObjRef, rid); + taos_stop_query(pSql); + taosReleaseRef(tscObjRef, rid); #else - printf("\nReceive ctrl+c or other signal, quit shell.\n"); - exit(0); + printf("\nReceive ctrl+c or other signal, quit shell.\n"); + exit(0); #endif + } + + return NULL; } int checkVersion() { @@ -107,6 +121,14 @@ int main(int argc, char* argv[]) { exit(EXIT_FAILURE); } + if (tsem_init(&cancelSem, 0, 0) != 0) { + printf("failed to create cancel semphore\n"); + exit(EXIT_FAILURE); + } + + pthread_t spid; + pthread_create(&spid, NULL, cancelHandler, NULL); + /* Interrupt handler. */ struct sigaction act; memset(&act, 0, sizeof(struct sigaction)); From fe4a31d5f9624e47ed1948075380aaf886de41f7 Mon Sep 17 00:00:00 2001 From: root Date: Thu, 17 Dec 2020 15:48:40 +0800 Subject: [PATCH 17/38] test appveyor on win32 --- .appveyor.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index 559431e2f9..d211580875 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -3,6 +3,7 @@ os: Visual Studio 2015 environment: matrix: - ARCH: amd64 + - ARCH: x86 clone_folder: c:\dev\TDengine clone_depth: 1 @@ -18,7 +19,7 @@ build_script: - cd build - cmake -G "NMake Makefiles" .. - nmake install - + - echo Building platform=%PLATFORM% notifications: - provider: Email to: From bdde3b4e3478dd683c804f2edb97fad214d10446 Mon Sep 17 00:00:00 2001 From: root Date: Thu, 17 Dec 2020 16:00:21 +0800 Subject: [PATCH 18/38] test --- .appveyor.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index d211580875..feb361b6d1 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -4,12 +4,14 @@ environment: matrix: - ARCH: amd64 - ARCH: x86 - +platform: + - x86 + - amd64 clone_folder: c:\dev\TDengine clone_depth: 1 init: - - call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" %ARCH% + - call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" %platform% before_build: - cd c:\dev\TDengine @@ -19,7 +21,7 @@ build_script: - cd build - cmake -G "NMake Makefiles" .. - nmake install - - echo Building platform=%PLATFORM% + - echo Building platform=%platform% notifications: - provider: Email to: From b696d22ded1a1ed68b2804ff187c20fceb3a3a93 Mon Sep 17 00:00:00 2001 From: root Date: Thu, 17 Dec 2020 16:02:11 +0800 Subject: [PATCH 19/38] test --- .appveyor.yml | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index feb361b6d1..ab629e337c 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,17 +1,14 @@ version: 1.0.{build} os: Visual Studio 2015 -environment: - matrix: - - ARCH: amd64 - - ARCH: x86 -platform: + +Platform: - x86 - amd64 clone_folder: c:\dev\TDengine clone_depth: 1 init: - - call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" %platform% + - call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" %Platform% before_build: - cd c:\dev\TDengine From 4069969a8989416f349d49d621d6e6bedf092045 Mon Sep 17 00:00:00 2001 From: Shengliang Guan Date: Thu, 17 Dec 2020 16:02:13 +0800 Subject: [PATCH 20/38] TD-1927 --- src/inc/tsync.h | 4 ---- src/sync/inc/syncInt.h | 12 +++++++++--- src/sync/src/syncMain.c | 43 +++++++++++++++++------------------------ 3 files changed, 27 insertions(+), 32 deletions(-) diff --git a/src/inc/tsync.h b/src/inc/tsync.h index 0ce2a1a495..4dae86bbed 100644 --- a/src/inc/tsync.h +++ b/src/inc/tsync.h @@ -119,10 +119,6 @@ int32_t syncGetNodesRole(int64_t rid, SNodesRole *); extern char *syncRole[]; //global configurable parameters -extern int32_t tsMaxSyncNum; -extern int32_t tsSyncTcpThreads; -extern int32_t tsSyncTimer; -extern int32_t tsMaxFwdInfo; extern int32_t sDebugFlag; extern char tsArbitrator[]; extern uint16_t tsSyncPort; diff --git a/src/sync/inc/syncInt.h b/src/sync/inc/syncInt.h index 535251ba11..d855c651f9 100644 --- a/src/sync/inc/syncInt.h +++ b/src/sync/inc/syncInt.h @@ -29,11 +29,17 @@ extern "C" { #define sDebug(...) { if (sDebugFlag & DEBUG_DEBUG) { taosPrintLog("SYN ", sDebugFlag, __VA_ARGS__); }} #define sTrace(...) { if (sDebugFlag & DEBUG_TRACE) { taosPrintLog("SYN ", sDebugFlag, __VA_ARGS__); }} +#define SYNC_TCP_THREADS 2 +#define SYNC_MAX_NUM 2 + #define SYNC_MAX_SIZE (TSDB_MAX_WAL_SIZE + sizeof(SWalHead) + sizeof(SSyncHead) + 16) #define SYNC_RECV_BUFFER_SIZE (5*1024*1024) -#define SYNC_FWD_TIMER 300 -#define SYNC_ROLE_TIMER 10000 -#define SYNC_WAIT_AFTER_CHOOSE_MASTER 3 + +#define SYNC_MAX_FWDS 512 +#define SYNC_FWD_TIMER 300 +#define SYNC_ROLE_TIMER 15000 // ms +#define SYNC_CHECK_INTERVAL 1 // ms +#define SYNC_WAIT_AFTER_CHOOSE_MASTER 10 // ms #define nodeRole pNode->peerInfo[pNode->selfIndex]->role #define nodeVersion pNode->peerInfo[pNode->selfIndex]->version diff --git a/src/sync/src/syncMain.c b/src/sync/src/syncMain.c index 078b02556c..d0dc291257 100644 --- a/src/sync/src/syncMain.c +++ b/src/sync/src/syncMain.c @@ -29,19 +29,12 @@ #include "syncTcp.h" #include "syncInt.h" -// global configurable -int32_t tsMaxSyncNum = 2; -int32_t tsSyncTcpThreads = 2; -int32_t tsMaxFwdInfo = 512; -int32_t tsSyncTimer = 1; +int32_t tsSyncNum = 0; // number of sync in process in whole system +char tsNodeFqdn[TSDB_FQDN_LEN] = {0}; -// module global, not configurable -int32_t tsSyncNum; // number of sync in process in whole system -char tsNodeFqdn[TSDB_FQDN_LEN]; - -static void * tsTcpPool; +static void * tsTcpPool = NULL; static void * tsSyncTmrCtrl = NULL; -static void * tsVgIdHash; +static void * tsVgIdHash = NULL; static int32_t tsSyncRefId = -1; // local functions @@ -83,7 +76,7 @@ char *syncStatus[] = { int32_t syncInit() { SPoolInfo info = {0}; - info.numOfThreads = tsSyncTcpThreads; + info.numOfThreads = SYNC_TCP_THREADS; info.serverIp = 0; info.port = tsSyncPort; info.bufferSize = SYNC_MAX_SIZE; @@ -107,7 +100,7 @@ int32_t syncInit() { tsVgIdHash = taosHashInit(TSDB_MIN_VNODES, taosGetDefaultHashFunction(TSDB_DATA_TYPE_INT), true, HASH_ENTRY_LOCK); if (tsVgIdHash == NULL) { - sError("failed to init tsVgIdHash"); + sError("failed to init vgIdHash"); taosTmrCleanUp(tsSyncTmrCtrl); syncCloseTcpThreadPool(tsTcpPool); tsTcpPool = NULL; @@ -210,7 +203,7 @@ int64_t syncStart(const SSyncInfo *pInfo) { sInfo("vgId:%d, %d replicas are configured, quorum:%d role:%s", pNode->vgId, pNode->replica, pNode->quorum, syncRole[nodeRole]); - pNode->pSyncFwds = calloc(sizeof(SSyncFwds) + tsMaxFwdInfo * sizeof(SFwdInfo), 1); + pNode->pSyncFwds = calloc(sizeof(SSyncFwds) + SYNC_MAX_FWDS * sizeof(SFwdInfo), 1); if (pNode->pSyncFwds == NULL) { sError("vgId:%d, no memory to allocate syncFwds", pNode->vgId); terrno = TAOS_SYSTEM_ERROR(errno); @@ -750,7 +743,7 @@ static void syncRestartPeer(SSyncPeer *pPeer) { int32_t ret = strcmp(pPeer->fqdn, tsNodeFqdn); if (ret > 0 || (ret == 0 && pPeer->port > tsSyncPort)) { sDebug("%s, check peer connection in 1000 ms", pPeer->id); - taosTmrReset(syncCheckPeerConnection, tsSyncTimer * 1000, pPeer, tsSyncTmrCtrl, &pPeer->timer); + taosTmrReset(syncCheckPeerConnection, SYNC_CHECK_INTERVAL, pPeer, tsSyncTmrCtrl, &pPeer->timer); } } @@ -828,7 +821,7 @@ static void syncRecoverFromMaster(SSyncPeer *pPeer) { taosTmrStopA(&pPeer->timer); // Ensure the sync of mnode not interrupted - if (pNode->vgId != 1 && tsSyncNum >= tsMaxSyncNum) { + if (pNode->vgId != 1 && tsSyncNum >= SYNC_MAX_NUM) { sInfo("%s, %d syncs are in process, try later", pPeer->id, tsSyncNum); taosTmrReset(syncTryRecoverFromMaster, 500 + (pNode->vgId * 10) % 200, pPeer, tsSyncTmrCtrl, &pPeer->timer); return; @@ -839,7 +832,7 @@ static void syncRecoverFromMaster(SSyncPeer *pPeer) { SSyncMsg msg; syncBuildSyncReqMsg(&msg, pNode->vgId); - taosTmrReset(syncNotStarted, tsSyncTimer * 1000, pPeer, tsSyncTmrCtrl, &pPeer->timer); + taosTmrReset(syncNotStarted, SYNC_CHECK_INTERVAL, pPeer, tsSyncTmrCtrl, &pPeer->timer); if (taosWriteMsg(pPeer->peerFd, &msg, sizeof(SSyncMsg)) != sizeof(SSyncMsg)) { sError("%s, failed to send sync-req to peer", pPeer->id); @@ -859,7 +852,7 @@ static void syncProcessFwdResponse(SFwdRsp *pFwdRsp, SSyncPeer *pPeer) { if (pFirst->version <= pFwdRsp->version && pSyncFwds->fwds > 0) { // find the forwardInfo from first for (int32_t i = 0; i < pSyncFwds->fwds; ++i) { - pFwdInfo = pSyncFwds->fwdInfo + (i + pSyncFwds->first) % tsMaxFwdInfo; + pFwdInfo = pSyncFwds->fwdInfo + (i + pSyncFwds->first) % SYNC_MAX_FWDS; if (pFwdRsp->version == pFwdInfo->version) { syncProcessFwdAck(pNode, pFwdInfo, pFwdRsp->code); syncRemoveConfirmedFwdInfo(pNode); @@ -995,7 +988,7 @@ static void syncSetupPeerConnection(SSyncPeer *pPeer) { int32_t connFd = taosOpenTcpClientSocket(pPeer->ip, pPeer->port, 0); if (connFd < 0) { sDebug("%s, failed to open tcp socket since %s", pPeer->id, strerror(errno)); - taosTmrReset(syncCheckPeerConnection, tsSyncTimer * 1000, pPeer, tsSyncTmrCtrl, &pPeer->timer); + taosTmrReset(syncCheckPeerConnection, SYNC_CHECK_INTERVAL, pPeer, tsSyncTmrCtrl, &pPeer->timer); return; } @@ -1011,7 +1004,7 @@ static void syncSetupPeerConnection(SSyncPeer *pPeer) { } else { sDebug("%s, failed to setup peer connection to server since %s, try later", pPeer->id, strerror(errno)); taosClose(connFd); - taosTmrReset(syncCheckPeerConnection, tsSyncTimer * 1000, pPeer, tsSyncTmrCtrl, &pPeer->timer); + taosTmrReset(syncCheckPeerConnection, SYNC_CHECK_INTERVAL, pPeer, tsSyncTmrCtrl, &pPeer->timer); } } @@ -1140,15 +1133,15 @@ static int32_t syncSaveFwdInfo(SSyncNode *pNode, uint64_t version, void *mhandle SSyncFwds *pSyncFwds = pNode->pSyncFwds; int64_t time = taosGetTimestampMs(); - if (pSyncFwds->fwds >= tsMaxFwdInfo) { - // pSyncFwds->first = (pSyncFwds->first + 1) % tsMaxFwdInfo; + if (pSyncFwds->fwds >= SYNC_MAX_FWDS) { + // pSyncFwds->first = (pSyncFwds->first + 1) % SYNC_MAX_FWDS; // pSyncFwds->fwds--; sError("vgId:%d, failed to save fwd info, hver:%" PRIu64 " fwds:%d", pNode->vgId, version, pSyncFwds->fwds); return TSDB_CODE_SYN_TOO_MANY_FWDINFO; } if (pSyncFwds->fwds > 0) { - pSyncFwds->last = (pSyncFwds->last + 1) % tsMaxFwdInfo; + pSyncFwds->last = (pSyncFwds->last + 1) % SYNC_MAX_FWDS; } SFwdInfo *pFwdInfo = pSyncFwds->fwdInfo + pSyncFwds->last; @@ -1171,7 +1164,7 @@ static void syncRemoveConfirmedFwdInfo(SSyncNode *pNode) { SFwdInfo *pFwdInfo = pSyncFwds->fwdInfo + pSyncFwds->first; if (pFwdInfo->confirmed == 0) break; - pSyncFwds->first = (pSyncFwds->first + 1) % tsMaxFwdInfo; + pSyncFwds->first = (pSyncFwds->first + 1) % SYNC_MAX_FWDS; pSyncFwds->fwds--; if (pSyncFwds->fwds == 0) pSyncFwds->first = pSyncFwds->last; sTrace("vgId:%d, fwd info is removed, hver:%" PRIu64 " fwds:%d", pNode->vgId, pFwdInfo->version, pSyncFwds->fwds); @@ -1237,7 +1230,7 @@ static void syncMonitorFwdInfos(void *param, void *tmrId) { if (pSyncFwds->fwds > 0) { pthread_mutex_lock(&pNode->mutex); for (int32_t i = 0; i < pSyncFwds->fwds; ++i) { - SFwdInfo *pFwdInfo = pSyncFwds->fwdInfo + (pSyncFwds->first + i) % tsMaxFwdInfo; + SFwdInfo *pFwdInfo = pSyncFwds->fwdInfo + (pSyncFwds->first + i) % SYNC_MAX_FWDS; if (ABS(time - pFwdInfo->time) < 2000) break; sDebug("vgId:%d, forward info expired, hver:%" PRIu64 " curtime:%" PRIu64 " savetime:%" PRIu64, pNode->vgId, From bf7c02d1270e35fb41a998751d1ea40e0a91810b Mon Sep 17 00:00:00 2001 From: root Date: Thu, 17 Dec 2020 16:03:02 +0800 Subject: [PATCH 21/38] test --- .appveyor.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index ab629e337c..d4c2b20198 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,14 +1,15 @@ version: 1.0.{build} os: Visual Studio 2015 +environment: + matrix: + - ARCH: amd64 + - ARCH: x86 -Platform: - - x86 - - amd64 clone_folder: c:\dev\TDengine clone_depth: 1 init: - - call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" %Platform% + - call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" %ARCH% before_build: - cd c:\dev\TDengine @@ -18,7 +19,7 @@ build_script: - cd build - cmake -G "NMake Makefiles" .. - nmake install - - echo Building platform=%platform% + - echo Building platform=%ARCH% notifications: - provider: Email to: From 69ce48ad901c47db37ba865cfbdc16b80307cee4 Mon Sep 17 00:00:00 2001 From: Shengliang Guan Date: Thu, 17 Dec 2020 16:04:28 +0800 Subject: [PATCH 22/38] compile error in clang --- src/sync/src/syncMsg.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sync/src/syncMsg.c b/src/sync/src/syncMsg.c index abb2ac896f..6e1dea854b 100644 --- a/src/sync/src/syncMsg.c +++ b/src/sync/src/syncMsg.c @@ -88,6 +88,7 @@ void syncBuildSyncDataMsg(SSyncMsg *pMsg, int32_t vgId) { syncBuildMsg(pMsg, vgI void syncBuildSyncSetupMsg(SSyncMsg *pMsg, int32_t vgId) { syncBuildMsg(pMsg, vgId, TAOS_SMSG_SETUP); } void syncBuildPeersStatus(SPeersStatus *pMsg, int32_t vgId) { + memset(pMsg, 0, sizeof(SPeersStatus)); pMsg->head.type = TAOS_SMSG_STATUS; pMsg->head.vgId = vgId; pMsg->head.len = sizeof(SPeersStatus) - sizeof(SSyncHead); From f6956407ca41e543a096e4bbb9df06b785cd728c Mon Sep 17 00:00:00 2001 From: root Date: Thu, 17 Dec 2020 16:15:27 +0800 Subject: [PATCH 23/38] [TD-2345]test appveyor on amd64/x86 --- .appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index d4c2b20198..b4907f348f 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -19,7 +19,7 @@ build_script: - cd build - cmake -G "NMake Makefiles" .. - nmake install - - echo Building platform=%ARCH% + notifications: - provider: Email to: From cea6df10a9e8225cbeae81cbb6310dc1f9e18122 Mon Sep 17 00:00:00 2001 From: Shengliang Guan Date: Thu, 17 Dec 2020 16:38:30 +0800 Subject: [PATCH 24/38] TD-2428 --- src/sync/src/syncMain.c | 5 +++-- src/sync/src/syncMsg.c | 3 --- src/sync/src/syncRestore.c | 1 + 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/sync/src/syncMain.c b/src/sync/src/syncMain.c index d0dc291257..ac79b48606 100644 --- a/src/sync/src/syncMain.c +++ b/src/sync/src/syncMain.c @@ -949,9 +949,10 @@ static int32_t syncProcessPeerMsg(void *param, void *buffer) { static void syncSendPeersStatusMsgToPeer(SSyncPeer *pPeer, char ack, int8_t type, uint16_t tranId) { if (pPeer->peerFd < 0 || pPeer->ip == 0) return; - SSyncNode *pNode = pPeer->pSyncNode; - SPeersStatus msg = {0}; + SSyncNode * pNode = pPeer->pSyncNode; + SPeersStatus msg; + memset(&msg, 0, sizeof(SPeersStatus)); syncBuildPeersStatus(&msg, pNode->vgId); msg.role = nodeRole; diff --git a/src/sync/src/syncMsg.c b/src/sync/src/syncMsg.c index 6e1dea854b..034f9a98a7 100644 --- a/src/sync/src/syncMsg.c +++ b/src/sync/src/syncMsg.c @@ -88,7 +88,6 @@ void syncBuildSyncDataMsg(SSyncMsg *pMsg, int32_t vgId) { syncBuildMsg(pMsg, vgI void syncBuildSyncSetupMsg(SSyncMsg *pMsg, int32_t vgId) { syncBuildMsg(pMsg, vgId, TAOS_SMSG_SETUP); } void syncBuildPeersStatus(SPeersStatus *pMsg, int32_t vgId) { - memset(pMsg, 0, sizeof(SPeersStatus)); pMsg->head.type = TAOS_SMSG_STATUS; pMsg->head.vgId = vgId; pMsg->head.len = sizeof(SPeersStatus) - sizeof(SSyncHead); @@ -96,7 +95,6 @@ void syncBuildPeersStatus(SPeersStatus *pMsg, int32_t vgId) { } void syncBuildFileAck(SFileAck *pMsg, int32_t vgId) { - memset(pMsg, 0, sizeof(SFileAck)); pMsg->head.type = TAOS_SMSG_SYNC_FILE_RSP; pMsg->head.vgId = vgId; pMsg->head.len = sizeof(SFileAck) - sizeof(SSyncHead); @@ -104,7 +102,6 @@ void syncBuildFileAck(SFileAck *pMsg, int32_t vgId) { } void syncBuildFileInfo(SFileInfo *pMsg, int32_t vgId) { - memset(pMsg, 0, sizeof(SFileInfo)); pMsg->head.type = TAOS_SMSG_SYNC_FILE; pMsg->head.vgId = vgId; pMsg->head.len = sizeof(SFileInfo) - sizeof(SSyncHead); diff --git a/src/sync/src/syncRestore.c b/src/sync/src/syncRestore.c index 088215ecc7..27570ce8f2 100644 --- a/src/sync/src/syncRestore.c +++ b/src/sync/src/syncRestore.c @@ -100,6 +100,7 @@ static int32_t syncRestoreFile(SSyncPeer *pPeer, uint64_t *fversion) { &sinfo.fversion); // if file not there or magic is not the same, file shall be synced + memset(&fileAck, 0, sizeof(SFileAck)); syncBuildFileAck(&fileAck, pNode->vgId); fileAck.sync = (sinfo.magic != minfo.magic || sinfo.name[0] == 0) ? 1 : 0; From ddff163c769c7aa1151bf735a667581dcfd86ed2 Mon Sep 17 00:00:00 2001 From: Yiqing Liu Date: Thu, 17 Dec 2020 17:00:24 +0800 Subject: [PATCH 25/38] Delete Jenkinsfile --- tests/Jenkinsfile | 147 ---------------------------------------------- 1 file changed, 147 deletions(-) delete mode 100644 tests/Jenkinsfile diff --git a/tests/Jenkinsfile b/tests/Jenkinsfile deleted file mode 100644 index 550a0d29ed..0000000000 --- a/tests/Jenkinsfile +++ /dev/null @@ -1,147 +0,0 @@ -import hudson.model.Result -import jenkins.model.CauseOfInterruption -properties([pipelineTriggers([githubPush()])]) -node { - git url: 'https://github.com/taosdata/TDengine.git' -} - - -def abortPreviousBuilds() { - def currentJobName = env.JOB_NAME - def currentBuildNumber = env.BUILD_NUMBER.toInteger() - def jobs = Jenkins.instance.getItemByFullName(currentJobName) - def builds = jobs.getBuilds() - - for (build in builds) { - if (!build.isBuilding()) { - continue; - } - - if (currentBuildNumber == build.getNumber().toInteger()) { - continue; - } - - build.doKill() //doTerm(),doKill(),doTerm() - } -} -//停止之前相同的分支。。 -abortPreviousBuilds() - -def pre_test(){ - catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') { - sh ''' - sudo rmtaos - ''' - } - sh ''' - - cd ${WKC} - rm -rf * - cd ${WK} - git reset --hard - git checkout develop - git pull - cd ${WKC} - rm -rf * - mv ${WORKSPACE}/* . - cd ${WK} - export TZ=Asia/Harbin - date - rm -rf ${WK}/debug - mkdir debug - cd debug - cmake .. > /dev/null - make > /dev/null - make install > /dev/null - cd ${WKC}/tests - ''' - return 1 -} -pipeline { - agent none - - environment{ - WK = '/var/lib/jenkins/workspace/TDinternal' - WKC= '/var/lib/jenkins/workspace/TDinternal/community' - } - - stages { - - - stage('Parallel test stage') { - //only pr triggering the build. - when { - changeRequest() - } - parallel { - stage('python') { - agent{label 'pytest'} - steps { - pre_test() - sh ''' - cd ${WKC}/tests - ./test-all.sh pytest - date''' - } - } - stage('test_b1') { - agent{label 'b1'} - steps { - pre_test() - sh ''' - cd ${WKC}/tests - ./test-all.sh b1 - date''' - } - } - - stage('test_crash_gen') { - agent{label "b2"} - steps { - pre_test() - catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') { - sh ''' - cd ${WKC}/tests/pytest - ./crash_gen.sh -a -p -t 4 -s 2000 - ''' - } - catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') { - sh ''' - cd ${WKC}/tests/pytest - ./handle_crash_gen_val_log.sh - ''' - } - sh ''' - date - cd ${WKC}/tests - ./test-all.sh b2 - date - ''' - } - } - - stage('test_valgrind') { - agent{label "b3"} - - steps { - pre_test() - catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') { - sh ''' - cd ${WKC}/tests/pytest - ./valgrind-test.sh 2>&1 > mem-error-out.log - ./handle_val_log.sh - ''' - } - sh ''' - date - cd ${WKC}/tests - ./test-all.sh b3 - date''' - } - } - - } - } - } - -} From 4f19013e13365812eae8dd1bb900186cb0e40963 Mon Sep 17 00:00:00 2001 From: root Date: Thu, 17 Dec 2020 17:09:28 +0800 Subject: [PATCH 26/38] [TD-2345]test appveyor on amd64/x86 --- .appveyor.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index b4907f348f..fe4816688b 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -19,11 +19,12 @@ build_script: - cd build - cmake -G "NMake Makefiles" .. - nmake install - + notifications: - provider: Email to: - sangshuduo@gmail.com + on_build_success: true on_build_failure: true on_build_status_changed: true From 51022921147221c1b3cb206a90905918375ecdc4 Mon Sep 17 00:00:00 2001 From: root Date: Thu, 17 Dec 2020 17:16:30 +0800 Subject: [PATCH 27/38] fix some errors --- tests/Jenkinsfile | 267 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 267 insertions(+) create mode 100644 tests/Jenkinsfile diff --git a/tests/Jenkinsfile b/tests/Jenkinsfile new file mode 100644 index 0000000000..e343de789e --- /dev/null +++ b/tests/Jenkinsfile @@ -0,0 +1,267 @@ +def pre_test(){ + catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') { + sh ''' + sudo rmtaos + ''' + } + sh ''' + cd ${WKC} + git reset --hard + git checkout ${BRANCH} + git pull + git submodule update + cd ${WK} + git reset --hard + git checkout ${BRANCH} + git pull + export TZ=Asia/Harbin + date + rm -rf ${WK}/debug + mkdir debug + cd debug + cmake .. > /dev/null + make > /dev/null + make install > /dev/null + ''' + return 1 +} +pipeline { + agent none + environment{ + BRANCH = 'develop' + WK = '/var/lib/jenkins/workspace/TDinternal' + WKC= '/var/lib/jenkins/workspace/TDinternal/community' + } + + stages { + stage('Parallel test stage') { + parallel { + stage('pytest') { + agent{label '184'} + steps { + pre_test() + sh ''' + cd ${WKC}/tests + ./test-all.sh pytest + date''' + } + } + stage('test_b1') { + agent{label 'master'} + steps { + pre_test() + catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') { + sh ''' + cd ${WKC}/tests/pytest + python3 concurrent_inquiry.py -c 1 + ''' + } + sh ''' + cd ${WKC}/tests + ./test-all.sh b1 + date''' + } + } + + stage('test_crash_gen') { + agent{label "185"} + steps { + pre_test() + sh ''' + cd ${WKC}/tests/pytest + ''' + catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') { + sh ''' + cd ${WKC}/tests/pytest + ./crash_gen.sh -a -p -t 4 -s 2000 + ''' + } + catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') { + sh ''' + cd ${WKC}/tests/pytest + ./handle_crash_gen_val_log.sh + ''' + } + sh ''' + cd ${WKC}/tests + ./test-all.sh b2 + date + ''' + } + } + + stage('test_valgrind') { + agent{label "186"} + + steps { + pre_test() + sh ''' + cd ${WKC}/tests/pytest + ./valgrind-test.sh 2>&1 > mem-error-out.log + ./handle_val_log.sh + + date + cd ${WKC}/tests + ./test-all.sh b3 + date''' + } + } + stage('connector'){ + agent{label "release"} + steps{ + sh''' + cd ${WORKSPACE} + git checkout develop + ''' + catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') { + sh ''' + cd ${WORKSPACE}/tests/gotest + bash batchtest.sh + ''' + } + catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') { + sh ''' + cd ${WORKSPACE}/tests/examples/python/PYTHONConnectorChecker + python3 PythonChecker.py + ''' + } + catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') { + sh ''' + cd ${WORKSPACE}/tests/examples/JDBC/JDBCDemo/ + mvn clean package assembly:single >/dev/null + java -jar target/jdbcChecker-SNAPSHOT-jar-with-dependencies.jar -host 127.0.0.1 + ''' + } + catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') { + sh ''' + cd ${JENKINS_HOME}/workspace/C#NET/src/CheckC# + dotnet run + ''' + } + + } + } + stage('arm64_build'){ + agent{label 'arm64'} + steps{ + sh ''' + cd ${WK} + git fetch + git checkout develop + git pull + cd ${WKC} + git fetch + git checkout develop + git pull + git submodule update + cd ${WKC}/packaging + ./release.sh -v cluster -c aarch64 -n 2.0.0.0 -m 2.0.0.0 + + ''' + } + } + stage('arm32_build'){ + agent{label 'arm32'} + steps{ + catchError(buildResult: 'SUCCESS', stageResult: 'FAILURE') { + sh ''' + cd ${WK} + git fetch + git checkout develop + git pull + cd ${WKC} + git fetch + git checkout develop + git pull + git submodule update + cd ${WKC}/packaging + ./release.sh -v cluster -c aarch32 -n 2.0.0.0 -m 2.0.0.0 + + ''' + } + + } + } + } + } + + } + post { + success { + emailext ( + subject: "SUCCESSFUL: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]'", + body: ''' + + + + + + + + + + + + +

+ 构建信息 +
+
    +
    +
  • 构建名称>>分支:${PROJECT_NAME}
  • +
  • 构建结果: Successful
  • +
  • 构建编号:${BUILD_NUMBER}
  • +
  • 触发用户:${CAUSE}
  • +
  • 变更概要:${CHANGES}
  • +
  • 构建地址:${BUILD_URL}
  • +
  • 构建日志:${BUILD_URL}console
  • +
  • 变更集:${JELLY_SCRIPT}
  • +
    +
+
+ + ''', + to: "yqliu@taosdata.com,pxiao@taosdata.com", + from: "support@taosdata.com" + ) + } + failure { + emailext ( + subject: "FAILED: Job '${env.JOB_NAME} [${env.BUILD_NUMBER}]'", + body: ''' + + + + + + + + + + + + +

+ 构建信息 +
+
    +
    +
  • 构建名称>>分支:${PROJECT_NAME}
  • +
  • 构建结果: Successful
  • +
  • 构建编号:${BUILD_NUMBER}
  • +
  • 触发用户:${CAUSE}
  • +
  • 变更概要:${CHANGES}
  • +
  • 构建地址:${BUILD_URL}
  • +
  • 构建日志:${BUILD_URL}console
  • +
  • 变更集:${JELLY_SCRIPT}
  • +
    +
+
+ + ''', + to: "yqliu@taosdata.com,pxiao@taosdata.com", + from: "support@taosdata.com" + ) + } + } +} \ No newline at end of file From 4d9887cd71ed67eb89450c71cca945ee69d2d15a Mon Sep 17 00:00:00 2001 From: liuyq-617 Date: Thu, 17 Dec 2020 18:38:21 +0800 Subject: [PATCH 28/38] [TD-2476]enhance test framework --- tests/pytest/test.py | 18 ++++++-- tests/pytest/util/dnodes.py | 87 +++++++++++++++++++++++-------------- 2 files changed, 69 insertions(+), 36 deletions(-) diff --git a/tests/pytest/test.py b/tests/pytest/test.py index a2c35444b5..6be86fe3fd 100644 --- a/tests/pytest/test.py +++ b/tests/pytest/test.py @@ -111,13 +111,25 @@ if __name__ == "__main__": tdLog.info('stop All dnodes') sys.exit(0) - + tdDnodes.init(deployPath) tdDnodes.setTestCluster(testCluster) tdDnodes.setValgrind(valgrind) - tdDnodes.stopAll() - tdDnodes.deploy(1) + is_test_framework = 0 + key_word = 'tdCases.addLinux' + if key_word in open(fileName).read(): + is_test_framework = 1 + if is_test_framework: + moduleName = fileName.replace(".py", "").replace("/", ".") + uModule = importlib.import_module(moduleName) + try: + ucase = uModule.TDTestCase() + tdDnodes.deploy(1,ucase.updatecfgDict) + except : + tdDnodes.deploy(1,{}) + else: + tdDnodes.deploy(1,{}) tdDnodes.start(1) if masterIp == "": diff --git a/tests/pytest/util/dnodes.py b/tests/pytest/util/dnodes.py index 38e9e01870..83cb4e8d99 100644 --- a/tests/pytest/util/dnodes.py +++ b/tests/pytest/util/dnodes.py @@ -108,6 +108,36 @@ class TDDnode: self.deployed = 0 self.testCluster = False self.valgrind = 0 + self.cfgDict = { + "numOfLogLines":"100000000", + "mnodeEqualVnodeNum":"0", + "walLevel":"2", + "fsync":"1000", + "statusInterval":"1", + "numOfMnodes":"3", + "numOfThreadsPerCore":"2.0", + "monitor":"0", + "maxVnodeConnections":"30000", + "maxMgmtConnections":"30000", + "maxMeterConnections":"30000", + "maxShellConns":"30000", + "locale":"en_US.UTF-8", + "charset":"UTF-8", + "asyncLog":"0", + "anyIp":"0", + "tsEnableTelemetryReporting":"0", + "dDebugFlag":"135", + "mDebugFlag":"135", + "sdbDebugFlag":"135", + "rpcDebugFlag":"135", + "tmrDebugFlag":"131", + "cDebugFlag":"135", + "httpDebugFlag":"135", + "monitorDebugFlag":"135", + "udebugFlag":"135", + "jnidebugFlag":"135", + "qdebugFlag":"135" + } def init(self, path): self.path = path @@ -131,7 +161,10 @@ class TDDnode: return totalSize - def deploy(self): + def addExtraCfg(self, option, value): + self.cfgDict.update({option: value}) + + def deploy(self, *updatecfgDict): self.logDir = "%s/sim/dnode%d/log" % (self.path, self.index) self.dataDir = "%s/sim/dnode%d/data" % (self.path, self.index) self.cfgDir = "%s/sim/dnode%d/cfg" % (self.path, self.index) @@ -175,36 +208,17 @@ class TDDnode: self.cfg("publicIp", "192.168.0.%d" % (self.index)) self.cfg("internalIp", "192.168.0.%d" % (self.index)) self.cfg("privateIp", "192.168.0.%d" % (self.index)) - self.cfg("dataDir", self.dataDir) - self.cfg("logDir", self.logDir) - self.cfg("numOfLogLines", "100000000") - self.cfg("mnodeEqualVnodeNum", "0") - self.cfg("walLevel", "2") - self.cfg("fsync", "1000") - self.cfg("statusInterval", "1") - self.cfg("numOfMnodes", "3") - self.cfg("numOfThreadsPerCore", "2.0") - self.cfg("monitor", "0") - self.cfg("maxVnodeConnections", "30000") - self.cfg("maxMgmtConnections", "30000") - self.cfg("maxMeterConnections", "30000") - self.cfg("maxShellConns", "30000") - self.cfg("locale", "en_US.UTF-8") - self.cfg("charset", "UTF-8") - self.cfg("asyncLog", "0") - self.cfg("anyIp", "0") - self.cfg("tsEnableTelemetryReporting", "0") - self.cfg("dDebugFlag", "135") - self.cfg("mDebugFlag", "135") - self.cfg("sdbDebugFlag", "135") - self.cfg("rpcDebugFlag", "135") - self.cfg("tmrDebugFlag", "131") - self.cfg("cDebugFlag", "135") - self.cfg("httpDebugFlag", "135") - self.cfg("monitorDebugFlag", "135") - self.cfg("udebugFlag", "135") - self.cfg("jnidebugFlag", "135") - self.cfg("qdebugFlag", "135") + + self.cfg("dataDir",self.dataDir) + self.cfg("logDir",self.logDir) + print(updatecfgDict) + if updatecfgDict[0] and updatecfgDict[0][0]: + print(updatecfgDict[0][0]) + for key,value in updatecfgDict[0][0].items(): + self.addExtraCfg(key,value) + for key, value in self.cfgDict.items(): + self.cfg(key, value) + self.deployed = 1 tdLog.debug( "dnode:%d is deployed and configured by %s" % @@ -260,6 +274,12 @@ class TDDnode: key = 'from offline to online' bkey = bytes(key,encoding="utf8") logFile = self.logDir + "/taosdlog.0" + i = 0 + while not os.path.exists(logFile): + sleep(0.1) + i += 1 + if i>50: + break popen = subprocess.Popen('tail -f ' + logFile, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True) pid = popen.pid print('Popen.pid:' + str(pid)) @@ -273,6 +293,7 @@ class TDDnode: else: tdLog.debug("wait 5 seconds for the dnode:%d to start." % (self.index)) time.sleep(5) + # time.sleep(5) @@ -454,7 +475,7 @@ class TDDnodes: def setValgrind(self, value): self.valgrind = value - def deploy(self, index): + def deploy(self, index, *updatecfgDict): self.sim.setTestCluster(self.testCluster) if (self.simDeployed == False): @@ -464,7 +485,7 @@ class TDDnodes: self.check(index) self.dnodes[index - 1].setTestCluster(self.testCluster) self.dnodes[index - 1].setValgrind(self.valgrind) - self.dnodes[index - 1].deploy() + self.dnodes[index - 1].deploy(updatecfgDict) def cfg(self, index, option, value): self.check(index) From 754deeef85ff086e6bd08d8e008f82af26a90a0b Mon Sep 17 00:00:00 2001 From: Shengliang Guan Date: Thu, 17 Dec 2020 19:36:38 +0800 Subject: [PATCH 29/38] fix compile error --- src/sync/src/syncRestore.c | 5 +++-- src/sync/src/syncRetrieve.c | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sync/src/syncRestore.c b/src/sync/src/syncRestore.c index 27570ce8f2..8651879eb6 100644 --- a/src/sync/src/syncRestore.c +++ b/src/sync/src/syncRestore.c @@ -56,7 +56,7 @@ static int32_t syncRestoreFile(SSyncPeer *pPeer, uint64_t *fversion) { SSyncNode *pNode = pPeer->pSyncNode; SFileInfo minfo; memset(&minfo, 0, sizeof(SFileInfo)); /* = {0}; */ SFileInfo sinfo; memset(&sinfo, 0, sizeof(SFileInfo)); /* = {0}; */ - SFileAck fileAck = {0}; + SFileAck fileAck; memset(&fileAck, 0, sizeof(SFileAck)); int32_t code = -1; char name[TSDB_FILENAME_LEN * 2] = {0}; uint32_t pindex = 0; // index in last restore @@ -73,7 +73,8 @@ static int32_t syncRestoreFile(SSyncPeer *pPeer, uint64_t *fversion) { break; } - ret = syncCheckHead((SSyncHead*)(&minfo)); + assert(ret == sizeof(SFileInfo)); + ret = syncCheckHead((SSyncHead *)(&minfo)); if (ret != 0) { sError("%s, failed to check fileinfo while restore file since %s", pPeer->id, strerror(ret)); break; diff --git a/src/sync/src/syncRetrieve.c b/src/sync/src/syncRetrieve.c index d579025ded..02d990313e 100644 --- a/src/sync/src/syncRetrieve.c +++ b/src/sync/src/syncRetrieve.c @@ -88,7 +88,7 @@ static bool syncAreFilesModified(SSyncNode *pNode, SSyncPeer *pPeer) { static int32_t syncRetrieveFile(SSyncPeer *pPeer) { SSyncNode *pNode = pPeer->pSyncNode; SFileInfo fileInfo; memset(&fileInfo, 0, sizeof(SFileInfo)); - SFileAck fileAck = {0}; + SFileAck fileAck; memset(&fileAck, 0, sizeof(SFileAck)); int32_t code = -1; char name[TSDB_FILENAME_LEN * 2] = {0}; From 0f237dc865516dd9dce2d399703b51158e508851 Mon Sep 17 00:00:00 2001 From: Shengliang Guan Date: Thu, 17 Dec 2020 22:11:00 +0800 Subject: [PATCH 30/38] scripts --- tests/script/unique/db/replica_add13.sim | 5 +++++ tests/script/unique/db/replica_add23.sim | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/tests/script/unique/db/replica_add13.sim b/tests/script/unique/db/replica_add13.sim index 1df49ba658..defe306f2f 100644 --- a/tests/script/unique/db/replica_add13.sim +++ b/tests/script/unique/db/replica_add13.sim @@ -110,6 +110,7 @@ sql insert into d1.t1 values(1589529000012, 2) sql insert into d2.t2 values(1589529000022, 2) sql insert into d3.t3 values(1589529000032, 2) sql insert into d4.t4 values(1589529000042, 2) +sleep 1000 sql select * from d1.t1 if $rows != 2 then @@ -141,6 +142,7 @@ sql insert into d1.t1 values(1589529000013, 3) sql insert into d2.t2 values(1589529000023, 3) sql insert into d3.t3 values(1589529000033, 3) sql insert into d4.t4 values(1589529000043, 3) +sleep 1000 sql select * from d1.t1 if $rows != 3 then @@ -172,6 +174,7 @@ sql insert into d1.t1 values(1589529000014, 4) sql insert into d2.t2 values(1589529000024, 4) sql insert into d3.t3 values(1589529000034, 4) sql insert into d4.t4 values(1589529000044, 4) +sleep 1000 sql select * from d1.t1 print select * from d1.t1 $rows @@ -207,6 +210,7 @@ sql insert into d1.t1 values(1589529000015, 5) sql insert into d2.t2 values(1589529000025, 5) sql insert into d3.t3 values(1589529000035, 5) sql insert into d4.t4 values(1589529000045, 5) +sleep 1000 sql select * from d1.t1 if $rows != 5 then @@ -238,6 +242,7 @@ sql insert into d1.t1 values(1589529000016, 6) sql insert into d2.t2 values(1589529000026, 6) sql insert into d3.t3 values(1589529000036, 6) sql insert into d4.t4 values(1589529000046, 6) +sleep 1000 sql select * from d1.t1 if $rows != 6 then diff --git a/tests/script/unique/db/replica_add23.sim b/tests/script/unique/db/replica_add23.sim index 5da73cd117..d93894deb8 100644 --- a/tests/script/unique/db/replica_add23.sim +++ b/tests/script/unique/db/replica_add23.sim @@ -110,6 +110,7 @@ sql insert into d1.t1 values(1588262400002, 2) sql insert into d2.t2 values(1588262400002, 2) sql insert into d3.t3 values(1588262400002, 2) sql insert into d4.t4 values(1588262400002, 2) +sleep 1000 sql select * from d1.t1 if $rows != 2 then @@ -142,6 +143,7 @@ sql insert into d1.t1 values(1588262400003, 3) sql insert into d2.t2 values(1588262400003, 3) sql insert into d3.t3 values(1588262400003, 3) sql insert into d4.t4 values(1588262400003, 3) +sleep 1000 sql select * from d1.t1 if $rows != 3 then @@ -173,6 +175,7 @@ sql insert into d1.t1 values(1588262400004, 4) sql insert into d2.t2 values(1588262400004, 4) sql insert into d3.t3 values(1588262400004, 4) sql insert into d4.t4 values(1588262400004, 4) +sleep 1000 sql select * from d1.t1 if $rows != 4 then @@ -204,6 +207,7 @@ sql insert into d1.t1 values(1588262400005, 5) sql insert into d2.t2 values(1588262400005, 5) sql insert into d3.t3 values(1588262400005, 5) sql insert into d4.t4 values(1588262400005, 5) +sleep 1000 sql select * from d1.t1 if $rows != 5 then @@ -235,6 +239,7 @@ sql insert into d1.t1 values(1588262400006, 6) sql insert into d2.t2 values(1588262400006, 6) sql insert into d3.t3 values(1588262400006, 6) sql insert into d4.t4 values(1588262400006, 6) +sleep 1000 sql select * from d1.t1 if $rows != 6 then From ee092c2dbb047f8e753ef205f0425e1eadc11e2f Mon Sep 17 00:00:00 2001 From: Minglei Jin Date: Wed, 16 Dec 2020 19:09:13 +0800 Subject: [PATCH 31/38] [TD-2469]: disable client epSet.fqdn update with single node cluster --- src/mnode/src/mnodeMnode.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/mnode/src/mnodeMnode.c b/src/mnode/src/mnodeMnode.c index b60b308cf8..8b3b2896ff 100644 --- a/src/mnode/src/mnodeMnode.c +++ b/src/mnode/src/mnodeMnode.c @@ -294,6 +294,11 @@ void mnodeGetMnodeEpSetForShell(SRpcEpSet *epSet, bool redirect) { *epSet = tsMEpForShell; mnodeMnodeUnLock(); + if (mnodeGetDnodesNum() <= 1) { + epSet->numOfEps = 0; + return; + } + mTrace("vgId:1, mnodes epSet for shell is returned, num:%d inUse:%d", tsMEpForShell.numOfEps, tsMEpForShell.inUse); for (int32_t i = 0; i < epSet->numOfEps; ++i) { if (redirect && strcmp(epSet->fqdn[i], tsLocalFqdn) == 0 && htons(epSet->port[i]) == tsServerPort) { From 1837098b44affd0988ec9ccc91667f7e45d96914 Mon Sep 17 00:00:00 2001 From: Minglei Jin <49711132+stephenkgu@users.noreply.github.com> Date: Fri, 18 Dec 2020 10:57:04 +0800 Subject: [PATCH 32/38] Revert "[TD-2340]: reserve field uint32_t crc for checksums" --- src/inc/taosmsg.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/inc/taosmsg.h b/src/inc/taosmsg.h index b0c7c0895f..bf7fe7cf99 100644 --- a/src/inc/taosmsg.h +++ b/src/inc/taosmsg.h @@ -199,8 +199,7 @@ typedef struct { } SMsgDesc; typedef struct SMsgVersion { - char clientVersion[TSDB_VERSION_LEN]; - uint32_t crc; + char clientVersion[TSDB_VERSION_LEN]; } SMsgVersion; typedef struct SMsgHead { From 16802aa3db8085fc29844de8ea5e8cd3a1c3422f Mon Sep 17 00:00:00 2001 From: Bomin Zhang Date: Fri, 18 Dec 2020 02:59:44 +0000 Subject: [PATCH 33/38] [TD-2481]: cannot create stream --- src/query/inc/sql.y | 4 ++-- src/query/src/sql.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/query/inc/sql.y b/src/query/inc/sql.y index e275c50e89..32e2721103 100644 --- a/src/query/inc/sql.y +++ b/src/query/inc/sql.y @@ -346,8 +346,8 @@ create_table_args(A) ::= ifnotexists(U) ids(V) cpxName(Z) AS select(S). { A = tSetCreateSQLElems(NULL, NULL, S, TSQL_CREATE_STREAM); setSQLInfo(pInfo, A, NULL, TSDB_SQL_CREATE_TABLE); - U.n += Z.n; - setCreatedTableName(pInfo, &U, &V); + V.n += Z.n; + setCreatedTableName(pInfo, &V, &U); } %type column{TAOS_FIELD} diff --git a/src/query/src/sql.c b/src/query/src/sql.c index 3a8eb23cf8..045036676d 100644 --- a/src/query/src/sql.c +++ b/src/query/src/sql.c @@ -2420,8 +2420,8 @@ static void yy_reduce( yylhsminor.yy538 = tSetCreateSQLElems(NULL, NULL, yymsp[0].minor.yy84, TSQL_CREATE_STREAM); setSQLInfo(pInfo, yylhsminor.yy538, NULL, TSDB_SQL_CREATE_TABLE); - yymsp[-4].minor.yy0.n += yymsp[-2].minor.yy0.n; - setCreatedTableName(pInfo, &yymsp[-4].minor.yy0, &yymsp[-3].minor.yy0); + yymsp[-3].minor.yy0.n += yymsp[-2].minor.yy0.n; + setCreatedTableName(pInfo, &yymsp[-3].minor.yy0, &yymsp[-4].minor.yy0); } yymsp[-4].minor.yy538 = yylhsminor.yy538; break; From 1f2ee6fc07f0f9ce80ebccf3cfb4e7707c228c7f Mon Sep 17 00:00:00 2001 From: liuyq-617 Date: Fri, 18 Dec 2020 11:00:16 +0800 Subject: [PATCH 34/38] [TD-2465]add error sql --- tests/pytest/query/queryError.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/pytest/query/queryError.py b/tests/pytest/query/queryError.py index f1fd9c0dec..539ce5141f 100644 --- a/tests/pytest/query/queryError.py +++ b/tests/pytest/query/queryError.py @@ -56,6 +56,15 @@ class TDTestCase: # query .. order by non-time field tdSql.error("select * from st order by name") + # TD-2133 + tdSql.error("select diff(tagtype),bottom(tagtype,1) from dev_001") + + # TD-2190 + tdSql.error("select min(tagtype),max(tagtype) from dev_002 interval(1n) fill(prev)") + + # TD-2208 + tdSql.error("select diff(tagtype),top(tagtype,1) from dev_001") + def stop(self): tdSql.close() tdLog.success("%s successfully executed" % __file__) From ccbac086d4884fd3e323434c39ab05311717c599 Mon Sep 17 00:00:00 2001 From: Minglei Jin <49711132+stephenkgu@users.noreply.github.com> Date: Fri, 18 Dec 2020 11:05:49 +0800 Subject: [PATCH 35/38] Revert "[TD-1827]: force version check for client messages" --- src/client/src/tscServer.c | 7 +++---- src/dnode/src/dnodeMRead.c | 2 ++ src/dnode/src/dnodeMWrite.c | 2 ++ src/dnode/src/dnodeShell.c | 15 +-------------- src/dnode/src/dnodeVRead.c | 2 ++ src/dnode/src/dnodeVWrite.c | 1 + src/inc/taosmsg.h | 4 ---- 7 files changed, 11 insertions(+), 22 deletions(-) diff --git a/src/client/src/tscServer.c b/src/client/src/tscServer.c index 9f6ccef50d..d1dc18605f 100644 --- a/src/client/src/tscServer.c +++ b/src/client/src/tscServer.c @@ -243,7 +243,7 @@ int tscSendMsgToServer(SSqlObj *pSql) { STscObj* pObj = pSql->pTscObj; SSqlCmd* pCmd = &pSql->cmd; - char *pMsg = rpcMallocCont(sizeof(SMsgVersion) + pCmd->payloadLen); + char *pMsg = rpcMallocCont(pCmd->payloadLen); if (NULL == pMsg) { tscError("%p msg:%s malloc failed", pSql, taosMsg[pSql->cmd.msgType]); return TSDB_CODE_TSC_OUT_OF_MEMORY; @@ -254,13 +254,12 @@ int tscSendMsgToServer(SSqlObj *pSql) { tscDumpMgmtEpSet(pSql); } - tstrncpy(pMsg, version, sizeof(SMsgVersion)); - memcpy(pMsg + sizeof(SMsgVersion), pSql->cmd.payload, pSql->cmd.payloadLen); + memcpy(pMsg, pSql->cmd.payload, pSql->cmd.payloadLen); SRpcMsg rpcMsg = { .msgType = pSql->cmd.msgType, .pCont = pMsg, - .contLen = pSql->cmd.payloadLen + sizeof(SMsgVersion), + .contLen = pSql->cmd.payloadLen, .ahandle = (void*)pSql->self, .handle = NULL, .code = 0 diff --git a/src/dnode/src/dnodeMRead.c b/src/dnode/src/dnodeMRead.c index b32326f4c2..0fc6400d99 100644 --- a/src/dnode/src/dnodeMRead.c +++ b/src/dnode/src/dnodeMRead.c @@ -124,6 +124,8 @@ void dnodeDispatchToMReadQueue(SRpcMsg *pMsg) { SMnodeMsg *pRead = mnodeCreateMsg(pMsg); taosWriteQitem(tsMReadQueue, TAOS_QTYPE_RPC, pRead); } + + rpcFreeCont(pMsg->pCont); } static void dnodeFreeMReadMsg(SMnodeMsg *pRead) { diff --git a/src/dnode/src/dnodeMWrite.c b/src/dnode/src/dnodeMWrite.c index 9007b54d47..414b66653d 100644 --- a/src/dnode/src/dnodeMWrite.c +++ b/src/dnode/src/dnodeMWrite.c @@ -125,6 +125,8 @@ void dnodeDispatchToMWriteQueue(SRpcMsg *pMsg) { taosMsg[pWrite->rpcMsg.msgType], tsMWriteQueue); taosWriteQitem(tsMWriteQueue, TAOS_QTYPE_RPC, pWrite); } + + rpcFreeCont(pMsg->pCont); } static void dnodeFreeMWriteMsg(SMnodeMsg *pWrite) { diff --git a/src/dnode/src/dnodeShell.c b/src/dnode/src/dnodeShell.c index 221e13d109..79cc70005b 100644 --- a/src/dnode/src/dnodeShell.c +++ b/src/dnode/src/dnodeShell.c @@ -127,20 +127,7 @@ static void dnodeProcessMsgFromShell(SRpcMsg *pMsg, SRpcEpSet *pEpSet) { } else {} if ( dnodeProcessShellMsgFp[pMsg->msgType] ) { - SMsgVersion *pMsgVersion = pMsg->pCont; - if (taosCheckVersion(pMsgVersion->clientVersion, version, 3) != TSDB_CODE_SUCCESS) { - rpcMsg.code = TSDB_CODE_TSC_INVALID_VERSION; - rpcSendResponse(&rpcMsg); - rpcFreeCont(pMsg->pCont); - return; // todo change the error code - } - pMsg->pCont += sizeof(*pMsgVersion); - pMsg->contLen -= sizeof(*pMsgVersion); - (*dnodeProcessShellMsgFp[pMsg->msgType])(pMsg); - - //pMsg->contLen += sizeof(*pMsgVersion); - rpcFreeCont(pMsg->pCont - sizeof(*pMsgVersion)); } else { dError("RPC %p, shell msg:%s is not processed", pMsg->handle, taosMsg[pMsg->msgType]); rpcMsg.code = TSDB_CODE_DND_MSG_NOT_PROCESSED; @@ -244,4 +231,4 @@ SStatisInfo dnodeGetStatisInfo() { } return info; -} +} \ No newline at end of file diff --git a/src/dnode/src/dnodeVRead.c b/src/dnode/src/dnodeVRead.c index 2995116ef5..3f31e49370 100644 --- a/src/dnode/src/dnodeVRead.c +++ b/src/dnode/src/dnodeVRead.c @@ -77,6 +77,8 @@ void dnodeDispatchToVReadQueue(SRpcMsg *pMsg) { SRpcMsg rpcRsp = {.handle = pMsg->handle, .code = TSDB_CODE_VND_INVALID_VGROUP_ID}; rpcSendResponse(&rpcRsp); } + + rpcFreeCont(pMsg->pCont); } void *dnodeAllocVQueryQueue(void *pVnode) { diff --git a/src/dnode/src/dnodeVWrite.c b/src/dnode/src/dnodeVWrite.c index 959789a6d2..a5ae8ac830 100644 --- a/src/dnode/src/dnodeVWrite.c +++ b/src/dnode/src/dnodeVWrite.c @@ -102,6 +102,7 @@ void dnodeDispatchToVWriteQueue(SRpcMsg *pRpcMsg) { } vnodeRelease(pVnode); + rpcFreeCont(pRpcMsg->pCont); } void *dnodeAllocVWriteQueue(void *pVnode) { diff --git a/src/inc/taosmsg.h b/src/inc/taosmsg.h index bf7fe7cf99..b7f0de54fe 100644 --- a/src/inc/taosmsg.h +++ b/src/inc/taosmsg.h @@ -198,10 +198,6 @@ typedef struct { int32_t numOfVnodes; } SMsgDesc; -typedef struct SMsgVersion { - char clientVersion[TSDB_VERSION_LEN]; -} SMsgVersion; - typedef struct SMsgHead { int32_t contLen; int32_t vgId; From fa83628a1758a6bfeda41ad76fb6ef83d2946fd2 Mon Sep 17 00:00:00 2001 From: Shengliang Guan Date: Fri, 18 Dec 2020 13:20:02 +0800 Subject: [PATCH 36/38] TD-2468 --- src/rpc/src/rpcMain.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rpc/src/rpcMain.c b/src/rpc/src/rpcMain.c index a0c1649556..200d189d45 100644 --- a/src/rpc/src/rpcMain.c +++ b/src/rpc/src/rpcMain.c @@ -404,7 +404,7 @@ void rpcSendRequest(void *shandle, const SRpcEpSet *pEpSet, SRpcMsg *pMsg, int64 if (type == TSDB_MSG_TYPE_QUERY || type == TSDB_MSG_TYPE_CM_RETRIEVE || type == TSDB_MSG_TYPE_FETCH || type == TSDB_MSG_TYPE_CM_STABLE_VGROUP || type == TSDB_MSG_TYPE_CM_TABLES_META || type == TSDB_MSG_TYPE_CM_TABLE_META - || type == TSDB_MSG_TYPE_CM_SHOW ) + || type == TSDB_MSG_TYPE_CM_SHOW || type == TSDB_MSG_TYPE_DM_STATUS) pContext->connType = RPC_CONN_TCPC; pContext->rid = taosAddRef(tsRpcRefId, pContext); From bd6da89a4427646efd3d2f27a4041713d88437f4 Mon Sep 17 00:00:00 2001 From: haojun Liao Date: Fri, 18 Dec 2020 15:02:58 +0800 Subject: [PATCH 37/38] Update basic.txt --- tests/script/jenkins/basic.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/script/jenkins/basic.txt b/tests/script/jenkins/basic.txt index 64a6c871fc..34b057e71b 100644 --- a/tests/script/jenkins/basic.txt +++ b/tests/script/jenkins/basic.txt @@ -154,6 +154,7 @@ cd ../../../debug; make ./test.sh -f general/parser/repeatAlter.sim ./test.sh -f general/parser/union.sim ./test.sh -f general/parser/topbot.sim +./test.sh -f general/parser/function.sim ./test.sh -f general/stable/disk.sim ./test.sh -f general/stable/dnode3.sim From fe5f6173068f5aced38da1ee3f561095bc81633c Mon Sep 17 00:00:00 2001 From: Shengliang Guan Date: Fri, 18 Dec 2020 16:53:05 +0800 Subject: [PATCH 38/38] Revert "Feature/wal" --- src/rpc/src/rpcMain.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/rpc/src/rpcMain.c b/src/rpc/src/rpcMain.c index 200d189d45..a0c1649556 100644 --- a/src/rpc/src/rpcMain.c +++ b/src/rpc/src/rpcMain.c @@ -404,7 +404,7 @@ void rpcSendRequest(void *shandle, const SRpcEpSet *pEpSet, SRpcMsg *pMsg, int64 if (type == TSDB_MSG_TYPE_QUERY || type == TSDB_MSG_TYPE_CM_RETRIEVE || type == TSDB_MSG_TYPE_FETCH || type == TSDB_MSG_TYPE_CM_STABLE_VGROUP || type == TSDB_MSG_TYPE_CM_TABLES_META || type == TSDB_MSG_TYPE_CM_TABLE_META - || type == TSDB_MSG_TYPE_CM_SHOW || type == TSDB_MSG_TYPE_DM_STATUS) + || type == TSDB_MSG_TYPE_CM_SHOW ) pContext->connType = RPC_CONN_TCPC; pContext->rid = taosAddRef(tsRpcRefId, pContext);