summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--storage/xtradb/btr/btr0btr.c4
-rw-r--r--storage/xtradb/handler/ha_innodb.cc108
-rw-r--r--storage/xtradb/include/buf0buf.h12
-rw-r--r--storage/xtradb/include/buf0buf.ic14
-rw-r--r--storage/xtradb/include/srv0srv.h8
-rw-r--r--storage/xtradb/include/univ.i2
-rw-r--r--storage/xtradb/log/log0log.c8
-rw-r--r--storage/xtradb/log/log0online.c12
-rw-r--r--storage/xtradb/log/log0recv.c2
-rw-r--r--storage/xtradb/mach/mach0data.c13
-rw-r--r--storage/xtradb/srv/srv0srv.c42
11 files changed, 179 insertions, 46 deletions
diff --git a/storage/xtradb/btr/btr0btr.c b/storage/xtradb/btr/btr0btr.c
index dec42f27d3b..0c429363789 100644
--- a/storage/xtradb/btr/btr0btr.c
+++ b/storage/xtradb/btr/btr0btr.c
@@ -76,7 +76,7 @@ btr_corruption_report(
buf_block_get_zip_size(block),
BUF_PAGE_PRINT_NO_CRASH);
}
- buf_page_print(buf_block_get_frame(block), 0, 0);
+ buf_page_print(buf_nonnull_block_get_frame(block), 0, 0);
}
#ifndef UNIV_HOTBACKUP
@@ -1077,7 +1077,7 @@ btr_get_size(
SRV_CORRUPT_TABLE_CHECK(root,
{
mtr_commit(mtr);
- return(0);
+ return(ULINT_UNDEFINED);
});
if (flag == BTR_N_LEAF_PAGES) {
diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc
index 896b27a2047..010aec1ea0d 100644
--- a/storage/xtradb/handler/ha_innodb.cc
+++ b/storage/xtradb/handler/ha_innodb.cc
@@ -475,6 +475,19 @@ innobase_is_fake_change(
THD* thd); /*!< in: MySQL thread handle of the user for
whom the transaction is being committed */
+/** Get the list of foreign keys referencing a specified table
+table.
+@param thd The thread handle
+@param path Path to the table
+@param f_key_list[out] The list of foreign keys
+
+@return error code or zero for success */
+static
+int
+innobase_get_parent_fk_list(
+ THD* thd,
+ const char* path,
+ List<FOREIGN_KEY_INFO>* f_key_list);
/******************************************************************//**
Maps a MySQL trx isolation level code to the InnoDB isolation level code
@@ -2710,6 +2723,7 @@ innobase_init(
innobase_hton->purge_changed_page_bitmaps
= innobase_purge_changed_page_bitmaps;
innobase_hton->is_fake_change = innobase_is_fake_change;
+ innobase_hton->get_parent_fk_list = innobase_get_parent_fk_list;
ut_a(DATA_MYSQL_TRUE_VARCHAR == (ulint)MYSQL_TYPE_VARCHAR);
@@ -9721,7 +9735,14 @@ ha_innobase::check(
prebuilt->select_lock_type = LOCK_NONE;
- if (!row_check_index_for_mysql(prebuilt, index, &n_rows)) {
+ bool check_result
+ = row_check_index_for_mysql(prebuilt, index, &n_rows);
+ DBUG_EXECUTE_IF(
+ "dict_set_index_corrupted",
+ if (!(index->type & DICT_CLUSTERED)) {
+ check_result = false;
+ });
+ if (!check_result) {
innobase_format_name(
index_name, sizeof index_name,
index->name, TRUE);
@@ -10057,6 +10078,73 @@ get_foreign_key_info(
return(pf_key_info);
}
+/** Get the list of foreign keys referencing a specified table
+table.
+@param thd The thread handle
+@param path Path to the table
+@param f_key_list[out] The list of foreign keys */
+static
+void
+fill_foreign_key_list(THD* thd,
+ const dict_table_t* table,
+ List<FOREIGN_KEY_INFO>* f_key_list)
+{
+ ut_ad(mutex_own(&dict_sys->mutex));
+
+ for (dict_foreign_t* foreign
+ = UT_LIST_GET_FIRST(table->referenced_list);
+ foreign != NULL;
+ foreign = UT_LIST_GET_NEXT(referenced_list, foreign)) {
+
+ FOREIGN_KEY_INFO* pf_key_info
+ = get_foreign_key_info(thd, foreign);
+ if (pf_key_info) {
+ f_key_list->push_back(pf_key_info);
+ }
+ }
+}
+
+/** Get the list of foreign keys referencing a specified table
+table.
+@param thd The thread handle
+@param path Path to the table
+@param f_key_list[out] The list of foreign keys
+
+@return error code or zero for success */
+static
+int
+innobase_get_parent_fk_list(
+ THD* thd,
+ const char* path,
+ List<FOREIGN_KEY_INFO>* f_key_list)
+{
+ ut_a(strlen(path) <= FN_REFLEN);
+ char norm_name[FN_REFLEN + 1];
+ normalize_table_name(norm_name, path);
+
+ trx_t* parent_trx = check_trx_exists(thd);
+ parent_trx->op_info = "getting list of referencing foreign keys";
+ trx_search_latch_release_if_reserved(parent_trx);
+
+ mutex_enter(&dict_sys->mutex);
+
+ dict_table_t* table
+ = dict_table_get_low(norm_name,
+ static_cast<dict_err_ignore_t>(
+ DICT_ERR_IGNORE_INDEX_ROOT
+ | DICT_ERR_IGNORE_CORRUPT));
+ if (!table) {
+ mutex_exit(&dict_sys->mutex);
+ return(HA_ERR_NO_SUCH_TABLE);
+ }
+
+ fill_foreign_key_list(thd, table, f_key_list);
+
+ mutex_exit(&dict_sys->mutex);
+ parent_trx->op_info = "";
+ return(0);
+}
+
/*******************************************************************//**
Gets the list of foreign keys in this table.
@return always 0, that is, always succeeds */
@@ -10105,9 +10193,6 @@ ha_innobase::get_parent_foreign_key_list(
THD* thd, /*!< in: user thread handle */
List<FOREIGN_KEY_INFO>* f_key_list) /*!< out: foreign key list */
{
- FOREIGN_KEY_INFO* pf_key_info;
- dict_foreign_t* foreign;
-
ut_a(prebuilt != NULL);
update_thd(ha_thd());
@@ -10116,16 +10201,7 @@ ha_innobase::get_parent_foreign_key_list(
trx_search_latch_release_if_reserved(prebuilt->trx);
mutex_enter(&(dict_sys->mutex));
-
- for (foreign = UT_LIST_GET_FIRST(prebuilt->table->referenced_list);
- foreign != NULL;
- foreign = UT_LIST_GET_NEXT(referenced_list, foreign)) {
- pf_key_info = get_foreign_key_info(thd, foreign);
- if (pf_key_info) {
- f_key_list->push_back(pf_key_info);
- }
- }
-
+ fill_foreign_key_list(thd, prebuilt->table, f_key_list);
mutex_exit(&(dict_sys->mutex));
prebuilt->trx->op_info = "";
@@ -12539,7 +12615,6 @@ innodb_track_changed_pages_validate(
for update function */
struct st_mysql_value* value) /*!< in: incoming bool */
{
- static bool enabled_on_startup = false;
long long intbuf = 0;
if (value->val_int(value, &intbuf)) {
@@ -12547,8 +12622,7 @@ innodb_track_changed_pages_validate(
return 1;
}
- if (srv_track_changed_pages || enabled_on_startup) {
- enabled_on_startup = true;
+ if (srv_redo_log_thread_started) {
*reinterpret_cast<ulong*>(save)
= static_cast<ulong>(intbuf);
return 0;
diff --git a/storage/xtradb/include/buf0buf.h b/storage/xtradb/include/buf0buf.h
index 77025c16373..23692c92c09 100644
--- a/storage/xtradb/include/buf0buf.h
+++ b/storage/xtradb/include/buf0buf.h
@@ -1110,8 +1110,20 @@ buf_block_get_frame(
/*================*/
const buf_block_t* block) /*!< in: pointer to the control block */
__attribute__((pure));
+
+/*********************************************************************//**
+Gets a pointer to the memory frame of a block, where block is known not to be
+NULL.
+@return pointer to the frame */
+UNIV_INLINE
+buf_frame_t*
+buf_nonnull_block_get_frame(
+ const buf_block_t* block) /*!< in: pointer to the control block */
+ __attribute__((pure));
+
#else /* UNIV_DEBUG */
# define buf_block_get_frame(block) (block ? (block)->frame : 0)
+# define buf_nonnull_block_get_frame(block) ((block)->frame)
#endif /* UNIV_DEBUG */
/*********************************************************************//**
Gets the space id of a block.
diff --git a/storage/xtradb/include/buf0buf.ic b/storage/xtradb/include/buf0buf.ic
index f214112c7ce..fae44a1ac4a 100644
--- a/storage/xtradb/include/buf0buf.ic
+++ b/storage/xtradb/include/buf0buf.ic
@@ -718,6 +718,19 @@ buf_block_get_frame(
{
SRV_CORRUPT_TABLE_CHECK(block, return(0););
+ return(buf_nonnull_block_get_frame(block));
+}
+
+/*********************************************************************//**
+Gets a pointer to the memory frame of a block, where block is known not to be
+NULL.
+@return pointer to the frame */
+UNIV_INLINE
+buf_frame_t*
+buf_nonnull_block_get_frame(
+/*========================*/
+ const buf_block_t* block) /*!< in: pointer to the control block */
+{
switch (buf_block_get_state(block)) {
case BUF_BLOCK_ZIP_FREE:
case BUF_BLOCK_ZIP_PAGE:
@@ -739,6 +752,7 @@ buf_block_get_frame(
ok:
return((buf_frame_t*) block->frame);
}
+
#endif /* UNIV_DEBUG */
/*********************************************************************//**
diff --git a/storage/xtradb/include/srv0srv.h b/storage/xtradb/include/srv0srv.h
index 3ccad0640b6..12ab9d9ed87 100644
--- a/storage/xtradb/include/srv0srv.h
+++ b/storage/xtradb/include/srv0srv.h
@@ -74,6 +74,11 @@ extern os_event_t srv_checkpoint_completed_event;
that the (slow) shutdown may proceed */
extern os_event_t srv_redo_log_thread_finished_event;
+/** Whether the redo log tracker thread has been started. Does not take into
+account whether the tracking is currently enabled (see srv_track_changed_pages
+for that) */
+extern my_bool srv_redo_log_thread_started;
+
/* If the last data file is auto-extended, we add this many pages to it
at a time */
#define SRV_AUTO_EXTEND_INCREMENT \
@@ -141,6 +146,9 @@ extern char* srv_doublewrite_file;
extern ibool srv_recovery_stats;
+/** Whether the redo log tracking is currently enabled. Note that it is
+possible for the log tracker thread to be running and the tracking to be
+disabled */
extern my_bool srv_track_changed_pages;
extern ib_uint64_t srv_max_bitmap_file_size;
diff --git a/storage/xtradb/include/univ.i b/storage/xtradb/include/univ.i
index b158a12027f..cc589166f8d 100644
--- a/storage/xtradb/include/univ.i
+++ b/storage/xtradb/include/univ.i
@@ -64,7 +64,7 @@ component, i.e. we show M.N.P as M.N */
(INNODB_VERSION_MAJOR << 8 | INNODB_VERSION_MINOR)
#ifndef PERCONA_INNODB_VERSION
-#define PERCONA_INNODB_VERSION 38.0
+#define PERCONA_INNODB_VERSION 38.3
#endif
#define INNODB_VERSION_STR MYSQL_SERVER_VERSION
diff --git a/storage/xtradb/log/log0log.c b/storage/xtradb/log/log0log.c
index b4b48a065f9..49ee8407b2c 100644
--- a/storage/xtradb/log/log0log.c
+++ b/storage/xtradb/log/log0log.c
@@ -3326,6 +3326,8 @@ logs_empty_and_mark_files_at_shutdown(void)
algorithm only works if the server is idle at shutdown */
srv_shutdown_state = SRV_SHUTDOWN_CLEANUP;
+
+ srv_wake_purge_thread();
loop:
os_thread_sleep(100000);
@@ -3499,7 +3501,7 @@ loop:
srv_shutdown_state = SRV_SHUTDOWN_LAST_PHASE;
/* Wake the log tracking thread which will then immediatelly
quit because of srv_shutdown_state value */
- if (srv_track_changed_pages) {
+ if (srv_redo_log_thread_started) {
os_event_set(srv_checkpoint_completed_event);
os_event_wait(srv_redo_log_thread_finished_event);
}
@@ -3576,7 +3578,7 @@ loop:
srv_shutdown_state = SRV_SHUTDOWN_LAST_PHASE;
/* Signal the log following thread to quit */
- if (srv_track_changed_pages) {
+ if (srv_redo_log_thread_started) {
os_event_set(srv_checkpoint_completed_event);
}
@@ -3600,7 +3602,7 @@ loop:
fil_flush_file_spaces(FIL_TABLESPACE);
- if (srv_track_changed_pages) {
+ if (srv_redo_log_thread_started) {
os_event_wait(srv_redo_log_thread_finished_event);
}
diff --git a/storage/xtradb/log/log0online.c b/storage/xtradb/log/log0online.c
index d0127488f67..fa2c8b882bf 100644
--- a/storage/xtradb/log/log0online.c
+++ b/storage/xtradb/log/log0online.c
@@ -1813,7 +1813,7 @@ log_online_purge_changed_page_bitmaps(
lsn = IB_ULONGLONG_MAX;
}
- if (srv_track_changed_pages) {
+ if (srv_redo_log_thread_started) {
/* User requests might happen with both enabled and disabled
tracking */
mutex_enter(&log_bmp_sys->mutex);
@@ -1821,13 +1821,13 @@ log_online_purge_changed_page_bitmaps(
if (!log_online_setup_bitmap_file_range(&bitmap_files, 0,
IB_ULONGLONG_MAX)) {
- if (srv_track_changed_pages) {
+ if (srv_redo_log_thread_started) {
mutex_exit(&log_bmp_sys->mutex);
}
return TRUE;
}
- if (srv_track_changed_pages && lsn > log_bmp_sys->end_lsn) {
+ if (srv_redo_log_thread_started && lsn > log_bmp_sys->end_lsn) {
/* If we have to delete the current output file, close it
first. */
os_file_close(log_bmp_sys->out.file);
@@ -1858,7 +1858,7 @@ log_online_purge_changed_page_bitmaps(
}
}
- if (srv_track_changed_pages) {
+ if (srv_redo_log_thread_started) {
if (lsn > log_bmp_sys->end_lsn) {
ib_uint64_t new_file_lsn;
if (lsn == IB_ULONGLONG_MAX) {
@@ -1869,9 +1869,7 @@ log_online_purge_changed_page_bitmaps(
new_file_lsn = log_bmp_sys->end_lsn;
}
if (!log_online_rotate_bitmap_file(new_file_lsn)) {
- /* If file create failed, signal the log
- tracking thread to quit next time it wakes
- up. */
+ /* If file create failed, stop log tracking */
srv_track_changed_pages = FALSE;
}
}
diff --git a/storage/xtradb/log/log0recv.c b/storage/xtradb/log/log0recv.c
index 6c2a121967e..527e7b3af0f 100644
--- a/storage/xtradb/log/log0recv.c
+++ b/storage/xtradb/log/log0recv.c
@@ -3015,7 +3015,7 @@ recv_recovery_from_checkpoint_start_func(
ib_uint64_t checkpoint_lsn;
ib_uint64_t checkpoint_no;
ib_uint64_t old_scanned_lsn;
- ib_uint64_t group_scanned_lsn;
+ ib_uint64_t group_scanned_lsn = 0;
ib_uint64_t contiguous_lsn;
#ifdef UNIV_LOG_ARCHIVE
ib_uint64_t archived_lsn;
diff --git a/storage/xtradb/mach/mach0data.c b/storage/xtradb/mach/mach0data.c
index 95b135b0954..00378f036c9 100644
--- a/storage/xtradb/mach/mach0data.c
+++ b/storage/xtradb/mach/mach0data.c
@@ -56,7 +56,18 @@ mach_parse_compressed(
*val = flag;
return(ptr + 1);
- } else if (flag < 0xC0UL) {
+ }
+
+ /* Workaround GCC bug
+ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=77673:
+ the compiler moves mach_read_from_4 right to the beginning of the
+ function, causing and out-of-bounds read if we are reading a short
+ integer close to the end of buffer. */
+#if defined(__GNUC__) && (__GNUC__ >= 5) && !defined(__clang__)
+ asm volatile("": : :"memory");
+#endif
+
+ if (flag < 0xC0UL) {
if (end_ptr < ptr + 2) {
return(NULL);
}
diff --git a/storage/xtradb/srv/srv0srv.c b/storage/xtradb/srv/srv0srv.c
index 26ad32cb1d1..0acce91f2c4 100644
--- a/storage/xtradb/srv/srv0srv.c
+++ b/storage/xtradb/srv/srv0srv.c
@@ -179,6 +179,9 @@ UNIV_INTERN char* srv_doublewrite_file = NULL;
UNIV_INTERN ibool srv_recovery_stats = FALSE;
+/** Whether the redo log tracking is currently enabled. Note that it is
+possible for the log tracker thread to be running and the tracking to be
+disabled */
UNIV_INTERN my_bool srv_track_changed_pages = FALSE;
UNIV_INTERN ib_uint64_t srv_max_bitmap_file_size = 100 * 1024 * 1024;
@@ -809,6 +812,11 @@ UNIV_INTERN os_event_t srv_checkpoint_completed_event;
UNIV_INTERN os_event_t srv_redo_log_thread_finished_event;
+/** Whether the redo log tracker thread has been started. Does not take into
+account whether the tracking is currently enabled (see srv_track_changed_pages
+for that) */
+UNIV_INTERN my_bool srv_redo_log_thread_started = FALSE;
+
UNIV_INTERN srv_sys_t* srv_sys = NULL;
/* padding to prevent other memory update hotspots from residing on
@@ -3179,18 +3187,15 @@ srv_redo_log_follow_thread(
#endif
my_thread_init();
+ srv_redo_log_thread_started = TRUE;
do {
os_event_wait(srv_checkpoint_completed_event);
os_event_reset(srv_checkpoint_completed_event);
-#ifdef UNIV_DEBUG
- if (!srv_track_changed_pages) {
- continue;
- }
-#endif
+ if (srv_track_changed_pages
+ && srv_shutdown_state < SRV_SHUTDOWN_LAST_PHASE) {
- if (srv_shutdown_state < SRV_SHUTDOWN_LAST_PHASE) {
if (!log_online_follow_redo_log()) {
/* TODO: sync with I_S log tracking status? */
fprintf(stderr,
@@ -3206,6 +3211,7 @@ srv_redo_log_follow_thread(
srv_track_changed_pages = FALSE;
log_online_read_shutdown();
os_event_set(srv_redo_log_thread_finished_event);
+ srv_redo_log_thread_started = FALSE; /* Defensive, not required */
my_thread_end();
os_thread_exit(NULL);
@@ -3327,7 +3333,7 @@ srv_master_do_purge(void)
ut_ad(!mutex_own(&kernel_mutex));
- ut_a(srv_n_purge_threads == 0 || (srv_shutdown_state > 0 && srv_n_threads_active[SRV_WORKER] == 0));
+ ut_a(srv_n_purge_threads == 0);
do {
/* Check for shutdown and change in purge config. */
@@ -3848,7 +3854,7 @@ retry_flush_batch:
/* Flush logs if needed */
srv_sync_log_buffer_in_background();
- if (srv_n_purge_threads == 0 || (srv_shutdown_state > 0 && srv_n_threads_active[SRV_WORKER] == 0)) {
+ if (srv_n_purge_threads == 0) {
srv_main_thread_op_info = "master purging";
srv_master_do_purge();
@@ -3926,7 +3932,7 @@ background_loop:
}
}
- if (srv_n_purge_threads == 0 || (srv_shutdown_state > 0 && srv_n_threads_active[SRV_WORKER] == 0)) {
+ if (srv_n_purge_threads == 0) {
srv_main_thread_op_info = "master purging";
srv_master_do_purge();
@@ -4142,9 +4148,10 @@ srv_purge_thread(
We peek at the history len without holding any mutex
because in the worst case we will end up waiting for
the next purge event. */
- if (trx_sys->rseg_history_len < srv_purge_batch_size
- || (n_total_purged == 0
- && retries >= TRX_SYS_N_RSEGS)) {
+ if (srv_shutdown_state == SRV_SHUTDOWN_NONE
+ && (trx_sys->rseg_history_len < srv_purge_batch_size
+ || (n_total_purged == 0
+ && retries >= TRX_SYS_N_RSEGS))) {
mutex_enter(&kernel_mutex);
@@ -4159,8 +4166,12 @@ srv_purge_thread(
/* Check for shutdown and whether we should do purge at all. */
if (srv_force_recovery >= SRV_FORCE_NO_BACKGROUND
- || srv_shutdown_state != 0
- || srv_fast_shutdown) {
+ || (srv_shutdown_state != SRV_SHUTDOWN_NONE
+ && srv_fast_shutdown)
+ || (srv_shutdown_state != SRV_SHUTDOWN_NONE
+ && srv_fast_shutdown == 0
+ && n_total_purged == 0
+ && retries >= TRX_SYS_N_RSEGS)) {
break;
}
@@ -4183,6 +4194,9 @@ srv_purge_thread(
srv_sync_log_buffer_in_background();
+ if (srv_shutdown_state != SRV_SHUTDOWN_NONE)
+ continue;
+
cur_time = ut_time_ms();
if (next_itr_time > cur_time) {
os_thread_sleep(ut_min(1000000,