July 2012

[MySQL 源码]MySQL5.1版本 lock table write与DML操作产生的MySQL层/Innodb层死锁

转载请署名:印风 ————————————- 当在set autocommit=0时,执行lock table write操作,如果此时有同一个表上进入Innodb层的DML,可能导致死锁,这种死锁MySQL不做检测,只能等待Innodb层超时,简单的分析如下: 1. 对于lock table write操作,backtrace如下: SQL :set aucommit = 0 && lock tables t1 write: mysql_execute_command     –>open_and_lock_tables_derived          –>simple_open_n_lock_tables             –>open_and_lock_tables_derived                 –>lock_tables                   –>mysql_lock_tables […]

[MySQL Bug] <=5.1.49 alter table rename 操作导致复制中断

转载请署名:印风 —————– 在我们传统的认识里,MySQL对于alter操作是隐式提交的,也就是说,执行一条Alter会直接写入binlog,而不等待commit。 这种看法在大多数情况下是正确的,但有一个例外,也就是alter table rename操作,在MySQL5.1.50之前,如果你设置了autocommit = 0 , 该DDL不会隐式提交,直到你显式的commit。 有意思的是,官方的修复初衷并不因为这个bug,而是其他的一个debug版本的断言失败(详见http://bugs.mysql.com/bug.php?id=54453) 废话不多说,看test case: session 1: root@test 10:42:03>reset master; Query OK, 0 rows affected (0.00 sec) root@test 10:42:07>create table t1 (a int, b int); Query OK, 0 rows affected (0.01 sec) root@test 10:42:22>set autocommit = 0; Query OK, 0 rows affected (0.00 sec) root@test 10:42:27>alter table […]

[MySQL5.6 新特性] 全局事务标示符(GTID)

GTID的全称为 global transaction identifier  , 可以翻译为全局事务标示符,GTID在原始master上的事务提交时被创建。GTID需要在全局的主-备拓扑结构中保持唯一性,GTID由两部分组成: GTID = source_id:transaction_id source_id用于标示源服务器,用server_uuid来表示,这个值在第一次启动时生成,并写入到配置文件data/auto.cnf中 transaction_id则是根据在源服务器上第几个提交的事务来确定。 一个GTID的生命周期包括: 1.事务在主库上执行并提交 给事务分配一个gtid(由主库的uuid和该服务器上未使用的最小事务序列号),该GTID被写入到binlog中。 2.备库读取relaylog中的gtid,并设置session级别的gtid_next的值,以告诉备库下一个事务必须使用这个值 3.备库检查该gtid是否已经被其使用并记录到他自己的binlog中。slave需要担保之前的事务没有使用这个gtid,也要担保此时已分读取gtid,但未提交的事务也不恩呢过使用这个gtid. 4.由于gtid_next非空,slave不会去生成一个新的gtid,而是使用从主库获得的gtid。这可以保证在一个复制拓扑中的同一个事务gtid不变。 由于GTID在全局的唯一性,通过GTID,我们可以在自动切换时对一些复杂的复制拓扑很方便的提升新主库及新备库,例如通过指向特定的GTID来确定新备库复制坐标。 当然,使用GTID也有一些限制: 1.事务中的更新包含非事务性存储引擎,这可能导致多个GTID分配给同一个事务。 2. create table…select语句不被支持,因为该语句会被拆分成create table 和insert两个事务,并且这个两个事务被分配了同一个GTID,这会导致insert被备库忽略掉。 3.不支持CREATE/DROP临时表操作 可以看到,支持GTID的复制对一些语句都有一些限制,MySQL也提供了一个选项disable-gtid-unsafe-statements以禁止这些语句的执行。 参考: http://dev.mysql.com/doc/refman/5.6/en/replication-gtids.html http://dev.mysql.com/doc/refman/5.6/en/replication-gtids-restrictions.html http://dev.mysql.com/doc/refman/5.6/en/replication-gtids-concepts.html 原创文章,转载请注明: 转载自Simple Life 本文链接地址: [MySQL5.6 新特性] 全局事务标示符(GTID) Post Footer automatically generated by wp-posturl plugin for wordpress.

[MySQL5.6 新特性] 并行复制代码结构(1)

相关文件: rpl_slave.cc  rpl_slave.h rpl_rli_pdb.cc rpl_rli_pdb.h 1.启动slave. init_slave    |—>start_slave_threads                          |—>handle_slave_io(IO thread) 启动IO线程                        |—>handle_slave_sql(SQL thread) 启动SQL线程(作为协调者)                                  |—>slave_start_workers(Worker thread)   […]

[MySQL Bug]版本<=5.1.52的MySQL在alter表时将table_map置为0,导致复制中断

RT,这是一个老bug: http://bugs.mysql.com/bug.php?id=56226 bug#56226的描述不太准确,事实上innodb同样存在问题。 低于5.1.53版本的MySQL在分别alter两个表时将table_map置为0,如果表上有触发器,这会导致在备库上的复制错误,例如如下的test case: reset master; drop table if exists t1; drop table if exists t2; drop table if exists t3; create table t1 (a int primary key ,b int)engine=innodb; create table t2 like t1; create table t3 select a from t1 where 1 = 0; alter table t2 add index (b) ; alter table […]

[MySQL 调试]DBUG_EXECUTE_IF简介

转载请署名:印风 ———————————————– DEBUG_EXECUTE_IF主要用于当设置了某个关键字key时,执行后面的代码, 可以简单的表示为: DEBUG_EXECUTE_IF(key,  code) 例如在open_and_lock_tables函数中. 5527 if (open_tables(thd, &tables, &counter, flags, prelocking_strategy)) 5528 goto err; 5529 5530 DBUG_EXECUTE_IF(“sleep_open_and_lock_after_open”, { 5531 const char *old_proc_info= thd->proc_info; 5532 thd->proc_info= “DBUG sleep”; 5533 my_sleep(6000000); 5534 thd->proc_info= old_proc_info;}); 5535 5536 if (lock_tables(thd, tables, counter, flags)) 5537 goto err;   那么如何让其生效呢,执行如下语句即可: set session debug=”+d, sleep_open_and_lock_after_open”   这时候当进入这个函数时,在执行完open_tables语句后,就会设置thd的状态为DBUG sleep,再sleep 6秒钟,然后再调用lock_tables函数   […]

[MySQL Bug]使用DEBUG_SYNC调试多线程并发导致的bug

转载请署名:印风 ———————————————————- 这里以一个简单的bug(bug#58198)为例,本例使用的也比较简单,就用SIGNAL 和WAIT_FOR 我们对Percona Server 5.5.18注入如下代码: 在函数mysql_change_db_impl(use db时会调用)中: Index: sql/sql_db.cc =================================================================== — sql/sql_db.cc (revision 1185) +++ sql/sql_db.cc (working copy) @@ -1291,7 +1291,7 @@ the previous database name, we should do it explicitly. */ my_free(thd->db); – + DEBUG_SYNC(thd, “use_db_free”); thd->reset_db(new_db_name->str, new_db_name->length); } 在函数mysqld_list_processes(show processlist时会调用)中: Index: sql/sql_show.cc =================================================================== — sql/sql_show.cc (revision 1185) +++ sql/sql_show.cc (working copy) […]

[MySQL Bug]对一个已经discard tablespace的表做DDL导致crash

转载请署名:印风 ————————————————– 该Bug在MySQL的内部版本号为bug13943231,并且很容易触发该BUG 1.Test case: create table t1(c1 int) engine=innodb; alter table t1 discard tablespace; alter table t1 add unique index(c1); 2.原因: MySQL的discard tablespace操作实际上已经删除了.ibd文件,但在innodb层并没有判断该行为,而是继续执行下去,因此很快就触发断言失败,以下是一次crash的backtrace: (gdb) f 2 #2 0x000000000089a39b in fil_space_get_latch (id=5988266, flags=0x4a20ed20) at /home/yinfeng.zwx/project/PS5518/trunk/Percona-Server-5.5.18/storage/innobase/fil/fil0fil.c:537 537 ut_a(space); (gdb) l 532 533 mutex_enter(&fil_system->mutex); 534 535 space = fil_space_get_by_id(id); 536 537 ut_a(space); 538 539 if (flags) { 540 *flags = space->flags; 541 } (gdb) p space $1 = (fil_space_t *) 0x0 #2 fil_space_get_latch #3 fseg_create_general #4 btr_create #5 dict_create_index_tree_step #6 dict_create_index_step #7 que_thr_step #8 que_run_threads_low #9 que_run_threads #10 row_merge_create_index_graph #11 row_merge_create_index #12 ha_innobase::add_index 3.修复(来自官方): 修复的方法很简单,就是在add_index时判断是否已经discard tablespace了,如果是,就返回错误。 === modified file ‘storage/innobase/handler/handler0alter.cc’ — storage/innobase/handler/handler0alter.cc   2012-02-28 12:04:21 +0000 +++ storage/innobase/handler/handler0alter.cc   2012-05-16 11:03:22 +0000 @@ -708,6 +708,10 @@ ut_a(indexed_table == prebuilt->table); +       if (indexed_table->tablespace_discarded) { +               DBUG_RETURN(-1); +       } + /* Check that index keys are sensible */ error = innobase_check_index_keys(key_info, num_of_keys, prebuilt->table); 原创文章,转载请注明: 转载自Simple Life 本文链接地址: [MySQL […]

[MySQL Bug]DDL操作导致备库复制中断

转载请署名:印风 ————————————————- 在MySQL5.1及之前的版本中,如果有未提交的事务trx,当执行DROP/RENAME/ALTER TABLE RENAME操作时,不会被其他事务阻塞住。这会导致如下问题(MySQL bug#989) master: 未提交的事务,但SQL已经完成(binlog也准备好了),表schema发生更改,在commit的时候不会被察觉到。 slave: 在binlog里是以事务提交顺序记录的,DDL隐式提交,因此在备库先执行DDL,后执行事务trx,由于trx作用的表已经发生了改变,因此trx会执行失败。 在DDL时的主库DML压力越大,这个问题触发的可能性就越高 一个简单的例子: session1,set autocommit=0,对表b执行一条DML root@xxx 11:48:28>set autocommit = 0; Query OK, 0 rows affected (0.00 sec) root@xxx 11:48:35>insert into b values (NULL,4); Query OK, 1 row affected (0.00 sec) session2,执行rename table a to tmp_b root@xxx 11:48:23>rename table b to tmp_b; Query OK, 0 rows affected […]

[MySQL Patch]自动处理备库错误

转载请署名:印风 ————————————————– 备库因为某些错误停止时有发生,最常见的错误就是”HA_ERR_KEY_NOT_FOUND”和 “HA_ERR_FOUND_DUPP_KEY”.这既有可能是主备切换导致的,也可能是MySQL Bug导致的 通常有两种办法来处理备库错误: 1). 设置 “sql_slave_skip_counter”来忽略错误. 2).set slave_exec_mode = “idempotent”来处理 “HA_ERR_FOUND_DUPP_KEY” (overwritten the record) 和”HA_ERR_KEY_NOT_FOUND”(简单的忽略掉错误). 这两种方法都可能导致主备不一致 如果你使用的是innodb存储引擎,并且使用的是ROW模式复制,那我们就可以fix这个Bug。 很久之前我写了一个工具(http://code.google.com/p/relay-fetch/,下面的slave_error_handler文件夹)可以用来处理这个问题。 以下的patch则通过修改代码,为slave_exec_mode增加新的选项SMART,来自动处理。 思想很简单 1) HA_ERR_KEY_NOT_FOUND UPDATE_ROWS_EVENT: 先写记录的’Before Image’ ,然后再update DELETE_ROWS_EVENT: 先写后删 , 或者直接忽略错误 2)HA_ERR_FOUND_DUPP_KEY WRITE_ROWS_EVENT: overwrite the record 对UPDATE_ROWS_EVENT导致的重复键错误暂不做处理。 以下patch基于Percona Server 5.5.18:   Index: /PS5518/branches/PS-r1086-slave-auto-fix/sql/log_event.cc =================================================================== — /PS5518/branches/PS-r1086-slave-auto-fix/sql/log_event.cc (revision 1136) +++ /PS5518/branches/PS-r1086-slave-auto-fix/sql/log_event.cc (revision 1180) @@ […]