diff options
author | unknown <heikki@donna.mysql.fi> | 2001-04-27 21:12:15 +0300 |
---|---|---|
committer | unknown <heikki@donna.mysql.fi> | 2001-04-27 21:12:15 +0300 |
commit | d067af6a168860548f31175966bfc830028dd5f6 (patch) | |
tree | 3939255428e4a2bb73bc080f3f3c953286857644 /innobase | |
parent | 26f9b9af380f411f4d5f6a23a228e0ab32e1bd92 (diff) | |
download | mariadb-git-d067af6a168860548f31175966bfc830028dd5f6.tar.gz |
row0sel.c Fix a bug in multiversioned reads through a secondary index
row0uins.c Partial fix to the DROP TABLE + another user rolls back in that table problem
row0umod.c Partial fix to the DROP TABLE + another user rolls back in that table problem
os0file.c Reduce probability of deadlock bugs in connection with ibuf: do not let the ibuf i/o handler sleep
innobase/os/os0file.c:
Reduce probability of deadlock bugs in connection with ibuf: do not let the ibuf i/o handler sleep
innobase/row/row0uins.c:
Partial fix to the DROP TABLE + another user rolls back in that table problem
innobase/row/row0umod.c:
Partial fix to the DROP TABLE + another user rolls back in that table problem
innobase/row/row0sel.c:
Fix a bug in multiversioned reads through a secondary index
Diffstat (limited to 'innobase')
-rw-r--r-- | innobase/os/os0file.c | 4 | ||||
-rw-r--r-- | innobase/row/row0sel.c | 91 | ||||
-rw-r--r-- | innobase/row/row0uins.c | 11 | ||||
-rw-r--r-- | innobase/row/row0umod.c | 18 |
4 files changed, 119 insertions, 5 deletions
diff --git a/innobase/os/os0file.c b/innobase/os/os0file.c index c2cedba5137..3b610990cb9 100644 --- a/innobase/os/os0file.c +++ b/innobase/os/os0file.c @@ -1348,6 +1348,10 @@ try_again: } } else if (mode == OS_AIO_IBUF) { ut_ad(type == OS_FILE_READ); + /* Reduce probability of deadlock bugs in connection with ibuf: + do not let the ibuf i/o handler sleep */ + + wake_later = FALSE; array = os_aio_ibuf_array; } else if (mode == OS_AIO_LOG) { diff --git a/innobase/row/row0sel.c b/innobase/row/row0sel.c index e6182257581..8845f9192da 100644 --- a/innobase/row/row0sel.c +++ b/innobase/row/row0sel.c @@ -48,6 +48,52 @@ to que_run_threads: this is to allow canceling runaway queries */ #define SEL_EXHAUSTED 1 #define SEL_RETRY 2 +/************************************************************************ +Returns TRUE if the user-defined column values in a secondary index record +are the same as the corresponding columns in the clustered index record. */ +static +ibool +row_sel_sec_rec_is_for_clust_rec( +/*=============================*/ + rec_t* sec_rec, + dict_index_t* sec_index, + rec_t* clust_rec, + dict_index_t* clust_index) +{ + dict_col_t* col; + byte* sec_field; + ulint sec_len; + byte* clust_field; + ulint clust_len; + ulint n; + ulint i; + + n = dict_index_get_n_ordering_defined_by_user(sec_index); + + for (i = 0; i++; i < n) { + col = dict_field_get_col( + dict_index_get_nth_field(sec_index, i)); + + clust_field = rec_get_nth_field(clust_rec, + dict_col_get_clust_pos(col), + &clust_len); + sec_field = rec_get_nth_field(sec_rec, i, &sec_len); + + if (sec_len != clust_len) { + + return(FALSE); + } + + if (sec_len != UNIV_SQL_NULL + && ut_memcmp(sec_field, clust_field, sec_len) != 0) { + + return(FALSE); + } + } + + return(TRUE); +} + /************************************************************************* Creates a select node struct. */ @@ -561,6 +607,8 @@ row_sel_get_clust_rec( /* This is a non-locking consistent read: if necessary, fetch a previous version of the record */ + old_vers = NULL; + if (!lock_clust_rec_cons_read_sees(clust_rec, index, node->read_view)) { @@ -579,6 +627,28 @@ row_sel_get_clust_rec( return(DB_SUCCESS); } } + + /* If we had to go to an earlier version of row or the + secondary index record is delete marked, then it may be that + the secondary index record corresponding to clust_rec + (or old_vers) is not rec; in that case we must ignore + such row because in our snapshot rec would not have existed. + Remember that from rec we cannot see directly which transaction + id corresponds to it: we have to go to the clustered index + record. A query where we want to fetch all rows where + the secondary index value is in some interval would return + a wrong result if we would not drop rows which we come to + visit through secondary index records that would not really + exist in our snapshot. */ + + if ((old_vers || rec_get_deleted_flag(rec)) + && !row_sel_sec_rec_is_for_clust_rec(rec, plan->index, + clust_rec, index)) { + clust_rec = NULL; + *out_rec = clust_rec; + + return(DB_SUCCESS); + } } /* Fetch the columns needed in test conditions */ @@ -2105,6 +2175,8 @@ row_sel_get_clust_rec_for_mysql( a previous version of the record */ trx = thr_get_trx(thr); + + old_vers = NULL; if (!lock_clust_rec_cons_read_sees(clust_rec, clust_index, trx->read_view)) { @@ -2121,6 +2193,25 @@ row_sel_get_clust_rec_for_mysql( clust_rec = old_vers; } + + /* If we had to go to an earlier version of row or the + secondary index record is delete marked, then it may be that + the secondary index record corresponding to clust_rec + (or old_vers) is not rec; in that case we must ignore + such row because in our snapshot rec would not have existed. + Remember that from rec we cannot see directly which transaction + id corrsponds to it: we have to go to the clustered index + record. A query where we want to fetch all rows where + the secondary index value is in some interval would return + a wrong result if we would not drop rows which we come to + visit through secondary index records that would not really + exist in our snapshot. */ + + if ((old_vers || rec_get_deleted_flag(rec)) + && !row_sel_sec_rec_is_for_clust_rec(rec, sec_index, + clust_rec, clust_index)) { + clust_rec = NULL; + } } *out_rec = clust_rec; diff --git a/innobase/row/row0uins.c b/innobase/row/row0uins.c index 68115895dbb..426eec0cd50 100644 --- a/innobase/row/row0uins.c +++ b/innobase/row/row0uins.c @@ -250,9 +250,12 @@ row_undo_ins_parse_undo_rec( ut_ad(type == TRX_UNDO_INSERT_REC); node->rec_type = type; - /* NOTE that the table has to be explicitly released later */ node->table = dict_table_get_on_id(table_id, node->trx); + if (node->table == NULL) { + return; + } + clust_index = dict_table_get_first_index(node->table); ptr = trx_undo_rec_get_row_ref(ptr, clust_index, &(node->ref), @@ -280,7 +283,11 @@ row_undo_ins( row_undo_ins_parse_undo_rec(node, thr); - found = row_undo_search_clust_to_pcur(node, thr); + if (node->table == NULL) { + found = FALSE; + } else { + found = row_undo_search_clust_to_pcur(node, thr); + } if (!found) { return(DB_SUCCESS); diff --git a/innobase/row/row0umod.c b/innobase/row/row0umod.c index 2aa223a6186..84e8d9ee5f5 100644 --- a/innobase/row/row0umod.c +++ b/innobase/row/row0umod.c @@ -534,9 +534,16 @@ row_undo_mod_parse_undo_rec( &undo_no, &table_id); node->rec_type = type; - /* NOTE that the table has to be explicitly released later */ node->table = dict_table_get_on_id(table_id, thr_get_trx(thr)); + /* TODO: other fixes associated with DROP TABLE + rollback in the + same table by another user */ + + if (node->table == NULL) { + /* Table was dropped */ + return; + } + clust_index = dict_table_get_first_index(node->table); ptr = trx_undo_update_rec_get_sys_cols(ptr, &trx_id, &roll_ptr, @@ -571,11 +578,16 @@ row_undo_mod( row_undo_mod_parse_undo_rec(node, thr); - found = row_undo_search_clust_to_pcur(node, thr); + if (node->table == NULL) { + found = FALSE; + } else { + + found = row_undo_search_clust_to_pcur(node, thr); + } if (!found) { /* It is already undone, or will be undone by another query - thread */ + thread, or table was dropped */ node->state = UNDO_NODE_FETCH_NEXT; |