259 lines
7.0 KiB
Python
Executable File
259 lines
7.0 KiB
Python
Executable File
#!/usr/bin/python
|
|
# coding=utf8
|
|
import os
|
|
import argparse
|
|
import mysql.connector
|
|
import sys
|
|
|
|
class Config:
|
|
pass
|
|
|
|
g_config = Config()
|
|
|
|
class Stat:
|
|
def reset(self):
|
|
self.db_count = 0
|
|
self.outline_count = 0
|
|
|
|
def __init__(self):
|
|
self.reset()
|
|
|
|
|
|
g_stat = Stat()
|
|
|
|
class ImportStat:
|
|
def reset(self):
|
|
self.succ_db_count = 0
|
|
self.fail_db_count = 0
|
|
self.succ_outline_count = 0
|
|
self.fail_outline_count = 0
|
|
|
|
def __init__(self):
|
|
self.reset()
|
|
|
|
|
|
g_import_stat = ImportStat()
|
|
|
|
#参数
|
|
#-h -P -u -p -t -i -d
|
|
#如果-t没指定就是所有租户
|
|
#
|
|
#-d 表示dump
|
|
#-i 表示import
|
|
|
|
#查询__all_server表。获取有多少台server, 设置并发度
|
|
#设置查询超时时间
|
|
#查询GV$OB_PLAN_CACHE_PLAN_STAT表获取outline_data
|
|
#
|
|
#select sql_id, sql_text, outline_data from GV$OB_PLAN_CACHE_PLAN_STAT。检查sql_id是否有冲突,outline_data是否有冲突//获取对应的database。
|
|
#
|
|
#dump成outline语句, 生成对应的database。
|
|
#生成outline语句
|
|
|
|
def get_connect():
|
|
return mysql.connector.connect(host = g_config.host, port = g_config.port, user = g_config.username, password = g_config.password)
|
|
|
|
def get_real_db_id(tenant_id, db_id):
|
|
if db_id == 1:
|
|
return tenant_id << 40 | db_id
|
|
else:
|
|
return db_id
|
|
|
|
def get_args(args):
|
|
parser = argparse.ArgumentParser(add_help = False)
|
|
parser.add_argument('-h', '--host', dest='host', type=str)
|
|
parser.add_argument('-P', '--port', dest='port', type=int)
|
|
parser.add_argument('-u', '--username', dest='username', type=str)
|
|
parser.add_argument('-p', '--password', dest='password', type=str)
|
|
parser.add_argument('-t', '--tenant', dest='tenant', type=int)
|
|
parser.add_argument('-d', '--dump', dest='dump', action='store_true')
|
|
parser.add_argument('-i', '--import', dest='import1', action='store_true')
|
|
ret = parser.parse_args(args)
|
|
|
|
if ret.host == None:
|
|
print >> sys.stderr, 'please give hostname: -h'
|
|
return -1
|
|
else:
|
|
g_config.host = ret.host
|
|
|
|
if ret.port == None:
|
|
print >> sys.stderr, 'please give port: -P'
|
|
return -1
|
|
else:
|
|
g_config.port = ret.port
|
|
|
|
if ret.username == None:
|
|
print >> sys.stderr, 'please give username: -u'
|
|
return -1
|
|
else:
|
|
g_config.username = ret.username
|
|
|
|
if ret.tenant == None:
|
|
print >> sys.stderr, 'please give tenant_id: -t'
|
|
return -1
|
|
else:
|
|
g_config.tenant = ret.tenant
|
|
|
|
g_config.password = ret.password
|
|
|
|
if ret.dump == False and ret.import1 == False:
|
|
print >> sys.stderr, 'please give dump or import: -d/-i'
|
|
return -1
|
|
elif ret.dump == True and ret.import1 == True:
|
|
print >> sys.stderr, 'only dump or import: -d/-i'
|
|
return -1
|
|
else:
|
|
g_config.dump = ret.dump
|
|
|
|
return 0
|
|
|
|
|
|
def output(name, sql_id, outline_data):
|
|
g_stat.outline_count += 1
|
|
print "create outline auto_gen_%s on '%s' using hint %s;" % (name, sql_id, outline_data)
|
|
|
|
def check(lines):
|
|
for i in range(1,len(lines)):
|
|
if lines[i][1] != lines[0][1]:
|
|
return False
|
|
elif lines[i][2] != lines[0][2]:
|
|
return False
|
|
return True
|
|
|
|
def get_db_name(db_id):
|
|
conn = get_connect()
|
|
cur = conn.cursor()
|
|
sql = "select database_name from oceanbase.__all_database where database_id = %d and tenant_id = %d" % (db_id, g_config.tenant)
|
|
cur.execute(sql)
|
|
rs = cur.fetchone()
|
|
return rs[0]
|
|
|
|
|
|
def dump_db_outline(db_id, items):
|
|
if db_id == 18446744073709551615:
|
|
for item in items:
|
|
print >> sys.stderr, "sql_id = %s | sql_text = %s : no use database" % (item[0], item[1])
|
|
return
|
|
db_name = get_db_name(db_id)
|
|
g_stat.db_count += 1
|
|
print
|
|
print "use %s;" % db_name
|
|
map = {}
|
|
for line in items:
|
|
sql_id = line[0]
|
|
sql_text = line[1]
|
|
outline_data = line[2]
|
|
|
|
if sql_id in map:
|
|
map[sql_id].append((sql_id, sql_text, outline_data))
|
|
else:
|
|
map[sql_id] = [(sql_id, sql_text, outline_data)]
|
|
|
|
count = 0
|
|
for k, v in map.items():
|
|
name = '%d_%s%d' % (g_config.tenant, db_name, count)
|
|
if len(v) == 1:
|
|
output(name, v[0][0], v[0][2])
|
|
else:
|
|
if check(v):
|
|
output(name, v[0][0], v[0][2])
|
|
else:
|
|
print >> sys.stderr, "sql_id = %s has conflict" % (v[0][0])
|
|
count += 1
|
|
|
|
|
|
def dump_outline():
|
|
conn = get_connect()
|
|
cur = conn.cursor()
|
|
cur.execute('select count(1) from oceanbase.__all_server')
|
|
rs = cur.fetchone()
|
|
server_count = rs[0]
|
|
cur.execute('select db_id, sql_id, statement, outline_data from oceanbase.GV$OB_PLAN_CACHE_PLAN_STAT where tenant_id = %d order by db_id' % g_config.tenant)
|
|
rs = cur.fetchall()
|
|
last_db_id = 0
|
|
items = []
|
|
for i in range(0, len(rs)):
|
|
db_id = get_real_db_id(1, rs[i][0])
|
|
if db_id == last_db_id:
|
|
items.append(rs[i][1:])
|
|
else:
|
|
if len(items) != 0:
|
|
dump_db_outline(last_db_id, items)
|
|
items = []
|
|
last_db_id = db_id
|
|
items.append(rs[i][1:])
|
|
if len(items) != 0:
|
|
dump_db_outline(last_db_id, items)
|
|
items = []
|
|
print >> sys.stderr, "%d database and %d outline dumped" % (g_stat.db_count, g_stat.outline_count)
|
|
|
|
#导入outline。判断outline是否存在。如果存在,那么就不导入了。
|
|
#
|
|
#查询__all_outline表。判断是否全部正确导入。
|
|
#
|
|
#输出导入信息。
|
|
#1. 总共导入了多少outline, 之前已经存在多少outline
|
|
#2. 中间有冲突的信息输出
|
|
|
|
def import_outline():
|
|
conn = get_connect()
|
|
cur = conn.cursor()
|
|
cur.execute("select effective_tenant_id()")
|
|
rs = cur.fetchone()
|
|
if rs[0] != g_config.tenant:
|
|
print >> sys.stderr, 'tenant id not equal %d <> %d' % (rs[0], g_config.tenant)
|
|
sys.exit(-1)
|
|
|
|
state = 0
|
|
for line in sys.stdin:
|
|
line = line.strip()
|
|
if len(line) != 0 and line[0] != '#':
|
|
if len(line) >= 3 and line[:3] == 'use':
|
|
print >> sys.stderr, 'change database: %s' % line
|
|
try:
|
|
cur.execute(line)
|
|
state = 0
|
|
g_import_stat.succ_db_count += 1
|
|
except:
|
|
g_import_stat.fail_db_count += 1
|
|
print >> sys.stderr, 'fail to execute: %s' % line
|
|
state = 1
|
|
else:
|
|
if state == 0:
|
|
try:
|
|
cur.execute(line)
|
|
g_import_stat.succ_outline_count += 1
|
|
except:
|
|
print >> sys.stderr, 'fail to execute: %s' % line
|
|
g_import_stat.fail_outline_count += 1
|
|
else:
|
|
g_import_stat.fail_outline_count += 1
|
|
print >> sys.stderr, 'skip to execute: %s' % line
|
|
print >> sys.stderr, "db succ %d | db fail %d | outline succ %d | outline fail %d" % (g_import_stat.succ_db_count, g_import_stat.fail_db_count, g_import_stat.succ_outline_count, g_import_stat.fail_outline_count)
|
|
|
|
|
|
if __name__ == '__main__':
|
|
if -1 == get_args(sys.argv[1:]):
|
|
sys.exit(-1)
|
|
|
|
if g_config.dump:
|
|
conn = get_connect()
|
|
cur = conn.cursor()
|
|
cur.execute("select effective_tenant_id()")
|
|
rs = cur.fetchone()
|
|
if rs[0] != 1:
|
|
print >> sys.stderr, 'please use sys tenant to dump'
|
|
sys.exit(-1)
|
|
|
|
cur.execute("select * from oceanbase.__all_tenant where tenant_id = %d" % g_config.tenant)
|
|
rs = cur.fetchall()
|
|
if 1 != len(rs):
|
|
print >> sys.stderr, 'no such tenant_id %d ' % g_config.tenant
|
|
sys.exit(-1)
|
|
|
|
dump_outline()
|
|
else:
|
|
import_outline()
|
|
|
|
|