mysql内核研究_MySQL · 内核特性 · Attachable transaction

目的

在学习代码的过程中经常看到attachable transaction,它到底是做什么的,目的是什么呢。这篇文章简单的介绍一下它的作用和用法,以帮助大家理解代码。

简介

Attachable transaction是从5.7引入的一个概念,主要用来对事务类型的系统表访问的接口,从事务的系统表查询得到一致的数据。目前主要是对innodb类型的系统表访问的接口,也只有innodb引擎实现了attachable transaction的支持。Attachable transaction 主要是为访问事务类型的系统表而设计的,它是一个嵌入用户事务的内部事务,当用户事务用到元信息时就需要开启一个attachable transaction去访问数据字典,得到用户表的元信息后,要结束attachable transaction,用户会话要能恢复到用户事务之前的状态。 Attachable transaction 是一个AC-RO-RC-NL (auto-commit, read-only, read-committed, non-locking) 事务。引入Attachable transaction主要有以下几个原因: 1) 如果用户开启的一个事务需要访问系统表获取表的元信息,而访问系统表可能和用户事务指定的隔离级别不一致,这时就需要开启一个独立的访问数据字典的事务,要求访问数据字典事务的隔离级别必须是READ COMMITTED,其隔离级别可能和用户指定的隔离级别不一致。 2) 对数据字典的访问必须是非锁定的。 3) 即时用户事务已经打开和锁定了用户表,在执行SQL语句的在任何时候也应该能对数据字典打开,来查询用户表的各种元信息。

核心数据结构

在每个会话的THD结构里,添加了一个 Attachable_trx *m_attachable_trx;字段,用来指向当前会话的内嵌事务。Attachable_trx 类型定义如下:

/**

Class representing read-only attachable transaction, encapsulates

knowledge how to backup state of current transaction, start

read-only attachable transaction in SE, finalize it and then restore

state of original transaction back. Also serves as a base class for

read-write attachable transaction implementation.

*/

class Attachable_trx

{

public:

Attachable_trx(THD *thd);

virtual ~Attachable_trx();

virtual bool is_read_only() const { return true; }

protected:

/// THD instance.

THD *m_thd;

/// Transaction state data.

Transaction_state m_trx_state;

private:

Attachable_trx(const Attachable_trx &);

Attachable_trx &operator =(const Attachable_trx &);

};

其中最重要的是m_trx_state字段,期存放着attachable transaction的重要信息,就是用它来保存外部用户事务的状态,以便在着attachable transaction结束后能恢复到原来的用户事务状态。其定义如下:

/** An utility struct for @c Attachable_trx */

struct Transaction_state

{

void backup(THD *thd);

void restore(THD *thd);

/// SQL-command.

enum_sql_command m_sql_command;

Query_tables_list m_query_tables_list;

/// Open-tables state.

Open_tables_backup m_open_tables_state;

/// SQL_MODE.

sql_mode_t m_sql_mode;

/// Transaction isolation level.

enum_tx_isolation m_tx_isolation;

/// Ha_data array.

Ha_data m_ha_data[MAX_HA];

/// Transaction_ctx instance.

Transaction_ctx *m_trx;

/// Transaction read-only state.

my_bool m_tx_read_only;

/// THD options.

ulonglong m_thd_option_bits;

/// Current transaction instrumentation.

PSI_transaction_locker *m_transaction_psi;

/// Server status flags.

uint m_server_status;

};

核心接口API

启动一个attachable transaction

主要有这几个函数THD::begin_attachable_transaction()/begin_attachable_ro_transaction()/begin_attachable_rw_transaction(), 启动attachable transaction的过程中主要完成以下功能: 1) 在开始一个attachable_transaction之前,先要保存当前已经开始的用户的正常事务状态。 2) 开始设置一个新的事务所需要的各种状态。 3) 重新设置THD::ha_data。通过重制THD::ha_data值使InnoDB在接下来的操作去创建以下新的事务。 4) 执行对系统表的操作。 5) 当执行到存储引擎层时,InnoDB从传进来的THD指针中发现事务还没开启 (因为THD::ha_data重置了),InnoDB就会新启一个事务。 6) InnoDB通过调用trans_register_ha()通知server它已经创建了一个新事务。 7) InnoDB执行请求的操作,返回给server层。

THD::Attachable_trx::Attachable_trx(THD *thd)

:m_thd(thd)

{

m_trx_state.backup(m_thd); //保存当前已经开始的用户的正常事务状态

......

m_thd->reset_n_backup_open_tables_state(&m_trx_state.m_open_tables_state); //保存一些打开表的状态信息,并且重新为新的事物重置表状态

// 为attachable transaction创建一个新的事物上下文

m_thd->m_transaction.release(); // it's been backed up.

m_thd->m_transaction.reset(new Transaction_ctx());

......

for (int i= 0; i < MAX_HA; ++i)

m_thd->ha_data[i]= Ha_data(); //重新设置THD::ha_data

m_thd->tx_isolation= ISO_READ_COMMITTED; // attachable transaction 必须是read committed

m_thd->tx_read_only= true; // attachable transaction 必须是只读的

// attachable transaction 必须是 AUTOCOMMIT

m_thd->variables.option_bits|= OPTION_AUTOCOMMIT;

m_thd->variables.option_bits&= ~OPTION_NOT_AUTOCOMMIT;

m_thd->variables.option_bits&= ~OPTION_BEGIN;

......

}

结束一个attachable transaction

THD::end_attachable_transaction()函数。因为attachable transaction事务是一个只读的自提交事务,所以它不需要调用任何事务需要提交火回滚的函数,比如: ha_commit_trans() / ha_rollback_trans() / trans_commit() / trans_rollback()。所以定义了此函数用来结束当前的attachable transaction。它主要完成以下功能: 1) 调用close_thread_tables()关闭在attachable transaction中打开的表。 2) 调用close_connection()通知引擎层去销毁为attachable transaction创建的事务。 3) InnoDB调用trx_commit_in_memory()去销毁readview等操作。 4) 最后要恢复之前正常的用户事务,包括THD::ha_data的恢复,这个通过调用下面提到的事务状态的backup()/restore()接口。

THD::Attachable_trx::~Attachable_trx()

{

......

close_thread_tables(m_thd); //调用close_thread_tables()关闭在attachable transaction中打开的

ha_close_connection(m_thd); //调用close_connection()通知引擎层去销毁为attachable transaction创建的事务

// 恢复之前正常的用户事状态

m_trx_state.restore(m_thd);

m_thd->restore_backup_open_tables_state(&m_trx_state.m_open_tables_state);

......

}

事务的保存、恢复接口函数 Transaction_state::backup()/restore()

由于一个会话同时只允许有一个活跃事务,当需要访问内部的事务系统表时,就需要开启一个Attachable transaction事务,这时就要先把外部的主事务状态先保存起来,等内部开启的Attachable transaction事务执行完,再把外部用户执行的事务恢复回来。为了实现这个功能,提供了backup和restore的接口。

Handler API的改动

为了让存储层知道server层开启的是一个attachable transaction,handler API新加了一个HA_ATTACHABLE_TRX_COMPATIBLE 标志。设置这个标志的存储引擎类型表示引擎层已经意识到开启了attachable transaction的事务类型。目前InnoDB和MyISAM引擎都能处理这种attachable transaction。但处理方式不同: 1)对InnoDB而言,完全支持attachable transaction事务,能够感知到THD::ha_data 的变化并开启一个attachable transaction事务。在close_connection时结束一个attachable transaction事务,然后恢复用户正常的事务继续处理。 2) 对MyISAM而言,虽然知道server开启了一个attachable transaction事务但也不做任何处理,就是简单但忽律掉 THD::ha_data and close_connection handlerton相关但处理。

在初始化一个InnoDB表时,设置HA_ATTACHABLE_TRX_COMPATIBLE 标志的代码如下:

ha_innobase::ha_innobase(

/*=====================*/

handlerton* hton,

TABLE_SHARE* table_arg)

:handler(hton, table_arg),

m_prebuilt(),

m_prebuilt_ptr(&m_prebuilt),

m_user_thd(),

m_int_table_flags(HA_REC_NOT_IN_SEQ

......

| HA_ATTACHABLE_TRX_COMPATIBLE

| HA_CAN_INDEX_VIRTUAL_GENERATED_COLUMN

),

m_start_of_scan(),

m_num_write_row(),

m_mysql_has_locked()

{}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值