diff options
author | unknown <heikki@hundin.mysql.fi> | 2003-06-18 02:18:19 +0300 |
---|---|---|
committer | unknown <heikki@hundin.mysql.fi> | 2003-06-18 02:18:19 +0300 |
commit | 1efc292be6c92316b16eef70b289f6e1ab7f2a33 (patch) | |
tree | 5a7046b5480dc7cb310b0b430a6a686599037f20 /innobase | |
parent | b518744d16a516c842c4ec0382c8ab44a38aebca (diff) | |
download | mariadb-git-1efc292be6c92316b16eef70b289f6e1ab7f2a33.tar.gz |
row0vers.c, row0sel.c, row0ins.c:
Fix bug: InnoDB could print that it cannot find a clustered index record if an update undo, purge, and a consistent read coincided, in rare cases it might also have returned a wrong row in a query
innobase/row/row0ins.c:
Fix bug: InnoDB could print that it cannot find a clustered index record if an update undo, purge, and a consistent read coincided, in rare cases it might also have returned a wrong row in a query
innobase/row/row0sel.c:
Fix bug: InnoDB could print that it cannot find a clustered index record if an update undo, purge, and a consistent read coincided, in rare cases it might also have returned a wrong row in a query
innobase/row/row0vers.c:
Fix bug: InnoDB could print that it cannot find a clustered index record if an update undo, purge, and a consistent read coincided, in rare cases it might also have returned a wrong row in a query
Diffstat (limited to 'innobase')
-rw-r--r-- | innobase/row/row0ins.c | 25 | ||||
-rw-r--r-- | innobase/row/row0sel.c | 89 | ||||
-rw-r--r-- | innobase/row/row0vers.c | 28 |
3 files changed, 88 insertions, 54 deletions
diff --git a/innobase/row/row0ins.c b/innobase/row/row0ins.c index 23da0b9b93c..d36e5a9761e 100644 --- a/innobase/row/row0ins.c +++ b/innobase/row/row0ins.c @@ -791,27 +791,28 @@ row_ins_foreign_check_on_constraint( mem_heap_free(tmp_heap); clust_rec = btr_pcur_get_rec(cascade->pcur); - } - if (!page_rec_is_user_rec(clust_rec)) { - fprintf(stderr, + if (btr_pcur_get_low_match(cascade->pcur) + < dict_index_get_n_unique(clust_index)) { + fprintf(stderr, "InnoDB: error in cascade of a foreign key op\n" "InnoDB: index %s table %s\n", index->name, index->table->name); - rec_sprintf(err_buf, 900, rec); - fprintf(stderr, "InnoDB: record %s\n", err_buf); - - rec_sprintf(err_buf, 900, clust_rec); - fprintf(stderr, "InnoDB: clustered record %s\n", err_buf); + rec_sprintf(err_buf, 900, rec); + fprintf(stderr, "InnoDB: record %s\n", err_buf); - fprintf(stderr, + rec_sprintf(err_buf, 900, clust_rec); + fprintf(stderr, "InnoDB: clustered record %s\n", + err_buf); + fprintf(stderr, "InnoDB: Make a detailed bug report and send it\n"); - fprintf(stderr, "InnoDB: to mysql@lists.mysql.com\n"); + fprintf(stderr, "InnoDB: to mysql@lists.mysql.com\n"); - err = DB_SUCCESS; + err = DB_SUCCESS; - goto nonstandard_exit_func; + goto nonstandard_exit_func; + } } /* Set an X-lock on the row to delete or update in the child table */ diff --git a/innobase/row/row0sel.c b/innobase/row/row0sel.c index 114ebf870b0..afc01247347 100644 --- a/innobase/row/row0sel.c +++ b/innobase/row/row0sel.c @@ -609,7 +609,25 @@ row_sel_get_clust_rec( clust_rec = btr_pcur_get_rec(&(plan->clust_pcur)); - ut_ad(page_rec_is_user_rec(clust_rec)); + if (btr_pcur_get_low_match(&(plan->clust_pcur)) + < dict_index_get_n_unique(index)) { + + ut_a(rec_get_deleted_flag(rec)); + ut_a(node->read_view); + + /* In a rare case it is possible that no clust rec is found + for a delete-marked secondary index record: if in row0umod.c + in row_undo_mod_remove_clust_low() we have already removed + the clust rec, while purge is still cleaning and removing + secondary index records associated with earlier versions of + the clustered index record. In that case we know that the + clustered index record did not exist in the read view of + trx. */ + + clust_rec = NULL; + + goto func_exit; + } if (!node->read_view) { /* Try to place a lock on the index record */ @@ -672,6 +690,7 @@ row_sel_get_clust_rec( row_sel_fetch_columns(index, clust_rec, UT_LIST_GET_FIRST(plan->columns)); +func_exit: *out_rec = clust_rec; return(DB_SUCCESS); @@ -1253,6 +1272,8 @@ rec_loop: /* PHASE 3: Get previous version in a consistent read */ + cons_read_requires_clust_rec = FALSE; + if (consistent_read) { /* This is a non-locking consistent read: if necessary, fetch a previous version of the record */ @@ -2269,7 +2290,10 @@ row_sel_get_clust_rec_for_mysql( /* out: DB_SUCCESS or error code */ row_prebuilt_t* prebuilt,/* in: prebuilt struct in the handle */ dict_index_t* sec_index,/* in: secondary index where rec resides */ - rec_t* rec, /* in: record in a non-clustered index */ + rec_t* rec, /* in: record in a non-clustered index; if + this is a locking read, then rec is not + allowed to be delete-marked, and that would + not make sense either */ que_thr_t* thr, /* in: query thread */ rec_t** out_rec,/* out: clustered record or an old version of it, NULL if the old version did not exist @@ -2285,7 +2309,7 @@ row_sel_get_clust_rec_for_mysql( ulint err; trx_t* trx; char err_buf[1000]; - + *out_rec = NULL; row_build_row_ref_in_tuple(prebuilt->clust_ref, sec_index, rec); @@ -2298,26 +2322,43 @@ row_sel_get_clust_rec_for_mysql( clust_rec = btr_pcur_get_rec(prebuilt->clust_pcur); - if (!page_rec_is_user_rec(clust_rec)) { - ut_print_timestamp(stderr); - fprintf(stderr, - " InnoDB: error clustered record for sec rec not found\n" - "InnoDB: index %s table %s\n", sec_index->name, - sec_index->table->name); + if (btr_pcur_get_low_match(prebuilt->clust_pcur) + < dict_index_get_n_unique(clust_index)) { + + /* In a rare case it is possible that no clust rec is found + for a delete-marked secondary index record: if in row0umod.c + in row_undo_mod_remove_clust_low() we have already removed + the clust rec, while purge is still cleaning and removing + secondary index records associated with earlier versions of + the clustered index record. In that case we know that the + clustered index record did not exist in the read view of + trx. */ + + if (!rec_get_deleted_flag(rec) + || prebuilt->select_lock_type != LOCK_NONE) { - rec_sprintf(err_buf, 900, rec); - fprintf(stderr, "InnoDB: sec index record %s\n", err_buf); + ut_print_timestamp(stderr); + fprintf(stderr, + " InnoDB: error clustered record for sec rec not found\n" + "InnoDB: index %s table %s\n", sec_index->name, + sec_index->table->name); - rec_sprintf(err_buf, 900, clust_rec); - fprintf(stderr, "InnoDB: clust index record %s\n", err_buf); + rec_sprintf(err_buf, 900, rec); + fprintf(stderr, + "InnoDB: sec index record %s\n", err_buf); - trx = thr_get_trx(thr); - trx_print(err_buf, trx); + rec_sprintf(err_buf, 900, clust_rec); + fprintf(stderr, + "InnoDB: clust index record %s\n", err_buf); + + trx = thr_get_trx(thr); + trx_print(err_buf, trx); - fprintf(stderr, - "%s\nInnoDB: Make a detailed bug report and send it\n", - err_buf); - fprintf(stderr, "InnoDB: to mysql@lists.mysql.com\n"); + fprintf(stderr, + "%s\nInnoDB: Make a detailed bug report and send it\n", + err_buf); + fprintf(stderr, "InnoDB: to mysql@lists.mysql.com\n"); + } clust_rec = NULL; @@ -2989,8 +3030,6 @@ rec_loop: /*-------------------------------------------------------------*/ /* PHASE 4: Look for matching records in a loop */ - cons_read_requires_clust_rec = FALSE; - rec = btr_pcur_get_rec(pcur); /* printf("Using index %s cnt %lu ", index->name, cnt); @@ -3145,6 +3184,8 @@ rec_loop: /* We are ready to look at a possible new index entry in the result set: the cursor is now placed on a user record */ + cons_read_requires_clust_rec = FALSE; + if (prebuilt->select_lock_type != LOCK_NONE) { /* Try to place a lock on the index record; note that delete marked records are a special case in a unique search. If there @@ -3170,8 +3211,6 @@ rec_loop: /* This is a non-locking consistent read: if necessary, fetch a previous version of the record */ - cons_read_requires_clust_rec = FALSE; - if (trx->isolation_level == TRX_ISO_READ_UNCOMMITTED) { /* Do nothing: we let a non-locking SELECT read the @@ -3215,7 +3254,7 @@ rec_loop: if (rec_get_deleted_flag(rec) && !cons_read_requires_clust_rec) { - /* The record is delete marked: we can skip it if this is + /* The record is delete-marked: we can skip it if this is not a consistent read which might see an earlier version of a non-clustered index record */ @@ -3324,7 +3363,7 @@ got_row: goto normal_return; next_rec: - /*-------------------------------------------------------------*/ + /*-------------------------------------------------------------*/ /* PHASE 5: Move the cursor to the next index record */ if (mtr_has_extra_clust_latch) { diff --git a/innobase/row/row0vers.c b/innobase/row/row0vers.c index 91aaba40812..5395f5160e4 100644 --- a/innobase/row/row0vers.c +++ b/innobase/row/row0vers.c @@ -59,7 +59,6 @@ row_vers_impl_x_locked_off_kernel( ibool rec_del; ulint err; mtr_t mtr; - char err_buf[1000]; ut_ad(mutex_own(&kernel_mutex)); ut_ad(!rw_lock_own(&(purge_sys->latch), RW_LOCK_SHARED)); @@ -77,22 +76,17 @@ row_vers_impl_x_locked_off_kernel( clust_rec = row_get_clust_rec(BTR_SEARCH_LEAF, rec, index, &clust_index, &mtr); if (!clust_rec) { - rec_sprintf(err_buf, 900, rec); - - ut_print_timestamp(stderr); - fprintf(stderr, -" InnoDB: Error: cannot find the clustered index record\n" -"InnoDB: for a secondary index record in table %s index %s.\n" -"InnoDB: Secondary index record %s.\n" -"InnoDB: The table is probably corrupt. Please run CHECK TABLE on it.\n" -"InnoDB: You can try to repair the table by dump + drop + reimport.\n" -"InnoDB: Send a detailed bug report to mysql@lists.mysql.com.\n", - index->table_name, index->name, err_buf); - mutex_enter(&kernel_mutex); - mtr_commit(&mtr); - - /* We assume there is no lock on the record, though this - is not certain because the table is apparently corrupt */ + /* In a rare case it is possible that no clust rec is found + for a secondary index record: if in row0umod.c + row_undo_mod_remove_clust_low() we have already removed the + clust rec, while purge is still cleaning and removing + secondary index records associated with earlier versions of + the clustered index record. In that case there cannot be + any implicit lock on the secondary index record, because + an active transaction which has modified the secondary index + record has also modified the clustered index record. And in + a rollback we always undo the modifications to secondary index + records before the clustered index record. */ return(NULL); } |