Flashback - MariaDB Knowledge Base
"Common use case" をとっても雑に説明すると、
- `--flashback` をつけたmysqldが吐いたバイナリーログに対して
- `mysqlbinlog --flashback` でデコードすると、フラッシュバックっぽいことができる
という感じ。
まず、サーバー側の `--flashback` について。
https://github.com/MariaDB/server/blob/mariadb-10.2.4/sql/mysqld.cc#L9541-L9551
binlog_format= ROWにセットしてくれるだけぽい。 `--flashback` じゃなくても `--log-bin --binlog_format=ROW --binlog-row-format=FULL` で吐かせたバイナリーログでも大丈夫だった。ので、特に気にしなくて良さそう。
mysqlbinlog側の `--flashback` が肝。
https://github.com/MariaDB/server/blob/mariadb-10.2.4/client/mysqlbinlog.cc#L1455-L1468
↑で順番にイベントを読み込んでバッファに入れておいたものを(この時点でchange_to_flashback_eventを呼んでフラッシュバック用にクエリーを書き換えているぽい)
↓で後ろから順番に取り出す。
https://github.com/MariaDB/server/blob/mariadb-10.2.4/client/mysqlbinlog.cc#L3019-L3034
バイナリーログのイベントを逆転させてるのは↓のあたり。
https://github.com/MariaDB/server/blob/mariadb-10.2.4/sql/log_event.cc#L3417-L3460
というわけで、
MariaDB [(none)]> use d2; MariaDB [d2]> create table t2 (num serial, val varchar(32)); MariaDB [d2]> INSERT INTO t2 VALUES (1, 'eins'); MariaDB [d2]> UPDATE t2 SET val = 'one' WHERE num = 1;
なんてことをやったbinlogを見ると、
C:\Users\yoku0825\Desktop\mariadb-10.2.4-winx64>bin\mysqlbinlog.exe -vv data\myhost-bin.000002 .. use `d2`/*!*/; SET TIMESTAMP=1487580544/*!*/; create table t2 (num serial, val varchar(32)) /*!*/; # at 745 #170220 17:49:20 server id 1 end_log_pos 787 CRC32 0x3a401e2f GTID 0-1-9 trans /*!100001 SET @@session.gtid_seq_no=9*//*!*/; BEGIN /*!*/; # at 787 # at 843 #170220 17:49:20 server id 1 end_log_pos 843 CRC32 0xee91dd13 Annotate_rows: #Q> INSERT INTO t2 VALUES (1, 'eins') #170220 17:49:20 server id 1 end_log_pos 889 CRC32 0xfac503f9 Table_map: `d2`.`t2` mapped to number 23 # at 889 #170220 17:49:20 server id 1 end_log_pos 936 CRC32 0x9cc43e21 Write_rows: table id 23 flags: STMT_END_F BINLOG ' kK2qWBMBAAAALgAAAHkDAAAAABcAAAAAAAEAAmQyAAJ0MgACCA8CIAAC+QPF+g== kK2qWBcBAAAALwAAAKgDAAAAABcAAAAAAAEAAv/8AQAAAAAAAAAEZWlucyE+xJw= '/*!*/; ### INSERT INTO `d2`.`t2` ### SET ### @1=1 /* LONGINT meta=0 nullable=0 is_null=0 */ ### @2='eins' /* VARSTRING(32) meta=32 nullable=1 is_null=0 */ # at 936 #170220 17:49:20 server id 1 end_log_pos 967 CRC32 0x7e5f60b7 Xid = 9 COMMIT/*!*/; # at 967 #170220 17:49:31 server id 1 end_log_pos 1009 CRC32 0x55d0a0bc GTID 0-1-10 trans /*!100001 SET @@session.gtid_seq_no=10*//*!*/; BEGIN /*!*/; # at 1009 # at 1071 #170220 17:49:31 server id 1 end_log_pos 1071 CRC32 0xb32de27c Annotate_rows: #Q> UPDATE t2 SET val = 'one' WHERE num = 1 #170220 17:49:31 server id 1 end_log_pos 1117 CRC32 0x4ee231f4 Table_map: `d2`.`t2` mapped to number 23 # at 1117 #170220 17:49:31 server id 1 end_log_pos 1178 CRC32 0xe87e056f Update_rows: table id 23 flags: STMT_END_F BINLOG ' m62qWBMBAAAALgAAAF0EAAAAABcAAAAAAAEAAmQyAAJ0MgACCA8CIAAC9DHiTg== m62qWBgBAAAAPQAAAJoEAAAAABcAAAAAAAEAAv///AEAAAAAAAAABGVpbnP8AQAAAAAAAAADb25l bwV+6A== '/*!*/; ### UPDATE `d2`.`t2` ### WHERE ### @1=1 /* LONGINT meta=0 nullable=0 is_null=0 */ ### @2='eins' /* VARSTRING(32) meta=32 nullable=1 is_null=0 */ ### SET ### @1=1 /* LONGINT meta=0 nullable=0 is_null=0 */ ### @2='one' /* VARSTRING(32) meta=32 nullable=1 is_null=0 */ # at 1178 #170220 17:49:31 server id 1 end_log_pos 1209 CRC32 0xdd417c80 Xid = 10 COMMIT/*!*/; ..
これが、 `--flashback` をつけるとこうなる。
C:\Users\yoku0825\Desktop\mariadb-10.2.4-winx64>bin\mysqlbinlog.exe --flashback -vv data\myhost-bin.000002 .. BEGIN/*!*/; #170220 17:49:31 server id 1 end_log_pos 1178 CRC32 0xe87e056f Update_rows: table id 23 flags: STMT_END_F BINLOG ' m62qWBMBAAAALgAAAF0EAAAAABcAAAAAAAEAAmQyAAJ0MgACCA8CIAAC9DHiTg== m62qWBgBAAAAPQAAAJoEAAAAABcAAAAAAAEAAv///AEAAAAAAAAAA29uZfwBAAAAAAAAAARlaW5z bwV+6A== '/*!*/; ### UPDATE `d2`.`t2` ### WHERE ### @1=1 /* LONGINT meta=0 nullable=0 is_null=0 */ ### @2='one' /* VARSTRING(32) meta=32 nullable=1 is_null=0 */ ### SET ### @1=1 /* LONGINT meta=0 nullable=0 is_null=0 */ ### @2='eins' /* VARSTRING(32) meta=32 nullable=1 is_null=0 */ COMMIT /*!*/; #170220 17:49:20 server id 1 end_log_pos 967 CRC32 0x7e5f60b7 Xid = 9 BEGIN/*!*/; #170220 17:49:20 server id 1 end_log_pos 936 CRC32 0x9cc43e21 Delete_rows: table id 23 flags: STMT_END_F BINLOG ' kK2qWBMBAAAALgAAAHkDAAAAABcAAAAAAAEAAmQyAAJ0MgACCA8CIAAC+QPF+g== kK2qWBkBAAAALwAAAKgDAAAAABcAAAAAAAEAAv/8AQAAAAAAAAAEZWlucyE+xJw= '/*!*/; ### DELETE FROM `d2`.`t2` ### WHERE ### @1=1 /* LONGINT meta=0 nullable=0 is_null=0 */ ### @2='eins' /* VARSTRING(32) meta=32 nullable=1 is_null=0 */ COMMIT /*!*/; ..
`--flashback` の方は時間降順に並んでいるのがちょっと面白い。
これで、`--start-datetime` で時間を指定してやれば、それ以降のDMLをフラッシュバック(個人的にはリバートと呼びたい)するためのDMLが手に入って、それを適用すればフラッシュバック(個人的には略)完了。
RBRだからそれなりには時間がかかるはず。やっぱリバートで良いじゃん。。
デフォルトのbinlog-row-imageはfullなので、変更前後をすべて記録していてます。なので通常変更前→変更後、を変更後をキーに変更前、に戻していくんじゃないですかね? https://t.co/dnyg3Qbe5Q
— 君の名は? シン明治! (@meijik) 2017年2月6日
めいじさんエスパー! :)
この辺( `--review` みたいなのがある)は後々なのかな(このマクロが有効化されてる箇所は見当たらなかった)
https://github.com/MariaDB/server/blob/mariadb-10.2.4/client/mysqlbinlog.cc#L1587-L1599