diff options
author | Marko Mäkelä <marko.makela@oracle.com> | 2011-11-10 12:49:31 +0200 |
---|---|---|
committer | Marko Mäkelä <marko.makela@oracle.com> | 2011-11-10 12:49:31 +0200 |
commit | a0a51251e49365cc0f256a2ebc90994dbe0d9a95 (patch) | |
tree | a1e5e010bd0a3644af8424d22ce41dcb33d26be1 /storage | |
parent | 77eb01b82776dc222da1543dc2d20295156a123d (diff) | |
download | mariadb-git-a0a51251e49365cc0f256a2ebc90994dbe0d9a95.tar.gz |
Bug#11759688 52020: InnoDB can still deadlock on just INSERT...ON DUPLICATE KEY
a.k.a. Bug#7975 deadlock without any locking, simple select and update
Bug#7975 was reintroduced when the storage engine API was made
pluggable in MySQL 5.1. Instead of looking at thd->lex directly, we
rely on handler::extra(). But, we were looking at the wrong extra()
flag, and we were ignoring the TRX_DUP_REPLACE flag in places where we
should obey it.
innodb_replace.test: Add tests for hopefully all affected statement
types, so that bug should never ever resurface. This kind of tests
should have been added when fixing Bug#7975 in MySQL 5.0.3 in the
first place.
rb:806 approved by Sunny Bains
Diffstat (limited to 'storage')
-rw-r--r-- | storage/innobase/handler/ha_innodb.cc | 16 | ||||
-rw-r--r-- | storage/innobase/row/row0ins.c | 6 | ||||
-rw-r--r-- | storage/innodb_plugin/ChangeLog | 7 | ||||
-rw-r--r-- | storage/innodb_plugin/handler/ha_innodb.cc | 16 | ||||
-rw-r--r-- | storage/innodb_plugin/row/row0ins.c | 8 |
5 files changed, 28 insertions, 25 deletions
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc index 3e3db33e588..7f82959dffd 100644 --- a/storage/innobase/handler/ha_innodb.cc +++ b/storage/innobase/handler/ha_innodb.cc @@ -4087,8 +4087,7 @@ no_commit: switch (sql_command) { case SQLCOM_LOAD: - if ((trx->duplicates - & (TRX_DUP_IGNORE | TRX_DUP_REPLACE))) { + if (trx->duplicates) { goto set_max_autoinc; } @@ -4364,8 +4363,7 @@ ha_innobase::update_row( && table->next_number_field && new_row == table->record[0] && thd_sql_command(user_thd) == SQLCOM_INSERT - && (trx->duplicates & (TRX_DUP_IGNORE | TRX_DUP_REPLACE)) - == TRX_DUP_IGNORE) { + && trx->duplicates) { ulonglong auto_inc; ulonglong col_max_value; @@ -7099,6 +7097,7 @@ ha_innobase::extra( break; case HA_EXTRA_RESET_STATE: reset_template(prebuilt); + thd_to_trx(ha_thd())->duplicates = 0; break; case HA_EXTRA_NO_KEYREAD: prebuilt->read_just_key = 0; @@ -7116,19 +7115,18 @@ ha_innobase::extra( parameters below. We must not invoke update_thd() either, because the calling threads may change. CAREFUL HERE, OR MEMORY CORRUPTION MAY OCCUR! */ - case HA_EXTRA_IGNORE_DUP_KEY: + case HA_EXTRA_INSERT_WITH_UPDATE: thd_to_trx(ha_thd())->duplicates |= TRX_DUP_IGNORE; break; + case HA_EXTRA_NO_IGNORE_DUP_KEY: + thd_to_trx(ha_thd())->duplicates &= ~TRX_DUP_IGNORE; + break; case HA_EXTRA_WRITE_CAN_REPLACE: thd_to_trx(ha_thd())->duplicates |= TRX_DUP_REPLACE; break; case HA_EXTRA_WRITE_CANNOT_REPLACE: thd_to_trx(ha_thd())->duplicates &= ~TRX_DUP_REPLACE; break; - case HA_EXTRA_NO_IGNORE_DUP_KEY: - thd_to_trx(ha_thd())->duplicates &= - ~(TRX_DUP_IGNORE | TRX_DUP_REPLACE); - break; default:/* Do nothing */ ; } diff --git a/storage/innobase/row/row0ins.c b/storage/innobase/row/row0ins.c index 6366beb6b47..c18b6995066 100644 --- a/storage/innobase/row/row0ins.c +++ b/storage/innobase/row/row0ins.c @@ -1674,7 +1674,7 @@ row_ins_scan_sec_index_for_duplicate( btr_pcur_open(index, entry, PAGE_CUR_GE, BTR_SEARCH_LEAF, &pcur, &mtr); - allow_duplicates = thr_get_trx(thr)->duplicates & TRX_DUP_IGNORE; + allow_duplicates = thr_get_trx(thr)->duplicates; /* Scan index records and check if there is a duplicate */ @@ -1814,7 +1814,7 @@ row_ins_duplicate_error_in_clust( sure that in roll-forward we get the same duplicate errors as in original execution */ - if (trx->duplicates & TRX_DUP_IGNORE) { + if (trx->duplicates) { /* If the SQL-query will update or replace duplicate key we will take X-lock for @@ -1856,7 +1856,7 @@ row_ins_duplicate_error_in_clust( offsets = rec_get_offsets(rec, cursor->index, offsets, ULINT_UNDEFINED, &heap); - if (trx->duplicates & TRX_DUP_IGNORE) { + if (trx->duplicates) { /* If the SQL-query will update or replace duplicate key we will take X-lock for diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index f7d01cd6773..a7c9c6e3212 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,3 +1,10 @@ +2011-11-10 The InnoDB Team + + * handler/ha_innodb.cc, row/row0ins.c, innodb_replace.test: + Fix Bug#11759688 52020: InnoDB can still deadlock + on just INSERT...ON DUPLICATE KEY a.k.a. the reintroduction of + Bug#7975 deadlock without any locking, simple select and update + 2011-11-08 The InnoDB Team * btr/btr0pcur.c, include/btr0pcur.h, include/btr0pcur.ic: diff --git a/storage/innodb_plugin/handler/ha_innodb.cc b/storage/innodb_plugin/handler/ha_innodb.cc index 35b2dcec23c..5ed4abe3d08 100644 --- a/storage/innodb_plugin/handler/ha_innodb.cc +++ b/storage/innodb_plugin/handler/ha_innodb.cc @@ -4793,8 +4793,7 @@ no_commit: switch (sql_command) { case SQLCOM_LOAD: - if ((trx->duplicates - & (TRX_DUP_IGNORE | TRX_DUP_REPLACE))) { + if (trx->duplicates) { goto set_max_autoinc; } @@ -5069,8 +5068,7 @@ ha_innobase::update_row( && table->next_number_field && new_row == table->record[0] && thd_sql_command(user_thd) == SQLCOM_INSERT - && (trx->duplicates & (TRX_DUP_IGNORE | TRX_DUP_REPLACE)) - == TRX_DUP_IGNORE) { + && trx->duplicates) { ulonglong auto_inc; ulonglong col_max_value; @@ -8423,6 +8421,7 @@ ha_innobase::extra( break; case HA_EXTRA_RESET_STATE: reset_template(prebuilt); + thd_to_trx(ha_thd())->duplicates = 0; break; case HA_EXTRA_NO_KEYREAD: prebuilt->read_just_key = 0; @@ -8440,19 +8439,18 @@ ha_innobase::extra( parameters below. We must not invoke update_thd() either, because the calling threads may change. CAREFUL HERE, OR MEMORY CORRUPTION MAY OCCUR! */ - case HA_EXTRA_IGNORE_DUP_KEY: + case HA_EXTRA_INSERT_WITH_UPDATE: thd_to_trx(ha_thd())->duplicates |= TRX_DUP_IGNORE; break; + case HA_EXTRA_NO_IGNORE_DUP_KEY: + thd_to_trx(ha_thd())->duplicates &= ~TRX_DUP_IGNORE; + break; case HA_EXTRA_WRITE_CAN_REPLACE: thd_to_trx(ha_thd())->duplicates |= TRX_DUP_REPLACE; break; case HA_EXTRA_WRITE_CANNOT_REPLACE: thd_to_trx(ha_thd())->duplicates &= ~TRX_DUP_REPLACE; break; - case HA_EXTRA_NO_IGNORE_DUP_KEY: - thd_to_trx(ha_thd())->duplicates &= - ~(TRX_DUP_IGNORE | TRX_DUP_REPLACE); - break; default:/* Do nothing */ ; } diff --git a/storage/innodb_plugin/row/row0ins.c b/storage/innodb_plugin/row/row0ins.c index 0f158cdc706..b14ae3de2bd 100644 --- a/storage/innodb_plugin/row/row0ins.c +++ b/storage/innodb_plugin/row/row0ins.c @@ -1662,7 +1662,7 @@ row_ins_scan_sec_index_for_duplicate( ulint n_fields_cmp; btr_pcur_t pcur; ulint err = DB_SUCCESS; - unsigned allow_duplicates; + ulint allow_duplicates; mtr_t mtr; mem_heap_t* heap = NULL; ulint offsets_[REC_OFFS_NORMAL_SIZE]; @@ -1693,7 +1693,7 @@ row_ins_scan_sec_index_for_duplicate( btr_pcur_open(index, entry, PAGE_CUR_GE, BTR_SEARCH_LEAF, &pcur, &mtr); - allow_duplicates = thr_get_trx(thr)->duplicates & TRX_DUP_IGNORE; + allow_duplicates = thr_get_trx(thr)->duplicates; /* Scan index records and check if there is a duplicate */ @@ -1827,7 +1827,7 @@ row_ins_duplicate_error_in_clust( sure that in roll-forward we get the same duplicate errors as in original execution */ - if (trx->duplicates & TRX_DUP_IGNORE) { + if (trx->duplicates) { /* If the SQL-query will update or replace duplicate key we will take X-lock for @@ -1871,7 +1871,7 @@ row_ins_duplicate_error_in_clust( offsets = rec_get_offsets(rec, cursor->index, offsets, ULINT_UNDEFINED, &heap); - if (trx->duplicates & TRX_DUP_IGNORE) { + if (trx->duplicates) { /* If the SQL-query will update or replace duplicate key we will take X-lock for |