summaryrefslogtreecommitdiff
path: root/innobase/trx/trx0roll.c
diff options
context:
space:
mode:
Diffstat (limited to 'innobase/trx/trx0roll.c')
-rw-r--r--innobase/trx/trx0roll.c141
1 files changed, 123 insertions, 18 deletions
diff --git a/innobase/trx/trx0roll.c b/innobase/trx/trx0roll.c
index eb7c7f43f03..4c68e0a0dd3 100644
--- a/innobase/trx/trx0roll.c
+++ b/innobase/trx/trx0roll.c
@@ -30,9 +30,13 @@ Created 3/26/1996 Heikki Tuuri
/* This many pages must be undone before a truncate is tried within rollback */
#define TRX_ROLL_TRUNC_THRESHOLD 1
+/* In crash recovery, the current trx to be rolled back */
+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
rolled back. Then we can print how many % the rollback has progressed. */
ib_longlong trx_roll_max_undo_no;
+
/* Auxiliary variable which tells the previous progress % we printed */
ulint trx_roll_progress_printed_pct;
@@ -48,6 +52,7 @@ trx_general_rollback_for_mysql(
trx_savept_t* savept) /* in: pointer to savepoint undo number, if
partial rollback requested */
{
+#ifndef UNIV_HOTBACKUP
mem_heap_t* heap;
que_thr_t* thr;
roll_node_t* roll_node;
@@ -99,6 +104,12 @@ trx_general_rollback_for_mysql(
srv_active_wake_master_thread();
return((int) trx->error_state);
+#else /* UNIV_HOTBACKUP */
+ /* This function depends on MySQL code that is not included in
+ InnoDB Hot Backup builds. Besides, this function should never
+ be called in InnoDB Hot Backup. */
+ ut_error;
+#endif /* UNIV_HOTBACKUP */
}
/***********************************************************************
@@ -313,6 +324,51 @@ trx_savepoint_for_mysql(
}
/***********************************************************************
+Releases a named savepoint. Savepoints which
+were set after this savepoint are deleted. */
+
+ulint
+trx_release_savepoint_for_mysql(
+/*============================*/
+ /* out: if no savepoint
+ of the name found then
+ DB_NO_SAVEPOINT,
+ otherwise DB_SUCCESS */
+ trx_t* trx, /* in: transaction handle */
+ const char* savepoint_name) /* in: savepoint name */
+{
+ trx_named_savept_t* savep;
+
+ savep = UT_LIST_GET_FIRST(trx->trx_savepoints);
+
+ while (savep != NULL) {
+ if (0 == ut_strcmp(savep->name, savepoint_name)) {
+ /* Found */
+ break;
+ }
+ savep = UT_LIST_GET_NEXT(trx_savepoints, savep);
+ }
+
+ if (savep == NULL) {
+
+ return(DB_NO_SAVEPOINT);
+ }
+
+ /* We can now free all savepoints strictly later than this one */
+
+ trx_roll_savepoints_free(trx, savep);
+
+ /* Now we can free this savepoint too */
+
+ UT_LIST_REMOVE(trx_savepoints, trx->trx_savepoints, savep);
+
+ mem_free(savep->name);
+ mem_free(savep);
+
+ return(DB_SUCCESS);
+}
+
+/***********************************************************************
Returns a transaction savepoint taken at this point in time. */
trx_savept_t
@@ -331,11 +387,20 @@ 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)
-/*========================================*/
+#ifndef __WIN__
+void*
+#else
+ulint
+#endif
+trx_rollback_or_clean_all_without_sess(
+/*===================================*/
+ /* out: a dummy parameter */
+ void* arg __attribute__((unused)))
+ /* in: a dummy parameter required by
+ os_thread_create */
{
mem_heap_t* heap;
que_fork_t* fork;
@@ -360,9 +425,9 @@ trx_rollback_or_clean_all_without_sess(void)
if (UT_LIST_GET_FIRST(trx_sys->trx_list)) {
fprintf(stderr,
- "InnoDB: Starting rollback of uncommitted transactions\n");
+"InnoDB: Starting in background the rollback of uncommitted transactions\n");
} else {
- return;
+ goto leave_function;
}
loop:
heap = mem_heap_create(512);
@@ -371,24 +436,40 @@ loop:
trx = UT_LIST_GET_FIRST(trx_sys->trx_list);
- while (trx && (trx->sess || (trx->conc_state == TRX_NOT_STARTED))) {
+ while (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) {
+
+ /* Roll back all prepared transactions if
+ innobase_force_recovery > 0 in my.cnf */
- trx = UT_LIST_GET_NEXT(trx_list, trx);
+ if (srv_force_recovery > 0) {
+ trx->conc_state = TRX_ACTIVE;
+ break;
+ } else {
+ trx->sess = trx_dummy_sess;
+ trx = UT_LIST_GET_NEXT(trx_list, trx);
+ }
+ } else {
+ break;
+ }
}
mutex_exit(&kernel_mutex);
if (trx == NULL) {
+ ut_print_timestamp(stderr);
fprintf(stderr,
- "InnoDB: Rollback of uncommitted transactions completed\n");
+ " InnoDB: Rollback of uncommitted transactions completed\n");
mem_heap_free(heap);
-
- return;
+
+ goto leave_function;
}
trx->sess = trx_dummy_sess;
-
+
if (trx->conc_state == TRX_COMMITTED_IN_MEMORY) {
fprintf(stderr, "InnoDB: Cleaning up trx with id %lu %lu\n",
(ulong) ut_dulint_get_high(trx->id),
@@ -417,21 +498,28 @@ loop:
ut_a(thr == que_fork_start_command(fork));
+ trx_roll_crash_recv_trx = trx;
trx_roll_max_undo_no = ut_conv_dulint_to_longlong(trx->undo_no);
trx_roll_progress_printed_pct = 0;
rows_to_undo = trx_roll_max_undo_no;
+
if (rows_to_undo > 1000000000) {
rows_to_undo = rows_to_undo / 1000000;
unit = "M";
}
+ ut_print_timestamp(stderr);
fprintf(stderr,
-"InnoDB: Rolling back trx with id %lu %lu, %lu%s rows to undo",
+" InnoDB: Rolling back trx with id %lu %lu, %lu%s rows to undo\n",
(ulong) ut_dulint_get_high(trx->id),
(ulong) ut_dulint_get_low(trx->id),
(ulong) rows_to_undo, unit);
mutex_exit(&kernel_mutex);
+ trx->mysql_thread_id = os_thread_get_curr_id();
+
+ trx->mysql_process_no = os_proc_get_number();
+
if (trx->dict_operation) {
row_mysql_lock_data_dictionary(trx);
}
@@ -446,7 +534,7 @@ loop:
fprintf(stderr,
"InnoDB: Waiting for rollback of trx id %lu to end\n",
- (ulong) ut_dulint_get_low(trx->id));
+ (ulong) ut_dulint_get_low(trx->id));
os_thread_sleep(100000);
mutex_enter(&kernel_mutex);
@@ -485,7 +573,23 @@ loop:
(ulong) ut_dulint_get_low(trx->id));
mem_heap_free(heap);
+ trx_roll_crash_recv_trx = NULL;
+
goto loop;
+
+leave_function:
+ /* We count the number of threads in os_thread_exit(). A created
+ thread should always use that to exit and not use return() to exit. */
+
+ os_thread_exit(NULL);
+
+ /* The following is dummy code to keep the compiler happy: */
+
+#ifndef __WIN__
+ return(NULL);
+#else
+ return(0);
+#endif
}
/***********************************************************************
@@ -846,16 +950,17 @@ try_again:
ut_ad(ut_dulint_cmp(ut_dulint_add(undo_no, 1), trx->undo_no) == 0);
/* We print rollback progress info if we are in a crash recovery
- and the transaction has at least 1000 row operations to undo */
+ and the transaction has at least 1000 row operations to undo. */
+
+ if (trx == trx_roll_crash_recv_trx && trx_roll_max_undo_no > 1000) {
- if (srv_is_being_started && trx_roll_max_undo_no > 1000) {
- progress_pct = 100 - (ulint)
+ progress_pct = 100 - (ulint)
((ut_conv_dulint_to_longlong(undo_no) * 100)
/ trx_roll_max_undo_no);
if (progress_pct != trx_roll_progress_printed_pct) {
if (trx_roll_progress_printed_pct == 0) {
fprintf(stderr,
- "\nInnoDB: Progress in percents: %lu", (ulong) progress_pct);
+"\nInnoDB: Progress in percents: %lu", (ulong) progress_pct);
} else {
fprintf(stderr,
" %lu", (ulong) progress_pct);