summaryrefslogtreecommitdiff
path: root/sql/ha_innodb.cc
diff options
context:
space:
mode:
authorheikki@hundin.mysql.fi <>2005-06-29 20:52:22 +0300
committerheikki@hundin.mysql.fi <>2005-06-29 20:52:22 +0300
commitc73914977cd36252678e21d303c8a23d8aebee3b (patch)
treefa077e1d1c21a3b5eadeb4f3e284011158cb6500 /sql/ha_innodb.cc
parent3dd28e98e6b46d033b20aeb2eeeb2b258202870d (diff)
downloadmariadb-git-c73914977cd36252678e21d303c8a23d8aebee3b.tar.gz
ha_innodb.cc:
Let InnoDB use a consistent read when it initializes the auto-inc counter for a table: this will eliminate spurious deadlocks, but will ignore an UPDATE if that happens at the same time that we init the auto-inc counter; this has to be documented; this path also fixes most of Bug #11633, but not all: if ::external_lock() is not called on the table in SHOW TABLE STATUS, that might cause a crash if someone simultaneously DROPs the table
Diffstat (limited to 'sql/ha_innodb.cc')
-rw-r--r--sql/ha_innodb.cc73
1 files changed, 51 insertions, 22 deletions
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc
index db354066849..f4c53f2b3da 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -1496,8 +1496,8 @@ innobase_start_trx_and_assign_read_view(
/*********************************************************************
Commits a transaction in an InnoDB database or marks an SQL statement
ended. */
-
-static int
+static
+int
innobase_commit(
/*============*/
/* out: 0 */
@@ -5991,6 +5991,7 @@ ha_innobase::external_lock(
reads. */
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
@@ -6030,7 +6031,6 @@ ha_innobase::external_lock(
trx->n_mysql_tables_in_use--;
prebuilt->mysql_has_locked = FALSE;
-
/* If the MySQL lock count drops to zero we know that the current SQL
statement has ended */
@@ -6563,12 +6563,14 @@ the value of the auto-inc counter. */
int
ha_innobase::innobase_read_and_init_auto_inc(
/*=========================================*/
- /* out: 0 or error code: deadlock or
- lock wait timeout */
+ /* out: 0 or error code: deadlock or lock wait
+ timeout */
longlong* ret) /* out: auto-inc value */
{
row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
longlong auto_inc;
+ ulint old_select_lock_type;
+ ibool trx_was_not_started = FALSE;
int error;
ut_a(prebuilt);
@@ -6576,6 +6578,10 @@ ha_innobase::innobase_read_and_init_auto_inc(
(trx_t*) current_thd->ha_data[innobase_hton.slot]);
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
possible adaptive hash latch to avoid deadlocks of threads */
@@ -6587,7 +6593,9 @@ ha_innobase::innobase_read_and_init_auto_inc(
/* Already initialized */
*ret = auto_inc;
- return(0);
+ error = 0;
+
+ goto func_exit_early;
}
error = row_lock_table_autoinc_for_mysql(prebuilt);
@@ -6595,7 +6603,7 @@ ha_innobase::innobase_read_and_init_auto_inc(
if (error != DB_SUCCESS) {
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 */
@@ -6604,30 +6612,37 @@ ha_innobase::innobase_read_and_init_auto_inc(
if (auto_inc != 0) {
*ret = auto_inc;
- return(0);
+ error = 0;
+
+ goto func_exit_early;
}
(void) extra(HA_EXTRA_KEYREAD);
index_init(table->s->next_number_index);
- /* We use an exclusive lock when we read the max key value from the
- auto-increment column index. This is because then build_template will
- advise InnoDB to fetch all columns. In SHOW TABLE STATUS the query
- id of the auto-increment column is not changed, and previously InnoDB
- did not fetch it, causing SHOW TABLE STATUS to show wrong values
- for the autoinc column. */
-
- prebuilt->select_lock_type = LOCK_X;
+ /* Starting from 5.0.9, we use a consistent read to read the auto-inc
+ column maximum value. This eliminates the spurious deadlocks caused
+ by the row X-lock that we previously used. Note the following flaw
+ in our algorithm: if some other user meanwhile UPDATEs the auto-inc
+ column, our consistent read will not return the largest value. We
+ accept this flaw, since the deadlocks were a bigger trouble. */
- /* Play safe and also give in another way the hint to fetch
- all columns in the key: */
+ /* Fetch all the columns in the key */
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]);
+ prebuilt->trx->n_mysql_tables_in_use--;
+ prebuilt->select_lock_type = old_select_lock_type;
+
if (error) {
if (error == HA_ERR_END_OF_FILE) {
/* The table was empty, initialize to 1 */
@@ -6635,7 +6650,10 @@ ha_innobase::innobase_read_and_init_auto_inc(
error = 0;
} 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;
goto func_exit;
@@ -6655,7 +6673,18 @@ func_exit:
*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);
}
/***********************************************************************