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()
 | |
| 
 | |
| 
 | 
