diff --git a/include/my_sys.h b/include/my_sys.h index da336bdf8c9..84a1e6a4752 100644 --- a/include/my_sys.h +++ b/include/my_sys.h @@ -652,6 +652,7 @@ extern size_t my_fwrite(FILE *stream,const uchar *Buffer,size_t Count, myf MyFlags); extern my_off_t my_fseek(FILE *stream,my_off_t pos,int whence,myf MyFlags); extern my_off_t my_ftell(FILE *stream,myf MyFlags); +extern void (*my_sleep_for_space)(unsigned int seconds); /* implemented in my_memmem.c */ extern void *my_memmem(const void *haystack, size_t haystacklen, diff --git a/mysys/errors.c b/mysys/errors.c index d88540fe277..a8be37bf2b6 100644 --- a/mysys/errors.c +++ b/mysys/errors.c @@ -112,6 +112,13 @@ void init_glob_errs() } #endif +static void my_space_sleep(uint seconds) +{ + sleep(seconds); +} + +void (*my_sleep_for_space)(uint seconds)= my_space_sleep; + void wait_for_free_space(const char *filename, int errors) { if (errors == 0) @@ -123,7 +130,7 @@ void wait_for_free_space(const char *filename, int errors) MYF(ME_BELL | ME_ERROR_LOG | ME_WARNING), MY_WAIT_FOR_USER_TO_FIX_PANIC, MY_WAIT_GIVE_USER_A_MESSAGE * MY_WAIT_FOR_USER_TO_FIX_PANIC ); - (void) sleep(MY_WAIT_FOR_USER_TO_FIX_PANIC); + my_sleep_for_space(MY_WAIT_FOR_USER_TO_FIX_PANIC); } const char **get_global_errmsgs(int nr __attribute__((unused))) diff --git a/sql/mysqld.cc b/sql/mysqld.cc index d10c342a6dc..16820300f1c 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -4880,6 +4880,9 @@ static int init_server_components() error_handler_hook= my_message_sql; proc_info_hook= set_thd_stage_info; + /* Set up hook to handle disk full */ + my_sleep_for_space= mariadb_sleep_for_space; + /* Print source revision hash, as one of the first lines, if not the first in error log, for troubleshooting and debugging purposes @@ -9216,6 +9219,7 @@ PSI_stage_info stage_user_lock= { 0, "User lock", 0}; PSI_stage_info stage_user_sleep= { 0, "User sleep", 0}; PSI_stage_info stage_verifying_table= { 0, "Verifying table", 0}; PSI_stage_info stage_waiting_for_delay_list= { 0, "Waiting for delay_list", 0}; +PSI_stage_info stage_waiting_for_disk_space= {0, "Waiting for someone to free space", 0}; PSI_stage_info stage_waiting_for_gtid_to_be_written_to_binary_log= { 0, "Waiting for GTID to be written to binary log", 0}; PSI_stage_info stage_waiting_for_handler_insert= { 0, "Waiting for handler insert", 0}; PSI_stage_info stage_waiting_for_handler_lock= { 0, "Waiting for handler lock", 0}; diff --git a/sql/mysqld.h b/sql/mysqld.h index c0a55ce49c7..fe73f14ee62 100644 --- a/sql/mysqld.h +++ b/sql/mysqld.h @@ -644,6 +644,7 @@ extern PSI_stage_info stage_user_sleep; extern PSI_stage_info stage_verifying_table; extern PSI_stage_info stage_waiting_for_ddl; extern PSI_stage_info stage_waiting_for_delay_list; +extern PSI_stage_info stage_waiting_for_disk_space; extern PSI_stage_info stage_waiting_for_flush; extern PSI_stage_info stage_waiting_for_gtid_to_be_written_to_binary_log; extern PSI_stage_info stage_waiting_for_handler_insert; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 35ab93cc8ba..6cabd7fbabd 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -8323,6 +8323,34 @@ wait_for_commit::unregister_wait_for_prior_commit2() mysql_mutex_unlock(&LOCK_wait_commit); } +/* + Wait # seconds or until someone sends a signal (through kill) + + Note that this must have same prototype as my_sleep_for_space() +*/ + +C_MODE_START + +void mariadb_sleep_for_space(unsigned int seconds) +{ + THD *thd= current_thd; + PSI_stage_info old_stage; + if (!thd) + { + sleep(seconds); + return; + } + mysql_mutex_lock(&thd->LOCK_wakeup_ready); + thd->ENTER_COND(&thd->COND_wakeup_ready, &thd->LOCK_wakeup_ready, + &stage_waiting_for_disk_space, &old_stage); + if (!thd->killed) + mysql_cond_wait(&thd->COND_wakeup_ready, &thd->LOCK_wakeup_ready); + thd->EXIT_COND(&old_stage); + return; +} + +C_MODE_END + bool Discrete_intervals_list::append(ulonglong start, ulonglong val, ulonglong incr) diff --git a/sql/sql_class.h b/sql/sql_class.h index 29efb45e097..84665979d6e 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -8185,6 +8185,9 @@ extern THD_list server_threads; void setup_tmp_table_column_bitmaps(TABLE *table, uchar *bitmaps, uint field_count); +C_MODE_START +void mariadb_sleep_for_space(unsigned int seconds); +C_MODE_END #endif /* MYSQL_SERVER */ #endif /* SQL_CLASS_INCLUDED */ diff --git a/storage/maria/ma_check.c b/storage/maria/ma_check.c index 044be038607..ac3ede3865c 100644 --- a/storage/maria/ma_check.c +++ b/storage/maria/ma_check.c @@ -3390,7 +3390,7 @@ static int sort_one_index(HA_CHECK *param, MARIA_HA *info, length= page.size; bzero(buff+length,keyinfo->block_length-length); if (write_page(share, new_file, buff, keyinfo->block_length, - new_page_pos, MYF(MY_NABP | MY_WAIT_IF_FULL))) + new_page_pos, MYF(MY_NABP | MY_WAIT_IF_FULL) & param->myf_rw)) { _ma_check_print_error(param,"Can't write indexblock, error: %d",my_errno); goto err; diff --git a/storage/maria/ma_extra.c b/storage/maria/ma_extra.c index 49b731af5fc..9116edbd671 100644 --- a/storage/maria/ma_extra.c +++ b/storage/maria/ma_extra.c @@ -601,6 +601,20 @@ uint _ma_file_callback_to_id(void *callback_data) return share ? share->id : 0; } +/* + Disable MY_WAIT_IF_FULL flag for temporary tables + + Temporary tables does not have MY_WAIT_IF_FULL in share->write_flags +*/ + +uint _ma_write_flags_callback(void *callback_data, myf flags) +{ + MARIA_SHARE *share= (MARIA_SHARE*) callback_data; + if (share) + flags&= ~(~share->write_flag & MY_WAIT_IF_FULL); + return flags; +} + /** @brief flushes the data and/or index file of a table diff --git a/storage/maria/ma_open.c b/storage/maria/ma_open.c index 6d9ae62ca8e..2497bc41e8f 100644 --- a/storage/maria/ma_open.c +++ b/storage/maria/ma_open.c @@ -172,7 +172,6 @@ static MARIA_HA *maria_clone_internal(MARIA_SHARE *share, mysql_mutex_lock(&share->intern_lock); info.read_record= share->read_record; share->reopen++; - share->write_flag=MYF(MY_NABP | MY_WAIT_IF_FULL); if (share->options & HA_OPTION_READ_ONLY_DATA) { info.lock_type=F_RDLCK; @@ -987,6 +986,7 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags, share->options|= HA_OPTION_READ_ONLY_DATA; share->is_log_table= FALSE; + share->write_flag=MYF(MY_NABP | MY_WAIT_IF_FULL); if (open_flags & HA_OPEN_TMP_TABLE || share->options & HA_OPTION_TMP_TABLE) { share->options|= HA_OPTION_TMP_TABLE; diff --git a/storage/maria/ma_pagecache.c b/storage/maria/ma_pagecache.c index 144b10a86da..49981e7964a 100644 --- a/storage/maria/ma_pagecache.c +++ b/storage/maria/ma_pagecache.c @@ -687,6 +687,8 @@ static my_bool pagecache_fwrite(PAGECACHE *pagecache, /* FIXME: ENGINE=Aria occasionally writes uninitialized data */ __msan_unpoison(args.page, pagecache->block_size); #endif + /* Reset MY_WAIT_IF_FULL for temporary tables */ + flags= _ma_write_flags_callback(filedesc->callback_data, flags); res= (int)my_pwrite(filedesc->file, args.page, pagecache->block_size, ((my_off_t) pageno << pagecache->shift), flags); (*filedesc->post_write_hook)(res, &args); diff --git a/storage/maria/maria_def.h b/storage/maria/maria_def.h index f3303884200..b12f21e39f9 100644 --- a/storage/maria/maria_def.h +++ b/storage/maria/maria_def.h @@ -1745,6 +1745,7 @@ extern my_bool ma_yield_and_check_if_killed(MARIA_HA *info, int inx); extern my_bool ma_killed_standalone(MARIA_HA *); extern uint _ma_file_callback_to_id(void *callback_data); +extern uint _ma_write_flags_callback(void *callback_data, myf flags); extern void free_maria_share(MARIA_SHARE *share); static inline void unmap_file(MARIA_HA *info __attribute__((unused)))