events_transactions_current表的写入读取和存储方式

祝灼光
2023-12-01

events_transactions_current是performance_schema中记录事务状态信息的表,它除了可以记录普通事务以外,还可以记录MySQL中的XA事务。
表结构如下:

mysql> show create table  performance_schema.events_transactions_current\G
*************************** 1. row ***************************
       Table: events_transactions_current
Create Table: CREATE TABLE `events_transactions_current` (
  `THREAD_ID` bigint(20) unsigned NOT NULL,
  `EVENT_ID` bigint(20) unsigned NOT NULL,
  `END_EVENT_ID` bigint(20) unsigned DEFAULT NULL,
  `EVENT_NAME` varchar(128) NOT NULL,
  `STATE` enum('ACTIVE','COMMITTED','ROLLED BACK') DEFAULT NULL,
  `TRX_ID` bigint(20) unsigned DEFAULT NULL,
  `GTID` varchar(64) DEFAULT NULL,
  `XID_FORMAT_ID` int(11) DEFAULT NULL,
  `XID_GTRID` varchar(130) DEFAULT NULL,
  `XID_BQUAL` varchar(130) DEFAULT NULL,
  `XA_STATE` varchar(64) DEFAULT NULL,
  `SOURCE` varchar(64) DEFAULT NULL,
  `TIMER_START` bigint(20) unsigned DEFAULT NULL,
  `TIMER_END` bigint(20) unsigned DEFAULT NULL,
  `TIMER_WAIT` bigint(20) unsigned DEFAULT NULL,
  `ACCESS_MODE` enum('READ ONLY','READ WRITE') DEFAULT NULL,
  `ISOLATION_LEVEL` varchar(64) DEFAULT NULL,
  `AUTOCOMMIT` enum('YES','NO') NOT NULL,
  `NUMBER_OF_SAVEPOINTS` bigint(20) unsigned DEFAULT NULL,
  `NUMBER_OF_ROLLBACK_TO_SAVEPOINT` bigint(20) unsigned DEFAULT NULL,
  `NUMBER_OF_RELEASE_SAVEPOINT` bigint(20) unsigned DEFAULT NULL,
  `OBJECT_INSTANCE_BEGIN` bigint(20) unsigned DEFAULT NULL,
  `NESTING_EVENT_ID` bigint(20) unsigned DEFAULT NULL,
  `NESTING_EVENT_TYPE` enum('TRANSACTION','STATEMENT','STAGE','WAIT') DEFAULT NULL
) ENGINE=PERFORMANCE_SCHEMA DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

总共有24个字段。
此表对应performance_schema存储引擎的struct row_events_transactions,如下 :

/** A row of table_events_transactions_common. */
struct row_events_transactions
{
  /** Column THREAD_ID. */
  ulonglong m_thread_internal_id;
  /** Column EVENT_ID. */
  ulonglong m_event_id;
  /** Column END_EVENT_ID. */
  ulonglong m_end_event_id;
  /** Column NESTING_EVENT_ID. */
  ulonglong m_nesting_event_id;
  /** Column NESTING_EVENT_TYPE. */
  enum_event_type m_nesting_event_type;
  /** Column EVENT_NAME. */
  const char *m_name;
  /** Length in bytes of @c m_name. */
  uint m_name_length;
  /** Column TIMER_START. */
  ulonglong m_timer_start;
  /** Column TIMER_END. */
  ulonglong m_timer_end;
  /** Column TIMER_WAIT. */
  ulonglong m_timer_wait;
  /** Column SOURCE. */
  char m_source[COL_SOURCE_SIZE];
  /** Length in bytes of @c m_source. */
  uint m_source_length;
  /** InnoDB transaction id. */
  ulonglong m_trxid;
  /** Transaction state. */
  enum_transaction_state m_state;
  /** Global Transaction ID. */
  char m_gtid[Gtid_specification::MAX_TEXT_LENGTH + 1];
  /** GTID length in bytes*/
  int m_gtid_length;
  /** XA transaction ID. */
  PSI_xid m_xid;
  /** XA transaction state. */
  enum_xa_transaction_state m_xa_state;
  /** True if XA transaction. */
  bool m_xa;
  /** True if autocommit transaction. */
  bool m_autocommit;
  /** Isolation level. */
  enum_isolation_level m_isolation_level;
  /** True if read-only, read-write otherwise. */
  bool m_read_only;
  /** Column NUMBER_OF_SAVEPOINTS. */
  ulonglong m_savepoint_count;
  /** Column NUMBER_OF_ROLLBACK_TO_SAVEPOINT. */
  ulonglong m_rollback_to_savepoint_count;
  /** Column NUMBER_OF_RELEASE_SAVEPOINT. */
  ulonglong m_release_savepoint_count;
};

row_events_transactions的信息由每一个客户端线程独立维护,如下:

class THD :public MDL_context_owner,
           public Query_arena,
           public Open_tables_state
{
...
  /** Current transaction instrumentation. */
  PSI_transaction_locker *m_transaction_psi;    
...
}

但是m_transaction_psi只记录了如下信息,并没有覆盖到row_events_transactions的所有信息,:

/** A transaction record. */
struct PFS_events_transactions : public PFS_events
{
  /** Source identifier, mapped from internal format. */
  rpl_sid m_sid;
  /** InnoDB transaction ID. */
  ulonglong m_trxid;
  /** Status */
  enum_transaction_state m_state;
  /** Global Transaction ID specifier. */
  Gtid_specification m_gtid_spec;
  /** True if XA transaction. */
  my_bool m_xa;
  /** XA transaction ID. */
  PSI_xid m_xid;
  /** XA status */
  enum_xa_transaction_state m_xa_state;
  /** Transaction isolation level. */
  enum_isolation_level m_isolation_level;
  /** True if read-only transaction, otherwise read-write. */
  my_bool m_read_only;
  /** True if autocommit transaction. */
  my_bool m_autocommit;
  /** Total number of savepoints. */
  ulonglong m_savepoint_count;
  /** Number of rollback_to_savepoint. */
  ulonglong m_rollback_to_savepoint_count;
  /** Number of release_savepoint. */
  ulonglong m_release_savepoint_count;
};

其它信息比如表示m_timer_end是在由用户查询此表时计算的。

数据写入过程

当我们开启监控时,需要对m_transaction_psi进行写入,其过程如下:

...
    Sql_cmd_xa_start::execute(THD*)
        Sql_cmd_xa_start::trans_xa_start(THD*)
            inline_mysql_set_transaction_xid(PSI_transaction_locker*, void const*, int)
                ::pfs_set_transaction_xid_v1(PSI_transaction_locker *, const void *, int)

函数pfs_set_transaction_xid_v1的主要作用是写入事务的xid,实现如下:

void pfs_set_transaction_xid_v1(PSI_transaction_locker *locker,
                                const void *xid,
                                int xa_state)
{
  PSI_transaction_locker_state *state= reinterpret_cast<PSI_transaction_locker_state*> (locker);
  DBUG_ASSERT(state != NULL);

  if (state->m_flags & STATE_FLAG_EVENT)
  {
    PFS_events_transactions *pfs= reinterpret_cast<PFS_events_transactions*> (state->m_transaction);
    DBUG_ASSERT(pfs != NULL);
    DBUG_ASSERT(xid != NULL);

    pfs->m_xid= *(PSI_xid *)xid;
    pfs->m_xa_state= (enum_xa_transaction_state)xa_state;
    pfs->m_xa= true;
  }
  return;
}

数据查询过程

下面来看下查询的过程:

handle_query(THD*, LEX*, Query_result*, unsigned long long, unsigned long long)
    ...
        handler::ha_rnd_next(unsigned char*)
            ha_perfschema::rnd_next(unsigned char*)
                table_events_transactions_current::rnd_next()
                    table_events_transactions_common::make_row(PFS_events_transactions*)

通过table_events_transactions_common::make_row(PFS_events_transactions *transaction)函数根据PSI_transaction_locker中的信息生成行数据返回给客户端,感兴趣的读者可以继续阅读函数table_events_transactions_common::make_row(PFS_events_transactions *transaction)。

 类似资料: