1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-30 16:24:05 +03:00

Manual merge from mysql-trunk-merge.

Conflicts:
  - include/my_no_pthread.h
  - mysql-test/r/sp-ucs2.result
  - sql/log.cc
  - sql/sql_acl.cc
  - sql/sql_yacc.yy
This commit is contained in:
Alexander Nozdrin
2009-12-16 21:02:21 +03:00
108 changed files with 3406 additions and 1159 deletions

View File

@ -1979,6 +1979,22 @@ void MYSQL_LOG::init(enum_log_type log_type_arg,
}
bool MYSQL_LOG::init_and_set_log_file_name(const char *log_name,
const char *new_name,
enum_log_type log_type_arg,
enum cache_type io_cache_type_arg)
{
init(log_type_arg, io_cache_type_arg);
if (new_name && !strmov(log_file_name, new_name))
return TRUE;
else if (!new_name && generate_new_name(log_file_name, log_name))
return TRUE;
return FALSE;
}
/*
Open a (new) log file.
@ -2011,17 +2027,14 @@ bool MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg,
write_error= 0;
init(log_type_arg, io_cache_type_arg);
if (!(name= my_strdup(log_name, MYF(MY_WME))))
{
name= (char *)log_name; // for the error message
goto err;
}
if (new_name)
strmov(log_file_name, new_name);
else if (generate_new_name(log_file_name, name))
if (init_and_set_log_file_name(name, new_name,
log_type_arg, io_cache_type_arg))
goto err;
if (io_cache_type == SEQ_READ_APPEND)
@ -2519,7 +2532,7 @@ MYSQL_BIN_LOG::MYSQL_BIN_LOG(uint *sync_period)
*/
index_file_name[0] = 0;
bzero((char*) &index_file, sizeof(index_file));
bzero((char*) &purge_temp, sizeof(purge_temp));
bzero((char*) &purge_index_file, sizeof(purge_index_file));
}
/* this is called only once */
@ -2563,7 +2576,7 @@ void MYSQL_BIN_LOG::init_pthread_objects()
bool MYSQL_BIN_LOG::open_index_file(const char *index_file_name_arg,
const char *log_name)
const char *log_name, bool need_mutex)
{
File index_file_nr= -1;
DBUG_ASSERT(!my_b_inited(&index_file));
@ -2588,7 +2601,8 @@ bool MYSQL_BIN_LOG::open_index_file(const char *index_file_name_arg,
init_io_cache(&index_file, index_file_nr,
IO_SIZE, WRITE_CACHE,
my_seek(index_file_nr,0L,MY_SEEK_END,MYF(0)),
0, MYF(MY_WME | MY_WAIT_IF_FULL)))
0, MYF(MY_WME | MY_WAIT_IF_FULL)) ||
DBUG_EVALUATE_IF("fault_injection_openning_index", 1, 0))
{
/*
TODO: all operations creating/deleting the index file or a log, should
@ -2599,6 +2613,28 @@ bool MYSQL_BIN_LOG::open_index_file(const char *index_file_name_arg,
my_close(index_file_nr,MYF(0));
return TRUE;
}
#ifdef HAVE_REPLICATION
/*
Sync the index by purging any binary log file that is not registered.
In other words, either purge binary log files that were removed from
the index but not purged from the file system due to a crash or purge
any binary log file that was created but not register in the index
due to a crash.
*/
if (set_purge_index_file_name(index_file_name_arg) ||
open_purge_index_file(FALSE) ||
purge_index_entry(NULL, NULL, need_mutex) ||
close_purge_index_file() ||
DBUG_EVALUATE_IF("fault_injection_recovering_index", 1, 0))
{
sql_print_error("MYSQL_BIN_LOG::open_index_file failed to sync the index "
"file.");
return TRUE;
}
#endif
return FALSE;
}
@ -2623,17 +2659,44 @@ bool MYSQL_BIN_LOG::open(const char *log_name,
enum cache_type io_cache_type_arg,
bool no_auto_events_arg,
ulong max_size_arg,
bool null_created_arg)
bool null_created_arg,
bool need_mutex)
{
File file= -1;
DBUG_ENTER("MYSQL_BIN_LOG::open");
DBUG_PRINT("enter",("log_type: %d",(int) log_type_arg));
write_error=0;
if (init_and_set_log_file_name(log_name, new_name, log_type_arg,
io_cache_type_arg))
{
sql_print_error("MSYQL_BIN_LOG::open failed to generate new file name.");
DBUG_RETURN(1);
}
#ifdef HAVE_REPLICATION
if (open_purge_index_file(TRUE) ||
register_create_index_entry(log_file_name) ||
sync_purge_index_file() ||
DBUG_EVALUATE_IF("fault_injection_registering_index", 1, 0))
{
sql_print_error("MSYQL_BIN_LOG::open failed to sync the index file.");
DBUG_RETURN(1);
}
DBUG_EXECUTE_IF("crash_create_non_critical_before_update_index", abort(););
#endif
write_error= 0;
/* open the main log file */
if (MYSQL_LOG::open(log_name, log_type_arg, new_name, io_cache_type_arg))
if (MYSQL_LOG::open(log_name, log_type_arg, new_name,
io_cache_type_arg))
{
#ifdef HAVE_REPLICATION
close_purge_index_file();
#endif
DBUG_RETURN(1); /* all warnings issued */
}
init(no_auto_events_arg, max_size_arg);
@ -2659,9 +2722,6 @@ bool MYSQL_BIN_LOG::open(const char *log_name,
write_file_name_to_index_file= 1;
}
DBUG_ASSERT(my_b_inited(&index_file) != 0);
reinit_io_cache(&index_file, WRITE_CACHE,
my_b_filelength(&index_file), 0, 0);
if (need_start_event && !no_auto_events)
{
/*
@ -2719,23 +2779,44 @@ bool MYSQL_BIN_LOG::open(const char *log_name,
if (write_file_name_to_index_file)
{
#ifdef HAVE_REPLICATION
DBUG_EXECUTE_IF("crash_create_critical_before_update_index", abort(););
#endif
DBUG_ASSERT(my_b_inited(&index_file) != 0);
reinit_io_cache(&index_file, WRITE_CACHE,
my_b_filelength(&index_file), 0, 0);
/*
As this is a new log file, we write the file name to the index
file. As every time we write to the index file, we sync it.
*/
if (my_b_write(&index_file, (uchar*) log_file_name,
strlen(log_file_name)) ||
my_b_write(&index_file, (uchar*) "\n", 1) ||
flush_io_cache(&index_file) ||
if (DBUG_EVALUATE_IF("fault_injection_updating_index", 1, 0) ||
my_b_write(&index_file, (uchar*) log_file_name,
strlen(log_file_name)) ||
my_b_write(&index_file, (uchar*) "\n", 1) ||
flush_io_cache(&index_file) ||
my_sync(index_file.file, MYF(MY_WME)))
goto err;
goto err;
#ifdef HAVE_REPLICATION
DBUG_EXECUTE_IF("crash_create_after_update_index", abort(););
#endif
}
}
log_state= LOG_OPENED;
#ifdef HAVE_REPLICATION
close_purge_index_file();
#endif
DBUG_RETURN(0);
err:
#ifdef HAVE_REPLICATION
if (is_inited_purge_index_file())
purge_index_entry(NULL, NULL, need_mutex);
close_purge_index_file();
#endif
sql_print_error("Could not use %s for logging (error %d). \
Turning logging off for the whole duration of the MySQL server process. \
To turn it on again: fix the cause, \
@ -2995,7 +3076,15 @@ bool MYSQL_BIN_LOG::reset_logs(THD* thd)
name=0; // Protect against free
close(LOG_CLOSE_TO_BE_OPENED);
/* First delete all old log files */
/*
First delete all old log files and then update the index file.
As we first delete the log files and do not use sort of logging,
a crash may lead to an inconsistent state where the index has
references to non-existent files.
We need to invert the steps and use the purge_index_file methods
in order to make the operation safe.
*/
if ((err= find_log_pos(&linfo, NullS, 0)) != 0)
{
@ -3066,8 +3155,8 @@ bool MYSQL_BIN_LOG::reset_logs(THD* thd)
}
if (!thd->slave_thread)
need_start_event=1;
if (!open_index_file(index_file_name, 0))
open(save_name, log_type, 0, io_cache_type, no_auto_events, max_size, 0);
if (!open_index_file(index_file_name, 0, FALSE))
open(save_name, log_type, 0, io_cache_type, no_auto_events, max_size, 0, FALSE);
my_free((uchar*) save_name, MYF(0));
err:
@ -3256,7 +3345,7 @@ int MYSQL_BIN_LOG::purge_logs(const char *to_log,
bool need_update_threads,
ulonglong *decrease_log_space)
{
int error;
int error= 0;
bool exit_loop= 0;
LOG_INFO log_info;
THD *thd= current_thd;
@ -3267,33 +3356,15 @@ int MYSQL_BIN_LOG::purge_logs(const char *to_log,
pthread_mutex_lock(&LOCK_index);
if ((error=find_log_pos(&log_info, to_log, 0 /*no mutex*/)))
{
sql_print_error("MYSQL_LOG::purge_logs was called with file %s not "
sql_print_error("MYSQL_BIN_LOG::purge_logs was called with file %s not "
"listed in the index.", to_log);
goto err;
}
/*
For crash recovery reasons the index needs to be updated before
any files are deleted. Move files to be deleted into a temp file
to be processed after the index is updated.
*/
if (!my_b_inited(&purge_temp))
if ((error= open_purge_index_file(TRUE)))
{
if ((error=open_cached_file(&purge_temp, mysql_tmpdir, TEMP_PREFIX,
DISK_BUFFER_SIZE, MYF(MY_WME))))
{
sql_print_error("MYSQL_LOG::purge_logs failed to open purge_temp");
goto err;
}
}
else
{
if ((error=reinit_io_cache(&purge_temp, WRITE_CACHE, 0, 0, 1)))
{
sql_print_error("MYSQL_LOG::purge_logs failed to reinit purge_temp "
"for write");
goto err;
}
sql_print_error("MYSQL_BIN_LOG::purge_logs failed to sync the index file.");
goto err;
}
/*
@ -3303,51 +3374,177 @@ int MYSQL_BIN_LOG::purge_logs(const char *to_log,
if ((error=find_log_pos(&log_info, NullS, 0 /*no mutex*/)))
goto err;
while ((strcmp(to_log,log_info.log_file_name) || (exit_loop=included)) &&
!is_active(log_info.log_file_name) &&
!log_in_use(log_info.log_file_name))
{
if ((error=my_b_write(&purge_temp, (const uchar*)log_info.log_file_name,
strlen(log_info.log_file_name))) ||
(error=my_b_write(&purge_temp, (const uchar*)"\n", 1)))
if ((error= register_purge_index_entry(log_info.log_file_name)))
{
sql_print_error("MYSQL_LOG::purge_logs failed to copy %s to purge_temp",
sql_print_error("MYSQL_BIN_LOG::purge_logs failed to copy %s to register file.",
log_info.log_file_name);
goto err;
}
if (find_next_log(&log_info, 0) || exit_loop)
break;
}
}
DBUG_EXECUTE_IF("crash_purge_before_update_index", abort(););
if ((error= sync_purge_index_file()))
{
sql_print_error("MSYQL_BIN_LOG::purge_logs failed to flush register file.");
goto err;
}
/* We know how many files to delete. Update index file. */
if ((error=update_log_index(&log_info, need_update_threads)))
{
sql_print_error("MSYQL_LOG::purge_logs failed to update the index file");
sql_print_error("MSYQL_BIN_LOG::purge_logs failed to update the index file");
goto err;
}
DBUG_EXECUTE_IF("crash_after_update_index", abort(););
DBUG_EXECUTE_IF("crash_purge_critical_after_update_index", abort(););
/* Switch purge_temp for read. */
if ((error=reinit_io_cache(&purge_temp, READ_CACHE, 0, 0, 0)))
err:
/* Read each entry from purge_index_file and delete the file. */
if (is_inited_purge_index_file() &&
(error= purge_index_entry(thd, decrease_log_space, FALSE)))
sql_print_error("MSYQL_BIN_LOG::purge_logs failed to process registered files"
" that would be purged.");
close_purge_index_file();
DBUG_EXECUTE_IF("crash_purge_non_critical_after_update_index", abort(););
if (need_mutex)
pthread_mutex_unlock(&LOCK_index);
DBUG_RETURN(error);
}
int MYSQL_BIN_LOG::set_purge_index_file_name(const char *base_file_name)
{
int error= 0;
DBUG_ENTER("MYSQL_BIN_LOG::set_purge_index_file_name");
if (fn_format(purge_index_file_name, base_file_name, mysql_data_home,
".~rec~", MYF(MY_UNPACK_FILENAME | MY_SAFE_PATH |
MY_REPLACE_EXT)) == NULL)
{
sql_print_error("MSYQL_LOG::purge_logs failed to reinit purge_temp "
error= 1;
sql_print_error("MYSQL_BIN_LOG::set_purge_index_file_name failed to set "
"file name.");
}
DBUG_RETURN(error);
}
int MYSQL_BIN_LOG::open_purge_index_file(bool destroy)
{
int error= 0;
File file= -1;
DBUG_ENTER("MYSQL_BIN_LOG::open_purge_index_file");
if (destroy)
close_purge_index_file();
if (!my_b_inited(&purge_index_file))
{
if ((file= my_open(purge_index_file_name, O_RDWR | O_CREAT | O_BINARY,
MYF(MY_WME | ME_WAITTANG))) < 0 ||
init_io_cache(&purge_index_file, file, IO_SIZE,
(destroy ? WRITE_CACHE : READ_CACHE),
0, 0, MYF(MY_WME | MY_NABP | MY_WAIT_IF_FULL)))
{
error= 1;
sql_print_error("MYSQL_BIN_LOG::open_purge_index_file failed to open register "
" file.");
}
}
DBUG_RETURN(error);
}
int MYSQL_BIN_LOG::close_purge_index_file()
{
int error= 0;
DBUG_ENTER("MYSQL_BIN_LOG::close_purge_index_file");
if (my_b_inited(&purge_index_file))
{
end_io_cache(&purge_index_file);
error= my_close(purge_index_file.file, MYF(0));
}
my_delete(purge_index_file_name, MYF(0));
bzero((char*) &purge_index_file, sizeof(purge_index_file));
DBUG_RETURN(error);
}
bool MYSQL_BIN_LOG::is_inited_purge_index_file()
{
DBUG_ENTER("MYSQL_BIN_LOG::is_inited_purge_index_file");
DBUG_RETURN (my_b_inited(&purge_index_file));
}
int MYSQL_BIN_LOG::sync_purge_index_file()
{
int error= 0;
DBUG_ENTER("MYSQL_BIN_LOG::sync_purge_index_file");
if ((error= flush_io_cache(&purge_index_file)) ||
(error= my_sync(purge_index_file.file, MYF(MY_WME))))
DBUG_RETURN(error);
DBUG_RETURN(error);
}
int MYSQL_BIN_LOG::register_purge_index_entry(const char *entry)
{
int error= 0;
DBUG_ENTER("MYSQL_BIN_LOG::register_purge_index_entry");
if ((error=my_b_write(&purge_index_file, (const uchar*)entry, strlen(entry))) ||
(error=my_b_write(&purge_index_file, (const uchar*)"\n", 1)))
DBUG_RETURN (error);
DBUG_RETURN(error);
}
int MYSQL_BIN_LOG::register_create_index_entry(const char *entry)
{
DBUG_ENTER("MYSQL_BIN_LOG::register_create_index_entry");
DBUG_RETURN(register_purge_index_entry(entry));
}
int MYSQL_BIN_LOG::purge_index_entry(THD *thd, ulonglong *decrease_log_space,
bool need_mutex)
{
MY_STAT s;
int error= 0;
LOG_INFO log_info;
LOG_INFO check_log_info;
DBUG_ENTER("MYSQL_BIN_LOG:purge_index_entry");
DBUG_ASSERT(my_b_inited(&purge_index_file));
if ((error=reinit_io_cache(&purge_index_file, READ_CACHE, 0, 0, 0)))
{
sql_print_error("MSYQL_BIN_LOG::purge_index_entry failed to reinit register file "
"for read");
goto err;
}
/* Read each entry from purge_temp and delete the file. */
for (;;)
{
uint length;
if ((length=my_b_gets(&purge_temp, log_info.log_file_name,
if ((length=my_b_gets(&purge_index_file, log_info.log_file_name,
FN_REFLEN)) <= 1)
{
if (purge_temp.error)
if (purge_index_file.error)
{
error= purge_temp.error;
sql_print_error("MSYQL_LOG::purge_logs error %d reading from "
"purge_temp", error);
error= purge_index_file.error;
sql_print_error("MSYQL_BIN_LOG::purge_index_entry error %d reading from "
"register file.", error);
goto err;
}
@ -3358,9 +3555,6 @@ int MYSQL_BIN_LOG::purge_logs(const char *to_log,
/* Get rid of the trailing '\n' */
log_info.log_file_name[length-1]= 0;
ha_binlog_index_purge_file(current_thd, log_info.log_file_name);
MY_STAT s;
if (!my_stat(log_info.log_file_name, &s, MYF(0)))
{
if (my_errno == ENOENT)
@ -3408,64 +3602,92 @@ int MYSQL_BIN_LOG::purge_logs(const char *to_log,
}
else
{
DBUG_PRINT("info",("purging %s",log_info.log_file_name));
if (!my_delete(log_info.log_file_name, MYF(0)))
if ((error= find_log_pos(&check_log_info, log_info.log_file_name, need_mutex)))
{
if (decrease_log_space)
*decrease_log_space-= s.st_size;
}
else
{
if (my_errno == ENOENT)
{
if (thd)
{
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE),
log_info.log_file_name);
}
sql_print_information("Failed to delete file '%s'",
log_info.log_file_name);
my_errno= 0;
}
else
if (error != LOG_INFO_EOF)
{
if (thd)
{
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_BINLOG_PURGE_FATAL_ERR,
"a problem with deleting %s; "
"consider examining correspondence "
"of your binlog index file "
"to the actual binlog files",
"a problem with deleting %s and "
"reading the binlog index file",
log_info.log_file_name);
}
else
{
sql_print_information("Failed to delete file '%s'; "
sql_print_information("Failed to delete file '%s' and "
"read the binlog index file",
log_info.log_file_name);
}
goto err;
}
error= 0;
if (!need_mutex)
{
/*
This is to avoid triggering an error in NDB.
*/
ha_binlog_index_purge_file(current_thd, log_info.log_file_name);
}
DBUG_PRINT("info",("purging %s",log_info.log_file_name));
if (!my_delete(log_info.log_file_name, MYF(0)))
{
if (decrease_log_space)
*decrease_log_space-= s.st_size;
}
else
{
if (my_errno == ENOENT)
{
if (thd)
{
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE),
log_info.log_file_name);
}
sql_print_information("Failed to delete file '%s'",
log_info.log_file_name);
my_errno= 0;
}
else
{
if (thd)
{
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_ERROR,
ER_BINLOG_PURGE_FATAL_ERR,
"a problem with deleting %s; "
"consider examining correspondence "
"of your binlog index file "
"to the actual binlog files",
log_info.log_file_name);
}
if (my_errno == EMFILE)
{
DBUG_PRINT("info",
("my_errno: %d, set ret = LOG_INFO_EMFILE", my_errno));
error= LOG_INFO_EMFILE;
}
else
{
sql_print_information("Failed to delete file '%s'; "
"consider examining correspondence "
"of your binlog index file "
"to the actual binlog files",
log_info.log_file_name);
}
if (my_errno == EMFILE)
{
DBUG_PRINT("info",
("my_errno: %d, set ret = LOG_INFO_EMFILE", my_errno));
error= LOG_INFO_EMFILE;
goto err;
}
error= LOG_INFO_FATAL;
goto err;
}
error= LOG_INFO_FATAL;
goto err;
}
}
}
}
err:
close_cached_file(&purge_temp);
if (need_mutex)
pthread_mutex_unlock(&LOCK_index);
DBUG_RETURN(error);
}
@ -3505,7 +3727,8 @@ int MYSQL_BIN_LOG::purge_logs_before_date(time_t purge_time)
goto err;
while (strcmp(log_file_name, log_info.log_file_name) &&
!log_in_use(log_info.log_file_name))
!is_active(log_info.log_file_name) &&
!log_in_use(log_info.log_file_name))
{
if (!my_stat(log_info.log_file_name, &stat_area, MYF(0)))
{
@ -3514,14 +3737,6 @@ int MYSQL_BIN_LOG::purge_logs_before_date(time_t purge_time)
/*
It's not fatal if we can't stat a log file that does not exist.
*/
if (thd)
{
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE),
log_info.log_file_name);
}
sql_print_information("Failed to execute my_stat on file '%s'",
log_info.log_file_name);
my_errno= 0;
}
else
@ -3716,9 +3931,9 @@ void MYSQL_BIN_LOG::new_file_impl(bool need_lock)
*/
/* reopen index binlog file, BUG#34582 */
if (!open_index_file(index_file_name, 0))
open(old_name, log_type, new_name_ptr,
io_cache_type, no_auto_events, max_size, 1);
if (!open_index_file(index_file_name, 0, FALSE))
open(old_name, log_type, new_name_ptr,
io_cache_type, no_auto_events, max_size, 1, FALSE);
my_free(old_name,MYF(0));
end:
@ -4380,6 +4595,9 @@ bool general_log_write(THD *thd, enum enum_server_command command,
void MYSQL_BIN_LOG::rotate_and_purge(uint flags)
{
#ifdef HAVE_REPLICATION
bool check_purge= false;
#endif
if (!(flags & RP_LOCK_LOG_IS_ALREADY_LOCKED))
pthread_mutex_lock(&LOCK_log);
if ((flags & RP_FORCE_ROTATE) ||
@ -4387,16 +4605,24 @@ void MYSQL_BIN_LOG::rotate_and_purge(uint flags)
{
new_file_without_locking();
#ifdef HAVE_REPLICATION
if (expire_logs_days)
{
time_t purge_time= my_time(0) - expire_logs_days*24*60*60;
if (purge_time >= 0)
purge_logs_before_date(purge_time);
}
check_purge= true;
#endif
}
if (!(flags & RP_LOCK_LOG_IS_ALREADY_LOCKED))
pthread_mutex_unlock(&LOCK_log);
#ifdef HAVE_REPLICATION
/*
NOTE: Run purge_logs wo/ holding LOCK_log
as it otherwise will deadlock in ndbcluster_binlog_index_purge_file
*/
if (check_purge && expire_logs_days)
{
time_t purge_time= my_time(0) - expire_logs_days*24*60*60;
if (purge_time >= 0)
purge_logs_before_date(purge_time);
}
#endif
}
uint MYSQL_BIN_LOG::next_file_id()
@ -5674,7 +5900,7 @@ int TC_LOG_BINLOG::open(const char *opt_name)
if (using_heuristic_recover())
{
/* generate a new binlog to mask a corrupted one */
open(opt_name, LOG_BIN, 0, WRITE_CACHE, 0, max_binlog_size, 0);
open(opt_name, LOG_BIN, 0, WRITE_CACHE, 0, max_binlog_size, 0, TRUE);
cleanup();
return 1;
}