diff options
-rw-r--r-- | storage/xtradb/btr/btr0btr.c | 4 | ||||
-rw-r--r-- | storage/xtradb/handler/ha_innodb.cc | 108 | ||||
-rw-r--r-- | storage/xtradb/include/buf0buf.h | 12 | ||||
-rw-r--r-- | storage/xtradb/include/buf0buf.ic | 14 | ||||
-rw-r--r-- | storage/xtradb/include/srv0srv.h | 8 | ||||
-rw-r--r-- | storage/xtradb/include/univ.i | 2 | ||||
-rw-r--r-- | storage/xtradb/log/log0log.c | 8 | ||||
-rw-r--r-- | storage/xtradb/log/log0online.c | 12 | ||||
-rw-r--r-- | storage/xtradb/log/log0recv.c | 2 | ||||
-rw-r--r-- | storage/xtradb/mach/mach0data.c | 13 | ||||
-rw-r--r-- | storage/xtradb/srv/srv0srv.c | 42 |
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, |