summaryrefslogtreecommitdiff
path: root/storage
diff options
context:
space:
mode:
authorMarko Mäkelä <marko.makela@mariadb.com>2017-02-08 08:53:34 +0200
committerMarko Mäkelä <marko.makela@mariadb.com>2017-02-08 08:53:34 +0200
commit2e67e66c3a5107c0df21b56f387a896cdd2ec4e4 (patch)
tree819bcd107a71c09e12ddd082e13b271b4a878173 /storage
parent6da2adfaa203fd9f76a32fa314b3c14f11ecddc1 (diff)
parentf1627045701b0dc0ff10ec09cca18dc5da351768 (diff)
downloadmariadb-git-2e67e66c3a5107c0df21b56f387a896cdd2ec4e4.tar.gz
Merge 10.0 into 10.1
Diffstat (limited to 'storage')
-rw-r--r--storage/innobase/handler/ha_innodb.cc10
-rw-r--r--storage/innobase/include/srv0srv.h28
-rw-r--r--storage/innobase/log/log0log.cc8
-rw-r--r--storage/innobase/srv/srv0srv.cc203
-rw-r--r--storage/innobase/srv/srv0start.cc103
-rw-r--r--storage/innobase/trx/trx0sys.cc4
-rw-r--r--storage/innobase/trx/trx0trx.cc6
-rw-r--r--storage/innobase/trx/trx0undo.cc29
-rw-r--r--storage/xtradb/handler/ha_innodb.cc10
-rw-r--r--storage/xtradb/include/srv0srv.h28
-rw-r--r--storage/xtradb/log/log0log.cc8
-rw-r--r--storage/xtradb/srv/srv0srv.cc203
-rw-r--r--storage/xtradb/srv/srv0start.cc101
-rw-r--r--storage/xtradb/trx/trx0sys.cc4
-rw-r--r--storage/xtradb/trx/trx0trx.cc6
-rw-r--r--storage/xtradb/trx/trx0undo.cc29
16 files changed, 387 insertions, 393 deletions
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index 350438e0495..8c01c3f8aa5 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -19360,13 +19360,6 @@ static MYSQL_SYSVAR_ULONG(force_recovery, srv_force_recovery,
"Helps to save your data in case the disk image of the database becomes corrupt.",
NULL, NULL, 0, 0, 6, 0);
-#ifndef DBUG_OFF
-static MYSQL_SYSVAR_ULONG(force_recovery_crash, srv_force_recovery_crash,
- PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
- "Kills the server during crash recovery.",
- NULL, NULL, 0, 0, 10, 0);
-#endif /* !DBUG_OFF */
-
static MYSQL_SYSVAR_ULONG(page_size, srv_page_size,
PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY,
"Page size to use for all InnoDB tablespaces.",
@@ -19957,9 +19950,6 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(flush_log_at_trx_commit),
MYSQL_SYSVAR(flush_method),
MYSQL_SYSVAR(force_recovery),
-#ifndef DBUG_OFF
- MYSQL_SYSVAR(force_recovery_crash),
-#endif /* !DBUG_OFF */
MYSQL_SYSVAR(ft_cache_size),
MYSQL_SYSVAR(ft_total_cache_size),
MYSQL_SYSVAR(ft_result_cache_limit),
diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h
index 9dd5b3efa9a..340bb555750 100644
--- a/storage/innobase/include/srv0srv.h
+++ b/storage/innobase/include/srv0srv.h
@@ -3,7 +3,7 @@
Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved.
Copyright (c) 2008, 2009, Google Inc.
Copyright (c) 2009, Percona Inc.
-Copyright (c) 2013, 2017, MariaDB Corporation
+Copyright (c) 2013, 2017, MariaDB Corporation Ab. All Rights Reserved.
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
@@ -439,9 +439,6 @@ extern double srv_adaptive_flushing_lwm;
extern ulong srv_flushing_avg_loops;
extern ulong srv_force_recovery;
-#ifndef DBUG_OFF
-extern ulong srv_force_recovery_crash;
-#endif /* !DBUG_OFF */
extern ulint srv_fast_shutdown; /*!< If this is 1, do not do a
purge and index buffer merge.
@@ -889,24 +886,17 @@ ulint
srv_get_task_queue_length(void);
/*===========================*/
-/*********************************************************************//**
-Releases threads of the type given from suspension in the thread table.
-NOTE! The server mutex has to be reserved by the caller!
-@return number of threads released: this may be less than n if not
-enough threads were suspended at the moment */
-UNIV_INTERN
-ulint
-srv_release_threads(
-/*================*/
- enum srv_thread_type type, /*!< in: thread type */
- ulint n); /*!< in: number of threads to release */
+/** Ensure that a given number of threads of the type given are running
+(or are already terminated).
+@param[in] type thread type
+@param[in] n number of threads that have to run */
+void
+srv_release_threads(enum srv_thread_type type, ulint n);
-/**********************************************************************//**
-Wakeup the purge threads. */
+/** Wake up the purge threads. */
UNIV_INTERN
void
-srv_purge_wakeup(void);
-/*==================*/
+srv_purge_wakeup();
/** Status variables to be passed to MySQL */
struct export_var_t{
diff --git a/storage/innobase/log/log0log.cc b/storage/innobase/log/log0log.cc
index 3c44baaf1de..0e9f1398033 100644
--- a/storage/innobase/log/log0log.cc
+++ b/storage/innobase/log/log0log.cc
@@ -3246,7 +3246,6 @@ logs_empty_and_mark_files_at_shutdown(void)
lsn_t lsn;
ulint arch_log_no;
ulint count = 0;
- ulint total_trx;
ulint pending_io;
ibool server_busy;
@@ -3279,10 +3278,9 @@ loop:
shutdown, because the InnoDB layer may have committed or
prepared transactions and we don't want to lose them. */
- total_trx = trx_sys_any_active_transactions();
-
- if (total_trx > 0) {
-
+ if (ulint total_trx = srv_was_started && !srv_read_only_mode
+ && srv_force_recovery < SRV_FORCE_NO_TRX_UNDO
+ ? trx_sys_any_active_transactions() : 0) {
if (srv_print_verbose_log && count > 600) {
ib_logf(IB_LOG_LEVEL_INFO,
"Waiting for %lu active transactions to finish",
diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc
index 147279dd0d1..62737a6dda4 100644
--- a/storage/innobase/srv/srv0srv.cc
+++ b/storage/innobase/srv/srv0srv.cc
@@ -3,7 +3,7 @@
Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, 2009 Google Inc.
Copyright (c) 2009, Percona Inc.
-Copyright (c) 2013, 2017, MariaDB Corporation.
+Copyright (c) 2013, 2017, MariaDB Corporation Ab. All Rights Reserved.
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
@@ -344,11 +344,6 @@ starting from SRV_FORCE_IGNORE_CORRUPT, so that data can be recovered
by SELECT or mysqldump. When this is nonzero, we do not allow any user
modifications to the data. */
UNIV_INTERN ulong srv_force_recovery;
-#ifndef DBUG_OFF
-/** Inject a crash at different steps of the recovery process.
-This is for testing and debugging only. */
-UNIV_INTERN ulong srv_force_recovery_crash;
-#endif /* !DBUG_OFF */
/** Print all user-level transactions deadlocks to mysqld stderr */
@@ -840,7 +835,6 @@ srv_suspend_thread_low(
/*===================*/
srv_slot_t* slot) /*!< in/out: thread slot */
{
-
ut_ad(!srv_read_only_mode);
ut_ad(srv_sys_mutex_own());
@@ -898,34 +892,71 @@ srv_suspend_thread(
return(sig_count);
}
-/*********************************************************************//**
-Releases threads of the type given from suspension in the thread table.
-NOTE! The server mutex has to be reserved by the caller!
-@return number of threads released: this may be less than n if not
- enough threads were suspended at the moment. */
-UNIV_INTERN
-ulint
-srv_release_threads(
-/*================*/
- srv_thread_type type, /*!< in: thread type */
- ulint n) /*!< in: number of threads to release */
+/** Resume the calling thread.
+@param[in,out] slot thread slot
+@param[in] sig_count signal count (if wait)
+@param[in] wait whether to wait for the event
+@param[in] timeout_usec timeout in microseconds (0=infinite)
+@return whether the wait timed out */
+static
+bool
+srv_resume_thread(srv_slot_t* slot, int64_t sig_count = 0, bool wait = true,
+ ulint timeout_usec = 0)
+{
+ bool timeout;
+
+ ut_ad(!srv_read_only_mode);
+ ut_ad(slot->in_use);
+ ut_ad(slot->suspended);
+
+ if (!wait) {
+ timeout = false;
+ } else if (timeout_usec) {
+ timeout = OS_SYNC_TIME_EXCEEDED == os_event_wait_time_low(
+ slot->event, timeout_usec, sig_count);
+ } else {
+ timeout = false;
+ os_event_wait_low(slot->event, sig_count);
+ }
+
+ srv_sys_mutex_enter();
+ ut_ad(slot->in_use);
+ ut_ad(slot->suspended);
+
+ slot->suspended = FALSE;
+ ++srv_sys->n_threads_active[slot->type];
+ srv_sys_mutex_exit();
+ return(timeout);
+}
+
+/** Ensure that a given number of threads of the type given are running
+(or are already terminated).
+@param[in] type thread type
+@param[in] n number of threads that have to run */
+void
+srv_release_threads(enum srv_thread_type type, ulint n)
{
- ulint i;
- ulint count = 0;
+ ulint running;
ut_ad(srv_thread_type_validate(type));
ut_ad(n > 0);
- srv_sys_mutex_enter();
+ do {
+ running = 0;
- for (i = 0; i < srv_sys->n_sys_threads; i++) {
- srv_slot_t* slot;
+ srv_sys_mutex_enter();
- slot = &srv_sys->sys_threads[i];
+ for (ulint i = 0; i < srv_sys->n_sys_threads; i++) {
+ srv_slot_t* slot = &srv_sys->sys_threads[i];
- if (slot->in_use
- && srv_slot_get_type(slot) == type
- && slot->suspended) {
+ if (!slot->in_use || srv_slot_get_type(slot) != type) {
+ continue;
+ } else if (!slot->suspended) {
+ if (++running >= n) {
+ break;
+ }
+ continue;
+ }
switch (type) {
case SRV_NONE:
@@ -955,21 +986,11 @@ srv_release_threads(
break;
}
- slot->suspended = FALSE;
-
- ++srv_sys->n_threads_active[type];
-
os_event_set(slot->event);
-
- if (++count == n) {
- break;
- }
}
- }
-
- srv_sys_mutex_exit();
- return(count);
+ srv_sys_mutex_exit();
+ } while (running && running < n);
}
/*********************************************************************//**
@@ -982,11 +1003,8 @@ srv_free_slot(
{
srv_sys_mutex_enter();
- if (!slot->suspended) {
- /* Mark the thread as inactive. */
- srv_suspend_thread_low(slot);
- }
-
+ /* Mark the thread as inactive. */
+ srv_suspend_thread_low(slot);
/* Free the slot for reuse. */
ut_ad(slot->in_use);
slot->in_use = FALSE;
@@ -2057,15 +2075,7 @@ srv_active_wake_master_thread(void)
if (slot->in_use) {
ut_a(srv_slot_get_type(slot) == SRV_MASTER);
-
- if (slot->suspended) {
-
- slot->suspended = FALSE;
-
- ++srv_sys->n_threads_active[SRV_MASTER];
-
- os_event_set(slot->event);
- }
+ os_event_set(slot->event);
}
srv_sys_mutex_exit();
@@ -2537,7 +2547,7 @@ suspend_thread:
manual also mentions this string in several places. */
srv_main_thread_op_info = "waiting for server activity";
- os_event_wait(slot->event);
+ srv_resume_thread(slot);
if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) {
os_thread_exit(NULL);
@@ -2649,8 +2659,7 @@ DECLARE_THREAD(srv_worker_thread)(
do {
srv_suspend_thread(slot);
-
- os_event_wait(slot->event);
+ srv_resume_thread(slot);
if (srv_task_execute()) {
@@ -2786,8 +2795,6 @@ srv_purge_coordinator_suspend(
ib_int64_t sig_count = srv_suspend_thread(slot);
do {
- ulint ret;
-
rw_lock_x_lock(&purge_sys->latch);
purge_sys->running = false;
@@ -2796,32 +2803,11 @@ srv_purge_coordinator_suspend(
/* We don't wait right away on the the non-timed wait because
we want to signal the thread that wants to suspend purge. */
-
- if (stop) {
- os_event_wait_low(slot->event, sig_count);
- ret = 0;
- } else if (rseg_history_len <= trx_sys->rseg_history_len) {
- ret = os_event_wait_time_low(
- slot->event, SRV_PURGE_MAX_TIMEOUT, sig_count);
- } else {
- /* We don't want to waste time waiting, if the
- history list increased by the time we got here,
- unless purge has been stopped. */
- ret = 0;
- }
-
- srv_sys_mutex_enter();
-
- /* The thread can be in state !suspended after the timeout
- but before this check if another thread sent a wakeup signal. */
-
- if (slot->suspended) {
- slot->suspended = FALSE;
- ++srv_sys->n_threads_active[slot->type];
- ut_a(srv_sys->n_threads_active[slot->type] == 1);
- }
-
- srv_sys_mutex_exit();
+ const bool wait = stop
+ || rseg_history_len <= trx_sys->rseg_history_len;
+ const bool timeout = srv_resume_thread(
+ slot, sig_count, wait,
+ stop ? 0 : SRV_PURGE_MAX_TIMEOUT);
sig_count = srv_suspend_thread(slot);
@@ -2833,6 +2819,19 @@ srv_purge_coordinator_suspend(
if (!stop) {
ut_a(purge_sys->n_stop == 0);
purge_sys->running = true;
+
+ if (timeout
+ && rseg_history_len == trx_sys->rseg_history_len
+ && trx_sys->rseg_history_len < 5000) {
+ /* No new records were added since the
+ wait started. Simply wait for new
+ records. The magic number 5000 is an
+ approximation for the case where we
+ have cached UNDO log records which
+ prevent truncate of the UNDO
+ segments. */
+ stop = true;
+ }
} else {
ut_a(purge_sys->n_stop > 0);
@@ -2841,33 +2840,9 @@ srv_purge_coordinator_suspend(
}
rw_lock_x_unlock(&purge_sys->latch);
-
- if (ret == OS_SYNC_TIME_EXCEEDED) {
-
- /* No new records added since wait started then simply
- wait for new records. The magic number 5000 is an
- approximation for the case where we have cached UNDO
- log records which prevent truncate of the UNDO
- segments. */
-
- if (rseg_history_len == trx_sys->rseg_history_len
- && trx_sys->rseg_history_len < 5000) {
-
- stop = true;
- }
- }
-
} while (stop);
- srv_sys_mutex_enter();
-
- if (slot->suspended) {
- slot->suspended = FALSE;
- ++srv_sys->n_threads_active[slot->type];
- ut_a(srv_sys->n_threads_active[slot->type] == 1);
- }
-
- srv_sys_mutex_exit();
+ srv_resume_thread(slot, 0, false);
}
/*********************************************************************//**
@@ -2920,8 +2895,9 @@ DECLARE_THREAD(srv_purge_coordinator_thread)(
srv_purge_coordinator_suspend(slot, rseg_history_len);
}
+ ut_ad(!slot->suspended);
+
if (srv_purge_should_exit(n_total_purged)) {
- ut_a(!slot->suspended);
break;
}
@@ -3032,12 +3008,10 @@ srv_get_task_queue_length(void)
return(n_tasks);
}
-/**********************************************************************//**
-Wakeup the purge threads. */
+/** Wake up the purge threads. */
UNIV_INTERN
void
-srv_purge_wakeup(void)
-/*==================*/
+srv_purge_wakeup()
{
ut_ad(!srv_read_only_mode);
@@ -3052,4 +3026,3 @@ srv_purge_wakeup(void)
}
}
}
-
diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc
index 286b6ae993e..b8362b13fbb 100644
--- a/storage/innobase/srv/srv0start.cc
+++ b/storage/innobase/srv/srv0start.cc
@@ -593,19 +593,6 @@ create_log_file(
/** Initial number of the first redo log file */
#define INIT_LOG_FILE0 (SRV_N_LOG_FILES_MAX + 1)
-#ifdef DBUG_OFF
-# define RECOVERY_CRASH(x) do {} while(0)
-#else
-# define RECOVERY_CRASH(x) do { \
- if (srv_force_recovery_crash == x) { \
- fprintf(stderr, "innodb_force_recovery_crash=%lu\n", \
- srv_force_recovery_crash); \
- fflush(stderr); \
- exit(3); \
- } \
-} while (0)
-#endif
-
/*********************************************************************//**
Creates all log files.
@return DB_SUCCESS or error code */
@@ -646,13 +633,14 @@ create_log_files(
file should be recoverable. The buffer
pool was clean, and we can simply create
all log files from the scratch. */
- RECOVERY_CRASH(6);
+ DBUG_EXECUTE_IF("innodb_log_abort_6",
+ return(DB_ERROR););
}
}
ut_ad(!buf_pool_check_no_pending_io());
- RECOVERY_CRASH(7);
+ DBUG_EXECUTE_IF("innodb_log_abort_7", return(DB_ERROR););
for (unsigned i = 0; i < srv_n_log_files; i++) {
sprintf(logfilename + dirnamelen,
@@ -665,7 +653,7 @@ create_log_files(
}
}
- RECOVERY_CRASH(8);
+ DBUG_EXECUTE_IF("innodb_log_abort_8", return(DB_ERROR););
/* We did not create the first log file initially as
ib_logfile0, so that crash recovery cannot find it until it
@@ -711,10 +699,16 @@ create_log_files(
return(DB_SUCCESS);
}
-/*********************************************************************//**
-Renames the first log file. */
+/** Rename the first redo log file.
+@param[in,out] logfilename buffer for the log file name
+@param[in] dirnamelen length of the directory path
+@param[in] lsn FIL_PAGE_FILE_FLUSH_LSN value
+@param[in,out] logfile0 name of the first log file
+@return error code
+@retval DB_SUCCESS on successful operation */
+MY_ATTRIBUTE((warn_unused_result, nonnull))
static
-void
+dberr_t
create_log_files_rename(
/*====================*/
char* logfilename, /*!< in/out: buffer for log file name */
@@ -725,6 +719,9 @@ create_log_files_rename(
/* If innodb_flush_method=O_DSYNC,
we need to explicitly flush the log buffers. */
fil_flush(SRV_LOG_SPACE_FIRST_ID);
+
+ DBUG_EXECUTE_IF("innodb_log_abort_9", return(DB_ERROR););
+
/* Close the log files, so that we can rename
the first one. */
fil_close_log_files(false);
@@ -733,26 +730,28 @@ create_log_files_rename(
checkpoint has been created. */
sprintf(logfilename + dirnamelen, "ib_logfile%u", 0);
- RECOVERY_CRASH(9);
-
ib_logf(IB_LOG_LEVEL_INFO,
"Renaming log file %s to %s", logfile0, logfilename);
mutex_enter(&log_sys->mutex);
ut_ad(strlen(logfile0) == 2 + strlen(logfilename));
- ibool success = os_file_rename(
- innodb_file_log_key, logfile0, logfilename);
- ut_a(success);
-
- RECOVERY_CRASH(10);
+ dberr_t err = os_file_rename(
+ innodb_file_log_key, logfile0, logfilename)
+ ? DB_SUCCESS : DB_ERROR;
/* Replace the first file with ib_logfile0. */
strcpy(logfile0, logfilename);
mutex_exit(&log_sys->mutex);
- fil_open_log_and_system_tablespace_files();
+ DBUG_EXECUTE_IF("innodb_log_abort_10", err = DB_ERROR;);
+
+ if (err == DB_SUCCESS) {
+ fil_open_log_and_system_tablespace_files();
+ ib_logf(IB_LOG_LEVEL_WARN,
+ "New log files created, LSN=" LSN_PF, lsn);
+ }
- ib_logf(IB_LOG_LEVEL_WARN, "New log files created, LSN=" LSN_PF, lsn);
+ return(err);
}
/*********************************************************************//**
@@ -2221,14 +2220,18 @@ innobase_start_or_create_for_mysql(void)
dirnamelen, max_flushed_lsn,
logfile0);
+ if (err == DB_SUCCESS) {
+ err = create_log_files_rename(
+ logfilename,
+ dirnamelen,
+ max_flushed_lsn,
+ logfile0);
+ }
+
if (err != DB_SUCCESS) {
return(err);
}
- create_log_files_rename(
- logfilename, dirnamelen,
- max_flushed_lsn, logfile0);
-
/* Suppress the message about
crash recovery. */
max_flushed_lsn = min_flushed_lsn
@@ -2396,8 +2399,12 @@ files_checked:
fil_flush_file_spaces(FIL_TABLESPACE);
- create_log_files_rename(logfilename, dirnamelen,
- max_flushed_lsn, logfile0);
+ err = create_log_files_rename(logfilename, dirnamelen,
+ max_flushed_lsn, logfile0);
+
+ if (err != DB_SUCCESS) {
+ return(err);
+ }
#ifdef UNIV_LOG_ARCHIVE
} else if (srv_archive_recovery) {
@@ -2629,7 +2636,8 @@ files_checked:
ULINT_MAX, LSN_MAX, NULL);
ut_a(success);
- RECOVERY_CRASH(1);
+ DBUG_EXECUTE_IF("innodb_log_abort_1",
+ return(DB_ERROR););
min_flushed_lsn = max_flushed_lsn = log_get_lsn();
@@ -2644,8 +2652,6 @@ files_checked:
buf_flush_wait_batch_end(NULL, BUF_FLUSH_LIST);
- RECOVERY_CRASH(2);
-
/* Flush the old log files. */
log_buffer_flush_to_disk();
/* If innodb_flush_method=O_DSYNC,
@@ -2660,21 +2666,27 @@ files_checked:
ut_d(recv_no_log_write = TRUE);
ut_ad(!buf_pool_check_no_pending_io());
- RECOVERY_CRASH(3);
+ DBUG_EXECUTE_IF("innodb_log_abort_3",
+ return(DB_ERROR););
/* Stamp the LSN to the data files. */
fil_write_flushed_lsn_to_data_files(
max_flushed_lsn, 0);
- fil_flush_file_spaces(FIL_TABLESPACE);
+ DBUG_EXECUTE_IF("innodb_log_abort_4", err = DB_ERROR;);
- RECOVERY_CRASH(4);
+ if (err != DB_SUCCESS) {
+ return(err);
+ }
+
+ fil_flush_file_spaces(FIL_TABLESPACE);
/* Close and free the redo log files, so that
we can replace them. */
fil_close_log_files(true);
- RECOVERY_CRASH(5);
+ DBUG_EXECUTE_IF("innodb_log_abort_5",
+ return(DB_ERROR););
/* Free the old log file space. */
log_group_close_all();
@@ -2688,12 +2700,15 @@ files_checked:
dirnamelen, max_flushed_lsn,
logfile0);
+ if (err == DB_SUCCESS) {
+ err = create_log_files_rename(
+ logfilename, dirnamelen,
+ max_flushed_lsn, logfile0);
+ }
+
if (err != DB_SUCCESS) {
return(err);
}
-
- create_log_files_rename(logfilename, dirnamelen,
- max_flushed_lsn, logfile0);
}
srv_startup_is_before_trx_rollback_phase = FALSE;
diff --git a/storage/innobase/trx/trx0sys.cc b/storage/innobase/trx/trx0sys.cc
index 76c8613fdbf..24c5ce38339 100644
--- a/storage/innobase/trx/trx0sys.cc
+++ b/storage/innobase/trx/trx0sys.cc
@@ -1322,7 +1322,9 @@ trx_sys_close(void)
ut_a(UT_LIST_GET_LEN(trx_sys->ro_trx_list) == 0);
/* Only prepared transactions may be left in the system. Free them. */
- ut_a(UT_LIST_GET_LEN(trx_sys->rw_trx_list) == trx_sys->n_prepared_trx);
+ ut_a(UT_LIST_GET_LEN(trx_sys->rw_trx_list) == trx_sys->n_prepared_trx
+ || srv_read_only_mode
+ || srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO);
while ((trx = UT_LIST_GET_FIRST(trx_sys->rw_trx_list)) != NULL) {
trx_free_prepared(trx);
diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc
index 11025b4c21c..301ef17197e 100644
--- a/storage/innobase/trx/trx0trx.cc
+++ b/storage/innobase/trx/trx0trx.cc
@@ -312,7 +312,11 @@ trx_free_prepared(
/*==============*/
trx_t* trx) /*!< in, own: trx object */
{
- ut_a(trx_state_eq(trx, TRX_STATE_PREPARED));
+ ut_a(trx_state_eq(trx, TRX_STATE_PREPARED)
+ || (trx_state_eq(trx, TRX_STATE_ACTIVE)
+ && trx->is_recovered
+ && (srv_read_only_mode
+ || srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO)));
ut_a(trx->magic_n == TRX_MAGIC_N);
lock_trx_release_locks(trx);
diff --git a/storage/innobase/trx/trx0undo.cc b/storage/innobase/trx/trx0undo.cc
index cdd23726f2e..220589dd9ff 100644
--- a/storage/innobase/trx/trx0undo.cc
+++ b/storage/innobase/trx/trx0undo.cc
@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2014, 2017, MariaDB Corporation. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -2011,13 +2012,37 @@ trx_undo_free_prepared(
ut_ad(srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS);
if (trx->update_undo) {
- ut_a(trx->update_undo->state == TRX_UNDO_PREPARED);
+ switch (trx->update_undo->state) {
+ case TRX_UNDO_PREPARED:
+ break;
+ case TRX_UNDO_ACTIVE:
+ /* lock_trx_release_locks() assigns
+ trx->is_recovered=false */
+ ut_a(srv_read_only_mode
+ || srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO);
+ break;
+ default:
+ ut_error;
+ }
+
UT_LIST_REMOVE(undo_list, trx->rseg->update_undo_list,
trx->update_undo);
trx_undo_mem_free(trx->update_undo);
}
if (trx->insert_undo) {
- ut_a(trx->insert_undo->state == TRX_UNDO_PREPARED);
+ switch (trx->insert_undo->state) {
+ case TRX_UNDO_PREPARED:
+ break;
+ case TRX_UNDO_ACTIVE:
+ /* lock_trx_release_locks() assigns
+ trx->is_recovered=false */
+ ut_a(srv_read_only_mode
+ || srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO);
+ break;
+ default:
+ ut_error;
+ }
+
UT_LIST_REMOVE(undo_list, trx->rseg->insert_undo_list,
trx->insert_undo);
trx_undo_mem_free(trx->insert_undo);
diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc
index bef54a910e6..4e5f223bc1e 100644
--- a/storage/xtradb/handler/ha_innodb.cc
+++ b/storage/xtradb/handler/ha_innodb.cc
@@ -20777,13 +20777,6 @@ static MYSQL_SYSVAR_ULONG(force_recovery, srv_force_recovery,
"Helps to save your data in case the disk image of the database becomes corrupt.",
NULL, NULL, 0, 0, 6, 0);
-#ifndef DBUG_OFF
-static MYSQL_SYSVAR_ULONG(force_recovery_crash, srv_force_recovery_crash,
- PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
- "Kills the server during crash recovery.",
- NULL, NULL, 0, 0, 10, 0);
-#endif /* !DBUG_OFF */
-
static MYSQL_SYSVAR_ULONG(page_size, srv_page_size,
PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY,
"Page size to use for all InnoDB tablespaces.",
@@ -21443,9 +21436,6 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(use_global_flush_log_at_trx_commit),
MYSQL_SYSVAR(flush_method),
MYSQL_SYSVAR(force_recovery),
-#ifndef DBUG_OFF
- MYSQL_SYSVAR(force_recovery_crash),
-#endif /* !DBUG_OFF */
MYSQL_SYSVAR(ft_cache_size),
MYSQL_SYSVAR(ft_total_cache_size),
MYSQL_SYSVAR(ft_result_cache_limit),
diff --git a/storage/xtradb/include/srv0srv.h b/storage/xtradb/include/srv0srv.h
index f65848fdf45..65dd7415624 100644
--- a/storage/xtradb/include/srv0srv.h
+++ b/storage/xtradb/include/srv0srv.h
@@ -3,7 +3,7 @@
Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved.
Copyright (c) 2008, 2009, Google Inc.
Copyright (c) 2009, Percona Inc.
-Copyright (c) 2013, 2017, MariaDB Corporation
+Copyright (c) 2013, 2017, MariaDB Corporation Ab. All Rights Reserved.
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
@@ -509,9 +509,6 @@ extern double srv_adaptive_flushing_lwm;
extern ulong srv_flushing_avg_loops;
extern ulong srv_force_recovery;
-#ifndef DBUG_OFF
-extern ulong srv_force_recovery_crash;
-#endif /* !DBUG_OFF */
extern ulint srv_fast_shutdown; /*!< If this is 1, do not do a
purge and index buffer merge.
@@ -1073,24 +1070,17 @@ ulint
srv_get_task_queue_length(void);
/*===========================*/
-/*********************************************************************//**
-Releases threads of the type given from suspension in the thread table.
-NOTE! The server mutex has to be reserved by the caller!
-@return number of threads released: this may be less than n if not
-enough threads were suspended at the moment */
-UNIV_INTERN
-ulint
-srv_release_threads(
-/*================*/
- enum srv_thread_type type, /*!< in: thread type */
- ulint n); /*!< in: number of threads to release */
+/** Ensure that a given number of threads of the type given are running
+(or are already terminated).
+@param[in] type thread type
+@param[in] n number of threads that have to run */
+void
+srv_release_threads(enum srv_thread_type type, ulint n);
-/**********************************************************************//**
-Wakeup the purge threads. */
+/** Wake up the purge threads. */
UNIV_INTERN
void
-srv_purge_wakeup(void);
-/*==================*/
+srv_purge_wakeup();
/** Status variables to be passed to MySQL */
struct export_var_t{
diff --git a/storage/xtradb/log/log0log.cc b/storage/xtradb/log/log0log.cc
index 9245ae160e6..dc54aa76dbe 100644
--- a/storage/xtradb/log/log0log.cc
+++ b/storage/xtradb/log/log0log.cc
@@ -3560,7 +3560,6 @@ logs_empty_and_mark_files_at_shutdown(void)
lsn_t lsn;
lsn_t tracked_lsn;
ulint count = 0;
- ulint total_trx;
ulint pending_io;
ibool server_busy;
@@ -3597,10 +3596,9 @@ loop:
shutdown, because the InnoDB layer may have committed or
prepared transactions and we don't want to lose them. */
- total_trx = trx_sys_any_active_transactions();
-
- if (total_trx > 0) {
-
+ if (ulint total_trx = srv_was_started && !srv_read_only_mode
+ && srv_force_recovery < SRV_FORCE_NO_TRX_UNDO
+ ? trx_sys_any_active_transactions() : 0) {
if (srv_print_verbose_log && count > 600) {
ib_logf(IB_LOG_LEVEL_INFO,
"Waiting for %lu active transactions to finish",
diff --git a/storage/xtradb/srv/srv0srv.cc b/storage/xtradb/srv/srv0srv.cc
index bc222b864ef..040fc8eab83 100644
--- a/storage/xtradb/srv/srv0srv.cc
+++ b/storage/xtradb/srv/srv0srv.cc
@@ -3,7 +3,7 @@
Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, 2009 Google Inc.
Copyright (c) 2009, Percona Inc.
-Copyright (c) 2013, 2017, MariaDB Corporation.
+Copyright (c) 2013, 2017, MariaDB Corporation Ab. All Rights Reserved.
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
@@ -474,11 +474,6 @@ starting from SRV_FORCE_IGNORE_CORRUPT, so that data can be recovered
by SELECT or mysqldump. When this is nonzero, we do not allow any user
modifications to the data. */
UNIV_INTERN ulong srv_force_recovery;
-#ifndef DBUG_OFF
-/** Inject a crash at different steps of the recovery process.
-This is for testing and debugging only. */
-UNIV_INTERN ulong srv_force_recovery_crash;
-#endif /* !DBUG_OFF */
/** Print all user-level transactions deadlocks to mysqld stderr */
@@ -998,7 +993,6 @@ srv_suspend_thread_low(
/*===================*/
srv_slot_t* slot) /*!< in/out: thread slot */
{
-
ut_ad(!srv_read_only_mode);
ut_ad(srv_sys_mutex_own());
@@ -1056,34 +1050,71 @@ srv_suspend_thread(
return(sig_count);
}
-/*********************************************************************//**
-Releases threads of the type given from suspension in the thread table.
-NOTE! The server mutex has to be reserved by the caller!
-@return number of threads released: this may be less than n if not
- enough threads were suspended at the moment. */
-UNIV_INTERN
-ulint
-srv_release_threads(
-/*================*/
- srv_thread_type type, /*!< in: thread type */
- ulint n) /*!< in: number of threads to release */
+/** Resume the calling thread.
+@param[in,out] slot thread slot
+@param[in] sig_count signal count (if wait)
+@param[in] wait whether to wait for the event
+@param[in] timeout_usec timeout in microseconds (0=infinite)
+@return whether the wait timed out */
+static
+bool
+srv_resume_thread(srv_slot_t* slot, int64_t sig_count = 0, bool wait = true,
+ ulint timeout_usec = 0)
{
- ulint i;
- ulint count = 0;
+ bool timeout;
+
+ ut_ad(!srv_read_only_mode);
+ ut_ad(slot->in_use);
+ ut_ad(slot->suspended);
+
+ if (!wait) {
+ timeout = false;
+ } else if (timeout_usec) {
+ timeout = OS_SYNC_TIME_EXCEEDED == os_event_wait_time_low(
+ slot->event, timeout_usec, sig_count);
+ } else {
+ timeout = false;
+ os_event_wait_low(slot->event, sig_count);
+ }
+
+ srv_sys_mutex_enter();
+ ut_ad(slot->in_use);
+ ut_ad(slot->suspended);
+
+ slot->suspended = FALSE;
+ ++srv_sys->n_threads_active[slot->type];
+ srv_sys_mutex_exit();
+ return(timeout);
+}
+
+/** Ensure that a given number of threads of the type given are running
+(or are already terminated).
+@param[in] type thread type
+@param[in] n number of threads that have to run */
+void
+srv_release_threads(enum srv_thread_type type, ulint n)
+{
+ ulint running;
ut_ad(srv_thread_type_validate(type));
ut_ad(n > 0);
- srv_sys_mutex_enter();
+ do {
+ running = 0;
- for (i = 0; i < srv_sys->n_sys_threads; i++) {
- srv_slot_t* slot;
+ srv_sys_mutex_enter();
- slot = &srv_sys->sys_threads[i];
+ for (ulint i = 0; i < srv_sys->n_sys_threads; i++) {
+ srv_slot_t* slot = &srv_sys->sys_threads[i];
- if (slot->in_use
- && srv_slot_get_type(slot) == type
- && slot->suspended) {
+ if (!slot->in_use || srv_slot_get_type(slot) != type) {
+ continue;
+ } else if (!slot->suspended) {
+ if (++running >= n) {
+ break;
+ }
+ continue;
+ }
switch (type) {
case SRV_NONE:
@@ -1113,21 +1144,11 @@ srv_release_threads(
break;
}
- slot->suspended = FALSE;
-
- ++srv_sys->n_threads_active[type];
-
os_event_set(slot->event);
-
- if (++count == n) {
- break;
- }
}
- }
-
- srv_sys_mutex_exit();
- return(count);
+ srv_sys_mutex_exit();
+ } while (running && running < n);
}
/*********************************************************************//**
@@ -1140,11 +1161,8 @@ srv_free_slot(
{
srv_sys_mutex_enter();
- if (!slot->suspended) {
- /* Mark the thread as inactive. */
- srv_suspend_thread_low(slot);
- }
-
+ /* Mark the thread as inactive. */
+ srv_suspend_thread_low(slot);
/* Free the slot for reuse. */
ut_ad(slot->in_use);
slot->in_use = FALSE;
@@ -2686,15 +2704,7 @@ srv_active_wake_master_thread(void)
if (slot->in_use) {
ut_a(srv_slot_get_type(slot) == SRV_MASTER);
-
- if (slot->suspended) {
-
- slot->suspended = FALSE;
-
- ++srv_sys->n_threads_active[SRV_MASTER];
-
- os_event_set(slot->event);
- }
+ os_event_set(slot->event);
}
srv_sys_mutex_exit();
@@ -3221,7 +3231,7 @@ suspend_thread:
manual also mentions this string in several places. */
srv_main_thread_op_info = "waiting for server activity";
- os_event_wait(slot->event);
+ srv_resume_thread(slot);
if (srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS) {
os_thread_exit(NULL);
@@ -3343,8 +3353,7 @@ DECLARE_THREAD(srv_worker_thread)(
do {
srv_suspend_thread(slot);
-
- os_event_wait(slot->event);
+ srv_resume_thread(slot);
srv_current_thread_priority = srv_purge_thread_priority;
@@ -3484,8 +3493,6 @@ srv_purge_coordinator_suspend(
ib_int64_t sig_count = srv_suspend_thread(slot);
do {
- ulint ret;
-
rw_lock_x_lock(&purge_sys->latch);
purge_sys->running = false;
@@ -3494,32 +3501,11 @@ srv_purge_coordinator_suspend(
/* We don't wait right away on the the non-timed wait because
we want to signal the thread that wants to suspend purge. */
-
- if (stop) {
- os_event_wait_low(slot->event, sig_count);
- ret = 0;
- } else if (rseg_history_len <= trx_sys->rseg_history_len) {
- ret = os_event_wait_time_low(
- slot->event, SRV_PURGE_MAX_TIMEOUT, sig_count);
- } else {
- /* We don't want to waste time waiting, if the
- history list increased by the time we got here,
- unless purge has been stopped. */
- ret = 0;
- }
-
- srv_sys_mutex_enter();
-
- /* The thread can be in state !suspended after the timeout
- but before this check if another thread sent a wakeup signal. */
-
- if (slot->suspended) {
- slot->suspended = FALSE;
- ++srv_sys->n_threads_active[slot->type];
- ut_a(srv_sys->n_threads_active[slot->type] == 1);
- }
-
- srv_sys_mutex_exit();
+ const bool wait = stop
+ || rseg_history_len <= trx_sys->rseg_history_len;
+ const bool timeout = srv_resume_thread(
+ slot, sig_count, wait,
+ stop ? 0 : SRV_PURGE_MAX_TIMEOUT);
sig_count = srv_suspend_thread(slot);
@@ -3531,6 +3517,19 @@ srv_purge_coordinator_suspend(
if (!stop) {
ut_a(purge_sys->n_stop == 0);
purge_sys->running = true;
+
+ if (timeout
+ && rseg_history_len == trx_sys->rseg_history_len
+ && trx_sys->rseg_history_len < 5000) {
+ /* No new records were added since the
+ wait started. Simply wait for new
+ records. The magic number 5000 is an
+ approximation for the case where we
+ have cached UNDO log records which
+ prevent truncate of the UNDO
+ segments. */
+ stop = true;
+ }
} else {
ut_a(purge_sys->n_stop > 0);
@@ -3539,33 +3538,9 @@ srv_purge_coordinator_suspend(
}
rw_lock_x_unlock(&purge_sys->latch);
-
- if (ret == OS_SYNC_TIME_EXCEEDED) {
-
- /* No new records added since wait started then simply
- wait for new records. The magic number 5000 is an
- approximation for the case where we have cached UNDO
- log records which prevent truncate of the UNDO
- segments. */
-
- if (rseg_history_len == trx_sys->rseg_history_len
- && trx_sys->rseg_history_len < 5000) {
-
- stop = true;
- }
- }
-
} while (stop);
- srv_sys_mutex_enter();
-
- if (slot->suspended) {
- slot->suspended = FALSE;
- ++srv_sys->n_threads_active[slot->type];
- ut_a(srv_sys->n_threads_active[slot->type] == 1);
- }
-
- srv_sys_mutex_exit();
+ srv_resume_thread(slot, 0, false);
}
/*********************************************************************//**
@@ -3621,8 +3596,9 @@ DECLARE_THREAD(srv_purge_coordinator_thread)(
srv_purge_coordinator_suspend(slot, rseg_history_len);
}
+ ut_ad(!slot->suspended);
+
if (srv_purge_should_exit(n_total_purged)) {
- ut_a(!slot->suspended);
break;
}
@@ -3737,12 +3713,10 @@ srv_get_task_queue_length(void)
return(n_tasks);
}
-/**********************************************************************//**
-Wakeup the purge threads. */
+/** Wake up the purge threads. */
UNIV_INTERN
void
-srv_purge_wakeup(void)
-/*==================*/
+srv_purge_wakeup()
{
ut_ad(!srv_read_only_mode);
@@ -3757,4 +3731,3 @@ srv_purge_wakeup(void)
}
}
}
-
diff --git a/storage/xtradb/srv/srv0start.cc b/storage/xtradb/srv/srv0start.cc
index 14f16870de9..a04f8dc732c 100644
--- a/storage/xtradb/srv/srv0start.cc
+++ b/storage/xtradb/srv/srv0start.cc
@@ -623,19 +623,6 @@ create_log_file(
/** Initial number of the first redo log file */
#define INIT_LOG_FILE0 (SRV_N_LOG_FILES_MAX + 1)
-#ifdef DBUG_OFF
-# define RECOVERY_CRASH(x) do {} while(0)
-#else
-# define RECOVERY_CRASH(x) do { \
- if (srv_force_recovery_crash == x) { \
- fprintf(stderr, "innodb_force_recovery_crash=%lu\n", \
- srv_force_recovery_crash); \
- fflush(stderr); \
- exit(3); \
- } \
-} while (0)
-#endif
-
/*********************************************************************//**
Creates all log files.
@return DB_SUCCESS or error code */
@@ -676,13 +663,14 @@ create_log_files(
file should be recoverable. The buffer
pool was clean, and we can simply create
all log files from the scratch. */
- RECOVERY_CRASH(6);
+ DBUG_EXECUTE_IF("innodb_log_abort_6",
+ return(DB_ERROR););
}
}
ut_ad(!buf_pool_check_no_pending_io());
- RECOVERY_CRASH(7);
+ DBUG_EXECUTE_IF("innodb_log_abort_7", return(DB_ERROR););
for (unsigned i = 0; i < srv_n_log_files; i++) {
sprintf(logfilename + dirnamelen,
@@ -695,7 +683,7 @@ create_log_files(
}
}
- RECOVERY_CRASH(8);
+ DBUG_EXECUTE_IF("innodb_log_abort_8", return(DB_ERROR););
/* We did not create the first log file initially as
ib_logfile0, so that crash recovery cannot find it until it
@@ -751,10 +739,16 @@ create_log_files(
return(DB_SUCCESS);
}
-/*********************************************************************//**
-Renames the first log file. */
+/** Rename the first redo log file.
+@param[in,out] logfilename buffer for the log file name
+@param[in] dirnamelen length of the directory path
+@param[in] lsn FIL_PAGE_FILE_FLUSH_LSN value
+@param[in,out] logfile0 name of the first log file
+@return error code
+@retval DB_SUCCESS on successful operation */
+MY_ATTRIBUTE((warn_unused_result, nonnull))
static
-void
+dberr_t
create_log_files_rename(
/*====================*/
char* logfilename, /*!< in/out: buffer for log file name */
@@ -765,6 +759,9 @@ create_log_files_rename(
/* If innodb_flush_method=O_DSYNC,
we need to explicitly flush the log buffers. */
fil_flush(SRV_LOG_SPACE_FIRST_ID);
+
+ DBUG_EXECUTE_IF("innodb_log_abort_9", return(DB_ERROR););
+
/* Close the log files, so that we can rename
the first one. */
fil_close_log_files(false);
@@ -773,26 +770,28 @@ create_log_files_rename(
checkpoint has been created. */
sprintf(logfilename + dirnamelen, "ib_logfile%u", 0);
- RECOVERY_CRASH(9);
-
ib_logf(IB_LOG_LEVEL_INFO,
"Renaming log file %s to %s", logfile0, logfilename);
mutex_enter(&log_sys->mutex);
ut_ad(strlen(logfile0) == 2 + strlen(logfilename));
- ibool success = os_file_rename(
- innodb_file_log_key, logfile0, logfilename);
- ut_a(success);
-
- RECOVERY_CRASH(10);
+ dberr_t err = os_file_rename(
+ innodb_file_log_key, logfile0, logfilename)
+ ? DB_SUCCESS : DB_ERROR;
/* Replace the first file with ib_logfile0. */
strcpy(logfile0, logfilename);
mutex_exit(&log_sys->mutex);
- fil_open_log_and_system_tablespace_files();
+ DBUG_EXECUTE_IF("innodb_log_abort_10", err = DB_ERROR;);
+
+ if (err == DB_SUCCESS) {
+ fil_open_log_and_system_tablespace_files();
+ ib_logf(IB_LOG_LEVEL_WARN,
+ "New log files created, LSN=" LSN_PF, lsn);
+ }
- ib_logf(IB_LOG_LEVEL_WARN, "New log files created, LSN=" LSN_PF, lsn);
+ return(err);
}
/*********************************************************************//**
@@ -2299,14 +2298,18 @@ innobase_start_or_create_for_mysql(void)
dirnamelen, max_flushed_lsn,
logfile0);
+ if (err == DB_SUCCESS) {
+ err = create_log_files_rename(
+ logfilename,
+ dirnamelen,
+ max_flushed_lsn,
+ logfile0);
+ }
+
if (err != DB_SUCCESS) {
return(err);
}
- create_log_files_rename(
- logfilename, dirnamelen,
- max_flushed_lsn, logfile0);
-
/* Suppress the message about
crash recovery. */
max_flushed_lsn = min_flushed_lsn
@@ -2476,8 +2479,12 @@ files_checked:
fil_flush_file_spaces(FIL_TABLESPACE);
- create_log_files_rename(logfilename, dirnamelen,
- max_flushed_lsn, logfile0);
+ err = create_log_files_rename(logfilename, dirnamelen,
+ max_flushed_lsn, logfile0);
+
+ if (err != DB_SUCCESS) {
+ return(err);
+ }
} else {
/* Check if we support the max format that is stamped
@@ -2679,7 +2686,8 @@ files_checked:
ULINT_MAX, LSN_MAX, NULL);
ut_a(success);
- RECOVERY_CRASH(1);
+ DBUG_EXECUTE_IF("innodb_log_abort_1",
+ return(DB_ERROR););
min_flushed_lsn = max_flushed_lsn = log_get_lsn();
@@ -2694,8 +2702,6 @@ files_checked:
buf_flush_wait_batch_end(NULL, BUF_FLUSH_LIST);
- RECOVERY_CRASH(2);
-
/* Flush the old log files. */
log_buffer_flush_to_disk();
/* If innodb_flush_method=O_DSYNC,
@@ -2710,21 +2716,27 @@ files_checked:
ut_d(recv_no_log_write = TRUE);
ut_ad(!buf_pool_check_no_pending_io());
- RECOVERY_CRASH(3);
+ DBUG_EXECUTE_IF("innodb_log_abort_3",
+ return(DB_ERROR););
/* Stamp the LSN to the data files. */
fil_write_flushed_lsn_to_data_files(
max_flushed_lsn, 0);
- fil_flush_file_spaces(FIL_TABLESPACE);
+ DBUG_EXECUTE_IF("innodb_log_abort_4", err = DB_ERROR;);
- RECOVERY_CRASH(4);
+ if (err != DB_SUCCESS) {
+ return(err);
+ }
+
+ fil_flush_file_spaces(FIL_TABLESPACE);
/* Close and free the redo log files, so that
we can replace them. */
fil_close_log_files(true);
- RECOVERY_CRASH(5);
+ DBUG_EXECUTE_IF("innodb_log_abort_5",
+ return(DB_ERROR););
/* Free the old log file space. */
log_group_close_all();
@@ -2748,8 +2760,11 @@ files_checked:
fil_write_flushed_lsn_to_data_files(min_flushed_lsn, 0);
fil_flush_file_spaces(FIL_TABLESPACE);
- create_log_files_rename(logfilename, dirnamelen,
- log_get_lsn(), logfile0);
+ err = create_log_files_rename(logfilename, dirnamelen,
+ log_get_lsn(), logfile0);
+ if (err != DB_SUCCESS) {
+ return(err);
+ }
}
srv_startup_is_before_trx_rollback_phase = FALSE;
diff --git a/storage/xtradb/trx/trx0sys.cc b/storage/xtradb/trx/trx0sys.cc
index 9b136ccef92..45315d35c42 100644
--- a/storage/xtradb/trx/trx0sys.cc
+++ b/storage/xtradb/trx/trx0sys.cc
@@ -1335,7 +1335,9 @@ trx_sys_close(void)
ut_a(UT_LIST_GET_LEN(trx_sys->ro_trx_list) == 0);
/* Only prepared transactions may be left in the system. Free them. */
- ut_a(UT_LIST_GET_LEN(trx_sys->rw_trx_list) == trx_sys->n_prepared_trx);
+ ut_a(UT_LIST_GET_LEN(trx_sys->rw_trx_list) == trx_sys->n_prepared_trx
+ || srv_read_only_mode
+ || srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO);
while ((trx = UT_LIST_GET_FIRST(trx_sys->rw_trx_list)) != NULL) {
trx_free_prepared(trx);
diff --git a/storage/xtradb/trx/trx0trx.cc b/storage/xtradb/trx/trx0trx.cc
index bdf407ff7fb..73c1172ff0f 100644
--- a/storage/xtradb/trx/trx0trx.cc
+++ b/storage/xtradb/trx/trx0trx.cc
@@ -478,7 +478,11 @@ trx_free_prepared(
/*==============*/
trx_t* trx) /*!< in, own: trx object */
{
- ut_a(trx_state_eq(trx, TRX_STATE_PREPARED));
+ ut_a(trx_state_eq(trx, TRX_STATE_PREPARED)
+ || (trx_state_eq(trx, TRX_STATE_ACTIVE)
+ && trx->is_recovered
+ && (srv_read_only_mode
+ || srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO)));
ut_a(trx->magic_n == TRX_MAGIC_N);
lock_trx_release_locks(trx);
diff --git a/storage/xtradb/trx/trx0undo.cc b/storage/xtradb/trx/trx0undo.cc
index cdd23726f2e..220589dd9ff 100644
--- a/storage/xtradb/trx/trx0undo.cc
+++ b/storage/xtradb/trx/trx0undo.cc
@@ -1,6 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2014, 2017, MariaDB Corporation. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -2011,13 +2012,37 @@ trx_undo_free_prepared(
ut_ad(srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS);
if (trx->update_undo) {
- ut_a(trx->update_undo->state == TRX_UNDO_PREPARED);
+ switch (trx->update_undo->state) {
+ case TRX_UNDO_PREPARED:
+ break;
+ case TRX_UNDO_ACTIVE:
+ /* lock_trx_release_locks() assigns
+ trx->is_recovered=false */
+ ut_a(srv_read_only_mode
+ || srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO);
+ break;
+ default:
+ ut_error;
+ }
+
UT_LIST_REMOVE(undo_list, trx->rseg->update_undo_list,
trx->update_undo);
trx_undo_mem_free(trx->update_undo);
}
if (trx->insert_undo) {
- ut_a(trx->insert_undo->state == TRX_UNDO_PREPARED);
+ switch (trx->insert_undo->state) {
+ case TRX_UNDO_PREPARED:
+ break;
+ case TRX_UNDO_ACTIVE:
+ /* lock_trx_release_locks() assigns
+ trx->is_recovered=false */
+ ut_a(srv_read_only_mode
+ || srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO);
+ break;
+ default:
+ ut_error;
+ }
+
UT_LIST_REMOVE(undo_list, trx->rseg->insert_undo_list,
trx->insert_undo);
trx_undo_mem_free(trx->insert_undo);