Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
taosdata
TDengine
提交
548838d9
T
TDengine
项目概览
taosdata
/
TDengine
大约 2 年 前同步成功
通知
1192
Star
22018
Fork
4786
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
1
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
T
TDengine
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
1
Issue
1
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
548838d9
编写于
5月 22, 2022
作者:
S
shenglian zhou
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
enhance: udf code refactoring
上级
3fe92062
变更
1
隐藏空白更改
内联
并排
Showing
1 changed file
with
537 addition
and
461 deletion
+537
-461
source/libs/function/src/tudf.c
source/libs/function/src/tudf.c
+537
-461
未找到文件。
source/libs/function/src/tudf.c
浏览文件 @
548838d9
...
@@ -46,6 +46,13 @@ typedef struct SUdfdData {
...
@@ -46,6 +46,13 @@ typedef struct SUdfdData {
SUdfdData
udfdGlobal
=
{
0
};
SUdfdData
udfdGlobal
=
{
0
};
static
int32_t
udfSpawnUdfd
(
SUdfdData
*
pData
);
static
int32_t
udfSpawnUdfd
(
SUdfdData
*
pData
);
void
udfUdfdExit
(
uv_process_t
*
process
,
int64_t
exitStatus
,
int
termSignal
);
static
int32_t
udfSpawnUdfd
(
SUdfdData
*
pData
);
static
void
udfUdfdCloseWalkCb
(
uv_handle_t
*
handle
,
void
*
arg
);
static
void
udfUdfdStopAsyncCb
(
uv_async_t
*
async
);
static
void
udfWatchUdfd
(
void
*
args
);
int32_t
udfStartUdfd
(
int32_t
startDnodeId
);
int32_t
udfStopUdfd
();
void
udfUdfdExit
(
uv_process_t
*
process
,
int64_t
exitStatus
,
int
termSignal
)
{
void
udfUdfdExit
(
uv_process_t
*
process
,
int64_t
exitStatus
,
int
termSignal
)
{
fnInfo
(
"udfd process exited with status %"
PRId64
", signal %d"
,
exitStatus
,
termSignal
);
fnInfo
(
"udfd process exited with status %"
PRId64
", signal %d"
,
exitStatus
,
termSignal
);
...
@@ -413,6 +420,34 @@ enum {
...
@@ -413,6 +420,34 @@ enum {
UDFC_STATE_STOPPING
,
// stopping after udfcClose
UDFC_STATE_STOPPING
,
// stopping after udfcClose
};
};
int32_t
getUdfdPipeName
(
char
*
pipeName
,
int32_t
size
);
int32_t
encodeUdfSetupRequest
(
void
**
buf
,
const
SUdfSetupRequest
*
setup
);
void
*
decodeUdfSetupRequest
(
const
void
*
buf
,
SUdfSetupRequest
*
request
);
int32_t
encodeUdfInterBuf
(
void
**
buf
,
const
SUdfInterBuf
*
state
);
void
*
decodeUdfInterBuf
(
const
void
*
buf
,
SUdfInterBuf
*
state
);
int32_t
encodeUdfCallRequest
(
void
**
buf
,
const
SUdfCallRequest
*
call
);
void
*
decodeUdfCallRequest
(
const
void
*
buf
,
SUdfCallRequest
*
call
);
int32_t
encodeUdfTeardownRequest
(
void
**
buf
,
const
SUdfTeardownRequest
*
teardown
);
void
*
decodeUdfTeardownRequest
(
const
void
*
buf
,
SUdfTeardownRequest
*
teardown
);
int32_t
encodeUdfRequest
(
void
**
buf
,
const
SUdfRequest
*
request
);
void
*
decodeUdfRequest
(
const
void
*
buf
,
SUdfRequest
*
request
);
int32_t
encodeUdfSetupResponse
(
void
**
buf
,
const
SUdfSetupResponse
*
setupRsp
);
void
*
decodeUdfSetupResponse
(
const
void
*
buf
,
SUdfSetupResponse
*
setupRsp
);
int32_t
encodeUdfCallResponse
(
void
**
buf
,
const
SUdfCallResponse
*
callRsp
);
void
*
decodeUdfCallResponse
(
const
void
*
buf
,
SUdfCallResponse
*
callRsp
);
int32_t
encodeUdfTeardownResponse
(
void
**
buf
,
const
SUdfTeardownResponse
*
teardownRsp
);
void
*
decodeUdfTeardownResponse
(
const
void
*
buf
,
SUdfTeardownResponse
*
teardownResponse
);
int32_t
encodeUdfResponse
(
void
**
buf
,
const
SUdfResponse
*
rsp
);
void
*
decodeUdfResponse
(
const
void
*
buf
,
SUdfResponse
*
rsp
);
void
freeUdfColumnData
(
SUdfColumnData
*
data
,
SUdfColumnMeta
*
meta
);
void
freeUdfColumn
(
SUdfColumn
*
col
);
void
freeUdfDataDataBlock
(
SUdfDataBlock
*
block
);
void
freeUdfInterBuf
(
SUdfInterBuf
*
buf
);
int32_t
convertDataBlockToUdfDataBlock
(
SSDataBlock
*
block
,
SUdfDataBlock
*
udfBlock
);
int32_t
convertUdfColumnToDataBlock
(
SUdfColumn
*
udfCol
,
SSDataBlock
*
block
);
int32_t
convertScalarParamToDataBlock
(
SScalarParam
*
input
,
int32_t
numOfCols
,
SSDataBlock
*
output
);
int32_t
convertDataBlockToScalarParm
(
SSDataBlock
*
input
,
SScalarParam
*
output
);
int32_t
getUdfdPipeName
(
char
*
pipeName
,
int32_t
size
)
{
int32_t
getUdfdPipeName
(
char
*
pipeName
,
int32_t
size
)
{
char
dnodeId
[
8
]
=
{
0
};
char
dnodeId
[
8
]
=
{
0
};
size_t
dnodeIdSize
=
sizeof
(
dnodeId
);
size_t
dnodeIdSize
=
sizeof
(
dnodeId
);
...
@@ -650,7 +685,7 @@ int32_t encodeUdfResponse(void** buf, const SUdfResponse* rsp) {
...
@@ -650,7 +685,7 @@ int32_t encodeUdfResponse(void** buf, const SUdfResponse* rsp) {
len
+=
encodeUdfTeardownResponse
(
buf
,
&
rsp
->
teardownRsp
);
len
+=
encodeUdfTeardownResponse
(
buf
,
&
rsp
->
teardownRsp
);
break
;
break
;
default:
default:
//TODO: log error
fnError
(
"encode udf response, invalid udf response type %d"
,
rsp
->
type
);
break
;
break
;
}
}
return
len
;
return
len
;
...
@@ -676,7 +711,7 @@ void* decodeUdfResponse(const void* buf, SUdfResponse* rsp) {
...
@@ -676,7 +711,7 @@ void* decodeUdfResponse(const void* buf, SUdfResponse* rsp) {
buf
=
decodeUdfTeardownResponse
(
buf
,
&
rsp
->
teardownRsp
);
buf
=
decodeUdfTeardownResponse
(
buf
,
&
rsp
->
teardownRsp
);
break
;
break
;
default:
default:
//TODO: log error
fnError
(
"decode udf response, invalid udf response type %d"
,
rsp
->
type
);
break
;
break
;
}
}
return
(
void
*
)
buf
;
return
(
void
*
)
buf
;
...
@@ -817,185 +852,498 @@ int32_t convertDataBlockToScalarParm(SSDataBlock *input, SScalarParam *output) {
...
@@ -817,185 +852,498 @@ int32_t convertDataBlockToScalarParm(SSDataBlock *input, SScalarParam *output) {
return
0
;
return
0
;
}
}
void
onUdfcPipeClose
(
uv_handle_t
*
handle
)
{
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
SClientUvConn
*
conn
=
handle
->
data
;
//memory layout |---SUdfAggRes----|-----final result-----|---inter result----|
if
(
!
QUEUE_EMPTY
(
&
conn
->
taskQueue
))
{
typedef
struct
SUdfAggRes
{
QUEUE
*
h
=
QUEUE_HEAD
(
&
conn
->
taskQueue
);
int8_t
finalResNum
;
SClientUvTaskNode
*
task
=
QUEUE_DATA
(
h
,
SClientUvTaskNode
,
connTaskQueue
);
int8_t
interResNum
;
task
->
errCode
=
0
;
char
*
finalResBuf
;
QUEUE_REMOVE
(
&
task
->
procTaskQueue
);
char
*
interResBuf
;
uv_sem_post
(
&
task
->
taskSem
);
}
SUdfAggRes
;
}
void
onUdfcPipeClose
(
uv_handle_t
*
handle
);
conn
->
session
->
udfUvPipe
=
NULL
;
int32_t
udfcGetUdfTaskResultFromUvTask
(
SClientUdfTask
*
task
,
SClientUvTaskNode
*
uvTask
);
taosMemoryFree
(
conn
->
readBuf
.
buf
);
void
udfcAllocateBuffer
(
uv_handle_t
*
handle
,
size_t
suggestedSize
,
uv_buf_t
*
buf
);
taosMemoryFree
(
conn
);
bool
isUdfcUvMsgComplete
(
SClientConnBuf
*
connBuf
);
taosMemoryFree
((
uv_pipe_t
*
)
handle
);
void
udfcUvHandleRsp
(
SClientUvConn
*
conn
);
}
void
udfcUvHandleError
(
SClientUvConn
*
conn
);
void
onUdfcPipeRead
(
uv_stream_t
*
client
,
ssize_t
nread
,
const
uv_buf_t
*
buf
);
int32_t
udfcGetUdfTaskResultFromUvTask
(
SClientUdfTask
*
task
,
SClientUvTaskNode
*
uvTask
)
{
void
onUdfcPipetWrite
(
uv_write_t
*
write
,
int
status
);
fnDebug
(
"udfc get uv task result. task: %p, uvTask: %p"
,
task
,
uvTask
);
void
onUdfcPipeConnect
(
uv_connect_t
*
connect
,
int
status
);
if
(
uvTask
->
type
==
UV_TASK_REQ_RSP
)
{
int32_t
udfcCreateUvTask
(
SClientUdfTask
*
task
,
int8_t
uvTaskType
,
SClientUvTaskNode
**
pUvTask
);
if
(
uvTask
->
rspBuf
.
base
!=
NULL
)
{
int32_t
udfcQueueUvTask
(
SClientUvTaskNode
*
uvTask
);
SUdfResponse
rsp
=
{
0
};
int32_t
udfcStartUvTask
(
SClientUvTaskNode
*
uvTask
);
void
*
buf
=
decodeUdfResponse
(
uvTask
->
rspBuf
.
base
,
&
rsp
);
void
udfcAsyncTaskCb
(
uv_async_t
*
async
);
assert
(
uvTask
->
rspBuf
.
len
==
POINTER_DISTANCE
(
buf
,
uvTask
->
rspBuf
.
base
));
void
cleanUpUvTasks
(
SUdfcProxy
*
udfc
);
task
->
errCode
=
rsp
.
code
;
void
udfStopAsyncCb
(
uv_async_t
*
async
);
void
constructUdfService
(
void
*
argsThread
);
int32_t
udfcRunUdfUvTask
(
SClientUdfTask
*
task
,
int8_t
uvTaskType
);
int32_t
doSetupUdf
(
char
udfName
[],
UdfcFuncHandle
*
funcHandle
);
int
compareUdfcFuncSub
(
const
void
*
elem1
,
const
void
*
elem2
);
int32_t
doTeardownUdf
(
UdfcFuncHandle
handle
);
switch
(
task
->
type
)
{
int32_t
callUdf
(
UdfcFuncHandle
handle
,
int8_t
callType
,
SSDataBlock
*
input
,
SUdfInterBuf
*
state
,
SUdfInterBuf
*
state2
,
case
UDF_TASK_SETUP
:
{
SSDataBlock
*
output
,
SUdfInterBuf
*
newState
);
//TODO: copy or not
int32_t
doCallUdfAggInit
(
UdfcFuncHandle
handle
,
SUdfInterBuf
*
interBuf
);
task
->
_setup
.
rsp
=
rsp
.
setupRsp
;
int32_t
doCallUdfAggProcess
(
UdfcFuncHandle
handle
,
SSDataBlock
*
block
,
SUdfInterBuf
*
state
,
SUdfInterBuf
*
newState
)
;
break
;
int32_t
doCallUdfAggMerge
(
UdfcFuncHandle
handle
,
SUdfInterBuf
*
interBuf1
,
SUdfInterBuf
*
interBuf2
,
SUdfInterBuf
*
resultBuf
)
;
}
int32_t
doCallUdfAggFinalize
(
UdfcFuncHandle
handle
,
SUdfInterBuf
*
interBuf
,
SUdfInterBuf
*
resultData
);
case
UDF_TASK_CALL
:
{
int32_t
doCallUdfScalarFunc
(
UdfcFuncHandle
handle
,
SScalarParam
*
input
,
int32_t
numOfCols
,
SScalarParam
*
output
);
task
->
_call
.
rsp
=
rsp
.
callRsp
;
int32_t
callUdfScalarFunc
(
char
*
udfName
,
SScalarParam
*
input
,
int32_t
numOfCols
,
SScalarParam
*
output
)
;
//TODO: copy or not
break
;
int32_t
udfcOpen
()
;
}
int32_t
udfcClose
();
case
UDF_TASK_TEARDOWN
:
{
task
->
_teardown
.
rsp
=
rsp
.
teardownRsp
;
int32_t
acquireUdfFuncHandle
(
char
*
udfName
,
UdfcFuncHandle
*
pHandle
)
;
//TODO: copy or not?
void
releaseUdfFuncHandle
(
char
*
udfName
);
break
;
int32_t
cleanUpUdfs
()
;
}
default:
{
bool
udfAggGetEnv
(
struct
SFunctionNode
*
pFunc
,
SFuncExecEnv
*
pEnv
);
break
;
bool
udfAggInit
(
struct
SqlFunctionCtx
*
pCtx
,
struct
SResultRowEntryInfo
*
pResultCellInfo
)
;
}
int32_t
udfAggProcess
(
struct
SqlFunctionCtx
*
pCtx
);
}
int32_t
udfAggFinalize
(
struct
SqlFunctionCtx
*
pCtx
,
SSDataBlock
*
pBlock
);
// TODO: the call buffer is setup and freed by udf invocation
int
compareUdfcFuncSub
(
const
void
*
elem1
,
const
void
*
elem2
)
{
taosMemoryFree
(
uvTask
->
rspBuf
.
base
);
SUdfcFuncStub
*
stub1
=
(
SUdfcFuncStub
*
)
elem1
;
}
else
{
SUdfcFuncStub
*
stub2
=
(
SUdfcFuncStub
*
)
elem2
;
task
->
errCode
=
uvTask
->
errCode
;
return
strcmp
(
stub1
->
udfName
,
stub2
->
udfName
);
}
}
else
if
(
uvTask
->
type
==
UV_TASK_CONNECT
)
{
task
->
errCode
=
uvTask
->
errCode
;
}
else
if
(
uvTask
->
type
==
UV_TASK_DISCONNECT
)
{
task
->
errCode
=
uvTask
->
errCode
;
}
return
0
;
}
}
void
udfcAllocateBuffer
(
uv_handle_t
*
handle
,
size_t
suggestedSize
,
uv_buf_t
*
buf
)
{
int32_t
acquireUdfFuncHandle
(
char
*
udfName
,
UdfcFuncHandle
*
pHandle
)
{
SClientUvConn
*
conn
=
handle
->
data
;
int32_t
code
=
0
;
SClientConnBuf
*
connBuf
=
&
conn
->
readBuf
;
uv_mutex_lock
(
&
gUdfdProxy
.
udfStubsMutex
);
SUdfcFuncStub
key
=
{
0
};
int32_t
msgHeadSize
=
sizeof
(
int32_t
)
+
sizeof
(
int64_t
);
strcpy
(
key
.
udfName
,
udfName
);
if
(
connBuf
->
cap
==
0
)
{
int32_t
stubIndex
=
taosArraySearchIdx
(
gUdfdProxy
.
udfStubs
,
&
key
,
compareUdfcFuncSub
,
TD_EQ
);
connBuf
->
buf
=
taosMemoryMalloc
(
msgHeadSize
);
if
(
stubIndex
!=
-
1
)
{
if
(
connBuf
->
buf
)
{
SUdfcFuncStub
*
foundStub
=
taosArrayGet
(
gUdfdProxy
.
udfStubs
,
stubIndex
);
connBuf
->
len
=
0
;
UdfcFuncHandle
handle
=
foundStub
->
handle
;
connBuf
->
cap
=
msgHeadSize
;
if
(
handle
!=
NULL
&&
((
SUdfcUvSession
*
)
handle
)
->
udfUvPipe
!=
NULL
)
{
connBuf
->
total
=
-
1
;
*
pHandle
=
foundStub
->
handle
;
++
foundStub
->
refCount
;
buf
->
base
=
connBuf
->
buf
;
foundStub
->
lastRefTime
=
taosGetTimestampUs
();
buf
->
len
=
connBuf
->
cap
;
uv_mutex_unlock
(
&
gUdfdProxy
.
udfStubsMutex
);
return
0
;
}
else
{
}
else
{
fn
Error
(
"udfc allocate buffer failure. size: %d"
,
msgHeadSize
);
fn
Info
(
"invalid handle for %s, refCount: %d, last ref time: %"
PRId64
". remove it from cache"
,
buf
->
base
=
NULL
;
udfName
,
foundStub
->
refCount
,
foundStub
->
lastRefTime
)
;
buf
->
len
=
0
;
taosArrayRemove
(
gUdfdProxy
.
udfStubs
,
stubIndex
)
;
}
}
}
*
pHandle
=
NULL
;
code
=
doSetupUdf
(
udfName
,
pHandle
);
if
(
code
==
TSDB_CODE_SUCCESS
)
{
SUdfcFuncStub
stub
=
{
0
};
strcpy
(
stub
.
udfName
,
udfName
);
stub
.
handle
=
*
pHandle
;
++
stub
.
refCount
;
stub
.
lastRefTime
=
taosGetTimestampUs
();
taosArrayPush
(
gUdfdProxy
.
udfStubs
,
&
stub
);
taosArraySort
(
gUdfdProxy
.
udfStubs
,
compareUdfcFuncSub
);
}
else
{
}
else
{
connBuf
->
cap
=
connBuf
->
total
>
connBuf
->
cap
?
connBuf
->
total
:
connBuf
->
cap
;
*
pHandle
=
NULL
;
void
*
resultBuf
=
taosMemoryRealloc
(
connBuf
->
buf
,
connBuf
->
cap
);
if
(
resultBuf
)
{
connBuf
->
buf
=
resultBuf
;
buf
->
base
=
connBuf
->
buf
+
connBuf
->
len
;
buf
->
len
=
connBuf
->
cap
-
connBuf
->
len
;
}
else
{
fnError
(
"udfc re-allocate buffer failure. size: %d"
,
connBuf
->
cap
);
buf
->
base
=
NULL
;
buf
->
len
=
0
;
}
}
}
fnTrace
(
"conn buf cap - len - total : %d - %d - %d"
,
connBuf
->
cap
,
connBuf
->
len
,
connBuf
->
total
);
uv_mutex_unlock
(
&
gUdfdProxy
.
udfStubsMutex
);
return
code
;
}
}
bool
isUdfcUvMsgComplete
(
SClientConnBuf
*
connBuf
)
{
void
releaseUdfFuncHandle
(
char
*
udfName
)
{
if
(
connBuf
->
total
==
-
1
&&
connBuf
->
len
>=
sizeof
(
int32_t
))
{
uv_mutex_lock
(
&
gUdfdProxy
.
udfStubsMutex
);
connBuf
->
total
=
*
(
int32_t
*
)
(
connBuf
->
buf
);
SUdfcFuncStub
key
=
{
0
};
strcpy
(
key
.
udfName
,
udfName
);
SUdfcFuncStub
*
foundStub
=
taosArraySearch
(
gUdfdProxy
.
udfStubs
,
&
key
,
compareUdfcFuncSub
,
TD_EQ
);
if
(
!
foundStub
)
{
return
;
}
}
if
(
connBuf
->
len
==
connBuf
->
cap
&&
connBuf
->
total
==
connBuf
->
cap
)
{
if
(
foundStub
->
refCount
>
0
)
{
fnTrace
(
"udfc complete message is received, now handle it"
);
--
foundStub
->
refCount
;
return
true
;
}
}
return
false
;
uv_mutex_unlock
(
&
gUdfdProxy
.
udfStubsMutex
)
;
}
}
void
udfcUvHandleRsp
(
SClientUvConn
*
conn
)
{
int32_t
cleanUpUdfs
()
{
SClientConnBuf
*
connBuf
=
&
conn
->
readBuf
;
uv_mutex_lock
(
&
gUdfdProxy
.
udfStubsMutex
);
int64_t
seqNum
=
*
(
int64_t
*
)
(
connBuf
->
buf
+
sizeof
(
int32_t
));
// msglen then seqnum
int32_t
i
=
0
;
SArray
*
udfStubs
=
taosArrayInit
(
16
,
sizeof
(
SUdfcFuncStub
));
if
(
QUEUE_EMPTY
(
&
conn
->
taskQueue
))
{
while
(
i
<
taosArrayGetSize
(
gUdfdProxy
.
udfStubs
))
{
fnError
(
"udfc no task waiting for response on connection"
);
SUdfcFuncStub
*
stub
=
taosArrayGet
(
gUdfdProxy
.
udfStubs
,
i
);
return
;
if
(
stub
->
refCount
==
0
)
{
}
fnInfo
(
"tear down udf. udf name: %s, handle: %p, ref count: %d"
,
stub
->
udfName
,
stub
->
handle
,
stub
->
refCount
);
bool
found
=
false
;
doTeardownUdf
(
stub
->
handle
);
SClientUvTaskNode
*
taskFound
=
NULL
;
}
else
{
QUEUE
*
h
=
QUEUE_NEXT
(
&
conn
->
taskQueue
);
fnInfo
(
"udf still in use. udf name: %s, ref count: %d, last ref time: %"
PRId64
", handle: %p"
,
SClientUvTaskNode
*
task
=
QUEUE_DATA
(
h
,
SClientUvTaskNode
,
connTaskQueue
);
stub
->
udfName
,
stub
->
refCount
,
stub
->
lastRefTime
,
stub
->
handle
);
UdfcFuncHandle
handle
=
stub
->
handle
;
while
(
h
!=
&
conn
->
taskQueue
)
{
if
(
handle
!=
NULL
&&
((
SUdfcUvSession
*
)
handle
)
->
udfUvPipe
!=
NULL
)
{
if
(
task
->
seqNum
==
seqNum
)
{
taosArrayPush
(
udfStubs
,
stub
);
if
(
found
==
false
)
{
found
=
true
;
taskFound
=
task
;
}
else
{
}
else
{
fn
Error
(
"udfc more than one task waiting for the same response"
);
fn
Info
(
"udf invalid handle for %s, refCount: %d, last ref time: %"
PRId64
". remove it from cache"
,
continue
;
stub
->
udfName
,
stub
->
refCount
,
stub
->
lastRefTime
)
;
}
}
}
}
h
=
QUEUE_NEXT
(
h
);
++
i
;
task
=
QUEUE_DATA
(
h
,
SClientUvTaskNode
,
connTaskQueue
);
}
}
taosArrayDestroy
(
gUdfdProxy
.
udfStubs
);
gUdfdProxy
.
udfStubs
=
udfStubs
;
uv_mutex_unlock
(
&
gUdfdProxy
.
udfStubsMutex
);
return
0
;
}
if
(
taskFound
)
{
int32_t
callUdfScalarFunc
(
char
*
udfName
,
SScalarParam
*
input
,
int32_t
numOfCols
,
SScalarParam
*
output
)
{
taskFound
->
rspBuf
=
uv_buf_init
(
connBuf
->
buf
,
connBuf
->
len
);
UdfcFuncHandle
handle
=
NULL
;
QUEUE_REMOVE
(
&
taskFound
->
connTaskQueue
);
int32_t
code
=
acquireUdfFuncHandle
(
udfName
,
&
handle
);
QUEUE_REMOVE
(
&
taskFound
->
procTaskQueue
);
if
(
code
!=
0
)
{
uv_sem_post
(
&
taskFound
->
taskSem
);
return
code
;
}
SUdfcUvSession
*
session
=
handle
;
code
=
doCallUdfScalarFunc
(
handle
,
input
,
numOfCols
,
output
);
if
(
output
->
columnData
==
NULL
)
{
fnError
(
"udfc scalar function calculate error. no column data"
);
code
=
TSDB_CODE_UDF_INVALID_OUTPUT_TYPE
;
}
else
{
}
else
{
fnError
(
"no task is waiting for the response."
);
if
(
session
->
outputType
!=
output
->
columnData
->
info
.
type
||
session
->
outputLen
!=
output
->
columnData
->
info
.
bytes
)
{
fnError
(
"udfc scalar function calculate error. type mismatch. session type: %d(%d), output type: %d(%d)"
,
session
->
outputType
,
session
->
outputLen
,
output
->
columnData
->
info
.
type
,
output
->
columnData
->
info
.
bytes
);
code
=
TSDB_CODE_UDF_INVALID_OUTPUT_TYPE
;
}
}
}
connBuf
->
buf
=
NULL
;
releaseUdfFuncHandle
(
udfName
);
connBuf
->
total
=
-
1
;
return
code
;
connBuf
->
len
=
0
;
connBuf
->
cap
=
0
;
}
}
void
udfcUvHandleError
(
SClientUvConn
*
conn
)
{
bool
udfAggGetEnv
(
struct
SFunctionNode
*
pFunc
,
SFuncExecEnv
*
pEnv
)
{
while
(
!
QUEUE_EMPTY
(
&
conn
->
taskQueue
))
{
if
(
fmIsScalarFunc
(
pFunc
->
funcId
))
{
QUEUE
*
h
=
QUEUE_HEAD
(
&
conn
->
taskQueue
);
return
false
;
SClientUvTaskNode
*
task
=
QUEUE_DATA
(
h
,
SClientUvTaskNode
,
connTaskQueue
);
task
->
errCode
=
TSDB_CODE_UDF_PIPE_READ_ERR
;
QUEUE_REMOVE
(
&
task
->
connTaskQueue
);
QUEUE_REMOVE
(
&
task
->
procTaskQueue
);
uv_sem_post
(
&
task
->
taskSem
);
}
}
pEnv
->
calcMemSize
=
sizeof
(
SUdfAggRes
)
+
pFunc
->
node
.
resType
.
bytes
+
pFunc
->
udfBufSize
;
uv_close
((
uv_handle_t
*
)
conn
->
pipe
,
onUdfcPipeClose
)
;
return
true
;
}
}
void
onUdfcPipeRead
(
uv_stream_t
*
client
,
ssize_t
nread
,
const
uv_buf_t
*
buf
)
{
bool
udfAggInit
(
struct
SqlFunctionCtx
*
pCtx
,
struct
SResultRowEntryInfo
*
pResultCellInfo
)
{
fnTrace
(
"udfc client %p, client read from pipe. nread: %zd"
,
client
,
nread
);
if
(
functionSetup
(
pCtx
,
pResultCellInfo
)
!=
true
)
{
if
(
nread
==
0
)
return
;
return
false
;
}
SClientUvConn
*
conn
=
client
->
data
;
UdfcFuncHandle
handle
;
SClientConnBuf
*
connBuf
=
&
conn
->
readBuf
;
int32_t
udfCode
=
0
;
if
(
nread
>
0
)
{
if
((
udfCode
=
acquireUdfFuncHandle
((
char
*
)
pCtx
->
udfName
,
&
handle
))
!=
0
)
{
connBuf
->
len
+=
nread
;
fnError
(
"udfAggInit error. step doSetupUdf. udf code: %d"
,
udfCode
);
if
(
isUdfcUvMsgComplete
(
connBuf
))
{
return
false
;
udfcUvHandleRsp
(
conn
);
}
}
SUdfcUvSession
*
session
=
(
SUdfcUvSession
*
)
handle
;
SUdfAggRes
*
udfRes
=
(
SUdfAggRes
*
)
GET_ROWCELL_INTERBUF
(
pResultCellInfo
);
}
int32_t
envSize
=
sizeof
(
SUdfAggRes
)
+
session
->
outputLen
+
session
->
bufSize
;
if
(
nread
<
0
)
{
memset
(
udfRes
,
0
,
envSize
);
fnError
(
"udfc client pipe %p read error: %zd, %s."
,
client
,
nread
,
uv_strerror
(
nread
));
if
(
nread
==
UV_EOF
)
{
udfRes
->
finalResBuf
=
(
char
*
)
udfRes
+
sizeof
(
SUdfAggRes
);
fnError
(
"
\t
udfc client pipe %p closed"
,
client
);
udfRes
->
interResBuf
=
(
char
*
)
udfRes
+
sizeof
(
SUdfAggRes
)
+
session
->
outputLen
;
}
udfcUvHandleError
(
conn
);
SUdfInterBuf
buf
=
{
0
};
if
((
udfCode
=
doCallUdfAggInit
(
handle
,
&
buf
))
!=
0
)
{
fnError
(
"udfAggInit error. step doCallUdfAggInit. udf code: %d"
,
udfCode
);
releaseUdfFuncHandle
(
pCtx
->
udfName
);
return
false
;
}
udfRes
->
interResNum
=
buf
.
numOfResult
;
if
(
buf
.
bufLen
<=
session
->
bufSize
)
{
memcpy
(
udfRes
->
interResBuf
,
buf
.
buf
,
buf
.
bufLen
);
}
else
{
fnError
(
"udfc inter buf size %d is greater than function bufSize %d"
,
buf
.
bufLen
,
session
->
bufSize
);
releaseUdfFuncHandle
(
pCtx
->
udfName
);
return
false
;
}
releaseUdfFuncHandle
(
pCtx
->
udfName
);
freeUdfInterBuf
(
&
buf
);
return
true
;
}
int32_t
udfAggProcess
(
struct
SqlFunctionCtx
*
pCtx
)
{
int32_t
udfCode
=
0
;
UdfcFuncHandle
handle
=
0
;
if
((
udfCode
=
acquireUdfFuncHandle
((
char
*
)
pCtx
->
udfName
,
&
handle
))
!=
0
)
{
fnError
(
"udfAggProcess error. step acquireUdfFuncHandle. udf code: %d"
,
udfCode
);
return
udfCode
;
}
SUdfcUvSession
*
session
=
handle
;
SUdfAggRes
*
udfRes
=
(
SUdfAggRes
*
)
GET_ROWCELL_INTERBUF
(
GET_RES_INFO
(
pCtx
));
udfRes
->
finalResBuf
=
(
char
*
)
udfRes
+
sizeof
(
SUdfAggRes
);
udfRes
->
interResBuf
=
(
char
*
)
udfRes
+
sizeof
(
SUdfAggRes
)
+
session
->
outputLen
;
SInputColumnInfoData
*
pInput
=
&
pCtx
->
input
;
int32_t
numOfCols
=
pInput
->
numOfInputCols
;
int32_t
start
=
pInput
->
startRowIndex
;
int32_t
numOfRows
=
pInput
->
numOfRows
;
SSDataBlock
tempBlock
=
{
0
};
tempBlock
.
info
.
numOfCols
=
numOfCols
;
tempBlock
.
info
.
rows
=
pInput
->
totalRows
;
tempBlock
.
info
.
uid
=
pInput
->
uid
;
bool
hasVarCol
=
false
;
tempBlock
.
pDataBlock
=
taosArrayInit
(
numOfCols
,
sizeof
(
SColumnInfoData
));
for
(
int32_t
i
=
0
;
i
<
numOfCols
;
++
i
)
{
SColumnInfoData
*
col
=
pInput
->
pData
[
i
];
if
(
IS_VAR_DATA_TYPE
(
col
->
info
.
type
))
{
hasVarCol
=
true
;
}
taosArrayPush
(
tempBlock
.
pDataBlock
,
col
);
}
tempBlock
.
info
.
hasVarCol
=
hasVarCol
;
SSDataBlock
*
inputBlock
=
blockDataExtractBlock
(
&
tempBlock
,
start
,
numOfRows
);
SUdfInterBuf
state
=
{.
buf
=
udfRes
->
interResBuf
,
.
bufLen
=
session
->
bufSize
,
.
numOfResult
=
udfRes
->
interResNum
};
SUdfInterBuf
newState
=
{
0
};
udfCode
=
doCallUdfAggProcess
(
session
,
inputBlock
,
&
state
,
&
newState
);
if
(
udfCode
!=
0
)
{
fnError
(
"udfAggProcess error. code: %d"
,
udfCode
);
newState
.
numOfResult
=
0
;
}
else
{
udfRes
->
interResNum
=
newState
.
numOfResult
;
if
(
newState
.
bufLen
<=
session
->
bufSize
)
{
memcpy
(
udfRes
->
interResBuf
,
newState
.
buf
,
newState
.
bufLen
);
}
else
{
fnError
(
"udfc inter buf size %d is greater than function bufSize %d"
,
newState
.
bufLen
,
session
->
bufSize
);
udfCode
=
TSDB_CODE_UDF_INVALID_BUFSIZE
;
}
}
if
(
newState
.
numOfResult
==
1
||
state
.
numOfResult
==
1
)
{
GET_RES_INFO
(
pCtx
)
->
numOfRes
=
1
;
}
blockDataDestroy
(
inputBlock
);
taosArrayDestroy
(
tempBlock
.
pDataBlock
);
releaseUdfFuncHandle
(
pCtx
->
udfName
);
freeUdfInterBuf
(
&
newState
);
return
udfCode
;
}
int32_t
udfAggFinalize
(
struct
SqlFunctionCtx
*
pCtx
,
SSDataBlock
*
pBlock
)
{
int32_t
udfCode
=
0
;
UdfcFuncHandle
handle
=
0
;
if
((
udfCode
=
acquireUdfFuncHandle
((
char
*
)
pCtx
->
udfName
,
&
handle
))
!=
0
)
{
fnError
(
"udfAggProcess error. step acquireUdfFuncHandle. udf code: %d"
,
udfCode
);
return
udfCode
;
}
SUdfcUvSession
*
session
=
handle
;
SUdfAggRes
*
udfRes
=
(
SUdfAggRes
*
)
GET_ROWCELL_INTERBUF
(
GET_RES_INFO
(
pCtx
));
udfRes
->
finalResBuf
=
(
char
*
)
udfRes
+
sizeof
(
SUdfAggRes
);
udfRes
->
interResBuf
=
(
char
*
)
udfRes
+
sizeof
(
SUdfAggRes
)
+
session
->
outputLen
;
SUdfInterBuf
resultBuf
=
{
0
};
SUdfInterBuf
state
=
{.
buf
=
udfRes
->
interResBuf
,
.
bufLen
=
session
->
bufSize
,
.
numOfResult
=
udfRes
->
interResNum
};
int32_t
udfCallCode
=
0
;
udfCallCode
=
doCallUdfAggFinalize
(
session
,
&
state
,
&
resultBuf
);
if
(
udfCallCode
!=
0
)
{
fnError
(
"udfAggFinalize error. doCallUdfAggFinalize step. udf code:%d"
,
udfCallCode
);
GET_RES_INFO
(
pCtx
)
->
numOfRes
=
0
;
}
else
{
if
(
resultBuf
.
bufLen
<=
session
->
outputLen
)
{
memcpy
(
udfRes
->
finalResBuf
,
resultBuf
.
buf
,
session
->
outputLen
);
udfRes
->
finalResNum
=
resultBuf
.
numOfResult
;
GET_RES_INFO
(
pCtx
)
->
numOfRes
=
udfRes
->
finalResNum
;
}
else
{
fnError
(
"udfc inter buf size %d is greater than function output size %d"
,
resultBuf
.
bufLen
,
session
->
outputLen
);
GET_RES_INFO
(
pCtx
)
->
numOfRes
=
0
;
udfCallCode
=
TSDB_CODE_UDF_INVALID_OUTPUT_TYPE
;
}
}
freeUdfInterBuf
(
&
resultBuf
);
int32_t
numOfResults
=
functionFinalizeWithResultBuf
(
pCtx
,
pBlock
,
udfRes
->
finalResBuf
);
releaseUdfFuncHandle
(
pCtx
->
udfName
);
return
udfCallCode
==
0
?
numOfResults
:
udfCallCode
;
}
void
onUdfcPipeClose
(
uv_handle_t
*
handle
)
{
SClientUvConn
*
conn
=
handle
->
data
;
if
(
!
QUEUE_EMPTY
(
&
conn
->
taskQueue
))
{
QUEUE
*
h
=
QUEUE_HEAD
(
&
conn
->
taskQueue
);
SClientUvTaskNode
*
task
=
QUEUE_DATA
(
h
,
SClientUvTaskNode
,
connTaskQueue
);
task
->
errCode
=
0
;
QUEUE_REMOVE
(
&
task
->
procTaskQueue
);
uv_sem_post
(
&
task
->
taskSem
);
}
conn
->
session
->
udfUvPipe
=
NULL
;
taosMemoryFree
(
conn
->
readBuf
.
buf
);
taosMemoryFree
(
conn
);
taosMemoryFree
((
uv_pipe_t
*
)
handle
);
}
int32_t
udfcGetUdfTaskResultFromUvTask
(
SClientUdfTask
*
task
,
SClientUvTaskNode
*
uvTask
)
{
fnDebug
(
"udfc get uv task result. task: %p, uvTask: %p"
,
task
,
uvTask
);
if
(
uvTask
->
type
==
UV_TASK_REQ_RSP
)
{
if
(
uvTask
->
rspBuf
.
base
!=
NULL
)
{
SUdfResponse
rsp
=
{
0
};
void
*
buf
=
decodeUdfResponse
(
uvTask
->
rspBuf
.
base
,
&
rsp
);
assert
(
uvTask
->
rspBuf
.
len
==
POINTER_DISTANCE
(
buf
,
uvTask
->
rspBuf
.
base
));
task
->
errCode
=
rsp
.
code
;
switch
(
task
->
type
)
{
case
UDF_TASK_SETUP
:
{
//TODO: copy or not
task
->
_setup
.
rsp
=
rsp
.
setupRsp
;
break
;
}
case
UDF_TASK_CALL
:
{
task
->
_call
.
rsp
=
rsp
.
callRsp
;
//TODO: copy or not
break
;
}
case
UDF_TASK_TEARDOWN
:
{
task
->
_teardown
.
rsp
=
rsp
.
teardownRsp
;
//TODO: copy or not?
break
;
}
default:
{
break
;
}
}
// TODO: the call buffer is setup and freed by udf invocation
taosMemoryFree
(
uvTask
->
rspBuf
.
base
);
}
else
{
task
->
errCode
=
uvTask
->
errCode
;
}
}
else
if
(
uvTask
->
type
==
UV_TASK_CONNECT
)
{
task
->
errCode
=
uvTask
->
errCode
;
}
else
if
(
uvTask
->
type
==
UV_TASK_DISCONNECT
)
{
task
->
errCode
=
uvTask
->
errCode
;
}
return
0
;
}
void
udfcAllocateBuffer
(
uv_handle_t
*
handle
,
size_t
suggestedSize
,
uv_buf_t
*
buf
)
{
SClientUvConn
*
conn
=
handle
->
data
;
SClientConnBuf
*
connBuf
=
&
conn
->
readBuf
;
int32_t
msgHeadSize
=
sizeof
(
int32_t
)
+
sizeof
(
int64_t
);
if
(
connBuf
->
cap
==
0
)
{
connBuf
->
buf
=
taosMemoryMalloc
(
msgHeadSize
);
if
(
connBuf
->
buf
)
{
connBuf
->
len
=
0
;
connBuf
->
cap
=
msgHeadSize
;
connBuf
->
total
=
-
1
;
buf
->
base
=
connBuf
->
buf
;
buf
->
len
=
connBuf
->
cap
;
}
else
{
fnError
(
"udfc allocate buffer failure. size: %d"
,
msgHeadSize
);
buf
->
base
=
NULL
;
buf
->
len
=
0
;
}
}
else
{
connBuf
->
cap
=
connBuf
->
total
>
connBuf
->
cap
?
connBuf
->
total
:
connBuf
->
cap
;
void
*
resultBuf
=
taosMemoryRealloc
(
connBuf
->
buf
,
connBuf
->
cap
);
if
(
resultBuf
)
{
connBuf
->
buf
=
resultBuf
;
buf
->
base
=
connBuf
->
buf
+
connBuf
->
len
;
buf
->
len
=
connBuf
->
cap
-
connBuf
->
len
;
}
else
{
fnError
(
"udfc re-allocate buffer failure. size: %d"
,
connBuf
->
cap
);
buf
->
base
=
NULL
;
buf
->
len
=
0
;
}
}
fnTrace
(
"conn buf cap - len - total : %d - %d - %d"
,
connBuf
->
cap
,
connBuf
->
len
,
connBuf
->
total
);
}
bool
isUdfcUvMsgComplete
(
SClientConnBuf
*
connBuf
)
{
if
(
connBuf
->
total
==
-
1
&&
connBuf
->
len
>=
sizeof
(
int32_t
))
{
connBuf
->
total
=
*
(
int32_t
*
)
(
connBuf
->
buf
);
}
if
(
connBuf
->
len
==
connBuf
->
cap
&&
connBuf
->
total
==
connBuf
->
cap
)
{
fnTrace
(
"udfc complete message is received, now handle it"
);
return
true
;
}
return
false
;
}
void
udfcUvHandleRsp
(
SClientUvConn
*
conn
)
{
SClientConnBuf
*
connBuf
=
&
conn
->
readBuf
;
int64_t
seqNum
=
*
(
int64_t
*
)
(
connBuf
->
buf
+
sizeof
(
int32_t
));
// msglen then seqnum
if
(
QUEUE_EMPTY
(
&
conn
->
taskQueue
))
{
fnError
(
"udfc no task waiting for response on connection"
);
return
;
}
bool
found
=
false
;
SClientUvTaskNode
*
taskFound
=
NULL
;
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
;
taskFound
=
task
;
}
else
{
fnError
(
"udfc more than one task waiting for the same response"
);
continue
;
}
}
h
=
QUEUE_NEXT
(
h
);
task
=
QUEUE_DATA
(
h
,
SClientUvTaskNode
,
connTaskQueue
);
}
if
(
taskFound
)
{
taskFound
->
rspBuf
=
uv_buf_init
(
connBuf
->
buf
,
connBuf
->
len
);
QUEUE_REMOVE
(
&
taskFound
->
connTaskQueue
);
QUEUE_REMOVE
(
&
taskFound
->
procTaskQueue
);
uv_sem_post
(
&
taskFound
->
taskSem
);
}
else
{
fnError
(
"no task is waiting for the response."
);
}
connBuf
->
buf
=
NULL
;
connBuf
->
total
=
-
1
;
connBuf
->
len
=
0
;
connBuf
->
cap
=
0
;
}
void
udfcUvHandleError
(
SClientUvConn
*
conn
)
{
while
(
!
QUEUE_EMPTY
(
&
conn
->
taskQueue
))
{
QUEUE
*
h
=
QUEUE_HEAD
(
&
conn
->
taskQueue
);
SClientUvTaskNode
*
task
=
QUEUE_DATA
(
h
,
SClientUvTaskNode
,
connTaskQueue
);
task
->
errCode
=
TSDB_CODE_UDF_PIPE_READ_ERR
;
QUEUE_REMOVE
(
&
task
->
connTaskQueue
);
QUEUE_REMOVE
(
&
task
->
procTaskQueue
);
uv_sem_post
(
&
task
->
taskSem
);
}
uv_close
((
uv_handle_t
*
)
conn
->
pipe
,
onUdfcPipeClose
);
}
void
onUdfcPipeRead
(
uv_stream_t
*
client
,
ssize_t
nread
,
const
uv_buf_t
*
buf
)
{
fnTrace
(
"udfc client %p, client read from pipe. nread: %zd"
,
client
,
nread
);
if
(
nread
==
0
)
return
;
SClientUvConn
*
conn
=
client
->
data
;
SClientConnBuf
*
connBuf
=
&
conn
->
readBuf
;
if
(
nread
>
0
)
{
connBuf
->
len
+=
nread
;
if
(
isUdfcUvMsgComplete
(
connBuf
))
{
udfcUvHandleRsp
(
conn
);
}
}
if
(
nread
<
0
)
{
fnError
(
"udfc client pipe %p read error: %zd, %s."
,
client
,
nread
,
uv_strerror
(
nread
));
if
(
nread
==
UV_EOF
)
{
fnError
(
"
\t
udfc client pipe %p closed"
,
client
);
}
udfcUvHandleError
(
conn
);
}
}
}
}
...
@@ -1271,134 +1619,47 @@ int32_t udfcRunUdfUvTask(SClientUdfTask *task, int8_t uvTaskType) {
...
@@ -1271,134 +1619,47 @@ int32_t udfcRunUdfUvTask(SClientUdfTask *task, int8_t uvTaskType) {
SClientUvConn
*
conn
=
uvTask
->
pipe
->
data
;
SClientUvConn
*
conn
=
uvTask
->
pipe
->
data
;
conn
->
session
=
task
->
session
;
conn
->
session
=
task
->
session
;
}
}
taosMemoryFree
(
uvTask
);
taosMemoryFree
(
uvTask
);
uvTask
=
NULL
;
uvTask
=
NULL
;
return
task
->
errCode
;
return
task
->
errCode
;
}
int32_t
doSetupUdf
(
char
udfName
[],
UdfcFuncHandle
*
funcHandle
)
{
if
(
gUdfdProxy
.
udfcState
!=
UDFC_STATE_READY
)
{
return
TSDB_CODE_UDF_INVALID_STATE
;
}
SClientUdfTask
*
task
=
taosMemoryCalloc
(
1
,
sizeof
(
SClientUdfTask
));
task
->
errCode
=
0
;
task
->
session
=
taosMemoryCalloc
(
1
,
sizeof
(
SUdfcUvSession
));
task
->
session
->
udfc
=
&
gUdfdProxy
;
task
->
type
=
UDF_TASK_SETUP
;
SUdfSetupRequest
*
req
=
&
task
->
_setup
.
req
;
strncpy
(
req
->
udfName
,
udfName
,
TSDB_FUNC_NAME_LEN
);
int32_t
errCode
=
udfcRunUdfUvTask
(
task
,
UV_TASK_CONNECT
);
if
(
errCode
!=
0
)
{
fnError
(
"failed to connect to pipe. udfName: %s, pipe: %s"
,
udfName
,
(
&
gUdfdProxy
)
->
udfdPipeName
);
return
TSDB_CODE_UDF_PIPE_CONNECT_ERR
;
}
udfcRunUdfUvTask
(
task
,
UV_TASK_REQ_RSP
);
SUdfSetupResponse
*
rsp
=
&
task
->
_setup
.
rsp
;
task
->
session
->
severHandle
=
rsp
->
udfHandle
;
task
->
session
->
outputType
=
rsp
->
outputType
;
task
->
session
->
outputLen
=
rsp
->
outputLen
;
task
->
session
->
bufSize
=
rsp
->
bufSize
;
strcpy
(
task
->
session
->
udfName
,
udfName
);
if
(
task
->
errCode
!=
0
)
{
fnError
(
"failed to setup udf. udfname: %s, err: %d"
,
udfName
,
task
->
errCode
)
}
else
{
fnInfo
(
"sucessfully setup udf func handle. udfName: %s, handle: %p"
,
udfName
,
task
->
session
);
*
funcHandle
=
task
->
session
;
}
int32_t
err
=
task
->
errCode
;
taosMemoryFree
(
task
);
return
err
;
}
int
compareUdfcFuncSub
(
const
void
*
elem1
,
const
void
*
elem2
)
{
SUdfcFuncStub
*
stub1
=
(
SUdfcFuncStub
*
)
elem1
;
SUdfcFuncStub
*
stub2
=
(
SUdfcFuncStub
*
)
elem2
;
return
strcmp
(
stub1
->
udfName
,
stub2
->
udfName
);
}
int32_t
acquireUdfFuncHandle
(
char
*
udfName
,
UdfcFuncHandle
*
pHandle
)
{
int32_t
code
=
0
;
uv_mutex_lock
(
&
gUdfdProxy
.
udfStubsMutex
);
SUdfcFuncStub
key
=
{
0
};
strcpy
(
key
.
udfName
,
udfName
);
int32_t
stubIndex
=
taosArraySearchIdx
(
gUdfdProxy
.
udfStubs
,
&
key
,
compareUdfcFuncSub
,
TD_EQ
);
if
(
stubIndex
!=
-
1
)
{
SUdfcFuncStub
*
foundStub
=
taosArrayGet
(
gUdfdProxy
.
udfStubs
,
stubIndex
);
UdfcFuncHandle
handle
=
foundStub
->
handle
;
if
(
handle
!=
NULL
&&
((
SUdfcUvSession
*
)
handle
)
->
udfUvPipe
!=
NULL
)
{
*
pHandle
=
foundStub
->
handle
;
++
foundStub
->
refCount
;
foundStub
->
lastRefTime
=
taosGetTimestampUs
();
uv_mutex_unlock
(
&
gUdfdProxy
.
udfStubsMutex
);
return
0
;
}
else
{
fnInfo
(
"invalid handle for %s, refCount: %d, last ref time: %"
PRId64
". remove it from cache"
,
udfName
,
foundStub
->
refCount
,
foundStub
->
lastRefTime
);
taosArrayRemove
(
gUdfdProxy
.
udfStubs
,
stubIndex
);
}
}
*
pHandle
=
NULL
;
code
=
doSetupUdf
(
udfName
,
pHandle
);
if
(
code
==
TSDB_CODE_SUCCESS
)
{
SUdfcFuncStub
stub
=
{
0
};
strcpy
(
stub
.
udfName
,
udfName
);
stub
.
handle
=
*
pHandle
;
++
stub
.
refCount
;
stub
.
lastRefTime
=
taosGetTimestampUs
();
taosArrayPush
(
gUdfdProxy
.
udfStubs
,
&
stub
);
taosArraySort
(
gUdfdProxy
.
udfStubs
,
compareUdfcFuncSub
);
}
else
{
*
pHandle
=
NULL
;
}
uv_mutex_unlock
(
&
gUdfdProxy
.
udfStubsMutex
);
return
code
;
}
}
void
releaseUdfFuncHandle
(
char
*
udfName
)
{
int32_t
doSetupUdf
(
char
udfName
[],
UdfcFuncHandle
*
funcHandle
)
{
uv_mutex_lock
(
&
gUdfdProxy
.
udfStubsMutex
);
if
(
gUdfdProxy
.
udfcState
!=
UDFC_STATE_READY
)
{
SUdfcFuncStub
key
=
{
0
};
return
TSDB_CODE_UDF_INVALID_STATE
;
strcpy
(
key
.
udfName
,
udfName
);
SUdfcFuncStub
*
foundStub
=
taosArraySearch
(
gUdfdProxy
.
udfStubs
,
&
key
,
compareUdfcFuncSub
,
TD_EQ
);
if
(
!
foundStub
)
{
return
;
}
}
if
(
foundStub
->
refCount
>
0
)
{
SClientUdfTask
*
task
=
taosMemoryCalloc
(
1
,
sizeof
(
SClientUdfTask
));
--
foundStub
->
refCount
;
task
->
errCode
=
0
;
task
->
session
=
taosMemoryCalloc
(
1
,
sizeof
(
SUdfcUvSession
));
task
->
session
->
udfc
=
&
gUdfdProxy
;
task
->
type
=
UDF_TASK_SETUP
;
SUdfSetupRequest
*
req
=
&
task
->
_setup
.
req
;
strncpy
(
req
->
udfName
,
udfName
,
TSDB_FUNC_NAME_LEN
);
int32_t
errCode
=
udfcRunUdfUvTask
(
task
,
UV_TASK_CONNECT
);
if
(
errCode
!=
0
)
{
fnError
(
"failed to connect to pipe. udfName: %s, pipe: %s"
,
udfName
,
(
&
gUdfdProxy
)
->
udfdPipeName
);
return
TSDB_CODE_UDF_PIPE_CONNECT_ERR
;
}
}
uv_mutex_unlock
(
&
gUdfdProxy
.
udfStubsMutex
);
}
int32_t
cleanUpUdfs
()
{
udfcRunUdfUvTask
(
task
,
UV_TASK_REQ_RSP
);
uv_mutex_lock
(
&
gUdfdProxy
.
udfStubsMutex
);
int32_t
i
=
0
;
SUdfSetupResponse
*
rsp
=
&
task
->
_setup
.
rsp
;
SArray
*
udfStubs
=
taosArrayInit
(
16
,
sizeof
(
SUdfcFuncStub
));
task
->
session
->
severHandle
=
rsp
->
udfHandle
;
while
(
i
<
taosArrayGetSize
(
gUdfdProxy
.
udfStubs
))
{
task
->
session
->
outputType
=
rsp
->
outputType
;
SUdfcFuncStub
*
stub
=
taosArrayGet
(
gUdfdProxy
.
udfStubs
,
i
);
task
->
session
->
outputLen
=
rsp
->
outputLen
;
if
(
stub
->
refCount
==
0
)
{
task
->
session
->
bufSize
=
rsp
->
bufSize
;
fnInfo
(
"tear down udf. udf name: %s, handle: %p, ref count: %d"
,
stub
->
udfName
,
stub
->
handle
,
stub
->
refCount
);
strcpy
(
task
->
session
->
udfName
,
udfName
);
doTeardownUdf
(
stub
->
handle
);
if
(
task
->
errCode
!=
0
)
{
}
else
{
fnError
(
"failed to setup udf. udfname: %s, err: %d"
,
udfName
,
task
->
errCode
)
fnInfo
(
"udf still in use. udf name: %s, ref count: %d, last ref time: %"
PRId64
", handle: %p"
,
}
else
{
stub
->
udfName
,
stub
->
refCount
,
stub
->
lastRefTime
,
stub
->
handle
);
fnInfo
(
"sucessfully setup udf func handle. udfName: %s, handle: %p"
,
udfName
,
task
->
session
);
UdfcFuncHandle
handle
=
stub
->
handle
;
*
funcHandle
=
task
->
session
;
if
(
handle
!=
NULL
&&
((
SUdfcUvSession
*
)
handle
)
->
udfUvPipe
!=
NULL
)
{
taosArrayPush
(
udfStubs
,
stub
);
}
else
{
fnInfo
(
"udf invalid handle for %s, refCount: %d, last ref time: %"
PRId64
". remove it from cache"
,
stub
->
udfName
,
stub
->
refCount
,
stub
->
lastRefTime
);
}
}
++
i
;
}
}
taosArrayDestroy
(
gUdfdProxy
.
udfStubs
);
int32_t
err
=
task
->
errCode
;
gUdfdProxy
.
udfStubs
=
udfStubs
;
taosMemoryFree
(
task
);
uv_mutex_unlock
(
&
gUdfdProxy
.
udfStubsMutex
);
return
err
;
return
0
;
}
}
int32_t
callUdf
(
UdfcFuncHandle
handle
,
int8_t
callType
,
SSDataBlock
*
input
,
SUdfInterBuf
*
state
,
SUdfInterBuf
*
state2
,
int32_t
callUdf
(
UdfcFuncHandle
handle
,
int8_t
callType
,
SSDataBlock
*
input
,
SUdfInterBuf
*
state
,
SUdfInterBuf
*
state2
,
...
@@ -1524,29 +1785,6 @@ int32_t doCallUdfScalarFunc(UdfcFuncHandle handle, SScalarParam *input, int32_t
...
@@ -1524,29 +1785,6 @@ int32_t doCallUdfScalarFunc(UdfcFuncHandle handle, SScalarParam *input, int32_t
return
err
;
return
err
;
}
}
int32_t
callUdfScalarFunc
(
char
*
udfName
,
SScalarParam
*
input
,
int32_t
numOfCols
,
SScalarParam
*
output
)
{
UdfcFuncHandle
handle
=
NULL
;
int32_t
code
=
acquireUdfFuncHandle
(
udfName
,
&
handle
);
if
(
code
!=
0
)
{
return
code
;
}
SUdfcUvSession
*
session
=
handle
;
code
=
doCallUdfScalarFunc
(
handle
,
input
,
numOfCols
,
output
);
if
(
output
->
columnData
==
NULL
)
{
fnError
(
"udfc scalar function calculate error. no column data"
);
code
=
TSDB_CODE_UDF_INVALID_OUTPUT_TYPE
;
}
else
{
if
(
session
->
outputType
!=
output
->
columnData
->
info
.
type
||
session
->
outputLen
!=
output
->
columnData
->
info
.
bytes
)
{
fnError
(
"udfc scalar function calculate error. type mismatch. session type: %d(%d), output type: %d(%d)"
,
session
->
outputType
,
session
->
outputLen
,
output
->
columnData
->
info
.
type
,
output
->
columnData
->
info
.
bytes
);
code
=
TSDB_CODE_UDF_INVALID_OUTPUT_TYPE
;
}
}
releaseUdfFuncHandle
(
udfName
);
return
code
;
}
int32_t
doTeardownUdf
(
UdfcFuncHandle
handle
)
{
int32_t
doTeardownUdf
(
UdfcFuncHandle
handle
)
{
SUdfcUvSession
*
session
=
(
SUdfcUvSession
*
)
handle
;
SUdfcUvSession
*
session
=
(
SUdfcUvSession
*
)
handle
;
...
@@ -1576,165 +1814,3 @@ int32_t doTeardownUdf(UdfcFuncHandle handle) {
...
@@ -1576,165 +1814,3 @@ int32_t doTeardownUdf(UdfcFuncHandle handle) {
return
err
;
return
err
;
}
}
//memory layout |---SUdfAggRes----|-----final result-----|---inter result----|
typedef
struct
SUdfAggRes
{
int8_t
finalResNum
;
int8_t
interResNum
;
char
*
finalResBuf
;
char
*
interResBuf
;
}
SUdfAggRes
;
bool
udfAggGetEnv
(
struct
SFunctionNode
*
pFunc
,
SFuncExecEnv
*
pEnv
)
{
if
(
fmIsScalarFunc
(
pFunc
->
funcId
))
{
return
false
;
}
pEnv
->
calcMemSize
=
sizeof
(
SUdfAggRes
)
+
pFunc
->
node
.
resType
.
bytes
+
pFunc
->
udfBufSize
;
return
true
;
}
bool
udfAggInit
(
struct
SqlFunctionCtx
*
pCtx
,
struct
SResultRowEntryInfo
*
pResultCellInfo
)
{
if
(
functionSetup
(
pCtx
,
pResultCellInfo
)
!=
true
)
{
return
false
;
}
UdfcFuncHandle
handle
;
int32_t
udfCode
=
0
;
if
((
udfCode
=
acquireUdfFuncHandle
((
char
*
)
pCtx
->
udfName
,
&
handle
))
!=
0
)
{
fnError
(
"udfAggInit error. step doSetupUdf. udf code: %d"
,
udfCode
);
return
false
;
}
SUdfcUvSession
*
session
=
(
SUdfcUvSession
*
)
handle
;
SUdfAggRes
*
udfRes
=
(
SUdfAggRes
*
)
GET_ROWCELL_INTERBUF
(
pResultCellInfo
);
int32_t
envSize
=
sizeof
(
SUdfAggRes
)
+
session
->
outputLen
+
session
->
bufSize
;
memset
(
udfRes
,
0
,
envSize
);
udfRes
->
finalResBuf
=
(
char
*
)
udfRes
+
sizeof
(
SUdfAggRes
);
udfRes
->
interResBuf
=
(
char
*
)
udfRes
+
sizeof
(
SUdfAggRes
)
+
session
->
outputLen
;
SUdfInterBuf
buf
=
{
0
};
if
((
udfCode
=
doCallUdfAggInit
(
handle
,
&
buf
))
!=
0
)
{
fnError
(
"udfAggInit error. step doCallUdfAggInit. udf code: %d"
,
udfCode
);
releaseUdfFuncHandle
(
pCtx
->
udfName
);
return
false
;
}
udfRes
->
interResNum
=
buf
.
numOfResult
;
if
(
buf
.
bufLen
<=
session
->
bufSize
)
{
memcpy
(
udfRes
->
interResBuf
,
buf
.
buf
,
buf
.
bufLen
);
}
else
{
fnError
(
"udfc inter buf size %d is greater than function bufSize %d"
,
buf
.
bufLen
,
session
->
bufSize
);
releaseUdfFuncHandle
(
pCtx
->
udfName
);
return
false
;
}
releaseUdfFuncHandle
(
pCtx
->
udfName
);
freeUdfInterBuf
(
&
buf
);
return
true
;
}
int32_t
udfAggProcess
(
struct
SqlFunctionCtx
*
pCtx
)
{
int32_t
udfCode
=
0
;
UdfcFuncHandle
handle
=
0
;
if
((
udfCode
=
acquireUdfFuncHandle
((
char
*
)
pCtx
->
udfName
,
&
handle
))
!=
0
)
{
fnError
(
"udfAggProcess error. step acquireUdfFuncHandle. udf code: %d"
,
udfCode
);
return
udfCode
;
}
SUdfcUvSession
*
session
=
handle
;
SUdfAggRes
*
udfRes
=
(
SUdfAggRes
*
)
GET_ROWCELL_INTERBUF
(
GET_RES_INFO
(
pCtx
));
udfRes
->
finalResBuf
=
(
char
*
)
udfRes
+
sizeof
(
SUdfAggRes
);
udfRes
->
interResBuf
=
(
char
*
)
udfRes
+
sizeof
(
SUdfAggRes
)
+
session
->
outputLen
;
SInputColumnInfoData
*
pInput
=
&
pCtx
->
input
;
int32_t
numOfCols
=
pInput
->
numOfInputCols
;
int32_t
start
=
pInput
->
startRowIndex
;
int32_t
numOfRows
=
pInput
->
numOfRows
;
SSDataBlock
tempBlock
=
{
0
};
tempBlock
.
info
.
numOfCols
=
numOfCols
;
tempBlock
.
info
.
rows
=
pInput
->
totalRows
;
tempBlock
.
info
.
uid
=
pInput
->
uid
;
bool
hasVarCol
=
false
;
tempBlock
.
pDataBlock
=
taosArrayInit
(
numOfCols
,
sizeof
(
SColumnInfoData
));
for
(
int32_t
i
=
0
;
i
<
numOfCols
;
++
i
)
{
SColumnInfoData
*
col
=
pInput
->
pData
[
i
];
if
(
IS_VAR_DATA_TYPE
(
col
->
info
.
type
))
{
hasVarCol
=
true
;
}
taosArrayPush
(
tempBlock
.
pDataBlock
,
col
);
}
tempBlock
.
info
.
hasVarCol
=
hasVarCol
;
SSDataBlock
*
inputBlock
=
blockDataExtractBlock
(
&
tempBlock
,
start
,
numOfRows
);
SUdfInterBuf
state
=
{.
buf
=
udfRes
->
interResBuf
,
.
bufLen
=
session
->
bufSize
,
.
numOfResult
=
udfRes
->
interResNum
};
SUdfInterBuf
newState
=
{
0
};
udfCode
=
doCallUdfAggProcess
(
session
,
inputBlock
,
&
state
,
&
newState
);
if
(
udfCode
!=
0
)
{
fnError
(
"udfAggProcess error. code: %d"
,
udfCode
);
newState
.
numOfResult
=
0
;
}
else
{
udfRes
->
interResNum
=
newState
.
numOfResult
;
if
(
newState
.
bufLen
<=
session
->
bufSize
)
{
memcpy
(
udfRes
->
interResBuf
,
newState
.
buf
,
newState
.
bufLen
);
}
else
{
fnError
(
"udfc inter buf size %d is greater than function bufSize %d"
,
newState
.
bufLen
,
session
->
bufSize
);
udfCode
=
TSDB_CODE_UDF_INVALID_BUFSIZE
;
}
}
if
(
newState
.
numOfResult
==
1
||
state
.
numOfResult
==
1
)
{
GET_RES_INFO
(
pCtx
)
->
numOfRes
=
1
;
}
blockDataDestroy
(
inputBlock
);
taosArrayDestroy
(
tempBlock
.
pDataBlock
);
releaseUdfFuncHandle
(
pCtx
->
udfName
);
freeUdfInterBuf
(
&
newState
);
return
udfCode
;
}
int32_t
udfAggFinalize
(
struct
SqlFunctionCtx
*
pCtx
,
SSDataBlock
*
pBlock
)
{
int32_t
udfCode
=
0
;
UdfcFuncHandle
handle
=
0
;
if
((
udfCode
=
acquireUdfFuncHandle
((
char
*
)
pCtx
->
udfName
,
&
handle
))
!=
0
)
{
fnError
(
"udfAggProcess error. step acquireUdfFuncHandle. udf code: %d"
,
udfCode
);
return
udfCode
;
}
SUdfcUvSession
*
session
=
handle
;
SUdfAggRes
*
udfRes
=
(
SUdfAggRes
*
)
GET_ROWCELL_INTERBUF
(
GET_RES_INFO
(
pCtx
));
udfRes
->
finalResBuf
=
(
char
*
)
udfRes
+
sizeof
(
SUdfAggRes
);
udfRes
->
interResBuf
=
(
char
*
)
udfRes
+
sizeof
(
SUdfAggRes
)
+
session
->
outputLen
;
SUdfInterBuf
resultBuf
=
{
0
};
SUdfInterBuf
state
=
{.
buf
=
udfRes
->
interResBuf
,
.
bufLen
=
session
->
bufSize
,
.
numOfResult
=
udfRes
->
interResNum
};
int32_t
udfCallCode
=
0
;
udfCallCode
=
doCallUdfAggFinalize
(
session
,
&
state
,
&
resultBuf
);
if
(
udfCallCode
!=
0
)
{
fnError
(
"udfAggFinalize error. doCallUdfAggFinalize step. udf code:%d"
,
udfCallCode
);
GET_RES_INFO
(
pCtx
)
->
numOfRes
=
0
;
}
else
{
if
(
resultBuf
.
bufLen
<=
session
->
outputLen
)
{
memcpy
(
udfRes
->
finalResBuf
,
resultBuf
.
buf
,
session
->
outputLen
);
udfRes
->
finalResNum
=
resultBuf
.
numOfResult
;
GET_RES_INFO
(
pCtx
)
->
numOfRes
=
udfRes
->
finalResNum
;
}
else
{
fnError
(
"udfc inter buf size %d is greater than function output size %d"
,
resultBuf
.
bufLen
,
session
->
outputLen
);
GET_RES_INFO
(
pCtx
)
->
numOfRes
=
0
;
udfCallCode
=
TSDB_CODE_UDF_INVALID_OUTPUT_TYPE
;
}
}
freeUdfInterBuf
(
&
resultBuf
);
int32_t
numOfResults
=
functionFinalizeWithResultBuf
(
pCtx
,
pBlock
,
udfRes
->
finalResBuf
);
releaseUdfFuncHandle
(
pCtx
->
udfName
);
return
udfCallCode
==
0
?
numOfResults
:
udfCallCode
;
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录