mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 20:12:31 +01:00
semi-manual merge, some more needs to be fixed in mysqltest.c in fully
manual mode
This commit is contained in:
commit
178f8e91b0
32 changed files with 528 additions and 118 deletions
|
@ -188,3 +188,4 @@ Docs/my_sys.doc
|
|||
tmp/*
|
||||
extra/resolve_stack_dump
|
||||
sql/share/*.sys
|
||||
BitKeeper/tmp/bkr3sAHD
|
||||
|
|
211
Docs/manual.texi
211
Docs/manual.texi
|
@ -17401,6 +17401,17 @@ Addresses may be 4 or 8 byte addresses:
|
|||
mysql> select INET_ATON("209.207.224.40");
|
||||
-> 3520061480
|
||||
@end example
|
||||
@findex MASTER_POS_WAIT()
|
||||
@item MASTER_POS_WAIT(log_name, log_pos)
|
||||
Blocks until the slave reaches the specified position in the master log during
|
||||
replication. If master information is not initialized, returns NULL. If the
|
||||
slave is not running, will block and wait until it is started and goes to or
|
||||
past
|
||||
the specified postion. If the slave is already past the specified postion,
|
||||
returns immediately. The return value is the number of log events it had to
|
||||
wait to get to the specified position, or NULL in case of error. Useful for
|
||||
control of master-slave synchronization, but was originally written to
|
||||
facilate replication testing.
|
||||
@end table
|
||||
|
||||
@findex GROUP BY functions
|
||||
|
@ -25618,6 +25629,7 @@ tables}.
|
|||
* Replication Options:: Replication Options in my.cnf
|
||||
* Replication SQL:: SQL Commands related to replication
|
||||
* Replication FAQ:: Frequently Asked Questions about replication
|
||||
* Troubleshooting Replication:: Troubleshooting Replication
|
||||
@end menu
|
||||
|
||||
@node Replication Intro, Replication Implementation, Replication, Replication
|
||||
|
@ -25634,7 +25646,7 @@ Starting in Version 3.23.15, @strong{MySQL} supports one-way replication
|
|||
internally. One server acts as the master, while the other acts as the
|
||||
slave. Note that one server could play the roles of master in one pair
|
||||
and slave in the other. The master server keeps a binary log of updates
|
||||
(@xref{Binary log}.) and an index file of binary logs to keep track of
|
||||
(@xref{Binary log}.) and an index file to binary logs to keep track of
|
||||
log rotation. The slave, upon connecting, informs the master where it
|
||||
left off since the last successfully propagated update, catches up on
|
||||
the updates, and then blocks and waits for the master to notify it of
|
||||
|
@ -25656,7 +25668,7 @@ master. @xref{Backup}.
|
|||
|
||||
@strong{MySQL} replication is based on the server keeping track of all
|
||||
changes to your database (updates, deletes, etc) in the binary
|
||||
log (@xref{Binary log}.), and the slave server(s) reading the saved
|
||||
log. (@xref{Binary log}.) and the slave server(s) reading the saved
|
||||
queries from the master server's binary log so that the slave can
|
||||
execute the same queries on its copy of the data.
|
||||
|
||||
|
@ -25668,9 +25680,11 @@ logging on the master. If you start your slaves with data that doesn't
|
|||
agree with what was on the master @strong{when the binary log was
|
||||
started}, your slaves may fail.
|
||||
|
||||
A future Version of @strong{MySQL} is planned remove the need to keep a
|
||||
A future version (4.0) of @strong{MySQL} will remove the need to keep a
|
||||
(possibly large) snapshot of data for new slaves that you might wish to
|
||||
set up.
|
||||
set up through the live backup functionality with no locking required.
|
||||
However, at this time, it is necessary to block all writes either with a
|
||||
global read lock or by shutting down the master while taking a snapshot.
|
||||
|
||||
Once a slave is properly configured and running, it will simply connect
|
||||
to the master and wait for updates to process. If the master goes away
|
||||
|
@ -25690,20 +25704,20 @@ The next section explains the master/slave setup process in more detail.
|
|||
Below is a quick description of how to set up complete replication on
|
||||
your current @strong{MySQL} server. It assumes you want to replicate all
|
||||
your databases and have not configured replication before. You will need
|
||||
to shutdown your master server briefly to complete the steps outlined
|
||||
to shutdown your master server briefly to complete the steops outlined
|
||||
below.
|
||||
|
||||
@enumerate
|
||||
@item
|
||||
Make sure you have a recent version of @strong{MySQL} installed on the
|
||||
master and slave(s).
|
||||
Make you have a recent version of @strong{MySQL} installed on the master
|
||||
and slave(s).
|
||||
|
||||
Use Version 3.23.29 or higher. Previous releases used a different binary
|
||||
log format and had bugs which have been fixed in newer releases. Please
|
||||
log format and had bugs which have been fixed in newer releases. Please,
|
||||
do not report bugs until you have verified that the problem is present
|
||||
in the latest release.
|
||||
@item
|
||||
Set up a special replication user on the master with the @code{FILE}
|
||||
Set up special a replication user on the master with the @code{FILE}
|
||||
privilege and permission to connect from all the slaves. If the user is
|
||||
only doing replication (which is recommended), you don't need to grant any
|
||||
additional privileges.
|
||||
|
@ -25726,7 +25740,7 @@ mysqladmin -u root -p<password> shutdown
|
|||
Snapshot all the data on your master server.
|
||||
|
||||
The easiest way to do this (on Unix) is to simply use @strong{tar} to
|
||||
produce an archive of your entrie data directory. The exact data
|
||||
produce an archvie of your entrie data directory. The exact data
|
||||
directory location depends on your installation.
|
||||
|
||||
@example
|
||||
|
@ -25738,8 +25752,11 @@ the data directory.
|
|||
|
||||
@item
|
||||
In @code{my.cnf} on the master add @code{log-bin} and
|
||||
@code{server-id=<some unique number>} to the @code{[mysqld]} section.
|
||||
|
||||
@code{server-id=unique number} to the @code{[mysqld]} section and
|
||||
restart it. It is very important that the id of the slave is different from
|
||||
the id of the master. Think of @code{server-id} as something similar
|
||||
to the IP address - it uniquely identifies the server instance in the
|
||||
comminity of replication partners.
|
||||
|
||||
@example
|
||||
[mysqld]
|
||||
|
@ -25764,7 +25781,12 @@ replacing the values in <> with what is relevant to your system.
|
|||
|
||||
@code{server-id} must be different for each server participating in
|
||||
replication. If you don't specify a server-id, it will be set to 1 if
|
||||
you have not defined @code{master-host}, else it will be set to 2.
|
||||
you have not defined @code{master-host}, else it will be set to 2. Note
|
||||
that in the case of @code{server-id} omission the master will refuse
|
||||
connections from all slaves, and the slave will refuse to connect to a
|
||||
master. Thus, omitting @code{server-id} is only good for backup with a
|
||||
binary log.
|
||||
|
||||
|
||||
@item
|
||||
Copy the snapshot data into your data directory on your slave(s). Make
|
||||
|
@ -25794,10 +25816,11 @@ If a slave is not able to replicate for any reason, you will find error
|
|||
messages in the error log on the slave.
|
||||
|
||||
Once a slave is replicating, you will find a file called
|
||||
@code{master.info} in the same directory as your error log. The
|
||||
@code{master.info} in the same directory as your error log. The
|
||||
@code{master.info} file is used by the slave to keep track of how much
|
||||
of the master's binary log it has processed. @strong{Do not} remove or
|
||||
edit this file.
|
||||
of the master's binary log is has processed. @strong{Do not} remove or
|
||||
edit the file, unless you really know what you are doing. Even in that case,
|
||||
it is preferred that you use @code{CHANGE MASTER TO} command.
|
||||
|
||||
@cindex options, replication
|
||||
@cindex @code{my.cnf} file
|
||||
|
@ -25812,20 +25835,16 @@ Below is an explanation of what is supported and what is not:
|
|||
Replication will be done correctly with @code{AUTO_INCREMENT},
|
||||
@code{LAST_INSERT_ID}, and @code{TIMESTAMP} values.
|
||||
@item
|
||||
@code{RAND()} in updates does not replicate properly. Use
|
||||
@code{RAND(some_non_rand_expr)} if you are replcating updates with
|
||||
@code{RAND()}. You can, for example, use @code{UNIX_TIMESTAMP()} for the
|
||||
argument to @code{RAND()}.
|
||||
@item
|
||||
@code{LOAD DATA INFILE} will be handled properly as long as the file
|
||||
still resides on the master server at the time of update
|
||||
propagation. @code{LOAD LOCAL DATA INFILE} will be skipped.
|
||||
@item
|
||||
The master and slave is not synchronizing @code{RAND()}. This means
|
||||
that you should not use @code{RAND()} with any statement that updates a
|
||||
table. As fixing this will require a change in the protocol, we will
|
||||
delay fixing this until 4.0. A workaround is using @code{RAND(#)}, where
|
||||
# is a random integer genearated by your application or by first
|
||||
executing @code{LAST_INSERT_ID(RAND())} and then using
|
||||
@code{LAST_INSERT_ID()} in the next statement.
|
||||
@item
|
||||
Update queries that use user variables (@code{@@variable}) are not yet
|
||||
replication-safe.
|
||||
Update queries that use user variables are not replication-safe (yet).
|
||||
@item
|
||||
Temporary tables starting in 3.23.29 are replicated properly with the
|
||||
exception of the case when you shut down slave server ( not just slave thread),
|
||||
|
@ -25892,15 +25911,17 @@ Starting in Version 3.23.19, you can clean up stale replication leftovers when
|
|||
something goes wrong and you want a clean start with @code{FLUSH MASTER}
|
||||
and @code{FLUSH SLAVE} commands. In Version 3.23.26 we have renamed them to
|
||||
@code{RESET MASTER} and @code{RESET SLAVE} respectively to clarify
|
||||
what they do. The old @code{FLUSH} variants still work, though for
|
||||
what they do. The old @code{FLUSH} variants still work, though, for
|
||||
compatibility.
|
||||
|
||||
@item
|
||||
Starting in Version 3.23.21, you can use @code{LOAD TABLE FROM MASTER} for
|
||||
network backup and to set up replication initially.
|
||||
network backup and to set up replication initially. We have recently
|
||||
received a number of bug reports concerning it that we are investigating, so
|
||||
we recommend that you use it only in testing until we make it more stable.
|
||||
@item
|
||||
Starting in Version 3.23.23, you can change masters with @code{CHANGE MASTER
|
||||
TO}.
|
||||
Starting in Version 3.23.23, you can change masters and adjust log position
|
||||
with @code{CHANGE MASTER TO}.
|
||||
@item
|
||||
Starting in Version 3.23.23, you tell the master that updates in certain
|
||||
databases should not be logged to the binary log with @code{binlog-ignore-db}.
|
||||
|
@ -25916,7 +25937,7 @@ to get rid of old logs while the slave is running.
|
|||
@node Replication Options, Replication SQL, Replication Features, Replication
|
||||
@section Replication Options in my.cnf
|
||||
|
||||
If you are using replication, we recommend you to use MySQL Version 3.23.28 or
|
||||
If you are using replication, we recommend you to use MySQL Version 3.23.30 or
|
||||
later. Older versions work, but they do have some bugs and are missing some
|
||||
features.
|
||||
|
||||
|
@ -26169,8 +26190,8 @@ last log on the list), backup all the logs you are about to delete
|
|||
|
||||
@end multitable
|
||||
|
||||
@node Replication FAQ, , Replication SQL, Replication
|
||||
@section Frequently Asked Questions about replication
|
||||
@node Replication FAQ,Troubleshooting Replication, Replication SQL, Replication
|
||||
@section Replication FAQ
|
||||
|
||||
@cindex @code{Binlog_Dump}
|
||||
@strong{Q}: Why do I sometimes see more than one @code{Binlog_Dump} thread on
|
||||
|
@ -26227,11 +26248,10 @@ the slave can stay down for some time - since the master is logging
|
|||
all the updates, the slave will be able to catch up once it is up and
|
||||
can connect.
|
||||
|
||||
We plan to make post 3.23.26 versions to be backwards compatible
|
||||
for replication down to Version 3.23.26, so upgrade should be just a matter
|
||||
of plug and play. Of course, as one joke goes, plug and play works
|
||||
usually only 50% of the time - just the plug part. We hope to do much
|
||||
better than that, though.
|
||||
After 3.23.26, we have locked the replication protocol for modifications, so
|
||||
you can upgrade masters and slave on the fly to a newer 3.23 version and you
|
||||
can have different versions of @code{MySQL} running on the slave and the
|
||||
master, as long as they are both newer than 3.23.26.
|
||||
|
||||
@cindex replication, two-way
|
||||
@strong{Q}: What issues should I be aware of when setting up two-way
|
||||
|
@ -26251,10 +26271,6 @@ two-way replication relationship, unless you are sure that you updates
|
|||
can safely happen in any order, or unless you take care of mis-ordered
|
||||
updates somehow in the client code.
|
||||
|
||||
Until we implement @code{server_id} variable, you cannot have more than
|
||||
two servers in a co-master replication relationship, and you must
|
||||
run @code{mysqld} without @code{log-slave-updates} (default) to avoid
|
||||
infinite update loops.
|
||||
|
||||
You must also realize that two-way replication actually does not improve
|
||||
performance very much, if at all, as far as updates are concerned. Both
|
||||
|
@ -26365,7 +26381,7 @@ to all servers)
|
|||
|
||||
So if N = 0, which means we have no replication, our system can handle
|
||||
1200/11, about 109 writes per second (which means we will have 9 times
|
||||
as many reads to the nature of our application).
|
||||
as many reads due to the nature of our application).
|
||||
|
||||
If N = 1, we can get up to 184 writes per second.
|
||||
|
||||
|
@ -26428,6 +26444,105 @@ We are currently working on intergrating an automatic master election
|
|||
system into @strong{MySQL}, but until it is ready, you will have to
|
||||
create your own monitoring tools.
|
||||
|
||||
@node Troubleshooting Replication, ,Replication FAQ, Replication
|
||||
@section Troubleshooting Replication
|
||||
|
||||
If you have followed the instructions, and your replication setup is not
|
||||
working, first elliminate the user error factor by checking the following:
|
||||
|
||||
@itemize @bullet
|
||||
@item
|
||||
Is the master logging to the binary log? Check with @code{SHOW MASTER STATUS}.
|
||||
If it is, @code{Position} will be non-zero. If not, verify that you have
|
||||
given the master @code{log-bin} option and have set @code{server-id}.
|
||||
@item
|
||||
Is the slave running? Check with @code{SHOW SLAVE STATUS}. The answer is found
|
||||
in @code{Slave_running} column. If not, verify slave options and check the
|
||||
error log for messages.
|
||||
@item
|
||||
If the slave is running, did it establish connection with the master? Do
|
||||
@code{SHOW PROCESSLIST}, find the thread with @code{system user} value in
|
||||
@code{User} column and @code{none} in the @code{Host} column, and check the
|
||||
@code{State} column. If it says @code{connecting to master}, verify the
|
||||
privileges for the replication user on the master, master host name, your
|
||||
DNS setup, whether the master is actually running, whether it is reachable
|
||||
from the slave, and if all that seems ok, read the error logs.
|
||||
@item
|
||||
If the slave was running, but then stopped, check the error logs. It usually
|
||||
happens when some query that succeeded on the master fails on the slave. This
|
||||
should never happen if you have taken a proper snapshot of the master, and
|
||||
never modify the data on the slave outside of the slave thread. If it does,
|
||||
it is a bug, read below on how to report it.
|
||||
@item
|
||||
Make sure you are not running into an old bug by upgrading to the most recent
|
||||
version.
|
||||
@item
|
||||
If all else fails, read the error logs. If they are big,
|
||||
@code{grep -i slave /path/to/your-log.err} on the slave. There is no
|
||||
generic pattern to search for on the master, as the only errors it logs
|
||||
are general system errors - if it can, it will send the error to the slave
|
||||
when things go wrong.
|
||||
@end itemize
|
||||
|
||||
When you have determined that there is no user error involved, and replication
|
||||
still either does not work at all or is unstable, it is time to start working
|
||||
on a bug report. We need to get as much info as possible from you to be able
|
||||
to track down the bug. Please do spend some time and effort preparing a good
|
||||
bug report. Ideally, we would like to have a test case in the format found in
|
||||
@code{mysql-test/t/rpl*} directory of the source tree. If you submit a test
|
||||
case like that, you can expect a patch within a day or two in most cases,
|
||||
although, of course, you mileage may vary depending on a number of factors.
|
||||
|
||||
Second best option is a just program with easily configurable connection
|
||||
arguments for the master and the slave that will demonstrate the problem on our
|
||||
systems. You can write one in Perl or in C, depending on which language you
|
||||
know better.
|
||||
|
||||
If you have one of the above ways to demonstrate the bug, use
|
||||
@code{mysqlbug} to prepare a bug report and send it to
|
||||
@email{bugs@@lists.mysql.com}. If you have a phantom - a problem that
|
||||
does occur but you cannot duplicate "at will":
|
||||
|
||||
@itemize @bullet
|
||||
@item
|
||||
Verify that there is no user error involved. For example, if you update the
|
||||
slave outside of the slave thread, the data will be out of sync, and you can
|
||||
have unique key violations on updates, in which case the slave thread will
|
||||
stop and wait for you to clean up the tables manually to bring them in sync.
|
||||
@item
|
||||
Run slave with @code{log-slave-updates} and @code{log-bin} - this will keep
|
||||
a log of all updates on the slave.
|
||||
@item
|
||||
Save all evidence before reseting the replication. If we have no or only
|
||||
sketchy information, it would take us a while to track down the problem. The
|
||||
evidence you should collect is:
|
||||
@itemize @bullet
|
||||
@item
|
||||
all binary logs on the master
|
||||
@item
|
||||
all binary log on the slave
|
||||
@item
|
||||
the output of @code{SHOW MASTER STATUS} on the master at the time
|
||||
you have discovered the problem
|
||||
@item
|
||||
the output of @code{SHOW SLAVE STATUS} on the master at the time
|
||||
you have discovered the problem
|
||||
@item
|
||||
Error logs on the master and on the slave
|
||||
@end itemize
|
||||
@item
|
||||
Use @code{mysqlbinlog} to examine the binary logs. The following should
|
||||
be helpful
|
||||
to find the trouble query, for example:
|
||||
@example
|
||||
mysqlbinlog -j pos_from_slave_status /path/to/log_from_slave_status | head
|
||||
@end example
|
||||
@end itemize
|
||||
|
||||
Once you have collected the evidence on the phantom problem, try hard to
|
||||
isolate it into a separate test case first. Then report the problem to
|
||||
@email{bugs@@lists.mysql.com} with as much info as possible.
|
||||
|
||||
|
||||
@cindex performance, maximizing
|
||||
@cindex optimization
|
||||
|
@ -40439,6 +40554,7 @@ version. The replication and BerkeleyDB code is still under development,
|
|||
though, so Version 3.23 is not released as a stable version yet.
|
||||
|
||||
@menu
|
||||
* News-3.23.32:: Changes in release 3.23.32
|
||||
* News-3.23.31:: Changes in release 3.23.31
|
||||
* News-3.23.30:: Changes in release 3.23.30
|
||||
* News-3.23.29:: Changes in release 3.23.29
|
||||
|
@ -40473,7 +40589,14 @@ though, so Version 3.23 is not released as a stable version yet.
|
|||
* News-3.23.0:: Changes in release 3.23.0
|
||||
@end menu
|
||||
|
||||
@node News-3.23.31, News-3.23.30, News-3.23.x, News-3.23.x
|
||||
@node News-3.23.32, News-3.23.31, News-3.23.x, News-3.23.x
|
||||
@appendixsubsec Changes in release 3.23.32
|
||||
@itemize @bullet
|
||||
@item
|
||||
Added MASTER_POS_WAIT()
|
||||
@end itemize
|
||||
|
||||
@node News-3.23.31, News-3.23.30, News-3.23.32, News-3.23.x
|
||||
@appendixsubsec Changes in release 3.23.31
|
||||
@itemize @bullet
|
||||
@item
|
||||
|
|
|
@ -125,6 +125,7 @@ static char *current_host,*current_db,*current_user=0,*opt_password=0,
|
|||
*default_charset;
|
||||
static char *histfile;
|
||||
static String glob_buffer,old_buffer;
|
||||
static int wait_time = 5;
|
||||
static STATUS status;
|
||||
static ulong select_limit,max_join_size,opt_connect_timeout=0;
|
||||
static char default_pager[FN_REFLEN];
|
||||
|
@ -427,7 +428,7 @@ static struct option long_options[] =
|
|||
{"verbose", no_argument, 0, 'v'},
|
||||
{"version", no_argument, 0, 'V'},
|
||||
{"vertical", no_argument, 0, 'E'},
|
||||
{"wait", no_argument, 0, 'w'},
|
||||
{"wait", optional_argument, 0, 'w'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
|
@ -560,7 +561,7 @@ static int get_options(int argc, char **argv)
|
|||
|
||||
set_all_changeable_vars(changeable_vars);
|
||||
while ((c=getopt_long(argc,argv,
|
||||
"?ABCD:LfgGHinNoqrstTU::vVwWEe:h:O:P:S:u:#::p::",
|
||||
"?ABCD:LfgGHinNoqrstTU::vVw::WEe:h:O:P:S:u:#::p::",
|
||||
long_options, &option_index)) != EOF)
|
||||
{
|
||||
switch(c) {
|
||||
|
@ -664,7 +665,10 @@ static int get_options(int argc, char **argv)
|
|||
case 'n': unbuffered=1; break;
|
||||
case 'v': verbose++; break;
|
||||
case 'E': vertical=1; break;
|
||||
case 'w': wait_flag=1; break;
|
||||
case 'w':
|
||||
wait_flag=1;
|
||||
if(optarg) wait_time = atoi(optarg) ;
|
||||
break;
|
||||
case 'A': no_rehash=1; break;
|
||||
case 'G': no_named_cmds=0; break;
|
||||
case 'g': no_named_cmds=1; break;
|
||||
|
@ -2114,7 +2118,7 @@ sql_connect(char *host,char *database,char *user,char *password,uint silent)
|
|||
message=1;
|
||||
tee_fputs("Waiting",stderr); (void) fflush(stderr);
|
||||
}
|
||||
(void) sleep(5);
|
||||
(void) sleep(wait_time);
|
||||
if (!silent)
|
||||
{
|
||||
putc('.',stderr); (void) fflush(stderr);
|
||||
|
|
|
@ -93,6 +93,12 @@ static uint global_expected_errno[MAX_EXPECTED_ERRORS];
|
|||
|
||||
DYNAMIC_ARRAY q_lines;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char file[FN_REFLEN];
|
||||
ulong pos;
|
||||
} MASTER_POS ;
|
||||
|
||||
struct connection
|
||||
{
|
||||
MYSQL mysql;
|
||||
|
@ -106,6 +112,7 @@ typedef
|
|||
} PARSER;
|
||||
|
||||
PARSER parser;
|
||||
MASTER_POS master_pos;
|
||||
int block_ok = 1; /* set to 0 if the current block should not be executed */
|
||||
int false_block_depth = 0;
|
||||
const char* result_file = 0; /* if set, all results are concated and
|
||||
|
@ -139,13 +146,15 @@ struct st_query
|
|||
enum { Q_CONNECTION=1, Q_QUERY, Q_CONNECT,
|
||||
Q_SLEEP, Q_INC, Q_DEC,Q_SOURCE,
|
||||
Q_DISCONNECT,Q_LET, Q_ECHO, Q_WHILE, Q_END_BLOCK,
|
||||
Q_SYSTEM, Q_RESULT, Q_REQUIRE, Q_ERROR,
|
||||
Q_SYSTEM, Q_RESULT, Q_REQUIRE, Q_SAVE_MASTER_POS,
|
||||
Q_SYNC_WITH_MASTER,
|
||||
Q_UNKNOWN, Q_COMMENT, Q_COMMENT_WITH_COMMAND} type;
|
||||
};
|
||||
|
||||
const char *command_names[] = {
|
||||
"connection", "query","connect","sleep","inc","dec","source","disconnect",
|
||||
"let","echo","while","end","system","result", "require","error",0
|
||||
"let","echo","while","end","system","result", "require", "save_master_pos",
|
||||
"sync_with_master", 0
|
||||
};
|
||||
|
||||
TYPELIB command_typelib= {array_elements(command_names),"",
|
||||
|
@ -473,6 +482,50 @@ int do_echo(struct st_query* q)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int do_sync_with_master()
|
||||
{
|
||||
MYSQL_RES* res;
|
||||
MYSQL_ROW row;
|
||||
MYSQL* mysql = &cur_con->mysql;
|
||||
char query_buf[FN_REFLEN+128];
|
||||
sprintf(query_buf, "select master_pos_wait('%s', %ld)", master_pos.file,
|
||||
master_pos.pos);
|
||||
if(mysql_query(mysql, query_buf))
|
||||
die("At line %u: failed in %s: %d: %s", start_lineno, query_buf,
|
||||
mysql_errno(mysql), mysql_error(mysql));
|
||||
|
||||
if(!(res = mysql_store_result(mysql)))
|
||||
die("line %u: mysql_store_result() retuned NULL", start_lineno);
|
||||
if(!(row = mysql_fetch_row(res)))
|
||||
die("line %u: empty result in %s", start_lineno, query_buf);
|
||||
if(!row[0])
|
||||
die("Error on slave while syncing with master");
|
||||
mysql_free_result(res);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int do_save_master_pos()
|
||||
{
|
||||
MYSQL_RES* res;
|
||||
MYSQL_ROW row;
|
||||
MYSQL* mysql = &cur_con->mysql;
|
||||
if(mysql_query(mysql, "show master status"))
|
||||
die("At line %u: failed in show master status: %d: %s", start_lineno,
|
||||
mysql_errno(mysql), mysql_error(mysql));
|
||||
|
||||
if(!(res = mysql_store_result(mysql)))
|
||||
die("line %u: mysql_store_result() retuned NULL", start_lineno);
|
||||
if(!(row = mysql_fetch_row(res)))
|
||||
die("line %u: empty result in show master status", start_lineno);
|
||||
strncpy(master_pos.file, row[0], sizeof(master_pos.file));
|
||||
master_pos.pos = strtoul(row[1], (char**) 0, 10);
|
||||
mysql_free_result(res);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int do_let(struct st_query* q)
|
||||
{
|
||||
char* p=q->first_argument;
|
||||
|
@ -1326,6 +1379,7 @@ int main(int argc, char** argv)
|
|||
cur_con = cons;
|
||||
|
||||
memset(file_stack, 0, sizeof(file_stack));
|
||||
memset(&master_pos, 0, sizeof(master_pos));
|
||||
file_stack_end = file_stack + MAX_INCLUDE_DEPTH;
|
||||
cur_file = file_stack;
|
||||
lineno = lineno_stack;
|
||||
|
@ -1391,6 +1445,8 @@ int main(int argc, char** argv)
|
|||
get_file_name(save_file,q);
|
||||
require_file=1;
|
||||
break;
|
||||
case Q_SAVE_MASTER_POS: do_save_master_pos(q); break;
|
||||
case Q_SYNC_WITH_MASTER: do_sync_with_master(q); break;
|
||||
case Q_COMMENT: /* Ignore row */
|
||||
case Q_COMMENT_WITH_COMMAND:
|
||||
default: processed = 0; break;
|
||||
|
|
|
@ -194,11 +194,13 @@ if [ x$SOURCE_DIST = x1 ] ; then
|
|||
MYSQLD="$BASEDIR/sql/mysqld"
|
||||
MYSQL_TEST="$BASEDIR/client/mysqltest"
|
||||
MYSQLADMIN="$BASEDIR/client/mysqladmin"
|
||||
MYSQL="$BASEDIR/client/mysql"
|
||||
INSTALL_DB="./install_test_db"
|
||||
else
|
||||
MYSQLD="$BASEDIR/bin/mysqld"
|
||||
MYSQL_TEST="$BASEDIR/bin/mysqltest"
|
||||
MYSQLADMIN="$BASEDIR/bin/mysqladmin"
|
||||
MYSQL="$BASEDIR/bin/mysql"
|
||||
INSTALL_DB="./install_test_db -bin"
|
||||
fi
|
||||
|
||||
|
@ -235,6 +237,11 @@ SLAVE_MYSQLD=$MYSQLD #this can be changed later if we are doing gcov
|
|||
#++
|
||||
# Function Definitions
|
||||
#--
|
||||
wait_for_server_start ()
|
||||
{
|
||||
$MYSQL -e "select 1" --silent -w1 --host=127.0.0.1 --port=$1 \
|
||||
>/dev/null
|
||||
}
|
||||
|
||||
prompt_user ()
|
||||
{
|
||||
|
@ -325,6 +332,7 @@ gcov_collect () {
|
|||
$ECHO "gcov info in $GCOV_MSG, errors in $GCOV_ERR"
|
||||
}
|
||||
|
||||
|
||||
start_master()
|
||||
{
|
||||
[ x$MASTER_RUNNING = 1 ] && return
|
||||
|
@ -359,6 +367,7 @@ start_master()
|
|||
else
|
||||
$MYSQLD $master_args >> $MASTER_MYERR 2>&1 &
|
||||
fi
|
||||
wait_for_server_start $MASTER_MYPORT
|
||||
MASTER_RUNNING=1
|
||||
}
|
||||
|
||||
|
@ -404,6 +413,7 @@ start_slave()
|
|||
else
|
||||
$SLAVE_MYSQLD $slave_args >> $SLAVE_MYERR 2>&1 &
|
||||
fi
|
||||
wait_for_server_start $SLAVE_MYPORT
|
||||
SLAVE_RUNNING=1
|
||||
}
|
||||
|
||||
|
@ -412,7 +422,6 @@ mysql_start () {
|
|||
start_master
|
||||
start_slave
|
||||
cd $MYSQL_TEST_DIR
|
||||
sleep $SLEEP_TIME # Give mysqld time to start properly
|
||||
return 1
|
||||
}
|
||||
|
||||
|
@ -435,7 +444,6 @@ stop_slave ()
|
|||
fi
|
||||
fi
|
||||
SLAVE_RUNNING=0
|
||||
sleep $SLEEP_TIME # Give mysqld time to go down properly
|
||||
fi
|
||||
}
|
||||
|
||||
|
@ -458,7 +466,6 @@ stop_master ()
|
|||
fi
|
||||
fi
|
||||
MASTER_RUNNING=0
|
||||
sleep $SLEEP_TIME # Give mysqld time to go down properly
|
||||
fi
|
||||
}
|
||||
|
||||
|
@ -468,7 +475,10 @@ mysql_stop ()
|
|||
$ECHO "Shutting-down MySQL daemon"
|
||||
$ECHO ""
|
||||
stop_master
|
||||
$ECHO "Master shutdown finished"
|
||||
stop_slave
|
||||
$ECHO "Slave shutdown finished"
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
|
|
5
mysql-test/r/rpl000001.result
Normal file
5
mysql-test/r/rpl000001.result
Normal file
|
@ -0,0 +1,5 @@
|
|||
n
|
||||
1
|
||||
2
|
||||
sum(length(word))
|
||||
71
|
|
@ -1,13 +1,13 @@
|
|||
File Position Binlog_do_db Binlog_ignore_db
|
||||
master-bin.001 73
|
||||
Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db
|
||||
127.0.0.1 root 9306 1 73 Yes
|
||||
127.0.0.1 root 9306 1 master-bin.001 73 Yes
|
||||
Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db
|
||||
127.0.0.1 root 9306 1 73 No
|
||||
127.0.0.1 root 9306 1 master-bin.001 73 No
|
||||
Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db
|
||||
127.0.0.1 root 9306 1 73 Yes
|
||||
127.0.0.1 root 9306 1 master-bin.001 73 Yes
|
||||
Master_Host Master_User Master_Port Connect_retry Log_File Pos Slave_Running Replicate_do_db Replicate_ignore_db
|
||||
127.0.0.1 root 9306 1 173 Yes
|
||||
127.0.0.1 root 9306 1 master-bin.001 173 Yes
|
||||
File Position Binlog_do_db Binlog_ignore_db
|
||||
master-bin.001 73
|
||||
n
|
||||
|
|
|
@ -7,12 +7,15 @@ load data infile '../../std_data/words.dat' into table t1;
|
|||
drop table if exists foo;
|
||||
create table foo(n int);
|
||||
insert into foo values(1),(2);
|
||||
save_master_pos;
|
||||
connection slave;
|
||||
sleep 2;
|
||||
sync_with_master;
|
||||
use test;
|
||||
@r/rpl000001.a.result select * from foo;
|
||||
@r/rpl000001.b.result select sum(length(word)) from t1;
|
||||
select * from foo;
|
||||
select sum(length(word)) from t1;
|
||||
connection master;
|
||||
drop table t1;
|
||||
|
||||
save_master_pos;
|
||||
connection slave;
|
||||
sync_with_master;
|
||||
|
||||
|
|
|
@ -5,8 +5,13 @@ drop table if exists t1;
|
|||
create table t1 (n int auto_increment primary key);
|
||||
set insert_id = 2000;
|
||||
insert into t1 values (NULL),(NULL),(NULL);
|
||||
save_master_pos;
|
||||
connection slave;
|
||||
use test;
|
||||
sleep 2;
|
||||
sync_with_master;
|
||||
@r/rpl000002.result select * from t1;
|
||||
connection master;
|
||||
drop table t1;
|
||||
save_master_pos;
|
||||
connection slave;
|
||||
sync_with_master;
|
||||
|
|
|
@ -4,7 +4,12 @@ drop table if exists t1;
|
|||
create table t1(n int primary key);
|
||||
!insert into t1 values (1),(2),(2);
|
||||
insert into t1 values (3);
|
||||
save_master_pos;
|
||||
connection slave;
|
||||
sleep 2;
|
||||
sync_with_master;
|
||||
@r/rpl000003.result select * from t1;
|
||||
connection master;
|
||||
drop table t1;
|
||||
save_master_pos;
|
||||
connection slave;
|
||||
sync_with_master;
|
||||
|
|
|
@ -16,4 +16,11 @@ drop table if exists t2;
|
|||
load table t2 from master;
|
||||
@r/rpl000004.a.result check table t1;
|
||||
@r/rpl000004.b.result select count(*) from t2;
|
||||
connection master;
|
||||
set SQL_LOG_BIN=1;
|
||||
drop table if exists t1,t2;
|
||||
save_master_pos;
|
||||
connection slave;
|
||||
sync_with_master;
|
||||
create table t1(n int);
|
||||
drop table t1;
|
||||
|
|
|
@ -7,8 +7,12 @@ INSERT t1 SET name='Jacob', age=2;
|
|||
INSERT into t1 SET name='Caleb', age=1;
|
||||
ALTER TABLE t1 ADD id int(8) ZEROFILL AUTO_INCREMENT PRIMARY KEY;
|
||||
@r/rpl000005.result select * from t1;
|
||||
save_master_pos;
|
||||
connection slave;
|
||||
sleep 2;
|
||||
sync_with_master;
|
||||
@r/rpl000005.result select * from t1;
|
||||
connection master;
|
||||
drop table t1;
|
||||
save_master_pos;
|
||||
connection slave;
|
||||
sync_with_master;
|
||||
|
|
|
@ -12,3 +12,6 @@ load table foo from master;
|
|||
@r/rpl000006.result select unix_timestamp(t) from foo;
|
||||
connection master;
|
||||
drop table foo;
|
||||
save_master_pos;
|
||||
connection slave;
|
||||
sync_with_master;
|
||||
|
|
|
@ -15,8 +15,12 @@ insert into foo values('five');
|
|||
drop table if exists bar;
|
||||
create table bar (m int);
|
||||
insert into bar values(15);
|
||||
save_master_pos;
|
||||
connection slave;
|
||||
sleep 2;
|
||||
sync_with_master;
|
||||
@r/rpl000007.result select foo.n,bar.m from foo,bar;
|
||||
connection master;
|
||||
drop table if exists bar,foo;
|
||||
save_master_pos;
|
||||
connection slave;
|
||||
sync_with_master;
|
||||
|
|
|
@ -17,8 +17,13 @@ insert into bar values(15);
|
|||
drop table if exists choo;
|
||||
create table choo (k int);
|
||||
insert into choo values(55);
|
||||
save_master_pos;
|
||||
connection slave;
|
||||
sleep 3;
|
||||
sync_with_master;
|
||||
@r/rpl000008.result select foo.n,bar.m,choo.k from foo,bar,choo;
|
||||
connection master;
|
||||
drop table if exists foo,bar,choo;
|
||||
save_master_pos;
|
||||
connection slave;
|
||||
sync_with_master;
|
||||
drop table if exists foo,bar,choo;
|
||||
|
|
|
@ -6,8 +6,9 @@ drop database if exists foo;
|
|||
create database foo;
|
||||
drop database if exists bar;
|
||||
create database bar;
|
||||
save_master_pos;
|
||||
connection slave;
|
||||
sleep 2;
|
||||
sync_with_master;
|
||||
drop table if exists foo.foo;
|
||||
create table foo.foo (n int);
|
||||
insert into foo.foo values(4);
|
||||
|
@ -18,9 +19,15 @@ insert into foo.foo values(5);
|
|||
drop table if exists bar.bar;
|
||||
create table bar.bar (m int);
|
||||
insert into bar.bar values(15);
|
||||
save_master_pos;
|
||||
connection slave;
|
||||
sleep 2;
|
||||
sync_with_master;
|
||||
@r/rpl000009.result select foo.foo.n,bar.bar.m from foo.foo,bar.bar;
|
||||
connection master;
|
||||
drop database if exists bar;
|
||||
drop database if exists foo;
|
||||
save_master_pos;
|
||||
connection slave;
|
||||
sync_with_master;
|
||||
drop database if exists bar;
|
||||
drop database if exists foo;
|
||||
|
|
|
@ -8,8 +8,12 @@ drop table if exists t1;
|
|||
create table t1 (n int not null auto_increment primary key);
|
||||
insert into t1 values(NULL);
|
||||
insert into t1 values(2);
|
||||
save_master_pos;
|
||||
connection slave;
|
||||
sleep 5;
|
||||
sync_with_master;
|
||||
@r/rpl000010.result select n from t1;
|
||||
connection master;
|
||||
drop table t1;
|
||||
save_master_pos;
|
||||
connection slave;
|
||||
sync_with_master;
|
||||
|
|
|
@ -4,16 +4,21 @@ use test;
|
|||
drop table if exists t1;
|
||||
create table t1 (n int);
|
||||
insert into t1 values(1);
|
||||
save_master_pos;
|
||||
connection slave;
|
||||
#give slave some breathing room to get started
|
||||
sleep 2;
|
||||
sync_with_master;
|
||||
slave stop;
|
||||
slave start;
|
||||
connection master;
|
||||
insert into t1 values(2);
|
||||
save_master_pos;
|
||||
connection slave;
|
||||
#let slave catch up
|
||||
sleep 2;
|
||||
sync_with_master;
|
||||
@r/rpl000011.result select * from t1;
|
||||
connection master;
|
||||
drop table t1;
|
||||
save_master_pos;
|
||||
connection slave;
|
||||
sync_with_master;
|
||||
|
|
|
@ -14,13 +14,18 @@ disconnect master;
|
|||
connection master1;
|
||||
insert into t2 values(6);
|
||||
disconnect master1;
|
||||
connect (master2,localhost,root,,test,0,mysql-master.sock);
|
||||
connection master2;
|
||||
save_master_pos;
|
||||
connection slave;
|
||||
sleep 1;
|
||||
sync_with_master;
|
||||
@r/rpl000012.result select * from t2;
|
||||
@r/rpl000012.status.result show status like 'Slave_open_temp_tables';
|
||||
#
|
||||
# Clean up
|
||||
#
|
||||
connect (master2,localhost,root,,test,0,mysql-master.sock);
|
||||
connection master2;
|
||||
drop table if exists t1,t2;
|
||||
save_master_pos;
|
||||
connection slave;
|
||||
sync_with_master;
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
source include/master-slave.inc;
|
||||
connection master;
|
||||
save_master_pos;
|
||||
connection slave;
|
||||
sync_with_master;
|
||||
connection master;
|
||||
drop table if exists t2;
|
||||
create table t2(n int);
|
||||
create temporary table t1 (n int);
|
||||
|
@ -12,21 +16,19 @@ insert into t2 select * from t1;
|
|||
disconnect master;
|
||||
connection master1;
|
||||
insert into t2 values(6);
|
||||
sleep 2;
|
||||
disconnect master1;
|
||||
connect (master2,localhost,root,,test,0,mysql-master.sock);
|
||||
connection master2;
|
||||
save_master_pos;
|
||||
connection slave;
|
||||
let $1=12;
|
||||
while ($1)
|
||||
{
|
||||
!slave start;
|
||||
sleep 0.2;
|
||||
dec $1;
|
||||
}
|
||||
sync_with_master;
|
||||
@r/rpl000013.result select * from t2;
|
||||
@r/rpl000013.status.result show status like 'Slave_open_temp_tables';
|
||||
#
|
||||
# Clean up
|
||||
#
|
||||
connect (master2,localhost,root,,test,0,mysql-master.sock);
|
||||
connection master2;
|
||||
drop table if exists t1,t2;
|
||||
save_master_pos;
|
||||
connection slave;
|
||||
sync_with_master;
|
||||
|
|
|
@ -2,11 +2,11 @@ source include/master-slave.inc;
|
|||
source include/have_default_master.inc;
|
||||
connection master;
|
||||
show master status;
|
||||
save_master_pos;
|
||||
connection slave;
|
||||
sleep 0.2;
|
||||
sync_with_master;
|
||||
show slave status;
|
||||
change master to master_log_pos=73;
|
||||
sleep 0.2;
|
||||
slave stop;
|
||||
change master to master_log_pos=73;
|
||||
show slave status;
|
||||
|
@ -20,9 +20,13 @@ create table if not exists foo(n int);
|
|||
drop table if exists foo;
|
||||
create table foo (n int);
|
||||
insert into foo values (1),(2),(3);
|
||||
save_master_pos;
|
||||
connection slave;
|
||||
change master to master_log_pos=73;
|
||||
sleep 2;
|
||||
sync_with_master;
|
||||
select * from foo;
|
||||
connection master;
|
||||
drop table foo;
|
||||
save_master_pos;
|
||||
connection slave;
|
||||
sync_with_master;
|
||||
|
|
|
@ -18,8 +18,13 @@ connection master;
|
|||
drop table if exists foo;
|
||||
create table foo (n int);
|
||||
insert into foo values (10),(45),(90);
|
||||
save_master_pos;
|
||||
connection slave;
|
||||
sleep 2;
|
||||
sync_with_master;
|
||||
select * from foo;
|
||||
connection master;
|
||||
drop table foo;
|
||||
save_master_pos;
|
||||
connection slave;
|
||||
sync_with_master;
|
||||
|
||||
|
|
|
@ -15,8 +15,9 @@ connection master;
|
|||
drop table if exists t1;
|
||||
create table t1 (s text);
|
||||
insert into t1 values('Could not break slave'),('Tried hard');
|
||||
save_master_pos;
|
||||
connection slave;
|
||||
sleep 2;
|
||||
sync_with_master;
|
||||
select * from t1;
|
||||
connection master;
|
||||
flush logs;
|
||||
|
@ -24,12 +25,14 @@ drop table if exists t2;
|
|||
create table t2(m int);
|
||||
insert into t2 values (34),(67),(123);
|
||||
flush logs;
|
||||
sleep 0.3;
|
||||
show master logs;
|
||||
purge master logs to 'master-bin.003';
|
||||
show master logs;
|
||||
insert into t2 values (65);
|
||||
save_master_pos;
|
||||
connection slave;
|
||||
sleep 2;
|
||||
sync_with_master;
|
||||
select * from t2;
|
||||
drop table if exists t1,t2;
|
||||
connection master;
|
||||
drop table if exists t1,t2;
|
||||
|
|
|
@ -376,3 +376,8 @@ Item *create_load_file(Item* a)
|
|||
{
|
||||
return new Item_load_file(a);
|
||||
}
|
||||
|
||||
Item *create_wait_for_master_pos(Item* a, Item* b)
|
||||
{
|
||||
return new Item_master_pos_wait(a, b);
|
||||
}
|
||||
|
|
|
@ -85,3 +85,4 @@ Item *create_func_ucase(Item* a);
|
|||
Item *create_func_version(void);
|
||||
Item *create_func_weekday(Item* a);
|
||||
Item *create_load_file(Item* a);
|
||||
Item *create_wait_for_master_pos(Item* a, Item* b);
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <hash.h>
|
||||
#include <time.h>
|
||||
#include <ft_global.h>
|
||||
#include "slave.h" // for wait_for_master_pos
|
||||
|
||||
/* return TRUE if item is a constant */
|
||||
|
||||
|
@ -1387,6 +1388,28 @@ void item_user_lock_release(ULL *ull)
|
|||
delete ull;
|
||||
}
|
||||
|
||||
/*
|
||||
Wait until we are at or past the given position in the master binlog
|
||||
on the slave
|
||||
*/
|
||||
|
||||
longlong Item_master_pos_wait::val_int()
|
||||
{
|
||||
THD* thd = current_thd;
|
||||
String *log_name = args[0]->val_str(&value);
|
||||
int event_count;
|
||||
|
||||
if(thd->slave_thread || !log_name || !log_name->length())
|
||||
{
|
||||
null_value = 1;
|
||||
return 0;
|
||||
}
|
||||
ulong pos = (ulong)args[1]->val_int();
|
||||
if((event_count = glob_mi.wait_for_pos(thd, log_name, pos)) == -1)
|
||||
null_value = 1;;
|
||||
return event_count;
|
||||
}
|
||||
|
||||
/*
|
||||
Get a user level lock. If the thread has an old lock this is first released.
|
||||
Returns 1: Got lock
|
||||
|
|
|
@ -778,6 +778,18 @@ class Item_func_release_lock :public Item_int_func
|
|||
void fix_length_and_dec() { decimals=0; max_length=1; maybe_null=1;}
|
||||
};
|
||||
|
||||
/* replication functions */
|
||||
|
||||
class Item_master_pos_wait :public Item_int_func
|
||||
{
|
||||
String value;
|
||||
public:
|
||||
Item_master_pos_wait(Item *a,Item *b) :Item_int_func(a,b) {}
|
||||
longlong val_int();
|
||||
const char *func_name() const { return "master_pos_wait"; }
|
||||
void fix_length_and_dec() { decimals=0; max_length=1; maybe_null=1;}
|
||||
};
|
||||
|
||||
|
||||
/* Handling of user definiable variables */
|
||||
|
||||
|
|
|
@ -398,6 +398,8 @@ static SYMBOL sql_functions[] = {
|
|||
{ "LOWER", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_lcase)},
|
||||
{ "LPAD", SYM(FUNC_ARG3),0,CREATE_FUNC(create_func_lpad)},
|
||||
{ "LTRIM", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_ltrim)},
|
||||
{ "MASTER_POS_WAIT", SYM(FUNC_ARG2),0,
|
||||
CREATE_FUNC(create_wait_for_master_pos)},
|
||||
{ "MAKE_SET", SYM(MAKE_SET_SYM),0,0},
|
||||
{ "MAX", SYM(MAX_SYM),0,0},
|
||||
{ "MD5", SYM(FUNC_ARG1),0,CREATE_FUNC(create_func_md5)},
|
||||
|
|
58
sql/slave.cc
58
sql/slave.cc
|
@ -616,6 +616,46 @@ int flush_master_info(MASTER_INFO* mi)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int st_master_info::wait_for_pos(THD* thd, String* log_name, ulong log_pos)
|
||||
{
|
||||
if(!inited) return -1;
|
||||
bool pos_reached = 0;
|
||||
int event_count = 0;
|
||||
for(;!pos_reached && !thd->killed;)
|
||||
{
|
||||
int cmp_result;
|
||||
char* basename;
|
||||
pthread_mutex_lock(&lock);
|
||||
if(*log_file_name)
|
||||
{
|
||||
basename = strrchr(log_file_name, FN_LIBCHAR);
|
||||
if(basename)
|
||||
++basename;
|
||||
else
|
||||
basename = log_file_name;
|
||||
cmp_result = strncmp(basename, log_name->ptr(),
|
||||
log_name->length());
|
||||
}
|
||||
else
|
||||
cmp_result = 0;
|
||||
|
||||
pos_reached = ((!cmp_result && pos >= log_pos) || cmp_result > 0);
|
||||
if(!pos_reached && !thd->killed)
|
||||
{
|
||||
const char* msg = thd->enter_cond(&cond, &lock,
|
||||
"Waiting for master update");
|
||||
pthread_cond_wait(&cond, &lock);
|
||||
thd->exit_cond(msg);
|
||||
event_count++;
|
||||
}
|
||||
pthread_mutex_unlock(&lock);
|
||||
if(thd->killed)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return event_count;
|
||||
}
|
||||
|
||||
|
||||
static int init_slave_thread(THD* thd)
|
||||
{
|
||||
|
@ -1003,10 +1043,17 @@ static int exec_event(THD* thd, NET* net, MASTER_INFO* mi, int event_len)
|
|||
{
|
||||
Rotate_log_event* rev = (Rotate_log_event*)ev;
|
||||
int ident_len = rev->ident_len;
|
||||
pthread_mutex_lock(&mi->lock);
|
||||
memcpy(mi->log_file_name, rev->new_log_ident,ident_len );
|
||||
mi->log_file_name[ident_len] = 0;
|
||||
mi->pos = 4; // skip magic number
|
||||
pthread_cond_broadcast(&mi->cond);
|
||||
pthread_mutex_unlock(&mi->lock);
|
||||
flush_master_info(mi);
|
||||
#ifndef DBUG_OFF
|
||||
if(abort_slave_event_count)
|
||||
++events_till_abort;
|
||||
#endif
|
||||
delete ev;
|
||||
break;
|
||||
}
|
||||
|
@ -1045,6 +1092,9 @@ static int exec_event(THD* thd, NET* net, MASTER_INFO* mi, int event_len)
|
|||
|
||||
pthread_handler_decl(handle_slave,arg __attribute__((unused)))
|
||||
{
|
||||
#ifndef DBUG_OFF
|
||||
slave_begin:
|
||||
#endif
|
||||
THD *thd; // needs to be first for thread_stack
|
||||
MYSQL *mysql = NULL ;
|
||||
|
||||
|
@ -1068,8 +1118,8 @@ pthread_handler_decl(handle_slave,arg __attribute__((unused)))
|
|||
#ifndef DBUG_OFF
|
||||
events_till_abort = abort_slave_event_count;
|
||||
#endif
|
||||
pthread_cond_broadcast(&COND_slave_start);
|
||||
pthread_mutex_unlock(&LOCK_slave);
|
||||
pthread_cond_broadcast(&COND_slave_start);
|
||||
pthread_mutex_unlock(&LOCK_slave);
|
||||
|
||||
int error = 1;
|
||||
bool retried_once = 0;
|
||||
|
@ -1241,6 +1291,10 @@ position %ld",
|
|||
net_end(&thd->net); // destructor will not free it, because we are weird
|
||||
delete thd;
|
||||
my_thread_end();
|
||||
#ifndef DBUG_OFF
|
||||
if(abort_slave_event_count && !events_till_abort)
|
||||
goto slave_begin;
|
||||
#endif
|
||||
pthread_exit(0);
|
||||
DBUG_RETURN(0); // Can't return anything here
|
||||
}
|
||||
|
|
|
@ -14,17 +14,20 @@ typedef struct st_master_info
|
|||
uint port;
|
||||
uint connect_retry;
|
||||
pthread_mutex_t lock;
|
||||
pthread_cond_t cond;
|
||||
bool inited;
|
||||
|
||||
st_master_info():pending(0),fd(-1),inited(0)
|
||||
{
|
||||
host[0] = 0; user[0] = 0; password[0] = 0;
|
||||
pthread_mutex_init(&lock, NULL);
|
||||
pthread_cond_init(&cond, NULL);
|
||||
}
|
||||
|
||||
~st_master_info()
|
||||
{
|
||||
pthread_mutex_destroy(&lock);
|
||||
pthread_cond_destroy(&cond);
|
||||
}
|
||||
inline void inc_pending(ulonglong val)
|
||||
{
|
||||
|
@ -35,6 +38,7 @@ typedef struct st_master_info
|
|||
pthread_mutex_lock(&lock);
|
||||
pos += val + pending;
|
||||
pending = 0;
|
||||
pthread_cond_broadcast(&cond);
|
||||
pthread_mutex_unlock(&lock);
|
||||
}
|
||||
// thread safe read of position - not needed if we are in the slave thread,
|
||||
|
@ -45,6 +49,8 @@ typedef struct st_master_info
|
|||
var = pos;
|
||||
pthread_mutex_unlock(&lock);
|
||||
}
|
||||
|
||||
int wait_for_pos(THD* thd, String* log_name, ulong log_pos);
|
||||
} MASTER_INFO;
|
||||
|
||||
typedef struct st_table_rule_ent
|
||||
|
|
|
@ -281,6 +281,25 @@ public:
|
|||
THD();
|
||||
~THD();
|
||||
bool store_globals();
|
||||
inline const char* enter_cond(pthread_cond_t *cond, pthread_mutex_t* mutex,
|
||||
const char* msg)
|
||||
{
|
||||
const char* old_msg = proc_info;
|
||||
pthread_mutex_lock(&mysys_var->mutex);
|
||||
mysys_var->current_mutex = mutex;
|
||||
mysys_var->current_cond = cond;
|
||||
proc_info = msg;
|
||||
pthread_mutex_unlock(&mysys_var->mutex);
|
||||
return old_msg;
|
||||
}
|
||||
inline void exit_cond(const char* old_msg)
|
||||
{
|
||||
pthread_mutex_lock(&mysys_var->mutex);
|
||||
mysys_var->current_mutex = 0;
|
||||
mysys_var->current_cond = 0;
|
||||
proc_info = old_msg;
|
||||
pthread_mutex_unlock(&mysys_var->mutex);
|
||||
}
|
||||
inline time_t query_start() { query_start_used=1; return start_time; }
|
||||
inline void set_time() { if (user_time) start_time=time_after_lock=user_time; else time_after_lock=time(&start_time); }
|
||||
inline void end_time() { time(&start_time); }
|
||||
|
|
|
@ -26,6 +26,36 @@
|
|||
|
||||
extern const char* any_db;
|
||||
extern pthread_handler_decl(handle_slave,arg);
|
||||
static int fake_rotate_event(NET* net, String* packet,
|
||||
const char* log_file_name);
|
||||
|
||||
static int fake_rotate_event(NET* net, String* packet, char* log_file_name,
|
||||
const char**errmsg)
|
||||
{
|
||||
char header[LOG_EVENT_HEADER_LEN];
|
||||
memset(header, 0, 4); // when does not matter
|
||||
header[EVENT_TYPE_OFFSET] = ROTATE_EVENT;
|
||||
char* p = strrchr(log_file_name, FN_LIBCHAR);
|
||||
// find the last slash
|
||||
if(p)
|
||||
p++;
|
||||
else
|
||||
p = log_file_name;
|
||||
|
||||
uint ident_len = (uint) strlen(p);
|
||||
ulong event_len = ident_len + sizeof(header);
|
||||
int4store(header + EVENT_TYPE_OFFSET + 1, server_id);
|
||||
int4store(header + EVENT_LEN_OFFSET, event_len);
|
||||
packet->append(header, sizeof(header));
|
||||
packet->append(p,ident_len);
|
||||
if(my_net_write(net, (char*)packet->ptr(), packet->length()))
|
||||
{
|
||||
*errmsg = "failed on my_net_write()";
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int send_file(THD *thd)
|
||||
{
|
||||
|
@ -281,6 +311,15 @@ sweepstakes if you report the bug";
|
|||
// we need to start a packet with something other than 255
|
||||
// to distiquish it from error
|
||||
|
||||
if(pos == 4) // tell the client log name with a fake rotate_event
|
||||
// if we are at the start of the log
|
||||
{
|
||||
if(fake_rotate_event(net, packet, log_file_name, &errmsg))
|
||||
goto err;
|
||||
packet->length(0);
|
||||
packet->append("\0", 1);
|
||||
}
|
||||
|
||||
while(!net->error && net->vio != 0 && !thd->killed)
|
||||
{
|
||||
pthread_mutex_t *log_lock = mysql_bin_log.get_log_lock();
|
||||
|
@ -437,36 +476,15 @@ sweepstakes if you report the bug";
|
|||
|
||||
end_io_cache(&log);
|
||||
(void) my_close(file, MYF(MY_WME));
|
||||
if ((file=open_log(&log, log_file_name, &errmsg)) < 0)
|
||||
goto err;
|
||||
|
||||
|
||||
// fake Rotate_log event just in case it did not make it to the log
|
||||
// otherwise the slave make get confused about the offset
|
||||
{
|
||||
char header[LOG_EVENT_HEADER_LEN];
|
||||
memset(header, 0, 4); // when does not matter
|
||||
header[EVENT_TYPE_OFFSET] = ROTATE_EVENT;
|
||||
char* p = strrchr(log_file_name, FN_LIBCHAR);
|
||||
// find the last slash
|
||||
if(p)
|
||||
p++;
|
||||
else
|
||||
p = log_file_name;
|
||||
if ((file=open_log(&log, log_file_name, &errmsg)) < 0 ||
|
||||
fake_rotate_event(net, packet, log_file_name, &errmsg))
|
||||
goto err;
|
||||
|
||||
uint ident_len = (uint) strlen(p);
|
||||
ulong event_len = ident_len + sizeof(header);
|
||||
int4store(header + EVENT_TYPE_OFFSET + 1, server_id);
|
||||
int4store(header + EVENT_LEN_OFFSET, event_len);
|
||||
packet->append(header, sizeof(header));
|
||||
packet->append(p,ident_len);
|
||||
if(my_net_write(net, (char*)packet->ptr(), packet->length()))
|
||||
{
|
||||
errmsg = "failed on my_net_write()";
|
||||
goto err;
|
||||
}
|
||||
packet->length(0);
|
||||
packet->append("\0",1);
|
||||
}
|
||||
packet->length(0);
|
||||
packet->append("\0",1);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue