Commit e952ee11 authored by Marko Mäkelä's avatar Marko Mäkelä

Bug#59230 assert 0 row_upd_changes_ord_field_binary() in post-crash

trx rollback or purge

This patch does not relax the failing debug assertion during purge.
That will be revisited once we have managed to repeat the assertion failure.

row_upd_changes_ord_field_binary_func(): Renamed from
row_upd_changes_ord_field_binary(). Add the parameter que_thr_t* in
UNIV_DEBUG builds. When the off-page column cannot be retrieved,
assert that the current transaction is a recovered one and that it is
the one that is currently being rolled back.

row_upd_changes_ord_field_binary(): A wrapper macro for
row_upd_changes_ord_field_binary_func() that discards the que_thr_t*
parameter unless UNIV_DEBUG is defined.

row_purge_upd_exist_or_extern_func(): Renamed from
row_purge_upd_exist_or_extern(). Add the parameter que_thr_t* in
UNIV_DEBUG builds.

row_purge_upd_exist_or_extern(): A wrapper macro for
row_purge_upd_exist_or_extern_func() that discards the que_thr_t*
parameter unless UNIV_DEBUG is defined.

Make trx_roll_crash_recv_trx const. If there were a 'do not
dereference' attribute, it would be appropriate as well.

rb://588 approved by Jimmy Yang
parent 7751e38c
2011-01-31 The InnoDB Team
* btr/btr0cur.c, include/row0upd.h,
row/row0purge.c, row/row0umod.c, row/row0upd.c:
Bug#59230 assert 0 row_upd_changes_ord_field_binary()
in post-crash rollback or purge
2011-01-27 The InnoDB Team 2011-01-27 The InnoDB Team
* btr/btr0cur.c: * btr/btr0cur.c:
......
...@@ -1768,8 +1768,8 @@ btr_cur_update_in_place( ...@@ -1768,8 +1768,8 @@ btr_cur_update_in_place(
NOT call it if index is secondary */ NOT call it if index is secondary */
if (!dict_index_is_clust(index) if (!dict_index_is_clust(index)
|| row_upd_changes_ord_field_binary(NULL, NULL, || row_upd_changes_ord_field_binary(index, update, thr,
index, update)) { NULL, NULL)) {
/* Remove possible hash index pointer to this record */ /* Remove possible hash index pointer to this record */
btr_search_update_hash_on_delete(cursor); btr_search_update_hash_on_delete(cursor);
......
...@@ -280,19 +280,29 @@ NOTE: we compare the fields as binary strings! ...@@ -280,19 +280,29 @@ NOTE: we compare the fields as binary strings!
@return TRUE if update vector changes an ordering field in the index record */ @return TRUE if update vector changes an ordering field in the index record */
UNIV_INTERN UNIV_INTERN
ibool ibool
row_upd_changes_ord_field_binary( row_upd_changes_ord_field_binary_func(
/*=============================*/ /*==================================*/
dict_index_t* index, /*!< in: index of the record */
const upd_t* update, /*!< in: update vector for the row; NOTE: the
field numbers in this MUST be clustered index
positions! */
#ifdef UNIV_DEBUG
const que_thr_t*thr, /*!< in: query thread */
#endif /* UNIV_DEBUG */
const dtuple_t* row, /*!< in: old value of row, or NULL if the const dtuple_t* row, /*!< in: old value of row, or NULL if the
row and the data values in update are not row and the data values in update are not
known when this function is called, e.g., at known when this function is called, e.g., at
compile time */ compile time */
const row_ext_t*ext, /*!< NULL, or prefixes of the externally const row_ext_t*ext) /*!< NULL, or prefixes of the externally
stored columns in the old row */ stored columns in the old row */
dict_index_t* index, /*!< in: index of the record */ __attribute__((nonnull(1,2), warn_unused_result));
const upd_t* update) /*!< in: update vector for the row; NOTE: the #ifdef UNIV_DEBUG
field numbers in this MUST be clustered index # define row_upd_changes_ord_field_binary(index,update,thr,row,ext) \
positions! */ row_upd_changes_ord_field_binary_func(index,update,thr,row,ext)
__attribute__((nonnull(3,4), warn_unused_result)); #else /* UNIV_DEBUG */
# define row_upd_changes_ord_field_binary(index,update,thr,row,ext) \
row_upd_changes_ord_field_binary_func(index,update,row,ext)
#endif /* UNIV_DEBUG */
/***********************************************************//** /***********************************************************//**
Checks if an update vector changes an ordering field of an index record. Checks if an update vector changes an ordering field of an index record.
This function is fast if the update vector is short or the number of ordering This function is fast if the update vector is short or the number of ordering
......
...@@ -387,8 +387,11 @@ Purges an update of an existing record. Also purges an update of a delete ...@@ -387,8 +387,11 @@ Purges an update of an existing record. Also purges an update of a delete
marked record if that record contained an externally stored field. */ marked record if that record contained an externally stored field. */
static static
void void
row_purge_upd_exist_or_extern( row_purge_upd_exist_or_extern_func(
/*==========================*/ /*===============================*/
#ifdef UNIV_DEBUG
const que_thr_t*thr, /*!< in: query thread */
#endif /* UNIV_DEBUG */
purge_node_t* node) /*!< in: row purge node */ purge_node_t* node) /*!< in: row purge node */
{ {
mem_heap_t* heap; mem_heap_t* heap;
...@@ -413,8 +416,8 @@ row_purge_upd_exist_or_extern( ...@@ -413,8 +416,8 @@ row_purge_upd_exist_or_extern(
while (node->index != NULL) { while (node->index != NULL) {
index = node->index; index = node->index;
if (row_upd_changes_ord_field_binary(NULL, NULL, node->index, if (row_upd_changes_ord_field_binary(node->index, node->update,
node->update)) { thr, NULL, NULL)) {
/* Build the older version of the index entry */ /* Build the older version of the index entry */
entry = row_build_index_entry(node->row, NULL, entry = row_build_index_entry(node->row, NULL,
index, heap); index, heap);
...@@ -496,6 +499,14 @@ skip_secondaries: ...@@ -496,6 +499,14 @@ skip_secondaries:
} }
} }
#ifdef UNIV_DEBUG
# define row_purge_upd_exist_or_extern(thr,node) \
row_purge_upd_exist_or_extern_func(thr,node)
#else /* UNIV_DEBUG */
# define row_purge_upd_exist_or_extern(thr,node) \
row_purge_upd_exist_or_extern_func(node)
#endif /* UNIV_DEBUG */
/***********************************************************//** /***********************************************************//**
Parses the row reference and other info in a modify undo log record. Parses the row reference and other info in a modify undo log record.
@return TRUE if purge operation required: NOTE that then the CALLER @return TRUE if purge operation required: NOTE that then the CALLER
...@@ -654,7 +665,7 @@ row_purge( ...@@ -654,7 +665,7 @@ row_purge(
} else if (updated_extern } else if (updated_extern
|| node->rec_type == TRX_UNDO_UPD_EXIST_REC) { || node->rec_type == TRX_UNDO_UPD_EXIST_REC) {
row_purge_upd_exist_or_extern(node); row_purge_upd_exist_or_extern(thr, node);
} }
if (node->found_clust) { if (node->found_clust) {
......
...@@ -668,8 +668,9 @@ row_undo_mod_upd_exist_sec( ...@@ -668,8 +668,9 @@ row_undo_mod_upd_exist_sec(
while (node->index != NULL) { while (node->index != NULL) {
index = node->index; index = node->index;
if (row_upd_changes_ord_field_binary( if (row_upd_changes_ord_field_binary(node->index, node->update,
node->row, node->ext, node->index, node->update)) { thr,
node->row, node->ext)) {
/* Build the newest version of the index entry */ /* Build the newest version of the index entry */
entry = row_build_index_entry(node->row, node->ext, entry = row_build_index_entry(node->row, node->ext,
......
...@@ -1192,25 +1192,31 @@ NOTE: we compare the fields as binary strings! ...@@ -1192,25 +1192,31 @@ NOTE: we compare the fields as binary strings!
@return TRUE if update vector changes an ordering field in the index record */ @return TRUE if update vector changes an ordering field in the index record */
UNIV_INTERN UNIV_INTERN
ibool ibool
row_upd_changes_ord_field_binary( row_upd_changes_ord_field_binary_func(
/*=============================*/ /*==================================*/
dict_index_t* index, /*!< in: index of the record */
const upd_t* update, /*!< in: update vector for the row; NOTE: the
field numbers in this MUST be clustered index
positions! */
#ifdef UNIV_DEBUG
const que_thr_t*thr, /*!< in: query thread */
#endif /* UNIV_DEBUG */
const dtuple_t* row, /*!< in: old value of row, or NULL if the const dtuple_t* row, /*!< in: old value of row, or NULL if the
row and the data values in update are not row and the data values in update are not
known when this function is called, e.g., at known when this function is called, e.g., at
compile time */ compile time */
const row_ext_t*ext, /*!< NULL, or prefixes of the externally const row_ext_t*ext) /*!< NULL, or prefixes of the externally
stored columns in the old row */ stored columns in the old row */
dict_index_t* index, /*!< in: index of the record */
const upd_t* update) /*!< in: update vector for the row; NOTE: the
field numbers in this MUST be clustered index
positions! */
{ {
ulint n_unique; ulint n_unique;
ulint i; ulint i;
const dict_index_t* clust_index; const dict_index_t* clust_index;
ut_ad(update);
ut_ad(index); ut_ad(index);
ut_ad(update);
ut_ad(thr);
ut_ad(thr->graph);
ut_ad(thr->graph->trx);
n_unique = dict_index_get_n_unique(index); n_unique = dict_index_get_n_unique(index);
...@@ -1263,9 +1269,14 @@ row_upd_changes_ord_field_binary( ...@@ -1263,9 +1269,14 @@ row_upd_changes_ord_field_binary(
if (UNIV_LIKELY_NULL(buf)) { if (UNIV_LIKELY_NULL(buf)) {
if (UNIV_UNLIKELY(buf == field_ref_zero)) { if (UNIV_UNLIKELY(buf == field_ref_zero)) {
/* This should never happen, but /* The externally stored field
we try to fail safe here. */ was not written yet. This
ut_ad(0); record should only be seen by
recv_recovery_rollback_active(),
when the server had crashed before
storing the field. */
ut_ad(thr->graph->trx->is_recovered);
ut_ad(trx_is_recv(thr->graph->trx));
return(TRUE); return(TRUE);
} }
...@@ -1612,8 +1623,8 @@ row_upd_sec_step( ...@@ -1612,8 +1623,8 @@ row_upd_sec_step(
ut_ad(!dict_index_is_clust(node->index)); ut_ad(!dict_index_is_clust(node->index));
if (node->state == UPD_NODE_UPDATE_ALL_SEC if (node->state == UPD_NODE_UPDATE_ALL_SEC
|| row_upd_changes_ord_field_binary(node->row, node->ext, || row_upd_changes_ord_field_binary(node->index, node->update,
node->index, node->update)) { thr, node->row, node->ext)) {
return(row_upd_sec_index_entry(node, thr)); return(row_upd_sec_index_entry(node, thr));
} }
...@@ -2140,8 +2151,8 @@ exit_func: ...@@ -2140,8 +2151,8 @@ exit_func:
row_upd_store_row(node); row_upd_store_row(node);
if (row_upd_changes_ord_field_binary(node->row, node->ext, index, if (row_upd_changes_ord_field_binary(index, node->update, thr,
node->update)) { node->row, node->ext)) {
/* Update causes an ordering field (ordering fields within /* Update causes an ordering field (ordering fields within
the B-tree) of the clustered index record to change: perform the B-tree) of the clustered index record to change: perform
......
...@@ -48,8 +48,8 @@ Created 3/26/1996 Heikki Tuuri ...@@ -48,8 +48,8 @@ Created 3/26/1996 Heikki Tuuri
rollback */ rollback */
#define TRX_ROLL_TRUNC_THRESHOLD 1 #define TRX_ROLL_TRUNC_THRESHOLD 1
/** In crash recovery, the current trx to be rolled back */ /** In crash recovery, the current trx to be rolled back; NULL otherwise */
static trx_t* trx_roll_crash_recv_trx = NULL; static const trx_t* trx_roll_crash_recv_trx = NULL;
/** In crash recovery we set this to the undo n:o of the current trx to be /** In crash recovery we set this to the undo n:o of the current trx to be
rolled back. Then we can print how many % the rollback has progressed. */ rolled back. Then we can print how many % the rollback has progressed. */
......
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