主要逻辑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| // 合法性检查 // 包括:是否有外键、用户权限、表是否合法、是否有唯一键等 // 创建变更记录表 CREATE /* changelog table */ TABLE _tbs_c // 创建影子表 CREATE /* shadow table */ TABLE _tbl_s LIKE tbl // 在影子表上应用alter语句 ALTER TABLE _tbl_s STATEMENT // 开始行拷贝线程 tbl -> _tbl_s // 开始binlog接收和应用线程 binlog -> _tbl_s // 等待行拷贝线程完成 // 通知binlog线程收工 // 等待binlog线程结束 // 开始切换 LOCK TABLES tbl WRITE RENAME TABLE tbl TO _tbl_old, _tbl_s TO tbl UNLOCK TABLES
|
确定行拷贝chunk范围
1 2 3
| select id from (select id from a where id>=0 and id<=3001 order by id asc limit 1000) select_osc_chunk order by id desc limit 1;
|
行拷贝in chunk
1 2 3 4 5 6 7
| begin; insert ignore into `a`.`_a_gho` (`id`, `value`) (select `id`, `value` from `a`.`a` force index (`PRIMARY`) where (((`id` > ?) or ((`id` = ?))) and ((`id` < ?) or ((`id` = ?)))) lock in share mode ) commit;
|
关键点
async binlog worker如何判断所有数据变更已经完成
binlog worker向changelog table发一行记录,在收到这个记录时,即表示完成
RENAME race condition with DML
mysql内部保证,LOCK TABLE后,如果有DML与RENAME并发操作,那么在UNLOCK TABLES时,RENAME
一定获取最高优先级,即:RENAME一定会先执行。
否则,会丢数据:
1 2 3 4 5 6 7
| LOCK TABLE WRITE INSERT // blocked RENAME // blocked UNLOCK TABLE INERT // 如果INSERT先执行,那么它会插入原表 RENAME // 原表被rename to tbl_old,刚才INSERT的数据丢失: 存放在了tbl_old
|
LOCK, RENAME
如果在一个mysql连接内执行LOCK; RENAME,那么会失败
解决办法:创建2个mysql连接,分别执行LOCK和RENAME