List:Commits« Previous MessageNext Message »
From:Davi Arnaut Date:July 28 2010 6:17pm
Subject:bzr commit into mysql-trunk-bugfixing branch (davi:3158) Bug#54790
View as plain text  
# At a local mysql-trunk-bugfixing repository of davi

 3158 Davi Arnaut	2010-07-28
      Bug#54790: Use of non-blocking mode for sockets limits performance
      
      A pre-requisite patch for unifying the handling of socket timeouts.
      This patch removes alarm based timeouts from the network layer
      and transitions the code to a pure socket based timeout approach.
      
      The handling of network I/O errors is split and documented, the
      server and client libraries have different approaches to treating
      interruptions.
      
      Also, the low level packet reading loop is unrolled into two specific
      sequences: reading the packet header and the payload. This make
      error handling easier down the road.
     @ include/my_global.h
        A socket timeout is signalled with EAGAIN/EWOULDBLOCK. See socket(7).
     @ sql/net_serv.cc
        Remove the use of signal based alarms for timeouts. Instead, rely
        on socket timeouts and blocking I/O. The error handling is changed
        to recognize EAGAIN/EWOULDBLOCK as a timeout and EINTR as a forced
        interruption depending on how the server was built.
        
        Furthermore, the loop in the packet reading path (my_real_path) is
        unrolled into two steps: reading the packet header and payload.
        Each step is now documented and should be easier to understand.
     @ vio/viosocket.c
        In some cases, I/O operations should only be retried on EINTR.
        Socket timeout is indicated with SOCKET_ETIMEDOUT. Method should
        be renamed to not cause confusion with other types of interruption.

    modified:
      include/my_global.h
      sql/net_serv.cc
      vio/viosocket.c
=== modified file 'include/my_global.h'
--- a/include/my_global.h	2010-07-23 20:18:36 +0000
+++ b/include/my_global.h	2010-07-28 18:17:27 +0000
@@ -977,7 +977,7 @@ typedef ulong nesting_map;  /* Used for
 #define closesocket(A)	close(A)
 #define SOCKET_EINTR	EINTR
 #define SOCKET_EAGAIN	EAGAIN
-#define SOCKET_ETIMEDOUT SOCKET_EINTR
+#define SOCKET_ETIMEDOUT SOCKET_EAGAIN
 #define SOCKET_EWOULDBLOCK EWOULDBLOCK
 #define SOCKET_EADDRINUSE EADDRINUSE
 #define SOCKET_ENFILE	ENFILE

=== modified file 'sql/net_serv.cc'
--- a/sql/net_serv.cc	2010-07-15 11:13:30 +0000
+++ b/sql/net_serv.cc	2010-07-28 18:17:27 +0000
@@ -61,29 +61,12 @@
   the client should have a bigger max_allowed_packet.
 */
 
-#if defined(__WIN__) || !defined(MYSQL_SERVER)
-  /* The following is because alarms doesn't work on windows. */
-#ifndef NO_ALARM
-#define NO_ALARM
-#endif
-#endif
-
-#ifndef NO_ALARM
-#include "my_pthread.h"
-void sql_print_error(const char *format,...);
-#else
-#define DONT_USE_THR_ALARM
-#endif /* NO_ALARM */
-
-#include "thr_alarm.h"
-
 #ifdef MYSQL_SERVER
 /*
   The following variables/functions should really not be declared
   extern, but as it's hard to include sql_priv.h here, we have to
   live with this for a while.
 */
-extern uint test_flags;
 extern ulong bytes_sent, bytes_received, net_big_packet_count;
 #ifndef MYSQL_INSTANCE_MANAGER
 #ifdef HAVE_QUERY_CACHE
@@ -100,7 +83,6 @@ extern void query_cache_insert(const cha
 #define thd_increment_bytes_sent(N)
 #endif
 
-#define TEST_BLOCKING		8
 #define MAX_PACKET_LENGTH (256L*256L*256L-1)
 
 static my_bool net_write_buff(NET *net,const uchar *packet,ulong len);
@@ -133,13 +115,6 @@ my_bool my_net_init(NET *net, Vio* vio)
   if (vio != 0)					/* If real connection */
   {
     net->fd  = vio_fd(vio);			/* For perl DBI/DBD */
-#if defined(MYSQL_SERVER) && !defined(__WIN__)
-    if (!(test_flags & TEST_BLOCKING))
-    {
-      my_bool old_mode;
-      vio_blocking(vio, FALSE, &old_mode);
-    }
-#endif
     vio_fastsend(vio);
   }
   DBUG_RETURN(0);
@@ -180,7 +155,7 @@ my_bool net_realloc(NET *net, size_t len
   /*
     We must allocate some extra bytes for the end 0 and to be able to
     read big compressed blocks + 1 safety byte since uint3korr() in
-    my_real_read() may actually read 4 bytes depending on build flags and
+    net_read_packet() may actually read 4 bytes depending on build flags and
     platform.
   */
   if (!(buff= (uchar*) my_realloc((char*) net->buff, pkt_length +
@@ -345,6 +320,48 @@ my_bool net_flush(NET *net)
 }
 
 
+#if defined(MYSQL_SERVER) && !defined(DONT_USE_THR_ALARM)
+
+/**
+  In the server, I/O operations are not retried if thread alarm is being
+  used (DONT_USE_THR_ALARM is not defined). In this scenario, pthread_kill
+  is used to wake up (interrupt) threads waiting for I/O.
+*/
+static my_bool net_should_retry(NET *, uint *)
+{
+  return FALSE;
+}
+
+#elif !defined(MYSQL_SERVER) && defined(THREAD_SAFE_CLIENT)
+
+/**
+  In the thread safe client library, I/O operations are always retried
+  after a interrupted I/O operation. Otherwise, its either a timeout or
+  a unrecoverable error.
+*/
+static my_bool net_should_retry(NET *net, uint *)
+{
+  return vio_should_retry(net->vio);
+}
+
+#else
+
+/**
+  In the non-thread safe client library, or in the server without thread
+  alarm, I/O operations are retried up to a limit after a interrupted I/O
+  operation.
+*/
+static my_bool net_should_retry(NET *net, uint *retry_count)
+{
+  if (vio_should_retry(net->vio) && (*retry_count)++ < net->retry_count)
+    return TRUE;
+  else
+    return FALSE;
+}
+
+#endif
+
+
 /*****************************************************************************
 ** Write something to server/client buffer
 *****************************************************************************/
@@ -569,12 +586,7 @@ net_real_write(NET *net,const uchar *pac
 {
   size_t length;
   const uchar *pos,*end;
-  thr_alarm_t alarmed;
-#ifndef NO_ALARM
-  ALARM alarm_buff;
-#endif
   uint retry_count=0;
-  my_bool net_blocking = vio_is_blocking(net->vio);
   DBUG_ENTER("net_real_write");
 
 #if defined(MYSQL_SERVER) && defined(USE_QUERY_CACHE)
@@ -616,14 +628,7 @@ net_real_write(NET *net,const uchar *pac
   DBUG_DUMP("data", packet, len);
 #endif
 
-#ifndef NO_ALARM
-  thr_alarm_init(&alarmed);
-  if (net_blocking)
-    thr_alarm(&alarmed, net->write_timeout, &alarm_buff);
-#else
-  alarmed=0;
-  /* Write timeout is set in my_net_set_write_timeout */
-#endif /* NO_ALARM */
+  DBUG_ASSERT(vio_is_blocking(net->vio));
 
   pos= packet;
   end=pos+len;
@@ -631,55 +636,11 @@ net_real_write(NET *net,const uchar *pac
   {
     if ((long) (length= vio_write(net->vio,pos,(size_t) (end-pos))) <= 0)
     {
-      my_bool interrupted = vio_should_retry(net->vio);
-#if !defined(__WIN__)
-      if ((interrupted || length == 0) && !thr_alarm_in_use(&alarmed))
-      {
-        if (!thr_alarm(&alarmed, net->write_timeout, &alarm_buff))
-        {                                       /* Always true for client */
-	  my_bool old_mode;
-	  while (vio_blocking(net->vio, TRUE, &old_mode) < 0)
-	  {
-	    if (vio_should_retry(net->vio) && retry_count++ < net->retry_count)
-	      continue;
-#ifdef EXTRA_DEBUG
-	    fprintf(stderr,
-		    "%s: my_net_write: fcntl returned error %d, aborting thread\n",
-		    my_progname,vio_errno(net->vio));
-#endif /* EXTRA_DEBUG */
-	    net->error= 2;                     /* Close socket */
-            net->last_errno= ER_NET_PACKET_TOO_LARGE;
-#ifdef MYSQL_SERVER
-            my_error(ER_NET_PACKET_TOO_LARGE, MYF(0));
-#endif
-	    goto end;
-	  }
-	  retry_count=0;
-	  continue;
-	}
-      }
-      else
-#endif /* !defined(__WIN__) */
-	if (thr_alarm_in_use(&alarmed) && !thr_got_alarm(&alarmed) &&
-	    interrupted)
-      {
-	if (retry_count++ < net->retry_count)
-	    continue;
-#ifdef EXTRA_DEBUG
-	  fprintf(stderr, "%s: write looped, aborting thread\n",
-		  my_progname);
-#endif /* EXTRA_DEBUG */
-      }
-#if defined(THREAD_SAFE_CLIENT) && !defined(MYSQL_SERVER)
-      if (vio_errno(net->vio) == SOCKET_EINTR)
-      {
-	DBUG_PRINT("warning",("Interrupted write. Retrying..."));
-	continue;
-      }
-#endif /* defined(THREAD_SAFE_CLIENT) && !defined(MYSQL_SERVER) */
+      if (net_should_retry(net, &retry_count))
+        continue;
       net->error= 2;				/* Close socket */
-      net->last_errno= (interrupted ? ER_NET_WRITE_INTERRUPTED :
-                               ER_NET_ERROR_ON_WRITE);
+      net->last_errno= vio_was_interrupted(net->vio) ?
+                       ER_NET_WRITE_INTERRUPTED : ER_NET_ERROR_ON_WRITE;
 #ifdef MYSQL_SERVER
       my_error(net->last_errno, MYF(0));
 #endif /* MYSQL_SERVER */
@@ -688,313 +649,202 @@ net_real_write(NET *net,const uchar *pac
     pos+=length;
     update_statistics(thd_increment_bytes_sent(length));
   }
-#ifndef __WIN__
- end:
-#endif
 #ifdef HAVE_COMPRESS
   if (net->compress)
     my_free((void*) packet);
 #endif
-  if (thr_alarm_in_use(&alarmed))
-  {
-    my_bool old_mode;
-    thr_end_alarm(&alarmed);
-    vio_blocking(net->vio, net_blocking, &old_mode);
-  }
   net->reading_or_writing=0;
   DBUG_RETURN(((int) (pos != end)));
 }
 
+#define MY_VIO_SOCKET_ERROR ((size_t) -1)
 
-/*****************************************************************************
-** Read something from server/clinet
-*****************************************************************************/
+/**
+  Read a determined number of bytes from a network handler.
 
-#ifndef NO_ALARM
+  @param  net     NET handler.
+  @param  count   The number of bytes to read.
 
-static my_bool net_safe_read(NET *net, uchar *buff, size_t length,
-			     thr_alarm_t *alarmed)
+  @return TRUE on error, FALSE on success.
+*/
+static my_bool net_read_raw_loop(NET *net, size_t count)
 {
-  uint retry_count=0;
-  while (length > 0)
+  size_t recvcnt;
+  unsigned int retry_count= 0;
+  uchar *buf= net->buff + net->where_b;
+
+  DBUG_ASSERT(vio_is_blocking(net->vio));
+
+  while (count)
   {
-    size_t tmp;
-    if ((long) (tmp= vio_read(net->vio, buff, length)) <= 0)
+    recvcnt= vio_read(net->vio, buf, count);
+
+    /* NET_SOCKET_ERROR (-1) indicates an error. */
+    if (recvcnt == MY_VIO_SOCKET_ERROR)
     {
-      my_bool interrupted = vio_should_retry(net->vio);
-      if (!thr_got_alarm(alarmed) && interrupted)
-      {					/* Probably in MIT threads */
-	if (retry_count++ < net->retry_count)
-	  continue;
-      }
-      return 1;
+      /* A recoverable I/O error occurred? */
+      if (net_should_retry(net, &retry_count))
+        continue;
+      else
+        break;
     }
-    length-= tmp;
-    buff+= tmp;
+    /* Zero indicates end of file. */
+    else if (!recvcnt)
+      break;
+
+    count-= recvcnt;
+    buf+= recvcnt;
+    update_statistics(thd_increment_bytes_received(recvcnt));
   }
-  return 0;
+
+  /* On failure, propagate the error code. */
+  if (count)
+  {
+    /* Socket should be closed. */
+    net->error= 2;
+
+    /* Interrupted by a timeout/kill? */
+    if (recvcnt && vio_was_interrupted(net->vio))
+      net->last_errno= ER_NET_READ_INTERRUPTED;
+    else
+      net->last_errno= ER_NET_READ_ERROR;
+
+#ifdef MYSQL_SERVER
+    my_error(net->last_errno, MYF(0));
+#endif
+  }
+
+  return test(count);
 }
 
+
+/*****************************************************************************
+** Read something from server/clinet
+*****************************************************************************/
+
+
 /**
-  Help function to clear the commuication buffer when we get a too big packet.
+  Read the header of a packet. The MySQL protocol packet header
+  consists of the length, in bytes, of the payload (packet data)
+  and a serial number.
 
-  @param net		Communication handle
-  @param remain	Bytes to read
-  @param alarmed	Parameter for thr_alarm()
-  @param alarm_buff	Parameter for thr_alarm()
+  @remark The encoded length is the length of the packet payload,
+          which does not include the packet header.
 
-  @retval
-   0	Was able to read the whole packet
-  @retval
-   1	Got mailformed packet from client
-*/
+  @remark The serial number is used to ensure that the packets are
+          received in order. If the packet serial number does not
+          match the expected value, a error is returned.
+
+  @param  net  NET handler.
 
-static my_bool my_net_skip_rest(NET *net, uint32 remain, thr_alarm_t *alarmed,
-				ALARM *alarm_buff)
+  @return TRUE on error, FALSE on success.
+*/
+static my_bool net_read_packet_header(NET *net)
 {
-  uint32 old=remain;
-  DBUG_ENTER("my_net_skip_rest");
-  DBUG_PRINT("enter",("bytes_to_skip: %u", (uint) remain));
+  uchar pkt_nr;
+  size_t count= NET_HEADER_SIZE;
 
-  /* The following is good for debugging */
-  update_statistics(thd_increment_net_big_packet_count(1));
+  if (net->compress)
+    count+= COMP_HEADER_SIZE;
 
-  if (!thr_alarm_in_use(alarmed))
-  {
-    my_bool old_mode;
-    if (thr_alarm(alarmed,net->read_timeout, alarm_buff) ||
-	vio_blocking(net->vio, TRUE, &old_mode) < 0)
-      DBUG_RETURN(1);				/* Can't setup, abort */
-  }
-  for (;;)
+  if (net_read_raw_loop(net, count))
+    return TRUE;
+
+  DBUG_DUMP("packet_header", net->buff + net->where_b, NET_HEADER_SIZE);
+
+  pkt_nr= net->buff[net->where_b + 3];
+
+  /*
+    Verify packet serial number against the truncated packet counter.
+    The local packet counter must be truncated since its not reset.
+  */
+  if (pkt_nr != (uchar) net->pkt_nr)
   {
-    while (remain > 0)
-    {
-      size_t length= min(remain, net->max_packet);
-      if (net_safe_read(net, net->buff, length, alarmed))
-	DBUG_RETURN(1);
-      update_statistics(thd_increment_bytes_received(length));
-      remain -= (uint32) length;
-    }
-    if (old != MAX_PACKET_LENGTH)
-      break;
-    if (net_safe_read(net, net->buff, NET_HEADER_SIZE, alarmed))
-      DBUG_RETURN(1);
-    old=remain= uint3korr(net->buff);
-    net->pkt_nr++;
+    /* Not a NET error on the client. XXX: why? */
+#if defined(MYSQL_SERVER)
+    my_error(ER_NET_PACKETS_OUT_OF_ORDER, MYF(0));
+#elif defined(EXTRA_DEBUG)
+    fprintf(stderr, "Error: packets out of order (found %u, expected %u)\n",
+            (uint) pkt_nr, net->pkt_nr);
+    DBUG_ASSERT(pkt_nr == net->pkt_nr);
+#endif
   }
-  DBUG_RETURN(0);
+
+  net->pkt_nr++;
+
+  return FALSE;
 }
-#endif /* NO_ALARM */
 
 
 /**
-  Reads one packet to net->buff + net->where_b.
-  Long packets are handled by my_net_read().
-  This function reallocates the net->buff buffer if necessary.
+  Read one (variable-length) MySQL protocol packet.
+  A MySQL packet consists of a header and a payload.
 
-  @return
-    Returns length of packet.
-*/
+  @remark Reads one packet to net->buff + net->where_b.
+  @remark Long packets are handled by my_net_read().
+  @remark The network buffer is expanded if necessary.
 
-static ulong
-my_real_read(NET *net, size_t *complen)
+  @return The length of the packet, or @packet_error on error.
+*/
+static ulong net_read_packet(NET *net, size_t *complen)
 {
-  uchar *pos;
-  size_t length;
-  uint i,retry_count=0;
-  ulong len=packet_error;
-  thr_alarm_t alarmed;
-#ifndef NO_ALARM
-  ALARM alarm_buff;
-#endif
-  my_bool net_blocking=vio_is_blocking(net->vio);
-  uint32 remain= (net->compress ? NET_HEADER_SIZE+COMP_HEADER_SIZE :
-		  NET_HEADER_SIZE);
-  *complen = 0;
-
-  net->reading_or_writing=1;
-  thr_alarm_init(&alarmed);
-#ifndef NO_ALARM
-  if (net_blocking)
-    thr_alarm(&alarmed,net->read_timeout,&alarm_buff);
-#else
-  /* Read timeout is set in my_net_set_read_timeout */
-#endif /* NO_ALARM */
+  size_t pkt_len, pkt_data_len;
 
-    pos = net->buff + net->where_b;		/* net->packet -4 */
-    for (i=0 ; i < 2 ; i++)
-    {
-      while (remain > 0)
-      {
-	/* First read is done with non blocking mode */
-        if ((long) (length= vio_read(net->vio, pos, remain)) <= 0L)
-        {
-          my_bool interrupted = vio_should_retry(net->vio);
-
-	  DBUG_PRINT("info",("vio_read returned %ld  errno: %d",
-			     (long) length, vio_errno(net->vio)));
-#if !defined(__WIN__) || defined(MYSQL_SERVER)
-	  /*
-	    We got an error that there was no data on the socket. We now set up
-	    an alarm to not 'read forever', change the socket to non blocking
-	    mode and try again
-	  */
-	  if ((interrupted || length == 0) && !thr_alarm_in_use(&alarmed))
-	  {
-	    if (!thr_alarm(&alarmed,net->read_timeout,&alarm_buff)) /* Don't wait too long */
-	    {
-	      my_bool old_mode;
-	      while (vio_blocking(net->vio, TRUE, &old_mode) < 0)
-	      {
-		if (vio_should_retry(net->vio) &&
-		    retry_count++ < net->retry_count)
-		  continue;
-		DBUG_PRINT("error",
-			   ("fcntl returned error %d, aborting thread",
-			    vio_errno(net->vio)));
-#ifdef EXTRA_DEBUG
-		fprintf(stderr,
-			"%s: read: fcntl returned error %d, aborting thread\n",
-			my_progname,vio_errno(net->vio));
-#endif /* EXTRA_DEBUG */
-		len= packet_error;
-		net->error= 2;                 /* Close socket */
-	        net->last_errno= ER_NET_FCNTL_ERROR;
-#ifdef MYSQL_SERVER
-		my_error(ER_NET_FCNTL_ERROR, MYF(0));
-#endif
-		goto end;
-	      }
-	      retry_count=0;
-	      continue;
-	    }
-	  }
-#endif /* (!defined(__WIN__) || defined(MYSQL_SERVER) */
-	  if (thr_alarm_in_use(&alarmed) && !thr_got_alarm(&alarmed) &&
-	      interrupted)
-	  {					/* Probably in MIT threads */
-	    if (retry_count++ < net->retry_count)
-	      continue;
-#ifdef EXTRA_DEBUG
-	    fprintf(stderr, "%s: read looped with error %d, aborting thread\n",
-		    my_progname,vio_errno(net->vio));
-#endif /* EXTRA_DEBUG */
-	  }
-#if defined(THREAD_SAFE_CLIENT) && !defined(MYSQL_SERVER)
-	  if (vio_errno(net->vio) == SOCKET_EINTR)
-	  {
-	    DBUG_PRINT("warning",("Interrupted read. Retrying..."));
-	    continue;
-	  }
-#endif
-	  DBUG_PRINT("error",("Couldn't read packet: remain: %u  errno: %d  length: %ld",
-			      remain, vio_errno(net->vio), (long) length));
-	  len= packet_error;
-	  net->error= 2;				/* Close socket */
-          net->last_errno= (vio_was_interrupted(net->vio) ?
-                                   ER_NET_READ_INTERRUPTED :
-                                   ER_NET_READ_ERROR);
-#ifdef MYSQL_SERVER
-          my_error(net->last_errno, MYF(0));
-#endif
-	  goto end;
-	}
-	remain -= (uint32) length;
-	pos+= length;
-	update_statistics(thd_increment_bytes_received(length));
-      }
-      if (i == 0)
-      {					/* First parts is packet length */
-	ulong helping;
-        DBUG_DUMP("packet_header", net->buff+net->where_b,
-                  NET_HEADER_SIZE);
-	if (net->buff[net->where_b + 3] != (uchar) net->pkt_nr)
-	{
-	  if (net->buff[net->where_b] != (uchar) 255)
-	  {
-	    DBUG_PRINT("error",
-		       ("Packets out of order (Found: %d, expected %u)",
-			(int) net->buff[net->where_b + 3],
-			net->pkt_nr));
-            /* 
-              We don't make noise server side, since the client is expected
-              to break the protocol for e.g. --send LOAD DATA .. LOCAL where
-              the server expects the client to send a file, but the client
-              may reply with a new command instead.
-            */
-#if defined (EXTRA_DEBUG) && !defined (MYSQL_SERVER)
-            fflush(stdout);
-	    fprintf(stderr,"Error: Packets out of order (Found: %d, expected %d)\n",
-		    (int) net->buff[net->where_b + 3],
-		    (uint) (uchar) net->pkt_nr);
-            fflush(stderr);
-            DBUG_ASSERT(0);
-#endif
-	  }
-	  len= packet_error;
-          /* Not a NET error on the client. XXX: why? */
-#ifdef MYSQL_SERVER
-	  my_error(ER_NET_PACKETS_OUT_OF_ORDER, MYF(0));
-#endif
-	  goto end;
-	}
-	net->compress_pkt_nr= ++net->pkt_nr;
-#ifdef HAVE_COMPRESS
-	if (net->compress)
-	{
-          /*
-            The following uint3korr() may read 4 bytes, so make sure we don't
-            read unallocated or uninitialized memory. The right-hand expression
-            must match the size of the buffer allocated in net_realloc().
-          */
-          DBUG_ASSERT(net->where_b + NET_HEADER_SIZE + sizeof(uint32) <=
-                      net->max_packet + NET_HEADER_SIZE + COMP_HEADER_SIZE + 1);
-	  /*
-	    If the packet is compressed then complen > 0 and contains the
-	    number of bytes in the uncompressed packet
-	  */
-	  *complen=uint3korr(&(net->buff[net->where_b + NET_HEADER_SIZE]));
-	}
-#endif
+  *complen= 0;
 
-	len=uint3korr(net->buff+net->where_b);
-	if (!len)				/* End of big multi-packet */
-	  goto end;
-	helping = max(len,*complen) + net->where_b;
-	/* The necessary size of net->buff */
-	if (helping >= net->max_packet)
-	{
-	  if (net_realloc(net,helping))
-	  {
-#if defined(MYSQL_SERVER) && !defined(NO_ALARM)
-	    if (!net->compress &&
-                net->skip_big_packet &&
-		!my_net_skip_rest(net, (uint32) len, &alarmed, &alarm_buff))
-	      net->error= 3;		/* Successfully skiped packet */
-#endif
-	    len= packet_error;          /* Return error and close connection */
-	    goto end;
-	  }
-	}
-	pos=net->buff + net->where_b;
-	remain = (uint32) len;
-      }
-    }
+  net->reading_or_writing= TRUE;
 
-end:
-  if (thr_alarm_in_use(&alarmed))
+  DBUG_ASSERT(vio_is_blocking(net->vio));
+
+  /* Retrieve packet length and number. */
+  if (net_read_packet_header(net))
+    goto error;
+
+#ifdef HAVE_COMPRESS
+  if (net->compress)
   {
-    my_bool old_mode;
-    thr_end_alarm(&alarmed);
-    vio_blocking(net->vio, net_blocking, &old_mode);
+    net->compress_pkt_nr= net->pkt_nr;
+
+    /*
+      The following uint3korr() may read 4 bytes, so make sure we don't
+      read unallocated or uninitialized memory. The right-hand expression
+      must match the size of the buffer allocated in net_realloc().
+    */
+    DBUG_ASSERT(net->where_b + NET_HEADER_SIZE + sizeof(uint32) <=
+                net->max_packet + NET_HEADER_SIZE + COMP_HEADER_SIZE + 1);
+
+    /*
+      If the packet is compressed then complen > 0 and contains the
+      number of bytes in the uncompressed packet.
+    */
+    *complen= uint3korr(&(net->buff[net->where_b + NET_HEADER_SIZE]));
   }
-  net->reading_or_writing=0;
-#ifdef DEBUG_DATA_PACKETS
-  if (len != packet_error)
-    DBUG_DUMP("data", net->buff+net->where_b, len);
 #endif
-  return(len);
+
+  /* The length of the packet that follows. */
+  pkt_len= uint3korr(net->buff+net->where_b);
+
+  /* End of big multi-packet. */
+  if (!pkt_len)
+    goto end;
+
+  pkt_data_len = max(pkt_len, *complen) + net->where_b;
+
+  /* Expand packet buffer if necessary. */
+  if ((pkt_data_len >= net->max_packet) && net_realloc(net, pkt_data_len))
+    goto error;
+
+  /* Read the packet data (payload). */
+  if (net_read_raw_loop(net, pkt_len))
+    goto error;
+
+end:
+  net->reading_or_writing= FALSE;
+  return pkt_len;
+
+error:
+  net->reading_or_writing= FALSE;
+  return packet_error;
 }
 
 
@@ -1025,7 +875,7 @@ my_net_read(NET *net)
   if (!net->compress)
   {
 #endif
-    len = my_real_read(net,&complen);
+    len= net_read_packet(net, &complen);
     if (len == MAX_PACKET_LENGTH)
     {
       /* First packet of a multi-packet.  Concatenate the packets */
@@ -1035,7 +885,7 @@ my_net_read(NET *net)
       {
 	net->where_b += len;
 	total_length += len;
-	len = my_real_read(net,&complen);
+	len= net_read_packet(net, &complen);
       } while (len == MAX_PACKET_LENGTH);
       if (len != packet_error)
 	len+= total_length;
@@ -1127,7 +977,7 @@ my_net_read(NET *net)
       }
 
       net->where_b=buf_length;
-      if ((packet_len = my_real_read(net,&complen)) == packet_error)
+      if ((packet_len= net_read_packet(net, &complen)) == packet_error)
       {
         MYSQL_NET_READ_DONE(1, 0);
 	return packet_error;
@@ -1165,10 +1015,8 @@ void my_net_set_read_timeout(NET *net, u
   DBUG_ENTER("my_net_set_read_timeout");
   DBUG_PRINT("enter", ("timeout: %d", timeout));
   net->read_timeout= timeout;
-#ifdef NO_ALARM
   if (net->vio)
     vio_timeout(net->vio, 0, timeout);
-#endif
   DBUG_VOID_RETURN;
 }
 
@@ -1178,9 +1026,7 @@ void my_net_set_write_timeout(NET *net,
   DBUG_ENTER("my_net_set_write_timeout");
   DBUG_PRINT("enter", ("timeout: %d", timeout));
   net->write_timeout= timeout;
-#ifdef NO_ALARM
   if (net->vio)
     vio_timeout(net->vio, 1, timeout);
-#endif
   DBUG_VOID_RETURN;
 }

=== modified file 'vio/viosocket.c'
--- a/vio/viosocket.c	2010-05-21 13:17:01 +0000
+++ b/vio/viosocket.c	2010-07-28 18:17:27 +0000
@@ -240,29 +240,16 @@ int vio_keepalive(Vio* vio, my_bool set_
 
 
 my_bool
-vio_should_retry(Vio * vio)
+vio_should_retry(Vio *vio __attribute__((unused)))
 {
-  int en = socket_errno;
-  /*
-    man 2 read write
-      EAGAIN or EWOULDBLOCK when a socket is a non-blocking mode means
-      that the read/write would block.
-    man 7 socket
-      EAGAIN or EWOULDBLOCK when a socket is in a blocking mode means
-      that the corresponding receiving or sending timeout was reached.
-  */
-  return  en == SOCKET_EINTR ||
-          (!vio_is_blocking(vio) &&
-            (en == SOCKET_EAGAIN || en == SOCKET_EWOULDBLOCK));
+  return (socket_errno == SOCKET_EINTR);
 }
 
 
 my_bool
 vio_was_interrupted(Vio *vio __attribute__((unused)))
 {
-  int en= socket_errno;
-  return (en == SOCKET_EAGAIN || en == SOCKET_EINTR ||
-	  en == SOCKET_EWOULDBLOCK || en == SOCKET_ETIMEDOUT);
+  return (socket_errno == SOCKET_ETIMEDOUT);
 }
 
 


Attachment: [text/bzr-bundle] bzr/davi.arnaut@oracle.com-20100728181727-gatfi0p243koals7.bundle
Thread
bzr commit into mysql-trunk-bugfixing branch (davi:3158) Bug#54790Davi Arnaut28 Jul