mirror of
https://github.com/MariaDB/server.git
synced 2025-08-08 11:22:35 +03:00
WWe now store the catalog in Query_log_event in binlog WITHOUT its end zero.
This saves one byte per Query_log_event on disk compared to 5.0.[0..3]. Compatibility problems with 5.0.x where x<4 are explained in the comments in log_event.cc. Putting back s/my_open(O_TRUNC)/(my_delete+my_create) change which had been wiped away by somebody doing a wrong 4.1->5.0 merge (which happened just before 5.0.3 :( ). Applying it to new events for LOAD DATA INFILE. If slave fails in Execute_load_query_log_event::exec_event(), don't delete the file (so that it's re-usable at next START SLAVE). And (youpi!) fix for BUG#3247 "a partially completed LOAD DATA INFILE is not executed at all on the slave" (storing an Execute_load_query_log_event to binlog, with its error code, instead of Delete_file_log_event). mysql-test/r/mix_innodb_myisam_binlog.result: we now use one less byte when storing the catalog in binlog so positions change mysql-test/r/rpl_change_master.result: we now use one less byte when storing the catalog in binlog so positions change mysql-test/r/rpl_deadlock.result: we now use one less byte when storing the catalog in binlog so positions change mysql-test/r/rpl_error_ignored_table.result: we now use one less byte when storing the catalog in binlog so positions change mysql-test/r/rpl_flush_log_loop.result: we now use one less byte when storing the catalog in binlog so positions change mysql-test/r/rpl_loaddata.result: we now use one less byte when storing the catalog in binlog so positions change. Plus testing replication of LOAD DATA INFILE if duplicate key and non-transactional table. mysql-test/r/rpl_log.result: we now use one less byte when storing the catalog in binlog so positions change mysql-test/r/rpl_max_relay_size.result: we now use one less byte when storing the catalog in binlog so positions change mysql-test/r/rpl_relayrotate.result: we now use one less byte when storing the catalog in binlog so positions change mysql-test/r/rpl_replicate_do.result: we now use one less byte when storing the catalog in binlog so positions change mysql-test/r/rpl_rotate_logs.result: we now use one less byte when storing the catalog in binlog so positions change mysql-test/r/rpl_until.result: we now use one less byte when storing the catalog in binlog so positions change mysql-test/t/mysqlbinlog.test: we now use one less byte when storing the catalog in binlog so positions change mysql-test/t/mysqlbinlog2.test: we now use one less byte when storing the catalog in binlog so positions change mysql-test/t/rpl_deadlock.test: we now use one less byte when storing the catalog in binlog so positions change mysql-test/t/rpl_loaddata.test: we now use one less byte when storing the catalog in binlog so positions change. Plus testing replication of LOAD DATA INFILE if duplicate key and non-transactional table. mysql-test/t/rpl_until.test: we now use one less byte when storing the catalog in binlog so positions change sql/log_event.cc: a) We now store the catalog in Query_log_event in binlog WITHOUT its end zero. This saves one byte per Query_log_event on disk. Compatibility problems with 5.0.x where x<4 are explained in the comments in this file. b) putting back s/my_open(O_TRUNC)/(my_delete+my_create) change which had been wiped away by somebody doing a wrong 4.1->5.0 merge (which happened just before 5.0.3 :( ). Applying it to new events for LOAD DATA INFILE. c) if slave fails in Execute_load_query_log_event::exec_event(), don't delete the file (so that it's re-usable at next START SLAVE). sql/log_event.h: We now store the catalog in Query_log_event in binlog WITHOUT its end zero. This saves one byte per Query_log_event on disk. This new storage for the catalog is denoted by Q_CATALOG_NZ_CODE (couldn't re-use Q_CATALOG_CODE as 5.0.3 slaves of this 5.0.4 master would segfault because it would expect a 0 when there is none. Renaming get_open_mode() to get_create_or_append() (see log_event.cc) sql/sql_load.cc: Fix for BUG#3247: if LOAD DATA INFILE fails but has permanently updated a table (i.e. has deleted/added/modified some rows in a non-transactional table), we must write an Execute_load_query_log_event to binlog (with the error code, as this class beautifully inherits from Query_log_event, it can store the error code - thanks Dmitri) and not a Delete_file_log_event (we use to write a Delete_file_log_event: no update happened on slave, bug).
This commit is contained in:
@@ -1041,25 +1041,28 @@ bool Query_log_event::write(IO_CACHE* file)
|
||||
}
|
||||
if (catalog_len) // i.e. "catalog inited" (false for 4.0 events)
|
||||
{
|
||||
*start++= Q_CATALOG_CODE;
|
||||
*start++= Q_CATALOG_NZ_CODE;
|
||||
*start++= (uchar) catalog_len;
|
||||
bmove(start, catalog, catalog_len);
|
||||
start+= catalog_len;
|
||||
/*
|
||||
We write a \0 at the end. As we also have written the length, it's
|
||||
apparently useless; but in fact it enables us to just do
|
||||
catalog= a_pointer_to_the_buffer_of_the_read_event
|
||||
later in the slave SQL thread.
|
||||
If we didn't have the \0, we would need to memdup to build the catalog in
|
||||
the slave SQL thread.
|
||||
And still the interest of having the length too is that in the slave SQL
|
||||
thread we immediately know at which position the catalog ends (no need to
|
||||
search for '\0'. In other words: length saves search, \0 saves mem alloc,
|
||||
at the cost of 1 redundant byte on the disk.
|
||||
Note that this is only a fix until we change 'catalog' to LEX_STRING
|
||||
(then we won't need the \0).
|
||||
*/
|
||||
*(start++)= '\0';
|
||||
In 5.0.x where x<4 masters we used to store the end zero here. This was
|
||||
a waste of one byte so we don't do it in x>=4 masters. We change code to
|
||||
Q_CATALOG_NZ_CODE, because re-using the old code would make x<4 slaves
|
||||
of this x>=4 master segfault (expecting a zero when there is
|
||||
none). Remaining compatibility problems are: the older slave will not
|
||||
find the catalog; but it is will not crash, and it's not an issue
|
||||
that it does not find the catalog as catalogs were not used in these older
|
||||
MySQL versions (we store it in binlog and read it from relay log but do
|
||||
nothing useful with it). What is an issue is that the older slave will
|
||||
stop processing the Q_* blocks (and jumps to the db/query) as soon as it
|
||||
sees unknown Q_CATALOG_NZ_CODE; so it will not be able to read
|
||||
Q_AUTO_INCREMENT*, Q_CHARSET and so replication will fail silently in
|
||||
various ways. Documented that you should not mix alpha/beta versions if
|
||||
they are not exactly the same version, with example of 5.0.2<->5.0.3 and
|
||||
5.0.3<->5.0.4. If replication is from older to new, the new won't find
|
||||
the catalog and will have the same problems.
|
||||
*/
|
||||
}
|
||||
if (auto_increment_increment != 1)
|
||||
{
|
||||
@@ -1259,10 +1262,10 @@ Query_log_event::Query_log_event(const char* buf, uint event_len,
|
||||
pos+= 8;
|
||||
break;
|
||||
}
|
||||
case Q_CATALOG_CODE:
|
||||
case Q_CATALOG_NZ_CODE:
|
||||
if ((catalog_len= *pos))
|
||||
catalog= (char*) pos+1; // Will be copied later
|
||||
pos+= catalog_len+2;
|
||||
pos+= catalog_len+1;
|
||||
break;
|
||||
case Q_AUTO_INCREMENT:
|
||||
auto_increment_increment= uint2korr(pos);
|
||||
@@ -1297,9 +1300,10 @@ Query_log_event::Query_log_event(const char* buf, uint event_len,
|
||||
DBUG_VOID_RETURN;
|
||||
if (catalog_len) // If catalog is given
|
||||
{
|
||||
memcpy(start, catalog, catalog_len+1); // Copy name and end \0
|
||||
memcpy(start, catalog, catalog_len);
|
||||
catalog= start;
|
||||
start+= catalog_len+1;
|
||||
start+= catalog_len;
|
||||
*start++= 0;
|
||||
}
|
||||
if (time_zone_len)
|
||||
{
|
||||
@@ -4006,8 +4010,10 @@ int Create_file_log_event::exec_event(struct st_relay_log_info* rli)
|
||||
strmov(p, ".info"); // strmov takes less code than memcpy
|
||||
strnmov(proc_info, "Making temp file ", 17); // no end 0
|
||||
thd->proc_info= proc_info;
|
||||
if ((fd = my_open(fname_buf, O_WRONLY|O_CREAT|O_BINARY|O_TRUNC,
|
||||
MYF(MY_WME))) < 0 ||
|
||||
my_delete(fname_buf, MYF(0)); // old copy may exist already
|
||||
if ((fd= my_create(fname_buf, CREATE_MODE,
|
||||
O_WRONLY | O_BINARY | O_EXCL | O_NOFOLLOW,
|
||||
MYF(MY_WME))) < 0 ||
|
||||
init_io_cache(&file, fd, IO_SIZE, WRITE_CACHE, (my_off_t)0, 0,
|
||||
MYF(MY_WME|MY_NABP)))
|
||||
{
|
||||
@@ -4031,8 +4037,10 @@ int Create_file_log_event::exec_event(struct st_relay_log_info* rli)
|
||||
my_close(fd, MYF(0));
|
||||
|
||||
// fname_buf now already has .data, not .info, because we did our trick
|
||||
if ((fd = my_open(fname_buf, O_WRONLY|O_CREAT|O_BINARY|O_TRUNC,
|
||||
MYF(MY_WME))) < 0)
|
||||
my_delete(fname_buf, MYF(0)); // old copy may exist already
|
||||
if ((fd= my_create(fname_buf, CREATE_MODE,
|
||||
O_WRONLY | O_BINARY | O_EXCL | O_NOFOLLOW,
|
||||
MYF(MY_WME))) < 0)
|
||||
{
|
||||
slave_print_error(rli,my_errno, "Error in Create_file event: could not open file '%s'", fname_buf);
|
||||
goto err;
|
||||
@@ -4148,12 +4156,12 @@ void Append_block_log_event::pack_info(Protocol *protocol)
|
||||
|
||||
|
||||
/*
|
||||
Append_block_log_event::get_open_mode()
|
||||
Append_block_log_event::get_create_or_append()
|
||||
*/
|
||||
|
||||
int Append_block_log_event::get_open_mode() const
|
||||
int Append_block_log_event::get_create_or_append() const
|
||||
{
|
||||
return O_WRONLY | O_APPEND | O_BINARY;
|
||||
return 0; /* append to the file, fail if not exists */
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -4171,7 +4179,20 @@ int Append_block_log_event::exec_event(struct st_relay_log_info* rli)
|
||||
memcpy(p, ".data", 6);
|
||||
strnmov(proc_info, "Making temp file ", 17); // no end 0
|
||||
thd->proc_info= proc_info;
|
||||
if ((fd = my_open(fname, get_open_mode(), MYF(MY_WME))) < 0)
|
||||
if (get_create_or_append())
|
||||
{
|
||||
my_delete(fname, MYF(0)); // old copy may exist already
|
||||
if ((fd= my_create(fname, CREATE_MODE,
|
||||
O_WRONLY | O_BINARY | O_EXCL | O_NOFOLLOW,
|
||||
MYF(MY_WME))) < 0)
|
||||
{
|
||||
slave_print_error(rli, my_errno,
|
||||
"Error in %s event: could not create file '%s'",
|
||||
get_type_str(), fname);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
else if ((fd = my_open(fname, O_WRONLY|O_APPEND|O_BINARY|O_NOFOLLOW, MYF(MY_WME))) < 0)
|
||||
{
|
||||
slave_print_error(rli, my_errno,
|
||||
"Error in %s event: could not open file '%s'",
|
||||
@@ -4384,7 +4405,7 @@ int Execute_load_log_event::exec_event(struct st_relay_log_info* rli)
|
||||
Load_log_event* lev = 0;
|
||||
|
||||
memcpy(p, ".info", 6);
|
||||
if ((fd = my_open(fname, O_RDONLY|O_BINARY, MYF(MY_WME))) < 0 ||
|
||||
if ((fd = my_open(fname, O_RDONLY|O_BINARY|O_NOFOLLOW, MYF(MY_WME))) < 0 ||
|
||||
init_io_cache(&file, fd, IO_SIZE, READ_CACHE, (my_off_t)0, 0,
|
||||
MYF(MY_WME|MY_NABP)))
|
||||
{
|
||||
@@ -4483,9 +4504,9 @@ Begin_load_query_log_event(const char* buf, uint len,
|
||||
|
||||
|
||||
#if defined( HAVE_REPLICATION) && !defined(MYSQL_CLIENT)
|
||||
int Begin_load_query_log_event::get_open_mode() const
|
||||
int Begin_load_query_log_event::get_create_or_append() const
|
||||
{
|
||||
return O_CREAT | O_WRONLY | O_BINARY | O_TRUNC;
|
||||
return 1; /* create the file */
|
||||
}
|
||||
#endif /* defined( HAVE_REPLICATION) && !defined(MYSQL_CLIENT) */
|
||||
|
||||
@@ -4662,7 +4683,12 @@ Execute_load_query_log_event::exec_event(struct st_relay_log_info* rli)
|
||||
/* Forging file name for deletion in same buffer */
|
||||
*fname_end= 0;
|
||||
|
||||
(void) my_delete(fname, MYF(MY_WME));
|
||||
/*
|
||||
If there was an error the slave is going to stop, leave the
|
||||
file so that we can re-execute this event at START SLAVE.
|
||||
*/
|
||||
if (!error)
|
||||
(void) my_delete(fname, MYF(MY_WME));
|
||||
|
||||
my_free(buf, MYF(MY_ALLOW_ZERO_PTR));
|
||||
return error;
|
||||
|
Reference in New Issue
Block a user