From 517e587c35fed98db63bc89efe76818ceb361950 Mon Sep 17 00:00:00 2001 From: shenglian zhou Date: Thu, 7 Apr 2022 17:32:58 +0800 Subject: [PATCH 01/19] udfd exit and restart processing --- source/libs/function/inc/tudf.h | 5 +++ source/libs/function/src/tudf.c | 80 ++++++++++++++++++++++++++++----- 2 files changed, 75 insertions(+), 10 deletions(-) diff --git a/source/libs/function/inc/tudf.h b/source/libs/function/inc/tudf.h index 72875239d2..f072866c67 100644 --- a/source/libs/function/inc/tudf.h +++ b/source/libs/function/inc/tudf.h @@ -22,6 +22,11 @@ extern "C" { //====================================================================================== //begin API to taosd and qworker +enum { + UDFC_CODE_STOPPING = -1, + UDFC_CODE_RESTARTING = -2, +}; + /** * start udf dameon service * @return error code diff --git a/source/libs/function/src/tudf.c b/source/libs/function/src/tudf.c index a1030f6c21..5b73662d45 100644 --- a/source/libs/function/src/tudf.c +++ b/source/libs/function/src/tudf.c @@ -22,9 +22,9 @@ //TODO: udfd restart when exist or aborts //TODO: network error processing. //TODO: add unit test -//TODO: add lua support void onUdfcRead(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf); - +int32_t destructUdfService(); +int32_t constructUdfService(); enum { UV_TASK_CONNECT = 0, UV_TASK_REQ_RSP = 1, @@ -103,14 +103,22 @@ uv_async_t gUdfLoopStopAsync; uv_mutex_t gUdfTaskQueueMutex; int64_t gUdfTaskSeqNum = 0; +enum { + UDFC_STATE_INITAL = 0, // initial state + UDFC_STATE_STARTNG, // starting after startUdfService + UDFC_STATE_READY, // started and begin to receive quests + UDFC_STATE_RESTARTING, // udfd abnormal exit. cleaning up and restart. + UDFC_STATE_STOPPING, // stopping after stopUdfService + UDFC_STATUS_FINAL, // stopped +}; +int8_t gUdfcState = UDFC_STATE_INITAL; + //double circular linked list typedef SClientUvTaskNode *SClientUvTaskQueue; SClientUvTaskNode gUdfQueueNode; SClientUvTaskQueue gUdfTaskQueue = &gUdfQueueNode; -//add SClientUvTaskNode task that close conn - - +//TODO: deal with uv task that has been started and then udfd core dumped void udfTaskQueueInit(SClientUvTaskQueue q) { q->next = q; @@ -465,6 +473,18 @@ void onUdfdExit(uv_process_t *req, int64_t exit_status, int term_signal) { debugPrint("Process exited with status %" PRId64 ", signal %d", exit_status, term_signal); uv_close((uv_handle_t *) req, NULL); //TODO: restart the udfd process + if (gUdfcState == UDFC_STATE_STOPPING) { + if (term_signal != SIGINT) { + //TODO: log error + } + } + if (gUdfcState == UDFC_STATE_READY) { + gUdfcState = UDFC_STATE_RESTARTING; + //TODO: asynchronous without blocking. how to do it + destructUdfService(); + constructUdfService(); + } + } void onUdfcPipeClose(uv_handle_t *handle) { @@ -602,7 +622,7 @@ void udfcUvHandleRsp(SClientUvConn *conn) { udfTaskQueueRemoveTask(taskFound); uv_sem_post(&taskFound->taskSem); } else { - //LOG error + //TODO: LOG error } connBuf->buf = NULL; connBuf->total = -1; @@ -777,10 +797,32 @@ void udfClientAsyncCb(uv_async_t *async) { } void udfStopAsyncCb(uv_async_t *async) { + SClientUvTaskNode node; + SClientUvTaskQueue q = &node; + udfTaskQueueInit(q); + + uv_mutex_lock(&gUdfTaskQueueMutex); + udfTaskQueueMove(gUdfTaskQueue, q); + uv_mutex_unlock(&gUdfTaskQueueMutex); + + while (!udfTaskQueueIsEmpty(q)) { + SClientUvTaskNode *task = udfTaskQueueHeadTask(q); + udfTaskQueueRemoveTask(task); + if (gUdfcState == UDFC_STATE_STOPPING) { + task->errCode = UDFC_CODE_STOPPING; + } else if (gUdfcState == UDFC_STATE_RESTARTING) { + task->errCode = UDFC_CODE_RESTARTING; + } + uv_sem_post(&task->taskSem); + } + + // TODO: deal with tasks that are waiting result. + uv_stop(&gUdfdLoop); - uv_loop_close(&gUdfdLoop); } + + void startUdfd(void *argsThread) { uv_loop_init(&gUdfdLoop); @@ -805,25 +847,43 @@ void startUdfd(void *argsThread) { uv_mutex_init(&gUdfTaskQueueMutex); udfTaskQueueInit(gUdfTaskQueue); uv_barrier_wait(&gUdfInitBarrier); + //TODO return value of uv_run uv_run(&gUdfdLoop, UV_RUN_DEFAULT); + uv_loop_close(&gUdfdLoop); } -int32_t startUdfService() { +int32_t constructUdfService() { uv_barrier_init(&gUdfInitBarrier, 2); uv_thread_create(&gUdfLoopThread, startUdfd, 0); uv_barrier_wait(&gUdfInitBarrier); return 0; } -int32_t stopUdfService() { +int32_t startUdfService() { + gUdfcState = UDFC_STATE_STARTNG; + constructUdfService(); + gUdfcState = UDFC_STATE_READY; + return 0; +} + +int32_t destructUdfService() { uv_barrier_destroy(&gUdfInitBarrier); - uv_process_kill(&gUdfdProcess, SIGINT); + if (gUdfcState == UDFC_STATE_STOPPING) { + uv_process_kill(&gUdfdProcess, SIGINT); + } uv_async_send(&gUdfLoopStopAsync); uv_mutex_destroy(&gUdfTaskQueueMutex); uv_thread_join(&gUdfLoopThread); return 0; } +int32_t stopUdfService() { + gUdfcState = UDFC_STATE_STOPPING; + destructUdfService(); + gUdfcState = UDFC_STATUS_FINAL; + return 0; +} + int32_t udfcRunUvTask(SClientUdfTask *task, int8_t uvTaskType) { SClientUvTaskNode *uvTask = NULL; From 44bc9731d09ca0918910cf04c6bdf90779419e7c Mon Sep 17 00:00:00 2001 From: shenglian zhou Date: Fri, 8 Apr 2022 11:50:16 +0800 Subject: [PATCH 02/19] sync home / office --- source/libs/function/src/tudf.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/source/libs/function/src/tudf.c b/source/libs/function/src/tudf.c index 5b73662d45..a179c29440 100644 --- a/source/libs/function/src/tudf.c +++ b/source/libs/function/src/tudf.c @@ -17,6 +17,7 @@ #include "tlog.h" #include "tudf.h" #include "tudfInt.h" +#include "tarray.h" //TODO: when startup, set thread poll size. add it to cfg //TODO: udfd restart when exist or aborts @@ -103,6 +104,8 @@ uv_async_t gUdfLoopStopAsync; uv_mutex_t gUdfTaskQueueMutex; int64_t gUdfTaskSeqNum = 0; +SArray* gUdfWaitResultTasks = NULL; + enum { UDFC_STATE_INITAL = 0, // initial state UDFC_STATE_STARTNG, // starting after startUdfService @@ -178,7 +181,6 @@ void udfTaskQueueMove(SClientUvTaskQueue q, SClientUvTaskQueue n) { } } - int32_t encodeRequest(char **pBuf, int32_t *pBufLen, SUdfRequest *request) { debugPrint("%s", "encoding request"); @@ -846,6 +848,7 @@ void startUdfd(void *argsThread) { uv_async_init(&gUdfdLoop, &gUdfLoopStopAsync, udfStopAsyncCb); uv_mutex_init(&gUdfTaskQueueMutex); udfTaskQueueInit(gUdfTaskQueue); + gUdfWaitResultTasks = taosArrayInit(256, sizeof(SClientUvTaskNode*)); uv_barrier_wait(&gUdfInitBarrier); //TODO return value of uv_run uv_run(&gUdfdLoop, UV_RUN_DEFAULT); From ce9585a350eb679402054b6587781bbb23e9b43f Mon Sep 17 00:00:00 2001 From: shenglian zhou Date: Sun, 10 Apr 2022 17:28:28 +0800 Subject: [PATCH 03/19] before integration test success --- source/libs/function/src/tudf.c | 349 ++++++++++++++++++------------- source/libs/function/test/udf1.c | 6 +- 2 files changed, 202 insertions(+), 153 deletions(-) diff --git a/source/libs/function/src/tudf.c b/source/libs/function/src/tudf.c index a179c29440..1f531be1f6 100644 --- a/source/libs/function/src/tudf.c +++ b/source/libs/function/src/tudf.c @@ -23,9 +23,95 @@ //TODO: udfd restart when exist or aborts //TODO: network error processing. //TODO: add unit test -void onUdfcRead(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf); -int32_t destructUdfService(); -int32_t constructUdfService(); +//TODO: test libuv queue +typedef void *QUEUE[2]; + +/* Private macros. */ +#define QUEUE_NEXT(q) (*(QUEUE **) &((*(q))[0])) +#define QUEUE_PREV(q) (*(QUEUE **) &((*(q))[1])) +#define QUEUE_PREV_NEXT(q) (QUEUE_NEXT(QUEUE_PREV(q))) +#define QUEUE_NEXT_PREV(q) (QUEUE_PREV(QUEUE_NEXT(q))) + +/* Public macros. */ +#define QUEUE_DATA(ptr, type, field) \ + ((type *) ((char *) (ptr) - offsetof(type, field))) + +/* Important note: mutating the list while QUEUE_FOREACH is + * iterating over its elements results in undefined behavior. + */ +#define QUEUE_FOREACH(q, h) \ + for ((q) = QUEUE_NEXT(h); (q) != (h); (q) = QUEUE_NEXT(q)) + +#define QUEUE_EMPTY(q) \ + ((const QUEUE *) (q) == (const QUEUE *) QUEUE_NEXT(q)) + +#define QUEUE_HEAD(q) \ + (QUEUE_NEXT(q)) + +#define QUEUE_INIT(q) \ + do { \ + QUEUE_NEXT(q) = (q); \ + QUEUE_PREV(q) = (q); \ + } \ + while (0) + +#define QUEUE_ADD(h, n) \ + do { \ + QUEUE_PREV_NEXT(h) = QUEUE_NEXT(n); \ + QUEUE_NEXT_PREV(n) = QUEUE_PREV(h); \ + QUEUE_PREV(h) = QUEUE_PREV(n); \ + QUEUE_PREV_NEXT(h) = (h); \ + } \ + while (0) + +#define QUEUE_SPLIT(h, q, n) \ + do { \ + QUEUE_PREV(n) = QUEUE_PREV(h); \ + QUEUE_PREV_NEXT(n) = (n); \ + QUEUE_NEXT(n) = (q); \ + QUEUE_PREV(h) = QUEUE_PREV(q); \ + QUEUE_PREV_NEXT(h) = (h); \ + QUEUE_PREV(q) = (n); \ + } \ + while (0) + +#define QUEUE_MOVE(h, n) \ + do { \ + if (QUEUE_EMPTY(h)) \ + QUEUE_INIT(n); \ + else { \ + QUEUE* q = QUEUE_HEAD(h); \ + QUEUE_SPLIT(h, q, n); \ + } \ + } \ + while (0) + +#define QUEUE_INSERT_HEAD(h, q) \ + do { \ + QUEUE_NEXT(q) = QUEUE_NEXT(h); \ + QUEUE_PREV(q) = (h); \ + QUEUE_NEXT_PREV(q) = (q); \ + QUEUE_NEXT(h) = (q); \ + } \ + while (0) + +#define QUEUE_INSERT_TAIL(h, q) \ + do { \ + QUEUE_NEXT(q) = (h); \ + QUEUE_PREV(q) = QUEUE_PREV(h); \ + QUEUE_PREV_NEXT(q) = (q); \ + QUEUE_PREV(h) = (q); \ + } \ + while (0) + +#define QUEUE_REMOVE(q) \ + do { \ + QUEUE_PREV_NEXT(q) = QUEUE_NEXT(q); \ + QUEUE_NEXT_PREV(q) = QUEUE_PREV(q); \ + } \ + while (0) + + enum { UV_TASK_CONNECT = 0, UV_TASK_REQ_RSP = 1, @@ -49,8 +135,9 @@ typedef struct SClientUvTaskNode { uv_sem_t taskSem; uv_buf_t rspBuf; - struct SClientUvTaskNode *prev; - struct SClientUvTaskNode *next; + QUEUE recvTaskQueue; + QUEUE procTaskQueue; + QUEUE connTaskQueue; } SClientUvTaskNode; typedef struct SClientUdfTask { @@ -87,7 +174,7 @@ typedef struct SClientConnBuf { typedef struct SClientUvConn { uv_pipe_t *pipe; - SClientUvTaskNode taskQueue; + QUEUE taskQueue; SClientConnBuf readBuf; } SClientUvConn; @@ -104,8 +191,6 @@ uv_async_t gUdfLoopStopAsync; uv_mutex_t gUdfTaskQueueMutex; int64_t gUdfTaskSeqNum = 0; -SArray* gUdfWaitResultTasks = NULL; - enum { UDFC_STATE_INITAL = 0, // initial state UDFC_STATE_STARTNG, // starting after startUdfService @@ -117,69 +202,11 @@ enum { int8_t gUdfcState = UDFC_STATE_INITAL; //double circular linked list -typedef SClientUvTaskNode *SClientUvTaskQueue; -SClientUvTaskNode gUdfQueueNode; -SClientUvTaskQueue gUdfTaskQueue = &gUdfQueueNode; + +QUEUE gUdfTaskQueue = {0}; //TODO: deal with uv task that has been started and then udfd core dumped - -void udfTaskQueueInit(SClientUvTaskQueue q) { - q->next = q; - q->prev = q; -} - -bool udfTaskQueueIsEmpty(SClientUvTaskQueue q) { - return q == q->next; -} - -void udfTaskQueueInsertTail(SClientUvTaskQueue q, SClientUvTaskNode *e) { - e->next = q; - e->prev = q->prev; - e->prev->next = e; - q->prev = e; -} - -void udfTaskQueueInsertTaskAtHead(SClientUvTaskQueue q, SClientUvTaskNode *e) { - e->next = q->next; - e->prev = q; - q->next->prev = e; - q->next = e; -} - -void udfTaskQueueRemoveTask(SClientUvTaskNode *e) { - e->prev->next = e->next; - e->next->prev = e->prev; -} - -void udfTaskQueueSplit(SClientUvTaskQueue q, SClientUvTaskNode *from, SClientUvTaskQueue n) { - n->prev = q->prev; - n->prev->next = n; - n->next = from; - q->prev = from->prev; - q->prev->next = q; - from->prev = n; -} - -SClientUvTaskNode *udfTaskQueueHeadTask(SClientUvTaskQueue q) { - return q->next; -} - -SClientUvTaskNode *udfTaskQueueTailTask(SClientUvTaskQueue q) { - return q->prev; -} - -SClientUvTaskNode *udfTaskQueueNext(SClientUvTaskNode *e) { - return e->next; -} - -void udfTaskQueueMove(SClientUvTaskQueue q, SClientUvTaskQueue n) { - if (udfTaskQueueIsEmpty(q)) { - udfTaskQueueInit(n); - } else { - SClientUvTaskNode *h = udfTaskQueueHeadTask(q); - udfTaskQueueSplit(q, h, n); - } -} +QUEUE gUvProcTaskQueue = {0}; int32_t encodeRequest(char **pBuf, int32_t *pBufLen, SUdfRequest *request) { debugPrint("%s", "encoding request"); @@ -471,30 +498,14 @@ int32_t decodeResponse(char *bufMsg, int32_t bufLen, SUdfResponse **pResponse) { return 0; } -void onUdfdExit(uv_process_t *req, int64_t exit_status, int term_signal) { - debugPrint("Process exited with status %" PRId64 ", signal %d", exit_status, term_signal); - uv_close((uv_handle_t *) req, NULL); - //TODO: restart the udfd process - if (gUdfcState == UDFC_STATE_STOPPING) { - if (term_signal != SIGINT) { - //TODO: log error - } - } - if (gUdfcState == UDFC_STATE_READY) { - gUdfcState = UDFC_STATE_RESTARTING; - //TODO: asynchronous without blocking. how to do it - destructUdfService(); - constructUdfService(); - } - -} - void onUdfcPipeClose(uv_handle_t *handle) { SClientUvConn *conn = handle->data; - if (!udfTaskQueueIsEmpty(&conn->taskQueue)) { - SClientUvTaskNode *task = udfTaskQueueHeadTask(&conn->taskQueue); + if (!QUEUE_EMPTY(&conn->taskQueue)) { + QUEUE* h = QUEUE_HEAD(&conn->taskQueue); + SClientUvTaskNode *task = QUEUE_DATA(h, SClientUvTaskNode, connTaskQueue); task->errCode = 0; uv_sem_post(&task->taskSem); + QUEUE_REMOVE(&task->procTaskQueue); } taosMemoryFree(conn->readBuf.buf); @@ -599,14 +610,16 @@ void udfcUvHandleRsp(SClientUvConn *conn) { SClientConnBuf *connBuf = &conn->readBuf; int64_t seqNum = *(int64_t *) (connBuf->buf + sizeof(int32_t)); // msglen int32_t then seqnum - if (udfTaskQueueIsEmpty(&conn->taskQueue)) { + if (QUEUE_EMPTY(&conn->taskQueue)) { //LOG error return; } bool found = false; SClientUvTaskNode *taskFound = NULL; - SClientUvTaskNode *task = udfTaskQueueNext(&conn->taskQueue); - while (task != &conn->taskQueue) { + QUEUE* h = QUEUE_NEXT(&conn->taskQueue); + SClientUvTaskNode *task = QUEUE_DATA(h, SClientUvTaskNode, connTaskQueue); + + while (h != &conn->taskQueue) { if (task->seqNum == seqNum) { if (found == false) { found = true; @@ -616,13 +629,15 @@ void udfcUvHandleRsp(SClientUvConn *conn) { continue; } } - task = udfTaskQueueNext(task); + h = QUEUE_NEXT(h); + task = QUEUE_DATA(h, SClientUvTaskNode, connTaskQueue); } if (taskFound) { taskFound->rspBuf = uv_buf_init(connBuf->buf, connBuf->len); - udfTaskQueueRemoveTask(taskFound); + QUEUE_REMOVE(&taskFound->connTaskQueue); uv_sem_post(&taskFound->taskSem); + QUEUE_REMOVE(&taskFound->procTaskQueue); } else { //TODO: LOG error } @@ -665,7 +680,7 @@ void onUdfClientWrite(uv_write_t *write, int status) { if (status == 0) { uv_pipe_t *pipe = uvTask->pipe; SClientUvConn *conn = pipe->data; - udfTaskQueueInsertTail(&conn->taskQueue, uvTask); + QUEUE_INSERT_TAIL(&conn->taskQueue, &uvTask->connTaskQueue); } else { //TODO Log error; } @@ -683,6 +698,7 @@ void onUdfClientConnect(uv_connect_t *connect, int status) { uv_read_start((uv_stream_t *) uvTask->pipe, udfcAllocateBuffer, onUdfcRead); taosMemoryFree(connect); uv_sem_post(&uvTask->taskSem); + QUEUE_REMOVE(&uvTask->procTaskQueue); } int32_t createUdfcUvTask(SClientUdfTask *task, int8_t uvTaskType, SClientUvTaskNode **pUvTask) { @@ -726,7 +742,7 @@ int32_t queueUvUdfTask(SClientUvTaskNode *uvTask) { debugPrint("%s, %d", "queue uv task", uvTask->type); uv_mutex_lock(&gUdfTaskQueueMutex); - udfTaskQueueInsertTail(gUdfTaskQueue, uvTask); + QUEUE_INSERT_TAIL(&gUdfTaskQueue, &uvTask->recvTaskQueue); uv_mutex_unlock(&gUdfTaskQueueMutex); uv_async_send(&gUdfLoopTaskAync); @@ -750,7 +766,7 @@ int32_t startUvUdfTask(SClientUvTaskNode *uvTask) { conn->readBuf.cap = 0; conn->readBuf.buf = 0; conn->readBuf.total = -1; - udfTaskQueueInit(&conn->taskQueue); + QUEUE_INIT(&conn->taskQueue); pipe->data = conn; @@ -769,7 +785,7 @@ int32_t startUvUdfTask(SClientUvTaskNode *uvTask) { } case UV_TASK_DISCONNECT: { SClientUvConn *conn = uvTask->pipe->data; - udfTaskQueueInsertTail(&conn->taskQueue, uvTask); + QUEUE_INSERT_TAIL(&conn->taskQueue, &uvTask->connTaskQueue); uv_close((uv_handle_t *) uvTask->pipe, onUdfcPipeClose); break; } @@ -782,34 +798,33 @@ int32_t startUvUdfTask(SClientUvTaskNode *uvTask) { } void udfClientAsyncCb(uv_async_t *async) { - SClientUvTaskNode node; - SClientUvTaskQueue q = &node; - udfTaskQueueInit(q); + QUEUE wq; uv_mutex_lock(&gUdfTaskQueueMutex); - udfTaskQueueMove(gUdfTaskQueue, q); + QUEUE_MOVE(&gUdfTaskQueue, &wq); uv_mutex_unlock(&gUdfTaskQueueMutex); - while (!udfTaskQueueIsEmpty(q)) { - SClientUvTaskNode *task = udfTaskQueueHeadTask(q); - udfTaskQueueRemoveTask(task); + while (!QUEUE_EMPTY(&wq)) { + QUEUE* h = QUEUE_HEAD(&wq); + QUEUE_REMOVE(h); + SClientUvTaskNode *task = QUEUE_DATA(h, SClientUvTaskNode, recvTaskQueue); startUvUdfTask(task); + QUEUE_INSERT_TAIL(&gUvProcTaskQueue, &task->procTaskQueue); } } -void udfStopAsyncCb(uv_async_t *async) { - SClientUvTaskNode node; - SClientUvTaskQueue q = &node; - udfTaskQueueInit(q); +void cleanUpUvTasks() { + QUEUE wq; uv_mutex_lock(&gUdfTaskQueueMutex); - udfTaskQueueMove(gUdfTaskQueue, q); + QUEUE_MOVE(&gUdfTaskQueue, &wq); uv_mutex_unlock(&gUdfTaskQueueMutex); - while (!udfTaskQueueIsEmpty(q)) { - SClientUvTaskNode *task = udfTaskQueueHeadTask(q); - udfTaskQueueRemoveTask(task); + while (!QUEUE_EMPTY(&wq)) { + QUEUE* h = QUEUE_HEAD(&wq); + QUEUE_REMOVE(h); + SClientUvTaskNode *task = QUEUE_DATA(h, SClientUvTaskNode, recvTaskQueue); if (gUdfcState == UDFC_STATE_STOPPING) { task->errCode = UDFC_CODE_STOPPING; } else if (gUdfcState == UDFC_STATE_RESTARTING) { @@ -819,57 +834,99 @@ void udfStopAsyncCb(uv_async_t *async) { } // TODO: deal with tasks that are waiting result. - - uv_stop(&gUdfdLoop); + while (!QUEUE_EMPTY(&gUvProcTaskQueue)) { + QUEUE* h = QUEUE_HEAD(&gUvProcTaskQueue); + QUEUE_REMOVE(h); + SClientUvTaskNode *task = QUEUE_DATA(h, SClientUvTaskNode, procTaskQueue); + if (gUdfcState == UDFC_STATE_STOPPING) { + task->errCode = UDFC_CODE_STOPPING; + } else if (gUdfcState == UDFC_STATE_RESTARTING) { + task->errCode = UDFC_CODE_RESTARTING; + } + uv_sem_post(&task->taskSem); + } } +void udfStopAsyncCb(uv_async_t *async) { + cleanUpUvTasks(); + if (gUdfcState == UDFC_STATE_STOPPING) { + uv_stop(&gUdfdLoop); + } +} +int32_t startUdfd(); +void onUdfdExit(uv_process_t *req, int64_t exit_status, int term_signal) { + debugPrint("Process exited with status %" PRId64 ", signal %d", exit_status, term_signal); + uv_close((uv_handle_t *) req, NULL); + //TODO: restart the udfd process + if (gUdfcState == UDFC_STATE_STOPPING) { + if (term_signal != SIGINT) { + //TODO: log error + } + } + if (gUdfcState == UDFC_STATE_READY) { + gUdfcState = UDFC_STATE_RESTARTING; + //TODO: asynchronous without blocking. how to do it + cleanUpUvTasks(); + startUdfd(); + } +} -void startUdfd(void *argsThread) { +int32_t startUdfd() { + //TODO: path + uv_process_options_t options = {0}; + static char path[256] = {0}; + size_t cwdSize; + uv_cwd(path, &cwdSize); + strcat(path, "/udfd"); + char* args[2] = {path, NULL}; + options.args = args; + options.file = path; + options.exit_cb = onUdfdExit; + options.stdio_count = 3; + uv_stdio_container_t child_stdio[3]; + child_stdio[0].flags = UV_IGNORE; + child_stdio[1].flags = UV_INHERIT_FD; + child_stdio[1].data.fd = 1; + child_stdio[2].flags = UV_INHERIT_FD; + child_stdio[2].data.fd = 2; + options.stdio = child_stdio; + //TODO spawn error + int err = uv_spawn(&gUdfdLoop, &gUdfdProcess, &options); + if (err != 0) { + debugPrint("can not spawn udfd. path: %s, error: %s", path, uv_strerror(err)); + } + return err; +} + +void constructUdfService(void *argsThread) { uv_loop_init(&gUdfdLoop); - //TODO: path - uv_process_options_t options; - static char path[256] = {0}; - size_t cwdSize; - uv_cwd(path, &cwdSize); - strcat(path, "./udfd"); - char* args[2] = {path, NULL}; - options.args = args; - options.file = path; - options.exit_cb = onUdfdExit; - - int err = uv_spawn(&gUdfdLoop, &gUdfdProcess, &options); - if (err != 0) { - debugPrint("can not spawn udfd. path: %s, error: %s", path, uv_strerror(err)); - } + //TODO spawn error + startUdfd(); uv_async_init(&gUdfdLoop, &gUdfLoopTaskAync, udfClientAsyncCb); uv_async_init(&gUdfdLoop, &gUdfLoopStopAsync, udfStopAsyncCb); uv_mutex_init(&gUdfTaskQueueMutex); - udfTaskQueueInit(gUdfTaskQueue); - gUdfWaitResultTasks = taosArrayInit(256, sizeof(SClientUvTaskNode*)); + QUEUE_INIT(&gUdfTaskQueue); + QUEUE_INIT(&gUvProcTaskQueue); uv_barrier_wait(&gUdfInitBarrier); //TODO return value of uv_run uv_run(&gUdfdLoop, UV_RUN_DEFAULT); uv_loop_close(&gUdfdLoop); } -int32_t constructUdfService() { - uv_barrier_init(&gUdfInitBarrier, 2); - uv_thread_create(&gUdfLoopThread, startUdfd, 0); - uv_barrier_wait(&gUdfInitBarrier); - return 0; -} int32_t startUdfService() { gUdfcState = UDFC_STATE_STARTNG; - constructUdfService(); - gUdfcState = UDFC_STATE_READY; + uv_barrier_init(&gUdfInitBarrier, 2); + uv_thread_create(&gUdfLoopThread, constructUdfService, 0); + uv_barrier_wait(&gUdfInitBarrier); gUdfcState = UDFC_STATE_READY; return 0; } -int32_t destructUdfService() { +int32_t stopUdfService() { + gUdfcState = UDFC_STATE_STOPPING; uv_barrier_destroy(&gUdfInitBarrier); if (gUdfcState == UDFC_STATE_STOPPING) { uv_process_kill(&gUdfdProcess, SIGINT); @@ -877,13 +934,7 @@ int32_t destructUdfService() { uv_async_send(&gUdfLoopStopAsync); uv_mutex_destroy(&gUdfTaskQueueMutex); uv_thread_join(&gUdfLoopThread); - return 0; -} - -int32_t stopUdfService() { - gUdfcState = UDFC_STATE_STOPPING; - destructUdfService(); - gUdfcState = UDFC_STATUS_FINAL; + return 0; gUdfcState = UDFC_STATUS_FINAL; return 0; } diff --git a/source/libs/function/test/udf1.c b/source/libs/function/test/udf1.c index dc88e8cf3e..3fdc522ef9 100644 --- a/source/libs/function/test/udf1.c +++ b/source/libs/function/test/udf1.c @@ -2,18 +2,16 @@ #include #include -#include "os.h" #include "tudf.h" - void udf1(int8_t step, char *state, int32_t stateSize, SUdfDataBlock input, char **newState, int32_t *newStateSize, SUdfDataBlock *output) { fprintf(stdout, "%s, step:%d\n", "udf function called", step); - char *newStateBuf = taosMemoryMalloc(stateSize); + char *newStateBuf = malloc(stateSize); memcpy(newStateBuf, state, stateSize); *newState = newStateBuf; *newStateSize = stateSize; - char *outputBuf = taosMemoryMalloc(input.size); + char *outputBuf = malloc(input.size); memcpy(outputBuf, input.data, input.size); output->data = outputBuf; output->size = input.size; From 6f5f6896a56ad6b3def02465570f03829b848229 Mon Sep 17 00:00:00 2001 From: shenglian zhou Date: Sun, 10 Apr 2022 21:59:07 +0800 Subject: [PATCH 04/19] udfc destroy mutex after thread exit --- source/libs/function/src/tudf.c | 5 +++-- source/libs/function/src/udfd.c | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/source/libs/function/src/tudf.c b/source/libs/function/src/tudf.c index 1f531be1f6..0cc5b1f92d 100644 --- a/source/libs/function/src/tudf.c +++ b/source/libs/function/src/tudf.c @@ -290,6 +290,7 @@ int32_t encodeRequest(char **pBuf, int32_t *pBufLen, SUdfRequest *request) { *(int32_t *) bufBegin = request->msgLen; *pBuf = bufBegin; *pBufLen = request->msgLen; + debugPrint("\tLen: estimate: %d, actual:%d", len, *pBufLen); return 0; } @@ -932,9 +933,9 @@ int32_t stopUdfService() { uv_process_kill(&gUdfdProcess, SIGINT); } uv_async_send(&gUdfLoopStopAsync); - uv_mutex_destroy(&gUdfTaskQueueMutex); uv_thread_join(&gUdfLoopThread); - return 0; gUdfcState = UDFC_STATUS_FINAL; + uv_mutex_destroy(&gUdfTaskQueueMutex); + gUdfcState = UDFC_STATUS_FINAL; return 0; } diff --git a/source/libs/function/src/udfd.c b/source/libs/function/src/udfd.c index b473f060c0..2d9344709a 100644 --- a/source/libs/function/src/udfd.c +++ b/source/libs/function/src/udfd.c @@ -181,7 +181,7 @@ void udfdProcessRequest(uv_work_t *req) { } void udfdOnWrite(uv_write_t *req, int status) { - debugPrint("%s", "after writing to pipe"); + debugPrint("%s", "server after writing to pipe"); if (status < 0) { debugPrint("Write error %s", uv_err_name(status)); } @@ -205,7 +205,7 @@ void udfdSendResponse(uv_work_t *work, int status) { } void udfdAllocBuffer(uv_handle_t *handle, size_t suggestedSize, uv_buf_t *buf) { - debugPrint("%s", "allocate buffer for read"); + debugPrint("%s", "server allocate buffer for read"); SUdfdUvConn *ctx = handle->data; int32_t msgHeadSize = sizeof(int32_t) + sizeof(int64_t); if (ctx->inputCap == 0) { From 3f62f8a3330d47c5956f6fc1cf754c944b77a06f Mon Sep 17 00:00:00 2001 From: shenglian zhou Date: Wed, 13 Apr 2022 19:45:33 +0800 Subject: [PATCH 05/19] sync home and office --- source/libs/function/inc/tudf.h | 104 ++-- source/libs/function/inc/tudfInt.h | 42 +- source/libs/function/src/tudf.c | 742 +++++++++++++++++++---------- source/libs/function/src/udfd.c | 2 +- 4 files changed, 574 insertions(+), 316 deletions(-) diff --git a/source/libs/function/inc/tudf.h b/source/libs/function/inc/tudf.h index f072866c67..41183d5533 100644 --- a/source/libs/function/inc/tudf.h +++ b/source/libs/function/inc/tudf.h @@ -22,6 +22,8 @@ extern "C" { //====================================================================================== //begin API to taosd and qworker +#define TSDB_UDF_MAX_COLUMNS 4 + enum { UDFC_CODE_STOPPING = -1, UDFC_CODE_RESTARTING = -2, @@ -49,15 +51,22 @@ enum { TSDB_UDF_SCRIPT_LUA = 1, }; +typedef struct SUdfColumnMeta { + int16_t type; + int32_t bytes; // <0 var length, others fixed length bytes + uint8_t precision; + uint8_t scale; +} SUdfColumnMeta; + typedef struct SUdfInfo { char *udfName; // function name int32_t udfType; // scalar function or aggregate function int8_t scriptType; char *path; - int8_t resType; // result type - int16_t resBytes; // result byte - int32_t bufSize; //interbuf size + // known info between qworker and udf + // struct SUdfColumnMeta resultMeta; + // int32_t bufSize; //interbuf size } SUdfInfo; @@ -72,33 +81,50 @@ typedef void *UdfHandle; int32_t setupUdf(SUdfInfo* udf, UdfHandle *handle); -enum { - TSDB_UDF_STEP_NORMAL = 0, - TSDB_UDF_STEP_MERGE, - TSDb_UDF_STEP_FINALIZE, - TSDB_UDF_STEP_MAX_NUM -}; -/** - * call udf - * @param handle udf handle - * @param step - * @param state - * @param stateSize - * @param input - * @param newstate - * @param newStateSize - * @param output - * @return error code - */ +typedef struct SUdfColumnData { + int32_t numOfRows; + bool varLengthColumn; + union { + int32_t nullBitmapLen; + char* nullBitmap; + int32_t dataLen; + char* data; + }; + + union { + int32_t varOffsetsLen; + char* varOffsets; + int32_t payloadLen; + char* payload; + }; +} SUdfColumnData; + + +typedef struct SUdfColumn { + SUdfColumnMeta colMeta; + SUdfColumnData colData; +} SUdfColumn; -//TODO: must change the following after metadata flow and data flow between qworker and udfd is well defined typedef struct SUdfDataBlock { - char* data; - int32_t size; + int32_t numOfRows; + int32_t numOfCols; + SUdfColumn udfCols[TSDB_UDF_MAX_COLUMNS]; } SUdfDataBlock; -int32_t callUdf(UdfHandle handle, int8_t step, char *state, int32_t stateSize, SUdfDataBlock input, char **newstate, - int32_t *newStateSize, SUdfDataBlock *output); +typedef struct SUdfInterBuf { + int32_t bufLen; + char* buf; +} SUdfInterBuf; + +// input: block, initFirst +// output: interbuf +int32_t callUdfAggProcess(SUdfDataBlock block, SUdfInterBuf *interBuf, bool initFirst); +// input: interBuf +// output: resultData +int32_t callUdfAggFinalize(SUdfInterBuf interBuf, SUdfColumnData* resultData); +// input: block +// output: resultData +int32_t callUdfScalaProcess(SUdfDataBlock block, SUdfColumnData* resultData); /** * tearn down udf @@ -109,30 +135,16 @@ int32_t teardownUdf(UdfHandle handle); // end API to taosd and qworker //============================================================================================================================= -// TODO: Must change // begin API to UDF writer. -// script - -//typedef int32_t (*scriptInitFunc)(void* pCtx); -//typedef void (*scriptNormalFunc)(void* pCtx, char* data, int16_t iType, int16_t iBytes, int32_t numOfRows, -// int64_t* ptList, int64_t key, char* dataOutput, char* tsOutput, int32_t* numOfOutput, -// int16_t oType, int16_t oBytes); -//typedef void (*scriptFinalizeFunc)(void* pCtx, int64_t key, char* dataOutput, int32_t* numOfOutput); -//typedef void (*scriptMergeFunc)(void* pCtx, char* data, int32_t numOfRows, char* dataOutput, int32_t* numOfOutput); -//typedef void (*scriptDestroyFunc)(void* pCtx); - -// dynamic lib +// dynamic lib init and destroy typedef int32_t (*TUdfInitFunc)(); -typedef void (*TUdfDestroyFunc)(); - -typedef void (*TUdfFunc)(int8_t step, - char *state, int32_t stateSize, SUdfDataBlock input, - char **newstate, int32_t *newStateSize, SUdfDataBlock *output); - -//typedef void (*udfMergeFunc)(char *data, int32_t numOfRows, char *dataOutput, int32_t* numOfOutput); -//typedef void (*udfFinalizeFunc)(char* state, int32_t stateSize, SUdfDataBlock *output); +typedef int32_t (*TUdfDestroyFunc)(); +typedef int32_t (*TUdfScalarProcFunc)(SUdfDataBlock block, SUdfColumnData *resultData); +typedef int32_t (*TUdfAggInit)(SUdfInterBuf *buf); +typedef int32_t (*TUdfAggProcess)(SUdfDataBlock block, SUdfInterBuf *interBuf); +typedef int32_t (*TUdfAggFinalize)(SUdfInterBuf buf, SUdfColumnData *resultData); // end API to UDF writer //======================================================================================================================= diff --git a/source/libs/function/inc/tudfInt.h b/source/libs/function/inc/tudfInt.h index 5f757c1ef0..2e0b405916 100644 --- a/source/libs/function/inc/tudfInt.h +++ b/source/libs/function/inc/tudfInt.h @@ -30,6 +30,12 @@ enum { }; +enum { + TSDB_UDF_CALL_AGG_PROC = 0, + TSDb_UDF_CALL_AGG_FIN, + TSDB_UDF_CALL_SCALA_PROC, +}; + typedef struct SUdfSetupRequest { char udfName[16]; // int8_t scriptType; // 0:c, 1: lua, 2:js @@ -42,24 +48,18 @@ typedef struct SUdfSetupResponse { int64_t udfHandle; } SUdfSetupResponse; - typedef struct SUdfCallRequest { int64_t udfHandle; - int8_t step; + int8_t callType; - int32_t inputBytes; - char *input; - - int32_t stateBytes; - char *state; + SUdfDataBlock block; + SUdfInterBuf interBuf; + bool initFirst; } SUdfCallRequest; - typedef struct SUdfCallResponse { - int32_t outputBytes; - char *output; - int32_t newStateBytes; - char *newState; + SUdfColumnData resultData; + SUdfInterBuf interBuf; } SUdfCallResponse; @@ -76,7 +76,11 @@ typedef struct SUdfRequest { int64_t seqNum; int8_t type; - void *subReq; + union { + SUdfSetupRequest setup; + SUdfCallRequest call; + SUdfTeardownRequest teardown; + }; } SUdfRequest; typedef struct SUdfResponse { @@ -85,13 +89,17 @@ typedef struct SUdfResponse { int8_t type; int32_t code; - void *subRsp; + union { + SUdfSetupResponse setupRsp; + SUdfCallResponse callRsp; + SUdfTeardownResponse teardownRsp; + }; } SUdfResponse; -int32_t decodeRequest(char *buf, int32_t bufLen, SUdfRequest **pRequest); -int32_t encodeResponse(char **buf, int32_t *bufLen, SUdfResponse *response); +int32_t decodeRequest(char *buf, int32_t bufLen, SUdfRequest *pRequest); int32_t encodeRequest(char **buf, int32_t *bufLen, SUdfRequest *request); -int32_t decodeResponse(char *buf, int32_t bufLen, SUdfResponse **pResponse); +int32_t decodeResponse(char *buf, int32_t bufLen, SUdfResponse *pResponse); +int32_t encodeResponse(char **buf, int32_t *bufLen, SUdfResponse *response); #ifdef __cplusplus } diff --git a/source/libs/function/src/tudf.c b/source/libs/function/src/tudf.c index 0cc5b1f92d..d5089ca0eb 100644 --- a/source/libs/function/src/tudf.c +++ b/source/libs/function/src/tudf.c @@ -19,11 +19,17 @@ #include "tudfInt.h" #include "tarray.h" -//TODO: when startup, set thread poll size. add it to cfg +//TODO: when startup, set thread poll size. add it to cfg +//TODO: test for udfd restart //TODO: udfd restart when exist or aborts +//TODO: deal with uv task that has been started and then udfd core dumped //TODO: network error processing. //TODO: add unit test -//TODO: test libuv queue +//TODO: include all global variable under context struct +/* Copyright (c) 2013, Ben Noordhuis + * The QUEUE is copied from queue.h under libuv + * */ + typedef void *QUEUE[2]; /* Private macros. */ @@ -205,104 +211,331 @@ int8_t gUdfcState = UDFC_STATE_INITAL; QUEUE gUdfTaskQueue = {0}; -//TODO: deal with uv task that has been started and then udfd core dumped QUEUE gUvProcTaskQueue = {0}; -int32_t encodeRequest(char **pBuf, int32_t *pBufLen, SUdfRequest *request) { - debugPrint("%s", "encoding request"); +int32_t serializeUdfColumnData(SUdfColumnData* data, char* pBuf) { + char* bufBeg = pBuf; + *(int32_t*)pBuf = data->numOfRows; + pBuf += sizeof(int32_t); + *(bool*)pBuf = data->varLengthColumn; + pBuf += sizeof(bool); - int len = sizeof(SUdfRequest) - sizeof(void *); - switch (request->type) { - case UDF_TASK_SETUP: { - SUdfSetupRequest *setup = (SUdfSetupRequest *) (request->subReq); - len += sizeof(SUdfSetupRequest) - 1 * sizeof(char *) + setup->pathSize; - break; - } - case UDF_TASK_CALL: { - SUdfCallRequest *call = (SUdfCallRequest *) (request->subReq); - len += sizeof(SUdfCallRequest) - 2 * sizeof(char *) + call->inputBytes + call->stateBytes; - break; - } - case UDF_TASK_TEARDOWN: { - SUdfTeardownRequest *teardown = (SUdfTeardownRequest *) (request->subReq); - len += sizeof(SUdfTeardownRequest); - break; - } - default: - break; + if (!data->varLengthColumn) { + *(int32_t*)pBuf = data->nullBitmapLen; + pBuf += sizeof(int32_t); + memcpy(pBuf, data->nullBitmap, data->nullBitmapLen); + pBuf += data->nullBitmapLen; + *(int32_t*)pBuf = data->dataLen; + pBuf += sizeof(int32_t); + memcpy(pBuf, data->data, data->dataLen); + pBuf += data->dataLen; + } else { + *(int32_t*)pBuf = data->varOffsetsLen; + pBuf += sizeof(int32_t); + memcpy(pBuf, data->varOffsets, data->varOffsetsLen); + pBuf += data->varOffsetsLen; + *(int32_t*)pBuf = data->payloadLen; + pBuf += sizeof(int32_t); + memcpy(pBuf, data->payload, data->payloadLen); + pBuf += data->payloadLen; + } + int32_t len = pBuf - bufBeg; + return len; +} + +int32_t deserializeUdfColumnData(SUdfColumnData* pData, char* buf) { + char* bufBeg = buf; + pData->numOfRows = *(int32_t*)buf; + buf += sizeof(int32_t); + pData->varLengthColumn = *(bool*)buf; + buf += sizeof(bool); + + if (!pData->varLengthColumn) { + pData->nullBitmapLen = *(int32_t*)buf; + buf += sizeof(int32_t); + + pData->nullBitmap = buf; + buf += pData->nullBitmapLen; + + pData->dataLen = *(int32_t*)buf; + buf += sizeof(int32_t); + + pData->data = buf; + buf += pData->dataLen; + } else { + pData->varOffsetsLen = *(int32_t*)buf; + buf += sizeof(int32_t); + + pData->varOffsets = buf; + buf += pData->varOffsetsLen; + + pData->payloadLen = *(int32_t*)buf; + buf += sizeof(int32_t); + + pData->payload = buf; + buf += pData->payloadLen; + } + int32_t len = buf - bufBeg; + return len; +} + +int32_t serializeUdfColumnMeta(SUdfColumnMeta *meta, char* pBuf) { + char* bufBeg = pBuf; + memcpy(pBuf, meta, sizeof(SUdfColumnMeta)); + pBuf += sizeof(SUdfColumnMeta); + + int32_t len = pBuf - bufBeg; + return len; +} + +int32_t deserializeUdfColumnMeta(SUdfColumnMeta *pMeta, char* buf) { + char *bufBegin = buf; + memcpy(pMeta, buf, sizeof(SUdfColumnMeta)); + buf += sizeof(SUdfColumnMeta); + + int32_t len = buf - bufBegin; + return len; +} + +int32_t serializeUdfColumn(SUdfColumn *udfCol, char *pBuf) { + char *bufBegin = pBuf; + + int32_t len = serializeUdfColumnMeta(&udfCol->colMeta, pBuf); + pBuf += len; + + len = serializeUdfColumnData(&udfCol->colData, pBuf); + pBuf += len; + + int32_t totalLen = pBuf - bufBegin; + return totalLen; +} + +int32_t deserializeUdfColumn(SUdfColumn *pUdfCol, char *buf) { + char *bufBegin = buf; + + int32_t len = deserializeUdfColumnMeta(&pUdfCol->colMeta, buf); + buf += len; + + len = deserializeUdfColumnData(&pUdfCol->colData, buf); + buf += len; + + int32_t totalLen = buf - bufBegin; + return totalLen; +} + +int32_t serializeUdfDataBlock(SUdfDataBlock *block, char *pBuf) { + char *bufBegin = pBuf; + + *(int32_t*)pBuf = block->numOfRows; + pBuf += sizeof(int32_t); + + *(int32_t*)pBuf = block->numOfCols; + pBuf += sizeof(int32_t); + + for (int32_t i = 0; i < block->numOfCols; ++i) { + SUdfColumn* col = block->udfCols + i; + int32_t l = serializeUdfColumn(col, pBuf); + pBuf += l; } - char *bufBegin = taosMemoryMalloc(len); - char *buf = bufBegin; + int32_t totalLen = pBuf - bufBegin; + return totalLen; +} - //skip msgLen first +int32_t deserailizeUdfDataBlock(SUdfDataBlock *pBlock, char *buf) { + char *bufBegin = buf; + + pBlock->numOfRows = *(int32_t*)buf; buf += sizeof(int32_t); - *(int64_t *) buf = request->seqNum; - buf += sizeof(int64_t); - *(int8_t *) buf = request->type; - buf += sizeof(int8_t); + pBlock->numOfCols = *(int32_t*)buf; + buf += sizeof(int32_t); - switch (request->type) { - case UDF_TASK_SETUP: { - SUdfSetupRequest *setup = (SUdfSetupRequest *) (request->subReq); - memcpy(buf, setup->udfName, 16); - buf += 16; - *(int8_t *) buf = setup->scriptType; - buf += sizeof(int8_t); - *(int8_t *) buf = setup->udfType; - buf += sizeof(int8_t); - *(int16_t *) buf = setup->pathSize; - buf += sizeof(int16_t); - memcpy(buf, setup->path, setup->pathSize); - buf += setup->pathSize; - break; - } - - case UDF_TASK_CALL: { - SUdfCallRequest *call = (SUdfCallRequest *) (request->subReq); - *(int64_t *) buf = call->udfHandle; - buf += sizeof(int64_t); - *(int8_t *) buf = call->step; - buf += sizeof(int8_t); - *(int32_t *) buf = call->inputBytes; - buf += sizeof(int32_t); - memcpy(buf, call->input, call->inputBytes); - buf += call->inputBytes; - *(int32_t *) buf = call->stateBytes; - buf += sizeof(int32_t); - memcpy(buf, call->state, call->stateBytes); - buf += call->stateBytes; - break; - } - - case UDF_TASK_TEARDOWN: { - SUdfTeardownRequest *teardown = (SUdfTeardownRequest *) (request->subReq); - *(int64_t *) buf = teardown->udfHandle; - buf += sizeof(int64_t); - break; - } - default: - break; + for (int32_t i = 0; i < pBlock->numOfCols; ++i) { + int32_t l = deserializeUdfColumn(pBlock->udfCols + i, buf); + buf += l; } - request->msgLen = buf - bufBegin; - *(int32_t *) bufBegin = request->msgLen; - *pBuf = bufBegin; - *pBufLen = request->msgLen; - debugPrint("\tLen: estimate: %d, actual:%d", len, *pBufLen); + int32_t totalLen = buf - bufBegin; + return totalLen; +} + +int32_t serializeUdfInterBuf(SUdfInterBuf *state, char *pBuf) { + char *bufBegin = pBuf; + + *(int32_t*)pBuf = state->bufLen; + pBuf += sizeof(int32_t); + + memcpy(pBuf, state->buf, state->bufLen); + pBuf += state->bufLen; + + return pBuf-bufBegin; +} + +int32_t deserializeUdfInterBuf(SUdfInterBuf *pState, char *buf) { + char* bufBegin = buf; + pState->bufLen = *(int32_t*)buf; + buf += sizeof(int32_t); + pState->buf = buf; + buf += pState->bufLen; + return buf - bufBegin; +} + +int32_t serializeUdfSetupRequest(SUdfSetupRequest *setup, char *buf) { + char *bufBegin = buf; + + memcpy(buf, setup->udfName, 16); + buf += 16; + *(int8_t *) buf = setup->scriptType; + buf += sizeof(int8_t); + *(int8_t *) buf = setup->udfType; + buf += sizeof(int8_t); + *(int16_t *) buf = setup->pathSize; + buf += sizeof(int16_t); + memcpy(buf, setup->path, setup->pathSize); + buf += setup->pathSize; + + return buf - bufBegin; +}; + +int32_t deserializeUdfSetupRequest(SUdfSetupRequest *setup, char *buf) { + char* bufBegin = buf; + + memcpy(setup->udfName, buf, 16); + buf += 16; + setup->scriptType = *(int8_t *) buf; + buf += sizeof(int8_t); + setup->udfType = *(int8_t *) buf; + buf += sizeof(int8_t); + setup->pathSize = *(int16_t *) buf; + buf += sizeof(int16_t); + setup->path = buf; + buf += setup->pathSize; + + return buf - bufBegin; +} + +int32_t serializeUdfTeardownRequest(SUdfTeardownRequest *teardown, char *buf) { + char* bufBegin = buf; + *(int64_t *) buf = teardown->udfHandle; + buf += sizeof(int64_t); + + return buf - bufBegin; +} + +int32_t deserializeUdfTeardownRequest(SUdfTeardownRequest *teardown, char *buf) { + char *bufBegin = buf; + teardown->udfHandle = *(int64_t *) buf; + buf += sizeof(int64_t); + return buf - bufBegin; +} + +int32_t serializeUdfSetupResponse(SUdfSetupResponse *setupRsp, char *buf) { + char *bufBegin = buf; + + *(int64_t *) buf = setupRsp->udfHandle; + buf += sizeof(int64_t); + + return buf-bufBegin; +} + +int32_t deserializeUdfSetupResponse(SUdfSetupResponse *setupRsp, char *buf) { + char *bufBegin = buf; + setupRsp->udfHandle = *(int64_t *) buf; + buf += sizeof(int64_t); + return buf-bufBegin; +} + +int32_t serializeUdfTeardownResponse(SUdfTeardownResponse *teardownRsp, char *buf) { return 0; } -int32_t decodeRequest(char *bufMsg, int32_t bufLen, SUdfRequest **pRequest) { - debugPrint("%s", "decoding request"); - if (*(int32_t *) bufMsg != bufLen) { - debugPrint("%s", "decoding request error"); - return -1; - } - char *buf = bufMsg; - SUdfRequest *request = taosMemoryMalloc(sizeof(SUdfRequest)); - request->subReq = NULL; +int32_t deserializeUdfTeardownResponse(SUdfTeardownResponse *teardownRsp, char *buf) { + return 0; +} + +int32_t serializeUdfCallRequest(SUdfCallRequest *call, char *buf) { + char* bufBegin = buf; + *(int64_t *) buf = call->udfHandle; + buf += sizeof(int64_t); + *(int8_t *) buf = call->callType; + buf += sizeof(int8_t); + int32_t l = 0; + l = serializeUdfDataBlock(&call->block, buf); + buf += l; + l = serializeUdfInterBuf(&call->interBuf, buf); + buf += l; + + *(bool*)buf = call->initFirst; + buf += sizeof(bool); + + return buf - bufBegin; +} + +int32_t deserializeUdfCallRequest(SUdfCallRequest *call, char *buf) { + char* bufBegin = buf; + call->udfHandle = *(int64_t *) buf; + buf += sizeof(int64_t); + call->callType = *(int8_t *) buf; + buf += sizeof(int8_t); + int32_t l = 0; + l = deserailizeUdfDataBlock(&call->block, buf); + buf += l; + l = deserializeUdfInterBuf(&call->interBuf, buf); + buf += l; + call->initFirst = *(bool*)buf; + buf += sizeof(bool); + return buf - bufBegin; +} + +int32_t serializeUdfCallResponse(SUdfCallResponse *callRsp, char * buf) { + char *bufBegin = buf; + int32_t l = 0; + l = serializeUdfColumnData(&callRsp->resultData, buf); + buf += l; + l = serializeUdfInterBuf(&callRsp->interBuf, buf); + buf += l; + + return buf - bufBegin; +} + +int32_t deserializeUdfCallResponse(SUdfCallResponse *callRsp, char * buf) { + char *bufBegin = buf; + int32_t l = 0; + l =deserializeUdfColumnData(&callRsp->resultData, buf); + buf += l; + l = deserializeUdfInterBuf(&callRsp->interBuf, buf); + buf += l; + return buf - bufBegin; +} + +int32_t serializeUdfRequest(SUdfRequest *request, char *buf) { + char* bufBegin = buf; + //skip msglen first + buf += sizeof(int32_t); + + *(int64_t *) buf = request->seqNum; + buf += sizeof(int64_t); + *(int8_t *) buf = request->type; + buf += sizeof(int8_t); + + int32_t l = 0; + if (request->type == UDF_TASK_SETUP) { + l = serializeUdfSetupRequest(&request->setup, buf); + buf += l; + } else if (request->type == UDF_TASK_CALL) { + l = serializeUdfCallRequest(&request->call, buf); + buf += l; + } else if (request->type == UDF_TASK_TEARDOWN){ + l = serializeUdfTeardownRequest(&request->teardown, buf); + buf += l; + } + *(int32_t*)bufBegin = buf - bufBegin; + return buf - bufBegin; +} + +int32_t deserializeUdfRequest(SUdfRequest *request, char *buf) { + char* bufBegin = buf; request->msgLen = *(int32_t *) (buf); buf += sizeof(int32_t); request->seqNum = *(int64_t *) (buf); @@ -310,89 +543,27 @@ int32_t decodeRequest(char *bufMsg, int32_t bufLen, SUdfRequest **pRequest) { request->type = *(int8_t *) (buf); buf += sizeof(int8_t); - switch (request->type) { - case UDF_TASK_SETUP: { - SUdfSetupRequest *setup = taosMemoryMalloc(sizeof(SUdfSetupRequest)); - - memcpy(setup->udfName, buf, 16); - buf += 16; - setup->scriptType = *(int8_t *) buf; - buf += sizeof(int8_t); - setup->udfType = *(int8_t *) buf; - buf += sizeof(int8_t); - setup->pathSize = *(int16_t *) buf; - buf += sizeof(int16_t); - setup->path = buf; - buf += setup->pathSize; - - request->subReq = setup; - break; - } - case UDF_TASK_CALL: { - SUdfCallRequest *call = taosMemoryMalloc(sizeof(SUdfCallRequest)); - - call->udfHandle = *(int64_t *) buf; - buf += sizeof(int64_t); - call->step = *(int8_t *) buf; - buf += sizeof(int8_t); - call->inputBytes = *(int32_t *) buf; - buf += sizeof(int32_t); - call->input = buf; - buf += call->inputBytes; - call->stateBytes = *(int32_t *) buf; - buf += sizeof(int32_t); - call->state = buf; - buf += call->stateBytes; - - request->subReq = call; - break; - } - - case UDF_TASK_TEARDOWN: { - SUdfTeardownRequest *teardown = taosMemoryMalloc(sizeof(SUdfTeardownRequest)); - - teardown->udfHandle = *(int64_t *) buf; - buf += sizeof(int64_t); - - request->subReq = teardown; - } - + int32_t l = 0; + if (request->type == UDF_TASK_SETUP) { + l = deserializeUdfSetupRequest(&request->setup, buf); + buf += l; + } else if (request->type == UDF_TASK_CALL) { + l = deserializeUdfCallRequest(&request->call, buf); + buf += l; + } else if (request->type == UDF_TASK_TEARDOWN){ + l = deserializeUdfTeardownRequest(&request->teardown, buf); + buf += l; } - if (buf - bufMsg != bufLen) { - debugPrint("%s", "decode request error"); - taosMemoryFree(request->subReq); - taosMemoryFree(request); + int32_t totalLen = buf-bufBegin; + if (totalLen != request->msgLen) { + debugPrint("decoding request error"); return -1; } - *pRequest = request; - return 0; + return buf - bufBegin; } -int32_t encodeResponse(char **pBuf, int32_t *pBufLen, SUdfResponse *response) { - debugPrint("%s", "encoding response"); - - int32_t len = sizeof(SUdfResponse) - sizeof(void *); - - switch (response->type) { - case UDF_TASK_SETUP: { - len += sizeof(SUdfSetupResponse); - break; - } - case UDF_TASK_CALL: { - SUdfCallResponse *callResp = (SUdfCallResponse *) (response->subRsp); - len += sizeof(SUdfCallResponse) - 2 * sizeof(char *) + - callResp->outputBytes + callResp->newStateBytes; - break; - } - case UDF_TASK_TEARDOWN: { - len += sizeof(SUdfTeardownResponse); - break; - } - } - - char *bufBegin = taosMemoryMalloc(len); - char *buf = bufBegin; - +int32_t serializeUdfResponse(SUdfResponse *response, char *buf) { + char* bufBegin = buf; //skip msgLen buf += sizeof(int32_t); @@ -402,51 +573,30 @@ int32_t encodeResponse(char **pBuf, int32_t *pBufLen, SUdfResponse *response) { buf += sizeof(int8_t); *(int32_t *) buf = response->code; buf += sizeof(int32_t); - - + int32_t l = 0; switch (response->type) { case UDF_TASK_SETUP: { - SUdfSetupResponse *setupResp = (SUdfSetupResponse *) (response->subRsp); - *(int64_t *) buf = setupResp->udfHandle; - buf += sizeof(int64_t); + l = serializeUdfSetupResponse(&response->setupRsp, buf); + buf += l; break; } case UDF_TASK_CALL: { - SUdfCallResponse *callResp = (SUdfCallResponse *) (response->subRsp); - *(int32_t *) buf = callResp->outputBytes; - buf += sizeof(int32_t); - memcpy(buf, callResp->output, callResp->outputBytes); - buf += callResp->outputBytes; - - *(int32_t *) buf = callResp->newStateBytes; - buf += sizeof(int32_t); - memcpy(buf, callResp->newState, callResp->newStateBytes); - buf += callResp->newStateBytes; + l = serializeUdfCallResponse(&response->callRsp, buf); + buf += l; break; } case UDF_TASK_TEARDOWN: { - SUdfTeardownResponse *teardownResp = (SUdfTeardownResponse *) (response->subRsp); - break; + l = serializeUdfTeardownResponse(&response->teardownRsp, buf); + buf += l; } - default: - break; } - response->msgLen = buf - bufBegin; - *(int32_t *) bufBegin = response->msgLen; - *pBuf = bufBegin; - *pBufLen = response->msgLen; - return 0; + + *(int32_t*)bufBegin = buf - bufBegin; + return buf - bufBegin; } -int32_t decodeResponse(char *bufMsg, int32_t bufLen, SUdfResponse **pResponse) { - debugPrint("%s", "decoding response"); - - if (*(int32_t *) bufMsg != bufLen) { - debugPrint("%s", "can not decode response"); - return -1; - } - char *buf = bufMsg; - SUdfResponse *rsp = taosMemoryMalloc(sizeof(SUdfResponse)); +int32_t deserializeUdfResponse(SUdfResponse *rsp, char *buf) { + char* bufBegin = buf; rsp->msgLen = *(int32_t *) buf; buf += sizeof(int32_t); rsp->seqNum = *(int64_t *) buf; @@ -455,47 +605,115 @@ int32_t decodeResponse(char *bufMsg, int32_t bufLen, SUdfResponse **pResponse) { buf += sizeof(int8_t); rsp->code = *(int32_t *) buf; buf += sizeof(int32_t); - + int32_t l = 0; switch (rsp->type) { case UDF_TASK_SETUP: { - SUdfSetupResponse *setupRsp = (SUdfSetupResponse *) taosMemoryMalloc(sizeof(SUdfSetupResponse)); - setupRsp->udfHandle = *(int64_t *) buf; - buf += sizeof(int64_t); - rsp->subRsp = (char *) setupRsp; + l = deserializeUdfSetupResponse(&rsp->setupRsp, buf); + buf += l; break; } case UDF_TASK_CALL: { - SUdfCallResponse *callRsp = (SUdfCallResponse *) taosMemoryMalloc(sizeof(SUdfCallResponse)); - callRsp->outputBytes = *(int32_t *) buf; - buf += sizeof(int32_t); - - callRsp->output = buf; - buf += callRsp->outputBytes; - - callRsp->newStateBytes = *(int32_t *) buf; - buf += sizeof(int32_t); - - callRsp->newState = buf; - buf += callRsp->newStateBytes; - - rsp->subRsp = callRsp; + l = deserializeUdfCallResponse(&rsp->callRsp, buf); + buf += l; break; } case UDF_TASK_TEARDOWN: { - SUdfTeardownResponse *teardownRsp = (SUdfTeardownResponse *) taosMemoryMalloc(sizeof(SUdfTeardownResponse)); - rsp->subRsp = teardownRsp; - break; + l = deserializeUdfTeardownResponse(&rsp->teardownRsp, buf); + buf += l; } - default: - break; } - if (buf - bufMsg != bufLen) { - debugPrint("%s", "can not decode response"); - taosMemoryFree(rsp->subRsp); - taosMemoryFree(rsp); + int32_t total = buf - bufBegin; + if (total != rsp->msgLen) { + debugPrint("decode response error"); + return -1; + } + return buf - bufBegin; +} + +int32_t estimateUdfRequestLen(SUdfRequest *request) { + // a larger estimated is generated + int32_t size = sizeof(SUdfRequest); + if (request->type == UDF_TASK_SETUP) { + size += request->setup.pathSize; + } else if (request->type == UDF_TASK_CALL) { + for (int32_t i = 0; i < request->call.block.numOfCols; ++i) { + SUdfColumn* col = request->call.block.udfCols + i; + if (col->colData.varLengthColumn) { + size += col->colData.varOffsetsLen; + size += col->colData.payloadLen; + } else { + size += col->colData.nullBitmapLen; + size += col->colData.dataLen; + } + } + size += request->call.interBuf.bufLen; + } + return size; +} + +int32_t estimateUdfResponseLen(SUdfResponse *response) { + int32_t size = sizeof(SUdfResponse); + if (response->type == UDF_TASK_CALL) { + size += response->callRsp.interBuf.bufLen; + SUdfColumnData *resultData = &response->callRsp.resultData; + if (!resultData->varLengthColumn) { + size += resultData->nullBitmapLen; + size += resultData->dataLen; + } else { + size += resultData->varOffsetsLen; + size += resultData->payloadLen; + } + } + + return size; +} + +int32_t encodeRequest(char **pBuf, int32_t *pBufLen, SUdfRequest *request) { + debugPrint("%s", "encoding request"); + + int len = estimateUdfRequestLen(request); + + char *bufBegin = taosMemoryMalloc(len); + char *buf = bufBegin; + serializeUdfRequest(request, buf); + *pBuf = bufBegin; + *pBufLen = request->msgLen; + debugPrint("\tLen: estimate: %d, actual:%d", len, *pBufLen); + return 0; +} + +int32_t decodeRequest(char *bufMsg, int32_t bufLen, SUdfRequest *pRequest) { + debugPrint("%s", "decoding request"); + if (*(int32_t *) bufMsg != bufLen) { + debugPrint("%s", "decoding request error"); return -1; } - *pResponse = rsp; + char *buf = bufMsg; + deserializeUdfRequest(pRequest, buf); + return 0; +} + +int32_t encodeResponse(char **pBuf, int32_t *pBufLen, SUdfResponse *response) { + debugPrint("%s", "encoding response"); + int32_t len = estimateUdfResponseLen(response); + + char *bufBegin = taosMemoryMalloc(len); + char *buf = bufBegin; + serializeUdfResponse(response, buf); + *pBuf = bufBegin; + *pBufLen = response->msgLen; + return 0; +} + +int32_t decodeResponse(char *bufMsg, int32_t bufLen, SUdfResponse *rsp) { + debugPrint("%s", "decoding response"); + + if (*(int32_t *) bufMsg != bufLen) { + debugPrint("%s", "can not decode response"); + return -1; + } + char *buf = bufMsg; + deserializeUdfResponse(rsp, buf); return 0; } @@ -519,23 +737,23 @@ int32_t udfcGetUvTaskResponseResult(SClientUdfTask *task, SClientUvTaskNode *uvT debugPrint("%s", "get uv task result"); if (uvTask->type == UV_TASK_REQ_RSP) { if (uvTask->rspBuf.base != NULL) { - SUdfResponse *rsp; + SUdfResponse rsp; decodeResponse(uvTask->rspBuf.base, uvTask->rspBuf.len, &rsp); - task->errCode = rsp->code; + task->errCode = rsp.code; switch (task->type) { case UDF_TASK_SETUP: { //TODO: copy or not - task->_setup.rsp = *(SUdfSetupResponse *) (rsp->subRsp); + task->_setup.rsp = rsp.setupRsp; break; } case UDF_TASK_CALL: { - task->_call.rsp = *(SUdfCallResponse *) (rsp->subRsp); + task->_call.rsp = rsp.callRsp; //TODO: copy or not break; } case UDF_TASK_TEARDOWN: { - task->_teardown.rsp = *(SUdfTeardownResponse *) (rsp->subRsp); + task->_teardown.rsp = rsp.teardownRsp; //TODO: copy or not? break; } @@ -546,8 +764,6 @@ int32_t udfcGetUvTaskResponseResult(SClientUdfTask *task, SClientUvTaskNode *uvT // TODO: the call buffer is setup and freed by udf invocation taosMemoryFree(uvTask->rspBuf.base); - taosMemoryFree(rsp->subRsp); - taosMemoryFree(rsp); } else { task->errCode = uvTask->errCode; } @@ -714,13 +930,13 @@ int32_t createUdfcUvTask(SClientUdfTask *task, int8_t uvTaskType, SClientUvTaskN request.seqNum = gUdfTaskSeqNum++; if (task->type == UDF_TASK_SETUP) { - request.subReq = &task->_setup.req; + request.setup = task->_setup.req; request.type = UDF_TASK_SETUP; } else if (task->type == UDF_TASK_CALL) { - request.subReq = &task->_call.req; + request.call = task->_call.req; request.type = UDF_TASK_CALL; } else if (task->type == UDF_TASK_TEARDOWN) { - request.subReq = &task->_teardown.req; + request.teardown = task->_teardown.req; request.type = UDF_TASK_TEARDOWN; } else { //TODO log and return error @@ -947,8 +1163,7 @@ int32_t udfcRunUvTask(SClientUdfTask *task, int8_t uvTaskType) { udfcGetUvTaskResponseResult(task, uvTask); if (uvTaskType == UV_TASK_CONNECT) { task->session->udfSvcPipe = uvTask->pipe; - } - taosMemoryFree(uvTask); + } taosMemoryFree(uvTask); uvTask = NULL; return task->errCode; } @@ -983,8 +1198,8 @@ int32_t setupUdf(SUdfInfo *udfInfo, UdfHandle *handle) { return err; } -int32_t callUdf(UdfHandle handle, int8_t step, char *state, int32_t stateSize, SUdfDataBlock input, char **newState, - int32_t *newStateSize, SUdfDataBlock *output) { +int32_t callUdf(UdfHandle handle, int8_t callType, SUdfDataBlock *input, SUdfInterBuf *state, + SUdfColumnData* output, SUdfInterBuf *newState, bool initFirst) { debugPrint("%s", "client call udf"); SClientUdfTask *task = taosMemoryMalloc(sizeof(SClientUdfTask)); @@ -993,24 +1208,47 @@ int32_t callUdf(UdfHandle handle, int8_t step, char *state, int32_t stateSize, S task->type = UDF_TASK_CALL; SUdfCallRequest *req = &task->_call.req; + switch (callType) { + case TSDB_UDF_CALL_AGG_PROC: { + req->block = *input; + req->interBuf = *state; + req->initFirst = initFirst; + break; + } + + case TSDb_UDF_CALL_AGG_FIN: { + req->interBuf = *state; + break; + } + case TSDB_UDF_CALL_SCALA_PROC: { + req->block = *input; + break; + } + } + - req->state = state; - req->stateBytes = stateSize; - req->inputBytes = input.size; - req->input = input.data; - req->udfHandle = task->session->severHandle; - req->step = step; udfcRunUvTask(task, UV_TASK_REQ_RSP); SUdfCallResponse *rsp = &task->_call.rsp; - *newState = rsp->newState; - *newStateSize = rsp->newStateBytes; - output->size = rsp->outputBytes; - output->data = rsp->output; - int32_t err = task->errCode; + switch (callType) { + case TSDB_UDF_CALL_AGG_PROC: { + *newState = rsp->interBuf; + break; + } + + case TSDb_UDF_CALL_AGG_FIN: { + *output = rsp->resultData; + break; + } + case TSDB_UDF_CALL_SCALA_PROC: { + *output = rsp->resultData; + break; + } + } + taosMemoryFree(task); - return err; + return task->errCode; } int32_t teardownUdf(UdfHandle handle) { diff --git a/source/libs/function/src/udfd.c b/source/libs/function/src/udfd.c index 2d9344709a..41995c8192 100644 --- a/source/libs/function/src/udfd.c +++ b/source/libs/function/src/udfd.c @@ -44,7 +44,7 @@ typedef struct SUdf { int8_t type; uv_lib_t lib; - TUdfFunc normalFunc; + TUdfScalarProcFunc normalFunc; } SUdf; //TODO: low priority: change name onxxx to xxxCb, and udfc or udfd as prefix From 946b565e992503fd538bb60af03ce4c6a95202ad Mon Sep 17 00:00:00 2001 From: shenglian zhou Date: Thu, 14 Apr 2022 19:29:41 +0800 Subject: [PATCH 06/19] sync home and office --- source/libs/function/CMakeLists.txt | 4 ++ source/libs/function/inc/tudf.h | 59 ++++++--------- source/libs/function/inc/tudfInt.h | 12 ++-- source/libs/function/src/tudf.c | 107 +++++++++++++++++----------- source/libs/function/src/udfd.c | 98 ++++++++++++------------- source/libs/function/test/udf1.c | 60 ++++++++++++---- 6 files changed, 191 insertions(+), 149 deletions(-) diff --git a/source/libs/function/CMakeLists.txt b/source/libs/function/CMakeLists.txt index aa909361ea..50900120a9 100644 --- a/source/libs/function/CMakeLists.txt +++ b/source/libs/function/CMakeLists.txt @@ -5,6 +5,7 @@ target_include_directories( function PUBLIC "${TD_SOURCE_DIR}/include/libs/function" + "${TD_SOURCE_DIR}/inlcude/util" "${TD_SOURCE_DIR}/contrib/libuv/include" PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/inc" ) @@ -21,6 +22,7 @@ target_include_directories( PUBLIC "${TD_SOURCE_DIR}/include/libs/function" "${TD_SOURCE_DIR}/contrib/libuv/include" + "${TD_SOURCE_DIR}/inlcude/util" "${TD_SOURCE_DIR}/include/os" PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/inc" ) @@ -35,6 +37,7 @@ target_include_directories( udf1 PUBLIC "${TD_SOURCE_DIR}/include/libs/function" + "${TD_SOURCE_DIR}/include/util" "${TD_SOURCE_DIR}/include/os" PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/inc" ) @@ -46,6 +49,7 @@ target_include_directories( PUBLIC "${TD_SOURCE_DIR}/include/libs/function" "${TD_SOURCE_DIR}/contrib/libuv/include" + "${TD_SOURCE_DIR}/inlcude/util" PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/inc" ) diff --git a/source/libs/function/inc/tudf.h b/source/libs/function/inc/tudf.h index 41183d5533..86a55d296c 100644 --- a/source/libs/function/inc/tudf.h +++ b/source/libs/function/inc/tudf.h @@ -16,13 +16,17 @@ #ifndef TDENGINE_TUDF_H #define TDENGINE_TUDF_H + +#include +#include +#include "tmsg.h" + #ifdef __cplusplus extern "C" { #endif //====================================================================================== //begin API to taosd and qworker -#define TSDB_UDF_MAX_COLUMNS 4 enum { UDFC_CODE_STOPPING = -1, @@ -41,35 +45,6 @@ int32_t startUdfService(); */ int32_t stopUdfService(); -enum { - TSDB_UDF_TYPE_SCALAR = 0, - TSDB_UDF_TYPE_AGGREGATE = 1 -}; - -enum { - TSDB_UDF_SCRIPT_BIN_LIB = 0, - TSDB_UDF_SCRIPT_LUA = 1, -}; - -typedef struct SUdfColumnMeta { - int16_t type; - int32_t bytes; // <0 var length, others fixed length bytes - uint8_t precision; - uint8_t scale; -} SUdfColumnMeta; - -typedef struct SUdfInfo { - char *udfName; // function name - int32_t udfType; // scalar function or aggregate function - int8_t scriptType; - char *path; - - // known info between qworker and udf - // struct SUdfColumnMeta resultMeta; - // int32_t bufSize; //interbuf size - -} SUdfInfo; - typedef void *UdfHandle; /** @@ -78,8 +53,14 @@ typedef void *UdfHandle; * @param handle, out * @return error code */ -int32_t setupUdf(SUdfInfo* udf, UdfHandle *handle); +int32_t setupUdf(char udfName[], SEpSet epSet, UdfHandle *handle); +typedef struct SUdfColumnMeta { + int16_t type; + int32_t bytes; // <0 var length, others fixed length bytes + uint8_t precision; + uint8_t scale; +} SUdfColumnMeta; typedef struct SUdfColumnData { int32_t numOfRows; @@ -108,7 +89,7 @@ typedef struct SUdfColumn { typedef struct SUdfDataBlock { int32_t numOfRows; int32_t numOfCols; - SUdfColumn udfCols[TSDB_UDF_MAX_COLUMNS]; + SUdfColumn **udfCols; } SUdfDataBlock; typedef struct SUdfInterBuf { @@ -138,13 +119,17 @@ int32_t teardownUdf(UdfHandle handle); // begin API to UDF writer. // dynamic lib init and destroy -typedef int32_t (*TUdfInitFunc)(); -typedef int32_t (*TUdfDestroyFunc)(); +typedef int32_t (*TUdfSetupFunc)(); +typedef int32_t (*TUdfTeardownFunc)(); + +typedef int32_t (*TUdfFreeUdfColumnDataFunc)(SUdfColumnData* columnData); typedef int32_t (*TUdfScalarProcFunc)(SUdfDataBlock block, SUdfColumnData *resultData); -typedef int32_t (*TUdfAggInit)(SUdfInterBuf *buf); -typedef int32_t (*TUdfAggProcess)(SUdfDataBlock block, SUdfInterBuf *interBuf); -typedef int32_t (*TUdfAggFinalize)(SUdfInterBuf buf, SUdfColumnData *resultData); +typedef int32_t (*TUdfAggInitFunc)(SUdfInterBuf *buf); +typedef int32_t (*TUdfAggProcessFunc)(SUdfDataBlock block, SUdfInterBuf *interBuf); +typedef int32_t (*TUdfAggFinalizeFunc)(SUdfInterBuf buf, SUdfColumnData *resultData); + + // end API to UDF writer //======================================================================================================================= diff --git a/source/libs/function/inc/tudfInt.h b/source/libs/function/inc/tudfInt.h index 2e0b405916..d765a8d2dc 100644 --- a/source/libs/function/inc/tudfInt.h +++ b/source/libs/function/inc/tudfInt.h @@ -15,7 +15,6 @@ #ifndef TDENGINE_TUDF_INT_H #define TDENGINE_TUDF_INT_H - #ifdef __cplusplus extern "C" { #endif @@ -37,11 +36,8 @@ enum { }; typedef struct SUdfSetupRequest { - char udfName[16]; // - int8_t scriptType; // 0:c, 1: lua, 2:js - int8_t udfType; //udaf, udf - int16_t pathSize; - char *path; + char udfName[TSDB_FUNC_NAME_LEN]; + SEpSet epSet; } SUdfSetupRequest; typedef struct SUdfSetupResponse { @@ -101,6 +97,10 @@ int32_t encodeRequest(char **buf, int32_t *bufLen, SUdfRequest *request); int32_t decodeResponse(char *buf, int32_t bufLen, SUdfResponse *pResponse); int32_t encodeResponse(char **buf, int32_t *bufLen, SUdfResponse *response); +void freeUdfColumnData(SUdfColumnData *data); +void freeUdfColumn(SUdfColumn* col); +void freeUdfDataDataBlock(SUdfDataBlock *block); + #ifdef __cplusplus } #endif diff --git a/source/libs/function/src/tudf.c b/source/libs/function/src/tudf.c index d5089ca0eb..0acb7210ae 100644 --- a/source/libs/function/src/tudf.c +++ b/source/libs/function/src/tudf.c @@ -254,25 +254,30 @@ int32_t deserializeUdfColumnData(SUdfColumnData* pData, char* buf) { pData->nullBitmapLen = *(int32_t*)buf; buf += sizeof(int32_t); - pData->nullBitmap = buf; + //TODO: optimize for less memory copy + pData->nullBitmap = taosMemoryMalloc(pData->nullBitmapLen); + memcpy(pData->nullBitmap, buf, pData->nullBitmapLen); buf += pData->nullBitmapLen; pData->dataLen = *(int32_t*)buf; buf += sizeof(int32_t); - pData->data = buf; + pData->data = taosMemoryMalloc(pData->dataLen); + memcpy(pData->data, buf, pData->dataLen); buf += pData->dataLen; } else { pData->varOffsetsLen = *(int32_t*)buf; buf += sizeof(int32_t); - pData->varOffsets = buf; + pData->varOffsets = taosMemoryMalloc(pData->varOffsetsLen); + memcpy(pData->varOffsets, buf, pData->varOffsetsLen); buf += pData->varOffsetsLen; pData->payloadLen = *(int32_t*)buf; buf += sizeof(int32_t); - pData->payload = buf; + pData->payload = taosMemoryMalloc(pData->payloadLen); + memcpy(pData->payload, buf, pData->payloadLen); buf += pData->payloadLen; } int32_t len = buf - bufBeg; @@ -333,7 +338,7 @@ int32_t serializeUdfDataBlock(SUdfDataBlock *block, char *pBuf) { pBuf += sizeof(int32_t); for (int32_t i = 0; i < block->numOfCols; ++i) { - SUdfColumn* col = block->udfCols + i; + SUdfColumn* col = block->udfCols[i]; int32_t l = serializeUdfColumn(col, pBuf); pBuf += l; } @@ -342,7 +347,7 @@ int32_t serializeUdfDataBlock(SUdfDataBlock *block, char *pBuf) { return totalLen; } -int32_t deserailizeUdfDataBlock(SUdfDataBlock *pBlock, char *buf) { +int32_t deserializeUdfDataBlock(SUdfDataBlock *pBlock, char *buf) { char *bufBegin = buf; pBlock->numOfRows = *(int32_t*)buf; @@ -351,8 +356,10 @@ int32_t deserailizeUdfDataBlock(SUdfDataBlock *pBlock, char *buf) { pBlock->numOfCols = *(int32_t*)buf; buf += sizeof(int32_t); + pBlock->udfCols = taosMemoryMalloc(sizeof(SUdfColumn*) * pBlock->numOfCols); for (int32_t i = 0; i < pBlock->numOfCols; ++i) { - int32_t l = deserializeUdfColumn(pBlock->udfCols + i, buf); + pBlock->udfCols[i] = taosMemoryMalloc(sizeof(SUdfColumn)); + int32_t l = deserializeUdfColumn(pBlock->udfCols[i], buf); buf += l; } @@ -369,14 +376,16 @@ int32_t serializeUdfInterBuf(SUdfInterBuf *state, char *pBuf) { memcpy(pBuf, state->buf, state->bufLen); pBuf += state->bufLen; - return pBuf-bufBegin; + return pBuf - bufBegin; } int32_t deserializeUdfInterBuf(SUdfInterBuf *pState, char *buf) { char* bufBegin = buf; pState->bufLen = *(int32_t*)buf; buf += sizeof(int32_t); - pState->buf = buf; + + pState->buf = taosMemoryMalloc(pState->bufLen); + memcpy(pState->buf, buf, pState->bufLen); buf += pState->bufLen; return buf - bufBegin; } @@ -384,16 +393,11 @@ int32_t deserializeUdfInterBuf(SUdfInterBuf *pState, char *buf) { int32_t serializeUdfSetupRequest(SUdfSetupRequest *setup, char *buf) { char *bufBegin = buf; - memcpy(buf, setup->udfName, 16); - buf += 16; - *(int8_t *) buf = setup->scriptType; - buf += sizeof(int8_t); - *(int8_t *) buf = setup->udfType; - buf += sizeof(int8_t); - *(int16_t *) buf = setup->pathSize; - buf += sizeof(int16_t); - memcpy(buf, setup->path, setup->pathSize); - buf += setup->pathSize; + memcpy(buf, setup->udfName, TSDB_FUNC_NAME_LEN); + buf += TSDB_FUNC_NAME_LEN; + + memcpy(buf, &setup->epSet, sizeof(SEpSet)); + buf += sizeof(SEpSet); return buf - bufBegin; }; @@ -401,17 +405,11 @@ int32_t serializeUdfSetupRequest(SUdfSetupRequest *setup, char *buf) { int32_t deserializeUdfSetupRequest(SUdfSetupRequest *setup, char *buf) { char* bufBegin = buf; - memcpy(setup->udfName, buf, 16); - buf += 16; - setup->scriptType = *(int8_t *) buf; - buf += sizeof(int8_t); - setup->udfType = *(int8_t *) buf; - buf += sizeof(int8_t); - setup->pathSize = *(int16_t *) buf; - buf += sizeof(int16_t); - setup->path = buf; - buf += setup->pathSize; + memcpy(setup->udfName, buf, TSDB_FUNC_NAME_LEN); + buf += TSDB_FUNC_NAME_LEN; + memcpy(&setup->epSet, buf, sizeof(SEpSet)); + buf += sizeof(SEpSet); return buf - bufBegin; } @@ -479,7 +477,7 @@ int32_t deserializeUdfCallRequest(SUdfCallRequest *call, char *buf) { call->callType = *(int8_t *) buf; buf += sizeof(int8_t); int32_t l = 0; - l = deserailizeUdfDataBlock(&call->block, buf); + l = deserializeUdfDataBlock(&call->block, buf); buf += l; l = deserializeUdfInterBuf(&call->interBuf, buf); buf += l; @@ -633,11 +631,11 @@ int32_t deserializeUdfResponse(SUdfResponse *rsp, char *buf) { int32_t estimateUdfRequestLen(SUdfRequest *request) { // a larger estimated is generated int32_t size = sizeof(SUdfRequest); - if (request->type == UDF_TASK_SETUP) { - size += request->setup.pathSize; - } else if (request->type == UDF_TASK_CALL) { + if (request->type == UDF_TASK_CALL) { + size += request->call.block.numOfCols * sizeof(SUdfColumn*); for (int32_t i = 0; i < request->call.block.numOfCols; ++i) { - SUdfColumn* col = request->call.block.udfCols + i; + size += sizeof(SUdfColumn); + SUdfColumn* col = request->call.block.udfCols[i]; if (col->colData.varLengthColumn) { size += col->colData.varOffsetsLen; size += col->colData.payloadLen; @@ -717,6 +715,39 @@ int32_t decodeResponse(char *bufMsg, int32_t bufLen, SUdfResponse *rsp) { return 0; } +void freeUdfColumnData(SUdfColumnData *data) { + if (data->varLengthColumn) { + taosMemoryFree(data->varOffsets); + data->varOffsets = NULL; + taosMemoryFree(data->payload); + data->payload = NULL; + } else { + taosMemoryFree(data->nullBitmap); + data->nullBitmap = NULL; + taosMemoryFree(data->data); + data->data = NULL; + } +} + +void freeUdfColumn(SUdfColumn* col) { + freeUdfColumnData(&col->colData); +} + +void freeUdfDataDataBlock(SUdfDataBlock *block) { + for (int32_t i = 0; i < block->numOfCols; ++i) { + freeUdfColumn(block->udfCols[i]); + taosMemoryFree(block->udfCols[i]); + block->udfCols[i] = NULL; + } + taosMemoryFree(block->udfCols); + block->udfCols = NULL; +} + +void freeUdfInterBuf(SUdfInterBuf *buf) { + taosMemoryFree(buf->buf); + buf->buf = NULL; +} + void onUdfcPipeClose(uv_handle_t *handle) { SClientUvConn *conn = handle->data; if (!QUEUE_EMPTY(&conn->taskQueue)) { @@ -1168,7 +1199,7 @@ int32_t udfcRunUvTask(SClientUdfTask *task, int8_t uvTaskType) { return task->errCode; } -int32_t setupUdf(SUdfInfo *udfInfo, UdfHandle *handle) { +int32_t setupUdf(char udfName[TSDB_FUNC_NAME_LEN], UdfHandle *handle) { debugPrint("%s", "client setup udf"); SClientUdfTask *task = taosMemoryMalloc(sizeof(SClientUdfTask)); task->errCode = 0; @@ -1176,11 +1207,7 @@ int32_t setupUdf(SUdfInfo *udfInfo, UdfHandle *handle) { task->type = UDF_TASK_SETUP; SUdfSetupRequest *req = &task->_setup.req; - memcpy(req->udfName, udfInfo->udfName, 16); - req->path = udfInfo->path; - req->pathSize = strlen(req->path) + 1; - req->udfType = udfInfo->udfType; - req->scriptType = udfInfo->scriptType; + memcpy(req->udfName, udfName, TSDB_FUNC_NAME_LEN); int32_t errCode = udfcRunUvTask(task, UV_TASK_CONNECT); if (errCode != 0) { diff --git a/source/libs/function/src/udfd.c b/source/libs/function/src/udfd.c index 41995c8192..477054abe8 100644 --- a/source/libs/function/src/udfd.c +++ b/source/libs/function/src/udfd.c @@ -44,7 +44,8 @@ typedef struct SUdf { int8_t type; uv_lib_t lib; - TUdfScalarProcFunc normalFunc; + TUdfScalarProcFunc scalarProcFunc; + TUdfFreeUdfColumnDataFunc freeUdfColumnData; } SUdf; //TODO: low priority: change name onxxx to xxxCb, and udfc or udfd as prefix @@ -56,19 +57,21 @@ typedef struct SUdfHandle { void udfdProcessRequest(uv_work_t *req) { SUvUdfWork *uvUdf = (SUvUdfWork *) (req->data); - SUdfRequest *request = NULL; + SUdfRequest request = {0}; decodeRequest(uvUdf->input.base, uvUdf->input.len, &request); - switch (request->type) { + switch (request.type) { case UDF_TASK_SETUP: { debugPrint("%s", "process setup request"); SUdf *udf = taosMemoryMalloc(sizeof(SUdf)); udf->refCount = 0; - SUdfSetupRequest *setup = request->subReq; + SUdfSetupRequest *setup = &request.setup; strcpy(udf->name, setup->udfName); - int err = uv_dlopen(setup->path, &udf->lib); + //TODO: retrive udf info from mnode + char* path = "udf1.so"; + int err = uv_dlopen(path, &udf->lib); if (err != 0) { - debugPrint("can not load library %s. error: %s", setup->path, uv_strerror(err)); + debugPrint("can not load library %s. error: %s", path, uv_strerror(err)); //TODO set error } @@ -76,99 +79,86 @@ void udfdProcessRequest(uv_work_t *req) { strcpy(normalFuncName, setup->udfName); //TODO error, //TODO find all functions normal, init, destroy, normal, merge, finalize - uv_dlsym(&udf->lib, normalFuncName, (void **) (&udf->normalFunc)); + uv_dlsym(&udf->lib, normalFuncName, (void **) (&udf->scalarProcFunc)); SUdfHandle *handle = taosMemoryMalloc(sizeof(SUdfHandle)); handle->udf = udf; udf->refCount++; //TODO: allocate private structure and call init function and set it to handle - SUdfResponse *rsp = taosMemoryMalloc(sizeof(SUdfResponse)); - rsp->seqNum = request->seqNum; - rsp->type = request->type; - rsp->code = 0; - SUdfSetupResponse *subRsp = taosMemoryMalloc(sizeof(SUdfSetupResponse)); - subRsp->udfHandle = (int64_t) (handle); - rsp->subRsp = subRsp; + SUdfResponse rsp; + rsp.seqNum = request.seqNum; + rsp.type = request.type; + rsp.code = 0; + rsp.setupRsp.udfHandle = (int64_t) (handle); char *buf; int32_t len; - encodeResponse(&buf, &len, rsp); + encodeResponse(&buf, &len, &rsp); uvUdf->output = uv_buf_init(buf, len); - taosMemoryFree(rsp->subRsp); - taosMemoryFree(rsp); - taosMemoryFree(request->subReq); - taosMemoryFree(request); taosMemoryFree(uvUdf->input.base); break; } case UDF_TASK_CALL: { debugPrint("%s", "process call request"); - SUdfCallRequest *call = request->subReq; + SUdfCallRequest *call = &request.call; SUdfHandle *handle = (SUdfHandle *) (call->udfHandle); SUdf *udf = handle->udf; - char *newState; - int32_t newStateSize; - SUdfDataBlock input = {.data = call->input, .size= call->inputBytes}; - SUdfDataBlock output; - //TODO: call different functions according to the step - udf->normalFunc(call->step, call->state, call->stateBytes, input, &newState, &newStateSize, &output); - SUdfResponse *rsp = taosMemoryMalloc(sizeof(SUdfResponse)); - rsp->seqNum = request->seqNum; - rsp->type = request->type; - rsp->code = 0; - SUdfCallResponse *subRsp = taosMemoryMalloc(sizeof(SUdfCallResponse)); - subRsp->outputBytes = output.size; - subRsp->output = output.data; - subRsp->newStateBytes = newStateSize; - subRsp->newState = newState; - rsp->subRsp = subRsp; + SUdfDataBlock input = call->block; + SUdfColumnData output; + //TODO: call different functions according to call type, for now just calar + if (call->callType == TSDB_UDF_CALL_SCALA_PROC) { + udf->scalarProcFunc(input, &output); + } + + SUdfResponse response = {0}; + SUdfResponse *rsp = &response; + if (call->callType == TSDB_UDF_CALL_SCALA_PROC) { + rsp->seqNum = request.seqNum; + rsp->type = request.type; + rsp->code = 0; + SUdfCallResponse *subRsp = &rsp->callRsp; + subRsp->resultData = output; + } char *buf; int32_t len; encodeResponse(&buf, &len, rsp); uvUdf->output = uv_buf_init(buf, len); - taosMemoryFree(rsp->subRsp); - taosMemoryFree(rsp); - taosMemoryFree(newState); - taosMemoryFree(output.data); - taosMemoryFree(request->subReq); - taosMemoryFree(request); + //TODO: free + udf->freeUdfColumnData(&output); + taosMemoryFree(uvUdf->input.base); break; } case UDF_TASK_TEARDOWN: { debugPrint("%s", "process teardown request"); - SUdfTeardownRequest *teardown = request->subReq; + SUdfTeardownRequest *teardown = &request.teardown; SUdfHandle *handle = (SUdfHandle *) (teardown->udfHandle); SUdf *udf = handle->udf; udf->refCount--; if (udf->refCount == 0) { uv_dlclose(&udf->lib); + taosMemoryFree(udf); } - taosMemoryFree(udf); - //TODO: call destroy and free udf private + //TODO: call destroy and free udf private taosMemoryFree(handle); - SUdfResponse *rsp = taosMemoryMalloc(sizeof(SUdfResponse)); - rsp->seqNum = request->seqNum; - rsp->type = request->type; + SUdfResponse response; + SUdfResponse *rsp = &response; + rsp->seqNum = request.seqNum; + rsp->type = request.type; rsp->code = 0; - SUdfTeardownResponse *subRsp = taosMemoryMalloc(sizeof(SUdfTeardownResponse)); - rsp->subRsp = subRsp; + SUdfTeardownResponse *subRsp = &response.teardownRsp; char *buf; int32_t len; encodeResponse(&buf, &len, rsp); uvUdf->output = uv_buf_init(buf, len); - taosMemoryFree(rsp->subRsp); - taosMemoryFree(rsp); - taosMemoryFree(request->subReq); - taosMemoryFree(request); taosMemoryFree(uvUdf->input.base); break; } diff --git a/source/libs/function/test/udf1.c b/source/libs/function/test/udf1.c index 3fdc522ef9..31819fa8e5 100644 --- a/source/libs/function/test/udf1.c +++ b/source/libs/function/test/udf1.c @@ -3,17 +3,53 @@ #include #include "tudf.h" -void udf1(int8_t step, char *state, int32_t stateSize, SUdfDataBlock input, - char **newState, int32_t *newStateSize, SUdfDataBlock *output) { - fprintf(stdout, "%s, step:%d\n", "udf function called", step); - char *newStateBuf = malloc(stateSize); - memcpy(newStateBuf, state, stateSize); - *newState = newStateBuf; - *newStateSize = stateSize; - char *outputBuf = malloc(input.size); - memcpy(outputBuf, input.data, input.size); - output->data = outputBuf; - output->size = input.size; - return; +int32_t udf1_setup() { + return 0; } + +int32_t udf1_teardown() { + return 0; +} + +int32_t udf1(SUdfDataBlock block, SUdfColumnData *resultData) { + + resultData->numOfRows = block.numOfRows; + SUdfColumnData *srcData = &block.udfCols[0]->colData; + resultData->varLengthColumn = srcData->varLengthColumn; + + if (resultData->varLengthColumn) { + resultData->varOffsetsLen = srcData->varOffsetsLen; + resultData->varOffsets = malloc(resultData->varOffsetsLen); + memcpy(resultData->varOffsets, srcData->varOffsets, srcData->varOffsetsLen); + + resultData->payloadLen = srcData->payloadLen; + resultData->payload = malloc(resultData->payloadLen); + memcpy(resultData->payload, srcData->payload, srcData->payloadLen); + } else { + resultData->nullBitmapLen = srcData->nullBitmapLen; + resultData->nullBitmap = malloc(resultData->nullBitmapLen); + memcpy(resultData->nullBitmap, srcData->nullBitmap, srcData->nullBitmapLen); + + resultData->dataLen = srcData->dataLen; + resultData->data = malloc(resultData->dataLen); + memcpy(resultData->data, srcData->data, srcData->dataLen); + } + + return 0; +} + +int32_t udf1_free(SUdfColumnData *data) { + if (data->varLengthColumn) { + free(data->varOffsets); + data->varOffsets = NULL; + free(data->payload); + data->payload = NULL; + } else { + free(data->nullBitmap); + data->nullBitmap = NULL; + free(data->data); + data->data = NULL; + } + return 0; +} \ No newline at end of file From ed597e6e54da13cf3605b03be80ec521de441161 Mon Sep 17 00:00:00 2001 From: slzhou Date: Fri, 15 Apr 2022 11:19:00 +0800 Subject: [PATCH 07/19] pass compilation before udf call refinement --- source/libs/function/CMakeLists.txt | 14 +++++++++++--- source/libs/function/inc/tudf.h | 2 +- source/libs/function/src/tudf.c | 2 +- source/libs/function/test/runUdf.c | 12 +++--------- source/libs/function/test/udf1.c | 4 ++++ 5 files changed, 20 insertions(+), 14 deletions(-) diff --git a/source/libs/function/CMakeLists.txt b/source/libs/function/CMakeLists.txt index 50900120a9..2ed8db589a 100644 --- a/source/libs/function/CMakeLists.txt +++ b/source/libs/function/CMakeLists.txt @@ -5,7 +5,9 @@ target_include_directories( function PUBLIC "${TD_SOURCE_DIR}/include/libs/function" - "${TD_SOURCE_DIR}/inlcude/util" + "${TD_SOURCE_DIR}/include/util" + "${TD_SOURCE_DIR}/include/common" + "${TD_SOURCE_DIR}/include/client" "${TD_SOURCE_DIR}/contrib/libuv/include" PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/inc" ) @@ -22,7 +24,9 @@ target_include_directories( PUBLIC "${TD_SOURCE_DIR}/include/libs/function" "${TD_SOURCE_DIR}/contrib/libuv/include" - "${TD_SOURCE_DIR}/inlcude/util" + "${TD_SOURCE_DIR}/include/util" + "${TD_SOURCE_DIR}/include/common" + "${TD_SOURCE_DIR}/include/client" "${TD_SOURCE_DIR}/include/os" PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/inc" ) @@ -38,6 +42,8 @@ target_include_directories( PUBLIC "${TD_SOURCE_DIR}/include/libs/function" "${TD_SOURCE_DIR}/include/util" + "${TD_SOURCE_DIR}/include/common" + "${TD_SOURCE_DIR}/include/client" "${TD_SOURCE_DIR}/include/os" PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/inc" ) @@ -49,7 +55,9 @@ target_include_directories( PUBLIC "${TD_SOURCE_DIR}/include/libs/function" "${TD_SOURCE_DIR}/contrib/libuv/include" - "${TD_SOURCE_DIR}/inlcude/util" + "${TD_SOURCE_DIR}/include/util" + "${TD_SOURCE_DIR}/include/common" + "${TD_SOURCE_DIR}/include/client" PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/inc" ) diff --git a/source/libs/function/inc/tudf.h b/source/libs/function/inc/tudf.h index 86a55d296c..64a7dd126f 100644 --- a/source/libs/function/inc/tudf.h +++ b/source/libs/function/inc/tudf.h @@ -53,7 +53,7 @@ typedef void *UdfHandle; * @param handle, out * @return error code */ -int32_t setupUdf(char udfName[], SEpSet epSet, UdfHandle *handle); +int32_t setupUdf(char udfName[], SEpSet *epSet, UdfHandle *handle); typedef struct SUdfColumnMeta { int16_t type; diff --git a/source/libs/function/src/tudf.c b/source/libs/function/src/tudf.c index 0acb7210ae..96c3756233 100644 --- a/source/libs/function/src/tudf.c +++ b/source/libs/function/src/tudf.c @@ -1199,7 +1199,7 @@ int32_t udfcRunUvTask(SClientUdfTask *task, int8_t uvTaskType) { return task->errCode; } -int32_t setupUdf(char udfName[TSDB_FUNC_NAME_LEN], UdfHandle *handle) { +int32_t setupUdf(char udfName[], SEpSet *epSet, UdfHandle *handle) { debugPrint("%s", "client setup udf"); SClientUdfTask *task = taosMemoryMalloc(sizeof(SClientUdfTask)); task->errCode = 0; diff --git a/source/libs/function/test/runUdf.c b/source/libs/function/test/runUdf.c index bd742d23d0..7afa459c89 100644 --- a/source/libs/function/test/runUdf.c +++ b/source/libs/function/test/runUdf.c @@ -18,10 +18,10 @@ int main(int argc, char *argv[]) { } fprintf(stdout, "current working directory:%s\n", path); strcat(path, "/libudf1.so"); - SUdfInfo udfInfo = {.udfName="udf1", .path=path}; UdfHandle handle; - setupUdf(&udfInfo, &handle); + SEpSet epSet; + setupUdf("udf1", &epSet, &handle); //char state[5000000] = "state"; //char input[5000000] = "input"; @@ -31,13 +31,7 @@ int main(int argc, char *argv[]) { if (argc > 2) callCount = atoi(argv[2]); char *state = taosMemoryMalloc(dataSize); char *input = taosMemoryMalloc(dataSize); - SUdfDataBlock blockInput = {.data = input, .size = dataSize}; - SUdfDataBlock blockOutput; - char* newState; - int32_t newStateSize; - for (int l = 0; l < callCount; ++l) { - callUdf(handle, 0, state, dataSize, blockInput, &newState, &newStateSize, &blockOutput); - } + //todo: call udf taosMemoryFree(state); taosMemoryFree(input); teardownUdf(handle); diff --git a/source/libs/function/test/udf1.c b/source/libs/function/test/udf1.c index 31819fa8e5..abe6e59984 100644 --- a/source/libs/function/test/udf1.c +++ b/source/libs/function/test/udf1.c @@ -4,6 +4,10 @@ #include "tudf.h" +#undef malloc +#define malloc malloc +#undef free +#define free free int32_t udf1_setup() { return 0; } From 5ea40c9d0e9d50bb833359f6ad2fe905f7df4667 Mon Sep 17 00:00:00 2001 From: slzhou Date: Fri, 15 Apr 2022 12:19:22 +0800 Subject: [PATCH 08/19] save for poweroff --- source/libs/function/inc/tudf.h | 9 ++++++--- source/libs/function/inc/tudfInt.h | 1 + source/libs/function/test/udf1.c | 1 + 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/source/libs/function/inc/tudf.h b/source/libs/function/inc/tudf.h index 64a7dd126f..fa009833c6 100644 --- a/source/libs/function/inc/tudf.h +++ b/source/libs/function/inc/tudf.h @@ -99,13 +99,16 @@ typedef struct SUdfInterBuf { // input: block, initFirst // output: interbuf -int32_t callUdfAggProcess(SUdfDataBlock block, SUdfInterBuf *interBuf, bool initFirst); +int32_t callUdfAggProcess(SUdfDataBlock *block, SUdfInterBuf *interBuf, bool initFirst); // input: interBuf // output: resultData -int32_t callUdfAggFinalize(SUdfInterBuf interBuf, SUdfColumnData* resultData); +int32_t callUdfAggFinalize(SUdfInterBuf *interBuf, SUdfColumnData *resultData); +// input: interbuf1, interbuf2 +// output: resultBuf +int32_t callUdfAggMerge(SUdfInterBuf *interBuf1, SUdfInterBuf *interBuf2, SUdfInterBuf *resultBuf); // input: block // output: resultData -int32_t callUdfScalaProcess(SUdfDataBlock block, SUdfColumnData* resultData); +int32_t callUdfScalaProcess(SUdfDataBlock *block, SUdfColumnData *resultData); /** * tearn down udf diff --git a/source/libs/function/inc/tudfInt.h b/source/libs/function/inc/tudfInt.h index d765a8d2dc..20fc98a08a 100644 --- a/source/libs/function/inc/tudfInt.h +++ b/source/libs/function/inc/tudfInt.h @@ -31,6 +31,7 @@ enum { enum { TSDB_UDF_CALL_AGG_PROC = 0, + TSDB_UDF_CALL_AGG_MERGE, TSDb_UDF_CALL_AGG_FIN, TSDB_UDF_CALL_SCALA_PROC, }; diff --git a/source/libs/function/test/udf1.c b/source/libs/function/test/udf1.c index abe6e59984..31e7a36e9c 100644 --- a/source/libs/function/test/udf1.c +++ b/source/libs/function/test/udf1.c @@ -8,6 +8,7 @@ #define malloc malloc #undef free #define free free + int32_t udf1_setup() { return 0; } From 7ed762430635b18bbb519399040de1eec587a1ab Mon Sep 17 00:00:00 2001 From: slzhou Date: Fri, 15 Apr 2022 18:31:57 +0800 Subject: [PATCH 09/19] after trying to retrive udf info from mnode --- source/dnode/mnode/impl/test/func/func.cpp | 2 +- source/libs/function/CMakeLists.txt | 1 + source/libs/function/src/udfd.c | 74 ++++++++++++++++++++++ 3 files changed, 76 insertions(+), 1 deletion(-) diff --git a/source/dnode/mnode/impl/test/func/func.cpp b/source/dnode/mnode/impl/test/func/func.cpp index f34f77de0c..ef1027c24b 100644 --- a/source/dnode/mnode/impl/test/func/func.cpp +++ b/source/dnode/mnode/impl/test/func/func.cpp @@ -230,7 +230,7 @@ TEST_F(MndTestFunc, 03_Retrieve_Func) { EXPECT_EQ(retrieveRsp.numOfFuncs, 1); EXPECT_EQ(retrieveRsp.numOfFuncs, (int32_t)taosArrayGetSize(retrieveRsp.pFuncInfos)); - SFuncInfo* pFuncInfo = (SFuncInfo*)taosArrayGet(retrieveRsp.pFuncInfos, 0); + * pFuncInfo = (SFuncInfo*)taosArrayGet(retrieveRsp.pFuncInfos, 0); EXPECT_STREQ(pFuncInfo->name, "f1"); EXPECT_EQ(pFuncInfo->funcType, 1); diff --git a/source/libs/function/CMakeLists.txt b/source/libs/function/CMakeLists.txt index 2ed8db589a..19a0897e20 100644 --- a/source/libs/function/CMakeLists.txt +++ b/source/libs/function/CMakeLists.txt @@ -57,6 +57,7 @@ target_include_directories( "${TD_SOURCE_DIR}/contrib/libuv/include" "${TD_SOURCE_DIR}/include/util" "${TD_SOURCE_DIR}/include/common" + "${TD_SOURCE_DIR}/include/libs/transport" "${TD_SOURCE_DIR}/include/client" PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/inc" ) diff --git a/source/libs/function/src/udfd.c b/source/libs/function/src/udfd.c index 477054abe8..27b99625fe 100644 --- a/source/libs/function/src/udfd.c +++ b/source/libs/function/src/udfd.c @@ -20,6 +20,10 @@ #include "tudf.h" #include "tudfInt.h" +#include "tdataformat.h" +#include "tglobal.h" +#include "tmsg.h" +#include "trpc.h" static uv_loop_t *loop; @@ -319,6 +323,76 @@ void removeListeningPipe(int sig) { exit(0); } +typedef struct SServerContext { + void *clientRpc; +} SUdfdContext; + + +void udfdProcessRpcRsp(void* parent, SRpcMsg* pMsg, SEpSet* pEpSet) { + + return; +} + +int32_t fetchUdfFuncInfo(void *clientRpc, SEpSet* pEpSet, char* udfNames[], int32_t numOfUdfs) { + SRetrieveFuncReq retrieveReq = {0}; + retrieveReq.numOfFuncs = 1; + retrieveReq.pFuncNames = taosArrayInit(1, TSDB_FUNC_NAME_LEN); + for (int32_t i = 0; i < numOfUdfs; ++i) { + taosArrayPush(retrieveReq.pFuncNames, udfNames[i]); + } + + int32_t contLen = tSerializeSRetrieveFuncReq(NULL, 0, &retrieveReq); + void* pReq = rpcMallocCont(contLen); + tSerializeSRetrieveFuncReq(pReq, contLen, &retrieveReq); + taosArrayDestroy(retrieveReq.pFuncNames); + + SRpcMsg rpcMsg = {0}; + rpcMsg.pCont = pReq; + rpcMsg.contLen = contLen; + rpcMsg.msgType = TDMT_MND_RETRIEVE_FUNC; + + SRpcMsg rpcRsp = {0}; + rpcSendRecv(clientRpc, pEpSet, &rpcMsg, &rpcRsp); + SRetrieveFuncRsp retrieveRsp = {0}; + tDeserializeSRetrieveFuncRsp(rpcRsp.pCont, rpcRsp.contLen, &retrieveRsp); + + SFuncInfo* pFuncInfo = (SFuncInfo*)taosArrayGet(retrieveRsp.pFuncInfos, 0); + + taosArrayDestroy(retrieveRsp.pFuncInfos); + + rpcFreeCont(rpcRsp.pCont); + return 0; +} + +int32_t openUdfdClientRpc(SUdfdContext *ctx) { + char *pass = "taosdata"; + char *user = "root"; + char secretEncrypt[TSDB_PASSWORD_LEN + 1] = {0}; + taosEncryptPass_c((uint8_t*)pass, strlen(pass), secretEncrypt); + SRpcInit rpcInit = {0}; + rpcInit.label = (char*)"UDFD"; + rpcInit.numOfThreads = 1; + rpcInit.cfp = udfdProcessRpcRsp; + rpcInit.sessions = 1024; + rpcInit.connType = TAOS_CONN_CLIENT; + rpcInit.idleTime = 30 * 1000; + rpcInit.parent = ctx; + + rpcInit.user = (char*)user; + rpcInit.ckey = (char*)"key"; + rpcInit.secret = (char*)secretEncrypt; + rpcInit.spi = 1; + + ctx->clientRpc = rpcOpen(&rpcInit); + + return 0; +} + +int32_t closeUdfdClientRpc(SUdfdContext *ctx) { + rpcClose(ctx->clientRpc); + + return 0; +} int main() { debugPrint("libuv version: %x", UV_VERSION_HEX); From 4e6caa3495f7cc56b5bebfd5289a3f527f54e3ad Mon Sep 17 00:00:00 2001 From: slzhou Date: Sat, 16 Apr 2022 14:19:33 +0800 Subject: [PATCH 10/19] before using ssdatablock for udfd/udfdc communication --- source/libs/function/inc/tudf.h | 5 +++++ source/libs/function/inc/tudfInt.h | 1 + source/libs/function/src/tudf.c | 5 ++--- source/libs/function/src/udfd.c | 1 + 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/source/libs/function/inc/tudf.h b/source/libs/function/inc/tudf.h index fa009833c6..45e4b2a0f5 100644 --- a/source/libs/function/inc/tudf.h +++ b/source/libs/function/inc/tudf.h @@ -125,6 +125,11 @@ int32_t teardownUdf(UdfHandle handle); typedef int32_t (*TUdfSetupFunc)(); typedef int32_t (*TUdfTeardownFunc)(); +//TODO: another way to manage memory is provide api for UDF to add data to SUdfColumnData and UDF framework will allocate memory. +// then UDF framework will free the memory +//typedef int32_t addFixedLengthColumnData(SColumnData *columnData, int rowIndex, bool isNull, int32_t colBytes, char* data); +//typedef int32_t addVariableLengthColumnData(SColumnData *columnData, int rowIndex, bool isNull, int32_t dataLen, char * data); + typedef int32_t (*TUdfFreeUdfColumnDataFunc)(SUdfColumnData* columnData); typedef int32_t (*TUdfScalarProcFunc)(SUdfDataBlock block, SUdfColumnData *resultData); diff --git a/source/libs/function/inc/tudfInt.h b/source/libs/function/inc/tudfInt.h index 20fc98a08a..7890eef8be 100644 --- a/source/libs/function/inc/tudfInt.h +++ b/source/libs/function/inc/tudfInt.h @@ -51,6 +51,7 @@ typedef struct SUdfCallRequest { SUdfDataBlock block; SUdfInterBuf interBuf; + SUdfInterBuf interBuf2; bool initFirst; } SUdfCallRequest; diff --git a/source/libs/function/src/tudf.c b/source/libs/function/src/tudf.c index 96c3756233..283dfd06bb 100644 --- a/source/libs/function/src/tudf.c +++ b/source/libs/function/src/tudf.c @@ -372,7 +372,6 @@ int32_t serializeUdfInterBuf(SUdfInterBuf *state, char *pBuf) { *(int32_t*)pBuf = state->bufLen; pBuf += sizeof(int32_t); - memcpy(pBuf, state->buf, state->bufLen); pBuf += state->bufLen; @@ -463,6 +462,8 @@ int32_t serializeUdfCallRequest(SUdfCallRequest *call, char *buf) { buf += l; l = serializeUdfInterBuf(&call->interBuf, buf); buf += l; + l = serializeUdfInterBuf(&call->interBuf2, buf); + buf += l; *(bool*)buf = call->initFirst; buf += sizeof(bool); @@ -1253,8 +1254,6 @@ int32_t callUdf(UdfHandle handle, int8_t callType, SUdfDataBlock *input, SUdfInt } } - - udfcRunUvTask(task, UV_TASK_REQ_RSP); SUdfCallResponse *rsp = &task->_call.rsp; diff --git a/source/libs/function/src/udfd.c b/source/libs/function/src/udfd.c index 27b99625fe..a1996133e7 100644 --- a/source/libs/function/src/udfd.c +++ b/source/libs/function/src/udfd.c @@ -393,6 +393,7 @@ int32_t closeUdfdClientRpc(SUdfdContext *ctx) { return 0; } + int main() { debugPrint("libuv version: %x", UV_VERSION_HEX); From 3526c0d45552d29e6a90b465594af1f7bc8cbd75 Mon Sep 17 00:00:00 2001 From: shenglian zhou Date: Sat, 16 Apr 2022 17:13:09 +0800 Subject: [PATCH 11/19] remove accidental change of func.cpp --- source/dnode/mnode/impl/test/func/func.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/dnode/mnode/impl/test/func/func.cpp b/source/dnode/mnode/impl/test/func/func.cpp index dc3d2d1b02..6b9c410738 100644 --- a/source/dnode/mnode/impl/test/func/func.cpp +++ b/source/dnode/mnode/impl/test/func/func.cpp @@ -208,7 +208,7 @@ TEST_F(MndTestFunc, 03_Retrieve_Func) { EXPECT_EQ(retrieveRsp.numOfFuncs, 1); EXPECT_EQ(retrieveRsp.numOfFuncs, (int32_t)taosArrayGetSize(retrieveRsp.pFuncInfos)); - * pFuncInfo = (SFuncInfo*)taosArrayGet(retrieveRsp.pFuncInfos, 0); + SFuncInfo* pFuncInfo = (SFuncInfo*)taosArrayGet(retrieveRsp.pFuncInfos, 0); EXPECT_STREQ(pFuncInfo->name, "f1"); EXPECT_EQ(pFuncInfo->funcType, 1); From 4817f54ae9acc52d31561b5a48ba2b9e567f9c40 Mon Sep 17 00:00:00 2001 From: shenglian zhou Date: Sat, 16 Apr 2022 23:34:40 +0800 Subject: [PATCH 12/19] SSDataBlock and SUdfInterBuf message passing between taosd/udfd --- source/libs/function/inc/tudf.h | 10 +- source/libs/function/inc/tudfInt.h | 21 +- source/libs/function/src/tudf.c | 736 ++++++++++------------------- source/libs/function/src/udfd.c | 28 +- 4 files changed, 278 insertions(+), 517 deletions(-) diff --git a/source/libs/function/inc/tudf.h b/source/libs/function/inc/tudf.h index 45e4b2a0f5..683274f3ae 100644 --- a/source/libs/function/inc/tudf.h +++ b/source/libs/function/inc/tudf.h @@ -20,6 +20,7 @@ #include #include #include "tmsg.h" +#include "tcommon.h" #ifdef __cplusplus extern "C" { @@ -97,18 +98,20 @@ typedef struct SUdfInterBuf { char* buf; } SUdfInterBuf; +//TODO: translate these calls to callUdf +int32_t callUdfAggInit(SUdfInterBuf *interBuf); // input: block, initFirst // output: interbuf -int32_t callUdfAggProcess(SUdfDataBlock *block, SUdfInterBuf *interBuf, bool initFirst); +int32_t callUdfAggProcess(SSDataBlock *block, SUdfInterBuf *interBuf); // input: interBuf // output: resultData -int32_t callUdfAggFinalize(SUdfInterBuf *interBuf, SUdfColumnData *resultData); +int32_t callUdfAggFinalize(SUdfInterBuf *interBuf, SSDataBlock *resultData); // input: interbuf1, interbuf2 // output: resultBuf int32_t callUdfAggMerge(SUdfInterBuf *interBuf1, SUdfInterBuf *interBuf2, SUdfInterBuf *resultBuf); // input: block // output: resultData -int32_t callUdfScalaProcess(SUdfDataBlock *block, SUdfColumnData *resultData); +int32_t callUdfScalaProcess(SSDataBlock *block, SSDataBlock *resultData); /** * tearn down udf @@ -125,6 +128,7 @@ int32_t teardownUdf(UdfHandle handle); typedef int32_t (*TUdfSetupFunc)(); typedef int32_t (*TUdfTeardownFunc)(); +//TODO: add API to check function arguments type, number etc. //TODO: another way to manage memory is provide api for UDF to add data to SUdfColumnData and UDF framework will allocate memory. // then UDF framework will free the memory //typedef int32_t addFixedLengthColumnData(SColumnData *columnData, int rowIndex, bool isNull, int32_t colBytes, char* data); diff --git a/source/libs/function/inc/tudfInt.h b/source/libs/function/inc/tudfInt.h index 7890eef8be..6c3da8cd89 100644 --- a/source/libs/function/inc/tudfInt.h +++ b/source/libs/function/inc/tudfInt.h @@ -30,9 +30,10 @@ enum { }; enum { - TSDB_UDF_CALL_AGG_PROC = 0, + TSDB_UDF_CALL_AGG_INIT = 0, + TSDB_UDF_CALL_AGG_PROC, TSDB_UDF_CALL_AGG_MERGE, - TSDb_UDF_CALL_AGG_FIN, + TSDB_UDF_CALL_AGG_FIN, TSDB_UDF_CALL_SCALA_PROC, }; @@ -49,14 +50,15 @@ typedef struct SUdfCallRequest { int64_t udfHandle; int8_t callType; - SUdfDataBlock block; + SSDataBlock block; SUdfInterBuf interBuf; SUdfInterBuf interBuf2; - bool initFirst; + int8_t initFirst; } SUdfCallRequest; typedef struct SUdfCallResponse { - SUdfColumnData resultData; + int8_t callType; + SSDataBlock resultData; SUdfInterBuf interBuf; } SUdfCallResponse; @@ -94,10 +96,11 @@ typedef struct SUdfResponse { }; } SUdfResponse; -int32_t decodeRequest(char *buf, int32_t bufLen, SUdfRequest *pRequest); -int32_t encodeRequest(char **buf, int32_t *bufLen, SUdfRequest *request); -int32_t decodeResponse(char *buf, int32_t bufLen, SUdfResponse *pResponse); -int32_t encodeResponse(char **buf, int32_t *bufLen, SUdfResponse *response); +int32_t encodeUdfRequest(void **buf, const SUdfRequest* request); +void* decodeUdfRequest(const void *buf, SUdfRequest* request); + +int32_t encodeUdfResponse(void **buf, const SUdfResponse *response); +void* decodeUdfResponse(const void* buf, SUdfResponse *response); void freeUdfColumnData(SUdfColumnData *data); void freeUdfColumn(SUdfColumn* col); diff --git a/source/libs/function/src/tudf.c b/source/libs/function/src/tudf.c index 283dfd06bb..c8601c69c8 100644 --- a/source/libs/function/src/tudf.c +++ b/source/libs/function/src/tudf.c @@ -213,507 +213,241 @@ QUEUE gUdfTaskQueue = {0}; QUEUE gUvProcTaskQueue = {0}; -int32_t serializeUdfColumnData(SUdfColumnData* data, char* pBuf) { - char* bufBeg = pBuf; - *(int32_t*)pBuf = data->numOfRows; - pBuf += sizeof(int32_t); - *(bool*)pBuf = data->varLengthColumn; - pBuf += sizeof(bool); +int32_t encodeUdfSetupRequest(void **buf, const SUdfSetupRequest *setup) { + int32_t len = 0; + len += taosEncodeBinary(buf, setup->udfName, TSDB_FUNC_NAME_LEN); + len += taosEncodeSEpSet(buf, &setup->epSet); + return len; +} - if (!data->varLengthColumn) { - *(int32_t*)pBuf = data->nullBitmapLen; - pBuf += sizeof(int32_t); - memcpy(pBuf, data->nullBitmap, data->nullBitmapLen); - pBuf += data->nullBitmapLen; - *(int32_t*)pBuf = data->dataLen; - pBuf += sizeof(int32_t); - memcpy(pBuf, data->data, data->dataLen); - pBuf += data->dataLen; +void* decodeUdfSetupRequest(const void* buf, SUdfSetupRequest *request) { + buf = taosDecodeBinaryTo(buf, request->udfName, TSDB_FUNC_NAME_LEN); + buf = taosDecodeSEpSet((void*)buf, &request->epSet); + return (void*)buf; +} + +int32_t encodeUdfInterBuf(void **buf, const SUdfInterBuf* state) { + int32_t len = 0; + len += taosEncodeFixedI32(buf, state->bufLen); + len += taosEncodeBinary(buf, state->buf, state->bufLen); + return len; +} + +void* decodeUdfInterBuf(const void* buf, SUdfInterBuf* state) { + buf = taosDecodeFixedI32(buf, &state->bufLen); + buf = taosDecodeBinary(buf, (void**)&state->buf, state->bufLen); + return (void*)buf; +} + +int32_t encodeUdfCallRequest(void **buf, const SUdfCallRequest *call) { + int32_t len = 0; + len += taosEncodeFixedI64(buf, call->udfHandle); + len += taosEncodeFixedI8(buf, call->callType); + if (call->callType == TSDB_UDF_CALL_SCALA_PROC) { + len += tEncodeDataBlock(buf, &call->block); + } else if (call->callType == TSDB_UDF_CALL_AGG_INIT) { + len += taosEncodeFixedI8(buf, call->initFirst); + } else if (call->callType == TSDB_UDF_CALL_AGG_PROC) { + len += tEncodeDataBlock(buf, &call->block); + len += encodeUdfInterBuf(buf, &call->interBuf); + } else if (call->callType == TSDB_UDF_CALL_AGG_MERGE) { + len += encodeUdfInterBuf(buf, &call->interBuf); + len += encodeUdfInterBuf(buf, &call->interBuf2); + } else if (call->callType == TSDB_UDF_CALL_AGG_FIN) { + len += encodeUdfInterBuf(buf, &call->interBuf); + } + return len; +} + +void* decodeUdfCallRequest(const void* buf, SUdfCallRequest* call) { + buf = taosDecodeFixedI64(buf, &call->udfHandle); + buf = taosDecodeFixedI8(buf, &call->callType); + switch (call->callType) { + case TSDB_UDF_CALL_SCALA_PROC: + buf = tDecodeDataBlock(buf, &call->block); + break; + case TSDB_UDF_CALL_AGG_INIT: + buf = taosDecodeFixedI8(buf, &call->initFirst); + break; + case TSDB_UDF_CALL_AGG_PROC: + buf = tDecodeDataBlock(buf, &call->block); + buf = decodeUdfInterBuf(buf, &call->interBuf); + break; + case TSDB_UDF_CALL_AGG_MERGE: + buf = decodeUdfInterBuf(buf, &call->interBuf); + buf = decodeUdfInterBuf(buf, &call->interBuf2); + break; + case TSDB_UDF_CALL_AGG_FIN: + buf = decodeUdfInterBuf(buf, &call->interBuf); + break; + } + return (void*)buf; +} + +int32_t encodeUdfTeardownRequest(void **buf, const SUdfTeardownRequest *teardown) { + int32_t len = 0; + len += taosEncodeFixedI64(buf, teardown->udfHandle); + return len; +} + +void* decodeUdfTeardownRequest(const void* buf, SUdfTeardownRequest *teardown) { + buf = taosDecodeFixedI64(buf, &teardown->udfHandle); + return (void*)buf; +} + +int32_t encodeUdfRequest(void** buf, const SUdfRequest* request) { + int32_t len = 0; + if (buf == NULL) { + len += sizeof(request->msgLen); } else { - *(int32_t*)pBuf = data->varOffsetsLen; - pBuf += sizeof(int32_t); - memcpy(pBuf, data->varOffsets, data->varOffsetsLen); - pBuf += data->varOffsetsLen; - *(int32_t*)pBuf = data->payloadLen; - pBuf += sizeof(int32_t); - memcpy(pBuf, data->payload, data->payloadLen); - pBuf += data->payloadLen; + *(int32_t*)(*buf) = request->msgLen; + *buf = POINTER_SHIFT(*buf, sizeof(request->msgLen)); } - int32_t len = pBuf - bufBeg; - return len; -} - -int32_t deserializeUdfColumnData(SUdfColumnData* pData, char* buf) { - char* bufBeg = buf; - pData->numOfRows = *(int32_t*)buf; - buf += sizeof(int32_t); - pData->varLengthColumn = *(bool*)buf; - buf += sizeof(bool); - - if (!pData->varLengthColumn) { - pData->nullBitmapLen = *(int32_t*)buf; - buf += sizeof(int32_t); - - //TODO: optimize for less memory copy - pData->nullBitmap = taosMemoryMalloc(pData->nullBitmapLen); - memcpy(pData->nullBitmap, buf, pData->nullBitmapLen); - buf += pData->nullBitmapLen; - - pData->dataLen = *(int32_t*)buf; - buf += sizeof(int32_t); - - pData->data = taosMemoryMalloc(pData->dataLen); - memcpy(pData->data, buf, pData->dataLen); - buf += pData->dataLen; - } else { - pData->varOffsetsLen = *(int32_t*)buf; - buf += sizeof(int32_t); - - pData->varOffsets = taosMemoryMalloc(pData->varOffsetsLen); - memcpy(pData->varOffsets, buf, pData->varOffsetsLen); - buf += pData->varOffsetsLen; - - pData->payloadLen = *(int32_t*)buf; - buf += sizeof(int32_t); - - pData->payload = taosMemoryMalloc(pData->payloadLen); - memcpy(pData->payload, buf, pData->payloadLen); - buf += pData->payloadLen; - } - int32_t len = buf - bufBeg; - return len; -} - -int32_t serializeUdfColumnMeta(SUdfColumnMeta *meta, char* pBuf) { - char* bufBeg = pBuf; - memcpy(pBuf, meta, sizeof(SUdfColumnMeta)); - pBuf += sizeof(SUdfColumnMeta); - - int32_t len = pBuf - bufBeg; - return len; -} - -int32_t deserializeUdfColumnMeta(SUdfColumnMeta *pMeta, char* buf) { - char *bufBegin = buf; - memcpy(pMeta, buf, sizeof(SUdfColumnMeta)); - buf += sizeof(SUdfColumnMeta); - - int32_t len = buf - bufBegin; - return len; -} - -int32_t serializeUdfColumn(SUdfColumn *udfCol, char *pBuf) { - char *bufBegin = pBuf; - - int32_t len = serializeUdfColumnMeta(&udfCol->colMeta, pBuf); - pBuf += len; - - len = serializeUdfColumnData(&udfCol->colData, pBuf); - pBuf += len; - - int32_t totalLen = pBuf - bufBegin; - return totalLen; -} - -int32_t deserializeUdfColumn(SUdfColumn *pUdfCol, char *buf) { - char *bufBegin = buf; - - int32_t len = deserializeUdfColumnMeta(&pUdfCol->colMeta, buf); - buf += len; - - len = deserializeUdfColumnData(&pUdfCol->colData, buf); - buf += len; - - int32_t totalLen = buf - bufBegin; - return totalLen; -} - -int32_t serializeUdfDataBlock(SUdfDataBlock *block, char *pBuf) { - char *bufBegin = pBuf; - - *(int32_t*)pBuf = block->numOfRows; - pBuf += sizeof(int32_t); - - *(int32_t*)pBuf = block->numOfCols; - pBuf += sizeof(int32_t); - - for (int32_t i = 0; i < block->numOfCols; ++i) { - SUdfColumn* col = block->udfCols[i]; - int32_t l = serializeUdfColumn(col, pBuf); - pBuf += l; - } - - int32_t totalLen = pBuf - bufBegin; - return totalLen; -} - -int32_t deserializeUdfDataBlock(SUdfDataBlock *pBlock, char *buf) { - char *bufBegin = buf; - - pBlock->numOfRows = *(int32_t*)buf; - buf += sizeof(int32_t); - - pBlock->numOfCols = *(int32_t*)buf; - buf += sizeof(int32_t); - - pBlock->udfCols = taosMemoryMalloc(sizeof(SUdfColumn*) * pBlock->numOfCols); - for (int32_t i = 0; i < pBlock->numOfCols; ++i) { - pBlock->udfCols[i] = taosMemoryMalloc(sizeof(SUdfColumn)); - int32_t l = deserializeUdfColumn(pBlock->udfCols[i], buf); - buf += l; - } - - int32_t totalLen = buf - bufBegin; - return totalLen; -} - -int32_t serializeUdfInterBuf(SUdfInterBuf *state, char *pBuf) { - char *bufBegin = pBuf; - - *(int32_t*)pBuf = state->bufLen; - pBuf += sizeof(int32_t); - memcpy(pBuf, state->buf, state->bufLen); - pBuf += state->bufLen; - - return pBuf - bufBegin; -} - -int32_t deserializeUdfInterBuf(SUdfInterBuf *pState, char *buf) { - char* bufBegin = buf; - pState->bufLen = *(int32_t*)buf; - buf += sizeof(int32_t); - - pState->buf = taosMemoryMalloc(pState->bufLen); - memcpy(pState->buf, buf, pState->bufLen); - buf += pState->bufLen; - return buf - bufBegin; -} - -int32_t serializeUdfSetupRequest(SUdfSetupRequest *setup, char *buf) { - char *bufBegin = buf; - - memcpy(buf, setup->udfName, TSDB_FUNC_NAME_LEN); - buf += TSDB_FUNC_NAME_LEN; - - memcpy(buf, &setup->epSet, sizeof(SEpSet)); - buf += sizeof(SEpSet); - - return buf - bufBegin; -}; - -int32_t deserializeUdfSetupRequest(SUdfSetupRequest *setup, char *buf) { - char* bufBegin = buf; - - memcpy(setup->udfName, buf, TSDB_FUNC_NAME_LEN); - buf += TSDB_FUNC_NAME_LEN; - - memcpy(&setup->epSet, buf, sizeof(SEpSet)); - buf += sizeof(SEpSet); - return buf - bufBegin; -} - -int32_t serializeUdfTeardownRequest(SUdfTeardownRequest *teardown, char *buf) { - char* bufBegin = buf; - *(int64_t *) buf = teardown->udfHandle; - buf += sizeof(int64_t); - - return buf - bufBegin; -} - -int32_t deserializeUdfTeardownRequest(SUdfTeardownRequest *teardown, char *buf) { - char *bufBegin = buf; - teardown->udfHandle = *(int64_t *) buf; - buf += sizeof(int64_t); - return buf - bufBegin; -} - -int32_t serializeUdfSetupResponse(SUdfSetupResponse *setupRsp, char *buf) { - char *bufBegin = buf; - - *(int64_t *) buf = setupRsp->udfHandle; - buf += sizeof(int64_t); - - return buf-bufBegin; -} - -int32_t deserializeUdfSetupResponse(SUdfSetupResponse *setupRsp, char *buf) { - char *bufBegin = buf; - setupRsp->udfHandle = *(int64_t *) buf; - buf += sizeof(int64_t); - return buf-bufBegin; -} - -int32_t serializeUdfTeardownResponse(SUdfTeardownResponse *teardownRsp, char *buf) { - return 0; -} - -int32_t deserializeUdfTeardownResponse(SUdfTeardownResponse *teardownRsp, char *buf) { - return 0; -} - -int32_t serializeUdfCallRequest(SUdfCallRequest *call, char *buf) { - char* bufBegin = buf; - *(int64_t *) buf = call->udfHandle; - buf += sizeof(int64_t); - *(int8_t *) buf = call->callType; - buf += sizeof(int8_t); - int32_t l = 0; - l = serializeUdfDataBlock(&call->block, buf); - buf += l; - l = serializeUdfInterBuf(&call->interBuf, buf); - buf += l; - l = serializeUdfInterBuf(&call->interBuf2, buf); - buf += l; - - *(bool*)buf = call->initFirst; - buf += sizeof(bool); - - return buf - bufBegin; -} - -int32_t deserializeUdfCallRequest(SUdfCallRequest *call, char *buf) { - char* bufBegin = buf; - call->udfHandle = *(int64_t *) buf; - buf += sizeof(int64_t); - call->callType = *(int8_t *) buf; - buf += sizeof(int8_t); - int32_t l = 0; - l = deserializeUdfDataBlock(&call->block, buf); - buf += l; - l = deserializeUdfInterBuf(&call->interBuf, buf); - buf += l; - call->initFirst = *(bool*)buf; - buf += sizeof(bool); - return buf - bufBegin; -} - -int32_t serializeUdfCallResponse(SUdfCallResponse *callRsp, char * buf) { - char *bufBegin = buf; - int32_t l = 0; - l = serializeUdfColumnData(&callRsp->resultData, buf); - buf += l; - l = serializeUdfInterBuf(&callRsp->interBuf, buf); - buf += l; - - return buf - bufBegin; -} - -int32_t deserializeUdfCallResponse(SUdfCallResponse *callRsp, char * buf) { - char *bufBegin = buf; - int32_t l = 0; - l =deserializeUdfColumnData(&callRsp->resultData, buf); - buf += l; - l = deserializeUdfInterBuf(&callRsp->interBuf, buf); - buf += l; - return buf - bufBegin; -} - -int32_t serializeUdfRequest(SUdfRequest *request, char *buf) { - char* bufBegin = buf; - //skip msglen first - buf += sizeof(int32_t); - - *(int64_t *) buf = request->seqNum; - buf += sizeof(int64_t); - *(int8_t *) buf = request->type; - buf += sizeof(int8_t); - - int32_t l = 0; - if (request->type == UDF_TASK_SETUP) { - l = serializeUdfSetupRequest(&request->setup, buf); - buf += l; - } else if (request->type == UDF_TASK_CALL) { - l = serializeUdfCallRequest(&request->call, buf); - buf += l; - } else if (request->type == UDF_TASK_TEARDOWN){ - l = serializeUdfTeardownRequest(&request->teardown, buf); - buf += l; - } - *(int32_t*)bufBegin = buf - bufBegin; - return buf - bufBegin; -} - -int32_t deserializeUdfRequest(SUdfRequest *request, char *buf) { - char* bufBegin = buf; - request->msgLen = *(int32_t *) (buf); - buf += sizeof(int32_t); - request->seqNum = *(int64_t *) (buf); - buf += sizeof(int64_t); - request->type = *(int8_t *) (buf); - buf += sizeof(int8_t); - - int32_t l = 0; + len += taosEncodeFixedI64(buf, request->seqNum); + len += taosEncodeFixedI8(buf, request->type); if (request->type == UDF_TASK_SETUP) { - l = deserializeUdfSetupRequest(&request->setup, buf); - buf += l; + len += encodeUdfSetupRequest(buf, &request->setup); } else if (request->type == UDF_TASK_CALL) { - l = deserializeUdfCallRequest(&request->call, buf); - buf += l; - } else if (request->type == UDF_TASK_TEARDOWN){ - l = deserializeUdfTeardownRequest(&request->teardown, buf); - buf += l; + len += encodeUdfCallRequest(buf, &request->call); + } else if (request->type == UDF_TASK_TEARDOWN) { + len += encodeUdfTeardownRequest(buf, &request->teardown); } - int32_t totalLen = buf-bufBegin; - if (totalLen != request->msgLen) { - debugPrint("decoding request error"); - return -1; - } - return buf - bufBegin; + return len; } -int32_t serializeUdfResponse(SUdfResponse *response, char *buf) { - char* bufBegin = buf; - //skip msgLen - buf += sizeof(int32_t); +void* decodeUdfRequest(const void* buf, SUdfRequest* request) { + request->msgLen = *(int32_t*)(buf); + POINTER_SHIFT(buf, sizeof(request->msgLen)); - *(int64_t *) buf = response->seqNum; - buf += sizeof(int64_t); - *(int8_t *) buf = response->type; - buf += sizeof(int8_t); - *(int32_t *) buf = response->code; - buf += sizeof(int32_t); - int32_t l = 0; - switch (response->type) { - case UDF_TASK_SETUP: { - l = serializeUdfSetupResponse(&response->setupRsp, buf); - buf += l; - break; - } - case UDF_TASK_CALL: { - l = serializeUdfCallResponse(&response->callRsp, buf); - buf += l; - break; - } - case UDF_TASK_TEARDOWN: { - l = serializeUdfTeardownResponse(&response->teardownRsp, buf); - buf += l; - } + buf = taosDecodeFixedI64(buf, &request->seqNum); + buf = taosDecodeFixedI8(buf, &request->type); + + if (request->type == UDF_TASK_SETUP) { + buf = decodeUdfSetupRequest(buf, &request->setup); + } else if (request->type == UDF_TASK_CALL) { + buf = decodeUdfCallRequest(buf, &request->call); + } else if (request->type == UDF_TASK_TEARDOWN) { + buf = decodeUdfTeardownRequest(buf, &request->teardown); } - - *(int32_t*)bufBegin = buf - bufBegin; - return buf - bufBegin; + return (void*)buf; } -int32_t deserializeUdfResponse(SUdfResponse *rsp, char *buf) { - char* bufBegin = buf; - rsp->msgLen = *(int32_t *) buf; - buf += sizeof(int32_t); - rsp->seqNum = *(int64_t *) buf; - buf += sizeof(int64_t); - rsp->type = *(int8_t *) buf; - buf += sizeof(int8_t); - rsp->code = *(int32_t *) buf; - buf += sizeof(int32_t); - int32_t l = 0; +int32_t encodeUdfSetupResponse(void **buf, const SUdfSetupResponse *setupRsp) { + int32_t len = 0; + len += taosEncodeFixedI64(buf, setupRsp->udfHandle); + return len; +} + +void* decodeUdfSetupResponse(const void* buf, SUdfSetupResponse* setupRsp) { + buf = taosDecodeFixedI64(buf, &setupRsp->udfHandle); + return (void*)buf; +} + +int32_t encodeUdfCallResponse(void **buf, const SUdfCallResponse *callRsp) { + int32_t len = 0; + len += taosEncodeFixedI8(buf, callRsp->callType); + switch (callRsp->callType) { + case TSDB_UDF_CALL_SCALA_PROC: + len += tEncodeDataBlock(buf, &callRsp->resultData); + break; + case TSDB_UDF_CALL_AGG_INIT: + len += encodeUdfInterBuf(buf, &callRsp->interBuf); + break; + case TSDB_UDF_CALL_AGG_PROC: + len += encodeUdfInterBuf(buf, &callRsp->interBuf); + break; + case TSDB_UDF_CALL_AGG_MERGE: + len += encodeUdfInterBuf(buf, &callRsp->interBuf); + break; + case TSDB_UDF_CALL_AGG_FIN: + len += tEncodeDataBlock(buf, &callRsp->resultData); + break; + } + return len; +} + +void* decodeUdfCallResponse(const void* buf, SUdfCallResponse* callRsp) { + buf = taosDecodeFixedI8(buf, &callRsp->callType); + switch (callRsp->callType) { + case TSDB_UDF_CALL_SCALA_PROC: + buf = tDecodeDataBlock(buf, &callRsp->resultData); + break; + case TSDB_UDF_CALL_AGG_INIT: + buf = decodeUdfInterBuf(buf, &callRsp->interBuf); + break; + case TSDB_UDF_CALL_AGG_PROC: + buf = decodeUdfInterBuf(buf, &callRsp->interBuf); + break; + case TSDB_UDF_CALL_AGG_MERGE: + buf = decodeUdfInterBuf(buf, &callRsp->interBuf); + break; + case TSDB_UDF_CALL_AGG_FIN: + buf = tDecodeDataBlock(buf, &callRsp->resultData); + break; + } + return (void*)buf; +} + +int32_t encodeUdfTeardownResponse(void** buf, const SUdfTeardownResponse* teardownRsp) { + return 0; +} + +void* decodeUdfTeardownResponse(const void* buf, SUdfTeardownResponse* teardownResponse) { + return (void*)buf; +} + +int32_t encodeUdfResponse(void** buf, const SUdfResponse* rsp) { + int32_t len = 0; + if (buf == NULL) { + len += sizeof(rsp->msgLen); + } else { + *(int32_t*)(*buf) = rsp->msgLen; + *buf = POINTER_SHIFT(*buf, sizeof(rsp->msgLen)); + } + + len += taosEncodeFixedI64(buf, rsp->seqNum); + len += taosEncodeFixedI8(buf, rsp->type); + len += taosEncodeFixedI32(buf, rsp->code); + switch (rsp->type) { - case UDF_TASK_SETUP: { - l = deserializeUdfSetupResponse(&rsp->setupRsp, buf); - buf += l; + case UDF_TASK_SETUP: + len += encodeUdfSetupResponse(buf, &rsp->setupRsp); break; - } - case UDF_TASK_CALL: { - l = deserializeUdfCallResponse(&rsp->callRsp, buf); - buf += l; + case UDF_TASK_CALL: + len += encodeUdfCallResponse(buf, &rsp->callRsp); + break; + case UDF_TASK_TEARDOWN: + len += encodeUdfTeardownResponse(buf, &rsp->teardownRsp); + break; + default: + //TODO: log error break; - } - case UDF_TASK_TEARDOWN: { - l = deserializeUdfTeardownResponse(&rsp->teardownRsp, buf); - buf += l; - } } - int32_t total = buf - bufBegin; - if (total != rsp->msgLen) { - debugPrint("decode response error"); - return -1; - } - return buf - bufBegin; + return len; } -int32_t estimateUdfRequestLen(SUdfRequest *request) { - // a larger estimated is generated - int32_t size = sizeof(SUdfRequest); - if (request->type == UDF_TASK_CALL) { - size += request->call.block.numOfCols * sizeof(SUdfColumn*); - for (int32_t i = 0; i < request->call.block.numOfCols; ++i) { - size += sizeof(SUdfColumn); - SUdfColumn* col = request->call.block.udfCols[i]; - if (col->colData.varLengthColumn) { - size += col->colData.varOffsetsLen; - size += col->colData.payloadLen; - } else { - size += col->colData.nullBitmapLen; - size += col->colData.dataLen; - } - } - size += request->call.interBuf.bufLen; +void* decodeUdfResponse(const void* buf, SUdfResponse* rsp) { + rsp->msgLen = *(int32_t*)(buf); + POINTER_SHIFT(buf, sizeof(rsp->msgLen)); + buf = taosDecodeFixedI64(buf, &rsp->seqNum); + buf = taosDecodeFixedI8(buf, &rsp->type); + buf = taosDecodeFixedI32(buf, &rsp->code); + + switch (rsp->type) { + case UDF_TASK_SETUP: + buf = decodeUdfSetupResponse(buf, &rsp->setupRsp); + break; + case UDF_TASK_CALL: + buf = decodeUdfCallResponse(buf, &rsp->callRsp); + break; + case UDF_TASK_TEARDOWN: + buf = decodeUdfTeardownResponse(buf, &rsp->teardownRsp); + break; + default: + //TODO: log error + break; } - return size; -} - -int32_t estimateUdfResponseLen(SUdfResponse *response) { - int32_t size = sizeof(SUdfResponse); - if (response->type == UDF_TASK_CALL) { - size += response->callRsp.interBuf.bufLen; - SUdfColumnData *resultData = &response->callRsp.resultData; - if (!resultData->varLengthColumn) { - size += resultData->nullBitmapLen; - size += resultData->dataLen; - } else { - size += resultData->varOffsetsLen; - size += resultData->payloadLen; - } - } - - return size; -} - -int32_t encodeRequest(char **pBuf, int32_t *pBufLen, SUdfRequest *request) { - debugPrint("%s", "encoding request"); - - int len = estimateUdfRequestLen(request); - - char *bufBegin = taosMemoryMalloc(len); - char *buf = bufBegin; - serializeUdfRequest(request, buf); - *pBuf = bufBegin; - *pBufLen = request->msgLen; - debugPrint("\tLen: estimate: %d, actual:%d", len, *pBufLen); - return 0; -} - -int32_t decodeRequest(char *bufMsg, int32_t bufLen, SUdfRequest *pRequest) { - debugPrint("%s", "decoding request"); - if (*(int32_t *) bufMsg != bufLen) { - debugPrint("%s", "decoding request error"); - return -1; - } - char *buf = bufMsg; - deserializeUdfRequest(pRequest, buf); - return 0; -} - -int32_t encodeResponse(char **pBuf, int32_t *pBufLen, SUdfResponse *response) { - debugPrint("%s", "encoding response"); - int32_t len = estimateUdfResponseLen(response); - - char *bufBegin = taosMemoryMalloc(len); - char *buf = bufBegin; - serializeUdfResponse(response, buf); - *pBuf = bufBegin; - *pBufLen = response->msgLen; - return 0; -} - -int32_t decodeResponse(char *bufMsg, int32_t bufLen, SUdfResponse *rsp) { - debugPrint("%s", "decoding response"); - - if (*(int32_t *) bufMsg != bufLen) { - debugPrint("%s", "can not decode response"); - return -1; - } - char *buf = bufMsg; - deserializeUdfResponse(rsp, buf); - return 0; + return (void*)buf; } void freeUdfColumnData(SUdfColumnData *data) { @@ -770,7 +504,8 @@ int32_t udfcGetUvTaskResponseResult(SClientUdfTask *task, SClientUvTaskNode *uvT if (uvTask->type == UV_TASK_REQ_RSP) { if (uvTask->rspBuf.base != NULL) { SUdfResponse rsp; - decodeResponse(uvTask->rspBuf.base, uvTask->rspBuf.len, &rsp); + void* buf = decodeUdfResponse(uvTask->rspBuf.base, &rsp); + assert(uvTask->rspBuf.len == POINTER_DISTANCE(buf, uvTask->rspBuf.base)); task->errCode = rsp.code; switch (task->type) { @@ -973,9 +708,10 @@ int32_t createUdfcUvTask(SClientUdfTask *task, int8_t uvTaskType, SClientUvTaskN } else { //TODO log and return error } - char *buf = NULL; - int32_t bufLen = 0; - encodeRequest(&buf, &bufLen, &request); + int32_t bufLen = encodeUdfRequest(NULL, &request); + request.msgLen = bufLen; + void *buf = taosMemoryMalloc(bufLen); + encodeUdfRequest(&buf, &request); uvTask->reqBuf = uv_buf_init(buf, bufLen); uvTask->seqNum = request.seqNum; } else if (uvTaskType == UV_TASK_DISCONNECT) { @@ -1226,8 +962,8 @@ int32_t setupUdf(char udfName[], SEpSet *epSet, UdfHandle *handle) { return err; } -int32_t callUdf(UdfHandle handle, int8_t callType, SUdfDataBlock *input, SUdfInterBuf *state, - SUdfColumnData* output, SUdfInterBuf *newState, bool initFirst) { +int32_t callUdf(UdfHandle handle, int8_t callType, int8_t initFirst, SSDataBlock *input, SUdfInterBuf *state, SUdfInterBuf *state2, + SSDataBlock* output, SUdfInterBuf *newState) { debugPrint("%s", "client call udf"); SClientUdfTask *task = taosMemoryMalloc(sizeof(SClientUdfTask)); @@ -1237,14 +973,21 @@ int32_t callUdf(UdfHandle handle, int8_t callType, SUdfDataBlock *input, SUdfInt SUdfCallRequest *req = &task->_call.req; switch (callType) { + case TSDB_UDF_CALL_AGG_INIT: { + req->initFirst = 1; + break; + } case TSDB_UDF_CALL_AGG_PROC: { req->block = *input; req->interBuf = *state; - req->initFirst = initFirst; break; } - - case TSDb_UDF_CALL_AGG_FIN: { + case TSDB_UDF_CALL_AGG_MERGE: { + req->interBuf = *state; + req->interBuf2 = *state2; + break; + } + case TSDB_UDF_CALL_AGG_FIN: { req->interBuf = *state; break; } @@ -1258,12 +1001,19 @@ int32_t callUdf(UdfHandle handle, int8_t callType, SUdfDataBlock *input, SUdfInt SUdfCallResponse *rsp = &task->_call.rsp; switch (callType) { + case TSDB_UDF_CALL_AGG_INIT: { + *newState = rsp->interBuf; + break; + } case TSDB_UDF_CALL_AGG_PROC: { *newState = rsp->interBuf; break; } - - case TSDb_UDF_CALL_AGG_FIN: { + case TSDB_UDF_CALL_AGG_MERGE: { + *newState = rsp->interBuf; + break; + } + case TSDB_UDF_CALL_AGG_FIN: { *output = rsp->resultData; break; } diff --git a/source/libs/function/src/udfd.c b/source/libs/function/src/udfd.c index a1996133e7..76c731a473 100644 --- a/source/libs/function/src/udfd.c +++ b/source/libs/function/src/udfd.c @@ -62,7 +62,7 @@ typedef struct SUdfHandle { void udfdProcessRequest(uv_work_t *req) { SUvUdfWork *uvUdf = (SUvUdfWork *) (req->data); SUdfRequest request = {0}; - decodeRequest(uvUdf->input.base, uvUdf->input.len, &request); + decodeUdfRequest(uvUdf->input.base, &request); switch (request.type) { case UDF_TASK_SETUP: { @@ -94,9 +94,10 @@ void udfdProcessRequest(uv_work_t *req) { rsp.type = request.type; rsp.code = 0; rsp.setupRsp.udfHandle = (int64_t) (handle); - char *buf; - int32_t len; - encodeResponse(&buf, &len, &rsp); + int32_t len = encodeUdfResponse(NULL, &rsp); + rsp.msgLen = len; + void *buf = taosMemoryMalloc(len); + encodeUdfResponse(&buf, &rsp); uvUdf->output = uv_buf_init(buf, len); @@ -110,7 +111,8 @@ void udfdProcessRequest(uv_work_t *req) { SUdfHandle *handle = (SUdfHandle *) (call->udfHandle); SUdf *udf = handle->udf; - SUdfDataBlock input = call->block; + SUdfDataBlock input = {0}; + //TODO: convertSDataBlockToUdfDataBlock(call->block, &input); SUdfColumnData output; //TODO: call different functions according to call type, for now just calar if (call->callType == TSDB_UDF_CALL_SCALA_PROC) { @@ -124,12 +126,13 @@ void udfdProcessRequest(uv_work_t *req) { rsp->type = request.type; rsp->code = 0; SUdfCallResponse *subRsp = &rsp->callRsp; - subRsp->resultData = output; + //TODO: convertSUdfColumnDataToSSDataBlock(output, &subRsp->resultData); } - char *buf; - int32_t len; - encodeResponse(&buf, &len, rsp); + int32_t len = encodeUdfResponse(NULL, rsp); + rsp->msgLen = len; + void *buf = taosMemoryMalloc(len); + encodeUdfResponse(&buf, rsp); uvUdf->output = uv_buf_init(buf, len); //TODO: free @@ -158,9 +161,10 @@ void udfdProcessRequest(uv_work_t *req) { rsp->type = request.type; rsp->code = 0; SUdfTeardownResponse *subRsp = &response.teardownRsp; - char *buf; - int32_t len; - encodeResponse(&buf, &len, rsp); + int32_t len = encodeUdfResponse(NULL, rsp); + void *buf = taosMemoryMalloc(len); + rsp->msgLen = len; + encodeUdfResponse(&buf, rsp); uvUdf->output = uv_buf_init(buf, len); taosMemoryFree(uvUdf->input.base); From 18943125f4d139d78353160ad160410af69628f2 Mon Sep 17 00:00:00 2001 From: slzhou Date: Sun, 17 Apr 2022 15:07:11 +0800 Subject: [PATCH 13/19] call udf for scalar and aggregate --- source/libs/function/inc/tudf.h | 21 ++--- source/libs/function/inc/tudfInt.h | 5 +- source/libs/function/src/tudf.c | 128 ++++++++++++++++++++++++++--- source/libs/function/src/udfd.c | 6 +- 4 files changed, 135 insertions(+), 25 deletions(-) diff --git a/source/libs/function/inc/tudf.h b/source/libs/function/inc/tudf.h index 683274f3ae..db62accb85 100644 --- a/source/libs/function/inc/tudf.h +++ b/source/libs/function/inc/tudf.h @@ -99,19 +99,20 @@ typedef struct SUdfInterBuf { } SUdfInterBuf; //TODO: translate these calls to callUdf -int32_t callUdfAggInit(SUdfInterBuf *interBuf); -// input: block, initFirst -// output: interbuf -int32_t callUdfAggProcess(SSDataBlock *block, SUdfInterBuf *interBuf); +// output: interBuf +int32_t callUdfAggInit(UdfHandle handle, SUdfInterBuf *interBuf); +// input: block, state +// output: newState +int32_t callUdfAggProcess(UdfHandle handle, SSDataBlock *block, SUdfInterBuf *state, SUdfInterBuf *newState); // input: interBuf // output: resultData -int32_t callUdfAggFinalize(SUdfInterBuf *interBuf, SSDataBlock *resultData); +int32_t callUdfAggFinalize(UdfHandle handle, SUdfInterBuf *interBuf, SUdfInterBuf *resultData); // input: interbuf1, interbuf2 // output: resultBuf -int32_t callUdfAggMerge(SUdfInterBuf *interBuf1, SUdfInterBuf *interBuf2, SUdfInterBuf *resultBuf); +int32_t callUdfAggMerge(UdfHandle handle, SUdfInterBuf *interBuf1, SUdfInterBuf *interBuf2, SUdfInterBuf *resultBuf); // input: block // output: resultData -int32_t callUdfScalaProcess(SSDataBlock *block, SSDataBlock *resultData); +int32_t callUdfScalaProcess(UdfHandle handle, SSDataBlock *block, SSDataBlock *resultData); /** * tearn down udf @@ -134,12 +135,12 @@ typedef int32_t (*TUdfTeardownFunc)(); //typedef int32_t addFixedLengthColumnData(SColumnData *columnData, int rowIndex, bool isNull, int32_t colBytes, char* data); //typedef int32_t addVariableLengthColumnData(SColumnData *columnData, int rowIndex, bool isNull, int32_t dataLen, char * data); -typedef int32_t (*TUdfFreeUdfColumnDataFunc)(SUdfColumnData* columnData); +typedef int32_t (*TUdfFreeUdfColumnDataFunc)(SUdfColumn* columnData); -typedef int32_t (*TUdfScalarProcFunc)(SUdfDataBlock block, SUdfColumnData *resultData); +typedef int32_t (*TUdfScalarProcFunc)(SUdfDataBlock block, SUdfColumn *resultCol); typedef int32_t (*TUdfAggInitFunc)(SUdfInterBuf *buf); typedef int32_t (*TUdfAggProcessFunc)(SUdfDataBlock block, SUdfInterBuf *interBuf); -typedef int32_t (*TUdfAggFinalizeFunc)(SUdfInterBuf buf, SUdfColumnData *resultData); +typedef int32_t (*TUdfAggFinalizeFunc)(SUdfInterBuf buf, SUdfInterBuf *resultData); // end API to UDF writer diff --git a/source/libs/function/inc/tudfInt.h b/source/libs/function/inc/tudfInt.h index 6c3da8cd89..496f486e05 100644 --- a/source/libs/function/inc/tudfInt.h +++ b/source/libs/function/inc/tudfInt.h @@ -59,7 +59,7 @@ typedef struct SUdfCallRequest { typedef struct SUdfCallResponse { int8_t callType; SSDataBlock resultData; - SUdfInterBuf interBuf; + SUdfInterBuf resultBuf; } SUdfCallResponse; @@ -106,6 +106,9 @@ void freeUdfColumnData(SUdfColumnData *data); void freeUdfColumn(SUdfColumn* col); void freeUdfDataDataBlock(SUdfDataBlock *block); +int32_t convertDataBlockToUdfDataBlock(SSDataBlock *block, SUdfDataBlock *udfBlock); +int32_t convertUdfColumnToDataBlock(SUdfColumn *udfCol, SSDataBlock *block); + #ifdef __cplusplus } #endif diff --git a/source/libs/function/src/tudf.c b/source/libs/function/src/tudf.c index c8601c69c8..1bc961d527 100644 --- a/source/libs/function/src/tudf.c +++ b/source/libs/function/src/tudf.c @@ -18,6 +18,7 @@ #include "tudf.h" #include "tudfInt.h" #include "tarray.h" +#include "tdatablock.h" //TODO: when startup, set thread poll size. add it to cfg //TODO: test for udfd restart @@ -351,13 +352,13 @@ int32_t encodeUdfCallResponse(void **buf, const SUdfCallResponse *callRsp) { len += tEncodeDataBlock(buf, &callRsp->resultData); break; case TSDB_UDF_CALL_AGG_INIT: - len += encodeUdfInterBuf(buf, &callRsp->interBuf); + len += encodeUdfInterBuf(buf, &callRsp->resultBuf); break; case TSDB_UDF_CALL_AGG_PROC: - len += encodeUdfInterBuf(buf, &callRsp->interBuf); + len += encodeUdfInterBuf(buf, &callRsp->resultBuf); break; case TSDB_UDF_CALL_AGG_MERGE: - len += encodeUdfInterBuf(buf, &callRsp->interBuf); + len += encodeUdfInterBuf(buf, &callRsp->resultBuf); break; case TSDB_UDF_CALL_AGG_FIN: len += tEncodeDataBlock(buf, &callRsp->resultData); @@ -373,13 +374,13 @@ void* decodeUdfCallResponse(const void* buf, SUdfCallResponse* callRsp) { buf = tDecodeDataBlock(buf, &callRsp->resultData); break; case TSDB_UDF_CALL_AGG_INIT: - buf = decodeUdfInterBuf(buf, &callRsp->interBuf); + buf = decodeUdfInterBuf(buf, &callRsp->resultBuf); break; case TSDB_UDF_CALL_AGG_PROC: - buf = decodeUdfInterBuf(buf, &callRsp->interBuf); + buf = decodeUdfInterBuf(buf, &callRsp->resultBuf); break; case TSDB_UDF_CALL_AGG_MERGE: - buf = decodeUdfInterBuf(buf, &callRsp->interBuf); + buf = decodeUdfInterBuf(buf, &callRsp->resultBuf); break; case TSDB_UDF_CALL_AGG_FIN: buf = tDecodeDataBlock(buf, &callRsp->resultData); @@ -483,6 +484,70 @@ void freeUdfInterBuf(SUdfInterBuf *buf) { buf->buf = NULL; } + +int32_t convertDataBlockToUdfDataBlock(SSDataBlock *block, SUdfDataBlock *udfBlock) { + udfBlock->numOfRows = block->info.rows; + udfBlock->numOfCols = block->info.numOfCols; + udfBlock->udfCols = taosMemoryMalloc(sizeof(SUdfColumn*) * udfBlock->numOfCols); + for (int32_t i = 0; i < udfBlock->numOfCols; ++i) { + udfBlock->udfCols[i] = taosMemoryMalloc(sizeof(SUdfColumn)); + SColumnInfoData *col= (SColumnInfoData*)taosArrayGet(block->pDataBlock, i); + SUdfColumn *udfCol = udfBlock->udfCols[i]; + udfCol->colMeta.type = col->info.type; + udfCol->colMeta.bytes = col->info.bytes; + udfCol->colMeta.scale = col->info.scale; + udfCol->colMeta.precision = col->info.precision; + udfCol->colData.numOfRows = udfBlock->numOfRows; + udfCol->colData.varLengthColumn = IS_VAR_DATA_TYPE(udfCol->colMeta.type); + if (udfCol->colData.varLengthColumn) { + udfCol->colData.varOffsetsLen = sizeof(int32_t) * udfBlock->numOfRows; + udfCol->colData.varOffsets = taosMemoryMalloc(udfCol->colData.varOffsetsLen); + memcpy(udfCol->colData.varOffsets, col->varmeta.offset, udfCol->colData.varOffsetsLen); + udfCol->colData.payloadLen = colDataGetLength(col, udfBlock->numOfRows); + udfCol->colData.payload = taosMemoryMalloc(udfCol->colData.payloadLen); + memcpy(udfCol->colData.payload, col->pData, udfCol->colData.payloadLen); + } else { + udfCol->colData.nullBitmapLen = BitmapLen(udfCol->colData.numOfRows); + udfCol->colData.nullBitmap = taosMemoryMalloc(udfCol->colData.nullBitmapLen); + memcpy(udfCol->colData.nullBitmap, col->nullbitmap, udfCol->colData.nullBitmapLen); + udfCol->colData.dataLen = colDataGetLength(col, udfBlock->numOfRows); + udfCol->colData.data = taosMemoryMalloc(udfCol->colData.dataLen); + memcpy(udfCol->colData.data, col->pData, udfCol->colData.dataLen); + } + } + return 0; +} + +int32_t convertUdfColumnToDataBlock(SUdfColumn *udfCol, SSDataBlock *block) { + block->info.numOfCols = 1; + block->info.rows = udfCol->colData.numOfRows; + block->info.hasVarCol = udfCol->colData.varLengthColumn; + + block->pDataBlock = taosArrayInit(1, sizeof(SColumnInfoData)); + taosArraySetSize(block->pDataBlock, 1); + SColumnInfoData *col = taosArrayGet(block->pDataBlock, 0); + SUdfColumnMeta *meta = &udfCol->colMeta; + col->info.precision = meta->precision; + col->info.bytes = meta->bytes; + col->info.scale = meta->scale; + col->info.type = meta->type; + SUdfColumnData *data = &udfCol->colData; + + if (!IS_VAR_DATA_TYPE(meta->type)) { + col->nullbitmap = taosMemoryMalloc(data->nullBitmapLen); + memcpy(col->nullbitmap, data->nullBitmap, data->nullBitmapLen); + col->pData = taosMemoryMalloc(data->dataLen); + memcpy(col->pData, data->payload, data->dataLen); + } else { + col->varmeta.offset = taosMemoryMalloc(data->varOffsetsLen); + memcpy(col->varmeta.offset, data->varOffsets, data->varOffsetsLen); + col->pData = taosMemoryMalloc(data->payloadLen); + memcpy(col->pData, data->payload, data->payloadLen); + } + return 0; +} + + void onUdfcPipeClose(uv_handle_t *handle) { SClientUvConn *conn = handle->data; if (!QUEUE_EMPTY(&conn->taskQueue)) { @@ -962,7 +1027,7 @@ int32_t setupUdf(char udfName[], SEpSet *epSet, UdfHandle *handle) { return err; } -int32_t callUdf(UdfHandle handle, int8_t callType, int8_t initFirst, SSDataBlock *input, SUdfInterBuf *state, SUdfInterBuf *state2, +int32_t callUdf(UdfHandle handle, int8_t callType, SSDataBlock *input, SUdfInterBuf *state, SUdfInterBuf *state2, SSDataBlock* output, SUdfInterBuf *newState) { debugPrint("%s", "client call udf"); @@ -1002,19 +1067,19 @@ int32_t callUdf(UdfHandle handle, int8_t callType, int8_t initFirst, SSDataBlock SUdfCallResponse *rsp = &task->_call.rsp; switch (callType) { case TSDB_UDF_CALL_AGG_INIT: { - *newState = rsp->interBuf; + *newState = rsp->resultBuf; break; } case TSDB_UDF_CALL_AGG_PROC: { - *newState = rsp->interBuf; + *newState = rsp->resultBuf; break; } case TSDB_UDF_CALL_AGG_MERGE: { - *newState = rsp->interBuf; + *newState = rsp->resultBuf; break; } case TSDB_UDF_CALL_AGG_FIN: { - *output = rsp->resultData; + *newState = rsp->resultBuf; break; } case TSDB_UDF_CALL_SCALA_PROC: { @@ -1027,6 +1092,47 @@ int32_t callUdf(UdfHandle handle, int8_t callType, int8_t initFirst, SSDataBlock return task->errCode; } +//TODO: translate these calls to callUdf +int32_t callUdfAggInit(UdfHandle handle, SUdfInterBuf *interBuf) { + int8_t callType = TSDB_UDF_CALL_AGG_INIT; + + int32_t err = callUdf(handle, callType, NULL, NULL, NULL, NULL, interBuf); + + return err; +} + +// input: block, state +// output: interbuf, +int32_t callUdfAggProcess(UdfHandle handle, SSDataBlock *block, SUdfInterBuf *state, SUdfInterBuf *newState) { + int8_t callType = TSDB_UDF_CALL_AGG_PROC; + int32_t err = callUdf(handle, callType, block, state, NULL, NULL, newState); + return err; +} + +// input: interbuf1, interbuf2 +// output: resultBuf +int32_t callUdfAggMerge(UdfHandle handle, SUdfInterBuf *interBuf1, SUdfInterBuf *interBuf2, SUdfInterBuf *resultBuf) { + int8_t callType = TSDB_UDF_CALL_AGG_MERGE; + int32_t err = callUdf(handle, callType, NULL, interBuf1, interBuf2, NULL, resultBuf); + return err; +} + +// input: interBuf +// output: resultData +int32_t callUdfAggFinalize(UdfHandle handle, SUdfInterBuf *interBuf, SUdfInterBuf *resultData) { + int8_t callType = TSDB_UDF_CALL_AGG_PROC; + int32_t err = callUdf(handle, callType, NULL, interBuf, NULL, NULL, resultData); + return err; +} + +// input: block +// output: resultData +int32_t callUdfScalaProcess(UdfHandle handle, SSDataBlock *block, SSDataBlock *resultData) { + int8_t callType = TSDB_UDF_CALL_SCALA_PROC; + int32_t err = callUdf(handle, callType, block, NULL, NULL, resultData, NULL); + return err; +} + int32_t teardownUdf(UdfHandle handle) { debugPrint("%s", "client teardown udf"); diff --git a/source/libs/function/src/udfd.c b/source/libs/function/src/udfd.c index 76c731a473..d5c917121a 100644 --- a/source/libs/function/src/udfd.c +++ b/source/libs/function/src/udfd.c @@ -112,8 +112,8 @@ void udfdProcessRequest(uv_work_t *req) { SUdf *udf = handle->udf; SUdfDataBlock input = {0}; - //TODO: convertSDataBlockToUdfDataBlock(call->block, &input); - SUdfColumnData output; + convertDataBlockToUdfDataBlock(&call->block, &input); + SUdfColumn output; //TODO: call different functions according to call type, for now just calar if (call->callType == TSDB_UDF_CALL_SCALA_PROC) { udf->scalarProcFunc(input, &output); @@ -126,7 +126,7 @@ void udfdProcessRequest(uv_work_t *req) { rsp->type = request.type; rsp->code = 0; SUdfCallResponse *subRsp = &rsp->callRsp; - //TODO: convertSUdfColumnDataToSSDataBlock(output, &subRsp->resultData); + convertUdfColumnToDataBlock(&output, &subRsp->resultData); } int32_t len = encodeUdfResponse(NULL, rsp); From d9580cff5312e97ef96f6d0e5dc97b6caa03261c Mon Sep 17 00:00:00 2001 From: shenglian zhou Date: Sun, 17 Apr 2022 17:37:07 +0800 Subject: [PATCH 14/19] runudf call scalar --- source/libs/function/test/runUdf.c | 31 +++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/source/libs/function/test/runUdf.c b/source/libs/function/test/runUdf.c index 7afa459c89..7c03ed727e 100644 --- a/source/libs/function/test/runUdf.c +++ b/source/libs/function/test/runUdf.c @@ -5,6 +5,7 @@ #include "uv.h" #include "os.h" #include "tudf.h" +#include "tdatablock.h" int main(int argc, char *argv[]) { startUdfService(); @@ -23,17 +24,25 @@ int main(int argc, char *argv[]) { SEpSet epSet; setupUdf("udf1", &epSet, &handle); - //char state[5000000] = "state"; - //char input[5000000] = "input"; - int dataSize = 500; - int callCount = 2; - if (argc > 1) dataSize = atoi(argv[1]); - if (argc > 2) callCount = atoi(argv[2]); - char *state = taosMemoryMalloc(dataSize); - char *input = taosMemoryMalloc(dataSize); - //todo: call udf - taosMemoryFree(state); - taosMemoryFree(input); + SSDataBlock block = {0}; + SSDataBlock* pBlock = █ + pBlock->pDataBlock = taosArrayInit(1, sizeof(SColumnInfoData)); + pBlock->info.numOfCols = 1; + pBlock->info.rows = 4; + for (int32_t i = 0; i < pBlock->info.numOfCols; ++i) { + SColumnInfoData colInfo = {0}; + colInfo.info.type = TSDB_DATA_TYPE_INT; + colInfo.info.bytes = sizeof(int32_t); + colInfo.info.colId = 1; + for (int32_t j = 0; j < pBlock->info.rows; ++j) { + colDataAppendInt32(&colInfo, j, &j); + } + taosArrayPush(pBlock->pDataBlock, &colInfo); + } + + SSDataBlock output = {0}; + callUdfScalaProcess(handle, pBlock, &output); + teardownUdf(handle); stopUdfService(); From eae11bf8f083fc227479b30cbf18ef9b6a1866b7 Mon Sep 17 00:00:00 2001 From: shenglian zhou Date: Tue, 19 Apr 2022 09:03:04 +0800 Subject: [PATCH 15/19] handle uv read error --- source/libs/function/inc/tudf.h | 1 + source/libs/function/src/tudf.c | 17 +++++++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/source/libs/function/inc/tudf.h b/source/libs/function/inc/tudf.h index db62accb85..775e6133f7 100644 --- a/source/libs/function/inc/tudf.h +++ b/source/libs/function/inc/tudf.h @@ -32,6 +32,7 @@ extern "C" { enum { UDFC_CODE_STOPPING = -1, UDFC_CODE_RESTARTING = -2, + UDFC_CODE_PIPE_READ_ERR = -3, }; /** diff --git a/source/libs/function/src/tudf.c b/source/libs/function/src/tudf.c index 1bc961d527..e3444ffa21 100644 --- a/source/libs/function/src/tudf.c +++ b/source/libs/function/src/tudf.c @@ -697,7 +697,18 @@ void udfcUvHandleRsp(SClientUvConn *conn) { } void udfcUvHandleError(SClientUvConn *conn) { - uv_close((uv_handle_t *) conn->pipe, onUdfcPipeClose); + while (!QUEUE_EMPTY(&conn->taskQueue)) { + QUEUE* h = QUEUE_HEAD(&conn->taskQueue); + SClientUvTaskNode *task = QUEUE_DATA(h, SClientUvTaskNode, connTaskQueue); + task->errCode = UDFC_CODE_PIPE_READ_ERR; + uv_sem_post(&task->taskSem); + QUEUE_REMOVE(&task->procTaskQueue); + } + + uv_close((uv_handle_t *) conn->pipe, NULL); + taosMemoryFree(conn->pipe); + taosMemoryFree(conn->readBuf.buf); + taosMemoryFree(conn); } void onUdfcRead(uv_stream_t *client, ssize_t nread, const uv_buf_t *buf) { @@ -903,8 +914,11 @@ void udfStopAsyncCb(uv_async_t *async) { uv_stop(&gUdfdLoop); } } + int32_t startUdfd(); + void onUdfdExit(uv_process_t *req, int64_t exit_status, int term_signal) { + //TODO: pipe close will be first received debugPrint("Process exited with status %" PRId64 ", signal %d", exit_status, term_signal); uv_close((uv_handle_t *) req, NULL); //TODO: restart the udfd process @@ -919,7 +933,6 @@ void onUdfdExit(uv_process_t *req, int64_t exit_status, int term_signal) { cleanUpUvTasks(); startUdfd(); } - } int32_t startUdfd() { From 71983725c3159a0b0d0da5f48eee3624c6848145 Mon Sep 17 00:00:00 2001 From: slzhou Date: Tue, 19 Apr 2022 12:00:59 +0800 Subject: [PATCH 16/19] befor debugging teardown --- source/libs/function/inc/tudf.h | 2 +- source/libs/function/src/tudf.c | 18 +++++++++++------- source/libs/function/src/udfd.c | 30 ++++++++++++++++++------------ source/libs/function/test/runUdf.c | 4 ++++ 4 files changed, 34 insertions(+), 20 deletions(-) diff --git a/source/libs/function/inc/tudf.h b/source/libs/function/inc/tudf.h index 775e6133f7..74aab09da2 100644 --- a/source/libs/function/inc/tudf.h +++ b/source/libs/function/inc/tudf.h @@ -136,7 +136,7 @@ typedef int32_t (*TUdfTeardownFunc)(); //typedef int32_t addFixedLengthColumnData(SColumnData *columnData, int rowIndex, bool isNull, int32_t colBytes, char* data); //typedef int32_t addVariableLengthColumnData(SColumnData *columnData, int rowIndex, bool isNull, int32_t dataLen, char * data); -typedef int32_t (*TUdfFreeUdfColumnDataFunc)(SUdfColumn* columnData); +typedef int32_t (*TUdfFreeUdfColumnFunc)(SUdfColumn* columnData); typedef int32_t (*TUdfScalarProcFunc)(SUdfDataBlock block, SUdfColumn *resultCol); typedef int32_t (*TUdfAggInitFunc)(SUdfInterBuf *buf); diff --git a/source/libs/function/src/tudf.c b/source/libs/function/src/tudf.c index e3444ffa21..c5542424f0 100644 --- a/source/libs/function/src/tudf.c +++ b/source/libs/function/src/tudf.c @@ -318,7 +318,7 @@ int32_t encodeUdfRequest(void** buf, const SUdfRequest* request) { void* decodeUdfRequest(const void* buf, SUdfRequest* request) { request->msgLen = *(int32_t*)(buf); - POINTER_SHIFT(buf, sizeof(request->msgLen)); + buf = POINTER_SHIFT(buf, sizeof(request->msgLen)); buf = taosDecodeFixedI64(buf, &request->seqNum); buf = taosDecodeFixedI8(buf, &request->type); @@ -429,7 +429,7 @@ int32_t encodeUdfResponse(void** buf, const SUdfResponse* rsp) { void* decodeUdfResponse(const void* buf, SUdfResponse* rsp) { rsp->msgLen = *(int32_t*)(buf); - POINTER_SHIFT(buf, sizeof(rsp->msgLen)); + buf = POINTER_SHIFT(buf, sizeof(rsp->msgLen)); buf = taosDecodeFixedI64(buf, &rsp->seqNum); buf = taosDecodeFixedI8(buf, &rsp->type); buf = taosDecodeFixedI32(buf, &rsp->code); @@ -786,9 +786,10 @@ int32_t createUdfcUvTask(SClientUdfTask *task, int8_t uvTaskType, SClientUvTaskN } int32_t bufLen = encodeUdfRequest(NULL, &request); request.msgLen = bufLen; - void *buf = taosMemoryMalloc(bufLen); + void *bufBegin = taosMemoryMalloc(bufLen); + void *buf = bufBegin; encodeUdfRequest(&buf, &request); - uvTask->reqBuf = uv_buf_init(buf, bufLen); + uvTask->reqBuf = uv_buf_init(bufBegin, bufLen); uvTask->seqNum = request.seqNum; } else if (uvTaskType == UV_TASK_DISCONNECT) { uvTask->pipe = task->session->udfSvcPipe; @@ -931,7 +932,7 @@ void onUdfdExit(uv_process_t *req, int64_t exit_status, int term_signal) { gUdfcState = UDFC_STATE_RESTARTING; //TODO: asynchronous without blocking. how to do it cleanUpUvTasks(); - startUdfd(); + //startUdfd(); } } @@ -966,7 +967,7 @@ void constructUdfService(void *argsThread) { uv_loop_init(&gUdfdLoop); //TODO spawn error - startUdfd(); + //startUdfd(); uv_async_init(&gUdfdLoop, &gUdfLoopTaskAync, udfClientAsyncCb); uv_async_init(&gUdfdLoop, &gUdfLoopStopAsync, udfStopAsyncCb); @@ -1009,7 +1010,8 @@ int32_t udfcRunUvTask(SClientUdfTask *task, int8_t uvTaskType) { udfcGetUvTaskResponseResult(task, uvTask); if (uvTaskType == UV_TASK_CONNECT) { task->session->udfSvcPipe = uvTask->pipe; - } taosMemoryFree(uvTask); + } + taosMemoryFree(uvTask); uvTask = NULL; return task->errCode; } @@ -1050,6 +1052,8 @@ int32_t callUdf(UdfHandle handle, int8_t callType, SSDataBlock *input, SUdfInter task->type = UDF_TASK_CALL; SUdfCallRequest *req = &task->_call.req; + req->udfHandle = task->session->severHandle; + switch (callType) { case TSDB_UDF_CALL_AGG_INIT: { req->initFirst = 1; diff --git a/source/libs/function/src/udfd.c b/source/libs/function/src/udfd.c index d5c917121a..50f8bdbd93 100644 --- a/source/libs/function/src/udfd.c +++ b/source/libs/function/src/udfd.c @@ -49,7 +49,7 @@ typedef struct SUdf { uv_lib_t lib; TUdfScalarProcFunc scalarProcFunc; - TUdfFreeUdfColumnDataFunc freeUdfColumnData; + TUdfFreeUdfColumnFunc freeUdfColumn; } SUdf; //TODO: low priority: change name onxxx to xxxCb, and udfc or udfd as prefix @@ -72,18 +72,22 @@ void udfdProcessRequest(uv_work_t *req) { SUdfSetupRequest *setup = &request.setup; strcpy(udf->name, setup->udfName); //TODO: retrive udf info from mnode - char* path = "udf1.so"; + char* path = "libudf1.so"; int err = uv_dlopen(path, &udf->lib); if (err != 0) { debugPrint("can not load library %s. error: %s", path, uv_strerror(err)); //TODO set error } - char normalFuncName[32] = {0}; + char normalFuncName[TSDB_FUNC_NAME_LEN] = {0}; strcpy(normalFuncName, setup->udfName); - //TODO error, + //TODO error, multi-thread, same udf, lock it //TODO find all functions normal, init, destroy, normal, merge, finalize uv_dlsym(&udf->lib, normalFuncName, (void **) (&udf->scalarProcFunc)); + char freeFuncName[TSDB_FUNC_NAME_LEN + 5]; + strncpy(freeFuncName, normalFuncName, strlen(normalFuncName)); + strcat(freeFuncName, "_free"); + uv_dlsym(&udf->lib, freeFuncName, (void **)(&udf->freeUdfColumn)); SUdfHandle *handle = taosMemoryMalloc(sizeof(SUdfHandle)); handle->udf = udf; @@ -96,10 +100,11 @@ void udfdProcessRequest(uv_work_t *req) { rsp.setupRsp.udfHandle = (int64_t) (handle); int32_t len = encodeUdfResponse(NULL, &rsp); rsp.msgLen = len; - void *buf = taosMemoryMalloc(len); + void *bufBegin = taosMemoryMalloc(len); + void *buf = bufBegin; encodeUdfResponse(&buf, &rsp); - uvUdf->output = uv_buf_init(buf, len); + uvUdf->output = uv_buf_init(bufBegin, len); taosMemoryFree(uvUdf->input.base); break; @@ -131,12 +136,13 @@ void udfdProcessRequest(uv_work_t *req) { int32_t len = encodeUdfResponse(NULL, rsp); rsp->msgLen = len; - void *buf = taosMemoryMalloc(len); + void *bufBegin = taosMemoryMalloc(len); + void *buf = bufBegin; encodeUdfResponse(&buf, rsp); - uvUdf->output = uv_buf_init(buf, len); + uvUdf->output = uv_buf_init(bufBegin, len); //TODO: free - udf->freeUdfColumnData(&output); + udf->freeUdfColumn(&output); taosMemoryFree(uvUdf->input.base); break; @@ -160,12 +166,12 @@ void udfdProcessRequest(uv_work_t *req) { rsp->seqNum = request.seqNum; rsp->type = request.type; rsp->code = 0; - SUdfTeardownResponse *subRsp = &response.teardownRsp; int32_t len = encodeUdfResponse(NULL, rsp); - void *buf = taosMemoryMalloc(len); rsp->msgLen = len; + void *bufBegin = taosMemoryMalloc(len); + void *buf = bufBegin; encodeUdfResponse(&buf, rsp); - uvUdf->output = uv_buf_init(buf, len); + uvUdf->output = uv_buf_init(bufBegin, len); taosMemoryFree(uvUdf->input.base); break; diff --git a/source/libs/function/test/runUdf.c b/source/libs/function/test/runUdf.c index 7c03ed727e..a03e006f7f 100644 --- a/source/libs/function/test/runUdf.c +++ b/source/libs/function/test/runUdf.c @@ -29,11 +29,15 @@ int main(int argc, char *argv[]) { pBlock->pDataBlock = taosArrayInit(1, sizeof(SColumnInfoData)); pBlock->info.numOfCols = 1; pBlock->info.rows = 4; + char data[16] = {0}; + char bitmap[1] = {0}; for (int32_t i = 0; i < pBlock->info.numOfCols; ++i) { SColumnInfoData colInfo = {0}; colInfo.info.type = TSDB_DATA_TYPE_INT; colInfo.info.bytes = sizeof(int32_t); colInfo.info.colId = 1; + colInfo.pData = data; + colInfo.nullbitmap = bitmap; for (int32_t j = 0; j < pBlock->info.rows; ++j) { colDataAppendInt32(&colInfo, j, &j); } From 7f0077cad5f87bcb93973227dee8e726ff8589cc Mon Sep 17 00:00:00 2001 From: Haojun Liao Date: Tue, 19 Apr 2022 16:32:19 +0800 Subject: [PATCH 17/19] feat(query): a new builtin aggregate function is added. --- source/libs/function/src/builtinsimpl.c | 56 +++++++++++++++---------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/source/libs/function/src/builtinsimpl.c b/source/libs/function/src/builtinsimpl.c index 2b1e4b9406..7699219f52 100644 --- a/source/libs/function/src/builtinsimpl.c +++ b/source/libs/function/src/builtinsimpl.c @@ -819,6 +819,8 @@ int32_t firstFunction(SqlFunctionCtx *pCtx) { continue; } + numOfElems++; + char* data = colDataGetData(pInputCol, i); TSKEY cts = getRowPTs(pInput->pPTS, i); @@ -828,9 +830,8 @@ int32_t firstFunction(SqlFunctionCtx *pCtx) { // DO_UPDATE_TAG_COLUMNS(pCtx, ts); pResInfo->numOfRes = 1; + break; } - - numOfElems++; } } else { // in case of descending order time stamp serial, which usually happens as the results of the nest query, @@ -847,6 +848,8 @@ int32_t firstFunction(SqlFunctionCtx *pCtx) { continue; } + numOfElems++; + char* data = colDataGetData(pInputCol, i); TSKEY cts = getRowPTs(pInput->pPTS, i); @@ -855,9 +858,8 @@ int32_t firstFunction(SqlFunctionCtx *pCtx) { *(TSKEY*)(buf + bytes) = cts; // DO_UPDATE_TAG_COLUMNS(pCtx, ts); pResInfo->numOfRes = 1; + break; } - - numOfElems++; } } @@ -874,43 +876,55 @@ int32_t lastFunction(SqlFunctionCtx *pCtx) { SInputColumnInfoData* pInput = &pCtx->input; SColumnInfoData* pInputCol = pInput->pData[0]; + int32_t bytes = pInputCol->info.bytes; + // All null data column, return directly. if (pInput->colDataAggIsSet && (pInput->pColumnDataAgg[0]->numOfNull == pInput->totalRows)) { ASSERT(pInputCol->hasNull == true); return 0; } - if (pCtx->order == TSDB_ORDER_DESC) { + SColumnDataAgg* pColAgg = (pInput->colDataAggIsSet)? pInput->pColumnDataAgg[0]:NULL; + + TSKEY startKey = getRowPTs(pInput->pPTS, 0); + TSKEY endKey = getRowPTs(pInput->pPTS, pInput->totalRows - 1); + + int32_t blockDataOrder = (startKey <= endKey)? TSDB_ORDER_ASC:TSDB_ORDER_DESC; + + if (blockDataOrder == TSDB_ORDER_ASC) { for (int32_t i = pInput->numOfRows + pInput->startRowIndex - 1; i >= pInput->startRowIndex; --i) { - if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, NULL)) { + if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) { continue; } - char* data = colDataGetData(pInputCol, i); - memcpy(buf, data, pInputCol->info.bytes); - -// TSKEY ts = pCtx->ptsList ? GET_TS_DATA(pCtx, i) : 0; -// DO_UPDATE_TAG_COLUMNS(pCtx, ts); - pResInfo->complete = true; // set query completed on this column numOfElems++; + + char* data = colDataGetData(pInputCol, i); + TSKEY cts = getRowPTs(pInput->pPTS, i); + if (pResInfo->numOfRes == 0 || *(TSKEY*)(buf + bytes) > cts) { + memcpy(buf, data, bytes); + *(TSKEY*)(buf + bytes) = cts; + // DO_UPDATE_TAG_COLUMNS(pCtx, ts); + pResInfo->numOfRes = 1; + } break; } - } else { // ascending order + } else { // descending order for (int32_t i = pInput->startRowIndex; i < pInput->numOfRows + pInput->startRowIndex; ++i) { - if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, NULL)) { + if (pInputCol->hasNull && colDataIsNull(pInputCol, pInput->totalRows, i, pColAgg)) { continue; } - char* data = colDataGetData(pInputCol, i); - TSKEY ts = pCtx->ptsList ? GET_TS_DATA(pCtx, i) : 0; + numOfElems++; - if (pResInfo->numOfRes == 0 || (*(TSKEY*)buf) < ts) { - memcpy(buf, data, pCtx->inputBytes); - *(TSKEY*)buf = ts; + char* data = colDataGetData(pInputCol, i); + TSKEY cts = getRowPTs(pInput->pPTS, i); + if (pResInfo->numOfRes == 0 || *(TSKEY*)(buf + bytes) > cts) { + memcpy(buf, data, bytes); + *(TSKEY*)(buf + bytes) = cts; + pResInfo->numOfRes = 1; // DO_UPDATE_TAG_COLUMNS(pCtx, ts); } - - numOfElems++; break; } } From 0776427f45724b01099a23e418bf5e53d105d27b Mon Sep 17 00:00:00 2001 From: slzhou Date: Tue, 19 Apr 2022 16:51:02 +0800 Subject: [PATCH 18/19] runUdf passed --- source/libs/function/inc/tudf.h | 24 +++++---- source/libs/function/src/tudf.c | 82 +++++++++++++++++------------- source/libs/function/src/udfd.c | 8 +-- source/libs/function/test/runUdf.c | 6 ++- source/libs/function/test/udf1.c | 55 +++++++++++--------- 5 files changed, 103 insertions(+), 72 deletions(-) diff --git a/source/libs/function/inc/tudf.h b/source/libs/function/inc/tudf.h index 74aab09da2..8ec02c777f 100644 --- a/source/libs/function/inc/tudf.h +++ b/source/libs/function/inc/tudf.h @@ -68,17 +68,19 @@ typedef struct SUdfColumnData { int32_t numOfRows; bool varLengthColumn; union { - int32_t nullBitmapLen; - char* nullBitmap; - int32_t dataLen; - char* data; - }; + struct { + int32_t nullBitmapLen; + char *nullBitmap; + int32_t dataLen; + char *data; + } fixLenCol; - union { - int32_t varOffsetsLen; - char* varOffsets; - int32_t payloadLen; - char* payload; + struct { + int32_t varOffsetsLen; + char *varOffsets; + int32_t payloadLen; + char *payload; + } varLenCol; }; } SUdfColumnData; @@ -136,7 +138,7 @@ typedef int32_t (*TUdfTeardownFunc)(); //typedef int32_t addFixedLengthColumnData(SColumnData *columnData, int rowIndex, bool isNull, int32_t colBytes, char* data); //typedef int32_t addVariableLengthColumnData(SColumnData *columnData, int rowIndex, bool isNull, int32_t dataLen, char * data); -typedef int32_t (*TUdfFreeUdfColumnFunc)(SUdfColumn* columnData); +typedef int32_t (*TUdfFreeUdfColumnFunc)(SUdfColumn* column); typedef int32_t (*TUdfScalarProcFunc)(SUdfDataBlock block, SUdfColumn *resultCol); typedef int32_t (*TUdfAggInitFunc)(SUdfInterBuf *buf); diff --git a/source/libs/function/src/tudf.c b/source/libs/function/src/tudf.c index c5542424f0..c41447b584 100644 --- a/source/libs/function/src/tudf.c +++ b/source/libs/function/src/tudf.c @@ -361,7 +361,7 @@ int32_t encodeUdfCallResponse(void **buf, const SUdfCallResponse *callRsp) { len += encodeUdfInterBuf(buf, &callRsp->resultBuf); break; case TSDB_UDF_CALL_AGG_FIN: - len += tEncodeDataBlock(buf, &callRsp->resultData); + len += encodeUdfInterBuf(buf, &callRsp->resultBuf); break; } return len; @@ -383,7 +383,7 @@ void* decodeUdfCallResponse(const void* buf, SUdfCallResponse* callRsp) { buf = decodeUdfInterBuf(buf, &callRsp->resultBuf); break; case TSDB_UDF_CALL_AGG_FIN: - buf = tDecodeDataBlock(buf, &callRsp->resultData); + buf = decodeUdfInterBuf(buf, &callRsp->resultBuf); break; } return (void*)buf; @@ -406,6 +406,13 @@ int32_t encodeUdfResponse(void** buf, const SUdfResponse* rsp) { *buf = POINTER_SHIFT(*buf, sizeof(rsp->msgLen)); } + if (buf == NULL) { + len += sizeof(rsp->seqNum); + } else { + *(int64_t*)(*buf) = rsp->seqNum; + *buf = POINTER_SHIFT(*buf, sizeof(rsp->seqNum)); + } + len += taosEncodeFixedI64(buf, rsp->seqNum); len += taosEncodeFixedI8(buf, rsp->type); len += taosEncodeFixedI32(buf, rsp->code); @@ -430,6 +437,8 @@ int32_t encodeUdfResponse(void** buf, const SUdfResponse* rsp) { void* decodeUdfResponse(const void* buf, SUdfResponse* rsp) { rsp->msgLen = *(int32_t*)(buf); buf = POINTER_SHIFT(buf, sizeof(rsp->msgLen)); + rsp->seqNum = *(int64_t*)(buf); + buf = POINTER_SHIFT(buf, sizeof(rsp->seqNum)); buf = taosDecodeFixedI64(buf, &rsp->seqNum); buf = taosDecodeFixedI8(buf, &rsp->type); buf = taosDecodeFixedI32(buf, &rsp->code); @@ -453,15 +462,15 @@ void* decodeUdfResponse(const void* buf, SUdfResponse* rsp) { void freeUdfColumnData(SUdfColumnData *data) { if (data->varLengthColumn) { - taosMemoryFree(data->varOffsets); - data->varOffsets = NULL; - taosMemoryFree(data->payload); - data->payload = NULL; + taosMemoryFree(data->varLenCol.varOffsets); + data->varLenCol.varOffsets = NULL; + taosMemoryFree(data->varLenCol.payload); + data->varLenCol.payload = NULL; } else { - taosMemoryFree(data->nullBitmap); - data->nullBitmap = NULL; - taosMemoryFree(data->data); - data->data = NULL; + taosMemoryFree(data->fixLenCol.nullBitmap); + data->fixLenCol.nullBitmap = NULL; + taosMemoryFree(data->fixLenCol.data); + data->fixLenCol.data = NULL; } } @@ -488,9 +497,9 @@ void freeUdfInterBuf(SUdfInterBuf *buf) { int32_t convertDataBlockToUdfDataBlock(SSDataBlock *block, SUdfDataBlock *udfBlock) { udfBlock->numOfRows = block->info.rows; udfBlock->numOfCols = block->info.numOfCols; - udfBlock->udfCols = taosMemoryMalloc(sizeof(SUdfColumn*) * udfBlock->numOfCols); + udfBlock->udfCols = taosMemoryCalloc(udfBlock->numOfCols, sizeof(SUdfColumn*)); for (int32_t i = 0; i < udfBlock->numOfCols; ++i) { - udfBlock->udfCols[i] = taosMemoryMalloc(sizeof(SUdfColumn)); + udfBlock->udfCols[i] = taosMemoryCalloc(1, sizeof(SUdfColumn)); SColumnInfoData *col= (SColumnInfoData*)taosArrayGet(block->pDataBlock, i); SUdfColumn *udfCol = udfBlock->udfCols[i]; udfCol->colMeta.type = col->info.type; @@ -500,19 +509,23 @@ int32_t convertDataBlockToUdfDataBlock(SSDataBlock *block, SUdfDataBlock *udfBlo udfCol->colData.numOfRows = udfBlock->numOfRows; udfCol->colData.varLengthColumn = IS_VAR_DATA_TYPE(udfCol->colMeta.type); if (udfCol->colData.varLengthColumn) { - udfCol->colData.varOffsetsLen = sizeof(int32_t) * udfBlock->numOfRows; - udfCol->colData.varOffsets = taosMemoryMalloc(udfCol->colData.varOffsetsLen); - memcpy(udfCol->colData.varOffsets, col->varmeta.offset, udfCol->colData.varOffsetsLen); - udfCol->colData.payloadLen = colDataGetLength(col, udfBlock->numOfRows); - udfCol->colData.payload = taosMemoryMalloc(udfCol->colData.payloadLen); - memcpy(udfCol->colData.payload, col->pData, udfCol->colData.payloadLen); + udfCol->colData.varLenCol.varOffsetsLen = sizeof(int32_t) * udfBlock->numOfRows; + udfCol->colData.varLenCol.varOffsets = taosMemoryMalloc(udfCol->colData.varLenCol.varOffsetsLen); + memcpy(udfCol->colData.varLenCol.varOffsets, col->varmeta.offset, udfCol->colData.varLenCol.varOffsetsLen); + udfCol->colData.varLenCol.payloadLen = colDataGetLength(col, udfBlock->numOfRows); + udfCol->colData.varLenCol.payload = taosMemoryMalloc(udfCol->colData.varLenCol.payloadLen); + memcpy(udfCol->colData.varLenCol.payload, col->pData, udfCol->colData.varLenCol.payloadLen); } else { - udfCol->colData.nullBitmapLen = BitmapLen(udfCol->colData.numOfRows); - udfCol->colData.nullBitmap = taosMemoryMalloc(udfCol->colData.nullBitmapLen); - memcpy(udfCol->colData.nullBitmap, col->nullbitmap, udfCol->colData.nullBitmapLen); - udfCol->colData.dataLen = colDataGetLength(col, udfBlock->numOfRows); - udfCol->colData.data = taosMemoryMalloc(udfCol->colData.dataLen); - memcpy(udfCol->colData.data, col->pData, udfCol->colData.dataLen); + udfCol->colData.fixLenCol.nullBitmapLen = BitmapLen(udfCol->colData.numOfRows); + int32_t bitmapLen = udfCol->colData.fixLenCol.nullBitmapLen; + udfCol->colData.fixLenCol.nullBitmap = taosMemoryMalloc(udfCol->colData.fixLenCol.nullBitmapLen); + char* bitmap = udfCol->colData.fixLenCol.nullBitmap; + memcpy(bitmap, col->nullbitmap, bitmapLen); + udfCol->colData.fixLenCol.dataLen = colDataGetLength(col, udfBlock->numOfRows); + int32_t dataLen = udfCol->colData.fixLenCol.dataLen; + udfCol->colData.fixLenCol.data = taosMemoryMalloc(udfCol->colData.fixLenCol.dataLen); + char* data = udfCol->colData.fixLenCol.data; + memcpy(data, col->pData, dataLen); } } return 0; @@ -534,15 +547,15 @@ int32_t convertUdfColumnToDataBlock(SUdfColumn *udfCol, SSDataBlock *block) { SUdfColumnData *data = &udfCol->colData; if (!IS_VAR_DATA_TYPE(meta->type)) { - col->nullbitmap = taosMemoryMalloc(data->nullBitmapLen); - memcpy(col->nullbitmap, data->nullBitmap, data->nullBitmapLen); - col->pData = taosMemoryMalloc(data->dataLen); - memcpy(col->pData, data->payload, data->dataLen); + col->nullbitmap = taosMemoryMalloc(data->fixLenCol.nullBitmapLen); + memcpy(col->nullbitmap, data->fixLenCol.nullBitmap, data->fixLenCol.nullBitmapLen); + col->pData = taosMemoryMalloc(data->fixLenCol.dataLen); + memcpy(col->pData, data->fixLenCol.data, data->fixLenCol.dataLen); } else { - col->varmeta.offset = taosMemoryMalloc(data->varOffsetsLen); - memcpy(col->varmeta.offset, data->varOffsets, data->varOffsetsLen); - col->pData = taosMemoryMalloc(data->payloadLen); - memcpy(col->pData, data->payload, data->payloadLen); + col->varmeta.offset = taosMemoryMalloc(data->varLenCol.varOffsetsLen); + memcpy(col->varmeta.offset, data->varLenCol.varOffsets, data->varLenCol.varOffsetsLen); + col->pData = taosMemoryMalloc(data->varLenCol.payloadLen); + memcpy(col->pData, data->varLenCol.payload, data->varLenCol.payloadLen); } return 0; } @@ -932,7 +945,7 @@ void onUdfdExit(uv_process_t *req, int64_t exit_status, int term_signal) { gUdfcState = UDFC_STATE_RESTARTING; //TODO: asynchronous without blocking. how to do it cleanUpUvTasks(); - //startUdfd(); + startUdfd(); } } @@ -967,7 +980,7 @@ void constructUdfService(void *argsThread) { uv_loop_init(&gUdfdLoop); //TODO spawn error - //startUdfd(); + startUdfd(); uv_async_init(&gUdfdLoop, &gUdfLoopTaskAync, udfClientAsyncCb); uv_async_init(&gUdfdLoop, &gUdfLoopStopAsync, udfStopAsyncCb); @@ -1053,6 +1066,7 @@ int32_t callUdf(UdfHandle handle, int8_t callType, SSDataBlock *input, SUdfInter SUdfCallRequest *req = &task->_call.req; req->udfHandle = task->session->severHandle; + req->callType = callType; switch (callType) { case TSDB_UDF_CALL_AGG_INIT: { diff --git a/source/libs/function/src/udfd.c b/source/libs/function/src/udfd.c index 50f8bdbd93..a02c94c109 100644 --- a/source/libs/function/src/udfd.c +++ b/source/libs/function/src/udfd.c @@ -84,9 +84,10 @@ void udfdProcessRequest(uv_work_t *req) { //TODO error, multi-thread, same udf, lock it //TODO find all functions normal, init, destroy, normal, merge, finalize uv_dlsym(&udf->lib, normalFuncName, (void **) (&udf->scalarProcFunc)); - char freeFuncName[TSDB_FUNC_NAME_LEN + 5]; + char freeFuncName[TSDB_FUNC_NAME_LEN + 6] = {0}; + char *freeSuffix = "_free"; strncpy(freeFuncName, normalFuncName, strlen(normalFuncName)); - strcat(freeFuncName, "_free"); + strncat(freeFuncName, freeSuffix, strlen(freeSuffix)); uv_dlsym(&udf->lib, freeFuncName, (void **)(&udf->freeUdfColumn)); SUdfHandle *handle = taosMemoryMalloc(sizeof(SUdfHandle)); @@ -118,7 +119,7 @@ void udfdProcessRequest(uv_work_t *req) { SUdfDataBlock input = {0}; convertDataBlockToUdfDataBlock(&call->block, &input); - SUdfColumn output; + SUdfColumn output = {0}; //TODO: call different functions according to call type, for now just calar if (call->callType == TSDB_UDF_CALL_SCALA_PROC) { udf->scalarProcFunc(input, &output); @@ -131,6 +132,7 @@ void udfdProcessRequest(uv_work_t *req) { rsp->type = request.type; rsp->code = 0; SUdfCallResponse *subRsp = &rsp->callRsp; + subRsp->callType = call->callType; convertUdfColumnToDataBlock(&output, &subRsp->resultData); } diff --git a/source/libs/function/test/runUdf.c b/source/libs/function/test/runUdf.c index a03e006f7f..28dc6bb99a 100644 --- a/source/libs/function/test/runUdf.c +++ b/source/libs/function/test/runUdf.c @@ -30,7 +30,7 @@ int main(int argc, char *argv[]) { pBlock->info.numOfCols = 1; pBlock->info.rows = 4; char data[16] = {0}; - char bitmap[1] = {0}; + char bitmap[4] = {0}; for (int32_t i = 0; i < pBlock->info.numOfCols; ++i) { SColumnInfoData colInfo = {0}; colInfo.info.type = TSDB_DATA_TYPE_INT; @@ -47,6 +47,10 @@ int main(int argc, char *argv[]) { SSDataBlock output = {0}; callUdfScalaProcess(handle, pBlock, &output); + SColumnInfoData *col = taosArrayGet(output.pDataBlock, 0); + for (int32_t i = 0; i < output.info.rows; ++i) { + fprintf(stderr, "%d\t%d\n" , i, *(int32_t*)(col->pData + i *sizeof(int32_t))); + } teardownUdf(handle); stopUdfService(); diff --git a/source/libs/function/test/udf1.c b/source/libs/function/test/udf1.c index 31e7a36e9c..94cab9fee9 100644 --- a/source/libs/function/test/udf1.c +++ b/source/libs/function/test/udf1.c @@ -17,44 +17,53 @@ int32_t udf1_teardown() { return 0; } -int32_t udf1(SUdfDataBlock block, SUdfColumnData *resultData) { - +int32_t udf1(SUdfDataBlock block, SUdfColumn *resultCol) { + SUdfColumnData *resultData = &resultCol->colData; resultData->numOfRows = block.numOfRows; SUdfColumnData *srcData = &block.udfCols[0]->colData; resultData->varLengthColumn = srcData->varLengthColumn; if (resultData->varLengthColumn) { - resultData->varOffsetsLen = srcData->varOffsetsLen; - resultData->varOffsets = malloc(resultData->varOffsetsLen); - memcpy(resultData->varOffsets, srcData->varOffsets, srcData->varOffsetsLen); + resultData->varLenCol.varOffsetsLen = srcData->varLenCol.varOffsetsLen; + resultData->varLenCol.varOffsets = malloc(resultData->varLenCol.varOffsetsLen); + memcpy(resultData->varLenCol.varOffsets, srcData->varLenCol.varOffsets, srcData->varLenCol.varOffsetsLen); - resultData->payloadLen = srcData->payloadLen; - resultData->payload = malloc(resultData->payloadLen); - memcpy(resultData->payload, srcData->payload, srcData->payloadLen); + resultData->varLenCol.payloadLen = srcData->varLenCol.payloadLen; + resultData->varLenCol.payload = malloc(resultData->varLenCol.payloadLen); + memcpy(resultData->varLenCol.payload, srcData->varLenCol.payload, srcData->varLenCol.payloadLen); } else { - resultData->nullBitmapLen = srcData->nullBitmapLen; - resultData->nullBitmap = malloc(resultData->nullBitmapLen); - memcpy(resultData->nullBitmap, srcData->nullBitmap, srcData->nullBitmapLen); + resultData->fixLenCol.nullBitmapLen = srcData->fixLenCol.nullBitmapLen; + resultData->fixLenCol.nullBitmap = malloc(resultData->fixLenCol.nullBitmapLen); + memcpy(resultData->fixLenCol.nullBitmap, srcData->fixLenCol.nullBitmap, srcData->fixLenCol.nullBitmapLen); - resultData->dataLen = srcData->dataLen; - resultData->data = malloc(resultData->dataLen); - memcpy(resultData->data, srcData->data, srcData->dataLen); + resultData->fixLenCol.dataLen = srcData->fixLenCol.dataLen; + resultData->fixLenCol.data = malloc(resultData->fixLenCol.dataLen); + memcpy(resultData->fixLenCol.data, srcData->fixLenCol.data, srcData->fixLenCol.dataLen); + for (int32_t i = 0; i < resultData->numOfRows; ++i) { + *(resultData->fixLenCol.data + i * sizeof(int32_t)) = 88; + } } + SUdfColumnMeta *meta = &resultCol->colMeta; + meta->bytes = 4; + meta->type = TSDB_DATA_TYPE_INT; + meta->scale = 0; + meta->precision = 0; return 0; } -int32_t udf1_free(SUdfColumnData *data) { +int32_t udf1_free(SUdfColumn *col) { + SUdfColumnData *data = &col->colData; if (data->varLengthColumn) { - free(data->varOffsets); - data->varOffsets = NULL; - free(data->payload); - data->payload = NULL; + free(data->varLenCol.varOffsets); + data->varLenCol.varOffsets = NULL; + free(data->varLenCol.payload); + data->varLenCol.payload = NULL; } else { - free(data->nullBitmap); - data->nullBitmap = NULL; - free(data->data); - data->data = NULL; + free(data->fixLenCol.nullBitmap); + data->fixLenCol.nullBitmap = NULL; + free(data->fixLenCol.data); + data->fixLenCol.data = NULL; } return 0; } \ No newline at end of file From a9192233def046bccb97aaa57411515b4409eef9 Mon Sep 17 00:00:00 2001 From: cpwu Date: Tue, 19 Apr 2022 16:49:34 +0800 Subject: [PATCH 19/19] fix case --- tests/system-test/2-query/cast.py | 167 ++++++++++++++++++++++++++++++ 1 file changed, 167 insertions(+) create mode 100644 tests/system-test/2-query/cast.py diff --git a/tests/system-test/2-query/cast.py b/tests/system-test/2-query/cast.py new file mode 100644 index 0000000000..2561aad1ef --- /dev/null +++ b/tests/system-test/2-query/cast.py @@ -0,0 +1,167 @@ +import taos +import sys + +from util.log import * +from util.sql import * +from util.cases import * + + + +class TDTestCase: + + def init(self, conn, logSql): + tdLog.debug(f"start to excute {__file__}") + tdSql.init(conn.cursor()) + + def run(self): # sourcery skip: extract-duplicate-method, remove-redundant-fstring + tdSql.prepare() + + tdLog.printNoPrefix("==========step1:create table") + tdSql.execute( + '''create table stb1 + (ts timestamp, c1 int, c2 bigint, c3 smallint, c4 tinyint, c5 float, c6 double, c7 bool, c8 binary(16),c9 nchar(32), c10 timestamp) + tags (t1 int) + ''' + ) + tdSql.execute( + ''' + create table t1 + (ts timestamp, c1 int, c2 bigint, c3 smallint, c4 tinyint, c5 float, c6 double, c7 bool, c8 binary(16),c9 nchar(32), c10 timestamp) + ''' + ) + for i in range(4): + tdSql.execute(f'create table ct{i+1} using stb1 tags ( {i+1} )') + + tdLog.printNoPrefix("==========step2:insert data") + for i in range(9): + tdSql.execute( + f"insert into ct1 values ( now()-{i*10}s, {1*i}, {11111*i}, {111*i}, {11*i}, {1.11*i}, {11.11*i}, {i%2}, 'binary{i}', 'nchar{i}', now()+{1*i}a )" + ) + tdSql.execute( + f"insert into ct4 values ( now()-{i*90}d, {1*i}, {11111*i}, {111*i}, {11*i}, {1.11*i}, {11.11*i}, {i%2}, 'binary{i}', 'nchar{i}', now()+{1*i}a )" + ) + tdSql.execute("insert into ct1 values (now()-45s, 0, 0, 0, 0, 0, 0, 0, 'binary0', 'nchar0', now()+8a )") + tdSql.execute("insert into ct1 values (now()+10s, 9, -99999, -999, -99, -9.99, -99.99, 1, 'binary9', 'nchar9', now()+9a )") + + tdSql.execute("insert into ct4 values (now()-810d, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ) ") + tdSql.execute("insert into ct4 values (now()-400d, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ) ") + tdSql.execute("insert into ct4 values (now()+90d, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ) ") + + tdSql.execute( + f'''insert into t1 values + ( '2020-04-21 01:01:01.000', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ) + ( '2020-10-21 01:01:01.000', 1, 11111, 111, 11, 1.11, 11.11, 1, "binary1", "nchar1", now()+1a ) + ( '2020-12-31 01:01:01.000', 2, 22222, 222, 22, 2.22, 22.22, 0, "binary2", "nchar2", now()+2a ) + ( '2021-01-01 01:01:06.000', 3, 33333, 333, 33, 3.33, 33.33, 0, "binary3", "nchar3", now()+3a ) + ( '2021-05-07 01:01:10.000', 4, 44444, 444, 44, 4.44, 44.44, 1, "binary4", "nchar4", now()+4a ) + ( '2021-07-21 01:01:01.000', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ) + ( '2021-09-30 01:01:16.000', 5, 55555, 555, 55, 5.55, 55.55, 0, "binary5", "nchar5", now()+5a ) + ( '2022-02-01 01:01:20.000', 6, 66666, 666, 66, 6.66, 66.66, 1, "binary6", "nchar6", now()+6a ) + ( '2022-10-28 01:01:26.000', 7, 00000, 000, 00, 0.00, 00.00, 1, "binary7", "nchar7", "1970-01-01 08:00:00.000" ) + ( '2022-12-01 01:01:30.000', 8, -88888, -888, -88, -8.88, -88.88, 0, "binary8", "nchar8", "1969-01-01 01:00:00.000" ) + ( '2022-12-31 01:01:36.000', 9, -99999999999999999, -999, -99, -9.99, -999999999999999999999.99, 1, "binary9", "nchar9", "1900-01-01 00:00:00.000" ) + ( '2023-02-21 01:01:01.000', NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL ) + ''' + ) + + tdSql.query("select c1 from ct4") + data_ct4 = [tdSql.getData(i,0) for i in range(tdSql.queryRows)] + tdSql.query("select c1 from t1") + data_t1 = [tdSql.getData(i,0) for i in range(tdSql.queryRows)] + + # tdLog.printNoPrefix("==========step1: cast int to int, expect no changes") + + # tdSql.query("select cast(c1 as int) as b from ct4") + # for i in range(len(data_ct4)): + # tdSql.checkData( i, 0, data_ct4[i]) + + # tdSql.query("select cast(c1 as int) as b from t1") + # for i in range(len(data_t1)): + # tdSql.checkData( i, 0, data_t1[i]) + + tdLog.printNoPrefix("==========step2: cast int to bigint, expect no changes") + + tdSql.query("select cast(c1 as bigint) as b from ct4") + for i in range(len(data_ct4)): + tdSql.checkData( i, 0, data_ct4[i]) + tdSql.query("select cast(c1 as bigint) as b from t1") + for i in range(len(data_t1)): + tdSql.checkData( i, 0, data_t1[i]) + + # tdLog.printNoPrefix("==========step3: cast int to float, expect no changes") + + # tdSql.query("select cast(c1 as float) as b from ct4") + # for i in range(len(data_ct4)): + # tdSql.checkData( i, 0, data_ct4[i]) + # tdSql.query("select cast(c1 as float) as b from t1") + # for i in range(len(data_t1)): + # tdSql.checkData( i, 0, data_t1[i]) + + # tdLog.printNoPrefix("==========step4: cast int to double, expect no changes") + + # tdSql.query("select cast(c1 as double) as b from ct4") + # for i in range(len(data_ct4)): + # tdSql.checkData( i, 0, data_ct4[i]) + # tdSql.query("select cast(c1 as double) as b from t1") + # for i in range(len(data_t1)): + # tdSql.checkData( i, 0, data_t1[i]) + + tdLog.printNoPrefix("==========step5: cast int to binary, expect no changes") + + tdSql.query("select cast(c1 as binary(32)) as b from ct4") + for i in range(len(data_ct4)): + tdSql.checkData( i, 0, str(data_ct4[i]) ) + tdSql.query("select cast(c1 as binary(32)) as b from t1") + for i in range(len(data_t1)): + tdSql.checkData( i, 0, str(data_t1[i]) ) + + tdLog.printNoPrefix("==========step6: cast int to nchar, expect no changes") + + tdSql.query("select cast(c1 as nchar(32)) as b from ct4") + for i in range(len(data_ct4)): + tdSql.checkData( i, 0, str(data_ct4[i]) ) + tdSql.query("select cast(c1 as nchar(32)) as b from t1") + for i in range(len(data_t1)): + tdSql.checkData( i, 0, str(data_t1[i]) ) + + tdLog.printNoPrefix("==========step7: cast int to timestamp, expect no changes") + + tdSql.query("select cast(c1 as timestamp) as b from ct4") + for i in range(len(data_ct4)): + tdSql.checkData( i, 0, data_ct4[i]) + tdSql.query("select cast(c1 as timestamp) as b from t1") + for i in range(len(data_t1)): + tdSql.checkData( i, 0, data_t1[i]) + + tdSql.error("select cast(c1 as int) as b from ct4") + tdSql.error("select cast(c1 as bool) as b from ct4") + tdSql.error("select cast(c1 as tinyint) as b from ct4") + tdSql.error("select cast(c1 as smallint) as b from ct4") + tdSql.error("select cast(c1 as float) as b from ct4") + tdSql.error("select cast(c1 as double) as b from ct4") + tdSql.error("select cast(c1 as tinyint unsigned) as b from ct4") + tdSql.error("select cast(c1 as smallint unsigned) as b from ct4") + tdSql.error("select cast(c1 as int unsigned) as b from ct4") + + tdSql.error("select cast(c2 as int) as b from ct4") + tdSql.error("select cast(c3 as bool) as b from ct4") + tdSql.error("select cast(c4 as tinyint) as b from ct4") + tdSql.error("select cast(c5 as smallint) as b from ct4") + tdSql.error("select cast(c6 as float) as b from ct4") + tdSql.error("select cast(c7 as double) as b from ct4") + tdSql.error("select cast(c8 as tinyint unsigned) as b from ct4") + + tdSql.error("select cast(c8 as timestamp ) as b from ct4") + + tdSql.error("select cast(c9 as binary(64) ) as b from ct4") + tdSql.error("select cast(c9 as timestamp ) as b from ct4") + tdSql.error("select cast(c10 as binary(64) ) as b from ct4") + tdSql.error("select cast(c10 as nchar(64) ) as b from ct4") + + + def stop(self): + tdSql.close() + tdLog.success(f"{__file__} successfully executed") + +tdCases.addLinux(__file__, TDTestCase()) +tdCases.addWindows(__file__, TDTestCase())