add rollback interval

This commit is contained in:
dfcao 2017-12-15 11:43:23 +08:00
parent 9a14642281
commit 1201a85406
3 changed files with 32 additions and 29 deletions

View File

@ -92,11 +92,13 @@ UPDATE `test`.`test3` SET `addtime`='2016-12-10 13:03:22', `data`='中文', `id`
-K, --no-primary-key 对INSERT语句去除主键。可选。 -K, --no-primary-key 对INSERT语句去除主键。可选。
-B, --flashback 生成回滚语句可解析大文件不受内存限制每打印一千行加一句SELECT SLEEP(1)。可选。与stop-never或no-primary-key不能同时添加。 -B, --flashback 生成回滚语句可解析大文件不受内存限制。可选。与stop-never或no-primary-key不能同时添加。
--back-interval -B模式下每打印一千行回滚语句加一句SLEEP多少秒如果不需要SLEEP请设为0。可选。默认1.0。
**解析范围控制** **解析范围控制**
--start-file 起始解析文件。必须。 --start-file 起始解析文件,只需文件名,无需全路径 。必须。
--start-position/--start-pos start-file的起始解析位置。可选。默认为start-file的起始位置。 --start-position/--start-pos start-file的起始解析位置。可选。默认为start-file的起始位置。
@ -114,6 +116,7 @@ UPDATE `test`.`test3` SET `addtime`='2016-12-10 13:03:22', `data`='中文', `id`
-t, --tables 只输出目标tables的sql。可选。默认为空。 -t, --tables 只输出目标tables的sql。可选。默认为空。
### 应用案例 ### 应用案例
#### **误删整张表数据,需要紧急回滚** #### **误删整张表数据,需要紧急回滚**

View File

@ -11,15 +11,14 @@ from pymysqlreplication.row_event import (
DeleteRowsEvent, DeleteRowsEvent,
) )
from pymysqlreplication.event import QueryEvent, RotateEvent, FormatDescriptionEvent from pymysqlreplication.event import QueryEvent, RotateEvent, FormatDescriptionEvent
from binlog2sql_util import command_line_args, concat_sql_from_binlog_event, create_unique_file, \ from binlog2sql_util import command_line_args, concat_sql_from_binlog_event, create_unique_file, temp_open, reversed_lines
temp_open, print_rollback_sql
class Binlog2sql(object): class Binlog2sql(object):
def __init__(self, connection_settings, start_file=None, start_pos=None, end_file=None, end_pos=None, def __init__(self, connection_settings, start_file=None, start_pos=None, end_file=None, end_pos=None,
start_time=None, stop_time=None, only_schemas=None, only_tables=None, no_pk=False, start_time=None, stop_time=None, only_schemas=None, only_tables=None, no_pk=False,
flashback=False, stop_never=False): flashback=False, stop_never=False, back_interval=1.0):
""" """
conn_setting: {'host': 127.0.0.1, 'port': 3306, 'user': user, 'passwd': passwd, 'charset': 'utf8'} conn_setting: {'host': 127.0.0.1, 'port': 3306, 'user': user, 'passwd': passwd, 'charset': 'utf8'}
""" """
@ -43,7 +42,7 @@ class Binlog2sql(object):
self.only_schemas = only_schemas if only_schemas else None self.only_schemas = only_schemas if only_schemas else None
self.only_tables = only_tables if only_tables else None self.only_tables = only_tables if only_tables else None
self.no_pk, self.flashback, self.stop_never = (no_pk, flashback, stop_never) self.no_pk, self.flashback, self.stop_never, self.back_interval = (no_pk, flashback, stop_never, back_interval)
self.binlogList = [] self.binlogList = []
self.connection = pymysql.connect(**self.conn_setting) self.connection = pymysql.connect(**self.conn_setting)
@ -122,9 +121,24 @@ class Binlog2sql(object):
stream.close() stream.close()
f_tmp.close() f_tmp.close()
if self.flashback: if self.flashback:
print_rollback_sql(filename=tmp_file) self.print_rollback_sql(filename=tmp_file)
return True return True
def print_rollback_sql(self, filename):
"""print rollback sql from tmp_file"""
with open(filename, "rb") as f_tmp:
batch_size = 1000
i = 0
for line in reversed_lines(f_tmp):
print(line.rstrip())
if i >= batch_size:
i = 0
if self.back_interval:
print('SELECT SLEEP(%s);' % self.back_interval)
else:
i += 1
def __del__(self): def __del__(self):
pass pass
@ -135,5 +149,6 @@ if __name__ == '__main__':
binlog2sql = Binlog2sql(connection_settings=conn_setting, start_file=args.start_file, start_pos=args.start_pos, binlog2sql = Binlog2sql(connection_settings=conn_setting, start_file=args.start_file, start_pos=args.start_pos,
end_file=args.end_file, end_pos=args.end_pos, start_time=args.start_time, end_file=args.end_file, end_pos=args.end_pos, start_time=args.start_time,
stop_time=args.stop_time, only_schemas=args.databases, only_tables=args.tables, stop_time=args.stop_time, only_schemas=args.databases, only_tables=args.tables,
no_pk=args.no_pk, flashback=args.flashback, stop_never=args.stop_never) no_pk=args.no_pk, flashback=args.flashback, stop_never=args.stop_never,
back_interval=args.back_interval)
binlog2sql.process_binlog() binlog2sql.process_binlog()

View File

@ -78,14 +78,13 @@ def parse_args():
"shell to set it properly).", default='') "shell to set it properly).", default='')
interval.add_argument('--stop-datetime', dest='stop_time', type=str, interval.add_argument('--stop-datetime', dest='stop_time', type=str,
help="Stop reading the binlog at first event having a datetime equal or posterior " help="Stop reading the binlog at first event having a datetime equal or posterior "
"to the argument; the argument must be a date and time in the local time zone," "to the argument;", default='')
" in any format accepted by the MySQL server for DATETIME and TIMESTAMP types,"
" for example: 2004-12-25 11:25:56 (you should probably use quotes for your "
"shell to set it properly).", default='')
parser.add_argument('--stop-never', dest='stop_never', action='store_true', parser.add_argument('--stop-never', dest='stop_never', action='store_true',
help="Wait for more data from the server. default: stop replicate at the last binlog" help="Wait for more data from the server. default: stop replicate at the last binlog "
" when you start binlog2sql", default=False) "when you start binlog2sql", default=False)
parser.add_argument('--back-interval', dest='back_interval', type=float,
help="Sleep time between chunks of 1000 rollback sql. If you do not need sleep between chunks, "
" set it to 0", default=1.0)
parser.add_argument('--help', dest='help', action='store_true', help='help information', default=False) parser.add_argument('--help', dest='help', action='store_true', help='help information', default=False)
schema = parser.add_argument_group('schema filter') schema = parser.add_argument_group('schema filter')
@ -217,20 +216,6 @@ def generate_sql_pattern(binlog_event, row=None, flashback=False, no_pk=False):
return {'template': template, 'values': list(values)} return {'template': template, 'values': list(values)}
def print_rollback_sql(filename):
"""print rollback sql from tmp_file"""
with open(filename, "rb") as f_tmp:
sleep_interval = 1000
i = 0
for line in reversed_lines(f_tmp):
print(line.rstrip())
if i >= sleep_interval:
print('SELECT SLEEP(1);')
i = 0
else:
i += 1
def reversed_lines(fin): def reversed_lines(fin):
"""Generate the lines of file in reverse order.""" """Generate the lines of file in reverse order."""
part = '' part = ''