Commit 968061fd authored by Vlad Lesin's avatar Vlad Lesin

MDEV-28682 gcol.gcol_purge contaminates further execution of innodb.gap_locks

ha_innobase::extra() invokes check_trx_exists() unconditionally even for
not supported operations. check_trx_exists() creates and registers trx_t
object if THD does not contain pointer to it. If ha_innobase::extra() does
not support some operation, it just invokes check_trx_exists() and quites.
If check_trx_exists() creates and registers new trx_t object for such
operation, it will never be freed and deregistered.

For example, if ha_innobase::extra() is invoked from purge thread with
operation = HA_EXTRA_IS_ATTACHED_CHILDREN, like it goes in
gcol.gcol_purge test, trx_t object will be registered, but not
deregisreted, and this causes innodb.gap_lock failure, as "SHOW ENGINE
INNODB STATUS" shows information about unexpected transaction at the end
of trx_sys.trx_list.

The fix is not to invoke check_trx_exists() for unsupported operations
in ha_innobase::extra().

Reviewed by: Marko Mäkelä
parent 387b92df
......@@ -15412,29 +15412,33 @@ ha_innobase::extra(
enum ha_extra_function operation)
/*!< in: HA_EXTRA_FLUSH or some other flag */
{
check_trx_exists(ha_thd());
/* Warning: since it is not sure that MySQL calls external_lock
before calling this function, the trx field in m_prebuilt can be
obsolete! */
trx_t *trx;
switch (operation) {
case HA_EXTRA_FLUSH:
(void)check_trx_exists(ha_thd());
if (m_prebuilt->blob_heap) {
row_mysql_prebuilt_free_blob_heap(m_prebuilt);
}
break;
case HA_EXTRA_RESET_STATE:
trx = check_trx_exists(ha_thd());
reset_template();
thd_to_trx(ha_thd())->duplicates = 0;
trx->duplicates = 0;
break;
case HA_EXTRA_NO_KEYREAD:
(void)check_trx_exists(ha_thd());
m_prebuilt->read_just_key = 0;
break;
case HA_EXTRA_KEYREAD:
(void)check_trx_exists(ha_thd());
m_prebuilt->read_just_key = 1;
break;
case HA_EXTRA_KEYREAD_PRESERVE_FIELDS:
(void)check_trx_exists(ha_thd());
m_prebuilt->keep_other_fields_on_keyread = 1;
break;
......@@ -15445,18 +15449,23 @@ ha_innobase::extra(
either, because the calling threads may change.
CAREFUL HERE, OR MEMORY CORRUPTION MAY OCCUR! */
case HA_EXTRA_INSERT_WITH_UPDATE:
thd_to_trx(ha_thd())->duplicates |= TRX_DUP_IGNORE;
trx = check_trx_exists(ha_thd());
trx->duplicates |= TRX_DUP_IGNORE;
break;
case HA_EXTRA_NO_IGNORE_DUP_KEY:
thd_to_trx(ha_thd())->duplicates &= ~TRX_DUP_IGNORE;
trx = check_trx_exists(ha_thd());
trx->duplicates &= ~TRX_DUP_IGNORE;
break;
case HA_EXTRA_WRITE_CAN_REPLACE:
thd_to_trx(ha_thd())->duplicates |= TRX_DUP_REPLACE;
trx = check_trx_exists(ha_thd());
trx->duplicates |= TRX_DUP_REPLACE;
break;
case HA_EXTRA_WRITE_CANNOT_REPLACE:
thd_to_trx(ha_thd())->duplicates &= ~TRX_DUP_REPLACE;
trx = check_trx_exists(ha_thd());
trx->duplicates &= ~TRX_DUP_REPLACE;
break;
case HA_EXTRA_BEGIN_ALTER_COPY:
(void)check_trx_exists(ha_thd());
m_prebuilt->table->skip_alter_undo = 1;
if (m_prebuilt->table->is_temporary()
|| !m_prebuilt->table->versioned_by_id()) {
......@@ -15470,6 +15479,7 @@ ha_innobase::extra(
.first->second.set_versioned(0);
break;
case HA_EXTRA_END_ALTER_COPY:
(void)check_trx_exists(ha_thd());
m_prebuilt->table->skip_alter_undo = 0;
break;
default:/* Do nothing */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment