Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
慢慢CG
TDengine
提交
2d76c467
T
TDengine
项目概览
慢慢CG
/
TDengine
与 Fork 源项目一致
Fork自
taosdata / TDengine
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
T
TDengine
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
提交
2d76c467
编写于
5月 03, 2020
作者:
S
Steven Li
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Added per-thread-db-connection option, after getting Python argparse
上级
24ad275d
变更
2
隐藏空白更改
内联
并排
Showing
2 changed file
with
96 addition
and
49 deletion
+96
-49
tests/pytest/crash_gen.py
tests/pytest/crash_gen.py
+93
-47
tests/pytest/crash_gen.sh
tests/pytest/crash_gen.sh
+3
-2
未找到文件。
tests/pytest/crash_gen.py
浏览文件 @
2d76c467
...
...
@@ -13,6 +13,7 @@
# -*- coding: utf-8 -*-
import
sys
import
getopt
import
argparse
import
threading
import
random
...
...
@@ -26,11 +27,11 @@ from util.sql import *
import
taos
# Constants
LOGGING_LEVEL
=
logging
.
DEBUG
def
runThread
(
workerThread
):
logger
.
info
(
"Running Thread: {}"
.
format
(
workerThread
.
tid
))
# Command-line/Environment Configurations
gConfig
=
None
# will set a bit later
def
runThread
(
workerThread
):
workerThread
.
run
()
# Used by one process to block till another is ready
...
...
@@ -63,36 +64,42 @@ def runThread(workerThread):
class
WorkerThread
:
def
__init__
(
self
,
pool
,
tid
,
dbState
):
# note: main thread context!
self
.
curStep
=
-
1
self
.
pool
=
pool
self
.
tid
=
tid
self
.
dbState
=
dbState
self
.
_
curStep
=
-
1
self
.
_
pool
=
pool
self
.
_
tid
=
tid
self
.
_
dbState
=
dbState
# self.threadIdent = threading.get_ident()
self
.
thread
=
threading
.
Thread
(
target
=
runThread
,
args
=
(
self
,))
self
.
stepGate
=
threading
.
Event
()
self
.
_
thread
=
threading
.
Thread
(
target
=
runThread
,
args
=
(
self
,))
self
.
_
stepGate
=
threading
.
Event
()
# Let us have a DB connection of our own
self
.
_dbConn
=
DbConn
()
if
(
gConfig
.
per_thread_db_connection
):
self
.
_dbConn
=
DbConn
()
def
start
(
self
):
self
.
thread
.
start
()
# AFTER the thread is recorded
self
.
_
thread
.
start
()
# AFTER the thread is recorded
def
run
(
self
):
# initialization after thread starts, in the thread context
# self.isSleeping = False
self
.
_dbConn
.
open
()
logger
.
info
(
"Starting to run thread: {}"
.
format
(
self
.
_tid
))
if
(
gConfig
.
per_thread_db_connection
):
self
.
_dbConn
.
open
()
# self._dbConn.resetDb()
while
self
.
curStep
<
self
.
pool
.
maxSteps
:
while
self
.
_curStep
<
self
.
_
pool
.
maxSteps
:
# stepNo = self.pool.waitForStep() # Step to run
self
.
crossStepGate
()
# self.curStep will get incremented
self
.
doWork
()
# clean up
self
.
_dbConn
.
close
()
if
(
gConfig
.
per_thread_db_connection
):
self
.
_dbConn
.
close
()
def
verifyThreadSelf
(
self
):
# ensure we are called by this own thread
if
(
threading
.
get_ident
()
!=
self
.
thread
.
ident
):
if
(
threading
.
get_ident
()
!=
self
.
_
thread
.
ident
):
raise
RuntimeError
(
"Unexpectly called from other threads"
)
def
verifyThreadMain
(
self
):
# ensure we are called by the main thread
...
...
@@ -100,7 +107,7 @@ class WorkerThread:
raise
RuntimeError
(
"Unexpectly called from other threads"
)
def
verifyThreadAlive
(
self
):
if
(
not
self
.
thread
.
is_alive
()
):
if
(
not
self
.
_
thread
.
is_alive
()
):
raise
RuntimeError
(
"Unexpected dead thread"
)
# def verifyIsSleeping(self, isSleeping):
...
...
@@ -113,30 +120,30 @@ class WorkerThread:
self
.
verifyThreadSelf
()
# only allowed by ourselves
# self.verifyIsSleeping(False) # has to be awake
logger
.
debug
(
"Worker thread {} about to cross pool barrier"
.
format
(
self
.
tid
))
logger
.
debug
(
"Worker thread {} about to cross pool barrier"
.
format
(
self
.
_
tid
))
# self.isSleeping = True # TODO: maybe too early?
self
.
pool
.
crossPoolBarrier
()
# wait for all other threads
self
.
_
pool
.
crossPoolBarrier
()
# wait for all other threads
# Wait again at the "gate", waiting to be "tapped"
logger
.
debug
(
"Worker thread {} about to cross the step gate"
.
format
(
self
.
tid
))
logger
.
debug
(
"Worker thread {} about to cross the step gate"
.
format
(
self
.
_
tid
))
# self.stepGate.acquire() # acquire lock immediately
self
.
stepGate
.
wait
()
self
.
stepGate
.
clear
()
self
.
_
stepGate
.
wait
()
self
.
_
stepGate
.
clear
()
# self.stepGate.release() # release
logger
.
debug
(
"Worker thread {} woke up"
.
format
(
self
.
tid
))
logger
.
debug
(
"Worker thread {} woke up"
.
format
(
self
.
_
tid
))
# Someone will wake us up here
self
.
curStep
+=
1
# off to a new step...
self
.
_
curStep
+=
1
# off to a new step...
def
tapStepGate
(
self
):
# give it a tap, release the thread waiting there
self
.
verifyThreadAlive
()
self
.
verifyThreadMain
()
# only allowed for main thread
# self.verifyIsSleeping(True) # has to be sleeping
logger
.
debug
(
"Tapping worker thread {}"
.
format
(
self
.
tid
))
logger
.
debug
(
"Tapping worker thread {}"
.
format
(
self
.
_
tid
))
# self.stepGate.acquire()
# logger.debug("Tapping worker thread {}, lock acquired".format(self.tid))
self
.
stepGate
.
set
()
# wake up!
self
.
_
stepGate
.
set
()
# wake up!
# logger.debug("Tapping worker thread {}, notified!".format(self.tid))
# self.isSleeping = False # No race condition for sure
# self.stepGate.release() # this finishes before .wait() can return
...
...
@@ -144,12 +151,15 @@ class WorkerThread:
time
.
sleep
(
0
)
# let the released thread run a bit, IMPORTANT, do it after release
def
doWork
(
self
):
logger
.
info
(
" Step {}, thread {}: "
.
format
(
self
.
curStep
,
self
.
tid
))
self
.
pool
.
dispatcher
.
doWork
(
self
)
logger
.
info
(
" Step {}, thread {}: "
.
format
(
self
.
_curStep
,
self
.
_
tid
))
self
.
_
pool
.
dispatcher
.
doWork
(
self
)
def
execSql
(
self
,
sql
):
return
self
.
dbState
.
execSql
(
sql
)
if
(
gConfig
.
per_thread_db_connection
):
return
self
.
_dbConn
.
execSql
(
sql
)
else
:
return
self
.
_dbState
.
getDbConn
().
execSql
(
sql
)
# We define a class to run a number of threads in locking steps.
class
SteppingThreadPool
:
...
...
@@ -188,7 +198,7 @@ class SteppingThreadPool:
# The threads will run through many steps
for
workerThread
in
self
.
threadList
:
workerThread
.
thread
.
join
()
# slight hack, accessing members
workerThread
.
_
thread
.
join
()
# slight hack, accessing members
logger
.
info
(
"All threads finished"
)
...
...
@@ -240,10 +250,15 @@ class LinearQueue():
def
pop
(
self
):
with
self
.
_lock
:
if
(
self
.
isEmpty
()
):
raise
RuntimeError
(
"Cannot pop an empty queue"
)
# raise RuntimeError("Cannot pop an empty queue")
return
False
# TODO: None?
index
=
self
.
firstIndex
if
(
index
in
self
.
inUse
):
self
.
inUse
.
remove
(
index
)
# TODO: what about discard?
return
False
# if ( index in self.inUse ):
# self.inUse.remove(index) # TODO: what about discard?
self
.
firstIndex
+=
1
return
index
...
...
@@ -259,13 +274,15 @@ class LinearQueue():
def
allocate
(
self
,
i
):
with
self
.
_lock
:
# logger.debug("LQ allocating item {}".format(i))
if
(
i
in
self
.
inUse
):
raise
RuntimeError
(
"Cannot re-use same index in queue: {}"
.
format
(
i
))
self
.
inUse
.
add
(
i
)
def
release
(
self
,
i
):
with
self
.
_lock
:
self
.
inUse
.
remove
(
i
)
# KeyError possible
# logger.debug("LQ releasing item {}".format(i))
self
.
inUse
.
remove
(
i
)
# KeyError possible, TODO: why?
def
size
(
self
):
return
self
.
lastIndex
+
1
-
self
.
firstIndex
...
...
@@ -287,6 +304,8 @@ class LinearQueue():
class
DbConn
:
def
__init__
(
self
):
self
.
_conn
=
None
self
.
_cursor
=
None
self
.
isOpen
=
False
def
open
(
self
):
# Open connection
...
...
@@ -294,16 +313,27 @@ class DbConn:
raise
RuntimeError
(
"Cannot re-open an existing DB connection"
)
cfgPath
=
"../../build/test/cfg"
conn
=
taos
.
connect
(
host
=
"127.0.0.1"
,
config
=
cfgPath
)
# TODO: make configurable
self
.
_conn
=
taos
.
connect
(
host
=
"127.0.0.1"
,
config
=
cfgPath
)
# TODO: make configurable
self
.
_cursor
=
self
.
_conn
.
cursor
()
# Get the connection/cursor ready
self
.
_cursor
.
execute
(
'reset query cache'
)
# self._cursor.execute('use db')
# Open connection
self
.
_tdSql
=
TDSql
()
self
.
_tdSql
.
init
(
conn
.
cursor
()
)
self
.
_tdSql
.
init
(
self
.
_cursor
)
self
.
isOpen
=
True
def
resetDb
(
self
):
# reset the whole database, etc.
if
(
not
self
.
isOpen
):
raise
RuntimeError
(
"Cannot reset database until connection is open"
)
self
.
_tdSql
.
prepare
()
# Recreate database, etc.
# self._tdSql.prepare() # Recreate database, etc.
self
.
_cursor
.
execute
(
'drop database if exists db'
)
self
.
_cursor
.
execute
(
'create database db'
)
# self._cursor.execute('use db')
# tdSql.execute('show databases')
def
close
(
self
):
...
...
@@ -312,7 +342,9 @@ class DbConn:
self
.
_tdSql
.
close
()
self
.
isOpen
=
False
def
execSql
(
self
,
sql
):
def
execSql
(
self
,
sql
):
if
(
not
self
.
isOpen
):
raise
RuntimeError
(
"Cannot query database until connection is open"
)
return
self
.
_tdSql
.
execute
(
sql
)
# State of the database as we believe it to be
...
...
@@ -328,6 +360,9 @@ class DbState():
self
.
_dbConn
.
open
()
self
.
_dbConn
.
resetDb
()
# drop and recreate DB
def
getDbConn
(
self
):
return
self
.
_dbConn
def
pickAndAllocateTable
(
self
):
# pick any table, and "use" it
return
self
.
tableNumQueue
.
pickAndAllocate
()
...
...
@@ -350,9 +385,10 @@ class DbState():
return
self
.
_lastInt
def
getTableNameToDelete
(
self
):
if
self
.
tableNumQueue
.
isEmpty
():
return
False
tblNum
=
self
.
tableNumQueue
.
pop
()
# TODO: race condition!
if
(
not
tblNum
):
# maybe false
return
False
return
"table_{}"
.
format
(
tblNum
)
def
execSql
(
self
,
sql
):
# using the main DB connection
...
...
@@ -375,7 +411,7 @@ class CreateTableTask(Task):
def
execute
(
self
,
wt
):
tIndex
=
dbState
.
addTable
()
logger
.
debug
(
" Creating a table {} ..."
.
format
(
tIndex
))
wt
.
execSql
(
"create table table_{} (ts timestamp, speed int)"
.
format
(
tIndex
))
wt
.
execSql
(
"create table
db.
table_{} (ts timestamp, speed int)"
.
format
(
tIndex
))
logger
.
debug
(
" Table {} created."
.
format
(
tIndex
))
dbState
.
releaseTable
(
tIndex
)
...
...
@@ -385,8 +421,8 @@ class DropTableTask(Task):
if
(
not
tableName
):
# May be "False"
logger
.
info
(
" Cannot generate a table to delete, skipping..."
)
return
logger
.
info
(
" Dropping a table {} ..."
.
format
(
tableName
))
wt
.
execSql
(
"drop table {}"
.
format
(
tableName
))
logger
.
info
(
" Dropping a table
db.
{} ..."
.
format
(
tableName
))
wt
.
execSql
(
"drop table
db.
{}"
.
format
(
tableName
))
class
AddDataTask
(
Task
):
def
execute
(
self
,
wt
):
...
...
@@ -396,7 +432,7 @@ class AddDataTask(Task):
if
(
tIndex
==
None
):
logger
.
info
(
" No table found to add data, skipping..."
)
return
sql
=
"insert into table_{} values ('{}', {});"
.
format
(
tIndex
,
ds
.
getNextTick
(),
ds
.
getNextInt
())
sql
=
"insert into
db.
table_{} values ('{}', {});"
.
format
(
tIndex
,
ds
.
getNextTick
(),
ds
.
getNextInt
())
logger
.
debug
(
" Executing SQL: {}"
.
format
(
sql
))
wt
.
execSql
(
sql
)
ds
.
releaseTable
(
tIndex
)
...
...
@@ -441,7 +477,7 @@ class WorkDispatcher():
# self.totalNumMethods = 2
self
.
tasks
=
[
CreateTableTask
(
dbState
),
#
DropTableTask(dbState),
DropTableTask
(
dbState
),
AddDataTask
(
dbState
),
]
...
...
@@ -457,14 +493,24 @@ class WorkDispatcher():
task
.
execute
(
workerThread
)
if
__name__
==
"__main__"
:
# Super cool Python argument library: https://docs.python.org/3/library/argparse.html
parser
=
argparse
.
ArgumentParser
(
description
=
'TDengine Auto Crash Generator'
)
parser
.
add_argument
(
'-p'
,
'--per-thread-db-connection'
,
action
=
'store_true'
,
help
=
'Use a single shared db connection (default: false)'
)
parser
.
add_argument
(
'-d'
,
'--debug'
,
action
=
'store_true'
,
help
=
'Turn on DEBUG mode for more logging (default: false)'
)
gConfig
=
parser
.
parse_args
()
logger
=
logging
.
getLogger
(
'myApp'
)
logger
.
setLevel
(
LOGGING_LEVEL
)
if
(
gConfig
.
debug
):
logger
.
setLevel
(
logging
.
DEBUG
)
# default seems to be INFO
ch
=
logging
.
StreamHandler
()
logger
.
addHandler
(
ch
)
Dice
.
seed
(
0
)
# initial seeding of dice
dbState
=
DbState
()
threadPool
=
SteppingThreadPool
(
dbState
,
3
,
5
,
0
)
threadPool
=
SteppingThreadPool
(
dbState
,
5
,
10
,
0
)
threadPool
.
run
()
logger
.
info
(
"Finished running thread pool"
)
dbState
.
cleanUp
()
...
...
tests/pytest/crash_gen.sh
浏览文件 @
2d76c467
...
...
@@ -9,6 +9,7 @@
# 3. Adjust the configuration file if needed under build/test/cfg/taos.cfg
# 4. Run the TDengine server instance: cd build; ./build/bin/taosd -c test/cfg
# 5. Make sure you have a working Python3 environment: run /usr/bin/python3 --version, and you should get 3.6 or above
# 6. Make sure you have the proper Python packages: # sudo apt install python3-setuptools python3-pip python3-distutils
#
# RUNNING THIS SCRIPT
#
...
...
@@ -36,5 +37,5 @@ export PYTHONPATH=$(pwd)/../../src/connector/python/linux/python3
# Then let us set up the library path so that our compiled SO file can be loaded by Python
export
LD_LIBRARY_PATH
=
$LD_LIBRARY_PATH
:
$(
pwd
)
/../../build/build/lib
# Now we are all let, and let's see if we can find a crash.
./crash_gen.py
# Now we are all let, and let's see if we can find a crash.
Note we pass all params
./crash_gen.py
$@
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录