perfschema transaction instrumentation related changes

This commit is contained in:
Sergei Golubchik 2020-02-14 16:38:49 +01:00
parent 6ded554fc2
commit 81cffda2e6
10 changed files with 188 additions and 41 deletions

View file

@ -40,6 +40,8 @@
#include "myisam.h"
#include "probes_mysql.h"
#include <mysql/psi/mysql_table.h>
#include <pfs_transaction_provider.h>
#include <mysql/psi/mysql_transaction.h>
#include "debug_sync.h" // DEBUG_SYNC
#include "sql_audit.h"
#include "ha_sequence.h"
@ -62,6 +64,39 @@
#include "wsrep_trans_observer.h" /* wsrep transaction hooks */
#endif /* WITH_WSREP */
/**
@def MYSQL_TABLE_LOCK_WAIT
Instrumentation helper for table io_waits.
@param OP the table operation to be performed
@param FLAGS per table operation flags.
@param PAYLOAD the code to instrument.
@sa MYSQL_END_TABLE_WAIT.
*/
#ifdef HAVE_PSI_TABLE_INTERFACE
#define MYSQL_TABLE_LOCK_WAIT(OP, FLAGS, PAYLOAD) \
{ \
if (m_psi != NULL) \
{ \
PSI_table_locker *locker; \
PSI_table_locker_state state; \
locker= PSI_TABLE_CALL(start_table_lock_wait) \
(& state, m_psi, OP, FLAGS, \
__FILE__, __LINE__); \
PAYLOAD \
if (locker != NULL) \
PSI_TABLE_CALL(end_table_lock_wait)(locker); \
} \
else \
{ \
PAYLOAD \
} \
}
#else
#define MYSQL_TABLE_LOCK_WAIT(OP, FLAGS, PAYLOAD) \
PAYLOAD
#endif
/*
While we have legacy_db_type, we have this array to
check for dups and to find handlerton from legacy_db_type.
@ -1201,7 +1236,8 @@ void ha_pre_shutdown()
times per transaction.
*/
void trans_register_ha(THD *thd, bool all, handlerton *ht_arg)
void trans_register_ha(THD *thd, bool all, handlerton *ht_arg,
const ulonglong *trxid)
{
THD_TRANS *trans;
Ha_trx_info *ha_info;
@ -1232,6 +1268,25 @@ void trans_register_ha(THD *thd, bool all, handlerton *ht_arg)
if (thd->transaction.implicit_xid.is_null())
thd->transaction.implicit_xid.set(thd->query_id);
/*
Register transaction start in performance schema if not done already.
By doing this, we handle cases when the transaction is started implicitly in
autocommit=0 mode, and cases when we are in normal autocommit=1 mode and the
executed statement is a single-statement transaction.
Explicitly started transactions are handled in trans_begin().
Do not register transactions in which binary log is the only participating
transactional storage engine.
*/
if (thd->m_transaction_psi == NULL && ht_arg->db_type != DB_TYPE_BINLOG)
{
thd->m_transaction_psi= MYSQL_START_TRANSACTION(&thd->m_transaction_state,
thd->get_xid(), trxid, thd->tx_isolation, thd->tx_read_only,
!thd->in_multi_stmt_transaction_mode());
DEBUG_SYNC(thd, "after_set_transaction_psi_before_set_transaction_gtid");
//gtid_set_performance_schema_values(thd);
}
DBUG_VOID_RETURN;
}
@ -1457,7 +1512,11 @@ int ha_commit_trans(THD *thd, bool all)
Free resources and perform other cleanup even for 'empty' transactions.
*/
if (is_real_trans)
{
thd->transaction.cleanup();
MYSQL_COMMIT_TRANSACTION(thd->m_transaction_psi);
thd->m_transaction_psi= NULL;
}
#ifdef WITH_WSREP
if (wsrep_is_active(thd) && is_real_trans && !error)
wsrep_commit_empty(thd, all);
@ -1651,12 +1710,15 @@ int ha_commit_trans(THD *thd, bool all)
#endif /* WITH_WSREP */
DBUG_EXECUTE_IF("crash_commit_before_unlog", DBUG_SUICIDE(););
if (tc_log->unlog(cookie, xid))
{
error= 2; /* Error during commit */
goto end;
}
done:
if (is_real_trans)
{
MYSQL_COMMIT_TRANSACTION(thd->m_transaction_psi);
thd->m_transaction_psi= NULL;
}
DBUG_EXECUTE_IF("crash_commit_after", DBUG_SUICIDE(););
mysql_mutex_assert_not_owner(&LOCK_prepare_ordered);
@ -1694,6 +1756,8 @@ err:
ha_rollback_trans(thd, all);
else
{
MYSQL_ROLLBACK_TRANSACTION(thd->m_transaction_psi);
thd->m_transaction_psi= NULL;
WSREP_DEBUG("rollback skipped %p %d",thd->rgi_slave,
thd->rgi_slave->is_parallel_exec);
}
@ -1913,6 +1977,13 @@ int ha_rollback_trans(THD *thd, bool all)
}
(void) wsrep_after_rollback(thd, all);
#endif /* WITH_WSREP */
if (all || !thd->in_active_multi_stmt_transaction())
{
MYSQL_ROLLBACK_TRANSACTION(thd->m_transaction_psi);
thd->m_transaction_psi= NULL;
}
/* Always cleanup. Even if nht==0. There may be savepoints. */
if (is_real_trans)
{
@ -2360,6 +2431,10 @@ int ha_rollback_to_savepoint(THD *thd, SAVEPOINT *sv)
ha_info->reset(); /* keep it conveniently zero-filled */
}
trans->ha_list= sv->ha_list;
if (thd->m_transaction_psi != NULL)
MYSQL_INC_TRANSACTION_ROLLBACK_TO_SAVEPOINT(thd->m_transaction_psi, 1);
DBUG_RETURN(error);
}
@ -2411,6 +2486,9 @@ int ha_savepoint(THD *thd, SAVEPOINT *sv)
*/
sv->ha_list= trans->ha_list;
if (!error && thd->m_transaction_psi != NULL)
MYSQL_INC_TRANSACTION_SAVEPOINTS(thd->m_transaction_psi, 1);
DBUG_RETURN(error);
}
@ -2435,6 +2513,10 @@ int ha_release_savepoint(THD *thd, SAVEPOINT *sv)
error=1;
}
}
if (thd->m_transaction_psi != NULL)
MYSQL_INC_TRANSACTION_RELEASE_SAVEPOINT(thd->m_transaction_psi, 1);
DBUG_RETURN(error);
}

View file

@ -2212,8 +2212,8 @@ void MYSQL_BIN_LOG::set_write_error(THD *thd, bool is_transactional)
if (WSREP_EMULATE_BINLOG(thd))
{
if (is_transactional)
trans_register_ha(thd, TRUE, binlog_hton);
trans_register_ha(thd, FALSE, binlog_hton);
trans_register_ha(thd, TRUE, binlog_hton, NULL);
trans_register_ha(thd, FALSE, binlog_hton, NULL);
}
#endif /* WITH_WSREP */
DBUG_VOID_RETURN;
@ -5713,8 +5713,8 @@ THD::binlog_start_trans_and_stmt()
}
#endif
if (mstmt_mode)
trans_register_ha(this, TRUE, binlog_hton);
trans_register_ha(this, FALSE, binlog_hton);
trans_register_ha(this, TRUE, binlog_hton, NULL);
trans_register_ha(this, FALSE, binlog_hton, NULL);
/*
Mark statement transaction as read/write. We never start
a binary log transaction and keep it read-only,
@ -5758,7 +5758,7 @@ binlog_start_consistent_snapshot(handlerton *hton, THD *thd)
strmake_buf(cache_mngr->last_commit_pos_file, mysql_bin_log.last_commit_pos_file);
cache_mngr->last_commit_pos_offset= mysql_bin_log.last_commit_pos_offset;
trans_register_ha(thd, TRUE, hton);
trans_register_ha(thd, TRUE, binlog_hton, NULL);
DBUG_RETURN(err);
}
@ -10749,8 +10749,8 @@ void wsrep_register_binlog_handler(THD *thd, bool trx)
Set callbacks in order to be able to call commmit or rollback.
*/
if (trx)
trans_register_ha(thd, TRUE, binlog_hton);
trans_register_ha(thd, FALSE, binlog_hton);
trans_register_ha(thd, TRUE, binlog_hton, NULL);
trans_register_ha(thd, FALSE, binlog_hton, NULL);
/*
Set the binary log as read/write otherwise callbacks are not called.

View file

@ -643,6 +643,7 @@ THD::THD(my_thread_id id, bool is_wsrep_applier)
accessed_rows_and_keys(0),
m_digest(NULL),
m_statement_psi(NULL),
m_transaction_psi(NULL),
m_idle_psi(NULL),
col_access(NO_ACL),
thread_id(id),
@ -1189,19 +1190,9 @@ void *thd_memdup(MYSQL_THD thd, const void* str, size_t size)
extern "C"
void thd_get_xid(const MYSQL_THD thd, MYSQL_XID *xid)
{
#ifdef WITH_WSREP
if (!thd->wsrep_xid.is_null())
{
*xid = *(MYSQL_XID *) &thd->wsrep_xid;
return;
}
#endif /* WITH_WSREP */
*xid= thd->transaction.xid_state.is_explicit_XA() ?
*(MYSQL_XID *) thd->transaction.xid_state.get_xid() :
*(MYSQL_XID *) &thd->transaction.implicit_xid;
*xid = *(MYSQL_XID *) thd->get_xid();
}
extern "C"
my_time_t thd_TIME_to_gmt_sec(MYSQL_THD thd, const MYSQL_TIME *ltime,
unsigned int *errcode)

View file

@ -3053,6 +3053,14 @@ public:
/** Current statement instrumentation state. */
PSI_statement_locker_state m_statement_state;
#endif /* HAVE_PSI_STATEMENT_INTERFACE */
/** Current transaction instrumentation. */
PSI_transaction_locker *m_transaction_psi;
#ifdef HAVE_PSI_TRANSACTION_INTERFACE
/** Current transaction instrumentation state. */
PSI_transaction_locker_state m_transaction_state;
#endif /* HAVE_PSI_TRANSACTION_INTERFACE */
/** Idle instrumentation. */
PSI_idle_locker *m_idle_psi;
#ifdef HAVE_PSI_IDLE_INTERFACE
@ -4819,6 +4827,17 @@ public:
LF_PINS *xid_hash_pins;
bool fix_xid_hash_pins();
const XID *get_xid() const
{
#ifdef WITH_WSREP
if (!wsrep_xid.is_null())
return &wsrep_xid;
#endif /* WITH_WSREP */
return transaction.xid_state.is_explicit_XA() ?
transaction.xid_state.get_xid() :
&transaction.implicit_xid;
}
/* Members related to temporary tables. */
public:
/* Opened table states. */

View file

@ -25,6 +25,8 @@
#include "debug_sync.h" // DEBUG_SYNC
#include "sql_acl.h"
#include "semisync_master.h"
#include <pfs_transaction_provider.h>
#include <mysql/psi/mysql_transaction.h>
#ifdef WITH_WSREP
#include "wsrep_trans_observer.h"
#endif /* WITH_WSREP */
@ -209,6 +211,23 @@ bool trans_begin(THD *thd, uint flags)
#endif //EMBEDDED_LIBRARY
res= ha_start_consistent_snapshot(thd);
}
/*
Register transaction start in performance schema if not done already.
We handle explicitly started transactions here, implicitly started
transactions (and single-statement transactions in autocommit=1 mode)
are handled in trans_register_ha().
We can't handle explicit transactions in the same way as implicit
because we want to correctly attribute statements which follow
BEGIN but do not touch any transactional tables.
*/
if (thd->m_transaction_psi == NULL)
{
thd->m_transaction_psi= MYSQL_START_TRANSACTION(&thd->m_transaction_state,
NULL, NULL, thd->tx_isolation,
thd->tx_read_only, false);
DEBUG_SYNC(thd, "after_set_transaction_psi_before_set_transaction_gtid");
//gtid_set_performance_schema_values(thd);
}
DBUG_RETURN(MY_TEST(res));
}
@ -255,6 +274,8 @@ bool trans_commit(THD *thd)
thd->transaction.all.reset();
thd->lex->start_transaction_opt= 0;
/* The transaction should be marked as complete in P_S. */
DBUG_ASSERT(thd->m_transaction_psi == NULL);
trans_track_end_trx(thd);
DBUG_RETURN(MY_TEST(res));
@ -299,6 +320,9 @@ bool trans_commit_implicit(THD *thd)
thd->variables.option_bits&= ~(OPTION_BEGIN | OPTION_KEEP_LOG);
thd->transaction.all.reset();
/* The transaction should be marked as complete in P_S. */
DBUG_ASSERT(thd->m_transaction_psi == NULL);
/*
Upon implicit commit, reset the current transaction
isolation level and access mode. We do not care about
@ -343,6 +367,9 @@ bool trans_rollback(THD *thd)
thd->transaction.all.reset();
thd->lex->start_transaction_opt= 0;
/* The transaction should be marked as complete in P_S. */
DBUG_ASSERT(thd->m_transaction_psi == NULL);
trans_track_end_trx(thd);
DBUG_RETURN(MY_TEST(res));
@ -389,7 +416,9 @@ bool trans_rollback_implicit(THD *thd)
thd->transaction.all.reset();
/* Rollback should clear transaction_rollback_request flag. */
DBUG_ASSERT(! thd->transaction_rollback_request);
DBUG_ASSERT(!thd->transaction_rollback_request);
/* The transaction should be marked as complete in P_S. */
DBUG_ASSERT(thd->m_transaction_psi == NULL);
trans_track_end_trx(thd);
@ -457,6 +486,10 @@ bool trans_commit_stmt(THD *thd)
#endif
}
/* In autocommit=1 mode the transaction should be marked as complete in P_S */
DBUG_ASSERT(thd->in_active_multi_stmt_transaction() ||
thd->m_transaction_psi == NULL);
thd->transaction.stmt.reset();
DBUG_RETURN(MY_TEST(res));
@ -496,6 +529,10 @@ bool trans_rollback_stmt(THD *thd)
repl_semisync_master.wait_after_rollback(thd, FALSE);
#endif
/* In autocommit=1 mode the transaction should be marked as complete in P_S */
DBUG_ASSERT(thd->in_active_multi_stmt_transaction() ||
thd->m_transaction_psi == NULL);
thd->transaction.stmt.reset();
DBUG_RETURN(FALSE);

View file

@ -19,7 +19,8 @@
#include "mariadb.h"
#include "sql_class.h"
#include "transaction.h"
#include <pfs_transaction_provider.h>
#include <mysql/psi/mysql_transaction.h>
/***************************************************************************
Handling of XA id caching
@ -425,7 +426,10 @@ bool trans_xa_start(THD *thd)
if (not_equal)
my_error(ER_XAER_NOTA, MYF(0));
else
{
thd->transaction.xid_state.xid_cache_element->xa_state= XA_ACTIVE;
MYSQL_SET_TRANSACTION_XA_STATE(thd->m_transaction_psi, XA_ACTIVE);
}
DBUG_RETURN(not_equal);
}
@ -440,6 +444,7 @@ bool trans_xa_start(THD *thd)
my_error(ER_XAER_OUTSIDE, MYF(0));
else if (!trans_begin(thd))
{
MYSQL_SET_TRANSACTION_XID(thd->m_transaction_psi, thd->lex->xid, XA_ACTIVE);
if (xid_cache_insert(thd, &thd->transaction.xid_state, thd->lex->xid))
{
trans_rollback(thd);
@ -474,7 +479,10 @@ bool trans_xa_end(THD *thd)
else if (!thd->transaction.xid_state.xid_cache_element->xid.eq(thd->lex->xid))
my_error(ER_XAER_NOTA, MYF(0));
else if (!xa_trans_rolled_back(thd->transaction.xid_state.xid_cache_element))
{
thd->transaction.xid_state.xid_cache_element->xa_state= XA_IDLE;
MYSQL_SET_TRANSACTION_XA_STATE(thd->m_transaction_psi, XA_IDLE);
}
DBUG_RETURN(thd->is_error() ||
thd->transaction.xid_state.xid_cache_element->xa_state != XA_IDLE);
@ -505,7 +513,10 @@ bool trans_xa_prepare(THD *thd)
my_error(ER_XA_RBROLLBACK, MYF(0));
}
else
{
thd->transaction.xid_state.xid_cache_element->xa_state= XA_PREPARED;
MYSQL_SET_TRANSACTION_XA_STATE(thd->m_transaction_psi, XA_PREPARED);
}
DBUG_RETURN(thd->is_error() ||
thd->transaction.xid_state.xid_cache_element->xa_state != XA_PREPARED);
@ -608,6 +619,16 @@ bool trans_xa_commit(THD *thd)
res= MY_TEST(ha_commit_one_phase(thd, 1));
if (res)
my_error(ER_XAER_RMERR, MYF(0));
else
{
/*
Since we don't call ha_commit_trans() for prepared transactions,
we need to explicitly mark the transaction as committed.
*/
MYSQL_COMMIT_TRANSACTION(thd->m_transaction_psi);
}
thd->m_transaction_psi= NULL;
}
}
else
@ -624,7 +645,8 @@ bool trans_xa_commit(THD *thd)
xid_cache_delete(thd, &thd->transaction.xid_state);
trans_track_end_trx(thd);
/* The transaction should be marked as complete in P_S. */
DBUG_ASSERT(thd->m_transaction_psi == NULL || res);
DBUG_RETURN(res);
}

View file

@ -3492,7 +3492,7 @@ int ha_federatedx::start_stmt(MYSQL_THD thd, thr_lock_type lock_type)
if (!txn->in_transaction())
{
txn->stmt_begin();
trans_register_ha(thd, FALSE, ht);
trans_register_ha(thd, FALSE, ht, NULL);
}
DBUG_RETURN(0);
}
@ -3515,12 +3515,12 @@ int ha_federatedx::external_lock(MYSQL_THD thd, int lock_type)
if (!thd_test_options(thd, (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))
{
txn->stmt_begin();
trans_register_ha(thd, FALSE, ht);
trans_register_ha(thd, FALSE, ht, NULL);
}
else
{
txn->txn_begin();
trans_register_ha(thd, TRUE, ht);
trans_register_ha(thd, TRUE, ht, NULL);
}
}
}
@ -3538,7 +3538,7 @@ int ha_federatedx::savepoint_set(handlerton *hton, MYSQL_THD thd, void *sv)
if (txn && txn->has_connections())
{
if (txn->txn_begin())
trans_register_ha(thd, TRUE, hton);
trans_register_ha(thd, TRUE, hton, NULL);
txn->sp_acquire((ulong *) sv);

View file

@ -2786,19 +2786,15 @@ innobase_register_trx(
THD* thd, /* in: MySQL thd (connection) object */
trx_t* trx) /* in: transaction to register */
{
/* JAN: TODO: MySQL 5.7 PSI
const ulonglong trx_id = static_cast<const ulonglong>(
const ulonglong trx_id = static_cast<ulonglong>(
trx_get_id_for_print(trx));
trans_register_ha(thd, FALSE, hton, &trx_id);
*/
trans_register_ha(thd, FALSE, hton);
if (!trx_is_registered_for_2pc(trx)
&& thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
//trans_register_ha(thd, TRUE, hton, &trx_id);
trans_register_ha(thd, TRUE, hton);
trans_register_ha(thd, TRUE, hton, &trx_id);
}
trx_register_for_2pc(trx);

View file

@ -4788,10 +4788,10 @@ static inline void rocksdb_register_tx(handlerton *const hton, THD *const thd,
Rdb_transaction *const tx) {
DBUG_ASSERT(tx != nullptr);
trans_register_ha(thd, FALSE, rocksdb_hton);
trans_register_ha(thd, FALSE, rocksdb_hton, NULL);
if (my_core::thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) {
tx->start_stmt();
trans_register_ha(thd, TRUE, rocksdb_hton);
trans_register_ha(thd, TRUE, rocksdb_hton, NULL);
}
}

View file

@ -1990,9 +1990,9 @@ int spider_internal_start_trx(
trx->trx_consistent_snapshot ? "TRUE" : "FALSE"));
if (!trx->trx_consistent_snapshot)
{
trans_register_ha(thd, FALSE, spider_hton_ptr);
trans_register_ha(thd, FALSE, spider_hton_ptr, NULL);
if (thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
trans_register_ha(thd, TRUE, spider_hton_ptr);
trans_register_ha(thd, TRUE, spider_hton_ptr, NULL);
}
trx->trx_start = TRUE;
trx->trx_xa_prepared = FALSE;
@ -3335,8 +3335,8 @@ int spider_start_consistent_snapshot(
trx->trx_consistent_snapshot = TRUE;
trx->use_consistent_snapshot = TRUE;
trx->internal_xa_snapshot = spider_param_internal_xa_snapshot(trx->thd);
trans_register_ha(trx->thd, FALSE, spider_hton_ptr);
trans_register_ha(trx->thd, TRUE, spider_hton_ptr);
trans_register_ha(trx->thd, FALSE, spider_hton_ptr, NULL);
trans_register_ha(trx->thd, TRUE, spider_hton_ptr, NULL);
if (spider_param_use_all_conns_snapshot(trx->thd))
{
trx->internal_xa = FALSE;