Fixes for Aria transaction handling with lock tables
MDEV-10130 Assertion `share->in_trans == 0' failed in storage/maria/ma_close.c MDEV-10378 Assertion `trn' failed in virtual int ha_maria::start_stmt The problem was that maria_handler->trn was not properly reset at commit/rollback and ha_maria::exernal_lock() could get confused because. There was some old code in ha_maria::implicit_commit() that tried to take care of this, but it was not bullet proof. Fixed by adding list of all tables that is part of the maria transaction to TRN. A nice side effect was of the fix is that loops in ha_maria::implict_commit() got to be much simpler. Other things: - Fixed a bug in mysql_admin_table() where argument open_for_modify was wrongly reset for the next table in the chain - rollback admin command also in case of fatal error. - Split _ma_set_trn_for_table() to three version to simplify code and debugging. - Several new asserts to detect the original problem (that file was not properly removed from trn before calling ma_close())
This commit is contained in:
parent
c1b5d2801e
commit
2f3779d31c
@ -99,3 +99,13 @@ f2
|
||||
3
|
||||
unlock tables;
|
||||
DROP TABLE t1,t2,tmp;
|
||||
#
|
||||
# MDEV-10378 Assertion `trn' failed in virtual int ha_maria::start_stmt
|
||||
#
|
||||
CREATE TABLE t1 (f1 VARCHAR(3), f2 INT, pk INT, PRIMARY KEY (pk)) ENGINE=Aria;
|
||||
INSERT INTO t1 VALUES ('foo',10,1), ('foo',1,2);
|
||||
LOCK TABLE t1 WRITE;
|
||||
ALTER TABLE t1 ADD UNIQUE KEY (f1);
|
||||
ERROR 23000: Duplicate entry 'foo' for key 'f1'
|
||||
ALTER TABLE t1 ADD KEY (f2);
|
||||
DROP TABLE t1;
|
||||
|
@ -105,3 +105,15 @@ INSERT INTO t2 (f2) SELECT f3 FROM tmp AS tmp_alias;
|
||||
select * from t2;
|
||||
unlock tables;
|
||||
DROP TABLE t1,t2,tmp;
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-10378 Assertion `trn' failed in virtual int ha_maria::start_stmt
|
||||
--echo #
|
||||
|
||||
CREATE TABLE t1 (f1 VARCHAR(3), f2 INT, pk INT, PRIMARY KEY (pk)) ENGINE=Aria;
|
||||
INSERT INTO t1 VALUES ('foo',10,1), ('foo',1,2);
|
||||
LOCK TABLE t1 WRITE;
|
||||
--error ER_DUP_ENTRY
|
||||
ALTER TABLE t1 ADD UNIQUE KEY (f1);
|
||||
ALTER TABLE t1 ADD KEY (f2);
|
||||
DROP TABLE t1;
|
||||
|
@ -302,7 +302,7 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
|
||||
HA_CHECK_OPT* check_opt,
|
||||
const char *operator_name,
|
||||
thr_lock_type lock_type,
|
||||
bool open_for_modify,
|
||||
bool org_open_for_modify,
|
||||
bool repair_table_use_frm,
|
||||
uint extra_open_options,
|
||||
int (*prepare_func)(THD *, TABLE_LIST *,
|
||||
@ -359,10 +359,10 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
|
||||
for (table= tables; table; table= table->next_local)
|
||||
{
|
||||
char table_name[SAFE_NAME_LEN*2+2];
|
||||
char* db = table->db;
|
||||
char *db= table->db;
|
||||
bool fatal_error=0;
|
||||
bool open_error;
|
||||
|
||||
bool open_for_modify= org_open_for_modify;
|
||||
DBUG_PRINT("admin", ("table: '%s'.'%s'", table->db, table->table_name));
|
||||
strxmov(table_name, db, ".", table->table_name, NullS);
|
||||
thd->open_options|= extra_open_options;
|
||||
@ -395,8 +395,8 @@ static bool mysql_admin_table(THD* thd, TABLE_LIST* tables,
|
||||
|
||||
/*
|
||||
CHECK TABLE command is allowed for views as well. Check on alter flags
|
||||
to differentiate from ALTER TABLE...CHECK PARTITION on which view is not
|
||||
allowed.
|
||||
to differentiate from ALTER TABLE...CHECK PARTITION on which view is
|
||||
not allowed.
|
||||
*/
|
||||
if (lex->alter_info.flags & Alter_info::ALTER_ADMIN_PARTITION ||
|
||||
view_operator_func == NULL)
|
||||
@ -1053,7 +1053,7 @@ send_result_message:
|
||||
}
|
||||
}
|
||||
/* Error path, a admin command failed. */
|
||||
if (thd->transaction_rollback_request)
|
||||
if (thd->transaction_rollback_request || fatal_error)
|
||||
{
|
||||
/*
|
||||
Unlikely, but transaction rollback was requested by one of storage
|
||||
|
@ -155,10 +155,11 @@ static void mysql_ha_close_table(SQL_HANDLER *handler)
|
||||
{
|
||||
THD *thd= handler->thd;
|
||||
TABLE *table= handler->table;
|
||||
DBUG_ENTER("mysql_ha_close_table");
|
||||
|
||||
/* check if table was already closed */
|
||||
if (!table)
|
||||
return;
|
||||
DBUG_VOID_RETURN;
|
||||
|
||||
if (!table->s->tmp_table)
|
||||
{
|
||||
@ -184,6 +185,7 @@ static void mysql_ha_close_table(SQL_HANDLER *handler)
|
||||
}
|
||||
my_free(handler->lock);
|
||||
handler->init();
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -37,6 +37,7 @@ C_MODE_START
|
||||
#include "ma_checkpoint.h"
|
||||
#include "ma_recovery.h"
|
||||
C_MODE_END
|
||||
#include "ma_trnman.h"
|
||||
|
||||
//#include "sql_priv.h"
|
||||
#include "protocol.h"
|
||||
@ -1384,7 +1385,8 @@ int ha_maria::check(THD * thd, HA_CHECK_OPT * check_opt)
|
||||
}
|
||||
|
||||
/* Reset trn, that may have been set by repair */
|
||||
_ma_set_trn_for_table(file, old_trn);
|
||||
if (old_trn && old_trn != file->trn)
|
||||
_ma_set_trn_for_table(file, old_trn);
|
||||
thd_proc_info(thd, old_proc_info);
|
||||
thd_progress_end(thd);
|
||||
return error ? HA_ADMIN_CORRUPT : HA_ADMIN_OK;
|
||||
@ -1518,7 +1520,8 @@ int ha_maria::zerofill(THD * thd, HA_CHECK_OPT *check_opt)
|
||||
error=maria_zerofill(param, file, share->open_file_name.str);
|
||||
|
||||
/* Reset trn, that may have been set by repair */
|
||||
_ma_set_trn_for_table(file, old_trn);
|
||||
if (old_trn && old_trn != file->trn)
|
||||
_ma_set_trn_for_table(file, old_trn);
|
||||
|
||||
if (!error)
|
||||
{
|
||||
@ -1758,7 +1761,8 @@ int ha_maria::repair(THD *thd, HA_CHECK *param, bool do_optimize)
|
||||
maria_lock_database(file, F_UNLCK);
|
||||
|
||||
/* Reset trn, that may have been set by repair */
|
||||
_ma_set_trn_for_table(file, old_trn);
|
||||
if (old_trn && old_trn != file->trn)
|
||||
_ma_set_trn_for_table(file, old_trn);
|
||||
error= error ? HA_ADMIN_FAILED :
|
||||
(optimize_done ?
|
||||
(write_log_record_for_repair(param, file) ? HA_ADMIN_FAILED :
|
||||
@ -2579,9 +2583,12 @@ int ha_maria::extra(enum ha_extra_function operation)
|
||||
without calling commit/rollback in between. If file->trn is not set
|
||||
we can't remove file->share from the transaction list in the extra() call.
|
||||
|
||||
We also ensure that we set file->trn to 0 if THD_TRN is 0 as in
|
||||
this case we have already freed the trn. This can happen when one
|
||||
implicit_commit() is called as part of alter table.
|
||||
In current code we don't have to do this for HA_EXTRA_PREPARE_FOR_RENAME
|
||||
as this is only used the intermediate table used by ALTER TABLE which
|
||||
is not part of the transaction (it's not in the TRN list). Better to
|
||||
keep this for now, to not break anything in a stable release.
|
||||
When HA_EXTRA_PREPARE_FOR_RENAME is not handled below, we can change
|
||||
the warnings in _ma_remove_table_from_trnman() to asserts.
|
||||
|
||||
table->in_use is not set in the case this is a done as part of closefrm()
|
||||
as part of drop table.
|
||||
@ -2594,7 +2601,7 @@ int ha_maria::extra(enum ha_extra_function operation)
|
||||
{
|
||||
THD *thd= table->in_use;
|
||||
TRN *trn= THD_TRN;
|
||||
_ma_set_trn_for_table(file, trn);
|
||||
_ma_set_tmp_trn_for_table(file, trn);
|
||||
}
|
||||
DBUG_ASSERT(file->s->base.born_transactional || file->trn == 0 ||
|
||||
file->trn == &dummy_transaction_object);
|
||||
@ -2710,6 +2717,7 @@ int ha_maria::external_lock(THD *thd, int lock_type)
|
||||
if (file->trn)
|
||||
{
|
||||
/* This can only happen with tables created with clone() */
|
||||
DBUG_PRINT("info",("file->trn: %p", file->trn));
|
||||
trnman_increment_locked_tables(file->trn);
|
||||
}
|
||||
|
||||
@ -2730,7 +2738,7 @@ int ha_maria::external_lock(THD *thd, int lock_type)
|
||||
}
|
||||
else
|
||||
{
|
||||
TRN *trn= THD_TRN;
|
||||
TRN *trn= (file->trn != &dummy_transaction_object ? file->trn : 0);
|
||||
/* End of transaction */
|
||||
|
||||
/*
|
||||
@ -2745,8 +2753,7 @@ int ha_maria::external_lock(THD *thd, int lock_type)
|
||||
*/
|
||||
if (_ma_reenable_logging_for_table(file, TRUE))
|
||||
DBUG_RETURN(1);
|
||||
/** @todo zero file->trn also in commit and rollback */
|
||||
_ma_set_trn_for_table(file, NULL); // Safety
|
||||
_ma_reset_trn_for_table(file);
|
||||
/*
|
||||
Ensure that file->state points to the current number of rows. This
|
||||
is needed if someone calls maria_info() without first doing an
|
||||
@ -2802,13 +2809,6 @@ int ha_maria::start_stmt(THD *thd, thr_lock_type lock_type)
|
||||
DBUG_ASSERT(lock_type != TL_UNLOCK);
|
||||
DBUG_ASSERT(file->trn == trn);
|
||||
|
||||
/*
|
||||
If there was an implicit commit under this LOCK TABLES by a previous
|
||||
statement (like a DDL), at least if that previous statement was about a
|
||||
different ha_maria than 'this' then this->file->trn is a stale
|
||||
pointer. We fix it:
|
||||
*/
|
||||
_ma_set_trn_for_table(file, trn);
|
||||
/*
|
||||
As external_lock() was already called, don't increment locked_tables.
|
||||
Note that we call the function below possibly several times when
|
||||
@ -2833,6 +2833,23 @@ int ha_maria::start_stmt(THD *thd, thr_lock_type lock_type)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Reset THD_TRN and all file->trn related to the transaction
|
||||
This is needed as some calls, like extra() or external_lock() may access
|
||||
it before next transaction is started
|
||||
*/
|
||||
|
||||
static void reset_thd_trn(THD *thd, MARIA_HA *first_table)
|
||||
{
|
||||
DBUG_ENTER("reset_thd_trn");
|
||||
THD_TRN= NULL;
|
||||
for (MARIA_HA *table= first_table; table ;
|
||||
table= table->trn_next)
|
||||
_ma_reset_trn_for_table(table);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Performs an implicit commit of the Maria transaction and creates a new
|
||||
one.
|
||||
@ -2856,9 +2873,9 @@ int ha_maria::implicit_commit(THD *thd, bool new_trn)
|
||||
TRN *trn;
|
||||
int error;
|
||||
uint locked_tables;
|
||||
DYNAMIC_ARRAY used_tables;
|
||||
|
||||
MARIA_HA *used_tables, *trn_next;
|
||||
DBUG_ENTER("ha_maria::implicit_commit");
|
||||
|
||||
if (!maria_hton || !(trn= THD_TRN))
|
||||
DBUG_RETURN(0);
|
||||
if (!new_trn && (thd->locked_tables_mode == LTM_LOCK_TABLES ||
|
||||
@ -2876,48 +2893,16 @@ int ha_maria::implicit_commit(THD *thd, bool new_trn)
|
||||
|
||||
locked_tables= trnman_has_locked_tables(trn);
|
||||
|
||||
if (new_trn && trn && trn->used_tables)
|
||||
{
|
||||
MARIA_USED_TABLES *tables;
|
||||
/*
|
||||
Save locked tables so that we can move them to another transaction
|
||||
We are using a dynamic array as locked_tables in some cases can be
|
||||
smaller than the used_tables list (for example when the server does
|
||||
early unlock of tables.
|
||||
*/
|
||||
|
||||
my_init_dynamic_array2(&used_tables, sizeof(MARIA_SHARE*), (void*) 0,
|
||||
locked_tables, 8, MYF(MY_THREAD_SPECIFIC));
|
||||
for (tables= (MARIA_USED_TABLES*) trn->used_tables;
|
||||
tables;
|
||||
tables= tables->next)
|
||||
{
|
||||
if (tables->share->base.born_transactional)
|
||||
{
|
||||
if (insert_dynamic(&used_tables, (uchar*) &tables->share))
|
||||
{
|
||||
error= HA_ERR_OUT_OF_MEM;
|
||||
goto end_and_free;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
bzero(&used_tables, sizeof(used_tables));
|
||||
|
||||
used_tables= (MARIA_HA*) trn->used_instances;
|
||||
error= 0;
|
||||
if (unlikely(ma_commit(trn)))
|
||||
error= 1;
|
||||
if (!new_trn)
|
||||
{
|
||||
/*
|
||||
To be extra safe, we should also reset file->trn for all open
|
||||
tables as some calls, like extra() may access it. We take care
|
||||
of this in extra() by resetting file->trn if THD_TRN is 0.
|
||||
*/
|
||||
THD_TRN= NULL;
|
||||
reset_thd_trn(thd, used_tables);
|
||||
goto end;
|
||||
}
|
||||
|
||||
/*
|
||||
We need to create a new transaction and put it in THD_TRN. Indeed,
|
||||
tables may be under LOCK TABLES, and so they will start the next
|
||||
@ -2927,8 +2912,9 @@ int ha_maria::implicit_commit(THD *thd, bool new_trn)
|
||||
THD_TRN= trn;
|
||||
if (unlikely(trn == NULL))
|
||||
{
|
||||
reset_thd_trn(thd, used_tables);
|
||||
error= HA_ERR_OUT_OF_MEM;
|
||||
goto end_and_free;
|
||||
goto end;
|
||||
}
|
||||
/*
|
||||
Move all locked tables to the new transaction
|
||||
@ -2938,35 +2924,25 @@ int ha_maria::implicit_commit(THD *thd, bool new_trn)
|
||||
in check table, we use the table without calling start_stmt().
|
||||
*/
|
||||
|
||||
uint i;
|
||||
for (i= 0 ; i < used_tables.elements ; i++)
|
||||
for (MARIA_HA *handler= used_tables; handler ;
|
||||
handler= trn_next)
|
||||
{
|
||||
MARIA_SHARE *share;
|
||||
LIST *handlers;
|
||||
trn_next= handler->trn_next;
|
||||
DBUG_ASSERT(handler->s->base.born_transactional);
|
||||
|
||||
share= *(dynamic_element(&used_tables, i, MARIA_SHARE**));
|
||||
/* Find table instances that was used in this transaction */
|
||||
for (handlers= share->open_list; handlers; handlers= handlers->next)
|
||||
/* If handler uses versioning */
|
||||
if (handler->s->lock_key_trees)
|
||||
{
|
||||
MARIA_HA *handler= (MARIA_HA*) handlers->data;
|
||||
if (handler->external_ref &&
|
||||
((TABLE*) handler->external_ref)->in_use == thd)
|
||||
{
|
||||
_ma_set_trn_for_table(handler, trn);
|
||||
/* If handler uses versioning */
|
||||
if (handler->s->lock_key_trees)
|
||||
{
|
||||
if (_ma_setup_live_state(handler))
|
||||
error= HA_ERR_OUT_OF_MEM;
|
||||
}
|
||||
}
|
||||
/* _ma_set_trn_for_table() will be called indirectly */
|
||||
if (_ma_setup_live_state(handler))
|
||||
error= HA_ERR_OUT_OF_MEM;
|
||||
}
|
||||
else
|
||||
_ma_set_trn_for_table(handler, trn);
|
||||
}
|
||||
/* This is just a commit, tables stay locked if they were: */
|
||||
trnman_reset_locked_tables(trn, locked_tables);
|
||||
|
||||
end_and_free:
|
||||
delete_dynamic(&used_tables);
|
||||
end:
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
@ -3340,10 +3316,10 @@ static int maria_commit(handlerton *hton __attribute__ ((unused)),
|
||||
trnman_set_flags(trn, trnman_get_flags(trn) & ~TRN_STATE_INFO_LOGGED);
|
||||
|
||||
/* statement or transaction ? */
|
||||
if ((thd->variables.option_bits & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) && !all)
|
||||
if ((thd->variables.option_bits & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)) &&
|
||||
!all)
|
||||
DBUG_RETURN(0); // end of statement
|
||||
DBUG_PRINT("info", ("THD_TRN set to 0x0"));
|
||||
THD_TRN= 0;
|
||||
reset_thd_trn(thd, (MARIA_HA*) trn->used_instances);
|
||||
DBUG_RETURN(ma_commit(trn)); // end of transaction
|
||||
}
|
||||
|
||||
@ -3360,8 +3336,7 @@ static int maria_rollback(handlerton *hton __attribute__ ((unused)),
|
||||
trnman_rollback_statement(trn);
|
||||
DBUG_RETURN(0); // end of statement
|
||||
}
|
||||
DBUG_PRINT("info", ("THD_TRN set to 0x0"));
|
||||
THD_TRN= 0;
|
||||
reset_thd_trn(thd, (MARIA_HA*) trn->used_instances);
|
||||
DBUG_RETURN(trnman_rollback_trn(trn) ?
|
||||
HA_ERR_OUT_OF_MEM : 0); // end of transaction
|
||||
}
|
||||
|
@ -193,6 +193,7 @@ public:
|
||||
private:
|
||||
DsMrr_impl ds_mrr;
|
||||
friend ICP_RESULT index_cond_func_maria(void *arg);
|
||||
friend void reset_thd_trn(THD *thd);
|
||||
};
|
||||
|
||||
#endif /* HA_MARIA_INCLUDED */
|
||||
|
@ -271,6 +271,7 @@
|
||||
#include "maria_def.h"
|
||||
#include "ma_blockrec.h"
|
||||
#include "trnman.h"
|
||||
#include "ma_trnman.h"
|
||||
#include "ma_key_recover.h"
|
||||
#include "ma_recovery_util.h"
|
||||
#include <lf.h>
|
||||
@ -7488,7 +7489,7 @@ void maria_ignore_trids(MARIA_HA *info)
|
||||
if (info->s->base.born_transactional)
|
||||
{
|
||||
if (!info->trn)
|
||||
_ma_set_trn_for_table(info, &dummy_transaction_object);
|
||||
_ma_set_tmp_trn_for_table(info, &dummy_transaction_object);
|
||||
/* Ignore transaction id when row is read */
|
||||
info->trn->min_read_from= ~(TrID) 0;
|
||||
}
|
||||
|
@ -36,6 +36,8 @@ int maria_close(register MARIA_HA *info)
|
||||
|
||||
/* Check that we have unlocked key delete-links properly */
|
||||
DBUG_ASSERT(info->key_del_used == 0);
|
||||
/* Check that file is not part of any uncommited transactions */
|
||||
DBUG_ASSERT(info->trn == 0 || info->trn == &dummy_transaction_object);
|
||||
|
||||
if (share->reopen == 1)
|
||||
{
|
||||
|
@ -15,6 +15,7 @@
|
||||
|
||||
#include "maria_def.h"
|
||||
#include "trnman.h"
|
||||
#include "ma_trnman.h"
|
||||
|
||||
/**
|
||||
writes a COMMIT record to log and commits transaction in memory
|
||||
@ -43,9 +44,9 @@ int ma_commit(TRN *trn)
|
||||
COMMIT record) and this is not an issue as
|
||||
* transaction's updates were not made visible to other transactions
|
||||
* "commit ok" was not sent to client
|
||||
Alternatively, Recovery might commit trn (if MY_MIN(rec_lsn) is before COMMIT
|
||||
record), which is ok too. All in all it means that "trn committed" is not
|
||||
100% equal to "COMMIT record written".
|
||||
Alternatively, Recovery might commit trn (if MY_MIN(rec_lsn) is before
|
||||
COMMIT record), which is ok too. All in all it means that "trn committed"
|
||||
is not 100% equal to "COMMIT record written".
|
||||
- if COMMIT record is written after trnman_commit_trn():
|
||||
if crash happens between the two, trn will be rolled back which is an
|
||||
issue (transaction's updates were made visible to other transactions).
|
||||
@ -93,7 +94,12 @@ int ma_commit(TRN *trn)
|
||||
|
||||
int maria_commit(MARIA_HA *info)
|
||||
{
|
||||
return info->s->now_transactional ? ma_commit(info->trn) : 0;
|
||||
TRN *trn;
|
||||
if (!info->s->now_transactional)
|
||||
return 0;
|
||||
trn= info->trn;
|
||||
info->trn= 0; /* checked in maria_close() */
|
||||
return ma_commit(trn);
|
||||
}
|
||||
|
||||
|
||||
@ -120,10 +126,7 @@ int maria_begin(MARIA_HA *info)
|
||||
TRN *trn= trnman_new_trn(0);
|
||||
if (unlikely(!trn))
|
||||
DBUG_RETURN(HA_ERR_OUT_OF_MEM);
|
||||
|
||||
DBUG_PRINT("info", ("TRN set to 0x%lx", (ulong) trn));
|
||||
_ma_set_trn_for_table(info, trn);
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
@ -345,7 +345,7 @@ int maria_extra(MARIA_HA *info, enum ha_extra_function function,
|
||||
_ma_decrement_open_count(info, 0);
|
||||
if (info->trn)
|
||||
{
|
||||
_ma_remove_table_from_trnman(share, info->trn);
|
||||
_ma_remove_table_from_trnman(info);
|
||||
/* Ensure we don't point to the deleted data in trn */
|
||||
info->state= info->state_start= &share->state.state;
|
||||
}
|
||||
@ -408,7 +408,7 @@ int maria_extra(MARIA_HA *info, enum ha_extra_function function,
|
||||
if (info->trn)
|
||||
{
|
||||
mysql_mutex_lock(&share->intern_lock);
|
||||
_ma_remove_table_from_trnman(share, info->trn);
|
||||
_ma_remove_table_from_trnman(info);
|
||||
/* Ensure we don't point to the deleted data in trn */
|
||||
info->state= info->state_start= &share->state.state;
|
||||
mysql_mutex_unlock(&share->intern_lock);
|
||||
|
@ -19,6 +19,8 @@
|
||||
#include "ma_sp_defs.h"
|
||||
#include "ma_rt_index.h"
|
||||
#include "ma_blockrec.h"
|
||||
#include "trnman.h"
|
||||
#include "ma_trnman.h"
|
||||
#include <m_ctype.h>
|
||||
|
||||
#if defined(MSDOS) || defined(__WIN__)
|
||||
@ -183,7 +185,7 @@ static MARIA_HA *maria_clone_internal(MARIA_SHARE *share,
|
||||
if (!share->base.born_transactional) /* For transactional ones ... */
|
||||
{
|
||||
/* ... force crash if no trn given */
|
||||
_ma_set_trn_for_table(&info, &dummy_transaction_object);
|
||||
_ma_set_tmp_trn_for_table(&info, &dummy_transaction_object);
|
||||
info.state= &share->state.state; /* Change global values by default */
|
||||
}
|
||||
else
|
||||
|
@ -66,7 +66,7 @@ my_bool _ma_setup_live_state(MARIA_HA *info)
|
||||
DBUG_RETURN(1);
|
||||
|
||||
trn= info->trn;
|
||||
for (tables= (MARIA_USED_TABLES*) info->trn->used_tables;
|
||||
for (tables= (MARIA_USED_TABLES*) trn->used_tables;
|
||||
tables;
|
||||
tables= tables->next)
|
||||
{
|
||||
@ -551,6 +551,7 @@ my_bool _ma_trnman_end_trans_hook(TRN *trn, my_bool commit,
|
||||
my_free(tables);
|
||||
}
|
||||
trn->used_tables= 0;
|
||||
trn->used_instances= 0;
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
|
||||
@ -565,18 +566,25 @@ my_bool _ma_trnman_end_trans_hook(TRN *trn, my_bool commit,
|
||||
share->internal_lock must be locked when function is called
|
||||
*/
|
||||
|
||||
void _ma_remove_table_from_trnman(MARIA_SHARE *share, TRN *trn)
|
||||
void _ma_remove_table_from_trnman(MARIA_HA *info)
|
||||
{
|
||||
MARIA_SHARE *share= info->s;
|
||||
TRN *trn= info->trn;
|
||||
MARIA_USED_TABLES *tables, **prev;
|
||||
MARIA_HA *handler, **prev_file;
|
||||
DBUG_ENTER("_ma_remove_table_from_trnman");
|
||||
DBUG_PRINT("enter", ("trn: %p used_tables: %p share: %p in_trans: %d",
|
||||
trn, trn->used_tables, share, share->in_trans));
|
||||
|
||||
mysql_mutex_assert_owner(&share->intern_lock);
|
||||
|
||||
for (prev= (MARIA_USED_TABLES**) (char*) &trn->used_tables, tables= *prev;
|
||||
tables;
|
||||
tables= *prev)
|
||||
if (trn == &dummy_transaction_object)
|
||||
DBUG_VOID_RETURN;
|
||||
|
||||
/* First remove share from used_tables */
|
||||
for (prev= (MARIA_USED_TABLES**) (char*) &trn->used_tables;
|
||||
(tables= *prev);
|
||||
prev= &tables->next)
|
||||
{
|
||||
if (tables->share == share)
|
||||
{
|
||||
@ -585,8 +593,36 @@ void _ma_remove_table_from_trnman(MARIA_SHARE *share, TRN *trn)
|
||||
my_free(tables);
|
||||
break;
|
||||
}
|
||||
prev= &tables->next;
|
||||
}
|
||||
if (tables != 0)
|
||||
{
|
||||
/*
|
||||
This can only happens in case of rename of intermediate table as
|
||||
part of alter table
|
||||
*/
|
||||
DBUG_PRINT("warning", ("share: %p where not in used_tables_list", share));
|
||||
}
|
||||
|
||||
/* unlink table from used_instances */
|
||||
for (prev_file= (MARIA_HA**) &trn->used_instances;
|
||||
(handler= *prev_file);
|
||||
prev_file= &handler->trn_next)
|
||||
{
|
||||
if (handler == info)
|
||||
{
|
||||
*prev_file= info->trn_next;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (handler != 0)
|
||||
{
|
||||
/*
|
||||
This can only happens in case of rename of intermediate table as
|
||||
part of alter table
|
||||
*/
|
||||
DBUG_PRINT("warning", ("table: %p where not in used_instances", info));
|
||||
}
|
||||
info->trn= 0; /* Not part of trans anymore */
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
@ -84,5 +84,5 @@ my_bool _ma_row_visible_non_transactional_table(MARIA_HA *info);
|
||||
my_bool _ma_row_visible_transactional_table(MARIA_HA *info);
|
||||
void _ma_remove_not_visible_states_with_lock(struct st_maria_share *share,
|
||||
my_bool all);
|
||||
void _ma_remove_table_from_trnman(struct st_maria_share *share, TRN *trn);
|
||||
void _ma_remove_table_from_trnman(MARIA_HA *info);
|
||||
void _ma_reset_history(struct st_maria_share *share);
|
||||
|
65
storage/maria/ma_trnman.h
Normal file
65
storage/maria/ma_trnman.h
Normal file
@ -0,0 +1,65 @@
|
||||
/* Copyright (C) 2006-2008 MySQL AB, 2008-2009 Sun Microsystems, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
#ifndef _ma_trnman_h
|
||||
#define _ma_trnman_h
|
||||
|
||||
/**
|
||||
Sets table's trn and prints debug information
|
||||
Links table into used_instances if new_trn is not 0
|
||||
|
||||
@param tbl MARIA_HA of table
|
||||
@param newtrn what to put into tbl->trn
|
||||
*/
|
||||
|
||||
static inline void _ma_set_trn_for_table(MARIA_HA *tbl, TRN *newtrn)
|
||||
{
|
||||
DBUG_PRINT("info",("table: %p trn: %p -> %p",
|
||||
tbl, tbl->trn, newtrn));
|
||||
|
||||
/* check that we are not calling this twice in a row */
|
||||
DBUG_ASSERT(newtrn->used_instances != (void*) tbl);
|
||||
|
||||
tbl->trn= newtrn;
|
||||
/* Link into used list */
|
||||
tbl->trn_next= (MARIA_HA*) newtrn->used_instances;
|
||||
newtrn->used_instances= tbl;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Same as _ma_set_trn_for_table(), but don't link table into used_instance list
|
||||
Used when we want to temporary set trn for a table in extra()
|
||||
*/
|
||||
|
||||
static inline void _ma_set_tmp_trn_for_table(MARIA_HA *tbl, TRN *newtrn)
|
||||
{
|
||||
DBUG_PRINT("info",("table: %p trn: %p -> %p",
|
||||
tbl, tbl->trn, newtrn));
|
||||
tbl->trn= newtrn;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Reset TRN in table
|
||||
*/
|
||||
|
||||
static inline void _ma_reset_trn_for_table(MARIA_HA *tbl)
|
||||
{
|
||||
DBUG_PRINT("info",("table: %p trn: %p -> NULL", tbl, tbl->trn));
|
||||
tbl->trn= 0;
|
||||
}
|
||||
|
||||
#endif /* _ma_trnman_h */
|
@ -576,6 +576,7 @@ struct st_maria_handler
|
||||
{
|
||||
MARIA_SHARE *s; /* Shared between open:s */
|
||||
struct st_ma_transaction *trn; /* Pointer to active transaction */
|
||||
struct st_maria_handler *trn_next;
|
||||
MARIA_STATUS_INFO *state, state_save;
|
||||
MARIA_STATUS_INFO *state_start; /* State at start of transaction */
|
||||
MARIA_USED_TABLES *used_tables;
|
||||
@ -824,19 +825,6 @@ struct st_maria_handler
|
||||
#define get_pack_length(length) ((length) >= 255 ? 3 : 1)
|
||||
#define _ma_have_versioning(info) ((info)->row_flag & ROW_FLAG_TRANSID)
|
||||
|
||||
/**
|
||||
Sets table's trn and prints debug information
|
||||
@param tbl MARIA_HA of table
|
||||
@param newtrn what to put into tbl->trn
|
||||
@note cast of newtrn is because %p of NULL gives warning (NULL is int)
|
||||
*/
|
||||
#define _ma_set_trn_for_table(tbl, newtrn) do { \
|
||||
DBUG_PRINT("info",("table: %p trn: %p -> %p", \
|
||||
(tbl), (tbl)->trn, (void *)(newtrn))); \
|
||||
(tbl)->trn= (newtrn); \
|
||||
} while (0)
|
||||
|
||||
|
||||
#define MARIA_MIN_BLOCK_LENGTH 20 /* Because of delete-link */
|
||||
/* Don't use to small record-blocks */
|
||||
#define MARIA_EXTEND_BLOCK_LENGTH 20
|
||||
|
@ -366,6 +366,7 @@ TRN *trnman_new_trn(WT_THD *wt)
|
||||
trn->commit_trid= MAX_TRID;
|
||||
trn->rec_lsn= trn->undo_lsn= trn->first_undo_lsn= 0;
|
||||
trn->used_tables= 0;
|
||||
trn->used_instances= 0;
|
||||
|
||||
trn->locked_tables= 0;
|
||||
trn->flags= 0;
|
||||
|
@ -46,7 +46,8 @@ struct st_ma_transaction
|
||||
LF_PINS *pins;
|
||||
WT_THD *wt;
|
||||
mysql_mutex_t state_lock;
|
||||
void *used_tables; /**< Tables used by transaction */
|
||||
void *used_tables; /**< Table shares used by transaction */
|
||||
void *used_instances; /* table files used by transaction */
|
||||
TRN *next, *prev;
|
||||
TrID trid, min_read_from, commit_trid;
|
||||
LSN rec_lsn, undo_lsn;
|
||||
|
Loading…
x
Reference in New Issue
Block a user