InnoDB插入缓冲:无法清除记录

  转载:http://mysqllover.com/?p=1264
  参考:InnoDB插入缓冲实现详解http://hedengcheng.com/?p=94
  
           

  MySQL5.6.23:修复”无法清除记录”   

                          

  本文简述下之前我们线上频繁碰到的“UNABLE 用PURGE  A 记录”的原因   

  

  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #   

  

  线上实例错误日志中偶尔出现,“UNABLE 用PURGE  A 记录”,从官方虫系统来看,很多用户都遇到了类似的问题。   

  

     

  

  当change 缓冲模块以如下序列来缓存索引操作时:   

  
      <李>   记录被标记删除(IBUF_OP_DELETE_MARK)   李   <李>   随后插入相同记录-IBUF_OP_INSERT   李   <李>   清洗线程需要物理删除二级索引记录,操作被buffer-IBUF_OP_DELETE   李   
  

  ,   

  

  当读入物理页时,需要进行ibuf 合并,当执行到IBUF_OP_DELETE时,发现记录并没有被标记删除,导致错误日志报的错。   

  

  ,   

  

  显然上述的操作序列是不合理的,正确的序列应该是IBUF_OP_DELETE_MARK, IBUF_OP_DELETE IBUF_OP_INSERT。   

  

  ,   

  

  为了理清逻辑,我们简单的理一下相关代码   

  

  ,   

  

  注意IBUF_OP_DELETE是由第一步的标记删除操作触发,清洗线程发起;在每个buffer 池的控制结构体中,有一个成员buf_pool→看[BUF_POOL_WATCH_SIZE], BUF_POOL_WATCH_SIZE的值为清洗线程个数,用于辅助清除操作。   

  

  ,   

  

  假定内存中没有对应的页面,清洗线程会做如下几件事儿:   

  
      <李>   首先查询buffer 池,看看页面是否已经读入内存;   李   
  

  如果不在内存中,则将page 没有等信息存储到观看数组中,并插入page 哈希(buf_pool_watch_set)。如果随后页面被读入内存,就会删除看标记。   

  
      <李>   判断该二级索引记录是否可以被清洗(row_purge_poss_sec,当该二级索引记录对应的聚集索引记录没有delete 马克并且其trx  id比当前的purge 视图还旧时,不可以做清洗操作)   李   
  

  ,   

  
      <李>   随后,再插入IBUF_OP_DELETE类型的ibuf记录时,还会double 检查下该页面是否被设为sentinel  (ibuf_insert_low buf_pool_watch_occurred),如果未被设置,表明已经页面已经读入内存,就可以直接去做清洗,而无需缓存了。   李   
  

  ,   

  
      <李>   对于普通的操作类型,例如IBUF_OP_INSERT和IBUF_OP_DELETE_MARK,同样也会double  check  page 是否读入了内存。在函数ibuf_insert中会调用buf_page_hash_get进行检查,,如果页面被读入内存,则不缓存操作,如果请求的页面被设为前哨,则从buf_page_hash_get返回零,因此随后判定需要缓存操作。这也正是问题的所在:   李   
  
      <李>   标记删除记录,写入IBUF_OP_DELETE_MARK   李   <李>   清洗线程设置页面对应的前哨,完成合法性检查,准备调用ibuf_insert   李   <李>   插入相同记录,写入IBUF_OP_INSERT   李   <李>   清洗线程写入IBUF_OP_DELETE   李   
  

  解决   

  

  如果记录所在的页面被设置了一个哨兵,那么对该页面的并发插入操作就不应该缓存到change 缓冲中,而是直接去尝试读取物理页。   

  

  https://github.com/mysql/mysql-server/commit/ec369cb4f363161dfbbbd662b20763b54808b7d1   

InnoDB插入缓冲:无法清除记录