• MySQL启动过程详解四:crash recovery


    当 MySQL关闭后,重启MySQL时,会进行 crash recovery操作,这里分析一下MySQL是如何进行的:

    1. 首先在启动Innodb存储引擎时会回滚事务系统的事务列表中未在Innodb中提交的处于 TRX_STATE_ACTIVE 状态的不完整的事务【在事务的两阶段提交过程中,xa prepare阶段会在Innodb中将事务的状态修改为 TRX_STATE_PREPARED状态】。核心代码如下:

    void
    trx_rollback_or_clean_recovered(
    /*============================*/
    	ibool	all)	/*!< in: FALSE=roll back dictionary transactions;
    			TRUE=roll back all non-PREPARED transactions */
    {
    	trx_t*	trx;
    
    	ut_a(srv_force_recovery < SRV_FORCE_NO_TRX_UNDO);
    
    	if (trx_sys_get_n_rw_trx() == 0) {
    
    		return;
    	}
    
    	if (all) {
    		ib::info() << "Starting in background the rollback"
    			" of uncommitted transactions";
    	}
    
    	/* Note: For XA recovered transactions, we rely on MySQL to
    	do rollback. They will be in TRX_STATE_PREPARED state. If the server
    	is shutdown and they are still lingering in trx_sys_t::trx_list
    	then the shutdown will hang. */
    
    	/* Loop over the transaction list as long as there are
    	recovered transactions to clean up or recover. */
    
    	do {
    		trx_sys_mutex_enter();
    
    		for (trx = UT_LIST_GET_FIRST(trx_sys->rw_trx_list);
    		     trx != NULL;
    		     trx = UT_LIST_GET_NEXT(trx_list, trx)) {
    
    			assert_trx_in_rw_list(trx);
    
    			/* If this function does a cleanup or rollback
    			then it will release the trx_sys->mutex, therefore
    			we need to reacquire it before retrying the loop. */
    
    			if (trx_rollback_resurrected(trx, all)) {
    
    				trx_sys_mutex_enter();
    
    				break;
    			}
    		}
    
    		trx_sys_mutex_exit();
    
    	} while (trx != NULL);
    
    	if (all) {
    		ib::info() << "Rollback of non-prepared transactions"
    			" completed";
    	}
    }
    
    static
    ibool
    trx_rollback_resurrected(
    /*=====================*/
    	trx_t*	trx,	/*!< in: transaction to rollback or clean */
    	ibool	all)	/*!< in: FALSE=roll back dictionary transactions;
    			TRUE=roll back all non-PREPARED transactions */
    {
    	ut_ad(trx_sys_mutex_own());
    
    	/* The trx->is_recovered flag and trx->state are set
    	atomically under the protection of the trx->mutex (and
    	lock_sys->mutex) in lock_trx_release_locks(). We do not want
    	to accidentally clean up a non-recovered transaction here. */
    
    	trx_mutex_enter(trx);
    	bool		is_recovered	= trx->is_recovered;
    	trx_state_t	state		= trx->state;
    	trx_mutex_exit(trx);
    
    	if (!is_recovered) {
    		return(FALSE);
    	}
    
    	switch (state) {
    	case TRX_STATE_COMMITTED_IN_MEMORY:
    		trx_sys_mutex_exit();
    		ib::info() << "Cleaning up trx with id "
    			<< trx_get_id_for_print(trx);
    
    		trx_cleanup_at_db_startup(trx);
    		trx_free_resurrected(trx);
    		return(TRUE);
    	case TRX_STATE_ACTIVE:
    		if (all || trx_get_dict_operation(trx) != TRX_DICT_OP_NONE) {
    			trx_sys_mutex_exit();
    			trx_rollback_active(trx);
    			trx_free_for_background(trx);
    			return(TRUE);
    		}
    		return(FALSE);
    	case TRX_STATE_PREPARED:
    		return(FALSE);
    	case TRX_STATE_NOT_STARTED:
    	case TRX_STATE_FORCED_ROLLBACK:
    		break;
    	}
    
    	ut_error;
    	return(FALSE);
    }
    

      

    2. 在 Innodb存储引擎启动之后根据 binlog 进行 xa recovery;Innodb解析 redo log,读取出所有处于 prepare 状态的事务的 xid,而后在读取最后一个 binlog 的 xid 的hash表中查找 xid 是否存在,存在则 commit,不存在则 rollback。

    static my_bool xarecover_handlerton(THD *unused, plugin_ref plugin,
                                        void *arg)
    {
     // 目前仅关注 Innodb
      handlerton *hton= plugin_data<handlerton*>(plugin);
      struct xarecover_st *info= (struct xarecover_st *) arg;
      int got;
    
      if (hton->state == SHOW_OPTION_YES && hton->recover)
      {
       // 调用 Innodb 存储引擎的 recover 函数, Innodb会解析 redo log,读出所有处于 prepare 状态的事务,返回事务的 xid
        while ((got= hton->recover(hton, info->list, info->len)) > 0)
        {
          sql_print_information("Found %d prepared transaction(s) in %s",
                                got, ha_resolve_storage_engine_name(hton));
        // 遍历 Innodb 返回的 xid
          for (int i= 0; i < got; i++)
          {
            my_xid x= info->list[i].get_my_xid();
            if (!x) // not "mine" - that is generated by external TM
            {
    #ifndef NDEBUG
              char buf[XIDDATASIZE * 4 + 6]; // see xid_to_str
              XID *xid= info->list + i;
              sql_print_information("ignore xid %s", xid->xid_to_str(buf));
    #endif
              transaction_cache_insert_recovery(info->list + i);
              info->found_foreign_xids++;
              continue;
            }
            if (info->dry_run)
            {
              info->found_my_xids++;
              continue;
            }
            // recovery mode
            // 在最后一个 binlog 中读取的xid的 hash 表中查找 xid,如果找到了,则说明事务记录了binlog,
         // 在 Innodb 中 进行提交。如果找不到,则进行回滚。
            if (info->commit_list ?
                my_hash_search(info->commit_list, (uchar *)&x, sizeof(x)) != 0 :
                tc_heuristic_recover == TC_HEURISTIC_RECOVER_COMMIT)
            {
    #ifndef NDEBUG
              char buf[XIDDATASIZE * 4 + 6]; // see xid_to_str
              XID *xid= info->list + i;
              sql_print_information("commit xid %s", xid->xid_to_str(buf));
    #endif
              hton->commit_by_xid(hton, info->list + i);
            }
            else
            {
    #ifndef NDEBUG
              char buf[XIDDATASIZE * 4 + 6]; // see xid_to_str
              XID *xid= info->list + i;
              sql_print_information("rollback xid %s", xid->xid_to_str(buf));
    #endif
              hton->rollback_by_xid(hton, info->list + i);
            }
          }
          if (got < info->len)
            break;
        }
      }
      return false;
    }
    

      

     

  • 相关阅读:
    FPGA在其他领域的应用(一)
    FPGA IN 消费电子
    FPGA IN 金融领域
    FPGA与PCI-E
    FPGA与数字信号处理
    FPGA与数字图像处理技术
    FPGA与安防领域
    FPGA在电平接口领域的应用
    FPGA与Deep Learning
    FPGA多时钟处理应用
  • 原文地址:https://www.cnblogs.com/juanmaofeifei/p/16139609.html
Copyright © 2020-2023  润新知