btr0cur.c, row0umod.c:

  Fix bug: if one updated a secondary index column so that its alphabetical value did not change (e.g., abc -> aBc) and rolled back the update, InnoDB failed to return the value in the secondary index to its original value
row0upd.h:
  Correct typing error
sync0sync.ic:
  Remove inadvertently pushed sync debug code
parent c7d940e1
...@@ -1175,7 +1175,8 @@ btr_cur_upd_lock_and_undo( ...@@ -1175,7 +1175,8 @@ btr_cur_upd_lock_and_undo(
if (!(index->type & DICT_CLUSTERED)) { if (!(index->type & DICT_CLUSTERED)) {
/* We do undo logging only when we update a clustered index /* We do undo logging only when we update a clustered index
record */ record */
return(lock_sec_rec_modify_check_and_lock(0, rec, index, thr)); return(lock_sec_rec_modify_check_and_lock(flags, rec, index,
thr));
} }
/* Check if we have to wait for a lock: enqueue an explicit lock /* Check if we have to wait for a lock: enqueue an explicit lock
......
...@@ -292,7 +292,7 @@ row_upd_index_parse( ...@@ -292,7 +292,7 @@ row_upd_index_parse(
/* Update vector field */ /* Update vector field */
struct upd_field_struct{ struct upd_field_struct{
ulint field_no; /* field number in an index, usually ulint field_no; /* field number in an index, usually
the clustered index, but in upadating the clustered index, but in updating
a secondary index record in btr0cur.c a secondary index record in btr0cur.c
this is the position in the secondary this is the position in the secondary
index */ index */
......
...@@ -257,8 +257,6 @@ mutex_enter_func( ...@@ -257,8 +257,6 @@ mutex_enter_func(
mutex->file_name = file_name; mutex->file_name = file_name;
mutex->line = line; mutex->line = line;
mutex->thread_id = os_thread_get_curr_id();
return; /* Succeeded! */ return; /* Succeeded! */
} }
......
...@@ -377,8 +377,14 @@ row_undo_mod_del_mark_or_remove_sec_low( ...@@ -377,8 +377,14 @@ row_undo_mod_del_mark_or_remove_sec_low(
} }
/*************************************************************** /***************************************************************
Delete marks or removes a secondary index entry if found. */ Delete marks or removes a secondary index entry if found.
UNIV_INLINE NOTE that if we updated the fields of a delete-marked secondary index record
so that alphabetically they stayed the same, e.g., 'abc' -> 'aBc', we cannot
return to the original values because we do not know them. But this should
not cause problems because in row0sel.c, in queries we always retrieve the
clustered index record or an earlier version of it, if the secondary index
record through which we do the search is delete-marked. */
static
ulint ulint
row_undo_mod_del_mark_or_remove_sec( row_undo_mod_del_mark_or_remove_sec(
/*================================*/ /*================================*/
...@@ -403,20 +409,31 @@ row_undo_mod_del_mark_or_remove_sec( ...@@ -403,20 +409,31 @@ row_undo_mod_del_mark_or_remove_sec(
} }
/*************************************************************** /***************************************************************
Delete unmarks a secondary index entry which must be found. */ Delete unmarks a secondary index entry which must be found. It might not be
delete-marked at the moment, but it does not harm to unmark it anyway. We also
need to update the fields of the secondary index record if we updated its
fields but alphabetically they stayed the same, e.g., 'abc' -> 'aBc'. */
static static
void ulint
row_undo_mod_del_unmark_sec( row_undo_mod_del_unmark_sec_and_undo_update(
/*========================*/ /*========================================*/
/* out: DB_FAIL or DB_SUCCESS or
DB_OUT_OF_FILE_SPACE */
ulint mode, /* in: search mode: BTR_MODIFY_LEAF or
BTR_MODIFY_TREE */
undo_node_t* node, /* in: row undo node */ undo_node_t* node, /* in: row undo node */
que_thr_t* thr, /* in: query thread */ que_thr_t* thr, /* in: query thread */
dict_index_t* index, /* in: index */ dict_index_t* index, /* in: index */
dtuple_t* entry) /* in: index entry */ dtuple_t* entry) /* in: index entry */
{ {
mem_heap_t* heap;
btr_pcur_t pcur; btr_pcur_t pcur;
btr_cur_t* btr_cur; btr_cur_t* btr_cur;
ulint err; upd_t* update;
rec_t* rec;
ulint err = DB_SUCCESS;
ibool found; ibool found;
big_rec_t* dummy_big_rec;
mtr_t mtr; mtr_t mtr;
char err_buf[1000]; char err_buf[1000];
...@@ -425,8 +442,8 @@ row_undo_mod_del_unmark_sec( ...@@ -425,8 +442,8 @@ row_undo_mod_del_unmark_sec(
log_free_check(); log_free_check();
mtr_start(&mtr); mtr_start(&mtr);
found = row_search_index_entry(index, entry, BTR_MODIFY_LEAF, &pcur, found = row_search_index_entry(index, entry, mode, &pcur, &mtr);
&mtr);
if (!found) { if (!found) {
fprintf(stderr, fprintf(stderr,
"InnoDB: error in sec index entry del undo in\n" "InnoDB: error in sec index entry del undo in\n"
...@@ -443,17 +460,47 @@ row_undo_mod_del_unmark_sec( ...@@ -443,17 +460,47 @@ row_undo_mod_del_unmark_sec(
"%s\nInnoDB: Make a detailed bug report and send it\n", "%s\nInnoDB: Make a detailed bug report and send it\n",
err_buf); err_buf);
fprintf(stderr, "InnoDB: to mysql@lists.mysql.com\n"); fprintf(stderr, "InnoDB: to mysql@lists.mysql.com\n");
} else { } else {
btr_cur = btr_pcur_get_btr_cur(&pcur); btr_cur = btr_pcur_get_btr_cur(&pcur);
rec = btr_cur_get_rec(btr_cur);
err = btr_cur_del_mark_set_sec_rec(BTR_NO_LOCKING_FLAG, err = btr_cur_del_mark_set_sec_rec(BTR_NO_LOCKING_FLAG,
btr_cur, FALSE, thr, &mtr); btr_cur, FALSE, thr, &mtr);
ut_ad(err == DB_SUCCESS); ut_a(err == DB_SUCCESS);
heap = mem_heap_create(100);
update = row_upd_build_sec_rec_difference_binary(index, entry,
rec, heap);
if (upd_get_n_fields(update) == 0) {
/* Do nothing */
} else if (mode == BTR_MODIFY_LEAF) {
/* Try an optimistic updating of the record, keeping
changes within the page */
err = btr_cur_optimistic_update(BTR_KEEP_SYS_FLAG
| BTR_NO_LOCKING_FLAG,
btr_cur, update, 0, thr, &mtr);
if (err == DB_OVERFLOW || err == DB_UNDERFLOW) {
err = DB_FAIL;
}
} else {
ut_a(mode == BTR_MODIFY_TREE);
err = btr_cur_pessimistic_update(BTR_KEEP_SYS_FLAG
| BTR_NO_LOCKING_FLAG,
btr_cur, &dummy_big_rec,
update, 0, thr, &mtr);
}
mem_heap_free(heap);
} }
btr_pcur_close(&pcur); btr_pcur_close(&pcur);
mtr_commit(&mtr); mtr_commit(&mtr);
return(err);
} }
/*************************************************************** /***************************************************************
...@@ -501,13 +548,14 @@ static ...@@ -501,13 +548,14 @@ static
ulint ulint
row_undo_mod_del_mark_sec( row_undo_mod_del_mark_sec(
/*======================*/ /*======================*/
/* out: DB_SUCCESS */ /* out: DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
undo_node_t* node, /* in: row undo node */ undo_node_t* node, /* in: row undo node */
que_thr_t* thr) /* in: query thread */ que_thr_t* thr) /* in: query thread */
{ {
mem_heap_t* heap; mem_heap_t* heap;
dtuple_t* entry; dtuple_t* entry;
dict_index_t* index; dict_index_t* index;
ulint err;
heap = mem_heap_create(1024); heap = mem_heap_create(1024);
...@@ -516,7 +564,21 @@ row_undo_mod_del_mark_sec( ...@@ -516,7 +564,21 @@ row_undo_mod_del_mark_sec(
entry = row_build_index_entry(node->row, index, heap); entry = row_build_index_entry(node->row, index, heap);
row_undo_mod_del_unmark_sec(node, thr, index, entry); err = row_undo_mod_del_unmark_sec_and_undo_update(
BTR_MODIFY_LEAF,
node, thr, index, entry);
if (err == DB_FAIL) {
err = row_undo_mod_del_unmark_sec_and_undo_update(
BTR_MODIFY_TREE,
node, thr, index, entry);
}
if (err != DB_SUCCESS) {
mem_heap_free(heap);
return(err);
}
node->index = dict_table_get_next_index(node->index); node->index = dict_table_get_next_index(node->index);
} }
...@@ -532,7 +594,7 @@ static ...@@ -532,7 +594,7 @@ static
ulint ulint
row_undo_mod_upd_exist_sec( row_undo_mod_upd_exist_sec(
/*=======================*/ /*=======================*/
/* out: DB_SUCCESS or error code */ /* out: DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
undo_node_t* node, /* in: row undo node */ undo_node_t* node, /* in: row undo node */
que_thr_t* thr) /* in: query thread */ que_thr_t* thr) /* in: query thread */
{ {
...@@ -558,22 +620,48 @@ row_undo_mod_upd_exist_sec( ...@@ -558,22 +620,48 @@ row_undo_mod_upd_exist_sec(
/* Build the newest version of the index entry */ /* Build the newest version of the index entry */
entry = row_build_index_entry(node->row, index, heap); entry = row_build_index_entry(node->row, index, heap);
/* NOTE that if we updated the fields of a
delete-marked secondary index record so that
alphabetically they stayed the same, e.g.,
'abc' -> 'aBc', we cannot return to the original
values because we do not know them. But this should
not cause problems because in row0sel.c, in queries
we always retrieve the clustered index record or an
earlier version of it, if the secondary index record
through which we do the search is delete-marked. */
err = row_undo_mod_del_mark_or_remove_sec(node, thr, err = row_undo_mod_del_mark_or_remove_sec(node, thr,
index, entry); index, entry);
if (err != DB_SUCCESS) { if (err != DB_SUCCESS) {
mem_heap_free(heap); mem_heap_free(heap);
return(err); return(err);
} }
/* We may have to update the delete mark in the /* We may have to update the delete mark in the
secondary index record of the previous version of secondary index record of the previous version of
the row */ the row. We also need to update the fields of
the secondary index record if we updated its fields
but alphabetically they stayed the same, e.g.,
'abc' -> 'aBc'. */
row_upd_index_replace_new_col_vals(entry, index, row_upd_index_replace_new_col_vals(entry, index,
node->update, NULL); node->update, NULL);
err = row_undo_mod_del_unmark_sec_and_undo_update(
BTR_MODIFY_LEAF,
node, thr, index, entry);
if (err == DB_FAIL) {
err =
row_undo_mod_del_unmark_sec_and_undo_update(
BTR_MODIFY_TREE,
node, thr, index, entry);
}
row_undo_mod_del_unmark_sec(node, thr, index, entry); if (err != DB_SUCCESS) {
mem_heap_free(heap);
return(err);
}
} }
node->index = dict_table_get_next_index(node->index); node->index = dict_table_get_next_index(node->index);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment