mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
Merge with 5.2
This commit is contained in:
254
sql/log.cc
254
sql/log.cc
@ -1,4 +1,4 @@
|
||||
/* Copyright 2000-2008 MySQL AB, 2008 Sun Microsystems, Inc.
|
||||
/* Copyright (c) 2000, 2011, Oracle and/or its affiliates.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@ -1908,10 +1908,11 @@ static int find_uniq_filename(char *name)
|
||||
*end='.';
|
||||
length= (size_t) (end-start+1);
|
||||
|
||||
if (!(dir_info = my_dir(buff,MYF(MY_DONT_SORT))))
|
||||
if ((DBUG_EVALUATE_IF("error_unique_log_filename", 1,
|
||||
!(dir_info = my_dir(buff,MYF(MY_DONT_SORT))))))
|
||||
{ // This shouldn't happen
|
||||
strmov(end,".1"); // use name+1
|
||||
DBUG_RETURN(0);
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
file_info= dir_info->dir_entry;
|
||||
for (i=dir_info->number_off_files ; i-- ; file_info++)
|
||||
@ -1925,8 +1926,7 @@ static int find_uniq_filename(char *name)
|
||||
my_dirend(dir_info);
|
||||
|
||||
*end++='.';
|
||||
sprintf(end,"%06ld",max_found+1);
|
||||
DBUG_RETURN(0);
|
||||
DBUG_RETURN((sprintf(end,"%06ld",max_found+1) < 0));
|
||||
}
|
||||
|
||||
|
||||
@ -2138,6 +2138,8 @@ int MYSQL_LOG::generate_new_name(char *new_name, const char *log_name)
|
||||
{
|
||||
if (find_uniq_filename(new_name))
|
||||
{
|
||||
my_printf_error(ER_NO_UNIQUE_LOGFILE, ER(ER_NO_UNIQUE_LOGFILE),
|
||||
MYF(ME_FATALERROR), log_name);
|
||||
sql_print_error(ER(ER_NO_UNIQUE_LOGFILE), log_name);
|
||||
return 1;
|
||||
}
|
||||
@ -2659,6 +2661,23 @@ bool MYSQL_BIN_LOG::open(const char *log_name,
|
||||
sync_purge_index_file() ||
|
||||
DBUG_EVALUATE_IF("fault_injection_registering_index", 1, 0))
|
||||
{
|
||||
/**
|
||||
TODO: although this was introduced to appease valgrind
|
||||
when injecting emulated faults using fault_injection_registering_index
|
||||
it may be good to consider what actually happens when
|
||||
open_purge_index_file succeeds but register or sync fails.
|
||||
|
||||
Perhaps we might need the code below in MYSQL_LOG_BIN::cleanup
|
||||
for "real life" purposes as well?
|
||||
*/
|
||||
DBUG_EXECUTE_IF("fault_injection_registering_index", {
|
||||
if (my_b_inited(&purge_index_file))
|
||||
{
|
||||
end_io_cache(&purge_index_file);
|
||||
my_close(purge_index_file.file, MYF(0));
|
||||
}
|
||||
});
|
||||
|
||||
sql_print_error("MSYQL_BIN_LOG::open failed to sync the index file.");
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
@ -3099,7 +3118,7 @@ bool MYSQL_BIN_LOG::reset_logs(THD* thd)
|
||||
}
|
||||
|
||||
/* Start logging with a new file */
|
||||
close(LOG_CLOSE_INDEX);
|
||||
close(LOG_CLOSE_INDEX | LOG_CLOSE_TO_BE_OPENED);
|
||||
if ((error= my_delete_allow_opened(index_file_name, MYF(0)))) // Reset (open will update)
|
||||
{
|
||||
if (my_errno == ENOENT)
|
||||
@ -3128,7 +3147,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, FALSE))
|
||||
open(save_name, log_type, 0, io_cache_type, no_auto_events, max_size, 0, FALSE);
|
||||
if ((error= open(save_name, log_type, 0, io_cache_type, no_auto_events, max_size, 0, FALSE)))
|
||||
goto err;
|
||||
my_free((uchar*) save_name, MYF(0));
|
||||
|
||||
err:
|
||||
@ -3790,17 +3810,23 @@ bool MYSQL_BIN_LOG::is_active(const char *log_file_name_arg)
|
||||
incapsulation 3) allows external access to the class without
|
||||
a lock (which is not possible with private new_file_without_locking
|
||||
method).
|
||||
|
||||
@retval
|
||||
nonzero - error
|
||||
*/
|
||||
|
||||
void MYSQL_BIN_LOG::new_file()
|
||||
int MYSQL_BIN_LOG::new_file()
|
||||
{
|
||||
new_file_impl(1);
|
||||
return new_file_impl(1);
|
||||
}
|
||||
|
||||
|
||||
void MYSQL_BIN_LOG::new_file_without_locking()
|
||||
/*
|
||||
@retval
|
||||
nonzero - error
|
||||
*/
|
||||
int MYSQL_BIN_LOG::new_file_without_locking()
|
||||
{
|
||||
new_file_impl(0);
|
||||
return new_file_impl(0);
|
||||
}
|
||||
|
||||
|
||||
@ -3809,19 +3835,23 @@ void MYSQL_BIN_LOG::new_file_without_locking()
|
||||
|
||||
@param need_lock Set to 1 if caller has not locked LOCK_log
|
||||
|
||||
@retval
|
||||
nonzero - error
|
||||
|
||||
@note
|
||||
The new file name is stored last in the index file
|
||||
*/
|
||||
|
||||
void MYSQL_BIN_LOG::new_file_impl(bool need_lock)
|
||||
int MYSQL_BIN_LOG::new_file_impl(bool need_lock)
|
||||
{
|
||||
char new_name[FN_REFLEN], *new_name_ptr, *old_name;
|
||||
int error= 0, close_on_error= FALSE;
|
||||
char new_name[FN_REFLEN], *new_name_ptr, *old_name, *file_to_open;
|
||||
|
||||
DBUG_ENTER("MYSQL_BIN_LOG::new_file_impl");
|
||||
if (!is_open())
|
||||
{
|
||||
DBUG_PRINT("info",("log is closed"));
|
||||
DBUG_VOID_RETURN;
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
|
||||
if (need_lock)
|
||||
@ -3859,7 +3889,7 @@ void MYSQL_BIN_LOG::new_file_impl(bool need_lock)
|
||||
We have to do this here and not in open as we want to store the
|
||||
new file name in the current binary log file.
|
||||
*/
|
||||
if (generate_new_name(new_name, name))
|
||||
if ((error= generate_new_name(new_name, name)))
|
||||
goto end;
|
||||
new_name_ptr=new_name;
|
||||
|
||||
@ -3873,7 +3903,14 @@ void MYSQL_BIN_LOG::new_file_impl(bool need_lock)
|
||||
*/
|
||||
Rotate_log_event r(new_name+dirname_length(new_name),
|
||||
0, LOG_EVENT_OFFSET, is_relay_log ? Rotate_log_event::RELAY_LOG : 0);
|
||||
r.write(&log_file);
|
||||
if(DBUG_EVALUATE_IF("fault_injection_new_file_rotate_event", (error=close_on_error=TRUE), FALSE) ||
|
||||
(error= r.write(&log_file)))
|
||||
{
|
||||
DBUG_EXECUTE_IF("fault_injection_new_file_rotate_event", errno=2;);
|
||||
close_on_error= TRUE;
|
||||
my_printf_error(ER_ERROR_ON_WRITE, ER(ER_CANT_OPEN_FILE), MYF(ME_FATALERROR), name, errno);
|
||||
goto end;
|
||||
}
|
||||
bytes_written += r.data_written;
|
||||
}
|
||||
/*
|
||||
@ -3901,17 +3938,56 @@ void MYSQL_BIN_LOG::new_file_impl(bool need_lock)
|
||||
*/
|
||||
|
||||
/* reopen index binlog file, BUG#34582 */
|
||||
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);
|
||||
file_to_open= index_file_name;
|
||||
error= open_index_file(index_file_name, 0, FALSE);
|
||||
if (!error)
|
||||
{
|
||||
/* reopen the binary log file. */
|
||||
file_to_open= new_name_ptr;
|
||||
error= open(old_name, log_type, new_name_ptr, io_cache_type,
|
||||
no_auto_events, max_size, 1, FALSE);
|
||||
}
|
||||
|
||||
/* handle reopening errors */
|
||||
if (error)
|
||||
{
|
||||
my_printf_error(ER_CANT_OPEN_FILE, ER(ER_CANT_OPEN_FILE),
|
||||
MYF(ME_FATALERROR), file_to_open, error);
|
||||
close_on_error= TRUE;
|
||||
}
|
||||
|
||||
my_free(old_name,MYF(0));
|
||||
|
||||
end:
|
||||
|
||||
if (error && close_on_error /* rotate or reopen failed */)
|
||||
{
|
||||
/*
|
||||
Close whatever was left opened.
|
||||
|
||||
We are keeping the behavior as it exists today, ie,
|
||||
we disable logging and move on (see: BUG#51014).
|
||||
|
||||
TODO: as part of WL#1790 consider other approaches:
|
||||
- kill mysql (safety);
|
||||
- try multiple locations for opening a log file;
|
||||
- switch server to protected/readonly mode
|
||||
- ...
|
||||
*/
|
||||
close(LOG_CLOSE_INDEX);
|
||||
sql_print_error("Could not open %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, shutdown the MySQL "
|
||||
"server and restart it.",
|
||||
new_name_ptr, errno);
|
||||
}
|
||||
|
||||
if (need_lock)
|
||||
pthread_mutex_unlock(&LOCK_log);
|
||||
pthread_mutex_unlock(&LOCK_index);
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
|
||||
|
||||
@ -3934,8 +4010,7 @@ bool MYSQL_BIN_LOG::append(Log_event* ev)
|
||||
bytes_written+= ev->data_written;
|
||||
DBUG_PRINT("info",("max_size: %lu",max_size));
|
||||
if ((uint) my_b_append_tell(&log_file) > max_size)
|
||||
new_file_without_locking();
|
||||
|
||||
error= new_file_without_locking();
|
||||
err:
|
||||
pthread_mutex_unlock(&LOCK_log);
|
||||
signal_update(); // Safe as we don't call close
|
||||
@ -3964,8 +4039,7 @@ bool MYSQL_BIN_LOG::appendv(const char* buf, uint len,...)
|
||||
} while ((buf=va_arg(args,const char*)) && (len=va_arg(args,uint)));
|
||||
DBUG_PRINT("info",("max_size: %lu",max_size));
|
||||
if ((uint) my_b_append_tell(&log_file) > max_size)
|
||||
new_file_without_locking();
|
||||
|
||||
error= new_file_without_locking();
|
||||
err:
|
||||
if (!error)
|
||||
signal_update();
|
||||
@ -4314,7 +4388,7 @@ MYSQL_BIN_LOG::flush_and_set_pending_rows_event(THD *thd,
|
||||
if (!error)
|
||||
{
|
||||
signal_update();
|
||||
rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED);
|
||||
error= rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED);
|
||||
}
|
||||
}
|
||||
|
||||
@ -4512,7 +4586,9 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info)
|
||||
if (flush_and_sync())
|
||||
goto err;
|
||||
signal_update();
|
||||
rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED);
|
||||
if ((error= rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED)))
|
||||
goto err;
|
||||
|
||||
}
|
||||
error=0;
|
||||
|
||||
@ -4595,8 +4671,19 @@ bool general_log_write(THD *thd, enum enum_server_command command,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void MYSQL_BIN_LOG::rotate_and_purge(uint flags)
|
||||
/**
|
||||
@note
|
||||
If rotation fails, for instance the server was unable
|
||||
to create a new log file, we still try to write an
|
||||
incident event to the current log.
|
||||
|
||||
@retval
|
||||
nonzero - error
|
||||
*/
|
||||
int MYSQL_BIN_LOG::rotate_and_purge(uint flags)
|
||||
{
|
||||
int error= 0;
|
||||
DBUG_ENTER("MYSQL_BIN_LOG::rotate_and_purge");
|
||||
#ifdef HAVE_REPLICATION
|
||||
bool check_purge= false;
|
||||
#endif
|
||||
@ -4605,26 +4692,38 @@ void MYSQL_BIN_LOG::rotate_and_purge(uint flags)
|
||||
if ((flags & RP_FORCE_ROTATE) ||
|
||||
(my_b_tell(&log_file) >= (my_off_t) max_size))
|
||||
{
|
||||
new_file_without_locking();
|
||||
if ((error= new_file_without_locking()))
|
||||
/**
|
||||
Be conservative... There are possible lost events (eg,
|
||||
failing to log the Execute_load_query_log_event
|
||||
on a LOAD DATA while using a non-transactional
|
||||
table)!
|
||||
|
||||
We give it a shot and try to write an incident event anyway
|
||||
to the current log.
|
||||
*/
|
||||
if (!write_incident(current_thd, FALSE))
|
||||
flush_and_sync();
|
||||
|
||||
#ifdef HAVE_REPLICATION
|
||||
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)
|
||||
if (!error && 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
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
|
||||
uint MYSQL_BIN_LOG::next_file_id()
|
||||
@ -4816,6 +4915,10 @@ bool MYSQL_BIN_LOG::write_incident(THD *thd, bool lock)
|
||||
{
|
||||
uint error= 0;
|
||||
DBUG_ENTER("MYSQL_BIN_LOG::write_incident");
|
||||
|
||||
if (!is_open())
|
||||
DBUG_RETURN(error);
|
||||
|
||||
LEX_STRING const write_error_msg=
|
||||
{ C_STRING_WITH_LEN("error writing to the binary log") };
|
||||
Incident incident= INCIDENT_LOST_EVENTS;
|
||||
@ -4829,7 +4932,7 @@ bool MYSQL_BIN_LOG::write_incident(THD *thd, bool lock)
|
||||
if (!error && !(error= flush_and_sync()))
|
||||
{
|
||||
signal_update();
|
||||
rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED);
|
||||
error= rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED);
|
||||
}
|
||||
pthread_mutex_unlock(&LOCK_log);
|
||||
}
|
||||
@ -4948,7 +5051,8 @@ bool MYSQL_BIN_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event,
|
||||
pthread_mutex_unlock(&LOCK_prep_xids);
|
||||
}
|
||||
else
|
||||
rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED);
|
||||
if (rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED))
|
||||
goto err;
|
||||
}
|
||||
VOID(pthread_mutex_unlock(&LOCK_log));
|
||||
|
||||
@ -5144,80 +5248,26 @@ void sql_perror(const char *message)
|
||||
}
|
||||
|
||||
|
||||
#ifdef __WIN__
|
||||
/*
|
||||
Change the file associated with two output streams. Used to
|
||||
redirect stdout and stderr to a file. The streams are reopened
|
||||
only for appending (writing at end of file).
|
||||
*/
|
||||
extern "C" my_bool reopen_fstreams(const char *filename,
|
||||
FILE *outstream, FILE *errstream)
|
||||
{
|
||||
int handle_fd;
|
||||
int err_fd, out_fd;
|
||||
HANDLE osfh;
|
||||
if (outstream && !my_freopen(filename, "a", outstream))
|
||||
return TRUE;
|
||||
|
||||
DBUG_ASSERT(filename && errstream);
|
||||
|
||||
// Services don't have stdout/stderr on Windows, so _fileno returns -1.
|
||||
err_fd= _fileno(errstream);
|
||||
if (err_fd < 0)
|
||||
{
|
||||
if (!freopen(filename, "a+", errstream))
|
||||
return TRUE;
|
||||
if (errstream && !my_freopen(filename, "a", errstream))
|
||||
return TRUE;
|
||||
|
||||
/* The error stream must be unbuffered. */
|
||||
if (errstream)
|
||||
setbuf(errstream, NULL);
|
||||
err_fd= _fileno(errstream);
|
||||
}
|
||||
|
||||
if (outstream)
|
||||
{
|
||||
out_fd= _fileno(outstream);
|
||||
if (out_fd < 0)
|
||||
{
|
||||
if (!freopen(filename, "a+", outstream))
|
||||
return TRUE;
|
||||
out_fd= _fileno(outstream);
|
||||
}
|
||||
}
|
||||
|
||||
if ((osfh= CreateFile(filename, GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE |
|
||||
FILE_SHARE_DELETE, NULL,
|
||||
OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL,
|
||||
NULL)) == INVALID_HANDLE_VALUE)
|
||||
return TRUE;
|
||||
|
||||
if ((handle_fd= _open_osfhandle((intptr_t)osfh,
|
||||
_O_APPEND | _O_TEXT)) == -1)
|
||||
{
|
||||
CloseHandle(osfh);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (_dup2(handle_fd, err_fd) < 0)
|
||||
{
|
||||
CloseHandle(osfh);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (outstream && _dup2(handle_fd, out_fd) < 0)
|
||||
{
|
||||
CloseHandle(osfh);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
_close(handle_fd);
|
||||
return FALSE;
|
||||
}
|
||||
#else
|
||||
extern "C" my_bool reopen_fstreams(const char *filename,
|
||||
FILE *outstream, FILE *errstream)
|
||||
{
|
||||
if (outstream && !freopen(filename, "a+", outstream))
|
||||
return TRUE;
|
||||
|
||||
if (errstream && !freopen(filename, "a+", errstream))
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
@ -5784,7 +5834,7 @@ int TC_LOG_MMAP::sync()
|
||||
cookie points directly to the memory where xid was logged.
|
||||
*/
|
||||
|
||||
void TC_LOG_MMAP::unlog(ulong cookie, my_xid xid)
|
||||
int TC_LOG_MMAP::unlog(ulong cookie, my_xid xid)
|
||||
{
|
||||
PAGE *p=pages+(cookie/tc_log_page_size);
|
||||
my_xid *x=(my_xid *)(data+cookie);
|
||||
@ -5802,6 +5852,7 @@ void TC_LOG_MMAP::unlog(ulong cookie, my_xid xid)
|
||||
if (p->waiters == 0) // the page is in pool and ready to rock
|
||||
pthread_cond_signal(&COND_pool); // ping ... for overflow()
|
||||
pthread_mutex_unlock(&p->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void TC_LOG_MMAP::close()
|
||||
@ -6043,8 +6094,9 @@ int TC_LOG_BINLOG::log_xid(THD *thd, my_xid xid)
|
||||
DBUG_RETURN(!binlog_end_trans(thd, trx_data, &xle, TRUE));
|
||||
}
|
||||
|
||||
void TC_LOG_BINLOG::unlog(ulong cookie, my_xid xid)
|
||||
int TC_LOG_BINLOG::unlog(ulong cookie, my_xid xid)
|
||||
{
|
||||
DBUG_ENTER("TC_LOG_BINLOG::unlog");
|
||||
pthread_mutex_lock(&LOCK_prep_xids);
|
||||
DBUG_ASSERT(prepared_xids > 0);
|
||||
if (--prepared_xids == 0) {
|
||||
@ -6052,7 +6104,7 @@ void TC_LOG_BINLOG::unlog(ulong cookie, my_xid xid)
|
||||
pthread_cond_signal(&COND_prep_xids);
|
||||
}
|
||||
pthread_mutex_unlock(&LOCK_prep_xids);
|
||||
rotate_and_purge(0); // as ::write() did not rotate
|
||||
DBUG_RETURN(rotate_and_purge(0)); // as ::write() did not rotate
|
||||
}
|
||||
|
||||
int TC_LOG_BINLOG::recover(IO_CACHE *log, Format_description_log_event *fdle)
|
||||
|
Reference in New Issue
Block a user