From 7eaa82ea38e1a9f0598ecfc88439583b51567e64 Mon Sep 17 00:00:00 2001
From: "msvensson@pilot.mysql.com" <>
Date: Mon, 29 Jan 2007 14:31:48 +0100
Subject: [PATCH] Bug#22943 syscall pruning in libmysql  - Set the timeout
 values only where needed

---
 sql-common/client.c  |  8 +++++++-
 sql/mysql_priv.h     |  2 ++
 sql/mysqld.cc        | 10 ++--------
 sql/net_serv.cc      | 27 +++++++++++++++++++++++++--
 sql/repl_failsafe.cc |  9 ++++++---
 sql/set_var.cc       |  4 ++--
 sql/slave.cc         |  1 -
 sql/sql_parse.cc     | 37 +++++++++++++++++++++++++------------
 sql/sql_repl.cc      |  6 +++---
 vio/vio.c            |  2 +-
 vio/viossl.c         | 11 -----------
 11 files changed, 73 insertions(+), 44 deletions(-)

diff --git a/sql-common/client.c b/sql-common/client.c
index 87e22624dd9..431c1bdf418 100644
--- a/sql-common/client.c
+++ b/sql-common/client.c
@@ -1881,11 +1881,17 @@ CLI_MYSQL_REAL_CONNECT(MYSQL *mysql,const char *host, const char *user,
     goto error;
   }
   vio_keepalive(net->vio,TRUE);
-  /* Override local client variables */
+
+  /* If user set read_timeout, let it override the default */
   if (mysql->options.read_timeout)
     net->read_timeout= mysql->options.read_timeout;
+  vio_timeout(net->vio, 0, net->read_timeout);
+
+  /* If user set write_timeout, let it override the default */
   if (mysql->options.write_timeout)
     net->write_timeout= mysql->options.write_timeout;
+  vio_timeout(net->vio, 1, net->write_timeout);
+
   if (mysql->options.max_allowed_packet)
     net->max_packet_size= mysql->options.max_allowed_packet;
 
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index a12944437d7..253eadd266e 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -59,6 +59,8 @@ void kill_one_thread(THD *thd, ulong id);
 bool net_request_file(NET* net, const char* fname);
 char* query_table_status(THD *thd,const char *db,const char *table_name);
 
+void net_set_write_timeout(NET *net, uint timeout);
+void net_set_read_timeout(NET *net, uint timeout);
 
 #define x_free(A)	{ my_free((gptr) (A),MYF(MY_WME | MY_FAE | MY_ALLOW_ZERO_PTR)); }
 #define safeFree(x)	{ if(x) { my_free((gptr) x,MYF(0)); x = NULL; } }
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 024e4682a22..59ed60d4c85 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -3601,10 +3601,9 @@ static bool read_init_file(char *file_name)
 #ifndef EMBEDDED_LIBRARY
 static void create_new_thread(THD *thd)
 {
+  NET *net=&thd->net;
   DBUG_ENTER("create_new_thread");
 
-  NET *net=&thd->net;				// For easy ref
-  net->read_timeout = (uint) connect_timeout;
   if (protocol_version > 9)
     net->return_errno=1;
 
@@ -3899,12 +3898,7 @@ extern "C" pthread_handler_decl(handle_connections_sockets,
     }
     if (sock == unix_sock)
       thd->host=(char*) my_localhost;
-#ifdef __WIN__
-    /* Set default wait_timeout */
-    ulong wait_timeout= global_system_variables.net_wait_timeout * 1000;
-    (void) setsockopt(new_sock, SOL_SOCKET, SO_RCVTIMEO, (char*)&wait_timeout,
-                    sizeof(wait_timeout));
-#endif
+
     create_new_thread(thd);
   }
 
diff --git a/sql/net_serv.cc b/sql/net_serv.cc
index 08184537896..a5a05d381cd 100644
--- a/sql/net_serv.cc
+++ b/sql/net_serv.cc
@@ -491,7 +491,7 @@ net_real_write(NET *net,const char *packet,ulong len)
     thr_alarm(&alarmed,(uint) net->write_timeout,&alarm_buff);
 #else
   alarmed=0;
-  vio_timeout(net->vio, 1, net->write_timeout);
+  /* Write timeout is set in net_set_write_timeout */
 #endif /* NO_ALARM */
 
   pos=(char*) packet; end=pos+len;
@@ -684,7 +684,7 @@ my_real_read(NET *net, ulong *complen)
   if (net_blocking)
     thr_alarm(&alarmed,net->read_timeout,&alarm_buff);
 #else
-  vio_timeout(net->vio, 0, net->read_timeout);
+  /* Read timeout is set in net_set_read_timeout */
 #endif /* NO_ALARM */
 
     pos = net->buff + net->where_b;		/* net->packet -4 */
@@ -995,3 +995,26 @@ my_net_read(NET *net)
   return len;
 }
 
+
+void net_set_read_timeout(NET *net, uint timeout)
+{
+  DBUG_ENTER("net_set_read_timeout");
+  DBUG_PRINT("enter", ("timeout: %d", timeout));
+  net->read_timeout= timeout;
+#ifdef NO_ALARM
+  vio_timeout(net->vio, 0, timeout);
+#endif
+  DBUG_VOID_RETURN;
+}
+
+
+void net_set_write_timeout(NET *net, uint timeout)
+{
+  DBUG_ENTER("net_set_write_timeout");
+  DBUG_PRINT("enter", ("timeout: %d", timeout));
+  net->write_timeout= timeout;
+#ifdef NO_ALARM
+  vio_timeout(net->vio, 1, timeout);
+#endif
+  DBUG_VOID_RETURN;
+}
diff --git a/sql/repl_failsafe.cc b/sql/repl_failsafe.cc
index 61fd5d9bce4..4c8703226a6 100644
--- a/sql/repl_failsafe.cc
+++ b/sql/repl_failsafe.cc
@@ -57,6 +57,7 @@ static Slave_log_event* find_slave_event(IO_CACHE* log,
   functions like register_slave()) are working.
 */
 
+#if NOT_USED
 static int init_failsafe_rpl_thread(THD* thd)
 {
   DBUG_ENTER("init_failsafe_rpl_thread");
@@ -99,7 +100,7 @@ static int init_failsafe_rpl_thread(THD* thd)
   thd->set_time();
   DBUG_RETURN(0);
 }
-
+#endif
 
 void change_rpl_status(RPL_STATUS from_status, RPL_STATUS to_status)
 {
@@ -573,12 +574,14 @@ err:
 }
 
 
+#if NOT_USED
 int find_recovery_captain(THD* thd, MYSQL* mysql)
 {
   return 0;
 }
+#endif
 
-
+#if NOT_USED
 pthread_handler_decl(handle_failsafe_rpl,arg)
 {
   DBUG_ENTER("handle_failsafe_rpl");
@@ -626,7 +629,7 @@ err:
   pthread_exit(0);
   DBUG_RETURN(0);
 }
-
+#endif
 
 int show_slave_hosts(THD* thd)
 {
diff --git a/sql/set_var.cc b/sql/set_var.cc
index 71ca382f9d9..bf76d96c0ed 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -1128,14 +1128,14 @@ static void fix_tx_isolation(THD *thd, enum_var_type type)
 static void fix_net_read_timeout(THD *thd, enum_var_type type)
 {
   if (type != OPT_GLOBAL)
-    thd->net.read_timeout=thd->variables.net_read_timeout;
+    net_set_read_timeout(&thd->net, thd->variables.net_read_timeout);
 }
 
 
 static void fix_net_write_timeout(THD *thd, enum_var_type type)
 {
   if (type != OPT_GLOBAL)
-    thd->net.write_timeout=thd->variables.net_write_timeout;
+    net_set_write_timeout(&thd->net, thd->variables.net_write_timeout);
 }
 
 static void fix_net_retry_count(THD *thd, enum_var_type type)
diff --git a/sql/slave.cc b/sql/slave.cc
index 6785e92b9f9..9e1ec86dd1d 100644
--- a/sql/slave.cc
+++ b/sql/slave.cc
@@ -2625,7 +2625,6 @@ static int init_slave_thread(THD* thd, SLAVE_THD_TYPE thd_type)
 */
   thd->variables.max_allowed_packet= global_system_variables.max_allowed_packet
     + MAX_LOG_EVENT_HEADER;  /* note, incr over the global not session var */
-  thd->net.read_timeout = slave_net_timeout;
   thd->master_access= ~(ulong)0;
   thd->priv_user = 0;
   thd->slave_thread = 1;
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 07064113209..808e08e4b21 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -867,7 +867,7 @@ static int check_connection(THD *thd)
       return(ER_HANDSHAKE_ERROR);
     }
     DBUG_PRINT("info", ("IO layer change in progress..."));
-    if (sslaccept(ssl_acceptor_fd, net->vio, thd->variables.net_wait_timeout))
+    if (sslaccept(ssl_acceptor_fd, net->vio, net->read_timeout))
     {
       DBUG_PRINT("error", ("Failed to read user information (pkt_len= %lu)",
 			   pkt_len));
@@ -897,7 +897,6 @@ static int check_connection(THD *thd)
   if ((thd->client_capabilities & CLIENT_TRANSACTIONS) &&
       opt_using_transactions)
     net->return_status= &thd->server_status;
-  net->read_timeout=(uint) thd->variables.net_read_timeout;
 
   char *user= end;
   char *passwd= strend(user)+1;
@@ -1029,6 +1028,10 @@ pthread_handler_decl(handle_one_connection,arg)
     NET *net= &thd->net;
     thd->thread_stack= (char*) &thd;
 
+    /* Use "connect_timeout" value during connection phase */
+    net_set_read_timeout(net, connect_timeout);
+    net_set_write_timeout(net, connect_timeout);
+
     if ((error=check_connection(thd)))
     {						// Wrong permissions
       if (error > 0)
@@ -1058,6 +1061,11 @@ pthread_handler_decl(handle_one_connection,arg)
       if (thd->query_error)
 	thd->killed= 1;
     }
+
+    /* Connect completed, set read/write timeouts back to tdefault */
+    net_set_read_timeout(net, thd->variables.net_read_timeout);
+    net_set_write_timeout(net, thd->variables.net_write_timeout);
+
     while (!net->error && net->vio != 0 && !thd->killed)
     {
       if (do_command(thd))
@@ -1261,7 +1269,7 @@ err:
 #ifndef EMBEDDED_LIBRARY
 
 /*
-  Read one command from socket and execute it (query or simple command).
+  Read one command from connection and execute it (query or simple command).
   This function is called in loop from thread function.
   SYNOPSIS
     do_command()
@@ -1272,24 +1280,26 @@ err:
 
 bool do_command(THD *thd)
 {
-  char *packet;
-  uint old_timeout;
+  char *packet= 0;
   ulong packet_length;
-  NET *net;
+  NET *net= &thd->net;
   enum enum_server_command command;
   DBUG_ENTER("do_command");
 
-  net= &thd->net;
   /*
     indicator of uninitialized lex => normal flow of errors handling
     (see my_message_sql)
   */
   thd->lex->current_select= 0;
 
-  packet=0;
-  old_timeout=net->read_timeout;
-  // Wait max for 8 hours
-  net->read_timeout=(uint) thd->variables.net_wait_timeout;
+  /*
+    This thread will do a blocking read from the client which
+    will be interrupted when the next command is received from
+    the client, the connection is closed or "net_wait_timeout"
+    number of seconds has passed
+  */
+  net_set_read_timeout(net, thd->variables.net_wait_timeout);
+
   thd->clear_error();				// Clear error message
 
   net_new_transaction(net);
@@ -1318,7 +1328,10 @@ bool do_command(THD *thd)
 		       vio_description(net->vio), command,
 		       command_name[command]));
   }
-  net->read_timeout=old_timeout;		// restore it
+
+  /* Restore read timeout value */
+  net_set_read_timeout(net, thd->variables.net_read_timeout);
+
   /*
     packet_length contains length of data, as it was stored in packet
     header. In case of malformed header, packet_length can be zero.
diff --git a/sql/sql_repl.cc b/sql/sql_repl.cc
index a20f2a6506c..f83313a8fd8 100644
--- a/sql/sql_repl.cc
+++ b/sql/sql_repl.cc
@@ -89,8 +89,8 @@ static int send_file(THD *thd)
     The client might be slow loading the data, give him wait_timeout to do
     the job
   */
-  old_timeout = thd->net.read_timeout;
-  thd->net.read_timeout = thd->variables.net_wait_timeout;
+  old_timeout= net->read_timeout;
+  net_set_read_timeout(net, thd->variables.net_wait_timeout);
 
   /*
     We need net_flush here because the client will not know it needs to send
@@ -134,7 +134,7 @@ static int send_file(THD *thd)
   error = 0;
 
  err:
-  thd->net.read_timeout = old_timeout;
+  net_set_read_timeout(net, old_timeout);
   if (fd >= 0)
     (void) my_close(fd, MYF(0));
   if (errmsg)
diff --git a/vio/vio.c b/vio/vio.c
index 6174acd7024..1eeafe483dc 100644
--- a/vio/vio.c
+++ b/vio/vio.c
@@ -96,7 +96,7 @@ void vio_reset(Vio* vio, enum enum_vio_type type,
     vio->in_addr	=vio_ssl_in_addr;
     vio->vioblocking	=vio_ssl_blocking;
     vio->is_blocking	=vio_is_blocking;
-    vio->timeout	=vio_ssl_timeout;
+    vio->timeout	=vio_timeout;
   }
   else					/* default is VIO_TYPE_TCPIP */
 #endif /* HAVE_OPENSSL */
diff --git a/vio/viossl.c b/vio/viossl.c
index 62145fe5006..8da9723d7d8 100644
--- a/vio/viossl.c
+++ b/vio/viossl.c
@@ -416,15 +416,4 @@ int vio_ssl_blocking(Vio * vio __attribute__((unused)),
 }
 
 
-void vio_ssl_timeout(Vio *vio __attribute__((unused)),
-		     uint which __attribute__((unused)),
-                     uint timeout __attribute__((unused)))
-{
-#ifdef __WIN__
-  ulong wait_timeout= (ulong) timeout * 1000;
-  (void) setsockopt(vio->sd, SOL_SOCKET,
-	which ? SO_SNDTIMEO : SO_RCVTIMEO, (char*) &wait_timeout,
-        sizeof(wait_timeout));
-#endif /* __WIN__ */
-}
 #endif /* HAVE_OPENSSL */