Commit f9bc3cb5 authored by heikki@hundin.mysql.fi's avatar heikki@hundin.mysql.fi

Merge heikki@bk-internal.mysql.com:/home/bk/mysql-5.0

into hundin.mysql.fi:/home/heikki/mysql-5.0
parents 0d894f3d c7391497
...@@ -1496,8 +1496,8 @@ innobase_start_trx_and_assign_read_view( ...@@ -1496,8 +1496,8 @@ innobase_start_trx_and_assign_read_view(
/********************************************************************* /*********************************************************************
Commits a transaction in an InnoDB database or marks an SQL statement Commits a transaction in an InnoDB database or marks an SQL statement
ended. */ ended. */
static
static int int
innobase_commit( innobase_commit(
/*============*/ /*============*/
/* out: 0 */ /* out: 0 */
...@@ -5991,6 +5991,7 @@ ha_innobase::external_lock( ...@@ -5991,6 +5991,7 @@ ha_innobase::external_lock(
reads. */ reads. */
prebuilt->select_lock_type = LOCK_S; prebuilt->select_lock_type = LOCK_S;
prebuilt->stored_select_lock_type = LOCK_S;
} }
/* Starting from 4.1.9, no InnoDB table lock is taken in LOCK /* Starting from 4.1.9, no InnoDB table lock is taken in LOCK
...@@ -6030,7 +6031,6 @@ ha_innobase::external_lock( ...@@ -6030,7 +6031,6 @@ ha_innobase::external_lock(
trx->n_mysql_tables_in_use--; trx->n_mysql_tables_in_use--;
prebuilt->mysql_has_locked = FALSE; prebuilt->mysql_has_locked = FALSE;
/* If the MySQL lock count drops to zero we know that the current SQL /* If the MySQL lock count drops to zero we know that the current SQL
statement has ended */ statement has ended */
...@@ -6563,12 +6563,14 @@ the value of the auto-inc counter. */ ...@@ -6563,12 +6563,14 @@ the value of the auto-inc counter. */
int int
ha_innobase::innobase_read_and_init_auto_inc( ha_innobase::innobase_read_and_init_auto_inc(
/*=========================================*/ /*=========================================*/
/* out: 0 or error code: deadlock or /* out: 0 or error code: deadlock or lock wait
lock wait timeout */ timeout */
longlong* ret) /* out: auto-inc value */ longlong* ret) /* out: auto-inc value */
{ {
row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt; row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
longlong auto_inc; longlong auto_inc;
ulint old_select_lock_type;
ibool trx_was_not_started = FALSE;
int error; int error;
ut_a(prebuilt); ut_a(prebuilt);
...@@ -6576,6 +6578,10 @@ ha_innobase::innobase_read_and_init_auto_inc( ...@@ -6576,6 +6578,10 @@ ha_innobase::innobase_read_and_init_auto_inc(
(trx_t*) current_thd->ha_data[innobase_hton.slot]); (trx_t*) current_thd->ha_data[innobase_hton.slot]);
ut_a(prebuilt->table); ut_a(prebuilt->table);
if (prebuilt->trx->conc_state == TRX_NOT_STARTED) {
trx_was_not_started = TRUE;
}
/* In case MySQL calls this in the middle of a SELECT query, release /* In case MySQL calls this in the middle of a SELECT query, release
possible adaptive hash latch to avoid deadlocks of threads */ possible adaptive hash latch to avoid deadlocks of threads */
...@@ -6587,7 +6593,9 @@ ha_innobase::innobase_read_and_init_auto_inc( ...@@ -6587,7 +6593,9 @@ ha_innobase::innobase_read_and_init_auto_inc(
/* Already initialized */ /* Already initialized */
*ret = auto_inc; *ret = auto_inc;
return(0); error = 0;
goto func_exit_early;
} }
error = row_lock_table_autoinc_for_mysql(prebuilt); error = row_lock_table_autoinc_for_mysql(prebuilt);
...@@ -6595,7 +6603,7 @@ ha_innobase::innobase_read_and_init_auto_inc( ...@@ -6595,7 +6603,7 @@ ha_innobase::innobase_read_and_init_auto_inc(
if (error != DB_SUCCESS) { if (error != DB_SUCCESS) {
error = convert_error_code_to_mysql(error, user_thd); error = convert_error_code_to_mysql(error, user_thd);
goto func_exit; goto func_exit_early;
} }
/* Check again if someone has initialized the counter meanwhile */ /* Check again if someone has initialized the counter meanwhile */
...@@ -6604,30 +6612,37 @@ ha_innobase::innobase_read_and_init_auto_inc( ...@@ -6604,30 +6612,37 @@ ha_innobase::innobase_read_and_init_auto_inc(
if (auto_inc != 0) { if (auto_inc != 0) {
*ret = auto_inc; *ret = auto_inc;
return(0); error = 0;
goto func_exit_early;
} }
(void) extra(HA_EXTRA_KEYREAD); (void) extra(HA_EXTRA_KEYREAD);
index_init(table->s->next_number_index); index_init(table->s->next_number_index);
/* We use an exclusive lock when we read the max key value from the /* Starting from 5.0.9, we use a consistent read to read the auto-inc
auto-increment column index. This is because then build_template will column maximum value. This eliminates the spurious deadlocks caused
advise InnoDB to fetch all columns. In SHOW TABLE STATUS the query by the row X-lock that we previously used. Note the following flaw
id of the auto-increment column is not changed, and previously InnoDB in our algorithm: if some other user meanwhile UPDATEs the auto-inc
did not fetch it, causing SHOW TABLE STATUS to show wrong values column, our consistent read will not return the largest value. We
for the autoinc column. */ accept this flaw, since the deadlocks were a bigger trouble. */
prebuilt->select_lock_type = LOCK_X;
/* Play safe and also give in another way the hint to fetch /* Fetch all the columns in the key */
all columns in the key: */
prebuilt->hint_need_to_fetch_extra_cols = ROW_RETRIEVE_ALL_COLS; prebuilt->hint_need_to_fetch_extra_cols = ROW_RETRIEVE_ALL_COLS;
prebuilt->trx->mysql_n_tables_locked += 1; old_select_lock_type = prebuilt->select_lock_type;
prebuilt->select_lock_type = LOCK_NONE;
/* Eliminate an InnoDB error print that happens when we try to SELECT
from a table when no table has been locked in ::external_lock(). */
prebuilt->trx->n_mysql_tables_in_use++;
error = index_last(table->record[1]); error = index_last(table->record[1]);
prebuilt->trx->n_mysql_tables_in_use--;
prebuilt->select_lock_type = old_select_lock_type;
if (error) { if (error) {
if (error == HA_ERR_END_OF_FILE) { if (error == HA_ERR_END_OF_FILE) {
/* The table was empty, initialize to 1 */ /* The table was empty, initialize to 1 */
...@@ -6635,7 +6650,10 @@ ha_innobase::innobase_read_and_init_auto_inc( ...@@ -6635,7 +6650,10 @@ ha_innobase::innobase_read_and_init_auto_inc(
error = 0; error = 0;
} else { } else {
/* Deadlock or a lock wait timeout */ /* This should not happen in a consistent read */
fprintf(stderr,
"InnoDB: Error: consistent read of auto-inc column returned %lu\n",
(ulong)error);
auto_inc = -1; auto_inc = -1;
goto func_exit; goto func_exit;
...@@ -6655,7 +6673,18 @@ func_exit: ...@@ -6655,7 +6673,18 @@ func_exit:
*ret = auto_inc; *ret = auto_inc;
return(error); func_exit_early:
/* Since MySQL does not seem to call autocommit after SHOW TABLE
STATUS (even if we would register the trx here), we must commit our
transaction here if it was started here. This is to eliminate a
dangling transaction. */
if (trx_was_not_started) {
innobase_commit_low(prebuilt->trx);
}
return(error);
} }
/*********************************************************************** /***********************************************************************
......
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