本文共 2418 字,大约阅读时间需要 8 分钟。
根据worklog的描述,该特性主要是为了解决WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS的缺点:
#该功能依赖于slave来运行,如果复制线程没有启动或者出错了,就会返回错误。在某些情况下我们需要一直等待;
#返回的是执行的事件的个数,这通常是没有意义的,返回成功或者失败即可。
引入新的语法:
WAIT_FOR_EXECUTED_GTID_SET(GTID_SET [, TIMEOUT])
当GTID_SUBSET(GTID_SET, @@global.gtid_executed)成立时,即指定的GTID是gtid_executed的子集时,返回0表示成功,否则返回1,表示失败。
例如:
root@(none) 07:46:32>select @@global.gtid_executed;
+——————————————-+
| @@global.gtid_executed |
+——————————————-+
| 46293b73-58db-11e4-8b9c-38eaa78f3a78:1-32 |
+——————————————-+
1 row in set (0.00 sec)
root@(none) 07:48:56>select WAIT_FOR_EXECUTED_GTID_SET(‘46293b73-58db-11e4-8b9c-38eaa78f3a78:1-6′,64) as status;
+——–+
| status |
+——–+
| 0 |
+——–+
1 row in set (0.00 sec)
如下则需要等待,如果一直不满足,就会超时返回…
root@(none) 07:47:32>select WAIT_FOR_EXECUTED_GTID_SET(‘46293b73-58db-11e4-8b9c-38eaa78f3a78:1-37′,64);
老规矩,我们继续来看看代码的相关实现。另外该补丁也可能引入一个性能问题(待证实)
Mutex_cond_array:
Mutex_cond_array::wait 需要判断线程是否被kill来结束等待
增加新接口函数,等待指定sidno的condion.
inline int wait(const THD* thd, int sidno, struct timespec* abstime)
Gtid_state
增加接口函数Gtid_state::wait_for_gtid_set
Owned_gtids
sql/item_create.cc
Create_func_executed_gtid_set_wait 为新的函数增加接口类定义,解取参数item,然后创建对象Item_wait_for_executed_gtid_set
以后要增加新的函数接口,可以按照这个典型又简单的套路来实现;
文件sql/item_func.cc, sql/item_func.h新增:
类Item_wait_for_executed_gtid_set
Item_wait_for_executed_gtid_set::itemize
Item_wait_for_executed_gtid_set::val_int
{
…
result= gtid_state->wait_for_gtid_set(thd, gtid, timeout);
…
}
sql/item_func.h
Item_executed_gtid_set_wait
Item_wait_for_executed_gtid_set::itemize
Item_wait_for_executed_gtid_set::val_int
堆栈:
mysql_select —> JOIN::exec —-> select_send::send_data —-> Protocol::send_result_set_row—> Item::send —> Item_wait_for_executed_gtid_set::val_int —> Gtid_state::wait_for_gtid_set —> Gtid_state::wait_for_gtid
Gtid_state::wait_for_gtid_set
检查请求的GTID集合 是否包含了当前的executed_gtid。如果不满足,则找出不满足的gtid的sidno (根据uuid 进行map后的整数),进入condition wait.
在事务提交时,会发送broadcast.
Gtid_state::update_on_commit —-> Gtid_state::broadcast_owned_sidnos
不过很显然,每次commit事务都需要做一次broadcast , 不管有没有线程在等待。感觉这部分应该可以被优化掉。
在之前版本中,如下逻辑:
开始刷Binlog cache时, gtid被加入到gtid_executed,在完成commit后,从gtid_owned移除;
在5.7.5版本里,加入到gtid_executed集合的操作被转移到完成commit后。由于在finish_commit中,各个线程是并发执行的,因此产生大量的锁竞争; 而在之前版本中,flush binlog cache总是只有一个线程进行,因此锁竞争很小。
当然这只是个人猜测,还没有回滚代码去证实,不过5.7.5的GTID改动确实引发了极大的性能退化,已经report了Bug并被verified了,感兴趣的可以看看这个bug:
http://bugs.mysql.com/bug.php?id=74328
转载地址:http://fcesa.baihongyu.com/