List:Commits« Previous MessageNext Message »
From:Andrei Elkin Date:April 22 2007 2:52pm
Subject:bk commit into 5.0 tree (aelkin:1.2490) BUG#22725
View as plain text  
Below is the list of changes that have just been committed into a local
5.0 repository of elkin. When elkin does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html

ChangeSet@stripped, 2007-04-22 17:51:55+03:00, aelkin@stripped +7 -0
  Bug#22725 Replication outages from ER_SERVER_SHUTDOWN (1053) set in replication events
  
  The reason for the bug was that replaying of a query on slave could not be possible since its event
  was recorded with the killed error. Due to the specific of handling INSERT, which per-row-while-loop is 
  unbreakable to killing, the query on ta-table should have not appeared in binlog unless there was 
  a call to a stored routine that got interrupted with killing.
  
  The offered solution introduced the following rules for binlogging of INSERT that accounts its specifics.
  For ta-table the query rolls back only if the error was set to non-zero regardless on the value of the killed
  flag. 
  The only raised flag without the error was set is harmless even though insert invoked a stored routine.
  For not-ta-table the combination forces to binlog the query with KILLED error to indicate that there
  was potentially partial execution on master and consistency is under the question.
  
  The fix relies on the specified behaviour of stored routine that must propagate the error to the top level
  query handling if the thd->killed flag was caught raised in the routine execution.
  
  The patch adds an arg with the default killed-status-unset value to Query_log_event::Query_log_event.

  mysql-test/r/kill.result@stripped, 2007-04-22 17:51:51+03:00, aelkin@stripped +124 -0
    changed, and will be changed after bug#27563,#27565 fixed

  mysql-test/t/kill.test@stripped, 2007-04-22 17:51:51+03:00, aelkin@stripped +191 -0
    regression tests for the bugs #22725, #27563, #27565

  sql/log_event.cc@stripped, 2007-04-22 17:51:51+03:00, aelkin@stripped +8 -4
    killed_err as the value of thd->killed_errno() can be passed as an arg to the constructor.
    Notice that error_code's value is calculated on the arg instead of killed_errno() whenever the arg's value
    was explicitly provided by the caller.
    So far only mysql_insert() uses such explicit way to tell the constructor about killing status.

  sql/log_event.h@stripped, 2007-04-22 17:51:52+03:00, aelkin@stripped +2 -1
    default arg to the constructor with meaning of killed status of the query. 
    if the arg is not explicitly provided thd->killed_errno() will be evaluated 
    inside of the constuctor, which is potentially incorrect (see bug#27571)

  sql/sql_class.h@stripped, 2007-04-22 17:51:52+03:00, aelkin@stripped +10 -2
    extending killed_state with the max element

  sql/sql_insert.cc@stripped, 2007-04-22 17:51:52+03:00, aelkin@stripped +37 -23
    roll back killed query if ta-table and `error' was set both;
    ignore the KILLED flag while the query event is created if no `error';

  sql/sql_update.cc@stripped, 2007-04-22 17:51:52+03:00, aelkin@stripped +14 -0
    Suggestion how to fix bug#27571 as comments.

# This is a BitKeeper patch.  What follows are the unified diffs for the
# set of deltas contained in the patch.  The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User:	aelkin
# Host:	dsl-hkibras1-ff1dc300-249.dhcp.inet.fi
# Root:	/home/elkin/MySQL/MAIN/mysql-5.0-marvel

--- 1.228/sql/log_event.cc	2007-03-07 11:24:41 +02:00
+++ 1.229/sql/log_event.cc	2007-04-22 17:51:51 +03:00
@@ -1267,16 +1267,13 @@ Query_log_event::Query_log_event()
 */
 Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
 				 ulong query_length, bool using_trans,
-				 bool suppress_use)
+				 bool suppress_use, THD::killed_state killed_err_arg)
   :Log_event(thd_arg,
 	     ((thd_arg->tmp_table_used ? LOG_EVENT_THREAD_SPECIFIC_F : 0)
 	      | (suppress_use          ? LOG_EVENT_SUPPRESS_USE_F    : 0)),
 	     using_trans),
    data_buf(0), query(query_arg), catalog(thd_arg->catalog),
    db(thd_arg->db), q_len((uint32) query_length),
-   error_code((thd_arg->killed != THD::NOT_KILLED) ?
-              ((thd_arg->system_thread & SYSTEM_THREAD_DELAYED_INSERT) ?
-               0 : thd->killed_errno()) : thd_arg->net.last_errno),
    thread_id(thd_arg->thread_id),
    /* save the original thread id; we already know the server id */
    slave_proxy_id(thd_arg->variables.pseudo_thread_id),
@@ -1288,6 +1285,13 @@ Query_log_event::Query_log_event(THD* th
    charset_database_number(0)
 {
   time_t end_time;
+  THD::killed_state kill_err;
+  error_code=
+    (kill_err=
+     (killed_err_arg != THD::KILLED_NO_VALUE? killed_err_arg : thd_arg->killed))
+    != THD::NOT_KILLED ?
+    ((thd_arg->system_thread & SYSTEM_THREAD_DELAYED_INSERT) ?
+     0 : kill_err) : thd_arg->net.last_errno;
   time(&end_time);
   exec_time = (ulong) (end_time  - thd->start_time);
   catalog_len = (catalog) ? (uint32) strlen(catalog) : 0;

--- 1.134/sql/log_event.h	2007-02-28 15:09:33 +02:00
+++ 1.135/sql/log_event.h	2007-04-22 17:51:52 +03:00
@@ -804,7 +804,8 @@ public:
 #ifndef MYSQL_CLIENT
 
   Query_log_event(THD* thd_arg, const char* query_arg, ulong query_length,
-		  bool using_trans, bool suppress_use);
+                  bool using_trans, bool suppress_use,
+                  THD::killed_state killed_err_arg= THD::KILLED_NO_VALUE);
   const char* get_db() { return db; }
 #ifdef HAVE_REPLICATION
   void pack_info(Protocol* protocol);

--- 1.325/sql/sql_class.h	2007-03-15 22:20:57 +02:00
+++ 1.326/sql/sql_class.h	2007-04-22 17:51:52 +03:00
@@ -1396,7 +1396,14 @@ public:
   DYNAMIC_ARRAY user_var_events;        /* For user variables replication */
   MEM_ROOT      *user_var_events_alloc; /* Allocate above array elements here */
 
-  enum killed_state { NOT_KILLED=0, KILL_BAD_DATA=1, KILL_CONNECTION=ER_SERVER_SHUTDOWN, KILL_QUERY=ER_QUERY_INTERRUPTED };
+  enum killed_state
+  {
+    NOT_KILLED=0,
+    KILL_BAD_DATA=1,
+    KILL_CONNECTION=ER_SERVER_SHUTDOWN,
+    KILL_QUERY=ER_QUERY_INTERRUPTED,
+    KILLED_NO_VALUE /* the last item just to know the size */
+  };
   killed_state volatile killed;
 
   /* scramble - random string sent to client on handshake */
@@ -1652,7 +1659,8 @@ public:
   void end_statement();
   inline int killed_errno() const
   {
-    return killed != KILL_BAD_DATA ? killed : 0;
+    killed_state killed_val;
+    return (killed_val= killed) != KILL_BAD_DATA ? killed_val : 0;
   }
   inline void send_kill_message() const
   {

--- 1.225/sql/sql_insert.cc	2007-03-19 23:39:47 +02:00
+++ 1.226/sql/sql_insert.cc	2007-04-22 17:51:52 +03:00
@@ -604,24 +604,24 @@ bool mysql_insert(THD *thd,TABLE_LIST *t
                                                table->triggers,
                                                TRG_EVENT_INSERT))
       {
-	if (values_list.elements != 1 && !thd->net.report_error)
-	{
-	  info.records++;
-	  continue;
-	}
-	/*
-	  TODO: set thd->abort_on_warning if values_list.elements == 1
-	  and check that all items return warning in case of problem with
-	  storing field.
+        if (values_list.elements != 1 && !thd->net.report_error)
+        {
+          info.records++;
+          continue;
+        }
+        /*
+          TODO: set thd->abort_on_warning if values_list.elements == 1
+          and check that all items return warning in case of problem with
+          storing field.
         */
-	error=1;
-	break;
+        error=1;
+        break;
       }
     }
     else
     {
       if (thd->used_tables)			// Column used in values()
-	restore_record(table,s->default_values);	// Get empty record
+        restore_record(table,s->default_values);	// Get empty record
       else
       {
         /*
@@ -629,22 +629,22 @@ bool mysql_insert(THD *thd,TABLE_LIST *t
           be overwritten by fill_record() anyway (and fill_record() does not
           use default values in this case).
         */
-	table->record[0][0]= table->s->default_values[0];
+        table->record[0][0]= table->s->default_values[0];
       }
       if (fill_record_n_invoke_before_triggers(thd, table->field, *values, 0,
                                                table->triggers,
                                                TRG_EVENT_INSERT))
       {
-	if (values_list.elements != 1 && ! thd->net.report_error)
-	{
-	  info.records++;
-	  continue;
-	}
-	error=1;
-	break;
+        if (values_list.elements != 1 && ! thd->net.report_error)
+        {
+          info.records++;
+          continue;
+        }
+        error=1;
+        break;
       }
     }
-
+    
     if ((res= table_list->view_check_option(thd,
 					    (values_list.elements == 1 ?
 					     0 :
@@ -723,10 +723,24 @@ bool mysql_insert(THD *thd,TABLE_LIST *t
       {
         if (mysql_bin_log.is_open())
         {
+          int killed_err= thd->killed_errno();
           if (error <= 0)
-            thd->clear_error();
+            thd->clear_error(); // todo/fixme: consider removing
+          /* bug#22725: 
+               
+          A query which per-row-loop can not be interrupted with
+          KILLED, like INSERT, and that does not invoke stored
+          routines can be binlogged with neglecting the KILLED error.
+          
+          If there was no error (error == zero) until after the end of
+          inserting loop the KILLED flag that appeared later can be
+          disregarded since previously possible invocation of stored
+          routines did not result in any error due to the KILLED.  In
+          such case the flag is ignored for constructing binlog event.
+          */
           Query_log_event qinfo(thd, thd->query, thd->query_length,
-                                transactional_table, FALSE);
+                                transactional_table, FALSE,
+                                error? (THD::killed_state) killed_err : THD::NOT_KILLED);
           if (mysql_bin_log.write(&qinfo) && transactional_table)
             error=1;
         }

--- 1.212/sql/sql_update.cc	2007-03-08 19:29:59 +02:00
+++ 1.213/sql/sql_update.cc	2007-04-22 17:51:52 +03:00
@@ -508,6 +508,20 @@ int mysql_update(THD *thd,
       table->file->unlock_row();
     thd->row_count++;
   }
+
+  /*
+    todo bug#27571: to avoid asyncronization of `error' and
+    `error_code' of binlog event constructor
+
+    The concept, which is a bit different for insert(!) : 
+
+    killed_error_code= thd->killed_errno();
+    error= (killed_error_code == THD::NOT_KILLED)? error : 1;
+    
+    applies to most mysql_$query functions.
+    Event's constructor will accept `killed_error_code' as an argument.
+  */
+
   if (thd->killed && !error)
     error= 1;					// Aborted
   end_read_record(&info);

--- 1.16/mysql-test/r/kill.result	2006-10-04 14:09:34 +03:00
+++ 1.17/mysql-test/r/kill.result	2007-04-22 17:51:51 +03:00
@@ -41,3 +41,127 @@ select 1;
 select RELEASE_LOCK("a");
 RELEASE_LOCK("a")
 1
+create function bug27563() 
+RETURNS int(11)
+DETERMINISTIC
+begin
+select get_lock("a", 10)  into @a;
+return 1;
+end|
+create function bug27565() 
+RETURNS int(11)
+DETERMINISTIC
+begin
+select a from t1 where a=1  into @a for update;
+return 1;
+end|
+create table t1 (a int auto_increment, b int, PRIMARY KEY (a)) ENGINE=InnoDB;
+create table t2 (a int auto_increment, b int, PRIMARY KEY (a)) ENGINE=MyISAM;
+create table t3 (a int auto_increment, b int, PRIMARY KEY (a)) ENGINE=InnoDB;
+reset master;
+select get_lock("a", 20);
+get_lock("a", 20)
+1
+insert into t1 values (bug27563(),1);
+kill query 3;
+affected rows: 1
+show binlog events from 98 /* nothing in binlog unless Bug#27563 */;
+Log_name	Pos	Event_type	Server_id	End_log_pos	Info
+master-bin.000001	98	Intvar	1	28	INSERT_ID=1
+master-bin.000001	126	Query	1	135	use `test`; insert into t1 values (bug27563(),1)
+master-bin.000001	233	Xid	1	260	COMMIT /* xid=4132 */
+select count(*) from t1 /* must be zero unless Bug#27563 */;
+count(*)
+1
+begin;
+insert into t1 values (bug27563(),1);
+kill query 3;
+affected rows: 1
+select count(*) from t1 /* must be zero unless Bug#27563 */;
+count(*)
+2
+commit;
+insert into t2 values (bug27563(),1);
+kill query 3;
+select count(*) from t2 /* must be one */;
+count(*)
+1
+show binlog events from 98 /* must have the insert on non-ta table */;
+Log_name	Pos	Event_type	Server_id	End_log_pos	Info
+master-bin.000001	98	Intvar	1	28	INSERT_ID=1
+master-bin.000001	126	Query	1	135	use `test`; insert into t1 values (bug27563(),1)
+master-bin.000001	233	Xid	1	260	COMMIT /* xid=4132 */
+master-bin.000001	260	Query	1	328	use `test`; BEGIN
+master-bin.000001	328	Intvar	1	28	INSERT_ID=2
+master-bin.000001	356	Query	1	127	use `test`; insert into t1 values (bug27563(),1)
+master-bin.000001	455	Xid	1	482	COMMIT /* xid=4139 */
+master-bin.000001	482	Intvar	1	510	INSERT_ID=1
+master-bin.000001	510	Query	1	609	use `test`; insert into t2 values (bug27563(),1)
+select RELEASE_LOCK("a");
+RELEASE_LOCK("a")
+1
+delete from t1;
+delete from t2;
+insert into t1 values (1,1);
+insert into t2 values (1,1);
+begin;
+update t1 set b=0 where a=1;
+update t2 set b=bug27565()-1 where a=1;
+kill query 3;
+commit;
+Got one of the listed errors
+select * from t1 /* must be: (1,0) */;
+a	b
+1	0
+select * from t2 /* must be as before: (1,1) */;
+a	b
+1	1
+reset master;
+begin;
+update t1 set b=0 where a=1;
+delete from t3;
+insert into t3 values  (0,0),(1,bug27565());
+kill query 3;
+commit;
+Got one of the listed errors
+select count(*) from t3 /* must be zero */;
+count(*)
+0
+show binlog events from 98 /* only killer ta in binlog */;
+Log_name	Pos	Event_type	Server_id	End_log_pos	Info
+master-bin.000001	98	Query	1	77	use `test`; delete from t3
+master-bin.000001	175	Xid	1	202	COMMIT /* xid=4167 */
+master-bin.000001	202	Query	1	270	use `test`; BEGIN
+master-bin.000001	270	Query	1	90	use `test`; update t1 set b=0 where a=1
+master-bin.000001	360	Xid	1	387	COMMIT /* xid=4166 */
+reset master;
+begin;
+update t1 set b=0 where a=1;
+delete from t2;
+insert into t2 values (0,0),(1,bug27565());
+kill query 3;
+commit;
+Got one of the listed errors
+select count(*) from t2    /* count must be one */;
+count(*)
+1
+show binlog events from 98 /* insert into non-ta must be in binlog */;
+Log_name	Pos	Event_type	Server_id	End_log_pos	Info
+master-bin.000001	98	Query	1	175	use `test`; delete from t2
+master-bin.000001	175	Query	1	243	use `test`; BEGIN
+master-bin.000001	243	Query	1	90	use `test`; update t1 set b=0 where a=1
+master-bin.000001	333	Xid	1	360	COMMIT /* xid=4177 */
+master-bin.000001	360	Intvar	1	388	INSERT_ID=2
+master-bin.000001	388	Query	1	493	use `test`; insert into t2 values (0,0),(1,bug27565())
+select
+(@a:=load_file("MYSQLTEST_VARDIR/tmp/kill_query_calling_sp.binlog"))
+is not null;
+(@a:=load_file("MYSQLTEST_VARDIR/tmp/kill_query_calling_sp.binlog"))
+is not null
+1
+select @a like "%#%error_code=1317%" /* must return 1 */;
+@a like "%#%error_code=1317%"
+1
+drop table t1,t2,t3;
+drop function bug27563;
+drop function bug27565;

--- 1.24/mysql-test/t/kill.test	2006-12-08 18:09:39 +02:00
+++ 1.25/mysql-test/t/kill.test	2007-04-22 17:51:51 +03:00
@@ -117,3 +117,194 @@ reap;
 select 1;
 connection con1;
 select RELEASE_LOCK("a");
+
+###
+### bug#22725 : incorrect killed error in binlogged query
+### and
+### Bug#27563 killing noticed in SF() stack but the error gets missed in action
+### Bug#27565 killed query of SF() is not reported correctly and
+###
+
+# the function is insensitive to killing - bug#27563
+delimiter |;
+create function bug27563() 
+RETURNS int(11)
+DETERMINISTIC
+begin
+  select get_lock("a", 10)  into @a;
+  return 1;
+end|
+delimiter ;|
+
+# the function sensitive to killing though with wrong client error bug#27565
+delimiter |;
+create function bug27565() 
+RETURNS int(11)
+DETERMINISTIC
+begin
+  select a from t1 where a=1  into @a for update;
+  return 1;
+end|
+delimiter ;|
+
+create table t1 (a int auto_increment, b int, PRIMARY KEY (a)) ENGINE=InnoDB;
+create table t2 (a int auto_increment, b int, PRIMARY KEY (a)) ENGINE=MyISAM;
+create table t3 (a int auto_increment, b int, PRIMARY KEY (a)) ENGINE=InnoDB;
+reset master;
+
+
+### ta table case: killing causes rollback
+
+# A. autocommit ON
+connection con1;
+select get_lock("a", 20);
+
+connection con2;
+let $ID= `select connection_id()`;
+send insert into t1 values (bug27563(),1);
+
+connection con1;
+eval kill query $ID;
+
+connection con2;
+# todo (re-record test): after bugs 27563,27565 got fixed affected rows will report zero
+--enable_info
+# todo: remove 0 return after fixing Bug#27563
+--error 0,ER_QUERY_INTERRUPTED
+reap;
+--disable_info
+show binlog events from 98 /* nothing in binlog unless Bug#27563 */;
+select count(*) from t1 /* must be zero unless Bug#27563 */;
+
+# M. multi-statement-ta
+connection con2;
+let $ID= `select connection_id()`;
+begin;
+send insert into t1 values (bug27563(),1);
+
+connection con1;
+eval kill query $ID;
+connection con2;
+# todo (re-record test): after bugs 27563,27565 got fixed affected rows will report zero
+--enable_info
+# todo: remove 0 return after fixing  Bug#27563
+--error 0,ER_QUERY_INTERRUPTED
+reap;
+--disable_info
+select count(*) from t1 /* must be zero unless Bug#27563 */;
+commit;
+
+
+### non-ta table case: killing must be recorded in binlog
+
+connection con2;
+let $ID= `select connection_id()`;
+send insert into t2 values (bug27563(),1);
+
+connection con1;
+eval kill query $ID;
+
+connection con2;
+# todo: remove 0 return after fixing  Bug#27563
+--error 0,ER_QUERY_INTERRUPTED
+reap;
+select count(*) from t2 /* must be one */;
+show binlog events from 98 /* must have the insert on non-ta table */;
+# the value of the error flag of KILLED_QUERY is tested further
+
+connection con1;
+select RELEASE_LOCK("a");
+
+### test with effective killing of SF()
+
+delete from t1;
+delete from t2;
+insert into t1 values (1,1);
+insert into t2 values (1,1);
+
+# 
+# Bug#27565
+# test where KILL is propagated as error to the top level
+# still another bug with the error message to the user
+# todo: fix reexecute the result file after fixing
+# 
+begin; update t1 set b=0 where a=1;
+
+connection con2;
+let $ID= `select connection_id()`;
+send update t2 set b=bug27565()-1 where a=1;
+
+connection con1;
+eval kill query $ID;
+commit;
+
+connection con2;
+# todo: fix Bug #27565 killed query of SF() is not reported correctly and 
+# remove 1105 (wrong)
+#--error ER_QUERY_INTERRUPTED
+--error 1105,ER_QUERY_INTERRUPTED
+reap;
+select * from t1 /* must be: (1,0) */;
+select * from t2 /* must be as before: (1,1) */;
+
+## bug#22725 with effective and propagating killing
+#
+# top-level ta-table
+connection con1;
+reset master;
+begin; update t1 set b=0 where a=1;
+
+connection con2;
+delete from t3;
+let $ID= `select connection_id()`;
+# the query won't perform completely since the function gets intrurrupted
+send insert into t3 values  (0,0),(1,bug27565());
+
+connection con1;
+eval kill query $ID;
+commit;
+
+connection con2;
+# todo: fix Bug #27565 killed query of SF() is not reported correctly and 
+# remove 1105 (wrong)
+#--error ER_QUERY_INTERRUPTED
+--error 1105,ER_QUERY_INTERRUPTED
+reap;
+select count(*) from t3 /* must be zero */;
+show binlog events from 98 /* only killer ta in binlog */;
+
+# top-level non-ta-table
+connection con1;
+reset master;
+begin; update t1 set b=0 where a=1;
+
+connection con2;
+delete from t2;
+let $ID= `select connection_id()`;
+# the query won't perform completely since the function gets intrurrupted
+send insert into t2 values (0,0),(1,bug27565());
+
+connection con1;
+eval kill query $ID;
+commit;
+
+connection con2;
+# todo: fix Bug #27565 killed query of SF() is not reported correctly and 
+# remove 1105 (wrong)
+#--error ER_QUERY_INTERRUPTED
+--error 1105,ER_QUERY_INTERRUPTED
+reap;
+
+select count(*) from t2    /* count must be one */;
+show binlog events from 98 /* insert into non-ta must be in binlog */;
+--exec $MYSQL_BINLOG --start-position=388 $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/kill_query_calling_sp.binlog
+--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
+eval select
+(@a:=load_file("$MYSQLTEST_VARDIR/tmp/kill_query_calling_sp.binlog"))
+is not null;
+--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR
+eval select @a like "%#%error_code=1317%" /* must return 1 */;
+
+drop table t1,t2,t3;
+drop function bug27563;
+drop function bug27565;
Thread
bk commit into 5.0 tree (aelkin:1.2490) BUG#22725Andrei Elkin22 Apr