Merge branch '3.0' into fix/TD-27206
This commit is contained in:
commit
398771da5b
Binary file not shown.
|
@ -38,11 +38,16 @@ Aggregation by time window is supported in TDengine. For example, in the case wh
|
||||||
window_clause: {
|
window_clause: {
|
||||||
SESSION(ts_col, tol_val)
|
SESSION(ts_col, tol_val)
|
||||||
| STATE_WINDOW(col)
|
| STATE_WINDOW(col)
|
||||||
| INTERVAL(interval [, offset]) [SLIDING sliding] [FILL({NONE | VALUE | PREV | NULL | LINEAR | NEXT})]
|
| INTERVAL(interval_val [, offset]) [SLIDING (sliding_value)] [FILL({NONE | VALUE | PREV | NULL | LINEAR | NEXT})]
|
||||||
| EVENT_WINDOW START WITH start_trigger_condition END WITH end_trigger_condition
|
| EVENT_WINDOW START WITH start_trigger_condition END WITH end_trigger_condition
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Both interval_val and sliding_value are time durations which have 3 forms of representation.
|
||||||
|
- INTERVAL(1s, 500a) SLIDING(1s), the unit char should be any one of a (millisecond), b (nanosecond), d (day), h (hour), m (minute), n (month), s (second), u (microsecond), w (week), y (year).
|
||||||
|
- INTERVAL(1000, 500) SLIDING(1000), the unit will the same as the queried database, if there are more than one databases, higher precision will be used.
|
||||||
|
- INTERVAL('1s', '500a') SLIDING('1s'), unit must be specified, no spaces allowed.
|
||||||
|
|
||||||
The following restrictions apply:
|
The following restrictions apply:
|
||||||
|
|
||||||
### Other Rules
|
### Other Rules
|
||||||
|
|
|
@ -44,7 +44,11 @@ window_clause: {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
在上述语法中的具体限制如下
|
其中,interval_val 和 sliding_val 都表示时间段, 语法上支持三种方式,举例说明如下:
|
||||||
|
- INTERVAL(1s, 500a) SLIDING(1s), 自带时间单位的形式,其中的时间单位是单字符表示, 分别为: a (毫秒), b (纳秒), d (天), h (小时), m (分钟), n (月), s (秒), u (微妙), w (周), y (年).
|
||||||
|
- INTERVAL(1000, 500) SLIDING(1000), 不带时间单位的形式,将使用查询库的时间精度作为默认时间单位,当存在多个库时默认采用精度更高的库.
|
||||||
|
- INTERVAL('1s', '500a') SLIDING('1s'), 自带时间单位的字符串形式,字符串内部不能有任何空格等其它字符.
|
||||||
|
|
||||||
|
|
||||||
### 窗口子句的规则
|
### 窗口子句的规则
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
#ifndef _TD_VND_COS_H_
|
#ifndef _TD_VND_COS_H_
|
||||||
#define _TD_VND_COS_H_
|
#define _TD_VND_COS_H_
|
||||||
|
|
||||||
#include "vnd.h"
|
#include "os.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
@ -24,6 +24,7 @@ extern "C" {
|
||||||
|
|
||||||
#define S3_BLOCK_CACHE
|
#define S3_BLOCK_CACHE
|
||||||
|
|
||||||
|
extern int8_t tsS3StreamEnabled;
|
||||||
extern int8_t tsS3Enabled;
|
extern int8_t tsS3Enabled;
|
||||||
extern int32_t tsS3BlockSize;
|
extern int32_t tsS3BlockSize;
|
||||||
extern int32_t tsS3BlockCacheSize;
|
extern int32_t tsS3BlockCacheSize;
|
||||||
|
@ -39,6 +40,7 @@ void s3DeleteObjects(const char *object_name[], int nobject);
|
||||||
bool s3Exists(const char *object_name);
|
bool s3Exists(const char *object_name);
|
||||||
bool s3Get(const char *object_name, const char *path);
|
bool s3Get(const char *object_name, const char *path);
|
||||||
int32_t s3GetObjectBlock(const char *object_name, int64_t offset, int64_t size, bool check, uint8_t **ppBlock);
|
int32_t s3GetObjectBlock(const char *object_name, int64_t offset, int64_t size, bool check, uint8_t **ppBlock);
|
||||||
|
int32_t s3GetObjectsByPrefix(const char *prefix, const char *path);
|
||||||
void s3EvictCache(const char *path, long object_size);
|
void s3EvictCache(const char *path, long object_size);
|
||||||
long s3Size(const char *object_name);
|
long s3Size(const char *object_name);
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
//
|
||||||
|
// Created by mingming wanng on 2023/11/2.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef TDENGINE_RSYNC_H
|
||||||
|
#define TDENGINE_RSYNC_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "tarray.h"
|
||||||
|
|
||||||
|
void stopRsync();
|
||||||
|
void startRsync();
|
||||||
|
int uploadRsync(char* id, char* path);
|
||||||
|
int downloadRsync(char* id, char* path);
|
||||||
|
int deleteRsync(char* id);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // TDENGINE_RSYNC_H
|
|
@ -75,6 +75,13 @@ extern int32_t tsElectInterval;
|
||||||
extern int32_t tsHeartbeatInterval;
|
extern int32_t tsHeartbeatInterval;
|
||||||
extern int32_t tsHeartbeatTimeout;
|
extern int32_t tsHeartbeatTimeout;
|
||||||
|
|
||||||
|
// snode
|
||||||
|
extern int32_t tsRsyncPort;
|
||||||
|
extern char tsCheckpointBackupDir[];
|
||||||
|
|
||||||
|
// vnode checkpoint
|
||||||
|
extern char tsSnodeAddress[]; //127.0.0.1:873
|
||||||
|
|
||||||
// mnode
|
// mnode
|
||||||
extern int64_t tsMndSdbWriteDelta;
|
extern int64_t tsMndSdbWriteDelta;
|
||||||
extern int64_t tsMndLogRetention;
|
extern int64_t tsMndLogRetention;
|
||||||
|
|
|
@ -184,11 +184,7 @@ void qDestroyTask(qTaskInfo_t tinfo);
|
||||||
|
|
||||||
void qProcessRspMsg(void* parent, struct SRpcMsg* pMsg, struct SEpSet* pEpSet);
|
void qProcessRspMsg(void* parent, struct SRpcMsg* pMsg, struct SEpSet* pEpSet);
|
||||||
|
|
||||||
int32_t qGetExplainExecInfo(qTaskInfo_t tinfo, SArray* pExecInfoList /*,int32_t* resNum, SExplainExecInfo** pRes*/);
|
int32_t qGetExplainExecInfo(qTaskInfo_t tinfo, SArray* pExecInfoList);
|
||||||
|
|
||||||
int32_t qSerializeTaskStatus(qTaskInfo_t tinfo, char** pOutput, int32_t* len);
|
|
||||||
|
|
||||||
int32_t qDeserializeTaskStatus(qTaskInfo_t tinfo, const char* pInput, int32_t len);
|
|
||||||
|
|
||||||
void getNextTimeWindow(const SInterval* pInterval, STimeWindow* tw, int32_t order);
|
void getNextTimeWindow(const SInterval* pInterval, STimeWindow* tw, int32_t order);
|
||||||
void getInitialStartTimeWindow(SInterval* pInterval, TSKEY ts, STimeWindow* w, bool ascQuery);
|
void getInitialStartTimeWindow(SInterval* pInterval, TSKEY ts, STimeWindow* w, bool ascQuery);
|
||||||
|
@ -217,7 +213,7 @@ int32_t qStreamSourceScanParamForHistoryScanStep1(qTaskInfo_t tinfo, SVersionRan
|
||||||
int32_t qStreamSourceScanParamForHistoryScanStep2(qTaskInfo_t tinfo, SVersionRange *pVerRange, STimeWindow* pWindow);
|
int32_t qStreamSourceScanParamForHistoryScanStep2(qTaskInfo_t tinfo, SVersionRange *pVerRange, STimeWindow* pWindow);
|
||||||
int32_t qStreamRecoverFinish(qTaskInfo_t tinfo);
|
int32_t qStreamRecoverFinish(qTaskInfo_t tinfo);
|
||||||
int32_t qRestoreStreamOperatorOption(qTaskInfo_t tinfo);
|
int32_t qRestoreStreamOperatorOption(qTaskInfo_t tinfo);
|
||||||
bool qStreamRecoverScanFinished(qTaskInfo_t tinfo);
|
bool qStreamScanhistoryFinished(qTaskInfo_t tinfo);
|
||||||
int32_t qStreamInfoResetTimewindowFilter(qTaskInfo_t tinfo);
|
int32_t qStreamInfoResetTimewindowFilter(qTaskInfo_t tinfo);
|
||||||
void resetTaskInfo(qTaskInfo_t tinfo);
|
void resetTaskInfo(qTaskInfo_t tinfo);
|
||||||
|
|
||||||
|
|
|
@ -241,6 +241,24 @@ typedef struct {
|
||||||
SEpSet epset;
|
SEpSet epset;
|
||||||
} SDownstreamTaskEpset;
|
} SDownstreamTaskEpset;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
TASK_SCANHISTORY_CONT = 0x1,
|
||||||
|
TASK_SCANHISTORY_QUIT = 0x2,
|
||||||
|
TASK_SCANHISTORY_REXEC = 0x3,
|
||||||
|
} EScanHistoryRet;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
EScanHistoryRet ret;
|
||||||
|
int32_t idleTime;
|
||||||
|
} SScanhistoryDataInfo;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int32_t idleDuration; // idle time before use time slice the continue execute scan-history
|
||||||
|
int32_t numOfTicks;
|
||||||
|
tmr_h pTimer;
|
||||||
|
int32_t execCount;
|
||||||
|
} SScanhistorySchedInfo;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int64_t stbUid;
|
int64_t stbUid;
|
||||||
char stbFullName[TSDB_TABLE_FNAME_LEN];
|
char stbFullName[TSDB_TABLE_FNAME_LEN];
|
||||||
|
@ -354,7 +372,9 @@ typedef struct STaskExecStatisInfo {
|
||||||
int64_t init;
|
int64_t init;
|
||||||
int64_t start;
|
int64_t start;
|
||||||
int64_t step1Start;
|
int64_t step1Start;
|
||||||
|
double step1El;
|
||||||
int64_t step2Start;
|
int64_t step2Start;
|
||||||
|
double step2El;
|
||||||
int32_t updateCount;
|
int32_t updateCount;
|
||||||
int64_t latestUpdateTs;
|
int64_t latestUpdateTs;
|
||||||
int32_t processDataBlocks;
|
int32_t processDataBlocks;
|
||||||
|
@ -378,6 +398,7 @@ typedef struct STaskOutputInfo {
|
||||||
union {
|
union {
|
||||||
STaskDispatcherFixed fixedDispatcher;
|
STaskDispatcherFixed fixedDispatcher;
|
||||||
STaskDispatcherShuffle shuffleDispatcher;
|
STaskDispatcherShuffle shuffleDispatcher;
|
||||||
|
|
||||||
STaskSinkTb tbSink;
|
STaskSinkTb tbSink;
|
||||||
STaskSinkSma smaSink;
|
STaskSinkSma smaSink;
|
||||||
STaskSinkFetch fetchSink;
|
STaskSinkFetch fetchSink;
|
||||||
|
@ -414,7 +435,10 @@ struct SStreamTask {
|
||||||
SStreamState* pState; // state backend
|
SStreamState* pState; // state backend
|
||||||
SArray* pRspMsgList;
|
SArray* pRspMsgList;
|
||||||
SUpstreamInfo upstreamInfo;
|
SUpstreamInfo upstreamInfo;
|
||||||
|
|
||||||
// the followings attributes don't be serialized
|
// the followings attributes don't be serialized
|
||||||
|
SScanhistorySchedInfo schedHistoryInfo;
|
||||||
|
|
||||||
int32_t notReadyTasks;
|
int32_t notReadyTasks;
|
||||||
int32_t numOfWaitingUpstream;
|
int32_t numOfWaitingUpstream;
|
||||||
int64_t checkReqId;
|
int64_t checkReqId;
|
||||||
|
@ -432,8 +456,10 @@ struct SStreamTask {
|
||||||
typedef struct STaskStartInfo {
|
typedef struct STaskStartInfo {
|
||||||
int64_t startTs;
|
int64_t startTs;
|
||||||
int64_t readyTs;
|
int64_t readyTs;
|
||||||
int32_t startAllTasksFlag;
|
int32_t tasksWillRestart;
|
||||||
|
int32_t taskStarting; // restart flag, sentinel to guard the restart procedure.
|
||||||
SHashObj* pReadyTaskSet; // tasks that are all ready for running stream processing
|
SHashObj* pReadyTaskSet; // tasks that are all ready for running stream processing
|
||||||
|
SHashObj* pFailedTaskSet; // tasks that are done the check downstream process, may be successful or failed
|
||||||
int32_t elapsedTime;
|
int32_t elapsedTime;
|
||||||
} STaskStartInfo;
|
} STaskStartInfo;
|
||||||
|
|
||||||
|
@ -732,8 +758,6 @@ void initRpcMsg(SRpcMsg* pMsg, int32_t msgType, void* pCont, int32_t contLen)
|
||||||
|
|
||||||
// recover and fill history
|
// recover and fill history
|
||||||
void streamTaskCheckDownstream(SStreamTask* pTask);
|
void streamTaskCheckDownstream(SStreamTask* pTask);
|
||||||
int32_t onNormalTaskReady(SStreamTask* pTask);
|
|
||||||
int32_t onScanhistoryTaskReady(SStreamTask* pTask);
|
|
||||||
|
|
||||||
int32_t streamTaskCheckStatus(SStreamTask* pTask, int32_t upstreamTaskId, int32_t vgId, int64_t stage);
|
int32_t streamTaskCheckStatus(SStreamTask* pTask, int32_t upstreamTaskId, int32_t vgId, int64_t stage);
|
||||||
int32_t streamTaskUpdateEpsetInfo(SStreamTask* pTask, SArray* pNodeList);
|
int32_t streamTaskUpdateEpsetInfo(SStreamTask* pTask, SArray* pNodeList);
|
||||||
|
@ -755,7 +779,9 @@ int32_t streamProcessCheckRsp(SStreamTask* pTask, const SStreamTaskCheckRsp* pRs
|
||||||
int32_t streamLaunchFillHistoryTask(SStreamTask* pTask);
|
int32_t streamLaunchFillHistoryTask(SStreamTask* pTask);
|
||||||
int32_t streamTaskScanHistoryDataComplete(SStreamTask* pTask);
|
int32_t streamTaskScanHistoryDataComplete(SStreamTask* pTask);
|
||||||
int32_t streamStartScanHistoryAsync(SStreamTask* pTask, int8_t igUntreated);
|
int32_t streamStartScanHistoryAsync(SStreamTask* pTask, int8_t igUntreated);
|
||||||
|
int32_t streamReExecScanHistoryFuture(SStreamTask* pTask, int32_t idleDuration);
|
||||||
bool streamHistoryTaskSetVerRangeStep2(SStreamTask* pTask, int64_t latestVer);
|
bool streamHistoryTaskSetVerRangeStep2(SStreamTask* pTask, int64_t latestVer);
|
||||||
|
|
||||||
int32_t streamQueueGetNumOfItems(const SStreamQueue* pQueue);
|
int32_t streamQueueGetNumOfItems(const SStreamQueue* pQueue);
|
||||||
|
|
||||||
// common
|
// common
|
||||||
|
@ -778,12 +804,11 @@ void streamTaskStatusCopy(STaskStatusEntry* pDst, const STaskStatusEntry* pSrc);
|
||||||
// source level
|
// source level
|
||||||
int32_t streamSetParamForStreamScannerStep1(SStreamTask* pTask, SVersionRange* pVerRange, STimeWindow* pWindow);
|
int32_t streamSetParamForStreamScannerStep1(SStreamTask* pTask, SVersionRange* pVerRange, STimeWindow* pWindow);
|
||||||
int32_t streamSetParamForStreamScannerStep2(SStreamTask* pTask, SVersionRange* pVerRange, STimeWindow* pWindow);
|
int32_t streamSetParamForStreamScannerStep2(SStreamTask* pTask, SVersionRange* pVerRange, STimeWindow* pWindow);
|
||||||
int32_t streamScanHistoryData(SStreamTask* pTask);
|
SScanhistoryDataInfo streamScanHistoryData(SStreamTask* pTask, int64_t st);
|
||||||
int32_t streamDispatchScanHistoryFinishMsg(SStreamTask* pTask);
|
int32_t streamDispatchScanHistoryFinishMsg(SStreamTask* pTask);
|
||||||
|
|
||||||
// agg level
|
// agg level
|
||||||
int32_t streamProcessScanHistoryFinishReq(SStreamTask* pTask, SStreamScanHistoryFinishReq* pReq,
|
int32_t streamProcessScanHistoryFinishReq(SStreamTask* pTask, SStreamScanHistoryFinishReq* pReq, SRpcHandleInfo* pInfo);
|
||||||
SRpcHandleInfo* pRpcInfo);
|
|
||||||
int32_t streamProcessScanHistoryFinishRsp(SStreamTask* pTask);
|
int32_t streamProcessScanHistoryFinishRsp(SStreamTask* pTask);
|
||||||
|
|
||||||
// stream task meta
|
// stream task meta
|
||||||
|
@ -805,11 +830,12 @@ void streamMetaNotifyClose(SStreamMeta* pMeta);
|
||||||
void streamMetaStartHb(SStreamMeta* pMeta);
|
void streamMetaStartHb(SStreamMeta* pMeta);
|
||||||
void streamMetaInitForSnode(SStreamMeta* pMeta);
|
void streamMetaInitForSnode(SStreamMeta* pMeta);
|
||||||
bool streamMetaTaskInTimer(SStreamMeta* pMeta);
|
bool streamMetaTaskInTimer(SStreamMeta* pMeta);
|
||||||
int32_t streamMetaUpdateTaskReadyInfo(SStreamTask* pTask);
|
int32_t streamMetaUpdateTaskDownstreamStatus(SStreamTask* pTask, int64_t startTs, int64_t endTs, bool succ);
|
||||||
void streamMetaRLock(SStreamMeta* pMeta);
|
void streamMetaRLock(SStreamMeta* pMeta);
|
||||||
void streamMetaRUnLock(SStreamMeta* pMeta);
|
void streamMetaRUnLock(SStreamMeta* pMeta);
|
||||||
void streamMetaWLock(SStreamMeta* pMeta);
|
void streamMetaWLock(SStreamMeta* pMeta);
|
||||||
void streamMetaWUnLock(SStreamMeta* pMeta);
|
void streamMetaWUnLock(SStreamMeta* pMeta);
|
||||||
|
void streamMetaResetStartInfo(STaskStartInfo* pMeta);
|
||||||
|
|
||||||
// checkpoint
|
// checkpoint
|
||||||
int32_t streamProcessCheckpointSourceReq(SStreamTask* pTask, SStreamCheckpointSourceReq* pReq);
|
int32_t streamProcessCheckpointSourceReq(SStreamTask* pTask, SStreamCheckpointSourceReq* pReq);
|
||||||
|
|
|
@ -237,6 +237,12 @@ void syslog(int unused, const char *format, ...);
|
||||||
#define TD_DIRSEP "/"
|
#define TD_DIRSEP "/"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(_WIN32)
|
||||||
|
#define TD_DIRSEP_CHAR '\\'
|
||||||
|
#else
|
||||||
|
#define TD_DIRSEP_CHAR '/'
|
||||||
|
#endif
|
||||||
|
|
||||||
#define TD_LOCALE_LEN 64
|
#define TD_LOCALE_LEN 64
|
||||||
#define TD_CHARSET_LEN 64
|
#define TD_CHARSET_LEN 64
|
||||||
#define TD_TIMEZONE_LEN 96
|
#define TD_TIMEZONE_LEN 96
|
||||||
|
|
|
@ -1052,6 +1052,7 @@ SRequestObj* launchQueryImpl(SRequestObj* pRequest, SQuery* pQuery, bool keepQue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pRequest->body.execMode = pQuery->execMode;
|
||||||
switch (pQuery->execMode) {
|
switch (pQuery->execMode) {
|
||||||
case QUERY_EXEC_MODE_LOCAL:
|
case QUERY_EXEC_MODE_LOCAL:
|
||||||
if (!pRequest->validateOnly) {
|
if (!pRequest->validateOnly) {
|
||||||
|
|
|
@ -46,6 +46,75 @@ target_link_libraries(
|
||||||
INTERFACE api
|
INTERFACE api
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if(${BUILD_S3})
|
||||||
|
|
||||||
|
if(${BUILD_WITH_S3})
|
||||||
|
target_include_directories(
|
||||||
|
common
|
||||||
|
|
||||||
|
PUBLIC "$ENV{HOME}/.cos-local.2/include"
|
||||||
|
)
|
||||||
|
|
||||||
|
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
|
||||||
|
set(CMAKE_PREFIX_PATH $ENV{HOME}/.cos-local.2)
|
||||||
|
find_library(S3_LIBRARY s3)
|
||||||
|
find_library(CURL_LIBRARY curl $ENV{HOME}/.cos-local.2/lib NO_DEFAULT_PATH)
|
||||||
|
find_library(XML2_LIBRARY xml2)
|
||||||
|
find_library(SSL_LIBRARY ssl $ENV{HOME}/.cos-local.2/lib64 NO_DEFAULT_PATH)
|
||||||
|
find_library(CRYPTO_LIBRARY crypto $ENV{HOME}/.cos-local.2/lib64 NO_DEFAULT_PATH)
|
||||||
|
target_link_libraries(
|
||||||
|
common
|
||||||
|
|
||||||
|
# s3
|
||||||
|
PUBLIC ${S3_LIBRARY}
|
||||||
|
PUBLIC ${CURL_LIBRARY}
|
||||||
|
PUBLIC ${SSL_LIBRARY}
|
||||||
|
PUBLIC ${CRYPTO_LIBRARY}
|
||||||
|
PUBLIC ${XML2_LIBRARY}
|
||||||
|
)
|
||||||
|
|
||||||
|
add_definitions(-DUSE_S3)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(${BUILD_WITH_COS})
|
||||||
|
|
||||||
|
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
|
||||||
|
find_library(APR_LIBRARY apr-1 PATHS /usr/local/apr/lib/)
|
||||||
|
find_library(APR_UTIL_LIBRARY aprutil-1 PATHS /usr/local/apr/lib/)
|
||||||
|
find_library(MINIXML_LIBRARY mxml)
|
||||||
|
find_library(CURL_LIBRARY curl)
|
||||||
|
target_link_libraries(
|
||||||
|
common
|
||||||
|
|
||||||
|
# s3
|
||||||
|
PUBLIC cos_c_sdk_static
|
||||||
|
PUBLIC ${APR_UTIL_LIBRARY}
|
||||||
|
PUBLIC ${APR_LIBRARY}
|
||||||
|
PUBLIC ${MINIXML_LIBRARY}
|
||||||
|
PUBLIC ${CURL_LIBRARY}
|
||||||
|
)
|
||||||
|
|
||||||
|
# s3
|
||||||
|
FIND_PROGRAM(APR_CONFIG_BIN NAMES apr-config apr-1-config PATHS /usr/bin /usr/local/bin /usr/local/apr/bin/)
|
||||||
|
IF (APR_CONFIG_BIN)
|
||||||
|
EXECUTE_PROCESS(
|
||||||
|
COMMAND ${APR_CONFIG_BIN} --includedir
|
||||||
|
OUTPUT_VARIABLE APR_INCLUDE_DIR
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
|
)
|
||||||
|
ENDIF()
|
||||||
|
include_directories (${APR_INCLUDE_DIR})
|
||||||
|
target_include_directories(
|
||||||
|
common
|
||||||
|
PUBLIC "${TD_SOURCE_DIR}/contrib/cos-c-sdk-v5/cos_c_sdk"
|
||||||
|
PUBLIC "$ENV{HOME}/.cos-local.1/include"
|
||||||
|
)
|
||||||
|
|
||||||
|
add_definitions(-DUSE_COS)
|
||||||
|
endif(${BUILD_WITH_COS})
|
||||||
|
|
||||||
|
endif()
|
||||||
|
|
||||||
if(${BUILD_TEST})
|
if(${BUILD_TEST})
|
||||||
ADD_SUBDIRECTORY(test)
|
ADD_SUBDIRECTORY(test)
|
||||||
endif(${BUILD_TEST})
|
endif(${BUILD_TEST})
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#define ALLOW_FORBID_FUNC
|
#define ALLOW_FORBID_FUNC
|
||||||
|
|
||||||
#include "vndCos.h"
|
#include "cos.h"
|
||||||
|
|
||||||
extern char tsS3Endpoint[];
|
extern char tsS3Endpoint[];
|
||||||
extern char tsS3AccessKeyId[];
|
extern char tsS3AccessKeyId[];
|
||||||
|
@ -13,6 +13,7 @@ extern int8_t tsS3Https;
|
||||||
#if defined(USE_S3)
|
#if defined(USE_S3)
|
||||||
|
|
||||||
#include "libs3.h"
|
#include "libs3.h"
|
||||||
|
#include "tarray.h"
|
||||||
|
|
||||||
static int verifyPeerG = 0;
|
static int verifyPeerG = 0;
|
||||||
static const char *awsRegionG = NULL;
|
static const char *awsRegionG = NULL;
|
||||||
|
@ -34,7 +35,7 @@ int32_t s3Begin() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((status = S3_initialize("s3", verifyPeerG | S3_INIT_ALL, hostname)) != S3StatusOK) {
|
if ((status = S3_initialize("s3", verifyPeerG | S3_INIT_ALL, hostname)) != S3StatusOK) {
|
||||||
vError("Failed to initialize libs3: %s\n", S3_get_status_name(status));
|
uError("Failed to initialize libs3: %s\n", S3_get_status_name(status));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,9 +68,9 @@ static int should_retry() {
|
||||||
|
|
||||||
static void s3PrintError(const char *func, S3Status status, char error_details[]) {
|
static void s3PrintError(const char *func, S3Status status, char error_details[]) {
|
||||||
if (status < S3StatusErrorAccessDenied) {
|
if (status < S3StatusErrorAccessDenied) {
|
||||||
vError("%s: %s", __func__, S3_get_status_name(status));
|
uError("%s: %s", __func__, S3_get_status_name(status));
|
||||||
} else {
|
} else {
|
||||||
vError("%s: %s, %s", __func__, S3_get_status_name(status), error_details);
|
uError("%s: %s, %s", __func__, S3_get_status_name(status), error_details);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,10 +78,22 @@ typedef struct {
|
||||||
char err_msg[512];
|
char err_msg[512];
|
||||||
S3Status status;
|
S3Status status;
|
||||||
uint64_t content_length;
|
uint64_t content_length;
|
||||||
|
TdFilePtr file;
|
||||||
|
} TS3GetData;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char err_msg[128];
|
||||||
|
S3Status status;
|
||||||
|
uint64_t content_length;
|
||||||
char *buf;
|
char *buf;
|
||||||
int64_t buf_pos;
|
int64_t buf_pos;
|
||||||
} TS3SizeCBD;
|
} TS3SizeCBD;
|
||||||
|
|
||||||
|
static S3Status responsePropertiesCallbackNull(const S3ResponseProperties *properties, void *callbackData) {
|
||||||
|
// (void)callbackData;
|
||||||
|
return S3StatusOK;
|
||||||
|
}
|
||||||
|
|
||||||
static S3Status responsePropertiesCallback(const S3ResponseProperties *properties, void *callbackData) {
|
static S3Status responsePropertiesCallback(const S3ResponseProperties *properties, void *callbackData) {
|
||||||
//(void)callbackData;
|
//(void)callbackData;
|
||||||
TS3SizeCBD *cbd = callbackData;
|
TS3SizeCBD *cbd = callbackData;
|
||||||
|
@ -299,7 +312,7 @@ S3Status initial_multipart_callback(const char *upload_id, void *callbackData) {
|
||||||
}
|
}
|
||||||
|
|
||||||
S3Status MultipartResponseProperiesCallback(const S3ResponseProperties *properties, void *callbackData) {
|
S3Status MultipartResponseProperiesCallback(const S3ResponseProperties *properties, void *callbackData) {
|
||||||
responsePropertiesCallback(properties, callbackData);
|
responsePropertiesCallbackNull(properties, callbackData);
|
||||||
|
|
||||||
MultipartPartData *data = (MultipartPartData *)callbackData;
|
MultipartPartData *data = (MultipartPartData *)callbackData;
|
||||||
int seq = data->seq;
|
int seq = data->seq;
|
||||||
|
@ -398,7 +411,8 @@ static int try_get_parts_info(const char *bucketName, const char *key, UploadMan
|
||||||
S3BucketContext bucketContext = {0, tsS3BucketName, protocolG, uriStyleG, tsS3AccessKeyId, tsS3AccessKeySecret,
|
S3BucketContext bucketContext = {0, tsS3BucketName, protocolG, uriStyleG, tsS3AccessKeyId, tsS3AccessKeySecret,
|
||||||
0, awsRegionG};
|
0, awsRegionG};
|
||||||
|
|
||||||
S3ListPartsHandler listPartsHandler = {{&responsePropertiesCallback, &responseCompleteCallback}, &listPartsCallback};
|
S3ListPartsHandler listPartsHandler = {{&responsePropertiesCallbackNull, &responseCompleteCallback},
|
||||||
|
&listPartsCallback};
|
||||||
|
|
||||||
list_parts_callback_data data;
|
list_parts_callback_data data;
|
||||||
|
|
||||||
|
@ -453,13 +467,13 @@ int32_t s3PutObjectFromFile2(const char *file, const char *object) {
|
||||||
data.noStatus = noStatus;
|
data.noStatus = noStatus;
|
||||||
|
|
||||||
if (taosStatFile(file, &contentLength, NULL, NULL) < 0) {
|
if (taosStatFile(file, &contentLength, NULL, NULL) < 0) {
|
||||||
vError("ERROR: %s Failed to stat file %s: ", __func__, file);
|
uError("ERROR: %s Failed to stat file %s: ", __func__, file);
|
||||||
code = TAOS_SYSTEM_ERROR(errno);
|
code = TAOS_SYSTEM_ERROR(errno);
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(data.infileFD = taosOpenFile(file, TD_FILE_READ))) {
|
if (!(data.infileFD = taosOpenFile(file, TD_FILE_READ))) {
|
||||||
vError("ERROR: %s Failed to open file %s: ", __func__, file);
|
uError("ERROR: %s Failed to open file %s: ", __func__, file);
|
||||||
code = TAOS_SYSTEM_ERROR(errno);
|
code = TAOS_SYSTEM_ERROR(errno);
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
@ -477,7 +491,7 @@ int32_t s3PutObjectFromFile2(const char *file, const char *object) {
|
||||||
metaProperties, useServerSideEncryption};
|
metaProperties, useServerSideEncryption};
|
||||||
|
|
||||||
if (contentLength <= MULTIPART_CHUNK_SIZE) {
|
if (contentLength <= MULTIPART_CHUNK_SIZE) {
|
||||||
S3PutObjectHandler putObjectHandler = {{&responsePropertiesCallback, &responseCompleteCallback},
|
S3PutObjectHandler putObjectHandler = {{&responsePropertiesCallbackNull, &responseCompleteCallback},
|
||||||
&putObjectDataCallback};
|
&putObjectDataCallback};
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
@ -494,7 +508,7 @@ int32_t s3PutObjectFromFile2(const char *file, const char *object) {
|
||||||
s3PrintError(__func__, data.status, data.err_msg);
|
s3PrintError(__func__, data.status, data.err_msg);
|
||||||
code = TAOS_SYSTEM_ERROR(EIO);
|
code = TAOS_SYSTEM_ERROR(EIO);
|
||||||
} else if (data.contentLength) {
|
} else if (data.contentLength) {
|
||||||
vError("ERROR: %s Failed to read remaining %llu bytes from input", __func__,
|
uError("ERROR: %s Failed to read remaining %llu bytes from input", __func__,
|
||||||
(unsigned long long)data.contentLength);
|
(unsigned long long)data.contentLength);
|
||||||
code = TAOS_SYSTEM_ERROR(EIO);
|
code = TAOS_SYSTEM_ERROR(EIO);
|
||||||
}
|
}
|
||||||
|
@ -514,14 +528,14 @@ int32_t s3PutObjectFromFile2(const char *file, const char *object) {
|
||||||
memset(&partData, 0, sizeof(MultipartPartData));
|
memset(&partData, 0, sizeof(MultipartPartData));
|
||||||
int partContentLength = 0;
|
int partContentLength = 0;
|
||||||
|
|
||||||
S3MultipartInitialHandler handler = {{&responsePropertiesCallback, &responseCompleteCallback},
|
S3MultipartInitialHandler handler = {{&responsePropertiesCallbackNull, &responseCompleteCallback},
|
||||||
&initial_multipart_callback};
|
&initial_multipart_callback};
|
||||||
|
|
||||||
S3PutObjectHandler putObjectHandler = {{&MultipartResponseProperiesCallback, &responseCompleteCallback},
|
S3PutObjectHandler putObjectHandler = {{&MultipartResponseProperiesCallback, &responseCompleteCallback},
|
||||||
&putObjectDataCallback};
|
&putObjectDataCallback};
|
||||||
|
|
||||||
S3MultipartCommitHandler commit_handler = {
|
S3MultipartCommitHandler commit_handler = {
|
||||||
{&responsePropertiesCallback, &responseCompleteCallback}, &multipartPutXmlCallback, 0};
|
{&responsePropertiesCallbackNull, &responseCompleteCallback}, &multipartPutXmlCallback, 0};
|
||||||
|
|
||||||
manager.etags = (char **)taosMemoryMalloc(sizeof(char *) * totalSeq);
|
manager.etags = (char **)taosMemoryMalloc(sizeof(char *) * totalSeq);
|
||||||
manager.next_etags_pos = 0;
|
manager.next_etags_pos = 0;
|
||||||
|
@ -666,19 +680,19 @@ static void s3FreeObjectKey(void *pItem) {
|
||||||
taosMemoryFree(key);
|
taosMemoryFree(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
void s3DeleteObjectsByPrefix(const char *prefix) {
|
static SArray *getListByPrefix(const char *prefix) {
|
||||||
S3BucketContext bucketContext = {0, tsS3BucketName, protocolG, uriStyleG, tsS3AccessKeyId, tsS3AccessKeySecret,
|
S3BucketContext bucketContext = {0, tsS3BucketName, protocolG, uriStyleG, tsS3AccessKeyId, tsS3AccessKeySecret,
|
||||||
0, awsRegionG};
|
0, awsRegionG};
|
||||||
S3ListBucketHandler listBucketHandler = {{&responsePropertiesCallback, &responseCompleteCallback},
|
S3ListBucketHandler listBucketHandler = {{&responsePropertiesCallbackNull, &responseCompleteCallback},
|
||||||
&listBucketCallback};
|
&listBucketCallback};
|
||||||
|
|
||||||
const char *marker = 0, *delimiter = 0;
|
const char *marker = 0, *delimiter = 0;
|
||||||
int maxkeys = 0, allDetails = 0;
|
int maxkeys = 0, allDetails = 0;
|
||||||
list_bucket_callback_data data;
|
list_bucket_callback_data data;
|
||||||
data.objectArray = taosArrayInit(32, POINTER_BYTES);
|
data.objectArray = taosArrayInit(32, sizeof(void *));
|
||||||
if (!data.objectArray) {
|
if (!data.objectArray) {
|
||||||
vError("%s: %s", __func__, "out of memoty");
|
uError("%s: %s", __func__, "out of memoty");
|
||||||
return;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (marker) {
|
if (marker) {
|
||||||
snprintf(data.nextMarker, sizeof(data.nextMarker), "%s", marker);
|
snprintf(data.nextMarker, sizeof(data.nextMarker), "%s", marker);
|
||||||
|
@ -701,18 +715,15 @@ void s3DeleteObjectsByPrefix(const char *prefix) {
|
||||||
|
|
||||||
if (data.status == S3StatusOK) {
|
if (data.status == S3StatusOK) {
|
||||||
if (data.keyCount > 0) {
|
if (data.keyCount > 0) {
|
||||||
// printListBucketHeader(allDetails);
|
return data.objectArray;
|
||||||
s3DeleteObjects(TARRAY_DATA(data.objectArray), TARRAY_SIZE(data.objectArray));
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
s3PrintError(__func__, data.status, data.err_msg);
|
s3PrintError(__func__, data.status, data.err_msg);
|
||||||
}
|
}
|
||||||
|
return NULL;
|
||||||
taosArrayDestroyEx(data.objectArray, s3FreeObjectKey);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void s3DeleteObjects(const char *object_name[], int nobject) {
|
void s3DeleteObjects(const char *object_name[], int nobject) {
|
||||||
int status = 0;
|
|
||||||
S3BucketContext bucketContext = {0, tsS3BucketName, protocolG, uriStyleG, tsS3AccessKeyId, tsS3AccessKeySecret,
|
S3BucketContext bucketContext = {0, tsS3BucketName, protocolG, uriStyleG, tsS3AccessKeyId, tsS3AccessKeySecret,
|
||||||
0, awsRegionG};
|
0, awsRegionG};
|
||||||
S3ResponseHandler responseHandler = {0, &responseCompleteCallback};
|
S3ResponseHandler responseHandler = {0, &responseCompleteCallback};
|
||||||
|
@ -729,6 +740,13 @@ void s3DeleteObjects(const char *object_name[], int nobject) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void s3DeleteObjectsByPrefix(const char *prefix) {
|
||||||
|
SArray *objectArray = getListByPrefix(prefix);
|
||||||
|
if (objectArray == NULL) return;
|
||||||
|
s3DeleteObjects(TARRAY_DATA(objectArray), TARRAY_SIZE(objectArray));
|
||||||
|
taosArrayDestroyEx(objectArray, s3FreeObjectKey);
|
||||||
|
}
|
||||||
|
|
||||||
static S3Status getObjectDataCallback(int bufferSize, const char *buffer, void *callbackData) {
|
static S3Status getObjectDataCallback(int bufferSize, const char *buffer, void *callbackData) {
|
||||||
TS3SizeCBD *cbd = callbackData;
|
TS3SizeCBD *cbd = callbackData;
|
||||||
/*
|
/*
|
||||||
|
@ -771,7 +789,7 @@ int32_t s3GetObjectBlock(const char *object_name, int64_t offset, int64_t size,
|
||||||
} while (S3_status_is_retryable(cbd.status) && should_retry());
|
} while (S3_status_is_retryable(cbd.status) && should_retry());
|
||||||
|
|
||||||
if (cbd.status != S3StatusOK) {
|
if (cbd.status != S3StatusOK) {
|
||||||
vError("%s: %d(%s)", __func__, cbd.status, cbd.err_msg);
|
uError("%s: %d(%s)", __func__, cbd.status, cbd.err_msg);
|
||||||
return TAOS_SYSTEM_ERROR(EIO);
|
return TAOS_SYSTEM_ERROR(EIO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -785,6 +803,66 @@ int32_t s3GetObjectBlock(const char *object_name, int64_t offset, int64_t size,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static S3Status getObjectCallback(int bufferSize, const char *buffer, void *callbackData) {
|
||||||
|
TS3GetData *cbd = (TS3GetData *)callbackData;
|
||||||
|
size_t wrote = taosWriteFile(cbd->file, buffer, bufferSize);
|
||||||
|
return ((wrote < (size_t)bufferSize) ? S3StatusAbortedByCallback : S3StatusOK);
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t s3GetObjectToFile(const char *object_name, char *fileName) {
|
||||||
|
int64_t ifModifiedSince = -1, ifNotModifiedSince = -1;
|
||||||
|
const char *ifMatch = 0, *ifNotMatch = 0;
|
||||||
|
|
||||||
|
S3BucketContext bucketContext = {0, tsS3BucketName, protocolG, uriStyleG, tsS3AccessKeyId, tsS3AccessKeySecret,
|
||||||
|
0, awsRegionG};
|
||||||
|
S3GetConditions getConditions = {ifModifiedSince, ifNotModifiedSince, ifMatch, ifNotMatch};
|
||||||
|
S3GetObjectHandler getObjectHandler = {{&responsePropertiesCallbackNull, &responseCompleteCallback},
|
||||||
|
&getObjectCallback};
|
||||||
|
|
||||||
|
TdFilePtr pFile = taosOpenFile(fileName, TD_FILE_CREATE | TD_FILE_WRITE | TD_FILE_TRUNC);
|
||||||
|
if (pFile == NULL) {
|
||||||
|
uError("[s3] open file error, errno:%d, fileName:%s", errno, fileName);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
TS3GetData cbd = {0};
|
||||||
|
cbd.file = pFile;
|
||||||
|
do {
|
||||||
|
S3_get_object(&bucketContext, object_name, &getConditions, 0, 0, 0, 0, &getObjectHandler, &cbd);
|
||||||
|
} while (S3_status_is_retryable(cbd.status) && should_retry());
|
||||||
|
|
||||||
|
if (cbd.status != S3StatusOK) {
|
||||||
|
uError("%s: %d(%s)", __func__, cbd.status, cbd.err_msg);
|
||||||
|
taosCloseFile(&pFile);
|
||||||
|
return TAOS_SYSTEM_ERROR(EIO);
|
||||||
|
}
|
||||||
|
|
||||||
|
taosCloseFile(&pFile);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t s3GetObjectsByPrefix(const char *prefix, const char *path) {
|
||||||
|
SArray *objectArray = getListByPrefix(prefix);
|
||||||
|
if (objectArray == NULL) return -1;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < taosArrayGetSize(objectArray); i++) {
|
||||||
|
char *object = taosArrayGetP(objectArray, i);
|
||||||
|
const char *tmp = strchr(object, '/');
|
||||||
|
tmp = (tmp == NULL) ? object : tmp + 1;
|
||||||
|
char fileName[PATH_MAX] = {0};
|
||||||
|
if (path[strlen(path) - 1] != TD_DIRSEP_CHAR) {
|
||||||
|
snprintf(fileName, PATH_MAX, "%s%s%s", path, TD_DIRSEP, tmp);
|
||||||
|
} else {
|
||||||
|
snprintf(fileName, PATH_MAX, "%s%s", path, tmp);
|
||||||
|
}
|
||||||
|
if (s3GetObjectToFile(object, fileName) != 0) {
|
||||||
|
taosArrayDestroyEx(objectArray, s3FreeObjectKey);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
taosArrayDestroyEx(objectArray, s3FreeObjectKey);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
long s3Size(const char *object_name) {
|
long s3Size(const char *object_name) {
|
||||||
long size = 0;
|
long size = 0;
|
||||||
int status = 0;
|
int status = 0;
|
||||||
|
@ -800,7 +878,7 @@ long s3Size(const char *object_name) {
|
||||||
} while (S3_status_is_retryable(cbd.status) && should_retry());
|
} while (S3_status_is_retryable(cbd.status) && should_retry());
|
||||||
|
|
||||||
if ((cbd.status != S3StatusOK) && (cbd.status != S3StatusErrorPreconditionFailed)) {
|
if ((cbd.status != S3StatusOK) && (cbd.status != S3StatusErrorPreconditionFailed)) {
|
||||||
vError("%s: %d(%s)", __func__, cbd.status, cbd.err_msg);
|
uError("%s: %d(%s)", __func__, cbd.status, cbd.err_msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
size = cbd.content_length;
|
size = cbd.content_length;
|
||||||
|
@ -1261,5 +1339,6 @@ int32_t s3GetObjectBlock(const char *object_name, int64_t offset, int64_t size,
|
||||||
}
|
}
|
||||||
void s3EvictCache(const char *path, long object_size) {}
|
void s3EvictCache(const char *path, long object_size) {}
|
||||||
long s3Size(const char *object_name) { return 0; }
|
long s3Size(const char *object_name) { return 0; }
|
||||||
|
int32_t s3GetObjectsByPrefix(const char *prefix, const char *path) { return 0; }
|
||||||
|
|
||||||
#endif
|
#endif
|
|
@ -0,0 +1,235 @@
|
||||||
|
//
|
||||||
|
// Created by mingming wanng on 2023/11/2.
|
||||||
|
//
|
||||||
|
#include "rsync.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "tglobal.h"
|
||||||
|
|
||||||
|
#define ERRNO_ERR_FORMAT "errno:%d,msg:%s"
|
||||||
|
#define ERRNO_ERR_DATA errno,strerror(errno)
|
||||||
|
|
||||||
|
// deleteRsync function produce empty directories, traverse base directory to remove them
|
||||||
|
static void removeEmptyDir(){
|
||||||
|
TdDirPtr pDir = taosOpenDir(tsCheckpointBackupDir);
|
||||||
|
if (pDir == NULL) return;
|
||||||
|
|
||||||
|
TdDirEntryPtr de = NULL;
|
||||||
|
while ((de = taosReadDir(pDir)) != NULL) {
|
||||||
|
if (!taosDirEntryIsDir(de)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcmp(taosGetDirEntryName(de), ".") == 0 || strcmp(taosGetDirEntryName(de), "..") == 0) continue;
|
||||||
|
|
||||||
|
char filename[PATH_MAX] = {0};
|
||||||
|
snprintf(filename, sizeof(filename), "%s%s", tsCheckpointBackupDir, taosGetDirEntryName(de));
|
||||||
|
|
||||||
|
TdDirPtr pDirTmp = taosOpenDir(filename);
|
||||||
|
TdDirEntryPtr deTmp = NULL;
|
||||||
|
bool empty = true;
|
||||||
|
while ((deTmp = taosReadDir(pDirTmp)) != NULL){
|
||||||
|
if (strcmp(taosGetDirEntryName(deTmp), ".") == 0 || strcmp(taosGetDirEntryName(deTmp), "..") == 0) continue;
|
||||||
|
empty = false;
|
||||||
|
}
|
||||||
|
if(empty) taosRemoveDir(filename);
|
||||||
|
taosCloseDir(&pDirTmp);
|
||||||
|
}
|
||||||
|
|
||||||
|
taosCloseDir(&pDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef WINDOWS
|
||||||
|
// C:\TDengine\data\backup\checkpoint\ -> /c/TDengine/data/backup/checkpoint/
|
||||||
|
static void changeDirFromWindowsToLinux(char* from, char* to){
|
||||||
|
to[0] = '/';
|
||||||
|
to[1] = from[0];
|
||||||
|
for(int i = 2; i < strlen(from); i++) {
|
||||||
|
if (from[i] == '\\') {
|
||||||
|
to[i] = '/';
|
||||||
|
} else {
|
||||||
|
to[i] = from[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int generateConfigFile(char* confDir){
|
||||||
|
TdFilePtr pFile = taosOpenFile(confDir, TD_FILE_CREATE | TD_FILE_WRITE | TD_FILE_TRUNC);
|
||||||
|
if (pFile == NULL) {
|
||||||
|
uError("[rsync] open conf file error, dir:%s,"ERRNO_ERR_FORMAT, confDir, ERRNO_ERR_DATA);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef WINDOWS
|
||||||
|
char path[PATH_MAX] = {0};
|
||||||
|
changeDirFromWindowsToLinux(tsCheckpointBackupDir, path);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
char confContent[PATH_MAX*4] = {0};
|
||||||
|
snprintf(confContent, PATH_MAX*4,
|
||||||
|
#ifndef WINDOWS
|
||||||
|
"uid = root\n"
|
||||||
|
"gid = root\n"
|
||||||
|
#endif
|
||||||
|
"use chroot = false\n"
|
||||||
|
"max connections = 200\n"
|
||||||
|
"timeout = 100\n"
|
||||||
|
"lock file = %srsync.lock\n"
|
||||||
|
"log file = %srsync.log\n"
|
||||||
|
"ignore errors = true\n"
|
||||||
|
"read only = false\n"
|
||||||
|
"list = false\n"
|
||||||
|
"[checkpoint]\n"
|
||||||
|
"path = %s", tsCheckpointBackupDir, tsCheckpointBackupDir,
|
||||||
|
#ifdef WINDOWS
|
||||||
|
path
|
||||||
|
#else
|
||||||
|
tsCheckpointBackupDir
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
uDebug("[rsync] conf:%s", confContent);
|
||||||
|
if (taosWriteFile(pFile, confContent, strlen(confContent)) <= 0){
|
||||||
|
uError("[rsync] write conf file error,"ERRNO_ERR_FORMAT, ERRNO_ERR_DATA);
|
||||||
|
taosCloseFile(&pFile);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
taosCloseFile(&pFile);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int execCommand(char* command){
|
||||||
|
int try = 3;
|
||||||
|
int32_t code = 0;
|
||||||
|
while(try-- > 0) {
|
||||||
|
code = system(command);
|
||||||
|
if (code == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
taosMsleep(10);
|
||||||
|
}
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
void stopRsync(){
|
||||||
|
int code =
|
||||||
|
#ifdef WINDOWS
|
||||||
|
system("taskkill /f /im rsync.exe");
|
||||||
|
#else
|
||||||
|
system("pkill rsync");
|
||||||
|
#endif
|
||||||
|
if(code != 0){
|
||||||
|
uError("[rsync] stop rsync server failed,"ERRNO_ERR_FORMAT, ERRNO_ERR_DATA);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uDebug("[rsync] stop rsync server successful");
|
||||||
|
}
|
||||||
|
|
||||||
|
void startRsync(){
|
||||||
|
if(taosMulMkDir(tsCheckpointBackupDir) != 0){
|
||||||
|
uError("[rsync] build checkpoint backup dir failed, dir:%s,"ERRNO_ERR_FORMAT, tsCheckpointBackupDir, ERRNO_ERR_DATA);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
removeEmptyDir();
|
||||||
|
|
||||||
|
char confDir[PATH_MAX] = {0};
|
||||||
|
snprintf(confDir, PATH_MAX, "%srsync.conf", tsCheckpointBackupDir);
|
||||||
|
|
||||||
|
int code = generateConfigFile(confDir);
|
||||||
|
if(code != 0){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
char cmd[PATH_MAX] = {0};
|
||||||
|
snprintf(cmd, PATH_MAX, "rsync --daemon --port=%d --config=%s", tsRsyncPort, confDir);
|
||||||
|
// start rsync service to backup checkpoint
|
||||||
|
code = system(cmd);
|
||||||
|
if(code != 0){
|
||||||
|
uError("[rsync] start server failed, code:%d,"ERRNO_ERR_FORMAT, code, ERRNO_ERR_DATA);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uDebug("[rsync] start server successful");
|
||||||
|
}
|
||||||
|
|
||||||
|
int uploadRsync(char* id, char* path){
|
||||||
|
#ifdef WINDOWS
|
||||||
|
char pathTransform[PATH_MAX] = {0};
|
||||||
|
changeDirFromWindowsToLinux(path, pathTransform);
|
||||||
|
#endif
|
||||||
|
char command[PATH_MAX] = {0};
|
||||||
|
#ifdef WINDOWS
|
||||||
|
if(pathTransform[strlen(pathTransform) - 1] != '/'){
|
||||||
|
#else
|
||||||
|
if(path[strlen(path) - 1] != '/'){
|
||||||
|
#endif
|
||||||
|
snprintf(command, PATH_MAX, "rsync -av --delete --timeout=10 --bwlimit=100000 %s/ rsync://%s/checkpoint/%s/",
|
||||||
|
#ifdef WINDOWS
|
||||||
|
pathTransform
|
||||||
|
#else
|
||||||
|
path
|
||||||
|
#endif
|
||||||
|
, tsSnodeAddress, id);
|
||||||
|
}else{
|
||||||
|
snprintf(command, PATH_MAX, "rsync -av --delete --timeout=10 --bwlimit=100000 %s rsync://%s/checkpoint/%s/",
|
||||||
|
#ifdef WINDOWS
|
||||||
|
pathTransform
|
||||||
|
#else
|
||||||
|
path
|
||||||
|
#endif
|
||||||
|
, tsSnodeAddress, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
int code = execCommand(command);
|
||||||
|
if(code != 0){
|
||||||
|
uError("[rsync] send failed code:%d," ERRNO_ERR_FORMAT, code, ERRNO_ERR_DATA);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
uDebug("[rsync] upload data:%s successful", id);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int downloadRsync(char* id, char* path){
|
||||||
|
#ifdef WINDOWS
|
||||||
|
char pathTransform[PATH_MAX] = {0};
|
||||||
|
changeDirFromWindowsToLinux(path, pathTransform);
|
||||||
|
#endif
|
||||||
|
char command[PATH_MAX] = {0};
|
||||||
|
snprintf(command, PATH_MAX, "rsync -av --timeout=10 --bwlimit=100000 rsync://%s/checkpoint/%s/ %s",
|
||||||
|
tsSnodeAddress, id,
|
||||||
|
#ifdef WINDOWS
|
||||||
|
pathTransform
|
||||||
|
#else
|
||||||
|
path
|
||||||
|
#endif
|
||||||
|
);
|
||||||
|
|
||||||
|
int code = execCommand(command);
|
||||||
|
if(code != 0){
|
||||||
|
uError("[rsync] get failed code:%d," ERRNO_ERR_FORMAT, code, ERRNO_ERR_DATA);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
uDebug("[rsync] down data:%s successful", id);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int deleteRsync(char* id){
|
||||||
|
char* tmp = "./tmp_empty/";
|
||||||
|
int code = taosMkDir(tmp);
|
||||||
|
if(code != 0){
|
||||||
|
uError("[rsync] make tmp dir failed. code:%d," ERRNO_ERR_FORMAT, code, ERRNO_ERR_DATA);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
char command[PATH_MAX] = {0};
|
||||||
|
snprintf(command, PATH_MAX, "rsync -av --delete --timeout=10 %s rsync://%s/checkpoint/%s/",
|
||||||
|
tmp, tsSnodeAddress, id);
|
||||||
|
|
||||||
|
code = execCommand(command);
|
||||||
|
taosRemoveDir(tmp);
|
||||||
|
if(code != 0){
|
||||||
|
uError("[rsync] get failed code:%d," ERRNO_ERR_FORMAT, code, ERRNO_ERR_DATA);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
uDebug("[rsync] delete data:%s successful", id);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -127,6 +127,15 @@ char tsSmlAutoChildTableNameDelimiter[TSDB_TABLE_NAME_LEN] = "";
|
||||||
// bool tsSmlDataFormat = false;
|
// bool tsSmlDataFormat = false;
|
||||||
// int32_t tsSmlBatchSize = 10000;
|
// int32_t tsSmlBatchSize = 10000;
|
||||||
|
|
||||||
|
// checkpoint backup
|
||||||
|
char tsSnodeAddress[TSDB_FQDN_LEN] = {0};
|
||||||
|
int32_t tsRsyncPort = 873;
|
||||||
|
#ifdef WINDOWS
|
||||||
|
char tsCheckpointBackupDir[PATH_MAX] = "C:\\TDengine\\data\\backup\\checkpoint\\";
|
||||||
|
#else
|
||||||
|
char tsCheckpointBackupDir[PATH_MAX] = "/var/lib/taos/backup/checkpoint/";
|
||||||
|
#endif
|
||||||
|
|
||||||
// tmq
|
// tmq
|
||||||
int32_t tmqMaxTopicNum = 20;
|
int32_t tmqMaxTopicNum = 20;
|
||||||
// query
|
// query
|
||||||
|
@ -260,6 +269,7 @@ char tsS3AccessKeySecret[TSDB_FQDN_LEN] = "<accesskeysecrect>";
|
||||||
char tsS3BucketName[TSDB_FQDN_LEN] = "<bucketname>";
|
char tsS3BucketName[TSDB_FQDN_LEN] = "<bucketname>";
|
||||||
char tsS3AppId[TSDB_FQDN_LEN] = "<appid>";
|
char tsS3AppId[TSDB_FQDN_LEN] = "<appid>";
|
||||||
int8_t tsS3Enabled = false;
|
int8_t tsS3Enabled = false;
|
||||||
|
int8_t tsS3StreamEnabled = false;
|
||||||
|
|
||||||
int8_t tsS3Https = true;
|
int8_t tsS3Https = true;
|
||||||
char tsS3Hostname[TSDB_FQDN_LEN] = "<hostname>";
|
char tsS3Hostname[TSDB_FQDN_LEN] = "<hostname>";
|
||||||
|
@ -323,9 +333,10 @@ int32_t taosSetS3Cfg(SConfig *pCfg) {
|
||||||
tstrncpy(tsS3AppId, appid + 1, TSDB_FQDN_LEN);
|
tstrncpy(tsS3AppId, appid + 1, TSDB_FQDN_LEN);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (tsS3BucketName[0] != '<' && tsDiskCfgNum > 1) {
|
if (tsS3BucketName[0] != '<') {
|
||||||
#if defined(USE_COS) || defined(USE_S3)
|
#if defined(USE_COS) || defined(USE_S3)
|
||||||
tsS3Enabled = true;
|
if(tsDiskCfgNum > 1) tsS3Enabled = true;
|
||||||
|
tsS3StreamEnabled = true;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -665,6 +676,10 @@ static int32_t taosAddServerCfg(SConfig *pCfg) {
|
||||||
if (cfgAddString(pCfg, "telemetryServer", tsTelemServer, CFG_SCOPE_BOTH, CFG_DYN_BOTH) != 0) return -1;
|
if (cfgAddString(pCfg, "telemetryServer", tsTelemServer, CFG_SCOPE_BOTH, CFG_DYN_BOTH) != 0) return -1;
|
||||||
if (cfgAddInt32(pCfg, "telemetryPort", tsTelemPort, 1, 65056, CFG_SCOPE_BOTH, CFG_DYN_NONE) != 0) return -1;
|
if (cfgAddInt32(pCfg, "telemetryPort", tsTelemPort, 1, 65056, CFG_SCOPE_BOTH, CFG_DYN_NONE) != 0) return -1;
|
||||||
|
|
||||||
|
if (cfgAddInt32(pCfg, "rsyncPort", tsRsyncPort, 1, 65535, CFG_SCOPE_BOTH, CFG_DYN_SERVER) != 0) return -1;
|
||||||
|
if (cfgAddString(pCfg, "snodeAddress", tsSnodeAddress, CFG_SCOPE_SERVER, CFG_DYN_SERVER) != 0) return -1;
|
||||||
|
if (cfgAddString(pCfg, "checkpointBackupDir", tsCheckpointBackupDir, CFG_SCOPE_SERVER, CFG_DYN_SERVER) != 0) return -1;
|
||||||
|
|
||||||
if (cfgAddInt32(pCfg, "tmqMaxTopicNum", tmqMaxTopicNum, 1, 10000, CFG_SCOPE_SERVER, CFG_DYN_ENT_SERVER) != 0)
|
if (cfgAddInt32(pCfg, "tmqMaxTopicNum", tmqMaxTopicNum, 1, 10000, CFG_SCOPE_SERVER, CFG_DYN_ENT_SERVER) != 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
@ -1104,7 +1119,10 @@ static int32_t taosSetServerCfg(SConfig *pCfg) {
|
||||||
tsTtlChangeOnWrite = cfgGetItem(pCfg, "ttlChangeOnWrite")->bval;
|
tsTtlChangeOnWrite = cfgGetItem(pCfg, "ttlChangeOnWrite")->bval;
|
||||||
tsTtlFlushThreshold = cfgGetItem(pCfg, "ttlFlushThreshold")->i32;
|
tsTtlFlushThreshold = cfgGetItem(pCfg, "ttlFlushThreshold")->i32;
|
||||||
tsTelemInterval = cfgGetItem(pCfg, "telemetryInterval")->i32;
|
tsTelemInterval = cfgGetItem(pCfg, "telemetryInterval")->i32;
|
||||||
|
tsRsyncPort = cfgGetItem(pCfg, "rsyncPort")->i32;
|
||||||
tstrncpy(tsTelemServer, cfgGetItem(pCfg, "telemetryServer")->str, TSDB_FQDN_LEN);
|
tstrncpy(tsTelemServer, cfgGetItem(pCfg, "telemetryServer")->str, TSDB_FQDN_LEN);
|
||||||
|
tstrncpy(tsSnodeAddress, cfgGetItem(pCfg, "snodeAddress")->str, TSDB_FQDN_LEN);
|
||||||
|
tstrncpy(tsCheckpointBackupDir, cfgGetItem(pCfg, "checkpointBackupDir")->str, PATH_MAX);
|
||||||
tsTelemPort = (uint16_t)cfgGetItem(pCfg, "telemetryPort")->i32;
|
tsTelemPort = (uint16_t)cfgGetItem(pCfg, "telemetryPort")->i32;
|
||||||
|
|
||||||
tmqMaxTopicNum = cfgGetItem(pCfg, "tmqMaxTopicNum")->i32;
|
tmqMaxTopicNum = cfgGetItem(pCfg, "tmqMaxTopicNum")->i32;
|
||||||
|
@ -1281,7 +1299,7 @@ int32_t taosApplyLocalCfg(SConfig *pCfg, char *name) {
|
||||||
if (strcasecmp("keepColumnName", name) == 0) {
|
if (strcasecmp("keepColumnName", name) == 0) {
|
||||||
tsKeepColumnName = cfgGetItem(pCfg, "keepColumnName")->bval;
|
tsKeepColumnName = cfgGetItem(pCfg, "keepColumnName")->bval;
|
||||||
} else if (strcasecmp("keepAliveIdle", name) == 0) {
|
} else if (strcasecmp("keepAliveIdle", name) == 0) {
|
||||||
tsKeepAliveIdle = cfgGetItem(pCfg, "keepAliveIdle")->bval;
|
tsKeepAliveIdle = cfgGetItem(pCfg, "keepAliveIdle")->i32;
|
||||||
} else {
|
} else {
|
||||||
matchItem = false;
|
matchItem = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "rsync.h"
|
||||||
#include "executor.h"
|
#include "executor.h"
|
||||||
#include "sndInt.h"
|
#include "sndInt.h"
|
||||||
#include "tstream.h"
|
#include "tstream.h"
|
||||||
|
@ -122,6 +123,9 @@ SSnode *sndOpen(const char *path, const SSnodeOpt *pOption) {
|
||||||
goto FAIL;
|
goto FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stopRsync();
|
||||||
|
startRsync();
|
||||||
|
|
||||||
// todo fix it: send msg to mnode to rollback to an existed checkpoint
|
// todo fix it: send msg to mnode to rollback to an existed checkpoint
|
||||||
streamMetaInitForSnode(pSnode->pMeta);
|
streamMetaInitForSnode(pSnode->pMeta);
|
||||||
return pSnode;
|
return pSnode;
|
||||||
|
|
|
@ -8,7 +8,6 @@ set(
|
||||||
"src/vnd/vnodeCommit.c"
|
"src/vnd/vnodeCommit.c"
|
||||||
"src/vnd/vnodeQuery.c"
|
"src/vnd/vnodeQuery.c"
|
||||||
"src/vnd/vnodeModule.c"
|
"src/vnd/vnodeModule.c"
|
||||||
"src/vnd/vnodeCos.c"
|
|
||||||
"src/vnd/vnodeSvr.c"
|
"src/vnd/vnodeSvr.c"
|
||||||
"src/vnd/vnodeSync.c"
|
"src/vnd/vnodeSync.c"
|
||||||
"src/vnd/vnodeSnapshot.c"
|
"src/vnd/vnodeSnapshot.c"
|
||||||
|
@ -161,75 +160,6 @@ target_link_libraries(
|
||||||
PUBLIC index
|
PUBLIC index
|
||||||
)
|
)
|
||||||
|
|
||||||
if(${BUILD_S3})
|
|
||||||
|
|
||||||
if(${BUILD_WITH_S3})
|
|
||||||
target_include_directories(
|
|
||||||
vnode
|
|
||||||
|
|
||||||
PUBLIC "$ENV{HOME}/.cos-local.2/include"
|
|
||||||
)
|
|
||||||
|
|
||||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
|
|
||||||
set(CMAKE_PREFIX_PATH $ENV{HOME}/.cos-local.2)
|
|
||||||
find_library(S3_LIBRARY s3)
|
|
||||||
find_library(CURL_LIBRARY curl $ENV{HOME}/.cos-local.2/lib NO_DEFAULT_PATH)
|
|
||||||
find_library(XML2_LIBRARY xml2)
|
|
||||||
find_library(SSL_LIBRARY ssl $ENV{HOME}/.cos-local.2/lib $ENV{HOME}/.cos-local.2/lib64 NO_DEFAULT_PATH)
|
|
||||||
find_library(CRYPTO_LIBRARY crypto $ENV{HOME}/.cos-local.2/lib $ENV{HOME}/.cos-local.2/lib64 NO_DEFAULT_PATH)
|
|
||||||
target_link_libraries(
|
|
||||||
vnode
|
|
||||||
|
|
||||||
# s3
|
|
||||||
PUBLIC ${S3_LIBRARY}
|
|
||||||
PUBLIC ${CURL_LIBRARY}
|
|
||||||
PUBLIC ${SSL_LIBRARY}
|
|
||||||
PUBLIC ${CRYPTO_LIBRARY}
|
|
||||||
PUBLIC ${XML2_LIBRARY}
|
|
||||||
)
|
|
||||||
|
|
||||||
add_definitions(-DUSE_S3)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(${BUILD_WITH_COS})
|
|
||||||
|
|
||||||
set(CMAKE_FIND_LIBRARY_SUFFIXES ".a")
|
|
||||||
find_library(APR_LIBRARY apr-1 PATHS /usr/local/apr/lib/)
|
|
||||||
find_library(APR_UTIL_LIBRARY aprutil-1 PATHS /usr/local/apr/lib/)
|
|
||||||
find_library(MINIXML_LIBRARY mxml)
|
|
||||||
find_library(CURL_LIBRARY curl)
|
|
||||||
target_link_libraries(
|
|
||||||
vnode
|
|
||||||
|
|
||||||
# s3
|
|
||||||
PUBLIC cos_c_sdk_static
|
|
||||||
PUBLIC ${APR_UTIL_LIBRARY}
|
|
||||||
PUBLIC ${APR_LIBRARY}
|
|
||||||
PUBLIC ${MINIXML_LIBRARY}
|
|
||||||
PUBLIC ${CURL_LIBRARY}
|
|
||||||
)
|
|
||||||
|
|
||||||
# s3
|
|
||||||
FIND_PROGRAM(APR_CONFIG_BIN NAMES apr-config apr-1-config PATHS /usr/bin /usr/local/bin /usr/local/apr/bin/)
|
|
||||||
IF (APR_CONFIG_BIN)
|
|
||||||
EXECUTE_PROCESS(
|
|
||||||
COMMAND ${APR_CONFIG_BIN} --includedir
|
|
||||||
OUTPUT_VARIABLE APR_INCLUDE_DIR
|
|
||||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
|
||||||
)
|
|
||||||
ENDIF()
|
|
||||||
include_directories (${APR_INCLUDE_DIR})
|
|
||||||
target_include_directories(
|
|
||||||
vnode
|
|
||||||
PUBLIC "${TD_SOURCE_DIR}/contrib/cos-c-sdk-v5/cos_c_sdk"
|
|
||||||
PUBLIC "$ENV{HOME}/.cos-local.1/include"
|
|
||||||
)
|
|
||||||
|
|
||||||
add_definitions(-DUSE_COS)
|
|
||||||
endif(${BUILD_WITH_COS})
|
|
||||||
|
|
||||||
endif()
|
|
||||||
|
|
||||||
IF (TD_GRANT)
|
IF (TD_GRANT)
|
||||||
TARGET_LINK_LIBRARIES(vnode PUBLIC grant)
|
TARGET_LINK_LIBRARIES(vnode PUBLIC grant)
|
||||||
ENDIF ()
|
ENDIF ()
|
||||||
|
|
|
@ -43,9 +43,9 @@ extern "C" {
|
||||||
|
|
||||||
typedef struct STqOffsetStore STqOffsetStore;
|
typedef struct STqOffsetStore STqOffsetStore;
|
||||||
|
|
||||||
// tqPush
|
|
||||||
#define STREAM_EXEC_EXTRACT_DATA_IN_WAL_ID (-1)
|
#define STREAM_EXEC_EXTRACT_DATA_IN_WAL_ID (-1)
|
||||||
#define STREAM_EXEC_TASK_STATUS_CHECK_ID (-2)
|
#define STREAM_EXEC_START_ALL_TASKS_ID (-2)
|
||||||
|
#define STREAM_EXEC_RESTART_ALL_TASKS_ID (-3)
|
||||||
#define IS_OFFSET_RESET_TYPE(_t) ((_t) < 0)
|
#define IS_OFFSET_RESET_TYPE(_t) ((_t) < 0)
|
||||||
|
|
||||||
// tqExec
|
// tqExec
|
||||||
|
@ -156,9 +156,6 @@ char* tqOffsetBuildFName(const char* path, int32_t fVer);
|
||||||
int32_t tqOffsetRestoreFromFile(STqOffsetStore* pStore, const char* fname);
|
int32_t tqOffsetRestoreFromFile(STqOffsetStore* pStore, const char* fname);
|
||||||
|
|
||||||
// tqStream
|
// tqStream
|
||||||
int32_t tqExpandTask(STQ* pTq, SStreamTask* pTask, int64_t ver);
|
|
||||||
int32_t tqScanWal(STQ* pTq);
|
|
||||||
int32_t tqStartStreamTask(STQ* pTq);
|
|
||||||
int32_t tqResetStreamTaskStatus(STQ* pTq);
|
int32_t tqResetStreamTaskStatus(STQ* pTq);
|
||||||
int32_t tqStopStreamTasks(STQ* pTq);
|
int32_t tqStopStreamTasks(STQ* pTq);
|
||||||
|
|
||||||
|
|
|
@ -231,7 +231,12 @@ int32_t tqProcessTaskCheckPointSourceReq(STQ* pTq, SRpcMsg* pMsg, SRpcMsg* pRsp)
|
||||||
int32_t tqProcessTaskCheckpointReadyMsg(STQ* pTq, SRpcMsg* pMsg);
|
int32_t tqProcessTaskCheckpointReadyMsg(STQ* pTq, SRpcMsg* pMsg);
|
||||||
int32_t tqProcessTaskUpdateReq(STQ* pTq, SRpcMsg* pMsg);
|
int32_t tqProcessTaskUpdateReq(STQ* pTq, SRpcMsg* pMsg);
|
||||||
int32_t tqProcessTaskResetReq(STQ* pTq, SRpcMsg* pMsg);
|
int32_t tqProcessTaskResetReq(STQ* pTq, SRpcMsg* pMsg);
|
||||||
int32_t tqLaunchStreamTaskAsync(STQ* pTq);
|
|
||||||
|
int32_t tqStartStreamTaskAsync(STQ* pTq, bool restart);
|
||||||
|
int32_t tqRestartStreamTasks(STQ* pTq);
|
||||||
|
int32_t tqExpandTask(STQ* pTq, SStreamTask* pTask, int64_t ver);
|
||||||
|
int32_t tqScanWal(STQ* pTq);
|
||||||
|
int32_t tqStartStreamTasks(STQ* pTq);
|
||||||
|
|
||||||
int tqCommit(STQ*);
|
int tqCommit(STQ*);
|
||||||
int32_t tqUpdateTbUidList(STQ* pTq, const SArray* tbUidList, bool isAdd);
|
int32_t tqUpdateTbUidList(STQ* pTq, const SArray* tbUidList, bool isAdd);
|
||||||
|
|
|
@ -1064,7 +1064,7 @@ int32_t tqProcessTaskDeployReq(STQ* pTq, int64_t sversion, char* msg, int32_t ms
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void doStartStep2(SStreamTask* pTask, SStreamTask* pStreamTask, STQ* pTq) {
|
static void doStartFillhistoryStep2(SStreamTask* pTask, SStreamTask* pStreamTask, STQ* pTq) {
|
||||||
const char* id = pTask->id.idStr;
|
const char* id = pTask->id.idStr;
|
||||||
int64_t nextProcessedVer = pStreamTask->hTaskInfo.haltVer;
|
int64_t nextProcessedVer = pStreamTask->hTaskInfo.haltVer;
|
||||||
|
|
||||||
|
@ -1105,7 +1105,11 @@ static void doStartStep2(SStreamTask* pTask, SStreamTask* pStreamTask, STQ* pTq)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// this function should be executed by only one thread
|
static void ddxx() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// this function should be executed by only one thread, so we set an sentinel to protect this function
|
||||||
int32_t tqProcessTaskScanHistory(STQ* pTq, SRpcMsg* pMsg) {
|
int32_t tqProcessTaskScanHistory(STQ* pTq, SRpcMsg* pMsg) {
|
||||||
SStreamScanHistoryReq* pReq = (SStreamScanHistoryReq*)pMsg->pCont;
|
SStreamScanHistoryReq* pReq = (SStreamScanHistoryReq*)pMsg->pCont;
|
||||||
SStreamMeta* pMeta = pTq->pStreamMeta;
|
SStreamMeta* pMeta = pTq->pStreamMeta;
|
||||||
|
@ -1134,6 +1138,7 @@ int32_t tqProcessTaskScanHistory(STQ* pTq, SRpcMsg* pMsg) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// let's decide which step should be executed now
|
||||||
if (pTask->execInfo.step1Start == 0) {
|
if (pTask->execInfo.step1Start == 0) {
|
||||||
ASSERT(pTask->status.pauseAllowed == false);
|
ASSERT(pTask->status.pauseAllowed == false);
|
||||||
int64_t ts = taosGetTimestampMs();
|
int64_t ts = taosGetTimestampMs();
|
||||||
|
@ -1147,7 +1152,8 @@ int32_t tqProcessTaskScanHistory(STQ* pTq, SRpcMsg* pMsg) {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (pTask->execInfo.step2Start == 0) {
|
if (pTask->execInfo.step2Start == 0) {
|
||||||
tqDebug("s-task:%s resume from paused, original step1 startTs:%" PRId64, id, pTask->execInfo.step1Start);
|
tqDebug("s-task:%s continue exec scan-history(step1), original step1 startTs:%" PRId64 ", already elapsed:%.2fs",
|
||||||
|
id, pTask->execInfo.step1Start, pTask->execInfo.step1El);
|
||||||
} else {
|
} else {
|
||||||
tqDebug("s-task:%s already in step2, no need to scan-history data, step2 starTs:%"PRId64, id, pTask->execInfo.step2Start);
|
tqDebug("s-task:%s already in step2, no need to scan-history data, step2 starTs:%"PRId64, id, pTask->execInfo.step2Start);
|
||||||
atomic_store_32(&pTask->status.inScanHistorySentinel, 0);
|
atomic_store_32(&pTask->status.inScanHistorySentinel, 0);
|
||||||
|
@ -1167,20 +1173,37 @@ int32_t tqProcessTaskScanHistory(STQ* pTq, SRpcMsg* pMsg) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
streamScanHistoryData(pTask);
|
int64_t st = taosGetTimestampMs();
|
||||||
|
SScanhistoryDataInfo retInfo = streamScanHistoryData(pTask, st);
|
||||||
|
|
||||||
double el = (taosGetTimestampMs() - pTask->execInfo.step1Start) / 1000.0;
|
double el = (taosGetTimestampMs() - st) / 1000.0;
|
||||||
if (streamTaskGetStatus(pTask, NULL) == TASK_STATUS__PAUSE) {
|
pTask->execInfo.step1El += el;
|
||||||
|
|
||||||
|
if (retInfo.ret == TASK_SCANHISTORY_QUIT || retInfo.ret == TASK_SCANHISTORY_REXEC) {
|
||||||
int8_t status = streamTaskSetSchedStatusInactive(pTask);
|
int8_t status = streamTaskSetSchedStatusInactive(pTask);
|
||||||
tqDebug("s-task:%s is paused in the step1, elapsed time:%.2fs, sched-status:%d", pTask->id.idStr, el, status);
|
|
||||||
|
|
||||||
atomic_store_32(&pTask->status.inScanHistorySentinel, 0);
|
atomic_store_32(&pTask->status.inScanHistorySentinel, 0);
|
||||||
|
|
||||||
|
if (retInfo.ret == TASK_SCANHISTORY_REXEC) {
|
||||||
|
streamReExecScanHistoryFuture(pTask, retInfo.idleTime);
|
||||||
|
} else {
|
||||||
|
char* p = NULL;
|
||||||
|
ETaskStatus s = streamTaskGetStatus(pTask, &p);
|
||||||
|
|
||||||
|
if (s == TASK_STATUS__PAUSE) {
|
||||||
|
tqDebug("s-task:%s is paused in the step1, elapsed time:%.2fs total:%.2fs, sched-status:%d", pTask->id.idStr,
|
||||||
|
el, pTask->execInfo.step1El, status);
|
||||||
|
} else if (s == TASK_STATUS__STOP || s == TASK_STATUS__DROPPING) {
|
||||||
|
tqDebug("s-task:%s status:%p not continue scan-history data, total elapsed time:%.2fs quit", pTask->id.idStr, p,
|
||||||
|
pTask->execInfo.step1El);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
streamMetaReleaseTask(pMeta, pTask);
|
streamMetaReleaseTask(pMeta, pTask);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// the following procedure should be executed, no matter status is stop/pause or not
|
// the following procedure should be executed, no matter status is stop/pause or not
|
||||||
tqDebug("s-task:%s scan-history(step 1) ended, elapsed time:%.2fs", id, el);
|
tqDebug("s-task:%s scan-history(step 1) ended, elapsed time:%.2fs", id, pTask->execInfo.step1El);
|
||||||
|
|
||||||
if (pTask->info.fillHistory) {
|
if (pTask->info.fillHistory) {
|
||||||
SStreamTask* pStreamTask = NULL;
|
SStreamTask* pStreamTask = NULL;
|
||||||
|
@ -1203,21 +1226,18 @@ int32_t tqProcessTaskScanHistory(STQ* pTq, SRpcMsg* pMsg) {
|
||||||
|
|
||||||
code = streamTaskHandleEvent(pStreamTask->status.pSM, TASK_EVENT_HALT);
|
code = streamTaskHandleEvent(pStreamTask->status.pSM, TASK_EVENT_HALT);
|
||||||
if (code == TSDB_CODE_SUCCESS) {
|
if (code == TSDB_CODE_SUCCESS) {
|
||||||
doStartStep2(pTask, pStreamTask, pTq);
|
doStartFillhistoryStep2(pTask, pStreamTask, pTq);
|
||||||
} else {
|
} else {
|
||||||
tqError("s-task:%s failed to halt s-task:%s, not launch step2", id, pStreamTask->id.idStr);
|
tqError("s-task:%s failed to halt s-task:%s, not launch step2", id, pStreamTask->id.idStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
streamMetaReleaseTask(pMeta, pStreamTask);
|
streamMetaReleaseTask(pMeta, pStreamTask);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
STimeWindow* pWindow = &pTask->dataRange.window;
|
STimeWindow* pWindow = &pTask->dataRange.window;
|
||||||
ASSERT(HAS_RELATED_FILLHISTORY_TASK(pTask));
|
ASSERT(HAS_RELATED_FILLHISTORY_TASK(pTask));
|
||||||
|
|
||||||
// Not update the fill-history time window until the state transfer is completed if the related fill-history task
|
// Not update the fill-history time window until the state transfer is completed.
|
||||||
// exists.
|
tqDebug("s-task:%s scan-history in stream time window completed, start to handle data from WAL, startVer:%" PRId64
|
||||||
tqDebug(
|
|
||||||
"s-task:%s scan-history in stream time window completed, now start to handle data from WAL, startVer:%" PRId64
|
|
||||||
", window:%" PRId64 " - %" PRId64,
|
", window:%" PRId64 " - %" PRId64,
|
||||||
id, pTask->chkInfo.nextProcessVer, pWindow->skey, pWindow->ekey);
|
id, pTask->chkInfo.nextProcessVer, pWindow->skey, pWindow->ekey);
|
||||||
|
|
||||||
|
@ -1297,14 +1317,15 @@ int32_t tqProcessTaskRunReq(STQ* pTq, SRpcMsg* pMsg) {
|
||||||
int32_t taskId = pReq->taskId;
|
int32_t taskId = pReq->taskId;
|
||||||
int32_t vgId = TD_VID(pTq->pVnode);
|
int32_t vgId = TD_VID(pTq->pVnode);
|
||||||
|
|
||||||
if (taskId == STREAM_EXEC_TASK_STATUS_CHECK_ID) {
|
|
||||||
tqStartStreamTask(pTq);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (taskId == STREAM_EXEC_EXTRACT_DATA_IN_WAL_ID) { // all tasks are extracted submit data from the wal
|
if (taskId == STREAM_EXEC_EXTRACT_DATA_IN_WAL_ID) { // all tasks are extracted submit data from the wal
|
||||||
tqScanWal(pTq);
|
tqScanWal(pTq);
|
||||||
return 0;
|
return 0;
|
||||||
|
} else if (taskId == STREAM_EXEC_START_ALL_TASKS_ID) {
|
||||||
|
tqStartStreamTasks(pTq);
|
||||||
|
return 0;
|
||||||
|
} else if (taskId == STREAM_EXEC_RESTART_ALL_TASKS_ID) {
|
||||||
|
tqRestartStreamTasks(pTq);
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
SStreamTask* pTask = streamMetaAcquireTask(pTq->pStreamMeta, pReq->streamId, taskId);
|
SStreamTask* pTask = streamMetaAcquireTask(pTq->pStreamMeta, pReq->streamId, taskId);
|
||||||
|
@ -1492,6 +1513,7 @@ int32_t tqProcessTaskResumeImpl(STQ* pTq, SStreamTask* pTask, int64_t sversion,
|
||||||
streamSchedExec(pTask);
|
streamSchedExec(pTask);
|
||||||
}
|
}
|
||||||
} else if (status == TASK_STATUS__UNINIT) {
|
} else if (status == TASK_STATUS__UNINIT) {
|
||||||
|
// todo: fill-history task init ?
|
||||||
if (pTask->info.fillHistory == 0) {
|
if (pTask->info.fillHistory == 0) {
|
||||||
EStreamTaskEvent event = HAS_RELATED_FILLHISTORY_TASK(pTask) ? TASK_EVENT_INIT_STREAM_SCANHIST : TASK_EVENT_INIT;
|
EStreamTaskEvent event = HAS_RELATED_FILLHISTORY_TASK(pTask) ? TASK_EVENT_INIT_STREAM_SCANHIST : TASK_EVENT_INIT;
|
||||||
streamTaskHandleEvent(pTask->status.pSM, event);
|
streamTaskHandleEvent(pTask->status.pSM, event);
|
||||||
|
@ -1890,7 +1912,7 @@ int32_t tqProcessTaskUpdateReq(STQ* pTq, SRpcMsg* pMsg) {
|
||||||
int32_t numOfTasks = streamMetaGetNumOfTasks(pMeta);
|
int32_t numOfTasks = streamMetaGetNumOfTasks(pMeta);
|
||||||
int32_t updateTasks = taosHashGetSize(pMeta->updateInfo.pTasks);
|
int32_t updateTasks = taosHashGetSize(pMeta->updateInfo.pTasks);
|
||||||
|
|
||||||
pMeta->startInfo.startAllTasksFlag = 1;
|
pMeta->startInfo.tasksWillRestart = 1;
|
||||||
|
|
||||||
if (updateTasks < numOfTasks) {
|
if (updateTasks < numOfTasks) {
|
||||||
tqDebug("vgId:%d closed tasks:%d, unclosed:%d, all tasks will be started when nodeEp update completed", vgId,
|
tqDebug("vgId:%d closed tasks:%d, unclosed:%d, all tasks will be started when nodeEp update completed", vgId,
|
||||||
|
@ -1899,45 +1921,11 @@ int32_t tqProcessTaskUpdateReq(STQ* pTq, SRpcMsg* pMsg) {
|
||||||
} else {
|
} else {
|
||||||
if (!pTq->pVnode->restored) {
|
if (!pTq->pVnode->restored) {
|
||||||
tqDebug("vgId:%d vnode restore not completed, not restart the tasks, clear the start after nodeUpdate flag", vgId);
|
tqDebug("vgId:%d vnode restore not completed, not restart the tasks, clear the start after nodeUpdate flag", vgId);
|
||||||
pMeta->startInfo.startAllTasksFlag = 0;
|
pMeta->startInfo.tasksWillRestart = 0;
|
||||||
streamMetaWUnLock(pMeta);
|
streamMetaWUnLock(pMeta);
|
||||||
} else {
|
} else {
|
||||||
tqInfo("vgId:%d tasks are all updated and stopped, restart them", vgId);
|
|
||||||
terrno = 0;
|
|
||||||
|
|
||||||
streamMetaWUnLock(pMeta);
|
|
||||||
|
|
||||||
while (streamMetaTaskInTimer(pMeta)) {
|
|
||||||
tqDebug("vgId:%d some tasks in timer, wait for 100ms and recheck", pMeta->vgId);
|
|
||||||
taosMsleep(100);
|
|
||||||
}
|
|
||||||
|
|
||||||
streamMetaWLock(pMeta);
|
|
||||||
|
|
||||||
int32_t code = streamMetaReopen(pMeta);
|
|
||||||
if (code != 0) {
|
|
||||||
tqError("vgId:%d failed to reopen stream meta", vgId);
|
|
||||||
streamMetaWUnLock(pMeta);
|
|
||||||
taosArrayDestroy(req.pNodeList);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (streamMetaLoadAllTasks(pTq->pStreamMeta) < 0) {
|
|
||||||
tqError("vgId:%d failed to load stream tasks", vgId);
|
|
||||||
streamMetaWUnLock(pMeta);
|
|
||||||
taosArrayDestroy(req.pNodeList);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vnodeIsRoleLeader(pTq->pVnode) && !tsDisableStream) {
|
|
||||||
tqInfo("vgId:%d restart all stream tasks after all tasks being updated", vgId);
|
|
||||||
tqResetStreamTaskStatus(pTq);
|
|
||||||
tqLaunchStreamTaskAsync(pTq);
|
|
||||||
} else {
|
|
||||||
tqInfo("vgId:%d, follower node not start stream tasks", vgId);
|
|
||||||
}
|
|
||||||
|
|
||||||
streamMetaWUnLock(pMeta);
|
streamMetaWUnLock(pMeta);
|
||||||
|
tqStartStreamTaskAsync(pTq, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,8 @@
|
||||||
static int32_t doScanWalForAllTasks(SStreamMeta* pStreamMeta, bool* pScanIdle);
|
static int32_t doScanWalForAllTasks(SStreamMeta* pStreamMeta, bool* pScanIdle);
|
||||||
static int32_t setWalReaderStartOffset(SStreamTask* pTask, int32_t vgId);
|
static int32_t setWalReaderStartOffset(SStreamTask* pTask, int32_t vgId);
|
||||||
static bool handleFillhistoryScanComplete(SStreamTask* pTask, int64_t ver);
|
static bool handleFillhistoryScanComplete(SStreamTask* pTask, int64_t ver);
|
||||||
|
static bool taskReadyForDataFromWal(SStreamTask* pTask);
|
||||||
|
static bool doPutDataIntoInputQFromWal(SStreamTask* pTask, int64_t maxVer, int32_t* numOfItems);
|
||||||
|
|
||||||
// extract data blocks(submit/delete) from WAL, and add them into the input queue for all the sources tasks.
|
// extract data blocks(submit/delete) from WAL, and add them into the input queue for all the sources tasks.
|
||||||
int32_t tqScanWal(STQ* pTq) {
|
int32_t tqScanWal(STQ* pTq) {
|
||||||
|
@ -58,7 +60,7 @@ int32_t tqScanWal(STQ* pTq) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t tqStartStreamTask(STQ* pTq) {
|
int32_t tqStartStreamTasks(STQ* pTq) {
|
||||||
int32_t code = TSDB_CODE_SUCCESS;
|
int32_t code = TSDB_CODE_SUCCESS;
|
||||||
int32_t vgId = TD_VID(pTq->pVnode);
|
int32_t vgId = TD_VID(pTq->pVnode);
|
||||||
SStreamMeta* pMeta = pTq->pStreamMeta;
|
SStreamMeta* pMeta = pTq->pStreamMeta;
|
||||||
|
@ -73,6 +75,7 @@ int32_t tqStartStreamTask(STQ* pTq) {
|
||||||
streamMetaWLock(pMeta);
|
streamMetaWLock(pMeta);
|
||||||
pTaskList = taosArrayDup(pMeta->pTaskList, NULL);
|
pTaskList = taosArrayDup(pMeta->pTaskList, NULL);
|
||||||
taosHashClear(pMeta->startInfo.pReadyTaskSet);
|
taosHashClear(pMeta->startInfo.pReadyTaskSet);
|
||||||
|
taosHashClear(pMeta->startInfo.pFailedTaskSet);
|
||||||
pMeta->startInfo.startTs = taosGetTimestampMs();
|
pMeta->startInfo.startTs = taosGetTimestampMs();
|
||||||
streamMetaWUnLock(pMeta);
|
streamMetaWUnLock(pMeta);
|
||||||
|
|
||||||
|
@ -97,7 +100,7 @@ int32_t tqStartStreamTask(STQ* pTq) {
|
||||||
streamLaunchFillHistoryTask(pTask);
|
streamLaunchFillHistoryTask(pTask);
|
||||||
}
|
}
|
||||||
|
|
||||||
streamMetaUpdateTaskReadyInfo(pTask);
|
streamMetaUpdateTaskDownstreamStatus(pTask, pTask->execInfo.init, pTask->execInfo.start, true);
|
||||||
streamMetaReleaseTask(pMeta, pTask);
|
streamMetaReleaseTask(pMeta, pTask);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -115,7 +118,67 @@ int32_t tqStartStreamTask(STQ* pTq) {
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t tqLaunchStreamTaskAsync(STQ* pTq) {
|
int32_t tqRestartStreamTasks(STQ* pTq) {
|
||||||
|
SStreamMeta* pMeta = pTq->pStreamMeta;
|
||||||
|
int32_t vgId = pMeta->vgId;
|
||||||
|
int32_t code = 0;
|
||||||
|
int64_t st = taosGetTimestampMs();
|
||||||
|
|
||||||
|
while(1) {
|
||||||
|
int32_t startVal = atomic_val_compare_exchange_32(&pMeta->startInfo.taskStarting, 0, 1);
|
||||||
|
if (startVal == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
tqDebug("vgId:%d in start stream tasks procedure, wait for 500ms and recheck", vgId);
|
||||||
|
taosMsleep(500);
|
||||||
|
}
|
||||||
|
|
||||||
|
terrno = 0;
|
||||||
|
tqInfo("vgId:%d tasks are all updated and stopped, restart all tasks, triggered by transId:%d", vgId,
|
||||||
|
pMeta->updateInfo.transId);
|
||||||
|
|
||||||
|
while (streamMetaTaskInTimer(pMeta)) {
|
||||||
|
tqDebug("vgId:%d some tasks in timer, wait for 100ms and recheck", pMeta->vgId);
|
||||||
|
taosMsleep(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
streamMetaWLock(pMeta);
|
||||||
|
|
||||||
|
code = streamMetaReopen(pMeta);
|
||||||
|
if (code != TSDB_CODE_SUCCESS) {
|
||||||
|
tqError("vgId:%d failed to reopen stream meta", vgId);
|
||||||
|
streamMetaWUnLock(pMeta);
|
||||||
|
code = terrno;
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t el = taosGetTimestampMs() - st;
|
||||||
|
|
||||||
|
tqInfo("vgId:%d close&reload state elapsed time:%.3fms", vgId, el/1000.);
|
||||||
|
|
||||||
|
code = streamMetaLoadAllTasks(pTq->pStreamMeta);
|
||||||
|
if (code != TSDB_CODE_SUCCESS) {
|
||||||
|
tqError("vgId:%d failed to load stream tasks, code:%s", vgId, tstrerror(terrno));
|
||||||
|
streamMetaWUnLock(pMeta);
|
||||||
|
code = terrno;
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (vnodeIsRoleLeader(pTq->pVnode) && !tsDisableStream) {
|
||||||
|
tqInfo("vgId:%d restart all stream tasks after all tasks being updated", vgId);
|
||||||
|
tqResetStreamTaskStatus(pTq);
|
||||||
|
tqStartStreamTasks(pTq);
|
||||||
|
} else {
|
||||||
|
tqInfo("vgId:%d, follower node not start stream tasks", vgId);
|
||||||
|
}
|
||||||
|
|
||||||
|
streamMetaWUnLock(pMeta);
|
||||||
|
code = terrno;
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t tqStartStreamTaskAsync(STQ* pTq, bool restart) {
|
||||||
SStreamMeta* pMeta = pTq->pStreamMeta;
|
SStreamMeta* pMeta = pTq->pStreamMeta;
|
||||||
int32_t vgId = pMeta->vgId;
|
int32_t vgId = pMeta->vgId;
|
||||||
|
|
||||||
|
@ -132,10 +195,10 @@ int32_t tqLaunchStreamTaskAsync(STQ* pTq) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
tqDebug("vgId:%d check %d stream task(s) status async", vgId, numOfTasks);
|
tqDebug("vgId:%d start all %d stream task(s) async", vgId, numOfTasks);
|
||||||
pRunReq->head.vgId = vgId;
|
pRunReq->head.vgId = vgId;
|
||||||
pRunReq->streamId = 0;
|
pRunReq->streamId = 0;
|
||||||
pRunReq->taskId = STREAM_EXEC_TASK_STATUS_CHECK_ID;
|
pRunReq->taskId = restart? STREAM_EXEC_RESTART_ALL_TASKS_ID:STREAM_EXEC_START_ALL_TASKS_ID;
|
||||||
|
|
||||||
SRpcMsg msg = {.msgType = TDMT_STREAM_TASK_RUN, .pCont = pRunReq, .contLen = sizeof(SStreamTaskRunReq)};
|
SRpcMsg msg = {.msgType = TDMT_STREAM_TASK_RUN, .pCont = pRunReq, .contLen = sizeof(SStreamTaskRunReq)};
|
||||||
tmsgPutToQueue(&pTq->pVnode->msgCb, STREAM_QUEUE, &msg);
|
tmsgPutToQueue(&pTq->pVnode->msgCb, STREAM_QUEUE, &msg);
|
||||||
|
@ -320,14 +383,13 @@ bool handleFillhistoryScanComplete(SStreamTask* pTask, int64_t ver) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool taskReadyForDataFromWal(SStreamTask* pTask) {
|
bool taskReadyForDataFromWal(SStreamTask* pTask) {
|
||||||
// non-source or fill-history tasks don't need to response the WAL scan action.
|
// non-source or fill-history tasks don't need to response the WAL scan action.
|
||||||
if ((pTask->info.taskLevel != TASK_LEVEL__SOURCE) || (pTask->status.downstreamReady == 0)) {
|
if ((pTask->info.taskLevel != TASK_LEVEL__SOURCE) || (pTask->status.downstreamReady == 0)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// not in ready state, do not handle the data from wal
|
// not in ready state, do not handle the data from wal
|
||||||
// int32_t status = pTask->status.taskStatus;
|
|
||||||
char* p = NULL;
|
char* p = NULL;
|
||||||
int32_t status = streamTaskGetStatus(pTask, &p);
|
int32_t status = streamTaskGetStatus(pTask, &p);
|
||||||
if (streamTaskGetStatus(pTask, &p) != TASK_STATUS__READY) {
|
if (streamTaskGetStatus(pTask, &p) != TASK_STATUS__READY) {
|
||||||
|
@ -359,7 +421,7 @@ static bool taskReadyForDataFromWal(SStreamTask* pTask) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool doPutDataIntoInputQFromWal(SStreamTask* pTask, int64_t maxVer, int32_t* numOfItems) {
|
bool doPutDataIntoInputQFromWal(SStreamTask* pTask, int64_t maxVer, int32_t* numOfItems) {
|
||||||
const char* id = pTask->id.idStr;
|
const char* id = pTask->id.idStr;
|
||||||
int32_t numOfNewItems = 0;
|
int32_t numOfNewItems = 0;
|
||||||
|
|
||||||
|
@ -449,7 +511,6 @@ int32_t doScanWalForAllTasks(SStreamMeta* pStreamMeta, bool* pScanIdle) {
|
||||||
int64_t maxVer = (pTask->info.fillHistory == 1) ? pTask->dataRange.range.maxVer : INT64_MAX;
|
int64_t maxVer = (pTask->info.fillHistory == 1) ? pTask->dataRange.range.maxVer : INT64_MAX;
|
||||||
|
|
||||||
taosThreadMutexLock(&pTask->lock);
|
taosThreadMutexLock(&pTask->lock);
|
||||||
tqDebug("s-task:%s lock", pTask->id.idStr);
|
|
||||||
|
|
||||||
char* p = NULL;
|
char* p = NULL;
|
||||||
ETaskStatus status = streamTaskGetStatus(pTask, &p);
|
ETaskStatus status = streamTaskGetStatus(pTask, &p);
|
||||||
|
|
|
@ -12,11 +12,11 @@
|
||||||
* You should have received a copy of the GNU Affero General Public License
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
#include "cos.h"
|
||||||
#include "tsdb.h"
|
#include "tsdb.h"
|
||||||
#include "tsdbDataFileRW.h"
|
#include "tsdbDataFileRW.h"
|
||||||
#include "tsdbReadUtil.h"
|
#include "tsdbReadUtil.h"
|
||||||
#include "vnd.h"
|
#include "vnd.h"
|
||||||
#include "vndCos.h"
|
|
||||||
|
|
||||||
#define ROCKS_BATCH_SIZE (4096)
|
#define ROCKS_BATCH_SIZE (4096)
|
||||||
|
|
||||||
|
|
|
@ -28,13 +28,16 @@ static int32_t saveOneRow(SArray* pRow, SSDataBlock* pBlock, SCacheRowsReader* p
|
||||||
// bool allNullRow = true;
|
// bool allNullRow = true;
|
||||||
|
|
||||||
if (HASTYPE(pReader->type, CACHESCAN_RETRIEVE_LAST)) {
|
if (HASTYPE(pReader->type, CACHESCAN_RETRIEVE_LAST)) {
|
||||||
|
uint64_t ts = 0;
|
||||||
|
SFirstLastRes* p;
|
||||||
for (int32_t i = 0; i < pReader->numOfCols; ++i) {
|
for (int32_t i = 0; i < pReader->numOfCols; ++i) {
|
||||||
SColumnInfoData* pColInfoData = taosArrayGet(pBlock->pDataBlock, dstSlotIds[i]);
|
SColumnInfoData* pColInfoData = taosArrayGet(pBlock->pDataBlock, dstSlotIds[i]);
|
||||||
SFirstLastRes* p = (SFirstLastRes*)varDataVal(pRes[i]);
|
|
||||||
int32_t slotId = slotIds[i];
|
int32_t slotId = slotIds[i];
|
||||||
SLastCol* pColVal = (SLastCol*)taosArrayGet(pRow, i);
|
SLastCol* pColVal = (SLastCol*)taosArrayGet(pRow, i);
|
||||||
|
p = (SFirstLastRes*)varDataVal(pRes[i]);
|
||||||
|
|
||||||
p->ts = pColVal->ts;
|
p->ts = pColVal->ts;
|
||||||
|
ts = p->ts;
|
||||||
p->isNull = !COL_VAL_IS_VALUE(&pColVal->colVal);
|
p->isNull = !COL_VAL_IS_VALUE(&pColVal->colVal);
|
||||||
// allNullRow = p->isNull & allNullRow;
|
// allNullRow = p->isNull & allNullRow;
|
||||||
|
|
||||||
|
@ -55,6 +58,20 @@ static int32_t saveOneRow(SArray* pRow, SSDataBlock* pBlock, SCacheRowsReader* p
|
||||||
varDataSetLen(pRes[i], pColInfoData->info.bytes - VARSTR_HEADER_SIZE);
|
varDataSetLen(pRes[i], pColInfoData->info.bytes - VARSTR_HEADER_SIZE);
|
||||||
colDataSetVal(pColInfoData, numOfRows, (const char*)pRes[i], false);
|
colDataSetVal(pColInfoData, numOfRows, (const char*)pRes[i], false);
|
||||||
}
|
}
|
||||||
|
for (int32_t idx = 0; idx < taosArrayGetSize(pBlock->pDataBlock); ++idx) {
|
||||||
|
SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, idx);
|
||||||
|
if (pCol->info.colId == PRIMARYKEY_TIMESTAMP_COL_ID && pCol->info.type == TSDB_DATA_TYPE_TIMESTAMP) {
|
||||||
|
colDataSetVal(pCol, numOfRows, (const char*)&ts, false);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (pReader->numOfCols == 1 && dstSlotIds[0] != idx) {
|
||||||
|
if (!p->isNull) {
|
||||||
|
colDataSetVal(pCol, numOfRows, p->buf, false);
|
||||||
|
} else {
|
||||||
|
colDataSetNULL(pCol, numOfRows);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// pBlock->info.rows += allNullRow ? 0 : 1;
|
// pBlock->info.rows += allNullRow ? 0 : 1;
|
||||||
++pBlock->info.rows;
|
++pBlock->info.rows;
|
||||||
|
|
|
@ -14,9 +14,9 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "tsdbFS2.h"
|
#include "tsdbFS2.h"
|
||||||
|
#include "cos.h"
|
||||||
#include "tsdbUpgrade.h"
|
#include "tsdbUpgrade.h"
|
||||||
#include "vnd.h"
|
#include "vnd.h"
|
||||||
#include "vndCos.h"
|
|
||||||
|
|
||||||
#define BLOCK_COMMIT_FACTOR 3
|
#define BLOCK_COMMIT_FACTOR 3
|
||||||
|
|
||||||
|
|
|
@ -846,14 +846,14 @@ static void tLDataIterPinSttBlock(SLDataIter* pIter, const char* id) {
|
||||||
if (pInfo->blockData[0].sttBlockIndex == pIter->iSttBlk) {
|
if (pInfo->blockData[0].sttBlockIndex == pIter->iSttBlk) {
|
||||||
pInfo->blockData[0].pin = true;
|
pInfo->blockData[0].pin = true;
|
||||||
ASSERT(!pInfo->blockData[1].pin);
|
ASSERT(!pInfo->blockData[1].pin);
|
||||||
tsdbDebug("pin stt-block, blockIndex:%d, stt-fileVer:%" PRId64 " %s", pIter->iSttBlk, pIter->cid, id);
|
tsdbTrace("pin stt-block, blockIndex:%d, stt-fileVer:%" PRId64 " %s", pIter->iSttBlk, pIter->cid, id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pInfo->blockData[1].sttBlockIndex == pIter->iSttBlk) {
|
if (pInfo->blockData[1].sttBlockIndex == pIter->iSttBlk) {
|
||||||
pInfo->blockData[1].pin = true;
|
pInfo->blockData[1].pin = true;
|
||||||
ASSERT(!pInfo->blockData[0].pin);
|
ASSERT(!pInfo->blockData[0].pin);
|
||||||
tsdbDebug("pin stt-block, blockIndex:%d, stt-fileVer:%"PRId64" %s", pIter->iSttBlk, pIter->cid, id);
|
tsdbTrace("pin stt-block, blockIndex:%d, stt-fileVer:%"PRId64" %s", pIter->iSttBlk, pIter->cid, id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -565,9 +565,9 @@ static int32_t doLoadFileBlock(STsdbReader* pReader, SArray* pIndexList, SBlockN
|
||||||
|
|
||||||
STableBlockScanInfo* pScanInfo = getTableBlockScanInfo(pReader->status.pTableMap, uid, pReader->idStr);
|
STableBlockScanInfo* pScanInfo = getTableBlockScanInfo(pReader->status.pTableMap, uid, pReader->idStr);
|
||||||
if (ASCENDING_TRAVERSE(pReader->info.order)) {
|
if (ASCENDING_TRAVERSE(pReader->info.order)) {
|
||||||
w.skey = pScanInfo->lastKey + step;
|
w.skey = pScanInfo->lastProcKey + step;
|
||||||
} else {
|
} else {
|
||||||
w.ekey = pScanInfo->lastKey + step;
|
w.ekey = pScanInfo->lastProcKey + step;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isEmptyQueryTimeWindow(&w)) {
|
if (isEmptyQueryTimeWindow(&w)) {
|
||||||
|
@ -607,14 +607,14 @@ static int32_t doLoadFileBlock(STsdbReader* pReader, SArray* pIndexList, SBlockN
|
||||||
|
|
||||||
clearBrinBlockIter(&iter);
|
clearBrinBlockIter(&iter);
|
||||||
|
|
||||||
pBlockNum->numOfLastFiles = pReader->status.pCurrentFileset->lvlArr->size;
|
pBlockNum->numOfSttFiles = pReader->status.pCurrentFileset->lvlArr->size;
|
||||||
int32_t total = pBlockNum->numOfLastFiles + pBlockNum->numOfBlocks;
|
int32_t total = pBlockNum->numOfSttFiles + pBlockNum->numOfBlocks;
|
||||||
|
|
||||||
double el = (taosGetTimestampUs() - st) / 1000.0;
|
double el = (taosGetTimestampUs() - st) / 1000.0;
|
||||||
tsdbDebug(
|
tsdbDebug(
|
||||||
"load block of %d tables completed, blocks:%d in %d tables, last-files:%d, block-info-size:%.2f Kb, elapsed "
|
"load block of %d tables completed, blocks:%d in %d tables, last-files:%d, block-info-size:%.2f Kb, elapsed "
|
||||||
"time:%.2f ms %s",
|
"time:%.2f ms %s",
|
||||||
numOfTables, pBlockNum->numOfBlocks, (int32_t)taosArrayGetSize(pTableScanInfoList), pBlockNum->numOfLastFiles,
|
numOfTables, pBlockNum->numOfBlocks, (int32_t)taosArrayGetSize(pTableScanInfoList), pBlockNum->numOfSttFiles,
|
||||||
sizeInDisk / 1000.0, el, pReader->idStr);
|
sizeInDisk / 1000.0, el, pReader->idStr);
|
||||||
|
|
||||||
pReader->cost.numOfBlocks += total;
|
pReader->cost.numOfBlocks += total;
|
||||||
|
@ -1200,13 +1200,12 @@ static bool overlapWithNeighborBlock2(SFileDataBlockInfo* pBlock, SBrinRecord* p
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int64_t getBoarderKeyInFiles(SFileDataBlockInfo* pBlock, SLastBlockReader* pLastBlockReader, int32_t order) {
|
static int64_t getBoarderKeyInFiles(SFileDataBlockInfo* pBlock, STableBlockScanInfo* pScanInfo, int32_t order) {
|
||||||
bool ascScan = ASCENDING_TRAVERSE(order);
|
bool ascScan = ASCENDING_TRAVERSE(order);
|
||||||
bool bHasDataInLastBlock = hasDataInLastBlock(pLastBlockReader);
|
|
||||||
|
|
||||||
int64_t key = 0;
|
int64_t key = 0;
|
||||||
if (bHasDataInLastBlock) {
|
if (pScanInfo->sttKeyInfo.status == STT_FILE_HAS_DATA) {
|
||||||
int64_t keyInStt = getCurrentKeyInLastBlock(pLastBlockReader);
|
int64_t keyInStt = pScanInfo->sttKeyInfo.nextProcKey;
|
||||||
key = ascScan ? TMIN(pBlock->record.firstKey, keyInStt) : TMAX(pBlock->record.lastKey, keyInStt);
|
key = ascScan ? TMIN(pBlock->record.firstKey, keyInStt) : TMAX(pBlock->record.lastKey, keyInStt);
|
||||||
} else {
|
} else {
|
||||||
key = ascScan ? pBlock->record.firstKey : pBlock->record.lastKey;
|
key = ascScan ? pBlock->record.firstKey : pBlock->record.lastKey;
|
||||||
|
@ -1215,10 +1214,10 @@ static int64_t getBoarderKeyInFiles(SFileDataBlockInfo* pBlock, SLastBlockReader
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool bufferDataInFileBlockGap(TSDBKEY keyInBuf, SFileDataBlockInfo* pBlock,
|
static bool bufferDataInFileBlockGap(TSDBKEY keyInBuf, SFileDataBlockInfo* pBlock, STableBlockScanInfo* pScanInfo,
|
||||||
SLastBlockReader* pLastBlockReader, int32_t order) {
|
int32_t order) {
|
||||||
bool ascScan = ASCENDING_TRAVERSE(order);
|
bool ascScan = ASCENDING_TRAVERSE(order);
|
||||||
int64_t key = getBoarderKeyInFiles(pBlock, pLastBlockReader, order);
|
int64_t key = getBoarderKeyInFiles(pBlock, pScanInfo, order);
|
||||||
|
|
||||||
return (ascScan && (keyInBuf.ts != TSKEY_INITIAL_VAL && keyInBuf.ts < key)) ||
|
return (ascScan && (keyInBuf.ts != TSKEY_INITIAL_VAL && keyInBuf.ts < key)) ||
|
||||||
(!ascScan && (keyInBuf.ts != TSKEY_INITIAL_VAL && keyInBuf.ts > key));
|
(!ascScan && (keyInBuf.ts != TSKEY_INITIAL_VAL && keyInBuf.ts > key));
|
||||||
|
@ -1302,10 +1301,9 @@ typedef struct {
|
||||||
} SDataBlockToLoadInfo;
|
} SDataBlockToLoadInfo;
|
||||||
|
|
||||||
static void getBlockToLoadInfo(SDataBlockToLoadInfo* pInfo, SFileDataBlockInfo* pBlockInfo,
|
static void getBlockToLoadInfo(SDataBlockToLoadInfo* pInfo, SFileDataBlockInfo* pBlockInfo,
|
||||||
STableBlockScanInfo* pScanInfo, TSDBKEY keyInBuf, SLastBlockReader* pLastBlockReader,
|
STableBlockScanInfo* pScanInfo, TSDBKEY keyInBuf, STsdbReader* pReader) {
|
||||||
STsdbReader* pReader) {
|
|
||||||
int32_t neighborIndex = 0;
|
|
||||||
SBrinRecord rec = {0};
|
SBrinRecord rec = {0};
|
||||||
|
int32_t neighborIndex = 0;
|
||||||
|
|
||||||
bool hasNeighbor = getNeighborBlockOfSameTable(&pReader->status.blockIter, pBlockInfo, pScanInfo, &neighborIndex,
|
bool hasNeighbor = getNeighborBlockOfSameTable(&pReader->status.blockIter, pBlockInfo, pScanInfo, &neighborIndex,
|
||||||
pReader->info.order, &rec);
|
pReader->info.order, &rec);
|
||||||
|
@ -1319,9 +1317,11 @@ static void getBlockToLoadInfo(SDataBlockToLoadInfo* pInfo, SFileDataBlockInfo*
|
||||||
pInfo->hasDupTs = (pBlockInfo->record.numRow > pBlockInfo->record.count) || (pBlockInfo->record.count <= 0);
|
pInfo->hasDupTs = (pBlockInfo->record.numRow > pBlockInfo->record.count) || (pBlockInfo->record.count <= 0);
|
||||||
pInfo->overlapWithDelInfo = overlapWithDelSkyline(pScanInfo, &pBlockInfo->record, pReader->info.order);
|
pInfo->overlapWithDelInfo = overlapWithDelSkyline(pScanInfo, &pBlockInfo->record, pReader->info.order);
|
||||||
|
|
||||||
if (hasDataInLastBlock(pLastBlockReader)) {
|
ASSERT(pScanInfo->sttKeyInfo.status != STT_FILE_READER_UNINIT);
|
||||||
int64_t tsLast = getCurrentKeyInLastBlock(pLastBlockReader);
|
if (pScanInfo->sttKeyInfo.status == STT_FILE_HAS_DATA) {
|
||||||
pInfo->overlapWithLastBlock = !(pBlockInfo->record.lastKey < tsLast || pBlockInfo->record.firstKey > tsLast);
|
int64_t nextProcKeyInStt = pScanInfo->sttKeyInfo.nextProcKey;
|
||||||
|
pInfo->overlapWithLastBlock =
|
||||||
|
!(pBlockInfo->record.lastKey < nextProcKeyInStt || pBlockInfo->record.firstKey > nextProcKeyInStt);
|
||||||
}
|
}
|
||||||
|
|
||||||
pInfo->moreThanCapcity = pBlockInfo->record.numRow > pReader->resBlockInfo.capacity;
|
pInfo->moreThanCapcity = pBlockInfo->record.numRow > pReader->resBlockInfo.capacity;
|
||||||
|
@ -1336,9 +1336,9 @@ static void getBlockToLoadInfo(SDataBlockToLoadInfo* pInfo, SFileDataBlockInfo*
|
||||||
// 5. delete info should not overlap with current block data
|
// 5. delete info should not overlap with current block data
|
||||||
// 6. current block should not contain the duplicated ts
|
// 6. current block should not contain the duplicated ts
|
||||||
static bool fileBlockShouldLoad(STsdbReader* pReader, SFileDataBlockInfo* pBlockInfo, STableBlockScanInfo* pScanInfo,
|
static bool fileBlockShouldLoad(STsdbReader* pReader, SFileDataBlockInfo* pBlockInfo, STableBlockScanInfo* pScanInfo,
|
||||||
TSDBKEY keyInBuf, SLastBlockReader* pLastBlockReader) {
|
TSDBKEY keyInBuf) {
|
||||||
SDataBlockToLoadInfo info = {0};
|
SDataBlockToLoadInfo info = {0};
|
||||||
getBlockToLoadInfo(&info, pBlockInfo, pScanInfo, keyInBuf, pLastBlockReader, pReader);
|
getBlockToLoadInfo(&info, pBlockInfo, pScanInfo, keyInBuf, pReader);
|
||||||
|
|
||||||
bool loadDataBlock =
|
bool loadDataBlock =
|
||||||
(info.overlapWithNeighborBlock || info.hasDupTs || info.partiallyRequired || info.overlapWithKeyInBuf ||
|
(info.overlapWithNeighborBlock || info.hasDupTs || info.partiallyRequired || info.overlapWithKeyInBuf ||
|
||||||
|
@ -1358,9 +1358,9 @@ static bool fileBlockShouldLoad(STsdbReader* pReader, SFileDataBlockInfo* pBlock
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool isCleanFileDataBlock(STsdbReader* pReader, SFileDataBlockInfo* pBlockInfo, STableBlockScanInfo* pScanInfo,
|
static bool isCleanFileDataBlock(STsdbReader* pReader, SFileDataBlockInfo* pBlockInfo, STableBlockScanInfo* pScanInfo,
|
||||||
TSDBKEY keyInBuf, SLastBlockReader* pLastBlockReader) {
|
TSDBKEY keyInBuf) {
|
||||||
SDataBlockToLoadInfo info = {0};
|
SDataBlockToLoadInfo info = {0};
|
||||||
getBlockToLoadInfo(&info, pBlockInfo, pScanInfo, keyInBuf, pLastBlockReader, pReader);
|
getBlockToLoadInfo(&info, pBlockInfo, pScanInfo, keyInBuf, pReader);
|
||||||
bool isCleanFileBlock = !(info.overlapWithNeighborBlock || info.hasDupTs || info.overlapWithKeyInBuf ||
|
bool isCleanFileBlock = !(info.overlapWithNeighborBlock || info.hasDupTs || info.overlapWithKeyInBuf ||
|
||||||
info.overlapWithDelInfo || info.overlapWithLastBlock);
|
info.overlapWithDelInfo || info.overlapWithLastBlock);
|
||||||
return isCleanFileBlock;
|
return isCleanFileBlock;
|
||||||
|
@ -1417,14 +1417,15 @@ static bool tryCopyDistinctRowFromFileBlock(STsdbReader* pReader, SBlockData* pB
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool nextRowFromLastBlocks(SLastBlockReader* pLastBlockReader, STableBlockScanInfo* pScanInfo,
|
static bool nextRowFromSttBlocks(SLastBlockReader* pLastBlockReader, STableBlockScanInfo* pScanInfo,
|
||||||
SVersionRange* pVerRange) {
|
SVersionRange* pVerRange) {
|
||||||
int32_t step = ASCENDING_TRAVERSE(pLastBlockReader->order) ? 1 : -1;
|
int32_t step = ASCENDING_TRAVERSE(pLastBlockReader->order) ? 1 : -1;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
bool hasVal = tMergeTreeNext(&pLastBlockReader->mergeTree);
|
bool hasVal = tMergeTreeNext(&pLastBlockReader->mergeTree);
|
||||||
if (!hasVal) { // the next value will be the accessed key in stt
|
if (!hasVal) { // the next value will be the accessed key in stt
|
||||||
pScanInfo->lastKeyInStt += step;
|
pScanInfo->sttKeyInfo.status = STT_FILE_NO_DATA;
|
||||||
|
pScanInfo->sttKeyInfo.nextProcKey += step;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1433,10 +1434,11 @@ static bool nextRowFromLastBlocks(SLastBlockReader* pLastBlockReader, STableBloc
|
||||||
int64_t ver = pRow->pBlockData->aVersion[pRow->iRow];
|
int64_t ver = pRow->pBlockData->aVersion[pRow->iRow];
|
||||||
|
|
||||||
pLastBlockReader->currentKey = key;
|
pLastBlockReader->currentKey = key;
|
||||||
pScanInfo->lastKeyInStt = key;
|
pScanInfo->sttKeyInfo.nextProcKey = key;
|
||||||
|
|
||||||
if (!hasBeenDropped(pScanInfo->delSkyline, &pScanInfo->sttBlockDelIndex, key, ver, pLastBlockReader->order,
|
if (!hasBeenDropped(pScanInfo->delSkyline, &pScanInfo->sttBlockDelIndex, key, ver, pLastBlockReader->order,
|
||||||
pVerRange)) {
|
pVerRange)) {
|
||||||
|
pScanInfo->sttKeyInfo.status = STT_FILE_HAS_DATA;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1457,7 +1459,7 @@ static bool tryCopyDistinctRowFromSttBlock(TSDBROW* fRow, SLastBlockReader* pLas
|
||||||
|
|
||||||
// avoid the fetch next row replace the referenced stt block in buffer
|
// avoid the fetch next row replace the referenced stt block in buffer
|
||||||
doPinSttBlock(pLastBlockReader);
|
doPinSttBlock(pLastBlockReader);
|
||||||
bool hasVal = nextRowFromLastBlocks(pLastBlockReader, pScanInfo, &pReader->info.verRange);
|
bool hasVal = nextRowFromSttBlocks(pLastBlockReader, pScanInfo, &pReader->info.verRange);
|
||||||
doUnpinSttBlock(pLastBlockReader);
|
doUnpinSttBlock(pLastBlockReader);
|
||||||
if (hasVal) {
|
if (hasVal) {
|
||||||
int64_t next1 = getCurrentKeyInLastBlock(pLastBlockReader);
|
int64_t next1 = getCurrentKeyInLastBlock(pLastBlockReader);
|
||||||
|
@ -1694,7 +1696,7 @@ static int32_t doMergeFileBlockAndLastBlock(SLastBlockReader* pLastBlockReader,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (copied) {
|
if (copied) {
|
||||||
pBlockScanInfo->lastKey = tsLastBlock;
|
pBlockScanInfo->lastProcKey = tsLastBlock;
|
||||||
return TSDB_CODE_SUCCESS;
|
return TSDB_CODE_SUCCESS;
|
||||||
} else {
|
} else {
|
||||||
code = tsdbRowMergerAdd(pMerger, &fRow, NULL);
|
code = tsdbRowMergerAdd(pMerger, &fRow, NULL);
|
||||||
|
@ -2062,9 +2064,9 @@ static int32_t initMemDataIterator(STableBlockScanInfo* pBlockScanInfo, STsdbRea
|
||||||
STbData* d = NULL;
|
STbData* d = NULL;
|
||||||
TSDBKEY startKey = {0};
|
TSDBKEY startKey = {0};
|
||||||
if (ASCENDING_TRAVERSE(pReader->info.order)) {
|
if (ASCENDING_TRAVERSE(pReader->info.order)) {
|
||||||
startKey = (TSDBKEY){.ts = pBlockScanInfo->lastKey + 1, .version = pReader->info.verRange.minVer};
|
startKey = (TSDBKEY){.ts = pBlockScanInfo->lastProcKey + 1, .version = pReader->info.verRange.minVer};
|
||||||
} else {
|
} else {
|
||||||
startKey = (TSDBKEY){.ts = pBlockScanInfo->lastKey - 1, .version = pReader->info.verRange.maxVer};
|
startKey = (TSDBKEY){.ts = pBlockScanInfo->lastProcKey - 1, .version = pReader->info.verRange.maxVer};
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t code =
|
int32_t code =
|
||||||
|
@ -2129,9 +2131,9 @@ static bool initLastBlockReader(SLastBlockReader* pLBlockReader, STableBlockScan
|
||||||
|
|
||||||
STimeWindow w = pLBlockReader->window;
|
STimeWindow w = pLBlockReader->window;
|
||||||
if (ASCENDING_TRAVERSE(pLBlockReader->order)) {
|
if (ASCENDING_TRAVERSE(pLBlockReader->order)) {
|
||||||
w.skey = pScanInfo->lastKeyInStt;
|
w.skey = pScanInfo->sttKeyInfo.nextProcKey;
|
||||||
} else {
|
} else {
|
||||||
w.ekey = pScanInfo->lastKeyInStt;
|
w.ekey = pScanInfo->sttKeyInfo.nextProcKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
int64_t st = taosGetTimestampUs();
|
int64_t st = taosGetTimestampUs();
|
||||||
|
@ -2164,7 +2166,7 @@ static bool initLastBlockReader(SLastBlockReader* pLBlockReader, STableBlockScan
|
||||||
initMemDataIterator(pScanInfo, pReader);
|
initMemDataIterator(pScanInfo, pReader);
|
||||||
initDelSkylineIterator(pScanInfo, pReader->info.order, &pReader->cost);
|
initDelSkylineIterator(pScanInfo, pReader->info.order, &pReader->cost);
|
||||||
|
|
||||||
code = nextRowFromLastBlocks(pLBlockReader, pScanInfo, &pReader->info.verRange);
|
code = nextRowFromSttBlocks(pLBlockReader, pScanInfo, &pReader->info.verRange);
|
||||||
|
|
||||||
int64_t el = taosGetTimestampUs() - st;
|
int64_t el = taosGetTimestampUs() - st;
|
||||||
pReader->cost.initLastBlockReader += (el / 1000.0);
|
pReader->cost.initLastBlockReader += (el / 1000.0);
|
||||||
|
@ -2209,7 +2211,7 @@ int32_t mergeRowsInFileBlocks(SBlockData* pBlockData, STableBlockScanInfo* pBloc
|
||||||
}
|
}
|
||||||
|
|
||||||
if (copied) {
|
if (copied) {
|
||||||
pBlockScanInfo->lastKey = key;
|
pBlockScanInfo->lastProcKey = key;
|
||||||
return TSDB_CODE_SUCCESS;
|
return TSDB_CODE_SUCCESS;
|
||||||
} else {
|
} else {
|
||||||
TSDBROW fRow = tsdbRowFromBlockData(pBlockData, pDumpInfo->rowIndex);
|
TSDBROW fRow = tsdbRowFromBlockData(pBlockData, pDumpInfo->rowIndex);
|
||||||
|
@ -2354,16 +2356,16 @@ static int32_t buildComposedDataBlock(STsdbReader* pReader) {
|
||||||
TSDBKEY keyInBuf = getCurrentKeyInBuf(pBlockScanInfo, pReader);
|
TSDBKEY keyInBuf = getCurrentKeyInBuf(pBlockScanInfo, pReader);
|
||||||
|
|
||||||
// it is a clean block, load it directly
|
// it is a clean block, load it directly
|
||||||
if (isCleanFileDataBlock(pReader, pBlockInfo, pBlockScanInfo, keyInBuf, pLastBlockReader) &&
|
int64_t cap = pReader->resBlockInfo.capacity;
|
||||||
(pRecord->numRow <= pReader->resBlockInfo.capacity)) {
|
if (isCleanFileDataBlock(pReader, pBlockInfo, pBlockScanInfo, keyInBuf) && (pRecord->numRow <= cap)) {
|
||||||
if (asc || (!hasDataInLastBlock(pLastBlockReader))) {
|
if (asc || (pBlockScanInfo->sttKeyInfo.status == STT_FILE_NO_DATA)) {
|
||||||
code = copyBlockDataToSDataBlock(pReader);
|
code = copyBlockDataToSDataBlock(pReader);
|
||||||
if (code) {
|
if (code) {
|
||||||
goto _end;
|
goto _end;
|
||||||
}
|
}
|
||||||
|
|
||||||
// record the last key value
|
// record the last key value
|
||||||
pBlockScanInfo->lastKey = asc ? pRecord->lastKey : pRecord->firstKey;
|
pBlockScanInfo->lastProcKey = asc ? pRecord->lastKey : pRecord->firstKey;
|
||||||
goto _end;
|
goto _end;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2378,6 +2380,7 @@ static int32_t buildComposedDataBlock(STsdbReader* pReader) {
|
||||||
}
|
}
|
||||||
|
|
||||||
SBlockData* pBlockData = &pReader->status.fileBlockData;
|
SBlockData* pBlockData = &pReader->status.fileBlockData;
|
||||||
|
initLastBlockReader(pLastBlockReader, pBlockScanInfo, pReader);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
bool hasBlockData = false;
|
bool hasBlockData = false;
|
||||||
|
@ -2527,7 +2530,7 @@ TSDBKEY getCurrentKeyInBuf(STableBlockScanInfo* pScanInfo, STsdbReader* pReader)
|
||||||
static int32_t moveToNextFile(STsdbReader* pReader, SBlockNumber* pBlockNum, SArray* pTableList) {
|
static int32_t moveToNextFile(STsdbReader* pReader, SBlockNumber* pBlockNum, SArray* pTableList) {
|
||||||
SReaderStatus* pStatus = &pReader->status;
|
SReaderStatus* pStatus = &pReader->status;
|
||||||
pBlockNum->numOfBlocks = 0;
|
pBlockNum->numOfBlocks = 0;
|
||||||
pBlockNum->numOfLastFiles = 0;
|
pBlockNum->numOfSttFiles = 0;
|
||||||
|
|
||||||
size_t numOfTables = tSimpleHashGetSize(pReader->status.pTableMap);
|
size_t numOfTables = tSimpleHashGetSize(pReader->status.pTableMap);
|
||||||
SArray* pIndexList = taosArrayInit(numOfTables, sizeof(SBrinBlk));
|
SArray* pIndexList = taosArrayInit(numOfTables, sizeof(SBrinBlk));
|
||||||
|
@ -2564,7 +2567,7 @@ static int32_t moveToNextFile(STsdbReader* pReader, SBlockNumber* pBlockNum, SAr
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pBlockNum->numOfBlocks + pBlockNum->numOfLastFiles > 0) {
|
if (pBlockNum->numOfBlocks + pBlockNum->numOfSttFiles > 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2684,11 +2687,13 @@ static int32_t doLoadLastBlockSequentially(STsdbReader* pReader) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool notOverlapWithSttFiles(SFileDataBlockInfo* pBlockInfo, SLastBlockReader* pLastBlockReader, bool asc) {
|
static bool notOverlapWithSttFiles(SFileDataBlockInfo* pBlockInfo, STableBlockScanInfo* pScanInfo, bool asc) {
|
||||||
if(!hasDataInLastBlock(pLastBlockReader)) {
|
ASSERT(pScanInfo->sttKeyInfo.status != STT_FILE_READER_UNINIT);
|
||||||
|
|
||||||
|
if(pScanInfo->sttKeyInfo.status == STT_FILE_NO_DATA) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
int64_t keyInStt = getCurrentKeyInLastBlock(pLastBlockReader);
|
int64_t keyInStt = pScanInfo->sttKeyInfo.nextProcKey;
|
||||||
return (asc && pBlockInfo->record.lastKey < keyInStt) || (!asc && pBlockInfo->record.firstKey > keyInStt);
|
return (asc && pBlockInfo->record.lastKey < keyInStt) || (!asc && pBlockInfo->record.firstKey > keyInStt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2717,10 +2722,12 @@ static int32_t doBuildDataBlock(STsdbReader* pReader) {
|
||||||
return terrno;
|
return terrno;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pScanInfo->sttKeyInfo.status == STT_FILE_READER_UNINIT) {
|
||||||
initLastBlockReader(pLastBlockReader, pScanInfo, pReader);
|
initLastBlockReader(pLastBlockReader, pScanInfo, pReader);
|
||||||
TSDBKEY keyInBuf = getCurrentKeyInBuf(pScanInfo, pReader);
|
}
|
||||||
|
|
||||||
if (fileBlockShouldLoad(pReader, pBlockInfo, pScanInfo, keyInBuf, pLastBlockReader)) {
|
TSDBKEY keyInBuf = getCurrentKeyInBuf(pScanInfo, pReader);
|
||||||
|
if (fileBlockShouldLoad(pReader, pBlockInfo, pScanInfo, keyInBuf)) {
|
||||||
code = doLoadFileBlockData(pReader, pBlockIter, &pStatus->fileBlockData, pScanInfo->uid);
|
code = doLoadFileBlockData(pReader, pBlockIter, &pStatus->fileBlockData, pScanInfo->uid);
|
||||||
if (code != TSDB_CODE_SUCCESS) {
|
if (code != TSDB_CODE_SUCCESS) {
|
||||||
return code;
|
return code;
|
||||||
|
@ -2728,13 +2735,13 @@ static int32_t doBuildDataBlock(STsdbReader* pReader) {
|
||||||
|
|
||||||
// build composed data block
|
// build composed data block
|
||||||
code = buildComposedDataBlock(pReader);
|
code = buildComposedDataBlock(pReader);
|
||||||
} else if (bufferDataInFileBlockGap(keyInBuf, pBlockInfo, pLastBlockReader, pReader->info.order)) {
|
} else if (bufferDataInFileBlockGap(keyInBuf, pBlockInfo, pScanInfo, pReader->info.order)) {
|
||||||
// data in memory that are earlier than current file block and stt blocks
|
// data in memory that are earlier than current file block and stt blocks
|
||||||
// rows in buffer should be less than the file block in asc, greater than file block in desc
|
// rows in buffer should be less than the file block in asc, greater than file block in desc
|
||||||
int64_t endKey = getBoarderKeyInFiles(pBlockInfo, pLastBlockReader, pReader->info.order);
|
int64_t endKey = getBoarderKeyInFiles(pBlockInfo, pScanInfo, pReader->info.order);
|
||||||
code = buildDataBlockFromBuf(pReader, pScanInfo, endKey);
|
code = buildDataBlockFromBuf(pReader, pScanInfo, endKey);
|
||||||
} else {
|
} else {
|
||||||
if (notOverlapWithSttFiles(pBlockInfo, pLastBlockReader, asc)) {
|
if (notOverlapWithSttFiles(pBlockInfo, pScanInfo, asc)) {
|
||||||
// whole block is required, return it directly
|
// whole block is required, return it directly
|
||||||
SDataBlockInfo* pInfo = &pReader->resBlockInfo.pResBlock->info;
|
SDataBlockInfo* pInfo = &pReader->resBlockInfo.pResBlock->info;
|
||||||
pInfo->rows = pBlockInfo->record.numRow;
|
pInfo->rows = pBlockInfo->record.numRow;
|
||||||
|
@ -2745,7 +2752,7 @@ static int32_t doBuildDataBlock(STsdbReader* pReader) {
|
||||||
setBlockAllDumped(&pStatus->fBlockDumpInfo, pBlockInfo->record.lastKey, pReader->info.order);
|
setBlockAllDumped(&pStatus->fBlockDumpInfo, pBlockInfo->record.lastKey, pReader->info.order);
|
||||||
|
|
||||||
// update the last key for the corresponding table
|
// update the last key for the corresponding table
|
||||||
pScanInfo->lastKey = asc ? pInfo->window.ekey : pInfo->window.skey;
|
pScanInfo->lastProcKey = asc ? pInfo->window.ekey : pInfo->window.skey;
|
||||||
tsdbDebug("%p uid:%" PRIu64
|
tsdbDebug("%p uid:%" PRIu64
|
||||||
" clean file block retrieved from file, global index:%d, "
|
" clean file block retrieved from file, global index:%d, "
|
||||||
"table index:%d, rows:%d, brange:%" PRId64 "-%" PRId64 ", %s",
|
"table index:%d, rows:%d, brange:%" PRId64 "-%" PRId64 ", %s",
|
||||||
|
@ -2760,8 +2767,13 @@ static int32_t doBuildDataBlock(STsdbReader* pReader) {
|
||||||
tsdbDebug("load data in last block firstly %s", pReader->idStr);
|
tsdbDebug("load data in last block firstly %s", pReader->idStr);
|
||||||
int64_t st = taosGetTimestampUs();
|
int64_t st = taosGetTimestampUs();
|
||||||
|
|
||||||
|
// let's load data from stt files
|
||||||
|
initLastBlockReader(pLastBlockReader, pScanInfo, pReader);
|
||||||
|
|
||||||
// no data in last block, no need to proceed.
|
// no data in last block, no need to proceed.
|
||||||
while (hasDataInLastBlock(pLastBlockReader)) {
|
while (hasDataInLastBlock(pLastBlockReader)) {
|
||||||
|
ASSERT(pScanInfo->sttKeyInfo.status == STT_FILE_HAS_DATA);
|
||||||
|
|
||||||
code = buildComposedDataBlockImpl(pReader, pScanInfo, &pReader->status.fileBlockData, pLastBlockReader);
|
code = buildComposedDataBlockImpl(pReader, pScanInfo, &pReader->status.fileBlockData, pLastBlockReader);
|
||||||
if (code != TSDB_CODE_SUCCESS) {
|
if (code != TSDB_CODE_SUCCESS) {
|
||||||
return code;
|
return code;
|
||||||
|
@ -2988,7 +3000,7 @@ static void initBlockDumpInfo(STsdbReader* pReader, SDataBlockIter* pBlockIter)
|
||||||
if (pBlockInfo) {
|
if (pBlockInfo) {
|
||||||
STableBlockScanInfo* pScanInfo = tSimpleHashGet(pBlockIter->pTableMap, &pBlockInfo->uid, sizeof(pBlockInfo->uid));
|
STableBlockScanInfo* pScanInfo = tSimpleHashGet(pBlockIter->pTableMap, &pBlockInfo->uid, sizeof(pBlockInfo->uid));
|
||||||
if (pScanInfo) {
|
if (pScanInfo) {
|
||||||
lastKey = pScanInfo->lastKey;
|
lastKey = pScanInfo->lastProcKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
pDumpInfo->totalRows = pBlockInfo->record.numRow;
|
pDumpInfo->totalRows = pBlockInfo->record.numRow;
|
||||||
|
@ -3013,7 +3025,7 @@ static int32_t initForFirstBlockInFile(STsdbReader* pReader, SDataBlockIter* pBl
|
||||||
}
|
}
|
||||||
|
|
||||||
// all data files are consumed, try data in buffer
|
// all data files are consumed, try data in buffer
|
||||||
if (num.numOfBlocks + num.numOfLastFiles == 0) {
|
if (num.numOfBlocks + num.numOfSttFiles == 0) {
|
||||||
pReader->status.loadFromFile = false;
|
pReader->status.loadFromFile = false;
|
||||||
taosArrayDestroy(pTableList);
|
taosArrayDestroy(pTableList);
|
||||||
return code;
|
return code;
|
||||||
|
@ -3458,15 +3470,15 @@ int32_t doMergeRowsInFileBlocks(SBlockData* pBlockData, STableBlockScanInfo* pSc
|
||||||
|
|
||||||
int32_t doMergeRowsInLastBlock(SLastBlockReader* pLastBlockReader, STableBlockScanInfo* pScanInfo, int64_t ts,
|
int32_t doMergeRowsInLastBlock(SLastBlockReader* pLastBlockReader, STableBlockScanInfo* pScanInfo, int64_t ts,
|
||||||
SRowMerger* pMerger, SVersionRange* pVerRange, const char* idStr) {
|
SRowMerger* pMerger, SVersionRange* pVerRange, const char* idStr) {
|
||||||
while (nextRowFromLastBlocks(pLastBlockReader, pScanInfo, pVerRange)) {
|
while (nextRowFromSttBlocks(pLastBlockReader, pScanInfo, pVerRange)) {
|
||||||
int64_t next1 = getCurrentKeyInLastBlock(pLastBlockReader);
|
int64_t next1 = getCurrentKeyInLastBlock(pLastBlockReader);
|
||||||
if (next1 == ts) {
|
if (next1 == ts) {
|
||||||
TSDBROW* pRow1 = tMergeTreeGetRow(&pLastBlockReader->mergeTree);
|
TSDBROW* pRow1 = tMergeTreeGetRow(&pLastBlockReader->mergeTree);
|
||||||
tsdbRowMergerAdd(pMerger, pRow1, NULL);
|
tsdbRowMergerAdd(pMerger, pRow1, NULL);
|
||||||
} else {
|
} else {
|
||||||
tsdbTrace("uid:%" PRIu64 " last del index:%d, del range:%d, lastKeyInStt:%" PRId64 ", %s", pScanInfo->uid,
|
tsdbTrace("uid:%" PRIu64 " last del index:%d, del range:%d, lastKeyInStt:%" PRId64 ", %s", pScanInfo->uid,
|
||||||
pScanInfo->sttBlockDelIndex, (int32_t)taosArrayGetSize(pScanInfo->delSkyline), pScanInfo->lastKeyInStt,
|
pScanInfo->sttBlockDelIndex, (int32_t)taosArrayGetSize(pScanInfo->delSkyline),
|
||||||
idStr);
|
pScanInfo->sttKeyInfo.nextProcKey, idStr);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3722,7 +3734,7 @@ int32_t doAppendRowFromTSRow(SSDataBlock* pBlock, STsdbReader* pReader, SRow* pT
|
||||||
|
|
||||||
pBlock->info.dataLoad = 1;
|
pBlock->info.dataLoad = 1;
|
||||||
pBlock->info.rows += 1;
|
pBlock->info.rows += 1;
|
||||||
pScanInfo->lastKey = pTSRow->ts;
|
pScanInfo->lastProcKey = pTSRow->ts;
|
||||||
return TSDB_CODE_SUCCESS;
|
return TSDB_CODE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3856,14 +3868,15 @@ int32_t tsdbSetTableList2(STsdbReader* pReader, const void* pTableList, int32_t
|
||||||
// todo extract method
|
// todo extract method
|
||||||
if (ASCENDING_TRAVERSE(pReader->info.order)) {
|
if (ASCENDING_TRAVERSE(pReader->info.order)) {
|
||||||
int64_t skey = pReader->info.window.skey;
|
int64_t skey = pReader->info.window.skey;
|
||||||
pInfo->lastKey = (skey > INT64_MIN) ? (skey - 1) : skey;
|
pInfo->lastProcKey = (skey > INT64_MIN) ? (skey - 1) : skey;
|
||||||
pInfo->lastKeyInStt = skey;
|
pInfo->sttKeyInfo.nextProcKey = skey;
|
||||||
} else {
|
} else {
|
||||||
int64_t ekey = pReader->info.window.ekey;
|
int64_t ekey = pReader->info.window.ekey;
|
||||||
pInfo->lastKey = (ekey < INT64_MAX) ? (ekey + 1) : ekey;
|
pInfo->lastProcKey = (ekey < INT64_MAX) ? (ekey + 1) : ekey;
|
||||||
pInfo->lastKeyInStt = ekey;
|
pInfo->sttKeyInfo.nextProcKey = ekey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pInfo->sttKeyInfo.status = STT_FILE_READER_UNINIT;
|
||||||
tSimpleHashPut(pReader->status.pTableMap, &pInfo->uid, sizeof(uint64_t), &pInfo, POINTER_BYTES);
|
tSimpleHashPut(pReader->status.pTableMap, &pInfo->uid, sizeof(uint64_t), &pInfo, POINTER_BYTES);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4224,7 +4237,7 @@ int32_t tsdbReaderSuspend2(STsdbReader* pReader) {
|
||||||
if (pBlockScanInfo) {
|
if (pBlockScanInfo) {
|
||||||
// save lastKey to restore memory iterator
|
// save lastKey to restore memory iterator
|
||||||
STimeWindow w = pReader->resBlockInfo.pResBlock->info.window;
|
STimeWindow w = pReader->resBlockInfo.pResBlock->info.window;
|
||||||
pBlockScanInfo->lastKey = ASCENDING_TRAVERSE(pReader->info.order) ? w.ekey : w.skey;
|
pBlockScanInfo->lastProcKey = ASCENDING_TRAVERSE(pReader->info.order) ? w.ekey : w.skey;
|
||||||
|
|
||||||
// reset current current table's data block scan info,
|
// reset current current table's data block scan info,
|
||||||
pBlockScanInfo->iterInit = false;
|
pBlockScanInfo->iterInit = false;
|
||||||
|
|
|
@ -157,17 +157,18 @@ SSHashObj* createDataBlockScanInfo(STsdbReader* pTsdbReader, SBlockInfoBuf* pBuf
|
||||||
|
|
||||||
if (ASCENDING_TRAVERSE(pTsdbReader->info.order)) {
|
if (ASCENDING_TRAVERSE(pTsdbReader->info.order)) {
|
||||||
int64_t skey = pTsdbReader->info.window.skey;
|
int64_t skey = pTsdbReader->info.window.skey;
|
||||||
pScanInfo->lastKey = (skey > INT64_MIN) ? (skey - 1) : skey;
|
pScanInfo->lastProcKey = (skey > INT64_MIN) ? (skey - 1) : skey;
|
||||||
pScanInfo->lastKeyInStt = skey;
|
pScanInfo->sttKeyInfo.nextProcKey = skey;
|
||||||
} else {
|
} else {
|
||||||
int64_t ekey = pTsdbReader->info.window.ekey;
|
int64_t ekey = pTsdbReader->info.window.ekey;
|
||||||
pScanInfo->lastKey = (ekey < INT64_MAX) ? (ekey + 1) : ekey;
|
pScanInfo->lastProcKey = (ekey < INT64_MAX) ? (ekey + 1) : ekey;
|
||||||
pScanInfo->lastKeyInStt = ekey;
|
pScanInfo->sttKeyInfo.nextProcKey = ekey;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pScanInfo->sttKeyInfo.status = STT_FILE_READER_UNINIT;
|
||||||
tSimpleHashPut(pTableMap, &pScanInfo->uid, sizeof(uint64_t), &pScanInfo, POINTER_BYTES);
|
tSimpleHashPut(pTableMap, &pScanInfo->uid, sizeof(uint64_t), &pScanInfo, POINTER_BYTES);
|
||||||
tsdbTrace("%p check table uid:%" PRId64 " from lastKey:%" PRId64 " %s", pTsdbReader, pScanInfo->uid,
|
tsdbTrace("%p check table uid:%" PRId64 " from lastKey:%" PRId64 " %s", pTsdbReader, pScanInfo->uid,
|
||||||
pScanInfo->lastKey, pTsdbReader->idStr);
|
pScanInfo->lastProcKey, pTsdbReader->idStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
taosSort(pUidList->tableUidList, numOfTables, sizeof(uint64_t), uidComparFunc);
|
taosSort(pUidList->tableUidList, numOfTables, sizeof(uint64_t), uidComparFunc);
|
||||||
|
@ -200,8 +201,8 @@ void resetAllDataBlockScanInfo(SSHashObj* pTableMap, int64_t ts, int32_t step) {
|
||||||
}
|
}
|
||||||
|
|
||||||
pInfo->delSkyline = taosArrayDestroy(pInfo->delSkyline);
|
pInfo->delSkyline = taosArrayDestroy(pInfo->delSkyline);
|
||||||
pInfo->lastKey = ts;
|
pInfo->lastProcKey = ts;
|
||||||
pInfo->lastKeyInStt = ts + step;
|
pInfo->sttKeyInfo.nextProcKey = ts + step;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -241,6 +242,7 @@ static void doCleanupInfoForNextFileset(STableBlockScanInfo* pScanInfo) {
|
||||||
taosArrayClear(pScanInfo->pBlockList);
|
taosArrayClear(pScanInfo->pBlockList);
|
||||||
taosArrayClear(pScanInfo->pBlockIdxList);
|
taosArrayClear(pScanInfo->pBlockIdxList);
|
||||||
taosArrayClear(pScanInfo->pFileDelData); // del data from each file set
|
taosArrayClear(pScanInfo->pFileDelData); // del data from each file set
|
||||||
|
pScanInfo->sttKeyInfo.status = STT_FILE_READER_UNINIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cleanupInfoFoxNextFileset(SSHashObj* pTableMap) {
|
void cleanupInfoFoxNextFileset(SSHashObj* pTableMap) {
|
||||||
|
|
|
@ -63,10 +63,21 @@ typedef struct STableDataBlockIdx {
|
||||||
int32_t globalIndex;
|
int32_t globalIndex;
|
||||||
} STableDataBlockIdx;
|
} STableDataBlockIdx;
|
||||||
|
|
||||||
|
typedef enum ESttKeyStatus {
|
||||||
|
STT_FILE_READER_UNINIT = 0x0,
|
||||||
|
STT_FILE_NO_DATA = 0x1,
|
||||||
|
STT_FILE_HAS_DATA = 0x2,
|
||||||
|
} ESttKeyStatus;
|
||||||
|
|
||||||
|
typedef struct SSttKeyInfo {
|
||||||
|
ESttKeyStatus status; // this value should be updated when switch to the next fileset
|
||||||
|
int64_t nextProcKey;
|
||||||
|
} SSttKeyInfo;
|
||||||
|
|
||||||
typedef struct STableBlockScanInfo {
|
typedef struct STableBlockScanInfo {
|
||||||
uint64_t uid;
|
uint64_t uid;
|
||||||
TSKEY lastKey;
|
TSKEY lastProcKey;
|
||||||
TSKEY lastKeyInStt; // last accessed key in stt
|
SSttKeyInfo sttKeyInfo;
|
||||||
SArray* pBlockList; // block data index list, SArray<SBrinRecord>
|
SArray* pBlockList; // block data index list, SArray<SBrinRecord>
|
||||||
SArray* pBlockIdxList; // SArray<STableDataBlockIndx>
|
SArray* pBlockIdxList; // SArray<STableDataBlockIndx>
|
||||||
SArray* pMemDelData; // SArray<SDelData>
|
SArray* pMemDelData; // SArray<SDelData>
|
||||||
|
@ -108,7 +119,7 @@ typedef struct STableUidList {
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
int32_t numOfBlocks;
|
int32_t numOfBlocks;
|
||||||
int32_t numOfLastFiles;
|
int32_t numOfSttFiles;
|
||||||
} SBlockNumber;
|
} SBlockNumber;
|
||||||
|
|
||||||
typedef struct SBlockIndex {
|
typedef struct SBlockIndex {
|
||||||
|
|
|
@ -13,8 +13,8 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "cos.h"
|
||||||
#include "tsdb.h"
|
#include "tsdb.h"
|
||||||
#include "vndCos.h"
|
|
||||||
|
|
||||||
static int32_t tsdbOpenFileImpl(STsdbFD *pFD) {
|
static int32_t tsdbOpenFileImpl(STsdbFD *pFD) {
|
||||||
int32_t code = 0;
|
int32_t code = 0;
|
||||||
|
|
|
@ -15,7 +15,8 @@
|
||||||
|
|
||||||
#include "tsdb.h"
|
#include "tsdb.h"
|
||||||
#include "tsdbFS2.h"
|
#include "tsdbFS2.h"
|
||||||
#include "vndCos.h"
|
#include "cos.h"
|
||||||
|
#include "vnd.h"
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
STsdb *tsdb;
|
STsdb *tsdb;
|
||||||
|
|
|
@ -13,8 +13,8 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "cos.h"
|
||||||
#include "tsdb.h"
|
#include "tsdb.h"
|
||||||
#include "vndCos.h"
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief max key by precision
|
* @brief max key by precision
|
||||||
|
|
|
@ -13,8 +13,8 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "cos.h"
|
||||||
#include "vnd.h"
|
#include "vnd.h"
|
||||||
#include "vndCos.h"
|
|
||||||
|
|
||||||
typedef struct SVnodeTask SVnodeTask;
|
typedef struct SVnodeTask SVnodeTask;
|
||||||
struct SVnodeTask {
|
struct SVnodeTask {
|
||||||
|
|
|
@ -13,10 +13,10 @@
|
||||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "cos.h"
|
||||||
#include "sync.h"
|
#include "sync.h"
|
||||||
#include "tsdb.h"
|
#include "tsdb.h"
|
||||||
#include "vnd.h"
|
#include "vnd.h"
|
||||||
#include "vndCos.h"
|
|
||||||
|
|
||||||
int32_t vnodeGetPrimaryDir(const char *relPath, int32_t diskPrimary, STfs *pTfs, char *buf, size_t bufLen) {
|
int32_t vnodeGetPrimaryDir(const char *relPath, int32_t diskPrimary, STfs *pTfs, char *buf, size_t bufLen) {
|
||||||
if (pTfs) {
|
if (pTfs) {
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
#include "tmsg.h"
|
#include "tmsg.h"
|
||||||
#include "tstrbuild.h"
|
#include "tstrbuild.h"
|
||||||
#include "vnd.h"
|
#include "vnd.h"
|
||||||
#include "vndCos.h"
|
#include "cos.h"
|
||||||
#include "vnode.h"
|
#include "vnode.h"
|
||||||
#include "vnodeInt.h"
|
#include "vnodeInt.h"
|
||||||
|
|
||||||
|
|
|
@ -557,7 +557,7 @@ static void vnodeRestoreFinish(const SSyncFSM *pFsm, const SyncIndex commitIdx)
|
||||||
SStreamMeta* pMeta = pVnode->pTq->pStreamMeta;
|
SStreamMeta* pMeta = pVnode->pTq->pStreamMeta;
|
||||||
streamMetaWLock(pMeta);
|
streamMetaWLock(pMeta);
|
||||||
|
|
||||||
if (pMeta->startInfo.startAllTasksFlag) {
|
if (pMeta->startInfo.tasksWillRestart) {
|
||||||
vInfo("vgId:%d, sync restore finished, stream tasks will be launched by other thread", vgId);
|
vInfo("vgId:%d, sync restore finished, stream tasks will be launched by other thread", vgId);
|
||||||
streamMetaWUnLock(pMeta);
|
streamMetaWUnLock(pMeta);
|
||||||
return;
|
return;
|
||||||
|
@ -570,7 +570,7 @@ static void vnodeRestoreFinish(const SSyncFSM *pFsm, const SyncIndex commitIdx)
|
||||||
} else {
|
} else {
|
||||||
vInfo("vgId:%d sync restore finished, start to launch stream tasks", pVnode->config.vgId);
|
vInfo("vgId:%d sync restore finished, start to launch stream tasks", pVnode->config.vgId);
|
||||||
tqResetStreamTaskStatus(pVnode->pTq);
|
tqResetStreamTaskStatus(pVnode->pTq);
|
||||||
tqLaunchStreamTaskAsync(pVnode->pTq);
|
tqStartStreamTaskAsync(pVnode->pTq, false);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
vInfo("vgId:%d, sync restore finished, not launch stream tasks since not leader", vgId);
|
vInfo("vgId:%d, sync restore finished, not launch stream tasks since not leader", vgId);
|
||||||
|
|
|
@ -40,7 +40,9 @@
|
||||||
#define GET_RES_WINDOW_KEY_LEN(_l) ((_l) + sizeof(uint64_t))
|
#define GET_RES_WINDOW_KEY_LEN(_l) ((_l) + sizeof(uint64_t))
|
||||||
|
|
||||||
typedef struct SGroupResInfo {
|
typedef struct SGroupResInfo {
|
||||||
int32_t index;
|
int32_t index; // rows consumed in func:doCopyToSDataBlockXX
|
||||||
|
int32_t iter; // relate to index-1, last consumed data's slot id in hash table
|
||||||
|
void* dataPos; // relate to index-1, last consumed data's position, in the nodelist of cur slot
|
||||||
SArray* pRows; // SArray<SResKeyPos>
|
SArray* pRows; // SArray<SResKeyPos>
|
||||||
char* pBuf;
|
char* pBuf;
|
||||||
bool freeItem;
|
bool freeItem;
|
||||||
|
|
|
@ -679,6 +679,12 @@ void initResultSizeInfo(SResultInfo* pResultInfo, int32_t numOfRows);
|
||||||
void doBuildResultDatablock(struct SOperatorInfo* pOperator, SOptrBasicInfo* pbInfo, SGroupResInfo* pGroupResInfo,
|
void doBuildResultDatablock(struct SOperatorInfo* pOperator, SOptrBasicInfo* pbInfo, SGroupResInfo* pGroupResInfo,
|
||||||
SDiskbasedBuf* pBuf);
|
SDiskbasedBuf* pBuf);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief copydata from hash table, instead of copying from SGroupResInfo's pRow
|
||||||
|
*/
|
||||||
|
int32_t doCopyToSDataBlockByHash(SExecTaskInfo* pTaskInfo, SSDataBlock* pBlock, SExprSupp* pSup, SDiskbasedBuf* pBuf,
|
||||||
|
SGroupResInfo* pGroupResInfo, SSHashObj* pHashmap, int32_t threshold, bool ignoreGroup);
|
||||||
|
|
||||||
bool hasLimitOffsetInfo(SLimitInfo* pLimitInfo);
|
bool hasLimitOffsetInfo(SLimitInfo* pLimitInfo);
|
||||||
bool hasSlimitOffsetInfo(SLimitInfo* pLimitInfo);
|
bool hasSlimitOffsetInfo(SLimitInfo* pLimitInfo);
|
||||||
void initLimitInfo(const SNode* pLimit, const SNode* pSLimit, SLimitInfo* pLimitInfo);
|
void initLimitInfo(const SNode* pLimit, const SNode* pSLimit, SLimitInfo* pLimitInfo);
|
||||||
|
|
|
@ -191,9 +191,9 @@ SSDataBlock* doScanCache(SOperatorInfo* pOperator) {
|
||||||
SSDataBlock* pRes = pInfo->pRes;
|
SSDataBlock* pRes = pInfo->pRes;
|
||||||
|
|
||||||
if (pInfo->indexOfBufferedRes < pInfo->pBufferredRes->info.rows) {
|
if (pInfo->indexOfBufferedRes < pInfo->pBufferredRes->info.rows) {
|
||||||
for (int32_t i = 0; i < taosArrayGetSize(pInfo->matchInfo.pList); ++i) {
|
for (int32_t i = 0; i < taosArrayGetSize(pInfo->pBufferredRes->pDataBlock); ++i) {
|
||||||
SColMatchItem* pMatchInfo = taosArrayGet(pInfo->matchInfo.pList, i);
|
SColumnInfoData* pCol = taosArrayGet(pInfo->pBufferredRes->pDataBlock, i);
|
||||||
int32_t slotId = pMatchInfo->dstSlotId;
|
int32_t slotId = pCol->info.slotId;
|
||||||
|
|
||||||
SColumnInfoData* pSrc = taosArrayGet(pInfo->pBufferredRes->pDataBlock, slotId);
|
SColumnInfoData* pSrc = taosArrayGet(pInfo->pBufferredRes->pDataBlock, slotId);
|
||||||
SColumnInfoData* pDst = taosArrayGet(pRes->pDataBlock, slotId);
|
SColumnInfoData* pDst = taosArrayGet(pRes->pDataBlock, slotId);
|
||||||
|
@ -201,10 +201,12 @@ SSDataBlock* doScanCache(SOperatorInfo* pOperator) {
|
||||||
if (colDataIsNull_s(pSrc, pInfo->indexOfBufferedRes)) {
|
if (colDataIsNull_s(pSrc, pInfo->indexOfBufferedRes)) {
|
||||||
colDataSetNULL(pDst, 0);
|
colDataSetNULL(pDst, 0);
|
||||||
} else {
|
} else {
|
||||||
|
if (pSrc->pData) {
|
||||||
char* p = colDataGetData(pSrc, pInfo->indexOfBufferedRes);
|
char* p = colDataGetData(pSrc, pInfo->indexOfBufferedRes);
|
||||||
colDataSetVal(pDst, 0, p, false);
|
colDataSetVal(pDst, 0, p, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pRes->info.id.uid = *(tb_uid_t*)taosArrayGet(pInfo->pUidList, pInfo->indexOfBufferedRes);
|
pRes->info.id.uid = *(tb_uid_t*)taosArrayGet(pInfo->pUidList, pInfo->indexOfBufferedRes);
|
||||||
pRes->info.rows = 1;
|
pRes->info.rows = 1;
|
||||||
|
|
|
@ -871,32 +871,6 @@ int32_t qGetExplainExecInfo(qTaskInfo_t tinfo, SArray* pExecInfoList) {
|
||||||
return getOperatorExplainExecInfo(pTaskInfo->pRoot, pExecInfoList);
|
return getOperatorExplainExecInfo(pTaskInfo->pRoot, pExecInfoList);
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t qSerializeTaskStatus(qTaskInfo_t tinfo, char** pOutput, int32_t* len) {
|
|
||||||
SExecTaskInfo* pTaskInfo = (struct SExecTaskInfo*)tinfo;
|
|
||||||
if (pTaskInfo->pRoot == NULL) {
|
|
||||||
return TSDB_CODE_INVALID_PARA;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t nOptrWithVal = 0;
|
|
||||||
// int32_t code = encodeOperator(pTaskInfo->pRoot, pOutput, len, &nOptrWithVal);
|
|
||||||
// if ((code == TSDB_CODE_SUCCESS) && (nOptrWithVal == 0)) {
|
|
||||||
// taosMemoryFreeClear(*pOutput);
|
|
||||||
// *len = 0;
|
|
||||||
// }
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t qDeserializeTaskStatus(qTaskInfo_t tinfo, const char* pInput, int32_t len) {
|
|
||||||
SExecTaskInfo* pTaskInfo = (struct SExecTaskInfo*)tinfo;
|
|
||||||
|
|
||||||
if (pTaskInfo == NULL || pInput == NULL || len == 0) {
|
|
||||||
return TSDB_CODE_INVALID_PARA;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
// return decodeOperator(pTaskInfo->pRoot, pInput, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t qExtractStreamScanner(qTaskInfo_t tinfo, void** scanner) {
|
int32_t qExtractStreamScanner(qTaskInfo_t tinfo, void** scanner) {
|
||||||
SExecTaskInfo* pTaskInfo = (SExecTaskInfo*)tinfo;
|
SExecTaskInfo* pTaskInfo = (SExecTaskInfo*)tinfo;
|
||||||
SOperatorInfo* pOperator = pTaskInfo->pRoot;
|
SOperatorInfo* pOperator = pTaskInfo->pRoot;
|
||||||
|
@ -1072,7 +1046,7 @@ int32_t qRestoreStreamOperatorOption(qTaskInfo_t tinfo) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool qStreamRecoverScanFinished(qTaskInfo_t tinfo) {
|
bool qStreamScanhistoryFinished(qTaskInfo_t tinfo) {
|
||||||
SExecTaskInfo* pTaskInfo = (SExecTaskInfo*)tinfo;
|
SExecTaskInfo* pTaskInfo = (SExecTaskInfo*)tinfo;
|
||||||
return pTaskInfo->streamInfo.recoverScanFinished;
|
return pTaskInfo->streamInfo.recoverScanFinished;
|
||||||
}
|
}
|
||||||
|
|
|
@ -655,6 +655,85 @@ int32_t finalizeResultRows(SDiskbasedBuf* pBuf, SResultRowPosition* resultRowPos
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int32_t doCopyToSDataBlockByHash(SExecTaskInfo* pTaskInfo, SSDataBlock* pBlock, SExprSupp* pSup, SDiskbasedBuf* pBuf,
|
||||||
|
SGroupResInfo* pGroupResInfo, SSHashObj* pHashmap, int32_t threshold,
|
||||||
|
bool ignoreGroup) {
|
||||||
|
SExprInfo* pExprInfo = pSup->pExprInfo;
|
||||||
|
int32_t numOfExprs = pSup->numOfExprs;
|
||||||
|
int32_t* rowEntryOffset = pSup->rowEntryInfoOffset;
|
||||||
|
SqlFunctionCtx* pCtx = pSup->pCtx;
|
||||||
|
|
||||||
|
size_t keyLen = 0;
|
||||||
|
int32_t numOfRows = tSimpleHashGetSize(pHashmap);
|
||||||
|
|
||||||
|
// begin from last iter
|
||||||
|
void* pData = pGroupResInfo->dataPos;
|
||||||
|
int32_t iter = pGroupResInfo->iter;
|
||||||
|
while ((pData = tSimpleHashIterate(pHashmap, pData, &iter)) != NULL) {
|
||||||
|
void* key = tSimpleHashGetKey(pData, &keyLen);
|
||||||
|
SResultRowPosition* pos = pData;
|
||||||
|
uint64_t groupId = *(uint64_t*)key;
|
||||||
|
|
||||||
|
SFilePage* page = getBufPage(pBuf, pos->pageId);
|
||||||
|
if (page == NULL) {
|
||||||
|
qError("failed to get buffer, code:%s, %s", tstrerror(terrno), GET_TASKID(pTaskInfo));
|
||||||
|
T_LONG_JMP(pTaskInfo->env, terrno);
|
||||||
|
}
|
||||||
|
|
||||||
|
SResultRow* pRow = (SResultRow*)((char*)page + pos->offset);
|
||||||
|
|
||||||
|
doUpdateNumOfRows(pCtx, pRow, numOfExprs, rowEntryOffset);
|
||||||
|
|
||||||
|
// no results, continue to check the next one
|
||||||
|
if (pRow->numOfRows == 0) {
|
||||||
|
pGroupResInfo->index += 1;
|
||||||
|
pGroupResInfo->iter = iter;
|
||||||
|
pGroupResInfo->dataPos = pData;
|
||||||
|
|
||||||
|
releaseBufPage(pBuf, page);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ignoreGroup) {
|
||||||
|
if (pBlock->info.id.groupId == 0) {
|
||||||
|
pBlock->info.id.groupId = groupId;
|
||||||
|
} else {
|
||||||
|
// current value belongs to different group, it can't be packed into one datablock
|
||||||
|
if (pBlock->info.id.groupId != groupId) {
|
||||||
|
releaseBufPage(pBuf, page);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pBlock->info.rows + pRow->numOfRows > pBlock->info.capacity) {
|
||||||
|
uint32_t newSize = pBlock->info.rows + pRow->numOfRows + ((numOfRows - iter) > 1 ? 1 : 0);
|
||||||
|
blockDataEnsureCapacity(pBlock, newSize);
|
||||||
|
qDebug("datablock capacity not sufficient, expand to required:%d, current capacity:%d, %s", newSize,
|
||||||
|
pBlock->info.capacity, GET_TASKID(pTaskInfo));
|
||||||
|
// todo set the pOperator->resultInfo size
|
||||||
|
}
|
||||||
|
|
||||||
|
pGroupResInfo->index += 1;
|
||||||
|
pGroupResInfo->iter = iter;
|
||||||
|
pGroupResInfo->dataPos = pData;
|
||||||
|
|
||||||
|
copyResultrowToDataBlock(pExprInfo, numOfExprs, pRow, pCtx, pBlock, rowEntryOffset, pTaskInfo);
|
||||||
|
|
||||||
|
releaseBufPage(pBuf, page);
|
||||||
|
pBlock->info.rows += pRow->numOfRows;
|
||||||
|
if (pBlock->info.rows >= threshold) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug("%s result generated, rows:%" PRId64 ", groupId:%" PRIu64, GET_TASKID(pTaskInfo), pBlock->info.rows,
|
||||||
|
pBlock->info.id.groupId);
|
||||||
|
pBlock->info.dataLoad = 1;
|
||||||
|
blockDataUpdateTsWindow(pBlock, 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int32_t doCopyToSDataBlock(SExecTaskInfo* pTaskInfo, SSDataBlock* pBlock, SExprSupp* pSup, SDiskbasedBuf* pBuf,
|
int32_t doCopyToSDataBlock(SExecTaskInfo* pTaskInfo, SSDataBlock* pBlock, SExprSupp* pSup, SDiskbasedBuf* pBuf,
|
||||||
SGroupResInfo* pGroupResInfo, int32_t threshold, bool ignoreGroup) {
|
SGroupResInfo* pGroupResInfo, int32_t threshold, bool ignoreGroup) {
|
||||||
SExprInfo* pExprInfo = pSup->pExprInfo;
|
SExprInfo* pExprInfo = pSup->pExprInfo;
|
||||||
|
|
|
@ -370,6 +370,72 @@ static SSDataBlock* buildGroupResultDataBlock(SOperatorInfo* pOperator) {
|
||||||
return (pRes->info.rows == 0) ? NULL : pRes;
|
return (pRes->info.rows == 0) ? NULL : pRes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool hasRemainResultByHash(SOperatorInfo* pOperator) {
|
||||||
|
SGroupbyOperatorInfo* pInfo = pOperator->info;
|
||||||
|
SSHashObj* pHashmap = pInfo->aggSup.pResultRowHashTable;
|
||||||
|
return pInfo->groupResInfo.index < tSimpleHashGetSize(pHashmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void doBuildResultDatablockByHash(SOperatorInfo* pOperator, SOptrBasicInfo* pbInfo, SGroupResInfo* pGroupResInfo,
|
||||||
|
SDiskbasedBuf* pBuf) {
|
||||||
|
SGroupbyOperatorInfo* pInfo = pOperator->info;
|
||||||
|
SSHashObj* pHashmap = pInfo->aggSup.pResultRowHashTable;
|
||||||
|
SExecTaskInfo* pTaskInfo = pOperator->pTaskInfo;
|
||||||
|
|
||||||
|
SSDataBlock* pBlock = pInfo->binfo.pRes;
|
||||||
|
|
||||||
|
// set output datablock version
|
||||||
|
pBlock->info.version = pTaskInfo->version;
|
||||||
|
|
||||||
|
blockDataCleanup(pBlock);
|
||||||
|
if (!hasRemainResultByHash(pOperator)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
pBlock->info.id.groupId = 0;
|
||||||
|
if (!pInfo->binfo.mergeResultBlock) {
|
||||||
|
doCopyToSDataBlockByHash(pTaskInfo, pBlock, &pOperator->exprSupp, pInfo->aggSup.pResultBuf, &pInfo->groupResInfo,
|
||||||
|
pHashmap, pOperator->resultInfo.threshold, false);
|
||||||
|
} else {
|
||||||
|
while (hasRemainResultByHash(pOperator)) {
|
||||||
|
doCopyToSDataBlockByHash(pTaskInfo, pBlock, &pOperator->exprSupp, pInfo->aggSup.pResultBuf, &pInfo->groupResInfo,
|
||||||
|
pHashmap, pOperator->resultInfo.threshold, true);
|
||||||
|
if (pBlock->info.rows >= pOperator->resultInfo.threshold) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pBlock->info.id.groupId = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear the group id info in SSDataBlock, since the client does not need it
|
||||||
|
pBlock->info.id.groupId = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static SSDataBlock* buildGroupResultDataBlockByHash(SOperatorInfo* pOperator) {
|
||||||
|
SGroupbyOperatorInfo* pInfo = pOperator->info;
|
||||||
|
SSDataBlock* pRes = pInfo->binfo.pRes;
|
||||||
|
|
||||||
|
// after filter, if result block turn to null, get next from whole set
|
||||||
|
while (1) {
|
||||||
|
doBuildResultDatablockByHash(pOperator, &pInfo->binfo, &pInfo->groupResInfo, pInfo->aggSup.pResultBuf);
|
||||||
|
|
||||||
|
doFilter(pRes, pOperator->exprSupp.pFilterInfo, NULL);
|
||||||
|
if (!hasRemainResultByHash(pOperator)) {
|
||||||
|
setOperatorCompleted(pOperator);
|
||||||
|
// clean hash after completed
|
||||||
|
tSimpleHashCleanup(pInfo->aggSup.pResultRowHashTable);
|
||||||
|
pInfo->aggSup.pResultRowHashTable = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (pRes->info.rows > 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pOperator->resultInfo.totalRows += pRes->info.rows;
|
||||||
|
return (pRes->info.rows == 0) ? NULL : pRes;
|
||||||
|
}
|
||||||
|
|
||||||
static SSDataBlock* hashGroupbyAggregate(SOperatorInfo* pOperator) {
|
static SSDataBlock* hashGroupbyAggregate(SOperatorInfo* pOperator) {
|
||||||
if (pOperator->status == OP_EXEC_DONE) {
|
if (pOperator->status == OP_EXEC_DONE) {
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -379,8 +445,9 @@ static SSDataBlock* hashGroupbyAggregate(SOperatorInfo* pOperator) {
|
||||||
|
|
||||||
SGroupbyOperatorInfo* pInfo = pOperator->info;
|
SGroupbyOperatorInfo* pInfo = pOperator->info;
|
||||||
if (pOperator->status == OP_RES_TO_RETURN) {
|
if (pOperator->status == OP_RES_TO_RETURN) {
|
||||||
return buildGroupResultDataBlock(pOperator);
|
return buildGroupResultDataBlockByHash(pOperator);
|
||||||
}
|
}
|
||||||
|
SGroupResInfo* pGroupResInfo = &pInfo->groupResInfo;
|
||||||
|
|
||||||
int32_t order = pInfo->binfo.inputTsOrder;
|
int32_t order = pInfo->binfo.inputTsOrder;
|
||||||
int64_t st = taosGetTimestampUs();
|
int64_t st = taosGetTimestampUs();
|
||||||
|
@ -425,10 +492,20 @@ static SSDataBlock* hashGroupbyAggregate(SOperatorInfo* pOperator) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
initGroupedResultInfo(&pInfo->groupResInfo, pInfo->aggSup.pResultRowHashTable, 0);
|
// initGroupedResultInfo(&pInfo->groupResInfo, pInfo->aggSup.pResultRowHashTable, 0);
|
||||||
|
if (pGroupResInfo->pRows != NULL) {
|
||||||
|
taosArrayDestroy(pGroupResInfo->pRows);
|
||||||
|
}
|
||||||
|
if (pGroupResInfo->pBuf) {
|
||||||
|
taosMemoryFree(pGroupResInfo->pBuf);
|
||||||
|
pGroupResInfo->pBuf = NULL;
|
||||||
|
}
|
||||||
|
pGroupResInfo->index = 0;
|
||||||
|
pGroupResInfo->iter = 0;
|
||||||
|
pGroupResInfo->dataPos = NULL;
|
||||||
|
|
||||||
pOperator->cost.openCost = (taosGetTimestampUs() - st) / 1000.0;
|
pOperator->cost.openCost = (taosGetTimestampUs() - st) / 1000.0;
|
||||||
return buildGroupResultDataBlock(pOperator);
|
return buildGroupResultDataBlockByHash(pOperator);
|
||||||
}
|
}
|
||||||
|
|
||||||
SOperatorInfo* createGroupOperatorInfo(SOperatorInfo* downstream, SAggPhysiNode* pAggNode, SExecTaskInfo* pTaskInfo) {
|
SOperatorInfo* createGroupOperatorInfo(SOperatorInfo* downstream, SAggPhysiNode* pAggNode, SExecTaskInfo* pTaskInfo) {
|
||||||
|
|
|
@ -2772,7 +2772,7 @@ const SBuiltinFuncDefinition funcMgtBuiltins[] = {
|
||||||
{
|
{
|
||||||
.name = "_cache_last",
|
.name = "_cache_last",
|
||||||
.type = FUNCTION_TYPE_CACHE_LAST,
|
.type = FUNCTION_TYPE_CACHE_LAST,
|
||||||
.classification = FUNC_MGT_AGG_FUNC | FUNC_MGT_MULTI_RES_FUNC | FUNC_MGT_FORBID_STREAM_FUNC | FUNC_MGT_FORBID_SYSTABLE_FUNC,
|
.classification = FUNC_MGT_AGG_FUNC | FUNC_MGT_MULTI_RES_FUNC | FUNC_MGT_SELECT_FUNC | FUNC_MGT_FORBID_STREAM_FUNC | FUNC_MGT_FORBID_SYSTABLE_FUNC,
|
||||||
.translateFunc = translateFirstLast,
|
.translateFunc = translateFirstLast,
|
||||||
.getEnvFunc = getFirstLastFuncEnv,
|
.getEnvFunc = getFirstLastFuncEnv,
|
||||||
.initFunc = functionSetup,
|
.initFunc = functionSetup,
|
||||||
|
|
|
@ -1584,8 +1584,7 @@ typedef union SRowsDataContext{
|
||||||
SStbRowsDataContext* pStbRowsCxt;
|
SStbRowsDataContext* pStbRowsCxt;
|
||||||
} SRowsDataContext;
|
} SRowsDataContext;
|
||||||
|
|
||||||
static int32_t parseTbnameToken(SInsertParseContext* pCxt, SStbRowsDataContext* pStbRowsCxt, SToken* pToken,
|
static int32_t parseTbnameToken(SInsertParseContext* pCxt, SStbRowsDataContext* pStbRowsCxt, SToken* pToken, bool* pFoundCtbName) {
|
||||||
char* ctbName, bool* pFoundCtbName) {
|
|
||||||
*pFoundCtbName = false;
|
*pFoundCtbName = false;
|
||||||
int32_t code = checkAndTrimValue(pToken, pCxt->tmpTokenBuf, &pCxt->msg);
|
int32_t code = checkAndTrimValue(pToken, pCxt->tmpTokenBuf, &pCxt->msg);
|
||||||
if (code == TSDB_CODE_SUCCESS){
|
if (code == TSDB_CODE_SUCCESS){
|
||||||
|
@ -1595,7 +1594,13 @@ static int32_t parseTbnameToken(SInsertParseContext* pCxt, SStbRowsDataContext*
|
||||||
|
|
||||||
if (pToken->n > 0) {
|
if (pToken->n > 0) {
|
||||||
if (pToken->n <= TSDB_TABLE_NAME_LEN - 1) {
|
if (pToken->n <= TSDB_TABLE_NAME_LEN - 1) {
|
||||||
memcpy(pStbRowsCxt->ctbName.tname, pToken->z, pToken->n);
|
for (int i = 0; i < pToken->n; ++i) {
|
||||||
|
if (pToken->z[i] == '.') {
|
||||||
|
return buildInvalidOperationMsg(&pCxt->msg, "tbname can not contain '.'");
|
||||||
|
} else {
|
||||||
|
pStbRowsCxt->ctbName.tname[i] = pToken->z[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
pStbRowsCxt->ctbName.tname[pToken->n] = '\0';
|
pStbRowsCxt->ctbName.tname[pToken->n] = '\0';
|
||||||
*pFoundCtbName = true;
|
*pFoundCtbName = true;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1677,8 +1682,7 @@ static int32_t doGetStbRowValues(SInsertParseContext* pCxt, SVnodeModifyOpStmt*
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (pCols->pColIndex[i] == tbnameIdx) {
|
else if (pCols->pColIndex[i] == tbnameIdx) {
|
||||||
char ctbName[TSDB_TABLE_NAME_LEN];
|
code = parseTbnameToken(pCxt, pStbRowsCxt, pToken, bFoundTbName);
|
||||||
code = parseTbnameToken(pCxt, pStbRowsCxt, pToken, ctbName, bFoundTbName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (code == TSDB_CODE_SUCCESS && i < pCols->numOfBound - 1) {
|
if (code == TSDB_CODE_SUCCESS && i < pCols->numOfBound - 1) {
|
||||||
|
|
|
@ -266,7 +266,7 @@ static EScanType getScanType(SLogicPlanContext* pCxt, SNodeList* pScanPseudoCols
|
||||||
|
|
||||||
if (NULL == pScanCols) {
|
if (NULL == pScanCols) {
|
||||||
if (NULL == pScanPseudoCols) {
|
if (NULL == pScanPseudoCols) {
|
||||||
return SCAN_TYPE_TABLE;
|
return (!tagScan) ? SCAN_TYPE_TABLE : SCAN_TYPE_TAG;
|
||||||
}
|
}
|
||||||
return FUNCTION_TYPE_BLOCK_DIST_INFO == ((SFunctionNode*)nodesListGetNode(pScanPseudoCols, 0))->funcType
|
return FUNCTION_TYPE_BLOCK_DIST_INFO == ((SFunctionNode*)nodesListGetNode(pScanPseudoCols, 0))->funcType
|
||||||
? SCAN_TYPE_BLOCK_INFO
|
? SCAN_TYPE_BLOCK_INFO
|
||||||
|
|
|
@ -2478,6 +2478,27 @@ static bool hasSuitableCache(int8_t cacheLastMode, bool hasLastRow, bool hasLast
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// @brief check if we can apply last row scan optimization
|
||||||
|
/// @param lastColNum how many distinct last col specified
|
||||||
|
/// @param lastColId only used when lastColNum equals 1, the col id of the only one last col
|
||||||
|
/// @param selectNonPKColNum num of normal cols
|
||||||
|
/// @param selectNonPKColId only used when selectNonPKColNum equals 1, the col id of the only one select col
|
||||||
|
static bool lastRowScanOptCheckColNum(int32_t lastColNum, col_id_t lastColId,
|
||||||
|
int32_t selectNonPKColNum, col_id_t selectNonPKColId) {
|
||||||
|
// multi select non pk col + last func: select c1, c2, last(c1)
|
||||||
|
if (selectNonPKColNum > 1 && lastColNum > 0) return false;
|
||||||
|
|
||||||
|
if (selectNonPKColNum == 1) {
|
||||||
|
// select last(c1), last(c2), c1 ...
|
||||||
|
// which is not possible currently
|
||||||
|
if (lastColNum > 1) return false;
|
||||||
|
|
||||||
|
// select last(c1), c2 ...
|
||||||
|
if (lastColNum == 1 && lastColId != selectNonPKColId) return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static bool lastRowScanOptMayBeOptimized(SLogicNode* pNode) {
|
static bool lastRowScanOptMayBeOptimized(SLogicNode* pNode) {
|
||||||
if (QUERY_NODE_LOGIC_PLAN_AGG != nodeType(pNode) || 1 != LIST_LENGTH(pNode->pChildren) ||
|
if (QUERY_NODE_LOGIC_PLAN_AGG != nodeType(pNode) || 1 != LIST_LENGTH(pNode->pChildren) ||
|
||||||
QUERY_NODE_LOGIC_PLAN_SCAN != nodeType(nodesListGetNode(pNode->pChildren, 0))) {
|
QUERY_NODE_LOGIC_PLAN_SCAN != nodeType(nodesListGetNode(pNode->pChildren, 0))) {
|
||||||
|
@ -2493,9 +2514,10 @@ static bool lastRowScanOptMayBeOptimized(SLogicNode* pNode) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hasLastFunc = false;
|
bool hasNonPKSelectFunc = false;
|
||||||
bool hasSelectFunc = false;
|
|
||||||
SNode* pFunc = NULL;
|
SNode* pFunc = NULL;
|
||||||
|
int32_t lastColNum = 0, selectNonPKColNum = 0;
|
||||||
|
col_id_t lastColId = -1, selectNonPKColId = -1;
|
||||||
FOREACH(pFunc, ((SAggLogicNode*)pNode)->pAggFuncs) {
|
FOREACH(pFunc, ((SAggLogicNode*)pNode)->pAggFuncs) {
|
||||||
SFunctionNode* pAggFunc = (SFunctionNode*)pFunc;
|
SFunctionNode* pAggFunc = (SFunctionNode*)pFunc;
|
||||||
if (FUNCTION_TYPE_LAST == pAggFunc->funcType) {
|
if (FUNCTION_TYPE_LAST == pAggFunc->funcType) {
|
||||||
|
@ -2505,16 +2527,33 @@ static bool lastRowScanOptMayBeOptimized(SLogicNode* pNode) {
|
||||||
if (pCol->colType != COLUMN_TYPE_COLUMN) {
|
if (pCol->colType != COLUMN_TYPE_COLUMN) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (lastColId != pCol->colId) {
|
||||||
|
lastColId = pCol->colId;
|
||||||
|
lastColNum++;
|
||||||
}
|
}
|
||||||
if (hasSelectFunc || QUERY_NODE_VALUE == nodeType(nodesListGetNode(pAggFunc->pParameterList, 0))) {
|
}
|
||||||
|
if (QUERY_NODE_VALUE == nodeType(nodesListGetNode(pAggFunc->pParameterList, 0))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
hasLastFunc = true;
|
if (!lastRowScanOptCheckColNum(lastColNum, lastColId, selectNonPKColNum, selectNonPKColId))
|
||||||
|
return false;
|
||||||
} else if (FUNCTION_TYPE_SELECT_VALUE == pAggFunc->funcType) {
|
} else if (FUNCTION_TYPE_SELECT_VALUE == pAggFunc->funcType) {
|
||||||
if (hasLastFunc) {
|
SNode* pParam = nodesListGetNode(pAggFunc->pParameterList, 0);
|
||||||
|
if (QUERY_NODE_COLUMN == nodeType(pParam)) {
|
||||||
|
SColumnNode* pCol = (SColumnNode*)pParam;
|
||||||
|
if (PRIMARYKEY_TIMESTAMP_COL_ID != pCol->colId) {
|
||||||
|
if (selectNonPKColId != pCol->colId) {
|
||||||
|
selectNonPKColId = pCol->colId;
|
||||||
|
selectNonPKColNum++;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else if (lastColNum > 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
hasSelectFunc = true;
|
if (!lastRowScanOptCheckColNum(lastColNum, lastColId, selectNonPKColNum, selectNonPKColId))
|
||||||
|
return false;
|
||||||
} else if (FUNCTION_TYPE_GROUP_KEY == pAggFunc->funcType) {
|
} else if (FUNCTION_TYPE_GROUP_KEY == pAggFunc->funcType) {
|
||||||
if (!lastRowScanOptLastParaIsTag(nodesListGetNode(pAggFunc->pParameterList, 0))) {
|
if (!lastRowScanOptLastParaIsTag(nodesListGetNode(pAggFunc->pParameterList, 0))) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -2581,6 +2620,9 @@ static int32_t lastRowScanOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogic
|
||||||
|
|
||||||
SLastRowScanOptSetColDataTypeCxt cxt = {.doAgg = true, .pLastCols = NULL};
|
SLastRowScanOptSetColDataTypeCxt cxt = {.doAgg = true, .pLastCols = NULL};
|
||||||
SNode* pNode = NULL;
|
SNode* pNode = NULL;
|
||||||
|
SColumnNode* pPKTsCol = NULL;
|
||||||
|
SColumnNode* pNonPKCol = NULL;
|
||||||
|
|
||||||
FOREACH(pNode, pAgg->pAggFuncs) {
|
FOREACH(pNode, pAgg->pAggFuncs) {
|
||||||
SFunctionNode* pFunc = (SFunctionNode*)pNode;
|
SFunctionNode* pFunc = (SFunctionNode*)pNode;
|
||||||
int32_t funcType = pFunc->funcType;
|
int32_t funcType = pFunc->funcType;
|
||||||
|
@ -2597,6 +2639,16 @@ static int32_t lastRowScanOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogic
|
||||||
nodesWalkExpr(nodesListGetNode(pFunc->pParameterList, 0), lastRowScanOptSetColDataType, &cxt);
|
nodesWalkExpr(nodesListGetNode(pFunc->pParameterList, 0), lastRowScanOptSetColDataType, &cxt);
|
||||||
nodesListErase(pFunc->pParameterList, nodesListGetCell(pFunc->pParameterList, 1));
|
nodesListErase(pFunc->pParameterList, nodesListGetCell(pFunc->pParameterList, 1));
|
||||||
}
|
}
|
||||||
|
} else if (FUNCTION_TYPE_SELECT_VALUE == funcType) {
|
||||||
|
pNode = nodesListGetNode(pFunc->pParameterList, 0);
|
||||||
|
if (nodeType(pNode) == QUERY_NODE_COLUMN) {
|
||||||
|
SColumnNode* pCol = (SColumnNode*)pNode;
|
||||||
|
if (pCol->colId == PRIMARYKEY_TIMESTAMP_COL_ID) {
|
||||||
|
pPKTsCol = pCol;
|
||||||
|
} else {
|
||||||
|
pNonPKCol = pCol;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2608,6 +2660,16 @@ static int32_t lastRowScanOptimize(SOptimizeContext* pCxt, SLogicSubplan* pLogic
|
||||||
lastRowScanOptSetLastTargets(pScan->pScanCols, cxt.pLastCols, true);
|
lastRowScanOptSetLastTargets(pScan->pScanCols, cxt.pLastCols, true);
|
||||||
nodesWalkExprs(pScan->pScanPseudoCols, lastRowScanOptSetColDataType, &cxt);
|
nodesWalkExprs(pScan->pScanPseudoCols, lastRowScanOptSetColDataType, &cxt);
|
||||||
lastRowScanOptSetLastTargets(pScan->node.pTargets, cxt.pLastCols, false);
|
lastRowScanOptSetLastTargets(pScan->node.pTargets, cxt.pLastCols, false);
|
||||||
|
if (pPKTsCol && pScan->node.pTargets->length == 1) {
|
||||||
|
// when select last(ts),ts from ..., we add another ts to targets
|
||||||
|
sprintf(pPKTsCol->colName, "#sel_val.%p", pPKTsCol);
|
||||||
|
nodesListAppend(pScan->node.pTargets, nodesCloneNode((SNode*)pPKTsCol));
|
||||||
|
}
|
||||||
|
if (pNonPKCol && cxt.pLastCols->length == 1 && nodesEqualNode((SNode*)pNonPKCol, nodesListGetNode(cxt.pLastCols, 0))) {
|
||||||
|
// when select last(c1), c1 from ..., we add c1 to targets
|
||||||
|
sprintf(pNonPKCol->colName, "#sel_val.%p", pNonPKCol);
|
||||||
|
nodesListAppend(pScan->node.pTargets, nodesCloneNode((SNode*)pNonPKCol));
|
||||||
|
}
|
||||||
nodesClearList(cxt.pLastCols);
|
nodesClearList(cxt.pLastCols);
|
||||||
}
|
}
|
||||||
pAgg->hasLastRow = false;
|
pAgg->hasLastRow = false;
|
||||||
|
|
|
@ -127,13 +127,11 @@ int32_t streamNotifyUpstreamContinue(SStreamTask* pTask);
|
||||||
int32_t streamTaskFillHistoryFinished(SStreamTask* pTask);
|
int32_t streamTaskFillHistoryFinished(SStreamTask* pTask);
|
||||||
int32_t streamTransferStateToStreamTask(SStreamTask* pTask);
|
int32_t streamTransferStateToStreamTask(SStreamTask* pTask);
|
||||||
|
|
||||||
int32_t streamTaskInitTokenBucket(STokenBucket* pBucket, int32_t numCap, int32_t numRate, float quotaRate);
|
int32_t streamTaskInitTokenBucket(STokenBucket* pBucket, int32_t numCap, int32_t numRate, float quotaRate, const char*);
|
||||||
STaskId streamTaskExtractKey(const SStreamTask* pTask);
|
STaskId streamTaskExtractKey(const SStreamTask* pTask);
|
||||||
void streamTaskInitForLaunchHTask(SHistoryTaskInfo* pInfo);
|
void streamTaskInitForLaunchHTask(SHistoryTaskInfo* pInfo);
|
||||||
void streamTaskSetRetryInfoForLaunch(SHistoryTaskInfo* pInfo);
|
void streamTaskSetRetryInfoForLaunch(SHistoryTaskInfo* pInfo);
|
||||||
|
|
||||||
void streamMetaResetStartInfo(STaskStartInfo* pMeta);
|
|
||||||
|
|
||||||
SStreamQueue* streamQueueOpen(int64_t cap);
|
SStreamQueue* streamQueueOpen(int64_t cap);
|
||||||
void streamQueueClose(SStreamQueue* pQueue, int32_t taskId);
|
void streamQueueClose(SStreamQueue* pQueue, int32_t taskId);
|
||||||
void streamQueueProcessSuccess(SStreamQueue* queue);
|
void streamQueueProcessSuccess(SStreamQueue* queue);
|
||||||
|
@ -142,6 +140,21 @@ void* streamQueueNextItem(SStreamQueue* pQueue);
|
||||||
void streamFreeQitem(SStreamQueueItem* data);
|
void streamFreeQitem(SStreamQueueItem* data);
|
||||||
int32_t streamQueueGetItemSize(const SStreamQueue* pQueue);
|
int32_t streamQueueGetItemSize(const SStreamQueue* pQueue);
|
||||||
|
|
||||||
|
typedef enum UPLOAD_TYPE{
|
||||||
|
UPLOAD_DISABLE = -1,
|
||||||
|
UPLOAD_S3 = 0,
|
||||||
|
UPLOAD_RSYNC = 1,
|
||||||
|
} UPLOAD_TYPE;
|
||||||
|
|
||||||
|
UPLOAD_TYPE getUploadType();
|
||||||
|
int uploadCheckpoint(char* id, char* path);
|
||||||
|
int downloadCheckpoint(char* id, char* path);
|
||||||
|
int deleteCheckpoint(char* id);
|
||||||
|
int deleteCheckpointFile(char* id, char* name);
|
||||||
|
|
||||||
|
int32_t onNormalTaskReady(SStreamTask* pTask);
|
||||||
|
int32_t onScanhistoryTaskReady(SStreamTask* pTask);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "streamInt.h"
|
#include "streamInt.h"
|
||||||
|
#include "rsync.h"
|
||||||
|
#include "cos.h"
|
||||||
|
|
||||||
int32_t tEncodeStreamCheckpointSourceReq(SEncoder* pEncoder, const SStreamCheckpointSourceReq* pReq) {
|
int32_t tEncodeStreamCheckpointSourceReq(SEncoder* pEncoder, const SStreamCheckpointSourceReq* pReq) {
|
||||||
if (tStartEncode(pEncoder) < 0) return -1;
|
if (tStartEncode(pEncoder) < 0) return -1;
|
||||||
|
@ -372,3 +374,91 @@ int32_t streamTaskBuildCheckpoint(SStreamTask* pTask) {
|
||||||
|
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int uploadCheckpointToS3(char* id, char* path){
|
||||||
|
TdDirPtr pDir = taosOpenDir(path);
|
||||||
|
if (pDir == NULL) return -1;
|
||||||
|
|
||||||
|
TdDirEntryPtr de = NULL;
|
||||||
|
while ((de = taosReadDir(pDir)) != NULL) {
|
||||||
|
char* name = taosGetDirEntryName(de);
|
||||||
|
if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0 ||
|
||||||
|
taosDirEntryIsDir(de)) continue;
|
||||||
|
|
||||||
|
char filename[PATH_MAX] = {0};
|
||||||
|
if(path[strlen(path) - 1] == TD_DIRSEP_CHAR){
|
||||||
|
snprintf(filename, sizeof(filename), "%s%s", path, name);
|
||||||
|
}else{
|
||||||
|
snprintf(filename, sizeof(filename), "%s%s%s", path, TD_DIRSEP, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
char object[PATH_MAX] = {0};
|
||||||
|
snprintf(object, sizeof(object), "%s%s%s", id, TD_DIRSEP, name);
|
||||||
|
|
||||||
|
if(s3PutObjectFromFile2(filename, object) != 0){
|
||||||
|
taosCloseDir(&pDir);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
stDebug("[s3] upload checkpoint:%s", filename);
|
||||||
|
}
|
||||||
|
taosCloseDir(&pDir);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
UPLOAD_TYPE getUploadType(){
|
||||||
|
if(strlen(tsSnodeAddress) != 0){
|
||||||
|
return UPLOAD_RSYNC;
|
||||||
|
}else if(tsS3StreamEnabled){
|
||||||
|
return UPLOAD_S3;
|
||||||
|
}else{
|
||||||
|
return UPLOAD_DISABLE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int uploadCheckpoint(char* id, char* path){
|
||||||
|
if(id == NULL || path == NULL || strlen(id) == 0 || strlen(path) == 0 || strlen(path) >= PATH_MAX){
|
||||||
|
stError("uploadCheckpoint parameters invalid");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(strlen(tsSnodeAddress) != 0){
|
||||||
|
return uploadRsync(id, path);
|
||||||
|
}else if(tsS3StreamEnabled){
|
||||||
|
return uploadCheckpointToS3(id, path);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int downloadCheckpoint(char* id, char* path){
|
||||||
|
if(id == NULL || path == NULL || strlen(id) == 0 || strlen(path) == 0 || strlen(path) >= PATH_MAX){
|
||||||
|
stError("downloadCheckpoint parameters invalid");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(strlen(tsSnodeAddress) != 0){
|
||||||
|
return downloadRsync(id, path);
|
||||||
|
}else if(tsS3StreamEnabled){
|
||||||
|
return s3GetObjectsByPrefix(id, path);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int deleteCheckpoint(char* id){
|
||||||
|
if(id == NULL || strlen(id) == 0){
|
||||||
|
stError("deleteCheckpoint parameters invalid");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(strlen(tsSnodeAddress) != 0){
|
||||||
|
return deleteRsync(id);
|
||||||
|
}else if(tsS3StreamEnabled){
|
||||||
|
s3DeleteObjectsByPrefix(id);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int deleteCheckpointFile(char* id, char* name){
|
||||||
|
char object[128] = {0};
|
||||||
|
snprintf(object, sizeof(object), "%s/%s", id, name);
|
||||||
|
char *tmp = object;
|
||||||
|
s3DeleteObjects((const char**)&tmp, 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -1007,7 +1007,6 @@ int32_t streamAddEndScanHistoryMsg(SStreamTask* pTask, SRpcHandleInfo* pRpcInfo,
|
||||||
info.msg.info = *pRpcInfo;
|
info.msg.info = *pRpcInfo;
|
||||||
|
|
||||||
taosThreadMutexLock(&pTask->lock);
|
taosThreadMutexLock(&pTask->lock);
|
||||||
stDebug("s-task:%s lock", pTask->id.idStr);
|
|
||||||
|
|
||||||
if (pTask->pRspMsgList == NULL) {
|
if (pTask->pRspMsgList == NULL) {
|
||||||
pTask->pRspMsgList = taosArrayInit(4, sizeof(SStreamContinueExecInfo));
|
pTask->pRspMsgList = taosArrayInit(4, sizeof(SStreamContinueExecInfo));
|
||||||
|
|
|
@ -18,7 +18,8 @@
|
||||||
// maximum allowed processed block batches. One block may include several submit blocks
|
// maximum allowed processed block batches. One block may include several submit blocks
|
||||||
#define MAX_STREAM_EXEC_BATCH_NUM 32
|
#define MAX_STREAM_EXEC_BATCH_NUM 32
|
||||||
#define STREAM_RESULT_DUMP_THRESHOLD 300
|
#define STREAM_RESULT_DUMP_THRESHOLD 300
|
||||||
#define STREAM_RESULT_DUMP_SIZE_THRESHOLD (1048576 * 1)
|
#define STREAM_RESULT_DUMP_SIZE_THRESHOLD (1048576 * 1) // 1MiB result data
|
||||||
|
#define STREAM_SCAN_HISTORY_TIMESLICE 1000 // 1000 ms
|
||||||
|
|
||||||
static int32_t streamDoTransferStateToStreamTask(SStreamTask* pTask);
|
static int32_t streamDoTransferStateToStreamTask(SStreamTask* pTask);
|
||||||
|
|
||||||
|
@ -48,10 +49,9 @@ static int32_t doOutputResultBlockImpl(SStreamTask* pTask, SStreamDataBlock* pBl
|
||||||
}
|
}
|
||||||
|
|
||||||
streamDispatchStreamBlock(pTask);
|
streamDispatchStreamBlock(pTask);
|
||||||
return code;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int32_t doDumpResult(SStreamTask* pTask, SStreamQueueItem* pItem, SArray* pRes, int32_t size, int64_t* totalSize,
|
static int32_t doDumpResult(SStreamTask* pTask, SStreamQueueItem* pItem, SArray* pRes, int32_t size, int64_t* totalSize,
|
||||||
|
@ -187,53 +187,47 @@ static int32_t streamTaskExecImpl(SStreamTask* pTask, SStreamQueueItem* pItem, i
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t streamScanHistoryData(SStreamTask* pTask) {
|
static int32_t handleResultBlocks(SStreamTask* pTask, SArray* pRes, int32_t size) {
|
||||||
ASSERT(pTask->info.taskLevel == TASK_LEVEL__SOURCE);
|
int32_t code = TSDB_CODE_SUCCESS;
|
||||||
|
if (taosArrayGetSize(pRes) > 0) {
|
||||||
|
SStreamDataBlock* pStreamBlocks = createStreamBlockFromResults(NULL, pTask, size, pRes);
|
||||||
|
code = doOutputResultBlockImpl(pTask, pStreamBlocks);
|
||||||
|
if (code != TSDB_CODE_SUCCESS) {
|
||||||
|
stDebug("s-task:%s dump fill-history results failed, code:%s", pTask->id.idStr, tstrerror(code));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
taosArrayDestroy(pRes);
|
||||||
|
}
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void streamScanHistoryDataImpl(SStreamTask* pTask, SArray* pRes, int32_t* pSize, bool* pFinish) {
|
||||||
int32_t code = TSDB_CODE_SUCCESS;
|
int32_t code = TSDB_CODE_SUCCESS;
|
||||||
void* exec = pTask->exec.pExecutor;
|
void* exec = pTask->exec.pExecutor;
|
||||||
bool finished = false;
|
int32_t numOfBlocks = 0;
|
||||||
|
|
||||||
qSetStreamOpOpen(exec);
|
while (1) {
|
||||||
|
if (streamTaskShouldStop(pTask)) {
|
||||||
while (!finished) {
|
|
||||||
if (streamTaskShouldPause(pTask)) {
|
|
||||||
double el = (taosGetTimestampMs() - pTask->execInfo.step1Start) / 1000.0;
|
|
||||||
stDebug("s-task:%s paused from the scan-history task, elapsed time:%.2fsec", pTask->id.idStr, el);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
SArray* pRes = taosArrayInit(0, sizeof(SSDataBlock));
|
|
||||||
if (pRes == NULL) {
|
|
||||||
terrno = TSDB_CODE_OUT_OF_MEMORY;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int32_t size = 0;
|
|
||||||
int32_t numOfBlocks = 0;
|
|
||||||
while (1) {
|
|
||||||
if (streamTaskShouldStop(pTask)) {
|
|
||||||
taosArrayDestroyEx(pRes, (FDelete)blockDataFreeRes);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pTask->inputq.status == TASK_INPUT_STATUS__BLOCKED) {
|
if (pTask->inputq.status == TASK_INPUT_STATUS__BLOCKED) {
|
||||||
stDebug("s-task:%s inputQ is blocked, wait for 10sec and retry", pTask->id.idStr);
|
stDebug("s-task:%s level:%d inputQ is blocked, retry in 5s", pTask->id.idStr, pTask->info.taskLevel);
|
||||||
taosMsleep(10000);
|
break;
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SSDataBlock* output = NULL;
|
SSDataBlock* output = NULL;
|
||||||
uint64_t ts = 0;
|
uint64_t ts = 0;
|
||||||
code = qExecTask(exec, &output, &ts);
|
code = qExecTask(exec, &output, &ts);
|
||||||
if (code != TSDB_CODE_TSC_QUERY_KILLED && code != TSDB_CODE_SUCCESS) {
|
if (code != TSDB_CODE_TSC_QUERY_KILLED && code != TSDB_CODE_SUCCESS) {
|
||||||
stError("%s scan-history data error occurred code:%s, continue scan", pTask->id.idStr, tstrerror(code));
|
stError("s-task:%s scan-history data error occurred code:%s, continue scan-history", pTask->id.idStr,
|
||||||
|
tstrerror(code));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// the generated results before fill-history task been paused, should be dispatched to sink node
|
// the generated results before fill-history task been paused, should be dispatched to sink node
|
||||||
if (output == NULL) {
|
if (output == NULL) {
|
||||||
finished = qStreamRecoverScanFinished(exec);
|
(*pFinish) = qStreamScanhistoryFinished(exec);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -242,28 +236,69 @@ int32_t streamScanHistoryData(SStreamTask* pTask) {
|
||||||
block.info.childId = pTask->info.selfChildId;
|
block.info.childId = pTask->info.selfChildId;
|
||||||
taosArrayPush(pRes, &block);
|
taosArrayPush(pRes, &block);
|
||||||
|
|
||||||
size += blockDataGetSize(output) + sizeof(SSDataBlock) + sizeof(SColumnInfoData) * blockDataGetNumOfCols(&block);
|
(*pSize) += blockDataGetSize(output) + sizeof(SSDataBlock) + sizeof(SColumnInfoData) * blockDataGetNumOfCols(&block);
|
||||||
|
numOfBlocks += 1;
|
||||||
|
|
||||||
if ((++numOfBlocks) >= STREAM_RESULT_DUMP_THRESHOLD || size >= STREAM_RESULT_DUMP_SIZE_THRESHOLD) {
|
if (numOfBlocks >= STREAM_RESULT_DUMP_THRESHOLD || (*pSize) >= STREAM_RESULT_DUMP_SIZE_THRESHOLD) {
|
||||||
stDebug("s-task:%s scan exec numOfBlocks:%d, size:%.2fKiB output num-limit:%d, size-limit:%.2fKiB reached",
|
stDebug("s-task:%s scan exec numOfBlocks:%d, size:%.2fKiB output num-limit:%d, size-limit:%.2fKiB reached",
|
||||||
pTask->id.idStr, numOfBlocks, SIZE_IN_KiB(size), STREAM_RESULT_DUMP_THRESHOLD,
|
pTask->id.idStr, numOfBlocks, SIZE_IN_KiB(*pSize), STREAM_RESULT_DUMP_THRESHOLD,
|
||||||
SIZE_IN_KiB(STREAM_RESULT_DUMP_SIZE_THRESHOLD));
|
SIZE_IN_KiB(STREAM_RESULT_DUMP_SIZE_THRESHOLD));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (taosArrayGetSize(pRes) > 0) {
|
SScanhistoryDataInfo streamScanHistoryData(SStreamTask* pTask, int64_t st) {
|
||||||
SStreamDataBlock* pStreamBlocks = createStreamBlockFromResults(NULL, pTask, size, pRes);
|
ASSERT(pTask->info.taskLevel == TASK_LEVEL__SOURCE);
|
||||||
code = doOutputResultBlockImpl(pTask, pStreamBlocks);
|
|
||||||
if (code != TSDB_CODE_SUCCESS) {
|
void* exec = pTask->exec.pExecutor;
|
||||||
return code;
|
bool finished = false;
|
||||||
}
|
|
||||||
} else {
|
qSetStreamOpOpen(exec);
|
||||||
taosArrayDestroy(pRes);
|
|
||||||
}
|
while (1) {
|
||||||
|
if (streamTaskShouldPause(pTask)) {
|
||||||
|
stDebug("s-task:%s paused from the scan-history task", pTask->id.idStr);
|
||||||
|
// quit from step1, not continue to handle the step2
|
||||||
|
return (SScanhistoryDataInfo){TASK_SCANHISTORY_QUIT, 0};
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
SArray* pRes = taosArrayInit(0, sizeof(SSDataBlock));
|
||||||
|
if (pRes == NULL) {
|
||||||
|
terrno = TSDB_CODE_OUT_OF_MEMORY;
|
||||||
|
stError("s-task:%s scan-history prepare result block failed, code:%s, retry later", pTask->id.idStr,
|
||||||
|
tstrerror(terrno));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t size = 0;
|
||||||
|
streamScanHistoryDataImpl(pTask, pRes, &size, &finished);
|
||||||
|
|
||||||
|
if(streamTaskShouldStop(pTask)) {
|
||||||
|
taosArrayDestroyEx(pRes, (FDelete)blockDataFreeRes);
|
||||||
|
return (SScanhistoryDataInfo){TASK_SCANHISTORY_QUIT, 0};
|
||||||
|
}
|
||||||
|
|
||||||
|
// dispatch the generated results
|
||||||
|
int32_t code = handleResultBlocks(pTask, pRes, size);
|
||||||
|
|
||||||
|
int64_t el = taosGetTimestampMs() - st;
|
||||||
|
|
||||||
|
// downstream task input queue is full, try in 5sec
|
||||||
|
if (pTask->inputq.status == TASK_INPUT_STATUS__BLOCKED) {
|
||||||
|
return (SScanhistoryDataInfo){TASK_SCANHISTORY_REXEC, 5000};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (finished) {
|
||||||
|
return (SScanhistoryDataInfo){TASK_SCANHISTORY_CONT, 0};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (el >= STREAM_SCAN_HISTORY_TIMESLICE) {
|
||||||
|
stDebug("s-task:%s fill-history:%d time slice exhausted, elapsed time:%.2fs, retry in 100ms",
|
||||||
|
pTask->id.idStr, pTask->info.fillHistory, el / 1000.0);
|
||||||
|
return (SScanhistoryDataInfo){TASK_SCANHISTORY_REXEC, 100};
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// wait for the stream task to be idle
|
// wait for the stream task to be idle
|
||||||
|
@ -647,23 +682,25 @@ int32_t streamExecTask(SStreamTask* pTask) {
|
||||||
int32_t streamTaskReleaseState(SStreamTask* pTask) {
|
int32_t streamTaskReleaseState(SStreamTask* pTask) {
|
||||||
stDebug("s-task:%s release exec state", pTask->id.idStr);
|
stDebug("s-task:%s release exec state", pTask->id.idStr);
|
||||||
void* pExecutor = pTask->exec.pExecutor;
|
void* pExecutor = pTask->exec.pExecutor;
|
||||||
|
|
||||||
|
int32_t code = TSDB_CODE_SUCCESS;
|
||||||
if (pExecutor != NULL) {
|
if (pExecutor != NULL) {
|
||||||
int32_t code = qStreamOperatorReleaseState(pExecutor);
|
code = qStreamOperatorReleaseState(pExecutor);
|
||||||
return code;
|
|
||||||
} else {
|
|
||||||
return TSDB_CODE_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t streamTaskReloadState(SStreamTask* pTask) {
|
int32_t streamTaskReloadState(SStreamTask* pTask) {
|
||||||
stDebug("s-task:%s reload exec state", pTask->id.idStr);
|
stDebug("s-task:%s reload exec state", pTask->id.idStr);
|
||||||
void* pExecutor = pTask->exec.pExecutor;
|
void* pExecutor = pTask->exec.pExecutor;
|
||||||
|
|
||||||
|
int32_t code = TSDB_CODE_SUCCESS;
|
||||||
if (pExecutor != NULL) {
|
if (pExecutor != NULL) {
|
||||||
int32_t code = qStreamOperatorReloadState(pExecutor);
|
code = qStreamOperatorReloadState(pExecutor);
|
||||||
return code;
|
|
||||||
} else {
|
|
||||||
return TSDB_CODE_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t streamAlignTransferState(SStreamTask* pTask) {
|
int32_t streamAlignTransferState(SStreamTask* pTask) {
|
||||||
|
|
|
@ -150,6 +150,12 @@ SStreamMeta* streamMetaOpen(const char* path, void* ahandle, FTaskExpand expandF
|
||||||
|
|
||||||
pMeta->startInfo.pReadyTaskSet = taosHashInit(64, fp, false, HASH_NO_LOCK);
|
pMeta->startInfo.pReadyTaskSet = taosHashInit(64, fp, false, HASH_NO_LOCK);
|
||||||
if (pMeta->startInfo.pReadyTaskSet == NULL) {
|
if (pMeta->startInfo.pReadyTaskSet == NULL) {
|
||||||
|
goto _err;
|
||||||
|
}
|
||||||
|
|
||||||
|
pMeta->startInfo.pFailedTaskSet = taosHashInit(4, fp, false, HASH_NO_LOCK);
|
||||||
|
if (pMeta->startInfo.pFailedTaskSet == NULL) {
|
||||||
|
goto _err;
|
||||||
}
|
}
|
||||||
|
|
||||||
pMeta->pHbInfo = taosMemoryCalloc(1, sizeof(SMetaHbInfo));
|
pMeta->pHbInfo = taosMemoryCalloc(1, sizeof(SMetaHbInfo));
|
||||||
|
@ -221,6 +227,7 @@ SStreamMeta* streamMetaOpen(const char* path, void* ahandle, FTaskExpand expandF
|
||||||
if (pMeta->pHbInfo) taosMemoryFreeClear(pMeta->pHbInfo);
|
if (pMeta->pHbInfo) taosMemoryFreeClear(pMeta->pHbInfo);
|
||||||
if (pMeta->updateInfo.pTasks) taosHashCleanup(pMeta->updateInfo.pTasks);
|
if (pMeta->updateInfo.pTasks) taosHashCleanup(pMeta->updateInfo.pTasks);
|
||||||
if (pMeta->startInfo.pReadyTaskSet) taosHashCleanup(pMeta->startInfo.pReadyTaskSet);
|
if (pMeta->startInfo.pReadyTaskSet) taosHashCleanup(pMeta->startInfo.pReadyTaskSet);
|
||||||
|
if (pMeta->startInfo.pFailedTaskSet) taosHashCleanup(pMeta->startInfo.pFailedTaskSet);
|
||||||
taosMemoryFree(pMeta);
|
taosMemoryFree(pMeta);
|
||||||
|
|
||||||
stError("failed to open stream meta");
|
stError("failed to open stream meta");
|
||||||
|
@ -228,12 +235,8 @@ SStreamMeta* streamMetaOpen(const char* path, void* ahandle, FTaskExpand expandF
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t streamMetaReopen(SStreamMeta* pMeta) {
|
int32_t streamMetaReopen(SStreamMeta* pMeta) {
|
||||||
// backup the restart flag
|
|
||||||
int32_t restartFlag = pMeta->startInfo.startAllTasksFlag;
|
|
||||||
streamMetaClear(pMeta);
|
streamMetaClear(pMeta);
|
||||||
|
|
||||||
pMeta->startInfo.startAllTasksFlag = restartFlag;
|
|
||||||
|
|
||||||
// NOTE: role should not be changed during reopen meta
|
// NOTE: role should not be changed during reopen meta
|
||||||
pMeta->streamBackendRid = -1;
|
pMeta->streamBackendRid = -1;
|
||||||
pMeta->streamBackend = NULL;
|
pMeta->streamBackend = NULL;
|
||||||
|
@ -302,7 +305,10 @@ void streamMetaClear(SStreamMeta* pMeta) {
|
||||||
pMeta->numOfPausedTasks = 0;
|
pMeta->numOfPausedTasks = 0;
|
||||||
pMeta->chkptNotReadyTasks = 0;
|
pMeta->chkptNotReadyTasks = 0;
|
||||||
|
|
||||||
streamMetaResetStartInfo(&pMeta->startInfo);
|
// the willrestart/starting flag can NOT be cleared
|
||||||
|
taosHashClear(pMeta->startInfo.pReadyTaskSet);
|
||||||
|
taosHashClear(pMeta->startInfo.pFailedTaskSet);
|
||||||
|
pMeta->startInfo.readyTs = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void streamMetaClose(SStreamMeta* pMeta) {
|
void streamMetaClose(SStreamMeta* pMeta) {
|
||||||
|
@ -342,6 +348,7 @@ void streamMetaCloseImpl(void* arg) {
|
||||||
taosHashCleanup(pMeta->pTaskBackendUnique);
|
taosHashCleanup(pMeta->pTaskBackendUnique);
|
||||||
taosHashCleanup(pMeta->updateInfo.pTasks);
|
taosHashCleanup(pMeta->updateInfo.pTasks);
|
||||||
taosHashCleanup(pMeta->startInfo.pReadyTaskSet);
|
taosHashCleanup(pMeta->startInfo.pReadyTaskSet);
|
||||||
|
taosHashCleanup(pMeta->startInfo.pFailedTaskSet);
|
||||||
|
|
||||||
taosMemoryFree(pMeta->pHbInfo);
|
taosMemoryFree(pMeta->pHbInfo);
|
||||||
taosMemoryFree(pMeta->path);
|
taosMemoryFree(pMeta->path);
|
||||||
|
@ -1093,8 +1100,11 @@ void streamMetaInitForSnode(SStreamMeta* pMeta) {
|
||||||
|
|
||||||
void streamMetaResetStartInfo(STaskStartInfo* pStartInfo) {
|
void streamMetaResetStartInfo(STaskStartInfo* pStartInfo) {
|
||||||
taosHashClear(pStartInfo->pReadyTaskSet);
|
taosHashClear(pStartInfo->pReadyTaskSet);
|
||||||
pStartInfo->startAllTasksFlag = 0;
|
taosHashClear(pStartInfo->pFailedTaskSet);
|
||||||
|
pStartInfo->tasksWillRestart = 0;
|
||||||
pStartInfo->readyTs = 0;
|
pStartInfo->readyTs = 0;
|
||||||
|
// reset the sentinel flag value to be 0
|
||||||
|
atomic_store_32(&pStartInfo->taskStarting, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void streamMetaRLock(SStreamMeta* pMeta) {
|
void streamMetaRLock(SStreamMeta* pMeta) {
|
||||||
|
@ -1104,7 +1114,6 @@ void streamMetaRLock(SStreamMeta* pMeta) {
|
||||||
void streamMetaRUnLock(SStreamMeta* pMeta) {
|
void streamMetaRUnLock(SStreamMeta* pMeta) {
|
||||||
stTrace("vgId:%d meta-runlock", pMeta->vgId);
|
stTrace("vgId:%d meta-runlock", pMeta->vgId);
|
||||||
taosRUnLockLatch(&pMeta->lock);
|
taosRUnLockLatch(&pMeta->lock);
|
||||||
|
|
||||||
}
|
}
|
||||||
void streamMetaWLock(SStreamMeta* pMeta) {
|
void streamMetaWLock(SStreamMeta* pMeta) {
|
||||||
stTrace("vgId:%d meta-wlock", pMeta->vgId);
|
stTrace("vgId:%d meta-wlock", pMeta->vgId);
|
||||||
|
|
|
@ -159,7 +159,8 @@ int32_t streamTaskGetDataFromInputQ(SStreamTask* pTask, SStreamQueueItem** pInpu
|
||||||
|
|
||||||
// no available token in bucket for sink task, let's wait for a little bit
|
// no available token in bucket for sink task, let's wait for a little bit
|
||||||
if (taskLevel == TASK_LEVEL__SINK && (!streamTaskExtractAvailableToken(pTask->outputInfo.pTokenBucket, pTask->id.idStr))) {
|
if (taskLevel == TASK_LEVEL__SINK && (!streamTaskExtractAvailableToken(pTask->outputInfo.pTokenBucket, pTask->id.idStr))) {
|
||||||
stDebug("s-task:%s no available token in bucket for sink data, wait for 50ms", id);
|
stDebug("s-task:%s no available token in bucket for sink data, wait for 10ms", id);
|
||||||
|
taosMsleep(10);
|
||||||
return TSDB_CODE_SUCCESS;
|
return TSDB_CODE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -340,10 +341,11 @@ int32_t streamTaskPutDataIntoInputQ(SStreamTask* pTask, SStreamQueueItem* pItem)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// the result should be put into the outputQ in any cases, otherwise, the result may be lost
|
// the result should be put into the outputQ in any cases, the result may be lost otherwise.
|
||||||
int32_t streamTaskPutDataIntoOutputQ(SStreamTask* pTask, SStreamDataBlock* pBlock) {
|
int32_t streamTaskPutDataIntoOutputQ(SStreamTask* pTask, SStreamDataBlock* pBlock) {
|
||||||
STaosQueue* pQueue = pTask->outputq.queue->pQueue;
|
STaosQueue* pQueue = pTask->outputq.queue->pQueue;
|
||||||
|
|
||||||
|
// wait for the output queue is available for new data to dispatch
|
||||||
while (streamQueueIsFull(pTask->outputq.queue)) {
|
while (streamQueueIsFull(pTask->outputq.queue)) {
|
||||||
if (streamTaskShouldStop(pTask)) {
|
if (streamTaskShouldStop(pTask)) {
|
||||||
stInfo("s-task:%s discard result block due to task stop", pTask->id.idStr);
|
stInfo("s-task:%s discard result block due to task stop", pTask->id.idStr);
|
||||||
|
@ -373,7 +375,8 @@ int32_t streamTaskPutDataIntoOutputQ(SStreamTask* pTask, SStreamDataBlock* pBloc
|
||||||
return TSDB_CODE_SUCCESS;
|
return TSDB_CODE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t streamTaskInitTokenBucket(STokenBucket* pBucket, int32_t numCap, int32_t numRate, float quotaRate) {
|
int32_t streamTaskInitTokenBucket(STokenBucket* pBucket, int32_t numCap, int32_t numRate, float quotaRate,
|
||||||
|
const char* id) {
|
||||||
if (numCap < 10 || numRate < 10 || pBucket == NULL) {
|
if (numCap < 10 || numRate < 10 || pBucket == NULL) {
|
||||||
stError("failed to init sink task bucket, cap:%d, rate:%d", numCap, numRate);
|
stError("failed to init sink task bucket, cap:%d, rate:%d", numCap, numRate);
|
||||||
return TSDB_CODE_INVALID_PARA;
|
return TSDB_CODE_INVALID_PARA;
|
||||||
|
@ -388,6 +391,7 @@ int32_t streamTaskInitTokenBucket(STokenBucket* pBucket, int32_t numCap, int32_t
|
||||||
pBucket->quotaRemain = pBucket->quotaCapacity;
|
pBucket->quotaRemain = pBucket->quotaCapacity;
|
||||||
|
|
||||||
pBucket->fillTimestamp = taosGetTimestampMs();
|
pBucket->fillTimestamp = taosGetTimestampMs();
|
||||||
|
stDebug("s-task:%s sink quotaRate:%.2fMiB, numRate:%d", id, quotaRate, numRate);
|
||||||
return TSDB_CODE_SUCCESS;
|
return TSDB_CODE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -406,12 +410,12 @@ static void fillTokenBucket(STokenBucket* pBucket, const char* id) {
|
||||||
double incSize = (delta / 1000.0) * pBucket->quotaRate;
|
double incSize = (delta / 1000.0) * pBucket->quotaRate;
|
||||||
if (incSize > 0) {
|
if (incSize > 0) {
|
||||||
pBucket->quotaRemain = TMIN(pBucket->quotaRemain + incSize, pBucket->quotaCapacity);
|
pBucket->quotaRemain = TMIN(pBucket->quotaRemain + incSize, pBucket->quotaCapacity);
|
||||||
|
pBucket->fillTimestamp = now;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (incNum > 0 || incSize > 0) {
|
if (incNum > 0 || incSize > 0) {
|
||||||
stDebug("new token and capacity available, current token:%d inc:%d, current quota:%.2fMiB inc:%.2fMiB, ts:%" PRId64
|
stTrace("token/quota available, token:%d inc:%d, quota:%.2fMiB inc:%.3fMiB, ts:%" PRId64 " idle:%" PRId64 "ms, %s",
|
||||||
" idle for %.2f Sec, %s",
|
pBucket->numOfToken, incNum, pBucket->quotaRemain, incSize, now, delta, id);
|
||||||
pBucket->numOfToken, incNum, pBucket->quotaRemain, incSize, now, delta / 1000.0, id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
#include "streamBackendRocksdb.h"
|
#include "streamBackendRocksdb.h"
|
||||||
#include "streamInt.h"
|
#include "streamInt.h"
|
||||||
#include "tcommon.h"
|
#include "tcommon.h"
|
||||||
#include "streamInt.h"
|
|
||||||
|
|
||||||
enum SBackendFileType {
|
enum SBackendFileType {
|
||||||
ROCKSDB_OPTIONS_TYPE = 1,
|
ROCKSDB_OPTIONS_TYPE = 1,
|
||||||
|
@ -52,6 +51,7 @@ struct SStreamSnapHandle {
|
||||||
int8_t filetype;
|
int8_t filetype;
|
||||||
SArray* pFileList;
|
SArray* pFileList;
|
||||||
int32_t currFileIdx;
|
int32_t currFileIdx;
|
||||||
|
int8_t delFlag; // 0 : not del, 1: del
|
||||||
};
|
};
|
||||||
struct SStreamSnapBlockHdr {
|
struct SStreamSnapBlockHdr {
|
||||||
int8_t type;
|
int8_t type;
|
||||||
|
@ -148,6 +148,7 @@ int32_t streamSnapHandleInit(SStreamSnapHandle* pHandle, char* path, int64_t chk
|
||||||
taosMemoryFree(tdir);
|
taosMemoryFree(tdir);
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
pHandle->delFlag = 1;
|
||||||
chkpId = 0;
|
chkpId = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -274,7 +275,7 @@ void streamSnapHandleDestroy(SStreamSnapHandle* handle) {
|
||||||
if (handle->checkpointId == 0) {
|
if (handle->checkpointId == 0) {
|
||||||
// del tmp dir
|
// del tmp dir
|
||||||
if (pFile && taosIsDir(pFile->path)) {
|
if (pFile && taosIsDir(pFile->path)) {
|
||||||
taosRemoveDir(pFile->path);
|
if (handle->delFlag) taosRemoveDir(pFile->path);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
streamBackendDelInUseChkp(handle->handle, handle->checkpointId);
|
streamBackendDelInUseChkp(handle->handle, handle->checkpointId);
|
||||||
|
@ -344,7 +345,7 @@ int32_t streamSnapRead(SStreamSnapReader* pReader, uint8_t** ppData, int64_t* si
|
||||||
stDebug("%s start to read file %s, current offset:%" PRId64 ", size:%" PRId64 ", file no.%d", STREAM_STATE_TRANSFER,
|
stDebug("%s start to read file %s, current offset:%" PRId64 ", size:%" PRId64 ", file no.%d", STREAM_STATE_TRANSFER,
|
||||||
item->name, (int64_t)pHandle->offset, item->size, pHandle->currFileIdx);
|
item->name, (int64_t)pHandle->offset, item->size, pHandle->currFileIdx);
|
||||||
uint8_t* buf = taosMemoryCalloc(1, sizeof(SStreamSnapBlockHdr) + kBlockSize);
|
uint8_t* buf = taosMemoryCalloc(1, sizeof(SStreamSnapBlockHdr) + kBlockSize);
|
||||||
if(buf == NULL){
|
if (buf == NULL) {
|
||||||
return TSDB_CODE_OUT_OF_MEMORY;
|
return TSDB_CODE_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
int64_t nread = taosPReadFile(pHandle->fd, buf + sizeof(SStreamSnapBlockHdr), kBlockSize, pHandle->offset);
|
int64_t nread = taosPReadFile(pHandle->fd, buf + sizeof(SStreamSnapBlockHdr), kBlockSize, pHandle->offset);
|
||||||
|
@ -423,6 +424,7 @@ int32_t streamSnapWriterOpen(void* pMeta, int64_t sver, int64_t ever, char* path
|
||||||
pHandle->pFileList = list;
|
pHandle->pFileList = list;
|
||||||
pHandle->currFileIdx = 0;
|
pHandle->currFileIdx = 0;
|
||||||
pHandle->offset = 0;
|
pHandle->offset = 0;
|
||||||
|
pHandle->delFlag = 0;
|
||||||
|
|
||||||
*ppWriter = pWriter;
|
*ppWriter = pWriter;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -19,6 +19,10 @@
|
||||||
#include "wal.h"
|
#include "wal.h"
|
||||||
#include "streamsm.h"
|
#include "streamsm.h"
|
||||||
|
|
||||||
|
#define SCANHISTORY_IDLE_TIME_SLICE 100 // 100ms
|
||||||
|
#define SCANHISTORY_MAX_IDLE_TIME 10 // 10 sec
|
||||||
|
#define SCANHISTORY_IDLE_TICK ((SCANHISTORY_MAX_IDLE_TIME * 1000) / SCANHISTORY_IDLE_TIME_SLICE)
|
||||||
|
|
||||||
typedef struct SLaunchHTaskInfo {
|
typedef struct SLaunchHTaskInfo {
|
||||||
SStreamMeta* pMeta;
|
SStreamMeta* pMeta;
|
||||||
STaskId id;
|
STaskId id;
|
||||||
|
@ -30,6 +34,12 @@ typedef struct STaskRecheckInfo {
|
||||||
void* checkTimer;
|
void* checkTimer;
|
||||||
} STaskRecheckInfo;
|
} STaskRecheckInfo;
|
||||||
|
|
||||||
|
typedef struct STaskInitTs {
|
||||||
|
int64_t start;
|
||||||
|
int64_t end;
|
||||||
|
bool success;
|
||||||
|
} STaskInitTs;
|
||||||
|
|
||||||
static int32_t streamSetParamForScanHistory(SStreamTask* pTask);
|
static int32_t streamSetParamForScanHistory(SStreamTask* pTask);
|
||||||
static void streamTaskSetRangeStreamCalc(SStreamTask* pTask);
|
static void streamTaskSetRangeStreamCalc(SStreamTask* pTask);
|
||||||
static int32_t initScanHistoryReq(SStreamTask* pTask, SStreamScanHistoryReq* pReq, int8_t igUntreated);
|
static int32_t initScanHistoryReq(SStreamTask* pTask, SStreamScanHistoryReq* pReq, int8_t igUntreated);
|
||||||
|
@ -57,7 +67,7 @@ int32_t streamTaskSetReady(SStreamTask* pTask) {
|
||||||
stDebug("s-task:%s all %d downstream ready, init completed, elapsed time:%" PRId64 "ms, task status:%s",
|
stDebug("s-task:%s all %d downstream ready, init completed, elapsed time:%" PRId64 "ms, task status:%s",
|
||||||
pTask->id.idStr, numOfDowns, el, p);
|
pTask->id.idStr, numOfDowns, el, p);
|
||||||
|
|
||||||
streamMetaUpdateTaskReadyInfo(pTask);
|
streamMetaUpdateTaskDownstreamStatus(pTask, pTask->execInfo.init, pTask->execInfo.start, true);
|
||||||
return TSDB_CODE_SUCCESS;
|
return TSDB_CODE_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,6 +91,60 @@ int32_t streamStartScanHistoryAsync(SStreamTask* pTask, int8_t igUntreated) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void doReExecScanhistory(void* param, void* tmrId) {
|
||||||
|
SStreamTask* pTask = param;
|
||||||
|
pTask->schedHistoryInfo.numOfTicks -= 1;
|
||||||
|
|
||||||
|
char* p = NULL;
|
||||||
|
ETaskStatus status = streamTaskGetStatus(pTask, &p);
|
||||||
|
if (status == TASK_STATUS__DROPPING || status == TASK_STATUS__STOP) {
|
||||||
|
streamMetaReleaseTask(pTask->pMeta, pTask);
|
||||||
|
int32_t ref = atomic_sub_fetch_32(&pTask->status.timerActive, 1);
|
||||||
|
stDebug("s-task:%s status:%s not start scan-history again, ref:%d", pTask->id.idStr, p, ref);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pTask->schedHistoryInfo.numOfTicks <= 0) {
|
||||||
|
streamStartScanHistoryAsync(pTask, 0);
|
||||||
|
|
||||||
|
int32_t ref = atomic_sub_fetch_32(&pTask->status.timerActive, 1);
|
||||||
|
stDebug("s-task:%s fill-history:%d start scan-history data, out of tmr, ref:%d", pTask->id.idStr,
|
||||||
|
pTask->info.fillHistory, ref);
|
||||||
|
|
||||||
|
// release the task.
|
||||||
|
streamMetaReleaseTask(pTask->pMeta, pTask);
|
||||||
|
} else {
|
||||||
|
taosTmrReset(doReExecScanhistory, SCANHISTORY_IDLE_TIME_SLICE, pTask, streamEnv.timer,
|
||||||
|
&pTask->schedHistoryInfo.pTimer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t streamReExecScanHistoryFuture(SStreamTask* pTask, int32_t idleDuration) {
|
||||||
|
int32_t numOfTicks = idleDuration / SCANHISTORY_IDLE_TIME_SLICE;
|
||||||
|
if (numOfTicks <= 0) {
|
||||||
|
numOfTicks = 1;
|
||||||
|
} else if (numOfTicks > SCANHISTORY_IDLE_TICK) {
|
||||||
|
numOfTicks = SCANHISTORY_IDLE_TICK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add ref for task
|
||||||
|
SStreamTask* p = streamMetaAcquireTask(pTask->pMeta, pTask->id.streamId, pTask->id.taskId);
|
||||||
|
ASSERT(p != NULL);
|
||||||
|
|
||||||
|
pTask->schedHistoryInfo.numOfTicks = numOfTicks;
|
||||||
|
|
||||||
|
int32_t ref = atomic_add_fetch_32(&pTask->status.timerActive, 1);
|
||||||
|
stDebug("s-task:%s scan-history start in %.2fs, ref:%d", pTask->id.idStr, numOfTicks*0.1, ref);
|
||||||
|
|
||||||
|
if (pTask->schedHistoryInfo.pTimer == NULL) {
|
||||||
|
pTask->schedHistoryInfo.pTimer = taosTmrStart(doReExecScanhistory, SCANHISTORY_IDLE_TIME_SLICE, pTask, streamEnv.timer);
|
||||||
|
} else {
|
||||||
|
taosTmrReset(doReExecScanhistory, SCANHISTORY_IDLE_TIME_SLICE, pTask, streamEnv.timer, &pTask->schedHistoryInfo.pTimer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return TSDB_CODE_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
static int32_t doStartScanHistoryTask(SStreamTask* pTask) {
|
static int32_t doStartScanHistoryTask(SStreamTask* pTask) {
|
||||||
SVersionRange* pRange = &pTask->dataRange.range;
|
SVersionRange* pRange = &pTask->dataRange.range;
|
||||||
if (pTask->info.fillHistory) {
|
if (pTask->info.fillHistory) {
|
||||||
|
@ -318,6 +382,31 @@ void doProcessDownstreamReadyRsp(SStreamTask* pTask) {
|
||||||
streamTaskOnHandleEventSuccess(pTask->status.pSM, event);
|
streamTaskOnHandleEventSuccess(pTask->status.pSM, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void addIntoNodeUpdateList(SStreamTask* pTask, int32_t nodeId) {
|
||||||
|
int32_t vgId = pTask->pMeta->vgId;
|
||||||
|
|
||||||
|
taosThreadMutexLock(&pTask->lock);
|
||||||
|
int32_t num = taosArrayGetSize(pTask->outputInfo.pDownstreamUpdateList);
|
||||||
|
bool existed = false;
|
||||||
|
for (int i = 0; i < num; ++i) {
|
||||||
|
SDownstreamTaskEpset* p = taosArrayGet(pTask->outputInfo.pDownstreamUpdateList, i);
|
||||||
|
if (p->nodeId == nodeId) {
|
||||||
|
existed = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!existed) {
|
||||||
|
SDownstreamTaskEpset t = {.nodeId = nodeId};
|
||||||
|
taosArrayPush(pTask->outputInfo.pDownstreamUpdateList, &t);
|
||||||
|
|
||||||
|
stInfo("s-task:%s vgId:%d downstream nodeId:%d needs to be updated, total needs updated:%d", pTask->id.idStr, vgId,
|
||||||
|
t.nodeId, (int32_t)taosArrayGetSize(pTask->outputInfo.pDownstreamUpdateList));
|
||||||
|
}
|
||||||
|
|
||||||
|
taosThreadMutexUnlock(&pTask->lock);
|
||||||
|
}
|
||||||
|
|
||||||
int32_t streamProcessCheckRsp(SStreamTask* pTask, const SStreamTaskCheckRsp* pRsp) {
|
int32_t streamProcessCheckRsp(SStreamTask* pTask, const SStreamTaskCheckRsp* pRsp) {
|
||||||
ASSERT(pTask->id.taskId == pRsp->upstreamTaskId);
|
ASSERT(pTask->id.taskId == pRsp->upstreamTaskId);
|
||||||
const char* id = pTask->id.idStr;
|
const char* id = pTask->id.idStr;
|
||||||
|
@ -367,40 +456,23 @@ int32_t streamProcessCheckRsp(SStreamTask* pTask, const SStreamTaskCheckRsp* pRs
|
||||||
doProcessDownstreamReadyRsp(pTask);
|
doProcessDownstreamReadyRsp(pTask);
|
||||||
}
|
}
|
||||||
} else { // not ready, wait for 100ms and retry
|
} else { // not ready, wait for 100ms and retry
|
||||||
|
if (pRsp->status == TASK_UPSTREAM_NEW_STAGE || pRsp->status == TASK_DOWNSTREAM_NOT_LEADER) {
|
||||||
if (pRsp->status == TASK_UPSTREAM_NEW_STAGE) {
|
if (pRsp->status == TASK_UPSTREAM_NEW_STAGE) {
|
||||||
stError(
|
stError(
|
||||||
"s-task:%s vgId:%d self vnode-transfer/leader-change/restart detected, old stage:%d, current stage:%d, "
|
"s-task:%s vgId:%d self vnode-transfer/leader-change/restart detected, old stage:%d, current stage:%d, "
|
||||||
"not check wait for downstream task nodeUpdate, and all tasks restart",
|
"not check wait for downstream task nodeUpdate, and all tasks restart",
|
||||||
id, pRsp->upstreamNodeId, pRsp->oldStage, (int32_t)pTask->pMeta->stage);
|
id, pRsp->upstreamNodeId, pRsp->oldStage, (int32_t)pTask->pMeta->stage);
|
||||||
} else {
|
} else {
|
||||||
if (pRsp->status == TASK_DOWNSTREAM_NOT_LEADER) {
|
|
||||||
stError(
|
stError(
|
||||||
"s-task:%s downstream taskId:0x%x (vgId:%d) not leader, self dispatch epset needs to be updated, not check "
|
"s-task:%s downstream taskId:0x%x (vgId:%d) not leader, self dispatch epset needs to be updated, not check "
|
||||||
"downstream again, nodeUpdate needed",
|
"downstream again, nodeUpdate needed",
|
||||||
id, pRsp->downstreamTaskId, pRsp->downstreamNodeId);
|
id, pRsp->downstreamTaskId, pRsp->downstreamNodeId);
|
||||||
|
|
||||||
taosThreadMutexLock(&pTask->lock);
|
|
||||||
int32_t num = taosArrayGetSize(pTask->outputInfo.pDownstreamUpdateList);
|
|
||||||
bool existed = false;
|
|
||||||
for (int i = 0; i < num; ++i) {
|
|
||||||
SDownstreamTaskEpset* p = taosArrayGet(pTask->outputInfo.pDownstreamUpdateList, i);
|
|
||||||
if (p->nodeId == pRsp->downstreamNodeId) {
|
|
||||||
existed = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!existed) {
|
addIntoNodeUpdateList(pTask, pRsp->downstreamNodeId);
|
||||||
SDownstreamTaskEpset t = {.nodeId = pRsp->downstreamNodeId};
|
streamMetaUpdateTaskDownstreamStatus(pTask, pTask->execInfo.init, taosGetTimestampMs(), false);
|
||||||
taosArrayPush(pTask->outputInfo.pDownstreamUpdateList, &t);
|
|
||||||
stInfo("s-task:%s vgId:%d downstream nodeId:%d needs to be updated, total needs updated:%d", id, vgId,
|
|
||||||
t.nodeId, (int32_t)taosArrayGetSize(pTask->outputInfo.pDownstreamUpdateList));
|
|
||||||
}
|
|
||||||
|
|
||||||
taosThreadMutexUnlock(&pTask->lock);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
} else { // TASK_DOWNSTREAM_NOT_READY, let's retry in 100ms
|
||||||
STaskRecheckInfo* pInfo = createRecheckInfo(pTask, pRsp);
|
STaskRecheckInfo* pInfo = createRecheckInfo(pTask, pRsp);
|
||||||
|
|
||||||
int32_t ref = atomic_add_fetch_32(&pTask->status.timerActive, 1);
|
int32_t ref = atomic_add_fetch_32(&pTask->status.timerActive, 1);
|
||||||
|
@ -676,8 +748,7 @@ static void tryLaunchHistoryTask(void* param, void* tmrId) {
|
||||||
int32_t hTaskId = pHTaskInfo->id.taskId;
|
int32_t hTaskId = pHTaskInfo->id.taskId;
|
||||||
|
|
||||||
streamTaskGetStatus(pTask, &p);
|
streamTaskGetStatus(pTask, &p);
|
||||||
stDebug(
|
stDebug("s-task:%s status:%s failed to launch fill-history task:0x%x, retry launch:%dms, retryCount:%d",
|
||||||
"s-task:%s status:%s failed to launch fill-history task:0x%x, retry launch:%dms, retryCount:%d",
|
|
||||||
pTask->id.idStr, p, hTaskId, pHTaskInfo->waitInterval, pHTaskInfo->retryTimes);
|
pTask->id.idStr, p, hTaskId, pHTaskInfo->waitInterval, pHTaskInfo->retryTimes);
|
||||||
|
|
||||||
taosTmrReset(tryLaunchHistoryTask, LAUNCH_HTASK_INTERVAL, pInfo, streamEnv.timer, &pHTaskInfo->pTimer);
|
taosTmrReset(tryLaunchHistoryTask, LAUNCH_HTASK_INTERVAL, pInfo, streamEnv.timer, &pHTaskInfo->pTimer);
|
||||||
|
@ -975,28 +1046,57 @@ void streamTaskEnablePause(SStreamTask* pTask) {
|
||||||
pTask->status.pauseAllowed = 1;
|
pTask->status.pauseAllowed = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t streamMetaUpdateTaskReadyInfo(SStreamTask* pTask) {
|
static void displayStatusInfo(SStreamMeta* pMeta, SHashObj* pTaskSet, bool succ) {
|
||||||
|
int32_t vgId = pMeta->vgId;
|
||||||
|
void* pIter = NULL;
|
||||||
|
size_t keyLen = 0;
|
||||||
|
|
||||||
|
stInfo("vgId:%d %d tasks check-downstream completed %s", vgId, taosHashGetSize(pTaskSet),
|
||||||
|
succ ? "success" : "failed");
|
||||||
|
|
||||||
|
while ((pIter = taosHashIterate(pTaskSet, pIter)) != NULL) {
|
||||||
|
STaskInitTs* pInfo = pIter;
|
||||||
|
void* key = taosHashGetKey(pIter, &keyLen);
|
||||||
|
|
||||||
|
SStreamTask** pTask1 = taosHashGet(pMeta->pTasksMap, key, sizeof(STaskId));
|
||||||
|
if (pTask1 == NULL) {
|
||||||
|
stInfo("s-task:0x%x is dropped already, %s", (int32_t)((STaskId*)key)->taskId, succ ? "success" : "failed");
|
||||||
|
} else {
|
||||||
|
stInfo("s-task:%s level:%d vgId:%d, init:%" PRId64 ", initEnd:%" PRId64 ", %s", (*pTask1)->id.idStr,
|
||||||
|
(*pTask1)->info.taskLevel, vgId, pInfo->start, pInfo->end, pInfo->success ? "success" : "failed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t streamMetaUpdateTaskDownstreamStatus(SStreamTask* pTask, int64_t startTs, int64_t endTs, bool ready) {
|
||||||
SStreamMeta* pMeta = pTask->pMeta;
|
SStreamMeta* pMeta = pTask->pMeta;
|
||||||
|
|
||||||
streamMetaWLock(pMeta);
|
streamMetaWLock(pMeta);
|
||||||
|
|
||||||
STaskId id = streamTaskExtractKey(pTask);
|
STaskId id = streamTaskExtractKey(pTask);
|
||||||
taosHashPut(pMeta->startInfo.pReadyTaskSet, &id, sizeof(id), NULL, 0);
|
STaskStartInfo* pStartInfo = &pMeta->startInfo;
|
||||||
|
|
||||||
|
SHashObj* pDst = ready? pStartInfo->pReadyTaskSet:pStartInfo->pFailedTaskSet;
|
||||||
|
|
||||||
|
STaskInitTs initTs = {.start = startTs, .end = endTs, .success = ready};
|
||||||
|
taosHashPut(pDst, &id, sizeof(id), &initTs, sizeof(STaskInitTs));
|
||||||
|
|
||||||
int32_t numOfTotal = streamMetaGetNumOfTasks(pMeta);
|
int32_t numOfTotal = streamMetaGetNumOfTasks(pMeta);
|
||||||
|
|
||||||
if (taosHashGetSize(pMeta->startInfo.pReadyTaskSet) == numOfTotal) {
|
if (taosHashGetSize(pStartInfo->pReadyTaskSet) + taosHashGetSize(pStartInfo->pFailedTaskSet) == numOfTotal) {
|
||||||
STaskStartInfo* pStartInfo = &pMeta->startInfo;
|
|
||||||
|
|
||||||
pStartInfo->readyTs = pTask->execInfo.start;
|
pStartInfo->readyTs = pTask->execInfo.start;
|
||||||
pStartInfo->elapsedTime = (pStartInfo->startTs != 0) ? pStartInfo->readyTs - pStartInfo->startTs : 0;
|
pStartInfo->elapsedTime = (pStartInfo->startTs != 0) ? pStartInfo->readyTs - pStartInfo->startTs : 0;
|
||||||
|
|
||||||
streamMetaResetStartInfo(pStartInfo);
|
stDebug("vgId:%d all %d task(s) check downstream completed, last completed task:%s level:%d, startTs:%" PRId64
|
||||||
|
|
||||||
stDebug("vgId:%d all %d task(s) are started successfully, last ready task:%s level:%d, startTs:%" PRId64
|
|
||||||
", readyTs:%" PRId64 " total elapsed time:%.2fs",
|
", readyTs:%" PRId64 " total elapsed time:%.2fs",
|
||||||
pMeta->vgId, numOfTotal, pTask->id.idStr, pTask->info.taskLevel, pStartInfo->startTs, pStartInfo->readyTs,
|
pMeta->vgId, numOfTotal, pTask->id.idStr, pTask->info.taskLevel, pStartInfo->startTs, pStartInfo->readyTs,
|
||||||
pStartInfo->elapsedTime / 1000.0);
|
pStartInfo->elapsedTime / 1000.0);
|
||||||
|
|
||||||
|
// print the initialization elapsed time and info
|
||||||
|
displayStatusInfo(pMeta, pStartInfo->pReadyTaskSet, true);
|
||||||
|
displayStatusInfo(pMeta, pStartInfo->pFailedTaskSet, false);
|
||||||
|
|
||||||
|
streamMetaResetStartInfo(pStartInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
streamMetaWUnLock(pMeta);
|
streamMetaWUnLock(pMeta);
|
||||||
|
|
|
@ -400,8 +400,7 @@ void tFreeStreamTask(SStreamTask* pTask) {
|
||||||
taosMemoryFree(pTask->outputInfo.pTokenBucket);
|
taosMemoryFree(pTask->outputInfo.pTokenBucket);
|
||||||
taosThreadMutexDestroy(&pTask->lock);
|
taosThreadMutexDestroy(&pTask->lock);
|
||||||
|
|
||||||
taosArrayDestroy(pTask->outputInfo.pDownstreamUpdateList);
|
pTask->outputInfo.pDownstreamUpdateList = taosArrayDestroy(pTask->outputInfo.pDownstreamUpdateList);
|
||||||
pTask->outputInfo.pDownstreamUpdateList = NULL;
|
|
||||||
|
|
||||||
taosMemoryFree(pTask);
|
taosMemoryFree(pTask);
|
||||||
stDebug("s-task:0x%x free task completed", taskId);
|
stDebug("s-task:0x%x free task completed", taskId);
|
||||||
|
@ -447,7 +446,7 @@ int32_t streamTaskInit(SStreamTask* pTask, SStreamMeta* pMeta, SMsgCb* pMsgCb, i
|
||||||
|
|
||||||
// 2MiB per second for sink task
|
// 2MiB per second for sink task
|
||||||
// 50 times sink operator per second
|
// 50 times sink operator per second
|
||||||
streamTaskInitTokenBucket(pTask->outputInfo.pTokenBucket, 50, 50, tsSinkDataRate);
|
streamTaskInitTokenBucket(pTask->outputInfo.pTokenBucket, 50, 50, tsSinkDataRate, pTask->id.idStr);
|
||||||
|
|
||||||
TdThreadMutexAttr attr = {0};
|
TdThreadMutexAttr attr = {0};
|
||||||
int code = taosThreadMutexAttrInit(&attr);
|
int code = taosThreadMutexAttrInit(&attr);
|
||||||
|
|
|
@ -315,7 +315,6 @@ int32_t streamTaskOnHandleEventSuccess(SStreamTaskSM* pSM, EStreamTaskEvent even
|
||||||
GET_EVT_NAME(event), pSM->current.name, GET_EVT_NAME(pSM->prev.evt));
|
GET_EVT_NAME(event), pSM->current.name, GET_EVT_NAME(pSM->prev.evt));
|
||||||
|
|
||||||
taosThreadMutexUnlock(&pTask->lock);
|
taosThreadMutexUnlock(&pTask->lock);
|
||||||
stDebug("s-task:%s unlockx", pTask->id.idStr);
|
|
||||||
return TSDB_CODE_STREAM_INVALID_STATETRANS;
|
return TSDB_CODE_STREAM_INVALID_STATETRANS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,6 +18,17 @@ TARGET_INCLUDE_DIRECTORIES(
|
||||||
PRIVATE "${TD_SOURCE_DIR}/source/libs/stream/inc"
|
PRIVATE "${TD_SOURCE_DIR}/source/libs/stream/inc"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
ADD_EXECUTABLE(checkpointTest checkpointTest.cpp)
|
||||||
|
TARGET_LINK_LIBRARIES(
|
||||||
|
checkpointTest
|
||||||
|
PUBLIC os common gtest stream executor qcom index transport util
|
||||||
|
)
|
||||||
|
|
||||||
|
TARGET_INCLUDE_DIRECTORIES(
|
||||||
|
checkpointTest
|
||||||
|
PRIVATE "${TD_SOURCE_DIR}/source/libs/stream/inc"
|
||||||
|
)
|
||||||
|
|
||||||
add_test(
|
add_test(
|
||||||
NAME streamUpdateTest
|
NAME streamUpdateTest
|
||||||
COMMAND streamUpdateTest
|
COMMAND streamUpdateTest
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||||
|
*
|
||||||
|
* This program is free software: you can use, redistribute, and/or modify
|
||||||
|
* it under the terms of the GNU Affero General Public License, version 3
|
||||||
|
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include <taoserror.h>
|
||||||
|
#include <tglobal.h>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wwrite-strings"
|
||||||
|
#pragma GCC diagnostic ignored "-Wunused-function"
|
||||||
|
#pragma GCC diagnostic ignored "-Wunused-variable"
|
||||||
|
#pragma GCC diagnostic ignored "-Wsign-compare"
|
||||||
|
|
||||||
|
#include "rsync.h"
|
||||||
|
#include "streamInt.h"
|
||||||
|
#include "cos.h"
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
testing::InitGoogleTest(&argc, argv);
|
||||||
|
|
||||||
|
if (taosInitCfg("/etc/taos/", NULL, NULL, NULL, NULL, 0) != 0) {
|
||||||
|
printf("error");
|
||||||
|
}
|
||||||
|
if (s3Init() < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
strcpy(tsSnodeAddress, "127.0.0.1");
|
||||||
|
return RUN_ALL_TESTS();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(testCase, checkpointUpload_Test) {
|
||||||
|
stopRsync();
|
||||||
|
startRsync();
|
||||||
|
|
||||||
|
taosSsleep(5);
|
||||||
|
char* id = "2013892036";
|
||||||
|
|
||||||
|
uploadCheckpoint(id, "/root/offset/");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(testCase, checkpointDownload_Test) {
|
||||||
|
char* id = "2013892036";
|
||||||
|
downloadCheckpoint(id, "/root/offset/download/");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(testCase, checkpointDelete_Test) {
|
||||||
|
char* id = "2013892036";
|
||||||
|
deleteCheckpoint(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(testCase, checkpointDeleteFile_Test) {
|
||||||
|
char* id = "2013892036";
|
||||||
|
deleteCheckpointFile(id, "offset-ver0");
|
||||||
|
}
|
|
@ -865,6 +865,9 @@ static int32_t syncSnapBufferRecv(SSyncSnapshotReceiver *pReceiver, SyncSnapshot
|
||||||
ASSERT(pRcvBuf->start <= pRcvBuf->cursor + 1 && pRcvBuf->cursor < pRcvBuf->end);
|
ASSERT(pRcvBuf->start <= pRcvBuf->cursor + 1 && pRcvBuf->cursor < pRcvBuf->end);
|
||||||
|
|
||||||
if (pMsg->seq > pRcvBuf->cursor) {
|
if (pMsg->seq > pRcvBuf->cursor) {
|
||||||
|
if (pRcvBuf->entries[pMsg->seq % pRcvBuf->size]) {
|
||||||
|
pRcvBuf->entryDeleteCb(pRcvBuf->entries[pMsg->seq % pRcvBuf->size]);
|
||||||
|
}
|
||||||
pRcvBuf->entries[pMsg->seq % pRcvBuf->size] = pMsg;
|
pRcvBuf->entries[pMsg->seq % pRcvBuf->size] = pMsg;
|
||||||
ppMsg[0] = NULL;
|
ppMsg[0] = NULL;
|
||||||
pRcvBuf->end = TMAX(pMsg->seq + 1, pRcvBuf->end);
|
pRcvBuf->end = TMAX(pMsg->seq + 1, pRcvBuf->end);
|
||||||
|
@ -1002,7 +1005,8 @@ int32_t syncNodeOnSnapshot(SSyncNode *pSyncNode, SRpcMsg *pRpcMsg) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pMsg->term < raftStoreGetTerm(pSyncNode)) {
|
if (pMsg->term < raftStoreGetTerm(pSyncNode)) {
|
||||||
syncLogRecvSyncSnapshotSend(pSyncNode, pMsg, "reject since small term");
|
sRError(pReceiver, "reject snap replication with smaller term. msg term:%" PRId64 ", seq:%d", pMsg->term,
|
||||||
|
pMsg->seq);
|
||||||
terrno = TSDB_CODE_SYN_MISMATCHED_SIGNATURE;
|
terrno = TSDB_CODE_SYN_MISMATCHED_SIGNATURE;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -268,7 +268,7 @@ void syncPrintSnapshotSenderLog(const char* flags, ELogLevel level, int32_t dfla
|
||||||
|
|
||||||
taosPrintLog(flags, level, dflag,
|
taosPrintLog(flags, level, dflag,
|
||||||
"vgId:%d, %s, sync:%s, snap-sender:%p signature:(%" PRId64 ", %" PRId64 "), {start:%" PRId64
|
"vgId:%d, %s, sync:%s, snap-sender:%p signature:(%" PRId64 ", %" PRId64 "), {start:%" PRId64
|
||||||
" end:%" PRId64 " last-index:%" PRId64 " last-term:%" PRIu64 " last-cfg:%" PRId64
|
" end:%" PRId64 " last-index:%" PRId64 " last-term:%" PRId64 " last-cfg:%" PRId64
|
||||||
", seq:%d, ack:%d, "
|
", seq:%d, ack:%d, "
|
||||||
" buf:[%" PRId64 " %" PRId64 ", %" PRId64
|
" buf:[%" PRId64 " %" PRId64 ", %" PRId64
|
||||||
"), finish:%d, as:%d, to-dnode:%d}"
|
"), finish:%d, as:%d, to-dnode:%d}"
|
||||||
|
|
|
@ -369,6 +369,15 @@ int32_t cfgCheckRangeForDynUpdate(SConfig *pCfg, const char *name, const char *p
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (pItem->dtype) {
|
switch (pItem->dtype) {
|
||||||
|
case CFG_DTYPE_BOOL: {
|
||||||
|
int32_t ival = (int32_t)atoi(pVal);
|
||||||
|
if (ival != 0 && ival != 1) {
|
||||||
|
uError("cfg:%s, type:%s value:%d out of range[0, 1]", pItem->name,
|
||||||
|
cfgDtypeStr(pItem->dtype), ival);
|
||||||
|
terrno = TSDB_CODE_OUT_OF_RANGE;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
case CFG_DTYPE_INT32: {
|
case CFG_DTYPE_INT32: {
|
||||||
int32_t ival = (int32_t)atoi(pVal);
|
int32_t ival = (int32_t)atoi(pVal);
|
||||||
if (ival < pItem->imin || ival > pItem->imax) {
|
if (ival < pItem->imin || ival > pItem->imax) {
|
||||||
|
|
|
@ -69,6 +69,10 @@
|
||||||
,,y,system-test,./pytest.sh python3 ./test.py -f 2-query/func_to_char_timestamp.py -Q 2
|
,,y,system-test,./pytest.sh python3 ./test.py -f 2-query/func_to_char_timestamp.py -Q 2
|
||||||
,,y,system-test,./pytest.sh python3 ./test.py -f 2-query/func_to_char_timestamp.py -Q 3
|
,,y,system-test,./pytest.sh python3 ./test.py -f 2-query/func_to_char_timestamp.py -Q 3
|
||||||
,,y,system-test,./pytest.sh python3 ./test.py -f 2-query/func_to_char_timestamp.py -Q 4
|
,,y,system-test,./pytest.sh python3 ./test.py -f 2-query/func_to_char_timestamp.py -Q 4
|
||||||
|
,,y,system-test,./pytest.sh python3 ./test.py -f 2-query/last_cache_scan.py
|
||||||
|
,,y,system-test,./pytest.sh python3 ./test.py -f 2-query/last_cache_scan.py -Q 2
|
||||||
|
,,y,system-test,./pytest.sh python3 ./test.py -f 2-query/last_cache_scan.py -Q 3
|
||||||
|
,,y,system-test,./pytest.sh python3 ./test.py -f 2-query/last_cache_scan.py -Q 4
|
||||||
,,y,system-test,./pytest.sh python3 ./test.py -f 7-tmq/tmqShow.py
|
,,y,system-test,./pytest.sh python3 ./test.py -f 7-tmq/tmqShow.py
|
||||||
,,y,system-test,./pytest.sh python3 ./test.py -f 7-tmq/tmqDropStb.py
|
,,y,system-test,./pytest.sh python3 ./test.py -f 7-tmq/tmqDropStb.py
|
||||||
,,y,system-test,./pytest.sh python3 ./test.py -f 7-tmq/subscribeStb0.py
|
,,y,system-test,./pytest.sh python3 ./test.py -f 7-tmq/subscribeStb0.py
|
||||||
|
@ -232,6 +236,8 @@ e
|
||||||
,,y,system-test,./pytest.sh python3 ./test.py -f 0-others/splitVGroupRep1.py -N 3
|
,,y,system-test,./pytest.sh python3 ./test.py -f 0-others/splitVGroupRep1.py -N 3
|
||||||
,,y,system-test,./pytest.sh python3 ./test.py -f 0-others/splitVGroupRep3.py -N 3
|
,,y,system-test,./pytest.sh python3 ./test.py -f 0-others/splitVGroupRep3.py -N 3
|
||||||
,,n,system-test,python3 ./test.py -f 0-others/timeRangeWise.py -N 3
|
,,n,system-test,python3 ./test.py -f 0-others/timeRangeWise.py -N 3
|
||||||
|
,,y,system-test,./pytest.sh python3 ./test.py -f 0-others/delete_check.py
|
||||||
|
|
||||||
,,y,system-test,./pytest.sh python3 ./test.py -f 1-insert/alter_database.py
|
,,y,system-test,./pytest.sh python3 ./test.py -f 1-insert/alter_database.py
|
||||||
,,y,system-test,./pytest.sh python3 ./test.py -f 1-insert/alter_replica.py -N 3
|
,,y,system-test,./pytest.sh python3 ./test.py -f 1-insert/alter_replica.py -N 3
|
||||||
,,y,system-test,./pytest.sh python3 ./test.py -f 1-insert/influxdb_line_taosc_insert.py
|
,,y,system-test,./pytest.sh python3 ./test.py -f 1-insert/influxdb_line_taosc_insert.py
|
||||||
|
|
|
@ -133,8 +133,6 @@ class AutoGen:
|
||||||
if batch_size == 1 or (i > 0 and i % batch_size == 0) :
|
if batch_size == 1 or (i > 0 and i % batch_size == 0) :
|
||||||
sql = f"insert into {child_name} values {values}"
|
sql = f"insert into {child_name} values {values}"
|
||||||
tdSql.execute(sql)
|
tdSql.execute(sql)
|
||||||
if batch_size > 40:
|
|
||||||
tdLog.info(f" insert data i={i}")
|
|
||||||
values = ""
|
values = ""
|
||||||
|
|
||||||
# end batch
|
# end batch
|
||||||
|
|
|
@ -19,6 +19,7 @@ exe:
|
||||||
gcc $(CFLAGS) ./whiteListTest.c -o $(ROOT)whiteListTest $(LFLAGS)
|
gcc $(CFLAGS) ./whiteListTest.c -o $(ROOT)whiteListTest $(LFLAGS)
|
||||||
gcc $(CFLAGS) ./insert_stb.c -o $(ROOT)insert_stb $(LFLAGS)
|
gcc $(CFLAGS) ./insert_stb.c -o $(ROOT)insert_stb $(LFLAGS)
|
||||||
gcc $(CFLAGS) ./tmqViewTest.c -o $(ROOT)tmqViewTest $(LFLAGS)
|
gcc $(CFLAGS) ./tmqViewTest.c -o $(ROOT)tmqViewTest $(LFLAGS)
|
||||||
|
gcc $(CFLAGS) ./stmtQuery.c -o $(ROOT)stmtQuery $(LFLAGS)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm $(ROOT)batchprepare
|
rm $(ROOT)batchprepare
|
||||||
|
@ -29,3 +30,4 @@ clean:
|
||||||
rm $(ROOT)whiteListTest
|
rm $(ROOT)whiteListTest
|
||||||
rm $(ROOT)insert_stb
|
rm $(ROOT)insert_stb
|
||||||
rm $(ROOT)tmqViewTest
|
rm $(ROOT)tmqViewTest
|
||||||
|
rm $(ROOT)stmtQuery
|
||||||
|
|
|
@ -0,0 +1,129 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include "../../../include/client/taos.h"
|
||||||
|
|
||||||
|
#define PRINT_ERROR printf("\033[31m");
|
||||||
|
#define PRINT_SUCCESS printf("\033[32m");
|
||||||
|
|
||||||
|
void execute_simple_sql(void *taos, char *sql) {
|
||||||
|
TAOS_RES *result = taos_query(taos, sql);
|
||||||
|
if ( result == NULL || taos_errno(result) != 0) {
|
||||||
|
PRINT_ERROR
|
||||||
|
printf("failed to %s, Reason: %s\n", sql, taos_errstr(result));
|
||||||
|
taos_free_result(result);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
taos_free_result(result);
|
||||||
|
PRINT_SUCCESS
|
||||||
|
printf("Successfully %s\n", sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
void check_result(TAOS_RES *result, int expected) {
|
||||||
|
int rows = 0;
|
||||||
|
TAOS_ROW row;
|
||||||
|
while ((row = taos_fetch_row(result))) {
|
||||||
|
rows++;
|
||||||
|
}
|
||||||
|
if (rows == expected) {
|
||||||
|
PRINT_SUCCESS
|
||||||
|
printf("%d rows are fetched as expected\n", rows);
|
||||||
|
} else {
|
||||||
|
PRINT_ERROR
|
||||||
|
printf("%d rows are fetched but %d expected\n", rows, expected);
|
||||||
|
}
|
||||||
|
taos_free_result(result);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
void *taos = taos_connect("127.0.0.1", "root", "taosdata", NULL, 0);
|
||||||
|
if (taos == NULL) {
|
||||||
|
PRINT_ERROR
|
||||||
|
printf("TDengine error: failed to connect\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
PRINT_SUCCESS
|
||||||
|
printf("Successfully connected to TDengine\n");
|
||||||
|
|
||||||
|
execute_simple_sql(taos, "drop database if exists test");
|
||||||
|
execute_simple_sql(taos, "create database test");
|
||||||
|
execute_simple_sql(taos, "use test");
|
||||||
|
execute_simple_sql(taos, "create table super(ts timestamp, c1 int, c2 bigint, c3 float, c4 double, c5 binary(8), c6 smallint, c7 tinyint, c8 bool, c9 nchar(8), c10 timestamp) tags (t1 int, t2 bigint, t3 float, t4 double, t5 binary(8), t6 smallint, t7 tinyint, t8 bool, t9 nchar(8))");
|
||||||
|
|
||||||
|
char *sql = calloc(1, 1024*1024);
|
||||||
|
int sqlLen = 0;
|
||||||
|
sqlLen = sprintf(sql, "create table");
|
||||||
|
for (int i = 0; i < 10; i++) {
|
||||||
|
sqlLen += sprintf(sql + sqlLen, " t%d using super tags (%d, 2147483648, 0.1, 0.000000001, 'abcdefgh', 32767, 127, 1, '一二三四五六七八')", i, i);
|
||||||
|
}
|
||||||
|
execute_simple_sql(taos, sql);
|
||||||
|
|
||||||
|
strcpy(sql, "insert into t0 (ts, c1) values(now, 1)");
|
||||||
|
execute_simple_sql(taos, sql);
|
||||||
|
|
||||||
|
strcpy(sql, "insert into t0 (ts, c1) values(now, 2)");
|
||||||
|
execute_simple_sql(taos, sql);
|
||||||
|
|
||||||
|
strcpy(sql, "insert into t0 (ts, c1) values(now, 3)");
|
||||||
|
execute_simple_sql(taos, sql);
|
||||||
|
|
||||||
|
|
||||||
|
int code = taos_load_table_info(taos, "t0,t1,t2,t3,t4,t5,t6,t7,t8,t9");
|
||||||
|
if (code != 0) {
|
||||||
|
PRINT_ERROR
|
||||||
|
printf("failed to load table info: 0x%08x\n", code);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
PRINT_SUCCESS
|
||||||
|
printf("Successfully load table info\n");
|
||||||
|
|
||||||
|
TAOS_STMT *stmt = taos_stmt_init(taos);
|
||||||
|
if (stmt == NULL) {
|
||||||
|
PRINT_ERROR
|
||||||
|
printf("TDengine error: failed to init taos_stmt\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
PRINT_SUCCESS
|
||||||
|
printf("Successfully init taos_stmt\n");
|
||||||
|
|
||||||
|
|
||||||
|
char* condBuf = "2 or c1 > 0";
|
||||||
|
TAOS_MULTI_BIND params[1];
|
||||||
|
params[0].buffer_type = TSDB_DATA_TYPE_BINARY;
|
||||||
|
params[0].buffer_length = strlen(condBuf) + 1;
|
||||||
|
params[0].buffer = condBuf;
|
||||||
|
params[0].length = (int*)¶ms[0].buffer_length;
|
||||||
|
params[0].is_null = NULL;
|
||||||
|
params[0].num = 1;
|
||||||
|
|
||||||
|
char *stmt_sql = "select * from super where c1 > ?";
|
||||||
|
code = taos_stmt_prepare(stmt, stmt_sql, 0);
|
||||||
|
if (code != 0){
|
||||||
|
PRINT_ERROR
|
||||||
|
printf("failed to execute taos_stmt_prepare. code:0x%x\n", code);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
PRINT_SUCCESS
|
||||||
|
printf("Successfully execute taos_stmt_prepare\n");
|
||||||
|
|
||||||
|
taos_stmt_bind_param(stmt, params);
|
||||||
|
taos_stmt_add_batch(stmt);
|
||||||
|
|
||||||
|
if (taos_stmt_execute(stmt) != 0) {
|
||||||
|
PRINT_ERROR
|
||||||
|
printf("failed to execute query statement.\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
PRINT_SUCCESS
|
||||||
|
printf("Successfully execute query statement.\n");
|
||||||
|
|
||||||
|
TAOS_RES *result = taos_stmt_use_result(stmt);
|
||||||
|
check_result(result, 1);
|
||||||
|
|
||||||
|
|
||||||
|
taos_stmt_close(stmt);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -70,6 +70,7 @@ sql_error insert into d2.st values(now, 1, 1)
|
||||||
sql_error insert into d2.st(ts, f) values(now, 1);
|
sql_error insert into d2.st(ts, f) values(now, 1);
|
||||||
sql_error insert into d2.st(ts, f, tbname) values(now, 1);
|
sql_error insert into d2.st(ts, f, tbname) values(now, 1);
|
||||||
sql_error insert into d2.st(ts, f, tbname) values(now, 1, '');
|
sql_error insert into d2.st(ts, f, tbname) values(now, 1, '');
|
||||||
|
sql_error insert into d2.st(ts, f, tbname) values(now, 1, 'd2.ct2');
|
||||||
sql_error insert into d2.st(ts, tbname) values(now, 1, 34)
|
sql_error insert into d2.st(ts, tbname) values(now, 1, 34)
|
||||||
sql_error insert into st using st2 tags(2) values(now,1);
|
sql_error insert into st using st2 tags(2) values(now,1);
|
||||||
system sh/exec.sh -n dnode1 -s stop -x SIGINT
|
system sh/exec.sh -n dnode1 -s stop -x SIGINT
|
||||||
|
|
|
@ -164,4 +164,9 @@ sql select count(*) from (select tags ts from stb34)
|
||||||
if $data00 != 2 then
|
if $data00 != 2 then
|
||||||
return -1
|
return -1
|
||||||
endi
|
endi
|
||||||
|
|
||||||
|
sql select tags 2 from stb34
|
||||||
|
if $rows != 1 then
|
||||||
|
return -1
|
||||||
|
endi
|
||||||
system sh/exec.sh -n dnode1 -s stop -x SIGINT
|
system sh/exec.sh -n dnode1 -s stop -x SIGINT
|
||||||
|
|
|
@ -0,0 +1,154 @@
|
||||||
|
###################################################################
|
||||||
|
# Copyright (c) 2016 by TAOS Technologies, Inc.
|
||||||
|
# All rights reserved.
|
||||||
|
#
|
||||||
|
# This file is proprietary and confidential to TAOS Technologies.
|
||||||
|
# No part of this file may be reproduced, stored, transmitted,
|
||||||
|
# disclosed or used in any form or by any means other than as
|
||||||
|
# expressly provided by the written permission from Jianhui Tao
|
||||||
|
#
|
||||||
|
###################################################################
|
||||||
|
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
|
||||||
|
from util.log import *
|
||||||
|
from util.cases import *
|
||||||
|
from util.sql import *
|
||||||
|
from util.common import *
|
||||||
|
from util.sqlset import *
|
||||||
|
from util.autogen import *
|
||||||
|
|
||||||
|
import random
|
||||||
|
import time
|
||||||
|
import traceback
|
||||||
|
import os
|
||||||
|
from os import path
|
||||||
|
|
||||||
|
|
||||||
|
class TDTestCase:
|
||||||
|
# init
|
||||||
|
def init(self, conn, logSql, replicaVar=1):
|
||||||
|
self.replicaVar = int(replicaVar)
|
||||||
|
tdLog.debug("start to execute %s" % __file__)
|
||||||
|
tdSql.init(conn.cursor(), True)
|
||||||
|
|
||||||
|
# autoGen
|
||||||
|
self.autoGen = AutoGen()
|
||||||
|
# init cluster path
|
||||||
|
selfPath = os.path.dirname(os.path.realpath(__file__))
|
||||||
|
if ("community" in selfPath):
|
||||||
|
projPath = selfPath[:selfPath.find("community")]
|
||||||
|
else:
|
||||||
|
projPath = selfPath[:selfPath.find("tests")]
|
||||||
|
self.projDir = f"{projPath}sim/"
|
||||||
|
tdLog.info(f" init projPath={self.projDir}")
|
||||||
|
|
||||||
|
def compactDatbase(self):
|
||||||
|
# compact database
|
||||||
|
tdSql.execute(f"compact database {self.dbname}", show=True)
|
||||||
|
waitSeconds = 20
|
||||||
|
if self.waitTranslation(waitSeconds) == False:
|
||||||
|
tdLog.exit(f"translation can not finish after wait {waitSeconds} seconds")
|
||||||
|
return
|
||||||
|
|
||||||
|
# check tsdb folder empty
|
||||||
|
def check_tsdb_dir(self, tsdbDir):
|
||||||
|
for vfile in os.listdir(tsdbDir):
|
||||||
|
fileName, ext = os.path.splitext(vfile)
|
||||||
|
pathFile = os.path.join(tsdbDir, vfile)
|
||||||
|
ext = ext.lower()
|
||||||
|
tdLog.info(f"check exist file {pathFile} ...")
|
||||||
|
if ext == ".head" or ext == ".data" or ext == ".stt" or ext == ".sma":
|
||||||
|
tdLog.info(f"found {pathFile} not to be deleted ...")
|
||||||
|
real = True
|
||||||
|
for i in range(50):
|
||||||
|
tdLog.info(f"i={i} compact and try again ...")
|
||||||
|
self.compactDatbase()
|
||||||
|
if os.path.exists(pathFile) is False:
|
||||||
|
real = False
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
time.sleep(0.5)
|
||||||
|
tdLog.info(f"file real exist {pathFile} , sleep 500ms and try")
|
||||||
|
|
||||||
|
if real is False:
|
||||||
|
continue
|
||||||
|
fileStat = os.stat(pathFile)
|
||||||
|
tdLog.exit(f" check file can not be deleted. file={pathFile} file size={fileStat.st_size}")
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
# check vnode tsdb folder empty
|
||||||
|
def check_filedelete(self):
|
||||||
|
# put all vnode to list
|
||||||
|
for dnode in os.listdir(self.projDir):
|
||||||
|
vnodesDir = self.projDir + f"{dnode}/data/vnode/"
|
||||||
|
if os.path.isdir(vnodesDir) == False or dnode[:5] != "dnode":
|
||||||
|
continue
|
||||||
|
print(f"vnodesDir={vnodesDir}")
|
||||||
|
# enum all vnode
|
||||||
|
for vnode in os.listdir(vnodesDir):
|
||||||
|
vnodeDir = path.join(vnodesDir, vnode)
|
||||||
|
print(f"vnodeDir={vnodeDir}")
|
||||||
|
if os.path.isdir(vnodesDir):
|
||||||
|
tsdbDir = path.join(vnodeDir, "tsdb")
|
||||||
|
if path.exists(tsdbDir) :
|
||||||
|
self.check_tsdb_dir(tsdbDir)
|
||||||
|
|
||||||
|
def waitTranslation(self, waitSeconds):
|
||||||
|
# wait end
|
||||||
|
for i in range(waitSeconds):
|
||||||
|
sql ="show transactions;"
|
||||||
|
rows = tdSql.query(sql)
|
||||||
|
if rows == 0:
|
||||||
|
return True
|
||||||
|
tdLog.info(f"i={i} wait for translation finish ...")
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
# run
|
||||||
|
def run(self):
|
||||||
|
# seed
|
||||||
|
random.seed(int(time.time()))
|
||||||
|
self.dbname = "deletecheck"
|
||||||
|
stbname = "meters"
|
||||||
|
childname= "d"
|
||||||
|
child_cnt = 2
|
||||||
|
batch_size = 8000
|
||||||
|
insert_rows = 100015
|
||||||
|
start_ts = 1600000000000
|
||||||
|
|
||||||
|
self.autoGen.create_db(self.dbname)
|
||||||
|
|
||||||
|
loop = 3
|
||||||
|
for i in range(loop):
|
||||||
|
self.autoGen.create_stable(stbname, 4, 10, 4, 8)
|
||||||
|
self.autoGen.create_child(stbname, childname, child_cnt)
|
||||||
|
self.autoGen.set_batch_size(batch_size)
|
||||||
|
self.autoGen.insert_data(insert_rows)
|
||||||
|
self.autoGen.set_start_ts(start_ts)
|
||||||
|
|
||||||
|
if i % 2 == 1:
|
||||||
|
tdSql.execute(f"flush database {self.dbname}", show=True)
|
||||||
|
|
||||||
|
# drop stable
|
||||||
|
tdSql.execute(f"drop table {self.dbname}.{stbname} ", show = True)
|
||||||
|
|
||||||
|
self.compactDatbase()
|
||||||
|
|
||||||
|
# check file delete
|
||||||
|
self.check_filedelete()
|
||||||
|
tdLog.info(f"loop = {i+1} / {loop} check file delete ok after drop table successfully.")
|
||||||
|
|
||||||
|
start_ts += i*100000000
|
||||||
|
|
||||||
|
|
||||||
|
# stop
|
||||||
|
def stop(self):
|
||||||
|
tdSql.close()
|
||||||
|
tdLog.success("%s successfully executed" % __file__)
|
||||||
|
|
||||||
|
tdCases.addWindows(__file__, TDTestCase())
|
||||||
|
tdCases.addLinux(__file__, TDTestCase())
|
|
@ -0,0 +1,298 @@
|
||||||
|
import taos
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import socket
|
||||||
|
import os
|
||||||
|
import threading
|
||||||
|
import math
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
from util.log import *
|
||||||
|
from util.sql import *
|
||||||
|
from util.cases import *
|
||||||
|
from util.dnodes import *
|
||||||
|
from util.common import *
|
||||||
|
# from tmqCommon import *
|
||||||
|
|
||||||
|
COMPARE_DATA = 0
|
||||||
|
COMPARE_LEN = 1
|
||||||
|
|
||||||
|
class TDTestCase:
|
||||||
|
def __init__(self):
|
||||||
|
self.vgroups = 4
|
||||||
|
self.ctbNum = 10
|
||||||
|
self.rowsPerTbl = 10000
|
||||||
|
self.duraion = '1h'
|
||||||
|
|
||||||
|
def init(self, conn, logSql, replicaVar=1):
|
||||||
|
self.replicaVar = int(replicaVar)
|
||||||
|
tdLog.debug(f"start to excute {__file__}")
|
||||||
|
tdSql.init(conn.cursor(), False)
|
||||||
|
|
||||||
|
def create_database(self,tsql, dbName,dropFlag=1,vgroups=2,replica=1, duration:str='1d'):
|
||||||
|
if dropFlag == 1:
|
||||||
|
tsql.execute("drop database if exists %s"%(dbName))
|
||||||
|
|
||||||
|
tsql.execute("create database if not exists %s vgroups %d replica %d duration %s CACHEMODEL 'both'"%(dbName, vgroups, replica, duration))
|
||||||
|
tdLog.debug("complete to create database %s"%(dbName))
|
||||||
|
return
|
||||||
|
|
||||||
|
def create_stable(self,tsql, paraDict):
|
||||||
|
colString = tdCom.gen_column_type_str(colname_prefix=paraDict["colPrefix"], column_elm_list=paraDict["colSchema"])
|
||||||
|
tagString = tdCom.gen_tag_type_str(tagname_prefix=paraDict["tagPrefix"], tag_elm_list=paraDict["tagSchema"])
|
||||||
|
sqlString = f"create table if not exists %s.%s (%s) tags (%s)"%(paraDict["dbName"], paraDict["stbName"], colString, tagString)
|
||||||
|
tdLog.debug("%s"%(sqlString))
|
||||||
|
tsql.execute(sqlString)
|
||||||
|
return
|
||||||
|
|
||||||
|
def create_ctable(self,tsql=None, dbName='dbx',stbName='stb',ctbPrefix='ctb',ctbNum=1,ctbStartIdx=0):
|
||||||
|
for i in range(ctbNum):
|
||||||
|
sqlString = "create table %s.%s%d using %s.%s tags(%d, 'tb%d', 'tb%d', %d, %d, %d)" % \
|
||||||
|
(dbName,ctbPrefix,i+ctbStartIdx,dbName,stbName,(i+ctbStartIdx) % 5,i+ctbStartIdx,i+ctbStartIdx,i+ctbStartIdx,i+ctbStartIdx,i+ctbStartIdx)
|
||||||
|
tsql.execute(sqlString)
|
||||||
|
|
||||||
|
tdLog.debug("complete to create %d child tables by %s.%s" %(ctbNum, dbName, stbName))
|
||||||
|
return
|
||||||
|
|
||||||
|
def insert_data(self,tsql,dbName,ctbPrefix,ctbNum,rowsPerTbl,batchNum,startTs,tsStep):
|
||||||
|
tdLog.debug("start to insert data ............")
|
||||||
|
tsql.execute("use %s" %dbName)
|
||||||
|
pre_insert = "insert into "
|
||||||
|
sql = pre_insert
|
||||||
|
|
||||||
|
for i in range(ctbNum):
|
||||||
|
rowsBatched = 0
|
||||||
|
sql += " %s%d values "%(ctbPrefix,i)
|
||||||
|
for j in range(rowsPerTbl):
|
||||||
|
if (i < ctbNum/2):
|
||||||
|
sql += "(%d, %d, %d, %d,%d,%d,%d,true,'binary%d', 'nchar%d', %d) "%(startTs + j*tsStep, j%1000, j%500, j%1000, j%5000, j%5400, j%128, j%10000, j%1000, startTs+j*tsStep+1000)
|
||||||
|
else:
|
||||||
|
sql += "(%d, %d, NULL, %d,NULL,%d,%d,true,'binary%d', 'nchar%d', %d) "%(startTs + j*tsStep, j%1000, j%500, j%1000, j%128, j%10000, j%1000, startTs + j*tsStep + 1000)
|
||||||
|
rowsBatched += 1
|
||||||
|
if ((rowsBatched == batchNum) or (j == rowsPerTbl - 1)):
|
||||||
|
tsql.execute(sql)
|
||||||
|
rowsBatched = 0
|
||||||
|
if j < rowsPerTbl - 1:
|
||||||
|
sql = "insert into %s%d values " %(ctbPrefix,i)
|
||||||
|
else:
|
||||||
|
sql = "insert into "
|
||||||
|
if sql != pre_insert:
|
||||||
|
tsql.execute(sql)
|
||||||
|
tdLog.debug("insert data ............ [OK]")
|
||||||
|
return
|
||||||
|
|
||||||
|
def prepareTestEnv(self):
|
||||||
|
tdLog.printNoPrefix("======== prepare test env include database, stable, ctables, and insert data: ")
|
||||||
|
paraDict = {'dbName': 'test',
|
||||||
|
'dropFlag': 1,
|
||||||
|
'vgroups': 2,
|
||||||
|
'stbName': 'meters',
|
||||||
|
'colPrefix': 'c',
|
||||||
|
'tagPrefix': 't',
|
||||||
|
'colSchema': [{'type': 'INT', 'count':1},
|
||||||
|
{'type': 'BIGINT', 'count':1},
|
||||||
|
{'type': 'FLOAT', 'count':1},
|
||||||
|
{'type': 'DOUBLE', 'count':1},
|
||||||
|
{'type': 'smallint', 'count':1},
|
||||||
|
{'type': 'tinyint', 'count':1},
|
||||||
|
{'type': 'bool', 'count':1},
|
||||||
|
{'type': 'binary', 'len':10, 'count':1},
|
||||||
|
{'type': 'nchar', 'len':10, 'count':1},
|
||||||
|
{'type': 'timestamp', 'count':1}],
|
||||||
|
'tagSchema': [{'type': 'INT', 'count':1},{'type': 'nchar', 'len':20, 'count':1},{'type': 'binary', 'len':20, 'count':1},{'type': 'BIGINT', 'count':1},{'type': 'smallint', 'count':1},{'type': 'DOUBLE', 'count':1}],
|
||||||
|
'ctbPrefix': 't',
|
||||||
|
'ctbStartIdx': 0,
|
||||||
|
'ctbNum': 100,
|
||||||
|
'rowsPerTbl': 10000,
|
||||||
|
'batchNum': 3000,
|
||||||
|
'startTs': 1537146000000,
|
||||||
|
'tsStep': 600000}
|
||||||
|
|
||||||
|
paraDict['vgroups'] = self.vgroups
|
||||||
|
paraDict['ctbNum'] = self.ctbNum
|
||||||
|
paraDict['rowsPerTbl'] = self.rowsPerTbl
|
||||||
|
|
||||||
|
tdLog.info("create database")
|
||||||
|
self.create_database(tsql=tdSql, dbName=paraDict["dbName"], dropFlag=paraDict["dropFlag"], vgroups=paraDict["vgroups"], replica=self.replicaVar, duration=self.duraion)
|
||||||
|
|
||||||
|
tdLog.info("create stb")
|
||||||
|
self.create_stable(tsql=tdSql, paraDict=paraDict)
|
||||||
|
|
||||||
|
tdLog.info("create child tables")
|
||||||
|
self.create_ctable(tsql=tdSql, dbName=paraDict["dbName"], \
|
||||||
|
stbName=paraDict["stbName"],ctbPrefix=paraDict["ctbPrefix"],\
|
||||||
|
ctbNum=paraDict["ctbNum"],ctbStartIdx=paraDict["ctbStartIdx"])
|
||||||
|
self.insert_data(tsql=tdSql, dbName=paraDict["dbName"],\
|
||||||
|
ctbPrefix=paraDict["ctbPrefix"],ctbNum=paraDict["ctbNum"],\
|
||||||
|
rowsPerTbl=paraDict["rowsPerTbl"],batchNum=paraDict["batchNum"],\
|
||||||
|
startTs=paraDict["startTs"],tsStep=paraDict["tsStep"])
|
||||||
|
return
|
||||||
|
|
||||||
|
def check_explain_res_has_row(self, plan_str_expect: str, rows, sql):
|
||||||
|
plan_found = False
|
||||||
|
for row in rows:
|
||||||
|
if str(row).find(plan_str_expect) >= 0:
|
||||||
|
tdLog.debug("plan: [%s] found in: [%s]" % (plan_str_expect, str(row)))
|
||||||
|
plan_found = True
|
||||||
|
break
|
||||||
|
if not plan_found:
|
||||||
|
tdLog.exit("plan: %s not found in res: [%s] in sql: %s" % (plan_str_expect, str(rows), sql))
|
||||||
|
|
||||||
|
def check_explain_res_no_row(self, plan_str_not_expect: str, res, sql):
|
||||||
|
for row in res:
|
||||||
|
if str(row).find(plan_str_not_expect) >= 0:
|
||||||
|
tdLog.exit('plan: [%s] found in: [%s] for sql: %s' % (plan_str_not_expect, str(row), sql))
|
||||||
|
|
||||||
|
def explain_sql(self, sql: str):
|
||||||
|
sql = "explain verbose true " + sql
|
||||||
|
tdSql.query(sql, queryTimes=1)
|
||||||
|
return tdSql.queryResult
|
||||||
|
|
||||||
|
def explain_and_check_res(self, sqls, hasLastRowScanRes):
|
||||||
|
for sql, has_last in zip(sqls, hasLastRowScanRes):
|
||||||
|
res = self.explain_sql(sql)
|
||||||
|
if has_last == 1:
|
||||||
|
self.check_explain_res_has_row("Last Row Scan", res, sql)
|
||||||
|
else:
|
||||||
|
self.check_explain_res_no_row("Last Row Scan", res, sql)
|
||||||
|
|
||||||
|
def format_sqls(self, sql_template, select_items):
|
||||||
|
sqls = []
|
||||||
|
for item in select_items:
|
||||||
|
sqls.append(sql_template % item)
|
||||||
|
return sqls
|
||||||
|
|
||||||
|
def query_check_one(self, sql, res_expect):
|
||||||
|
if res_expect is not None:
|
||||||
|
tdSql.query(sql, queryTimes=1)
|
||||||
|
tdSql.checkRows(1)
|
||||||
|
for i in range(0, tdSql.queryCols):
|
||||||
|
tdSql.checkData(0, i, res_expect[i])
|
||||||
|
tdLog.info('%s check res col: %d succeed value: %s' % (sql, i, str(res_expect[i])))
|
||||||
|
|
||||||
|
def query_check_sqls(self, sqls, has_last_row_scan_res, res_expect):
|
||||||
|
for sql, has_last, res in zip(sqls, has_last_row_scan_res, res_expect):
|
||||||
|
if has_last == 1:
|
||||||
|
self.query_check_one(sql, res)
|
||||||
|
|
||||||
|
def test_last_cache_scan(self):
|
||||||
|
sql_template = 'select %s from meters'
|
||||||
|
select_items = [
|
||||||
|
"last(ts), ts", "last(ts), c1", "last(ts), c2", "last(ts), c3",\
|
||||||
|
"last(ts), c4", "last(ts), tbname", "last(ts), t1", "last(ts), ts, ts"]
|
||||||
|
has_last_row_scan_res = [1, 0, 0, 0, 0, 0, 0, 1]
|
||||||
|
res_expect = [
|
||||||
|
["2018-11-25 19:30:00.000", "2018-11-25 19:30:00.000"],
|
||||||
|
None, None, None, None, None, None,
|
||||||
|
["2018-11-25 19:30:00.000", "2018-11-25 19:30:00.000", "2018-11-25 19:30:00.000"]
|
||||||
|
]
|
||||||
|
sqls = self.format_sqls(sql_template, select_items)
|
||||||
|
self.explain_and_check_res(sqls, has_last_row_scan_res)
|
||||||
|
self.query_check_sqls(sqls, has_last_row_scan_res, res_expect)
|
||||||
|
|
||||||
|
select_items = ["last(c1),ts", "last(c1), c1", "last(c1), c2", "last(c1), c3",\
|
||||||
|
"last(c1), c4", "last(c1), tbname", "last(c1), t1", "last(c1), ts, ts", "last(c1), c1, c1"]
|
||||||
|
has_last_row_scan_res = [1, 1, 0, 0, 0, 0, 0, 1, 1]
|
||||||
|
res_expect = [
|
||||||
|
[999, "2018-11-25 19:30:00.000"],
|
||||||
|
[999, 999], None, None, None, None, None,
|
||||||
|
[999, "2018-11-25 19:30:00.000", "2018-11-25 19:30:00.000"],
|
||||||
|
[999,999,999]
|
||||||
|
]
|
||||||
|
sqls = self.format_sqls(sql_template, select_items)
|
||||||
|
self.explain_and_check_res(sqls, has_last_row_scan_res)
|
||||||
|
self.query_check_sqls(sqls, has_last_row_scan_res, res_expect)
|
||||||
|
|
||||||
|
sql_template = 'select %s from t1'
|
||||||
|
select_items = ["last(c4),ts", "last(c4), c1", "last(c4), c2", "last(c4), c3",\
|
||||||
|
"last(c4), c4", "last(c4), tbname", "last(c4), t1"]
|
||||||
|
has_last_row_scan_res = [1, 0, 0, 0, 1, 0, 0]
|
||||||
|
res_expect = [
|
||||||
|
[4999.000000000000000, "2018-11-25 19:30:00.000"],
|
||||||
|
None,None,None,
|
||||||
|
[4999.000000000000000, 4999.000000000000000]
|
||||||
|
]
|
||||||
|
sqls = self.format_sqls(sql_template, select_items)
|
||||||
|
self.explain_and_check_res(sqls, has_last_row_scan_res)
|
||||||
|
self.query_check_sqls(sqls, has_last_row_scan_res, res_expect)
|
||||||
|
|
||||||
|
sql_template = 'select %s from meters'
|
||||||
|
select_items = ["last(c8), ts", "last(c8), c1", "last(c8), c8", "last(c8), tbname", \
|
||||||
|
"last(c8), t1", "last(c8), c8, c8", "last(c8), ts, ts"]
|
||||||
|
has_last_row_scan_res = [1, 0, 1, 0, 0, 1, 1]
|
||||||
|
res_expect = [
|
||||||
|
["binary9999", "2018-11-25 19:30:00.000"],
|
||||||
|
None,
|
||||||
|
["binary9999", "binary9999"],
|
||||||
|
None, None,
|
||||||
|
["binary9999", "binary9999", "binary9999"],
|
||||||
|
["binary9999", "2018-11-25 19:30:00.000", "2018-11-25 19:30:00.000"]
|
||||||
|
]
|
||||||
|
sqls = self.format_sqls(sql_template, select_items)
|
||||||
|
self.explain_and_check_res(sqls, has_last_row_scan_res)
|
||||||
|
self.query_check_sqls(sqls, has_last_row_scan_res, res_expect)
|
||||||
|
|
||||||
|
# c2, c4 in last row of t5,t6,t7,t8,t9 will always be NULL
|
||||||
|
sql_template = 'select %s from t5'
|
||||||
|
select_items = ["last(c4), ts", "last(c4), c4", "last(c4), c4, c4", "last(c4), ts, ts"]
|
||||||
|
has_last_row_scan_res = [1,1,1,1]
|
||||||
|
|
||||||
|
sqls = self.format_sqls(sql_template, select_items)
|
||||||
|
self.explain_and_check_res(sqls, has_last_row_scan_res)
|
||||||
|
#for sql in sqls:
|
||||||
|
#tdSql.query(sql, queryTimes=1)
|
||||||
|
#tdSql.checkRows(0)
|
||||||
|
|
||||||
|
sql_template = 'select %s from meters'
|
||||||
|
select_items = [
|
||||||
|
"last_row(ts), last(ts)",
|
||||||
|
"last_row(c1), last(c1)",
|
||||||
|
"last_row(c1), c1,c3, ts"
|
||||||
|
]
|
||||||
|
has_last_row_scan_res = [0,0,1]
|
||||||
|
sqls = self.format_sqls(sql_template, select_items)
|
||||||
|
self.explain_and_check_res(sqls, has_last_row_scan_res)
|
||||||
|
#res_expect = [None, None, [999, 999, 499, "2018-11-25 19:30:00.000"]]
|
||||||
|
#self.query_check_sqls(sqls, has_last_row_scan_res, res_expect)
|
||||||
|
|
||||||
|
select_items = ["last(c10), c10",
|
||||||
|
"last(c10), ts",
|
||||||
|
"last(c10), c10, ts",
|
||||||
|
"last(c10), c10, ts, c10,ts",
|
||||||
|
"last(c10), ts, c1"]
|
||||||
|
has_last_row_scan_res = [1,1,1,1,0]
|
||||||
|
sqls = self.format_sqls(sql_template, select_items)
|
||||||
|
self.explain_and_check_res(sqls, has_last_row_scan_res)
|
||||||
|
res_expect = [
|
||||||
|
["2018-11-25 19:30:01.000", "2018-11-25 19:30:01.000"],
|
||||||
|
["2018-11-25 19:30:01.000", "2018-11-25 19:30:00.000"],
|
||||||
|
["2018-11-25 19:30:01.000", "2018-11-25 19:30:01.000", "2018-11-25 19:30:00.000"],
|
||||||
|
["2018-11-25 19:30:01.000", "2018-11-25 19:30:01.000", "2018-11-25 19:30:00.000", "2018-11-25 19:30:01.000", "2018-11-25 19:30:00.000"]
|
||||||
|
]
|
||||||
|
self.query_check_sqls(sqls, has_last_row_scan_res, res_expect)
|
||||||
|
|
||||||
|
sql = "select last(c1), c1, c1+1, c1+2, ts from meters"
|
||||||
|
res = self.explain_sql(sql)
|
||||||
|
self.check_explain_res_has_row("Last Row Scan", res, sql)
|
||||||
|
|
||||||
|
tdSql.query(sql)
|
||||||
|
tdSql.checkRows(1)
|
||||||
|
tdSql.checkData(0, 0, 999)
|
||||||
|
tdSql.checkData(0, 1, 999)
|
||||||
|
tdSql.checkData(0, 2, 1000)
|
||||||
|
tdSql.checkData(0, 3, 1001)
|
||||||
|
tdSql.checkData(0, 4, "2018-11-25 19:30:00.000")
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
self.prepareTestEnv()
|
||||||
|
#time.sleep(99999999)
|
||||||
|
self.test_last_cache_scan()
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
tdSql.close()
|
||||||
|
tdLog.success(f"{__file__} successfully executed")
|
||||||
|
|
||||||
|
event = threading.Event()
|
||||||
|
|
||||||
|
tdCases.addLinux(__file__, TDTestCase())
|
||||||
|
tdCases.addWindows(__file__, TDTestCase())
|
Loading…
Reference in New Issue