mirror of
https://github.com/MariaDB/server.git
synced 2025-01-31 11:01:52 +01:00
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
This commit is contained in:
parent
0f9a30ab86
commit
af27c38ff6
4 changed files with 119 additions and 5 deletions
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue