Commit 3655cefc authored by Monty's avatar Monty

MDEV-33813 ERROR 1021 (HY000): Disk full (./org/test1.MAI); waiting for someone to free some space

Fixed that internal temporary tables are not waiting for freed disk space.

Other things:
- 'kill id' will now kill a query waiting for free disk space instantly.
  Before it could take up to 60 seconds for the kill would be noticed.
- Fixed that sorting one index is not using MY_WAIT_IF_FULL for temp files.
- Fixed bug where share->write_flag set MY_WAIT_IF_FULL for temp files.

It is quite hard to do a test case for this. Instead I tested all
combinations interactively.
parent 33af5575
...@@ -652,6 +652,7 @@ extern size_t my_fwrite(FILE *stream,const uchar *Buffer,size_t Count, ...@@ -652,6 +652,7 @@ extern size_t my_fwrite(FILE *stream,const uchar *Buffer,size_t Count,
myf MyFlags); myf MyFlags);
extern my_off_t my_fseek(FILE *stream,my_off_t pos,int whence,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 my_off_t my_ftell(FILE *stream,myf MyFlags);
extern void (*my_sleep_for_space)(unsigned int seconds);
/* implemented in my_memmem.c */ /* implemented in my_memmem.c */
extern void *my_memmem(const void *haystack, size_t haystacklen, extern void *my_memmem(const void *haystack, size_t haystacklen,
......
...@@ -112,6 +112,13 @@ void init_glob_errs() ...@@ -112,6 +112,13 @@ void init_glob_errs()
} }
#endif #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) void wait_for_free_space(const char *filename, int errors)
{ {
if (errors == 0) if (errors == 0)
...@@ -123,7 +130,7 @@ void wait_for_free_space(const char *filename, int errors) ...@@ -123,7 +130,7 @@ void wait_for_free_space(const char *filename, int errors)
MYF(ME_BELL | ME_ERROR_LOG | ME_WARNING), MYF(ME_BELL | ME_ERROR_LOG | ME_WARNING),
MY_WAIT_FOR_USER_TO_FIX_PANIC, MY_WAIT_FOR_USER_TO_FIX_PANIC,
MY_WAIT_GIVE_USER_A_MESSAGE * 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))) const char **get_global_errmsgs(int nr __attribute__((unused)))
......
...@@ -4880,6 +4880,9 @@ static int init_server_components() ...@@ -4880,6 +4880,9 @@ static int init_server_components()
error_handler_hook= my_message_sql; error_handler_hook= my_message_sql;
proc_info_hook= set_thd_stage_info; 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 Print source revision hash, as one of the first lines, if not the
first in error log, for troubleshooting and debugging purposes first in error log, for troubleshooting and debugging purposes
...@@ -9216,6 +9219,7 @@ PSI_stage_info stage_user_lock= { 0, "User lock", 0}; ...@@ -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_user_sleep= { 0, "User sleep", 0};
PSI_stage_info stage_verifying_table= { 0, "Verifying table", 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_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_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_insert= { 0, "Waiting for handler insert", 0};
PSI_stage_info stage_waiting_for_handler_lock= { 0, "Waiting for handler lock", 0}; PSI_stage_info stage_waiting_for_handler_lock= { 0, "Waiting for handler lock", 0};
......
...@@ -644,6 +644,7 @@ extern PSI_stage_info stage_user_sleep; ...@@ -644,6 +644,7 @@ extern PSI_stage_info stage_user_sleep;
extern PSI_stage_info stage_verifying_table; extern PSI_stage_info stage_verifying_table;
extern PSI_stage_info stage_waiting_for_ddl; extern PSI_stage_info stage_waiting_for_ddl;
extern PSI_stage_info stage_waiting_for_delay_list; 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_flush;
extern PSI_stage_info stage_waiting_for_gtid_to_be_written_to_binary_log; extern PSI_stage_info stage_waiting_for_gtid_to_be_written_to_binary_log;
extern PSI_stage_info stage_waiting_for_handler_insert; extern PSI_stage_info stage_waiting_for_handler_insert;
......
...@@ -8323,6 +8323,34 @@ wait_for_commit::unregister_wait_for_prior_commit2() ...@@ -8323,6 +8323,34 @@ wait_for_commit::unregister_wait_for_prior_commit2()
mysql_mutex_unlock(&LOCK_wait_commit); 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, bool Discrete_intervals_list::append(ulonglong start, ulonglong val,
ulonglong incr) ulonglong incr)
......
...@@ -8185,6 +8185,9 @@ extern THD_list server_threads; ...@@ -8185,6 +8185,9 @@ extern THD_list server_threads;
void setup_tmp_table_column_bitmaps(TABLE *table, uchar *bitmaps, void setup_tmp_table_column_bitmaps(TABLE *table, uchar *bitmaps,
uint field_count); uint field_count);
C_MODE_START
void mariadb_sleep_for_space(unsigned int seconds);
C_MODE_END
#endif /* MYSQL_SERVER */ #endif /* MYSQL_SERVER */
#endif /* SQL_CLASS_INCLUDED */ #endif /* SQL_CLASS_INCLUDED */
...@@ -3390,7 +3390,7 @@ static int sort_one_index(HA_CHECK *param, MARIA_HA *info, ...@@ -3390,7 +3390,7 @@ static int sort_one_index(HA_CHECK *param, MARIA_HA *info,
length= page.size; length= page.size;
bzero(buff+length,keyinfo->block_length-length); bzero(buff+length,keyinfo->block_length-length);
if (write_page(share, new_file, buff, keyinfo->block_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); _ma_check_print_error(param,"Can't write indexblock, error: %d",my_errno);
goto err; goto err;
......
...@@ -601,6 +601,20 @@ uint _ma_file_callback_to_id(void *callback_data) ...@@ -601,6 +601,20 @@ uint _ma_file_callback_to_id(void *callback_data)
return share ? share->id : 0; 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 @brief flushes the data and/or index file of a table
......
...@@ -172,7 +172,6 @@ static MARIA_HA *maria_clone_internal(MARIA_SHARE *share, ...@@ -172,7 +172,6 @@ static MARIA_HA *maria_clone_internal(MARIA_SHARE *share,
mysql_mutex_lock(&share->intern_lock); mysql_mutex_lock(&share->intern_lock);
info.read_record= share->read_record; info.read_record= share->read_record;
share->reopen++; share->reopen++;
share->write_flag=MYF(MY_NABP | MY_WAIT_IF_FULL);
if (share->options & HA_OPTION_READ_ONLY_DATA) if (share->options & HA_OPTION_READ_ONLY_DATA)
{ {
info.lock_type=F_RDLCK; info.lock_type=F_RDLCK;
...@@ -987,6 +986,7 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags, ...@@ -987,6 +986,7 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags,
share->options|= HA_OPTION_READ_ONLY_DATA; share->options|= HA_OPTION_READ_ONLY_DATA;
share->is_log_table= FALSE; 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) if (open_flags & HA_OPEN_TMP_TABLE || share->options & HA_OPTION_TMP_TABLE)
{ {
share->options|= HA_OPTION_TMP_TABLE; share->options|= HA_OPTION_TMP_TABLE;
......
...@@ -687,6 +687,8 @@ static my_bool pagecache_fwrite(PAGECACHE *pagecache, ...@@ -687,6 +687,8 @@ static my_bool pagecache_fwrite(PAGECACHE *pagecache,
/* FIXME: ENGINE=Aria occasionally writes uninitialized data */ /* FIXME: ENGINE=Aria occasionally writes uninitialized data */
__msan_unpoison(args.page, pagecache->block_size); __msan_unpoison(args.page, pagecache->block_size);
#endif #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, res= (int)my_pwrite(filedesc->file, args.page, pagecache->block_size,
((my_off_t) pageno << pagecache->shift), flags); ((my_off_t) pageno << pagecache->shift), flags);
(*filedesc->post_write_hook)(res, &args); (*filedesc->post_write_hook)(res, &args);
......
...@@ -1745,6 +1745,7 @@ extern my_bool ma_yield_and_check_if_killed(MARIA_HA *info, int inx); ...@@ -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 my_bool ma_killed_standalone(MARIA_HA *);
extern uint _ma_file_callback_to_id(void *callback_data); 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); extern void free_maria_share(MARIA_SHARE *share);
static inline void unmap_file(MARIA_HA *info __attribute__((unused))) static inline void unmap_file(MARIA_HA *info __attribute__((unused)))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment