summaryrefslogtreecommitdiff
path: root/storage
diff options
context:
space:
mode:
authorAnnamalai Gurusami <annamalai.gurusami@oracle.com>2012-09-28 16:02:58 +0530
committerAnnamalai Gurusami <annamalai.gurusami@oracle.com>2012-09-28 16:02:58 +0530
commitb59a64e2f3a48b9e584f73fde0962f4876b20f05 (patch)
treee5845689d8ed6df5de8e4721bc0e31504745a73a /storage
parentfaca6ed81e90e953fb7cf6e9756c424a0ecd391d (diff)
downloadmariadb-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.h9
-rw-r--r--storage/innobase/row/row0umod.c54
-rw-r--r--storage/innobase/row/row0undo.c19
-rw-r--r--storage/innodb_plugin/ChangeLog7
-rw-r--r--storage/innodb_plugin/include/row0undo.h7
-rw-r--r--storage/innodb_plugin/row/row0umod.c53
-rw-r--r--storage/innodb_plugin/row/row0undo.c19
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.