Commit af27c38f authored by heikki@donna.mysql.fi's avatar heikki@donna.mysql.fi
Browse files

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
parent 0f9a30ab
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -1348,6 +1348,10 @@ os_aio(
		}
	} 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) {
+91 −0
Original line number Diff line number Diff line
@@ -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 */
@@ -2106,6 +2176,8 @@ row_sel_get_clust_rec_for_mysql(

		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;
+9 −2
Original line number Diff line number Diff line
@@ -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);

	if (node->table == NULL) {
	  found = FALSE;
	} else {
	  found = row_undo_search_clust_to_pcur(node, thr);
	}

	if (!found) {
		return(DB_SUCCESS);
+15 −3
Original line number Diff line number Diff line
@@ -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);

	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;