Commit f89418b4 authored by sasha@mysql.sashanet.com's avatar sasha@mysql.sashanet.com

Merge work:/home/bk/mysql-4.0

into mysql.sashanet.com:/home/sasha/src/bk/mysql-4.0
parents 2f51cf20 beaf95b0
...@@ -21,6 +21,8 @@ ...@@ -21,6 +21,8 @@
#include <time.h> #include <time.h>
#include "log_event.h" #include "log_event.h"
#define PROBE_HEADER_LEN (4+EVENT_LEN_OFFSET)
#define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | CLIENT_LOCAL_FILES) #define CLIENT_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | CLIENT_LOCAL_FILES)
char server_version[SERVER_VERSION_LENGTH]; char server_version[SERVER_VERSION_LENGTH];
...@@ -288,6 +290,52 @@ static void dump_remote_table(NET* net, const char* db, const char* table) ...@@ -288,6 +290,52 @@ static void dump_remote_table(NET* net, const char* db, const char* table)
} }
} }
static int check_master_version(MYSQL* mysql)
{
MYSQL_RES* res = 0;
MYSQL_ROW row;
const char* version;
int old_format = 0;
if (mysql_query(mysql, "SELECT VERSION()")
|| !(res = mysql_store_result(mysql)))
{
mysql_close(mysql);
die("Error checking master version: %s",
mysql_error(mysql));
}
if (!(row = mysql_fetch_row(res)))
{
mysql_free_result(res);
mysql_close(mysql);
die("Master returned no rows for SELECT VERSION()");
return 1;
}
if (!(version = row[0]))
{
mysql_free_result(res);
mysql_close(mysql);
die("Master reported NULL for the version");
}
switch (*version)
{
case '3':
old_format = 1;
break;
case '4':
old_format = 0;
break;
default:
sql_print_error("Master reported unrecognized MySQL version '%s'",
version);
mysql_free_result(res);
mysql_close(mysql);
return 1;
}
mysql_free_result(res);
return old_format;
}
static void dump_remote_log_entries(const char* logname) static void dump_remote_log_entries(const char* logname)
{ {
...@@ -295,6 +343,9 @@ static void dump_remote_log_entries(const char* logname) ...@@ -295,6 +343,9 @@ static void dump_remote_log_entries(const char* logname)
char last_db[FN_REFLEN+1] = ""; char last_db[FN_REFLEN+1] = "";
uint len; uint len;
NET* net = &mysql->net; NET* net = &mysql->net;
int old_format;
old_format = check_master_version(mysql);
if(!position) position = 4; // protect the innocent from spam if(!position) position = 4; // protect the innocent from spam
if (position < 4) if (position < 4)
{ {
...@@ -307,7 +358,7 @@ static void dump_remote_log_entries(const char* logname) ...@@ -307,7 +358,7 @@ static void dump_remote_log_entries(const char* logname)
len = (uint) strlen(logname); len = (uint) strlen(logname);
int4store(buf + 6, 0); int4store(buf + 6, 0);
memcpy(buf + 10, logname,len); memcpy(buf + 10, logname,len);
if(simple_command(mysql, COM_BINLOG_DUMP, buf, len + 10, 1)) if (simple_command(mysql, COM_BINLOG_DUMP, buf, len + 10, 1))
die("Error sending the log dump command"); die("Error sending the log dump command");
for(;;) for(;;)
...@@ -322,7 +373,7 @@ static void dump_remote_log_entries(const char* logname) ...@@ -322,7 +373,7 @@ static void dump_remote_log_entries(const char* logname)
len, net->read_pos[5])); len, net->read_pos[5]));
Log_event * ev = Log_event::read_log_event( Log_event * ev = Log_event::read_log_event(
(const char*) net->read_pos + 1 , (const char*) net->read_pos + 1 ,
len - 1, &error); len - 1, &error, old_format);
if (ev) if (ev)
{ {
ev->print(result_file, short_form, last_db); ev->print(result_file, short_form, last_db);
...@@ -335,12 +386,34 @@ static void dump_remote_log_entries(const char* logname) ...@@ -335,12 +386,34 @@ static void dump_remote_log_entries(const char* logname)
} }
} }
static int check_header (IO_CACHE* file)
{
char buf[PROBE_HEADER_LEN];
int old_format;
my_off_t pos = my_b_tell(file);
my_b_seek(file, (my_off_t)0);
if (my_b_read(file, buf, sizeof(buf)))
die("Failed reading header");
if (buf[EVENT_TYPE_OFFSET+4] == START_EVENT)
{
uint event_len;
event_len = uint4korr(buf + EVENT_LEN_OFFSET + 4);
old_format = (event_len < LOG_EVENT_HEADER_LEN + START_HEADER_LEN);
}
else
old_format = 0;
my_b_seek(file, pos);
return old_format;
}
static void dump_local_log_entries(const char* logname) static void dump_local_log_entries(const char* logname)
{ {
File fd = -1; File fd = -1;
IO_CACHE cache,*file= &cache; IO_CACHE cache,*file= &cache;
ulonglong rec_count = 0; ulonglong rec_count = 0;
char last_db[FN_REFLEN+1] = ""; char last_db[FN_REFLEN+1] = "";
bool old_format = 0;
if (logname && logname[0] != '-') if (logname && logname[0] != '-')
{ {
...@@ -349,12 +422,14 @@ static void dump_local_log_entries(const char* logname) ...@@ -349,12 +422,14 @@ static void dump_local_log_entries(const char* logname)
if (init_io_cache(file, fd, 0, READ_CACHE, (my_off_t) position, 0, if (init_io_cache(file, fd, 0, READ_CACHE, (my_off_t) position, 0,
MYF(MY_WME | MY_NABP))) MYF(MY_WME | MY_NABP)))
exit(1); exit(1);
old_format = check_header(file);
} }
else else
{ {
if (init_io_cache(file, fileno(result_file), 0, READ_CACHE, (my_off_t) 0, if (init_io_cache(file, fileno(result_file), 0, READ_CACHE, (my_off_t) 0,
0, MYF(MY_WME | MY_NABP | MY_DONT_CHECK_FILESIZE))) 0, MYF(MY_WME | MY_NABP | MY_DONT_CHECK_FILESIZE)))
exit(1); exit(1);
old_format = check_header(file);
if (position) if (position)
{ {
/* skip 'position' characters from stdout */ /* skip 'position' characters from stdout */
...@@ -385,7 +460,7 @@ static void dump_local_log_entries(const char* logname) ...@@ -385,7 +460,7 @@ static void dump_local_log_entries(const char* logname)
char llbuff[21]; char llbuff[21];
my_off_t old_off = my_b_tell(file); my_off_t old_off = my_b_tell(file);
Log_event* ev = Log_event::read_log_event(file); Log_event* ev = Log_event::read_log_event(file, old_format);
if (!ev) if (!ev)
{ {
if (file->error) if (file->error)
......
...@@ -55,7 +55,8 @@ mysysobjects1 = my_init.lo my_static.lo my_malloc.lo my_realloc.lo \ ...@@ -55,7 +55,8 @@ mysysobjects1 = my_init.lo my_static.lo my_malloc.lo my_realloc.lo \
mf_loadpath.lo my_pthread.lo my_thr_init.lo \ mf_loadpath.lo my_pthread.lo my_thr_init.lo \
thr_mutex.lo mulalloc.lo string.lo default.lo \ thr_mutex.lo mulalloc.lo string.lo default.lo \
my_compress.lo array.lo my_once.lo list.lo my_net.lo \ my_compress.lo array.lo my_once.lo list.lo my_net.lo \
charset.lo hash.lo mf_iocache.lo my_seek.lo \ charset.lo hash.lo mf_iocache.lo \
mf_iocache2.lo my_seek.lo \
my_pread.lo mf_cache.lo my_vsnprintf.lo md5.lo my_pread.lo mf_cache.lo my_vsnprintf.lo md5.lo
# Not needed in the minimum library # Not needed in the minimum library
......
...@@ -168,6 +168,9 @@ while test $# -gt 0; do ...@@ -168,6 +168,9 @@ while test $# -gt 0; do
USE_MANAGER=1 USE_MANAGER=1
USE_RUNNING_SERVER= USE_RUNNING_SERVER=
;; ;;
--start-and-exit)
START_AND_EXIT=1
;;
--skip-innobase) --skip-innobase)
EXTRA_MASTER_MYSQLD_OPT="$EXTRA_MASTER_MYSQLD_OPT --skip-innobase" EXTRA_MASTER_MYSQLD_OPT="$EXTRA_MASTER_MYSQLD_OPT --skip-innobase"
EXTRA_SLAVE_MYSQLD_OPT="$EXTRA_SLAVE_MYSQLD_OPT --skip-innobase" ;; EXTRA_SLAVE_MYSQLD_OPT="$EXTRA_SLAVE_MYSQLD_OPT --skip-innobase" ;;
...@@ -1091,6 +1094,10 @@ then ...@@ -1091,6 +1094,10 @@ then
mysql_loadstd mysql_loadstd
fi fi
if [ "x$START_AND_EXIT" = "x1" ] ; then
echo "Servers started, exiting"
exit
fi
$ECHO "Starting Tests" $ECHO "Starting Tests"
......
...@@ -16,7 +16,7 @@ n ...@@ -16,7 +16,7 @@ n
2002 2002
show slave hosts; show slave hosts;
Server_id Host Port Rpl_recovery_rank Master_id Server_id Host Port Rpl_recovery_rank Master_id
2 127.0.0.1 9307 2 1 2 127.0.0.1 $SLAVE_MYPORT 2 1
drop table t1; drop table t1;
slave stop; slave stop;
drop table if exists t2; drop table if exists t2;
......
...@@ -15,7 +15,7 @@ create table t1 (s text); ...@@ -15,7 +15,7 @@ create table t1 (s text);
insert into t1 values('Could not break slave'),('Tried hard'); insert into t1 values('Could not break slave'),('Tried hard');
show slave status; show slave status;
Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Last_log_seq Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Last_log_seq
127.0.0.1 root 9999 60 master-bin.001 234 Yes 0 0 3 127.0.0.1 root $MASTER_MYPORT 60 master-bin.001 234 Yes 0 0 3
select * from t1; select * from t1;
s s
Could not break slave Could not break slave
...@@ -42,7 +42,7 @@ master-bin.003 ...@@ -42,7 +42,7 @@ master-bin.003
insert into t2 values (65); insert into t2 values (65);
show slave status; show slave status;
Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Last_log_seq Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Last_log_seq
127.0.0.1 root 9999 60 master-bin.003 202 Yes 0 0 3 127.0.0.1 root $MASTER_MYPORT 60 master-bin.003 127 Yes 0 0 2
select * from t2; select * from t2;
m m
34 34
...@@ -60,12 +60,12 @@ master-bin.005 ...@@ -60,12 +60,12 @@ master-bin.005
master-bin.006 master-bin.006
show master status; show master status;
File Position Binlog_do_db Binlog_ignore_db File Position Binlog_do_db Binlog_ignore_db
master-bin.006 710 master-bin.006 382
slave stop; slave stop;
slave start; slave start;
show slave status; show slave status;
Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Last_log_seq Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Last_log_seq
127.0.0.1 root 9999 60 master-bin.006 710 Yes 0 0 11 127.0.0.1 root $MASTER_MYPORT 60 master-bin.006 382 Yes 0 0 6
lock tables t3 read; lock tables t3 read;
select count(*) from t3 where n >= 4; select count(*) from t3 where n >= 4;
count(*) count(*)
......
...@@ -16,7 +16,7 @@ load data infile '../../std_data/words.dat' into table t1; ...@@ -16,7 +16,7 @@ load data infile '../../std_data/words.dat' into table t1;
drop table t1; drop table t1;
show binlog events; show binlog events;
Log_name Pos Event_type Server_id Log_seq Info Log_name Pos Event_type Server_id Log_seq Info
master-bin.001 4 Start 1 1 Server ver: $VERSION, Binlog ver: 2 master-bin.001 4 Start 1 1 Server ver: 4.0.1-alpha-debug-log, Binlog ver: 2
master-bin.001 79 Query 1 2 use test; create table t1(n int not null auto_increment primary key) master-bin.001 79 Query 1 2 use test; create table t1(n int not null auto_increment primary key)
master-bin.001 172 Intvar 1 3 INSERT_ID=1 master-bin.001 172 Intvar 1 3 INSERT_ID=1
master-bin.001 200 Query 1 4 use test; insert into t1 values (NULL) master-bin.001 200 Query 1 4 use test; insert into t1 values (NULL)
...@@ -41,7 +41,7 @@ insert into t1 values (1); ...@@ -41,7 +41,7 @@ insert into t1 values (1);
drop table t1; drop table t1;
show binlog events; show binlog events;
Log_name Pos Event_type Server_id Log_seq Info Log_name Pos Event_type Server_id Log_seq Info
master-bin.001 4 Start 1 1 Server ver: $VERSION, Binlog ver: 2 master-bin.001 4 Start 1 1 Server ver: 4.0.1-alpha-debug-log, Binlog ver: 2
master-bin.001 79 Query 1 2 use test; create table t1(n int not null auto_increment primary key) master-bin.001 79 Query 1 2 use test; create table t1(n int not null auto_increment primary key)
master-bin.001 172 Intvar 1 3 INSERT_ID=1 master-bin.001 172 Intvar 1 3 INSERT_ID=1
master-bin.001 200 Query 1 4 use test; insert into t1 values (NULL) master-bin.001 200 Query 1 4 use test; insert into t1 values (NULL)
...@@ -54,10 +54,9 @@ master-bin.001 627 Rotate 1 10 master-bin.002;pos=4 ...@@ -54,10 +54,9 @@ master-bin.001 627 Rotate 1 10 master-bin.002;pos=4
master-bin.001 668 Stop 1 11 master-bin.001 668 Stop 1 11
show binlog events in 'master-bin.002'; show binlog events in 'master-bin.002';
Log_name Pos Event_type Server_id Log_seq Info Log_name Pos Event_type Server_id Log_seq Info
master-bin.002 4 Start 1 1 Server ver: $VERSION, Binlog ver: 2 master-bin.002 4 Query 1 1 use test; create table t1 (n int)
master-bin.002 79 Query 1 2 use test; create table t1 (n int) master-bin.002 62 Query 1 2 use test; insert into t1 values (1)
master-bin.002 137 Query 1 3 use test; insert into t1 values (1) master-bin.002 122 Query 1 3 use test; drop table t1
master-bin.002 197 Query 1 4 use test; drop table t1
show master logs; show master logs;
Log_name Log_name
master-bin.001 master-bin.001
...@@ -69,7 +68,7 @@ slave-bin.001 ...@@ -69,7 +68,7 @@ slave-bin.001
slave-bin.002 slave-bin.002
show binlog events in 'slave-bin.001' from 4; show binlog events in 'slave-bin.001' from 4;
Log_name Pos Event_type Server_id Log_seq Info Log_name Pos Event_type Server_id Log_seq Info
slave-bin.001 4 Start 2 1 Server ver: $VERSION, Binlog ver: 2 slave-bin.001 4 Start 2 1 Server ver: 4.0.1-alpha-debug-log, Binlog ver: 2
slave-bin.001 79 Slave 2 3 host=127.0.0.1,port=$MASTER_MYPORT,log=master-bin.001,pos=4 slave-bin.001 79 Slave 2 3 host=127.0.0.1,port=$MASTER_MYPORT,log=master-bin.001,pos=4
slave-bin.001 132 Query 1 2 use test; create table t1(n int not null auto_increment primary key) slave-bin.001 132 Query 1 2 use test; create table t1(n int not null auto_increment primary key)
slave-bin.001 225 Intvar 1 3 INSERT_ID=1 slave-bin.001 225 Intvar 1 3 INSERT_ID=1
...@@ -83,14 +82,13 @@ slave-bin.001 689 Rotate 1 4 slave-bin.002;pos=4; forced by master ...@@ -83,14 +82,13 @@ slave-bin.001 689 Rotate 1 4 slave-bin.002;pos=4; forced by master
slave-bin.001 729 Stop 2 5 slave-bin.001 729 Stop 2 5
show binlog events in 'slave-bin.002' from 4; show binlog events in 'slave-bin.002' from 4;
Log_name Pos Event_type Server_id Log_seq Info Log_name Pos Event_type Server_id Log_seq Info
slave-bin.002 4 Start 2 1 Server ver: $VERSION, Binlog ver: 2 slave-bin.002 4 Slave 2 10 host=127.0.0.1,port=$MASTER_MYPORT,log=master-bin.002,pos=4
slave-bin.002 79 Slave 2 10 host=127.0.0.1,port=$MASTER_MYPORT,log=master-bin.002,pos=4 slave-bin.002 57 Query 1 1 use test; create table t1 (n int)
slave-bin.002 132 Query 1 2 use test; create table t1 (n int) slave-bin.002 115 Query 1 2 use test; insert into t1 values (1)
slave-bin.002 190 Query 1 3 use test; insert into t1 values (1) slave-bin.002 175 Query 1 3 use test; drop table t1
slave-bin.002 250 Query 1 4 use test; drop table t1
show slave status; show slave status;
Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Last_log_seq Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db Last_errno Last_error Skip_counter Last_log_seq
127.0.0.1 root $MASTER_MYPORT 1 master-bin.002 245 Yes 0 0 4 127.0.0.1 root $MASTER_MYPORT 1 master-bin.002 170 Yes 0 0 3
show new master for slave with master_log_file='master-bin.001' and show new master for slave with master_log_file='master-bin.001' and
master_log_pos=4 and master_log_seq=1 and master_server_id=1; master_log_pos=4 and master_log_seq=1 and master_server_id=1;
Log_name Log_pos Log_name Log_pos
...@@ -106,8 +104,8 @@ slave-bin.001 439 ...@@ -106,8 +104,8 @@ slave-bin.001 439
show new master for slave with master_log_file='master-bin.002' and show new master for slave with master_log_file='master-bin.002' and
master_log_pos=4 and master_log_seq=1 and master_server_id=1; master_log_pos=4 and master_log_seq=1 and master_server_id=1;
Log_name Log_pos Log_name Log_pos
slave-bin.002 132 slave-bin.002 57
show new master for slave with master_log_file='master-bin.002' and show new master for slave with master_log_file='master-bin.002' and
master_log_pos=137 and master_log_seq=3 and master_server_id=1; master_log_pos=137 and master_log_seq=3 and master_server_id=1;
Log_name Log_pos Log_name Log_pos
slave-bin.002 250 slave-bin.002 223
...@@ -23,7 +23,6 @@ insert into t1 values('Could not break slave'),('Tried hard'); ...@@ -23,7 +23,6 @@ insert into t1 values('Could not break slave'),('Tried hard');
save_master_pos; save_master_pos;
connection slave; connection slave;
sync_with_master; sync_with_master;
--replace_result 9306 9999 3334 9999 3335 9999
show slave status; show slave status;
select * from t1; select * from t1;
connection master; connection master;
...@@ -70,7 +69,6 @@ insert into t2 values (65); ...@@ -70,7 +69,6 @@ insert into t2 values (65);
save_master_pos; save_master_pos;
connection slave; connection slave;
sync_with_master; sync_with_master;
--replace_result 9306 9999 3334 9999 3335 9999
show slave status; show slave status;
select * from t2; select * from t2;
connection master; connection master;
...@@ -92,7 +90,6 @@ connection slave; ...@@ -92,7 +90,6 @@ connection slave;
slave stop; slave stop;
slave start; slave start;
sync_with_master; sync_with_master;
--replace_result 9306 9999 3334 9999 3335 9999
show slave status; show slave status;
# because of concurrent insert, the table may not be up to date # because of concurrent insert, the table may not be up to date
# if we do not lock # if we do not lock
......
...@@ -166,7 +166,8 @@ int init_io_cache(IO_CACHE *info, File file, uint cachesize, ...@@ -166,7 +166,8 @@ int init_io_cache(IO_CACHE *info, File file, uint cachesize,
info->seek_not_done= test(file >= 0 && type != READ_FIFO && info->seek_not_done= test(file >= 0 && type != READ_FIFO &&
type != READ_NET); type != READ_NET);
info->myflags=cache_myflags & ~(MY_NABP | MY_FNABP); info->myflags=cache_myflags & ~(MY_NABP | MY_FNABP);
info->rc_request_pos=info->rc_pos=info->buffer; info->rc_request_pos=info->rc_pos= info->write_pos = info->buffer;
info->write_pos = info->write_end = 0;
if (type == SEQ_READ_APPEND) if (type == SEQ_READ_APPEND)
{ {
info->append_read_pos = info->write_pos = info->append_buffer; info->append_read_pos = info->write_pos = info->append_buffer;
...@@ -308,6 +309,11 @@ my_bool reinit_io_cache(IO_CACHE *info, enum cache_type type, ...@@ -308,6 +309,11 @@ my_bool reinit_io_cache(IO_CACHE *info, enum cache_type type,
{ {
info->append_read_pos = info->write_pos = info->append_buffer; info->append_read_pos = info->write_pos = info->append_buffer;
} }
if (!info->write_pos)
info->write_pos = info->buffer;
if (!info->write_end)
info->write_end = info->buffer+info->buffer_length-
(seek_offset & (IO_SIZE-1));
info->type=type; info->type=type;
info->error=0; info->error=0;
init_read_function(info,type); init_read_function(info,type);
......
...@@ -81,7 +81,8 @@ static int find_uniq_filename(char *name) ...@@ -81,7 +81,8 @@ static int find_uniq_filename(char *name)
MYSQL_LOG::MYSQL_LOG(): last_time(0), query_start(0),index_file(-1), MYSQL_LOG::MYSQL_LOG(): last_time(0), query_start(0),index_file(-1),
name(0), log_type(LOG_CLOSED),write_error(0), name(0), log_type(LOG_CLOSED),write_error(0),
inited(0), log_seq(1), file_id(1),no_rotate(0) inited(0), log_seq(1), file_id(1),no_rotate(0),
need_start_event(1)
{ {
/* /*
We don't want to intialize LOCK_Log here as the thread system may We don't want to intialize LOCK_Log here as the thread system may
...@@ -136,9 +137,11 @@ bool MYSQL_LOG::open_index( int options) ...@@ -136,9 +137,11 @@ bool MYSQL_LOG::open_index( int options)
MYF(MY_WME))) < 0); MYF(MY_WME))) < 0);
} }
void MYSQL_LOG::init(enum_log_type log_type_arg) void MYSQL_LOG::init(enum_log_type log_type_arg,
enum cache_type io_cache_type_arg)
{ {
log_type = log_type_arg; log_type = log_type_arg;
io_cache_type = io_cache_type_arg;
if (!inited) if (!inited)
{ {
inited=1; inited=1;
...@@ -184,7 +187,7 @@ void MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg, ...@@ -184,7 +187,7 @@ void MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg,
if ((file=my_open(log_file_name,O_CREAT | O_APPEND | O_WRONLY | O_BINARY, if ((file=my_open(log_file_name,O_CREAT | O_APPEND | O_WRONLY | O_BINARY,
MYF(MY_WME | ME_WAITTANG))) < 0 || MYF(MY_WME | ME_WAITTANG))) < 0 ||
init_io_cache(&log_file, file, IO_SIZE, WRITE_CACHE, init_io_cache(&log_file, file, IO_SIZE, io_cache_type,
my_tell(file,MYF(MY_WME)), 0, MYF(MY_WME | MY_NABP))) my_tell(file,MYF(MY_WME)), 0, MYF(MY_WME | MY_NABP)))
goto err; goto err;
...@@ -220,6 +223,7 @@ void MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg, ...@@ -220,6 +223,7 @@ void MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg,
} }
else if (log_type == LOG_BIN) else if (log_type == LOG_BIN)
{ {
bool error;
/* /*
Explanation of the boolean black magic: Explanation of the boolean black magic:
if we are supposed to write magic number try write if we are supposed to write magic number try write
...@@ -232,10 +236,13 @@ void MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg, ...@@ -232,10 +236,13 @@ void MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg,
goto err; goto err;
log_seq = 1; log_seq = 1;
if (need_start_event)
{
Start_log_event s; Start_log_event s;
bool error;
s.set_log_seq(0, this); s.set_log_seq(0, this);
s.write(&log_file); s.write(&log_file);
need_start_event=0;
}
flush_io_cache(&log_file); flush_io_cache(&log_file);
pthread_mutex_lock(&LOCK_index); pthread_mutex_lock(&LOCK_index);
error=(my_write(index_file, (byte*) log_file_name, strlen(log_file_name), error=(my_write(index_file, (byte*) log_file_name, strlen(log_file_name),
...@@ -715,7 +722,8 @@ bool MYSQL_LOG::write(Log_event* event_info) ...@@ -715,7 +722,8 @@ bool MYSQL_LOG::write(Log_event* event_info)
file == &log_file && flush_io_cache(file)) file == &log_file && flush_io_cache(file))
goto err; goto err;
error=0; error=0;
should_rotate = (file == &log_file && my_b_tell(file) >= max_binlog_size); should_rotate = (file == &log_file &&
(uint)my_b_tell(file) >= max_binlog_size);
err: err:
if (error) if (error)
{ {
......
...@@ -149,12 +149,21 @@ static void cleanup_load_tmpdir() ...@@ -149,12 +149,21 @@ static void cleanup_load_tmpdir()
#endif #endif
Log_event::Log_event(const char* buf):cached_event_len(0),temp_buf(0) Log_event::Log_event(const char* buf, bool old_format):
cached_event_len(0),temp_buf(0)
{ {
when = uint4korr(buf); when = uint4korr(buf);
server_id = uint4korr(buf + SERVER_ID_OFFSET); server_id = uint4korr(buf + SERVER_ID_OFFSET);
if (old_format)
{
log_seq=0;
flags=0;
}
else
{
log_seq = uint4korr(buf + LOG_SEQ_OFFSET); log_seq = uint4korr(buf + LOG_SEQ_OFFSET);
flags = uint2korr(buf + FLAGS_OFFSET); flags = uint2korr(buf + FLAGS_OFFSET);
}
#ifndef MYSQL_CLIENT #ifndef MYSQL_CLIENT
thd = 0; thd = 0;
#endif #endif
...@@ -441,17 +450,24 @@ int Log_event::read_log_event(IO_CACHE* file, String* packet, ...@@ -441,17 +450,24 @@ int Log_event::read_log_event(IO_CACHE* file, String* packet,
#define UNLOCK_MUTEX #define UNLOCK_MUTEX
#endif #endif
#ifndef MYSQL_CLIENT
#define LOCK_MUTEX if(log_lock) pthread_mutex_lock(log_lock);
#else
#define LOCK_MUTEX
#endif
// allocates memory - the caller is responsible for clean-up // allocates memory - the caller is responsible for clean-up
#ifndef MYSQL_CLIENT #ifndef MYSQL_CLIENT
Log_event* Log_event::read_log_event(IO_CACHE* file, pthread_mutex_t* log_lock) Log_event* Log_event::read_log_event(IO_CACHE* file,
pthread_mutex_t* log_lock,
bool old_format)
#else #else
Log_event* Log_event::read_log_event(IO_CACHE* file) Log_event* Log_event::read_log_event(IO_CACHE* file, bool old_format)
#endif #endif
{ {
char head[LOG_EVENT_HEADER_LEN]; char head[LOG_EVENT_HEADER_LEN];
#ifndef MYSQL_CLIENT LOCK_MUTEX;
if(log_lock) pthread_mutex_lock(log_lock);
#endif
if (my_b_read(file, (byte *) head, sizeof(head))) if (my_b_read(file, (byte *) head, sizeof(head)))
{ {
UNLOCK_MUTEX; UNLOCK_MUTEX;
...@@ -489,7 +505,7 @@ Log_event* Log_event::read_log_event(IO_CACHE* file) ...@@ -489,7 +505,7 @@ Log_event* Log_event::read_log_event(IO_CACHE* file)
error = "read error"; error = "read error";
goto err; goto err;
} }
if ((res = read_log_event(buf, data_len, &error))) if ((res = read_log_event(buf, data_len, &error, old_format)))
res->register_temp_buf(buf); res->register_temp_buf(buf);
err: err:
UNLOCK_MUTEX; UNLOCK_MUTEX;
...@@ -502,7 +518,7 @@ Log_event* Log_event::read_log_event(IO_CACHE* file) ...@@ -502,7 +518,7 @@ Log_event* Log_event::read_log_event(IO_CACHE* file)
} }
Log_event* Log_event::read_log_event(const char* buf, int event_len, Log_event* Log_event::read_log_event(const char* buf, int event_len,
const char **error) const char **error, bool old_format)
{ {
if (event_len < EVENT_LEN_OFFSET || if (event_len < EVENT_LEN_OFFSET ||
(uint)event_len != uint4korr(buf+EVENT_LEN_OFFSET)) (uint)event_len != uint4korr(buf+EVENT_LEN_OFFSET))
...@@ -513,14 +529,14 @@ Log_event* Log_event::read_log_event(const char* buf, int event_len, ...@@ -513,14 +529,14 @@ Log_event* Log_event::read_log_event(const char* buf, int event_len,
switch(buf[EVENT_TYPE_OFFSET]) switch(buf[EVENT_TYPE_OFFSET])
{ {
case QUERY_EVENT: case QUERY_EVENT:
ev = new Query_log_event(buf, event_len); ev = new Query_log_event(buf, event_len, old_format);
break; break;
case LOAD_EVENT: case LOAD_EVENT:
case NEW_LOAD_EVENT: case NEW_LOAD_EVENT:
ev = new Load_log_event(buf, event_len); ev = new Load_log_event(buf, event_len, old_format);
break; break;
case ROTATE_EVENT: case ROTATE_EVENT:
ev = new Rotate_log_event(buf, event_len); ev = new Rotate_log_event(buf, event_len, old_format);
break; break;
case SLAVE_EVENT: case SLAVE_EVENT:
ev = new Slave_log_event(buf, event_len); ev = new Slave_log_event(buf, event_len);
...@@ -538,13 +554,13 @@ Log_event* Log_event::read_log_event(const char* buf, int event_len, ...@@ -538,13 +554,13 @@ Log_event* Log_event::read_log_event(const char* buf, int event_len,
ev = new Execute_load_log_event(buf, event_len); ev = new Execute_load_log_event(buf, event_len);
break; break;
case START_EVENT: case START_EVENT:
ev = new Start_log_event(buf); ev = new Start_log_event(buf, old_format);
break; break;
case STOP_EVENT: case STOP_EVENT:
ev = new Stop_log_event(buf); ev = new Stop_log_event(buf, old_format);
break; break;
case INTVAR_EVENT: case INTVAR_EVENT:
ev = new Intvar_log_event(buf); ev = new Intvar_log_event(buf, old_format);
break; break;
default: default:
break; break;
...@@ -634,7 +650,8 @@ void Rotate_log_event::print(FILE* file, bool short_form, char* last_db) ...@@ -634,7 +650,8 @@ void Rotate_log_event::print(FILE* file, bool short_form, char* last_db)
#endif /* #ifdef MYSQL_CLIENT */ #endif /* #ifdef MYSQL_CLIENT */
Start_log_event::Start_log_event(const char* buf) :Log_event(buf) Start_log_event::Start_log_event(const char* buf,
bool old_format) :Log_event(buf, old_format)
{ {
binlog_version = uint2korr(buf + LOG_EVENT_HEADER_LEN + binlog_version = uint2korr(buf + LOG_EVENT_HEADER_LEN +
ST_BINLOG_VER_OFFSET); ST_BINLOG_VER_OFFSET);
...@@ -652,8 +669,9 @@ int Start_log_event::write_data(IO_CACHE* file) ...@@ -652,8 +669,9 @@ int Start_log_event::write_data(IO_CACHE* file)
return (my_b_write(file, (byte*) buff, sizeof(buff)) ? -1 : 0); return (my_b_write(file, (byte*) buff, sizeof(buff)) ? -1 : 0);
} }
Rotate_log_event::Rotate_log_event(const char* buf, int event_len): Rotate_log_event::Rotate_log_event(const char* buf, int event_len,
Log_event(buf),new_log_ident(NULL),alloced(0) bool old_format):
Log_event(buf, old_format),new_log_ident(NULL),alloced(0)
{ {
// the caller will ensure that event_len is what we have at // the caller will ensure that event_len is what we have at
// EVENT_LEN_OFFSET // EVENT_LEN_OFFSET
...@@ -695,8 +713,9 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg, ...@@ -695,8 +713,9 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
} }
#endif #endif
Query_log_event::Query_log_event(const char* buf, int event_len): Query_log_event::Query_log_event(const char* buf, int event_len,
Log_event(buf),data_buf(0), query(NULL), db(NULL) bool old_format):
Log_event(buf, old_format),data_buf(0), query(NULL), db(NULL)
{ {
if ((uint)event_len < QUERY_EVENT_OVERHEAD) if ((uint)event_len < QUERY_EVENT_OVERHEAD)
return; return;
...@@ -766,7 +785,8 @@ int Query_log_event::write_data(IO_CACHE* file) ...@@ -766,7 +785,8 @@ int Query_log_event::write_data(IO_CACHE* file)
my_b_write(file, (byte*) query, q_len)) ? -1 : 0; my_b_write(file, (byte*) query, q_len)) ? -1 : 0;
} }
Intvar_log_event::Intvar_log_event(const char* buf):Log_event(buf) Intvar_log_event::Intvar_log_event(const char* buf, bool old_format):
Log_event(buf, old_format)
{ {
buf += LOG_EVENT_HEADER_LEN; buf += LOG_EVENT_HEADER_LEN;
type = buf[I_TYPE_OFFSET]; type = buf[I_TYPE_OFFSET];
...@@ -1003,8 +1023,9 @@ Load_log_event::Load_log_event(THD* thd, sql_exchange* ex, ...@@ -1003,8 +1023,9 @@ Load_log_event::Load_log_event(THD* thd, sql_exchange* ex,
// the caller must do buf[event_len] = 0 before he starts using the // the caller must do buf[event_len] = 0 before he starts using the
// constructed event // constructed event
Load_log_event::Load_log_event(const char* buf, int event_len): Load_log_event::Load_log_event(const char* buf, int event_len,
Log_event(buf),num_fields(0),fields(0), bool old_format):
Log_event(buf, old_format),num_fields(0),fields(0),
field_lens(0),field_block_len(0), field_lens(0),field_block_len(0),
table_name(0),db(0),fname(0) table_name(0),db(0),fname(0)
{ {
...@@ -1237,7 +1258,7 @@ void Slave_log_event::init_from_mem_pool(int data_size) ...@@ -1237,7 +1258,7 @@ void Slave_log_event::init_from_mem_pool(int data_size)
} }
Slave_log_event::Slave_log_event(const char* buf, int event_len): Slave_log_event::Slave_log_event(const char* buf, int event_len):
Log_event(buf),mem_pool(0),master_host(0) Log_event(buf,0),mem_pool(0),master_host(0)
{ {
event_len -= LOG_EVENT_HEADER_LEN; event_len -= LOG_EVENT_HEADER_LEN;
if(event_len < 0) if(event_len < 0)
...@@ -1291,7 +1312,7 @@ int Create_file_log_event::write_base(IO_CACHE* file) ...@@ -1291,7 +1312,7 @@ int Create_file_log_event::write_base(IO_CACHE* file)
} }
Create_file_log_event::Create_file_log_event(const char* buf, int len): Create_file_log_event::Create_file_log_event(const char* buf, int len):
Load_log_event(buf,0),fake_base(0),block(0) Load_log_event(buf,0,0),fake_base(0),block(0)
{ {
int block_offset; int block_offset;
if (copy_log_event(buf,len)) if (copy_log_event(buf,len))
...@@ -1347,7 +1368,7 @@ Append_block_log_event::Append_block_log_event(THD* thd_arg, char* block_arg, ...@@ -1347,7 +1368,7 @@ Append_block_log_event::Append_block_log_event(THD* thd_arg, char* block_arg,
#endif #endif
Append_block_log_event::Append_block_log_event(const char* buf, int len): Append_block_log_event::Append_block_log_event(const char* buf, int len):
Log_event(buf),block(0) Log_event(buf, 0),block(0)
{ {
if((uint)len < APPEND_BLOCK_EVENT_OVERHEAD) if((uint)len < APPEND_BLOCK_EVENT_OVERHEAD)
return; return;
...@@ -1399,7 +1420,7 @@ Delete_file_log_event::Delete_file_log_event(THD* thd_arg): ...@@ -1399,7 +1420,7 @@ Delete_file_log_event::Delete_file_log_event(THD* thd_arg):
#endif #endif
Delete_file_log_event::Delete_file_log_event(const char* buf, int len): Delete_file_log_event::Delete_file_log_event(const char* buf, int len):
Log_event(buf),file_id(0) Log_event(buf, 0),file_id(0)
{ {
if((uint)len < DELETE_FILE_EVENT_OVERHEAD) if((uint)len < DELETE_FILE_EVENT_OVERHEAD)
return; return;
...@@ -1446,7 +1467,7 @@ Execute_load_log_event::Execute_load_log_event(THD* thd_arg): ...@@ -1446,7 +1467,7 @@ Execute_load_log_event::Execute_load_log_event(THD* thd_arg):
#endif #endif
Execute_load_log_event::Execute_load_log_event(const char* buf,int len): Execute_load_log_event::Execute_load_log_event(const char* buf,int len):
Log_event(buf),file_id(0) Log_event(buf, 0),file_id(0)
{ {
if((uint)len < EXEC_LOAD_EVENT_OVERHEAD) if((uint)len < EXEC_LOAD_EVENT_OVERHEAD)
return; return;
...@@ -1657,15 +1678,11 @@ int Load_log_event::exec_event(NET* net, struct st_master_info* mi) ...@@ -1657,15 +1678,11 @@ int Load_log_event::exec_event(NET* net, struct st_master_info* mi)
int Start_log_event::exec_event(struct st_master_info* mi) int Start_log_event::exec_event(struct st_master_info* mi)
{ {
#ifdef TO_BE_DELETED if (!mi->old_format)
/* {
We can't close temporary files or cleanup the tmpdir here, becasue
someone may have just rotated the logs on the master.
We should only do this cleanup when we know the master restarted.
*/
close_temporary_tables(thd); close_temporary_tables(thd);
cleanup_load_tmpdir(); cleanup_load_tmpdir();
#endif }
return Log_event::exec_event(mi); return Log_event::exec_event(mi);
} }
...@@ -1866,7 +1883,9 @@ int Execute_load_log_event::exec_event(struct st_master_info* mi) ...@@ -1866,7 +1883,9 @@ int Execute_load_log_event::exec_event(struct st_master_info* mi)
slave_print_error(my_errno, "Could not open file '%s'", fname); slave_print_error(my_errno, "Could not open file '%s'", fname);
goto err; goto err;
} }
if (!(lev = (Load_log_event*)Log_event::read_log_event(&file,0)) if (!(lev = (Load_log_event*)Log_event::read_log_event(&file,
(pthread_mutex_t*)0,
(bool)0))
|| lev->get_type_code() != NEW_LOAD_EVENT) || lev->get_type_code() != NEW_LOAD_EVENT)
{ {
slave_print_error(0, "File '%s' appears corrupted", fname); slave_print_error(0, "File '%s' appears corrupted", fname);
......
...@@ -242,7 +242,7 @@ class Log_event ...@@ -242,7 +242,7 @@ class Log_event
virtual Log_event_type get_type_code() = 0; virtual Log_event_type get_type_code() = 0;
virtual bool is_valid() = 0; virtual bool is_valid() = 0;
virtual bool get_cache_stmt() { return 0; } virtual bool get_cache_stmt() { return 0; }
Log_event(const char* buf); Log_event(const char* buf, bool old_format);
#ifndef MYSQL_CLIENT #ifndef MYSQL_CLIENT
Log_event(THD* thd_arg, uint16 flags_arg = 0); Log_event(THD* thd_arg, uint16 flags_arg = 0);
#endif #endif
...@@ -268,12 +268,14 @@ class Log_event ...@@ -268,12 +268,14 @@ class Log_event
#ifndef MYSQL_CLIENT #ifndef MYSQL_CLIENT
// if mutex is 0, the read will proceed without mutex // if mutex is 0, the read will proceed without mutex
static Log_event* read_log_event(IO_CACHE* file, pthread_mutex_t* log_lock); static Log_event* read_log_event(IO_CACHE* file,
pthread_mutex_t* log_lock,
bool old_format);
#else // avoid having to link mysqlbinlog against libpthread #else // avoid having to link mysqlbinlog against libpthread
static Log_event* read_log_event(IO_CACHE* file); static Log_event* read_log_event(IO_CACHE* file, bool old_format);
#endif #endif
static Log_event* read_log_event(const char* buf, int event_len, static Log_event* read_log_event(const char* buf, int event_len,
const char **error); const char **error, bool old_format);
const char* get_type_str(); const char* get_type_str();
#ifndef MYSQL_CLIENT #ifndef MYSQL_CLIENT
...@@ -317,7 +319,7 @@ class Query_log_event: public Log_event ...@@ -317,7 +319,7 @@ class Query_log_event: public Log_event
bool get_cache_stmt() { return cache_stmt; } bool get_cache_stmt() { return cache_stmt; }
#endif #endif
Query_log_event(const char* buf, int event_len); Query_log_event(const char* buf, int event_len, bool old_format);
~Query_log_event() ~Query_log_event()
{ {
if (data_buf) if (data_buf)
...@@ -411,7 +413,7 @@ class Load_log_event: public Log_event ...@@ -411,7 +413,7 @@ class Load_log_event: public Log_event
int exec_event(NET* net, struct st_master_info* mi); int exec_event(NET* net, struct st_master_info* mi);
#endif #endif
Load_log_event(const char* buf, int event_len); Load_log_event(const char* buf, int event_len, bool old_format);
~Load_log_event() ~Load_log_event()
{ {
} }
...@@ -451,7 +453,7 @@ class Start_log_event: public Log_event ...@@ -451,7 +453,7 @@ class Start_log_event: public Log_event
memcpy(server_version, ::server_version, ST_SERVER_VER_LEN); memcpy(server_version, ::server_version, ST_SERVER_VER_LEN);
} }
#endif #endif
Start_log_event(const char* buf); Start_log_event(const char* buf, bool old_format);
~Start_log_event() {} ~Start_log_event() {}
Log_event_type get_type_code() { return START_EVENT;} Log_event_type get_type_code() { return START_EVENT;}
int write_data(IO_CACHE* file); int write_data(IO_CACHE* file);
...@@ -479,7 +481,7 @@ class Intvar_log_event: public Log_event ...@@ -479,7 +481,7 @@ class Intvar_log_event: public Log_event
:Log_event(thd_arg),val(val_arg),type(type_arg) :Log_event(thd_arg),val(val_arg),type(type_arg)
{} {}
#endif #endif
Intvar_log_event(const char* buf); Intvar_log_event(const char* buf, bool old_format);
~Intvar_log_event() {} ~Intvar_log_event() {}
Log_event_type get_type_code() { return INTVAR_EVENT;} Log_event_type get_type_code() { return INTVAR_EVENT;}
const char* get_var_type_name(); const char* get_var_type_name();
...@@ -503,7 +505,8 @@ class Stop_log_event: public Log_event ...@@ -503,7 +505,8 @@ class Stop_log_event: public Log_event
Stop_log_event() :Log_event((THD*)0) Stop_log_event() :Log_event((THD*)0)
{} {}
#endif #endif
Stop_log_event(const char* buf):Log_event(buf) Stop_log_event(const char* buf, bool old_format):Log_event(buf,
old_format)
{ {
} }
~Stop_log_event() {} ~Stop_log_event() {}
...@@ -534,7 +537,7 @@ class Rotate_log_event: public Log_event ...@@ -534,7 +537,7 @@ class Rotate_log_event: public Log_event
alloced(0) alloced(0)
{} {}
#endif #endif
Rotate_log_event(const char* buf, int event_len); Rotate_log_event(const char* buf, int event_len, bool old_format);
~Rotate_log_event() ~Rotate_log_event()
{ {
if (alloced) if (alloced)
...@@ -686,7 +689,6 @@ class Execute_load_log_event: public Log_event ...@@ -686,7 +689,6 @@ class Execute_load_log_event: public Log_event
#endif #endif
}; };
#endif #endif
......
...@@ -20,12 +20,21 @@ ...@@ -20,12 +20,21 @@
#include "repl_failsafe.h" #include "repl_failsafe.h"
#include "sql_repl.h" #include "sql_repl.h"
#include "slave.h" #include "slave.h"
#include "sql_acl.h"
#include "mini_client.h" #include "mini_client.h"
#include "log_event.h"
#include <mysql.h> #include <mysql.h>
#include <thr_alarm.h>
#define SLAVE_LIST_CHUNK 128
#define SLAVE_ERRMSG_SIZE (FN_REFLEN+64)
RPL_STATUS rpl_status=RPL_NULL; RPL_STATUS rpl_status=RPL_NULL;
pthread_mutex_t LOCK_rpl_status; pthread_mutex_t LOCK_rpl_status;
pthread_cond_t COND_rpl_status; pthread_cond_t COND_rpl_status;
HASH slave_list;
extern const char* any_db;
const char *rpl_role_type[] = {"MASTER","SLAVE",NullS}; const char *rpl_role_type[] = {"MASTER","SLAVE",NullS};
TYPELIB rpl_role_typelib = {array_elements(rpl_role_type)-1,"", TYPELIB rpl_role_typelib = {array_elements(rpl_role_type)-1,"",
...@@ -37,6 +46,10 @@ const char* rpl_status_type[] = {"AUTH_MASTER","ACTIVE_SLAVE","IDLE_SLAVE", ...@@ -37,6 +46,10 @@ const char* rpl_status_type[] = {"AUTH_MASTER","ACTIVE_SLAVE","IDLE_SLAVE",
TYPELIB rpl_status_typelib= {array_elements(rpl_status_type)-1,"", TYPELIB rpl_status_typelib= {array_elements(rpl_status_type)-1,"",
rpl_status_type}; rpl_status_type};
static Slave_log_event* find_slave_event(IO_CACHE* log,
const char* log_file_name,
char* errmsg);
static int init_failsafe_rpl_thread(THD* thd) static int init_failsafe_rpl_thread(THD* thd)
{ {
DBUG_ENTER("init_failsafe_rpl_thread"); DBUG_ENTER("init_failsafe_rpl_thread");
...@@ -89,6 +102,333 @@ void change_rpl_status(RPL_STATUS from_status, RPL_STATUS to_status) ...@@ -89,6 +102,333 @@ void change_rpl_status(RPL_STATUS from_status, RPL_STATUS to_status)
pthread_mutex_unlock(&LOCK_rpl_status); pthread_mutex_unlock(&LOCK_rpl_status);
} }
#define get_object(p, obj) \
{\
uint len = (uint)*p++; \
if (p + len > p_end || len >= sizeof(obj)) \
goto err; \
strmake(obj,(char*) p,len); \
p+= len; \
}\
static inline int cmp_master_pos(Slave_log_event* sev, LEX_MASTER_INFO* mi)
{
return cmp_master_pos(sev->master_log, sev->master_pos, mi->log_file_name,
mi->pos);
}
void unregister_slave(THD* thd, bool only_mine, bool need_mutex)
{
if (need_mutex)
pthread_mutex_lock(&LOCK_slave_list);
if (thd->server_id)
{
SLAVE_INFO* old_si;
if ((old_si = (SLAVE_INFO*)hash_search(&slave_list,
(byte*)&thd->server_id, 4)) &&
(!only_mine || old_si->thd == thd))
hash_delete(&slave_list, (byte*)old_si);
}
if (need_mutex)
pthread_mutex_unlock(&LOCK_slave_list);
}
int register_slave(THD* thd, uchar* packet, uint packet_length)
{
SLAVE_INFO *si;
int res = 1;
uchar* p = packet, *p_end = packet + packet_length;
if (check_access(thd, FILE_ACL, any_db))
return 1;
if (!(si = (SLAVE_INFO*)my_malloc(sizeof(SLAVE_INFO), MYF(MY_WME))))
goto err;
thd->server_id = si->server_id = uint4korr(p);
p += 4;
get_object(p,si->host);
get_object(p,si->user);
get_object(p,si->password);
si->port = uint2korr(p);
p += 2;
si->rpl_recovery_rank = uint4korr(p);
p += 4;
if (!(si->master_id = uint4korr(p)))
si->master_id = server_id;
si->thd = thd;
pthread_mutex_lock(&LOCK_slave_list);
unregister_slave(thd,0,0);
res = hash_insert(&slave_list, (byte*) si);
pthread_mutex_unlock(&LOCK_slave_list);
return res;
err:
if (si)
my_free((gptr) si, MYF(MY_WME));
return res;
}
static uint32* slave_list_key(SLAVE_INFO* si, uint* len,
my_bool not_used __attribute__((unused)))
{
*len = 4;
return &si->server_id;
}
static void slave_info_free(void *s)
{
my_free((gptr) s, MYF(MY_WME));
}
void init_slave_list()
{
hash_init(&slave_list, SLAVE_LIST_CHUNK, 0, 0,
(hash_get_key) slave_list_key, slave_info_free, 0);
pthread_mutex_init(&LOCK_slave_list, MY_MUTEX_INIT_FAST);
}
void end_slave_list()
{
pthread_mutex_lock(&LOCK_slave_list);
hash_free(&slave_list);
pthread_mutex_unlock(&LOCK_slave_list);
pthread_mutex_destroy(&LOCK_slave_list);
}
static int find_target_pos(LEX_MASTER_INFO* mi, IO_CACHE* log, char* errmsg)
{
uint32 log_seq = mi->last_log_seq;
uint32 target_server_id = mi->server_id;
for (;;)
{
Log_event* ev;
if (!(ev = Log_event::read_log_event(log, (pthread_mutex_t*)0,
0)))
{
if (log->error > 0)
strmov(errmsg, "Binary log truncated in the middle of event");
else if (log->error < 0)
strmov(errmsg, "I/O error reading binary log");
else
strmov(errmsg, "Could not find target event in the binary log");
return 1;
}
if (ev->log_seq == log_seq && ev->server_id == target_server_id)
{
delete ev;
mi->pos = my_b_tell(log);
return 0;
}
delete ev;
}
}
int translate_master(THD* thd, LEX_MASTER_INFO* mi, char* errmsg)
{
LOG_INFO linfo;
char search_file_name[FN_REFLEN],last_log_name[FN_REFLEN];
IO_CACHE log;
File file = -1, last_file = -1;
pthread_mutex_t *log_lock;
const char* errmsg_p;
Slave_log_event* sev = 0;
my_off_t last_pos = 0;
int error = 1;
int cmp_res;
LINT_INIT(cmp_res);
if (!mysql_bin_log.is_open())
{
strmov(errmsg,"Binary log is not open");
return 1;
}
if (!server_id_supplied)
{
strmov(errmsg, "Misconfigured master - server id was not set");
return 1;
}
linfo.index_file_offset = 0;
search_file_name[0] = 0;
if (mysql_bin_log.find_first_log(&linfo, search_file_name))
{
strmov(errmsg,"Could not find first log");
return 1;
}
thd->current_linfo = &linfo;
bzero((char*) &log,sizeof(log));
log_lock = mysql_bin_log.get_log_lock();
pthread_mutex_lock(log_lock);
for (;;)
{
if ((file=open_binlog(&log, linfo.log_file_name, &errmsg_p)) < 0)
{
strmov(errmsg, errmsg_p);
goto err;
}
if (!(sev = find_slave_event(&log, linfo.log_file_name, errmsg)))
goto err;
cmp_res = cmp_master_pos(sev, mi);
delete sev;
if (!cmp_res)
{
/* Copy basename */
fn_format(mi->log_file_name, linfo.log_file_name, "","",1);
mi->pos = my_b_tell(&log);
goto mi_inited;
}
else if (cmp_res > 0)
{
if (!last_pos)
{
strmov(errmsg,
"Slave event in first log points past the target position");
goto err;
}
end_io_cache(&log);
(void) my_close(file, MYF(MY_WME));
if (init_io_cache(&log, (file = last_file), IO_SIZE, READ_CACHE, 0, 0,
MYF(MY_WME)))
{
errmsg[0] = 0;
goto err;
}
break;
}
strmov(last_log_name, linfo.log_file_name);
last_pos = my_b_tell(&log);
switch (mysql_bin_log.find_next_log(&linfo)) {
case LOG_INFO_EOF:
if (last_file >= 0)
(void)my_close(last_file, MYF(MY_WME));
last_file = -1;
goto found_log;
case 0:
break;
default:
strmov(errmsg, "Error reading log index");
goto err;
}
end_io_cache(&log);
if (last_file >= 0)
(void) my_close(last_file, MYF(MY_WME));
last_file = file;
}
found_log:
my_b_seek(&log, last_pos);
if (find_target_pos(mi,&log,errmsg))
goto err;
fn_format(mi->log_file_name, last_log_name, "","",1); /* Copy basename */
mi_inited:
error = 0;
err:
pthread_mutex_unlock(log_lock);
end_io_cache(&log);
pthread_mutex_lock(&LOCK_thread_count);
thd->current_linfo = 0;
pthread_mutex_unlock(&LOCK_thread_count);
if (file >= 0)
(void) my_close(file, MYF(MY_WME));
if (last_file >= 0 && last_file != file)
(void) my_close(last_file, MYF(MY_WME));
return error;
}
// caller must delete result when done
static Slave_log_event* find_slave_event(IO_CACHE* log,
const char* log_file_name,
char* errmsg)
{
Log_event* ev;
int i;
bool slave_event_found = 0;
LINT_INIT(ev);
for (i = 0; i < 2; i++)
{
if (!(ev = Log_event::read_log_event(log, (pthread_mutex_t*)0, 0)))
{
my_snprintf(errmsg, SLAVE_ERRMSG_SIZE,
"Error reading event in log '%s'",
(char*)log_file_name);
return 0;
}
if (ev->get_type_code() == SLAVE_EVENT)
{
slave_event_found = 1;
break;
}
delete ev;
}
if (!slave_event_found)
{
my_snprintf(errmsg, SLAVE_ERRMSG_SIZE,
"Could not find slave event in log '%s'",
(char*)log_file_name);
delete ev;
return 0;
}
return (Slave_log_event*)ev;
}
int show_new_master(THD* thd)
{
DBUG_ENTER("show_new_master");
List<Item> field_list;
char errmsg[SLAVE_ERRMSG_SIZE];
LEX_MASTER_INFO* lex_mi = &thd->lex.mi;
errmsg[0]=0; // Safety
if (translate_master(thd, lex_mi, errmsg))
{
if (errmsg[0])
net_printf(&thd->net, ER_ERROR_WHEN_EXECUTING_COMMAND,
"SHOW NEW MASTER", errmsg);
else
send_error(&thd->net, 0);
DBUG_RETURN(1);
}
else
{
String* packet = &thd->packet;
field_list.push_back(new Item_empty_string("Log_name", 20));
field_list.push_back(new Item_empty_string("Log_pos", 20));
if (send_fields(thd, field_list, 1))
DBUG_RETURN(-1);
packet->length(0);
net_store_data(packet, lex_mi->log_file_name);
net_store_data(packet, (longlong)lex_mi->pos);
if (my_net_write(&thd->net, packet->ptr(), packet->length()))
DBUG_RETURN(-1);
send_eof(&thd->net);
DBUG_RETURN(0);
}
}
int update_slave_list(MYSQL* mysql) int update_slave_list(MYSQL* mysql)
{ {
MYSQL_RES* res=0; MYSQL_RES* res=0;
...@@ -216,6 +556,277 @@ pthread_handler_decl(handle_failsafe_rpl,arg) ...@@ -216,6 +556,277 @@ pthread_handler_decl(handle_failsafe_rpl,arg)
DBUG_RETURN(0); DBUG_RETURN(0);
} }
int show_slave_hosts(THD* thd)
{
List<Item> field_list;
NET* net = &thd->net;
String* packet = &thd->packet;
DBUG_ENTER("show_slave_hosts");
field_list.push_back(new Item_empty_string("Server_id", 20));
field_list.push_back(new Item_empty_string("Host", 20));
if (opt_show_slave_auth_info)
{
field_list.push_back(new Item_empty_string("User",20));
field_list.push_back(new Item_empty_string("Password",20));
}
field_list.push_back(new Item_empty_string("Port",20));
field_list.push_back(new Item_empty_string("Rpl_recovery_rank", 20));
field_list.push_back(new Item_empty_string("Master_id", 20));
if (send_fields(thd, field_list, 1))
DBUG_RETURN(-1);
pthread_mutex_lock(&LOCK_slave_list);
for (uint i = 0; i < slave_list.records; ++i)
{
SLAVE_INFO* si = (SLAVE_INFO*) hash_element(&slave_list, i);
packet->length(0);
net_store_data(packet, si->server_id);
net_store_data(packet, si->host);
if (opt_show_slave_auth_info)
{
net_store_data(packet, si->user);
net_store_data(packet, si->password);
}
net_store_data(packet, (uint32) si->port);
net_store_data(packet, si->rpl_recovery_rank);
net_store_data(packet, si->master_id);
if (my_net_write(net, (char*)packet->ptr(), packet->length()))
{
pthread_mutex_unlock(&LOCK_slave_list);
DBUG_RETURN(-1);
}
}
pthread_mutex_unlock(&LOCK_slave_list);
send_eof(net);
DBUG_RETURN(0);
}
int connect_to_master(THD *thd, MYSQL* mysql, MASTER_INFO* mi)
{
if (!mc_mysql_connect(mysql, mi->host, mi->user, mi->password, 0,
mi->port, 0, 0))
{
sql_print_error("Connection to master failed: %s",
mc_mysql_error(mysql));
return 1;
}
return 0;
}
static inline void cleanup_mysql_results(MYSQL_RES* db_res,
MYSQL_RES** cur, MYSQL_RES** start)
{
for( ; cur >= start; --cur)
{
if (*cur)
mc_mysql_free_result(*cur);
}
mc_mysql_free_result(db_res);
}
static inline int fetch_db_tables(THD* thd, MYSQL* mysql, const char* db,
MYSQL_RES* table_res)
{
MYSQL_ROW row;
for( row = mc_mysql_fetch_row(table_res); row;
row = mc_mysql_fetch_row(table_res))
{
TABLE_LIST table;
const char* table_name = row[0];
int error;
if (table_rules_on)
{
table.next = 0;
table.db = (char*)db;
table.real_name = (char*)table_name;
table.updating = 1;
if (!tables_ok(thd, &table))
continue;
}
if ((error = fetch_nx_table(thd, db, table_name, &glob_mi, mysql)))
return error;
}
return 0;
}
int load_master_data(THD* thd)
{
MYSQL mysql;
MYSQL_RES* master_status_res = 0;
bool slave_was_running = 0;
int error = 0;
mc_mysql_init(&mysql);
// we do not want anyone messing with the slave at all for the entire
// duration of the data load;
pthread_mutex_lock(&LOCK_slave);
// first, kill the slave
if ((slave_was_running = slave_running))
{
abort_slave = 1;
KICK_SLAVE;
thd->proc_info = "waiting for slave to die";
while (slave_running)
pthread_cond_wait(&COND_slave_stopped, &LOCK_slave); // wait until done
}
if (connect_to_master(thd, &mysql, &glob_mi))
{
net_printf(&thd->net, error = ER_CONNECT_TO_MASTER,
mc_mysql_error(&mysql));
goto err;
}
// now that we are connected, get all database and tables in each
{
MYSQL_RES *db_res, **table_res, **table_res_end, **cur_table_res;
uint num_dbs;
if (mc_mysql_query(&mysql, "show databases", 0) ||
!(db_res = mc_mysql_store_result(&mysql)))
{
net_printf(&thd->net, error = ER_QUERY_ON_MASTER,
mc_mysql_error(&mysql));
goto err;
}
if (!(num_dbs = (uint) mc_mysql_num_rows(db_res)))
goto err;
// in theory, the master could have no databases at all
// and run with skip-grant
if (!(table_res = (MYSQL_RES**)thd->alloc(num_dbs * sizeof(MYSQL_RES*))))
{
net_printf(&thd->net, error = ER_OUTOFMEMORY);
goto err;
}
// this is a temporary solution until we have online backup
// capabilities - to be replaced once online backup is working
// we wait to issue FLUSH TABLES WITH READ LOCK for as long as we
// can to minimize the lock time
if (mc_mysql_query(&mysql, "FLUSH TABLES WITH READ LOCK", 0) ||
mc_mysql_query(&mysql, "SHOW MASTER STATUS",0) ||
!(master_status_res = mc_mysql_store_result(&mysql)))
{
net_printf(&thd->net, error = ER_QUERY_ON_MASTER,
mc_mysql_error(&mysql));
goto err;
}
// go through every table in every database, and if the replication
// rules allow replicating it, get it
table_res_end = table_res + num_dbs;
for(cur_table_res = table_res; cur_table_res < table_res_end;
cur_table_res++)
{
// since we know how many rows we have, this can never be NULL
MYSQL_ROW row = mc_mysql_fetch_row(db_res);
char* db = row[0];
/*
Do not replicate databases excluded by rules
also skip mysql database - in most cases the user will
mess up and not exclude mysql database with the rules when
he actually means to - in this case, he is up for a surprise if
his priv tables get dropped and downloaded from master
TO DO - add special option, not enabled
by default, to allow inclusion of mysql database into load
data from master
*/
if (!db_ok(db, replicate_do_db, replicate_ignore_db) ||
!strcmp(db,"mysql"))
{
*cur_table_res = 0;
continue;
}
if (mysql_rm_db(thd, db, 1,1) ||
mysql_create_db(thd, db, 0, 1))
{
send_error(&thd->net, 0, 0);
cleanup_mysql_results(db_res, cur_table_res - 1, table_res);
goto err;
}
if (mc_mysql_select_db(&mysql, db) ||
mc_mysql_query(&mysql, "show tables", 0) ||
!(*cur_table_res = mc_mysql_store_result(&mysql)))
{
net_printf(&thd->net, error = ER_QUERY_ON_MASTER,
mc_mysql_error(&mysql));
cleanup_mysql_results(db_res, cur_table_res - 1, table_res);
goto err;
}
if ((error = fetch_db_tables(thd, &mysql, db, *cur_table_res)))
{
// we do not report the error - fetch_db_tables handles it
cleanup_mysql_results(db_res, cur_table_res, table_res);
goto err;
}
}
cleanup_mysql_results(db_res, cur_table_res - 1, table_res);
// adjust position in the master
if (master_status_res)
{
MYSQL_ROW row = mc_mysql_fetch_row(master_status_res);
/*
We need this check because the master may not be running with
log-bin, but it will still allow us to do all the steps
of LOAD DATA FROM MASTER - no reason to forbid it, really,
although it does not make much sense for the user to do it
*/
if (row[0] && row[1])
{
strmake(glob_mi.log_file_name, row[0], sizeof(glob_mi.log_file_name));
glob_mi.pos = atoi(row[1]); // atoi() is ok, since offset is <= 1GB
if (glob_mi.pos < 4)
glob_mi.pos = 4; // don't hit the magic number
glob_mi.pending = 0;
flush_master_info(&glob_mi);
}
mc_mysql_free_result(master_status_res);
}
if (mc_mysql_query(&mysql, "UNLOCK TABLES", 0))
{
net_printf(&thd->net, error = ER_QUERY_ON_MASTER,
mc_mysql_error(&mysql));
goto err;
}
}
err:
pthread_mutex_unlock(&LOCK_slave);
if (slave_was_running)
start_slave(0, 0);
mc_mysql_close(&mysql); // safe to call since we always do mc_mysql_init()
if (!error)
send_ok(&thd->net);
return error;
}
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
#define REPL_FAILSAFE_H #define REPL_FAILSAFE_H
#include "mysql.h" #include "mysql.h"
#include "my_sys.h"
#include "slave.h"
typedef enum {RPL_AUTH_MASTER=0,RPL_ACTIVE_SLAVE,RPL_IDLE_SLAVE, typedef enum {RPL_AUTH_MASTER=0,RPL_ACTIVE_SLAVE,RPL_IDLE_SLAVE,
RPL_LOST_SOLDIER,RPL_TROOP_SOLDIER, RPL_LOST_SOLDIER,RPL_TROOP_SOLDIER,
...@@ -19,4 +21,18 @@ pthread_handler_decl(handle_failsafe_rpl,arg); ...@@ -19,4 +21,18 @@ pthread_handler_decl(handle_failsafe_rpl,arg);
void change_rpl_status(RPL_STATUS from_status, RPL_STATUS to_status); void change_rpl_status(RPL_STATUS from_status, RPL_STATUS to_status);
int find_recovery_captain(THD* thd, MYSQL* mysql); int find_recovery_captain(THD* thd, MYSQL* mysql);
int update_slave_list(MYSQL* mysql); int update_slave_list(MYSQL* mysql);
extern HASH slave_list;
int load_master_data(THD* thd);
int connect_to_master(THD *thd, MYSQL* mysql, MASTER_INFO* mi);
int show_new_master(THD* thd);
int show_slave_hosts(THD* thd);
int translate_master(THD* thd, LEX_MASTER_INFO* mi, char* errmsg);
void init_slave_list();
void end_slave_list();
int register_slave(THD* thd, uchar* packet, uint packet_length);
void unregister_slave(THD* thd, bool only_mine, bool need_mutex);
#endif #endif
...@@ -61,6 +61,8 @@ static int safe_sleep(THD* thd, int sec); ...@@ -61,6 +61,8 @@ static int safe_sleep(THD* thd, int sec);
static int request_table_dump(MYSQL* mysql, const char* db, const char* table); static int request_table_dump(MYSQL* mysql, const char* db, const char* table);
static int create_table_from_dump(THD* thd, NET* net, const char* db, static int create_table_from_dump(THD* thd, NET* net, const char* db,
const char* table_name); const char* table_name);
static int check_master_version(MYSQL* mysql, MASTER_INFO* mi);
char* rewrite_db(char* db); char* rewrite_db(char* db);
static void free_table_ent(TABLE_RULE_ENT* e) static void free_table_ent(TABLE_RULE_ENT* e)
...@@ -333,6 +335,54 @@ static int init_intvar_from_file(int* var, IO_CACHE* f, int default_val) ...@@ -333,6 +335,54 @@ static int init_intvar_from_file(int* var, IO_CACHE* f, int default_val)
return 1; return 1;
} }
static int check_master_version(MYSQL* mysql, MASTER_INFO* mi)
{
MYSQL_RES* res;
MYSQL_ROW row;
const char* version;
const char* errmsg = 0;
if (mc_mysql_query(mysql, "SELECT VERSION()", 0)
|| !(res = mc_mysql_store_result(mysql)))
{
sql_print_error("Error checking master version: %s",
mc_mysql_error(mysql));
return 1;
}
if (!(row = mc_mysql_fetch_row(res)))
{
errmsg = "Master returned no rows for SELECT VERSION()";
goto err;
}
if (!(version = row[0]))
{
errmsg = "Master reported NULL for the version";
goto err;
}
switch (*version)
{
case '3':
mi->old_format = 1;
break;
case '4':
mi->old_format = 0;
break;
default:
errmsg = "Master reported unrecognized MySQL version";
goto err;
}
err:
if (res)
mc_mysql_free_result(res);
if (errmsg)
{
sql_print_error(errmsg);
return 1;
}
return 0;
}
static int create_table_from_dump(THD* thd, NET* net, const char* db, static int create_table_from_dump(THD* thd, NET* net, const char* db,
const char* table_name) const char* table_name)
...@@ -580,7 +630,7 @@ int init_master_info(MASTER_INFO* mi) ...@@ -580,7 +630,7 @@ int init_master_info(MASTER_INFO* mi)
mi->inited = 1; mi->inited = 1;
// now change the cache from READ to WRITE - must do this // now change the cache from READ to WRITE - must do this
// before flush_master_info // before flush_master_info
reinit_io_cache(&mi->file, WRITE_CACHE, 0L,0,1); reinit_io_cache(&mi->file, WRITE_CACHE,0L,0,1);
error=test(flush_master_info(mi)); error=test(flush_master_info(mi));
pthread_mutex_unlock(&mi->lock); pthread_mutex_unlock(&mi->lock);
return error; return error;
...@@ -943,12 +993,14 @@ static int exec_event(THD* thd, NET* net, MASTER_INFO* mi, int event_len) ...@@ -943,12 +993,14 @@ static int exec_event(THD* thd, NET* net, MASTER_INFO* mi, int event_len)
{ {
const char *error_msg; const char *error_msg;
Log_event * ev = Log_event::read_log_event((const char*)net->read_pos + 1, Log_event * ev = Log_event::read_log_event((const char*)net->read_pos + 1,
event_len, &error_msg); event_len, &error_msg,
mi->old_format);
if (ev) if (ev)
{ {
int type_code = ev->get_type_code(); int type_code = ev->get_type_code();
int exec_res; int exec_res;
if (ev->server_id == ::server_id || slave_skip_counter) if (ev->server_id == ::server_id ||
(slave_skip_counter && ev->get_type_code() != ROTATE_EVENT))
{ {
if(type_code == LOAD_EVENT) if(type_code == LOAD_EVENT)
skip_load_data_infile(net); skip_load_data_infile(net);
...@@ -1070,9 +1122,17 @@ pthread_handler_decl(handle_slave,arg __attribute__((unused))) ...@@ -1070,9 +1122,17 @@ pthread_handler_decl(handle_slave,arg __attribute__((unused)))
// register ourselves with the master // register ourselves with the master
// if fails, this is not fatal - we just print the error message and go // if fails, this is not fatal - we just print the error message and go
// on with life // on with life
thd->proc_info = "Checking master version";
if (check_master_version(mysql, &glob_mi))
{
goto err;
}
if (!glob_mi.old_format)
{
thd->proc_info = "Registering slave on master"; thd->proc_info = "Registering slave on master";
register_slave_on_master(mysql); if (register_slave_on_master(mysql) || update_slave_list(mysql))
update_slave_list(mysql); goto err;
}
while (!slave_killed(thd)) while (!slave_killed(thd))
{ {
......
...@@ -23,8 +23,10 @@ typedef struct st_master_info ...@@ -23,8 +23,10 @@ typedef struct st_master_info
pthread_mutex_t lock; pthread_mutex_t lock;
pthread_cond_t cond; pthread_cond_t cond;
bool inited; bool inited;
bool old_format; /* master binlog is in 3.23 format */
st_master_info():pending(0),fd(-1),last_log_seq(0),inited(0) st_master_info():pending(0),fd(-1),last_log_seq(0),inited(0),
old_format(0)
{ {
host[0] = 0; user[0] = 0; password[0] = 0; host[0] = 0; user[0] = 0; password[0] = 0;
pthread_mutex_init(&lock, MY_MUTEX_INIT_FAST); pthread_mutex_init(&lock, MY_MUTEX_INIT_FAST);
......
...@@ -72,15 +72,18 @@ class MYSQL_LOG { ...@@ -72,15 +72,18 @@ class MYSQL_LOG {
// we should not try to rotate it or write any rotation events // we should not try to rotate it or write any rotation events
// the user should use FLUSH MASTER instead of FLUSH LOGS for // the user should use FLUSH MASTER instead of FLUSH LOGS for
// purging // purging
enum cache_type io_cache_type;
bool need_start_event;
friend class Log_event; friend class Log_event;
public: public:
MYSQL_LOG(); MYSQL_LOG();
~MYSQL_LOG(); ~MYSQL_LOG();
pthread_mutex_t* get_log_lock() { return &LOCK_log; } pthread_mutex_t* get_log_lock() { return &LOCK_log; }
void set_need_start_event() { need_start_event = 1; }
void set_index_file_name(const char* index_file_name = 0); void set_index_file_name(const char* index_file_name = 0);
void init(enum_log_type log_type_arg); void init(enum_log_type log_type_arg,
enum cache_type io_cache_type_arg = WRITE_CACHE);
void open(const char *log_name,enum_log_type log_type, void open(const char *log_name,enum_log_type log_type,
const char *new_name=0); const char *new_name=0);
void new_file(bool inside_mutex = 0); void new_file(bool inside_mutex = 0);
......
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include "mysql_priv.h" #include "mysql_priv.h"
#include "sql_acl.h" #include "sql_acl.h"
#include "sql_repl.h" #include "sql_repl.h"
#include "repl_failsafe.h"
#include <m_ctype.h> #include <m_ctype.h>
#include <thr_alarm.h> #include <thr_alarm.h>
#include <myisam.h> #include <myisam.h>
......
...@@ -24,58 +24,15 @@ ...@@ -24,58 +24,15 @@
#include <thr_alarm.h> #include <thr_alarm.h>
#include <my_dir.h> #include <my_dir.h>
#define SLAVE_LIST_CHUNK 128
#define SLAVE_ERRMSG_SIZE (FN_REFLEN+64)
extern const char* any_db; extern const char* any_db;
extern pthread_handler_decl(handle_slave,arg); extern pthread_handler_decl(handle_slave,arg);
HASH slave_list;
#ifndef DBUG_OFF #ifndef DBUG_OFF
int max_binlog_dump_events = 0; // unlimited int max_binlog_dump_events = 0; // unlimited
bool opt_sporadic_binlog_dump_fail = 0; bool opt_sporadic_binlog_dump_fail = 0;
static int binlog_dump_count = 0; static int binlog_dump_count = 0;
#endif #endif
#ifdef SIGNAL_WITH_VIO_CLOSE
#define KICK_SLAVE { slave_thd->close_active_vio(); \
thr_alarm_kill(slave_real_id); }
#else
#define KICK_SLAVE thr_alarm_kill(slave_real_id);
#endif
static Slave_log_event* find_slave_event(IO_CACHE* log,
const char* log_file_name,
char* errmsg);
static uint32* slave_list_key(SLAVE_INFO* si, uint* len,
my_bool not_used __attribute__((unused)))
{
*len = 4;
return &si->server_id;
}
static void slave_info_free(void *s)
{
my_free((gptr) s, MYF(MY_WME));
}
void init_slave_list()
{
hash_init(&slave_list, SLAVE_LIST_CHUNK, 0, 0,
(hash_get_key) slave_list_key, slave_info_free, 0);
pthread_mutex_init(&LOCK_slave_list, MY_MUTEX_INIT_FAST);
}
void end_slave_list()
{
pthread_mutex_lock(&LOCK_slave_list);
hash_free(&slave_list);
pthread_mutex_unlock(&LOCK_slave_list);
pthread_mutex_destroy(&LOCK_slave_list);
}
static int fake_rotate_event(NET* net, String* packet, char* log_file_name, static int fake_rotate_event(NET* net, String* packet, char* log_file_name,
const char**errmsg) const char**errmsg)
{ {
...@@ -104,69 +61,6 @@ static int fake_rotate_event(NET* net, String* packet, char* log_file_name, ...@@ -104,69 +61,6 @@ static int fake_rotate_event(NET* net, String* packet, char* log_file_name,
return 0; return 0;
} }
#define get_object(p, obj) \
{\
uint len = (uint)*p++; \
if (p + len > p_end || len >= sizeof(obj)) \
goto err; \
strmake(obj,(char*) p,len); \
p+= len; \
}\
void unregister_slave(THD* thd, bool only_mine, bool need_mutex)
{
if (need_mutex)
pthread_mutex_lock(&LOCK_slave_list);
if (thd->server_id)
{
SLAVE_INFO* old_si;
if ((old_si = (SLAVE_INFO*)hash_search(&slave_list,
(byte*)&thd->server_id, 4)) &&
(!only_mine || old_si->thd == thd))
hash_delete(&slave_list, (byte*)old_si);
}
if (need_mutex)
pthread_mutex_unlock(&LOCK_slave_list);
}
int register_slave(THD* thd, uchar* packet, uint packet_length)
{
SLAVE_INFO *si;
int res = 1;
uchar* p = packet, *p_end = packet + packet_length;
if (check_access(thd, FILE_ACL, any_db))
return 1;
if (!(si = (SLAVE_INFO*)my_malloc(sizeof(SLAVE_INFO), MYF(MY_WME))))
goto err;
thd->server_id = si->server_id = uint4korr(p);
p += 4;
get_object(p,si->host);
get_object(p,si->user);
get_object(p,si->password);
si->port = uint2korr(p);
p += 2;
si->rpl_recovery_rank = uint4korr(p);
p += 4;
if (!(si->master_id = uint4korr(p)))
si->master_id = server_id;
si->thd = thd;
pthread_mutex_lock(&LOCK_slave_list);
unregister_slave(thd,0,0);
res = hash_insert(&slave_list, (byte*) si);
pthread_mutex_unlock(&LOCK_slave_list);
return res;
err:
if (si)
my_free((gptr) si, MYF(MY_WME));
return res;
}
static int send_file(THD *thd) static int send_file(THD *thd)
{ {
NET* net = &thd->net; NET* net = &thd->net;
...@@ -252,6 +146,8 @@ File open_binlog(IO_CACHE *log, const char *log_file_name, ...@@ -252,6 +146,8 @@ File open_binlog(IO_CACHE *log, const char *log_file_name,
if (my_b_read(log, (byte*) magic, sizeof(magic))) if (my_b_read(log, (byte*) magic, sizeof(magic)))
{ {
*errmsg = "I/O error reading the header from the binary log"; *errmsg = "I/O error reading the header from the binary log";
sql_print_error("%s, errno=%d, io cache code=%d", *errmsg, my_errno,
log->error);
goto err; goto err;
} }
if (memcmp(magic, BINLOG_MAGIC, sizeof(magic))) if (memcmp(magic, BINLOG_MAGIC, sizeof(magic)))
...@@ -887,8 +783,13 @@ void reset_master() ...@@ -887,8 +783,13 @@ void reset_master()
} }
LOG_INFO linfo; LOG_INFO linfo;
pthread_mutex_t* log_lock = mysql_bin_log.get_log_lock();
pthread_mutex_lock(log_lock);
if (mysql_bin_log.find_first_log(&linfo, "")) if (mysql_bin_log.find_first_log(&linfo, ""))
{
pthread_mutex_unlock(log_lock);
return; return;
}
for(;;) for(;;)
{ {
...@@ -898,7 +799,9 @@ void reset_master() ...@@ -898,7 +799,9 @@ void reset_master()
} }
mysql_bin_log.close(1); // exiting close mysql_bin_log.close(1); // exiting close
my_delete(mysql_bin_log.get_index_fname(), MYF(MY_WME)); my_delete(mysql_bin_log.get_index_fname(), MYF(MY_WME));
mysql_bin_log.set_need_start_event();
mysql_bin_log.open(opt_bin_logname,LOG_BIN); mysql_bin_log.open(opt_bin_logname,LOG_BIN);
pthread_mutex_unlock(log_lock);
} }
...@@ -915,242 +818,6 @@ int cmp_master_pos(const char* log_file_name1, ulonglong log_pos1, ...@@ -915,242 +818,6 @@ int cmp_master_pos(const char* log_file_name1, ulonglong log_pos1,
return -1; return -1;
} }
static inline int cmp_master_pos(Slave_log_event* sev, LEX_MASTER_INFO* mi)
{
return cmp_master_pos(sev->master_log, sev->master_pos, mi->log_file_name,
mi->pos);
}
static int find_target_pos(LEX_MASTER_INFO* mi, IO_CACHE* log, char* errmsg)
{
uint32 log_seq = mi->last_log_seq;
uint32 target_server_id = mi->server_id;
for (;;)
{
Log_event* ev;
if (!(ev = Log_event::read_log_event(log, 0)))
{
if (log->error > 0)
strmov(errmsg, "Binary log truncated in the middle of event");
else if (log->error < 0)
strmov(errmsg, "I/O error reading binary log");
else
strmov(errmsg, "Could not find target event in the binary log");
return 1;
}
if (ev->log_seq == log_seq && ev->server_id == target_server_id)
{
delete ev;
mi->pos = my_b_tell(log);
return 0;
}
delete ev;
}
}
int translate_master(THD* thd, LEX_MASTER_INFO* mi, char* errmsg)
{
LOG_INFO linfo;
char search_file_name[FN_REFLEN],last_log_name[FN_REFLEN];
IO_CACHE log;
File file = -1, last_file = -1;
pthread_mutex_t *log_lock;
const char* errmsg_p;
Slave_log_event* sev = 0;
my_off_t last_pos = 0;
int error = 1;
int cmp_res;
LINT_INIT(cmp_res);
if (!mysql_bin_log.is_open())
{
strmov(errmsg,"Binary log is not open");
return 1;
}
if (!server_id_supplied)
{
strmov(errmsg, "Misconfigured master - server id was not set");
return 1;
}
linfo.index_file_offset = 0;
search_file_name[0] = 0;
if (mysql_bin_log.find_first_log(&linfo, search_file_name))
{
strmov(errmsg,"Could not find first log");
return 1;
}
thd->current_linfo = &linfo;
bzero((char*) &log,sizeof(log));
log_lock = mysql_bin_log.get_log_lock();
pthread_mutex_lock(log_lock);
for (;;)
{
if ((file=open_binlog(&log, linfo.log_file_name, &errmsg_p)) < 0)
{
strmov(errmsg, errmsg_p);
goto err;
}
if (!(sev = find_slave_event(&log, linfo.log_file_name, errmsg)))
goto err;
cmp_res = cmp_master_pos(sev, mi);
delete sev;
if (!cmp_res)
{
/* Copy basename */
fn_format(mi->log_file_name, linfo.log_file_name, "","",1);
mi->pos = my_b_tell(&log);
goto mi_inited;
}
else if (cmp_res > 0)
{
if (!last_pos)
{
strmov(errmsg,
"Slave event in first log points past the target position");
goto err;
}
end_io_cache(&log);
(void) my_close(file, MYF(MY_WME));
if (init_io_cache(&log, (file = last_file), IO_SIZE, READ_CACHE, 0, 0,
MYF(MY_WME)))
{
errmsg[0] = 0;
goto err;
}
break;
}
strmov(last_log_name, linfo.log_file_name);
last_pos = my_b_tell(&log);
switch (mysql_bin_log.find_next_log(&linfo)) {
case LOG_INFO_EOF:
if (last_file >= 0)
(void)my_close(last_file, MYF(MY_WME));
last_file = -1;
goto found_log;
case 0:
break;
default:
strmov(errmsg, "Error reading log index");
goto err;
}
end_io_cache(&log);
if (last_file >= 0)
(void) my_close(last_file, MYF(MY_WME));
last_file = file;
}
found_log:
my_b_seek(&log, last_pos);
if (find_target_pos(mi,&log,errmsg))
goto err;
fn_format(mi->log_file_name, last_log_name, "","",1); /* Copy basename */
mi_inited:
error = 0;
err:
pthread_mutex_unlock(log_lock);
end_io_cache(&log);
pthread_mutex_lock(&LOCK_thread_count);
thd->current_linfo = 0;
pthread_mutex_unlock(&LOCK_thread_count);
if (file >= 0)
(void) my_close(file, MYF(MY_WME));
if (last_file >= 0 && last_file != file)
(void) my_close(last_file, MYF(MY_WME));
return error;
}
// caller must delete result when done
static Slave_log_event* find_slave_event(IO_CACHE* log,
const char* log_file_name,
char* errmsg)
{
Log_event* ev;
if (!(ev = Log_event::read_log_event(log, 0)))
{
my_snprintf(errmsg, SLAVE_ERRMSG_SIZE,
"Error reading start event in log '%s'",
(char*)log_file_name);
return 0;
}
delete ev;
if (!(ev = Log_event::read_log_event(log, 0)))
{
my_snprintf(errmsg, SLAVE_ERRMSG_SIZE,
"Error reading slave event in log '%s'",
(char*)log_file_name);
return 0;
}
if (ev->get_type_code() != SLAVE_EVENT)
{
my_snprintf(errmsg, SLAVE_ERRMSG_SIZE,
"Second event in log '%s' is not slave event",
(char*)log_file_name);
delete ev;
return 0;
}
return (Slave_log_event*)ev;
}
int show_new_master(THD* thd)
{
DBUG_ENTER("show_new_master");
List<Item> field_list;
char errmsg[SLAVE_ERRMSG_SIZE];
LEX_MASTER_INFO* lex_mi = &thd->lex.mi;
errmsg[0]=0; // Safety
if (translate_master(thd, lex_mi, errmsg))
{
if (errmsg[0])
net_printf(&thd->net, ER_ERROR_WHEN_EXECUTING_COMMAND,
"SHOW NEW MASTER", errmsg);
else
send_error(&thd->net, 0);
DBUG_RETURN(1);
}
else
{
String* packet = &thd->packet;
field_list.push_back(new Item_empty_string("Log_name", 20));
field_list.push_back(new Item_empty_string("Log_pos", 20));
if (send_fields(thd, field_list, 1))
DBUG_RETURN(-1);
packet->length(0);
net_store_data(packet, lex_mi->log_file_name);
net_store_data(packet, (longlong)lex_mi->pos);
if (my_net_write(&thd->net, packet->ptr(), packet->length()))
DBUG_RETURN(-1);
send_eof(&thd->net);
DBUG_RETURN(0);
}
}
int show_binlog_events(THD* thd) int show_binlog_events(THD* thd)
{ {
DBUG_ENTER("show_binlog_events"); DBUG_ENTER("show_binlog_events");
...@@ -1202,7 +869,8 @@ int show_binlog_events(THD* thd) ...@@ -1202,7 +869,8 @@ int show_binlog_events(THD* thd)
pthread_mutex_lock(mysql_bin_log.get_log_lock()); pthread_mutex_lock(mysql_bin_log.get_log_lock());
my_b_seek(&log, pos); my_b_seek(&log, pos);
for (event_count = 0; (ev = Log_event::read_log_event(&log, 0)); ) for (event_count = 0;
(ev = Log_event::read_log_event(&log,(pthread_mutex_t*)0,0)); )
{ {
if (event_count >= limit_start && if (event_count >= limit_start &&
ev->net_send(thd, linfo.log_file_name, pos)) ev->net_send(thd, linfo.log_file_name, pos))
...@@ -1247,56 +915,6 @@ int show_binlog_events(THD* thd) ...@@ -1247,56 +915,6 @@ int show_binlog_events(THD* thd)
DBUG_RETURN(0); DBUG_RETURN(0);
} }
int show_slave_hosts(THD* thd)
{
List<Item> field_list;
NET* net = &thd->net;
String* packet = &thd->packet;
DBUG_ENTER("show_slave_hosts");
field_list.push_back(new Item_empty_string("Server_id", 20));
field_list.push_back(new Item_empty_string("Host", 20));
if (opt_show_slave_auth_info)
{
field_list.push_back(new Item_empty_string("User",20));
field_list.push_back(new Item_empty_string("Password",20));
}
field_list.push_back(new Item_empty_string("Port",20));
field_list.push_back(new Item_empty_string("Rpl_recovery_rank", 20));
field_list.push_back(new Item_empty_string("Master_id", 20));
if (send_fields(thd, field_list, 1))
DBUG_RETURN(-1);
pthread_mutex_lock(&LOCK_slave_list);
for (uint i = 0; i < slave_list.records; ++i)
{
SLAVE_INFO* si = (SLAVE_INFO*) hash_element(&slave_list, i);
packet->length(0);
net_store_data(packet, si->server_id);
net_store_data(packet, si->host);
if (opt_show_slave_auth_info)
{
net_store_data(packet, si->user);
net_store_data(packet, si->password);
}
net_store_data(packet, (uint32) si->port);
net_store_data(packet, si->rpl_recovery_rank);
net_store_data(packet, si->master_id);
if (my_net_write(net, (char*)packet->ptr(), packet->length()))
{
pthread_mutex_unlock(&LOCK_slave_list);
DBUG_RETURN(-1);
}
}
pthread_mutex_unlock(&LOCK_slave_list);
send_eof(net);
DBUG_RETURN(0);
}
int show_binlog_info(THD* thd) int show_binlog_info(THD* thd)
{ {
DBUG_ENTER("show_binlog_info"); DBUG_ENTER("show_binlog_info");
...@@ -1402,230 +1020,6 @@ int show_binlogs(THD* thd) ...@@ -1402,230 +1020,6 @@ int show_binlogs(THD* thd)
return 1; return 1;
} }
int connect_to_master(THD *thd, MYSQL* mysql, MASTER_INFO* mi)
{
if (!mc_mysql_connect(mysql, mi->host, mi->user, mi->password, 0,
mi->port, 0, 0))
{
sql_print_error("Connection to master failed: %s",
mc_mysql_error(mysql));
return 1;
}
return 0;
}
static inline void cleanup_mysql_results(MYSQL_RES* db_res,
MYSQL_RES** cur, MYSQL_RES** start)
{
for( ; cur >= start; --cur)
{
if (*cur)
mc_mysql_free_result(*cur);
}
mc_mysql_free_result(db_res);
}
static inline int fetch_db_tables(THD* thd, MYSQL* mysql, const char* db,
MYSQL_RES* table_res)
{
MYSQL_ROW row;
for( row = mc_mysql_fetch_row(table_res); row;
row = mc_mysql_fetch_row(table_res))
{
TABLE_LIST table;
const char* table_name = row[0];
int error;
if (table_rules_on)
{
table.next = 0;
table.db = (char*)db;
table.real_name = (char*)table_name;
table.updating = 1;
if (!tables_ok(thd, &table))
continue;
}
if ((error = fetch_nx_table(thd, db, table_name, &glob_mi, mysql)))
return error;
}
return 0;
}
int load_master_data(THD* thd)
{
MYSQL mysql;
MYSQL_RES* master_status_res = 0;
bool slave_was_running = 0;
int error = 0;
mc_mysql_init(&mysql);
// we do not want anyone messing with the slave at all for the entire
// duration of the data load;
pthread_mutex_lock(&LOCK_slave);
// first, kill the slave
if ((slave_was_running = slave_running))
{
abort_slave = 1;
KICK_SLAVE;
thd->proc_info = "waiting for slave to die";
while (slave_running)
pthread_cond_wait(&COND_slave_stopped, &LOCK_slave); // wait until done
}
if (connect_to_master(thd, &mysql, &glob_mi))
{
net_printf(&thd->net, error = ER_CONNECT_TO_MASTER,
mc_mysql_error(&mysql));
goto err;
}
// now that we are connected, get all database and tables in each
{
MYSQL_RES *db_res, **table_res, **table_res_end, **cur_table_res;
uint num_dbs;
if (mc_mysql_query(&mysql, "show databases", 0) ||
!(db_res = mc_mysql_store_result(&mysql)))
{
net_printf(&thd->net, error = ER_QUERY_ON_MASTER,
mc_mysql_error(&mysql));
goto err;
}
if (!(num_dbs = (uint) mc_mysql_num_rows(db_res)))
goto err;
// in theory, the master could have no databases at all
// and run with skip-grant
if (!(table_res = (MYSQL_RES**)thd->alloc(num_dbs * sizeof(MYSQL_RES*))))
{
net_printf(&thd->net, error = ER_OUTOFMEMORY);
goto err;
}
// this is a temporary solution until we have online backup
// capabilities - to be replaced once online backup is working
// we wait to issue FLUSH TABLES WITH READ LOCK for as long as we
// can to minimize the lock time
if (mc_mysql_query(&mysql, "FLUSH TABLES WITH READ LOCK", 0) ||
mc_mysql_query(&mysql, "SHOW MASTER STATUS",0) ||
!(master_status_res = mc_mysql_store_result(&mysql)))
{
net_printf(&thd->net, error = ER_QUERY_ON_MASTER,
mc_mysql_error(&mysql));
goto err;
}
// go through every table in every database, and if the replication
// rules allow replicating it, get it
table_res_end = table_res + num_dbs;
for(cur_table_res = table_res; cur_table_res < table_res_end;
cur_table_res++)
{
// since we know how many rows we have, this can never be NULL
MYSQL_ROW row = mc_mysql_fetch_row(db_res);
char* db = row[0];
/*
Do not replicate databases excluded by rules
also skip mysql database - in most cases the user will
mess up and not exclude mysql database with the rules when
he actually means to - in this case, he is up for a surprise if
his priv tables get dropped and downloaded from master
TO DO - add special option, not enabled
by default, to allow inclusion of mysql database into load
data from master
*/
if (!db_ok(db, replicate_do_db, replicate_ignore_db) ||
!strcmp(db,"mysql"))
{
*cur_table_res = 0;
continue;
}
if (mysql_rm_db(thd, db, 1,1) ||
mysql_create_db(thd, db, 0, 1))
{
send_error(&thd->net, 0, 0);
cleanup_mysql_results(db_res, cur_table_res - 1, table_res);
goto err;
}
if (mc_mysql_select_db(&mysql, db) ||
mc_mysql_query(&mysql, "show tables", 0) ||
!(*cur_table_res = mc_mysql_store_result(&mysql)))
{
net_printf(&thd->net, error = ER_QUERY_ON_MASTER,
mc_mysql_error(&mysql));
cleanup_mysql_results(db_res, cur_table_res - 1, table_res);
goto err;
}
if ((error = fetch_db_tables(thd, &mysql, db, *cur_table_res)))
{
// we do not report the error - fetch_db_tables handles it
cleanup_mysql_results(db_res, cur_table_res, table_res);
goto err;
}
}
cleanup_mysql_results(db_res, cur_table_res - 1, table_res);
// adjust position in the master
if (master_status_res)
{
MYSQL_ROW row = mc_mysql_fetch_row(master_status_res);
/*
We need this check because the master may not be running with
log-bin, but it will still allow us to do all the steps
of LOAD DATA FROM MASTER - no reason to forbid it, really,
although it does not make much sense for the user to do it
*/
if (row[0] && row[1])
{
strmake(glob_mi.log_file_name, row[0], sizeof(glob_mi.log_file_name));
glob_mi.pos = atoi(row[1]); // atoi() is ok, since offset is <= 1GB
if (glob_mi.pos < 4)
glob_mi.pos = 4; // don't hit the magic number
glob_mi.pending = 0;
flush_master_info(&glob_mi);
}
mc_mysql_free_result(master_status_res);
}
if (mc_mysql_query(&mysql, "UNLOCK TABLES", 0))
{
net_printf(&thd->net, error = ER_QUERY_ON_MASTER,
mc_mysql_error(&mysql));
goto err;
}
}
err:
pthread_mutex_unlock(&LOCK_slave);
if (slave_was_running)
start_slave(0, 0);
mc_mysql_close(&mysql); // safe to call since we always do mc_mysql_init()
if (!error)
send_ok(&thd->net);
return error;
}
int log_loaded_block(IO_CACHE* file) int log_loaded_block(IO_CACHE* file)
{ {
LOAD_FILE_INFO* lf_info; LOAD_FILE_INFO* lf_info;
......
...@@ -15,7 +15,6 @@ typedef struct st_slave_info ...@@ -15,7 +15,6 @@ typedef struct st_slave_info
} SLAVE_INFO; } SLAVE_INFO;
extern bool opt_show_slave_auth_info, opt_old_rpl_compat; extern bool opt_show_slave_auth_info, opt_old_rpl_compat;
extern HASH slave_list;
extern char* master_host; extern char* master_host;
extern my_string opt_bin_logname, master_info_file; extern my_string opt_bin_logname, master_info_file;
extern uint32 server_id; extern uint32 server_id;
...@@ -27,26 +26,24 @@ extern int max_binlog_dump_events; ...@@ -27,26 +26,24 @@ extern int max_binlog_dump_events;
extern bool opt_sporadic_binlog_dump_fail; extern bool opt_sporadic_binlog_dump_fail;
#endif #endif
#ifdef SIGNAL_WITH_VIO_CLOSE
#define KICK_SLAVE { slave_thd->close_active_vio(); \
thr_alarm_kill(slave_real_id); }
#else
#define KICK_SLAVE thr_alarm_kill(slave_real_id);
#endif
File open_binlog(IO_CACHE *log, const char *log_file_name, File open_binlog(IO_CACHE *log, const char *log_file_name,
const char **errmsg); const char **errmsg);
int start_slave(THD* thd = 0, bool net_report = 1); int start_slave(THD* thd = 0, bool net_report = 1);
int stop_slave(THD* thd = 0, bool net_report = 1); int stop_slave(THD* thd = 0, bool net_report = 1);
int load_master_data(THD* thd);
int connect_to_master(THD *thd, MYSQL* mysql, MASTER_INFO* mi);
int change_master(THD* thd); int change_master(THD* thd);
int show_new_master(THD* thd);
int show_slave_hosts(THD* thd);
int show_binlog_events(THD* thd); int show_binlog_events(THD* thd);
int translate_master(THD* thd, LEX_MASTER_INFO* mi, char* errmsg);
int cmp_master_pos(const char* log_file_name1, ulonglong log_pos1, int cmp_master_pos(const char* log_file_name1, ulonglong log_pos1,
const char* log_file_name2, ulonglong log_pos2); const char* log_file_name2, ulonglong log_pos2);
void reset_slave(); void reset_slave();
void reset_master(); void reset_master();
void init_slave_list();
void end_slave_list();
int register_slave(THD* thd, uchar* packet, uint packet_length);
void unregister_slave(THD* thd, bool only_mine, bool need_mutex);
int purge_master_logs(THD* thd, const char* to_log); int purge_master_logs(THD* thd, const char* to_log);
bool log_in_use(const char* log_name); bool log_in_use(const char* log_name);
void adjust_linfo_offsets(my_off_t purge_offset); void adjust_linfo_offsets(my_off_t purge_offset);
......
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