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

Reply via email to