summaryrefslogtreecommitdiff
path: root/innobase
diff options
context:
space:
mode:
authorunknown <heikki@hundin.mysql.fi>2003-06-18 02:18:19 +0300
committerunknown <heikki@hundin.mysql.fi>2003-06-18 02:18:19 +0300
commit1efc292be6c92316b16eef70b289f6e1ab7f2a33 (patch)
tree5a7046b5480dc7cb310b0b430a6a686599037f20 /innobase
parentb518744d16a516c842c4ec0382c8ab44a38aebca (diff)
downloadmariadb-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.c25
-rw-r--r--innobase/row/row0sel.c89
-rw-r--r--innobase/row/row0vers.c28
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);
}