diff options
author | heikki@hundin.mysql.fi <> | 2005-06-29 20:52:22 +0300 |
---|---|---|
committer | heikki@hundin.mysql.fi <> | 2005-06-29 20:52:22 +0300 |
commit | c73914977cd36252678e21d303c8a23d8aebee3b (patch) | |
tree | fa077e1d1c21a3b5eadeb4f3e284011158cb6500 /sql/ha_innodb.cc | |
parent | 3dd28e98e6b46d033b20aeb2eeeb2b258202870d (diff) | |
download | mariadb-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.cc | 73 |
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); } /*********************************************************************** |