On Tuesday 10 April 2001 10:55, Sasha Pachev wrote:
> Scott:
>
> See my comments below regarding the replication bug you have reported.
>
> error from log file:
> 010410 15:18:20 Slave: connected to master 'navrep@hsNavYkfPrd4:3306',
> replication started in log 'hsNavYkfPrd4-bin.060' at position 14290269
> ERROR: 1064 You have an error in your SQL syntax near '' at line 1
> 010410 15:18:34 Slave: did not get the expected error running query
> from master - expected: 'Got an error reading communication packets',
> got 'no error'
> 010410 15:18:34 Slave: error running query 'drop table
> scratch.#sql-6fd2_9b3'
> 010410 15:18:34 Error running query, slave aborted. Fix the problem,
> and re-start the slave thread with "mysqladmin start-slave". We stopped
> at log 'hsNavYkfPrd4-bin.060' position 14298032
> 010410 15:18:34 Slave thread exiting, replication stopped in log
> 'hsNavYkfPrd4-bin.060' at position 14298032
Found the problem - if somehow there was a temporary table left over in the
temporary tables list of the the thread that was created internally by MySQL
to process some query, on disconnect the record of it being dropped was
erroneously made in the binary log. This is why you see the slave trying to
drop a table with a very strange name - scratch.#sql-6fd2_9b3.
The patch below not only takes care of the left over internal temp table bug,
but also addresses the issue of dealing with updates that only partially
complete because of some unusual conditions or errors, eg killed thread. If
the slave sees a query in the log that completed with an abnormal error, it
will now just abort and wait for the DBA to verify data integrity and restart
the slave with SET SQL_SLAVE_SKIP_COUNTER=1; SLAVE START; . The patch will be
present in 3.23.37:
--- 1.73/sql/sql_base.cc Sun Apr 1 16:45:24 2001
+++ edited/sql_base.cc Tue Apr 10 11:44:37 2001
@@ -497,13 +497,14 @@
TABLE *table,*next;
uint init_query_buf_size = 11, query_buf_size; // "drop table "
char* query, *p;
+ bool found_user_tables = 0;
+
LINT_INIT(p);
query_buf_size = init_query_buf_size;
for (table=thd->temporary_tables ; table ; table=table->next)
{
query_buf_size += table->key_length;
-
}
if(query_buf_size == init_query_buf_size)
@@ -519,15 +520,20 @@
{
if(query) // we might be out of memory, but this is not fatal
{
- p = strxmov(p,table->table_cache_key,".",
+ // skip temporary tables not created directly by the user
+ if(table->table_name[0] != '#')
+ {
+ p = strxmov(p,table->table_cache_key,".",
table->table_name,",", NullS);
- // here we assume table_cache_key always starts
- // with \0 terminated db name
+ // here we assume table_cache_key always starts
+ // with \0 terminated db name
+ found_user_tables = 1;
+ }
}
next=table->next;
close_temporary(table);
}
- if (query && mysql_bin_log.is_open())
+ if (query && found_user_tables && mysql_bin_log.is_open())
{
uint save_query_len = thd->query_length;
*--p = 0;
--- 1.94/sql/slave.cc Tue Mar 13 23:07:11 2001
+++ edited/slave.cc Tue Apr 10 19:48:11 2001
@@ -59,6 +59,8 @@
static int create_table_from_dump(THD* thd, NET* net, const char* db,
const char* table_name);
inline char* rewrite_db(char* db);
+static int check_expected_error(THD* thd, int expected_error);
+
static void free_table_ent(TABLE_RULE_ENT* e)
{
my_free((gptr) e, MYF(0));
@@ -834,6 +836,27 @@
return len - 1;
}
+static int check_expected_error(THD* thd, int expected_error)
+{
+ switch(expected_error)
+ {
+ case ER_NET_READ_ERROR:
+ case ER_NET_ERROR_ON_WRITE:
+ case ER_SERVER_SHUTDOWN:
+ case ER_NEW_ABORTING_CONNECTION:
+ my_snprintf(last_slave_error, sizeof(last_slave_error),
+ "Slave: query '%s' partially completed on the master \
+and was aborted. There is a chance that your master is inconsistent at this
\ +point. If you are sure that your master is ok, run this query manually on
the\+ slave and then restart the slave with SET SQL_SLAVE_SKIP_COUNTER=1;\
+ SLAVE START;", thd->query);
+ last_slave_errno = expected_error;
+ sql_print_error(last_slave_error);
+ return 1;
+ default:
+ return 0;
+ }
+}
static int exec_event(THD* thd, NET* net, MASTER_INFO* mi, int event_len)
{
@@ -883,22 +906,38 @@
thd->net.last_errno = 0;
thd->net.last_error[0] = 0;
thd->slave_proxy_id = qev->thread_id; // for temp tables
- mysql_parse(thd, thd->query, q_len);
- if ((expected_error = qev->error_code) !=
- (actual_error = thd->net.last_errno) && expected_error)
- {
- const char* errmsg = "Slave: did not get the expected error\
+
+ // sanity check to make sure the master did not get a really bad
+ // error on the query
+ if(!check_expected_error(thd, (expected_error = qev->error_code)))
+ {
+ mysql_parse(thd, thd->query, q_len);
+ if (expected_error !=
+ (actual_error = thd->net.last_errno) && expected_error)
+ {
+ const char* errmsg = "Slave: did not get the expected error\
running query from master - expected: '%s', got '%s'";
- sql_print_error(errmsg, ER(expected_error),
- actual_error ? thd->net.last_error:"no error"
- );
- thd->query_error = 1;
- }
- else if (expected_error == actual_error)
+ sql_print_error(errmsg, ER(expected_error),
+ actual_error ? thd->net.last_error:"no error"
+ );
+ thd->query_error = 1;
+ }
+ else if (expected_error == actual_error)
+ {
+ thd->query_error = 0;
+ *last_slave_error = 0;
+ last_slave_errno = 0;
+ }
+ }
+ else // master could be inconsistent, abort and tell DBA to
+ // check/fix it
{
- thd->query_error = 0;
- *last_slave_error = 0;
- last_slave_errno = 0;
+ thd->db = thd->query = 0;
+ thd->convert_set = 0;
+ close_thread_tables(thd);
+ free_root(&thd->mem_root,0);
+ delete ev;
+ return 1;
}
}
thd->db = 0; // prevent db from being freed
===== log_event.h 1.39 vs edited =====
--- 1.39/sql/log_event.h Mon Feb 19 23:08:23 2001
+++ edited/log_event.h Tue Apr 10 20:17:07 2001
@@ -136,7 +136,7 @@
Query_log_event(THD* thd_arg, const char* query_arg, bool using_trans=0):
Log_event(thd_arg->start_time,0,1,thd_arg->server_id), data_buf(0),
query(query_arg), db(thd_arg->db), q_len(thd_arg->query_length),
- error_code(thd_arg->net.last_errno),
+ error_code(thd_arg->killed ? ER_SERVER_SHUTDOWN:
thd_arg->net.last_errno), thread_id(thd_arg->thread_id), thd(thd_arg),
cache_stmt(using_trans &&
(thd_arg->options & (OPTION_NOT_AUTO_COMMIT | OPTION_BEGIN)))
--
MySQL Development Team
__ ___ ___ ____ __
/ |/ /_ __/ __/ __ \/ / Sasha Pachev <[EMAIL PROTECTED]>
/ /|_/ / // /\ \/ /_/ / /__ MySQL AB, http://www.mysql.com/
/_/ /_/\_, /___/\___\_\___/ Provo, Utah, USA
<___/
---------------------------------------------------------------------
Before posting, please check:
http://www.mysql.com/manual.php (the manual)
http://lists.mysql.com/ (the list archive)
To request this thread, e-mail <[EMAIL PROTECTED]>
To unsubscribe, e-mail <[EMAIL PROTECTED]>
Trouble unsubscribing? Try: http://lists.mysql.com/php/unsubscribe.php