提交 0d54c5a3 编写于 作者: Z zhihaop

feat: sql objects merging and sending are asynchronous

上级 e2a029ca
...@@ -109,6 +109,14 @@ typedef struct SDispatcherTimeoutManager { ...@@ -109,6 +109,14 @@ typedef struct SDispatcherTimeoutManager {
volatile bool shutdown; volatile bool shutdown;
} SDispatcherTimeoutManager; } SDispatcherTimeoutManager;
/**
* A batch that polls from SAsyncBatchWriteDispatcher::buffer.
*/
typedef struct SBatchRequest {
size_t nRequests;
SSqlObj* pRequests[];
} SBatchRequest;
/** /**
* Create the dispatcher timeout manager. * Create the dispatcher timeout manager.
*/ */
...@@ -135,20 +143,25 @@ void shutdownSDispatcherTimeoutManager(SDispatcherTimeoutManager* manager); ...@@ -135,20 +143,25 @@ void shutdownSDispatcherTimeoutManager(SDispatcherTimeoutManager* manager);
/** /**
* Merge SSqlObjs into single SSqlObj. * Merge SSqlObjs into single SSqlObj.
* *
* @param polls the array of SSqlObj*. * @param pRequest the batch request.
* @param nPolls the number of SSqlObj* in the array. * @param batch the batch SSqlObj*.
* @param batch the merged SSqlObj*. * @return the status code.
* @return the merged SSqlObj. */
int32_t dispatcherBatchBuilder(SBatchRequest* pRequest, SSqlObj** batch);
/**
* Merge the sql statements and execute the merged sql statement asynchronously.
*
* @param pRequest the batch request. the request will be promised to free after calling this function.
*/ */
int32_t dispatcherBatchBuilder(SSqlObj** polls, size_t nPolls, SSqlObj** batch); void dispatcherAsyncExecute(SBatchRequest* pRequest);
/** /**
* Merge the sql statements and execute the merged sql statement. * Merge the sql statements and execute the merged sql statement.
* *
* @param polls the array of SSqlObj*. * @param pRequest the batch request. you must call free(pRequest) after calling this function.
* @param nPolls the number of SSqlObj* in the array.
*/ */
void dispatcherExecute(SSqlObj** polls, size_t nPolls); void dispatcherExecute(SBatchRequest* pRequest);
/** /**
* Create the async batch write dispatcher. * Create the async batch write dispatcher.
......
...@@ -17,9 +17,9 @@ ...@@ -17,9 +17,9 @@
#include "tscBatchMerge.h" #include "tscBatchMerge.h"
#include "tscBatchWrite.h" #include "tscBatchWrite.h"
#include "tscLog.h"
#include "tscSubquery.h" #include "tscSubquery.h"
#include "tsclient.h" #include "tsclient.h"
#include "tscLog.h"
/** /**
* Represents the callback function and its context. * Represents the callback function and its context.
...@@ -57,9 +57,7 @@ inline static void tscReturnsError(SSqlObj* pSql, int code) { ...@@ -57,9 +57,7 @@ inline static void tscReturnsError(SSqlObj* pSql, int code) {
} }
pSql->res.code = code; pSql->res.code = code;
if (pSql->fp) { tscAsyncResultOnError(pSql);
pSql->fp(pSql->param, pSql, code);
}
} }
/** /**
...@@ -104,47 +102,47 @@ static void batchResultCallback(void* param, TAOS_RES* tres, int32_t code) { ...@@ -104,47 +102,47 @@ static void batchResultCallback(void* param, TAOS_RES* tres, int32_t code) {
free(context); free(context);
} }
int32_t dispatcherBatchBuilder(SSqlObj** polls, size_t nPolls, SSqlObj** batch) { int32_t dispatcherBatchBuilder(SBatchRequest* pRequest, SSqlObj** batch) {
if (!polls || !nPolls) { assert(pRequest);
return TSDB_CODE_SUCCESS; assert(pRequest->pRequests);
} assert(pRequest->nRequests);
// create the callback context. // create the callback context.
SBatchCallbackContext* context = calloc(1, sizeof(SBatchCallbackContext) + nPolls * sizeof(SCallbackHandler)); SBatchCallbackContext* context =
calloc(1, sizeof(SBatchCallbackContext) + pRequest->nRequests * sizeof(SCallbackHandler));
if (context == NULL) { if (context == NULL) {
return TSDB_CODE_TSC_OUT_OF_MEMORY; return TSDB_CODE_TSC_OUT_OF_MEMORY;
} }
tscDebug("create batch call back context: %p", context); tscDebug("create batch call back context: %p", context);
// initialize the callback context. // initialize the callback context.
context->nHandlers = nPolls; context->nHandlers = pRequest->nRequests;
for (size_t i = 0; i < nPolls; ++i) { for (size_t i = 0; i < pRequest->nRequests; ++i) {
SSqlObj* pSql = polls[i]; SSqlObj* pSql = pRequest->pRequests[i];
context->handler[i].fp = pSql->fp; context->handler[i].fp = pSql->fp;
context->handler[i].param = pSql->param; context->handler[i].param = pSql->param;
} }
// merge the statements into single one. // merge the statements into single one.
tscDebug("start to merge %zu sql objs", nPolls); tscDebug("start to merge %zu sql objs", pRequest->nRequests);
SSqlObj *pFirst = polls[0]; SSqlObj* pFirst = pRequest->pRequests[0];
int32_t code = tscMergeSSqlObjs(polls, nPolls, pFirst); int32_t code = tscMergeSSqlObjs(pRequest->pRequests, pRequest->nRequests, pFirst);
if (code != TSDB_CODE_SUCCESS) { if (code != TSDB_CODE_SUCCESS) {
const char* msg = tstrerror(code); const char* msg = tstrerror(code);
tscDebug("failed to merge sql objects: %s", msg); tscDebug("failed to merge sql objects: %s", msg);
free(context); free(context);
taosReleaseRef(tscObjRef, pFirst->self);
return code; return code;
} }
pFirst->fp = batchResultCallback; pFirst->fp = batchResultCallback;
pFirst->param = context; pFirst->param = context;
pFirst->fetchFp = pFirst->fp; pFirst->fetchFp = pFirst->fp;
taosAcquireRef(tscObjRef, pFirst->self);
*batch = pFirst; *batch = pFirst;
for (int i = 1; i < nPolls; ++i) { for (int i = 0; i < pRequest->nRequests; ++i) {
SSqlObj *pSql = polls[i]; SSqlObj* pSql = pRequest->pRequests[i];
taosReleaseRef(tscObjRef, pSql->self); taosReleaseRef(tscObjRef, pSql->self);
} }
return code; return code;
...@@ -158,40 +156,37 @@ int32_t dispatcherBatchBuilder(SSqlObj** polls, size_t nPolls, SSqlObj** batch) ...@@ -158,40 +156,37 @@ int32_t dispatcherBatchBuilder(SSqlObj** polls, size_t nPolls, SSqlObj** batch)
* @param nPolls the number of polled SSqlObj*. * @param nPolls the number of polled SSqlObj*.
* @return all the SSqlObj* in the buffer. * @return all the SSqlObj* in the buffer.
*/ */
inline static SSqlObj** dispatcherPollAll(SAsyncBatchWriteDispatcher* dispatcher, size_t* nPolls) { inline static SBatchRequest* dispatcherPollAll(SAsyncBatchWriteDispatcher* dispatcher) {
if (!dispatcher->bufferSize) { if (!dispatcher->bufferSize) {
*nPolls = 0;
return NULL; return NULL;
} }
SSqlObj** clone = malloc(sizeof(SSqlObj*) * dispatcher->bufferSize); SBatchRequest* pRequest = malloc(sizeof(SBatchRequest) + sizeof(SSqlObj*) * dispatcher->bufferSize);
if (clone == NULL) { if (pRequest == NULL) {
tscError("failed to poll all items: out of memory"); tscError("failed to poll all items: out of memory");
*nPolls = 0;
return NULL; return NULL;
} }
memcpy(clone, dispatcher->buffer, sizeof(SSqlObj*) * dispatcher->bufferSize);
*nPolls = dispatcher->bufferSize; memcpy(pRequest->pRequests, dispatcher->buffer, sizeof(SSqlObj*) * dispatcher->bufferSize);
pRequest->nRequests = dispatcher->bufferSize;
dispatcher->currentSize = 0; dispatcher->currentSize = 0;
dispatcher->bufferSize = 0; dispatcher->bufferSize = 0;
return clone; return pRequest;
} }
/** /**
* Poll all the SSqlObj* in the dispatcher's buffer. * Poll all the SSqlObj* in the dispatcher's buffer.
* *
* @param dispatcher the dispatcher. * @param dispatcher the dispatcher.
* @param nPolls the number of polled SSqlObj*.
* @return all the SSqlObj* in the buffer. * @return all the SSqlObj* in the buffer.
*/ */
inline static SSqlObj** dispatcherLockPollAll(SAsyncBatchWriteDispatcher* dispatcher, size_t* nPolls) { inline static SBatchRequest* dispatcherLockPollAll(SAsyncBatchWriteDispatcher* dispatcher) {
SSqlObj** polls = NULL; SBatchRequest* pRequest = NULL;
pthread_mutex_lock(&dispatcher->bufferMutex); pthread_mutex_lock(&dispatcher->bufferMutex);
polls = dispatcherPollAll(dispatcher, nPolls); pRequest = dispatcherPollAll(dispatcher);
pthread_cond_broadcast(&dispatcher->notFull); pthread_cond_broadcast(&dispatcher->notFull);
pthread_mutex_unlock(&dispatcher->bufferMutex); pthread_mutex_unlock(&dispatcher->bufferMutex);
return polls; return pRequest;
} }
/** /**
...@@ -229,41 +224,42 @@ inline static bool dispatcherTryOffer(SAsyncBatchWriteDispatcher* dispatcher, SS ...@@ -229,41 +224,42 @@ inline static bool dispatcherTryOffer(SAsyncBatchWriteDispatcher* dispatcher, SS
} }
// the dispatcher reaches batch size. // the dispatcher reaches batch size.
size_t nPolls = 0; SBatchRequest* pRequest = dispatcherPollAll(dispatcher);
SSqlObj** polls = dispatcherPollAll(dispatcher, &nPolls);
pthread_cond_broadcast(&dispatcher->notFull); pthread_cond_broadcast(&dispatcher->notFull);
pthread_mutex_unlock(&dispatcher->bufferMutex); pthread_mutex_unlock(&dispatcher->bufferMutex);
if (polls) { if (pRequest) {
dispatcherExecute(polls, nPolls); dispatcherAsyncExecute(pRequest);
free(polls);
} }
return true; return true;
} }
void dispatcherExecute(SSqlObj** polls, size_t nPolls) { void dispatcherExecute(SBatchRequest* pRequest) {
int32_t code = TSDB_CODE_SUCCESS; int32_t code = TSDB_CODE_SUCCESS;
// no item in the buffer (items has been taken by other threads). // no item in the buffer (items has been taken by other threads).
if (!polls || !nPolls) { if (!pRequest) {
return; return;
} }
assert(pRequest->pRequests);
assert(pRequest->nRequests);
// merge the statements into single one. // merge the statements into single one.
SSqlObj* merged = NULL; SSqlObj* pSql = NULL;
code = dispatcherBatchBuilder(polls, nPolls, &merged); code = dispatcherBatchBuilder(pRequest, &pSql);
if (code != TSDB_CODE_SUCCESS) { if (code != TSDB_CODE_SUCCESS) {
goto _error; goto _error;
} }
tscDebug("merging %zu sql objs into %p", nPolls, merged); tscDebug("merging %zu sql objs into %p", pRequest->nRequests, pSql);
tscHandleMultivnodeInsert(merged); tscHandleMultivnodeInsert(pSql);
return; return;
_error: _error:
tscError("send async batch sql obj failed, reason: %s", tstrerror(code)); tscError("send async batch sql obj failed, reason: %s", tstrerror(code));
// handling the failures. // handling the failures.
for (size_t i = 0; i < nPolls; ++i) { for (size_t i = 0; i < pRequest->nRequests; ++i) {
SSqlObj* item = polls[i]; SSqlObj* item = pRequest->pRequests[i];
tscReturnsError(item, code); tscReturnsError(item, code);
} }
} }
...@@ -275,7 +271,7 @@ _error: ...@@ -275,7 +271,7 @@ _error:
* @param millis the duration in milliseconds. * @param millis the duration in milliseconds.
* @return the timespec after `millis` ms. * @return the timespec after `millis` ms.
*/ */
static inline void afterMillis(struct timespec *t, int32_t millis) { static inline void afterMillis(struct timespec* t, int32_t millis) {
t->tv_nsec += millis * 1000000L; t->tv_nsec += millis * 1000000L;
t->tv_sec += t->tv_nsec / 1000000000L; t->tv_sec += t->tv_nsec / 1000000000L;
t->tv_nsec %= 1000000000L; t->tv_nsec %= 1000000000L;
...@@ -314,12 +310,9 @@ static void* timeoutManagerCallback(void* arg) { ...@@ -314,12 +310,9 @@ static void* timeoutManagerCallback(void* arg) {
clock_gettime(CLOCK_REALTIME, &timeout); clock_gettime(CLOCK_REALTIME, &timeout);
afterMillis(&timeout, manager->timeoutMs); afterMillis(&timeout, manager->timeoutMs);
size_t nPolls = 0; SBatchRequest* pRequest = dispatcherLockPollAll(manager->dispatcher);
SSqlObj** polls = dispatcherLockPollAll(manager->dispatcher, &nPolls); if (pRequest) {
dispatcherAsyncExecute(pRequest);
if (polls) {
dispatcherExecute(polls, nPolls);
free(polls);
} }
// Similar to scheduleAtFixedRate in Java, if the execution time exceed // Similar to scheduleAtFixedRate in Java, if the execution time exceed
...@@ -380,13 +373,12 @@ void destroySAsyncBatchWriteDispatcher(SAsyncBatchWriteDispatcher* dispatcher) { ...@@ -380,13 +373,12 @@ void destroySAsyncBatchWriteDispatcher(SAsyncBatchWriteDispatcher* dispatcher) {
// poll and send all the statements in the buffer. // poll and send all the statements in the buffer.
while (true) { while (true) {
size_t nPolls = 0; SBatchRequest* pRequest = dispatcherLockPollAll(dispatcher);
SSqlObj** polls = dispatcherLockPollAll(dispatcher, &nPolls); if (!pRequest) {
if (!polls) { break;
break ;
} }
dispatcherExecute(polls, nPolls); dispatcherExecute(pRequest);
free(polls); free(pRequest);
} }
// destroy the timeout manager. // destroy the timeout manager.
destroySDispatcherTimeoutManager(dispatcher->timeoutManager); destroySDispatcherTimeoutManager(dispatcher->timeoutManager);
...@@ -463,7 +455,8 @@ static void destroyDispatcher(void* arg) { ...@@ -463,7 +455,8 @@ static void destroyDispatcher(void* arg) {
destroySAsyncBatchWriteDispatcher(dispatcher); destroySAsyncBatchWriteDispatcher(dispatcher);
} }
SDispatcherManager* createDispatcherManager(STscObj* pClient, int32_t batchSize, int32_t timeoutMs, bool isThreadLocal) { SDispatcherManager* createDispatcherManager(STscObj* pClient, int32_t batchSize, int32_t timeoutMs,
bool isThreadLocal) {
SDispatcherManager* dispatcher = calloc(1, sizeof(SDispatcherManager)); SDispatcherManager* dispatcher = calloc(1, sizeof(SDispatcherManager));
if (!dispatcher) { if (!dispatcher) {
return NULL; return NULL;
...@@ -576,3 +569,35 @@ bool isShutdownSDispatcherTimeoutManager(SDispatcherTimeoutManager* manager) { ...@@ -576,3 +569,35 @@ bool isShutdownSDispatcherTimeoutManager(SDispatcherTimeoutManager* manager) {
} }
return atomic_load_8(&manager->shutdown); return atomic_load_8(&manager->shutdown);
} }
/**
* The proxy function to call `dispatcherExecute`.
*
* @param pMsg the schedule message.
*/
static void dispatcherExecuteProxy(struct SSchedMsg* pMsg) {
SBatchRequest* pRequest = pMsg->ahandle;
if (!pRequest) {
return;
}
pMsg->ahandle = NULL;
dispatcherExecute(pRequest);
free(pRequest);
}
void dispatcherAsyncExecute(SBatchRequest* pRequest) {
if (!pRequest) {
return;
}
assert(pRequest->pRequests);
assert(pRequest->nRequests);
SSchedMsg schedMsg = {0};
schedMsg.fp = dispatcherExecuteProxy;
schedMsg.ahandle = (void*) pRequest;
schedMsg.thandle = (void*) 1;
schedMsg.msg = 0;
taosScheduleTask(tscQhandle, &schedMsg);
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册