Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
taosdata
TDengine
提交
5fcff75c
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看板
提交
5fcff75c
编写于
9月 16, 2022
作者:
Z
zhihaop
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
feat: improve the performance of async bulk write dispatcher
上级
08f7a4fa
变更
2
隐藏空白更改
内联
并排
Showing
2 changed file
with
115 addition
and
74 deletion
+115
-74
src/client/inc/tscBulkWrite.h
src/client/inc/tscBulkWrite.h
+10
-22
src/client/src/tscBulkWrite.c
src/client/src/tscBulkWrite.c
+105
-52
未找到文件。
src/client/inc/tscBulkWrite.h
浏览文件 @
5fcff75c
...
@@ -31,11 +31,14 @@ typedef struct SAsyncBulkWriteDispatcher {
...
@@ -31,11 +31,14 @@ typedef struct SAsyncBulkWriteDispatcher {
// the buffer to store the insertion statements. equivalent to SArray<SSqlObj*>.
// the buffer to store the insertion statements. equivalent to SArray<SSqlObj*>.
SArray
*
buffer
;
SArray
*
buffer
;
// the mutex to protect the
buff
er.
// the mutex to protect the
dispatch
er.
pthread_mutex_t
mutex
;
pthread_mutex_t
mutex
;
// the cond to signal to background thread.
// the cond to signal to background thread.
pthread_cond_t
cond
;
pthread_cond_t
timeout
;
// the cond to signal to background thread.
pthread_cond_t
notFull
;
// the background thread to manage batching timeout.
// the background thread to manage batching timeout.
pthread_t
background
;
pthread_t
background
;
...
@@ -73,24 +76,7 @@ typedef struct SSqlObj SSqlObj;
...
@@ -73,24 +76,7 @@ typedef struct SSqlObj SSqlObj;
int32_t
dispatcherStatementMerge
(
SArray
*
statements
,
SSqlObj
**
result
);
int32_t
dispatcherStatementMerge
(
SArray
*
statements
,
SSqlObj
**
result
);
/**
/**
* Poll all the SSqlObj* in the dispatcher's buffer.
* Merge the sql statements and execute the merged sql statement.
*
* @param dispatcher the dispatcher.
* @return the items in the dispatcher, SArray<SSqlObj*>.
*/
SArray
*
dispatcherPollAll
(
SAsyncBulkWriteDispatcher
*
dispatcher
);
/**
* @brief Try to offer the SSqlObj* to the dispatcher.
*
* @param dispatcher the async bulk write dispatcher.
* @param pSql the sql object to offer.
* @return if offer success, return the current size of the buffer. otherwise returns -1.
*/
int32_t
dispatcherTryOffer
(
SAsyncBulkWriteDispatcher
*
dispatcher
,
SSqlObj
*
pSql
);
/**
* @brief Merge the sql statements and execute the merged sql statement.
*
*
* @param statements the array of sql statement. a.k.a SArray<SSqlObj*>.
* @param statements the array of sql statement. a.k.a SArray<SSqlObj*>.
*/
*/
...
@@ -117,11 +103,12 @@ void destroyAsyncDispatcher(SAsyncBulkWriteDispatcher* dispatcher);
...
@@ -117,11 +103,12 @@ void destroyAsyncDispatcher(SAsyncBulkWriteDispatcher* dispatcher);
* 1. auto batch feature on the sql object must be enabled.
* 1. auto batch feature on the sql object must be enabled.
* 2. must be an `insert into ... value ...` statement.
* 2. must be an `insert into ... value ...` statement.
* 3. the payload type must be kv payload.
* 3. the payload type must be kv payload.
*
*
* @param dispatcher the async dispatcher.
* @param pSql the sql object to check.
* @param pSql the sql object to check.
* @return returns true if the sql object supports auto batch.
* @return returns true if the sql object supports auto batch.
*/
*/
bool
tscSupportBulkInsertion
(
SSqlObj
*
pSql
);
bool
tscSupportBulkInsertion
(
S
AsyncBulkWriteDispatcher
*
dispatcher
,
S
SqlObj
*
pSql
);
/**
/**
* Try to offer the SSqlObj* to the buffer. If the number of row reach `asyncBatchSize`, the function
* Try to offer the SSqlObj* to the buffer. If the number of row reach `asyncBatchSize`, the function
...
@@ -174,6 +161,7 @@ void destroyDispatcherHolder(SDispatcherHolder* holder);
...
@@ -174,6 +161,7 @@ void destroyDispatcherHolder(SDispatcherHolder* holder);
/**
/**
* Get an instance of SAsyncBulkWriteDispatcher.
* Get an instance of SAsyncBulkWriteDispatcher.
*
* @param holder the holder of SAsyncBulkWriteDispatcher.
* @param holder the holder of SAsyncBulkWriteDispatcher.
* @return the SAsyncBulkWriteDispatcher instance.
* @return the SAsyncBulkWriteDispatcher instance.
*/
*/
...
...
src/client/src/tscBulkWrite.c
浏览文件 @
5fcff75c
...
@@ -143,12 +143,20 @@ int32_t dispatcherStatementMerge(SArray* statements, SSqlObj** result) {
...
@@ -143,12 +143,20 @@ int32_t dispatcherStatementMerge(SArray* statements, SSqlObj** result) {
return
code
;
return
code
;
}
}
SArray
*
dispatcherPollAll
(
SAsyncBulkWriteDispatcher
*
dispatcher
)
{
/**
* Poll all the SSqlObj* in the dispatcher's buffer.
*
* @param dispatcher the dispatcher.
* @return the items in the dispatcher, SArray<SSqlObj*>.
*/
inline
static
SArray
*
dispatcherPollAll
(
SAsyncBulkWriteDispatcher
*
dispatcher
)
{
pthread_mutex_lock
(
&
dispatcher
->
mutex
);
if
(
!
atomic_load_32
(
&
dispatcher
->
bufferSize
))
{
if
(
!
atomic_load_32
(
&
dispatcher
->
bufferSize
))
{
pthread_cond_broadcast
(
&
dispatcher
->
notFull
);
pthread_mutex_unlock
(
&
dispatcher
->
mutex
);
return
NULL
;
return
NULL
;
}
}
pthread_mutex_lock
(
&
dispatcher
->
mutex
);
SArray
*
statements
=
taosArrayDup
(
dispatcher
->
buffer
);
SArray
*
statements
=
taosArrayDup
(
dispatcher
->
buffer
);
if
(
statements
==
NULL
)
{
if
(
statements
==
NULL
)
{
pthread_mutex_unlock
(
&
dispatcher
->
mutex
);
pthread_mutex_unlock
(
&
dispatcher
->
mutex
);
...
@@ -159,27 +167,38 @@ SArray* dispatcherPollAll(SAsyncBulkWriteDispatcher* dispatcher) {
...
@@ -159,27 +167,38 @@ SArray* dispatcherPollAll(SAsyncBulkWriteDispatcher* dispatcher) {
atomic_store_32
(
&
dispatcher
->
bufferSize
,
0
);
atomic_store_32
(
&
dispatcher
->
bufferSize
,
0
);
atomic_store_32
(
&
dispatcher
->
currentSize
,
0
);
atomic_store_32
(
&
dispatcher
->
currentSize
,
0
);
taosArrayClear
(
dispatcher
->
buffer
);
taosArrayClear
(
dispatcher
->
buffer
);
pthread_cond_broadcast
(
&
dispatcher
->
notFull
);
pthread_mutex_unlock
(
&
dispatcher
->
mutex
);
pthread_mutex_unlock
(
&
dispatcher
->
mutex
);
return
statements
;
return
statements
;
}
}
int32_t
dispatcherTryOffer
(
SAsyncBulkWriteDispatcher
*
dispatcher
,
SSqlObj
*
pSql
)
{
/**
// pre-check: the buffer is full.
* @brief Try to offer the SSqlObj* to the dispatcher.
if
(
atomic_load_32
(
&
dispatcher
->
currentSize
)
>=
dispatcher
->
batchSize
)
{
*
return
-
1
;
* @param dispatcher the async bulk write dispatcher.
}
* @param pSql the sql object to offer.
* @return if offer success, return the current size of the buffer. otherwise returns -1.
*/
inline
static
int32_t
dispatcherTryOffer
(
SAsyncBulkWriteDispatcher
*
dispatcher
,
SSqlObj
*
pSql
)
{
pthread_mutex_lock
(
&
dispatcher
->
mutex
);
pthread_mutex_lock
(
&
dispatcher
->
mutex
);
// double-check: the buffer is full.
// if dispatcher is shutdown, must fail back to normal insertion.
if
(
atomic_load_32
(
&
dispatcher
->
currentSize
)
>=
dispatcher
->
batchSize
)
{
// usually not happen, unless taos_query_a(...) after taos_close(...).
if
(
atomic_load_8
(
&
dispatcher
->
shutdown
))
{
pthread_mutex_unlock
(
&
dispatcher
->
mutex
);
pthread_mutex_unlock
(
&
dispatcher
->
mutex
);
return
-
1
;
return
-
1
;
}
}
// the buffer is full.
while
(
atomic_load_32
(
&
dispatcher
->
currentSize
)
>=
dispatcher
->
batchSize
)
{
if
(
pthread_cond_wait
(
&
dispatcher
->
notFull
,
&
dispatcher
->
mutex
))
{
pthread_mutex_unlock
(
&
dispatcher
->
mutex
);
return
-
1
;
}
}
taosArrayPush
(
dispatcher
->
buffer
,
pSql
);
taosArrayPush
(
dispatcher
->
buffer
,
pSql
);
tscDebug
(
"sql obj %p has been write to insert buffer"
,
pSql
);
tscDebug
(
"sql obj %p has been write to insert buffer"
,
pSql
);
atomic_fetch_add_32
(
&
dispatcher
->
bufferSize
,
1
);
atomic_fetch_add_32
(
&
dispatcher
->
bufferSize
,
1
);
...
@@ -205,9 +224,7 @@ void dispatcherExecute(SArray* statements) {
...
@@ -205,9 +224,7 @@ void dispatcherExecute(SArray* statements) {
tscDebug
(
"merging %zu sql objs into %p"
,
taosArrayGetSize
(
statements
),
merged
);
tscDebug
(
"merging %zu sql objs into %p"
,
taosArrayGetSize
(
statements
),
merged
);
tscHandleMultivnodeInsert
(
merged
);
tscHandleMultivnodeInsert
(
merged
);
taosArrayDestroy
(
&
statements
);
return
;
return
;
_error:
_error:
tscError
(
"send async batch sql obj failed, reason: %s"
,
tstrerror
(
code
));
tscError
(
"send async batch sql obj failed, reason: %s"
,
tstrerror
(
code
));
...
@@ -216,7 +233,6 @@ _error:
...
@@ -216,7 +233,6 @@ _error:
SSqlObj
*
item
=
*
((
SSqlObj
**
)
taosArrayGet
(
statements
,
i
));
SSqlObj
*
item
=
*
((
SSqlObj
**
)
taosArrayGet
(
statements
,
i
));
tscReturnsError
(
item
,
code
);
tscReturnsError
(
item
,
code
);
}
}
taosArrayDestroy
(
&
statements
);
}
}
/**
/**
...
@@ -245,43 +261,58 @@ static inline int64_t durationMillis(struct timespec s, struct timespec t) {
...
@@ -245,43 +261,58 @@ static inline int64_t durationMillis(struct timespec s, struct timespec t) {
return
d
;
return
d
;
}
}
/**
* Sleep until `timeout` timespec. When dispatcherShutdown(...) called, the function will return immediately.
*
* @param dispatcher the dispatcher thread to sleep.
* @param timeout the timeout in CLOCK_REALTIME.
*/
inline
static
void
dispatcherSleepUntil
(
SAsyncBulkWriteDispatcher
*
dispatcher
,
struct
timespec
timeout
)
{
struct
timespec
current
;
clock_gettime
(
CLOCK_REALTIME
,
&
current
);
// if current > timeout, no sleep required.
if
(
durationMillis
(
current
,
timeout
)
<=
0
)
{
return
;
}
if
(
pthread_mutex_timedlock
(
&
dispatcher
->
mutex
,
&
timeout
))
{
return
;
}
while
(
true
)
{
// notified by dispatcherShutdown(...).
if
(
atomic_load_8
(
&
dispatcher
->
shutdown
))
{
break
;
}
if
(
pthread_cond_timedwait
(
&
dispatcher
->
timeout
,
&
dispatcher
->
mutex
,
&
timeout
))
{
break
;
}
}
pthread_mutex_unlock
(
&
dispatcher
->
mutex
);
}
/**
/**
* The thread to manage batching timeout.
* The thread to manage batching timeout.
*/
*/
static
void
*
dispatcherTimeoutCallback
(
void
*
arg
)
{
static
void
*
dispatcherTimeoutCallback
(
void
*
arg
)
{
SAsyncBulkWriteDispatcher
*
dispatcher
=
arg
;
SAsyncBulkWriteDispatcher
*
dispatcher
=
arg
;
setThreadName
(
"tscBackground"
);
setThreadName
(
"tsc
Async
Background"
);
while
(
!
atomic_load_8
(
&
dispatcher
->
shutdown
))
{
while
(
!
atomic_load_8
(
&
dispatcher
->
shutdown
))
{
struct
timespec
t1
,
t2
;
struct
timespec
current
;
clock_gettime
(
CLOCK_REALTIME
,
&
t1
);
clock_gettime
(
CLOCK_REALTIME
,
&
current
);
struct
timespec
timeout
=
afterMillis
(
current
,
dispatcher
->
timeoutMs
);
atomic_store_8
(
&
dispatcher
->
exclusive
,
true
);
atomic_store_8
(
&
dispatcher
->
exclusive
,
true
);
SArray
*
statements
=
dispatcherPollAll
(
dispatcher
);
SArray
*
statements
=
dispatcherPollAll
(
dispatcher
);
atomic_store_8
(
&
dispatcher
->
exclusive
,
false
);
atomic_store_8
(
&
dispatcher
->
exclusive
,
false
);
dispatcherExecute
(
statements
);
dispatcherExecute
(
statements
);
clock_gettime
(
CLOCK_REALTIME
,
&
t2
);
taosArrayDestroy
(
&
statements
);
// Similar to scheduleAtFixedRate in Java, if the execution time exceed
// Similar to scheduleAtFixedRate in Java, if the execution time exceed
// `timeoutMs` milliseconds, then there will be no sleep.
// `timeoutMs` milliseconds, then there will be no sleep.
struct
timespec
t3
=
afterMillis
(
t1
,
dispatcher
->
timeoutMs
);
dispatcherSleepUntil
(
dispatcher
,
timeout
);
if
(
durationMillis
(
t2
,
t3
)
>
0
)
{
if
(
pthread_mutex_timedlock
(
&
dispatcher
->
mutex
,
&
t3
))
{
continue
;
}
while
(
true
)
{
if
(
atomic_load_8
(
&
dispatcher
->
shutdown
))
{
break
;
}
if
(
pthread_cond_timedwait
(
&
dispatcher
->
cond
,
&
dispatcher
->
mutex
,
&
t3
))
{
break
;
}
}
pthread_mutex_unlock
(
&
dispatcher
->
mutex
);
}
}
}
return
NULL
;
return
NULL
;
}
}
...
@@ -309,10 +340,14 @@ SAsyncBulkWriteDispatcher* createAsyncBulkWriteDispatcher(int32_t batchSize, int
...
@@ -309,10 +340,14 @@ SAsyncBulkWriteDispatcher* createAsyncBulkWriteDispatcher(int32_t batchSize, int
// init the mutex and the cond.
// init the mutex and the cond.
pthread_mutex_init
(
&
dispatcher
->
mutex
,
NULL
);
pthread_mutex_init
(
&
dispatcher
->
mutex
,
NULL
);
pthread_cond_init
(
&
dispatcher
->
cond
,
NULL
);
pthread_cond_init
(
&
dispatcher
->
timeout
,
NULL
);
pthread_cond_init
(
&
dispatcher
->
notFull
,
NULL
);
// init background thread.
// init background thread.
if
(
pthread_create
(
&
dispatcher
->
background
,
NULL
,
dispatcherTimeoutCallback
,
dispatcher
))
{
if
(
pthread_create
(
&
dispatcher
->
background
,
NULL
,
dispatcherTimeoutCallback
,
dispatcher
))
{
pthread_mutex_destroy
(
&
dispatcher
->
mutex
);
pthread_cond_destroy
(
&
dispatcher
->
timeout
);
pthread_cond_destroy
(
&
dispatcher
->
notFull
);
taosArrayDestroy
(
&
dispatcher
->
buffer
);
taosArrayDestroy
(
&
dispatcher
->
buffer
);
tfree
(
dispatcher
);
tfree
(
dispatcher
);
return
NULL
;
return
NULL
;
...
@@ -321,24 +356,34 @@ SAsyncBulkWriteDispatcher* createAsyncBulkWriteDispatcher(int32_t batchSize, int
...
@@ -321,24 +356,34 @@ SAsyncBulkWriteDispatcher* createAsyncBulkWriteDispatcher(int32_t batchSize, int
return
dispatcher
;
return
dispatcher
;
}
}
void
destroyAsyncDispatcher
(
SAsyncBulkWriteDispatcher
*
dispatcher
)
{
/**
if
(
dispatcher
==
NULL
)
{
* Shutdown the dispatcher and join the timeout thread.
return
;
*
}
* @param dispatcher the dispatcher.
*/
inline
static
void
dispatcherShutdown
(
SAsyncBulkWriteDispatcher
*
dispatcher
)
{
// mark shutdown, signal shutdown to timeout thread.
// mark shutdown, signal shutdown to timeout thread.
pthread_mutex_lock
(
&
dispatcher
->
mutex
);
pthread_mutex_lock
(
&
dispatcher
->
mutex
);
atomic_store_8
(
&
dispatcher
->
shutdown
,
true
);
atomic_store_8
(
&
dispatcher
->
shutdown
,
true
);
pthread_cond_
signal
(
&
dispatcher
->
cond
);
pthread_cond_
broadcast
(
&
dispatcher
->
timeout
);
pthread_mutex_unlock
(
&
dispatcher
->
mutex
);
pthread_mutex_unlock
(
&
dispatcher
->
mutex
);
// make sure the timeout thread exit.
// make sure the timeout thread exit.
pthread_join
(
dispatcher
->
background
,
NULL
);
pthread_join
(
dispatcher
->
background
,
NULL
);
}
void
destroyAsyncDispatcher
(
SAsyncBulkWriteDispatcher
*
dispatcher
)
{
if
(
dispatcher
==
NULL
)
{
return
;
}
dispatcherShutdown
(
dispatcher
);
// poll and send all the statements in the buffer.
// poll and send all the statements in the buffer.
while
(
atomic_load_32
(
&
dispatcher
->
bufferSize
))
{
while
(
atomic_load_32
(
&
dispatcher
->
bufferSize
))
{
SArray
*
statements
=
dispatcherPollAll
(
dispatcher
);
SArray
*
statements
=
dispatcherPollAll
(
dispatcher
);
dispatcherExecute
(
statements
);
dispatcherExecute
(
statements
);
taosArrayDestroy
(
&
statements
);
}
}
// destroy the buffer.
// destroy the buffer.
...
@@ -346,10 +391,13 @@ void destroyAsyncDispatcher(SAsyncBulkWriteDispatcher* dispatcher) {
...
@@ -346,10 +391,13 @@ void destroyAsyncDispatcher(SAsyncBulkWriteDispatcher* dispatcher) {
// destroy the mutex.
// destroy the mutex.
pthread_mutex_destroy
(
&
dispatcher
->
mutex
);
pthread_mutex_destroy
(
&
dispatcher
->
mutex
);
pthread_cond_destroy
(
&
dispatcher
->
timeout
);
pthread_cond_destroy
(
&
dispatcher
->
notFull
);
free
(
dispatcher
);
free
(
dispatcher
);
}
}
bool
tscSupportBulkInsertion
(
SSqlObj
*
pSql
)
{
bool
tscSupportBulkInsertion
(
SAsyncBulkWriteDispatcher
*
dispatcher
,
SSqlObj
*
pSql
)
{
if
(
pSql
==
NULL
||
!
pSql
->
enableBatch
)
{
if
(
pSql
==
NULL
||
!
pSql
->
enableBatch
)
{
return
false
;
return
false
;
}
}
...
@@ -373,6 +421,11 @@ bool tscSupportBulkInsertion(SSqlObj* pSql) {
...
@@ -373,6 +421,11 @@ bool tscSupportBulkInsertion(SSqlObj* pSql) {
if
(
pInsertParam
->
payloadType
!=
PAYLOAD_TYPE_KV
)
{
if
(
pInsertParam
->
payloadType
!=
PAYLOAD_TYPE_KV
)
{
return
false
;
return
false
;
}
}
// too many insertion rows, fail back to normal insertion.
if
(
statementGetInsertionRows
(
pSql
)
>=
dispatcher
->
batchSize
)
{
return
false
;
}
return
true
;
return
true
;
}
}
...
@@ -383,7 +436,7 @@ bool dispatcherTryBatching(SAsyncBulkWriteDispatcher* dispatcher, SSqlObj* pSql)
...
@@ -383,7 +436,7 @@ bool dispatcherTryBatching(SAsyncBulkWriteDispatcher* dispatcher, SSqlObj* pSql)
}
}
// the sql object doesn't support bulk insertion.
// the sql object doesn't support bulk insertion.
if
(
!
tscSupportBulkInsertion
(
pSql
))
{
if
(
!
tscSupportBulkInsertion
(
dispatcher
,
pSql
))
{
return
false
;
return
false
;
}
}
...
@@ -397,11 +450,11 @@ bool dispatcherTryBatching(SAsyncBulkWriteDispatcher* dispatcher, SSqlObj* pSql)
...
@@ -397,11 +450,11 @@ bool dispatcherTryBatching(SAsyncBulkWriteDispatcher* dispatcher, SSqlObj* pSql)
if
(
currentSize
<
0
)
{
if
(
currentSize
<
0
)
{
return
false
;
return
false
;
}
}
// the buffer is full or reach batch size.
if
(
atomic_load_8
(
&
dispatcher
->
shutdown
)
||
currentSize
>=
dispatcher
->
batchSize
)
{
if
(
currentSize
>=
dispatcher
->
batchSize
)
{
SArray
*
statements
=
dispatcherPollAll
(
dispatcher
);
SArray
*
statements
=
dispatcherPollAll
(
dispatcher
);
dispatcherExecute
(
statements
);
dispatcherExecute
(
statements
);
taosArrayDestroy
(
&
statements
);
}
}
return
true
;
return
true
;
}
}
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录