95 lines
2.5 KiB
Python
95 lines
2.5 KiB
Python
"""
|
|
This script stress tests deadlock detection.
|
|
|
|
Usage: xengine_deadlock_stress.py user host port db_name table_name
|
|
num_iters num_threads
|
|
"""
|
|
import cStringIO
|
|
import hashlib
|
|
import MySQLdb
|
|
from MySQLdb.constants import ER
|
|
import os
|
|
import random
|
|
import signal
|
|
import sys
|
|
import threading
|
|
import time
|
|
import string
|
|
import traceback
|
|
|
|
def is_deadlock_error(exc):
|
|
error_code = exc.args[0]
|
|
return (error_code == MySQLdb.constants.ER.LOCK_DEADLOCK)
|
|
|
|
def get_query(table_name, idx):
|
|
# Let's assume that even indexes will always be acquireable, to make
|
|
# deadlock detection more interesting.
|
|
if idx % 2 == 0:
|
|
return """SELECT * from %s WHERE a = %d LOCK IN SHARE MODE""" % (table_name, idx)
|
|
else:
|
|
r = random.randint(1, 3);
|
|
if r == 1:
|
|
return """SELECT * from %s WHERE a = %d FOR UPDATE""" % (table_name, idx)
|
|
elif r == 2:
|
|
return """INSERT INTO %s VALUES (%d, 1)
|
|
ON DUPLICATE KEY UPDATE b=b+1""" % (table_name, idx)
|
|
else:
|
|
return """DELETE from %s WHERE a = %d""" % (table_name, idx)
|
|
|
|
class Worker(threading.Thread):
|
|
def __init__(self, con, table_name, num_iters):
|
|
threading.Thread.__init__(self)
|
|
self.con = con
|
|
self.table_name = table_name
|
|
self.num_iters = num_iters
|
|
self.exception = None
|
|
self.start()
|
|
def run(self):
|
|
try:
|
|
self.runme()
|
|
except Exception, e:
|
|
self.exception = traceback.format_exc()
|
|
def runme(self):
|
|
cur = self.con.cursor()
|
|
for x in xrange(self.num_iters):
|
|
try:
|
|
for i in random.sample(xrange(100), 10):
|
|
cur.execute(get_query(self.table_name, i))
|
|
self.con.commit()
|
|
except MySQLdb.OperationalError, e:
|
|
self.con.rollback()
|
|
cur = self.con.cursor()
|
|
if not is_deadlock_error(e):
|
|
raise e
|
|
|
|
if __name__ == '__main__':
|
|
if len(sys.argv) != 8:
|
|
print "Usage: xengine_deadlock_stress.py user host port db_name " \
|
|
"table_name num_iters num_threads"
|
|
sys.exit(1)
|
|
|
|
user = sys.argv[1]
|
|
host = sys.argv[2]
|
|
port = int(sys.argv[3])
|
|
db = sys.argv[4]
|
|
table_name = sys.argv[5]
|
|
num_iters = int(sys.argv[6])
|
|
num_workers = int(sys.argv[7])
|
|
|
|
worker_failed = False
|
|
workers = []
|
|
for i in xrange(num_workers):
|
|
w = Worker(
|
|
MySQLdb.connect(user=user, host=host, port=port, db=db), table_name,
|
|
num_iters)
|
|
workers.append(w)
|
|
|
|
for w in workers:
|
|
w.join()
|
|
if w.exception:
|
|
print "Worker hit an exception:\n%s\n" % w.exception
|
|
worker_failed = True
|
|
|
|
if worker_failed:
|
|
sys.exit(1)
|