mysql 5.1版本无innodb trx_[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_lock_tables函数中:

调用lock_external

->handler::ha_external_lock

->ha_innodb::external_lock

->row_lock_table_for_mysql   对innodb表进行加锁(LOCK_X)

随后调用thr_multi_lock

->thr_lock->wait_for_lock   —>等待锁释放  (如果已经有DML进入Innodb层还没完成的话)

2.

对于进入Innodb层的DML,例如一条insert操作,该线程会被suspend:

row_insert_for_mysql

–>row_ins_step(thr)

–>lock_table(0, node->table, LOCK_IX, thr);

由于lock table操作为该表加了LOCK_X锁,因此这里insert操作在尝试加LOCK_IX锁时失败,返回

DB_LOCK_WAIT,线程被suspend,等待超时。

5.5通过MDL锁解决了MySQL层和Innodb层的死锁问题,但在5.1里,目前唯一的办法就是等待在innodb层超时。

.

.

.

.

.

.

.

.

/

以下为本人自言自语,记录目的为以后调试方便,不保证正确性。。。。。。

///

最近看到参数skip_external_locking,看了官方的解释,该参数看起来只对MyISAM引擎有用,用于在多进程(也就是有多个服务器程序时)对单个表操作时进行锁定,默认值为打开,也就是跳过外部锁定。

之前一直对external lock没啥概念,大概浏览了下,以下只是简略的笔记。

从代码里可以发现,innodb也实现了相应的external_lock函数。那么这个external lock是做什么的呢?

在handler.cc里对应的是:

handler::ha_external_lock(THD *thd, int lock_type)

调用的地方包括

sql_table.cc:

copy_data_between_tables

当alter table,需要拷贝数据时,对目标表上F_WRLCK锁,然后再向其中拷贝数据。

lock.cc:

mysql_lock_tables->lock_external->handler::ha_external_lock

mysql_unlock_tables->unlock_external->handler::ha_external_lock

mysql_lock_tables用于对SQL涉及到的表进行加锁,从lock_external里可以看到

当只对表做读操作时(TL_READ_NO_INSERT>=lock_type >= TL_READ),锁类型为F_RDLCK

否则为F_WRLCK

然后对涉及到的表依次调用(*tables)->file->ha_external_lock

opt_range.cc:

QUICK_RANGE_SELECT::init_ror_merged_scan

QUICK_RANGE_SELECT::~QUICK_RANGE_SELECT

在初始化ROR(RowidOrderedRetrieval) merge scan时调用。

ha_partition.cc:

ha_partition::prepare_new_partition

ha_partition::cleanup_new_partition

在innodb层,调用的是ha_innobase::external_lock,主要做如下工作:

1.update_thd(thd);

2.设置prebuilt->sql_stat_start = TRUE

3.根据lock_type的类型值,设置相应的变量,所谓的external lock,并不是实际上加锁,仅仅是设置某些标记。加锁操作包括:

–当lock_type == F_WRLCK时:

prebuilt->select_lock_type = LOCK_X;

prebuilt->stored_select_lock_type = LOCK_X;

–当lock_type不等于F_UNLCK

(1).innobase_register_trx(ht, thd, trx);

(2).if (trx->isolation_level == TRX_ISO_SERIALIZABLE          —-隔离级别为SERIALIZABLE

&& prebuilt->select_lock_type == LOCK_NONE

&& thd_test_options(

thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {

prebuilt->select_lock_type = LOCK_S;

prebuilt->stored_select_lock_type = LOCK_S;

}

(3).对于LOCK TABLE操作,只有在AUTOCOMMIT = 0时,才会对Innodb表加锁(row_lock_table_for_mysql)

(4).trx->n_mysql_tables_in_use++;

prebuilt->mysql_has_locked = TRUE;

DBUG_RETURN(0);

—以下为解锁逻辑

(1)设置标记

trx->n_mysql_tables_in_use–;

prebuilt->mysql_has_locked = FALSE;

(2)innobase_release_stat_resources(trx);

if (trx->n_mysql_tables_in_use == 0)   //表明该SQL语句已经完成,需要重置相关变量和标记

当设置为自动提交时,则会在innodb层提交事务(innobase_commit),否则如果隔离级别小于等于read commited,则关闭该SQL的read view。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值