From 25e2a9dd7222dbde2ff256bd6e12a397300842e7 Mon Sep 17 00:00:00 2001 From: Haojun Liao Date: Fri, 20 May 2022 23:58:34 +0800 Subject: [PATCH 01/13] refactor: do some internal refactor, and set the correct intermediate buffer size for average function. --- source/libs/executor/inc/executil.h | 43 ++----------------- source/libs/executor/inc/executorimpl.h | 1 - source/libs/executor/src/executil.c | 36 +++------------- source/libs/executor/src/timewindowoperator.c | 25 ++++------- source/libs/function/src/builtinsimpl.c | 2 +- source/util/src/tpagedbuf.c | 3 -- 6 files changed, 20 insertions(+), 90 deletions(-) diff --git a/source/libs/executor/inc/executil.h b/source/libs/executor/inc/executil.h index edc21626f5..63c398618f 100644 --- a/source/libs/executor/inc/executil.h +++ b/source/libs/executor/inc/executil.h @@ -42,11 +42,8 @@ #define GET_TASKID(_t) (((SExecTaskInfo*)(_t))->id.str) typedef struct SGroupResInfo { - int32_t totalGroup; - int32_t currentGroup; int32_t index; - SArray* pRows; // SArray - bool ordered; + SArray* pRows; // SArray int32_t position; } SGroupResInfo; @@ -80,18 +77,12 @@ typedef struct SResultRowInfo { SResultRowPosition cur; } SResultRowInfo; -struct STaskAttr; -struct STaskRuntimeEnv; -struct SUdfInfo; struct SqlFunctionCtx; -int32_t getOutputInterResultBufSize(struct STaskAttr* pQueryAttr); - size_t getResultRowSize(struct SqlFunctionCtx* pCtx, int32_t numOfOutput); int32_t initResultRowInfo(SResultRowInfo* pResultRowInfo, int32_t size); void cleanupResultRowInfo(SResultRowInfo* pResultRowInfo); -void resetResultRowInfo(struct STaskRuntimeEnv* pRuntimeEnv, SResultRowInfo* pResultRowInfo); int32_t numOfClosedResultRows(SResultRowInfo* pResultRowInfo); void closeAllResultRows(SResultRowInfo* pResultRowInfo); @@ -99,9 +90,7 @@ void initResultRow(SResultRow *pResultRow); void closeResultRow(SResultRow* pResultRow); bool isResultRowClosed(SResultRow* pResultRow); -struct SResultRowEntryInfo* getResultCell(const SResultRow* pRow, int32_t index, int32_t* offset); - -int32_t getRowNumForMultioutput(struct STaskAttr* pQueryAttr, bool topBottomQuery, bool stable); +struct SResultRowEntryInfo* getResultCell(const SResultRow* pRow, int32_t index, const int32_t* offset); static FORCE_INLINE SResultRow *getResultRow(SDiskbasedBuf* pBuf, SResultRowInfo *pResultRowInfo, int32_t slot) { ASSERT(pResultRowInfo != NULL && slot >= 0 && slot < pResultRowInfo->size); @@ -118,39 +107,13 @@ static FORCE_INLINE SResultRow *getResultRowByPos(SDiskbasedBuf* pBuf, SResultRo return pRow; } -static FORCE_INLINE char* getPosInResultPage(struct STaskAttr* pQueryAttr, SFilePage* page, int32_t rowOffset, - int32_t offset) { - assert(rowOffset >= 0 && pQueryAttr != NULL); - - // int32_t numOfRows = (int32_t)getRowNumForMultioutput(pQueryAttr, pQueryAttr->topBotQuery, pQueryAttr->stableQuery); - return ((char *)page->data); - -} - -static FORCE_INLINE char* getPosInResultPage_rv(SFilePage* page, int32_t rowOffset, int32_t offset) { - assert(rowOffset >= 0); - - int32_t numOfRows = 1;//(int32_t)getRowNumForMultioutput(pQueryAttr, pQueryAttr->topBotQuery, pQueryAttr->stableQuery); - return (char*) page + rowOffset + offset * numOfRows; -} - -typedef struct { - SArray* pResult; // SArray - int32_t colId; -} SStddevInterResult; - void initGroupedResultInfo(SGroupResInfo* pGroupResInfo, SHashObj* pHashmap, int32_t order); void initMultiResInfoFromArrayList(SGroupResInfo* pGroupResInfo, SArray* pArrayList); void cleanupGroupResInfo(SGroupResInfo* pGroupResInfo); -bool hasRemainDataInCurrentGroup(SGroupResInfo* pGroupResInfo); -bool hasRemainData(SGroupResInfo* pGroupResInfo); +bool hashRemainDataInGroupInfo(SGroupResInfo* pGroupResInfo); bool incNextGroup(SGroupResInfo* pGroupResInfo); int32_t getNumOfTotalRes(SGroupResInfo* pGroupResInfo); -int32_t mergeIntoGroupResult(SGroupResInfo* pGroupResInfo, struct STaskRuntimeEnv *pRuntimeEnv, int32_t* offset); - -//int32_t initUdfInfo(struct SUdfInfo* pUdfInfo); - #endif // TDENGINE_QUERYUTIL_H diff --git a/source/libs/executor/inc/executorimpl.h b/source/libs/executor/inc/executorimpl.h index 78f3266d74..0dacbba8e5 100644 --- a/source/libs/executor/inc/executorimpl.h +++ b/source/libs/executor/inc/executorimpl.h @@ -666,7 +666,6 @@ int32_t initAggInfo(SOptrBasicInfo* pBasicInfo, SAggSupporter* pAggSup, SExprInf void initResultSizeInfo(SOperatorInfo* pOperator, int32_t numOfRows); void doBuildResultDatablock(SOperatorInfo* pOperator, SOptrBasicInfo* pbInfo, SGroupResInfo* pGroupResInfo, SDiskbasedBuf* pBuf); -void finalizeMultiTupleQueryResult(int32_t numOfOutput, SDiskbasedBuf* pBuf, SResultRowInfo* pResultRowInfo, int32_t* rowCellInfoOffset); void doApplyFunctions(SExecTaskInfo* taskInfo, SqlFunctionCtx* pCtx, STimeWindow* pWin, SColumnInfoData* pTimeWindowData, int32_t offset, int32_t forwardStep, TSKEY* tsCol, int32_t numOfTotal, int32_t numOfOutput, int32_t order); int32_t setGroupResultOutputBuf(SOptrBasicInfo* binfo, int32_t numOfCols, char* pData, int16_t type, int16_t bytes, diff --git a/source/libs/executor/src/executil.c b/source/libs/executor/src/executil.c index 14cff488ec..5a02547f58 100644 --- a/source/libs/executor/src/executil.c +++ b/source/libs/executor/src/executil.c @@ -114,12 +114,6 @@ void closeAllResultRows(SResultRowInfo *pResultRowInfo) { assert(pResultRowInfo->size >= 0 && pResultRowInfo->capacity >= pResultRowInfo->size); for (int32_t i = 0; i < pResultRowInfo->size; ++i) { -// SResultRow* pRow = pResultRowInfo->pResult[i]; -// if (pRow->closed) { -// continue; -// } - -// pRow->closed = true; } } @@ -144,11 +138,11 @@ void clearResultRow(STaskRuntimeEnv *pRuntimeEnv, SResultRow *pResultRow) { for (int32_t i = 0; i < pRuntimeEnv->pQueryAttr->numOfOutput; ++i) { struct SResultRowEntryInfo *pEntryInfo = NULL;//pResultRow->pEntryInfo[i]; - int16_t size = pRuntimeEnv->pQueryAttr->pExpr1[i].base.resSchema.bytes; - char * s = getPosInResultPage(pRuntimeEnv->pQueryAttr, page, pResultRow->offset, offset); - memset(s, 0, size); +// int16_t size = pRuntimeEnv->pQueryAttr->pExpr1[i].base.resSchema.bytes; +// char * s = getPosInResultPage(pRuntimeEnv->pQueryAttr, page, pResultRow->offset, offset); +// memset(s, 0, size); - offset += size; +// offset += size; cleanupResultRowEntry(pEntryInfo); } } @@ -161,7 +155,7 @@ void clearResultRow(STaskRuntimeEnv *pRuntimeEnv, SResultRow *pResultRow) { } // TODO refactor: use macro -SResultRowEntryInfo* getResultCell(const SResultRow* pRow, int32_t index, int32_t* offset) { +SResultRowEntryInfo* getResultCell(const SResultRow* pRow, int32_t index, const int32_t* offset) { assert(index >= 0 && offset != NULL); return (SResultRowEntryInfo*)((char*) pRow->pEntryInfo + offset[index]); } @@ -247,7 +241,7 @@ void initMultiResInfoFromArrayList(SGroupResInfo* pGroupResInfo, SArray* pArrayL ASSERT(pGroupResInfo->index <= getNumOfTotalRes(pGroupResInfo)); } -bool hasRemainDataInCurrentGroup(SGroupResInfo* pGroupResInfo) { +bool hashRemainDataInGroupInfo(SGroupResInfo* pGroupResInfo) { if (pGroupResInfo->pRows == NULL) { return false; } @@ -255,18 +249,6 @@ bool hasRemainDataInCurrentGroup(SGroupResInfo* pGroupResInfo) { return pGroupResInfo->index < taosArrayGetSize(pGroupResInfo->pRows); } -bool hasRemainData(SGroupResInfo* pGroupResInfo) { - if (hasRemainDataInCurrentGroup(pGroupResInfo)) { - return true; - } - - return pGroupResInfo->currentGroup < pGroupResInfo->totalGroup; -} - -bool incNextGroup(SGroupResInfo* pGroupResInfo) { - return (++pGroupResInfo->currentGroup) < pGroupResInfo->totalGroup; -} - int32_t getNumOfTotalRes(SGroupResInfo* pGroupResInfo) { assert(pGroupResInfo != NULL); if (pGroupResInfo->pRows == 0) { @@ -387,11 +369,6 @@ void orderTheResultRows(STaskRuntimeEnv* pRuntimeEnv) { } static int32_t mergeIntoGroupResultImplRv(STaskRuntimeEnv *pRuntimeEnv, SGroupResInfo* pGroupResInfo, uint64_t groupId, int32_t* rowCellInfoOffset) { - if (!pGroupResInfo->ordered) { - orderTheResultRows(pRuntimeEnv); - pGroupResInfo->ordered = true; - } - if (pGroupResInfo->pRows == NULL) { pGroupResInfo->pRows = taosArrayInit(100, POINTER_BYTES); } @@ -403,6 +380,7 @@ static int32_t mergeIntoGroupResultImplRv(STaskRuntimeEnv *pRuntimeEnv, SGroupRe break; } + int64_t num = getNumOfResultWindowRes(pRuntimeEnv, &pResultRowCell->pos, rowCellInfoOffset); if (num <= 0) { continue; diff --git a/source/libs/executor/src/timewindowoperator.c b/source/libs/executor/src/timewindowoperator.c index 3be131e550..c3a447c802 100644 --- a/source/libs/executor/src/timewindowoperator.c +++ b/source/libs/executor/src/timewindowoperator.c @@ -815,9 +815,6 @@ static int32_t doOpenIntervalAgg(SOperatorInfo* pOperator) { } closeAllResultRows(&pInfo->binfo.resultRowInfo); - finalizeMultiTupleQueryResult(pOperator->numOfExprs, pInfo->aggSup.pResultBuf, &pInfo->binfo.resultRowInfo, - pInfo->binfo.rowCellInfoOffset); - initGroupedResultInfo(&pInfo->groupResInfo, pInfo->aggSup.pResultRowHashTable, pInfo->order); OPTR_SET_OPENED(pOperator); return TSDB_CODE_SUCCESS; @@ -933,7 +930,7 @@ static SSDataBlock* doStateWindowAgg(SOperatorInfo* pOperator) { if (pOperator->status == OP_RES_TO_RETURN) { doBuildResultDatablock(pOperator, pBInfo, &pInfo->groupResInfo, pInfo->aggSup.pResultBuf); - if (pBInfo->pRes->info.rows == 0 || !hasRemainDataInCurrentGroup(&pInfo->groupResInfo)) { + if (pBInfo->pRes->info.rows == 0 || !hashRemainDataInGroupInfo(&pInfo->groupResInfo)) { doSetOperatorCompleted(pOperator); return NULL; } @@ -960,13 +957,11 @@ static SSDataBlock* doStateWindowAgg(SOperatorInfo* pOperator) { pOperator->status = OP_RES_TO_RETURN; closeAllResultRows(&pBInfo->resultRowInfo); - finalizeMultiTupleQueryResult(pOperator->numOfExprs, pInfo->aggSup.pResultBuf, &pBInfo->resultRowInfo, - pBInfo->rowCellInfoOffset); initGroupedResultInfo(&pInfo->groupResInfo, pInfo->aggSup.pResultRowHashTable, TSDB_ORDER_ASC); blockDataEnsureCapacity(pBInfo->pRes, pOperator->resultInfo.capacity); doBuildResultDatablock(pOperator, pBInfo, &pInfo->groupResInfo, pInfo->aggSup.pResultBuf); - if (pBInfo->pRes->info.rows == 0 || !hasRemainDataInCurrentGroup(&pInfo->groupResInfo)) { + if (pBInfo->pRes->info.rows == 0 || !hashRemainDataInGroupInfo(&pInfo->groupResInfo)) { doSetOperatorCompleted(pOperator); } @@ -994,7 +989,7 @@ static SSDataBlock* doBuildIntervalResult(SOperatorInfo* pOperator) { blockDataEnsureCapacity(pBlock, pOperator->resultInfo.capacity); doBuildResultDatablock(pOperator, &pInfo->binfo, &pInfo->groupResInfo, pInfo->aggSup.pResultBuf); - if (pBlock->info.rows == 0 || !hasRemainDataInCurrentGroup(&pInfo->groupResInfo)) { + if (pBlock->info.rows == 0 || !hashRemainDataInGroupInfo(&pInfo->groupResInfo)) { doSetOperatorCompleted(pOperator); } @@ -1082,7 +1077,7 @@ static SSDataBlock* doStreamIntervalAgg(SOperatorInfo* pOperator) { if (pOperator->status == OP_RES_TO_RETURN) { doBuildResultDatablock(pOperator, &pInfo->binfo, &pInfo->groupResInfo, pInfo->aggSup.pResultBuf); - if (pInfo->binfo.pRes->info.rows == 0 || !hasRemainDataInCurrentGroup(&pInfo->groupResInfo)) { + if (pInfo->binfo.pRes->info.rows == 0 || !hashRemainDataInGroupInfo(&pInfo->groupResInfo)) { pOperator->status = OP_EXEC_DONE; } return pInfo->binfo.pRes->info.rows == 0 ? NULL : pInfo->binfo.pRes; @@ -1413,7 +1408,7 @@ static SSDataBlock* doSessionWindowAgg(SOperatorInfo* pOperator) { if (pOperator->status == OP_RES_TO_RETURN) { doBuildResultDatablock(pOperator, pBInfo, &pInfo->groupResInfo, pInfo->aggSup.pResultBuf); - if (pBInfo->pRes->info.rows == 0 || !hasRemainDataInCurrentGroup(&pInfo->groupResInfo)) { + if (pBInfo->pRes->info.rows == 0 || !hashRemainDataInGroupInfo(&pInfo->groupResInfo)) { doSetOperatorCompleted(pOperator); return NULL; } @@ -1440,13 +1435,11 @@ static SSDataBlock* doSessionWindowAgg(SOperatorInfo* pOperator) { // restore the value pOperator->status = OP_RES_TO_RETURN; closeAllResultRows(&pBInfo->resultRowInfo); - finalizeMultiTupleQueryResult(pOperator->numOfExprs, pInfo->aggSup.pResultBuf, &pBInfo->resultRowInfo, - pBInfo->rowCellInfoOffset); initGroupedResultInfo(&pInfo->groupResInfo, pInfo->aggSup.pResultRowHashTable, TSDB_ORDER_ASC); blockDataEnsureCapacity(pBInfo->pRes, pOperator->resultInfo.capacity); doBuildResultDatablock(pOperator, pBInfo, &pInfo->groupResInfo, pInfo->aggSup.pResultBuf); - if (pBInfo->pRes->info.rows == 0 || !hasRemainDataInCurrentGroup(&pInfo->groupResInfo)) { + if (pBInfo->pRes->info.rows == 0 || !hashRemainDataInGroupInfo(&pInfo->groupResInfo)) { doSetOperatorCompleted(pOperator); } @@ -1461,7 +1454,7 @@ static SSDataBlock* doAllIntervalAgg(SOperatorInfo* pOperator) { STimeSliceOperatorInfo* pSliceInfo = pOperator->info; if (pOperator->status == OP_RES_TO_RETURN) { // doBuildResultDatablock(&pRuntimeEnv->groupResInfo, pRuntimeEnv, pIntervalInfo->pRes); - if (pSliceInfo->binfo.pRes->info.rows == 0 || !hasRemainDataInCurrentGroup(&pSliceInfo->groupResInfo)) { + if (pSliceInfo->binfo.pRes->info.rows == 0 || !hashRemainDataInGroupInfo(&pSliceInfo->groupResInfo)) { doSetOperatorCompleted(pOperator); } @@ -1493,7 +1486,7 @@ static SSDataBlock* doAllIntervalAgg(SOperatorInfo* pOperator) { // initGroupedResultInfo(&pSliceInfo->groupResInfo, &pSliceInfo->binfo.resultRowInfo); // doBuildResultDatablock(&pRuntimeEnv->groupResInfo, pRuntimeEnv, pSliceInfo->pRes); - if (pSliceInfo->binfo.pRes->info.rows == 0 || !hasRemainDataInCurrentGroup(&pSliceInfo->groupResInfo)) { + if (pSliceInfo->binfo.pRes->info.rows == 0 || !hashRemainDataInGroupInfo(&pSliceInfo->groupResInfo)) { pOperator->status = OP_EXEC_DONE; } @@ -1695,7 +1688,7 @@ static SSDataBlock* doStreamFinalIntervalAgg(SOperatorInfo* pOperator) { return NULL; } else if (pOperator->status == OP_RES_TO_RETURN) { doBuildResultDatablock(pOperator, &pInfo->binfo, &pInfo->groupResInfo, pInfo->aggSup.pResultBuf); - if (pInfo->binfo.pRes->info.rows == 0 || !hasRemainDataInCurrentGroup(&pInfo->groupResInfo)) { + if (pInfo->binfo.pRes->info.rows == 0 || !hashRemainDataInGroupInfo(&pInfo->groupResInfo)) { pOperator->status = OP_EXEC_DONE; } return pInfo->binfo.pRes->info.rows == 0 ? NULL : pInfo->binfo.pRes; diff --git a/source/libs/function/src/builtinsimpl.c b/source/libs/function/src/builtinsimpl.c index 020df6cc3d..ad92d095d5 100644 --- a/source/libs/function/src/builtinsimpl.c +++ b/source/libs/function/src/builtinsimpl.c @@ -543,7 +543,7 @@ bool getSumFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) { } bool getAvgFuncEnv(SFunctionNode* UNUSED_PARAM(pFunc), SFuncExecEnv* pEnv) { - pEnv->calcMemSize = sizeof(double); + pEnv->calcMemSize = sizeof(SAvgRes); return true; } diff --git a/source/util/src/tpagedbuf.c b/source/util/src/tpagedbuf.c index 1ad12ef43a..00f1233707 100644 --- a/source/util/src/tpagedbuf.c +++ b/source/util/src/tpagedbuf.c @@ -187,9 +187,6 @@ static char* doFlushPageToDisk(SDiskbasedBuf* pBuf, SPageInfo* pg) { } } else { // NOTE: the size may be -1, the this recycle page has not been flushed to disk yet. size = pg->length; - if (size == -1) { - printf("----\n"); - } } ASSERT(size > 0 || (pg->offset == -1 && pg->length == -1)); From 03c916b436cb27520ff13cf803cfa2fbd8f25aec Mon Sep 17 00:00:00 2001 From: Haojun Liao Date: Fri, 20 May 2022 23:59:17 +0800 Subject: [PATCH 02/13] fix(query): set buffer page dirty when place data in it. --- source/libs/executor/src/executorimpl.c | 118 ++++++----------------- source/libs/executor/src/groupoperator.c | 7 +- 2 files changed, 32 insertions(+), 93 deletions(-) diff --git a/source/libs/executor/src/executorimpl.c b/source/libs/executor/src/executorimpl.c index 750554e828..2020be54d6 100644 --- a/source/libs/executor/src/executorimpl.c +++ b/source/libs/executor/src/executorimpl.c @@ -156,7 +156,7 @@ SOperatorFpSet createOperatorFpSet(__optr_open_fn_t openFn, __optr_fn_t nextFn, void operatorDummyCloseFn(void* param, int32_t numOfCols) {} static int32_t doCopyToSDataBlock(SExecTaskInfo* taskInfo, SSDataBlock* pBlock, SExprInfo* pExprInfo, SDiskbasedBuf* pBuf, SGroupResInfo* pGroupResInfo, - int32_t* rowCellOffset, SqlFunctionCtx* pCtx, int32_t numOfExprs); + const int32_t* rowCellOffset, SqlFunctionCtx* pCtx, int32_t numOfExprs); static void initCtxOutputBuffer(SqlFunctionCtx* pCtx, int32_t size); static void setResultBufSize(STaskAttr* pQueryAttr, SResultInfo* pResultInfo); @@ -182,10 +182,11 @@ static int compareRowData(const void* a, const void* b, const void* userData) { SFilePage* page2 = getBufPage(pRuntimeEnv->pResultBuf, pRow2->pageId); int16_t offset = supporter->dataOffset; - char* in1 = getPosInResultPage(pRuntimeEnv->pQueryAttr, page1, pRow1->offset, offset); - char* in2 = getPosInResultPage(pRuntimeEnv->pQueryAttr, page2, pRow2->offset, offset); + return 0; +// char* in1 = getPosInResultPage(pRuntimeEnv->pQueryAttr, page1, pRow1->offset, offset); +// char* in2 = getPosInResultPage(pRuntimeEnv->pQueryAttr, page2, pRow2->offset, offset); - return (in1 != NULL && in2 != NULL) ? supporter->comFunc(in1, in2) : 0; +// return (in1 != NULL && in2 != NULL) ? supporter->comFunc(in1, in2) : 0; } // setup the output buffer for each operator @@ -333,6 +334,8 @@ SResultRow* getNewResultRow_rv(SDiskbasedBuf* pResultBuf, int64_t tableGroupId, return NULL; } + setBufPageDirty(pData, true); + // set the number of rows in current disk page SResultRow* pResultRow = (SResultRow*)((char*)pData + pData->num); pResultRow->pageId = pageId; @@ -364,12 +367,14 @@ SResultRow* doSetResultOutBufByKey(SDiskbasedBuf* pResultBuf, SResultRowInfo* pR if (isIntervalQuery) { if (masterscan && p1 != NULL) { // the *p1 may be NULL in case of sliding+offset exists. pResult = getResultRowByPos(pResultBuf, p1); + ASSERT(pResult->pageId == p1->pageId && pResult->offset == p1->offset); } } else { // In case of group by column query, the required SResultRow object must be existInCurrentResusltRowInfo in the // pResultRowInfo object. if (p1 != NULL) { pResult = getResultRowByPos(pResultBuf, p1); + ASSERT(pResult->pageId == p1->pageId && pResult->offset == p1->offset); } } @@ -1417,21 +1422,6 @@ static int32_t updateBlockLoadStatus(STaskAttr* pQuery, int32_t status) { // } //} -static void getIntermediateBufInfo(STaskRuntimeEnv* pRuntimeEnv, int32_t* ps, int32_t* rowsize) { - STaskAttr* pQueryAttr = pRuntimeEnv->pQueryAttr; - int32_t MIN_ROWS_PER_PAGE = 4; - - *rowsize = (int32_t)(pQueryAttr->resultRowSize * - getRowNumForMultioutput(pQueryAttr, pQueryAttr->topBotQuery, pQueryAttr->stableQuery)); - int32_t overhead = sizeof(SFilePage); - - // one page contains at least two rows - *ps = DEFAULT_INTERN_BUF_PAGE_SIZE; - while (((*rowsize) * MIN_ROWS_PER_PAGE) > (*ps) - overhead) { - *ps = ((*ps) << 1u); - } -} - // static FORCE_INLINE bool doFilterByBlockStatistics(STaskRuntimeEnv* pRuntimeEnv, SDataStatis *pDataStatis, // SqlFunctionCtx *pCtx, int32_t numOfRows) { // STaskAttr* pQueryAttr = pRuntimeEnv->pQueryAttr; @@ -1708,36 +1698,6 @@ int32_t loadDataBlockOnDemand(SExecTaskInfo* pTaskInfo, STableScanInfo* pTableSc return TSDB_CODE_SUCCESS; } -void copyToSDataBlock(SSDataBlock* pBlock, int32_t* offset, SGroupResInfo* pGroupResInfo, SDiskbasedBuf* pResBuf) { - pBlock->info.rows = 0; - - int32_t code = TSDB_CODE_SUCCESS; - while (pGroupResInfo->currentGroup < pGroupResInfo->totalGroup) { - // all results in current group have been returned to client, try next group - if ((pGroupResInfo->pRows == NULL) || taosArrayGetSize(pGroupResInfo->pRows) == 0) { - assert(pGroupResInfo->index == 0); - // if ((code = mergeIntoGroupResult(&pGroupResInfo, pRuntimeEnv, offset)) != TSDB_CODE_SUCCESS) { - return; - // } - } - - // doCopyToSDataBlock(pResBuf, pGroupResInfo, TSDB_ORDER_ASC, pBlock, ); - - // current data are all dumped to result buffer, clear it - if (!hasRemainDataInCurrentGroup(pGroupResInfo)) { - cleanupGroupResInfo(pGroupResInfo); - if (!incNextGroup(pGroupResInfo)) { - break; - } - } - - // enough results in data buffer, return - // if (pBlock->info.rows >= threshold) { - // break; - // } - } -} - static void updateTableQueryInfoForReverseScan(STableQueryInfo* pTableQueryInfo) { if (pTableQueryInfo == NULL) { return; @@ -1884,35 +1844,6 @@ void setTaskStatus(SExecTaskInfo* pTaskInfo, int8_t status) { } } -// todo merged with the build group result. -void finalizeMultiTupleQueryResult(int32_t numOfOutput, SDiskbasedBuf* pBuf, SResultRowInfo* pResultRowInfo, - int32_t* rowCellInfoOffset) { - for (int32_t i = 0; i < pResultRowInfo->size; ++i) { - SResultRowPosition* pPos = &pResultRowInfo->pPosition[i]; - - SFilePage* bufPage = getBufPage(pBuf, pPos->pageId); - SResultRow* pRow = (SResultRow*)((char*)bufPage + pPos->offset); - - // TODO ignore the close status anyway. - // if (!isResultRowClosed(pRow)) { - // continue; - // } - - for (int32_t j = 0; j < numOfOutput; ++j) { - struct SResultRowEntryInfo* pResInfo = getResultCell(pRow, j, rowCellInfoOffset); - if (!isRowEntryInitialized(pResInfo)) { - continue; - } - - if (pRow->numOfRows < pResInfo->numOfRes) { - pRow->numOfRows = pResInfo->numOfRes; - } - } - - releaseBufPage(pBuf, bufPage); - } -} - STableQueryInfo* createTableQueryInfo(void* buf, STimeWindow win) { STableQueryInfo* pTableQueryInfo = buf; pTableQueryInfo->lastKey = win.skey; @@ -2062,20 +1993,34 @@ void setExecutionContext(int32_t numOfOutput, uint64_t groupId, SExecTaskInfo* p pAggInfo->groupId = groupId; } +static void doUpdateNumOfRows(SResultRow* pRow, int32_t numOfExprs, const int32_t* rowCellOffset) { + for (int32_t j = 0; j < numOfExprs; ++j) { + struct SResultRowEntryInfo* pResInfo = getResultCell(pRow, j, rowCellOffset); + if (!isRowEntryInitialized(pResInfo)) { + continue; + } + + if (pRow->numOfRows < pResInfo->numOfRes) { + pRow->numOfRows = pResInfo->numOfRes; + } + } +} + int32_t doCopyToSDataBlock(SExecTaskInfo* pTaskInfo, SSDataBlock* pBlock, SExprInfo* pExprInfo, SDiskbasedBuf* pBuf, SGroupResInfo* pGroupResInfo, - int32_t* rowCellOffset, SqlFunctionCtx* pCtx, int32_t numOfExprs) { + const int32_t* rowCellOffset, SqlFunctionCtx* pCtx, int32_t numOfExprs) { int32_t numOfRows = getNumOfTotalRes(pGroupResInfo); int32_t start = pGroupResInfo->index; - // qDebug("QInfo:0x%"PRIx64" start to copy data from windowResInfo to output buf", GET_TASKID(pRuntimeEnv)); - for (int32_t i = start; i < numOfRows; i += 1) { SResKeyPos* pPos = taosArrayGetP(pGroupResInfo->pRows, i); SFilePage* page = getBufPage(pBuf, pPos->pos.pageId); SResultRow* pRow = (SResultRow*)((char*)page + pPos->pos.offset); + + doUpdateNumOfRows(pRow, numOfExprs, rowCellOffset); if (pRow->numOfRows == 0) { pGroupResInfo->index += 1; + releaseBufPage(pBuf, page); continue; } @@ -2084,11 +2029,13 @@ int32_t doCopyToSDataBlock(SExecTaskInfo* pTaskInfo, SSDataBlock* pBlock, SExprI } else { // current value belongs to different group, it can't be packed into one datablock if (pBlock->info.groupId != pPos->groupId) { + releaseBufPage(pBuf, page); break; } } if (pBlock->info.rows + pRow->numOfRows > pBlock->info.capacity) { + releaseBufPage(pBuf, page); break; } @@ -2130,8 +2077,6 @@ int32_t doCopyToSDataBlock(SExecTaskInfo* pTaskInfo, SSDataBlock* pBlock, SExprI } void doBuildResultDatablock(SOperatorInfo* pOperator, SOptrBasicInfo* pbInfo, SGroupResInfo* pGroupResInfo, SDiskbasedBuf* pBuf) { - assert(pGroupResInfo->currentGroup <= pGroupResInfo->totalGroup); - SExprInfo* pExprInfo = pOperator->pExpr; int32_t numOfExprs = pOperator->numOfExprs; SExecTaskInfo* pTaskInfo = pOperator->pTaskInfo; @@ -2141,7 +2086,7 @@ void doBuildResultDatablock(SOperatorInfo* pOperator, SOptrBasicInfo* pbInfo, SG SqlFunctionCtx* pCtx = pbInfo->pCtx; blockDataCleanup(pBlock); - if (!hasRemainDataInCurrentGroup(pGroupResInfo)) { + if (!hashRemainDataInGroupInfo(pGroupResInfo)) { return; } @@ -3627,9 +3572,6 @@ static int32_t doOpenAggregateOptr(SOperatorInfo* pOperator) { } closeAllResultRows(&pAggInfo->binfo.resultRowInfo); - finalizeMultiTupleQueryResult(pOperator->numOfExprs, pAggInfo->aggSup.pResultBuf, &pAggInfo->binfo.resultRowInfo, - pAggInfo->binfo.rowCellInfoOffset); - initGroupedResultInfo(&pAggInfo->groupResInfo, pAggInfo->aggSup.pResultRowHashTable, 0); OPTR_SET_OPENED(pOperator); return TSDB_CODE_SUCCESS; @@ -3651,7 +3593,7 @@ static SSDataBlock* getAggregateResult(SOperatorInfo* pOperator) { blockDataEnsureCapacity(pInfo->pRes, pOperator->resultInfo.capacity); doBuildResultDatablock(pOperator, pInfo, &pAggInfo->groupResInfo, pAggInfo->aggSup.pResultBuf); - if (pInfo->pRes->info.rows == 0 || !hasRemainDataInCurrentGroup(&pAggInfo->groupResInfo)) { + if (pInfo->pRes->info.rows == 0 || !hashRemainDataInGroupInfo(&pAggInfo->groupResInfo)) { doSetOperatorCompleted(pOperator); } diff --git a/source/libs/executor/src/groupoperator.c b/source/libs/executor/src/groupoperator.c index b1e19213dd..16dcf30f39 100644 --- a/source/libs/executor/src/groupoperator.c +++ b/source/libs/executor/src/groupoperator.c @@ -269,7 +269,7 @@ static SSDataBlock* hashGroupbyAggregate(SOperatorInfo* pOperator) { if (pOperator->status == OP_RES_TO_RETURN) { doBuildResultDatablock(pOperator, &pInfo->binfo, &pInfo->groupResInfo, pInfo->aggSup.pResultBuf); - if (pRes->info.rows == 0 || !hasRemainDataInCurrentGroup(&pInfo->groupResInfo)) { + if (pRes->info.rows == 0 || !hashRemainDataInGroupInfo(&pInfo->groupResInfo)) { pOperator->status = OP_EXEC_DONE; } return (pRes->info.rows == 0)? NULL:pRes; @@ -303,9 +303,6 @@ static SSDataBlock* hashGroupbyAggregate(SOperatorInfo* pOperator) { pOperator->status = OP_RES_TO_RETURN; closeAllResultRows(&pInfo->binfo.resultRowInfo); - - finalizeMultiTupleQueryResult(pOperator->numOfExprs, pInfo->aggSup.pResultBuf, &pInfo->binfo.resultRowInfo, - pInfo->binfo.rowCellInfoOffset); // if (!stableQuery) { // finalize include the update of result rows // finalizeQueryResult(pInfo->binfo.pCtx, pOperator->numOfExprs); // } else { @@ -320,7 +317,7 @@ static SSDataBlock* hashGroupbyAggregate(SOperatorInfo* pOperator) { doBuildResultDatablock(pOperator, &pInfo->binfo, &pInfo->groupResInfo, pInfo->aggSup.pResultBuf); doFilter(pInfo->pCondition, pRes, NULL); - bool hasRemain = hasRemainDataInCurrentGroup(&pInfo->groupResInfo); + bool hasRemain = hashRemainDataInGroupInfo(&pInfo->groupResInfo); if (!hasRemain) { pOperator->status = OP_EXEC_DONE; break; From fe048d5f44a428fb61c921a993d15ee244bbbeb3 Mon Sep 17 00:00:00 2001 From: Shengliang Guan Date: Sat, 21 May 2022 10:19:29 +0800 Subject: [PATCH 03/13] test: case for alter stable --- tests/script/tsim/stable/add_column.sim | 64 +++++++++++++++++++------ 1 file changed, 49 insertions(+), 15 deletions(-) diff --git a/tests/script/tsim/stable/add_column.sim b/tests/script/tsim/stable/add_column.sim index acacc13524..0b2df509f9 100644 --- a/tests/script/tsim/stable/add_column.sim +++ b/tests/script/tsim/stable/add_column.sim @@ -6,7 +6,7 @@ sql connect print ========== prepare stb and ctb sql create database db vgroups 1 sql create table db.stb (ts timestamp, c1 int, c2 binary(4)) tags(t1 int, t2 float, t3 binary(16)) comment "abd" -sql create table db.ctb using db.stb tags(1, 2, "3") +sql create table db.ctb using db.stb tags(101, 102, "103") sql insert into db.ctb values(now, 1, "2") sql show db.stables @@ -62,25 +62,23 @@ endi if $data[0][2] != 2 then return -1 endi -if $data[0][3] != 1 then +if $data[0][3] != 101 then return -1 endi -print ========== add column +print ========== add column c3 sql alter table db.stb add column c3 int -sql alter table db.stb add column c4 bigint -sql alter table db.stb add column c5 binary(12) - sql show db.stables -if $data[0][3] != 6 then +if $data[0][3] != 4 then return -1 endi sql show db.tables -if $data[0][3] != 6 then +if $data[0][3] != 4 then return -1 endi +sql select * from db.stb sql select * from db.stb print $data[0][0] $data[0][1] $data[0][2] $data[0][3] $data[0][4] $data[0][5] $data[0][6] if $rows != 1 then @@ -95,13 +93,49 @@ endi if $data[0][3] != NULL then return -1 endi -if $data[0][4] != NULL then - return -1 -endi -if $data[0][5] != NULL then - return -1 -endi -if $data[0][6] != 1 then +if $data[0][4] != 101 then return -1 endi +sql insert into db.ctb values(now+1s, 1, 2, 3) +sql select * from db.stb +print $data[0][0] $data[0][1] $data[0][2] $data[0][3] $data[0][4] $data[0][5] $data[0][6] +print $data[1][0] $data[1][1] $data[1][2] $data[1][3] $data[1][4] $data[1][5] $data[1][6] + +if $rows != 2 then + return -1 +endi +if $data[0][1] != 1 then + return -1 +endi +if $data[0][2] != 2 then + return -1 +endi +if $data[0][3] != NULL then + return -1 +endi +if $data[0][4] != 101 then + return -1 +endi +if $data[1][1] != 1 then + return -1 +endi +if $data[2][2] != 2 then + return -1 +endi +if $data[1][3] != 3 then + return -1 +endi +if $data[1][4] != 101 then + return -1 +endi + +print ========== add column c4 +sql alter table db.stb add column c4 bigint +sql insert into db.ctb values(now+2s, 1, 2, 3, 4) +sql select * from db.stb +sql select * from db.stb +print $data[0][0] $data[0][1] $data[0][2] $data[0][3] $data[0][4] $data[0][5] $data[0][6] +print $data[1][0] $data[1][1] $data[1][2] $data[1][3] $data[1][4] $data[1][5] $data[1][6] +print $data[1][0] $data[1][1] $data[1][2] $data[1][3] $data[1][4] $data[1][5] $data[1][6] + From 00821527be1105600d95a78d175a1e2f674d1bd4 Mon Sep 17 00:00:00 2001 From: Haojun Liao Date: Sat, 21 May 2022 11:02:53 +0800 Subject: [PATCH 04/13] fix(query): specify the primary timestamp column in ssdatablock when update the time range of ssdatablock. --- include/common/tdatablock.h | 2 +- source/common/src/tdatablock.c | 5 +++-- source/libs/executor/src/executorimpl.c | 8 +++++--- source/libs/executor/src/groupoperator.c | 2 +- source/libs/executor/src/scanoperator.c | 4 ++-- source/libs/executor/src/timewindowoperator.c | 8 ++++++-- source/libs/executor/test/executorTests.cpp | 2 +- 7 files changed, 19 insertions(+), 12 deletions(-) diff --git a/include/common/tdatablock.h b/include/common/tdatablock.h index cea40f4785..db8644ecfe 100644 --- a/include/common/tdatablock.h +++ b/include/common/tdatablock.h @@ -190,7 +190,7 @@ int32_t colDataAppend(SColumnInfoData* pColumnInfoData, uint32_t currentRow, con int32_t colDataMergeCol(SColumnInfoData* pColumnInfoData, uint32_t numOfRow1, int32_t* capacity, const SColumnInfoData* pSource, uint32_t numOfRow2); int32_t colDataAssign(SColumnInfoData* pColumnInfoData, const SColumnInfoData* pSource, int32_t numOfRows); -int32_t blockDataUpdateTsWindow(SSDataBlock* pDataBlock); +int32_t blockDataUpdateTsWindow(SSDataBlock* pDataBlock, int32_t tsColumnIndex); int32_t colDataGetLength(const SColumnInfoData* pColumnInfoData, int32_t numOfRows); void colDataTrim(SColumnInfoData* pColumnInfoData); diff --git a/source/common/src/tdatablock.c b/source/common/src/tdatablock.c index 736cb98549..6e1a9c5726 100644 --- a/source/common/src/tdatablock.c +++ b/source/common/src/tdatablock.c @@ -341,7 +341,7 @@ size_t blockDataGetNumOfCols(const SSDataBlock* pBlock) { size_t blockDataGetNumOfRows(const SSDataBlock* pBlock) { return pBlock->info.rows; } -int32_t blockDataUpdateTsWindow(SSDataBlock* pDataBlock) { +int32_t blockDataUpdateTsWindow(SSDataBlock* pDataBlock, int32_t tsColumnIndex) { if (pDataBlock == NULL || pDataBlock->info.rows <= 0) { return 0; } @@ -350,7 +350,8 @@ int32_t blockDataUpdateTsWindow(SSDataBlock* pDataBlock) { return -1; } - SColumnInfoData* pColInfoData = taosArrayGet(pDataBlock->pDataBlock, 0); + int32_t index = (tsColumnIndex == -1)? 0:tsColumnIndex; + SColumnInfoData* pColInfoData = taosArrayGet(pDataBlock->pDataBlock, index); if (pColInfoData->info.type != TSDB_DATA_TYPE_TIMESTAMP) { return 0; } diff --git a/source/libs/executor/src/executorimpl.c b/source/libs/executor/src/executorimpl.c index 2020be54d6..7351339f13 100644 --- a/source/libs/executor/src/executorimpl.c +++ b/source/libs/executor/src/executorimpl.c @@ -1903,7 +1903,7 @@ void doFilter(const SNode* pFilterNode, SSDataBlock* pBlock, SArray* pColMatchIn filterFreeInfo(filter); extractQualifiedTupleByFilterResult(pBlock, rowRes, keep); - blockDataUpdateTsWindow(pBlock); + blockDataUpdateTsWindow(pBlock, 0); } void extractQualifiedTupleByFilterResult(SSDataBlock* pBlock, const int8_t* rowRes, bool keep) { @@ -2072,7 +2072,7 @@ int32_t doCopyToSDataBlock(SExecTaskInfo* pTaskInfo, SSDataBlock* pBlock, SExprI } qDebug("%s result generated, rows:%d, groupId:%"PRIu64, GET_TASKID(pTaskInfo), pBlock->info.rows, pBlock->info.groupId); - blockDataUpdateTsWindow(pBlock); + blockDataUpdateTsWindow(pBlock, 0); return 0; } @@ -2797,7 +2797,9 @@ int32_t setSDataBlockFromFetchRsp(SSDataBlock* pRes, SLoadRemoteDataInfo* pLoadI } pRes->info.rows = numOfRows; - blockDataUpdateTsWindow(pRes); + + // todo move this to time window aggregator, since the primary timestamp may not be known by exchange operator. + blockDataUpdateTsWindow(pRes, 0); int64_t el = taosGetTimestampUs() - startTs; diff --git a/source/libs/executor/src/groupoperator.c b/source/libs/executor/src/groupoperator.c index 16dcf30f39..7606374cdb 100644 --- a/source/libs/executor/src/groupoperator.c +++ b/source/libs/executor/src/groupoperator.c @@ -553,7 +553,7 @@ static SSDataBlock* buildPartitionResult(SOperatorInfo* pOperator) { pInfo->pageIndex += 1; - blockDataUpdateTsWindow(pInfo->binfo.pRes); + blockDataUpdateTsWindow(pInfo->binfo.pRes, 0); pInfo->binfo.pRes->info.groupId = pGroupInfo->groupId; return pInfo->binfo.pRes; } diff --git a/source/libs/executor/src/scanoperator.c b/source/libs/executor/src/scanoperator.c index 8b6ab96b6d..4e27b6ac4f 100644 --- a/source/libs/executor/src/scanoperator.c +++ b/source/libs/executor/src/scanoperator.c @@ -689,7 +689,7 @@ static SSDataBlock* getUpdateDataBlock(SStreamBlockScanInfo* pInfo, bool inverti } pDataBlock->info.rows = size; pDataBlock->info.type = STREAM_REPROCESS; - blockDataUpdateTsWindow(pDataBlock); + blockDataUpdateTsWindow(pDataBlock, 0); taosArrayClear(pInfo->tsArray); return pDataBlock; } @@ -899,7 +899,7 @@ static SSDataBlock* doStreamBlockScan(SOperatorInfo* pOperator) { } rows = pBlockInfo->rows; doFilter(pInfo->pCondition, pInfo->pRes, NULL); - blockDataUpdateTsWindow(pInfo->pRes); + blockDataUpdateTsWindow(pInfo->pRes, 0); break; } diff --git a/source/libs/executor/src/timewindowoperator.c b/source/libs/executor/src/timewindowoperator.c index c3a447c802..8abebf184b 100644 --- a/source/libs/executor/src/timewindowoperator.c +++ b/source/libs/executor/src/timewindowoperator.c @@ -790,6 +790,7 @@ static int32_t doOpenIntervalAgg(SOperatorInfo* pOperator) { } getTableScanInfo(pOperator, &pInfo->order, &scanFlag); + blockDataUpdateTsWindow(pBlock, pInfo->primaryTsIndex); // the pDataBlock are always the same one, no need to call this again setInputDataBlock(pOperator, pInfo->binfo.pCtx, pBlock, pInfo->order, scanFlag, true); @@ -938,8 +939,7 @@ static SSDataBlock* doStateWindowAgg(SOperatorInfo* pOperator) { return pBInfo->pRes; } - int32_t order = TSDB_ORDER_ASC; - STimeWindow win = pTaskInfo->window; + int32_t order = TSDB_ORDER_ASC; SOperatorInfo* downstream = pOperator->pDownstream[0]; while (1) { @@ -952,6 +952,8 @@ static SSDataBlock* doStateWindowAgg(SOperatorInfo* pOperator) { } setInputDataBlock(pOperator, pBInfo->pCtx, pBlock, order, MAIN_SCAN, true); + blockDataUpdateTsWindow(pBlock, pInfo->tsSlotId); + doStateWindowAggImpl(pOperator, pInfo, pBlock); } @@ -1429,6 +1431,8 @@ static SSDataBlock* doSessionWindowAgg(SOperatorInfo* pOperator) { // the pDataBlock are always the same one, no need to call this again setInputDataBlock(pOperator, pBInfo->pCtx, pBlock, order, MAIN_SCAN, true); + blockDataUpdateTsWindow(pBlock, pInfo->tsSlotId); + doSessionWindowAggImpl(pOperator, pInfo, pBlock); } diff --git a/source/libs/executor/test/executorTests.cpp b/source/libs/executor/test/executorTests.cpp index c7ec0eece2..880ac6c78e 100644 --- a/source/libs/executor/test/executorTests.cpp +++ b/source/libs/executor/test/executorTests.cpp @@ -189,7 +189,7 @@ SSDataBlock* get2ColsDummyBlock(SOperatorInfo* pOperator) { pInfo->current += 1; - blockDataUpdateTsWindow(pBlock); + blockDataUpdateTsWindow(pBlock, 0); return pBlock; } From f82d830734ef2246e4178995a0dd26939e01728e Mon Sep 17 00:00:00 2001 From: gccgdb1234 Date: Sat, 21 May 2022 11:11:57 +0800 Subject: [PATCH 05/13] docs: copy docs-examples from 2.6 to 3.0 --- docs-examples/.gitignore | 3 + docs-examples/.gitignre | 2 + docs-examples/R/connect_native.r | 16 ++ docs-examples/R/connect_rest.r | 12 + docs-examples/c/.gitignore | 3 + docs-examples/c/async_query_example.c | 195 ++++++++++++++ docs-examples/c/connect_example.c | 24 ++ docs-examples/c/error_handle_example.c | 24 ++ docs-examples/c/insert_example.c | 51 ++++ docs-examples/c/json_protocol_example.c | 52 ++++ docs-examples/c/line_example.c | 47 ++++ docs-examples/c/multi_bind_example.c | 147 +++++++++++ docs-examples/c/query_example.c | 143 +++++++++++ docs-examples/c/stmt_example.c | 141 +++++++++++ docs-examples/c/subscribe_demo.c | 66 +++++ docs-examples/c/telnet_line_example.c | 54 ++++ docs-examples/csharp/.gitignore | 4 + docs-examples/csharp/AsyncQueryExample.cs | 238 ++++++++++++++++++ docs-examples/csharp/ConnectExample.cs | 29 +++ docs-examples/csharp/InfluxDBLineExample.cs | 77 ++++++ docs-examples/csharp/OptsJsonExample.cs | 76 ++++++ docs-examples/csharp/OptsTelnetExample.cs | 80 ++++++ docs-examples/csharp/QueryExample.cs | 162 ++++++++++++ docs-examples/csharp/SQLInsertExample.cs | 69 +++++ docs-examples/csharp/StmtInsertExample.cs | 115 +++++++++ docs-examples/csharp/SubscribeDemo.cs | 12 + docs-examples/csharp/asyncquery.csproj | 15 ++ docs-examples/csharp/connect.csproj | 15 ++ docs-examples/csharp/influxdbline.csproj | 15 ++ docs-examples/csharp/optsjson.csproj | 15 ++ docs-examples/csharp/optstelnet.csproj | 15 ++ docs-examples/csharp/query.csproj | 15 ++ docs-examples/csharp/sqlinsert.csproj | 15 ++ docs-examples/csharp/stmtinsert.csproj | 15 ++ docs-examples/csharp/subscribe.csproj | 15 ++ docs-examples/go/.gitignore | 3 + docs-examples/go/connect/afconn/main.go | 17 ++ docs-examples/go/connect/cgoexample/main.go | 23 ++ docs-examples/go/connect/restexample/main.go | 23 ++ docs-examples/go/connect/wrapper/main.go | 17 ++ docs-examples/go/go.mod | 6 + docs-examples/go/insert/json/main.go | 37 +++ docs-examples/go/insert/line/main.go | 38 +++ docs-examples/go/insert/stmt/main.go | 73 ++++++ docs-examples/go/insert/telnet/main.go | 42 ++++ docs-examples/go/query/async/main.go | 7 + docs-examples/go/query/sync/main.go | 38 +++ docs-examples/go/rest/opentsdbjson/main.go | 45 ++++ docs-examples/go/sub/main.go | 53 ++++ docs-examples/java/.gitignore | 2 + docs-examples/java/pom.xml | 35 +++ .../com/taos/example/JNIConnectExample.java | 25 ++ .../com/taos/example/JSONProtocolExample.java | 40 +++ .../com/taos/example/LineProtocolExample.java | 42 ++++ .../com/taos/example/RESTConnectExample.java | 16 ++ .../com/taos/example/RestInsertExample.java | 74 ++++++ .../com/taos/example/RestQueryExample.java | 55 ++++ .../com/taos/example/StmtInsertExample.java | 84 +++++++ .../java/com/taos/example/SubscribeDemo.java | 65 +++++ .../example/TelnetLineProtocolExample.java | 45 ++++ .../com/taos/example/WSConnectExample.java | 21 ++ .../src/test/java/com/taos/test/TestAll.java | 91 +++++++ docs-examples/node/.gitignore | 3 + .../node/nativeexample/async_query_example.js | 21 ++ docs-examples/node/nativeexample/connect.js | 13 + .../nativeexample/influxdb_line_example.js | 34 +++ .../node/nativeexample/insert_example.js | 31 +++ .../node/nativeexample/multi_bind_example.js | 53 ++++ .../nativeexample/opentsdb_json_example.js | 55 ++++ .../nativeexample/opentsdb_telnet_example.js | 38 +++ .../node/nativeexample/param_bind_example.js | 57 +++++ .../node/nativeexample/query_example.js | 17 ++ .../node/nativeexample/subscribe_demo.js | 4 + docs-examples/node/package.json | 10 + docs-examples/node/restexample/connect.js | 20 ++ docs-examples/php/connect.php | 20 ++ docs-examples/php/insert.php | 33 +++ docs-examples/php/insert_stmt.php | 49 ++++ docs-examples/php/query.php | 23 ++ docs-examples/python/.gitignore | 1 + docs-examples/python/.gitkeep | 0 docs-examples/python/async_query_example.py | 72 ++++++ docs-examples/python/bind_param_example.py | 60 +++++ docs-examples/python/conn_native_pandas.py | 19 ++ docs-examples/python/conn_rest_pandas.py | 19 ++ docs-examples/python/connect_example.py | 19 ++ .../python/connect_native_reference.py | 20 ++ docs-examples/python/connect_rest_examples.py | 45 ++++ .../connection_usage_native_reference.py | 45 ++++ .../python/cursor_usage_native_reference.py | 32 +++ docs-examples/python/handle_exception.py | 19 ++ docs-examples/python/json_protocol_example.py | 38 +++ docs-examples/python/line_protocol_example.py | 34 +++ docs-examples/python/multi_bind_example.py | 88 +++++++ docs-examples/python/native_insert_example.py | 60 +++++ docs-examples/python/query_example.py | 42 ++++ docs-examples/python/rest_client_example.py | 9 + docs-examples/python/result_set_examples.py | 33 +++ docs-examples/python/subscribe_demo.py | 38 +++ .../python/telnet_line_protocol_example.py | 38 +++ docs-examples/rust/Cargo.toml | 2 + docs-examples/rust/nativeexample/Cargo.toml | 10 + .../rust/nativeexample/examples/connect.rs | 19 ++ .../nativeexample/examples/stmt_example.rs | 38 +++ .../nativeexample/examples/subscribe_demo.rs | 3 + docs-examples/rust/nativeexample/src/main.rs | 3 + docs-examples/rust/restexample/Cargo.toml | 8 + .../rust/restexample/examples/connect.rs | 20 ++ .../restexample/examples/insert_example.rs | 18 ++ .../restexample/examples/query_example.rs | 39 +++ docs-examples/rust/restexample/src/main.rs | 3 + .../rust/schemalessexample/Cargo.toml | 7 + .../examples/influxdb_line_example.rs | 22 ++ .../examples/opentsdb_json_example.rs | 25 ++ .../examples/opentsdb_telnet_example.rs | 28 +++ .../rust/schemalessexample/src/main.rs | 3 + 116 files changed, 4454 insertions(+) create mode 100644 docs-examples/.gitignore create mode 100644 docs-examples/.gitignre create mode 100644 docs-examples/R/connect_native.r create mode 100644 docs-examples/R/connect_rest.r create mode 100644 docs-examples/c/.gitignore create mode 100644 docs-examples/c/async_query_example.c create mode 100644 docs-examples/c/connect_example.c create mode 100644 docs-examples/c/error_handle_example.c create mode 100644 docs-examples/c/insert_example.c create mode 100644 docs-examples/c/json_protocol_example.c create mode 100644 docs-examples/c/line_example.c create mode 100644 docs-examples/c/multi_bind_example.c create mode 100644 docs-examples/c/query_example.c create mode 100644 docs-examples/c/stmt_example.c create mode 100644 docs-examples/c/subscribe_demo.c create mode 100644 docs-examples/c/telnet_line_example.c create mode 100644 docs-examples/csharp/.gitignore create mode 100644 docs-examples/csharp/AsyncQueryExample.cs create mode 100644 docs-examples/csharp/ConnectExample.cs create mode 100644 docs-examples/csharp/InfluxDBLineExample.cs create mode 100644 docs-examples/csharp/OptsJsonExample.cs create mode 100644 docs-examples/csharp/OptsTelnetExample.cs create mode 100644 docs-examples/csharp/QueryExample.cs create mode 100644 docs-examples/csharp/SQLInsertExample.cs create mode 100644 docs-examples/csharp/StmtInsertExample.cs create mode 100644 docs-examples/csharp/SubscribeDemo.cs create mode 100644 docs-examples/csharp/asyncquery.csproj create mode 100644 docs-examples/csharp/connect.csproj create mode 100644 docs-examples/csharp/influxdbline.csproj create mode 100644 docs-examples/csharp/optsjson.csproj create mode 100644 docs-examples/csharp/optstelnet.csproj create mode 100644 docs-examples/csharp/query.csproj create mode 100644 docs-examples/csharp/sqlinsert.csproj create mode 100644 docs-examples/csharp/stmtinsert.csproj create mode 100644 docs-examples/csharp/subscribe.csproj create mode 100644 docs-examples/go/.gitignore create mode 100644 docs-examples/go/connect/afconn/main.go create mode 100644 docs-examples/go/connect/cgoexample/main.go create mode 100644 docs-examples/go/connect/restexample/main.go create mode 100644 docs-examples/go/connect/wrapper/main.go create mode 100644 docs-examples/go/go.mod create mode 100644 docs-examples/go/insert/json/main.go create mode 100644 docs-examples/go/insert/line/main.go create mode 100644 docs-examples/go/insert/stmt/main.go create mode 100644 docs-examples/go/insert/telnet/main.go create mode 100644 docs-examples/go/query/async/main.go create mode 100644 docs-examples/go/query/sync/main.go create mode 100644 docs-examples/go/rest/opentsdbjson/main.go create mode 100644 docs-examples/go/sub/main.go create mode 100644 docs-examples/java/.gitignore create mode 100644 docs-examples/java/pom.xml create mode 100644 docs-examples/java/src/main/java/com/taos/example/JNIConnectExample.java create mode 100644 docs-examples/java/src/main/java/com/taos/example/JSONProtocolExample.java create mode 100644 docs-examples/java/src/main/java/com/taos/example/LineProtocolExample.java create mode 100644 docs-examples/java/src/main/java/com/taos/example/RESTConnectExample.java create mode 100644 docs-examples/java/src/main/java/com/taos/example/RestInsertExample.java create mode 100644 docs-examples/java/src/main/java/com/taos/example/RestQueryExample.java create mode 100644 docs-examples/java/src/main/java/com/taos/example/StmtInsertExample.java create mode 100644 docs-examples/java/src/main/java/com/taos/example/SubscribeDemo.java create mode 100644 docs-examples/java/src/main/java/com/taos/example/TelnetLineProtocolExample.java create mode 100644 docs-examples/java/src/main/java/com/taos/example/WSConnectExample.java create mode 100644 docs-examples/java/src/test/java/com/taos/test/TestAll.java create mode 100644 docs-examples/node/.gitignore create mode 100644 docs-examples/node/nativeexample/async_query_example.js create mode 100644 docs-examples/node/nativeexample/connect.js create mode 100644 docs-examples/node/nativeexample/influxdb_line_example.js create mode 100644 docs-examples/node/nativeexample/insert_example.js create mode 100644 docs-examples/node/nativeexample/multi_bind_example.js create mode 100644 docs-examples/node/nativeexample/opentsdb_json_example.js create mode 100644 docs-examples/node/nativeexample/opentsdb_telnet_example.js create mode 100644 docs-examples/node/nativeexample/param_bind_example.js create mode 100644 docs-examples/node/nativeexample/query_example.js create mode 100644 docs-examples/node/nativeexample/subscribe_demo.js create mode 100644 docs-examples/node/package.json create mode 100644 docs-examples/node/restexample/connect.js create mode 100644 docs-examples/php/connect.php create mode 100644 docs-examples/php/insert.php create mode 100644 docs-examples/php/insert_stmt.php create mode 100644 docs-examples/php/query.php create mode 100644 docs-examples/python/.gitignore create mode 100644 docs-examples/python/.gitkeep create mode 100644 docs-examples/python/async_query_example.py create mode 100644 docs-examples/python/bind_param_example.py create mode 100644 docs-examples/python/conn_native_pandas.py create mode 100644 docs-examples/python/conn_rest_pandas.py create mode 100644 docs-examples/python/connect_example.py create mode 100644 docs-examples/python/connect_native_reference.py create mode 100644 docs-examples/python/connect_rest_examples.py create mode 100644 docs-examples/python/connection_usage_native_reference.py create mode 100644 docs-examples/python/cursor_usage_native_reference.py create mode 100644 docs-examples/python/handle_exception.py create mode 100644 docs-examples/python/json_protocol_example.py create mode 100644 docs-examples/python/line_protocol_example.py create mode 100644 docs-examples/python/multi_bind_example.py create mode 100644 docs-examples/python/native_insert_example.py create mode 100644 docs-examples/python/query_example.py create mode 100644 docs-examples/python/rest_client_example.py create mode 100644 docs-examples/python/result_set_examples.py create mode 100644 docs-examples/python/subscribe_demo.py create mode 100644 docs-examples/python/telnet_line_protocol_example.py create mode 100644 docs-examples/rust/Cargo.toml create mode 100644 docs-examples/rust/nativeexample/Cargo.toml create mode 100644 docs-examples/rust/nativeexample/examples/connect.rs create mode 100644 docs-examples/rust/nativeexample/examples/stmt_example.rs create mode 100644 docs-examples/rust/nativeexample/examples/subscribe_demo.rs create mode 100644 docs-examples/rust/nativeexample/src/main.rs create mode 100644 docs-examples/rust/restexample/Cargo.toml create mode 100644 docs-examples/rust/restexample/examples/connect.rs create mode 100644 docs-examples/rust/restexample/examples/insert_example.rs create mode 100644 docs-examples/rust/restexample/examples/query_example.rs create mode 100644 docs-examples/rust/restexample/src/main.rs create mode 100644 docs-examples/rust/schemalessexample/Cargo.toml create mode 100644 docs-examples/rust/schemalessexample/examples/influxdb_line_example.rs create mode 100644 docs-examples/rust/schemalessexample/examples/opentsdb_json_example.rs create mode 100644 docs-examples/rust/schemalessexample/examples/opentsdb_telnet_example.rs create mode 100644 docs-examples/rust/schemalessexample/src/main.rs diff --git a/docs-examples/.gitignore b/docs-examples/.gitignore new file mode 100644 index 0000000000..7ed6d403bf --- /dev/null +++ b/docs-examples/.gitignore @@ -0,0 +1,3 @@ +.vscode +*.lock +.idea \ No newline at end of file diff --git a/docs-examples/.gitignre b/docs-examples/.gitignre new file mode 100644 index 0000000000..0853156c65 --- /dev/null +++ b/docs-examples/.gitignre @@ -0,0 +1,2 @@ +.vscode +*.lock \ No newline at end of file diff --git a/docs-examples/R/connect_native.r b/docs-examples/R/connect_native.r new file mode 100644 index 0000000000..18c142872b --- /dev/null +++ b/docs-examples/R/connect_native.r @@ -0,0 +1,16 @@ +if (! "RJDBC" %in% installed.packages()[, "Package"]) { + install.packages('RJDBC', repos='http://cran.us.r-project.org') +} + +# ANCHOR: demo +library("DBI") +library("rJava") +library("RJDBC") + +args<- commandArgs(trailingOnly = TRUE) +driver_path = args[1] # path to jdbc-driver for example: "/root/taos-jdbcdriver-2.0.37-dist.jar" +driver = JDBC("com.taosdata.jdbc.TSDBDriver", driver_path) +conn = dbConnect(driver, "jdbc:TAOS://127.0.0.1:6030/?user=root&password=taosdata") +dbGetQuery(conn, "SELECT server_version()") +dbDisconnect(conn) +# ANCHOR_END: demo \ No newline at end of file diff --git a/docs-examples/R/connect_rest.r b/docs-examples/R/connect_rest.r new file mode 100644 index 0000000000..5ceec572fc --- /dev/null +++ b/docs-examples/R/connect_rest.r @@ -0,0 +1,12 @@ +if (! "RJDBC" %in% installed.packages()[, "Package"]) { + install.packages('RJDBC', repos='http://cran.us.r-project.org') +} + +library("DBI") +library("rJava") +library("RJDBC") +driver_path = "/home/debug/build/lib/taos-jdbcdriver-2.0.38-dist.jar" +driver = JDBC("com.taosdata.jdbc.rs.RestfulDriver", driver_path) +conn = dbConnect(driver, "jdbc:TAOS-RS://localhost:6041?user=root&password=taosdata") +dbGetQuery(conn, "SELECT server_version()") +dbDisconnect(conn) \ No newline at end of file diff --git a/docs-examples/c/.gitignore b/docs-examples/c/.gitignore new file mode 100644 index 0000000000..afe9743149 --- /dev/null +++ b/docs-examples/c/.gitignore @@ -0,0 +1,3 @@ +* +!*.c +!.gitignore diff --git a/docs-examples/c/async_query_example.c b/docs-examples/c/async_query_example.c new file mode 100644 index 0000000000..262757f02b --- /dev/null +++ b/docs-examples/c/async_query_example.c @@ -0,0 +1,195 @@ +// compile with: +// gcc -o async_query_example async_query_example.c -ltaos + +#include +#include +#include +#include +#include +#include + +typedef int16_t VarDataLenT; + +#define TSDB_NCHAR_SIZE sizeof(int32_t) +#define VARSTR_HEADER_SIZE sizeof(VarDataLenT) + +#define GET_FLOAT_VAL(x) (*(float *)(x)) +#define GET_DOUBLE_VAL(x) (*(double *)(x)) + +#define varDataLen(v) ((VarDataLenT *)(v))[0] + +int printRow(char *str, TAOS_ROW row, TAOS_FIELD *fields, int numFields) { + int len = 0; + char split = ' '; + + for (int i = 0; i < numFields; ++i) { + if (i > 0) { + str[len++] = split; + } + + if (row[i] == NULL) { + len += sprintf(str + len, "%s", "NULL"); + continue; + } + + switch (fields[i].type) { + case TSDB_DATA_TYPE_TINYINT: + len += sprintf(str + len, "%d", *((int8_t *)row[i])); + break; + + case TSDB_DATA_TYPE_UTINYINT: + len += sprintf(str + len, "%u", *((uint8_t *)row[i])); + break; + + case TSDB_DATA_TYPE_SMALLINT: + len += sprintf(str + len, "%d", *((int16_t *)row[i])); + break; + + case TSDB_DATA_TYPE_USMALLINT: + len += sprintf(str + len, "%u", *((uint16_t *)row[i])); + break; + + case TSDB_DATA_TYPE_INT: + len += sprintf(str + len, "%d", *((int32_t *)row[i])); + break; + + case TSDB_DATA_TYPE_UINT: + len += sprintf(str + len, "%u", *((uint32_t *)row[i])); + break; + + case TSDB_DATA_TYPE_BIGINT: + len += sprintf(str + len, "%" PRId64, *((int64_t *)row[i])); + break; + + case TSDB_DATA_TYPE_UBIGINT: + len += sprintf(str + len, "%" PRIu64, *((uint64_t *)row[i])); + break; + + case TSDB_DATA_TYPE_FLOAT: { + float fv = 0; + fv = GET_FLOAT_VAL(row[i]); + len += sprintf(str + len, "%f", fv); + } break; + + case TSDB_DATA_TYPE_DOUBLE: { + double dv = 0; + dv = GET_DOUBLE_VAL(row[i]); + len += sprintf(str + len, "%lf", dv); + } break; + + case TSDB_DATA_TYPE_BINARY: + case TSDB_DATA_TYPE_NCHAR: { + int32_t charLen = varDataLen((char *)row[i] - VARSTR_HEADER_SIZE); + memcpy(str + len, row[i], charLen); + len += charLen; + } break; + + case TSDB_DATA_TYPE_TIMESTAMP: + len += sprintf(str + len, "%" PRId64, *((int64_t *)row[i])); + break; + + case TSDB_DATA_TYPE_BOOL: + len += sprintf(str + len, "%d", *((int8_t *)row[i])); + default: + break; + } + } + + return len; +} + +void printHeader(TAOS_RES *res) { + int numFields = taos_num_fields(res); + TAOS_FIELD *fields = taos_fetch_fields(res); + char header[256] = {0}; + int len = 0; + for (int i = 0; i < numFields; ++i) { + len += sprintf(header + len, "%s ", fields[i].name); + } + puts(header); +} + +// ANCHOR: demo + +/** + * @brief call back function of taos_fetch_row_a + * + * @param param : the third parameter you passed to taos_fetch_row_a + * @param res : pointer of TAOS_RES + * @param numOfRow : number of rows fetched in this batch. will be 0 if there is no more data. + * @return void* + */ +void *fetch_row_callback(void *param, TAOS_RES *res, int numOfRow) { + printf("numOfRow = %d \n", numOfRow); + int numFields = taos_num_fields(res); + TAOS_FIELD *fields = taos_fetch_fields(res); + TAOS *_taos = (TAOS *)param; + if (numOfRow > 0) { + for (int i = 0; i < numOfRow; ++i) { + TAOS_ROW row = taos_fetch_row(res); + char temp[256] = {0}; + printRow(temp, row, fields, numFields); + puts(temp); + } + taos_fetch_rows_a(res, fetch_row_callback, _taos); + } else { + printf("no more data, close the connection.\n"); + taos_free_result(res); + taos_close(_taos); + taos_cleanup(); + } +} + +/** + * @brief callback function of taos_query_a + * + * @param param: the fourth parameter you passed to taos_query_a + * @param res : the result set + * @param code : status code + * @return void* + */ +void *select_callback(void *param, TAOS_RES *res, int code) { + printf("query callback ...\n"); + TAOS *_taos = (TAOS *)param; + if (code == 0 && res) { + printHeader(res); + taos_fetch_rows_a(res, fetch_row_callback, _taos); + } else { + printf("failed to execute taos_query. error: %s\n", taos_errstr(res)); + taos_free_result(res); + taos_close(_taos); + taos_cleanup(); + exit(EXIT_FAILURE); + } +} + +int main() { + TAOS *taos = taos_connect("localhost", "root", "taosdata", "power", 6030); + if (taos == NULL) { + puts("failed to connect to server"); + exit(EXIT_FAILURE); + } + // param one is the connection returned by taos_connect. + // param two is the SQL to execute. + // param three is the callback function. + // param four can be any pointer. It will be passed to your callback function as the first parameter. we use taos + // here, because we want to close it after getting data. + taos_query_a(taos, "SELECT * FROM meters", select_callback, taos); + sleep(1); +} + +// output: +// query callback ... +// ts current voltage phase location groupid +// numOfRow = 8 +// 1538548685000 10.300000 219 0.310000 beijing.chaoyang 2 +// 1538548695000 12.600000 218 0.330000 beijing.chaoyang 2 +// 1538548696800 12.300000 221 0.310000 beijing.chaoyang 2 +// 1538548696650 10.300000 218 0.250000 beijing.chaoyang 3 +// 1538548685500 11.800000 221 0.280000 beijing.haidian 2 +// 1538548696600 13.400000 223 0.290000 beijing.haidian 2 +// 1538548685000 10.800000 223 0.290000 beijing.haidian 3 +// 1538548686500 11.500000 221 0.350000 beijing.haidian 3 +// numOfRow = 0 +// no more data, close the connection. +// ANCHOR_END: demo \ No newline at end of file diff --git a/docs-examples/c/connect_example.c b/docs-examples/c/connect_example.c new file mode 100644 index 0000000000..1a23df4806 --- /dev/null +++ b/docs-examples/c/connect_example.c @@ -0,0 +1,24 @@ +// compile with +// gcc connect_example.c -o connect_example -ltaos +#include +#include +#include "taos.h" + +int main() { + const char *host = "localhost"; + const char *user = "root"; + const char *passwd = "taosdata"; + // if don't want to connect to a default db, set it to NULL or "" + const char *db = NULL; + uint16_t port = 0; // 0 means use the default port + TAOS *taos = taos_connect(host, user, passwd, db, port); + if (taos == NULL) { + int errno = taos_errno(NULL); + char *msg = taos_errstr(NULL); + printf("%d, %s\n", errno, msg); + } else { + printf("connected\n"); + taos_close(taos); + } + taos_cleanup(); +} diff --git a/docs-examples/c/error_handle_example.c b/docs-examples/c/error_handle_example.c new file mode 100644 index 0000000000..e7dedb263d --- /dev/null +++ b/docs-examples/c/error_handle_example.c @@ -0,0 +1,24 @@ +// compile with +// gcc error_handle_example.c -o error_handle_example -ltaos +#include +#include +#include "taos.h" + +int main() { + const char *host = "localhost"; + const char *user = "root"; + const char *passwd = "taosdata"; + // if don't want to connect to a default db, set it to NULL or "" + const char *db = "notexist"; + uint16_t port = 0; // 0 means use the default port + TAOS *taos = taos_connect(host, user, passwd, db, port); + if (taos == NULL) { + int errno = taos_errno(NULL); + char *msg = taos_errstr(NULL); + printf("%d, %s\n", errno, msg); + } else { + printf("connected\n"); + taos_close(taos); + } + taos_cleanup(); +} diff --git a/docs-examples/c/insert_example.c b/docs-examples/c/insert_example.c new file mode 100644 index 0000000000..ca12be9314 --- /dev/null +++ b/docs-examples/c/insert_example.c @@ -0,0 +1,51 @@ +// compile with +// gcc -o insert_example insert_example.c -ltaos +#include +#include +#include "taos.h" + + +/** + * @brief execute sql and print affected rows. + * + * @param taos + * @param sql + */ +void executeSQL(TAOS *taos, const char *sql) { + TAOS_RES *res = taos_query(taos, sql); + int code = taos_errno(res); + if (code != 0) { + printf("Error code: %d; Message: %s\n", code, taos_errstr(res)); + taos_free_result(res); + taos_close(taos); + exit(EXIT_FAILURE); + } + int affectedRows = taos_affected_rows(res); + printf("affected rows %d\n", affectedRows); + taos_free_result(res); +} + + + +int main() { + TAOS *taos = taos_connect("localhost", "root", "taosdata", NULL, 6030); + if (taos == NULL) { + printf("failed to connect to server\n"); + exit(EXIT_FAILURE); + } + executeSQL(taos, "CREATE DATABASE power"); + executeSQL(taos, "USE power"); + executeSQL(taos, "CREATE STABLE meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (location BINARY(64), groupId INT)"); + executeSQL(taos, "INSERT INTO d1001 USING meters TAGS(Beijing.Chaoyang, 2) VALUES ('2018-10-03 14:38:05.000', 10.30000, 219, 0.31000) ('2018-10-03 14:38:15.000', 12.60000, 218, 0.33000) ('2018-10-03 14:38:16.800', 12.30000, 221, 0.31000)" + "d1002 USING meters TAGS(Beijing.Chaoyang, 3) VALUES ('2018-10-03 14:38:16.650', 10.30000, 218, 0.25000)" + "d1003 USING meters TAGS(Beijing.Haidian, 2) VALUES ('2018-10-03 14:38:05.500', 11.80000, 221, 0.28000) ('2018-10-03 14:38:16.600', 13.40000, 223, 0.29000)" + "d1004 USING meters TAGS(Beijing.Haidian, 3) VALUES ('2018-10-03 14:38:05.000', 10.80000, 223, 0.29000) ('2018-10-03 14:38:06.500', 11.50000, 221, 0.35000)"); + taos_close(taos); + taos_cleanup(); +} + +// output: +// affected rows 0 +// affected rows 0 +// affected rows 0 +// affected rows 8 \ No newline at end of file diff --git a/docs-examples/c/json_protocol_example.c b/docs-examples/c/json_protocol_example.c new file mode 100644 index 0000000000..182fd20130 --- /dev/null +++ b/docs-examples/c/json_protocol_example.c @@ -0,0 +1,52 @@ +// compile with +// gcc -o json_protocol_example json_protocol_example.c -ltaos +#include +#include +#include +#include "taos.h" + +void executeSQL(TAOS *taos, const char *sql) { + TAOS_RES *res = taos_query(taos, sql); + int code = taos_errno(res); + if (code != 0) { + printf("%s\n", taos_errstr(res)); + taos_free_result(res); + taos_close(taos); + exit(EXIT_FAILURE); + } + taos_free_result(res); +} + +// ANCHOR: main +int main() { + TAOS *taos = taos_connect("localhost", "root", "taosdata", "", 6030); + if (taos == NULL) { + printf("failed to connect to server\n"); + exit(EXIT_FAILURE); + } + executeSQL(taos, "DROP DATABASE IF EXISTS test"); + executeSQL(taos, "CREATE DATABASE test"); + executeSQL(taos, "USE test"); + char *line = + "[{\"metric\": \"meters.current\", \"timestamp\": 1648432611249, \"value\": 10.3, \"tags\": {\"location\": " + "\"Beijing.Chaoyang\", \"groupid\": 2}},{\"metric\": \"meters.voltage\", \"timestamp\": 1648432611249, " + "\"value\": 219, \"tags\": {\"location\": \"Beijing.Haidian\", \"groupid\": 1}},{\"metric\": \"meters.current\", " + "\"timestamp\": 1648432611250, \"value\": 12.6, \"tags\": {\"location\": \"Beijing.Chaoyang\", \"groupid\": " + "2}},{\"metric\": \"meters.voltage\", \"timestamp\": 1648432611250, \"value\": 221, \"tags\": {\"location\": " + "\"Beijing.Haidian\", \"groupid\": 1}}]"; + + char *lines[] = {line}; + TAOS_RES *res = taos_schemaless_insert(taos, lines, 1, TSDB_SML_JSON_PROTOCOL, TSDB_SML_TIMESTAMP_NOT_CONFIGURED); + if (taos_errno(res) != 0) { + printf("failed to insert schema-less data, reason: %s\n", taos_errstr(res)); + } else { + int affectedRow = taos_affected_rows(res); + printf("successfully inserted %d rows\n", affectedRow); + } + taos_free_result(res); + taos_close(taos); + taos_cleanup(); +} +// output: +// successfully inserted 4 rows +// ANCHOR_END: main diff --git a/docs-examples/c/line_example.c b/docs-examples/c/line_example.c new file mode 100644 index 0000000000..8dd4b1a507 --- /dev/null +++ b/docs-examples/c/line_example.c @@ -0,0 +1,47 @@ +// compile with +// gcc -o line_example line_example.c -ltaos +#include +#include +#include +#include "taos.h" + +void executeSQL(TAOS *taos, const char *sql) { + TAOS_RES *res = taos_query(taos, sql); + int code = taos_errno(res); + if (code != 0) { + printf("%s\n", taos_errstr(res)); + taos_free_result(res); + taos_close(taos); + exit(EXIT_FAILURE); + } + taos_free_result(res); +} + +// ANCHOR: main +int main() { + TAOS *taos = taos_connect("localhost", "root", "taosdata", "", 0); + if (taos == NULL) { + printf("failed to connect to server\n"); + exit(EXIT_FAILURE); + } + executeSQL(taos, "DROP DATABASE IF EXISTS test"); + executeSQL(taos, "CREATE DATABASE test"); + executeSQL(taos, "USE test"); + char *lines[] = {"meters,location=Beijing.Haidian,groupid=2 current=11.8,voltage=221,phase=0.28 1648432611249", + "meters,location=Beijing.Haidian,groupid=2 current=13.4,voltage=223,phase=0.29 1648432611250", + "meters,location=Beijing.Haidian,groupid=3 current=10.8,voltage=223,phase=0.29 1648432611249", + "meters,location=Beijing.Haidian,groupid=3 current=11.3,voltage=221,phase=0.35 1648432611250"}; + TAOS_RES *res = taos_schemaless_insert(taos, lines, 4, TSDB_SML_LINE_PROTOCOL, TSDB_SML_TIMESTAMP_MILLI_SECONDS); + if (taos_errno(res) != 0) { + printf("failed to insert schema-less data, reason: %s\n", taos_errstr(res)); + } else { + int affectedRows = taos_affected_rows(res); + printf("successfully inserted %d rows\n", affectedRows); + } + taos_free_result(res); + taos_close(taos); + taos_cleanup(); +} +// output: +// successfully inserted 4 rows +// ANCHOR_END: main \ No newline at end of file diff --git a/docs-examples/c/multi_bind_example.c b/docs-examples/c/multi_bind_example.c new file mode 100644 index 0000000000..fe11df9caa --- /dev/null +++ b/docs-examples/c/multi_bind_example.c @@ -0,0 +1,147 @@ +// compile with +// gcc -o multi_bind_example multi_bind_example.c -ltaos +#include +#include +#include +#include "taos.h" + +/** + * @brief execute sql only and ignore result set + * + * @param taos + * @param sql + */ +void executeSQL(TAOS *taos, const char *sql) { + TAOS_RES *res = taos_query(taos, sql); + int code = taos_errno(res); + if (code != 0) { + printf("%s\n", taos_errstr(res)); + taos_free_result(res); + taos_close(taos); + exit(EXIT_FAILURE); + } + taos_free_result(res); +} + +/** + * @brief exit program when error occur. + * + * @param stmt + * @param code + * @param msg + */ +void checkErrorCode(TAOS_STMT *stmt, int code, const char *msg) { + if (code != 0) { + printf("%s. error: %s\n", msg, taos_stmt_errstr(stmt)); + taos_stmt_close(stmt); + exit(EXIT_FAILURE); + } +} + +/** + * @brief insert data using stmt API + * + * @param taos + */ +void insertData(TAOS *taos) { + // init + TAOS_STMT *stmt = taos_stmt_init(taos); + // prepare + const char *sql = "INSERT INTO ? USING meters TAGS(?, ?) values(?, ?, ?, ?)"; + int code = taos_stmt_prepare(stmt, sql, 0); + checkErrorCode(stmt, code, "failed to execute taos_stmt_prepare"); + // bind table name and tags + TAOS_BIND tags[2]; + char *location = "Beijing.Chaoyang"; + int groupId = 2; + tags[0].buffer_type = TSDB_DATA_TYPE_BINARY; + tags[0].buffer_length = strlen(location); + tags[0].length = &tags[0].buffer_length; + tags[0].buffer = location; + tags[0].is_null = NULL; + + tags[1].buffer_type = TSDB_DATA_TYPE_INT; + tags[1].buffer_length = sizeof(int); + tags[1].length = &tags[1].buffer_length; + tags[1].buffer = &groupId; + tags[1].is_null = NULL; + + code = taos_stmt_set_tbname_tags(stmt, "d1001", tags); + checkErrorCode(stmt, code, "failed to execute taos_stmt_set_tbname_tags"); + + // highlight-start + // insert two rows with multi binds + TAOS_MULTI_BIND params[4]; + // values to bind + int64_t ts[] = {1648432611249, 1648432611749}; + float current[] = {10.3, 12.6}; + int voltage[] = {219, 218}; + float phase[] = {0.31, 0.33}; + // is_null array + char is_null[2] = {0}; + // length array + int32_t int64Len[2] = {sizeof(int64_t)}; + int32_t floatLen[2] = {sizeof(float)}; + int32_t intLen[2] = {sizeof(int)}; + + params[0].buffer_type = TSDB_DATA_TYPE_TIMESTAMP; + params[0].buffer_length = sizeof(int64_t); + params[0].buffer = ts; + params[0].length = int64Len; + params[0].is_null = is_null; + params[0].num = 2; + + params[1].buffer_type = TSDB_DATA_TYPE_FLOAT; + params[1].buffer_length = sizeof(float); + params[1].buffer = current; + params[1].length = floatLen; + params[1].is_null = is_null; + params[1].num = 2; + + params[2].buffer_type = TSDB_DATA_TYPE_INT; + params[2].buffer_length = sizeof(int); + params[2].buffer = voltage; + params[2].length = intLen; + params[2].is_null = is_null; + params[2].num = 2; + + params[3].buffer_type = TSDB_DATA_TYPE_FLOAT; + params[3].buffer_length = sizeof(float); + params[3].buffer = phase; + params[3].length = floatLen; + params[3].is_null = is_null; + params[3].num = 2; + + code = taos_stmt_bind_param_batch(stmt, params); // bind batch + checkErrorCode(stmt, code, "failed to execute taos_stmt_bind_param_batch"); + code = taos_stmt_add_batch(stmt); // add batch + checkErrorCode(stmt, code, "failed to execute taos_stmt_add_batch"); + // highlight-end + // execute + code = taos_stmt_execute(stmt); + checkErrorCode(stmt, code, "failed to execute taos_stmt_execute"); + int affectedRows = taos_stmt_affected_rows(stmt); + printf("successfully inserted %d rows\n", affectedRows); + // close + taos_stmt_close(stmt); +} + +int main() { + TAOS *taos = taos_connect("localhost", "root", "taosdata", NULL, 6030); + if (taos == NULL) { + printf("failed to connect to server\n"); + exit(EXIT_FAILURE); + } + executeSQL(taos, "DROP DATABASE IF EXISTS power"); + executeSQL(taos, "CREATE DATABASE power"); + executeSQL(taos, "USE power"); + executeSQL(taos, + "CREATE STABLE meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (location BINARY(64), " + "groupId INT)"); + insertData(taos); + taos_close(taos); + taos_cleanup(); +} + +// output: +// successfully inserted 2 rows \ No newline at end of file diff --git a/docs-examples/c/query_example.c b/docs-examples/c/query_example.c new file mode 100644 index 0000000000..f88b2467ce --- /dev/null +++ b/docs-examples/c/query_example.c @@ -0,0 +1,143 @@ +// compile with: +// gcc -o query_example query_example.c -ltaos +#include +#include +#include +#include +#include + +typedef int16_t VarDataLenT; + +#define TSDB_NCHAR_SIZE sizeof(int32_t) +#define VARSTR_HEADER_SIZE sizeof(VarDataLenT) + +#define GET_FLOAT_VAL(x) (*(float *)(x)) +#define GET_DOUBLE_VAL(x) (*(double *)(x)) + +#define varDataLen(v) ((VarDataLenT *)(v))[0] + +int printRow(char *str, TAOS_ROW row, TAOS_FIELD *fields, int numFields) { + int len = 0; + char split = ' '; + + for (int i = 0; i < numFields; ++i) { + if (i > 0) { + str[len++] = split; + } + + if (row[i] == NULL) { + len += sprintf(str + len, "%s", "NULL"); + continue; + } + + switch (fields[i].type) { + case TSDB_DATA_TYPE_TINYINT: + len += sprintf(str + len, "%d", *((int8_t *)row[i])); + break; + + case TSDB_DATA_TYPE_UTINYINT: + len += sprintf(str + len, "%u", *((uint8_t *)row[i])); + break; + + case TSDB_DATA_TYPE_SMALLINT: + len += sprintf(str + len, "%d", *((int16_t *)row[i])); + break; + + case TSDB_DATA_TYPE_USMALLINT: + len += sprintf(str + len, "%u", *((uint16_t *)row[i])); + break; + + case TSDB_DATA_TYPE_INT: + len += sprintf(str + len, "%d", *((int32_t *)row[i])); + break; + + case TSDB_DATA_TYPE_UINT: + len += sprintf(str + len, "%u", *((uint32_t *)row[i])); + break; + + case TSDB_DATA_TYPE_BIGINT: + len += sprintf(str + len, "%" PRId64, *((int64_t *)row[i])); + break; + + case TSDB_DATA_TYPE_UBIGINT: + len += sprintf(str + len, "%" PRIu64, *((uint64_t *)row[i])); + break; + + case TSDB_DATA_TYPE_FLOAT: { + float fv = 0; + fv = GET_FLOAT_VAL(row[i]); + len += sprintf(str + len, "%f", fv); + } break; + + case TSDB_DATA_TYPE_DOUBLE: { + double dv = 0; + dv = GET_DOUBLE_VAL(row[i]); + len += sprintf(str + len, "%lf", dv); + } break; + + case TSDB_DATA_TYPE_BINARY: + case TSDB_DATA_TYPE_NCHAR: { + int32_t charLen = varDataLen((char *)row[i] - VARSTR_HEADER_SIZE); + memcpy(str + len, row[i], charLen); + len += charLen; + } break; + + case TSDB_DATA_TYPE_TIMESTAMP: + len += sprintf(str + len, "%" PRId64, *((int64_t *)row[i])); + break; + + case TSDB_DATA_TYPE_BOOL: + len += sprintf(str + len, "%d", *((int8_t *)row[i])); + default: + break; + } + } + + return len; +} + +/** + * @brief print column name and values of each row + * + * @param res + * @return int + */ +static int printResult(TAOS_RES *res) { + int numFields = taos_num_fields(res); + TAOS_FIELD *fields = taos_fetch_fields(res); + char header[256] = {0}; + int len = 0; + for (int i = 0; i < numFields; ++i) { + len += sprintf(header + len, "%s ", fields[i].name); + } + puts(header); + + TAOS_ROW row = NULL; + while ((row = taos_fetch_row(res))) { + char temp[256] = {0}; + printRow(temp, row, fields, numFields); + puts(temp); + } +} + +int main() { + TAOS *taos = taos_connect("localhost", "root", "taosdata", "power", 6030); + if (taos == NULL) { + puts("failed to connect to server"); + exit(EXIT_FAILURE); + } + TAOS_RES *res = taos_query(taos, "SELECT * FROM meters LIMIT 2"); + if (taos_errno(res) != 0) { + printf("failed to execute taos_query. error: %s\n", taos_errstr(res)); + exit(EXIT_FAILURE); + } + printResult(res); + taos_free_result(res); + taos_close(taos); + taos_cleanup(); +} + +// output: +// ts current voltage phase location groupid +// 1648432611249 10.300000 219 0.310000 Beijing.Chaoyang 2 +// 1648432611749 12.600000 218 0.330000 Beijing.Chaoyang 2 \ No newline at end of file diff --git a/docs-examples/c/stmt_example.c b/docs-examples/c/stmt_example.c new file mode 100644 index 0000000000..fab1506f95 --- /dev/null +++ b/docs-examples/c/stmt_example.c @@ -0,0 +1,141 @@ +// compile with +// gcc -o stmt_example stmt_example.c -ltaos +#include +#include +#include +#include "taos.h" + +/** + * @brief execute sql only. + * + * @param taos + * @param sql + */ +void executeSQL(TAOS *taos, const char *sql) { + TAOS_RES *res = taos_query(taos, sql); + int code = taos_errno(res); + if (code != 0) { + printf("%s\n", taos_errstr(res)); + taos_free_result(res); + taos_close(taos); + exit(EXIT_FAILURE); + } + taos_free_result(res); +} + +/** + * @brief check return status and exit program when error occur. + * + * @param stmt + * @param code + * @param msg + */ +void checkErrorCode(TAOS_STMT *stmt, int code, const char* msg) { + if (code != 0) { + printf("%s. error: %s\n", msg, taos_stmt_errstr(stmt)); + taos_stmt_close(stmt); + exit(EXIT_FAILURE); + } +} + +typedef struct { + int64_t ts; + float current; + int voltage; + float phase; +} Row; + +/** + * @brief insert data using stmt API + * + * @param taos + */ +void insertData(TAOS *taos) { + // init + TAOS_STMT *stmt = taos_stmt_init(taos); + // prepare + const char *sql = "INSERT INTO ? USING meters TAGS(?, ?) VALUES(?, ?, ?, ?)"; + int code = taos_stmt_prepare(stmt, sql, 0); + checkErrorCode(stmt, code, "failed to execute taos_stmt_prepare"); + // bind table name and tags + TAOS_BIND tags[2]; + char* location = "Beijing.Chaoyang"; + int groupId = 2; + tags[0].buffer_type = TSDB_DATA_TYPE_BINARY; + tags[0].buffer_length = strlen(location); + tags[0].length = &tags[0].buffer_length; + tags[0].buffer = location; + tags[0].is_null = NULL; + + tags[1].buffer_type = TSDB_DATA_TYPE_INT; + tags[1].buffer_length = sizeof(int); + tags[1].length = &tags[1].buffer_length; + tags[1].buffer = &groupId; + tags[1].is_null = NULL; + + code = taos_stmt_set_tbname_tags(stmt, "d1001", tags); + checkErrorCode(stmt, code, "failed to execute taos_stmt_set_tbname_tags"); + + // insert two rows + Row rows[2] = { + {1648432611249, 10.3, 219, 0.31}, + {1648432611749, 12.6, 218, 0.33}, + }; + + TAOS_BIND values[4]; + values[0].buffer_type = TSDB_DATA_TYPE_TIMESTAMP; + values[0].buffer_length = sizeof(int64_t); + values[0].length = &values[0].buffer_length; + values[0].is_null = NULL; + + values[1].buffer_type = TSDB_DATA_TYPE_FLOAT; + values[1].buffer_length = sizeof(float); + values[1].length = &values[1].buffer_length; + values[1].is_null = NULL; + + values[2].buffer_type = TSDB_DATA_TYPE_INT; + values[2].buffer_length = sizeof(int); + values[2].length = &values[2].buffer_length; + values[2].is_null = NULL; + + values[3].buffer_type = TSDB_DATA_TYPE_FLOAT; + values[3].buffer_length = sizeof(float); + values[3].length = &values[3].buffer_length; + values[3].is_null = NULL; + + for (int i = 0; i < 2; ++i) { + values[0].buffer = &rows[i].ts; + values[1].buffer = &rows[i].current; + values[2].buffer = &rows[i].voltage; + values[3].buffer = &rows[i].phase; + code = taos_stmt_bind_param(stmt, values); // bind param + checkErrorCode(stmt, code, "failed to execute taos_stmt_bind_param"); + code = taos_stmt_add_batch(stmt); // add batch + checkErrorCode(stmt, code, "failed to execute taos_stmt_add_batch"); + } + // execute + code = taos_stmt_execute(stmt); + checkErrorCode(stmt, code, "failed to execute taos_stmt_execute"); + int affectedRows = taos_stmt_affected_rows(stmt); + printf("successfully inserted %d rows\n", affectedRows); + // close + taos_stmt_close(stmt); +} + +int main() { + TAOS *taos = taos_connect("localhost", "root", "taosdata", NULL, 6030); + if (taos == NULL) { + printf("failed to connect to server\n"); + exit(EXIT_FAILURE); + } + executeSQL(taos, "CREATE DATABASE power"); + executeSQL(taos, "USE power"); + executeSQL(taos, "CREATE STABLE meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (location BINARY(64), groupId INT)"); + insertData(taos); + taos_close(taos); + taos_cleanup(); +} + + +// output: +// successfully inserted 2 rows \ No newline at end of file diff --git a/docs-examples/c/subscribe_demo.c b/docs-examples/c/subscribe_demo.c new file mode 100644 index 0000000000..2fe62c24eb --- /dev/null +++ b/docs-examples/c/subscribe_demo.c @@ -0,0 +1,66 @@ +// A simple demo for asynchronous subscription. +// compile with: +// gcc -o subscribe_demo subscribe_demo.c -ltaos + +#include +#include +#include +#include + +int nTotalRows; + +/** + * @brief callback function of subscription. + * + * @param tsub + * @param res + * @param param. the additional parameter passed to taos_subscribe + * @param code. error code + */ +void subscribe_callback(TAOS_SUB* tsub, TAOS_RES* res, void* param, int code) { + if (code != 0) { + printf("error: %d\n", code); + exit(EXIT_FAILURE); + } + + TAOS_ROW row = NULL; + int num_fields = taos_num_fields(res); + TAOS_FIELD* fields = taos_fetch_fields(res); + int nRows = 0; + + while ((row = taos_fetch_row(res))) { + char buf[4096] = {0}; + taos_print_row(buf, row, fields, num_fields); + puts(buf); + nRows++; + } + + nTotalRows += nRows; + printf("%d rows consumed.\n", nRows); +} + +int main() { + TAOS* taos = taos_connect("localhost", "root", "taosdata", NULL, 6030); + if (taos == NULL) { + printf("failed to connect to server\n"); + exit(EXIT_FAILURE); + } + + int restart = 1; // if the topic already exists, where to subscribe from the begin. + const char* topic = "topic-meter-current-bg-10"; + const char* sql = "select * from power.meters where current > 10"; + void* param = NULL; // additional parameter. + int interval = 2000; // consumption interval in microseconds. + TAOS_SUB* tsub = taos_subscribe(taos, restart, topic, sql, subscribe_callback, NULL, interval); + + // wait for insert from others process. you can open TDengine CLI to insert some records for test. + + getchar(); // press Enter to stop + + printf("total rows consumed: %d\n", nTotalRows); + int keep = 0; // whether to keep subscribe process + taos_unsubscribe(tsub, keep); + + taos_close(taos); + taos_cleanup(); +} diff --git a/docs-examples/c/telnet_line_example.c b/docs-examples/c/telnet_line_example.c new file mode 100644 index 0000000000..913d433f6a --- /dev/null +++ b/docs-examples/c/telnet_line_example.c @@ -0,0 +1,54 @@ +// compile with +// gcc -o telnet_line_example telnet_line_example.c -ltaos +#include +#include +#include +#include "taos.h" + +void executeSQL(TAOS *taos, const char *sql) { + TAOS_RES *res = taos_query(taos, sql); + int code = taos_errno(res); + if (code != 0) { + printf("%s\n", taos_errstr(res)); + taos_free_result(res); + taos_close(taos); + exit(EXIT_FAILURE); + } + taos_free_result(res); +} + +// ANCHOR: main +int main() { + TAOS *taos = taos_connect("localhost", "root", "taosdata", "", 6030); + if (taos == NULL) { + printf("failed to connect to server\n"); + exit(EXIT_FAILURE); + } + executeSQL(taos, "DROP DATABASE IF EXISTS test"); + executeSQL(taos, "CREATE DATABASE test"); + executeSQL(taos, "USE test"); + char *lines[] = { + "meters.current 1648432611249 10.3 location=Beijing.Chaoyang groupid=2", + "meters.current 1648432611250 12.6 location=Beijing.Chaoyang groupid=2", + "meters.current 1648432611249 10.8 location=Beijing.Haidian groupid=3", + "meters.current 1648432611250 11.3 location=Beijing.Haidian groupid=3", + "meters.voltage 1648432611249 219 location=Beijing.Chaoyang groupid=2", + "meters.voltage 1648432611250 218 location=Beijing.Chaoyang groupid=2", + "meters.voltage 1648432611249 221 location=Beijing.Haidian groupid=3", + "meters.voltage 1648432611250 217 location=Beijing.Haidian groupid=3", + }; + TAOS_RES *res = taos_schemaless_insert(taos, lines, 8, TSDB_SML_TELNET_PROTOCOL, TSDB_SML_TIMESTAMP_NOT_CONFIGURED); + if (taos_errno(res) != 0) { + printf("failed to insert schema-less data, reason: %s\n", taos_errstr(res)); + } else { + int affectedRow = taos_affected_rows(res); + printf("successfully inserted %d rows\n", affectedRow); + } + + taos_free_result(res); + taos_close(taos); + taos_cleanup(); +} +// output: +// successfully inserted 8 rows +// ANCHOR_END: main diff --git a/docs-examples/csharp/.gitignore b/docs-examples/csharp/.gitignore new file mode 100644 index 0000000000..b3aff79f37 --- /dev/null +++ b/docs-examples/csharp/.gitignore @@ -0,0 +1,4 @@ +bin +obj +.vs +*.sln \ No newline at end of file diff --git a/docs-examples/csharp/AsyncQueryExample.cs b/docs-examples/csharp/AsyncQueryExample.cs new file mode 100644 index 0000000000..fe30d21efe --- /dev/null +++ b/docs-examples/csharp/AsyncQueryExample.cs @@ -0,0 +1,238 @@ +using TDengineDriver; +using System.Runtime.InteropServices; + +namespace TDengineExample +{ + public class AsyncQueryExample + { + static void Main() + { + IntPtr conn = GetConnection(); + QueryAsyncCallback queryAsyncCallback = new QueryAsyncCallback(QueryCallback); + TDengine.QueryAsync(conn, "select * from meters", queryAsyncCallback, IntPtr.Zero); + Thread.Sleep(2000); + TDengine.Close(conn); + TDengine.Cleanup(); + } + + static void QueryCallback(IntPtr param, IntPtr taosRes, int code) + { + if (code == 0 && taosRes != IntPtr.Zero) + { + FetchRowAsyncCallback fetchRowAsyncCallback = new FetchRowAsyncCallback(FetchRowCallback); + TDengine.FetchRowAsync(taosRes, fetchRowAsyncCallback, param); + } + else + { + Console.WriteLine($"async query data failed, failed code {code}"); + } + } + + static void FetchRowCallback(IntPtr param, IntPtr taosRes, int numOfRows) + { + if (numOfRows > 0) + { + Console.WriteLine($"{numOfRows} rows async retrieved"); + DisplayRes(taosRes); + TDengine.FetchRowAsync(taosRes, FetchRowCallback, param); + } + else + { + if (numOfRows == 0) + { + Console.WriteLine("async retrieve complete."); + + } + else + { + Console.WriteLine($"FetchRowAsync callback error, error code {numOfRows}"); + } + TDengine.FreeResult(taosRes); + } + } + + public static void DisplayRes(IntPtr res) + { + if (!IsValidResult(res)) + { + TDengine.Cleanup(); + System.Environment.Exit(1); + } + + List metaList = TDengine.FetchFields(res); + int fieldCount = metaList.Count; + // metaList.ForEach((item) => { Console.Write("{0} ({1}) \t|\t", item.name, item.size); }); + + List dataList = QueryRes(res, metaList); + for (int index = 0; index < dataList.Count; index++) + { + if (index % fieldCount == 0 && index != 0) + { + Console.WriteLine(""); + } + Console.Write("{0} \t|\t", dataList[index].ToString()); + + } + Console.WriteLine(""); + } + + public static bool IsValidResult(IntPtr res) + { + if ((res == IntPtr.Zero) || (TDengine.ErrorNo(res) != 0)) + { + if (res != IntPtr.Zero) + { + Console.Write("reason: " + TDengine.Error(res)); + return false; + } + Console.WriteLine(""); + return false; + } + return true; + } + + private static List QueryRes(IntPtr res, List meta) + { + IntPtr taosRow; + List dataRaw = new(); + while ((taosRow = TDengine.FetchRows(res)) != IntPtr.Zero) + { + dataRaw.AddRange(FetchRow(taosRow, res)); + } + if (TDengine.ErrorNo(res) != 0) + { + Console.Write("Query is not complete, Error {0} {1}", TDengine.ErrorNo(res), TDengine.Error(res)); + } + TDengine.FreeResult(res); + Console.WriteLine(""); + return dataRaw; + } + + public static List FetchRow(IntPtr taosRow, IntPtr taosRes)//, List metaList, int numOfFiled + { + List metaList = TDengine.FetchFields(taosRes); + int numOfFiled = TDengine.FieldCount(taosRes); + + + List dataRaw = new(); + + IntPtr colLengthPrt = TDengine.FetchLengths(taosRes); + int[] colLengthArr = new int[numOfFiled]; + Marshal.Copy(colLengthPrt, colLengthArr, 0, numOfFiled); + + for (int i = 0; i < numOfFiled; i++) + { + TDengineMeta meta = metaList[i]; + IntPtr data = Marshal.ReadIntPtr(taosRow, IntPtr.Size * i); + + if (data == IntPtr.Zero) + { + dataRaw.Add("NULL"); + continue; + } + switch ((TDengineDataType)meta.type) + { + case TDengineDataType.TSDB_DATA_TYPE_BOOL: + bool v1 = Marshal.ReadByte(data) != 0; + dataRaw.Add(v1); + break; + case TDengineDataType.TSDB_DATA_TYPE_TINYINT: + sbyte v2 = (sbyte)Marshal.ReadByte(data); + dataRaw.Add(v2); + break; + case TDengineDataType.TSDB_DATA_TYPE_SMALLINT: + short v3 = Marshal.ReadInt16(data); + dataRaw.Add(v3); + break; + case TDengineDataType.TSDB_DATA_TYPE_INT: + int v4 = Marshal.ReadInt32(data); + dataRaw.Add(v4); + break; + case TDengineDataType.TSDB_DATA_TYPE_BIGINT: + long v5 = Marshal.ReadInt64(data); + dataRaw.Add(v5); + break; + case TDengineDataType.TSDB_DATA_TYPE_FLOAT: + float v6 = (float)Marshal.PtrToStructure(data, typeof(float)); + dataRaw.Add(v6); + break; + case TDengineDataType.TSDB_DATA_TYPE_DOUBLE: + double v7 = (double)Marshal.PtrToStructure(data, typeof(double)); + dataRaw.Add(v7); + break; + case TDengineDataType.TSDB_DATA_TYPE_BINARY: + string v8 = Marshal.PtrToStringUTF8(data, colLengthArr[i]); + dataRaw.Add(v8); + break; + case TDengineDataType.TSDB_DATA_TYPE_TIMESTAMP: + long v9 = Marshal.ReadInt64(data); + dataRaw.Add(v9); + break; + case TDengineDataType.TSDB_DATA_TYPE_NCHAR: + string v10 = Marshal.PtrToStringUTF8(data, colLengthArr[i]); + dataRaw.Add(v10); + break; + case TDengineDataType.TSDB_DATA_TYPE_UTINYINT: + byte v12 = Marshal.ReadByte(data); + dataRaw.Add(v12.ToString()); + break; + case TDengineDataType.TSDB_DATA_TYPE_USMALLINT: + ushort v13 = (ushort)Marshal.ReadInt16(data); + dataRaw.Add(v13); + break; + case TDengineDataType.TSDB_DATA_TYPE_UINT: + uint v14 = (uint)Marshal.ReadInt32(data); + dataRaw.Add(v14); + break; + case TDengineDataType.TSDB_DATA_TYPE_UBIGINT: + ulong v15 = (ulong)Marshal.ReadInt64(data); + dataRaw.Add(v15); + break; + case TDengineDataType.TSDB_DATA_TYPE_JSONTAG: + string v16 = Marshal.PtrToStringUTF8(data, colLengthArr[i]); + dataRaw.Add(v16); + break; + default: + dataRaw.Add("nonsupport data type"); + break; + } + + } + return dataRaw; + } + + static IntPtr GetConnection() + { + string host = "localhost"; + short port = 6030; + string username = "root"; + string password = "taosdata"; + string dbname = "power"; + var conn = TDengine.Connect(host, username, password, dbname, port); + if (conn == IntPtr.Zero) + { + Console.WriteLine("Connect to TDengine failed"); + Environment.Exit(0); + } + else + { + Console.WriteLine("Connect to TDengine success"); + } + return conn; + } + } +} + +//output: +//Connect to TDengine success +//8 rows async retrieved + +//1538548685000 | 10.3 | 219 | 0.31 | beijing.chaoyang | 2 | +//1538548695000 | 12.6 | 218 | 0.33 | beijing.chaoyang | 2 | +//1538548696800 | 12.3 | 221 | 0.31 | beijing.chaoyang | 2 | +//1538548696650 | 10.3 | 218 | 0.25 | beijing.chaoyang | 3 | +//1538548685500 | 11.8 | 221 | 0.28 | beijing.haidian | 2 | +//1538548696600 | 13.4 | 223 | 0.29 | beijing.haidian | 2 | +//1538548685000 | 10.8 | 223 | 0.29 | beijing.haidian | 3 | +//1538548686500 | 11.5 | 221 | 0.35 | beijing.haidian | 3 | +//async retrieve complete. \ No newline at end of file diff --git a/docs-examples/csharp/ConnectExample.cs b/docs-examples/csharp/ConnectExample.cs new file mode 100644 index 0000000000..f3548ee65d --- /dev/null +++ b/docs-examples/csharp/ConnectExample.cs @@ -0,0 +1,29 @@ +using TDengineDriver; + +namespace TDengineExample +{ + + internal class ConnectExample + { + static void Main(String[] args) + { + string host = "localhost"; + short port = 6030; + string username = "root"; + string password = "taosdata"; + string dbname = ""; + + var conn = TDengine.Connect(host, username, password, dbname, port); + if (conn == IntPtr.Zero) + { + Console.WriteLine("Connect to TDengine failed"); + } + else + { + Console.WriteLine("Connect to TDengine success"); + } + TDengine.Close(conn); + TDengine.Cleanup(); + } + } +} diff --git a/docs-examples/csharp/InfluxDBLineExample.cs b/docs-examples/csharp/InfluxDBLineExample.cs new file mode 100644 index 0000000000..7aad088252 --- /dev/null +++ b/docs-examples/csharp/InfluxDBLineExample.cs @@ -0,0 +1,77 @@ +using TDengineDriver; + +namespace TDengineExample +{ + internal class InfluxDBLineExample + { + static void Main() + { + IntPtr conn = GetConnection(); + PrepareDatabase(conn); + string[] lines = { + "meters,location=Beijing.Haidian,groupid=2 current=11.8,voltage=221,phase=0.28 1648432611249", + "meters,location=Beijing.Haidian,groupid=2 current=13.4,voltage=223,phase=0.29 1648432611250", + "meters,location=Beijing.Haidian,groupid=3 current=10.8,voltage=223,phase=0.29 1648432611249", + "meters,location=Beijing.Haidian,groupid=3 current=11.3,voltage=221,phase=0.35 1648432611250" + }; + IntPtr res = TDengine.SchemalessInsert(conn, lines, lines.Length, (int)TDengineSchemalessProtocol.TSDB_SML_LINE_PROTOCOL, (int)TDengineSchemalessPrecision.TSDB_SML_TIMESTAMP_MILLI_SECONDS); + if (TDengine.ErrorNo(res) != 0) + { + Console.WriteLine("SchemalessInsert failed since " + TDengine.Error(res)); + ExitProgram(conn, 1); + } + else + { + int affectedRows = TDengine.AffectRows(res); + Console.WriteLine($"SchemalessInsert success, affected {affectedRows} rows"); + } + TDengine.FreeResult(res); + ExitProgram(conn, 0); + + } + static IntPtr GetConnection() + { + string host = "localhost"; + short port = 6030; + string username = "root"; + string password = "taosdata"; + string dbname = ""; + var conn = TDengine.Connect(host, username, password, dbname, port); + if (conn == IntPtr.Zero) + { + Console.WriteLine("Connect to TDengine failed"); + TDengine.Cleanup(); + Environment.Exit(1); + } + else + { + Console.WriteLine("Connect to TDengine success"); + } + return conn; + } + + static void PrepareDatabase(IntPtr conn) + { + IntPtr res = TDengine.Query(conn, "CREATE DATABASE test"); + if (TDengine.ErrorNo(res) != 0) + { + Console.WriteLine("failed to create database, reason: " + TDengine.Error(res)); + ExitProgram(conn, 1); + } + res = TDengine.Query(conn, "USE test"); + if (TDengine.ErrorNo(res) != 0) + { + Console.WriteLine("failed to change database, reason: " + TDengine.Error(res)); + ExitProgram(conn, 1); + } + } + + static void ExitProgram(IntPtr conn, int exitCode) + { + TDengine.Close(conn); + TDengine.Cleanup(); + Environment.Exit(exitCode); + } + } + +} diff --git a/docs-examples/csharp/OptsJsonExample.cs b/docs-examples/csharp/OptsJsonExample.cs new file mode 100644 index 0000000000..d774a325af --- /dev/null +++ b/docs-examples/csharp/OptsJsonExample.cs @@ -0,0 +1,76 @@ +using TDengineDriver; + +namespace TDengineExample +{ + internal class OptsJsonExample + { + static void Main() + { + IntPtr conn = GetConnection(); + PrepareDatabase(conn); + string[] lines = { "[{\"metric\": \"meters.current\", \"timestamp\": 1648432611249, \"value\": 10.3, \"tags\": {\"location\": \"Beijing.Chaoyang\", \"groupid\": 2}}," + + " {\"metric\": \"meters.voltage\", \"timestamp\": 1648432611249, \"value\": 219, \"tags\": {\"location\": \"Beijing.Haidian\", \"groupid\": 1}}, " + + "{\"metric\": \"meters.current\", \"timestamp\": 1648432611250, \"value\": 12.6, \"tags\": {\"location\": \"Beijing.Chaoyang\", \"groupid\": 2}}," + + " {\"metric\": \"meters.voltage\", \"timestamp\": 1648432611250, \"value\": 221, \"tags\": {\"location\": \"Beijing.Haidian\", \"groupid\": 1}}]" + }; + + IntPtr res = TDengine.SchemalessInsert(conn, lines, 1, (int)TDengineSchemalessProtocol.TSDB_SML_JSON_PROTOCOL, (int)TDengineSchemalessPrecision.TSDB_SML_TIMESTAMP_NOT_CONFIGURED); + if (TDengine.ErrorNo(res) != 0) + { + Console.WriteLine("SchemalessInsert failed since " + TDengine.Error(res)); + ExitProgram(conn, 1); + } + else + { + int affectedRows = TDengine.AffectRows(res); + Console.WriteLine($"SchemalessInsert success, affected {affectedRows} rows"); + } + TDengine.FreeResult(res); + ExitProgram(conn, 0); + + } + static IntPtr GetConnection() + { + string host = "localhost"; + short port = 6030; + string username = "root"; + string password = "taosdata"; + string dbname = ""; + var conn = TDengine.Connect(host, username, password, dbname, port); + if (conn == IntPtr.Zero) + { + Console.WriteLine("Connect to TDengine failed"); + TDengine.Cleanup(); + Environment.Exit(1); + } + else + { + Console.WriteLine("Connect to TDengine success"); + } + return conn; + } + + static void PrepareDatabase(IntPtr conn) + { + IntPtr res = TDengine.Query(conn, "CREATE DATABASE test"); + if (TDengine.ErrorNo(res) != 0) + { + Console.WriteLine("failed to create database, reason: " + TDengine.Error(res)); + ExitProgram(conn, 1); + } + res = TDengine.Query(conn, "USE test"); + if (TDengine.ErrorNo(res) != 0) + { + Console.WriteLine("failed to change database, reason: " + TDengine.Error(res)); + ExitProgram(conn, 1); + } + } + + static void ExitProgram(IntPtr conn, int exitCode) + { + TDengine.Close(conn); + TDengine.Cleanup(); + Environment.Exit(exitCode); + } + } +} diff --git a/docs-examples/csharp/OptsTelnetExample.cs b/docs-examples/csharp/OptsTelnetExample.cs new file mode 100644 index 0000000000..81608c3221 --- /dev/null +++ b/docs-examples/csharp/OptsTelnetExample.cs @@ -0,0 +1,80 @@ +using TDengineDriver; + +namespace TDengineExample +{ + internal class OptsTelnetExample + { + static void Main() + { + IntPtr conn = GetConnection(); + PrepareDatabase(conn); + string[] lines = { + "meters.current 1648432611249 10.3 location=Beijing.Chaoyang groupid=2", + "meters.current 1648432611250 12.6 location=Beijing.Chaoyang groupid=2", + "meters.current 1648432611249 10.8 location=Beijing.Haidian groupid=3", + "meters.current 1648432611250 11.3 location=Beijing.Haidian groupid=3", + "meters.voltage 1648432611249 219 location=Beijing.Chaoyang groupid=2", + "meters.voltage 1648432611250 218 location=Beijing.Chaoyang groupid=2", + "meters.voltage 1648432611249 221 location=Beijing.Haidian groupid=3", + "meters.voltage 1648432611250 217 location=Beijing.Haidian groupid=3", + }; + IntPtr res = TDengine.SchemalessInsert(conn, lines, lines.Length, (int)TDengineSchemalessProtocol.TSDB_SML_TELNET_PROTOCOL, (int)TDengineSchemalessPrecision.TSDB_SML_TIMESTAMP_NOT_CONFIGURED); + if (TDengine.ErrorNo(res) != 0) + { + Console.WriteLine("SchemalessInsert failed since " + TDengine.Error(res)); + ExitProgram(conn, 1); + } + else + { + int affectedRows = TDengine.AffectRows(res); + Console.WriteLine($"SchemalessInsert success, affected {affectedRows} rows"); + } + TDengine.FreeResult(res); + ExitProgram(conn, 0); + + } + static IntPtr GetConnection() + { + string host = "localhost"; + short port = 6030; + string username = "root"; + string password = "taosdata"; + string dbname = ""; + var conn = TDengine.Connect(host, username, password, dbname, port); + if (conn == IntPtr.Zero) + { + Console.WriteLine("Connect to TDengine failed"); + TDengine.Cleanup(); + Environment.Exit(1); + } + else + { + Console.WriteLine("Connect to TDengine success"); + } + return conn; + } + + static void PrepareDatabase(IntPtr conn) + { + IntPtr res = TDengine.Query(conn, "CREATE DATABASE test"); + if (TDengine.ErrorNo(res) != 0) + { + Console.WriteLine("failed to create database, reason: " + TDengine.Error(res)); + ExitProgram(conn, 1); + } + res = TDengine.Query(conn, "USE test"); + if (TDengine.ErrorNo(res) != 0) + { + Console.WriteLine("failed to change database, reason: " + TDengine.Error(res)); + ExitProgram(conn, 1); + } + } + + static void ExitProgram(IntPtr conn, int exitCode) + { + TDengine.Close(conn); + TDengine.Cleanup(); + Environment.Exit(exitCode); + } + } +} diff --git a/docs-examples/csharp/QueryExample.cs b/docs-examples/csharp/QueryExample.cs new file mode 100644 index 0000000000..f00e391100 --- /dev/null +++ b/docs-examples/csharp/QueryExample.cs @@ -0,0 +1,162 @@ +using TDengineDriver; +using System.Runtime.InteropServices; + +namespace TDengineExample +{ + internal class QueryExample + { + static void Main() + { + IntPtr conn = GetConnection(); + // run query + IntPtr res = TDengine.Query(conn, "SELECT * FROM test.meters LIMIT 2"); + if (TDengine.ErrorNo(res) != 0) + { + Console.WriteLine("Failed to query since: " + TDengine.Error(res)); + TDengine.Close(conn); + TDengine.Cleanup(); + return; + } + + // get filed count + int fieldCount = TDengine.FieldCount(res); + Console.WriteLine("fieldCount=" + fieldCount); + + // print column names + List metas = TDengine.FetchFields(res); + for (int i = 0; i < metas.Count; i++) + { + Console.Write(metas[i].name + "\t"); + } + Console.WriteLine(); + + // print values + IntPtr row; + while ((row = TDengine.FetchRows(res)) != IntPtr.Zero) + { + List metaList = TDengine.FetchFields(res); + int numOfFiled = TDengine.FieldCount(res); + + List dataRaw = new List(); + + IntPtr colLengthPrt = TDengine.FetchLengths(res); + int[] colLengthArr = new int[numOfFiled]; + Marshal.Copy(colLengthPrt, colLengthArr, 0, numOfFiled); + + for (int i = 0; i < numOfFiled; i++) + { + TDengineMeta meta = metaList[i]; + IntPtr data = Marshal.ReadIntPtr(row, IntPtr.Size * i); + + if (data == IntPtr.Zero) + { + Console.Write("NULL\t"); + continue; + } + switch ((TDengineDataType)meta.type) + { + case TDengineDataType.TSDB_DATA_TYPE_BOOL: + bool v1 = Marshal.ReadByte(data) == 0 ? false : true; + Console.Write(v1.ToString() + "\t"); + break; + case TDengineDataType.TSDB_DATA_TYPE_TINYINT: + sbyte v2 = (sbyte)Marshal.ReadByte(data); + Console.Write(v2.ToString() + "\t"); + break; + case TDengineDataType.TSDB_DATA_TYPE_SMALLINT: + short v3 = Marshal.ReadInt16(data); + Console.Write(v3.ToString() + "\t"); + break; + case TDengineDataType.TSDB_DATA_TYPE_INT: + int v4 = Marshal.ReadInt32(data); + Console.Write(v4.ToString() + "\t"); + break; + case TDengineDataType.TSDB_DATA_TYPE_BIGINT: + long v5 = Marshal.ReadInt64(data); + Console.Write(v5.ToString() + "\t"); + break; + case TDengineDataType.TSDB_DATA_TYPE_FLOAT: + float v6 = (float)Marshal.PtrToStructure(data, typeof(float)); + Console.Write(v6.ToString() + "\t"); + break; + case TDengineDataType.TSDB_DATA_TYPE_DOUBLE: + double v7 = (double)Marshal.PtrToStructure(data, typeof(double)); + Console.Write(v7.ToString() + "\t"); + break; + case TDengineDataType.TSDB_DATA_TYPE_BINARY: + string v8 = Marshal.PtrToStringUTF8(data, colLengthArr[i]); + Console.Write(v8 + "\t"); + break; + case TDengineDataType.TSDB_DATA_TYPE_TIMESTAMP: + long v9 = Marshal.ReadInt64(data); + Console.Write(v9.ToString() + "\t"); + break; + case TDengineDataType.TSDB_DATA_TYPE_NCHAR: + string v10 = Marshal.PtrToStringUTF8(data, colLengthArr[i]); + Console.Write(v10 + "\t"); + break; + case TDengineDataType.TSDB_DATA_TYPE_UTINYINT: + byte v12 = Marshal.ReadByte(data); + Console.Write(v12.ToString() + "\t"); + break; + case TDengineDataType.TSDB_DATA_TYPE_USMALLINT: + ushort v13 = (ushort)Marshal.ReadInt16(data); + Console.Write(v13.ToString() + "\t"); + break; + case TDengineDataType.TSDB_DATA_TYPE_UINT: + uint v14 = (uint)Marshal.ReadInt32(data); + Console.Write(v14.ToString() + "\t"); + break; + case TDengineDataType.TSDB_DATA_TYPE_UBIGINT: + ulong v15 = (ulong)Marshal.ReadInt64(data); + Console.Write(v15.ToString() + "\t"); + break; + case TDengineDataType.TSDB_DATA_TYPE_JSONTAG: + string v16 = Marshal.PtrToStringUTF8(data, colLengthArr[i]); + Console.Write(v16 + "\t"); + break; + default: + Console.Write("nonsupport data type value"); + break; + } + + } + Console.WriteLine(); + } + if (TDengine.ErrorNo(res) != 0) + { + Console.WriteLine($"Query is not complete, Error {TDengine.ErrorNo(res)} {TDengine.Error(res)}"); + } + // exit + TDengine.FreeResult(res); + TDengine.Close(conn); + TDengine.Cleanup(); + } + static IntPtr GetConnection() + { + string host = "localhost"; + short port = 6030; + string username = "root"; + string password = "taosdata"; + string dbname = "power"; + var conn = TDengine.Connect(host, username, password, dbname, port); + if (conn == IntPtr.Zero) + { + Console.WriteLine("Connect to TDengine failed"); + System.Environment.Exit(0); + } + else + { + Console.WriteLine("Connect to TDengine success"); + } + return conn; + } + } +} + +// output: +// Connect to TDengine success +// fieldCount=6 +// ts current voltage phase location groupid +// 1648432611249 10.3 219 0.31 Beijing.Chaoyang 2 +// 1648432611749 12.6 218 0.33 Beijing.Chaoyang 2 \ No newline at end of file diff --git a/docs-examples/csharp/SQLInsertExample.cs b/docs-examples/csharp/SQLInsertExample.cs new file mode 100644 index 0000000000..fa2e2a50da --- /dev/null +++ b/docs-examples/csharp/SQLInsertExample.cs @@ -0,0 +1,69 @@ +using TDengineDriver; + + +namespace TDengineExample +{ + internal class SQLInsertExample + { + + static void Main() + { + IntPtr conn = GetConnection(); + IntPtr res = TDengine.Query(conn, "CREATE DATABASE power"); + CheckRes(conn, res, "failed to create database"); + res = TDengine.Query(conn, "USE power"); + CheckRes(conn, res, "failed to change database"); + res = TDengine.Query(conn, "CREATE STABLE power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (location BINARY(64), groupId INT)"); + CheckRes(conn, res, "failed to create stable"); + var sql = "INSERT INTO d1001 USING meters TAGS(Beijing.Chaoyang, 2) VALUES ('2018-10-03 14:38:05.000', 10.30000, 219, 0.31000) ('2018-10-03 14:38:15.000', 12.60000, 218, 0.33000) ('2018-10-03 14:38:16.800', 12.30000, 221, 0.31000) " + + "d1002 USING power.meters TAGS(Beijing.Chaoyang, 3) VALUES('2018-10-03 14:38:16.650', 10.30000, 218, 0.25000) " + + "d1003 USING power.meters TAGS(Beijing.Haidian, 2) VALUES('2018-10-03 14:38:05.500', 11.80000, 221, 0.28000)('2018-10-03 14:38:16.600', 13.40000, 223, 0.29000) " + + "d1004 USING power.meters TAGS(Beijing.Haidian, 3) VALUES('2018-10-03 14:38:05.000', 10.80000, 223, 0.29000)('2018-10-03 14:38:06.500', 11.50000, 221, 0.35000)"; + res = TDengine.Query(conn, sql); + CheckRes(conn, res, "failed to insert data"); + int affectedRows = TDengine.AffectRows(res); + Console.WriteLine("affectedRows " + affectedRows); + ExitProgram(conn, 0); + } + + static IntPtr GetConnection() + { + string host = "localhost"; + short port = 6030; + string username = "root"; + string password = "taosdata"; + string dbname = ""; + var conn = TDengine.Connect(host, username, password, dbname, port); + if (conn == IntPtr.Zero) + { + Console.WriteLine("Connect to TDengine failed"); + Environment.Exit(0); + } + else + { + Console.WriteLine("Connect to TDengine success"); + } + return conn; + } + + static void CheckRes(IntPtr conn, IntPtr res, String errorMsg) + { + if (TDengine.ErrorNo(res) != 0) + { + Console.Write(errorMsg + " since: " + TDengine.Error(res)); + ExitProgram(conn, 1); + } + } + + static void ExitProgram(IntPtr conn, int exitCode) + { + TDengine.Close(conn); + TDengine.Cleanup(); + Environment.Exit(exitCode); + } + } +} + +// output: +// Connect to TDengine success +// affectedRows 8 diff --git a/docs-examples/csharp/StmtInsertExample.cs b/docs-examples/csharp/StmtInsertExample.cs new file mode 100644 index 0000000000..d6e00dd4ac --- /dev/null +++ b/docs-examples/csharp/StmtInsertExample.cs @@ -0,0 +1,115 @@ +using TDengineDriver; + +namespace TDengineExample +{ + internal class StmtInsertExample + { + private static IntPtr conn; + private static IntPtr stmt; + static void Main() + { + conn = GetConnection(); + PrepareSTable(); + // 1. init and prepare + stmt = TDengine.StmtInit(conn); + if (stmt == IntPtr.Zero) + { + Console.WriteLine("failed to init stmt, " + TDengine.Error(stmt)); + ExitProgram(); + } + int res = TDengine.StmtPrepare(stmt, "INSERT INTO ? USING meters TAGS(?, ?) VALUES(?, ?, ?, ?)"); + CheckStmtRes(res, "failed to prepare stmt"); + + // 2. bind table name and tags + TAOS_BIND[] tags = new TAOS_BIND[2] { TaosBind.BindBinary("Beijing.Chaoyang"), TaosBind.BindInt(2) }; + res = TDengine.StmtSetTbnameTags(stmt, "d1001", tags); + CheckStmtRes(res, "failed to bind table name and tags"); + + // 3. bind values + TAOS_MULTI_BIND[] values = new TAOS_MULTI_BIND[4] { + TaosMultiBind.MultiBindTimestamp(new long[2] { 1648432611249, 1648432611749}), + TaosMultiBind.MultiBindFloat(new float?[2] { 10.3f, 12.6f}), + TaosMultiBind.MultiBindInt(new int?[2] { 219, 218}), + TaosMultiBind.MultiBindFloat(new float?[2]{ 0.31f, 0.33f}) + }; + res = TDengine.StmtBindParamBatch(stmt, values); + CheckStmtRes(res, "failed to bind params"); + + // 4. add batch + res = TDengine.StmtAddBatch(stmt); + CheckStmtRes(res, "failed to add batch"); + + // 5. execute + res = TDengine.StmtExecute(stmt); + CheckStmtRes(res, "faild to execute"); + + // 6. free + TaosBind.FreeTaosBind(tags); + TaosMultiBind.FreeTaosBind(values); + TDengine.Close(conn); + TDengine.Cleanup(); + } + + static IntPtr GetConnection() + { + string host = "localhost"; + short port = 6030; + string username = "root"; + string password = "taosdata"; + string dbname = ""; + var conn = TDengine.Connect(host, username, password, dbname, port); + if (conn == IntPtr.Zero) + { + Console.WriteLine("Connect to TDengine failed"); + Environment.Exit(0); + } + else + { + Console.WriteLine("Connect to TDengine success"); + } + return conn; + } + + + + static void PrepareSTable() + { + IntPtr res = TDengine.Query(conn, "CREATE DATABASE power"); + CheckResPtr(res, "failed to create database"); + res = TDengine.Query(conn, "USE power"); + CheckResPtr(res, "failed to change database"); + res = TDengine.Query(conn, "CREATE STABLE power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (location BINARY(64), groupId INT)"); + CheckResPtr(res, "failed to create stable"); + } + + static void CheckStmtRes(int res, string errorMsg) + { + if (res != 0) + { + Console.WriteLine(errorMsg + ", " + TDengine.StmtErrorStr(stmt)); + int code = TDengine.StmtClose(stmt); + if (code != 0) + { + Console.WriteLine($"falied to close stmt, {code} reason: {TDengine.StmtErrorStr(stmt)} "); + } + ExitProgram(); + } + } + + static void CheckResPtr(IntPtr res, string errorMsg) + { + if (TDengine.ErrorNo(res) != 0) + { + Console.WriteLine(errorMsg + " since:" + TDengine.Error(res)); + ExitProgram(); + } + } + + static void ExitProgram() + { + TDengine.Close(conn); + TDengine.Cleanup(); + Environment.Exit(1); + } + } +} diff --git a/docs-examples/csharp/SubscribeDemo.cs b/docs-examples/csharp/SubscribeDemo.cs new file mode 100644 index 0000000000..34509215da --- /dev/null +++ b/docs-examples/csharp/SubscribeDemo.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace csharp +{ + internal class SubscribeDemo + { + } +} diff --git a/docs-examples/csharp/asyncquery.csproj b/docs-examples/csharp/asyncquery.csproj new file mode 100644 index 0000000000..7a952fe7ab --- /dev/null +++ b/docs-examples/csharp/asyncquery.csproj @@ -0,0 +1,15 @@ + + + + Exe + net6.0 + enable + enable + TDengineExample.AsyncQueryExample + + + + + + + diff --git a/docs-examples/csharp/connect.csproj b/docs-examples/csharp/connect.csproj new file mode 100644 index 0000000000..27cffa30ae --- /dev/null +++ b/docs-examples/csharp/connect.csproj @@ -0,0 +1,15 @@ + + + + Exe + net6.0 + enable + enable + TDengineExample.ConnectExample + + + + + + + diff --git a/docs-examples/csharp/influxdbline.csproj b/docs-examples/csharp/influxdbline.csproj new file mode 100644 index 0000000000..a8b197dc71 --- /dev/null +++ b/docs-examples/csharp/influxdbline.csproj @@ -0,0 +1,15 @@ + + + + Exe + net6.0 + enable + enable + TDengineExample.InfluxDBLineExample + + + + + + + diff --git a/docs-examples/csharp/optsjson.csproj b/docs-examples/csharp/optsjson.csproj new file mode 100644 index 0000000000..b1bd83405e --- /dev/null +++ b/docs-examples/csharp/optsjson.csproj @@ -0,0 +1,15 @@ + + + + Exe + net6.0 + enable + enable + TDengineExample.OptsJsonExample + + + + + + + diff --git a/docs-examples/csharp/optstelnet.csproj b/docs-examples/csharp/optstelnet.csproj new file mode 100644 index 0000000000..1ab4106771 --- /dev/null +++ b/docs-examples/csharp/optstelnet.csproj @@ -0,0 +1,15 @@ + + + + Exe + net6.0 + enable + enable + TDengineExample.OptsTelnetExample + + + + + + + diff --git a/docs-examples/csharp/query.csproj b/docs-examples/csharp/query.csproj new file mode 100644 index 0000000000..63f13c3ddb --- /dev/null +++ b/docs-examples/csharp/query.csproj @@ -0,0 +1,15 @@ + + + + Exe + net6.0 + enable + enable + TDengineExample.QueryExample + + + + + + + diff --git a/docs-examples/csharp/sqlinsert.csproj b/docs-examples/csharp/sqlinsert.csproj new file mode 100644 index 0000000000..0380395a5a --- /dev/null +++ b/docs-examples/csharp/sqlinsert.csproj @@ -0,0 +1,15 @@ + + + + Exe + net6.0 + enable + enable + TDengineExample.SQLInsertExample + + + + + + + diff --git a/docs-examples/csharp/stmtinsert.csproj b/docs-examples/csharp/stmtinsert.csproj new file mode 100644 index 0000000000..8defb895eb --- /dev/null +++ b/docs-examples/csharp/stmtinsert.csproj @@ -0,0 +1,15 @@ + + + + Exe + net6.0 + enable + enable + TDengineExample.StmtInsertExample + + + + + + + diff --git a/docs-examples/csharp/subscribe.csproj b/docs-examples/csharp/subscribe.csproj new file mode 100644 index 0000000000..8286922c6f --- /dev/null +++ b/docs-examples/csharp/subscribe.csproj @@ -0,0 +1,15 @@ + + + + Exe + net6.0 + enable + enable + TDengineExample.SubscribeDemo + + + + + + + diff --git a/docs-examples/go/.gitignore b/docs-examples/go/.gitignore new file mode 100644 index 0000000000..b6128386c3 --- /dev/null +++ b/docs-examples/go/.gitignore @@ -0,0 +1,3 @@ +.idea +.vscode +tmp/ \ No newline at end of file diff --git a/docs-examples/go/connect/afconn/main.go b/docs-examples/go/connect/afconn/main.go new file mode 100644 index 0000000000..2d36ef03ab --- /dev/null +++ b/docs-examples/go/connect/afconn/main.go @@ -0,0 +1,17 @@ +package main + +import ( + "fmt" + + "github.com/taosdata/driver-go/v2/af" +) + +func main() { + conn, err := af.Open("localhost", "root", "taosdata", "", 6030) + defer conn.Close() + if err != nil { + fmt.Println("failed to connect, err:", err) + } else { + fmt.Println("connected") + } +} diff --git a/docs-examples/go/connect/cgoexample/main.go b/docs-examples/go/connect/cgoexample/main.go new file mode 100644 index 0000000000..8b9aba4ce4 --- /dev/null +++ b/docs-examples/go/connect/cgoexample/main.go @@ -0,0 +1,23 @@ +package main + +import ( + "database/sql" + "fmt" + + _ "github.com/taosdata/driver-go/v2/taosSql" +) + +func main() { + var taosDSN = "root:taosdata@tcp(localhost:6030)/" + taos, err := sql.Open("taosSql", taosDSN) + if err != nil { + fmt.Println("failed to connect TDengine, err:", err) + return + } + fmt.Println("Connected") + defer taos.Close() +} + +// use +// var taosDSN = "root:taosdata@tcp(localhost:6030)/dbName" +// if you want to connect to a default database. diff --git a/docs-examples/go/connect/restexample/main.go b/docs-examples/go/connect/restexample/main.go new file mode 100644 index 0000000000..9c05e7eed8 --- /dev/null +++ b/docs-examples/go/connect/restexample/main.go @@ -0,0 +1,23 @@ +package main + +import ( + "database/sql" + "fmt" + + _ "github.com/taosdata/driver-go/v2/taosRestful" +) + +func main() { + var taosDSN = "root:taosdata@http(localhost:6041)/" + taos, err := sql.Open("taosRestful", taosDSN) + if err != nil { + fmt.Println("failed to connect TDengine, err:", err) + return + } + fmt.Println("Connected") + defer taos.Close() +} + +// use +// var taosDSN = "root:taosdata@http(localhost:6041)/dbName" +// if you want to connect to a default database. diff --git a/docs-examples/go/connect/wrapper/main.go b/docs-examples/go/connect/wrapper/main.go new file mode 100644 index 0000000000..d7e71a8baf --- /dev/null +++ b/docs-examples/go/connect/wrapper/main.go @@ -0,0 +1,17 @@ +package main + +import ( + "fmt" + + "github.com/taosdata/driver-go/v2/wrapper" +) + +func main() { + conn, err := wrapper.TaosConnect("localhost", "root", "taosdata", "", 6030) + defer wrapper.TaosClose(conn) + if err != nil { + fmt.Println("fail to connect, err:", err) + } else { + fmt.Println("connected") + } +} diff --git a/docs-examples/go/go.mod b/docs-examples/go/go.mod new file mode 100644 index 0000000000..5945e395e9 --- /dev/null +++ b/docs-examples/go/go.mod @@ -0,0 +1,6 @@ +module goexample + +go 1.17 + +require github.com/taosdata/driver-go/v2 develop + diff --git a/docs-examples/go/insert/json/main.go b/docs-examples/go/insert/json/main.go new file mode 100644 index 0000000000..47d9e9984a --- /dev/null +++ b/docs-examples/go/insert/json/main.go @@ -0,0 +1,37 @@ +package main + +import ( + "fmt" + + "github.com/taosdata/driver-go/v2/af" +) + +func prepareDatabase(conn *af.Connector) { + _, err := conn.Exec("CREATE DATABASE test") + if err != nil { + panic(err) + } + _, err = conn.Exec("USE test") + if err != nil { + panic(err) + } +} + +func main() { + conn, err := af.Open("localhost", "root", "taosdata", "", 6030) + if err != nil { + fmt.Println("fail to connect, err:", err) + } + defer conn.Close() + prepareDatabase(conn) + + payload := `[{"metric": "meters.current", "timestamp": 1648432611249, "value": 10.3, "tags": {"location": "Beijing.Chaoyang", "groupid": 2}}, + {"metric": "meters.voltage", "timestamp": 1648432611249, "value": 219, "tags": {"location": "Beijing.Haidian", "groupid": 1}}, + {"metric": "meters.current", "timestamp": 1648432611250, "value": 12.6, "tags": {"location": "Beijing.Chaoyang", "groupid": 2}}, + {"metric": "meters.voltage", "timestamp": 1648432611250, "value": 221, "tags": {"location": "Beijing.Haidian", "groupid": 1}}]` + + err = conn.OpenTSDBInsertJsonPayload(payload) + if err != nil { + fmt.Println("insert error:", err) + } +} diff --git a/docs-examples/go/insert/line/main.go b/docs-examples/go/insert/line/main.go new file mode 100644 index 0000000000..bbc41468fe --- /dev/null +++ b/docs-examples/go/insert/line/main.go @@ -0,0 +1,38 @@ +package main + +import ( + "fmt" + + "github.com/taosdata/driver-go/v2/af" +) + +func prepareDatabase(conn *af.Connector) { + _, err := conn.Exec("CREATE DATABASE test") + if err != nil { + panic(err) + } + _, err = conn.Exec("USE test") + if err != nil { + panic(err) + } +} + +func main() { + conn, err := af.Open("localhost", "root", "taosdata", "", 6030) + if err != nil { + fmt.Println("fail to connect, err:", err) + } + defer conn.Close() + prepareDatabase(conn) + var lines = []string{ + "meters,location=Beijing.Haidian,groupid=2 current=11.8,voltage=221,phase=0.28 1648432611249", + "meters,location=Beijing.Haidian,groupid=2 current=13.4,voltage=223,phase=0.29 1648432611250", + "meters,location=Beijing.Haidian,groupid=3 current=10.8,voltage=223,phase=0.29 1648432611249", + "meters,location=Beijing.Haidian,groupid=3 current=11.3,voltage=221,phase=0.35 1648432611250", + } + + err = conn.InfluxDBInsertLines(lines, "ms") + if err != nil { + fmt.Println("insert error:", err) + } +} diff --git a/docs-examples/go/insert/stmt/main.go b/docs-examples/go/insert/stmt/main.go new file mode 100644 index 0000000000..c50200ebb4 --- /dev/null +++ b/docs-examples/go/insert/stmt/main.go @@ -0,0 +1,73 @@ +package main + +import ( + "fmt" + "time" + + "github.com/taosdata/driver-go/v2/af" + "github.com/taosdata/driver-go/v2/af/param" + "github.com/taosdata/driver-go/v2/common" +) + +func checkErr(err error, prompt string) { + if err != nil { + fmt.Printf("%s\n", prompt) + panic(err) + } +} + +func prepareStable(conn *af.Connector) { + _, err := conn.Exec("CREATE DATABASE power") + checkErr(err, "failed to create database") + _, err = conn.Exec("CREATE STABLE power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (location BINARY(64), groupId INT)") + checkErr(err, "failed to create stable") + _, err = conn.Exec("USE power") + checkErr(err, "failed to change database") +} + +func main() { + conn, err := af.Open("localhost", "root", "taosdata", "", 6030) + checkErr(err, "fail to connect") + defer conn.Close() + prepareStable(conn) + // create stmt + stmt := conn.InsertStmt() + defer stmt.Close() + err = stmt.Prepare("INSERT INTO ? USING meters TAGS(?, ?) VALUES(?, ?, ?, ?)") + checkErr(err, "failed to create prepare statement") + + // bind table name and tags + tagParams := param.NewParam(2).AddBinary([]byte("Beijing.Chaoyang")).AddInt(2) + err = stmt.SetTableNameWithTags("d1001", tagParams) + checkErr(err, "failed to execute SetTableNameWithTags") + + // specify ColumnType + var bindType *param.ColumnType = param.NewColumnType(4).AddTimestamp().AddFloat().AddInt().AddFloat() + + // bind values. note: can only bind one row each time. + valueParams := []*param.Param{ + param.NewParam(1).AddTimestamp(time.Unix(1648432611, 249300000), common.PrecisionMilliSecond), + param.NewParam(1).AddFloat(10.3), + param.NewParam(1).AddInt(219), + param.NewParam(1).AddFloat(0.31), + } + err = stmt.BindParam(valueParams, bindType) + checkErr(err, "BindParam error") + err = stmt.AddBatch() + checkErr(err, "AddBatch error") + + // bind one more row + valueParams = []*param.Param{ + param.NewParam(1).AddTimestamp(time.Unix(1648432611, 749300000), common.PrecisionMilliSecond), + param.NewParam(1).AddFloat(12.6), + param.NewParam(1).AddInt(218), + param.NewParam(1).AddFloat(0.33), + } + err = stmt.BindParam(valueParams, bindType) + checkErr(err, "BindParam error") + err = stmt.AddBatch() + checkErr(err, "AddBatch error") + // execute + err = stmt.Execute() + checkErr(err, "Execute batch error") +} diff --git a/docs-examples/go/insert/telnet/main.go b/docs-examples/go/insert/telnet/main.go new file mode 100644 index 0000000000..879e6d5cec --- /dev/null +++ b/docs-examples/go/insert/telnet/main.go @@ -0,0 +1,42 @@ +package main + +import ( + "fmt" + + "github.com/taosdata/driver-go/v2/af" +) + +func prepareDatabase(conn *af.Connector) { + _, err := conn.Exec("CREATE DATABASE test") + if err != nil { + panic(err) + } + _, err = conn.Exec("USE test") + if err != nil { + panic(err) + } +} + +func main() { + conn, err := af.Open("localhost", "root", "taosdata", "", 6030) + if err != nil { + fmt.Println("fail to connect, err:", err) + } + defer conn.Close() + prepareDatabase(conn) + var lines = []string{ + "meters.current 1648432611249 10.3 location=Beijing.Chaoyang groupid=2", + "meters.current 1648432611250 12.6 location=Beijing.Chaoyang groupid=2", + "meters.current 1648432611249 10.8 location=Beijing.Haidian groupid=3", + "meters.current 1648432611250 11.3 location=Beijing.Haidian groupid=3", + "meters.voltage 1648432611249 219 location=Beijing.Chaoyang groupid=2", + "meters.voltage 1648432611250 218 location=Beijing.Chaoyang groupid=2", + "meters.voltage 1648432611249 221 location=Beijing.Haidian groupid=3", + "meters.voltage 1648432611250 217 location=Beijing.Haidian groupid=3", + } + + err = conn.OpenTSDBInsertTelnetLines(lines) + if err != nil { + fmt.Println("insert error:", err) + } +} diff --git a/docs-examples/go/query/async/main.go b/docs-examples/go/query/async/main.go new file mode 100644 index 0000000000..7776ec8d3f --- /dev/null +++ b/docs-examples/go/query/async/main.go @@ -0,0 +1,7 @@ +package main + +import "fmt" + +func main() { + fmt.Println("hello world!") +} diff --git a/docs-examples/go/query/sync/main.go b/docs-examples/go/query/sync/main.go new file mode 100644 index 0000000000..0326c7a7da --- /dev/null +++ b/docs-examples/go/query/sync/main.go @@ -0,0 +1,38 @@ +package main + +import ( + "database/sql" + "fmt" + "time" + + _ "github.com/taosdata/driver-go/v2/taosRestful" +) + +func main() { + var taosDSN = "root:taosdata@http(localhost:6041)/power" + taos, err := sql.Open("taosRestful", taosDSN) + if err != nil { + fmt.Println("failed to connect TDengine, err:", err) + return + } + defer taos.Close() + rows, err := taos.Query("SELECT ts, current FROM meters LIMIT 2") + if err != nil { + fmt.Println("failed to select from table, err:", err) + return + } + + defer rows.Close() + for rows.Next() { + var r struct { + ts time.Time + current float32 + } + err := rows.Scan(&r.ts, &r.current) + if err != nil { + fmt.Println("scan error:\n", err) + return + } + fmt.Println(r.ts, r.current) + } +} diff --git a/docs-examples/go/rest/opentsdbjson/main.go b/docs-examples/go/rest/opentsdbjson/main.go new file mode 100644 index 0000000000..f4f5792e29 --- /dev/null +++ b/docs-examples/go/rest/opentsdbjson/main.go @@ -0,0 +1,45 @@ +package main + +import ( + "bytes" + "encoding/json" + "fmt" + "net/http" + "time" +) + +type Tags struct { + Location string `json:"location"` + Groupid int32 `json:"groupid"` +} + +type Metric struct { + Metric string `json:"metric"` + Timestamp int64 `json:"timestamp"` + Value int32 `json:"value"` + Tags Tags `json:"tags"` +} + +func main() { + client := http.Client{} + for i := 0; i < 10; i++ { + metric := Metric{"voltage", time.Now().UnixMilli(), 1, Tags{"A", 1}} + json, err := json.Marshal(metric) + if err != nil { + panic(err) + } + req, err := http.NewRequest("POST", "http://localhost:6041/opentsdb/v1/put/json/rest_go", bytes.NewBuffer(json)) + if err != nil { + panic(err) + } + req.Header.Set("Content-Type", "application/json") + req.Header.Set("Authorization", "Basic cm9vdDp0YW9zZGF0YQ==") + resp, err := client.Do(req) + if err != nil { + panic(err) + } + fmt.Printf("%v\n", resp) + time.Sleep(time.Second) + + } +} diff --git a/docs-examples/go/sub/main.go b/docs-examples/go/sub/main.go new file mode 100644 index 0000000000..c44521b340 --- /dev/null +++ b/docs-examples/go/sub/main.go @@ -0,0 +1,53 @@ +package main + +import ( + "database/sql/driver" + "fmt" + "io" + "os" + "time" + + taos "github.com/taosdata/driver-go/v2/af" +) + +func main() { + db, err := taos.Open("", "", "", "log", 0) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + defer db.Close() + topic, err := db.Subscribe(false, "taoslogtail", "select ts, level, ipaddr, content from log", time.Second) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(2) + } + defer topic.Unsubscribe(true) + for { + func() { + rows, err := topic.Consume() + defer func() { rows.Close(); time.Sleep(time.Second) }() + if err != nil { + fmt.Println(err) + os.Exit(3) + } + for { + values := make([]driver.Value, 4) + err := rows.Next(values) + if err == io.EOF { + break + } else if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(4) + } + ts := values[0].(time.Time) + level := values[1].(int8) + ipaddr := values[2].(string) + content := values[3].(string) + fmt.Printf("%s %d %s %s\n", ts.Format(time.StampMilli), level, ipaddr, content) + } + }() + } +} + +// 未完成 diff --git a/docs-examples/java/.gitignore b/docs-examples/java/.gitignore new file mode 100644 index 0000000000..d48c759d6c --- /dev/null +++ b/docs-examples/java/.gitignore @@ -0,0 +1,2 @@ +.idea +.vscode \ No newline at end of file diff --git a/docs-examples/java/pom.xml b/docs-examples/java/pom.xml new file mode 100644 index 0000000000..a48ba398da --- /dev/null +++ b/docs-examples/java/pom.xml @@ -0,0 +1,35 @@ + + + + 4.0.0 + + com.taos + javaexample + 1.0 + + JavaExample + + + UTF-8 + 1.8 + 1.8 + + + + + + com.taosdata.jdbc + taos-jdbcdriver + 2.0.38 + + + + junit + junit + 4.13.1 + test + + + + diff --git a/docs-examples/java/src/main/java/com/taos/example/JNIConnectExample.java b/docs-examples/java/src/main/java/com/taos/example/JNIConnectExample.java new file mode 100644 index 0000000000..c6ce2ef978 --- /dev/null +++ b/docs-examples/java/src/main/java/com/taos/example/JNIConnectExample.java @@ -0,0 +1,25 @@ +package com.taos.example; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.Properties; + +import com.taosdata.jdbc.TSDBDriver; + +public class JNIConnectExample { + public static void main(String[] args) throws SQLException { + String jdbcUrl = "jdbc:TAOS://localhost:6030?user=root&password=taosdata"; + Properties connProps = new Properties(); + connProps.setProperty(TSDBDriver.PROPERTY_KEY_CHARSET, "UTF-8"); + connProps.setProperty(TSDBDriver.PROPERTY_KEY_LOCALE, "en_US.UTF-8"); + connProps.setProperty(TSDBDriver.PROPERTY_KEY_TIME_ZONE, "UTC-8"); + Connection conn = DriverManager.getConnection(jdbcUrl, connProps); + System.out.println("Connected"); + conn.close(); + } +} + +// use +// String jdbcUrl = "jdbc:TAOS://localhost:6030/dbName?user=root&password=taosdata"; +// if you want to connect to a default database. \ No newline at end of file diff --git a/docs-examples/java/src/main/java/com/taos/example/JSONProtocolExample.java b/docs-examples/java/src/main/java/com/taos/example/JSONProtocolExample.java new file mode 100644 index 0000000000..cb83424576 --- /dev/null +++ b/docs-examples/java/src/main/java/com/taos/example/JSONProtocolExample.java @@ -0,0 +1,40 @@ +package com.taos.example; + +import com.taosdata.jdbc.SchemalessWriter; +import com.taosdata.jdbc.enums.SchemalessProtocolType; +import com.taosdata.jdbc.enums.SchemalessTimestampType; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.sql.Statement; + +public class JSONProtocolExample { + private static Connection getConnection() throws SQLException { + String jdbcUrl = "jdbc:TAOS://localhost:6030?user=root&password=taosdata"; + return DriverManager.getConnection(jdbcUrl); + } + + private static void createDatabase(Connection conn) throws SQLException { + try (Statement stmt = conn.createStatement()) { + stmt.execute("CREATE DATABASE IF NOT EXISTS test"); + stmt.execute("USE test"); + } + } + + private static String getJSONData() { + return "[{\"metric\": \"meters.current\", \"timestamp\": 1648432611249, \"value\": 10.3, \"tags\": {\"location\": \"Beijing.Chaoyang\", \"groupid\": 2}}," + + " {\"metric\": \"meters.voltage\", \"timestamp\": 1648432611249, \"value\": 219, \"tags\": {\"location\": \"Beijing.Haidian\", \"groupid\": 1}}, " + + "{\"metric\": \"meters.current\", \"timestamp\": 1648432611250, \"value\": 12.6, \"tags\": {\"location\": \"Beijing.Chaoyang\", \"groupid\": 2}}," + + " {\"metric\": \"meters.voltage\", \"timestamp\": 1648432611250, \"value\": 221, \"tags\": {\"location\": \"Beijing.Haidian\", \"groupid\": 1}}]"; + } + + public static void main(String[] args) throws SQLException { + try (Connection conn = getConnection()) { + createDatabase(conn); + SchemalessWriter writer = new SchemalessWriter(conn); + String jsonData = getJSONData(); + writer.write(jsonData, SchemalessProtocolType.JSON, SchemalessTimestampType.NOT_CONFIGURED); + } + } +} diff --git a/docs-examples/java/src/main/java/com/taos/example/LineProtocolExample.java b/docs-examples/java/src/main/java/com/taos/example/LineProtocolExample.java new file mode 100644 index 0000000000..8a2eabe0a9 --- /dev/null +++ b/docs-examples/java/src/main/java/com/taos/example/LineProtocolExample.java @@ -0,0 +1,42 @@ +package com.taos.example; + +import com.taosdata.jdbc.SchemalessWriter; +import com.taosdata.jdbc.enums.SchemalessProtocolType; +import com.taosdata.jdbc.enums.SchemalessTimestampType; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.sql.Statement; + +public class LineProtocolExample { + // format: measurement,tag_set field_set timestamp + private static String[] lines = { + "meters,location=Beijing.Haidian,groupid=2 current=11.8,voltage=221,phase=0.28 1648432611249000", // micro + // seconds + "meters,location=Beijing.Haidian,groupid=2 current=13.4,voltage=223,phase=0.29 1648432611249500", + "meters,location=Beijing.Haidian,groupid=3 current=10.8,voltage=223,phase=0.29 1648432611249300", + "meters,location=Beijing.Haidian,groupid=3 current=11.3,voltage=221,phase=0.35 1648432611249800", + }; + + private static Connection getConnection() throws SQLException { + String jdbcUrl = "jdbc:TAOS://localhost:6030?user=root&password=taosdata"; + return DriverManager.getConnection(jdbcUrl); + } + + private static void createDatabase(Connection conn) throws SQLException { + try (Statement stmt = conn.createStatement()) { + // the default precision is ms (microsecond), but we use us(microsecond) here. + stmt.execute("CREATE DATABASE IF NOT EXISTS test PRECISION 'us'"); + stmt.execute("USE test"); + } + } + + public static void main(String[] args) throws SQLException { + try (Connection conn = getConnection()) { + createDatabase(conn); + SchemalessWriter writer = new SchemalessWriter(conn); + writer.write(lines, SchemalessProtocolType.LINE, SchemalessTimestampType.MICRO_SECONDS); + } + } +} diff --git a/docs-examples/java/src/main/java/com/taos/example/RESTConnectExample.java b/docs-examples/java/src/main/java/com/taos/example/RESTConnectExample.java new file mode 100644 index 0000000000..9d077812e0 --- /dev/null +++ b/docs-examples/java/src/main/java/com/taos/example/RESTConnectExample.java @@ -0,0 +1,16 @@ +package com.taos.example; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; + +public class RESTConnectExample { + // ANCHOR: main + public static void main(String[] args) throws SQLException { + String jdbcUrl = "jdbc:TAOS-RS://localhost:6041?user=root&password=taosdata"; + Connection conn = DriverManager.getConnection(jdbcUrl); + System.out.println("Connected"); + conn.close(); + } + // ANCHOR_END: main +} \ No newline at end of file diff --git a/docs-examples/java/src/main/java/com/taos/example/RestInsertExample.java b/docs-examples/java/src/main/java/com/taos/example/RestInsertExample.java new file mode 100644 index 0000000000..de89f26cbe --- /dev/null +++ b/docs-examples/java/src/main/java/com/taos/example/RestInsertExample.java @@ -0,0 +1,74 @@ +package com.taos.example; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Arrays; +import java.util.List; + + +public class RestInsertExample { + private static Connection getConnection() throws SQLException { + String jdbcUrl = "jdbc:TAOS-RS://localhost:6041?user=root&password=taosdata"; + return DriverManager.getConnection(jdbcUrl); + } + + private static List getRawData() { + return Arrays.asList( + "d1001,2018-10-03 14:38:05.000,10.30000,219,0.31000,Beijing.Chaoyang,2", + "d1001,2018-10-03 14:38:15.000,12.60000,218,0.33000,Beijing.Chaoyang,2", + "d1001,2018-10-03 14:38:16.800,12.30000,221,0.31000,Beijing.Chaoyang,2", + "d1002,2018-10-03 14:38:16.650,10.30000,218,0.25000,Beijing.Chaoyang,3", + "d1003,2018-10-03 14:38:05.500,11.80000,221,0.28000,Beijing.Haidian,2", + "d1003,2018-10-03 14:38:16.600,13.40000,223,0.29000,Beijing.Haidian,2", + "d1004,2018-10-03 14:38:05.000,10.80000,223,0.29000,Beijing.Haidian,3", + "d1004,2018-10-03 14:38:06.500,11.50000,221,0.35000,Beijing.Haidian,3" + ); + } + + + /** + * The generated SQL is: + * INSERT INTO power.d1001 USING power.meters TAGS(Beijing.Chaoyang, 2) VALUES('2018-10-03 14:38:05.000',10.30000,219,0.31000) + * power.d1001 USING power.meters TAGS(Beijing.Chaoyang, 2) VALUES('2018-10-03 14:38:15.000',12.60000,218,0.33000) + * power.d1001 USING power.meters TAGS(Beijing.Chaoyang, 2) VALUES('2018-10-03 14:38:16.800',12.30000,221,0.31000) + * power.d1002 USING power.meters TAGS(Beijing.Chaoyang, 3) VALUES('2018-10-03 14:38:16.650',10.30000,218,0.25000) + * power.d1003 USING power.meters TAGS(Beijing.Haidian, 2) VALUES('2018-10-03 14:38:05.500',11.80000,221,0.28000) + * power.d1003 USING power.meters TAGS(Beijing.Haidian, 2) VALUES('2018-10-03 14:38:16.600',13.40000,223,0.29000) + * power.d1004 USING power.meters TAGS(Beijing.Haidian, 3) VALUES('2018-10-03 14:38:05.000',10.80000,223,0.29000) + * power.d1004 USING power.meters TAGS(Beijing.Haidian, 3) VALUES('2018-10-03 14:38:06.500',11.50000,221,0.35000) + */ + private static String getSQL() { + StringBuilder sb = new StringBuilder("INSERT INTO "); + for (String line : getRawData()) { + String[] ps = line.split(","); + sb.append("power." + ps[0]).append(" USING power.meters TAGS(") + .append(ps[5]).append(", ") // tag: location + .append(ps[6]) // tag: groupId + .append(") VALUES(") + .append('\'').append(ps[1]).append('\'').append(",") // ts + .append(ps[2]).append(",") // current + .append(ps[3]).append(",") // voltage + .append(ps[4]).append(") "); // phase + } + return sb.toString(); + } + + public static void insertData() throws SQLException { + try (Connection conn = getConnection()) { + try (Statement stmt = conn.createStatement()) { + stmt.execute("CREATE DATABASE power KEEP 3650"); + stmt.execute("CREATE STABLE power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) " + + "TAGS (location BINARY(64), groupId INT)"); + String sql = getSQL(); + int rowCount = stmt.executeUpdate(sql); + System.out.println("rowCount=" + rowCount); // rowCount=8 + } + } + } + + public static void main(String[] args) throws SQLException { + insertData(); + } +} diff --git a/docs-examples/java/src/main/java/com/taos/example/RestQueryExample.java b/docs-examples/java/src/main/java/com/taos/example/RestQueryExample.java new file mode 100644 index 0000000000..b1a1d224c6 --- /dev/null +++ b/docs-examples/java/src/main/java/com/taos/example/RestQueryExample.java @@ -0,0 +1,55 @@ +package com.taos.example; + +import java.sql.*; + +public class RestQueryExample { + private static Connection getConnection() throws SQLException { + String jdbcUrl = "jdbc:TAOS-RS://localhost:6041/power?user=root&password=taosdata"; + return DriverManager.getConnection(jdbcUrl); + } + + private static void printRow(ResultSet rs) throws SQLException { + ResultSetMetaData meta = rs.getMetaData(); + for (int i = 1; i <= meta.getColumnCount(); i++) { + String value = rs.getString(i); + System.out.print(value); + System.out.print("\t"); + } + System.out.println(); + } + + private static void printColName(ResultSet rs) throws SQLException { + ResultSetMetaData meta = rs.getMetaData(); + for (int i = 1; i <= meta.getColumnCount(); i++) { + String colLabel = meta.getColumnLabel(i); + System.out.print(colLabel); + System.out.print("\t"); + } + System.out.println(); + } + + private static void processResult(ResultSet rs) throws SQLException { + printColName(rs); + while (rs.next()) { + printRow(rs); + } + } + + private static void queryData() throws SQLException { + try (Connection conn = getConnection()) { + try (Statement stmt = conn.createStatement()) { + ResultSet rs = stmt.executeQuery("SELECT AVG(voltage) FROM meters GROUP BY location"); + processResult(rs); + } + } + } + + public static void main(String[] args) throws SQLException { + queryData(); + } +} + +// possible output: +// avg(voltage) location +// 222.0 Beijing.Haidian +// 219.0 Beijing.Chaoyang diff --git a/docs-examples/java/src/main/java/com/taos/example/StmtInsertExample.java b/docs-examples/java/src/main/java/com/taos/example/StmtInsertExample.java new file mode 100644 index 0000000000..2a7ccebf41 --- /dev/null +++ b/docs-examples/java/src/main/java/com/taos/example/StmtInsertExample.java @@ -0,0 +1,84 @@ +package com.taos.example; + +import com.taosdata.jdbc.TSDBPreparedStatement; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.sql.Statement; +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class StmtInsertExample { + private static ArrayList tsToLongArray(String ts) { + ArrayList result = new ArrayList<>(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"); + LocalDateTime localDateTime = LocalDateTime.parse(ts, formatter); + result.add(localDateTime.toInstant(ZoneOffset.of("+8")).toEpochMilli()); + return result; + } + + private static ArrayList toArray(T v) { + ArrayList result = new ArrayList<>(); + result.add(v); + return result; + } + + private static List getRawData() { + return Arrays.asList( + "d1001,2018-10-03 14:38:05.000,10.30000,219,0.31000,Beijing.Chaoyang,2", + "d1001,2018-10-03 14:38:15.000,12.60000,218,0.33000,Beijing.Chaoyang,2", + "d1001,2018-10-03 14:38:16.800,12.30000,221,0.31000,Beijing.Chaoyang,2", + "d1002,2018-10-03 14:38:16.650,10.30000,218,0.25000,Beijing.Chaoyang,3", + "d1003,2018-10-03 14:38:05.500,11.80000,221,0.28000,Beijing.Haidian,2", + "d1003,2018-10-03 14:38:16.600,13.40000,223,0.29000,Beijing.Haidian,2", + "d1004,2018-10-03 14:38:05.000,10.80000,223,0.29000,Beijing.Haidian,3", + "d1004,2018-10-03 14:38:06.500,11.50000,221,0.35000,Beijing.Haidian,3" + ); + } + + private static Connection getConnection() throws SQLException { + String jdbcUrl = "jdbc:TAOS://localhost:6030?user=root&password=taosdata"; + return DriverManager.getConnection(jdbcUrl); + } + + private static void createTable(Connection conn) throws SQLException { + try (Statement stmt = conn.createStatement()) { + stmt.execute("CREATE DATABASE power KEEP 3650"); + stmt.executeUpdate("USE power"); + stmt.execute("CREATE STABLE meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) " + + "TAGS (location BINARY(64), groupId INT)"); + } + } + + private static void insertData() throws SQLException { + try (Connection conn = getConnection()) { + createTable(conn); + String psql = "INSERT INTO ? USING meters TAGS(?, ?) VALUES(?, ?, ?, ?)"; + try (TSDBPreparedStatement pst = (TSDBPreparedStatement) conn.prepareStatement(psql)) { + for (String line : getRawData()) { + String[] ps = line.split(","); + // bind table name and tags + pst.setTableName(ps[0]); + pst.setTagString(0, ps[5]); + pst.setTagInt(1, Integer.valueOf(ps[6])); + // bind values + pst.setTimestamp(0, tsToLongArray(ps[1])); //ps[1] looks like: 2018-10-03 14:38:05.000 + pst.setFloat(1, toArray(Float.valueOf(ps[2]))); + pst.setInt(2, toArray(Integer.valueOf(ps[3]))); + pst.setFloat(3, toArray(Float.valueOf(ps[4]))); + pst.columnDataAddBatch(); + } + pst.columnDataExecuteBatch(); + } + } + } + + public static void main(String[] args) throws SQLException { + insertData(); + } +} diff --git a/docs-examples/java/src/main/java/com/taos/example/SubscribeDemo.java b/docs-examples/java/src/main/java/com/taos/example/SubscribeDemo.java new file mode 100644 index 0000000000..d82d03b9de --- /dev/null +++ b/docs-examples/java/src/main/java/com/taos/example/SubscribeDemo.java @@ -0,0 +1,65 @@ +package com.taos.example; + +import com.taosdata.jdbc.TSDBConnection; +import com.taosdata.jdbc.TSDBDriver; +import com.taosdata.jdbc.TSDBResultSet; +import com.taosdata.jdbc.TSDBSubscribe; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.util.Properties; +import java.util.concurrent.TimeUnit; + +public class SubscribeDemo { + private static final String topic = "topic-meter-current-bg-10"; + private static final String sql = "select * from meters where current > 10"; + + public static void main(String[] args) { + Connection connection = null; + TSDBSubscribe subscribe = null; + + try { + Class.forName("com.taosdata.jdbc.TSDBDriver"); + Properties properties = new Properties(); + properties.setProperty(TSDBDriver.PROPERTY_KEY_CHARSET, "UTF-8"); + properties.setProperty(TSDBDriver.PROPERTY_KEY_TIME_ZONE, "UTC-8"); + String jdbcUrl = "jdbc:TAOS://127.0.0.1:6030/power?user=root&password=taosdata"; + connection = DriverManager.getConnection(jdbcUrl, properties); + // create subscribe + subscribe = ((TSDBConnection) connection).subscribe(topic, sql, true); + int count = 0; + while (count < 10) { + // wait 1 second to avoid frequent calls to consume + TimeUnit.SECONDS.sleep(1); + // consume + TSDBResultSet resultSet = subscribe.consume(); + if (resultSet == null) { + continue; + } + ResultSetMetaData metaData = resultSet.getMetaData(); + while (resultSet.next()) { + int columnCount = metaData.getColumnCount(); + for (int i = 1; i <= columnCount; i++) { + System.out.print(metaData.getColumnLabel(i) + ": " + resultSet.getString(i) + "\t"); + } + System.out.println(); + count++; + } + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + try { + if (null != subscribe) + // close subscribe + subscribe.close(true); + if (connection != null) + connection.close(); + } catch (SQLException throwable) { + throwable.printStackTrace(); + } + } + } +} \ No newline at end of file diff --git a/docs-examples/java/src/main/java/com/taos/example/TelnetLineProtocolExample.java b/docs-examples/java/src/main/java/com/taos/example/TelnetLineProtocolExample.java new file mode 100644 index 0000000000..1431eccf16 --- /dev/null +++ b/docs-examples/java/src/main/java/com/taos/example/TelnetLineProtocolExample.java @@ -0,0 +1,45 @@ +package com.taos.example; + +import com.taosdata.jdbc.SchemalessWriter; +import com.taosdata.jdbc.enums.SchemalessProtocolType; +import com.taosdata.jdbc.enums.SchemalessTimestampType; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.sql.Statement; + +public class TelnetLineProtocolExample { + // format: =[ =] + private static String[] lines = { "meters.current 1648432611249 10.3 location=Beijing.Chaoyang groupid=2", + "meters.current 1648432611250 12.6 location=Beijing.Chaoyang groupid=2", + "meters.current 1648432611249 10.8 location=Beijing.Haidian groupid=3", + "meters.current 1648432611250 11.3 location=Beijing.Haidian groupid=3", + "meters.voltage 1648432611249 219 location=Beijing.Chaoyang groupid=2", + "meters.voltage 1648432611250 218 location=Beijing.Chaoyang groupid=2", + "meters.voltage 1648432611249 221 location=Beijing.Haidian groupid=3", + "meters.voltage 1648432611250 217 location=Beijing.Haidian groupid=3", + }; + + private static Connection getConnection() throws SQLException { + String jdbcUrl = "jdbc:TAOS://localhost:6030?user=root&password=taosdata"; + return DriverManager.getConnection(jdbcUrl); + } + + private static void createDatabase(Connection conn) throws SQLException { + try (Statement stmt = conn.createStatement()) { + // the default precision is ms (microsecond), but we use us(microsecond) here. + stmt.execute("CREATE DATABASE IF NOT EXISTS test precision 'us'"); + stmt.execute("USE test"); + } + } + + public static void main(String[] args) throws SQLException { + try (Connection conn = getConnection()) { + createDatabase(conn); + SchemalessWriter writer = new SchemalessWriter(conn); + writer.write(lines, SchemalessProtocolType.TELNET, SchemalessTimestampType.NOT_CONFIGURED); + } + } + +} diff --git a/docs-examples/java/src/main/java/com/taos/example/WSConnectExample.java b/docs-examples/java/src/main/java/com/taos/example/WSConnectExample.java new file mode 100644 index 0000000000..48d1dde593 --- /dev/null +++ b/docs-examples/java/src/main/java/com/taos/example/WSConnectExample.java @@ -0,0 +1,21 @@ +package com.taos.example; + +import com.taosdata.jdbc.TSDBDriver; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.Properties; + +public class WSConnectExample { + // ANCHOR: main + public static void main(String[] args) throws SQLException { + String jdbcUrl = "jdbc:TAOS-RS://localhost:6041?user=root&password=taosdata"; + Properties connProps = new Properties(); + connProps.setProperty(TSDBDriver.PROPERTY_KEY_BATCH_LOAD, "true"); + Connection conn = DriverManager.getConnection(jdbcUrl, connProps); + System.out.println("Connected"); + conn.close(); + } + // ANCHOR_END: main +} diff --git a/docs-examples/java/src/test/java/com/taos/test/TestAll.java b/docs-examples/java/src/test/java/com/taos/test/TestAll.java new file mode 100644 index 0000000000..92fe14a49d --- /dev/null +++ b/docs-examples/java/src/test/java/com/taos/test/TestAll.java @@ -0,0 +1,91 @@ +package com.taos.test; + +import com.taos.example.*; +import org.junit.FixMethodOrder; +import org.junit.Test; + +import java.sql.*; + +@FixMethodOrder +public class TestAll { + private String[] args = new String[]{}; + + public void dropDB(String dbName) throws SQLException { + String jdbcUrl = "jdbc:TAOS://localhost:6030?user=root&password=taosdata"; + try (Connection conn = DriverManager.getConnection(jdbcUrl)) { + try (Statement stmt = conn.createStatement()) { + stmt.execute("drop database if exists " + dbName); + } + } + } + + public void insertData() throws SQLException { + String jdbcUrl = "jdbc:TAOS://localhost:6030?user=root&password=taosdata"; + try (Connection conn = DriverManager.getConnection(jdbcUrl)) { + try (Statement stmt = conn.createStatement()) { + String sql = "INSERT INTO power.d1001 USING power.meters TAGS(Beijing.Chaoyang, 2) VALUES('2018-10-03 14:38:05.000',10.30000,219,0.31000)\n" + + " power.d1001 USING power.meters TAGS(Beijing.Chaoyang, 2) VALUES('2018-10-03 15:38:15.000',12.60000,218,0.33000)\n" + + " power.d1001 USING power.meters TAGS(Beijing.Chaoyang, 2) VALUES('2018-10-03 15:38:16.800',12.30000,221,0.31000)\n" + + " power.d1002 USING power.meters TAGS(Beijing.Chaoyang, 3) VALUES('2018-10-03 15:38:16.650',10.30000,218,0.25000)\n" + + " power.d1003 USING power.meters TAGS(Beijing.Haidian, 2) VALUES('2018-10-03 15:38:05.500',11.80000,221,0.28000)\n" + + " power.d1003 USING power.meters TAGS(Beijing.Haidian, 2) VALUES('2018-10-03 15:38:16.600',13.40000,223,0.29000)\n" + + " power.d1004 USING power.meters TAGS(Beijing.Haidian, 3) VALUES('2018-10-03 15:38:05.000',10.80000,223,0.29000)\n" + + " power.d1004 USING power.meters TAGS(Beijing.Haidian, 3) VALUES('2018-10-03 15:38:06.000',10.80000,223,0.29000)\n" + + " power.d1004 USING power.meters TAGS(Beijing.Haidian, 3) VALUES('2018-10-03 15:38:07.000',10.80000,223,0.29000)\n" + + " power.d1004 USING power.meters TAGS(Beijing.Haidian, 3) VALUES('2018-10-03 15:38:08.500',11.50000,221,0.35000)"; + + stmt.execute(sql); + } + } + } + + @Test + public void testJNIConnect() throws SQLException { + JNIConnectExample.main(args); + } + + @Test + public void testRestConnect() throws SQLException { + RESTConnectExample.main(args); + } + + @Test + public void testRestInsert() throws SQLException { + dropDB("power"); + RestInsertExample.main(args); + RestQueryExample.main(args); + } + + @Test + public void testStmtInsert() throws SQLException { + dropDB("power"); + StmtInsertExample.main(args); + } + + @Test + public void testSubscribe() { + + Thread thread = new Thread(() -> { + try { + Thread.sleep(1000); + insertData(); + } catch (SQLException e) { + e.printStackTrace(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + }); + thread.start(); + SubscribeDemo.main(args); + } + + @Test + public void testSchemaless() throws SQLException { + LineProtocolExample.main(args); + TelnetLineProtocolExample.main(args); + // for json protocol, tags may be double type. but for telnet protocol tag must be nchar type. + // To avoid type mismatch, we delete database test. + dropDB("test"); + JSONProtocolExample.main(args); + } +} diff --git a/docs-examples/node/.gitignore b/docs-examples/node/.gitignore new file mode 100644 index 0000000000..1071ed2b9f --- /dev/null +++ b/docs-examples/node/.gitignore @@ -0,0 +1,3 @@ +node_modules +package-lock.json +yarn-lock.json \ No newline at end of file diff --git a/docs-examples/node/nativeexample/async_query_example.js b/docs-examples/node/nativeexample/async_query_example.js new file mode 100644 index 0000000000..25b78bc48a --- /dev/null +++ b/docs-examples/node/nativeexample/async_query_example.js @@ -0,0 +1,21 @@ +const taos = require("td2.0-connector"); +const conn = taos.connect({ host: "localhost", database: "power" }); +const cursor = conn.cursor(); + +function queryExample() { + cursor + .query("SELECT ts, current FROM meters LIMIT 2") + .execute_a() + .then((result) => { + result.pretty(); + }); +} + +try { + queryExample(); +} finally { + setTimeout(() => { + conn.close(); + }, 2000); +} +// bug here: jira 14506 diff --git a/docs-examples/node/nativeexample/connect.js b/docs-examples/node/nativeexample/connect.js new file mode 100644 index 0000000000..da791c566e --- /dev/null +++ b/docs-examples/node/nativeexample/connect.js @@ -0,0 +1,13 @@ +const taos = require("td2.0-connector"); + +var conn = taos.connect({ + host: "localhost", + port: 6030, + user: "root", + password: "taosdata", +}); +conn.close(); + +// run with: node connect.js +// output: +// Successfully connected to TDengine diff --git a/docs-examples/node/nativeexample/influxdb_line_example.js b/docs-examples/node/nativeexample/influxdb_line_example.js new file mode 100644 index 0000000000..a9fc6d11df --- /dev/null +++ b/docs-examples/node/nativeexample/influxdb_line_example.js @@ -0,0 +1,34 @@ +const taos = require("td2.0-connector"); + +const conn = taos.connect({ + host: "localhost", +}); + +const cursor = conn.cursor(); + +function createDatabase() { + cursor.execute("CREATE DATABASE test"); + cursor.execute("USE test"); +} + +function insertData() { + const lines = [ + "meters,location=Beijing.Haidian,groupid=2 current=11.8,voltage=221,phase=0.28 1648432611249", + "meters,location=Beijing.Haidian,groupid=2 current=13.4,voltage=223,phase=0.29 1648432611250", + "meters,location=Beijing.Haidian,groupid=3 current=10.8,voltage=223,phase=0.29 1648432611249", + "meters,location=Beijing.Haidian,groupid=3 current=11.3,voltage=221,phase=0.35 1648432611250", + ]; + cursor.schemalessInsert( + lines, + taos.SCHEMALESS_PROTOCOL.TSDB_SML_LINE_PROTOCOL, + taos.SCHEMALESS_PRECISION.TSDB_SML_TIMESTAMP_MILLI_SECONDS + ); +} + +try { + createDatabase(); + insertData(); +} finally { + cursor.close(); + conn.close(); +} diff --git a/docs-examples/node/nativeexample/insert_example.js b/docs-examples/node/nativeexample/insert_example.js new file mode 100644 index 0000000000..85a353f889 --- /dev/null +++ b/docs-examples/node/nativeexample/insert_example.js @@ -0,0 +1,31 @@ +const taos = require("td2.0-connector"); + +const conn = taos.connect({ + host: "localhost", +}); + +const cursor = conn.cursor(); +try { + cursor.execute("CREATE DATABASE power"); + cursor.execute("USE power"); + cursor.execute( + "CREATE STABLE meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (location BINARY(64), groupId INT)" + ); + var sql = `INSERT INTO power.d1001 USING power.meters TAGS(Beijing.Chaoyang, 2) VALUES ('2018-10-03 14:38:05.000', 10.30000, 219, 0.31000) ('2018-10-03 14:38:15.000', 12.60000, 218, 0.33000) ('2018-10-03 14:38:16.800', 12.30000, 221, 0.31000) +power.d1002 USING power.meters TAGS(Beijing.Chaoyang, 3) VALUES ('2018-10-03 14:38:16.650', 10.30000, 218, 0.25000) +power.d1003 USING power.meters TAGS(Beijing.Haidian, 2) VALUES ('2018-10-03 14:38:05.500', 11.80000, 221, 0.28000) ('2018-10-03 14:38:16.600', 13.40000, 223, 0.29000) +power.d1004 USING power.meters TAGS(Beijing.Haidian, 3) VALUES ('2018-10-03 14:38:05.000', 10.80000, 223, 0.29000) ('2018-10-03 14:38:06.500', 11.50000, 221, 0.35000)`; + cursor.execute(sql); +} finally { + cursor.close(); + conn.close(); +} + +// run with: node insert_example.js +// output: +// Successfully connected to TDengine +// Query OK, 0 row(s) affected (0.00509570s) +// Query OK, 0 row(s) affected (0.00130880s) +// Query OK, 0 row(s) affected (0.00467900s) +// Query OK, 8 row(s) affected (0.04043550s) +// Connection is closed diff --git a/docs-examples/node/nativeexample/multi_bind_example.js b/docs-examples/node/nativeexample/multi_bind_example.js new file mode 100644 index 0000000000..d52581ec8e --- /dev/null +++ b/docs-examples/node/nativeexample/multi_bind_example.js @@ -0,0 +1,53 @@ +const taos = require("td2.0-connector"); + +const conn = taos.connect({ + host: "localhost", +}); + +const cursor = conn.cursor(); + +function prepareSTable() { + cursor.execute("CREATE DATABASE power"); + cursor.execute("USE power"); + cursor.execute( + "CREATE STABLE meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (location BINARY(64), groupId INT)" + ); +} + +//ANCHOR: insertData +function insertData() { + // init + cursor.stmtInit(); + // prepare + cursor.stmtPrepare( + "INSERT INTO ? USING meters TAGS(?, ?) VALUES(?, ?, ?, ?)" + ); + + // bind table name and tags + let tagBind = new taos.TaosBind(2); + tagBind.bindBinary("Beijing.Chaoyang"); + tagBind.bindInt(2); + cursor.stmtSetTbnameTags("d1001", tagBind.getBind()); + + // bind values + let valueBind = new taos.TaosMultiBindArr(4); + valueBind.multiBindTimestamp([1648432611249, 1648432611749]); + valueBind.multiBindFloat([10.3, 12.6]); + valueBind.multiBindInt([219, 218]); + valueBind.multiBindFloat([0.31, 0.33]); + cursor.stmtBindParamBatch(valueBind.getMultiBindArr()); + cursor.stmtAddBatch(); + + // execute + cursor.stmtExecute(); + cursor.stmtClose(); +} +//ANCHOR_END: insertData + +try { + prepareSTable(); + insertData(); +} finally { + cursor.close(); + conn.close(); +} diff --git a/docs-examples/node/nativeexample/opentsdb_json_example.js b/docs-examples/node/nativeexample/opentsdb_json_example.js new file mode 100644 index 0000000000..6d436a8e9e --- /dev/null +++ b/docs-examples/node/nativeexample/opentsdb_json_example.js @@ -0,0 +1,55 @@ +const taos = require("td2.0-connector"); + +const conn = taos.connect({ + host: "localhost", +}); + +const cursor = conn.cursor(); + +function createDatabase() { + cursor.execute("CREATE DATABASE test"); + cursor.execute("USE test"); +} + +function insertData() { + const lines = [ + { + metric: "meters.current", + timestamp: 1648432611249, + value: 10.3, + tags: { location: "Beijing.Chaoyang", groupid: 2 }, + }, + { + metric: "meters.voltage", + timestamp: 1648432611249, + value: 219, + tags: { location: "Beijing.Haidian", groupid: 1 }, + }, + { + metric: "meters.current", + timestamp: 1648432611250, + value: 12.6, + tags: { location: "Beijing.Chaoyang", groupid: 2 }, + }, + { + metric: "meters.voltage", + timestamp: 1648432611250, + value: 221, + tags: { location: "Beijing.Haidian", groupid: 1 }, + }, + ]; + + cursor.schemalessInsert( + [JSON.stringify(lines)], + taos.SCHEMALESS_PROTOCOL.TSDB_SML_JSON_PROTOCOL, + taos.SCHEMALESS_PRECISION.TSDB_SML_TIMESTAMP_NOT_CONFIGURED + ); +} + +try { + createDatabase(); + insertData(); +} finally { + cursor.close(); + conn.close(); +} diff --git a/docs-examples/node/nativeexample/opentsdb_telnet_example.js b/docs-examples/node/nativeexample/opentsdb_telnet_example.js new file mode 100644 index 0000000000..01e79c2dca --- /dev/null +++ b/docs-examples/node/nativeexample/opentsdb_telnet_example.js @@ -0,0 +1,38 @@ +const taos = require("td2.0-connector"); + +const conn = taos.connect({ + host: "localhost", +}); + +const cursor = conn.cursor(); + +function createDatabase() { + cursor.execute("CREATE DATABASE test"); + cursor.execute("USE test"); +} + +function insertData() { + const lines = [ + "meters.current 1648432611249 10.3 location=Beijing.Chaoyang groupid=2", + "meters.current 1648432611250 12.6 location=Beijing.Chaoyang groupid=2", + "meters.current 1648432611249 10.8 location=Beijing.Haidian groupid=3", + "meters.current 1648432611250 11.3 location=Beijing.Haidian groupid=3", + "meters.voltage 1648432611249 219 location=Beijing.Chaoyang groupid=2", + "meters.voltage 1648432611250 218 location=Beijing.Chaoyang groupid=2", + "meters.voltage 1648432611249 221 location=Beijing.Haidian groupid=3", + "meters.voltage 1648432611250 217 location=Beijing.Haidian groupid=3", + ]; + cursor.schemalessInsert( + lines, + taos.SCHEMALESS_PROTOCOL.TSDB_SML_TELNET_PROTOCOL, + taos.SCHEMALESS_PRECISION.TSDB_SML_TIMESTAMP_NOT_CONFIGURED + ); +} + +try { + createDatabase(); + insertData(); +} finally { + cursor.close(); + conn.close(); +} diff --git a/docs-examples/node/nativeexample/param_bind_example.js b/docs-examples/node/nativeexample/param_bind_example.js new file mode 100644 index 0000000000..9117f46c3e --- /dev/null +++ b/docs-examples/node/nativeexample/param_bind_example.js @@ -0,0 +1,57 @@ +const taos = require("td2.0-connector"); + +const conn = taos.connect({ + host: "localhost", +}); + +const cursor = conn.cursor(); + +function prepareSTable() { + cursor.execute("CREATE DATABASE power"); + cursor.execute("USE power"); + cursor.execute( + "CREATE STABLE meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (location BINARY(64), groupId INT)" + ); +} + +function insertData() { + // init + cursor.stmtInit(); + // prepare + cursor.stmtPrepare( + "INSERT INTO ? USING meters TAGS(?, ?) VALUES(?, ?, ?, ?)" + ); + + // bind table name and tags + let tagBind = new taos.TaosBind(2); + tagBind.bindBinary("Beijing.Chaoyang"); + tagBind.bindInt(2); + cursor.stmtSetTbnameTags("d1001", tagBind.getBind()); + + // bind values + let rows = [ + [1648432611249, 10.3, 219, 0.31], + [1648432611749, 12.6, 218, 0.33], + ]; + for (let row of rows) { + let valueBind = new taos.TaosBind(4); + valueBind.bindTimestamp(row[0]); + valueBind.bindFloat(row[1]); + valueBind.bindInt(row[2]); + valueBind.bindFloat(row[3]); + cursor.stmtBindParam(valueBind.getBind()); + cursor.stmtAddBatch(); + } + + // execute + cursor.stmtExecute(); + cursor.stmtClose(); +} + +try { + prepareSTable(); + insertData(); +} finally { + cursor.close(); + conn.close(); +} diff --git a/docs-examples/node/nativeexample/query_example.js b/docs-examples/node/nativeexample/query_example.js new file mode 100644 index 0000000000..a51bc939ae --- /dev/null +++ b/docs-examples/node/nativeexample/query_example.js @@ -0,0 +1,17 @@ +const taos = require("td2.0-connector"); + +const conn = taos.connect({ host: "localhost", database: "power" }); +const cursor = conn.cursor(); +const query = cursor.query("SELECT ts, current FROM meters LIMIT 2"); +query.execute().then(function (result) { + result.pretty(); +}); + +// output: +// Successfully connected to TDengine +// Query OK, 2 row(s) in set (0.00317767s) + +// ts | current | +// ======================================================= +// 2018-10-03 14:38:05.000 | 10.3 | +// 2018-10-03 14:38:15.000 | 12.6 | diff --git a/docs-examples/node/nativeexample/subscribe_demo.js b/docs-examples/node/nativeexample/subscribe_demo.js new file mode 100644 index 0000000000..bdf0c98687 --- /dev/null +++ b/docs-examples/node/nativeexample/subscribe_demo.js @@ -0,0 +1,4 @@ +const taos = require("td2.0-connector"); + +const conn = taos.connect({ host: "localhost", database: "power" }); +// 未完成 \ No newline at end of file diff --git a/docs-examples/node/package.json b/docs-examples/node/package.json new file mode 100644 index 0000000000..f56196d2e5 --- /dev/null +++ b/docs-examples/node/package.json @@ -0,0 +1,10 @@ +{ + "name": "examples", + "version": "1.0.0", + "main": "index.js", + "license": "MIT", + "dependencies": { + "td2.0-connector": "^2.0.12", + "td2.0-rest-connector": "^1.0.0" + } +} diff --git a/docs-examples/node/restexample/connect.js b/docs-examples/node/restexample/connect.js new file mode 100644 index 0000000000..b84ce2fadf --- /dev/null +++ b/docs-examples/node/restexample/connect.js @@ -0,0 +1,20 @@ +const { options, connect } = require("td2.0-rest-connector"); + +async function test() { + options.path = "/rest/sqlt"; + options.host = "localhost"; + let conn = connect(options); + let cursor = conn.cursor(); + try { + let res = await cursor.query("SELECT server_version()"); + res.toString(); + } catch (err) { + console.log(err); + } +} +test(); + +// output: +// server_version() | +// =================== +// 2.4.0.12 | diff --git a/docs-examples/php/connect.php b/docs-examples/php/connect.php new file mode 100644 index 0000000000..5af77b9768 --- /dev/null +++ b/docs-examples/php/connect.php @@ -0,0 +1,20 @@ +connect(); +} catch (TDengineException $e) { + // 连接失败捕获异常 + throw $e; +} diff --git a/docs-examples/php/insert.php b/docs-examples/php/insert.php new file mode 100644 index 0000000000..0d9cfc4843 --- /dev/null +++ b/docs-examples/php/insert.php @@ -0,0 +1,33 @@ +connect(); + + // 插入 + $connection->query('CREATE DATABASE if not exists power'); + $connection->query('CREATE STABLE if not exists meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (location BINARY(64), groupId INT)'); + $resource = $connection->query(<<<'SQL' + INSERT INTO power.d1001 USING power.meters TAGS(Beijing.Chaoyang, 2) VALUES ('2018-10-03 14:38:05.000', 10.30000, 219, 0.31000) ('2018-10-03 14:38:15.000', 12.60000, 218, 0.33000) ('2018-10-03 14:38:16.800', 12.30000, 221, 0.31000) + power.d1002 USING power.meters TAGS(Beijing.Chaoyang, 3) VALUES ('2018-10-03 14:38:16.650', 10.30000, 218, 0.25000) + power.d1003 USING power.meters TAGS(Beijing.Haidian, 2) VALUES ('2018-10-03 14:38:05.500', 11.80000, 221, 0.28000) ('2018-10-03 14:38:16.600', 13.40000, 223, 0.29000) + power.d1004 USING power.meters TAGS(Beijing.Haidian, 3) VALUES ('2018-10-03 14:38:05.000', 10.80000, 223, 0.29000) ('2018-10-03 14:38:06.500', 11.50000, 221, 0.35000) + SQL); + + // 影响行数 + var_dump($resource->affectedRows()); +} catch (TDengineException $e) { + // 捕获异常 + throw $e; +} diff --git a/docs-examples/php/insert_stmt.php b/docs-examples/php/insert_stmt.php new file mode 100644 index 0000000000..5d4b4809d2 --- /dev/null +++ b/docs-examples/php/insert_stmt.php @@ -0,0 +1,49 @@ +connect(); + + // 插入 + $connection->query('CREATE DATABASE if not exists power'); + $connection->query('CREATE STABLE if not exists meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (location BINARY(64), groupId INT)'); + $stmt = $connection->prepare('INSERT INTO ? USING meters TAGS(?, ?) VALUES(?, ?, ?, ?)'); + + // 设置表名和标签 + $stmt->setTableNameTags('d1001', [ + // 支持格式同参数绑定 + [TDengine\TSDB_DATA_TYPE_BINARY, 'Beijing.Chaoyang'], + [TDengine\TSDB_DATA_TYPE_INT, 2], + ]); + + $stmt->bindParams([ + [TDengine\TSDB_DATA_TYPE_TIMESTAMP, 1648432611249], + [TDengine\TSDB_DATA_TYPE_FLOAT, 10.3], + [TDengine\TSDB_DATA_TYPE_INT, 219], + [TDengine\TSDB_DATA_TYPE_FLOAT, 0.31], + ]); + $stmt->bindParams([ + [TDengine\TSDB_DATA_TYPE_TIMESTAMP, 1648432611749], + [TDengine\TSDB_DATA_TYPE_FLOAT, 12.6], + [TDengine\TSDB_DATA_TYPE_INT, 218], + [TDengine\TSDB_DATA_TYPE_FLOAT, 0.33], + ]); + $resource = $stmt->execute(); + + // 影响行数 + var_dump($resource->affectedRows()); +} catch (TDengineException $e) { + // 捕获异常 + throw $e; +} diff --git a/docs-examples/php/query.php b/docs-examples/php/query.php new file mode 100644 index 0000000000..4e86a2cec7 --- /dev/null +++ b/docs-examples/php/query.php @@ -0,0 +1,23 @@ +connect(); + + $resource = $connection->query('SELECT ts, current FROM meters LIMIT 2'); + var_dump($resource->fetch()); +} catch (TDengineException $e) { + // 捕获异常 + throw $e; +} diff --git a/docs-examples/python/.gitignore b/docs-examples/python/.gitignore new file mode 100644 index 0000000000..723ef36f4e --- /dev/null +++ b/docs-examples/python/.gitignore @@ -0,0 +1 @@ +.idea \ No newline at end of file diff --git a/docs-examples/python/.gitkeep b/docs-examples/python/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/docs-examples/python/async_query_example.py b/docs-examples/python/async_query_example.py new file mode 100644 index 0000000000..a78f44230a --- /dev/null +++ b/docs-examples/python/async_query_example.py @@ -0,0 +1,72 @@ +import time +from ctypes import * + +from taos import * + + +def fetch_callback(p_param, p_result, num_of_rows): + print("fetched ", num_of_rows, "rows") + p = cast(p_param, POINTER(Counter)) + result = TaosResult(p_result) + + if num_of_rows == 0: + print("fetching completed") + p.contents.done = True + result.close() + return + if num_of_rows < 0: + p.contents.done = True + result.check_error(num_of_rows) + result.close() + return None + + for row in result.rows_iter(num_of_rows): + print(row) + p.contents.count += result.row_count + result.fetch_rows_a(fetch_callback, p_param) + + +def query_callback(p_param, p_result, code): + if p_result is None: + return + result = TaosResult(p_result) + if code == 0: + result.fetch_rows_a(fetch_callback, p_param) + result.check_error(code) + + +class Counter(Structure): + _fields_ = [("count", c_int), ("done", c_bool)] + + def __str__(self): + return "{ count: %d, done: %s }" % (self.count, self.done) + + +def test_query(conn): + counter = Counter(count=0) + conn.query_a("select ts, current, voltage from power.meters", query_callback, byref(counter)) + + while not counter.done: + print(counter) + time.sleep(1) + print(counter) + conn.close() + + +if __name__ == "__main__": + test_query(connect()) + +# possible output: +# { count: 0, done: False } +# fetched 8 rows +# 1538548685000 10.300000 219 +# 1538548695000 12.600000 218 +# 1538548696800 12.300000 221 +# 1538548696650 10.300000 218 +# 1538548685500 11.800000 221 +# 1538548696600 13.400000 223 +# 1538548685500 10.800000 223 +# 1538548686500 11.500000 221 +# fetched 0 rows +# fetching completed +# { count: 8, done: True } diff --git a/docs-examples/python/bind_param_example.py b/docs-examples/python/bind_param_example.py new file mode 100644 index 0000000000..503a2eb5dd --- /dev/null +++ b/docs-examples/python/bind_param_example.py @@ -0,0 +1,60 @@ +import taos +from datetime import datetime + +# note: lines have already been sorted by table name +lines = [('d1001', '2018-10-03 14:38:05.000', 10.30000, 219, 0.31000, 'Beijing.Chaoyang', 2), + ('d1001', '2018-10-03 14:38:15.000', 12.60000, 218, 0.33000, 'Beijing.Chaoyang', 2), + ('d1001', '2018-10-03 14:38:16.800', 12.30000, 221, 0.31000, 'Beijing.Chaoyang', 2), + ('d1002', '2018-10-03 14:38:16.650', 10.30000, 218, 0.25000, 'Beijing.Chaoyang', 3), + ('d1003', '2018-10-03 14:38:05.500', 11.80000, 221, 0.28000, 'Beijing.Haidian', 2), + ('d1003', '2018-10-03 14:38:16.600', 13.40000, 223, 0.29000, 'Beijing.Haidian', 2), + ('d1004', '2018-10-03 14:38:05.000', 10.80000, 223, 0.29000, 'Beijing.Haidian', 3), + ('d1004', '2018-10-03 14:38:06.500', 11.50000, 221, 0.35000, 'Beijing.Haidian', 3)] + + +def get_ts(ts: str): + dt = datetime.strptime(ts, '%Y-%m-%d %H:%M:%S.%f') + return int(dt.timestamp() * 1000) + + +def create_stable(): + conn = taos.connect() + try: + conn.execute("CREATE DATABASE power") + conn.execute("CREATE STABLE power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) " + "TAGS (location BINARY(64), groupId INT)") + finally: + conn.close() + + +def bind_row_by_row(stmt: taos.TaosStmt): + tb_name = None + for row in lines: + if tb_name != row[0]: + tb_name = row[0] + tags: taos.TaosBind = taos.new_bind_params(2) # 2 is count of tags + tags[0].binary(row[5]) # location + tags[1].int(row[6]) # groupId + stmt.set_tbname_tags(tb_name, tags) + values: taos.TaosBind = taos.new_bind_params(4) # 4 is count of columns + values[0].timestamp(get_ts(row[1])) + values[1].float(row[2]) + values[2].int(row[3]) + values[3].float(row[4]) + stmt.bind_param(values) + + +def insert_data(): + conn = taos.connect(database="power") + try: + stmt = conn.statement("INSERT INTO ? USING meters TAGS(?, ?) VALUES(?, ?, ?, ?)") + bind_row_by_row(stmt) + stmt.execute() + stmt.close() + finally: + conn.close() + + +if __name__ == '__main__': + create_stable() + insert_data() diff --git a/docs-examples/python/conn_native_pandas.py b/docs-examples/python/conn_native_pandas.py new file mode 100644 index 0000000000..314759f766 --- /dev/null +++ b/docs-examples/python/conn_native_pandas.py @@ -0,0 +1,19 @@ +import pandas +from sqlalchemy import create_engine + +engine = create_engine("taos://root:taosdata@localhost:6030/power") +df = pandas.read_sql("SELECT * FROM meters", engine) + +# print index +print(df.index) +# print data type of element in ts column +print(type(df.ts[0])) +print(df.head(3)) + +# output: +# RangeIndex(start=0, stop=8, step=1) +# +# ts current voltage phase location groupid +# 0 2018-10-03 14:38:05.000 10.3 219 0.31 beijing.chaoyang 2 +# 1 2018-10-03 14:38:15.000 12.6 218 0.33 beijing.chaoyang 2 +# 2 2018-10-03 14:38:16.800 12.3 221 0.31 beijing.chaoyang 2 diff --git a/docs-examples/python/conn_rest_pandas.py b/docs-examples/python/conn_rest_pandas.py new file mode 100644 index 0000000000..143e4275fa --- /dev/null +++ b/docs-examples/python/conn_rest_pandas.py @@ -0,0 +1,19 @@ +import pandas +from sqlalchemy import create_engine + +engine = create_engine("taosrest://root:taosdata@localhost:6041") +df: pandas.DataFrame = pandas.read_sql("SELECT * FROM power.meters", engine) + +# print index +print(df.index) +# print data type of element in ts column +print(type(df.ts[0])) +print(df.head(3)) + +# output: +# +# RangeIndex(start=0, stop=8, step=1) +# ts current ... location groupid +# 0 2018-10-03 14:38:05+08:00 10.3 ... beijing.chaoyang 2 +# 1 2018-10-03 14:38:15+08:00 12.6 ... beijing.chaoyang 2 +# 2 2018-10-03 14:38:16.800000+08:00 12.3 ... beijing.chaoyang 2 diff --git a/docs-examples/python/connect_example.py b/docs-examples/python/connect_example.py new file mode 100644 index 0000000000..719af79fd1 --- /dev/null +++ b/docs-examples/python/connect_example.py @@ -0,0 +1,19 @@ +import taos + + +def test_connection(): + # all parameters are optional. + # if database is specified, + # then it must exist. + conn = taos.connect(host="localhost", + port=6030, + user="root", + password="taosdata", + database="log") + print('client info:', conn.client_info) + print('server info:', conn.server_info) + conn.close() + + +if __name__ == "__main__": + test_connection() diff --git a/docs-examples/python/connect_native_reference.py b/docs-examples/python/connect_native_reference.py new file mode 100644 index 0000000000..c17e9795b5 --- /dev/null +++ b/docs-examples/python/connect_native_reference.py @@ -0,0 +1,20 @@ +import taos + +conn: taos.TaosConnection = taos.connect(host="localhost", + user="root", + password="taosdata", + database="test", + port=6030, + config="/etc/taos", # for windows the default value is C:\TDengine\cfg + timezone="Asia/Shanghai") # default your host's timezone + +server_version = conn.server_info +print("server_version", server_version) +client_version = conn.client_info +print("client_version", client_version) # 2.4.0.16 + +conn.close() + +# possible output: +# 2.4.0.16 +# 2.4.0.16 diff --git a/docs-examples/python/connect_rest_examples.py b/docs-examples/python/connect_rest_examples.py new file mode 100644 index 0000000000..a043d506b9 --- /dev/null +++ b/docs-examples/python/connect_rest_examples.py @@ -0,0 +1,45 @@ +# ANCHOR: connect +from taosrest import connect, TaosRestConnection, TaosRestCursor + +conn: TaosRestConnection = connect(host="localhost", + user="root", + password="taosdata", + port=6041, + timeout=30) + +# ANCHOR_END: connect +# ANCHOR: basic +# create STable +cursor: TaosRestCursor = conn.cursor() +cursor.execute("DROP DATABASE IF EXISTS power") +cursor.execute("CREATE DATABASE power") +cursor.execute("CREATE STABLE power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (location BINARY(64), groupId INT)") + +# insert data +cursor.execute("""INSERT INTO power.d1001 USING power.meters TAGS(Beijing.Chaoyang, 2) VALUES ('2018-10-03 14:38:05.000', 10.30000, 219, 0.31000) ('2018-10-03 14:38:15.000', 12.60000, 218, 0.33000) ('2018-10-03 14:38:16.800', 12.30000, 221, 0.31000) + power.d1002 USING power.meters TAGS(Beijing.Chaoyang, 3) VALUES ('2018-10-03 14:38:16.650', 10.30000, 218, 0.25000) + power.d1003 USING power.meters TAGS(Beijing.Haidian, 2) VALUES ('2018-10-03 14:38:05.500', 11.80000, 221, 0.28000) ('2018-10-03 14:38:16.600', 13.40000, 223, 0.29000) + power.d1004 USING power.meters TAGS(Beijing.Haidian, 3) VALUES ('2018-10-03 14:38:05.000', 10.80000, 223, 0.29000) ('2018-10-03 14:38:06.500', 11.50000, 221, 0.35000)""") +print("inserted row count:", cursor.rowcount) + +# query data +cursor.execute("SELECT * FROM power.meters LIMIT 3") +# get total rows +print("queried row count:", cursor.rowcount) +# get column names from cursor +column_names = [meta[0] for meta in cursor.description] +# get rows +data: list[tuple] = cursor.fetchall() +print(column_names) +for row in data: + print(row) + +# output: +# inserted row count: 8 +# queried row count: 3 +# ['ts', 'current', 'voltage', 'phase', 'location', 'groupid'] +# [datetime.datetime(2018, 10, 3, 14, 38, 5, tzinfo=datetime.timezone(datetime.timedelta(seconds=28800), '+08:00')), 10.3, 219, 0.31, 'beijing.chaoyang', 2] +# [datetime.datetime(2018, 10, 3, 14, 38, 15, tzinfo=datetime.timezone(datetime.timedelta(seconds=28800), '+08:00')), 12.6, 218, 0.33, 'beijing.chaoyang', 2] +# [datetime.datetime(2018, 10, 3, 14, 38, 16, 800000, tzinfo=datetime.timezone(datetime.timedelta(seconds=28800), '+08:00')), 12.3, 221, 0.31, 'beijing.chaoyang', 2] + +# ANCHOR_END: basic diff --git a/docs-examples/python/connection_usage_native_reference.py b/docs-examples/python/connection_usage_native_reference.py new file mode 100644 index 0000000000..4803511e42 --- /dev/null +++ b/docs-examples/python/connection_usage_native_reference.py @@ -0,0 +1,45 @@ +import taos + +# ANCHOR: insert +conn = taos.connect() +# Execute a sql, ignore the result set, just get affected rows. It's useful for DDL and DML statement. +conn.execute("DROP DATABASE IF EXISTS test") +conn.execute("CREATE DATABASE test") +# change database. same as execute "USE db" +conn.select_db("test") +conn.execute("CREATE STABLE weather(ts TIMESTAMP, temperature FLOAT) TAGS (location INT)") +affected_row: int = conn.execute("INSERT INTO t1 USING weather TAGS(1) VALUES (now, 23.5) (now+1m, 23.5) (now+2m 24.4)") +print("affected_row", affected_row) +# output: +# affected_row 3 +# ANCHOR_END: insert + +# ANCHOR: query +# Execute a sql and get its result set. It's useful for SELECT statement +result: taos.TaosResult = conn.query("SELECT * from weather") + +# Get fields from result +fields: taos.field.TaosFields = result.fields +for field in fields: + print(field) # {name: ts, type: 9, bytes: 8} + +# output: +# {name: ts, type: 9, bytes: 8} +# {name: temperature, type: 6, bytes: 4} +# {name: location, type: 4, bytes: 4} + +# Get data from result as list of tuple +data = result.fetch_all() +print(data) +# output: +# [(datetime.datetime(2022, 4, 27, 9, 4, 25, 367000), 23.5, 1), (datetime.datetime(2022, 4, 27, 9, 5, 25, 367000), 23.5, 1), (datetime.datetime(2022, 4, 27, 9, 6, 25, 367000), 24.399999618530273, 1)] + +# Or get data from result as a list of dict +# map_data = result.fetch_all_into_dict() +# print(map_data) +# output: +# [{'ts': datetime.datetime(2022, 4, 27, 9, 1, 15, 343000), 'temperature': 23.5, 'location': 1}, {'ts': datetime.datetime(2022, 4, 27, 9, 2, 15, 343000), 'temperature': 23.5, 'location': 1}, {'ts': datetime.datetime(2022, 4, 27, 9, 3, 15, 343000), 'temperature': 24.399999618530273, 'location': 1}] +# ANCHOR_END: query + + +conn.close() diff --git a/docs-examples/python/cursor_usage_native_reference.py b/docs-examples/python/cursor_usage_native_reference.py new file mode 100644 index 0000000000..a5103810f0 --- /dev/null +++ b/docs-examples/python/cursor_usage_native_reference.py @@ -0,0 +1,32 @@ +import taos + +conn = taos.connect() +cursor = conn.cursor() + +cursor.execute("DROP DATABASE IF EXISTS test") +cursor.execute("CREATE DATABASE test") +cursor.execute("USE test") +cursor.execute("CREATE STABLE weather(ts TIMESTAMP, temperature FLOAT) TAGS (location INT)") + +for i in range(1000): + location = str(i % 10) + tb = "t" + location + cursor.execute(f"INSERT INTO {tb} USING weather TAGS({location}) VALUES (now+{i}a, 23.5) (now+{i + 1}a, 23.5)") + +cursor.execute("SELECT count(*) FROM weather") +data = cursor.fetchall() +print("count:", data[0][0]) +cursor.execute("SELECT tbname, * FROM weather LIMIT 2") +col_names = [meta[0] for meta in cursor.description] +print(col_names) +rows = cursor.fetchall() +print(rows) + +cursor.close() +conn.close() + +# output: +# count: 2000 +# ['tbname', 'ts', 'temperature', 'location'] +# row_count: -1 +# [('t0', datetime.datetime(2022, 4, 27, 14, 54, 24, 392000), 23.5, 0), ('t0', datetime.datetime(2022, 4, 27, 14, 54, 24, 393000), 23.5, 0)] diff --git a/docs-examples/python/handle_exception.py b/docs-examples/python/handle_exception.py new file mode 100644 index 0000000000..59554465c0 --- /dev/null +++ b/docs-examples/python/handle_exception.py @@ -0,0 +1,19 @@ +import taos + +try: + conn = taos.connect() + conn.execute("CREATE TABLE 123") # wrong sql +except taos.Error as e: + print(e) + print("exception class: ", e.__class__.__name__) + print("error number:", e.errno) + print("error message:", e.msg) +except BaseException as other: + print("exception occur") + print(other) + +# output: +# [0x0216]: syntax error near 'Incomplete SQL statement' +# exception class: ProgrammingError +# error number: -2147483114 +# error message: syntax error near 'Incomplete SQL statement' diff --git a/docs-examples/python/json_protocol_example.py b/docs-examples/python/json_protocol_example.py new file mode 100644 index 0000000000..5bb4d629bc --- /dev/null +++ b/docs-examples/python/json_protocol_example.py @@ -0,0 +1,38 @@ +import json + +import taos +from taos import SmlProtocol, SmlPrecision + +lines = [{"metric": "meters.current", "timestamp": 1648432611249, "value": 10.3, "tags": {"location": "Beijing.Chaoyang", "groupid": 2}}, + {"metric": "meters.voltage", "timestamp": 1648432611249, "value": 219, + "tags": {"location": "Beijing.Haidian", "groupid": 1}}, + {"metric": "meters.current", "timestamp": 1648432611250, "value": 12.6, + "tags": {"location": "Beijing.Chaoyang", "groupid": 2}}, + {"metric": "meters.voltage", "timestamp": 1648432611250, "value": 221, "tags": {"location": "Beijing.Haidian", "groupid": 1}}] + + +def get_connection(): + return taos.connect() + + +def create_database(conn): + conn.execute("CREATE DATABASE test") + conn.execute("USE test") + + +def insert_lines(conn): + global lines + lines = json.dumps(lines) + # note: the first parameter must be a list with only one element. + affected_rows = conn.schemaless_insert( + [lines], SmlProtocol.JSON_PROTOCOL, SmlPrecision.NOT_CONFIGURED) + print(affected_rows) # 4 + + +if __name__ == '__main__': + connection = get_connection() + try: + create_database(connection) + insert_lines(connection) + finally: + connection.close() diff --git a/docs-examples/python/line_protocol_example.py b/docs-examples/python/line_protocol_example.py new file mode 100644 index 0000000000..02baeb2104 --- /dev/null +++ b/docs-examples/python/line_protocol_example.py @@ -0,0 +1,34 @@ +import taos +from taos import SmlProtocol, SmlPrecision + +lines = ["meters,location=Beijing.Haidian,groupid=2 current=11.8,voltage=221,phase=0.28 1648432611249000", + "meters,location=Beijing.Haidian,groupid=2 current=13.4,voltage=223,phase=0.29 1648432611249500", + "meters,location=Beijing.Haidian,groupid=3 current=10.8,voltage=223,phase=0.29 1648432611249300", + "meters,location=Beijing.Haidian,groupid=3 current=11.3,voltage=221,phase=0.35 1648432611249800", + ] + + +def get_connection(): + # create connection use firstEP in taos.cfg. + return taos.connect() + + +def create_database(conn): + # the default precision is ms (microsecond), but we use us(microsecond) here. + conn.execute("CREATE DATABASE test precision 'us'") + conn.execute("USE test") + + +def insert_lines(conn): + affected_rows = conn.schemaless_insert( + lines, SmlProtocol.LINE_PROTOCOL, SmlPrecision.MICRO_SECONDS) + print(affected_rows) # 8 + + +if __name__ == '__main__': + connection = get_connection() + try: + create_database(connection) + insert_lines(connection) + finally: + connection.close() diff --git a/docs-examples/python/multi_bind_example.py b/docs-examples/python/multi_bind_example.py new file mode 100644 index 0000000000..1714121d72 --- /dev/null +++ b/docs-examples/python/multi_bind_example.py @@ -0,0 +1,88 @@ +import taos +from datetime import datetime + +# ANCHOR: bind_batch +table_tags = { + "d1001": ('Beijing.Chaoyang', 2), + "d1002": ('Beijing.Chaoyang', 3), + "d1003": ('Beijing.Haidian', 2), + "d1004": ('Beijing.Haidian', 3) +} + +table_values = { + "d1001": [ + ['2018-10-03 14:38:05.000', '2018-10-03 14:38:15.000', '2018-10-03 14:38:16.800'], + [10.3, 12.6, 12.3], + [219, 218, 221], + [0.31, 0.33, 0.32] + ], + "d1002": [ + ['2018-10-03 14:38:16.650'], [10.3], [218], [0.25] + ], + "d1003": [ + ['2018-10-03 14:38:05.500', '2018-10-03 14:38:16.600'], + [11.8, 13.4], + [221, 223], + [0.28, 0.29] + ], + "d1004": [ + ['2018-10-03 14:38:05.500', '2018-10-03 14:38:06.500'], + [10.8, 11.5], + [223, 221], + [0.29, 0.35] + ] +} + + +def bind_multi_rows(stmt: taos.TaosStmt): + """ + batch bind example + """ + for tb_name in table_values.keys(): + tags = table_tags[tb_name] + tag_params = taos.new_bind_params(2) + tag_params[0].binary(tags[0]) + tag_params[1].int(tags[1]) + stmt.set_tbname_tags(tb_name, tag_params) + + values = table_values[tb_name] + value_params = taos.new_multi_binds(4) + value_params[0].timestamp([get_ts(t) for t in values[0]]) + value_params[1].float(values[1]) + value_params[2].int(values[2]) + value_params[3].float(values[3]) + stmt.bind_param_batch(value_params) + + +def insert_data(): + conn = taos.connect(database="power") + try: + stmt = conn.statement("INSERT INTO ? USING meters TAGS(?, ?) VALUES(?, ?, ?, ?)") + bind_multi_rows(stmt) + stmt.execute() + stmt.close() + finally: + conn.close() + + +# ANCHOR_END: bind_batch + + +def create_stable(): + conn = taos.connect() + try: + conn.execute("CREATE DATABASE power") + conn.execute("CREATE STABLE power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) " + "TAGS (location BINARY(64), groupId INT)") + finally: + conn.close() + + +def get_ts(ts: str): + dt = datetime.strptime(ts, '%Y-%m-%d %H:%M:%S.%f') + return int(dt.timestamp() * 1000) + + +if __name__ == '__main__': + create_stable() + insert_data() diff --git a/docs-examples/python/native_insert_example.py b/docs-examples/python/native_insert_example.py new file mode 100644 index 0000000000..94d4888a8f --- /dev/null +++ b/docs-examples/python/native_insert_example.py @@ -0,0 +1,60 @@ +import taos + +lines = ["d1001,2018-10-03 14:38:05.000,10.30000,219,0.31000,Beijing.Chaoyang,2", + "d1004,2018-10-03 14:38:05.000,10.80000,223,0.29000,Beijing.Haidian,3", + "d1003,2018-10-03 14:38:05.500,11.80000,221,0.28000,Beijing.Haidian,2", + "d1004,2018-10-03 14:38:06.500,11.50000,221,0.35000,Beijing.Haidian,3", + "d1002,2018-10-03 14:38:16.650,10.30000,218,0.25000,Beijing.Chaoyang,3", + "d1001,2018-10-03 14:38:15.000,12.60000,218,0.33000,Beijing.Chaoyang,2", + "d1001,2018-10-03 14:38:16.800,12.30000,221,0.31000,Beijing.Chaoyang,2", + "d1003,2018-10-03 14:38:16.600,13.40000,223,0.29000,Beijing.Haidian,2"] + + +def get_connection() -> taos.TaosConnection: + """ + create connection use firstEp in taos.cfg and use default user and password. + """ + return taos.connect() + + +def create_stable(conn: taos.TaosConnection): + conn.execute("CREATE DATABASE power") + conn.execute("USE power") + conn.execute("CREATE STABLE meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) " + "TAGS (location BINARY(64), groupId INT)") + + +# The generated SQL is: +# INSERT INTO d1001 USING meters TAGS(Beijing.Chaoyang, 2) VALUES ('2018-10-03 14:38:05.000', 10.30000, 219, 0.31000) ('2018-10-03 14:38:15.000', 12.60000, 218, 0.33000) ('2018-10-03 14:38:16.800', 12.30000, 221, 0.31000) +# d1002 USING meters TAGS(Beijing.Chaoyang, 3) VALUES ('2018-10-03 14:38:16.650', 10.30000, 218, 0.25000) +# d1003 USING meters TAGS(Beijing.Haidian, 2) VALUES ('2018-10-03 14:38:05.500', 11.80000, 221, 0.28000) ('2018-10-03 14:38:16.600', 13.40000, 223, 0.29000) +# d1004 USING meters TAGS(Beijing.Haidian, 3) VALUES ('2018-10-03 14:38:05.000', 10.80000, 223, 0.29000) ('2018-10-03 14:38:06.500', 11.50000, 221, 0.35000) + +def get_sql(): + global lines + lines = map(lambda line: line.split(','), lines) # [['d1001', ...]...] + lines = sorted(lines, key=lambda ls: ls[0]) # sort by table name + sql = "INSERT INTO " + tb_name = None + for ps in lines: + tmp_tb_name = ps[0] + if tb_name != tmp_tb_name: + tb_name = tmp_tb_name + sql += f"{tb_name} USING meters TAGS({ps[5]}, {ps[6]}) VALUES " + sql += f"('{ps[1]}', {ps[2]}, {ps[3]}, {ps[4]}) " + return sql + + +def insert_data(conn: taos.TaosConnection): + sql = get_sql() + affected_rows = conn.execute(sql) + print("affected_rows", affected_rows) # 8 + + +if __name__ == '__main__': + connection = get_connection() + try: + create_stable(connection) + insert_data(connection) + finally: + connection.close() diff --git a/docs-examples/python/query_example.py b/docs-examples/python/query_example.py new file mode 100644 index 0000000000..6d33c49c96 --- /dev/null +++ b/docs-examples/python/query_example.py @@ -0,0 +1,42 @@ +import taos + + +# ANCHOR: iter +def query_api_demo(conn: taos.TaosConnection): + result: taos.TaosResult = conn.query("SELECT tbname, * FROM meters LIMIT 2") + print("field count:", result.field_count) + print("meta of fields[1]:", result.fields[1]) + print("======================Iterate on result=========================") + for row in result: + print(row) + + +# field count: 7 +# meta of files[1]: {name: ts, type: 9, bytes: 8} +# ======================Iterate on result========================= +# ('d1001', datetime.datetime(2018, 10, 3, 14, 38, 5), 10.300000190734863, 219, 0.3100000023841858, 'Beijing.Chaoyang', 2) +# ('d1001', datetime.datetime(2018, 10, 3, 14, 38, 15), 12.600000381469727, 218, 0.33000001311302185, 'Beijing.Chaoyang', 2) +# ANCHOR_END: iter + +# ANCHOR: fetch_all +def fetch_all_demo(conn: taos.TaosConnection): + result: taos.TaosResult = conn.query("SELECT ts, current FROM meters LIMIT 2") + rows = result.fetch_all_into_dict() + print("row count:", result.row_count) + print("===============all data===================") + print(rows) + + +# row count: 2 +# ===============all data=================== +# [{'ts': datetime.datetime(2018, 10, 3, 14, 38, 5), 'current': 10.300000190734863}, +# {'ts': datetime.datetime(2018, 10, 3, 14, 38, 15), 'current': 12.600000381469727}] +# ANCHOR_END: fetch_all + +if __name__ == '__main__': + connection = taos.connect(database="power") + try: + query_api_demo(connection) + fetch_all_demo(connection) + finally: + connection.close() diff --git a/docs-examples/python/rest_client_example.py b/docs-examples/python/rest_client_example.py new file mode 100644 index 0000000000..46d33a1d79 --- /dev/null +++ b/docs-examples/python/rest_client_example.py @@ -0,0 +1,9 @@ +from taosrest import RestClient + +client = RestClient("localhost", 6041, "root", "taosdata") +res: dict = client.sql("SELECT ts, current FROM power.meters LIMIT 1") +print(res) + +# output: +# {'status': 'succ', 'head': ['ts', 'current'], 'column_meta': [['ts', 9, 8], ['current', 6, 4]], 'data': [[datetime.datetime(2018, 10, 3, 14, 38, 5, tzinfo=datetime.timezone(datetime.timedelta(seconds=28800), '+08:00')), 10.3]], 'rows': 1} + diff --git a/docs-examples/python/result_set_examples.py b/docs-examples/python/result_set_examples.py new file mode 100644 index 0000000000..6cba0d3f73 --- /dev/null +++ b/docs-examples/python/result_set_examples.py @@ -0,0 +1,33 @@ +import taos + +conn = taos.connect() +conn.execute("DROP DATABASE IF EXISTS test") +conn.execute("CREATE DATABASE test") +conn.select_db("test") +conn.execute("CREATE STABLE weather(ts TIMESTAMP, temperature FLOAT) TAGS (location INT)") +# prepare data +for i in range(2000): + location = str(i % 10) + tb = "t" + location + conn.execute(f"INSERT INTO {tb} USING weather TAGS({location}) VALUES (now+{i}a, 23.5) (now+{i + 1}a, 23.5)") + +result: taos.TaosResult = conn.query("SELECT * FROM weather") + +block_index = 0 +blocks: taos.TaosBlocks = result.blocks_iter() +for rows, length in blocks: + print("block ", block_index, " length", length) + print("first row in this block:", rows[0]) + block_index += 1 + +conn.close() + +# possible output: +# block 0 length 1200 +# first row in this block: (datetime.datetime(2022, 4, 27, 15, 14, 52, 46000), 23.5, 0) +# block 1 length 1200 +# first row in this block: (datetime.datetime(2022, 4, 27, 15, 14, 52, 76000), 23.5, 3) +# block 2 length 1200 +# first row in this block: (datetime.datetime(2022, 4, 27, 15, 14, 52, 99000), 23.5, 6) +# block 3 length 400 +# first row in this block: (datetime.datetime(2022, 4, 27, 15, 14, 52, 122000), 23.5, 9) diff --git a/docs-examples/python/subscribe_demo.py b/docs-examples/python/subscribe_demo.py new file mode 100644 index 0000000000..db9d49c3f4 --- /dev/null +++ b/docs-examples/python/subscribe_demo.py @@ -0,0 +1,38 @@ +""" +Python asynchronous subscribe demo. +run on Linux system with: python3 subscribe_demo.py +""" + +from ctypes import c_void_p + +import taos +import time + + +def query_callback(p_sub, p_result, p_param, code): + """ + :param p_sub: pointer returned by native API -- taos_subscribe + :param p_result: pointer to native TAOS_RES + :param p_param: None + :param code: error code + :return: None + """ + print("in callback") + result = taos.TaosResult(c_void_p(p_result)) + # raise exception if error occur + result.check_error(code) + for row in result.rows_iter(): + print(row) + print(f"{result.row_count} rows consumed.") + + +if __name__ == '__main__': + conn = taos.connect() + restart = True + topic = "topic-meter-current-bg" + sql = "select * from power.meters where current > 10" # Error sql + interval = 2000 # consumption interval in microseconds. + _ = conn.subscribe(restart, topic, sql, interval, query_callback) + # Note: we received the return value as _ above, to avoid the TaosSubscription object to be deleted by gc. + while True: + time.sleep(10) # use Ctrl + C to interrupt diff --git a/docs-examples/python/telnet_line_protocol_example.py b/docs-examples/python/telnet_line_protocol_example.py new file mode 100644 index 0000000000..072835109e --- /dev/null +++ b/docs-examples/python/telnet_line_protocol_example.py @@ -0,0 +1,38 @@ +import taos +from taos import SmlProtocol, SmlPrecision + +# format: =[ =] +lines = ["meters.current 1648432611249 10.3 location=Beijing.Chaoyang groupid=2", + "meters.current 1648432611250 12.6 location=Beijing.Chaoyang groupid=2", + "meters.current 1648432611249 10.8 location=Beijing.Haidian groupid=3", + "meters.current 1648432611250 11.3 location=Beijing.Haidian groupid=3", + "meters.voltage 1648432611249 219 location=Beijing.Chaoyang groupid=2", + "meters.voltage 1648432611250 218 location=Beijing.Chaoyang groupid=2", + "meters.voltage 1648432611249 221 location=Beijing.Haidian groupid=3", + "meters.voltage 1648432611250 217 location=Beijing.Haidian groupid=3", + ] + + +# create connection use firstEp in taos.cfg. +def get_connection(): + return taos.connect() + + +def create_database(conn): + conn.execute("CREATE DATABASE test") + conn.execute("USE test") + + +def insert_lines(conn): + affected_rows = conn.schemaless_insert( + lines, SmlProtocol.TELNET_PROTOCOL, SmlPrecision.NOT_CONFIGURED) + print(affected_rows) # 8 + + +if __name__ == '__main__': + connection = get_connection() + try: + create_database(connection) + insert_lines(connection) + finally: + connection.close() diff --git a/docs-examples/rust/Cargo.toml b/docs-examples/rust/Cargo.toml new file mode 100644 index 0000000000..114407e69e --- /dev/null +++ b/docs-examples/rust/Cargo.toml @@ -0,0 +1,2 @@ +[workspace] +members = ["restexample", "nativeexample", "schemalessexample"] diff --git a/docs-examples/rust/nativeexample/Cargo.toml b/docs-examples/rust/nativeexample/Cargo.toml new file mode 100644 index 0000000000..64fd10a3e9 --- /dev/null +++ b/docs-examples/rust/nativeexample/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "nativeexample" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[dependencies] +libtaos = { version = "0.4.3" } +tokio = { version = "*", features = ["rt", "macros", "rt-multi-thread"] } +bstr = { version = "*" } diff --git a/docs-examples/rust/nativeexample/examples/connect.rs b/docs-examples/rust/nativeexample/examples/connect.rs new file mode 100644 index 0000000000..8e27458de5 --- /dev/null +++ b/docs-examples/rust/nativeexample/examples/connect.rs @@ -0,0 +1,19 @@ +use libtaos::*; + +fn taos_connect() -> Result { + TaosCfgBuilder::default() + .ip("localhost") + .user("root") + .pass("taosdata") + // .db("log") // remove comment if you want to connect to database log by default. + .port(6030u16) + .build() + .expect("TaosCfg builder error") + .connect() +} + +fn main() { + #[allow(unused_variables)] + let taos = taos_connect().unwrap(); + println!("Connected") +} diff --git a/docs-examples/rust/nativeexample/examples/stmt_example.rs b/docs-examples/rust/nativeexample/examples/stmt_example.rs new file mode 100644 index 0000000000..a791a41359 --- /dev/null +++ b/docs-examples/rust/nativeexample/examples/stmt_example.rs @@ -0,0 +1,38 @@ +use bstr::BString; +use libtaos::*; + +#[tokio::main] +async fn main() -> Result<(), Error> { + let taos = TaosCfg::default().connect().expect("fail to connect"); + taos.create_database("power").await?; + taos.use_database("power").await?; + taos.exec("CREATE STABLE meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (location BINARY(64), groupId INT)").await?; + let mut stmt = taos.stmt("INSERT INTO ? USING meters TAGS(?, ?) VALUES(?, ?, ?, ?)")?; + // bind table name and tags + stmt.set_tbname_tags( + "d1001", + [ + Field::Binary(BString::from("Beijing.Chaoyang")), + Field::Int(2), + ], + )?; + // bind values. + let values = vec![ + Field::Timestamp(Timestamp::new(1648432611249, TimestampPrecision::Milli)), + Field::Float(10.3), + Field::Int(219), + Field::Float(0.31), + ]; + stmt.bind(&values)?; + // bind one more row + let values2 = vec![ + Field::Timestamp(Timestamp::new(1648432611749, TimestampPrecision::Milli)), + Field::Float(12.6), + Field::Int(218), + Field::Float(0.33), + ]; + stmt.bind(&values2)?; + // execute + stmt.execute()?; + Ok(()) +} diff --git a/docs-examples/rust/nativeexample/examples/subscribe_demo.rs b/docs-examples/rust/nativeexample/examples/subscribe_demo.rs new file mode 100644 index 0000000000..4febff9be7 --- /dev/null +++ b/docs-examples/rust/nativeexample/examples/subscribe_demo.rs @@ -0,0 +1,3 @@ +fn main() { + +} \ No newline at end of file diff --git a/docs-examples/rust/nativeexample/src/main.rs b/docs-examples/rust/nativeexample/src/main.rs new file mode 100644 index 0000000000..e7a11a969c --- /dev/null +++ b/docs-examples/rust/nativeexample/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} diff --git a/docs-examples/rust/restexample/Cargo.toml b/docs-examples/rust/restexample/Cargo.toml new file mode 100644 index 0000000000..a5f89f8a3b --- /dev/null +++ b/docs-examples/rust/restexample/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "restexample" +version = "0.1.0" +edition = "2021" + +[dependencies] +libtaos = { version = "0.4.3", features = ["rest"] } +tokio = { version = "*", features = ["rt", "macros", "rt-multi-thread"] } diff --git a/docs-examples/rust/restexample/examples/connect.rs b/docs-examples/rust/restexample/examples/connect.rs new file mode 100644 index 0000000000..b3718342c4 --- /dev/null +++ b/docs-examples/rust/restexample/examples/connect.rs @@ -0,0 +1,20 @@ +use libtaos::*; + +fn taos_connect() -> Result { + TaosCfgBuilder::default() + .ip("localhost") + .user("root") + .pass("taosdata") + // .db("log") // remove comment if you want to connect to database log by default. + .port(6030u16) + .build() + .expect("TaosCfg builder error") + .connect() +} + +#[tokio::main] +async fn main() { + #[allow(unused_variables)] + let taos = taos_connect().expect("connect error"); + println!("Connected") +} diff --git a/docs-examples/rust/restexample/examples/insert_example.rs b/docs-examples/rust/restexample/examples/insert_example.rs new file mode 100644 index 0000000000..d7acc98d09 --- /dev/null +++ b/docs-examples/rust/restexample/examples/insert_example.rs @@ -0,0 +1,18 @@ +use libtaos::*; + +#[tokio::main] +async fn main() -> Result<(), Error> { + let taos = TaosCfg::default().connect().expect("fail to connect"); + taos.create_database("power").await?; + taos.exec("CREATE STABLE power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (location BINARY(64), groupId INT)").await?; + let sql = "INSERT INTO power.d1001 USING power.meters TAGS(Beijing.Chaoyang, 2) VALUES ('2018-10-03 14:38:05.000', 10.30000, 219, 0.31000) ('2018-10-03 14:38:15.000', 12.60000, 218, 0.33000) ('2018-10-03 14:38:16.800', 12.30000, 221, 0.31000) + power.d1002 USING power.meters TAGS(Beijing.Chaoyang, 3) VALUES ('2018-10-03 14:38:16.650', 10.30000, 218, 0.25000) + power.d1003 USING power.meters TAGS(Beijing.Haidian, 2) VALUES ('2018-10-03 14:38:05.500', 11.80000, 221, 0.28000) ('2018-10-03 14:38:16.600', 13.40000, 223, 0.29000) + power.d1004 USING power.meters TAGS(Beijing.Haidian, 3) VALUES ('2018-10-03 14:38:05.000', 10.80000, 223, 0.29000) ('2018-10-03 14:38:06.500', 11.50000, 221, 0.35000)"; + let result = taos.query(sql).await?; + println!("{:?}", result); + Ok(()) +} + +// output: +// TaosQueryData { column_meta: [ColumnMeta { name: "affected_rows", type_: Int, bytes: 4 }], rows: [[Int(8)]] } diff --git a/docs-examples/rust/restexample/examples/query_example.rs b/docs-examples/rust/restexample/examples/query_example.rs new file mode 100644 index 0000000000..bbe0cfaabf --- /dev/null +++ b/docs-examples/rust/restexample/examples/query_example.rs @@ -0,0 +1,39 @@ +use libtaos::*; + +fn taos_connect() -> Result { + TaosCfgBuilder::default() + .ip("localhost") + .user("root") + .pass("taosdata") + .db("power") + .port(6030u16) + .build() + .expect("TaosCfg builder error") + .connect() +} + +#[tokio::main] +async fn main() -> Result<(), Error> { + let taos = taos_connect().expect("connect error"); + let result = taos.query("SELECT ts, current FROM meters LIMIT 2").await?; + // print column names + let meta: Vec = result.column_meta; + for column in meta { + print!("{}\t", column.name) + } + println!(); + // print rows + let rows: Vec> = result.rows; + for row in rows { + for field in row { + print!("{}\t", field); + } + println!(); + } + Ok(()) +} + +// output: +// ts current +// 2022-03-28 09:56:51.249 10.3 +// 2022-03-28 09:56:51.749 12.6 diff --git a/docs-examples/rust/restexample/src/main.rs b/docs-examples/rust/restexample/src/main.rs new file mode 100644 index 0000000000..e7a11a969c --- /dev/null +++ b/docs-examples/rust/restexample/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} diff --git a/docs-examples/rust/schemalessexample/Cargo.toml b/docs-examples/rust/schemalessexample/Cargo.toml new file mode 100644 index 0000000000..32c6a12231 --- /dev/null +++ b/docs-examples/rust/schemalessexample/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "schemalessexample" +version = "0.1.0" +edition = "2021" + +[dependencies] +libtaos = { version = "0.4.3" } diff --git a/docs-examples/rust/schemalessexample/examples/influxdb_line_example.rs b/docs-examples/rust/schemalessexample/examples/influxdb_line_example.rs new file mode 100644 index 0000000000..e93888cc83 --- /dev/null +++ b/docs-examples/rust/schemalessexample/examples/influxdb_line_example.rs @@ -0,0 +1,22 @@ +use libtaos::schemaless::*; +use libtaos::*; + +fn main() { + let taos = TaosCfg::default().connect().expect("fail to connect"); + taos.raw_query("CREATE DATABASE test").unwrap(); + taos.raw_query("USE test").unwrap(); + let lines = ["meters,location=Beijing.Haidian,groupid=2 current=11.8,voltage=221,phase=0.28 1648432611249", + "meters,location=Beijing.Haidian,groupid=2 current=13.4,voltage=223,phase=0.29 1648432611250", + "meters,location=Beijing.Haidian,groupid=3 current=10.8,voltage=223,phase=0.29 1648432611249", + "meters,location=Beijing.Haidian,groupid=3 current=11.3,voltage=221,phase=0.35 1648432611250"]; + let affected_rows = taos + .schemaless_insert( + &lines, + TSDB_SML_LINE_PROTOCOL, + TSDB_SML_TIMESTAMP_MILLISECONDS, + ) + .unwrap(); + println!("affected_rows={}", affected_rows); +} + +// run with: cargo run --example influxdb_line_example diff --git a/docs-examples/rust/schemalessexample/examples/opentsdb_json_example.rs b/docs-examples/rust/schemalessexample/examples/opentsdb_json_example.rs new file mode 100644 index 0000000000..1d66bd1f2b --- /dev/null +++ b/docs-examples/rust/schemalessexample/examples/opentsdb_json_example.rs @@ -0,0 +1,25 @@ +use libtaos::schemaless::*; +use libtaos::*; + +fn main() { + let taos = TaosCfg::default().connect().expect("fail to connect"); + taos.raw_query("CREATE DATABASE test").unwrap(); + taos.raw_query("USE test").unwrap(); + let lines = [ + r#"[{"metric": "meters.current", "timestamp": 1648432611249, "value": 10.3, "tags": {"location": "Beijing.Chaoyang", "groupid": 2}}, + {"metric": "meters.voltage", "timestamp": 1648432611249, "value": 219, "tags": {"location": "Beijing.Haidian", "groupid": 1}}, + {"metric": "meters.current", "timestamp": 1648432611250, "value": 12.6, "tags": {"location": "Beijing.Chaoyang", "groupid": 2}}, + {"metric": "meters.voltage", "timestamp": 1648432611250, "value": 221, "tags": {"location": "Beijing.Haidian", "groupid": 1}}]"#, + ]; + + let affected_rows = taos + .schemaless_insert( + &lines, + TSDB_SML_JSON_PROTOCOL, + TSDB_SML_TIMESTAMP_NOT_CONFIGURED, + ) + .unwrap(); + println!("affected_rows={}", affected_rows); // affected_rows=4 +} + +// run with: cargo run --example opentsdb_json_example diff --git a/docs-examples/rust/schemalessexample/examples/opentsdb_telnet_example.rs b/docs-examples/rust/schemalessexample/examples/opentsdb_telnet_example.rs new file mode 100644 index 0000000000..18d7500714 --- /dev/null +++ b/docs-examples/rust/schemalessexample/examples/opentsdb_telnet_example.rs @@ -0,0 +1,28 @@ +use libtaos::schemaless::*; +use libtaos::*; + +fn main() { + let taos = TaosCfg::default().connect().expect("fail to connect"); + taos.raw_query("CREATE DATABASE test").unwrap(); + taos.raw_query("USE test").unwrap(); + let lines = [ + "meters.current 1648432611249 10.3 location=Beijing.Chaoyang groupid=2", + "meters.current 1648432611250 12.6 location=Beijing.Chaoyang groupid=2", + "meters.current 1648432611249 10.8 location=Beijing.Haidian groupid=3", + "meters.current 1648432611250 11.3 location=Beijing.Haidian groupid=3", + "meters.voltage 1648432611249 219 location=Beijing.Chaoyang groupid=2", + "meters.voltage 1648432611250 218 location=Beijing.Chaoyang groupid=2", + "meters.voltage 1648432611249 221 location=Beijing.Haidian groupid=3", + "meters.voltage 1648432611250 217 location=Beijing.Haidian groupid=3", + ]; + let affected_rows = taos + .schemaless_insert( + &lines, + TSDB_SML_TELNET_PROTOCOL, + TSDB_SML_TIMESTAMP_NOT_CONFIGURED, + ) + .unwrap(); + println!("affected_rows={}", affected_rows); // affected_rows=8 +} + +// run with: cargo run --example opentsdb_telnet_example diff --git a/docs-examples/rust/schemalessexample/src/main.rs b/docs-examples/rust/schemalessexample/src/main.rs new file mode 100644 index 0000000000..e7a11a969c --- /dev/null +++ b/docs-examples/rust/schemalessexample/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} From 51f0687645519384965ad7e5b399daed647d7e3f Mon Sep 17 00:00:00 2001 From: Hongze Cheng Date: Sat, 21 May 2022 03:13:58 +0000 Subject: [PATCH 06/13] fix snapshot version --- source/dnode/vnode/src/vnd/vnodeOpen.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/dnode/vnode/src/vnd/vnodeOpen.c b/source/dnode/vnode/src/vnd/vnodeOpen.c index f0af677641..a90bb7afcb 100644 --- a/source/dnode/vnode/src/vnd/vnodeOpen.c +++ b/source/dnode/vnode/src/vnd/vnodeOpen.c @@ -77,7 +77,8 @@ SVnode *vnodeOpen(const char *path, STfs *pTfs, SMsgCb msgCb) { pVnode->path = (char *)&pVnode[1]; strcpy(pVnode->path, path); pVnode->config = info.config; - pVnode->state = info.state; + pVnode->state.committed = info.state.committed; + pVnode->state.applied = info.state.committed; pVnode->pTfs = pTfs; pVnode->msgCb = msgCb; From 305fa25490b350ad7aa1cf5bd074d4e27d5ed4b3 Mon Sep 17 00:00:00 2001 From: yihaoDeng Date: Sat, 21 May 2022 11:18:32 +0800 Subject: [PATCH 07/13] enh: delete redundancy code --- include/libs/transport/rpcHead.h | 79 - include/libs/transport/transport.h | 3 +- source/libs/transport/inc/rpcCache.h | 34 - source/libs/transport/inc/rpcLog.h | 72 - source/libs/transport/inc/rpcTcp.h | 40 - source/libs/transport/inc/rpcUdp.h | 41 - source/libs/transport/inc/transComm.h | 33 +- source/libs/transport/inc/transLog.h | 38 + source/libs/transport/inc/transportInt.h | 4 +- source/libs/transport/src/rpcCache.c | 294 ---- source/libs/transport/src/rpcMain.c | 1682 ---------------------- source/libs/transport/src/rpcTcp.c | 657 --------- source/libs/transport/src/rpcUdp.c | 261 ---- source/libs/transport/test/pushServer.c | 2 +- source/libs/transport/test/rclient.c | 2 +- source/libs/transport/test/rserver.c | 2 +- source/libs/transport/test/syncClient.c | 2 +- source/libs/transport/test/transUT.cpp | 2 +- 18 files changed, 58 insertions(+), 3190 deletions(-) delete mode 100644 include/libs/transport/rpcHead.h delete mode 100644 source/libs/transport/inc/rpcCache.h delete mode 100644 source/libs/transport/inc/rpcLog.h delete mode 100644 source/libs/transport/inc/rpcTcp.h delete mode 100644 source/libs/transport/inc/rpcUdp.h create mode 100644 source/libs/transport/inc/transLog.h delete mode 100644 source/libs/transport/src/rpcCache.c delete mode 100644 source/libs/transport/src/rpcMain.c delete mode 100644 source/libs/transport/src/rpcTcp.c delete mode 100644 source/libs/transport/src/rpcUdp.c diff --git a/include/libs/transport/rpcHead.h b/include/libs/transport/rpcHead.h deleted file mode 100644 index 5ddf1a83c9..0000000000 --- a/include/libs/transport/rpcHead.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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_RPCHEAD_H -#define TDENGINE_RPCHEAD_H - -#include -#ifdef __cplusplus -extern "C" { -#endif - -#define RPC_CONN_TCP 2 - -extern int tsRpcOverhead; - -typedef struct { - void* msg; - int msgLen; - uint32_t ip; - uint16_t port; - int connType; - void* shandle; - void* thandle; - void* chandle; -} SRecvInfo; - -#pragma pack(push, 1) - -typedef struct { - char version : 4; // RPC version - char comp : 4; // compression algorithm, 0:no compression 1:lz4 - char resflag : 2; // reserved bits - char spi : 3; // security parameter index - char encrypt : 3; // encrypt algorithm, 0: no encryption - uint16_t tranId; // transcation ID - uint32_t linkUid; // for unique connection ID assigned by client - uint64_t ahandle; // ahandle assigned by client - uint32_t sourceId; // source ID, an index for connection list - uint32_t destId; // destination ID, an index for connection list - uint32_t destIp; // destination IP address, for NAT scenario - char user[TSDB_UNI_LEN]; // user ID - uint16_t port; // for UDP only, port may be changed - char empty[1]; // reserved - uint16_t msgType; // message type - int32_t msgLen; // message length including the header iteslf - uint32_t msgVer; - int32_t code; // code in response message - uint8_t content[0]; // message body starts from here -} SRpcHead; - -typedef struct { - int32_t reserved; - int32_t contLen; -} SRpcComp; - -typedef struct { - uint32_t timeStamp; - uint8_t auth[TSDB_AUTH_LEN]; -} SRpcDigest; - -#pragma pack(pop) - -#ifdef __cplusplus -} -#endif - -#endif // TDENGINE_RPCHEAD_H diff --git a/include/libs/transport/transport.h b/include/libs/transport/transport.h index f5ffc125ea..136e8b35cd 100644 --- a/include/libs/transport/transport.h +++ b/include/libs/transport/transport.h @@ -20,9 +20,8 @@ extern "C" { #endif - #ifdef __cplusplus } #endif -#endif /*_TD_TRANSPORT_H_*/ \ No newline at end of file +#endif /*_TD_TRANSPORT_H_*/ diff --git a/source/libs/transport/inc/rpcCache.h b/source/libs/transport/inc/rpcCache.h deleted file mode 100644 index 5148f5e23c..0000000000 --- a/source/libs/transport/inc/rpcCache.h +++ /dev/null @@ -1,34 +0,0 @@ -/* - * 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_RPC_CACHE_H -#define TDENGINE_RPC_CACHE_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -void *rpcOpenConnCache(int maxSessions, void (*cleanFp)(void *), void *tmrCtrl, int64_t keepTimer); -void rpcCloseConnCache(void *handle); -void rpcAddConnIntoCache(void *handle, void *data, char *fqdn, uint16_t port, int8_t connType); -void *rpcGetConnFromCache(void *handle, char *fqdn, uint16_t port, int8_t connType); - -#ifdef __cplusplus -} -#endif - -#endif // TDENGINE_RPC_CACHE_H diff --git a/source/libs/transport/inc/rpcLog.h b/source/libs/transport/inc/rpcLog.h deleted file mode 100644 index a5db866932..0000000000 --- a/source/libs/transport/inc/rpcLog.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * 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_RPC_LOG_H -#define TDENGINE_RPC_LOG_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include "tlog.h" - -#define tFatal(...) \ - { \ - if (rpcDebugFlag & DEBUG_FATAL) { \ - taosPrintLog("RPC FATAL ", DEBUG_FATAL, rpcDebugFlag, __VA_ARGS__); \ - } \ - } -#define tError(...) \ - { \ - if (rpcDebugFlag & DEBUG_ERROR) { \ - taosPrintLog("RPC ERROR ", DEBUG_ERROR, rpcDebugFlag, __VA_ARGS__); \ - } \ - } -#define tWarn(...) \ - { \ - if (rpcDebugFlag & DEBUG_WARN) { \ - taosPrintLog("RPC WARN ", DEBUG_WARN, rpcDebugFlag, __VA_ARGS__); \ - } \ - } -#define tInfo(...) \ - { \ - if (rpcDebugFlag & DEBUG_INFO) { \ - taosPrintLog("RPC ", DEBUG_INFO, rpcDebugFlag, __VA_ARGS__); \ - } \ - } -#define tDebug(...) \ - { \ - if (rpcDebugFlag & DEBUG_DEBUG) { \ - taosPrintLog("RPC ", DEBUG_DEBUG, rpcDebugFlag, __VA_ARGS__); \ - } \ - } -#define tTrace(...) \ - { \ - if (rpcDebugFlag & DEBUG_TRACE) { \ - taosPrintLog("RPC ", DEBUG_TRACE, rpcDebugFlag, __VA_ARGS__); \ - } \ - } -#define tDump(x, y) \ - { \ - if (rpcDebugFlag & DEBUG_DUMP) { \ - taosDumpData((unsigned char *)x, y); \ - } \ - } - -#ifdef __cplusplus -} -#endif - -#endif // TDENGINE_RPC_LOG_H diff --git a/source/libs/transport/inc/rpcTcp.h b/source/libs/transport/inc/rpcTcp.h deleted file mode 100644 index ad42307516..0000000000 --- a/source/libs/transport/inc/rpcTcp.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * 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 _rpc_tcp_header_ -#define _rpc_tcp_header_ -#include - -#ifdef __cplusplus -extern "C" { -#endif - -void *taosInitTcpServer(uint32_t ip, uint16_t port, char *label, int numOfThreads, void *fp, void *shandle); -void taosStopTcpServer(void *param); -void taosCleanUpTcpServer(void *param); - -void *taosInitTcpClient(uint32_t ip, uint16_t port, char *label, int num, void *fp, void *shandle); -void taosStopTcpClient(void *chandle); -void taosCleanUpTcpClient(void *chandle); -void *taosOpenTcpClientConnection(void *shandle, void *thandle, uint32_t ip, uint16_t port); - -void taosCloseTcpConnection(void *chandle); -int taosSendTcpData(uint32_t ip, uint16_t port, void *data, int len, void *chandle); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/source/libs/transport/inc/rpcUdp.h b/source/libs/transport/inc/rpcUdp.h deleted file mode 100644 index 0c651d07ed..0000000000 --- a/source/libs/transport/inc/rpcUdp.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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 _rpc_udp_header_ -#define _rpc_udp_header_ - -#ifdef __cplusplus -extern "C" { -#endif - -#include "taosdef.h" - -void *taosInitUdpConnection(uint32_t ip, uint16_t port, char *label, int, void *fp, void *shandle); -void taosStopUdpConnection(void *handle); -void taosCleanUpUdpConnection(void *handle); -int taosSendUdpData(uint32_t ip, uint16_t port, void *data, int dataLen, void *chandle); -void *taosOpenUdpConnection(void *shandle, void *thandle, uint32_t ip, uint16_t port); - -void taosFreeMsgHdr(void *hdr); -int taosMsgHdrSize(void *hdr); -void taosSendMsgHdr(void *hdr, TdFilePtr pFile); -void taosInitMsgHdr(void **hdr, void *dest, int maxPkts); -void taosSetMsgHdrData(void *hdr, char *data, int dataLen); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/source/libs/transport/inc/transComm.h b/source/libs/transport/inc/transComm.h index e4e79ccf47..3f82d6e2d8 100644 --- a/source/libs/transport/inc/transComm.h +++ b/source/libs/transport/inc/transComm.h @@ -12,7 +12,8 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -#ifdef USE_UV +#ifndef _TD_TRANSPORT_COMM_H +#define _TD_TRANSPORT_COMM_H #ifdef __cplusplus extern "C" { @@ -22,9 +23,6 @@ extern "C" { #include "lz4.h" #include "os.h" #include "osSocket.h" -#include "rpcCache.h" -#include "rpcHead.h" -#include "rpcLog.h" #include "taoserror.h" #include "tglobal.h" #include "thash.h" @@ -33,6 +31,7 @@ extern "C" { #include "tmd5.h" #include "tmempool.h" #include "tmsg.h" +#include "transLog.h" #include "transportInt.h" #include "tref.h" #include "trpc.h" @@ -193,12 +192,7 @@ typedef enum { ConnNormal, ConnAcquire, ConnRelease, ConnBroken, ConnInPool } Co #define container_of(ptr, type, member) ((type*)((char*)(ptr)-offsetof(type, member))) #define RPC_RESERVE_SIZE (sizeof(STranConnCtx)) -#define RPC_MSG_OVERHEAD (sizeof(SRpcHead) + sizeof(SRpcDigest)) -#define rpcHeadFromCont(cont) ((SRpcHead*)((char*)cont - sizeof(SRpcHead))) -#define rpcContFromHead(msg) (msg + sizeof(SRpcHead)) -#define rpcMsgLenFromCont(contLen) (contLen + sizeof(SRpcHead)) -#define rpcContLenFromMsg(msgLen) (msgLen - sizeof(SRpcHead)) -#define rpcIsReq(type) (type & 1U) +#define rpcIsReq(type) (type & 1U) #define TRANS_RESERVE_SIZE (sizeof(STranConnCtx)) @@ -209,15 +203,14 @@ typedef enum { ConnNormal, ConnAcquire, ConnRelease, ConnBroken, ConnInPool } Co #define transContLenFromMsg(msgLen) (msgLen - sizeof(STransMsgHead)); #define transIsReq(type) (type & 1U) -int rpcAuthenticateMsg(void* pMsg, int msgLen, void* pAuth, void* pKey); -void rpcBuildAuthHead(void* pMsg, int msgLen, void* pAuth, void* pKey); -int32_t rpcCompressRpcMsg(char* pCont, int32_t contLen); -SRpcHead* rpcDecompressRpcMsg(SRpcHead* pHead); - -int transAuthenticateMsg(void* pMsg, int msgLen, void* pAuth, void* pKey); -void transBuildAuthHead(void* pMsg, int msgLen, void* pAuth, void* pKey); -bool transCompressMsg(char* msg, int32_t len, int32_t* flen); -bool transDecompressMsg(char* msg, int32_t len, int32_t* flen); +// int rpcAuthenticateMsg(void* pMsg, int msgLen, void* pAuth, void* pKey); +// void rpcBuildAuthHead(void* pMsg, int msgLen, void* pAuth, void* pKey); +//// int32_t rpcCompressRpcMsg(char* pCont, int32_t contLen); +// +// int transAuthenticateMsg(void* pMsg, int msgLen, void* pAuth, void* pKey); +// void transBuildAuthHead(void* pMsg, int msgLen, void* pAuth, void* pKey); +// bool transCompressMsg(char* msg, int32_t len, int32_t* flen); +// bool transDecompressMsg(char* msg, int32_t len, int32_t* flen); void transFreeMsg(void* msg); @@ -365,4 +358,4 @@ void transThreadOnce(); } #endif -#endif +#endif // _TD_TRANSPORT_COMM_H diff --git a/source/libs/transport/inc/transLog.h b/source/libs/transport/inc/transLog.h new file mode 100644 index 0000000000..ebf231cfcf --- /dev/null +++ b/source/libs/transport/inc/transLog.h @@ -0,0 +1,38 @@ +/* + * 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 _TD_TRANSPORT_LOG_H +#define _TD_TRANSPORT_LOG_H + +#ifdef __cplusplus +extern "C" { +#endif + +// clang-format off +#include "tlog.h" + +#define tFatal(...) do {if (rpcDebugFlag & DEBUG_FATAL){ taosPrintLog("RPC FATAL ", DEBUG_FATAL, rpcDebugFlag, __VA_ARGS__); }} while (0) +#define tError(...)do { if (rpcDebugFlag & DEBUG_ERROR){ taosPrintLog("RPC ERROR ", DEBUG_ERROR, rpcDebugFlag, __VA_ARGS__); } } while(0) +#define tWarn(...) do { if (rpcDebugFlag & DEBUG_WARN) { taosPrintLog("RPC WARN ", DEBUG_WARN, rpcDebugFlag, __VA_ARGS__); }} while(0) +#define tInfo(...) do { if (rpcDebugFlag & DEBUG_INFO) { taosPrintLog("RPC ", DEBUG_INFO, rpcDebugFlag, __VA_ARGS__); }} while(0) +#define tDebug(...) do {if (rpcDebugFlag & DEBUG_DEBUG){ taosPrintLog("RPC ", DEBUG_DEBUG, rpcDebugFlag, __VA_ARGS__); }} while(0) +#define tTrace(...) do {if (rpcDebugFlag & DEBUG_TRACE){ taosPrintLog("RPC ", DEBUG_TRACE, rpcDebugFlag, __VA_ARGS__); }} while(0) +#define tDump(x, y) do {if (rpcDebugFlag & DEBUG_DUMP) { taosDumpData((unsigned char *)x, y); } } while(0) +// clang-format on +#ifdef __cplusplus +} +#endif + +#endif // __TRANS_LOG_H diff --git a/source/libs/transport/inc/transportInt.h b/source/libs/transport/inc/transportInt.h index c8972067d8..a498571f33 100644 --- a/source/libs/transport/inc/transportInt.h +++ b/source/libs/transport/inc/transportInt.h @@ -21,14 +21,12 @@ #endif #include "lz4.h" #include "os.h" -#include "rpcCache.h" -#include "rpcHead.h" -#include "rpcLog.h" #include "taoserror.h" #include "tglobal.h" #include "thash.h" #include "tidpool.h" #include "tmsg.h" +#include "transLog.h" #include "tref.h" #include "trpc.h" #include "ttimer.h" diff --git a/source/libs/transport/src/rpcCache.c b/source/libs/transport/src/rpcCache.c deleted file mode 100644 index e02de2d8b9..0000000000 --- a/source/libs/transport/src/rpcCache.c +++ /dev/null @@ -1,294 +0,0 @@ -/* - * 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 . - */ - -#include "rpcCache.h" -#include "os.h" -#include "rpcLog.h" -#include "taosdef.h" -#include "tglobal.h" -#include "tmempool.h" -#include "ttimer.h" -#include "tutil.h" - -typedef struct SConnHash { - char fqdn[TSDB_FQDN_LEN]; - uint16_t port; - char connType; - struct SConnHash *prev; - struct SConnHash *next; - void * data; - uint64_t time; -} SConnHash; - -typedef struct { - SConnHash ** connHashList; - mpool_h connHashMemPool; - int maxSessions; - int total; - int * count; - int64_t keepTimer; - TdThreadMutex mutex; - void (*cleanFp)(void *); - void * tmrCtrl; - void * pTimer; - int64_t *lockedBy; -} SConnCache; - -static int rpcHashConn(void *handle, char *fqdn, uint16_t port, int8_t connType); -static void rpcLockCache(int64_t *lockedBy); -static void rpcUnlockCache(int64_t *lockedBy); -static void rpcCleanConnCache(void *handle, void *tmrId); -static void rpcRemoveExpiredNodes(SConnCache *pCache, SConnHash *pNode, int hash, uint64_t time); - -void *rpcOpenConnCache(int maxSessions, void (*cleanFp)(void *), void *tmrCtrl, int64_t keepTimer) { - SConnHash **connHashList; - mpool_h connHashMemPool; - SConnCache *pCache; - - connHashMemPool = taosMemPoolInit(maxSessions, sizeof(SConnHash)); - if (connHashMemPool == 0) return NULL; - - connHashList = taosMemoryCalloc(sizeof(SConnHash *), maxSessions); - if (connHashList == 0) { - taosMemPoolCleanUp(connHashMemPool); - return NULL; - } - - pCache = taosMemoryMalloc(sizeof(SConnCache)); - if (pCache == NULL) { - taosMemPoolCleanUp(connHashMemPool); - taosMemoryFree(connHashList); - return NULL; - } - memset(pCache, 0, sizeof(SConnCache)); - - pCache->count = taosMemoryCalloc(sizeof(int), maxSessions); - pCache->total = 0; - pCache->keepTimer = keepTimer; - pCache->maxSessions = maxSessions; - pCache->connHashMemPool = connHashMemPool; - pCache->connHashList = connHashList; - pCache->cleanFp = cleanFp; - pCache->tmrCtrl = tmrCtrl; - pCache->lockedBy = taosMemoryCalloc(sizeof(int64_t), maxSessions); - taosTmrReset(rpcCleanConnCache, (int32_t)(pCache->keepTimer * 2), pCache, pCache->tmrCtrl, &pCache->pTimer); - - taosThreadMutexInit(&pCache->mutex, NULL); - - return pCache; -} - -void rpcCloseConnCache(void *handle) { - SConnCache *pCache; - - pCache = (SConnCache *)handle; - if (pCache == NULL || pCache->maxSessions == 0) return; - - taosThreadMutexLock(&pCache->mutex); - - taosTmrStopA(&(pCache->pTimer)); - - if (pCache->connHashMemPool) taosMemPoolCleanUp(pCache->connHashMemPool); - - taosMemoryFreeClear(pCache->connHashList); - taosMemoryFreeClear(pCache->count); - taosMemoryFreeClear(pCache->lockedBy); - - taosThreadMutexUnlock(&pCache->mutex); - - taosThreadMutexDestroy(&pCache->mutex); - - memset(pCache, 0, sizeof(SConnCache)); - taosMemoryFree(pCache); -} - -void rpcAddConnIntoCache(void *handle, void *data, char *fqdn, uint16_t port, int8_t connType) { - int hash; - SConnHash * pNode; - SConnCache *pCache; - - uint64_t time = taosGetTimestampMs(); - - pCache = (SConnCache *)handle; - assert(pCache); - assert(data); - - hash = rpcHashConn(pCache, fqdn, port, connType); - pNode = (SConnHash *)taosMemPoolMalloc(pCache->connHashMemPool); - tstrncpy(pNode->fqdn, fqdn, sizeof(pNode->fqdn)); - pNode->port = port; - pNode->connType = connType; - pNode->data = data; - pNode->prev = NULL; - pNode->time = time; - - rpcLockCache(pCache->lockedBy + hash); - - pNode->next = pCache->connHashList[hash]; - if (pCache->connHashList[hash] != NULL) (pCache->connHashList[hash])->prev = pNode; - pCache->connHashList[hash] = pNode; - - pCache->count[hash]++; - rpcRemoveExpiredNodes(pCache, pNode->next, hash, time); - - rpcUnlockCache(pCache->lockedBy + hash); - - pCache->total++; - // tTrace("%p %s:%hu:%d:%d:%p added into cache, connections:%d", data, fqdn, port, connType, hash, pNode, - // pCache->count[hash]); - - return; -} - -void *rpcGetConnFromCache(void *handle, char *fqdn, uint16_t port, int8_t connType) { - int hash; - SConnHash * pNode; - SConnCache *pCache; - void * pData = NULL; - - pCache = (SConnCache *)handle; - assert(pCache); - - uint64_t time = taosGetTimestampMs(); - - hash = rpcHashConn(pCache, fqdn, port, connType); - rpcLockCache(pCache->lockedBy + hash); - - pNode = pCache->connHashList[hash]; - while (pNode) { - if (time >= pCache->keepTimer + pNode->time) { - rpcRemoveExpiredNodes(pCache, pNode, hash, time); - pNode = NULL; - break; - } - - if (strcmp(pNode->fqdn, fqdn) == 0 && pNode->port == port && pNode->connType == connType) break; - - pNode = pNode->next; - } - - if (pNode) { - rpcRemoveExpiredNodes(pCache, pNode->next, hash, time); - - if (pNode->prev) { - pNode->prev->next = pNode->next; - } else { - pCache->connHashList[hash] = pNode->next; - } - - if (pNode->next) { - pNode->next->prev = pNode->prev; - } - - pData = pNode->data; - taosMemPoolFree(pCache->connHashMemPool, (char *)pNode); - pCache->total--; - pCache->count[hash]--; - } - - rpcUnlockCache(pCache->lockedBy + hash); - - if (pData) { - // tTrace("%p %s:%hu:%d:%d:%p retrieved from cache, connections:%d", pData, fqdn, port, connType, hash, pNode, - // pCache->count[hash]); - } else { - // tTrace("%s:%hu:%d:%d failed to retrieve conn from cache, connections:%d", fqdn, port, connType, hash, - // pCache->count[hash]); - } - - return pData; -} - -static void rpcCleanConnCache(void *handle, void *tmrId) { - int hash; - SConnHash * pNode; - SConnCache *pCache; - - pCache = (SConnCache *)handle; - if (pCache == NULL || pCache->maxSessions == 0) return; - if (pCache->pTimer != tmrId) return; - - taosThreadMutexLock(&pCache->mutex); - uint64_t time = taosGetTimestampMs(); - - for (hash = 0; hash < pCache->maxSessions; ++hash) { - rpcLockCache(pCache->lockedBy + hash); - pNode = pCache->connHashList[hash]; - rpcRemoveExpiredNodes(pCache, pNode, hash, time); - rpcUnlockCache(pCache->lockedBy + hash); - } - - // tTrace("timer, total connections in cache:%d", pCache->total); - taosTmrReset(rpcCleanConnCache, (int32_t)(pCache->keepTimer * 2), pCache, pCache->tmrCtrl, &pCache->pTimer); - taosThreadMutexUnlock(&pCache->mutex); -} - -static void rpcRemoveExpiredNodes(SConnCache *pCache, SConnHash *pNode, int hash, uint64_t time) { - if (pNode == NULL || (time < pCache->keepTimer + pNode->time)) return; - - SConnHash *pPrev = pNode->prev, *pNext; - - while (pNode) { - (*pCache->cleanFp)(pNode->data); - pNext = pNode->next; - pCache->total--; - pCache->count[hash]--; - // tTrace("%p %s:%hu:%d:%d:%p removed from cache, connections:%d", pNode->data, pNode->fqdn, pNode->port, - // pNode->connType, hash, pNode, - // pCache->count[hash]); - taosMemPoolFree(pCache->connHashMemPool, (char *)pNode); - pNode = pNext; - } - - if (pPrev) - pPrev->next = NULL; - else - pCache->connHashList[hash] = NULL; -} - -static int rpcHashConn(void *handle, char *fqdn, uint16_t port, int8_t connType) { - SConnCache *pCache = (SConnCache *)handle; - int hash = 0; - char * temp = fqdn; - - while (*temp) { - hash += *temp; - ++temp; - } - - hash += port; - hash += connType; - - hash = hash % pCache->maxSessions; - - return hash; -} - -static void rpcLockCache(int64_t *lockedBy) { - int64_t tid = taosGetSelfPthreadId(); - int i = 0; - while (atomic_val_compare_exchange_64(lockedBy, 0, tid) != 0) { - if (++i % 100 == 0) { - sched_yield(); - } - } -} - -static void rpcUnlockCache(int64_t *lockedBy) { - int64_t tid = taosGetSelfPthreadId(); - if (atomic_val_compare_exchange_64(lockedBy, tid, 0) != tid) { - assert(false); - } -} diff --git a/source/libs/transport/src/rpcMain.c b/source/libs/transport/src/rpcMain.c deleted file mode 100644 index 0e425970da..0000000000 --- a/source/libs/transport/src/rpcMain.c +++ /dev/null @@ -1,1682 +0,0 @@ -/* - * 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 . - */ - -#include "lz4.h" -#include "transportInt.h" -#include "os.h" -#include "rpcCache.h" -#include "rpcHead.h" -#include "rpcLog.h" -#include "rpcTcp.h" -#include "rpcUdp.h" -#include "taoserror.h" -#include "tglobal.h" -#include "thash.h" -#include "tidpool.h" -#include "tmd5.h" -#include "tmempool.h" -#include "tmsg.h" -#include "tref.h" -#include "trpc.h" -#include "ttimer.h" -#include "tutil.h" - -static TdThreadOnce tsRpcInitOnce = PTHREAD_ONCE_INIT; - -int tsRpcMaxUdpSize = 15000; // bytes -int tsProgressTimer = 100; -// not configurable -int tsRpcMaxRetry; -int tsRpcHeadSize; -int tsRpcOverhead; - -SHashObj *tsFqdnHash; - -#ifndef USE_UV - -typedef struct { - int sessions; // number of sessions allowed - int numOfThreads; // number of threads to process incoming messages - int idleTime; // milliseconds; - uint16_t localPort; - int8_t connType; - int index; // for UDP server only, round robin for multiple threads - char label[TSDB_LABEL_LEN]; - - char user[TSDB_UNI_LEN]; // meter ID - char spi; // security parameter index - char encrypt; // encrypt algorithm - char secret[TSDB_PASSWORD_LEN]; // secret for the link - char ckey[TSDB_PASSWORD_LEN]; // ciphering key - - void (*cfp)(void *parent, SRpcMsg *, SEpSet *); - int (*afp)(void *parent, char *user, char *spi, char *encrypt, char *secret, char *ckey); - - int32_t refCount; - void * parent; - void * idPool; // handle to ID pool - void * tmrCtrl; // handle to timer - SHashObj * hash; // handle returned by hash utility - void * tcphandle; // returned handle from TCP initialization - void * udphandle; // returned handle from UDP initialization - void * pCache; // connection cache - TdThreadMutex mutex; - struct SRpcConn *connList; // connection list -} SRpcInfo; - -typedef struct { - SRpcInfo * pRpc; // associated SRpcInfo - SEpSet epSet; // ip list provided by app - void * ahandle; // handle provided by app - struct SRpcConn *pConn; // pConn allocated - tmsg_t msgType; // message type - uint8_t * pCont; // content provided by app - int32_t contLen; // content length - int32_t code; // error code - int16_t numOfTry; // number of try for different servers - int8_t oldInUse; // server EP inUse passed by app - int8_t redirect; // flag to indicate redirect - int8_t connType; // connection type - int64_t rid; // refId returned by taosAddRef - SRpcMsg * pRsp; // for synchronous API - tsem_t * pSem; // for synchronous API - SEpSet * pSet; // for synchronous API - char msg[0]; // RpcHead starts from here -} SRpcReqContext; - -#define RPC_MSG_OVERHEAD (sizeof(SRpcReqContext) + sizeof(SRpcHead) + sizeof(SRpcDigest)) -#define rpcHeadFromCont(cont) ((SRpcHead *)((char *)cont - sizeof(SRpcHead))) -#define rpcContFromHead(msg) (msg + sizeof(SRpcHead)) -#define rpcMsgLenFromCont(contLen) (contLen + sizeof(SRpcHead)) -#define rpcContLenFromMsg(msgLen) (msgLen - sizeof(SRpcHead)) -#define rpcIsReq(type) (type & 1U) - -typedef struct SRpcConn { - char info[48]; // debug info: label + pConn + ahandle - int sid; // session ID - uint32_t ownId; // own link ID - uint32_t peerId; // peer link ID - char user[TSDB_UNI_LEN]; // user ID for the link - char spi; // security parameter index - char encrypt; // encryption, 0:1 - char secret[TSDB_PASSWORD_LEN]; // secret for the link - char ckey[TSDB_PASSWORD_LEN]; // ciphering key - char secured; // if set to 1, no authentication - uint16_t localPort; // for UDP only - uint32_t linkUid; // connection unique ID assigned by client - uint32_t peerIp; // peer IP - uint16_t peerPort; // peer port - char peerFqdn[TSDB_FQDN_LEN]; // peer FQDN or ip string - uint16_t tranId; // outgoing transcation ID, for build message - uint16_t outTranId; // outgoing transcation ID - uint16_t inTranId; // transcation ID for incoming msg - tmsg_t outType; // message type for outgoing request - tmsg_t inType; // message type for incoming request - void * chandle; // handle passed by TCP/UDP connection layer - void * ahandle; // handle provided by upper app layter - int retry; // number of retry for sending request - int tretry; // total retry - void * pTimer; // retry timer to monitor the response - void * pIdleTimer; // idle timer - char * pRspMsg; // response message including header - int rspMsgLen; // response messag length - char * pReqMsg; // request message including header - int reqMsgLen; // request message length - SRpcInfo * pRpc; // the associated SRpcInfo - int8_t connType; // connection type - int64_t lockedBy; // lock for connection - SRpcReqContext *pContext; // request context -} SRpcConn; - -static int tsRpcRefId = -1; -static int32_t tsRpcNum = 0; - -// static TdThreadOnce tsRpcInit = PTHREAD_ONCE_INIT; - -// server:0 client:1 tcp:2 udp:0 -#define RPC_CONN_UDPS 0 -#define RPC_CONN_UDPC 1 -#define RPC_CONN_TCPS 2 -#define RPC_CONN_TCPC 3 - -void *(*taosInitConn[])(uint32_t ip, uint16_t port, char *label, int threads, void *fp, void *shandle) = { - taosInitUdpConnection, taosInitUdpConnection, taosInitTcpServer, taosInitTcpClient}; - -void (*taosCleanUpConn[])(void *thandle) = {taosCleanUpUdpConnection, taosCleanUpUdpConnection, taosCleanUpTcpServer, - taosCleanUpTcpClient}; - -void (*taosStopConn[])(void *thandle) = { - taosStopUdpConnection, - taosStopUdpConnection, - taosStopTcpServer, - taosStopTcpClient, -}; - -int (*taosSendData[])(uint32_t ip, uint16_t port, void *data, int len, void *chandle) = { - taosSendUdpData, taosSendUdpData, taosSendTcpData, taosSendTcpData}; - -void *(*taosOpenConn[])(void *shandle, void *thandle, uint32_t ip, uint16_t port) = { - taosOpenUdpConnection, - taosOpenUdpConnection, - NULL, - taosOpenTcpClientConnection, -}; - -void (*taosCloseConn[])(void *chandle) = {NULL, NULL, taosCloseTcpConnection, taosCloseTcpConnection}; - -static SRpcConn *rpcOpenConn(SRpcInfo *pRpc, char *peerFqdn, uint16_t peerPort, int8_t connType); -static void rpcCloseConn(void *thandle); -static SRpcConn *rpcSetupConnToServer(SRpcReqContext *pContext); -static SRpcConn *rpcAllocateClientConn(SRpcInfo *pRpc); -static SRpcConn *rpcAllocateServerConn(SRpcInfo *pRpc, SRecvInfo *pRecv); -static SRpcConn *rpcGetConnObj(SRpcInfo *pRpc, int sid, SRecvInfo *pRecv); - -static void rpcSendReqToServer(SRpcInfo *pRpc, SRpcReqContext *pContext); -static void rpcSendQuickRsp(SRpcConn *pConn, int32_t code); -static void rpcSendErrorMsgToPeer(SRecvInfo *pRecv, int32_t code); -static void rpcSendMsgToPeer(SRpcConn *pConn, void *data, int dataLen); -static void rpcSendReqHead(SRpcConn *pConn); - -static void *rpcProcessMsgFromPeer(SRecvInfo *pRecv); -static void rpcProcessIncomingMsg(SRpcConn *pConn, SRpcHead *pHead, SRpcReqContext *pContext); -static void rpcProcessConnError(void *param, void *id); -static void rpcProcessRetryTimer(void *, void *); -static void rpcProcessIdleTimer(void *param, void *tmrId); -static void rpcProcessProgressTimer(void *param, void *tmrId); - -static void rpcFreeMsg(void *msg); -static int32_t rpcCompressRpcMsg(char *pCont, int32_t contLen); -static SRpcHead *rpcDecompressRpcMsg(SRpcHead *pHead); -static int rpcAddAuthPart(SRpcConn *pConn, char *msg, int msgLen); -static int rpcCheckAuthentication(SRpcConn *pConn, char *msg, int msgLen); -static void rpcLockConn(SRpcConn *pConn); -static void rpcUnlockConn(SRpcConn *pConn); -static void rpcAddRef(SRpcInfo *pRpc); -static void rpcDecRef(SRpcInfo *pRpc); - -static void rpcFree(void *p) { - tTrace("free mem: %p", p); - taosMemoryFree(p); -} - -static void rpcInitImp(void) { - tsProgressTimer = tsRpcTimer / 2; - tsRpcMaxRetry = tsRpcMaxTime * 1000 / tsProgressTimer; - tsRpcHeadSize = RPC_MSG_OVERHEAD; - tsRpcOverhead = sizeof(SRpcReqContext); - - tsRpcRefId = taosOpenRef(200, rpcFree); - - tsFqdnHash = taosHashInit(64, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), false, HASH_ENTRY_LOCK); -} - -int32_t rpcInit() { - taosThreadOnce(&tsRpcInitOnce, rpcInitImp); - return 0; -} - -void rpcCleanup(void) { - taosCloseRef(tsRpcRefId); - taosHashClear(tsFqdnHash); - taosHashCleanup(tsFqdnHash); - tsFqdnHash = NULL; - tsRpcRefId = -1; -} - -void *rpcOpen(const SRpcInit *pInit) { - SRpcInfo *pRpc; - - // taosThreadOnce(&tsRpcInit, rpcInit); - - pRpc = (SRpcInfo *)taosMemoryCalloc(1, sizeof(SRpcInfo)); - if (pRpc == NULL) return NULL; - - if (pInit->label) tstrncpy(pRpc->label, pInit->label, tListLen(pInit->label)); - - pRpc->connType = pInit->connType; - if (pRpc->connType == TAOS_CONN_CLIENT) { - pRpc->numOfThreads = pInit->numOfThreads; - if (pRpc->numOfThreads >= 10) { - pRpc->numOfThreads = 10; - } - } else { - pRpc->numOfThreads = pInit->numOfThreads > TSDB_MAX_RPC_THREADS ? TSDB_MAX_RPC_THREADS : pInit->numOfThreads; - } - pRpc->idleTime = pInit->idleTime; - pRpc->localPort = pInit->localPort; - pRpc->afp = pInit->afp; - pRpc->sessions = pInit->sessions + 1; - if (pInit->user) tstrncpy(pRpc->user, pInit->user, sizeof(pRpc->user)); - if (pInit->secret) memcpy(pRpc->secret, pInit->secret, sizeof(pRpc->secret)); - if (pInit->ckey) tstrncpy(pRpc->ckey, pInit->ckey, sizeof(pRpc->ckey)); - pRpc->spi = pInit->spi; - pRpc->cfp = pInit->cfp; - pRpc->afp = pInit->afp; - pRpc->parent = pInit->parent; - pRpc->refCount = 1; - - atomic_add_fetch_32(&tsRpcNum, 1); - - size_t size = sizeof(SRpcConn) * pRpc->sessions; - pRpc->connList = (SRpcConn *)taosMemoryCalloc(1, size); - if (pRpc->connList == NULL) { - tError("%s failed to allocate memory for taos connections, size:%" PRId64, pRpc->label, (int64_t)size); - rpcClose(pRpc); - return NULL; - } - - pRpc->idPool = taosInitIdPool(pRpc->sessions - 1); - if (pRpc->idPool == NULL) { - tError("%s failed to init ID pool", pRpc->label); - rpcClose(pRpc); - return NULL; - } - - pRpc->tmrCtrl = taosTmrInit(pRpc->sessions * 2 + 1, 50, 10000, pRpc->label); - if (pRpc->tmrCtrl == NULL) { - tError("%s failed to init timers", pRpc->label); - rpcClose(pRpc); - return NULL; - } - - if (pRpc->connType == TAOS_CONN_SERVER) { - pRpc->hash = taosHashInit(pRpc->sessions, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), true, true); - if (pRpc->hash == NULL) { - tError("%s failed to init string hash", pRpc->label); - rpcClose(pRpc); - return NULL; - } - } else { - pRpc->pCache = rpcOpenConnCache(pRpc->sessions, rpcCloseConn, pRpc->tmrCtrl, pRpc->idleTime * 20); - if (pRpc->pCache == NULL) { - tError("%s failed to init connection cache", pRpc->label); - rpcClose(pRpc); - return NULL; - } - } - - taosThreadMutexInit(&pRpc->mutex, NULL); - - pRpc->tcphandle = (*taosInitConn[pRpc->connType | RPC_CONN_TCP])(0, pRpc->localPort, pRpc->label, pRpc->numOfThreads, - rpcProcessMsgFromPeer, pRpc); - pRpc->udphandle = - (*taosInitConn[pRpc->connType])(0, pRpc->localPort, pRpc->label, pRpc->numOfThreads, rpcProcessMsgFromPeer, pRpc); - - if (pRpc->tcphandle == NULL || pRpc->udphandle == NULL) { - tError("%s failed to init network, port:%d", pRpc->label, pRpc->localPort); - rpcClose(pRpc); - return NULL; - } - - tDebug("%s rpc is opened, threads:%d sessions:%d", pRpc->label, pRpc->numOfThreads, pInit->sessions); - - return pRpc; -} - -void rpcClose(void *param) { - SRpcInfo *pRpc = (SRpcInfo *)param; - - // stop connection to outside first - (*taosStopConn[pRpc->connType | RPC_CONN_TCP])(pRpc->tcphandle); - (*taosStopConn[pRpc->connType])(pRpc->udphandle); - - // close all connections - for (int i = 0; i < pRpc->sessions; ++i) { - if (pRpc->connList && pRpc->connList[i].user[0]) { - rpcCloseConn((void *)(pRpc->connList + i)); - } - } - - // clean up - (*taosCleanUpConn[pRpc->connType | RPC_CONN_TCP])(pRpc->tcphandle); - (*taosCleanUpConn[pRpc->connType])(pRpc->udphandle); - - tDebug("%s rpc is closed", pRpc->label); - rpcDecRef(pRpc); -} - -void *rpcMallocCont(int contLen) { - int size = contLen + RPC_MSG_OVERHEAD; - - char *start = (char *)taosMemoryCalloc(1, (size_t)size); - if (start == NULL) { - tError("failed to malloc msg, size:%d", size); - return NULL; - } else { - tTrace("malloc mem:%p size:%d", start, size); - } - - return start + sizeof(SRpcReqContext) + sizeof(SRpcHead); -} - -void rpcFreeCont(void *cont) { - if (cont) { - char *temp = ((char *)cont) - sizeof(SRpcHead) - sizeof(SRpcReqContext); - taosMemoryFree(temp); - tTrace("free mem: %p", temp); - } -} - -void *rpcReallocCont(void *ptr, int contLen) { - if (ptr == NULL) return rpcMallocCont(contLen); - - char *start = ((char *)ptr) - sizeof(SRpcReqContext) - sizeof(SRpcHead); - if (contLen == 0) { - taosMemoryFree(start); - return NULL; - } - - int size = contLen + RPC_MSG_OVERHEAD; - start = taosMemoryRealloc(start, size); - if (start == NULL) { - tError("failed to realloc cont, size:%d", size); - return NULL; - } - - return start + sizeof(SRpcReqContext) + sizeof(SRpcHead); -} - -void rpcSendRequest(void *shandle, const SEpSet *pEpSet, SRpcMsg *pMsg, int64_t *pRid) { - SRpcInfo * pRpc = (SRpcInfo *)shandle; - SRpcReqContext *pContext; - - int contLen = rpcCompressRpcMsg(pMsg->pCont, pMsg->contLen); - pContext = (SRpcReqContext *)((char *)pMsg->pCont - sizeof(SRpcHead) - sizeof(SRpcReqContext)); - pContext->ahandle = pMsg->ahandle; - pContext->pRpc = (SRpcInfo *)shandle; - pContext->epSet = *pEpSet; - pContext->contLen = contLen; - pContext->pCont = pMsg->pCont; - pContext->msgType = pMsg->msgType; - pContext->oldInUse = pEpSet->inUse; - - pContext->connType = RPC_CONN_UDPC; - if (contLen > tsRpcMaxUdpSize || tsRpcForceTcp) pContext->connType = RPC_CONN_TCPC; - - // connection type is application specific. - // for TDengine, all the query, show commands shall have TCP connection - tmsg_t type = pMsg->msgType; - if (type == TDMT_VND_QUERY || type == TDMT_MND_SHOW_RETRIEVE || type == TDMT_VND_FETCH || - type == TDMT_MND_VGROUP_LIST || type == TDMT_VND_TABLES_META || type == TDMT_VND_TABLE_META || - type == TDMT_MND_SHOW || type == TDMT_MND_STATUS || type == TDMT_VND_ALTER_TABLE) - pContext->connType = RPC_CONN_TCPC; - - pContext->rid = taosAddRef(tsRpcRefId, pContext); - if (pRid) *pRid = pContext->rid; - - rpcSendReqToServer(pRpc, pContext); -} - -void rpcSendResponse(const SRpcMsg *pRsp) { - ASSERT(pRsp->handle != NULL); - - int msgLen = 0; - SRpcConn *pConn = (SRpcConn *)pRsp->handle; - SRpcMsg rpcMsg = *pRsp; - SRpcMsg * pMsg = &rpcMsg; - SRpcInfo *pRpc = pConn->pRpc; - - if (pMsg->pCont == NULL) { - pMsg->pCont = rpcMallocCont(0); - pMsg->contLen = 0; - } - - SRpcHead *pHead = rpcHeadFromCont(pMsg->pCont); - char * msg = (char *)pHead; - - pMsg->contLen = rpcCompressRpcMsg(pMsg->pCont, pMsg->contLen); - msgLen = rpcMsgLenFromCont(pMsg->contLen); - - rpcLockConn(pConn); - - if (pConn->inType == 0 || pConn->user[0] == 0) { - tError("%s, connection is already released, rsp wont be sent", pConn->info); - rpcUnlockConn(pConn); - rpcFreeCont(pMsg->pCont); - rpcDecRef(pRpc); - return; - } - - // set msg header - pHead->version = 1; - pHead->msgType = pConn->inType + 1; - pHead->spi = pConn->spi; - pHead->encrypt = pConn->encrypt; - pHead->tranId = pConn->inTranId; - pHead->sourceId = pConn->ownId; - pHead->destId = pConn->peerId; - pHead->linkUid = pConn->linkUid; - pHead->port = htons(pConn->localPort); - pHead->code = htonl(pMsg->code); - pHead->ahandle = (uint64_t)pConn->ahandle; - - // set pConn parameters - pConn->inType = 0; - - // response message is released until new response is sent - rpcFreeMsg(pConn->pRspMsg); - pConn->pRspMsg = msg; - pConn->rspMsgLen = msgLen; - if (pMsg->code == TSDB_CODE_RPC_ACTION_IN_PROGRESS) pConn->inTranId--; - - // stop the progress timer - taosTmrStopA(&pConn->pTimer); - - // set the idle timer to monitor the activity - taosTmrReset(rpcProcessIdleTimer, pRpc->idleTime * 30, pConn, pRpc->tmrCtrl, &pConn->pIdleTimer); - rpcSendMsgToPeer(pConn, msg, msgLen); - - // if not set to secured, set it expcet NOT_READY case, since client wont treat it as secured - if (pConn->secured == 0 && pMsg->code != TSDB_CODE_RPC_NOT_READY) pConn->secured = 1; // connection shall be secured - - if (pConn->pReqMsg) rpcFreeCont(pConn->pReqMsg); - pConn->pReqMsg = NULL; - pConn->reqMsgLen = 0; - - rpcUnlockConn(pConn); - rpcDecRef(pRpc); // decrease the referene count - - return; -} - -void rpcSendRedirectRsp(void *thandle, const SEpSet *pEpSet) { - SRpcMsg rpcMsg; - memset(&rpcMsg, 0, sizeof(rpcMsg)); - - rpcMsg.contLen = sizeof(SEpSet); - rpcMsg.pCont = rpcMallocCont(rpcMsg.contLen); - if (rpcMsg.pCont == NULL) return; - - memcpy(rpcMsg.pCont, pEpSet, sizeof(SEpSet)); - - rpcMsg.code = TSDB_CODE_RPC_REDIRECT; - rpcMsg.handle = thandle; - - rpcSendResponse(&rpcMsg); - - return; -} - -int rpcGetConnInfo(void *thandle, SRpcConnInfo *pInfo) { - SRpcConn *pConn = (SRpcConn *)thandle; - if (pConn->user[0] == 0) return -1; - - pInfo->clientIp = pConn->peerIp; - pInfo->clientPort = pConn->peerPort; - // pInfo->serverIp = pConn->destIp; - - tstrncpy(pInfo->user, pConn->user, sizeof(pInfo->user)); - return 0; -} - -void rpcSendRecv(void *shandle, SEpSet *pEpSet, SRpcMsg *pMsg, SRpcMsg *pRsp) { - SRpcReqContext *pContext; - pContext = (SRpcReqContext *)((char *)pMsg->pCont - sizeof(SRpcHead) - sizeof(SRpcReqContext)); - - memset(pRsp, 0, sizeof(SRpcMsg)); - - tsem_t sem; - tsem_init(&sem, 0, 0); - pContext->pSem = &sem; - pContext->pRsp = pRsp; - pContext->pSet = pEpSet; - - rpcSendRequest(shandle, pEpSet, pMsg, NULL); - - tsem_wait(&sem); - tsem_destroy(&sem); - - return; -} - -// this API is used by server app to keep an APP context in case connection is broken -int rpcReportProgress(void *handle, char *pCont, int contLen) { - SRpcConn *pConn = (SRpcConn *)handle; - int code = 0; - - rpcLockConn(pConn); - - if (pConn->user[0]) { - // pReqMsg and reqMsgLen is re-used to store the context from app server - pConn->pReqMsg = pCont; - pConn->reqMsgLen = contLen; - } else { - tDebug("%s, rpc connection is already released", pConn->info); - rpcFreeCont(pCont); - code = -1; - } - - rpcUnlockConn(pConn); - return code; -} - -void rpcCancelRequest(int64_t rid) { - SRpcReqContext *pContext = taosAcquireRef(tsRpcRefId, rid); - if (pContext == NULL) return; - - rpcCloseConn(pContext->pConn); - - taosReleaseRef(tsRpcRefId, rid); -} - -static void rpcFreeMsg(void *msg) { - if (msg) { - char *temp = (char *)msg - sizeof(SRpcReqContext); - taosMemoryFree(temp); - tTrace("free mem: %p", temp); - } -} - -static SRpcConn *rpcOpenConn(SRpcInfo *pRpc, char *peerFqdn, uint16_t peerPort, int8_t connType) { - SRpcConn *pConn; - - uint32_t peerIp = 0; - uint32_t *pPeerIp = taosHashGet(tsFqdnHash, peerFqdn, strlen(peerFqdn) + 1); - if (pPeerIp != NULL) { - peerIp = *pPeerIp; - } else { - peerIp = taosGetIpv4FromFqdn(peerFqdn); - if (peerIp != 0xFFFFFFFF) { - taosHashPut(tsFqdnHash, peerFqdn, strlen(peerFqdn) + 1, &peerIp, sizeof(peerIp)); - } - } - - if (peerIp == 0xFFFFFFFF) { - tError("%s, failed to resolve FQDN:%s", pRpc->label, peerFqdn); - terrno = TSDB_CODE_RPC_FQDN_ERROR; - return NULL; - } - - pConn = rpcAllocateClientConn(pRpc); - - if (pConn) { - tstrncpy(pConn->peerFqdn, peerFqdn, sizeof(pConn->peerFqdn)); - pConn->peerIp = peerIp; - pConn->peerPort = peerPort; - tstrncpy(pConn->user, pRpc->user, sizeof(pConn->user)); - pConn->connType = connType; - - if (taosOpenConn[connType]) { - void *shandle = (connType & RPC_CONN_TCP) ? pRpc->tcphandle : pRpc->udphandle; - pConn->chandle = (*taosOpenConn[connType])(shandle, pConn, pConn->peerIp, pConn->peerPort); - if (pConn->chandle == NULL) { - tError("failed to connect to:%s:%d", taosIpStr(pConn->peerIp), pConn->peerPort); - - terrno = TSDB_CODE_RPC_NETWORK_UNAVAIL; - rpcCloseConn(pConn); - pConn = NULL; - } - } - } - - return pConn; -} - -static void rpcReleaseConn(SRpcConn *pConn) { - SRpcInfo *pRpc = pConn->pRpc; - if (pConn->user[0] == 0) return; - - pConn->user[0] = 0; - if (taosCloseConn[pConn->connType]) (*taosCloseConn[pConn->connType])(pConn->chandle); - - taosTmrStopA(&pConn->pTimer); - taosTmrStopA(&pConn->pIdleTimer); - - if (pRpc->connType == TAOS_CONN_SERVER) { - char hashstr[40] = {0}; - size_t size = snprintf(hashstr, sizeof(hashstr), "%x:%x:%x:%d", pConn->peerIp, pConn->linkUid, pConn->peerId, - pConn->connType); - taosHashRemove(pRpc->hash, hashstr, size); - rpcFreeMsg(pConn->pRspMsg); // it may have a response msg saved, but not request msg - pConn->pRspMsg = NULL; - - // if server has ever reported progress, free content - if (pConn->pReqMsg) rpcFreeCont(pConn->pReqMsg); // do not use rpcFreeMsg - } else { - // if there is an outgoing message, free it - if (pConn->outType && pConn->pReqMsg) { - SRpcReqContext *pContext = pConn->pContext; - if (pContext) { - if (pContext->pRsp) { - // for synchronous API, post semaphore to unblock app - pContext->pRsp->code = TSDB_CODE_RPC_APP_ERROR; - pContext->pRsp->pCont = NULL; - pContext->pRsp->contLen = 0; - tsem_post(pContext->pSem); - } - pContext->pConn = NULL; - taosRemoveRef(tsRpcRefId, pContext->rid); - } else { - assert(0); - } - } - } - - // memset could not be used, since lockeBy can not be reset - pConn->inType = 0; - pConn->outType = 0; - pConn->inTranId = 0; - pConn->outTranId = 0; - pConn->secured = 0; - pConn->peerId = 0; - pConn->peerIp = 0; - pConn->peerPort = 0; - pConn->pReqMsg = NULL; - pConn->reqMsgLen = 0; - pConn->pContext = NULL; - pConn->chandle = NULL; - - taosFreeId(pRpc->idPool, pConn->sid); - tDebug("%s, rpc connection is released", pConn->info); -} - -static void rpcCloseConn(void *thandle) { - SRpcConn *pConn = (SRpcConn *)thandle; - if (pConn == NULL) return; - - rpcLockConn(pConn); - - if (pConn->user[0]) rpcReleaseConn(pConn); - - rpcUnlockConn(pConn); -} - -static SRpcConn *rpcAllocateClientConn(SRpcInfo *pRpc) { - SRpcConn *pConn = NULL; - - int sid = taosAllocateId(pRpc->idPool); - if (sid <= 0) { - tError("%s maximum number of sessions:%d is reached", pRpc->label, pRpc->sessions); - terrno = TSDB_CODE_RPC_MAX_SESSIONS; - } else { - pConn = pRpc->connList + sid; - - pConn->pRpc = pRpc; - pConn->sid = sid; - pConn->tranId = (uint16_t)(taosRand() & 0xFFFF); - pConn->ownId = htonl(pConn->sid); - pConn->linkUid = (uint32_t)((int64_t)pConn + taosGetPId() + (int64_t)pConn->tranId); - pConn->spi = pRpc->spi; - pConn->encrypt = pRpc->encrypt; - if (pConn->spi) memcpy(pConn->secret, pRpc->secret, TSDB_PASSWORD_LEN); - tDebug("%s %p client connection is allocated, uid:0x%x", pRpc->label, pConn, pConn->linkUid); - } - - return pConn; -} - -static SRpcConn *rpcAllocateServerConn(SRpcInfo *pRpc, SRecvInfo *pRecv) { - SRpcConn *pConn = NULL; - char hashstr[40] = {0}; - SRpcHead *pHead = (SRpcHead *)pRecv->msg; - - size_t size = - snprintf(hashstr, sizeof(hashstr), "%x:%x:%x:%d", pRecv->ip, pHead->linkUid, pHead->sourceId, pRecv->connType); - - // check if it is already allocated - SRpcConn **ppConn = (SRpcConn **)(taosHashGet(pRpc->hash, hashstr, size)); - if (ppConn) pConn = *ppConn; - if (pConn) { - pConn->secured = 0; - return pConn; - } - - // if code is not 0, it means it is simple reqhead, just ignore - if (pHead->code != 0) { - terrno = TSDB_CODE_RPC_ALREADY_PROCESSED; - return NULL; - } - - int sid = taosAllocateId(pRpc->idPool); - if (sid <= 0) { - tError("%s maximum number of sessions:%d is reached", pRpc->label, pRpc->sessions); - terrno = TSDB_CODE_RPC_MAX_SESSIONS; - } else { - pConn = pRpc->connList + sid; - memcpy(pConn->user, pHead->user, tListLen(pConn->user)); - pConn->pRpc = pRpc; - pConn->sid = sid; - pConn->tranId = (uint16_t)(taosRand() & 0xFFFF); - pConn->ownId = htonl(pConn->sid); - pConn->linkUid = pHead->linkUid; - if (pRpc->afp) { - if (pConn->user[0] == 0) { - terrno = TSDB_CODE_RPC_AUTH_REQUIRED; - } else { - terrno = (*pRpc->afp)(pRpc->parent, pConn->user, &pConn->spi, &pConn->encrypt, pConn->secret, pConn->ckey); - } - - if (terrno != 0) { - taosFreeId(pRpc->idPool, sid); // sid shall be released - pConn = NULL; - } - } - } - - if (pConn) { - if (pRecv->connType == RPC_CONN_UDPS && pRpc->numOfThreads > 1) { - // UDP server, assign to new connection - pRpc->index = (pRpc->index + 1) % pRpc->numOfThreads; - pConn->localPort = (pRpc->localPort + pRpc->index); - } - - taosHashPut(pRpc->hash, hashstr, size, (char *)&pConn, POINTER_BYTES); - tDebug("%s %p server connection is allocated, uid:0x%x sid:%d key:%s spi:%d", pRpc->label, pConn, pConn->linkUid, - sid, hashstr, pConn->spi); - } - - return pConn; -} - -static SRpcConn *rpcGetConnObj(SRpcInfo *pRpc, int sid, SRecvInfo *pRecv) { - SRpcConn *pConn = NULL; - SRpcHead *pHead = (SRpcHead *)pRecv->msg; - - if (sid) { - pConn = pRpc->connList + sid; - if (pConn->user[0] == 0) pConn = NULL; - } - - if (pConn == NULL) { - if (pRpc->connType == TAOS_CONN_SERVER) { - pConn = rpcAllocateServerConn(pRpc, pRecv); - } else { - terrno = TSDB_CODE_RPC_UNEXPECTED_RESPONSE; - } - } - - if (pConn) { - if (pConn->linkUid != pHead->linkUid) { - terrno = TSDB_CODE_RPC_MISMATCHED_LINK_ID; - tDebug("%s %p %p, linkUid:0x%x is not matched with received:0x%x", pRpc->label, pConn, (void *)pHead->ahandle, - pConn->linkUid, pHead->linkUid); - pConn = NULL; - } - } - - return pConn; -} - -static SRpcConn *rpcSetupConnToServer(SRpcReqContext *pContext) { - SRpcConn *pConn; - SRpcInfo *pRpc = pContext->pRpc; - SEpSet * pEpSet = &pContext->epSet; - - pConn = rpcGetConnFromCache(pRpc->pCache, pEpSet->eps[pEpSet->inUse].fqdn, pEpSet->eps[pEpSet->inUse].port, - pContext->connType); - if (pConn == NULL || pConn->user[0] == 0) { - pConn = rpcOpenConn(pRpc, pEpSet->eps[pEpSet->inUse].fqdn, pEpSet->eps[pEpSet->inUse].port, pContext->connType); - } - - if (pConn) { - pConn->tretry = 0; - pConn->ahandle = pContext->ahandle; - snprintf(pConn->info, sizeof(pConn->info), "%s %p %p", pRpc->label, pConn, pConn->ahandle); - pConn->tretry = 0; - } else { - tError("%s %p, failed to set up connection(%s)", pRpc->label, pContext->ahandle, tstrerror(terrno)); - } - - return pConn; -} - -static int rpcProcessReqHead(SRpcConn *pConn, SRpcHead *pHead) { - if (pConn->peerId == 0) { - pConn->peerId = pHead->sourceId; - } else { - if (pConn->peerId != pHead->sourceId) { - tDebug("%s, source Id is changed, old:0x%08x new:0x%08x", pConn->info, pConn->peerId, pHead->sourceId); - return TSDB_CODE_RPC_INVALID_VALUE; - } - } - - if (pConn->inTranId == pHead->tranId) { - if (pConn->inType == pHead->msgType) { - if (pHead->code == 0) { - tDebug("%s, %s is retransmitted", pConn->info, TMSG_INFO(pHead->msgType)); - rpcSendQuickRsp(pConn, TSDB_CODE_RPC_ACTION_IN_PROGRESS); - } else { - // do nothing, it is heart beat from client - } - } else if (pConn->inType == 0) { - tDebug("%s, %s is already processed, tranId:%d", pConn->info, TMSG_INFO(pHead->msgType), pConn->inTranId); - rpcSendMsgToPeer(pConn, pConn->pRspMsg, pConn->rspMsgLen); // resend the response - } else { - tDebug("%s, mismatched message %s and tranId", pConn->info, TMSG_INFO(pHead->msgType)); - } - - // do not reply any message - return TSDB_CODE_RPC_ALREADY_PROCESSED; - } - - if (pConn->inType != 0) { - tDebug("%s, last session is not finished, inTranId:%d tranId:%d", pConn->info, pConn->inTranId, pHead->tranId); - return TSDB_CODE_RPC_LAST_SESSION_NOT_FINISHED; - } - - if (rpcContLenFromMsg(pHead->msgLen) <= 0) { - tDebug("%s, message body is empty, ignore", pConn->info); - return TSDB_CODE_RPC_APP_ERROR; - } - - pConn->inTranId = pHead->tranId; - pConn->inType = pHead->msgType; - - // start the progress timer to monitor the response from server app - if (pConn->connType != RPC_CONN_TCPS) - pConn->pTimer = taosTmrStart(rpcProcessProgressTimer, tsProgressTimer, pConn, pConn->pRpc->tmrCtrl); - - return 0; -} - -static int rpcProcessRspHead(SRpcConn *pConn, SRpcHead *pHead) { - SRpcInfo *pRpc = pConn->pRpc; - pConn->peerId = pHead->sourceId; - - if (pConn->outType == 0 || pConn->pContext == NULL) { - return TSDB_CODE_RPC_UNEXPECTED_RESPONSE; - } - - if (pHead->tranId != pConn->outTranId) { - return TSDB_CODE_RPC_INVALID_TRAN_ID; - } - - if (pHead->msgType != pConn->outType + 1) { - return TSDB_CODE_RPC_INVALID_RESPONSE_TYPE; - } - - taosTmrStopA(&pConn->pTimer); - pConn->retry = 0; - - if (pHead->code == TSDB_CODE_RPC_AUTH_REQUIRED && pRpc->spi) { - tDebug("%s, authentication shall be restarted", pConn->info); - pConn->secured = 0; - rpcSendMsgToPeer(pConn, pConn->pReqMsg, pConn->reqMsgLen); - if (pConn->connType != RPC_CONN_TCPC) - pConn->pTimer = taosTmrStart(rpcProcessRetryTimer, tsRpcTimer, pConn, pRpc->tmrCtrl); - return TSDB_CODE_RPC_ALREADY_PROCESSED; - } - - if (pHead->code == TSDB_CODE_RPC_MISMATCHED_LINK_ID) { - tDebug("%s, mismatched linkUid, link shall be restarted", pConn->info); - pConn->secured = 0; - ((SRpcHead *)pConn->pReqMsg)->destId = 0; - rpcSendMsgToPeer(pConn, pConn->pReqMsg, pConn->reqMsgLen); - if (pConn->connType != RPC_CONN_TCPC) - pConn->pTimer = taosTmrStart(rpcProcessRetryTimer, tsRpcTimer, pConn, pRpc->tmrCtrl); - return TSDB_CODE_RPC_ALREADY_PROCESSED; - } - - if (pHead->code == TSDB_CODE_RPC_ACTION_IN_PROGRESS) { - if (pConn->tretry <= tsRpcMaxRetry) { - tDebug("%s, peer is still processing the transaction, retry:%d", pConn->info, pConn->tretry); - pConn->tretry++; - rpcSendReqHead(pConn); - if (pConn->connType != RPC_CONN_TCPC) - pConn->pTimer = taosTmrStart(rpcProcessRetryTimer, tsRpcTimer, pConn, pRpc->tmrCtrl); - return TSDB_CODE_RPC_ALREADY_PROCESSED; - } else { - // peer still in processing, give up - tDebug("%s, server processing takes too long time, give up", pConn->info); - pHead->code = TSDB_CODE_RPC_TOO_SLOW; - } - } - - pConn->outType = 0; - pConn->pReqMsg = NULL; - pConn->reqMsgLen = 0; - SRpcReqContext *pContext = pConn->pContext; - - if (pHead->code == TSDB_CODE_RPC_REDIRECT) { - if (rpcContLenFromMsg(pHead->msgLen) < sizeof(SEpSet)) { - // if EpSet is not included in the msg, treat it as NOT_READY - pHead->code = TSDB_CODE_RPC_NOT_READY; - } else { - pContext->redirect++; - if (pContext->redirect > TSDB_MAX_REPLICA) { - pHead->code = TSDB_CODE_RPC_NETWORK_UNAVAIL; - tWarn("%s, too many redirects, quit", pConn->info); - } - } - } - - return TSDB_CODE_SUCCESS; -} - -static SRpcConn *rpcProcessMsgHead(SRpcInfo *pRpc, SRecvInfo *pRecv, SRpcReqContext **ppContext) { - int32_t sid; - SRpcConn *pConn = NULL; - - SRpcHead *pHead = (SRpcHead *)pRecv->msg; - - sid = htonl(pHead->destId); - *ppContext = NULL; - - if (TMSG_INDEX(pHead->msgType) >= TDMT_MAX || TMSG_INDEX(pHead->msgType) <= 0) { - tDebug("%s sid:%d, invalid message type:%d", pRpc->label, sid, pHead->msgType); - terrno = TSDB_CODE_RPC_INVALID_MSG_TYPE; - return NULL; - } - - if (sid < 0 || sid >= pRpc->sessions) { - tDebug("%s sid:%d, sid is out of range, max sid:%d, %s discarded", pRpc->label, sid, pRpc->sessions, - TMSG_INFO(pHead->msgType)); - terrno = TSDB_CODE_RPC_INVALID_SESSION_ID; - return NULL; - } - - if (rpcIsReq(pHead->msgType) && htonl(pHead->msgVer) != tsVersion >> 8) { - tDebug("%s sid:%d, invalid client version:%x/%x %s", pRpc->label, sid, htonl(pHead->msgVer), tsVersion, - TMSG_INFO(pHead->msgType)); - terrno = TSDB_CODE_RPC_INVALID_VERSION; - return NULL; - } - - pConn = rpcGetConnObj(pRpc, sid, pRecv); - if (pConn == NULL) { - tDebug("%s %p, failed to get connection obj(%s)", pRpc->label, (void *)pHead->ahandle, tstrerror(terrno)); - return NULL; - } - - rpcLockConn(pConn); - - if (rpcIsReq(pHead->msgType)) { - pConn->ahandle = (void *)pHead->ahandle; - snprintf(pConn->info, sizeof(pConn->info), "%s %p %p", pRpc->label, pConn, pConn->ahandle); - } - - sid = pConn->sid; - if (pConn->chandle == NULL) pConn->chandle = pRecv->chandle; - pConn->peerIp = pRecv->ip; - pConn->peerPort = pRecv->port; - if (pHead->port) pConn->peerPort = htons(pHead->port); - - terrno = rpcCheckAuthentication(pConn, (char *)pHead, pRecv->msgLen); - - // code can be transformed only after authentication - pHead->code = htonl(pHead->code); - - if (terrno == 0) { - if (pHead->encrypt) { - // decrypt here - } - - if (rpcIsReq(pHead->msgType)) { - pConn->connType = pRecv->connType; - terrno = rpcProcessReqHead(pConn, pHead); - - // stop idle timer - taosTmrStopA(&pConn->pIdleTimer); - - // client shall send the request within tsRpcTime again for UDP, double it - if (pConn->connType != RPC_CONN_TCPS) - pConn->pIdleTimer = taosTmrStart(rpcProcessIdleTimer, tsRpcTimer * 2, pConn, pRpc->tmrCtrl); - } else { - terrno = rpcProcessRspHead(pConn, pHead); - *ppContext = pConn->pContext; - } - } - - rpcUnlockConn(pConn); - - return pConn; -} - -static void doRpcReportBrokenLinkToServer(void *param, void *id) { - SRpcMsg * pRpcMsg = (SRpcMsg *)(param); - SRpcConn *pConn = (SRpcConn *)(pRpcMsg->handle); - SRpcInfo *pRpc = pConn->pRpc; - (*(pRpc->cfp))(pRpc->parent, pRpcMsg, NULL); - taosMemoryFree(pRpcMsg); -} -static void rpcReportBrokenLinkToServer(SRpcConn *pConn) { - SRpcInfo *pRpc = pConn->pRpc; - if (pConn->pReqMsg == NULL) return; - - // if there are pending request, notify the app - rpcAddRef(pRpc); - tDebug("%s, notify the server app, connection is gone", pConn->info); - - SRpcMsg *rpcMsg = taosMemoryMalloc(sizeof(SRpcMsg)); - rpcMsg->pCont = pConn->pReqMsg; // pReqMsg is re-used to store the APP context from server - rpcMsg->contLen = pConn->reqMsgLen; // reqMsgLen is re-used to store the APP context length - rpcMsg->ahandle = pConn->ahandle; - rpcMsg->handle = pConn; - rpcMsg->msgType = pConn->inType; - rpcMsg->code = TSDB_CODE_RPC_NETWORK_UNAVAIL; - pConn->pReqMsg = NULL; - pConn->reqMsgLen = 0; - if (pRpc->cfp) { - taosTmrStart(doRpcReportBrokenLinkToServer, 0, rpcMsg, pRpc->tmrCtrl); - } else { - taosMemoryFree(rpcMsg); - } -} - -static void rpcProcessBrokenLink(SRpcConn *pConn) { - if (pConn == NULL) return; - SRpcInfo *pRpc = pConn->pRpc; - tDebug("%s, link is broken", pConn->info); - - rpcLockConn(pConn); - - if (pConn->outType) { - SRpcReqContext *pContext = pConn->pContext; - pContext->code = TSDB_CODE_RPC_NETWORK_UNAVAIL; - pContext->pConn = NULL; - pConn->pReqMsg = NULL; - taosTmrStart(rpcProcessConnError, 0, pContext, pRpc->tmrCtrl); - } - - if (pConn->inType) rpcReportBrokenLinkToServer(pConn); - - rpcReleaseConn(pConn); - rpcUnlockConn(pConn); -} - -static void *rpcProcessMsgFromPeer(SRecvInfo *pRecv) { - SRpcHead *pHead = (SRpcHead *)pRecv->msg; - SRpcInfo *pRpc = (SRpcInfo *)pRecv->shandle; - SRpcConn *pConn = (SRpcConn *)pRecv->thandle; - - tDump(pRecv->msg, pRecv->msgLen); - - // underlying UDP layer does not know it is server or client - pRecv->connType = pRecv->connType | pRpc->connType; - - if (pRecv->msg == NULL) { - rpcProcessBrokenLink(pConn); - return NULL; - } - - terrno = 0; - SRpcReqContext *pContext; - pConn = rpcProcessMsgHead(pRpc, pRecv, &pContext); - - char ipstr[24] = {0}; - taosIpPort2String(pRecv->ip, pRecv->port, ipstr); - - if (TMSG_INDEX(pHead->msgType) >= 1 && TMSG_INDEX(pHead->msgType) < TDMT_MAX) { - tDebug("%s %p %p, %s received from %s, parse code:0x%x len:%d sig:0x%08x:0x%08x:%d code:0x%x", pRpc->label, pConn, - (void *)pHead->ahandle, TMSG_INFO(pHead->msgType), ipstr, terrno, pRecv->msgLen, pHead->sourceId, - pHead->destId, pHead->tranId, pHead->code); - } else { - tDebug("%s %p %p, %d received from %s, parse code:0x%x len:%d sig:0x%08x:0x%08x:%d code:0x%x", pRpc->label, pConn, - (void *)pHead->ahandle, pHead->msgType, ipstr, terrno, pRecv->msgLen, pHead->sourceId, pHead->destId, - pHead->tranId, pHead->code); - } - - int32_t code = terrno; - if (code != TSDB_CODE_RPC_ALREADY_PROCESSED) { - if (code != 0) { // parsing error - if (rpcIsReq(pHead->msgType)) { - rpcSendErrorMsgToPeer(pRecv, code); - if (code == TSDB_CODE_RPC_INVALID_TIME_STAMP || code == TSDB_CODE_RPC_AUTH_FAILURE) { - rpcCloseConn(pConn); - } - if (TMSG_INDEX(pHead->msgType) + 1 > 1 && TMSG_INDEX(pHead->msgType) + 1 < TDMT_MAX) { - tDebug("%s %p %p, %s is sent with error code:0x%x", pRpc->label, pConn, (void *)pHead->ahandle, - TMSG_INFO(pHead->msgType + 1), code); - } else { - tError("%s %p %p, %s is sent with error code:0x%x", pRpc->label, pConn, (void *)pHead->ahandle, - TMSG_INFO(pHead->msgType), code); - } - } - } else { // msg is passed to app only parsing is ok - rpcProcessIncomingMsg(pConn, pHead, pContext); - } - } - - if (code) rpcFreeMsg(pRecv->msg); // parsing failed, msg shall be freed - return pConn; -} - -static void rpcNotifyClient(SRpcReqContext *pContext, SRpcMsg *pMsg) { - SRpcInfo *pRpc = pContext->pRpc; - - pContext->pConn = NULL; - if (pContext->pRsp) { - // for synchronous API - memcpy(pContext->pSet, &pContext->epSet, sizeof(SEpSet)); - memcpy(pContext->pRsp, pMsg, sizeof(SRpcMsg)); - tsem_post(pContext->pSem); - } else { - // for asynchronous API - SEpSet *pEpSet = NULL; - if (pContext->epSet.inUse != pContext->oldInUse || pContext->redirect) pEpSet = &pContext->epSet; - - (*pRpc->cfp)(pRpc->parent, pMsg, pEpSet); - } - - // free the request message - taosRemoveRef(tsRpcRefId, pContext->rid); -} - -static void rpcProcessIncomingMsg(SRpcConn *pConn, SRpcHead *pHead, SRpcReqContext *pContext) { - SRpcInfo *pRpc = pConn->pRpc; - SRpcMsg rpcMsg; - - pHead = rpcDecompressRpcMsg(pHead); - rpcMsg.contLen = rpcContLenFromMsg(pHead->msgLen); - rpcMsg.pCont = pHead->content; - rpcMsg.msgType = pHead->msgType; - rpcMsg.code = pHead->code; - - if (rpcIsReq(pHead->msgType)) { - rpcMsg.ahandle = pConn->ahandle; - rpcMsg.handle = pConn; - rpcAddRef(pRpc); // add the refCount for requests - - // notify the server app - (*(pRpc->cfp))(pRpc->parent, &rpcMsg, NULL); - } else { - // it's a response - rpcMsg.handle = pContext; - rpcMsg.ahandle = pContext->ahandle; - pContext->pConn = NULL; - - // for UDP, port may be changed by server, the port in epSet shall be used for cache - if (pHead->code != TSDB_CODE_RPC_TOO_SLOW) { - rpcAddConnIntoCache(pRpc->pCache, pConn, pConn->peerFqdn, pContext->epSet.eps[pContext->epSet.inUse].port, - pConn->connType); - } else { - rpcCloseConn(pConn); - } - - if (pHead->code == TSDB_CODE_RPC_REDIRECT) { - pContext->numOfTry = 0; - SEpSet *pEpSet = (SEpSet *)pHead->content; - if (pEpSet->numOfEps > 0) { - memcpy(&pContext->epSet, pHead->content, sizeof(pContext->epSet)); - tDebug("%s, redirect is received, numOfEps:%d inUse:%d", pConn->info, pContext->epSet.numOfEps, - pContext->epSet.inUse); - for (int i = 0; i < pContext->epSet.numOfEps; ++i) { - pContext->epSet.eps[i].port = htons(pContext->epSet.eps[i].port); - tDebug("%s, redirect is received, index:%d ep:%s:%u", pConn->info, i, pContext->epSet.eps[i].fqdn, - pContext->epSet.eps[i].port); - } - } - rpcSendReqToServer(pRpc, pContext); - rpcFreeCont(rpcMsg.pCont); - } else if (pHead->code == TSDB_CODE_RPC_NOT_READY || pHead->code == TSDB_CODE_APP_NOT_READY || - pHead->code == TSDB_CODE_NODE_OFFLINE) { - pContext->code = pHead->code; - rpcProcessConnError(pContext, NULL); - rpcFreeCont(rpcMsg.pCont); - } else { - rpcNotifyClient(pContext, &rpcMsg); - } - } -} - -static void rpcSendQuickRsp(SRpcConn *pConn, int32_t code) { - char msg[RPC_MSG_OVERHEAD]; - SRpcHead *pHead; - - // set msg header - memset(msg, 0, sizeof(SRpcHead)); - pHead = (SRpcHead *)msg; - pHead->version = 1; - pHead->msgType = pConn->inType + 1; - pHead->spi = pConn->spi; - pHead->encrypt = 0; - pHead->tranId = pConn->inTranId; - pHead->sourceId = pConn->ownId; - pHead->destId = pConn->peerId; - pHead->linkUid = pConn->linkUid; - pHead->ahandle = (uint64_t)pConn->ahandle; - memcpy(pHead->user, pConn->user, tListLen(pHead->user)); - pHead->code = htonl(code); - - rpcSendMsgToPeer(pConn, msg, sizeof(SRpcHead)); - pConn->secured = 1; // connection shall be secured -} - -static void rpcSendReqHead(SRpcConn *pConn) { - char msg[RPC_MSG_OVERHEAD]; - SRpcHead *pHead; - - // set msg header - memset(msg, 0, sizeof(SRpcHead)); - pHead = (SRpcHead *)msg; - pHead->version = 1; - pHead->msgType = pConn->outType; - pHead->msgVer = htonl(tsVersion >> 8); - pHead->spi = pConn->spi; - pHead->encrypt = 0; - pHead->tranId = pConn->outTranId; - pHead->sourceId = pConn->ownId; - pHead->destId = pConn->peerId; - pHead->linkUid = pConn->linkUid; - pHead->ahandle = (uint64_t)pConn->ahandle; - memcpy(pHead->user, pConn->user, tListLen(pHead->user)); - pHead->code = 1; - - rpcSendMsgToPeer(pConn, msg, sizeof(SRpcHead)); -} - -static void rpcSendErrorMsgToPeer(SRecvInfo *pRecv, int32_t code) { - SRpcHead *pRecvHead, *pReplyHead; - char msg[sizeof(SRpcHead) + sizeof(SRpcDigest) + sizeof(uint32_t)]; - uint32_t timeStamp; - int msgLen; - - pRecvHead = (SRpcHead *)pRecv->msg; - pReplyHead = (SRpcHead *)msg; - - memset(msg, 0, sizeof(SRpcHead)); - pReplyHead->version = pRecvHead->version; - pReplyHead->msgType = (tmsg_t)(pRecvHead->msgType + 1); - pReplyHead->spi = 0; - pReplyHead->encrypt = pRecvHead->encrypt; - pReplyHead->tranId = pRecvHead->tranId; - pReplyHead->sourceId = pRecvHead->destId; - pReplyHead->destId = pRecvHead->sourceId; - pReplyHead->linkUid = pRecvHead->linkUid; - pReplyHead->ahandle = pRecvHead->ahandle; - - pReplyHead->code = htonl(code); - msgLen = sizeof(SRpcHead); - - if (code == TSDB_CODE_RPC_INVALID_TIME_STAMP) { - // include a time stamp if client's time is not synchronized well - uint8_t *pContent = pReplyHead->content; - timeStamp = htonl(taosGetTimestampSec()); - memcpy(pContent, &timeStamp, sizeof(timeStamp)); - msgLen += sizeof(timeStamp); - } - - pReplyHead->msgLen = (int32_t)htonl((uint32_t)msgLen); - (*taosSendData[pRecv->connType])(pRecv->ip, pRecv->port, msg, msgLen, pRecv->chandle); - - return; -} - -static void rpcSendReqToServer(SRpcInfo *pRpc, SRpcReqContext *pContext) { - SRpcHead *pHead = rpcHeadFromCont(pContext->pCont); - char * msg = (char *)pHead; - int msgLen = rpcMsgLenFromCont(pContext->contLen); - tmsg_t msgType = pContext->msgType; - - pContext->numOfTry++; - SRpcConn *pConn = rpcSetupConnToServer(pContext); - if (pConn == NULL) { - pContext->code = terrno; - taosTmrStart(rpcProcessConnError, 1, pContext, pRpc->tmrCtrl); - return; - } - - pContext->pConn = pConn; - pConn->ahandle = pContext->ahandle; - rpcLockConn(pConn); - - // set the message header - pHead->version = 1; - pHead->msgVer = htonl(tsVersion >> 8); - pHead->msgType = msgType; - pHead->encrypt = 0; - pConn->tranId++; - if (pConn->tranId == 0) pConn->tranId++; - pHead->tranId = pConn->tranId; - pHead->sourceId = pConn->ownId; - pHead->destId = pConn->peerId; - pHead->port = 0; - pHead->linkUid = pConn->linkUid; - pHead->ahandle = (uint64_t)pConn->ahandle; - memcpy(pHead->user, pConn->user, tListLen(pHead->user)); - - // set the connection parameters - pConn->outType = msgType; - pConn->outTranId = pHead->tranId; - pConn->pReqMsg = msg; - pConn->reqMsgLen = msgLen; - pConn->pContext = pContext; - - rpcSendMsgToPeer(pConn, msg, msgLen); - if (pConn->connType != RPC_CONN_TCPC) - taosTmrReset(rpcProcessRetryTimer, tsRpcTimer, pConn, pRpc->tmrCtrl, &pConn->pTimer); - - rpcUnlockConn(pConn); -} - -static void rpcSendMsgToPeer(SRpcConn *pConn, void *msg, int msgLen) { - int writtenLen = 0; - SRpcHead *pHead = (SRpcHead *)msg; - - msgLen = rpcAddAuthPart(pConn, msg, msgLen); - - if (rpcIsReq(pHead->msgType)) { - tDebug("%s, %s is sent to %s:%hu, len:%d sig:0x%08x:0x%08x:%d", pConn->info, TMSG_INFO(pHead->msgType), - pConn->peerFqdn, pConn->peerPort, msgLen, pHead->sourceId, pHead->destId, pHead->tranId); - } else { - if (pHead->code == 0) { - pConn->secured = 1; // for success response, set link as secured - } - - char ipport[40] = {0}; - taosIpPort2String(pConn->peerIp, pConn->peerPort, ipport); - tDebug("%s, %s is sent to %s, code:0x%x len:%d sig:0x%08x:0x%08x:%d", pConn->info, TMSG_INFO(pHead->msgType), - ipport, htonl(pHead->code), msgLen, pHead->sourceId, pHead->destId, pHead->tranId); - } - - // tTrace("connection type is: %d", pConn->connType); - writtenLen = (*taosSendData[pConn->connType])(pConn->peerIp, pConn->peerPort, pHead, msgLen, pConn->chandle); - - if (writtenLen != msgLen) { - tError("%s, failed to send, msgLen:%d written:%d, reason:%s", pConn->info, msgLen, writtenLen, strerror(errno)); - } - - tDump(msg, msgLen); -} - -static void rpcProcessConnError(void *param, void *id) { - SRpcReqContext *pContext = (SRpcReqContext *)param; - SRpcInfo * pRpc = pContext->pRpc; - SRpcMsg rpcMsg = {0}; - - if (pRpc == NULL) { - return; - } - - tDebug("%s %p, connection error happens", pRpc->label, pContext->ahandle); - - if (pContext->numOfTry >= pContext->epSet.numOfEps || pContext->msgType == TDMT_VND_FETCH) { - rpcMsg.msgType = pContext->msgType + 1; - rpcMsg.ahandle = pContext->ahandle; - rpcMsg.code = pContext->code; - rpcMsg.pCont = NULL; - rpcMsg.contLen = 0; - - rpcNotifyClient(pContext, &rpcMsg); - } else { - // move to next IP - pContext->epSet.inUse++; - pContext->epSet.inUse = pContext->epSet.inUse % pContext->epSet.numOfEps; - rpcSendReqToServer(pRpc, pContext); - } -} - -static void rpcProcessRetryTimer(void *param, void *tmrId) { - SRpcConn *pConn = (SRpcConn *)param; - SRpcInfo *pRpc = pConn->pRpc; - - rpcLockConn(pConn); - - if (pConn->outType && pConn->user[0]) { - tDebug("%s, expected %s is not received", pConn->info, TMSG_INFO((int)pConn->outType + 1)); - pConn->pTimer = NULL; - pConn->retry++; - - if (pConn->retry < 4) { - tDebug("%s, re-send msg:%s to %s:%hu", pConn->info, TMSG_INFO(pConn->outType), pConn->peerFqdn, pConn->peerPort); - rpcSendMsgToPeer(pConn, pConn->pReqMsg, pConn->reqMsgLen); - pConn->pTimer = taosTmrStart(rpcProcessRetryTimer, tsRpcTimer, pConn, pRpc->tmrCtrl); - } else { - // close the connection - tDebug("%s, failed to send msg:%s to %s:%hu", pConn->info, TMSG_INFO(pConn->outType), pConn->peerFqdn, - pConn->peerPort); - if (pConn->pContext) { - pConn->pContext->code = TSDB_CODE_RPC_NETWORK_UNAVAIL; - pConn->pContext->pConn = NULL; - pConn->pReqMsg = NULL; - taosTmrStart(rpcProcessConnError, 1, pConn->pContext, pRpc->tmrCtrl); - rpcReleaseConn(pConn); - } - } - } else { - tDebug("%s, retry timer not processed", pConn->info); - } - - rpcUnlockConn(pConn); -} - -static void rpcProcessIdleTimer(void *param, void *tmrId) { - SRpcConn *pConn = (SRpcConn *)param; - - rpcLockConn(pConn); - - if (pConn->user[0]) { - tDebug("%s, close the connection since no activity", pConn->info); - if (pConn->inType) rpcReportBrokenLinkToServer(pConn); - rpcReleaseConn(pConn); - } else { - tDebug("%s, idle timer:%p not processed", pConn->info, tmrId); - } - - rpcUnlockConn(pConn); -} - -static void rpcProcessProgressTimer(void *param, void *tmrId) { - SRpcConn *pConn = (SRpcConn *)param; - SRpcInfo *pRpc = pConn->pRpc; - - rpcLockConn(pConn); - - if (pConn->inType && pConn->user[0]) { - tDebug("%s, progress timer expired, send progress", pConn->info); - rpcSendQuickRsp(pConn, TSDB_CODE_RPC_ACTION_IN_PROGRESS); - pConn->pTimer = taosTmrStart(rpcProcessProgressTimer, tsProgressTimer, pConn, pRpc->tmrCtrl); - } else { - tDebug("%s, progress timer:%p not processed", pConn->info, tmrId); - } - - rpcUnlockConn(pConn); -} - -static int32_t rpcCompressRpcMsg(char *pCont, int32_t contLen) { - SRpcHead *pHead = rpcHeadFromCont(pCont); - int32_t finalLen = 0; - int overhead = sizeof(SRpcComp); - - if (!NEEDTO_COMPRESSS_MSG(contLen)) { - return contLen; - } - - char *buf = taosMemoryMalloc(contLen + overhead + 8); // 8 extra bytes - if (buf == NULL) { - tError("failed to allocate memory for rpc msg compression, contLen:%d", contLen); - return contLen; - } - - int32_t compLen = LZ4_compress_default(pCont, buf, contLen, contLen + overhead); - tDebug("compress rpc msg, before:%d, after:%d, overhead:%d", contLen, compLen, overhead); - - /* - * only the compressed size is less than the value of contLen - overhead, the compression is applied - * The first four bytes is set to 0, the second four bytes are utilized to keep the original length of message - */ - if (compLen > 0 && compLen < contLen - overhead) { - SRpcComp *pComp = (SRpcComp *)pCont; - pComp->reserved = 0; - pComp->contLen = htonl(contLen); - memcpy(pCont + overhead, buf, compLen); - - pHead->comp = 1; - tDebug("compress rpc msg, before:%d, after:%d", contLen, compLen); - finalLen = compLen + overhead; - } else { - finalLen = contLen; - } - - taosMemoryFree(buf); - return finalLen; -} - -static SRpcHead *rpcDecompressRpcMsg(SRpcHead *pHead) { - int overhead = sizeof(SRpcComp); - SRpcHead *pNewHead = NULL; - uint8_t * pCont = pHead->content; - SRpcComp *pComp = (SRpcComp *)pHead->content; - - if (pHead->comp) { - // decompress the content - assert(pComp->reserved == 0); - int contLen = htonl(pComp->contLen); - - // prepare the temporary buffer to decompress message - char *temp = (char *)taosMemoryMalloc(contLen + RPC_MSG_OVERHEAD); - pNewHead = (SRpcHead *)(temp + sizeof(SRpcReqContext)); // reserve SRpcReqContext - - if (pNewHead) { - int compLen = rpcContLenFromMsg(pHead->msgLen) - overhead; - int origLen = LZ4_decompress_safe((char *)(pCont + overhead), (char *)pNewHead->content, compLen, contLen); - assert(origLen == contLen); - - memcpy(pNewHead, pHead, sizeof(SRpcHead)); - pNewHead->msgLen = rpcMsgLenFromCont(origLen); - rpcFreeMsg(pHead); // free the compressed message buffer - pHead = pNewHead; - tTrace("decomp malloc mem:%p", temp); - } else { - tError("failed to allocate memory to decompress msg, contLen:%d", contLen); - } - } - - return pHead; -} - -static int rpcAuthenticateMsg(void *pMsg, int msgLen, void *pAuth, void *pKey) { - T_MD5_CTX context; - int ret = -1; - - tMD5Init(&context); - tMD5Update(&context, (uint8_t *)pKey, TSDB_PASSWORD_LEN); - tMD5Update(&context, (uint8_t *)pMsg, msgLen); - tMD5Update(&context, (uint8_t *)pKey, TSDB_PASSWORD_LEN); - tMD5Final(&context); - - if (memcmp(context.digest, pAuth, sizeof(context.digest)) == 0) ret = 0; - - return ret; -} - -static void rpcBuildAuthHead(void *pMsg, int msgLen, void *pAuth, void *pKey) { - T_MD5_CTX context; - - tMD5Init(&context); - tMD5Update(&context, (uint8_t *)pKey, TSDB_PASSWORD_LEN); - tMD5Update(&context, (uint8_t *)pMsg, msgLen); - tMD5Update(&context, (uint8_t *)pKey, TSDB_PASSWORD_LEN); - tMD5Final(&context); - - memcpy(pAuth, context.digest, sizeof(context.digest)); -} - -static int rpcAddAuthPart(SRpcConn *pConn, char *msg, int msgLen) { - SRpcHead *pHead = (SRpcHead *)msg; - - if (pConn->spi && pConn->secured == 0) { - // add auth part - pHead->spi = pConn->spi; - SRpcDigest *pDigest = (SRpcDigest *)(msg + msgLen); - pDigest->timeStamp = htonl(taosGetTimestampSec()); - msgLen += sizeof(SRpcDigest); - pHead->msgLen = (int32_t)htonl((uint32_t)msgLen); - rpcBuildAuthHead(pHead, msgLen - TSDB_AUTH_LEN, pDigest->auth, pConn->secret); - } else { - pHead->spi = 0; - pHead->msgLen = (int32_t)htonl((uint32_t)msgLen); - } - - return msgLen; -} - -static int rpcCheckAuthentication(SRpcConn *pConn, char *msg, int msgLen) { - SRpcHead *pHead = (SRpcHead *)msg; - int code = 0; - - if ((pConn->secured && pHead->spi == 0) || (pHead->spi == 0 && pConn->spi == 0)) { - // secured link, or no authentication - pHead->msgLen = (int32_t)htonl((uint32_t)pHead->msgLen); - // tTrace("%s, secured link, no auth is required", pConn->info); - return 0; - } - - if (!rpcIsReq(pHead->msgType)) { - // for response, if code is auth failure, it shall bypass the auth process - code = htonl(pHead->code); - if (code == TSDB_CODE_RPC_INVALID_TIME_STAMP || code == TSDB_CODE_RPC_AUTH_FAILURE || - code == TSDB_CODE_RPC_INVALID_VERSION || code == TSDB_CODE_RPC_AUTH_REQUIRED || - code == TSDB_CODE_MND_USER_NOT_EXIST || code == TSDB_CODE_RPC_NOT_READY) { - pHead->msgLen = (int32_t)htonl((uint32_t)pHead->msgLen); - // tTrace("%s, dont check authentication since code is:0x%x", pConn->info, code); - return 0; - } - } - - code = 0; - if (pHead->spi == pConn->spi) { - // authentication - SRpcDigest *pDigest = (SRpcDigest *)((char *)pHead + msgLen - sizeof(SRpcDigest)); - - int32_t delta; - delta = (int32_t)htonl(pDigest->timeStamp); - delta -= (int32_t)taosGetTimestampSec(); - if (abs(delta) > 900) { - tWarn("%s, time diff:%d is too big, msg discarded", pConn->info, delta); - code = TSDB_CODE_RPC_INVALID_TIME_STAMP; - } else { - if (rpcAuthenticateMsg(pHead, msgLen - TSDB_AUTH_LEN, pDigest->auth, pConn->secret) < 0) { - tDebug("%s, authentication failed, msg discarded", pConn->info); - code = TSDB_CODE_RPC_AUTH_FAILURE; - } else { - pHead->msgLen = (int32_t)htonl((uint32_t)pHead->msgLen) - sizeof(SRpcDigest); - if (!rpcIsReq(pHead->msgType)) pConn->secured = 1; // link is secured for client - // tTrace("%s, message is authenticated", pConn->info); - } - } - } else { - tError("%s, auth spi:%d not matched with received:%d %p", pConn->info, pConn->spi, pHead->spi, pConn); - code = pHead->spi ? TSDB_CODE_RPC_AUTH_FAILURE : TSDB_CODE_RPC_AUTH_REQUIRED; - } - - return code; -} - -static void rpcLockConn(SRpcConn *pConn) { - int64_t tid = taosGetSelfPthreadId(); - int i = 0; - while (atomic_val_compare_exchange_64(&(pConn->lockedBy), 0, tid) != 0) { - if (++i % 1000 == 0) { - sched_yield(); - } - } -} - -static void rpcUnlockConn(SRpcConn *pConn) { - int64_t tid = taosGetSelfPthreadId(); - if (atomic_val_compare_exchange_64(&(pConn->lockedBy), tid, 0) != tid) { - assert(false); - } -} - -static void rpcAddRef(SRpcInfo *pRpc) { atomic_add_fetch_32(&pRpc->refCount, 1); } - -static void rpcDecRef(SRpcInfo *pRpc) { - if (atomic_sub_fetch_32(&pRpc->refCount, 1) == 0) { - rpcCloseConnCache(pRpc->pCache); - taosHashCleanup(pRpc->hash); - taosTmrCleanUp(pRpc->tmrCtrl); - taosIdPoolCleanUp(pRpc->idPool); - - taosMemoryFreeClear(pRpc->connList); - taosThreadMutexDestroy(&pRpc->mutex); - tDebug("%s rpc resources are released", pRpc->label); - taosMemoryFreeClear(pRpc); - - atomic_sub_fetch_32(&tsRpcNum, 1); - } -} -#endif diff --git a/source/libs/transport/src/rpcTcp.c b/source/libs/transport/src/rpcTcp.c deleted file mode 100644 index 52c5ddcf63..0000000000 --- a/source/libs/transport/src/rpcTcp.c +++ /dev/null @@ -1,657 +0,0 @@ -/* - * 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 . - */ - -#include "rpcTcp.h" -#include "os.h" -#include "rpcHead.h" -#include "rpcLog.h" -#include "taosdef.h" -#include "taoserror.h" -#include "tutil.h" - -#ifndef USE_UV -typedef struct SFdObj { - void * signature; - TdSocketPtr pSocket; // TCP socket FD - void * thandle; // handle from upper layer, like TAOS - uint32_t ip; - uint16_t port; - int16_t closedByApp; // 1: already closed by App - struct SThreadObj *pThreadObj; - struct SFdObj * prev; - struct SFdObj * next; -} SFdObj; - -typedef struct SThreadObj { - TdThread thread; - SFdObj * pHead; - TdThreadMutex mutex; - uint32_t ip; - bool stop; - TdEpollPtr pEpoll; - int numOfFds; - int threadId; - char label[TSDB_LABEL_LEN]; - void * shandle; // handle passed by upper layer during server initialization - void *(*processData)(SRecvInfo *pPacket); -} SThreadObj; - -typedef struct { - char label[TSDB_LABEL_LEN]; - int32_t index; - int numOfThreads; - SThreadObj **pThreadObj; -} SClientObj; - -typedef struct { - TdSocketServerPtr pSocketServer; - uint32_t ip; - uint16_t port; - int8_t stop; - int8_t reserve; - char label[TSDB_LABEL_LEN]; - int numOfThreads; - void * shandle; - SThreadObj **pThreadObj; - TdThread thread; -} SServerObj; - -static void * taosProcessTcpData(void *param); -static SFdObj *taosMallocFdObj(SThreadObj *pThreadObj, TdSocketPtr pSocket); -static void taosFreeFdObj(SFdObj *pFdObj); -static void taosReportBrokenLink(SFdObj *pFdObj); -static void * taosAcceptTcpConnection(void *arg); - -void *taosInitTcpServer(uint32_t ip, uint16_t port, char *label, int numOfThreads, void *fp, void *shandle) { - SServerObj *pServerObj; - SThreadObj *pThreadObj; - - pServerObj = (SServerObj *)taosMemoryCalloc(sizeof(SServerObj), 1); - if (pServerObj == NULL) { - tError("TCP:%s no enough memory", label); - terrno = TAOS_SYSTEM_ERROR(errno); - return NULL; - } - - pServerObj->pSocketServer = NULL; - taosResetPthread(&pServerObj->thread); - pServerObj->ip = ip; - pServerObj->port = port; - tstrncpy(pServerObj->label, label, sizeof(pServerObj->label)); - pServerObj->numOfThreads = numOfThreads; - - pServerObj->pThreadObj = (SThreadObj **)taosMemoryCalloc(sizeof(SThreadObj *), numOfThreads); - if (pServerObj->pThreadObj == NULL) { - tError("TCP:%s no enough memory", label); - terrno = TAOS_SYSTEM_ERROR(errno); - taosMemoryFree(pServerObj); - return NULL; - } - - int code = 0; - TdThreadAttr thattr; - taosThreadAttrInit(&thattr); - taosThreadAttrSetDetachState(&thattr, PTHREAD_CREATE_JOINABLE); - - // initialize parameters in case it may encounter error later - for (int i = 0; i < numOfThreads; ++i) { - pThreadObj = (SThreadObj *)taosMemoryCalloc(sizeof(SThreadObj), 1); - if (pThreadObj == NULL) { - tError("TCP:%s no enough memory", label); - terrno = TAOS_SYSTEM_ERROR(errno); - for (int j = 0; j < i; ++j) taosMemoryFree(pServerObj->pThreadObj[j]); - taosMemoryFree(pServerObj->pThreadObj); - taosMemoryFree(pServerObj); - return NULL; - } - - pServerObj->pThreadObj[i] = pThreadObj; - pThreadObj->pEpoll = NULL; - taosResetPthread(&pThreadObj->thread); - pThreadObj->processData = fp; - tstrncpy(pThreadObj->label, label, sizeof(pThreadObj->label)); - pThreadObj->shandle = shandle; - pThreadObj->stop = false; - } - - // initialize mutex, thread, fd which may fail - for (int i = 0; i < numOfThreads; ++i) { - pThreadObj = pServerObj->pThreadObj[i]; - code = taosThreadMutexInit(&(pThreadObj->mutex), NULL); - if (code < 0) { - tError("%s failed to init TCP process data mutex(%s)", label, strerror(errno)); - break; - } - - pThreadObj->pEpoll = taosCreateEpoll(10); // size does not matter - if (pThreadObj->pEpoll == NULL) { - tError("%s failed to create TCP epoll", label); - code = -1; - break; - } - - code = taosThreadCreate(&(pThreadObj->thread), &thattr, taosProcessTcpData, (void *)(pThreadObj)); - if (code != 0) { - tError("%s failed to create TCP process data thread(%s)", label, strerror(errno)); - break; - } - - pThreadObj->threadId = i; - } - - pServerObj->pSocketServer = taosOpenTcpServerSocket(pServerObj->ip, pServerObj->port); - if (pServerObj->pSocketServer == NULL) code = -1; - - if (code == 0) { - code = taosThreadCreate(&pServerObj->thread, &thattr, taosAcceptTcpConnection, (void *)pServerObj); - if (code != 0) { - tError("%s failed to create TCP accept thread(%s)", label, strerror(code)); - } - } - - if (code != 0) { - terrno = TAOS_SYSTEM_ERROR(errno); - taosCleanUpTcpServer(pServerObj); - pServerObj = NULL; - } else { - tDebug("%s TCP server is initialized, ip:0x%x port:%hu numOfThreads:%d", label, ip, port, numOfThreads); - } - - taosThreadAttrDestroy(&thattr); - return (void *)pServerObj; -} - -static void taosStopTcpThread(SThreadObj *pThreadObj) { - if (pThreadObj == NULL) { - return; - } - // save thread into local variable and signal thread to stop - TdThread thread = pThreadObj->thread; - if (!taosCheckPthreadValid(thread)) { - return; - } - pThreadObj->stop = true; - if (taosComparePthread(thread, taosThreadSelf())) { - pthread_detach(taosThreadSelf()); - return; - } - taosThreadJoin(thread, NULL); -} - -void taosStopTcpServer(void *handle) { - SServerObj *pServerObj = handle; - - if (pServerObj == NULL) return; - pServerObj->stop = 1; - - if (pServerObj->pSocketServer != NULL) { - taosShutDownSocketServerRD(pServerObj->pSocketServer); - } - if (taosCheckPthreadValid(pServerObj->thread)) { - if (taosComparePthread(pServerObj->thread, taosThreadSelf())) { - pthread_detach(taosThreadSelf()); - } else { - taosThreadJoin(pServerObj->thread, NULL); - } - } - - tDebug("%s TCP server is stopped", pServerObj->label); -} - -void taosCleanUpTcpServer(void *handle) { - SServerObj *pServerObj = handle; - SThreadObj *pThreadObj; - if (pServerObj == NULL) return; - - for (int i = 0; i < pServerObj->numOfThreads; ++i) { - pThreadObj = pServerObj->pThreadObj[i]; - taosStopTcpThread(pThreadObj); - } - - tDebug("%s TCP server is cleaned up", pServerObj->label); - - taosMemoryFreeClear(pServerObj->pThreadObj); - taosMemoryFreeClear(pServerObj); -} - -static void *taosAcceptTcpConnection(void *arg) { - TdSocketPtr pSocket = NULL; - struct sockaddr_in caddr; - int threadId = 0; - SThreadObj * pThreadObj; - SServerObj * pServerObj; - - pServerObj = (SServerObj *)arg; - tDebug("%s TCP server is ready, ip:0x%x:%hu", pServerObj->label, pServerObj->ip, pServerObj->port); - setThreadName("acceptTcpConn"); - - while (1) { - socklen_t addrlen = sizeof(caddr); - pSocket = taosAcceptTcpConnectSocket(pServerObj->pSocketServer, (struct sockaddr *)&caddr, &addrlen); - if (pServerObj->stop) { - tDebug("%s TCP server stop accepting new connections", pServerObj->label); - break; - } - - if (pSocket == NULL) { - if (errno == EINVAL) { - tDebug("%s TCP server stop accepting new connections, exiting", pServerObj->label); - break; - } - - tError("%s TCP accept failure(%s)", pServerObj->label, strerror(errno)); - continue; - } - - taosKeepTcpAlive(pSocket); - struct timeval to = {5, 0}; - int32_t ret = taosSetSockOpt(pSocket, SOL_SOCKET, SO_RCVTIMEO, &to, sizeof(to)); - if (ret != 0) { - taosCloseSocket(&pSocket); - tError("%s failed to set recv timeout fd(%s)for connection from:%s:%hu", pServerObj->label, strerror(errno), - taosInetNtoa(caddr.sin_addr), htons(caddr.sin_port)); - continue; - } - - // pick up the thread to handle this connection - pThreadObj = pServerObj->pThreadObj[threadId]; - - SFdObj *pFdObj = taosMallocFdObj(pThreadObj, pSocket); - if (pFdObj) { - pFdObj->ip = caddr.sin_addr.s_addr; - pFdObj->port = htons(caddr.sin_port); - tDebug("%s new TCP connection from %s:%hu, FD:%p numOfFds:%d", pServerObj->label, - taosInetNtoa(caddr.sin_addr), pFdObj->port, pFdObj, pThreadObj->numOfFds); - } else { - taosCloseSocket(&pSocket); - tError("%s failed to malloc FdObj(%s) for connection from:%s:%hu", pServerObj->label, strerror(errno), - taosInetNtoa(caddr.sin_addr), htons(caddr.sin_port)); - } - - // pick up next thread for next connection - threadId++; - threadId = threadId % pServerObj->numOfThreads; - } - - taosCloseSocketServer(&pServerObj->pSocketServer); - return NULL; -} - -void *taosInitTcpClient(uint32_t ip, uint16_t port, char *label, int numOfThreads, void *fp, void *shandle) { - SClientObj *pClientObj = (SClientObj *)taosMemoryCalloc(1, sizeof(SClientObj)); - if (pClientObj == NULL) { - tError("TCP:%s no enough memory", label); - terrno = TAOS_SYSTEM_ERROR(errno); - return NULL; - } - - tstrncpy(pClientObj->label, label, sizeof(pClientObj->label)); - pClientObj->numOfThreads = numOfThreads; - pClientObj->pThreadObj = (SThreadObj **)taosMemoryCalloc(numOfThreads, sizeof(SThreadObj *)); - if (pClientObj->pThreadObj == NULL) { - tError("TCP:%s no enough memory", label); - taosMemoryFreeClear(pClientObj); - terrno = TAOS_SYSTEM_ERROR(errno); - } - - int code = 0; - TdThreadAttr thattr; - taosThreadAttrInit(&thattr); - taosThreadAttrSetDetachState(&thattr, PTHREAD_CREATE_JOINABLE); - - for (int i = 0; i < numOfThreads; ++i) { - SThreadObj *pThreadObj = (SThreadObj *)taosMemoryCalloc(1, sizeof(SThreadObj)); - if (pThreadObj == NULL) { - tError("TCP:%s no enough memory", label); - terrno = TAOS_SYSTEM_ERROR(errno); - for (int j = 0; j < i; ++j) taosMemoryFree(pClientObj->pThreadObj[j]); - taosMemoryFree(pClientObj); - taosThreadAttrDestroy(&thattr); - return NULL; - } - pClientObj->pThreadObj[i] = pThreadObj; - taosResetPthread(&pThreadObj->thread); - pThreadObj->ip = ip; - pThreadObj->stop = false; - tstrncpy(pThreadObj->label, label, sizeof(pThreadObj->label)); - pThreadObj->shandle = shandle; - pThreadObj->processData = fp; - } - - // initialize mutex, thread, fd which may fail - for (int i = 0; i < numOfThreads; ++i) { - SThreadObj *pThreadObj = pClientObj->pThreadObj[i]; - code = taosThreadMutexInit(&(pThreadObj->mutex), NULL); - if (code < 0) { - tError("%s failed to init TCP process data mutex(%s)", label, strerror(errno)); - break; - } - - pThreadObj->pEpoll = taosCreateEpoll(10); // size does not matter - if (pThreadObj->pEpoll == NULL) { - tError("%s failed to create TCP epoll", label); - code = -1; - break; - } - - code = taosThreadCreate(&(pThreadObj->thread), &thattr, taosProcessTcpData, (void *)(pThreadObj)); - if (code != 0) { - tError("%s failed to create TCP process data thread(%s)", label, strerror(errno)); - break; - } - pThreadObj->threadId = i; - } - if (code != 0) { - terrno = TAOS_SYSTEM_ERROR(errno); - taosCleanUpTcpClient(pClientObj); - pClientObj = NULL; - } - return pClientObj; -} - -void taosStopTcpClient(void *chandle) { - SClientObj *pClientObj = chandle; - - if (pClientObj == NULL) return; - - tDebug("%s TCP client is stopped", pClientObj->label); -} - -void taosCleanUpTcpClient(void *chandle) { - SClientObj *pClientObj = chandle; - if (pClientObj == NULL) return; - for (int i = 0; i < pClientObj->numOfThreads; ++i) { - SThreadObj *pThreadObj = pClientObj->pThreadObj[i]; - taosStopTcpThread(pThreadObj); - } - - tDebug("%s TCP client is cleaned up", pClientObj->label); - taosMemoryFreeClear(pClientObj->pThreadObj); - taosMemoryFreeClear(pClientObj); -} - -void *taosOpenTcpClientConnection(void *shandle, void *thandle, uint32_t ip, uint16_t port) { - SClientObj *pClientObj = shandle; - int32_t index = atomic_load_32(&pClientObj->index) % pClientObj->numOfThreads; - atomic_store_32(&pClientObj->index, index + 1); - SThreadObj *pThreadObj = pClientObj->pThreadObj[index]; - - TdSocketPtr pSocket = taosOpenTcpClientSocket(ip, port, pThreadObj->ip); - if (pSocket == NULL) return NULL; - - struct sockaddr_in sin; - uint16_t localPort = 0; - unsigned int addrlen = sizeof(sin); - if (taosGetSocketName(pSocket, (struct sockaddr *)&sin, &addrlen) == 0 && sin.sin_family == AF_INET && addrlen == sizeof(sin)) { - localPort = (uint16_t)ntohs(sin.sin_port); - } - - SFdObj *pFdObj = taosMallocFdObj(pThreadObj, pSocket); - - if (pFdObj) { - pFdObj->thandle = thandle; - pFdObj->port = port; - pFdObj->ip = ip; - - char ipport[40] = {0}; - taosIpPort2String(ip, port, ipport); - tDebug("%s %p TCP connection to %s is created, localPort:%hu FD:%p numOfFds:%d", pThreadObj->label, thandle, - ipport, localPort, pFdObj, pThreadObj->numOfFds); - } else { - tError("%s failed to malloc client FdObj(%s)", pThreadObj->label, strerror(errno)); - taosCloseSocket(&pSocket); - } - - return pFdObj; -} - -void taosCloseTcpConnection(void *chandle) { - SFdObj *pFdObj = chandle; - if (pFdObj == NULL || pFdObj->signature != pFdObj) return; - - SThreadObj *pThreadObj = pFdObj->pThreadObj; - tDebug("%s %p TCP connection will be closed, FD:%p", pThreadObj->label, pFdObj->thandle, pFdObj); - - // pFdObj->thandle = NULL; - pFdObj->closedByApp = 1; - taosShutDownSocketWR(pFdObj->pSocket); -} - -int taosSendTcpData(uint32_t ip, uint16_t port, void *data, int len, void *chandle) { - SFdObj *pFdObj = chandle; - if (pFdObj == NULL || pFdObj->signature != pFdObj) return -1; - SThreadObj *pThreadObj = pFdObj->pThreadObj; - - int ret = taosWriteMsg(pFdObj->pSocket, data, len); - tTrace("%s %p TCP data is sent, FD:%p bytes:%d", pThreadObj->label, pFdObj->thandle, pFdObj, ret); - - return ret; -} - -static void taosReportBrokenLink(SFdObj *pFdObj) { - SThreadObj *pThreadObj = pFdObj->pThreadObj; - - // notify the upper layer, so it will clean the associated context - if (pFdObj->closedByApp == 0) { - taosShutDownSocketWR(pFdObj->pSocket); - - SRecvInfo recvInfo; - recvInfo.msg = NULL; - recvInfo.msgLen = 0; - recvInfo.ip = 0; - recvInfo.port = 0; - recvInfo.shandle = pThreadObj->shandle; - recvInfo.thandle = pFdObj->thandle; - recvInfo.chandle = NULL; - recvInfo.connType = RPC_CONN_TCP; - (*(pThreadObj->processData))(&recvInfo); - } - - taosFreeFdObj(pFdObj); -} - -static int taosReadTcpData(SFdObj *pFdObj, SRecvInfo *pInfo) { - SRpcHead rpcHead; - int32_t msgLen, leftLen, retLen, headLen; - char * buffer, *msg; - - SThreadObj *pThreadObj = pFdObj->pThreadObj; - - headLen = taosReadMsg(pFdObj->pSocket, &rpcHead, sizeof(SRpcHead)); - if (headLen != sizeof(SRpcHead)) { - tDebug("%s %p read error, FD:%p headLen:%d", pThreadObj->label, pFdObj->thandle, pFdObj, headLen); - return -1; - } - - msgLen = (int32_t)htonl((uint32_t)rpcHead.msgLen); - int32_t size = msgLen + tsRpcOverhead; - buffer = taosMemoryMalloc(size); - if (NULL == buffer) { - tError("%s %p TCP taosMemoryMalloc(size:%d) fail", pThreadObj->label, pFdObj->thandle, msgLen); - return -1; - } else { - tTrace("%s %p read data, FD:%p TCP malloc mem:%p", pThreadObj->label, pFdObj->thandle, pFdObj, buffer); - } - - msg = buffer + tsRpcOverhead; - leftLen = msgLen - headLen; - retLen = taosReadMsg(pFdObj->pSocket, msg + headLen, leftLen); - - if (leftLen != retLen) { - tError("%s %p read error, leftLen:%d retLen:%d FD:%p", pThreadObj->label, pFdObj->thandle, leftLen, retLen, pFdObj); - taosMemoryFree(buffer); - return -1; - } - - memcpy(msg, &rpcHead, sizeof(SRpcHead)); - - pInfo->msg = msg; - pInfo->msgLen = msgLen; - pInfo->ip = pFdObj->ip; - pInfo->port = pFdObj->port; - pInfo->shandle = pThreadObj->shandle; - pInfo->thandle = pFdObj->thandle; - pInfo->chandle = pFdObj; - pInfo->connType = RPC_CONN_TCP; - - if (pFdObj->closedByApp) { - taosMemoryFree(buffer); - return -1; - } - - return 0; -} - -#define maxEvents 10 - -static void *taosProcessTcpData(void *param) { - SThreadObj * pThreadObj = param; - SFdObj * pFdObj; - struct epoll_event events[maxEvents]; - SRecvInfo recvInfo; - - char name[16] = {0}; - snprintf(name, tListLen(name), "%s-tcp", pThreadObj->label); - setThreadName(name); - - while (1) { - int fdNum = taosWaitEpoll(pThreadObj->pEpoll, events, maxEvents, TAOS_EPOLL_WAIT_TIME); - if (pThreadObj->stop) { - tDebug("%s TCP thread get stop event, exiting...", pThreadObj->label); - break; - } - if (fdNum < 0) continue; - - for (int i = 0; i < fdNum; ++i) { - pFdObj = events[i].data.ptr; - - if (events[i].events & EPOLLERR) { - tDebug("%s %p FD:%p epoll errors", pThreadObj->label, pFdObj->thandle, pFdObj); - taosReportBrokenLink(pFdObj); - continue; - } - - if (events[i].events & EPOLLRDHUP) { - tDebug("%s %p FD:%p RD hang up", pThreadObj->label, pFdObj->thandle, pFdObj); - taosReportBrokenLink(pFdObj); - continue; - } - - if (events[i].events & EPOLLHUP) { - tDebug("%s %p FD:%p hang up", pThreadObj->label, pFdObj->thandle, pFdObj); - taosReportBrokenLink(pFdObj); - continue; - } - - if (taosReadTcpData(pFdObj, &recvInfo) < 0) { - taosShutDownSocketWR(pFdObj->pSocket); - continue; - } - - pFdObj->thandle = (*(pThreadObj->processData))(&recvInfo); - if (pFdObj->thandle == NULL) taosFreeFdObj(pFdObj); - } - - if (pThreadObj->stop) break; - } - - if (pThreadObj->pEpoll != NULL) { - taosCloseEpoll(&pThreadObj->pEpoll); - pThreadObj->pEpoll = NULL; - } - - while (pThreadObj->pHead) { - pFdObj = pThreadObj->pHead; - pThreadObj->pHead = pFdObj->next; - taosReportBrokenLink(pFdObj); - } - - taosThreadMutexDestroy(&(pThreadObj->mutex)); - tDebug("%s TCP thread exits ...", pThreadObj->label); - taosMemoryFreeClear(pThreadObj); - - return NULL; -} - -static SFdObj *taosMallocFdObj(SThreadObj *pThreadObj, TdSocketPtr pSocket) { - struct epoll_event event; - - SFdObj *pFdObj = (SFdObj *)taosMemoryCalloc(sizeof(SFdObj), 1); - if (pFdObj == NULL) { - return NULL; - } - - pFdObj->closedByApp = 0; - pFdObj->pSocket = pSocket; - pFdObj->pThreadObj = pThreadObj; - pFdObj->signature = pFdObj; - - event.events = EPOLLIN | EPOLLRDHUP; - event.data.ptr = pFdObj; - if (taosCtlEpoll(pThreadObj->pEpoll, EPOLL_CTL_ADD, pSocket, &event) < 0) { - taosMemoryFreeClear(pFdObj); - terrno = TAOS_SYSTEM_ERROR(errno); - return NULL; - } - - // notify the data process, add into the FdObj list - taosThreadMutexLock(&(pThreadObj->mutex)); - pFdObj->next = pThreadObj->pHead; - if (pThreadObj->pHead) (pThreadObj->pHead)->prev = pFdObj; - pThreadObj->pHead = pFdObj; - pThreadObj->numOfFds++; - taosThreadMutexUnlock(&(pThreadObj->mutex)); - - return pFdObj; -} - -static void taosFreeFdObj(SFdObj *pFdObj) { - if (pFdObj == NULL) return; - if (pFdObj->signature != pFdObj) return; - - SThreadObj *pThreadObj = pFdObj->pThreadObj; - taosThreadMutexLock(&pThreadObj->mutex); - - if (pFdObj->signature == NULL) { - taosThreadMutexUnlock(&pThreadObj->mutex); - return; - } - - pFdObj->signature = NULL; - taosCtlEpoll(pThreadObj->pEpoll, EPOLL_CTL_DEL, pFdObj->pSocket, NULL); - taosCloseSocket(&pFdObj->pSocket); - - pThreadObj->numOfFds--; - if (pThreadObj->numOfFds < 0) - tError("%s %p TCP thread:%d, number of FDs is negative!!!", pThreadObj->label, pFdObj->thandle, - pThreadObj->threadId); - - if (pFdObj->prev) { - (pFdObj->prev)->next = pFdObj->next; - } else { - pThreadObj->pHead = pFdObj->next; - } - - if (pFdObj->next) { - (pFdObj->next)->prev = pFdObj->prev; - } - - taosThreadMutexUnlock(&pThreadObj->mutex); - - tDebug("%s %p TCP connection is closed, FD:%p numOfFds:%d", pThreadObj->label, pFdObj->thandle, pFdObj, pThreadObj->numOfFds); - - taosMemoryFreeClear(pFdObj); -} -#endif \ No newline at end of file diff --git a/source/libs/transport/src/rpcUdp.c b/source/libs/transport/src/rpcUdp.c deleted file mode 100644 index 359a94011d..0000000000 --- a/source/libs/transport/src/rpcUdp.c +++ /dev/null @@ -1,261 +0,0 @@ -/* - * 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 . - */ - -#include "rpcUdp.h" -#include "os.h" -#include "rpcHead.h" -#include "rpcLog.h" -#include "taosdef.h" -#include "taoserror.h" -#include "ttimer.h" -#include "tutil.h" - -#ifndef USE_UV - -#define RPC_MAX_UDP_CONNS 256 -#define RPC_MAX_UDP_PKTS 1000 -#define RPC_UDP_BUF_TIME 5 // mseconds -#define RPC_MAX_UDP_SIZE 65480 - -typedef struct { - int index; - TdSocketPtr pSocket; - uint16_t port; // peer port - uint16_t localPort; // local port - char label[TSDB_LABEL_LEN]; // copy from udpConnSet; - TdThread thread; - void *hash; - void *shandle; // handle passed by upper layer during server initialization - void *pSet; - void *(*processData)(SRecvInfo *pRecv); - char *buffer; // buffer to receive data -} SUdpConn; - -typedef struct { - int index; - int server; - uint32_t ip; // local IP - uint16_t port; // local Port - void * shandle; // handle passed by upper layer during server initialization - int threads; - char label[TSDB_LABEL_LEN]; - void *(*fp)(SRecvInfo *pPacket); - SUdpConn udpConn[]; -} SUdpConnSet; - -static void *taosRecvUdpData(void *param); - -void *taosInitUdpConnection(uint32_t ip, uint16_t port, char *label, int threads, void *fp, void *shandle) { - SUdpConn * pConn; - SUdpConnSet *pSet; - - int size = (int)sizeof(SUdpConnSet) + threads * (int)sizeof(SUdpConn); - pSet = (SUdpConnSet *)taosMemoryMalloc((size_t)size); - if (pSet == NULL) { - tError("%s failed to allocate UdpConn", label); - terrno = TAOS_SYSTEM_ERROR(errno); - return NULL; - } - - memset(pSet, 0, (size_t)size); - pSet->ip = ip; - pSet->port = port; - pSet->shandle = shandle; - pSet->fp = fp; - pSet->threads = threads; - tstrncpy(pSet->label, label, sizeof(pSet->label)); - - TdThreadAttr thAttr; - taosThreadAttrInit(&thAttr); - taosThreadAttrSetDetachState(&thAttr, PTHREAD_CREATE_JOINABLE); - - int i; - uint16_t ownPort; - for (i = 0; i < threads; ++i) { - pConn = pSet->udpConn + i; - ownPort = (port ? port + i : 0); - pConn->pSocket = taosOpenUdpSocket(ip, ownPort); - if (pConn->pSocket == NULL) { - tError("%s failed to open UDP socket %x:%hu", label, ip, port); - break; - } - - pConn->buffer = taosMemoryMalloc(RPC_MAX_UDP_SIZE); - if (NULL == pConn->buffer) { - tError("%s failed to malloc recv buffer", label); - break; - } - - struct sockaddr_in sin; - unsigned int addrlen = sizeof(sin); - if (taosGetSocketName(pConn->pSocket, (struct sockaddr *)&sin, &addrlen) == 0 && sin.sin_family == AF_INET && - addrlen == sizeof(sin)) { - pConn->localPort = (uint16_t)ntohs(sin.sin_port); - } - - tstrncpy(pConn->label, label, sizeof(pConn->label)); - pConn->shandle = shandle; - pConn->processData = fp; - pConn->index = i; - pConn->pSet = pSet; - - int code = taosThreadCreate(&pConn->thread, &thAttr, taosRecvUdpData, pConn); - if (code != 0) { - tError("%s failed to create thread to process UDP data(%s)", label, strerror(errno)); - break; - } - } - - taosThreadAttrDestroy(&thAttr); - - if (i != threads) { - terrno = TAOS_SYSTEM_ERROR(errno); - taosCleanUpUdpConnection(pSet); - return NULL; - } - - tDebug("%s UDP connection is initialized, ip:%x:%hu threads:%d", label, ip, port, threads); - return pSet; -} - -void taosStopUdpConnection(void *handle) { - SUdpConnSet *pSet = (SUdpConnSet *)handle; - SUdpConn * pConn; - - if (pSet == NULL) return; - - for (int i = 0; i < pSet->threads; ++i) { - pConn = pSet->udpConn + i; - if (pConn->pSocket != NULL) taosShutDownSocketRDWR(pConn->pSocket); - if (pConn->pSocket != NULL) taosCloseSocket(&pConn->pSocket); - pConn->pSocket = NULL; - } - - for (int i = 0; i < pSet->threads; ++i) { - pConn = pSet->udpConn + i; - if (taosCheckPthreadValid(pConn->thread)) { - taosThreadJoin(pConn->thread, NULL); - } - taosMemoryFreeClear(pConn->buffer); - // tTrace("%s UDP thread is closed, index:%d", pConn->label, i); - } - - tDebug("%s UDP is stopped", pSet->label); -} - -void taosCleanUpUdpConnection(void *handle) { - SUdpConnSet *pSet = (SUdpConnSet *)handle; - SUdpConn * pConn; - - if (pSet == NULL) return; - - for (int i = 0; i < pSet->threads; ++i) { - pConn = pSet->udpConn + i; - if (pConn->pSocket != NULL) taosCloseSocket(&pConn->pSocket); - } - - tDebug("%s UDP is cleaned up", pSet->label); - taosMemoryFreeClear(pSet); -} - -void *taosOpenUdpConnection(void *shandle, void *thandle, uint32_t ip, uint16_t port) { - SUdpConnSet *pSet = (SUdpConnSet *)shandle; - - pSet->index = (pSet->index + 1) % pSet->threads; - - SUdpConn *pConn = pSet->udpConn + pSet->index; - pConn->port = port; - - tDebug("%s UDP connection is setup, ip:%x:%hu localPort:%hu", pConn->label, ip, port, pConn->localPort); - - return pConn; -} - -static void *taosRecvUdpData(void *param) { - SUdpConn * pConn = param; - struct sockaddr_in sourceAdd; - ssize_t dataLen; - unsigned int addLen; - uint16_t port; - SRecvInfo recvInfo; - - memset(&sourceAdd, 0, sizeof(sourceAdd)); - addLen = sizeof(sourceAdd); - tDebug("%s UDP thread is created, index:%d", pConn->label, pConn->index); - char *msg = pConn->buffer; - - setThreadName("recvUdpData"); - - while (1) { - dataLen = taosReadFromSocket(pConn->pSocket, pConn->buffer, RPC_MAX_UDP_SIZE, 0, (struct sockaddr *)&sourceAdd, &addLen); - if (dataLen <= 0) { - tDebug("%s UDP socket was closed, exiting(%s), dataLen:%d", pConn->label, strerror(errno), (int32_t)dataLen); - - // for windows usage, remote shutdown also returns - 1 in windows client - if (pConn->pSocket == NULL) { - break; - } else { - continue; - } - } - - port = ntohs(sourceAdd.sin_port); - - if (dataLen < sizeof(SRpcHead)) { - tError("%s recvfrom failed(%s)", pConn->label, strerror(errno)); - continue; - } - - int32_t size = dataLen + tsRpcOverhead; - char * tmsg = taosMemoryMalloc(size); - if (NULL == tmsg) { - tError("%s failed to allocate memory, size:%" PRId64, pConn->label, (int64_t)dataLen); - continue; - } else { - tTrace("UDP malloc mem:%p size:%d", tmsg, size); - } - - tmsg += tsRpcOverhead; // overhead for SRpcReqContext - memcpy(tmsg, msg, dataLen); - recvInfo.msg = tmsg; - recvInfo.msgLen = dataLen; - recvInfo.ip = sourceAdd.sin_addr.s_addr; - recvInfo.port = port; - recvInfo.shandle = pConn->shandle; - recvInfo.thandle = NULL; - recvInfo.chandle = pConn; - recvInfo.connType = 0; - (*(pConn->processData))(&recvInfo); - } - - return NULL; -} - -int taosSendUdpData(uint32_t ip, uint16_t port, void *data, int dataLen, void *chandle) { - SUdpConn *pConn = (SUdpConn *)chandle; - - if (pConn == NULL) return -1; - - struct sockaddr_in destAdd; - memset(&destAdd, 0, sizeof(destAdd)); - destAdd.sin_family = AF_INET; - destAdd.sin_addr.s_addr = ip; - destAdd.sin_port = htons(port); - - int ret = taosSendto(pConn->pSocket, data, (size_t)dataLen, 0, (struct sockaddr *)&destAdd, sizeof(destAdd)); - - return ret; -} -#endif \ No newline at end of file diff --git a/source/libs/transport/test/pushServer.c b/source/libs/transport/test/pushServer.c index 2bf086b99b..8b1dcd46cf 100644 --- a/source/libs/transport/test/pushServer.c +++ b/source/libs/transport/test/pushServer.c @@ -15,9 +15,9 @@ //#define _DEFAULT_SOURCE #include "os.h" -#include "rpcLog.h" #include "tglobal.h" #include "tqueue.h" +#include "transLog.h" #include "trpc.h" int msgSize = 128; diff --git a/source/libs/transport/test/rclient.c b/source/libs/transport/test/rclient.c index 5755e4a273..eea76096ff 100644 --- a/source/libs/transport/test/rclient.c +++ b/source/libs/transport/test/rclient.c @@ -14,9 +14,9 @@ */ #include #include "os.h" -#include "rpcLog.h" #include "taoserror.h" #include "tglobal.h" +#include "transLog.h" #include "trpc.h" #include "tutil.h" diff --git a/source/libs/transport/test/rserver.c b/source/libs/transport/test/rserver.c index 42bebe5191..6262b3ae48 100644 --- a/source/libs/transport/test/rserver.c +++ b/source/libs/transport/test/rserver.c @@ -15,9 +15,9 @@ //#define _DEFAULT_SOURCE #include "os.h" -#include "rpcLog.h" #include "tglobal.h" #include "tqueue.h" +#include "transLog.h" #include "trpc.h" int msgSize = 128; diff --git a/source/libs/transport/test/syncClient.c b/source/libs/transport/test/syncClient.c index 6fb7d81fca..bc6461eaed 100644 --- a/source/libs/transport/test/syncClient.c +++ b/source/libs/transport/test/syncClient.c @@ -14,9 +14,9 @@ */ #include #include "os.h" -#include "rpcLog.h" #include "taoserror.h" #include "tglobal.h" +#include "transLog.h" #include "trpc.h" #include "tutil.h" diff --git a/source/libs/transport/test/transUT.cpp b/source/libs/transport/test/transUT.cpp index 4829f5aa39..3f5ef1fb53 100644 --- a/source/libs/transport/test/transUT.cpp +++ b/source/libs/transport/test/transUT.cpp @@ -15,10 +15,10 @@ #include #include #include -#include "rpcLog.h" #include "tdatablock.h" #include "tglobal.h" #include "tlog.h" +#include "transLog.h" #include "trpc.h" using namespace std; From 86dcce42ac4590c8c8f7dfc4662f87293939f116 Mon Sep 17 00:00:00 2001 From: Hongze Cheng Date: Sat, 21 May 2022 03:28:29 +0000 Subject: [PATCH 08/13] fix: alter column length --- source/dnode/vnode/src/meta/metaTable.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/dnode/vnode/src/meta/metaTable.c b/source/dnode/vnode/src/meta/metaTable.c index 2bcfd01904..ee4dfc6531 100644 --- a/source/dnode/vnode/src/meta/metaTable.c +++ b/source/dnode/vnode/src/meta/metaTable.c @@ -483,12 +483,12 @@ static int metaAlterTableColumn(SMeta *pMeta, int64_t version, SVAlterTbReq *pAl terrno = TSDB_CODE_VND_TABLE_COL_NOT_EXISTS; goto _err; } - if (!IS_VAR_DATA_TYPE(pColumn->type) || pColumn->bytes <= pAlterTbReq->bytes) { + if (!IS_VAR_DATA_TYPE(pColumn->type) || pColumn->bytes > pAlterTbReq->colModBytes) { terrno = TSDB_CODE_VND_INVALID_TABLE_ACTION; goto _err; } pSchema->sver++; - pColumn->bytes = pAlterTbReq->bytes; + pColumn->bytes = pAlterTbReq->colModBytes; break; case TSDB_ALTER_TABLE_UPDATE_COLUMN_NAME: if (pColumn == NULL) { From 61f4f83bca5d14a218041d8d52a5d912e6bdf902 Mon Sep 17 00:00:00 2001 From: plum-lihui Date: Sat, 21 May 2022 12:01:45 +0800 Subject: [PATCH 09/13] test:open all cases of stb in tmq --- tests/system-test/7-tmq/subscribeStb.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/system-test/7-tmq/subscribeStb.py b/tests/system-test/7-tmq/subscribeStb.py index 5730efd9e2..3fc964b37d 100644 --- a/tests/system-test/7-tmq/subscribeStb.py +++ b/tests/system-test/7-tmq/subscribeStb.py @@ -1382,12 +1382,12 @@ class TDTestCase: self.tmqCase5(cfgPath, buildPath) self.tmqCase6(cfgPath, buildPath) self.tmqCase7(cfgPath, buildPath) - #self.tmqCase8(cfgPath, buildPath) - #self.tmqCase9(cfgPath, buildPath) - #self.tmqCase10(cfgPath, buildPath) - #self.tmqCase11(cfgPath, buildPath) - #self.tmqCase12(cfgPath, buildPath) - #self.tmqCase13(cfgPath, buildPath) + self.tmqCase8(cfgPath, buildPath) + self.tmqCase9(cfgPath, buildPath) + self.tmqCase10(cfgPath, buildPath) + self.tmqCase11(cfgPath, buildPath) + self.tmqCase12(cfgPath, buildPath) + self.tmqCase13(cfgPath, buildPath) def stop(self): tdSql.close() From de8089ac30cbcd81efc68cfbfc711e56184af424 Mon Sep 17 00:00:00 2001 From: plum-lihui Date: Sat, 21 May 2022 13:08:26 +0800 Subject: [PATCH 10/13] test: modify tmq cases --- tests/system-test/7-tmq/subscribeStb.py | 16 +- tests/system-test/7-tmq/subscribeStb1.py | 1399 ++++++++++++++++++++++ tests/system-test/fulltest.sh | 1 + 3 files changed, 1408 insertions(+), 8 deletions(-) create mode 100644 tests/system-test/7-tmq/subscribeStb1.py diff --git a/tests/system-test/7-tmq/subscribeStb.py b/tests/system-test/7-tmq/subscribeStb.py index 3fc964b37d..d0463be710 100644 --- a/tests/system-test/7-tmq/subscribeStb.py +++ b/tests/system-test/7-tmq/subscribeStb.py @@ -1380,14 +1380,14 @@ class TDTestCase: self.tmqCase3(cfgPath, buildPath) self.tmqCase4(cfgPath, buildPath) self.tmqCase5(cfgPath, buildPath) - self.tmqCase6(cfgPath, buildPath) - self.tmqCase7(cfgPath, buildPath) - self.tmqCase8(cfgPath, buildPath) - self.tmqCase9(cfgPath, buildPath) - self.tmqCase10(cfgPath, buildPath) - self.tmqCase11(cfgPath, buildPath) - self.tmqCase12(cfgPath, buildPath) - self.tmqCase13(cfgPath, buildPath) + #self.tmqCase6(cfgPath, buildPath) + #self.tmqCase7(cfgPath, buildPath) + #self.tmqCase8(cfgPath, buildPath) + #self.tmqCase9(cfgPath, buildPath) + #self.tmqCase10(cfgPath, buildPath) + #self.tmqCase11(cfgPath, buildPath) + #self.tmqCase12(cfgPath, buildPath) + #self.tmqCase13(cfgPath, buildPath) def stop(self): tdSql.close() diff --git a/tests/system-test/7-tmq/subscribeStb1.py b/tests/system-test/7-tmq/subscribeStb1.py new file mode 100644 index 0000000000..049b297d2d --- /dev/null +++ b/tests/system-test/7-tmq/subscribeStb1.py @@ -0,0 +1,1399 @@ + +import taos +import sys +import time +import socket +import os +import threading +from enum import Enum + +from util.log import * +from util.sql import * +from util.cases import * +from util.dnodes import * + +class actionType(Enum): + CREATE_DATABASE = 0 + CREATE_STABLE = 1 + CREATE_CTABLE = 2 + INSERT_DATA = 3 + +class TDTestCase: + hostname = socket.gethostname() + #rpcDebugFlagVal = '143' + #clientCfgDict = {'serverPort': '', 'firstEp': '', 'secondEp':'', 'rpcDebugFlag':'135', 'fqdn':''} + #clientCfgDict["rpcDebugFlag"] = rpcDebugFlagVal + #updatecfgDict = {'clientCfg': {}, 'serverPort': '', 'firstEp': '', 'secondEp':'', 'rpcDebugFlag':'135', 'fqdn':''} + #updatecfgDict["rpcDebugFlag"] = rpcDebugFlagVal + #print ("===================: ", updatecfgDict) + + def init(self, conn, logSql): + tdLog.debug(f"start to excute {__file__}") + #tdSql.init(conn.cursor()) + tdSql.init(conn.cursor(), logSql) # output sql.txt file + + def getBuildPath(self): + selfPath = os.path.dirname(os.path.realpath(__file__)) + + if ("community" in selfPath): + projPath = selfPath[:selfPath.find("community")] + else: + projPath = selfPath[:selfPath.find("tests")] + + for root, dirs, files in os.walk(projPath): + if ("taosd" in files): + rootRealPath = os.path.dirname(os.path.realpath(root)) + if ("packaging" not in rootRealPath): + buildPath = root[:len(root) - len("/build/bin")] + break + return buildPath + + def newcur(self,cfg,host,port): + user = "root" + password = "taosdata" + con=taos.connect(host=host, user=user, password=password, config=cfg ,port=port) + cur=con.cursor() + print(cur) + return cur + + def initConsumerTable(self,cdbName='cdb'): + tdLog.info("create consume database, and consume info table, and consume result table") + tdSql.query("create database if not exists %s vgroups 1"%(cdbName)) + tdSql.query("drop table if exists %s.consumeinfo "%(cdbName)) + tdSql.query("drop table if exists %s.consumeresult "%(cdbName)) + + tdSql.query("create table %s.consumeinfo (ts timestamp, consumerid int, topiclist binary(1024), keylist binary(1024), expectmsgcnt bigint, ifcheckdata int, ifmanualcommit int)"%cdbName) + tdSql.query("create table %s.consumeresult (ts timestamp, consumerid int, consummsgcnt bigint, consumrowcnt bigint, checkresult int)"%cdbName) + + def initConsumerInfoTable(self,cdbName='cdb'): + tdLog.info("drop consumeinfo table") + tdSql.query("drop table if exists %s.consumeinfo "%(cdbName)) + tdSql.query("create table %s.consumeinfo (ts timestamp, consumerid int, topiclist binary(1024), keylist binary(1024), expectmsgcnt bigint, ifcheckdata int, ifmanualcommit int)"%cdbName) + + def insertConsumerInfo(self,consumerId, expectrowcnt,topicList,keyList,ifcheckdata,ifmanualcommit,cdbName='cdb'): + sql = "insert into %s.consumeinfo values "%cdbName + sql += "(now, %d, '%s', '%s', %d, %d, %d)"%(consumerId, topicList, keyList, expectrowcnt, ifcheckdata, ifmanualcommit) + tdLog.info("consume info sql: %s"%sql) + tdSql.query(sql) + + def selectConsumeResult(self,expectRows,cdbName='cdb'): + resultList=[] + while 1: + tdSql.query("select * from %s.consumeresult"%cdbName) + #tdLog.info("row: %d, %l64d, %l64d"%(tdSql.getData(0, 1),tdSql.getData(0, 2),tdSql.getData(0, 3)) + if tdSql.getRows() == expectRows: + break + else: + time.sleep(5) + + for i in range(expectRows): + tdLog.info ("consume id: %d, consume msgs: %d, consume rows: %d"%(tdSql.getData(i , 1), tdSql.getData(i , 2), tdSql.getData(i , 3))) + resultList.append(tdSql.getData(i , 3)) + + return resultList + + def startTmqSimProcess(self,buildPath,cfgPath,pollDelay,dbName,showMsg=1,showRow=1,cdbName='cdb',valgrind=0): + shellCmd = 'nohup ' + if valgrind == 1: + logFile = cfgPath + '/../log/valgrind-tmq.log' + shellCmd = 'nohup valgrind --log-file=' + logFile + shellCmd += '--tool=memcheck --leak-check=full --show-reachable=no --track-origins=yes --show-leak-kinds=all --num-callers=20 -v --workaround-gcc296-bugs=yes ' + + shellCmd += buildPath + '/build/bin/tmq_sim -c ' + cfgPath + shellCmd += " -y %d -d %s -g %d -r %d -w %s "%(pollDelay, dbName, showMsg, showRow, cdbName) + shellCmd += "> /dev/null 2>&1 &" + tdLog.info(shellCmd) + os.system(shellCmd) + + def create_database(self,tsql, dbName,dropFlag=1,vgroups=4,replica=1): + if dropFlag == 1: + tsql.execute("drop database if exists %s"%(dbName)) + + tsql.execute("create database if not exists %s vgroups %d replica %d"%(dbName, vgroups, replica)) + tdLog.debug("complete to create database %s"%(dbName)) + return + + def create_stable(self,tsql, dbName,stbName): + tsql.execute("create table if not exists %s.%s (ts timestamp, c1 bigint, c2 binary(16)) tags(t1 int)"%(dbName, stbName)) + tdLog.debug("complete to create %s.%s" %(dbName, stbName)) + return + + def create_ctables(self,tsql, dbName,stbName,ctbNum): + tsql.execute("use %s" %dbName) + pre_create = "create table" + sql = pre_create + #tdLog.debug("doing create one stable %s and %d child table in %s ..." %(stbname, count ,dbname)) + for i in range(ctbNum): + sql += " %s_%d using %s tags(%d)"%(stbName,i,stbName,i+1) + if (i > 0) and (i%100 == 0): + tsql.execute(sql) + sql = pre_create + if sql != pre_create: + tsql.execute(sql) + + tdLog.debug("complete to create %d child tables in %s.%s" %(ctbNum, dbName, stbName)) + return + + def insert_data(self,tsql,dbName,stbName,ctbNum,rowsPerTbl,batchNum,startTs=0): + tdLog.debug("start to insert data ............") + tsql.execute("use %s" %dbName) + pre_insert = "insert into " + sql = pre_insert + + if startTs == 0: + t = time.time() + startTs = int(round(t * 1000)) + + #tdLog.debug("doing insert data into stable:%s rows:%d ..."%(stbName, allRows)) + rowsOfSql = 0 + for i in range(ctbNum): + sql += " %s_%d values "%(stbName,i) + for j in range(rowsPerTbl): + sql += "(%d, %d, 'tmqrow_%d') "%(startTs + j, j, j) + rowsOfSql += 1 + if (j > 0) and ((rowsOfSql == batchNum) or (j == rowsPerTbl - 1)): + tsql.execute(sql) + rowsOfSql = 0 + if j < rowsPerTbl - 1: + sql = "insert into %s_%d values " %(stbName,i) + else: + sql = "insert into " + #end sql + if sql != pre_insert: + #print("insert sql:%s"%sql) + tsql.execute(sql) + tdLog.debug("insert data ............ [OK]") + return + + def prepareEnv(self, **parameterDict): + # create new connector for my thread + tsql=self.newcur(parameterDict['cfg'], 'localhost', 6030) + + if parameterDict["actionType"] == actionType.CREATE_DATABASE: + self.create_database(tsql, parameterDict["dbName"]) + elif parameterDict["actionType"] == actionType.CREATE_STABLE: + self.create_stable(tsql, parameterDict["dbName"], parameterDict["stbName"]) + elif parameterDict["actionType"] == actionType.CREATE_CTABLE: + self.create_ctables(tsql, parameterDict["dbName"], parameterDict["stbName"], parameterDict["ctbNum"]) + elif parameterDict["actionType"] == actionType.INSERT_DATA: + self.insert_data(tsql, parameterDict["dbName"], parameterDict["stbName"], parameterDict["ctbNum"],\ + parameterDict["rowsPerTbl"],parameterDict["batchNum"]) + else: + tdLog.exit("not support's action: ", parameterDict["actionType"]) + + return + + def tmqCase1(self, cfgPath, buildPath): + tdLog.printNoPrefix("======== test case 1: ") + + self.initConsumerTable() + + # create and start thread + parameterDict = {'cfg': '', \ + 'actionType': 0, \ + 'dbName': 'db1', \ + 'dropFlag': 1, \ + 'vgroups': 4, \ + 'replica': 1, \ + 'stbName': 'stb1', \ + 'ctbNum': 10, \ + 'rowsPerTbl': 10000, \ + 'batchNum': 100, \ + 'startTs': 1640966400000} # 2022-01-01 00:00:00.000 + parameterDict['cfg'] = cfgPath + + self.create_database(tdSql, parameterDict["dbName"]) + self.create_stable(tdSql, parameterDict["dbName"], parameterDict["stbName"]) + + tdLog.info("create topics from stb1") + topicFromStb1 = 'topic_stb1' + + tdSql.execute("create topic %s as select ts, c1, c2 from %s.%s" %(topicFromStb1, parameterDict['dbName'], parameterDict['stbName'])) + consumerId = 0 + expectrowcnt = parameterDict["rowsPerTbl"] * parameterDict["ctbNum"] + topicList = topicFromStb1 + ifcheckdata = 0 + ifManualCommit = 0 + keyList = 'group.id:cgrp1,\ + enable.auto.commit:false,\ + auto.commit.interval.ms:6000,\ + auto.offset.reset:earliest' + self.insertConsumerInfo(consumerId, expectrowcnt,topicList,keyList,ifcheckdata,ifManualCommit) + + tdLog.info("start consume processor") + pollDelay = 100 + showMsg = 1 + showRow = 1 + self.startTmqSimProcess(buildPath,cfgPath,pollDelay,parameterDict["dbName"],showMsg, showRow) + + time.sleep(5) + self.create_ctables(tdSql, parameterDict["dbName"], parameterDict["stbName"], parameterDict["ctbNum"]) + self.insert_data(tdSql,\ + parameterDict["dbName"],\ + parameterDict["stbName"],\ + parameterDict["ctbNum"],\ + parameterDict["rowsPerTbl"],\ + parameterDict["batchNum"]) + + tdLog.info("insert process end, and start to check consume result") + expectRows = 1 + resultList = self.selectConsumeResult(expectRows) + totalConsumeRows = 0 + for i in range(expectRows): + totalConsumeRows += resultList[i] + + if totalConsumeRows != expectrowcnt: + tdLog.info("act consume rows: %d, expect consume rows: %d"%(totalConsumeRows, expectrowcnt)) + tdLog.exit("tmq consume rows error!") + + tdSql.query("drop topic %s"%topicFromStb1) + + tdLog.printNoPrefix("======== test case 1 end ...... ") + + def tmqCase2(self, cfgPath, buildPath): + tdLog.printNoPrefix("======== test case 2: ") + + self.initConsumerTable() + + # create and start thread + parameterDict = {'cfg': '', \ + 'actionType': 0, \ + 'dbName': 'db2', \ + 'dropFlag': 1, \ + 'vgroups': 4, \ + 'replica': 1, \ + 'stbName': 'stb1', \ + 'ctbNum': 10, \ + 'rowsPerTbl': 10000, \ + 'batchNum': 100, \ + 'startTs': 1640966400000} # 2022-01-01 00:00:00.000 + parameterDict['cfg'] = cfgPath + + parameterDict2 = {'cfg': '', \ + 'actionType': 0, \ + 'dbName': 'db2', \ + 'dropFlag': 1, \ + 'vgroups': 4, \ + 'replica': 1, \ + 'stbName': 'stb2', \ + 'ctbNum': 10, \ + 'rowsPerTbl': 10000, \ + 'batchNum': 100, \ + 'startTs': 1640966400000} # 2022-01-01 00:00:00.000 + parameterDict2['cfg'] = cfgPath + + self.create_database(tdSql, parameterDict["dbName"]) + self.create_stable(tdSql, parameterDict["dbName"], parameterDict["stbName"]) + self.create_stable(tdSql, parameterDict2["dbName"], parameterDict2["stbName"]) + + tdLog.info("create topics from stb1") + topicFromStb1 = 'topic_stb1' + + tdSql.execute("create topic %s as select ts, c1, c2 from %s.%s" %(topicFromStb1, parameterDict['dbName'], parameterDict['stbName'])) + consumerId = 0 + expectrowcnt = parameterDict["rowsPerTbl"] * parameterDict["ctbNum"] + topicList = topicFromStb1 + ifcheckdata = 0 + ifManualCommit = 0 + keyList = 'group.id:cgrp1,\ + enable.auto.commit:false,\ + auto.commit.interval.ms:6000,\ + auto.offset.reset:earliest' + self.insertConsumerInfo(consumerId, expectrowcnt,topicList,keyList,ifcheckdata,ifManualCommit) + + tdLog.info("start consume processor") + pollDelay = 100 + showMsg = 1 + showRow = 1 + self.startTmqSimProcess(buildPath,cfgPath,pollDelay,parameterDict["dbName"],showMsg, showRow) + + tdLog.info("start create child tables of stb1 and stb2") + parameterDict['actionType'] = actionType.CREATE_CTABLE + parameterDict2['actionType'] = actionType.CREATE_CTABLE + + prepareEnvThread = threading.Thread(target=self.prepareEnv, kwargs=parameterDict) + prepareEnvThread.start() + prepareEnvThread2 = threading.Thread(target=self.prepareEnv, kwargs=parameterDict2) + prepareEnvThread2.start() + + prepareEnvThread.join() + prepareEnvThread2.join() + + tdLog.info("start insert data into child tables of stb1 and stb2") + parameterDict['actionType'] = actionType.INSERT_DATA + parameterDict2['actionType'] = actionType.INSERT_DATA + + prepareEnvThread = threading.Thread(target=self.prepareEnv, kwargs=parameterDict) + prepareEnvThread.start() + prepareEnvThread2 = threading.Thread(target=self.prepareEnv, kwargs=parameterDict2) + prepareEnvThread2.start() + + prepareEnvThread.join() + prepareEnvThread2.join() + + tdLog.info("insert process end, and start to check consume result") + expectRows = 1 + resultList = self.selectConsumeResult(expectRows) + totalConsumeRows = 0 + for i in range(expectRows): + totalConsumeRows += resultList[i] + + if totalConsumeRows != expectrowcnt: + tdLog.info("act consume rows: %d, expect consume rows: %d"%(totalConsumeRows, expectrowcnt)) + tdLog.exit("tmq consume rows error!") + + tdSql.query("drop topic %s"%topicFromStb1) + + tdLog.printNoPrefix("======== test case 2 end ...... ") + + def tmqCase3(self, cfgPath, buildPath): + tdLog.printNoPrefix("======== test case 3: ") + + self.initConsumerTable() + + # create and start thread + parameterDict = {'cfg': '', \ + 'actionType': 0, \ + 'dbName': 'db3', \ + 'dropFlag': 1, \ + 'vgroups': 4, \ + 'replica': 1, \ + 'stbName': 'stb1', \ + 'ctbNum': 10, \ + 'rowsPerTbl': 10000, \ + 'batchNum': 13, \ + 'startTs': 1640966400000} # 2022-01-01 00:00:00.000 + parameterDict['cfg'] = cfgPath + + self.create_database(tdSql, parameterDict["dbName"]) + self.create_stable(tdSql, parameterDict["dbName"], parameterDict["stbName"]) + self.create_ctables(tdSql, parameterDict["dbName"], parameterDict["stbName"], parameterDict["ctbNum"]) + self.insert_data(tdSql,parameterDict["dbName"],parameterDict["stbName"],parameterDict["ctbNum"],parameterDict["rowsPerTbl"],parameterDict["batchNum"]) + + tdLog.info("create topics from stb1") + topicFromStb1 = 'topic_stb1' + + tdSql.execute("create topic %s as select ts, c1, c2 from %s.%s" %(topicFromStb1, parameterDict['dbName'], parameterDict['stbName'])) + consumerId = 0 + expectrowcnt = parameterDict["rowsPerTbl"] * parameterDict["ctbNum"] + topicList = topicFromStb1 + ifcheckdata = 0 + ifManualCommit = 0 + keyList = 'group.id:cgrp1,\ + enable.auto.commit:false,\ + auto.commit.interval.ms:6000,\ + auto.offset.reset:earliest' + self.insertConsumerInfo(consumerId, expectrowcnt,topicList,keyList,ifcheckdata,ifManualCommit) + + tdLog.info("start consume processor") + pollDelay = 5 + showMsg = 1 + showRow = 1 + self.startTmqSimProcess(buildPath,cfgPath,pollDelay,parameterDict["dbName"],showMsg, showRow) + + time.sleep(2) + tdLog.info("drop som child table of stb1") + dropTblNum = 4 + tdSql.query("drop table if exists %s.%s_9"%(parameterDict["dbName"], parameterDict["stbName"])) + tdSql.query("drop table if exists %s.%s_8"%(parameterDict["dbName"], parameterDict["stbName"])) + tdSql.query("drop table if exists %s.%s_7"%(parameterDict["dbName"], parameterDict["stbName"])) + tdSql.query("drop table if exists %s.%s_3"%(parameterDict["dbName"], parameterDict["stbName"])) + + tdLog.info("drop some child tables, then start to check consume result") + expectRows = 1 + resultList = self.selectConsumeResult(expectRows) + totalConsumeRows = 0 + for i in range(expectRows): + totalConsumeRows += resultList[i] + + remaindrowcnt = parameterDict["rowsPerTbl"] * (parameterDict["ctbNum"] - dropTblNum) + + if not (totalConsumeRows < expectrowcnt and totalConsumeRows > remaindrowcnt): + tdLog.info("act consume rows: %d, expect consume rows: between %d and %d"%(totalConsumeRows, remaindrowcnt, expectrowcnt)) + tdLog.exit("tmq consume rows error!") + + tdSql.query("drop topic %s"%topicFromStb1) + + tdLog.printNoPrefix("======== test case 3 end ...... ") + + def tmqCase4(self, cfgPath, buildPath): + tdLog.printNoPrefix("======== test case 4: ") + + self.initConsumerTable() + + # create and start thread + parameterDict = {'cfg': '', \ + 'actionType': 0, \ + 'dbName': 'db4', \ + 'dropFlag': 1, \ + 'vgroups': 4, \ + 'replica': 1, \ + 'stbName': 'stb1', \ + 'ctbNum': 10, \ + 'rowsPerTbl': 10000, \ + 'batchNum': 100, \ + 'startTs': 1640966400000} # 2022-01-01 00:00:00.000 + parameterDict['cfg'] = cfgPath + + self.create_database(tdSql, parameterDict["dbName"]) + self.create_stable(tdSql, parameterDict["dbName"], parameterDict["stbName"]) + self.create_ctables(tdSql, parameterDict["dbName"], parameterDict["stbName"], parameterDict["ctbNum"]) + self.insert_data(tdSql,\ + parameterDict["dbName"],\ + parameterDict["stbName"],\ + parameterDict["ctbNum"],\ + parameterDict["rowsPerTbl"],\ + parameterDict["batchNum"]) + + tdLog.info("create topics from stb1") + topicFromStb1 = 'topic_stb1' + + tdSql.execute("create topic %s as select ts, c1, c2 from %s.%s" %(topicFromStb1, parameterDict['dbName'], parameterDict['stbName'])) + consumerId = 0 + expectrowcnt = parameterDict["rowsPerTbl"] * parameterDict["ctbNum"] + topicList = topicFromStb1 + ifcheckdata = 0 + ifManualCommit = 1 + keyList = 'group.id:cgrp1,\ + enable.auto.commit:false,\ + auto.commit.interval.ms:6000,\ + auto.offset.reset:earliest' + self.insertConsumerInfo(consumerId, expectrowcnt/4,topicList,keyList,ifcheckdata,ifManualCommit) + + tdLog.info("start consume processor") + pollDelay = 5 + showMsg = 1 + showRow = 1 + self.startTmqSimProcess(buildPath,cfgPath,pollDelay,parameterDict["dbName"],showMsg, showRow) + + tdLog.info("start to check consume result") + expectRows = 1 + resultList = self.selectConsumeResult(expectRows) + totalConsumeRows = 0 + for i in range(expectRows): + totalConsumeRows += resultList[i] + + if totalConsumeRows != expectrowcnt/4: + tdLog.info("act consume rows: %d, expect consume rows: %d"%(totalConsumeRows, expectrowcnt/4)) + tdLog.exit("tmq consume rows error!") + + self.initConsumerInfoTable() + consumerId = 1 + self.insertConsumerInfo(consumerId, expectrowcnt,topicList,keyList,ifcheckdata,ifManualCommit) + + tdLog.info("again start consume processor") + self.startTmqSimProcess(buildPath,cfgPath,pollDelay,parameterDict["dbName"],showMsg, showRow) + + tdLog.info("again check consume result") + expectRows = 2 + resultList = self.selectConsumeResult(expectRows) + totalConsumeRows = 0 + for i in range(expectRows): + totalConsumeRows += resultList[i] + + if totalConsumeRows != expectrowcnt: + tdLog.info("act consume rows: %d, expect consume rows: %d"%(totalConsumeRows, expectrowcnt)) + tdLog.exit("tmq consume rows error!") + + tdSql.query("drop topic %s"%topicFromStb1) + + tdLog.printNoPrefix("======== test case 4 end ...... ") + + def tmqCase5(self, cfgPath, buildPath): + tdLog.printNoPrefix("======== test case 5: ") + + self.initConsumerTable() + + # create and start thread + parameterDict = {'cfg': '', \ + 'actionType': 0, \ + 'dbName': 'db5', \ + 'dropFlag': 1, \ + 'vgroups': 4, \ + 'replica': 1, \ + 'stbName': 'stb1', \ + 'ctbNum': 10, \ + 'rowsPerTbl': 10000, \ + 'batchNum': 100, \ + 'startTs': 1640966400000} # 2022-01-01 00:00:00.000 + parameterDict['cfg'] = cfgPath + + self.create_database(tdSql, parameterDict["dbName"]) + self.create_stable(tdSql, parameterDict["dbName"], parameterDict["stbName"]) + self.create_ctables(tdSql, parameterDict["dbName"], parameterDict["stbName"], parameterDict["ctbNum"]) + self.insert_data(tdSql,\ + parameterDict["dbName"],\ + parameterDict["stbName"],\ + parameterDict["ctbNum"],\ + parameterDict["rowsPerTbl"],\ + parameterDict["batchNum"]) + + tdLog.info("create topics from stb1") + topicFromStb1 = 'topic_stb1' + + tdSql.execute("create topic %s as select ts, c1, c2 from %s.%s" %(topicFromStb1, parameterDict['dbName'], parameterDict['stbName'])) + consumerId = 0 + expectrowcnt = parameterDict["rowsPerTbl"] * parameterDict["ctbNum"] + topicList = topicFromStb1 + ifcheckdata = 0 + ifManualCommit = 0 + keyList = 'group.id:cgrp1,\ + enable.auto.commit:false,\ + auto.commit.interval.ms:6000,\ + auto.offset.reset:earliest' + self.insertConsumerInfo(consumerId, expectrowcnt/4,topicList,keyList,ifcheckdata,ifManualCommit) + + tdLog.info("start consume processor") + pollDelay = 5 + showMsg = 1 + showRow = 1 + self.startTmqSimProcess(buildPath,cfgPath,pollDelay,parameterDict["dbName"],showMsg, showRow) + + tdLog.info("start to check consume result") + expectRows = 1 + resultList = self.selectConsumeResult(expectRows) + totalConsumeRows = 0 + for i in range(expectRows): + totalConsumeRows += resultList[i] + + if totalConsumeRows != expectrowcnt/4: + tdLog.info("act consume rows: %d, expect consume rows: %d"%(totalConsumeRows, expectrowcnt/4)) + tdLog.exit("tmq consume rows error!") + + self.initConsumerInfoTable() + consumerId = 1 + self.insertConsumerInfo(consumerId, expectrowcnt,topicList,keyList,ifcheckdata,ifManualCommit) + + tdLog.info("again start consume processor") + self.startTmqSimProcess(buildPath,cfgPath,pollDelay,parameterDict["dbName"],showMsg, showRow) + + tdLog.info("again check consume result") + expectRows = 2 + resultList = self.selectConsumeResult(expectRows) + totalConsumeRows = 0 + for i in range(expectRows): + totalConsumeRows += resultList[i] + + if totalConsumeRows != (expectrowcnt * (1 + 1/4)): + tdLog.info("act consume rows: %d, expect consume rows: %d"%(totalConsumeRows, expectrowcnt)) + tdLog.exit("tmq consume rows error!") + + tdSql.query("drop topic %s"%topicFromStb1) + + tdLog.printNoPrefix("======== test case 5 end ...... ") + + def tmqCase6(self, cfgPath, buildPath): + tdLog.printNoPrefix("======== test case 6: ") + + self.initConsumerTable() + + # create and start thread + parameterDict = {'cfg': '', \ + 'actionType': 0, \ + 'dbName': 'db6', \ + 'dropFlag': 1, \ + 'vgroups': 4, \ + 'replica': 1, \ + 'stbName': 'stb1', \ + 'ctbNum': 10, \ + 'rowsPerTbl': 10000, \ + 'batchNum': 100, \ + 'startTs': 1640966400000} # 2022-01-01 00:00:00.000 + parameterDict['cfg'] = cfgPath + + self.create_database(tdSql, parameterDict["dbName"]) + self.create_stable(tdSql, parameterDict["dbName"], parameterDict["stbName"]) + self.create_ctables(tdSql, parameterDict["dbName"], parameterDict["stbName"], parameterDict["ctbNum"]) + self.insert_data(tdSql,\ + parameterDict["dbName"],\ + parameterDict["stbName"],\ + parameterDict["ctbNum"],\ + parameterDict["rowsPerTbl"],\ + parameterDict["batchNum"]) + + tdLog.info("create topics from stb1") + topicFromStb1 = 'topic_stb1' + + tdSql.execute("create topic %s as select ts, c1, c2 from %s.%s" %(topicFromStb1, parameterDict['dbName'], parameterDict['stbName'])) + consumerId = 0 + expectrowcnt = parameterDict["rowsPerTbl"] * parameterDict["ctbNum"] + topicList = topicFromStb1 + ifcheckdata = 0 + ifManualCommit = 1 + keyList = 'group.id:cgrp1,\ + enable.auto.commit:false,\ + auto.commit.interval.ms:6000,\ + auto.offset.reset:earliest' + self.insertConsumerInfo(consumerId, expectrowcnt/4,topicList,keyList,ifcheckdata,ifManualCommit) + + tdLog.info("start consume processor") + pollDelay = 5 + showMsg = 1 + showRow = 1 + self.startTmqSimProcess(buildPath,cfgPath,pollDelay,parameterDict["dbName"],showMsg, showRow) + + tdLog.info("start to check consume result") + expectRows = 1 + resultList = self.selectConsumeResult(expectRows) + totalConsumeRows = 0 + for i in range(expectRows): + totalConsumeRows += resultList[i] + + if totalConsumeRows != expectrowcnt/4: + tdLog.info("act consume rows: %d, expect consume rows: %d"%(totalConsumeRows, expectrowcnt/4)) + tdLog.exit("tmq consume rows error!") + + self.initConsumerInfoTable() + consumerId = 1 + keyList = 'group.id:cgrp1,\ + enable.auto.commit:false,\ + auto.commit.interval.ms:6000,\ + auto.offset.reset:latest' + self.insertConsumerInfo(consumerId, expectrowcnt,topicList,keyList,ifcheckdata,ifManualCommit) + + tdLog.info("again start consume processor") + self.startTmqSimProcess(buildPath,cfgPath,pollDelay,parameterDict["dbName"],showMsg, showRow) + + tdLog.info("again check consume result") + expectRows = 2 + resultList = self.selectConsumeResult(expectRows) + totalConsumeRows = 0 + for i in range(expectRows): + totalConsumeRows += resultList[i] + + if totalConsumeRows != expectrowcnt: + tdLog.info("act consume rows: %d, expect consume rows: %d"%(totalConsumeRows, expectrowcnt)) + tdLog.exit("tmq consume rows error!") + + tdSql.query("drop topic %s"%topicFromStb1) + + tdLog.printNoPrefix("======== test case 6 end ...... ") + + def tmqCase7(self, cfgPath, buildPath): + tdLog.printNoPrefix("======== test case 7: ") + + self.initConsumerTable() + + # create and start thread + parameterDict = {'cfg': '', \ + 'actionType': 0, \ + 'dbName': 'db7', \ + 'dropFlag': 1, \ + 'vgroups': 4, \ + 'replica': 1, \ + 'stbName': 'stb1', \ + 'ctbNum': 10, \ + 'rowsPerTbl': 10000, \ + 'batchNum': 100, \ + 'startTs': 1640966400000} # 2022-01-01 00:00:00.000 + parameterDict['cfg'] = cfgPath + + self.create_database(tdSql, parameterDict["dbName"]) + self.create_stable(tdSql, parameterDict["dbName"], parameterDict["stbName"]) + self.create_ctables(tdSql, parameterDict["dbName"], parameterDict["stbName"], parameterDict["ctbNum"]) + self.insert_data(tdSql,\ + parameterDict["dbName"],\ + parameterDict["stbName"],\ + parameterDict["ctbNum"],\ + parameterDict["rowsPerTbl"],\ + parameterDict["batchNum"]) + + tdLog.info("create topics from stb1") + topicFromStb1 = 'topic_stb1' + + tdSql.execute("create topic %s as select ts, c1, c2 from %s.%s" %(topicFromStb1, parameterDict['dbName'], parameterDict['stbName'])) + consumerId = 0 + expectrowcnt = parameterDict["rowsPerTbl"] * parameterDict["ctbNum"] + topicList = topicFromStb1 + ifcheckdata = 0 + ifManualCommit = 1 + keyList = 'group.id:cgrp1,\ + enable.auto.commit:false,\ + auto.commit.interval.ms:6000,\ + auto.offset.reset:latest' + self.insertConsumerInfo(consumerId, expectrowcnt,topicList,keyList,ifcheckdata,ifManualCommit) + + tdLog.info("start consume processor") + pollDelay = 5 + showMsg = 1 + showRow = 1 + self.startTmqSimProcess(buildPath,cfgPath,pollDelay,parameterDict["dbName"],showMsg, showRow) + + tdLog.info("start to check consume result") + expectRows = 1 + resultList = self.selectConsumeResult(expectRows) + totalConsumeRows = 0 + for i in range(expectRows): + totalConsumeRows += resultList[i] + + if totalConsumeRows != 0: + tdLog.info("act consume rows: %d, expect consume rows: %d"%(totalConsumeRows, 0)) + tdLog.exit("tmq consume rows error!") + + self.initConsumerInfoTable() + consumerId = 1 + self.insertConsumerInfo(consumerId, expectrowcnt,topicList,keyList,ifcheckdata,ifManualCommit) + + tdLog.info("again start consume processor") + self.startTmqSimProcess(buildPath,cfgPath,pollDelay,parameterDict["dbName"],showMsg, showRow) + + tdLog.info("again check consume result") + expectRows = 2 + resultList = self.selectConsumeResult(expectRows) + totalConsumeRows = 0 + for i in range(expectRows): + totalConsumeRows += resultList[i] + + if totalConsumeRows != 0: + tdLog.info("act consume rows: %d, expect consume rows: %d"%(totalConsumeRows, 0)) + tdLog.exit("tmq consume rows error!") + + tdSql.query("drop topic %s"%topicFromStb1) + + tdLog.printNoPrefix("======== test case 7 end ...... ") + + def tmqCase8(self, cfgPath, buildPath): + tdLog.printNoPrefix("======== test case 8: ") + + self.initConsumerTable() + + # create and start thread + parameterDict = {'cfg': '', \ + 'actionType': 0, \ + 'dbName': 'db8', \ + 'dropFlag': 1, \ + 'vgroups': 4, \ + 'replica': 1, \ + 'stbName': 'stb1', \ + 'ctbNum': 10, \ + 'rowsPerTbl': 10000, \ + 'batchNum': 100, \ + 'startTs': 1640966400000} # 2022-01-01 00:00:00.000 + parameterDict['cfg'] = cfgPath + + self.create_database(tdSql, parameterDict["dbName"]) + self.create_stable(tdSql, parameterDict["dbName"], parameterDict["stbName"]) + self.create_ctables(tdSql, parameterDict["dbName"], parameterDict["stbName"], parameterDict["ctbNum"]) + self.insert_data(tdSql,\ + parameterDict["dbName"],\ + parameterDict["stbName"],\ + parameterDict["ctbNum"],\ + parameterDict["rowsPerTbl"],\ + parameterDict["batchNum"]) + + tdLog.info("create topics from stb1") + topicFromStb1 = 'topic_stb1' + + tdSql.execute("create topic %s as select ts, c1, c2 from %s.%s" %(topicFromStb1, parameterDict['dbName'], parameterDict['stbName'])) + consumerId = 0 + expectrowcnt = parameterDict["rowsPerTbl"] * parameterDict["ctbNum"] + topicList = topicFromStb1 + ifcheckdata = 0 + ifManualCommit = 1 + keyList = 'group.id:cgrp1,\ + enable.auto.commit:false,\ + auto.commit.interval.ms:6000,\ + auto.offset.reset:latest' + self.insertConsumerInfo(consumerId, expectrowcnt,topicList,keyList,ifcheckdata,ifManualCommit) + + tdLog.info("start consume 0 processor") + pollDelay = 10 + showMsg = 1 + showRow = 1 + self.startTmqSimProcess(buildPath,cfgPath,pollDelay,parameterDict["dbName"],showMsg, showRow) + + tdLog.info("start to check consume 0 result") + expectRows = 1 + resultList = self.selectConsumeResult(expectRows) + totalConsumeRows = 0 + for i in range(expectRows): + totalConsumeRows += resultList[i] + + if totalConsumeRows != 0: + tdLog.info("act consume rows: %d, expect consume rows: %d"%(totalConsumeRows, 0)) + tdLog.exit("tmq consume rows error!") + + tdLog.info("start consume 1 processor") + self.startTmqSimProcess(buildPath,cfgPath,pollDelay,parameterDict["dbName"],showMsg, showRow) + + tdLog.info("start one new thread to insert data") + parameterDict['actionType'] = actionType.INSERT_DATA + prepareEnvThread = threading.Thread(target=self.prepareEnv, kwargs=parameterDict) + prepareEnvThread.start() + prepareEnvThread.join() + + tdLog.info("start to check consume 0 and 1 result") + expectRows = 2 + resultList = self.selectConsumeResult(expectRows) + totalConsumeRows = 0 + for i in range(expectRows): + totalConsumeRows += resultList[i] + + if totalConsumeRows != expectrowcnt: + tdLog.info("act consume rows: %d, expect consume rows: %d"%(totalConsumeRows, expectrowcnt)) + tdLog.exit("tmq consume rows error!") + + tdLog.info("start consume 2 processor") + self.startTmqSimProcess(buildPath,cfgPath,pollDelay,parameterDict["dbName"],showMsg, showRow) + + tdLog.info("start one new thread to insert data") + parameterDict['actionType'] = actionType.INSERT_DATA + prepareEnvThread = threading.Thread(target=self.prepareEnv, kwargs=parameterDict) + prepareEnvThread.start() + prepareEnvThread.join() + + tdLog.info("start to check consume 0 and 1 and 2 result") + expectRows = 3 + resultList = self.selectConsumeResult(expectRows) + totalConsumeRows = 0 + for i in range(expectRows): + totalConsumeRows += resultList[i] + + if totalConsumeRows != expectrowcnt*2: + tdLog.info("act consume rows: %d, expect consume rows: %d"%(totalConsumeRows, expectrowcnt*2)) + tdLog.exit("tmq consume rows error!") + + tdSql.query("drop topic %s"%topicFromStb1) + + tdLog.printNoPrefix("======== test case 8 end ...... ") + + def tmqCase9(self, cfgPath, buildPath): + tdLog.printNoPrefix("======== test case 9: ") + + self.initConsumerTable() + + # create and start thread + parameterDict = {'cfg': '', \ + 'actionType': 0, \ + 'dbName': 'db9', \ + 'dropFlag': 1, \ + 'vgroups': 4, \ + 'replica': 1, \ + 'stbName': 'stb1', \ + 'ctbNum': 10, \ + 'rowsPerTbl': 10000, \ + 'batchNum': 100, \ + 'startTs': 1640966400000} # 2022-01-01 00:00:00.000 + parameterDict['cfg'] = cfgPath + + self.create_database(tdSql, parameterDict["dbName"]) + self.create_stable(tdSql, parameterDict["dbName"], parameterDict["stbName"]) + self.create_ctables(tdSql, parameterDict["dbName"], parameterDict["stbName"], parameterDict["ctbNum"]) + self.insert_data(tdSql,\ + parameterDict["dbName"],\ + parameterDict["stbName"],\ + parameterDict["ctbNum"],\ + parameterDict["rowsPerTbl"],\ + parameterDict["batchNum"]) + + tdLog.info("create topics from stb1") + topicFromStb1 = 'topic_stb1' + + tdSql.execute("create topic %s as select ts, c1, c2 from %s.%s" %(topicFromStb1, parameterDict['dbName'], parameterDict['stbName'])) + consumerId = 0 + expectrowcnt = parameterDict["rowsPerTbl"] * parameterDict["ctbNum"] + topicList = topicFromStb1 + ifcheckdata = 0 + ifManualCommit = 1 + keyList = 'group.id:cgrp1,\ + enable.auto.commit:false,\ + auto.commit.interval.ms:6000,\ + auto.offset.reset:latest' + self.insertConsumerInfo(consumerId, expectrowcnt,topicList,keyList,ifcheckdata,ifManualCommit) + + tdLog.info("start consume 0 processor") + pollDelay = 10 + showMsg = 1 + showRow = 1 + self.startTmqSimProcess(buildPath,cfgPath,pollDelay,parameterDict["dbName"],showMsg, showRow) + + tdLog.info("start to check consume 0 result") + expectRows = 1 + resultList = self.selectConsumeResult(expectRows) + totalConsumeRows = 0 + for i in range(expectRows): + totalConsumeRows += resultList[i] + + if totalConsumeRows != 0: + tdLog.info("act consume rows: %d, expect consume rows: %d"%(totalConsumeRows, 0)) + tdLog.exit("tmq consume rows error!") + + tdLog.info("start consume 1 processor") + self.initConsumerInfoTable() + consumerId = 1 + ifManualCommit = 0 + self.insertConsumerInfo(consumerId, expectrowcnt,topicList,keyList,ifcheckdata,ifManualCommit) + self.startTmqSimProcess(buildPath,cfgPath,pollDelay,parameterDict["dbName"],showMsg, showRow) + + tdLog.info("start one new thread to insert data") + parameterDict['actionType'] = actionType.INSERT_DATA + prepareEnvThread = threading.Thread(target=self.prepareEnv, kwargs=parameterDict) + prepareEnvThread.start() + prepareEnvThread.join() + + tdLog.info("start to check consume 0 and 1 result") + expectRows = 2 + resultList = self.selectConsumeResult(expectRows) + totalConsumeRows = 0 + for i in range(expectRows): + totalConsumeRows += resultList[i] + + if totalConsumeRows != expectrowcnt: + tdLog.info("act consume rows: %d, expect consume rows: %d"%(totalConsumeRows, expectrowcnt)) + tdLog.exit("tmq consume rows error!") + + tdLog.info("start consume 2 processor") + self.startTmqSimProcess(buildPath,cfgPath,pollDelay,parameterDict["dbName"],showMsg, showRow) + + tdLog.info("start one new thread to insert data") + parameterDict['actionType'] = actionType.INSERT_DATA + prepareEnvThread = threading.Thread(target=self.prepareEnv, kwargs=parameterDict) + prepareEnvThread.start() + prepareEnvThread.join() + + tdLog.info("start to check consume 0 and 1 and 2 result") + expectRows = 3 + resultList = self.selectConsumeResult(expectRows) + totalConsumeRows = 0 + for i in range(expectRows): + totalConsumeRows += resultList[i] + + if totalConsumeRows != expectrowcnt*2: + tdLog.info("act consume rows: %d, expect consume rows: %d"%(totalConsumeRows, expectrowcnt*2)) + tdLog.exit("tmq consume rows error!") + + tdSql.query("drop topic %s"%topicFromStb1) + + tdLog.printNoPrefix("======== test case 9 end ...... ") + + def tmqCase10(self, cfgPath, buildPath): + tdLog.printNoPrefix("======== test case 10: ") + + self.initConsumerTable() + + # create and start thread + parameterDict = {'cfg': '', \ + 'actionType': 0, \ + 'dbName': 'db10', \ + 'dropFlag': 1, \ + 'vgroups': 4, \ + 'replica': 1, \ + 'stbName': 'stb1', \ + 'ctbNum': 10, \ + 'rowsPerTbl': 10000, \ + 'batchNum': 100, \ + 'startTs': 1640966400000} # 2022-01-01 00:00:00.000 + parameterDict['cfg'] = cfgPath + + self.create_database(tdSql, parameterDict["dbName"]) + self.create_stable(tdSql, parameterDict["dbName"], parameterDict["stbName"]) + self.create_ctables(tdSql, parameterDict["dbName"], parameterDict["stbName"], parameterDict["ctbNum"]) + self.insert_data(tdSql,\ + parameterDict["dbName"],\ + parameterDict["stbName"],\ + parameterDict["ctbNum"],\ + parameterDict["rowsPerTbl"],\ + parameterDict["batchNum"]) + + tdLog.info("create topics from stb1") + topicFromStb1 = 'topic_stb1' + + tdSql.execute("create topic %s as select ts, c1, c2 from %s.%s" %(topicFromStb1, parameterDict['dbName'], parameterDict['stbName'])) + consumerId = 0 + expectrowcnt = parameterDict["rowsPerTbl"] * parameterDict["ctbNum"] + topicList = topicFromStb1 + ifcheckdata = 0 + ifManualCommit = 1 + keyList = 'group.id:cgrp1,\ + enable.auto.commit:false,\ + auto.commit.interval.ms:6000,\ + auto.offset.reset:latest' + self.insertConsumerInfo(consumerId, expectrowcnt,topicList,keyList,ifcheckdata,ifManualCommit) + + tdLog.info("start consume 0 processor") + pollDelay = 10 + showMsg = 1 + showRow = 1 + self.startTmqSimProcess(buildPath,cfgPath,pollDelay,parameterDict["dbName"],showMsg, showRow) + + tdLog.info("start to check consume 0 result") + expectRows = 1 + resultList = self.selectConsumeResult(expectRows) + totalConsumeRows = 0 + for i in range(expectRows): + totalConsumeRows += resultList[i] + + if totalConsumeRows != 0: + tdLog.info("act consume rows: %d, expect consume rows: %d"%(totalConsumeRows, 0)) + tdLog.exit("tmq consume rows error!") + + tdLog.info("start consume 1 processor") + self.initConsumerInfoTable() + consumerId = 1 + ifManualCommit = 1 + self.insertConsumerInfo(consumerId, expectrowcnt-10000,topicList,keyList,ifcheckdata,ifManualCommit) + self.startTmqSimProcess(buildPath,cfgPath,pollDelay,parameterDict["dbName"],showMsg, showRow) + + tdLog.info("start one new thread to insert data") + parameterDict['actionType'] = actionType.INSERT_DATA + prepareEnvThread = threading.Thread(target=self.prepareEnv, kwargs=parameterDict) + prepareEnvThread.start() + prepareEnvThread.join() + + tdLog.info("start to check consume 0 and 1 result") + expectRows = 2 + resultList = self.selectConsumeResult(expectRows) + totalConsumeRows = 0 + for i in range(expectRows): + totalConsumeRows += resultList[i] + + if totalConsumeRows != expectrowcnt-10000: + tdLog.info("act consume rows: %d, expect consume rows: %d"%(totalConsumeRows, expectrowcnt-10000)) + tdLog.exit("tmq consume rows error!") + + tdLog.info("start consume 2 processor") + self.initConsumerInfoTable() + consumerId = 2 + ifManualCommit = 1 + self.insertConsumerInfo(consumerId, expectrowcnt+10000,topicList,keyList,ifcheckdata,ifManualCommit) + self.startTmqSimProcess(buildPath,cfgPath,pollDelay,parameterDict["dbName"],showMsg, showRow) + + tdLog.info("start one new thread to insert data") + parameterDict['actionType'] = actionType.INSERT_DATA + prepareEnvThread = threading.Thread(target=self.prepareEnv, kwargs=parameterDict) + prepareEnvThread.start() + prepareEnvThread.join() + + tdLog.info("start to check consume 0 and 1 and 2 result") + expectRows = 3 + resultList = self.selectConsumeResult(expectRows) + totalConsumeRows = 0 + for i in range(expectRows): + totalConsumeRows += resultList[i] + + if totalConsumeRows != expectrowcnt*2: + tdLog.info("act consume rows: %d, expect consume rows: %d"%(totalConsumeRows, expectrowcnt*2)) + tdLog.exit("tmq consume rows error!") + + tdSql.query("drop topic %s"%topicFromStb1) + + tdLog.printNoPrefix("======== test case 10 end ...... ") + + def tmqCase11(self, cfgPath, buildPath): + tdLog.printNoPrefix("======== test case 11: ") + + self.initConsumerTable() + + # create and start thread + parameterDict = {'cfg': '', \ + 'actionType': 0, \ + 'dbName': 'db11', \ + 'dropFlag': 1, \ + 'vgroups': 4, \ + 'replica': 1, \ + 'stbName': 'stb1', \ + 'ctbNum': 10, \ + 'rowsPerTbl': 10000, \ + 'batchNum': 100, \ + 'startTs': 1640966400000} # 2022-01-01 00:00:00.000 + parameterDict['cfg'] = cfgPath + + self.create_database(tdSql, parameterDict["dbName"]) + self.create_stable(tdSql, parameterDict["dbName"], parameterDict["stbName"]) + self.create_ctables(tdSql, parameterDict["dbName"], parameterDict["stbName"], parameterDict["ctbNum"]) + self.insert_data(tdSql,\ + parameterDict["dbName"],\ + parameterDict["stbName"],\ + parameterDict["ctbNum"],\ + parameterDict["rowsPerTbl"],\ + parameterDict["batchNum"]) + + tdLog.info("create topics from stb1") + topicFromStb1 = 'topic_stb1' + + tdSql.execute("create topic %s as select ts, c1, c2 from %s.%s" %(topicFromStb1, parameterDict['dbName'], parameterDict['stbName'])) + consumerId = 0 + expectrowcnt = parameterDict["rowsPerTbl"] * parameterDict["ctbNum"] + topicList = topicFromStb1 + ifcheckdata = 0 + ifManualCommit = 1 + keyList = 'group.id:cgrp1,\ + enable.auto.commit:false,\ + auto.commit.interval.ms:6000,\ + auto.offset.reset:none' + self.insertConsumerInfo(consumerId, expectrowcnt/4,topicList,keyList,ifcheckdata,ifManualCommit) + + tdLog.info("start consume processor") + pollDelay = 5 + showMsg = 1 + showRow = 1 + self.startTmqSimProcess(buildPath,cfgPath,pollDelay,parameterDict["dbName"],showMsg, showRow) + + tdLog.info("start to check consume result") + expectRows = 1 + resultList = self.selectConsumeResult(expectRows) + totalConsumeRows = 0 + for i in range(expectRows): + totalConsumeRows += resultList[i] + + if totalConsumeRows != 0: + tdLog.info("act consume rows: %d, expect consume rows: %d"%(totalConsumeRows, 0)) + tdLog.exit("tmq consume rows error!") + + self.initConsumerInfoTable() + consumerId = 1 + keyList = 'group.id:cgrp1,\ + enable.auto.commit:false,\ + auto.commit.interval.ms:6000,\ + auto.offset.reset:none' + self.insertConsumerInfo(consumerId, expectrowcnt,topicList,keyList,ifcheckdata,ifManualCommit) + + tdLog.info("again start consume processor") + self.startTmqSimProcess(buildPath,cfgPath,pollDelay,parameterDict["dbName"],showMsg, showRow) + + tdLog.info("again check consume result") + expectRows = 2 + resultList = self.selectConsumeResult(expectRows) + totalConsumeRows = 0 + for i in range(expectRows): + totalConsumeRows += resultList[i] + + if totalConsumeRows != 0: + tdLog.info("act consume rows: %d, expect consume rows: %d"%(totalConsumeRows, 0)) + tdLog.exit("tmq consume rows error!") + + tdSql.query("drop topic %s"%topicFromStb1) + + tdLog.printNoPrefix("======== test case 11 end ...... ") + + def tmqCase12(self, cfgPath, buildPath): + tdLog.printNoPrefix("======== test case 12: ") + + self.initConsumerTable() + + # create and start thread + parameterDict = {'cfg': '', \ + 'actionType': 0, \ + 'dbName': 'db12', \ + 'dropFlag': 1, \ + 'vgroups': 4, \ + 'replica': 1, \ + 'stbName': 'stb1', \ + 'ctbNum': 10, \ + 'rowsPerTbl': 10000, \ + 'batchNum': 100, \ + 'startTs': 1640966400000} # 2022-01-01 00:00:00.000 + parameterDict['cfg'] = cfgPath + + self.create_database(tdSql, parameterDict["dbName"]) + self.create_stable(tdSql, parameterDict["dbName"], parameterDict["stbName"]) + self.create_ctables(tdSql, parameterDict["dbName"], parameterDict["stbName"], parameterDict["ctbNum"]) + self.insert_data(tdSql,\ + parameterDict["dbName"],\ + parameterDict["stbName"],\ + parameterDict["ctbNum"],\ + parameterDict["rowsPerTbl"],\ + parameterDict["batchNum"]) + + tdLog.info("create topics from stb1") + topicFromStb1 = 'topic_stb1' + + tdSql.execute("create topic %s as select ts, c1, c2 from %s.%s" %(topicFromStb1, parameterDict['dbName'], parameterDict['stbName'])) + consumerId = 0 + expectrowcnt = parameterDict["rowsPerTbl"] * parameterDict["ctbNum"] + topicList = topicFromStb1 + ifcheckdata = 0 + ifManualCommit = 0 + keyList = 'group.id:cgrp1,\ + enable.auto.commit:false,\ + auto.commit.interval.ms:6000,\ + auto.offset.reset:earliest' + self.insertConsumerInfo(consumerId, expectrowcnt/4,topicList,keyList,ifcheckdata,ifManualCommit) + + tdLog.info("start consume processor") + pollDelay = 5 + showMsg = 1 + showRow = 1 + self.startTmqSimProcess(buildPath,cfgPath,pollDelay,parameterDict["dbName"],showMsg, showRow) + + tdLog.info("start to check consume result") + expectRows = 1 + resultList = self.selectConsumeResult(expectRows) + totalConsumeRows = 0 + for i in range(expectRows): + totalConsumeRows += resultList[i] + + if totalConsumeRows != expectrowcnt/4: + tdLog.info("act consume rows: %d, expect consume rows: %d"%(totalConsumeRows, expectrowcnt/4)) + tdLog.exit("tmq consume rows error!") + + self.initConsumerInfoTable() + consumerId = 1 + keyList = 'group.id:cgrp1,\ + enable.auto.commit:false,\ + auto.commit.interval.ms:6000,\ + auto.offset.reset:none' + self.insertConsumerInfo(consumerId, expectrowcnt,topicList,keyList,ifcheckdata,ifManualCommit) + + tdLog.info("again start consume processor") + self.startTmqSimProcess(buildPath,cfgPath,pollDelay,parameterDict["dbName"],showMsg, showRow) + + tdLog.info("again check consume result") + expectRows = 2 + resultList = self.selectConsumeResult(expectRows) + totalConsumeRows = 0 + for i in range(expectRows): + totalConsumeRows += resultList[i] + + if totalConsumeRows != expectrowcnt/4: + tdLog.info("act consume rows: %d, expect consume rows: %d"%(totalConsumeRows, expectrowcnt/4)) + tdLog.exit("tmq consume rows error!") + + tdSql.query("drop topic %s"%topicFromStb1) + + tdLog.printNoPrefix("======== test case 12 end ...... ") + + def tmqCase13(self, cfgPath, buildPath): + tdLog.printNoPrefix("======== test case 13: ") + + self.initConsumerTable() + + # create and start thread + parameterDict = {'cfg': '', \ + 'actionType': 0, \ + 'dbName': 'db13', \ + 'dropFlag': 1, \ + 'vgroups': 4, \ + 'replica': 1, \ + 'stbName': 'stb1', \ + 'ctbNum': 10, \ + 'rowsPerTbl': 10000, \ + 'batchNum': 100, \ + 'startTs': 1640966400000} # 2022-01-01 00:00:00.000 + parameterDict['cfg'] = cfgPath + + self.create_database(tdSql, parameterDict["dbName"]) + self.create_stable(tdSql, parameterDict["dbName"], parameterDict["stbName"]) + self.create_ctables(tdSql, parameterDict["dbName"], parameterDict["stbName"], parameterDict["ctbNum"]) + self.insert_data(tdSql,\ + parameterDict["dbName"],\ + parameterDict["stbName"],\ + parameterDict["ctbNum"],\ + parameterDict["rowsPerTbl"],\ + parameterDict["batchNum"]) + + tdLog.info("create topics from stb1") + topicFromStb1 = 'topic_stb1' + + tdSql.execute("create topic %s as select ts, c1, c2 from %s.%s" %(topicFromStb1, parameterDict['dbName'], parameterDict['stbName'])) + consumerId = 0 + expectrowcnt = parameterDict["rowsPerTbl"] * parameterDict["ctbNum"] + topicList = topicFromStb1 + ifcheckdata = 0 + ifManualCommit = 1 + keyList = 'group.id:cgrp1,\ + enable.auto.commit:false,\ + auto.commit.interval.ms:6000,\ + auto.offset.reset:earliest' + self.insertConsumerInfo(consumerId, expectrowcnt/4,topicList,keyList,ifcheckdata,ifManualCommit) + + tdLog.info("start consume processor") + pollDelay = 5 + showMsg = 1 + showRow = 1 + self.startTmqSimProcess(buildPath,cfgPath,pollDelay,parameterDict["dbName"],showMsg, showRow) + + tdLog.info("start to check consume result") + expectRows = 1 + resultList = self.selectConsumeResult(expectRows) + totalConsumeRows = 0 + for i in range(expectRows): + totalConsumeRows += resultList[i] + + if totalConsumeRows != expectrowcnt/4: + tdLog.info("act consume rows: %d, expect consume rows: %d"%(totalConsumeRows, expectrowcnt/4)) + tdLog.exit("tmq consume rows error!") + + self.initConsumerInfoTable() + consumerId = 1 + ifManualCommit = 1 + keyList = 'group.id:cgrp1,\ + enable.auto.commit:false,\ + auto.commit.interval.ms:6000,\ + auto.offset.reset:none' + self.insertConsumerInfo(consumerId, expectrowcnt/2,topicList,keyList,ifcheckdata,ifManualCommit) + + tdLog.info("again start consume processor") + self.startTmqSimProcess(buildPath,cfgPath,pollDelay,parameterDict["dbName"],showMsg, showRow) + + tdLog.info("again check consume result") + expectRows = 2 + resultList = self.selectConsumeResult(expectRows) + totalConsumeRows = 0 + for i in range(expectRows): + totalConsumeRows += resultList[i] + + if totalConsumeRows != expectrowcnt*(1/2+1/4): + tdLog.info("act consume rows: %d, expect consume rows: %d"%(totalConsumeRows, expectrowcnt*(1/2+1/4))) + tdLog.exit("tmq consume rows error!") + + self.initConsumerInfoTable() + consumerId = 2 + ifManualCommit = 1 + keyList = 'group.id:cgrp1,\ + enable.auto.commit:false,\ + auto.commit.interval.ms:6000,\ + auto.offset.reset:none' + self.insertConsumerInfo(consumerId, expectrowcnt,topicList,keyList,ifcheckdata,ifManualCommit) + + tdLog.info("again start consume processor") + self.startTmqSimProcess(buildPath,cfgPath,pollDelay,parameterDict["dbName"],showMsg, showRow) + + tdLog.info("again check consume result") + expectRows = 3 + resultList = self.selectConsumeResult(expectRows) + totalConsumeRows = 0 + for i in range(expectRows): + totalConsumeRows += resultList[i] + + if totalConsumeRows != expectrowcnt: + tdLog.info("act consume rows: %d, expect consume rows: %d"%(totalConsumeRows, expectrowcnt)) + tdLog.exit("tmq consume rows error!") + + tdSql.query("drop topic %s"%topicFromStb1) + + tdLog.printNoPrefix("======== test case 13 end ...... ") + + def run(self): + tdSql.prepare() + + buildPath = self.getBuildPath() + if (buildPath == ""): + tdLog.exit("taosd not found!") + else: + tdLog.info("taosd found in %s" % buildPath) + cfgPath = buildPath + "/../sim/psim/cfg" + tdLog.info("cfgPath: %s" % cfgPath) + + #self.tmqCase1(cfgPath, buildPath) + #self.tmqCase2(cfgPath, buildPath) + #self.tmqCase3(cfgPath, buildPath) + #self.tmqCase4(cfgPath, buildPath) + #self.tmqCase5(cfgPath, buildPath) + self.tmqCase6(cfgPath, buildPath) + self.tmqCase7(cfgPath, buildPath) + self.tmqCase8(cfgPath, buildPath) + self.tmqCase9(cfgPath, buildPath) + self.tmqCase10(cfgPath, buildPath) + self.tmqCase11(cfgPath, buildPath) + self.tmqCase12(cfgPath, buildPath) + self.tmqCase13(cfgPath, buildPath) + + def stop(self): + tdSql.close() + tdLog.success(f"{__file__} successfully executed") + +event = threading.Event() + +tdCases.addLinux(__file__, TDTestCase()) +tdCases.addWindows(__file__, TDTestCase()) diff --git a/tests/system-test/fulltest.sh b/tests/system-test/fulltest.sh index 06be29a636..561114a284 100755 --- a/tests/system-test/fulltest.sh +++ b/tests/system-test/fulltest.sh @@ -65,3 +65,4 @@ python3 ./test.py -f 7-tmq/basic5.py python3 ./test.py -f 7-tmq/subscribeDb.py python3 ./test.py -f 7-tmq/subscribeDb1.py python3 ./test.py -f 7-tmq/subscribeStb.py +python3 ./test.py -f 7-tmq/subscribeStb1.py From 5dc9e27a363316cd7eed0d626dd9d5d1da518c1d Mon Sep 17 00:00:00 2001 From: gccgdb1234 Date: Sat, 21 May 2022 13:18:35 +0800 Subject: [PATCH 11/13] docs: add missing files in docs-examples --- docs-examples/go/insert/sql/main.go | 49 +++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 docs-examples/go/insert/sql/main.go diff --git a/docs-examples/go/insert/sql/main.go b/docs-examples/go/insert/sql/main.go new file mode 100644 index 0000000000..9138685533 --- /dev/null +++ b/docs-examples/go/insert/sql/main.go @@ -0,0 +1,49 @@ +package main + +import ( + "database/sql" + "fmt" + + _ "github.com/taosdata/driver-go/v2/taosRestful" +) + +func createStable(taos *sql.DB) { + _, err := taos.Exec("CREATE DATABASE power") + if err != nil { + fmt.Println("failed to create database, err:", err) + } + _, err = taos.Exec("CREATE STABLE power.meters (ts TIMESTAMP, current FLOAT, voltage INT, phase FLOAT) TAGS (location BINARY(64), groupId INT)") + if err != nil { + fmt.Println("failed to create stable, err:", err) + } +} + +func insertData(taos *sql.DB) { + sql := `INSERT INTO power.d1001 USING power.meters TAGS(Beijing.Chaoyang, 2) VALUES ('2018-10-03 14:38:05.000', 10.30000, 219, 0.31000) ('2018-10-03 14:38:15.000', 12.60000, 218, 0.33000) ('2018-10-03 14:38:16.800', 12.30000, 221, 0.31000) + power.d1002 USING power.meters TAGS(Beijing.Chaoyang, 3) VALUES ('2018-10-03 14:38:16.650', 10.30000, 218, 0.25000) + power.d1003 USING power.meters TAGS(Beijing.Haidian, 2) VALUES ('2018-10-03 14:38:05.500', 11.80000, 221, 0.28000) ('2018-10-03 14:38:16.600', 13.40000, 223, 0.29000) + power.d1004 USING power.meters TAGS(Beijing.Haidian, 3) VALUES ('2018-10-03 14:38:05.000', 10.80000, 223, 0.29000) ('2018-10-03 14:38:06.500', 11.50000, 221, 0.35000)` + result, err := taos.Exec(sql) + if err != nil { + fmt.Println("failed to insert, err:", err) + return + } + rowsAffected, err := result.RowsAffected() + if err != nil { + fmt.Println("failed to get affected rows, err:", err) + return + } + fmt.Println("RowsAffected", rowsAffected) +} + +func main() { + var taosDSN = "root:taosdata@http(localhost:6041)/" + taos, err := sql.Open("taosRestful", taosDSN) + if err != nil { + fmt.Println("failed to connect TDengine, err:", err) + return + } + defer taos.Close() + createStable(taos) + insertData(taos) +} From c96036a7c42723b6d675a1c336f7b50821037d3f Mon Sep 17 00:00:00 2001 From: Haojun Liao Date: Sat, 21 May 2022 14:08:00 +0800 Subject: [PATCH 12/13] fix(query): add null value check before update the block window info --- source/libs/executor/src/timewindowoperator.c | 39 ++++++++++--------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/source/libs/executor/src/timewindowoperator.c b/source/libs/executor/src/timewindowoperator.c index 8abebf184b..588c3e90e7 100644 --- a/source/libs/executor/src/timewindowoperator.c +++ b/source/libs/executor/src/timewindowoperator.c @@ -621,7 +621,7 @@ static void saveDataBlockLastRow(char** pRow, SArray* pDataBlock, int32_t rowInd } } -static SArray* hashIntervalAgg(SOperatorInfo* pOperatorInfo, SResultRowInfo* pResultRowInfo, SSDataBlock* pSDataBlock, +static SArray* hashIntervalAgg(SOperatorInfo* pOperatorInfo, SResultRowInfo* pResultRowInfo, SSDataBlock* pBlock, uint64_t tableGroupId) { SIntervalAggOperatorInfo* pInfo = (SIntervalAggOperatorInfo*)pOperatorInfo->info; @@ -639,13 +639,17 @@ static SArray* hashIntervalAgg(SOperatorInfo* pOperatorInfo, SResultRowInfo* pRe // int32_t prevIndex = pResultRowInfo->curPos; TSKEY* tsCols = NULL; - if (pSDataBlock->pDataBlock != NULL) { - SColumnInfoData* pColDataInfo = taosArrayGet(pSDataBlock->pDataBlock, pInfo->primaryTsIndex); + if (pBlock->pDataBlock != NULL) { + SColumnInfoData* pColDataInfo = taosArrayGet(pBlock->pDataBlock, pInfo->primaryTsIndex); tsCols = (int64_t*)pColDataInfo->pData; + + if (tsCols != NULL) { + blockDataUpdateTsWindow(pBlock, pInfo->primaryTsIndex); + } } int32_t startPos = 0; - TSKEY ts = getStartTsKey(&pSDataBlock->info.window, tsCols, pSDataBlock->info.rows, ascScan); + TSKEY ts = getStartTsKey(&pBlock->info.window, tsCols, pBlock->info.rows, ascScan); STimeWindow win = getActiveTimeWindow(pInfo->aggSup.pResultBuf, pResultRowInfo, ts, &pInfo->interval, pInfo->interval.precision, &pInfo->win); @@ -670,7 +674,7 @@ static SArray* hashIntervalAgg(SOperatorInfo* pOperatorInfo, SResultRowInfo* pRe int32_t forwardStep = 0; TSKEY ekey = ascScan? win.ekey:win.skey; forwardStep = - getNumOfRowsInTimeWindow(&pSDataBlock->info, tsCols, startPos, ekey, binarySearchForKey, NULL, pInfo->order); + getNumOfRowsInTimeWindow(&pBlock->info, tsCols, startPos, ekey, binarySearchForKey, NULL, pInfo->order); ASSERT(forwardStep > 0); // prev time window not interpolation yet. @@ -686,7 +690,7 @@ static SArray* hashIntervalAgg(SOperatorInfo* pOperatorInfo, SResultRowInfo* pRe } STimeWindow w = pRes->win; - ret = setTimeWindowOutputBuf(pResultRowInfo, pSDataBlock->info.uid, &w, masterScan, &pResult, tableGroupId, + ret = setTimeWindowOutputBuf(pResultRowInfo, pBlock->info.uid, &w, masterScan, &pResult, tableGroupId, pInfo->binfo.pCtx, numOfOutput, pInfo->binfo.rowCellInfoOffset, &pInfo->aggSup, pTaskInfo); if (ret != TSDB_CODE_SUCCESS) { @@ -694,17 +698,17 @@ static SArray* hashIntervalAgg(SOperatorInfo* pOperatorInfo, SResultRowInfo* pRe } assert(!resultRowInterpolated(pResult, RESULT_ROW_END_INTERP)); - doTimeWindowInterpolation(pOperatorInfo, &pInfo->binfo, pSDataBlock->pDataBlock, *(TSKEY*)pInfo->pRow[0], -1, + doTimeWindowInterpolation(pOperatorInfo, &pInfo->binfo, pBlock->pDataBlock, *(TSKEY*)pInfo->pRow[0], -1, tsCols[startPos], startPos, w.ekey, RESULT_ROW_END_INTERP); setResultRowInterpo(pResult, RESULT_ROW_END_INTERP); setNotInterpoWindowKey(pInfo->binfo.pCtx, pOperatorInfo->numOfExprs, RESULT_ROW_START_INTERP); - doApplyFunctions(pInfo->binfo.pCtx, &w, &pInfo->timeWindowData, startPos, 0, tsCols, pSDataBlock->info.rows, numOfOutput, TSDB_ORDER_ASC); + doApplyFunctions(pInfo->binfo.pCtx, &w, &pInfo->timeWindowData, startPos, 0, tsCols, pBlock->info.rows, numOfOutput, TSDB_ORDER_ASC); } // restore current time window - ret = setTimeWindowOutputBuf(pResultRowInfo, pSDataBlock->info.uid, &win, masterScan, &pResult, tableGroupId, + ret = setTimeWindowOutputBuf(pResultRowInfo, pBlock->info.uid, &win, masterScan, &pResult, tableGroupId, pInfo->binfo.pCtx, numOfOutput, pInfo->binfo.rowCellInfoOffset, &pInfo->aggSup, pTaskInfo); if (ret != TSDB_CODE_SUCCESS) { @@ -714,17 +718,17 @@ static SArray* hashIntervalAgg(SOperatorInfo* pOperatorInfo, SResultRowInfo* pRe #endif // window start key interpolation - doWindowBorderInterpolation(pOperatorInfo, pSDataBlock, pInfo->binfo.pCtx, pResult, &win, startPos, forwardStep, + doWindowBorderInterpolation(pOperatorInfo, pBlock, pInfo->binfo.pCtx, pResult, &win, startPos, forwardStep, pInfo->order, false); updateTimeWindowInfo(&pInfo->twAggSup.timeWindowData, &win, true); doApplyFunctions(pTaskInfo, pInfo->binfo.pCtx, &win, &pInfo->twAggSup.timeWindowData, startPos, forwardStep, tsCols, - pSDataBlock->info.rows, numOfOutput, TSDB_ORDER_ASC); + pBlock->info.rows, numOfOutput, TSDB_ORDER_ASC); STimeWindow nextWin = win; while (1) { int32_t prevEndPos = (forwardStep - 1) * step + startPos; - startPos = getNextQualifiedWindow(&pInfo->interval, &nextWin, &pSDataBlock->info, tsCols, prevEndPos, pInfo->order); + startPos = getNextQualifiedWindow(&pInfo->interval, &nextWin, &pBlock->info, tsCols, prevEndPos, pInfo->order); if (startPos < 0) { break; } @@ -748,20 +752,20 @@ static SArray* hashIntervalAgg(SOperatorInfo* pOperatorInfo, SResultRowInfo* pRe ekey = ascScan? nextWin.ekey:nextWin.skey; forwardStep = - getNumOfRowsInTimeWindow(&pSDataBlock->info, tsCols, startPos, ekey, binarySearchForKey, NULL, pInfo->order); + getNumOfRowsInTimeWindow(&pBlock->info, tsCols, startPos, ekey, binarySearchForKey, NULL, pInfo->order); // window start(end) key interpolation - doWindowBorderInterpolation(pOperatorInfo, pSDataBlock, pInfo->binfo.pCtx, pResult, &nextWin, startPos, forwardStep, + doWindowBorderInterpolation(pOperatorInfo, pBlock, pInfo->binfo.pCtx, pResult, &nextWin, startPos, forwardStep, pInfo->order, false); updateTimeWindowInfo(&pInfo->twAggSup.timeWindowData, &nextWin, true); doApplyFunctions(pTaskInfo, pInfo->binfo.pCtx, &nextWin, &pInfo->twAggSup.timeWindowData, startPos, forwardStep, tsCols, - pSDataBlock->info.rows, numOfOutput, TSDB_ORDER_ASC); + pBlock->info.rows, numOfOutput, TSDB_ORDER_ASC); } if (pInfo->timeWindowInterpo) { - int32_t rowIndex = ascScan ? (pSDataBlock->info.rows - 1) : 0; - saveDataBlockLastRow(pInfo->pRow, pSDataBlock->pDataBlock, rowIndex, pSDataBlock->info.numOfCols); + int32_t rowIndex = ascScan ? (pBlock->info.rows - 1) : 0; + saveDataBlockLastRow(pInfo->pRow, pBlock->pDataBlock, rowIndex, pBlock->info.numOfCols); } return pUpdated; @@ -790,7 +794,6 @@ static int32_t doOpenIntervalAgg(SOperatorInfo* pOperator) { } getTableScanInfo(pOperator, &pInfo->order, &scanFlag); - blockDataUpdateTsWindow(pBlock, pInfo->primaryTsIndex); // the pDataBlock are always the same one, no need to call this again setInputDataBlock(pOperator, pInfo->binfo.pCtx, pBlock, pInfo->order, scanFlag, true); From 23801197fc000a4894b628d783d84943b87781fe Mon Sep 17 00:00:00 2001 From: Haojun Liao Date: Sat, 21 May 2022 14:46:44 +0800 Subject: [PATCH 13/13] fix(query): set the correct schema version for rows in buffer. --- source/dnode/vnode/src/tsdb/tsdbRead.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/dnode/vnode/src/tsdb/tsdbRead.c b/source/dnode/vnode/src/tsdb/tsdbRead.c index f0aa4d2ac6..d3b1f56a71 100644 --- a/source/dnode/vnode/src/tsdb/tsdbRead.c +++ b/source/dnode/vnode/src/tsdb/tsdbRead.c @@ -2775,7 +2775,7 @@ static int tsdbReadRowsFromCache(STableCheckInfo* pCheckInfo, TSKEY maxKey, int win->ekey = key; if (rv != TD_ROW_SVER(row)) { - pSchema = metaGetTbTSchema(REPO_META(pTsdbReadHandle->pTsdb), pCheckInfo->tableId, 1); + pSchema = metaGetTbTSchema(REPO_META(pTsdbReadHandle->pTsdb), pCheckInfo->tableId, TD_ROW_SVER(row)); rv = TD_ROW_SVER(row); } numOfRows += mergeTwoRowFromMem(pTsdbReadHandle, maxRowsToRead, &curRows, row, NULL, numOfCols, pCheckInfo->tableId,