diff options
author | Annamalai Gurusami <annamalai.gurusami@oracle.com> | 2012-09-28 16:02:58 +0530 |
---|---|---|
committer | Annamalai Gurusami <annamalai.gurusami@oracle.com> | 2012-09-28 16:02:58 +0530 |
commit | b59a64e2f3a48b9e584f73fde0962f4876b20f05 (patch) | |
tree | e5845689d8ed6df5de8e4721bc0e31504745a73a /storage | |
parent | faca6ed81e90e953fb7cf6e9756c424a0ecd391d (diff) | |
download | mariadb-git-b59a64e2f3a48b9e584f73fde0962f4876b20f05.tar.gz |
Bug #13249921 ASSERT !BPAGE->FILE_PAGE_WAS_FREED, USUALLY IN
TRANSACTION ROLLBACK
Description: During the rollback operation, a blob page
is removed earlier than desired. Consider following scenario:
1. create table t1(a int primary key,b blob) engine=innodb;
2. insert into t1 values (1,repeat('b',9000));
3. begin;
4. update t1 set b=concat(b,'b');
5. update t1 set a=a+1;
6. insert into t1 values (1,repeat('b',9000));
7. rollback;
The update operation in line 5 produces 2 undo log record. The first
undo record (TRX_UNDO_DEL_MARK_REC) goes to trx->update_undo and the
second undo record (TRX_UNDO_INSERT_REC) goes to trx->insert_undo.
During rollback, they are executed out of order.
When the undo record TRX_UNDO_DEL_MARK_REC is applied/executed,
the blob ownership is also reset. Because of this the blob page
is released earlier than desired. This blob page must have been
freed only as part of applying/executing the undo record
TRX_UNDO_INSERT_REC.
This problem can be avoided by executing the undo records in
order. This patch will make innodb to execute the undo records
in order.
rb://1125 approved by Marko.
Diffstat (limited to 'storage')
-rw-r--r-- | storage/innobase/include/row0undo.h | 9 | ||||
-rw-r--r-- | storage/innobase/row/row0umod.c | 54 | ||||
-rw-r--r-- | storage/innobase/row/row0undo.c | 19 | ||||
-rw-r--r-- | storage/innodb_plugin/ChangeLog | 7 | ||||
-rw-r--r-- | storage/innodb_plugin/include/row0undo.h | 7 | ||||
-rw-r--r-- | storage/innodb_plugin/row/row0umod.c | 53 | ||||
-rw-r--r-- | storage/innodb_plugin/row/row0undo.c | 19 |
7 files changed, 9 insertions, 159 deletions
diff --git a/storage/innobase/include/row0undo.h b/storage/innobase/include/row0undo.h index 0be09ed1822..f7f71a440b5 100644 --- a/storage/innobase/include/row0undo.h +++ b/storage/innobase/include/row0undo.h @@ -78,8 +78,6 @@ struct undo_node_struct{ dulint undo_no;/* undo number of the record */ ulint rec_type;/* undo log record type: TRX_UNDO_INSERT_REC, ... */ - dulint new_roll_ptr; /* roll ptr to restore to clustered index - record */ dulint new_trx_id; /* trx id to restore to clustered index record */ btr_pcur_t pcur; /* persistent cursor used in searching the @@ -101,11 +99,8 @@ struct undo_node_struct{ /* Execution states for an undo node */ #define UNDO_NODE_FETCH_NEXT 1 /* we should fetch the next undo log record */ -#define UNDO_NODE_PREV_VERS 2 /* the roll ptr to previous version of - a row is stored in node, and undo - should be done based on it */ -#define UNDO_NODE_INSERT 3 -#define UNDO_NODE_MODIFY 4 +#define UNDO_NODE_INSERT 2 +#define UNDO_NODE_MODIFY 3 #ifndef UNIV_NONINL diff --git a/storage/innobase/row/row0umod.c b/storage/innobase/row/row0umod.c index a3333fcc536..83288c570cb 100644 --- a/storage/innobase/row/row0umod.c +++ b/storage/innobase/row/row0umod.c @@ -42,37 +42,6 @@ some of its fields were changed. Now, it is possible that the delete marked version has become obsolete at the time the undo is started. */ /*************************************************************** -Checks if also the previous version of the clustered index record was -modified or inserted by the same transaction, and its undo number is such -that it should be undone in the same rollback. */ -UNIV_INLINE -ibool -row_undo_mod_undo_also_prev_vers( -/*=============================*/ - /* out: TRUE if also previous modify or - insert of this row should be undone */ - undo_node_t* node, /* in: row undo node */ - dulint* undo_no)/* out: the undo number */ -{ - trx_undo_rec_t* undo_rec; - trx_t* trx; - - trx = node->trx; - - if (0 != ut_dulint_cmp(node->new_trx_id, trx->id)) { - - *undo_no = ut_dulint_zero; - return(FALSE); - } - - undo_rec = trx_undo_get_undo_rec_low(node->new_roll_ptr, node->heap); - - *undo_no = trx_undo_rec_get_undo_no(undo_rec); - - return(ut_dulint_cmp(trx->roll_limit, *undo_no) <= 0); -} - -/*************************************************************** Undoes a modify in a clustered index record. */ static ulint @@ -202,17 +171,9 @@ row_undo_mod_clust( btr_pcur_t* pcur; mtr_t mtr; ulint err; - ibool success; - ibool more_vers; - dulint new_undo_no; ut_ad(node && thr); - /* Check if also the previous version of the clustered index record - should be undone in this same rollback operation */ - - more_vers = row_undo_mod_undo_also_prev_vers(node, &new_undo_no); - pcur = &(node->pcur); mtr_start(&mtr); @@ -260,20 +221,6 @@ row_undo_mod_clust( trx_undo_rec_release(node->trx, node->undo_no); - if (more_vers && err == DB_SUCCESS) { - - /* Reserve the undo log record to the prior version after - committing &mtr: this is necessary to comply with the latching - order, as &mtr may contain the fsp latch which is lower in - the latch hierarchy than trx->undo_mutex. */ - - success = trx_undo_rec_reserve(node->trx, new_undo_no); - - if (success) { - node->state = UNDO_NODE_PREV_VERS; - } - } - return(err); } @@ -702,7 +649,6 @@ row_undo_mod_parse_undo_rec( trx_undo_update_rec_get_update(ptr, clust_index, type, trx_id, roll_ptr, info_bits, trx, node->heap, &(node->update)); - node->new_roll_ptr = roll_ptr; node->new_trx_id = trx_id; node->cmpl_info = cmpl_info; } diff --git a/storage/innobase/row/row0undo.c b/storage/innobase/row/row0undo.c index 7f31fd0060c..1cb6c722b6f 100644 --- a/storage/innobase/row/row0undo.c +++ b/storage/innobase/row/row0undo.c @@ -242,25 +242,6 @@ row_undo( } else { node->state = UNDO_NODE_MODIFY; } - - } else if (node->state == UNDO_NODE_PREV_VERS) { - - /* Undo should be done to the same clustered index record - again in this same rollback, restoring the previous version */ - - roll_ptr = node->new_roll_ptr; - - node->undo_rec = trx_undo_get_undo_rec_low(roll_ptr, - node->heap); - node->roll_ptr = roll_ptr; - node->undo_no = trx_undo_rec_get_undo_no(node->undo_rec); - - if (trx_undo_roll_ptr_is_insert(roll_ptr)) { - - node->state = UNDO_NODE_INSERT; - } else { - node->state = UNDO_NODE_MODIFY; - } } /* Prevent DROP TABLE etc. while we are rolling back this row. diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index f71ca0b009a..1e5b388643d 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,3 +1,10 @@ +2012-09-28 The InnoDB Team + + * include/row0undo.h, row/row0umod.c, row/row0undo.c: + Fix Bug#13249921 ASSERT !BPAGE->FILE_PAGE_WAS_FREED, USUALLY + IN TRANSACTION ROLLBACK. This patch will ensure that the + undo logs will be applied in proper reverse order. + 2012-09-18 The InnoDB Team * btr/btr0cur.c, handler/ha_innodb.cc, ibuf/ibuf0ibuf.c, diff --git a/storage/innodb_plugin/include/row0undo.h b/storage/innodb_plugin/include/row0undo.h index 6eb4ca448b3..9420d022e3b 100644 --- a/storage/innodb_plugin/include/row0undo.h +++ b/storage/innodb_plugin/include/row0undo.h @@ -87,10 +87,6 @@ that index record. */ enum undo_exec { UNDO_NODE_FETCH_NEXT = 1, /*!< we should fetch the next undo log record */ - UNDO_NODE_PREV_VERS, /*!< the roll ptr to previous - version of a row is stored in - node, and undo should be done - based on it */ UNDO_NODE_INSERT, /*!< undo a fresh insert of a row to a table */ UNDO_NODE_MODIFY /*!< undo a modify operation @@ -108,9 +104,6 @@ struct undo_node_struct{ undo_no_t undo_no;/*!< undo number of the record */ ulint rec_type;/*!< undo log record type: TRX_UNDO_INSERT_REC, ... */ - roll_ptr_t new_roll_ptr; - /*!< roll ptr to restore to clustered index - record */ trx_id_t new_trx_id; /*!< trx id to restore to clustered index record */ btr_pcur_t pcur; /*!< persistent cursor used in searching the diff --git a/storage/innodb_plugin/row/row0umod.c b/storage/innodb_plugin/row/row0umod.c index 5202a498eed..31f7c9f4888 100644 --- a/storage/innodb_plugin/row/row0umod.c +++ b/storage/innodb_plugin/row/row0umod.c @@ -69,36 +69,6 @@ If you make a change in this module make sure that no codepath is introduced where a call to log_free_check() is bypassed. */ /***********************************************************//** -Checks if also the previous version of the clustered index record was -modified or inserted by the same transaction, and its undo number is such -that it should be undone in the same rollback. -@return TRUE if also previous modify or insert of this row should be undone */ -static -ibool -row_undo_mod_undo_also_prev_vers( -/*=============================*/ - undo_node_t* node, /*!< in: row undo node */ - undo_no_t* undo_no)/*!< out: the undo number */ -{ - trx_undo_rec_t* undo_rec; - trx_t* trx; - - trx = node->trx; - - if (0 != ut_dulint_cmp(node->new_trx_id, trx->id)) { - - *undo_no = ut_dulint_zero; - return(FALSE); - } - - undo_rec = trx_undo_get_undo_rec_low(node->new_roll_ptr, node->heap); - - *undo_no = trx_undo_rec_get_undo_no(undo_rec); - - return(ut_dulint_cmp(trx->roll_limit, *undo_no) <= 0); -} - -/***********************************************************//** Undoes a modify in a clustered index record. @return DB_SUCCESS, DB_FAIL, or error code: we may run out of file space */ static @@ -226,19 +196,11 @@ row_undo_mod_clust( btr_pcur_t* pcur; mtr_t mtr; ulint err; - ibool success; - ibool more_vers; - undo_no_t new_undo_no; ut_ad(node && thr); log_free_check(); - /* Check if also the previous version of the clustered index record - should be undone in this same rollback operation */ - - more_vers = row_undo_mod_undo_also_prev_vers(node, &new_undo_no); - pcur = &(node->pcur); mtr_start(&mtr); @@ -286,20 +248,6 @@ row_undo_mod_clust( trx_undo_rec_release(node->trx, node->undo_no); - if (more_vers && err == DB_SUCCESS) { - - /* Reserve the undo log record to the prior version after - committing &mtr: this is necessary to comply with the latching - order, as &mtr may contain the fsp latch which is lower in - the latch hierarchy than trx->undo_mutex. */ - - success = trx_undo_rec_reserve(node->trx, new_undo_no); - - if (success) { - node->state = UNDO_NODE_PREV_VERS; - } - } - return(err); } @@ -799,7 +747,6 @@ row_undo_mod_parse_undo_rec( trx_undo_update_rec_get_update(ptr, clust_index, type, trx_id, roll_ptr, info_bits, trx, node->heap, &(node->update)); - node->new_roll_ptr = roll_ptr; node->new_trx_id = trx_id; node->cmpl_info = cmpl_info; } diff --git a/storage/innodb_plugin/row/row0undo.c b/storage/innodb_plugin/row/row0undo.c index fd28a4f6520..b1606bda5ef 100644 --- a/storage/innodb_plugin/row/row0undo.c +++ b/storage/innodb_plugin/row/row0undo.c @@ -283,25 +283,6 @@ row_undo( } else { node->state = UNDO_NODE_MODIFY; } - - } else if (node->state == UNDO_NODE_PREV_VERS) { - - /* Undo should be done to the same clustered index record - again in this same rollback, restoring the previous version */ - - roll_ptr = node->new_roll_ptr; - - node->undo_rec = trx_undo_get_undo_rec_low(roll_ptr, - node->heap); - node->roll_ptr = roll_ptr; - node->undo_no = trx_undo_rec_get_undo_no(node->undo_rec); - - if (trx_undo_roll_ptr_is_insert(roll_ptr)) { - - node->state = UNDO_NODE_INSERT; - } else { - node->state = UNDO_NODE_MODIFY; - } } /* Prevent DROP TABLE etc. while we are rolling back this row. |