diff options
Diffstat (limited to 'sql/ha_innodb.cc')
-rw-r--r-- | sql/ha_innodb.cc | 130 |
1 files changed, 93 insertions, 37 deletions
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc index 78b70d9876a..4167b7c2dde 100644 --- a/sql/ha_innodb.cc +++ b/sql/ha_innodb.cc @@ -326,7 +326,7 @@ innodb_srv_conc_enter_innodb( /*=========================*/ trx_t* trx) /* in: transaction handle */ { - if (UNIV_LIKELY(srv_thread_concurrency >= 20)) { + if (UNIV_LIKELY(srv_thread_concurrency >= SRV_CONCURRENCY_THRESHOLD)) { return; } @@ -343,7 +343,7 @@ innodb_srv_conc_exit_innodb( /*========================*/ trx_t* trx) /* in: transaction handle */ { - if (UNIV_LIKELY(srv_thread_concurrency >= 20)) { + if (UNIV_LIKELY(srv_thread_concurrency >= SRV_CONCURRENCY_THRESHOLD)) { return; } @@ -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 */ @@ -2955,22 +2955,45 @@ build_template( templ = prebuilt->mysql_template + n_requested_fields; field = table->field[i]; - ibool index_contains_field= - dict_index_contains_col_or_prefix(index, i); + if (UNIV_LIKELY(templ_type == ROW_MYSQL_REC_FIELDS)) { + /* Decide which columns we should fetch + and which we can skip. */ + register const ibool index_contains_field = + dict_index_contains_col_or_prefix(index, i); + + if (!index_contains_field && prebuilt->read_just_key) { + /* If this is a 'key read', we do not need + columns that are not in the key */ + + goto skip_field; + } + + if (index_contains_field && fetch_all_in_key) { + /* This field is needed in the query */ + + goto include_field; + } + + if (table->file->ha_get_bit_in_read_set(i+1) || + table->file->ha_get_bit_in_write_set(i+1)) { + /* This field is needed in the query */ + + goto include_field; + } - if (templ_type == ROW_MYSQL_REC_FIELDS && - ((prebuilt->read_just_key && !index_contains_field) || - (!(fetch_all_in_key && index_contains_field) && - !(fetch_primary_key_cols && - dict_table_col_in_clustered_key(index->table, i)) && - (!(table->file->ha_get_bit_in_read_set(i+1) || - table->file->ha_get_bit_in_write_set(i+1)))))) { + if (fetch_primary_key_cols + && dict_table_col_in_clustered_key(index->table, + i)) { + /* This field is needed in the query */ + + goto include_field; + } /* This field is not needed in the query, skip it */ goto skip_field; } - +include_field: n_requested_fields++; templ->col_no = i; @@ -3539,7 +3562,9 @@ ha_innobase::delete_row( } /************************************************************************** -Deletes a lock set to a row */ +Removes a new lock set on a row. This can be called after a row has been read +in the processing of an UPDATE or a DELETE query, if the option +innodb_locks_unsafe_for_binlog is set. */ void ha_innobase::unlock_row(void) @@ -3557,8 +3582,10 @@ ha_innobase::unlock_row(void) mem_analyze_corruption((byte *) prebuilt->trx); ut_error; } - - row_unlock_for_mysql(prebuilt); + + if (srv_locks_unsafe_for_binlog) { + row_unlock_for_mysql(prebuilt, FALSE); + } } /********************************************************************** @@ -5992,6 +6019,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 @@ -6031,7 +6059,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 */ @@ -6564,12 +6591,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); @@ -6577,6 +6606,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 */ @@ -6588,7 +6621,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); @@ -6596,7 +6631,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 */ @@ -6605,30 +6640,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 */ @@ -6636,7 +6678,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; @@ -6656,7 +6701,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); } /*********************************************************************** |