Commit bc7bf937 authored by Vasil Dimov's avatar Vasil Dimov

Merge mysql-5.1-innodb -> mysql-5.1

parents 39f71a29 2e0e518f
......@@ -4461,13 +4461,14 @@ static int my_kill(int pid, int sig)
command called command
DESCRIPTION
shutdown [<timeout>]
shutdown_server [<timeout>]
*/
void do_shutdown_server(struct st_command *command)
{
int timeout=60, pid;
long timeout=60;
int pid;
DYNAMIC_STRING ds_pidfile_name;
MYSQL* mysql = &cur_con->mysql;
static DYNAMIC_STRING ds_timeout;
......@@ -4482,8 +4483,9 @@ void do_shutdown_server(struct st_command *command)
if (ds_timeout.length)
{
timeout= atoi(ds_timeout.str);
if (timeout == 0)
char* endptr;
timeout= strtol(ds_timeout.str, &endptr, 10);
if (*endptr != '\0')
die("Illegal argument for timeout: '%s'", ds_timeout.str);
}
dynstr_free(&ds_timeout);
......@@ -4525,7 +4527,7 @@ void do_shutdown_server(struct st_command *command)
DBUG_PRINT("info", ("Process %d does not exist anymore", pid));
DBUG_VOID_RETURN;
}
DBUG_PRINT("info", ("Sleeping, timeout: %d", timeout));
DBUG_PRINT("info", ("Sleeping, timeout: %ld", timeout));
my_sleep(1000000L);
}
......
......@@ -7,7 +7,7 @@ let $counter= 500;
let $mysql_errno= 0;
while (!$mysql_errno)
{
--error 0,1053,2002,2006,2013
--error 0,1040,1053,2002,2003,2006,2013
show status;
dec $counter;
......
create table `bug59410_1`(`a` int)engine=innodb;
insert into `bug59410_1` values (1),(2),(3);
select 1 from `bug59410_1` where `a` <> any (
select 1 from `bug59410_1` where `a` <> 1 for update)
for update;
1
1
1
drop table bug59410_1;
create table bug59410_2(`a` char(1),`b` int)engine=innodb;
insert into bug59410_2 values('0',0);
set transaction isolation level read uncommitted;
start transaction;
set @a=(select b from bug59410_2 where
(select 1 from bug59410_2 where a group by @a=b)
group by @a:=b);
drop table bug59410_2;
CREATE TABLE t(a INT PRIMARY KEY, b INT)ENGINE=InnoDB;
INSERT INTO t VALUES(2,2),(4,4),(8,8),(16,16),(32,32);
COMMIT;
XA START '123';
INSERT INTO t VALUES(1,1);
XA END '123';
XA PREPARE '123';
XA START '456';
INSERT INTO t VALUES(3,47),(5,67);
UPDATE t SET b=2*b WHERE a BETWEEN 5 AND 8;
XA END '456';
XA PREPARE '456';
XA START '789';
UPDATE t SET b=4*a WHERE a=32;
XA END '789';
XA PREPARE '789';
call mtr.add_suppression("Found 3 prepared XA transactions");
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SELECT * FROM t;
a b
1 1
2 2
3 47
4 4
5 134
8 16
16 16
32 128
COMMIT;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SELECT * FROM t;
a b
1 1
2 2
3 47
4 4
5 134
8 16
16 16
32 128
COMMIT;
XA RECOVER;
formatID gtrid_length bqual_length data
1 3 0 789
1 3 0 456
1 3 0 123
XA ROLLBACK '123';
XA ROLLBACK '456';
XA COMMIT '789';
SELECT * FROM t;
a b
2 2
4 4
8 8
16 16
32 128
DROP TABLE t;
#
# Bug#59410 read uncommitted: unlock row could not find a 3 mode lock on the record
#
-- source include/have_innodb.inc
# only interested that the following do not produce something like
# InnoDB: Error: unlock row could not find a 2 mode lock on the record
# in the error log
create table `bug59410_1`(`a` int)engine=innodb;
insert into `bug59410_1` values (1),(2),(3);
select 1 from `bug59410_1` where `a` <> any (
select 1 from `bug59410_1` where `a` <> 1 for update)
for update;
drop table bug59410_1;
create table bug59410_2(`a` char(1),`b` int)engine=innodb;
insert into bug59410_2 values('0',0);
set transaction isolation level read uncommitted;
start transaction;
set @a=(select b from bug59410_2 where
(select 1 from bug59410_2 where a group by @a=b)
group by @a:=b);
drop table bug59410_2;
# Bug #59641 Prepared XA transaction causes shutdown hang after a crash
-- source include/not_embedded.inc
-- source include/have_innodb.inc
CREATE TABLE t(a INT PRIMARY KEY, b INT)ENGINE=InnoDB;
INSERT INTO t VALUES(2,2),(4,4),(8,8),(16,16),(32,32);
COMMIT;
XA START '123';
INSERT INTO t VALUES(1,1);
XA END '123';
XA PREPARE '123';
CONNECT (con1,localhost,root,,);
CONNECTION con1;
XA START '456';
INSERT INTO t VALUES(3,47),(5,67);
UPDATE t SET b=2*b WHERE a BETWEEN 5 AND 8;
XA END '456';
XA PREPARE '456';
CONNECT (con2,localhost,root,,);
CONNECTION con2;
XA START '789';
UPDATE t SET b=4*a WHERE a=32;
XA END '789';
XA PREPARE '789';
# The server would issue this warning on restart.
call mtr.add_suppression("Found 3 prepared XA transactions");
# Kill the server without sending a shutdown command
-- exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
-- shutdown_server 0
-- source include/wait_until_disconnected.inc
# Restart the server.
-- exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
-- enable_reconnect
-- source include/wait_until_connected_again.inc
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SELECT * FROM t;
COMMIT;
# Shut down the server. This would hang because of the bug.
-- exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
-- shutdown_server
-- source include/wait_until_disconnected.inc
# Restart the server.
-- exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
-- enable_reconnect
-- source include/wait_until_connected_again.inc
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SELECT * FROM t;
COMMIT;
XA RECOVER;
XA ROLLBACK '123';
XA ROLLBACK '456';
XA COMMIT '789';
SELECT * FROM t;
DROP TABLE t;
create table `bug59410_1`(`a` int)engine=innodb;
insert into `bug59410_1` values (1),(2),(3);
select 1 from `bug59410_1` where `a` <> any (
select 1 from `bug59410_1` where `a` <> 1 for update)
for update;
1
1
1
drop table bug59410_1;
create table bug59410_2(`a` char(1),`b` int)engine=innodb;
insert into bug59410_2 values('0',0);
set transaction isolation level read uncommitted;
start transaction;
set @a=(select b from bug59410_2 where
(select 1 from bug59410_2 where a group by @a=b)
group by @a:=b);
drop table bug59410_2;
CREATE TABLE t(a INT PRIMARY KEY, b INT)ENGINE=InnoDB;
INSERT INTO t VALUES(2,2),(4,4),(8,8),(16,16),(32,32);
COMMIT;
XA START '123';
INSERT INTO t VALUES(1,1);
XA END '123';
XA PREPARE '123';
XA START '456';
INSERT INTO t VALUES(3,47),(5,67);
UPDATE t SET b=2*b WHERE a BETWEEN 5 AND 8;
XA END '456';
XA PREPARE '456';
XA START '789';
UPDATE t SET b=4*a WHERE a=32;
XA END '789';
XA PREPARE '789';
call mtr.add_suppression("Found 3 prepared XA transactions");
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SELECT * FROM t;
a b
1 1
2 2
3 47
4 4
5 134
8 16
16 16
32 128
COMMIT;
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SELECT * FROM t;
a b
1 1
2 2
3 47
4 4
5 134
8 16
16 16
32 128
COMMIT;
XA RECOVER;
formatID gtrid_length bqual_length data
1 3 0 789
1 3 0 456
1 3 0 123
XA ROLLBACK '123';
XA ROLLBACK '456';
XA COMMIT '789';
SELECT * FROM t;
a b
2 2
4 4
8 8
16 16
32 128
DROP TABLE t;
#
# Bug#59410 read uncommitted: unlock row could not find a 3 mode lock on the record
#
-- source include/have_innodb_plugin.inc
# only interested that the following do not produce something like
# InnoDB: Error: unlock row could not find a 2 mode lock on the record
# in the error log
create table `bug59410_1`(`a` int)engine=innodb;
insert into `bug59410_1` values (1),(2),(3);
select 1 from `bug59410_1` where `a` <> any (
select 1 from `bug59410_1` where `a` <> 1 for update)
for update;
drop table bug59410_1;
create table bug59410_2(`a` char(1),`b` int)engine=innodb;
insert into bug59410_2 values('0',0);
set transaction isolation level read uncommitted;
start transaction;
set @a=(select b from bug59410_2 where
(select 1 from bug59410_2 where a group by @a=b)
group by @a:=b);
drop table bug59410_2;
# Bug #59641 Prepared XA transaction causes shutdown hang after a crash
-- source include/not_embedded.inc
-- source include/have_innodb_plugin.inc
let $innodb_file_format_check_orig=`select @@innodb_file_format_check`;
CREATE TABLE t(a INT PRIMARY KEY, b INT)ENGINE=InnoDB;
INSERT INTO t VALUES(2,2),(4,4),(8,8),(16,16),(32,32);
COMMIT;
XA START '123';
INSERT INTO t VALUES(1,1);
XA END '123';
XA PREPARE '123';
CONNECT (con1,localhost,root,,);
CONNECTION con1;
XA START '456';
INSERT INTO t VALUES(3,47),(5,67);
UPDATE t SET b=2*b WHERE a BETWEEN 5 AND 8;
XA END '456';
XA PREPARE '456';
CONNECT (con2,localhost,root,,);
CONNECTION con2;
XA START '789';
UPDATE t SET b=4*a WHERE a=32;
XA END '789';
XA PREPARE '789';
# The server would issue this warning on restart.
call mtr.add_suppression("Found 3 prepared XA transactions");
# Kill the server without sending a shutdown command
-- exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
-- shutdown_server 0
-- source include/wait_until_disconnected.inc
# Restart the server.
-- exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
-- enable_reconnect
-- source include/wait_until_connected_again.inc
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SELECT * FROM t;
COMMIT;
# Shut down the server. This would hang because of the bug.
-- exec echo "wait" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
-- shutdown_server
-- source include/wait_until_disconnected.inc
# Restart the server.
-- exec echo "restart" > $MYSQLTEST_VARDIR/tmp/mysqld.1.expect
-- enable_reconnect
-- source include/wait_until_connected_again.inc
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SELECT * FROM t;
COMMIT;
XA RECOVER;
XA ROLLBACK '123';
XA ROLLBACK '456';
XA COMMIT '789';
SELECT * FROM t;
DROP TABLE t;
--disable_query_log
eval set global innodb_file_format_check=$innodb_file_format_check_orig;
......@@ -3383,6 +3383,7 @@ bool xid_cache_insert(XID *xid, enum xa_states xa_state)
xs->xa_state=xa_state;
xs->xid.set(xid);
xs->in_thd=0;
xs->rm_error=0;
res=my_hash_insert(&xid_cache, (uchar*)xs);
}
pthread_mutex_unlock(&LOCK_xid_cache);
......
......@@ -189,7 +189,7 @@ innobase_index_name_is_reserved(
/*============================*/
/* out: true if index name matches a
reserved name */
const trx_t* trx, /* in: InnoDB transaction handle */
THD* thd, /* in/out: MySQL connection */
const TABLE* form, /* in: information on table
columns and indexes */
const char* norm_name); /* in: table name */
......@@ -5285,10 +5285,6 @@ create_table_def(
DBUG_PRINT("enter", ("table_name: %s", table_name));
ut_a(trx->mysql_thd != NULL);
if (IS_MAGIC_TABLE_AND_USER_DENIED_ACCESS(table_name,
(THD*) trx->mysql_thd)) {
DBUG_RETURN(HA_ERR_GENERIC);
}
n_cols = form->s->fields;
......@@ -5397,6 +5393,8 @@ create_table_def(
col_len);
}
srv_lower_case_table_names = lower_case_table_names;
error = row_create_table_for_mysql(table, trx);
innodb_check_for_record_too_big_error(flags & DICT_TF_COMPACT, error);
......@@ -5642,6 +5640,35 @@ ha_innobase::create(
DBUG_RETURN(HA_ERR_TO_BIG_ROW);
}
strcpy(name2, name);
normalize_table_name(norm_name, name2);
/* Create the table definition in InnoDB */
flags = form->s->row_type != ROW_TYPE_REDUNDANT ? DICT_TF_COMPACT : 0;
/* Look for a primary key */
primary_key_no= (form->s->primary_key != MAX_KEY ?
(int) form->s->primary_key :
-1);
/* Our function row_get_mysql_key_number_for_index assumes
the primary key is always number 0, if it exists */
DBUG_ASSERT(primary_key_no == -1 || primary_key_no == 0);
/* Check for name conflicts (with reserved name) for
any user indices to be created. */
if (innobase_index_name_is_reserved(thd, form, norm_name)) {
DBUG_RETURN(-1);
}
if (IS_MAGIC_TABLE_AND_USER_DENIED_ACCESS(norm_name, thd)) {
DBUG_RETURN(HA_ERR_GENERIC);
}
/* Get the transaction associated with the current thd, or create one
if not yet created */
......@@ -5665,48 +5692,12 @@ ha_innobase::create(
trx->check_unique_secondary = FALSE;
}
if (lower_case_table_names) {
srv_lower_case_table_names = TRUE;
} else {
srv_lower_case_table_names = FALSE;
}
strcpy(name2, name);
normalize_table_name(norm_name, name2);
/* Latch the InnoDB data dictionary exclusively so that no deadlocks
or lock waits can happen in it during a table create operation.
Drop table etc. do this latching in row0mysql.c. */
row_mysql_lock_data_dictionary(trx);
/* Create the table definition in InnoDB */
flags = 0;
if (form->s->row_type != ROW_TYPE_REDUNDANT) {
flags |= DICT_TF_COMPACT;
}
/* Look for a primary key */
primary_key_no= (form->s->primary_key != MAX_KEY ?
(int) form->s->primary_key :
-1);
/* Our function row_get_mysql_key_number_for_index assumes
the primary key is always number 0, if it exists */
DBUG_ASSERT(primary_key_no == -1 || primary_key_no == 0);
/* Check for name conflicts (with reserved name) for
any user indices to be created. */
if (innobase_index_name_is_reserved(trx, form, norm_name)) {
error = -1;
goto cleanup;
}
error = create_table_def(trx, form, norm_name,
create_info->options & HA_LEX_CREATE_TMP_TABLE ? name2 : NULL,
flags);
......@@ -5936,12 +5927,6 @@ ha_innobase::delete_table(
trx_search_latch_release_if_reserved(parent_trx);
if (lower_case_table_names) {
srv_lower_case_table_names = TRUE;
} else {
srv_lower_case_table_names = FALSE;
}
trx = trx_allocate_for_mysql();
trx->mysql_thd = thd;
......@@ -5961,6 +5946,8 @@ ha_innobase::delete_table(
/* Drop the table in InnoDB */
srv_lower_case_table_names = lower_case_table_names;
error = row_drop_table_for_mysql(norm_name, trx,
thd_sql_command(thd)
== SQLCOM_DROP_DB);
......@@ -6089,12 +6076,6 @@ ha_innobase::rename_table(
trx_search_latch_release_if_reserved(parent_trx);
if (lower_case_table_names) {
srv_lower_case_table_names = TRUE;
} else {
srv_lower_case_table_names = FALSE;
}
trx = trx_allocate_for_mysql();
trx->mysql_thd = thd;
INNOBASE_COPY_STMT(thd, trx);
......@@ -6114,6 +6095,8 @@ ha_innobase::rename_table(
/* Rename the table in InnoDB */
srv_lower_case_table_names = lower_case_table_names;
error = row_rename_table_for_mysql(norm_from, norm_to, trx);
/* Flush the log to reduce probability that the .frm files and
......@@ -8565,7 +8548,7 @@ innobase_commit_by_xid(
if (trx) {
innobase_commit_low(trx);
trx_free_for_background(trx);
return(XA_OK);
} else {
return(XAER_NOTA);
......@@ -8588,7 +8571,9 @@ innobase_rollback_by_xid(
trx = trx_get_trx_by_xid(xid);
if (trx) {
return(innobase_rollback_trx(trx));
int ret = innobase_rollback_trx(trx);
trx_free_for_background(trx);
return(ret);
} else {
return(XAER_NOTA);
}
......@@ -8824,7 +8809,7 @@ innobase_index_name_is_reserved(
/*============================*/
/* out: true if an index name
matches the reserved name */
const trx_t* trx, /* in: InnoDB transaction handle */
THD* thd, /* in/out: MySQL connection */
const TABLE* form, /* in: information on table
columns and indexes */
const char* norm_name) /* in: table name */
......@@ -8838,7 +8823,7 @@ innobase_index_name_is_reserved(
if (innobase_strcasecmp(key->name,
innobase_index_reserve_name) == 0) {
/* Push warning to mysql */
push_warning_printf((THD*) trx->mysql_thd,
push_warning_printf(thd,
MYSQL_ERROR::WARN_LEVEL_WARN,
ER_CANT_CREATE_TABLE,
"Cannot Create Index with name "
......
......@@ -19,7 +19,12 @@ Created 3/26/1996 Heikki Tuuri
#include "dict0types.h"
#include "trx0xa.h"
/* Number of transactions currently allocated for MySQL: protected by
the kernel mutex */
extern ulint trx_n_mysql_transactions;
/* Number of transactions currently in the XA PREPARED state: protected by
the kernel mutex */
extern ulint trx_n_prepared;
/************************************************************************
Releases the search latch if trx has reserved it. */
......
......@@ -3052,12 +3052,13 @@ logs_empty_and_mark_files_at_shutdown(void)
goto loop;
}
/* Check that there are no longer transactions. We need this wait even
for the 'very fast' shutdown, because the InnoDB layer may have
committed or prepared transactions and we don't want to lose them. */
/* Check that there are no longer transactions, except for
PREPARED ones. We need this wait even for the 'very fast'
shutdown, because the InnoDB layer may have committed or
prepared transactions and we don't want to lose them. */
if (trx_n_mysql_transactions > 0
|| UT_LIST_GET_LEN(trx_sys->trx_list) > 0) {
|| UT_LIST_GET_LEN(trx_sys->trx_list) > trx_n_prepared) {
mutex_exit(&kernel_mutex);
......
......@@ -41,6 +41,9 @@ sess_t* trx_dummy_sess = NULL;
/* Number of transactions currently allocated for MySQL: protected by
the kernel mutex */
ulint trx_n_mysql_transactions = 0;
/* Number of transactions currently in the XA PREPARED state: protected by
the kernel mutex */
ulint trx_n_prepared = 0;
/*****************************************************************
Starts the transaction if it is not yet started. */
......@@ -480,6 +483,7 @@ trx_lists_init_at_db_start(void)
if (srv_force_recovery == 0) {
trx->conc_state = TRX_PREPARED;
trx_n_prepared++;
} else {
fprintf(stderr,
"InnoDB: Since"
......@@ -558,6 +562,7 @@ trx_lists_init_at_db_start(void)
trx->conc_state
= TRX_PREPARED;
trx_n_prepared++;
} else {
fprintf(stderr,
"InnoDB: Since"
......@@ -832,6 +837,11 @@ trx_commit_off_kernel(
|| trx->conc_state == TRX_PREPARED);
ut_ad(mutex_own(&kernel_mutex));
if (UNIV_UNLIKELY(trx->conc_state == TRX_PREPARED)) {
ut_a(trx_n_prepared > 0);
trx_n_prepared--;
}
/* The following assignment makes the transaction committed in memory
and makes its changes to data visible to other transactions.
NOTE that there is a small discrepancy from the strict formal
......@@ -1882,6 +1892,7 @@ trx_prepare_off_kernel(
/*--------------------------------------*/
trx->conc_state = TRX_PREPARED;
trx_n_prepared++;
/*--------------------------------------*/
if (must_flush_log) {
......
2011-04-07 The InnoDB Team
* handler/ha_innodb.cc, handler/ha_innodb.h, handler/handler0alter.cc:
Fix Bug #52409 Assertion failure: long semaphore wait
2011-04-07 The InnoDB Team
* handler/ha_innodb.cc, include/trx0trx.h, include/trx0undo.h,
log/log0log.c, trx/trx0sys.c, trx/trx0trx.c, trx/trx0undo.c:
Fix Bug #59641 Prepared XA transaction in system after hard crash
causes future shutdown hang
2011-03-30 The InnoDB Team
* srv/srv0srv.c, sync/sync0arr.h, sync/sync0arr.c:
......
......@@ -6023,10 +6023,6 @@ create_table_def(
DBUG_PRINT("enter", ("table_name: %s", table_name));
ut_a(trx->mysql_thd != NULL);
if (IS_MAGIC_TABLE_AND_USER_DENIED_ACCESS(table_name,
(THD*) trx->mysql_thd)) {
DBUG_RETURN(HA_ERR_GENERIC);
}
/* MySQL does the name length check. But we do additional check
on the name length here */
......@@ -6146,6 +6142,8 @@ create_table_def(
col_len);
}
srv_lower_case_table_names = lower_case_table_names;
error = row_create_table_for_mysql(table, trx);
if (error == DB_DUPLICATE_KEY) {
......@@ -6562,42 +6560,17 @@ ha_innobase::create(
DBUG_RETURN(HA_ERR_TO_BIG_ROW);
}
/* Get the transaction associated with the current thd, or create one
if not yet created */
parent_trx = check_trx_exists(thd);
/* In case MySQL calls this in the middle of a SELECT query, release
possible adaptive hash latch to avoid deadlocks of threads */
trx_search_latch_release_if_reserved(parent_trx);
trx = innobase_trx_allocate(thd);
if (lower_case_table_names) {
srv_lower_case_table_names = TRUE;
} else {
srv_lower_case_table_names = FALSE;
}
strcpy(name2, name);
normalize_table_name(norm_name, name2);
/* Latch the InnoDB data dictionary exclusively so that no deadlocks
or lock waits can happen in it during a table create operation.
Drop table etc. do this latching in row0mysql.c. */
row_mysql_lock_data_dictionary(trx);
/* Create the table definition in InnoDB */
flags = 0;
/* Validate create options if innodb_strict_mode is set. */
if (!create_options_are_valid(thd, form, create_info)) {
error = ER_ILLEGAL_HA_CREATE_OPTION;
goto cleanup;
DBUG_RETURN(ER_ILLEGAL_HA_CREATE_OPTION);
}
if (create_info->key_block_size) {
......@@ -6739,16 +6712,37 @@ ha_innobase::create(
/* Check for name conflicts (with reserved name) for
any user indices to be created. */
if (innobase_index_name_is_reserved(trx, form->key_info,
if (innobase_index_name_is_reserved(thd, form->key_info,
form->s->keys)) {
error = -1;
goto cleanup;
DBUG_RETURN(-1);
}
if (IS_MAGIC_TABLE_AND_USER_DENIED_ACCESS(norm_name, thd)) {
DBUG_RETURN(HA_ERR_GENERIC);
}
if (create_info->options & HA_LEX_CREATE_TMP_TABLE) {
flags |= DICT_TF2_TEMPORARY << DICT_TF2_SHIFT;
}
/* Get the transaction associated with the current thd, or create one
if not yet created */
parent_trx = check_trx_exists(thd);
/* In case MySQL calls this in the middle of a SELECT query, release
possible adaptive hash latch to avoid deadlocks of threads */
trx_search_latch_release_if_reserved(parent_trx);
trx = innobase_trx_allocate(thd);
/* Latch the InnoDB data dictionary exclusively so that no deadlocks
or lock waits can happen in it during a table create operation.
Drop table etc. do this latching in row0mysql.c. */
row_mysql_lock_data_dictionary(trx);
error = create_table_def(trx, form, norm_name,
create_info->options & HA_LEX_CREATE_TMP_TABLE ? name2 : NULL,
flags);
......@@ -6992,18 +6986,14 @@ ha_innobase::delete_table(
trx = innobase_trx_allocate(thd);
if (lower_case_table_names) {
srv_lower_case_table_names = TRUE;
} else {
srv_lower_case_table_names = FALSE;
}
name_len = strlen(name);
ut_a(name_len < 1000);
/* Drop the table in InnoDB */
srv_lower_case_table_names = lower_case_table_names;
error = row_drop_table_for_mysql(norm_name, trx,
thd_sql_command(thd)
== SQLCOM_DROP_DB);
......@@ -7119,12 +7109,6 @@ innobase_rename_table(
char* norm_to;
char* norm_from;
if (lower_case_table_names) {
srv_lower_case_table_names = TRUE;
} else {
srv_lower_case_table_names = FALSE;
}
// Magic number 64 arbitrary
norm_to = (char*) my_malloc(strlen(to) + 64, MYF(0));
norm_from = (char*) my_malloc(strlen(from) + 64, MYF(0));
......@@ -7139,6 +7123,8 @@ innobase_rename_table(
row_mysql_lock_data_dictionary(trx);
}
srv_lower_case_table_names = lower_case_table_names;
error = row_rename_table_for_mysql(
norm_from, norm_to, trx, lock_and_commit);
......@@ -9998,7 +9984,7 @@ innobase_commit_by_xid(
if (trx) {
innobase_commit_low(trx);
trx_free_for_background(trx);
return(XA_OK);
} else {
return(XAER_NOTA);
......@@ -10024,7 +10010,9 @@ innobase_rollback_by_xid(
trx = trx_get_trx_by_xid(xid);
if (trx) {
return(innobase_rollback_trx(trx));
int ret = innobase_rollback_trx(trx);
trx_free_for_background(trx);
return(ret);
} else {
return(XAER_NOTA);
}
......@@ -10698,19 +10686,19 @@ static int show_innodb_vars(THD *thd, SHOW_VAR *var, char *buff)
return 0;
}
/***********************************************************************
/*********************************************************************//**
This function checks each index name for a table against reserved
system default primary index name 'GEN_CLUST_INDEX'. If a name matches,
this function pushes an warning message to the client, and returns true. */
system default primary index name 'GEN_CLUST_INDEX'. If a name
matches, this function pushes an warning message to the client,
and returns true.
@return true if the index name matches the reserved name */
extern "C" UNIV_INTERN
bool
innobase_index_name_is_reserved(
/*============================*/
/* out: true if an index name
matches the reserved name */
const trx_t* trx, /* in: InnoDB transaction handle */
const KEY* key_info, /* in: Indexes to be created */
ulint num_of_keys) /* in: Number of indexes to
THD* thd, /*!< in/out: MySQL connection */
const KEY* key_info, /*!< in: Indexes to be created */
ulint num_of_keys) /*!< in: Number of indexes to
be created. */
{
const KEY* key;
......@@ -10722,7 +10710,7 @@ innobase_index_name_is_reserved(
if (innobase_strcasecmp(key->name,
innobase_index_reserve_name) == 0) {
/* Push warning to mysql */
push_warning_printf((THD*) trx->mysql_thd,
push_warning_printf(thd,
MYSQL_ERROR::WARN_LEVEL_WARN,
ER_WRONG_NAME_FOR_INDEX,
"Cannot Create Index with name "
......
......@@ -317,15 +317,14 @@ innobase_trx_allocate(
This function checks each index name for a table against reserved
system default primary index name 'GEN_CLUST_INDEX'. If a name
matches, this function pushes an warning message to the client,
and returns true. */
and returns true.
@return true if the index name matches the reserved name */
extern "C"
bool
innobase_index_name_is_reserved(
/*============================*/
/* out: true if the index name
matches the reserved name */
const trx_t* trx, /* in: InnoDB transaction handle */
const KEY* key_info, /* in: Indexes to be created */
ulint num_of_keys); /* in: Number of indexes to
THD* thd, /*!< in/out: MySQL connection */
const KEY* key_info, /*!< in: Indexes to be created */
ulint num_of_keys); /*!< in: Number of indexes to
be created. */
......@@ -649,44 +649,37 @@ ha_innobase::add_index(
update_thd();
heap = mem_heap_create(1024);
/* In case MySQL calls this in the middle of a SELECT query, release
possible adaptive hash latch to avoid deadlocks of threads. */
trx_search_latch_release_if_reserved(prebuilt->trx);
trx_start_if_not_started(prebuilt->trx);
/* Create a background transaction for the operations on
the data dictionary tables. */
trx = innobase_trx_allocate(user_thd);
trx_start_if_not_started(trx);
/* Check if the index name is reserved. */
if (innobase_index_name_is_reserved(user_thd, key_info, num_of_keys)) {
DBUG_RETURN(-1);
}
innodb_table = indexed_table
= dict_table_get(prebuilt->table->name, FALSE);
if (UNIV_UNLIKELY(!innodb_table)) {
error = HA_ERR_NO_SUCH_TABLE;
goto err_exit;
DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);
}
/* Check if the index name is reserved. */
if (innobase_index_name_is_reserved(trx, key_info, num_of_keys)) {
error = -1;
} else {
/* Check that index keys are sensible */
error = innobase_check_index_keys(key_info, num_of_keys,
innodb_table);
}
/* Check that index keys are sensible */
error = innobase_check_index_keys(key_info, num_of_keys, innodb_table);
if (UNIV_UNLIKELY(error)) {
err_exit:
mem_heap_free(heap);
trx_general_rollback_for_mysql(trx, NULL);
trx_free_for_mysql(trx);
trx_commit_for_mysql(prebuilt->trx);
DBUG_RETURN(error);
}
heap = mem_heap_create(1024);
trx_start_if_not_started(prebuilt->trx);
/* Create a background transaction for the operations on
the data dictionary tables. */
trx = innobase_trx_allocate(user_thd);
trx_start_if_not_started(trx);
/* Create table containing all indexes to be built in this
alter table add index so that they are in the correct order
in the table. */
......@@ -758,8 +751,12 @@ ha_innobase::add_index(
ut_d(dict_table_check_for_dup_indexes(innodb_table,
FALSE));
mem_heap_free(heap);
trx_general_rollback_for_mysql(trx, NULL);
row_mysql_unlock_data_dictionary(trx);
goto err_exit;
trx_free_for_mysql(trx);
trx_commit_for_mysql(prebuilt->trx);
DBUG_RETURN(error);
}
trx->table_id = indexed_table->id;
......
......@@ -44,6 +44,9 @@ extern sess_t* trx_dummy_sess;
/** Number of transactions currently allocated for MySQL: protected by
the kernel mutex */
extern ulint trx_n_mysql_transactions;
/** Number of transactions currently in the XA PREPARED state: protected by
the kernel mutex */
extern ulint trx_n_prepared;
/********************************************************************//**
Releases the search latch if trx has reserved it. */
......@@ -108,6 +111,14 @@ trx_free(
/*=====*/
trx_t* trx); /*!< in, own: trx object */
/********************************************************************//**
At shutdown, frees a transaction object that is in the PREPARED state. */
UNIV_INTERN
void
trx_free_prepared(
/*==============*/
trx_t* trx) /*!< in, own: trx object */
__attribute__((nonnull));
/********************************************************************//**
Frees a transaction object for MySQL. */
UNIV_INTERN
void
......
......@@ -298,6 +298,15 @@ void
trx_undo_insert_cleanup(
/*====================*/
trx_t* trx); /*!< in: transaction handle */
/********************************************************************//**
At shutdown, frees the undo logs of a PREPARED transaction. */
UNIV_INTERN
void
trx_undo_free_prepared(
/*===================*/
trx_t* trx) /*!< in/out: PREPARED transaction */
__attribute__((nonnull));
#endif /* !UNIV_HOTBACKUP */
/***********************************************************//**
Parses the redo log entry of an undo log page initialization.
......
......@@ -3085,12 +3085,13 @@ logs_empty_and_mark_files_at_shutdown(void)
goto loop;
}
/* Check that there are no longer transactions. We need this wait even
for the 'very fast' shutdown, because the InnoDB layer may have
committed or prepared transactions and we don't want to lose them. */
/* Check that there are no longer transactions, except for
PREPARED ones. We need this wait even for the 'very fast'
shutdown, because the InnoDB layer may have committed or
prepared transactions and we don't want to lose them. */
if (trx_n_mysql_transactions > 0
|| UT_LIST_GET_LEN(trx_sys->trx_list) > 0) {
|| UT_LIST_GET_LEN(trx_sys->trx_list) > trx_n_prepared) {
mutex_exit(&kernel_mutex);
......
......@@ -37,6 +37,7 @@ Created 3/26/1996 Heikki Tuuri
#include "trx0rseg.h"
#include "trx0undo.h"
#include "srv0srv.h"
#include "srv0start.h"
#include "trx0purge.h"
#include "log0log.h"
#include "os0file.h"
......@@ -1548,10 +1549,12 @@ void
trx_sys_close(void)
/*===============*/
{
trx_t* trx;
trx_rseg_t* rseg;
read_view_t* view;
ut_ad(trx_sys != NULL);
ut_ad(srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS);
/* Check that all read views are closed except read view owned
by a purge. */
......@@ -1583,6 +1586,13 @@ trx_sys_close(void)
mem_free(trx_doublewrite);
trx_doublewrite = NULL;
/* Only prepared transactions may be left in the system. Free them. */
ut_a(UT_LIST_GET_LEN(trx_sys->trx_list) == trx_n_prepared);
while ((trx = UT_LIST_GET_FIRST(trx_sys->trx_list)) != NULL) {
trx_free_prepared(trx);
}
/* There can't be any active transactions. */
rseg = UT_LIST_GET_FIRST(trx_sys->rseg_list);
......
......@@ -50,6 +50,9 @@ UNIV_INTERN sess_t* trx_dummy_sess = NULL;
/** Number of transactions currently allocated for MySQL: protected by
the kernel mutex */
UNIV_INTERN ulint trx_n_mysql_transactions = 0;
/* Number of transactions currently in the XA PREPARED state: protected by
the kernel mutex */
UNIV_INTERN ulint trx_n_prepared = 0;
/*************************************************************//**
Set detailed error message for the transaction. */
......@@ -333,6 +336,60 @@ trx_free(
mem_free(trx);
}
/********************************************************************//**
At shutdown, frees a transaction object that is in the PREPARED state. */
UNIV_INTERN
void
trx_free_prepared(
/*==============*/
trx_t* trx) /*!< in, own: trx object */
{
ut_ad(mutex_own(&kernel_mutex));
ut_a(trx->conc_state == TRX_PREPARED);
ut_a(trx->magic_n == TRX_MAGIC_N);
/* Prepared transactions are sort of active; they allow
ROLLBACK and COMMIT operations. Because the system does not
contain any other transactions than prepared transactions at
the shutdown stage and because a transaction cannot become
PREPARED while holding locks, it is safe to release the locks
held by PREPARED transactions here at shutdown.*/
lock_release_off_kernel(trx);
trx_undo_free_prepared(trx);
mutex_free(&trx->undo_mutex);
if (trx->undo_no_arr) {
trx_undo_arr_free(trx->undo_no_arr);
}
ut_a(UT_LIST_GET_LEN(trx->signals) == 0);
ut_a(UT_LIST_GET_LEN(trx->reply_signals) == 0);
ut_a(trx->wait_lock == NULL);
ut_a(UT_LIST_GET_LEN(trx->wait_thrs) == 0);
ut_a(!trx->has_search_latch);
ut_a(trx->dict_operation_lock_mode == 0);
if (trx->lock_heap) {
mem_heap_free(trx->lock_heap);
}
if (trx->global_read_view_heap) {
mem_heap_free(trx->global_read_view_heap);
}
ut_a(ib_vector_is_empty(trx->autoinc_locks));
ib_vector_free(trx->autoinc_locks);
UT_LIST_REMOVE(trx_list, trx_sys->trx_list, trx);
mem_free(trx);
}
/********************************************************************//**
Frees a transaction object for MySQL. */
UNIV_INTERN
......@@ -463,6 +520,7 @@ trx_lists_init_at_db_start(void)
if (srv_force_recovery == 0) {
trx->conc_state = TRX_PREPARED;
trx_n_prepared++;
} else {
fprintf(stderr,
"InnoDB: Since"
......@@ -541,6 +599,7 @@ trx_lists_init_at_db_start(void)
trx->conc_state
= TRX_PREPARED;
trx_n_prepared++;
} else {
fprintf(stderr,
"InnoDB: Since"
......@@ -820,6 +879,11 @@ trx_commit_off_kernel(
|| trx->conc_state == TRX_PREPARED);
ut_ad(mutex_own(&kernel_mutex));
if (UNIV_UNLIKELY(trx->conc_state == TRX_PREPARED)) {
ut_a(trx_n_prepared > 0);
trx_n_prepared--;
}
/* The following assignment makes the transaction committed in memory
and makes its changes to data visible to other transactions.
NOTE that there is a small discrepancy from the strict formal
......@@ -1857,6 +1921,7 @@ trx_prepare_off_kernel(
/*--------------------------------------*/
trx->conc_state = TRX_PREPARED;
trx_n_prepared++;
/*--------------------------------------*/
if (lsn) {
......@@ -2031,10 +2096,11 @@ trx_get_trx_by_xid(
while (trx) {
/* Compare two X/Open XA transaction id's: their
length should be the same and binary comparison
of gtrid_lenght+bqual_length bytes should be
of gtrid_length+bqual_length bytes should be
the same */
if (trx->conc_state == TRX_PREPARED
if (trx->is_recovered
&& trx->conc_state == TRX_PREPARED
&& xid->gtrid_length == trx->xid.gtrid_length
&& xid->bqual_length == trx->xid.bqual_length
&& memcmp(xid->data, trx->xid.data,
......
......@@ -36,6 +36,7 @@ Created 3/26/1996 Heikki Tuuri
#include "trx0rseg.h"
#include "trx0trx.h"
#include "srv0srv.h"
#include "srv0start.h"
#include "trx0rec.h"
#include "trx0purge.h"
......@@ -1976,4 +1977,31 @@ trx_undo_insert_cleanup(
mutex_exit(&(rseg->mutex));
}
/********************************************************************//**
At shutdown, frees the undo logs of a PREPARED transaction. */
UNIV_INTERN
void
trx_undo_free_prepared(
/*===================*/
trx_t* trx) /*!< in/out: PREPARED transaction */
{
mutex_enter(&trx->rseg->mutex);
ut_ad(srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS);
if (trx->update_undo) {
ut_a(trx->update_undo->state == TRX_UNDO_PREPARED);
UT_LIST_REMOVE(undo_list, trx->rseg->update_undo_list,
trx->update_undo);
trx_undo_mem_free(trx->update_undo);
}
if (trx->insert_undo) {
ut_a(trx->insert_undo->state == TRX_UNDO_PREPARED);
UT_LIST_REMOVE(undo_list, trx->rseg->insert_undo_list,
trx->insert_undo);
trx_undo_mem_free(trx->insert_undo);
}
mutex_exit(&trx->rseg->mutex);
}
#endif /* !UNIV_HOTBACKUP */
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