Commit 89ef355b authored by monty@mashka.mysql.fi's avatar monty@mashka.mysql.fi

Fix for bug in LOAD DATA INFILE and replication

Fix for SHOW VARIABLES in embedded server
parent 602f3664
...@@ -96,13 +96,84 @@ cached for each user/database combination. ...@@ -96,13 +96,84 @@ cached for each user/database combination.
Many use of @code{GROUP BY} or @code{DISTINCT} caches all found rows in Many use of @code{GROUP BY} or @code{DISTINCT} caches all found rows in
a @code{HEAP} table. (This is a very quick in-memory table with hash index.) a @code{HEAP} table. (This is a very quick in-memory table with hash index.)
@item Join Row Cache @item Join buffer Cache
For every full join in a @code{SELECT} statement (a full join here means For every full join in a @code{SELECT} statement (a full join here means
there were no keys that one could use to find the next table in a list), there were no keys that one could use to find the next table in a list),
the found rows are cached in a join cache. One @code{SELECT} query can the found rows are cached in a join cache. One @code{SELECT} query can
use many join caches in the worst case. use many join caches in the worst case.
@end table @end table
@node join_buffer_size, flush tables, caching, Top
@subchapter How MySQL uses the join_buffer cache
Basic information about @code{join_buffer_size}:
@itemize @bullet
@item
It's only used in the case when join type is of type @code{ALL} or
@code{index}; In other words: no possible keys can be used.
@item
A join buffer is never allocated for the first not-const table,
even it it would be of type @code{ALL}/@code{index}.
@item
The buffer is allocated when we need to do a each full join between two
tables and freed after the query is done.
@item
Accepted row combinations of tables before the @code{ALL}/@code{index}
able is stored in the cache and is used to compare against each read
row in the @code{ALL} table.
@item
We only store the used fields in the join_buffer cache, not the
whole rows.
@end itemize
Assume you have the following join:
@example
Table name Type
t1 range
t2 ref
t3 @code{ALL}
@end example
The join is then done as follows:
@example
- While rows in t1 matching range
- Read through all rows in t2 according to reference key
- Store used fields form t1,t2 in cache
- If cache is full
- Read through all rows in t3
- Compare t3 row against all t1,t2 combination in cache
- If rows satisfying join condition, send it to client
- Empty cache
- Read through all rows in t3
- Compare t3 row against all stored t1,t2 combinations in cache
- If rows satisfying join condition, send it to client
@end example
The above means that table t3 is scanned
@example
(size-of-stored-row(t1,t2) * accepted-row-cominations(t1,t2))/
join_buffer_size+1
@end example
times.
Some conclusions:
@itemize @bullet
@item
The larger the join_buff_size, the fewer scans of t3.
If @code{join_buff_size} is already large enough to hold all previous row
combinations then there is no speed to gain by making it bigger.
@item
If there is several tables of @code{ALL}/@code{index} then the we
allocate one @code{join_buffer_size buffer} for each of them and use the
same algorithm described above to handle it. (In other words, we store
the same row combination several times into different buffers)
@end itemize
@node flush tables, filesort, caching, Top @node flush tables, filesort, caching, Top
@chapter How MySQL Handles @code{FLUSH TABLES} @chapter How MySQL Handles @code{FLUSH TABLES}
......
...@@ -4,7 +4,7 @@ dnl Process this file with autoconf to produce a configure script. ...@@ -4,7 +4,7 @@ dnl Process this file with autoconf to produce a configure script.
AC_INIT(sql/mysqld.cc) AC_INIT(sql/mysqld.cc)
AC_CANONICAL_SYSTEM AC_CANONICAL_SYSTEM
# The Docs Makefile.am parses this line! # The Docs Makefile.am parses this line!
AM_INIT_AUTOMAKE(mysql, 4.0.8-gamma) AM_INIT_AUTOMAKE(mysql, 4.0.9-gamma)
AM_CONFIG_HEADER(config.h) AM_CONFIG_HEADER(config.h)
PROTOCOL_VERSION=10 PROTOCOL_VERSION=10
......
...@@ -206,7 +206,19 @@ Log_event::Log_event(const char* buf, bool old_format) ...@@ -206,7 +206,19 @@ Log_event::Log_event(const char* buf, bool old_format)
int Log_event::exec_event(struct st_relay_log_info* rli) int Log_event::exec_event(struct st_relay_log_info* rli)
{ {
if (rli) // QQ When is this not true ? /*
rli is null when (as far as I (Guilhem) know)
the caller is
Load_log_event::exec_event *and* that one is called from
Execute_load_log_event::exec_event.
In this case, we don't do anything here ;
Execute_load_log_event::exec_event will call Log_event::exec_event
again later with the proper rli.
Strictly speaking, if we were sure that rli is null
only in the case discussed above, 'if (rli)' is useless here.
But as we are not 100% sure, keep it for now.
*/
if (rli)
{ {
if (rli->inside_transaction) if (rli->inside_transaction)
rli->inc_pending(get_event_len()); rli->inc_pending(get_event_len());
...@@ -1773,8 +1785,34 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli) ...@@ -1773,8 +1785,34 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli)
return Log_event::exec_event(rli); return Log_event::exec_event(rli);
} }
/*
Does the data loading job when executing a LOAD DATA on the slave
SYNOPSIS
Load_log_event::exec_event
net
rli
use_rli_only_for_errors - if set to 1, rli is provided to
Load_log_event::exec_event only for this
function to have RPL_LOG_NAME and
rli->last_slave_error, both being used by
error reports. rli's position advancing
is skipped (done by the caller which is
Execute_load_log_event::exec_event).
- if set to 0, rli is provided for full use,
i.e. for error reports and position
advancing.
DESCRIPTION
Does the data loading job when executing a LOAD DATA on the slave
RETURN VALUE
0 Success
1 Failure
*/
int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli) int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli,
bool use_rli_only_for_errors)
{ {
init_sql_alloc(&thd->mem_root, 8192,0); init_sql_alloc(&thd->mem_root, 8192,0);
thd->db = rewrite_db((char*)db); thd->db = rewrite_db((char*)db);
...@@ -1836,8 +1874,12 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli) ...@@ -1836,8 +1874,12 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli)
TL_WRITE)) TL_WRITE))
thd->query_error = 1; thd->query_error = 1;
if (thd->cuted_fields) if (thd->cuted_fields)
/*
log_pos is the position of the LOAD
event in the master log
*/
sql_print_error("Slave: load data infile at position %s in log \ sql_print_error("Slave: load data infile at position %s in log \
'%s' produced %d warning(s)", llstr(rli->master_log_pos,llbuff), RPL_LOG_NAME, '%s' produced %d warning(s)", llstr(log_pos,llbuff), RPL_LOG_NAME,
thd->cuted_fields ); thd->cuted_fields );
if (net) if (net)
net->pkt_nr= thd->net.pkt_nr; net->pkt_nr= thd->net.pkt_nr;
...@@ -1877,7 +1919,7 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli) ...@@ -1877,7 +1919,7 @@ int Load_log_event::exec_event(NET* net, struct st_relay_log_info* rli)
return 1; return 1;
} }
return Log_event::exec_event(rli); return ( use_rli_only_for_errors ? 0 : Log_event::exec_event(rli) );
} }
...@@ -2132,7 +2174,11 @@ int Execute_load_log_event::exec_event(struct st_relay_log_info* rli) ...@@ -2132,7 +2174,11 @@ int Execute_load_log_event::exec_event(struct st_relay_log_info* rli)
save_options = thd->options; save_options = thd->options;
thd->options &= ~ (ulong) (OPTION_BIN_LOG); thd->options &= ~ (ulong) (OPTION_BIN_LOG);
lev->thd = thd; lev->thd = thd;
if (lev->exec_event(0,0)) /*
lev->exec_event should use rli only for errors
i.e. should not advance rli's position
*/
if (lev->exec_event(0,rli,1))
{ {
slave_print_error(rli,my_errno, "Failed executing load from '%s'", fname); slave_print_error(rli,my_errno, "Failed executing load from '%s'", fname);
thd->options = save_options; thd->options = save_options;
......
...@@ -417,9 +417,10 @@ class Load_log_event: public Log_event ...@@ -417,9 +417,10 @@ class Load_log_event: public Log_event
const char* get_db() { return db; } const char* get_db() { return db; }
int exec_event(struct st_relay_log_info* rli) int exec_event(struct st_relay_log_info* rli)
{ {
return exec_event(thd->slave_net,rli); return exec_event(thd->slave_net,rli,0);
} }
int exec_event(NET* net, struct st_relay_log_info* rli); int exec_event(NET* net, struct st_relay_log_info* rli,
bool use_rli_only_for_errors);
#else #else
void print(FILE* file, bool short_form = 0, char* last_db = 0); void print(FILE* file, bool short_form = 0, char* last_db = 0);
#endif #endif
......
...@@ -2343,12 +2343,6 @@ static int process_io_rotate(MASTER_INFO *mi, Rotate_log_event *rev) ...@@ -2343,12 +2343,6 @@ static int process_io_rotate(MASTER_INFO *mi, Rotate_log_event *rev)
memcpy(mi->master_log_name, rev->new_log_ident, rev->ident_len+1); memcpy(mi->master_log_name, rev->new_log_ident, rev->ident_len+1);
mi->master_log_pos= rev->pos; mi->master_log_pos= rev->pos;
pthread_mutex_lock(&mi->rli.data_lock);
memcpy(mi->rli.master_log_name, rev->new_log_ident, rev->ident_len+1);
mi->rli.master_log_pos= rev->pos;
pthread_mutex_unlock(&mi->rli.data_lock);
DBUG_PRINT("info", ("master_log_pos: '%s' %d", DBUG_PRINT("info", ("master_log_pos: '%s' %d",
mi->master_log_name, (ulong) mi->master_log_pos)); mi->master_log_name, (ulong) mi->master_log_pos));
#ifndef DBUG_OFF #ifndef DBUG_OFF
......
...@@ -1217,6 +1217,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables, ...@@ -1217,6 +1217,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables,
case SHOW_RPL_STATUS: case SHOW_RPL_STATUS:
net_store_data(&packet2, rpl_status_type[(int)rpl_status]); net_store_data(&packet2, rpl_status_type[(int)rpl_status]);
break; break;
#ifndef EMBEDDED_LIBRARY
case SHOW_SLAVE_RUNNING: case SHOW_SLAVE_RUNNING:
{ {
LOCK_ACTIVE_MI; LOCK_ACTIVE_MI;
...@@ -1226,6 +1227,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables, ...@@ -1226,6 +1227,7 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables,
UNLOCK_ACTIVE_MI; UNLOCK_ACTIVE_MI;
break; break;
} }
#endif
case SHOW_OPENTABLES: case SHOW_OPENTABLES:
net_store_data(&packet2,(uint32) cached_tables()); net_store_data(&packet2,(uint32) cached_tables());
break; break;
......
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