summaryrefslogtreecommitdiff
path: root/innobase/trx
diff options
context:
space:
mode:
authorunknown <jan@hundin.mysql.fi>2004-11-30 11:45:02 +0200
committerunknown <jan@hundin.mysql.fi>2004-11-30 11:45:02 +0200
commitdf0e057a52db9f085c42ec593f3000da4afdbbd7 (patch)
treecb2f2ad9f5ccc63eec024ffada123df6cf2e74ba /innobase/trx
parentf4110834a374dc647f2cba4d7bceaa88dc9d66e9 (diff)
downloadmariadb-git-df0e057a52db9f085c42ec593f3000da4afdbbd7.tar.gz
Added support for X/Open XA prepare, recover, commit and rollback.
innobase/include/trx0roll.h: Changed prototype of the function trx_rollback_or_clean_all_without_sess because this function is executed in a background thread. innobase/include/trx0trx.h: Added support for X/Open XA prepare, recover and search by X/Open XA XID. innobase/include/trx0undo.h: Added support for X/Open XA prepare and recover. We need to store X/Open XA XID to the undo log header for recovery. innobase/log/log0recv.c: Create a thread to run trx_rollback_or_clean_all_without_sess function to rollback the uncommitted transactions which have no user session. innobase/row/row0ins.c: Remove unnecessary variables. innobase/trx/trx0roll.c: Changed so that trx_rollback_or_clean_all_without_sess is executed in a background thread. We should also leave all prepared transactions active to wait for commit or abort from MySQL. innobase/trx/trx0sys.c: Only those rows which belong to the active transaction in crash recovery are undone. innobase/trx/trx0trx.c: Added support for X/Open XA prepare and recover. We need to store X/Open XA XID to trx structure and left prepared transactions to wait for a commit or abort from MySQL. This requires also that we add TRX_PREPARED state to the transaction and TRX_UNDO_PREPARED state for undo logs. innobase/trx/trx0undo.c: Added support for X/Open XA prepare and recover. We need to store X/Open XA XID to undo log header for recovery of distributed transactions. sql/ha_innodb.h: Added prototypes for X/Open XA prepare, recover, commit and rollback. sql/handler.h: Added definition for X/Open XA XID structure.
Diffstat (limited to 'innobase/trx')
-rw-r--r--innobase/trx/trx0roll.c24
-rw-r--r--innobase/trx/trx0sys.c6
-rw-r--r--innobase/trx/trx0trx.c272
-rw-r--r--innobase/trx/trx0undo.c202
4 files changed, 470 insertions, 34 deletions
diff --git a/innobase/trx/trx0roll.c b/innobase/trx/trx0roll.c
index eb7c7f43f03..db5e16c7778 100644
--- a/innobase/trx/trx0roll.c
+++ b/innobase/trx/trx0roll.c
@@ -331,10 +331,11 @@ trx_savept_take(
/***********************************************************************
Rollback or clean up transactions which have no user session. If the
transaction already was committed, then we clean up a possible insert
-undo log. If the transaction was not yet committed, then we roll it back. */
+undo log. If the transaction was not yet committed, then we roll it back.
+Note: this is done in a background thread */
-void
-trx_rollback_or_clean_all_without_sess(void)
+void *
+trx_rollback_or_clean_all_without_sess(void *i)
/*========================================*/
{
mem_heap_t* heap;
@@ -362,7 +363,7 @@ trx_rollback_or_clean_all_without_sess(void)
fprintf(stderr,
"InnoDB: Starting rollback of uncommitted transactions\n");
} else {
- return;
+ os_thread_exit(i);
}
loop:
heap = mem_heap_create(512);
@@ -371,9 +372,15 @@ loop:
trx = UT_LIST_GET_FIRST(trx_sys->trx_list);
- while (trx && (trx->sess || (trx->conc_state == TRX_NOT_STARTED))) {
+ while (trx) {
- trx = UT_LIST_GET_NEXT(trx_list, trx);
+ if ((trx->sess || (trx->conc_state == TRX_NOT_STARTED))) {
+ trx = UT_LIST_GET_NEXT(trx_list, trx);
+ } else if (trx->conc_state == TRX_PREPARED) {
+ trx->sess = trx_dummy_sess;
+ } else {
+ break;
+ }
}
mutex_exit(&kernel_mutex);
@@ -384,10 +391,11 @@ loop:
mem_heap_free(heap);
- return;
+ os_thread_exit(i);
}
trx->sess = trx_dummy_sess;
+
if (trx->conc_state == TRX_COMMITTED_IN_MEMORY) {
fprintf(stderr, "InnoDB: Cleaning up trx with id %lu %lu\n",
@@ -486,6 +494,8 @@ loop:
mem_heap_free(heap);
goto loop;
+
+ os_thread_exit(i); /* not reached */
}
/***********************************************************************
diff --git a/innobase/trx/trx0sys.c b/innobase/trx/trx0sys.c
index 54bd5be01a1..35e18064329 100644
--- a/innobase/trx/trx0sys.c
+++ b/innobase/trx/trx0sys.c
@@ -887,8 +887,12 @@ trx_sys_init_at_db_start(void)
trx = UT_LIST_GET_FIRST(trx_sys->trx_list);
for (;;) {
- rows_to_undo +=
+
+ if ( trx->conc_state != TRX_PREPARED) {
+ rows_to_undo +=
ut_conv_dulint_to_longlong(trx->undo_no);
+ }
+
trx = UT_LIST_GET_NEXT(trx_list, trx);
if (!trx) {
diff --git a/innobase/trx/trx0trx.c b/innobase/trx/trx0trx.c
index f7497ac4090..d7daecdb5b7 100644
--- a/innobase/trx/trx0trx.c
+++ b/innobase/trx/trx0trx.c
@@ -24,6 +24,7 @@ Created 3/26/1996 Heikki Tuuri
#include "thr0loc.h"
#include "btr0sea.h"
#include "os0proc.h"
+#include "xa.h"
/* Copy of the prototype for innobase_mysql_print_thd: this
copy MUST be equal to the one in mysql/sql/ha_innodb.cc ! */
@@ -156,6 +157,10 @@ trx_create(
trx->read_view_heap = mem_heap_create(256);
trx->read_view = NULL;
+ /* Set X/Open XA transaction identification to NULL */
+ memset(&trx->xid,0,sizeof(trx->xid));
+ trx->xid.formatID = -1;
+
return(trx);
}
@@ -408,13 +413,22 @@ trx_lists_init_at_db_start(void)
trx = trx_create(NULL);
trx->id = undo->trx_id;
-
+ trx->xid = undo->xid;
trx->insert_undo = undo;
trx->rseg = rseg;
if (undo->state != TRX_UNDO_ACTIVE) {
- trx->conc_state = TRX_COMMITTED_IN_MEMORY;
+ /* Prepared transactions are left in
+ the prepared state waiting for a
+ commit or abort decision from MySQL */
+
+ if (undo->state == TRX_UNDO_PREPARED) {
+ trx->conc_state = TRX_PREPARED;
+ } else {
+ trx->conc_state =
+ TRX_COMMITTED_IN_MEMORY;
+ }
/* We give a dummy value for the trx no;
this should have no relevance since purge
@@ -457,10 +471,22 @@ trx_lists_init_at_db_start(void)
trx = trx_create(NULL);
trx->id = undo->trx_id;
+ trx->xid = undo->xid;
if (undo->state != TRX_UNDO_ACTIVE) {
- trx->conc_state =
- TRX_COMMITTED_IN_MEMORY;
+
+ /* Prepared transactions are left in
+ the prepared state waiting for a
+ commit or abort decision from MySQL */
+
+ if (undo->state == TRX_UNDO_PREPARED) {
+ trx->conc_state =
+ TRX_PREPARED;
+ } else {
+ trx->conc_state =
+ TRX_COMMITTED_IN_MEMORY;
+ }
+
/* We give a dummy value for the trx
number */
@@ -726,7 +752,8 @@ trx_commit_off_kernel(
mutex_enter(&kernel_mutex);
}
- ut_ad(trx->conc_state == TRX_ACTIVE);
+ ut_ad(trx->conc_state == TRX_ACTIVE || trx->conc_state == TRX_PREPARED);
+
#ifdef UNIV_SYNC_DEBUG
ut_ad(mutex_own(&kernel_mutex));
#endif /* UNIV_SYNC_DEBUG */
@@ -1667,3 +1694,238 @@ trx_print(
innobase_mysql_print_thd(f, trx->mysql_thd);
}
}
+
+/********************************************************************
+Prepares a transaction. */
+
+void
+trx_prepare_off_kernel(
+/*==================*/
+ trx_t* trx) /* in: transaction */
+{
+ page_t* update_hdr_page;
+ dulint lsn;
+ trx_rseg_t* rseg;
+ trx_undo_t* undo;
+ ibool must_flush_log = FALSE;
+ mtr_t mtr;
+
+#ifdef UNIV_SYNC_DEBUG
+ ut_ad(mutex_own(&kernel_mutex));
+#endif /* UNIV_SYNC_DEBUG */
+
+ rseg = trx->rseg;
+
+ if (trx->insert_undo != NULL || trx->update_undo != NULL) {
+
+ mutex_exit(&kernel_mutex);
+
+ mtr_start(&mtr);
+
+ must_flush_log = TRUE;
+
+ /* Change the undo log segment states from TRX_UNDO_ACTIVE
+ to some other state: these modifications to the file data
+ structure define the transaction as prepared in the file
+ based world, at the serialization point of the log sequence
+ number lsn obtained below. */
+
+ mutex_enter(&(rseg->mutex));
+
+ if (trx->insert_undo != NULL) {
+ trx_undo_set_state_at_prepare(trx, trx->insert_undo,
+ &mtr);
+ }
+
+ undo = trx->update_undo;
+
+ if (undo) {
+ mutex_enter(&kernel_mutex);
+ trx->no = trx_sys_get_new_trx_no();
+
+ mutex_exit(&kernel_mutex);
+
+ /* It is not necessary to obtain trx->undo_mutex here
+ because only a single OS thread is allowed to do the
+ transaction prepare for this transaction. */
+
+ update_hdr_page = trx_undo_set_state_at_prepare(trx, undo, &mtr);
+ }
+
+ mutex_exit(&(rseg->mutex));
+
+ /*--------------*/
+ mtr_commit(&mtr);
+ /*--------------*/
+ lsn = mtr.end_lsn;
+
+ mutex_enter(&kernel_mutex);
+ }
+
+#ifdef UNIV_SYNC_DEBUG
+ ut_ad(mutex_own(&kernel_mutex));
+#endif /* UNIV_SYNC_DEBUG */
+
+ /*--------------------------------------*/
+ trx->conc_state = TRX_PREPARED;
+ /*--------------------------------------*/
+
+ if (trx->read_view) {
+ read_view_close(trx->read_view);
+
+ mem_heap_empty(trx->read_view_heap);
+ trx->read_view = NULL;
+ }
+
+ if (must_flush_log) {
+
+ mutex_exit(&kernel_mutex);
+
+ if (trx->insert_undo != NULL) {
+
+ trx_undo_insert_cleanup(trx);
+ }
+
+ /* Write the log to the log files AND flush them to disk */
+
+ /*-------------------------------------*/
+
+ log_write_up_to(lsn, LOG_WAIT_ONE_GROUP, TRUE);
+
+ /*-------------------------------------*/
+
+ mutex_enter(&kernel_mutex);
+ }
+}
+
+/**************************************************************************
+Does the transaction prepare for MySQL. */
+
+ulint
+trx_prepare_for_mysql(
+/*=================*/
+ /* out: 0 or error number */
+ trx_t* trx) /* in: trx handle */
+{
+ /* Because we do not do the prepare by sending an Innobase
+ sig to the transaction, we must here make sure that trx has been
+ started. */
+
+ ut_a(trx);
+
+ trx->op_info = "preparing";
+
+ trx_start_if_not_started(trx);
+
+ mutex_enter(&kernel_mutex);
+
+ trx_prepare_off_kernel(trx);
+
+ mutex_exit(&kernel_mutex);
+
+ trx->op_info = "";
+
+ return(0);
+}
+
+/**************************************************************************
+This function is used to find number of prepared transactions and
+their transaction objects for a recovery. */
+
+int
+trx_recover_for_mysql(
+/*==================*/
+ /* out: number of prepared transactions
+ stored in xid_list */
+ XID* xid_list, /* in/out: prepared transactions */
+ uint len) /* in: number of slots in xid_list */
+{
+ trx_t* trx;
+ int num_of_transactions = 0;
+
+ ut_ad(xid_list);
+ ut_ad(len);
+
+ fprintf(stderr,
+ "InnoDB: Starting recovery for XA transactions...\n");
+
+
+ /* We should set those transactions which are in
+ the prepared state to the xid_list */
+
+ mutex_enter(&kernel_mutex);
+
+ trx = UT_LIST_GET_FIRST(trx_sys->trx_list);
+
+ while (trx) {
+ if (trx->conc_state == TRX_PREPARED) {
+ xid_list[num_of_transactions] = trx->xid;
+ num_of_transactions++;
+
+ if ( (uint)num_of_transactions == len ) {
+ break;
+ }
+ }
+
+ trx = UT_LIST_GET_NEXT(trx_list, trx);
+ }
+
+ mutex_exit(&kernel_mutex);
+
+ fprintf(stderr,
+ "InnoDB: %d transactions in prepare state after recovery\n",
+ num_of_transactions);
+
+ return (num_of_transactions);
+}
+
+/***********************************************************************
+This function is used to find one X/Open XA distributed transaction
+which is in the prepared state */
+
+trx_t *
+trx_get_trx_by_xid(
+/*===============*/
+ /* out: trx or NULL */
+ XID* xid) /* in: X/Open XA Transaction Idenfication */
+{
+ trx_t* trx;
+
+ if (xid == NULL) {
+ return (NULL);
+ }
+
+ mutex_enter(&kernel_mutex);
+
+ trx = UT_LIST_GET_FIRST(trx_sys->trx_list);
+
+ while (trx) {
+ /* Compare two X/Open XA transaction id's: their
+ length should be the same and binary comparison
+ of gtrid_lenght+bqual_length bytes should be
+ the same */
+
+ if (xid->gtrid_length == trx->xid.gtrid_length &&
+ xid->bqual_length == trx->xid.bqual_length &&
+ memcmp(xid, &trx->xid,
+ xid->gtrid_length +
+ xid->bqual_length) == 0) {
+ break;
+ }
+
+ trx = UT_LIST_GET_NEXT(trx_list, trx);
+ }
+
+ mutex_exit(&kernel_mutex);
+
+ if (trx) {
+ if (trx->conc_state != TRX_PREPARED) {
+ return(NULL);
+ }
+
+ return(trx);
+ } else {
+ return(NULL);
+ }
+}
+
diff --git a/innobase/trx/trx0undo.c b/innobase/trx/trx0undo.c
index c1edc223cbc..8c911b29d26 100644
--- a/innobase/trx/trx0undo.c
+++ b/innobase/trx/trx0undo.c
@@ -19,6 +19,7 @@ Created 3/26/1996 Heikki Tuuri
#include "srv0srv.h"
#include "trx0rec.h"
#include "trx0purge.h"
+#include "xa.h"
/* How should the old versions in the history list be managed?
----------------------------------------------------------
@@ -97,6 +98,7 @@ trx_undo_mem_create(
TRX_UNDO_UPDATE */
dulint trx_id, /* in: id of the trx for which the undo log
is created */
+ XID* xid, /* in: X/Open XA transaction identification*/
ulint page_no,/* in: undo log header page number */
ulint offset); /* in: undo log header byte offset on page */
/*******************************************************************
@@ -109,6 +111,7 @@ trx_undo_insert_header_reuse(
page_t* undo_page, /* in: insert undo log segment header page,
x-latched */
dulint trx_id, /* in: transaction id */
+ XID* xid, /* in: X/Open XA transaction identification*/
mtr_t* mtr); /* in: mtr */
/**************************************************************************
If an update undo log can be discarded immediately, this function frees the
@@ -484,6 +487,7 @@ trx_undo_header_create(
TRX_UNDO_LOG_HDR_SIZE bytes free space
on it */
dulint trx_id, /* in: transaction id */
+ XID* xid, /* in: X/Open XA XID */
mtr_t* mtr) /* in: mtr */
{
trx_upagef_t* page_hdr;
@@ -530,11 +534,24 @@ trx_undo_header_create(
mach_write_to_8(log_hdr + TRX_UNDO_TRX_ID, trx_id);
mach_write_to_2(log_hdr + TRX_UNDO_LOG_START, new_free);
- mach_write_to_2(log_hdr + TRX_UNDO_DICT_OPERATION, FALSE);
-
+ /* If X/Open XID exits in the log header we store a
+ flag of it in upper byte of dict operation flag. */
+
+ if ( xid == NULL || xid->formatID == -1) {
+ mach_write_to_2(log_hdr + TRX_UNDO_DICT_OPERATION, FALSE);
+ } else {
+ mach_write_to_2(log_hdr + TRX_UNDO_DICT_OPERATION,
+ TRX_UNDO_XA_EXISTS|FALSE);
+ }
+
mach_write_to_2(log_hdr + TRX_UNDO_NEXT_LOG, 0);
mach_write_to_2(log_hdr + TRX_UNDO_PREV_LOG, prev_log);
-
+
+ /* Write X/Open XA transaction identification if exists */
+ if ( xid && xid->formatID != -1) {
+ trx_undo_write_xid(log_hdr, xid);
+ }
+
trx_undo_header_create_log(undo_page, trx_id, mtr);
return(free);
@@ -569,6 +586,11 @@ trx_undo_parse_page_header(
mtr_t* mtr) /* in: mtr or NULL */
{
dulint trx_id;
+ XID xid;
+
+ /* Set X/Open XA transaction identification to NULL */
+ memset(&xid, 0, sizeof(xid));
+ xid.formatID = -1;
ptr = mach_dulint_parse_compressed(ptr, end_ptr, &trx_id);
@@ -579,10 +601,10 @@ trx_undo_parse_page_header(
if (page) {
if (type == MLOG_UNDO_HDR_CREATE) {
- trx_undo_header_create(page, trx_id, mtr);
+ trx_undo_header_create(page, trx_id, &xid, mtr);
} else {
ut_ad(type == MLOG_UNDO_HDR_REUSE);
- trx_undo_insert_header_reuse(page, trx_id, mtr);
+ trx_undo_insert_header_reuse(page, trx_id, &xid, mtr);
}
}
@@ -599,6 +621,7 @@ trx_undo_insert_header_reuse(
page_t* undo_page, /* in: insert undo log segment header page,
x-latched */
dulint trx_id, /* in: transaction id */
+ XID* xid, /* in: X/Open XA transaction identification */
mtr_t* mtr) /* in: mtr */
{
trx_upagef_t* page_hdr;
@@ -636,7 +659,17 @@ trx_undo_insert_header_reuse(
mach_write_to_8(log_hdr + TRX_UNDO_TRX_ID, trx_id);
mach_write_to_2(log_hdr + TRX_UNDO_LOG_START, new_free);
- mach_write_to_2(log_hdr + TRX_UNDO_DICT_OPERATION, FALSE);
+ /* If X/Open XID exits in the log header we store a
+ flag of it in upper byte of dict operation flag and
+ then write the xid. */
+
+ if ( xid && xid->formatID != -1) {
+ mach_write_to_2(log_hdr + TRX_UNDO_DICT_OPERATION,
+ TRX_UNDO_XA_EXISTS|FALSE);
+ trx_undo_write_xid(log_hdr, xid);
+ } else {
+ mach_write_to_2(log_hdr + TRX_UNDO_DICT_OPERATION, FALSE);
+ }
trx_undo_insert_header_reuse_log(undo_page, trx_id, mtr);
@@ -718,6 +751,52 @@ trx_undo_discard_latest_update_undo(
}
/************************************************************************
+Write X/Open XA Transaction Identification (XID) to undo log header */
+
+void
+trx_undo_write_xid(
+/*===============*/
+ trx_ulogf_t* log_hdr,/* in: undo log header */
+ XID* xid) /* in: X/Open XA Transaction Identification */
+{
+ ulint i;
+
+ mach_write_to_4(log_hdr + TRX_UNDO_XA_FORMAT, xid->formatID);
+
+ mach_write_to_4(log_hdr + TRX_UNDO_XA_TRID_LEN, xid->gtrid_length);
+
+ mach_write_to_4(log_hdr + TRX_UNDO_XA_BQUAL_LEN, xid->bqual_length);
+
+ for(i=0; i < XIDDATASIZE; i++) {
+ mach_write_to_1(log_hdr + TRX_UNDO_XA_XID + i,
+ (ulint)(xid->data[i]));
+ }
+}
+
+/************************************************************************
+Read X/Open XA Transaction Identification (XID) from undo log header */
+
+void
+trx_undo_read_xid(
+/*==============*/
+ trx_ulogf_t* log_hdr,/* in: undo log header */
+ XID* xid) /* out: X/Open XA Transaction Identification */
+{
+ ulint i;
+
+ xid->formatID = mach_read_from_4(log_hdr + TRX_UNDO_XA_FORMAT);
+
+ xid->gtrid_length = mach_read_from_4(log_hdr + TRX_UNDO_XA_TRID_LEN);
+
+ xid->bqual_length = mach_read_from_4(log_hdr + TRX_UNDO_XA_BQUAL_LEN);
+
+ for(i=0; i < XIDDATASIZE; i++) {
+ xid->data[i] = (char)mach_read_from_1(log_hdr +
+ TRX_UNDO_XA_XID +i);
+ }
+}
+
+/************************************************************************
Tries to add a page to the undo log segment where the undo log is placed. */
ulint
@@ -1123,6 +1202,8 @@ trx_undo_mem_create_at_db_start(
fil_addr_t last_addr;
page_t* last_page;
trx_undo_rec_t* rec;
+ XID xid;
+ ulint dict_op;
if (id >= TRX_RSEG_N_SLOTS) {
fprintf(stderr,
@@ -1145,15 +1226,29 @@ trx_undo_mem_create_at_db_start(
undo_header = undo_page + offset;
trx_id = mtr_read_dulint(undo_header + TRX_UNDO_TRX_ID, mtr);
+
+ dict_op = mtr_read_ulint(
+ undo_header + TRX_UNDO_DICT_OPERATION,
+ MLOG_2BYTES, mtr);
+
+ /* Read X/Open XA transaction identification if exists or
+ set it to NULL. */
+
+ memset(&xid, 0, sizeof(xid));
+ xid.formatID = -1;
+
+ if (dict_op & TRX_UNDO_XA_EXISTS) {
+ trx_undo_read_xid(undo_header, &xid);
+ }
+
mutex_enter(&(rseg->mutex));
- undo = trx_undo_mem_create(rseg, id, type, trx_id, page_no, offset);
+ undo = trx_undo_mem_create(rseg, id, type, trx_id, &xid,
+ page_no, offset);
mutex_exit(&(rseg->mutex));
- undo->dict_operation = mtr_read_ulint(
- undo_header + TRX_UNDO_DICT_OPERATION,
- MLOG_2BYTES, mtr);
+ undo->dict_operation = (dict_op & 1);
undo->table_id = mtr_read_dulint(undo_header + TRX_UNDO_TABLE_ID, mtr);
undo->state = state;
undo->size = flst_get_len(seg_header + TRX_UNDO_PAGE_LIST, mtr);
@@ -1272,7 +1367,8 @@ trx_undo_mem_create(
ulint type, /* in: type of the log: TRX_UNDO_INSERT or
TRX_UNDO_UPDATE */
dulint trx_id, /* in: id of the trx for which the undo log
- is created */
+ is created */
+ XID* xid, /* in: X/Open transaction identification */
ulint page_no,/* in: undo log header page number */
ulint offset) /* in: undo log header byte offset on page */
{
@@ -1295,6 +1391,7 @@ trx_undo_mem_create(
undo->state = TRX_UNDO_ACTIVE;
undo->del_marks = FALSE;
undo->trx_id = trx_id;
+ undo->xid = *xid;
undo->dict_operation = FALSE;
@@ -1322,6 +1419,7 @@ trx_undo_mem_init_for_reuse(
trx_undo_t* undo, /* in: undo log to init */
dulint trx_id, /* in: id of the trx for which the undo log
is created */
+ XID* xid, /* in: X/Open XA transaction identification*/
ulint offset) /* in: undo log header byte offset on page */
{
#ifdef UNIV_SYNC_DEBUG
@@ -1339,6 +1437,7 @@ trx_undo_mem_init_for_reuse(
undo->state = TRX_UNDO_ACTIVE;
undo->del_marks = FALSE;
undo->trx_id = trx_id;
+ undo->xid = *xid;
undo->dict_operation = FALSE;
@@ -1376,6 +1475,7 @@ trx_undo_create(
TRX_UNDO_UPDATE */
dulint trx_id, /* in: id of the trx for which the undo log
is created */
+ XID* xid, /* in: X/Open transaction identification*/
mtr_t* mtr) /* in: mtr */
{
trx_rsegf_t* rseg_header;
@@ -1410,9 +1510,10 @@ trx_undo_create(
page_no = buf_frame_get_page_no(undo_page);
- offset = trx_undo_header_create(undo_page, trx_id, mtr);
+ offset = trx_undo_header_create(undo_page, trx_id, xid, mtr);
- undo = trx_undo_mem_create(rseg, id, type, trx_id, page_no, offset);
+ undo = trx_undo_mem_create(rseg, id, type, trx_id, xid ,
+ page_no, offset);
return(undo);
}
@@ -1432,6 +1533,7 @@ trx_undo_reuse_cached(
TRX_UNDO_UPDATE */
dulint trx_id, /* in: id of the trx for which the undo log
is used */
+ XID* xid, /* in: X/Open XA transaction identification*/
mtr_t* mtr) /* in: mtr */
{
trx_undo_t* undo;
@@ -1475,16 +1577,17 @@ trx_undo_reuse_cached(
undo_page = trx_undo_page_get(undo->space, undo->hdr_page_no, mtr);
if (type == TRX_UNDO_INSERT) {
- offset = trx_undo_insert_header_reuse(undo_page, trx_id, mtr);
+ offset = trx_undo_insert_header_reuse(undo_page, trx_id,
+ xid, mtr);
} else {
ut_a(mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR
+ TRX_UNDO_PAGE_TYPE)
== TRX_UNDO_UPDATE);
- offset = trx_undo_header_create(undo_page, trx_id, mtr);
+ offset = trx_undo_header_create(undo_page, trx_id, xid, mtr);
}
- trx_undo_mem_init_for_reuse(undo, trx_id, offset);
+ trx_undo_mem_init_for_reuse(undo, trx_id, xid, offset);
return(undo);
}
@@ -1506,9 +1609,19 @@ trx_undo_mark_as_dict_operation(
hdr_page = trx_undo_page_get(undo->space, undo->hdr_page_no, mtr);
- mlog_write_ulint(hdr_page + undo->hdr_offset + TRX_UNDO_DICT_OPERATION,
- trx->dict_operation, MLOG_2BYTES, mtr);
-
+ /* Mark X/Open XA XID if it is not NULL to dict operation bit */
+
+ if ( trx->xid.formatID == -1) {
+ mlog_write_ulint(hdr_page + undo->hdr_offset +
+ TRX_UNDO_DICT_OPERATION,
+ trx->dict_operation, MLOG_2BYTES, mtr);
+ } else {
+ mlog_write_ulint(hdr_page + undo->hdr_offset +
+ TRX_UNDO_DICT_OPERATION,
+ trx->dict_operation | TRX_UNDO_XA_EXISTS,
+ MLOG_2BYTES, mtr);
+ }
+
mlog_write_dulint(hdr_page + undo->hdr_offset + TRX_UNDO_TABLE_ID,
trx->table_id, mtr);
@@ -1548,10 +1661,10 @@ trx_undo_assign_undo(
#endif /* UNIV_SYNC_DEBUG */
mutex_enter(&(rseg->mutex));
- undo = trx_undo_reuse_cached(rseg, type, trx->id, &mtr);
+ undo = trx_undo_reuse_cached(rseg, type, trx->id, &trx->xid, &mtr);
if (undo == NULL) {
- undo = trx_undo_create(rseg, type, trx->id, &mtr);
+ undo = trx_undo_create(rseg, type, trx->id, &trx->xid, &mtr);
if (undo == NULL) {
/* Did not succeed */
@@ -1632,6 +1745,53 @@ trx_undo_set_state_at_finish(
return(undo_page);
}
+/**********************************************************************
+Sets the state of the undo log segment at a transaction prepare. */
+
+page_t*
+trx_undo_set_state_at_prepare(
+/*==========================*/
+ /* out: undo log segment header page,
+ x-latched */
+ trx_t* trx, /* in: transaction */
+ trx_undo_t* undo, /* in: undo log memory copy */
+ mtr_t* mtr) /* in: mtr */
+{
+ trx_usegf_t* seg_hdr;
+ trx_upagef_t* page_hdr;
+ trx_ulogf_t* undo_header;
+ page_t* undo_page;
+ ulint offset;
+
+ ut_ad(trx && undo && mtr);
+
+ if (undo->id >= TRX_RSEG_N_SLOTS) {
+ fprintf(stderr, "InnoDB: Error: undo->id is %lu\n",
+ (ulong) undo->id);
+ mem_analyze_corruption((byte*)undo);
+ ut_error;
+ }
+
+ undo_page = trx_undo_page_get(undo->space, undo->hdr_page_no, mtr);
+
+ seg_hdr = undo_page + TRX_UNDO_SEG_HDR;
+ page_hdr = undo_page + TRX_UNDO_PAGE_HDR;
+
+ /*------------------------------*/
+ undo->state = TRX_UNDO_PREPARED;
+ undo->xid = trx->xid;
+ /*------------------------------*/
+
+ mlog_write_ulint(seg_hdr + TRX_UNDO_STATE, undo->state,
+ MLOG_2BYTES, mtr);
+
+ offset = mach_read_from_2(seg_hdr + TRX_UNDO_LAST_LOG);
+ undo_header = undo_page + offset;
+
+ trx_undo_write_xid(undo_header, &undo->xid);
+ return(undo_page);
+}
+
/**************************************************************************
Adds the update undo log header as the first in the history list, and
frees the memory object, or puts it to the list of cached update undo log