MySQL Lists are EOL. Please join:

List:Commits« Previous MessageNext Message »
From:Davi Arnaut Date:May 21 2009 7:48pm
Subject:bzr commit into mysql-6.0-bugteam branch (davi:3313) Bug#41860
View as plain text  
# At a local mysql-6.0-bugteam repository of davi

 3313 Davi Arnaut	2009-05-21
      Bug#41860: Without Windows named pipe
      
      The problem was that the patch for Bug#10374 broke named pipe
      and shared memory transports on Windows due to a failure to
      implement a dummy poll method for transports other than BSD
      sockets. Another problem was that mysqltest lacked support
      for named pipe and shared memory connections, which lead to
      misleading test cases that were supposed run common queries
      over both transports.
      
      The solution is to properly implement, at the VIO layer, the
      poll and is_connected methods. The is_connected method is
      implemented for every suppported transport and the poll one
      only where it makes sense. Furthermore, support for named pipe
      and shared memory connections is added to mysqltest as to
      enable testing of both transports using the test suite.
     @ client/mysqltest.cc
        Add support for named pipe and shared memory connections.
     @ include/violite.h
        Move private functions to vio/vio_priv.h
        Add poll_read and is_connected methods.
     @ mysql-test/t/named_pipe.test
        Run tests over a named pipe connection.
     @ mysql-test/t/shm.test
        Run tests over a shared memory connection.
     @ sql/item_func.cc
        vio_ok is done inside is_connected now.
     @ sql/set_var.cc
        named_pipe functionality is compiled-in under _WIN32,
        so the variable should be tied in. Any mention of
        __NT__ is probably a bug as pre-NT systems are not
        supported.
     @ sql/sql_class.cc
        Remove higher-level vio_is_connected implementation.
     @ sql/sql_class.h
        Rename vio_is_connected to not conflict with the vio one.
     @ vio/vio.c
        Add poll_read and is_connected methods.
     @ vio/vio_priv.h
        Add private functions.
     @ vio/viosocket.c
        Implement the is_connected method for the various transports.

    modified:
      client/mysqltest.cc
      include/violite.h
      mysql-test/t/named_pipe.test
      mysql-test/t/shm.test
      sql/item_func.cc
      sql/set_var.cc
      sql/sql_class.cc
      sql/sql_class.h
      vio/vio.c
      vio/vio_priv.h
      vio/viosocket.c
=== modified file 'client/mysqltest.cc'
--- a/client/mysqltest.cc	2009-05-15 13:38:06 +0000
+++ b/client/mysqltest.cc	2009-05-21 19:47:54 +0000
@@ -4849,6 +4849,8 @@ do_handle_error:
   <opts> - options to use for the connection
    * SSL - use SSL if available
    * COMPRESS - use compression if available
+   * SHM - use shared memory if available
+   * PIPE - use named pipe if available
 
 */
 
@@ -4857,6 +4859,7 @@ void do_connect(struct st_command *comma
   int con_port= opt_port;
   char *con_options;
   my_bool con_ssl= 0, con_compress= 0;
+  my_bool con_pipe= 0, con_shm= 0;
   struct st_connection* con_slot;
 
   static DYNAMIC_STRING ds_connection_name;
@@ -4867,6 +4870,9 @@ void do_connect(struct st_command *comma
   static DYNAMIC_STRING ds_port;
   static DYNAMIC_STRING ds_sock;
   static DYNAMIC_STRING ds_options;
+#ifdef HAVE_SMEM
+  static DYNAMIC_STRING ds_shm;
+#endif
   const struct command_arg connect_args[] = {
     { "connection name", ARG_STRING, TRUE, &ds_connection_name, "Name of the connection" },
     { "host", ARG_STRING, TRUE, &ds_host, "Host to connect to" },
@@ -4894,6 +4900,11 @@ void do_connect(struct st_command *comma
       die("Illegal argument for port: '%s'", ds_port.str);
   }
 
+#ifdef HAVE_SMEM
+  /* Shared memory */
+  init_dynamic_string(&ds_shm, ds_sock.str, 0, 0);
+#endif
+
   /* Sock */
   if (ds_sock.length)
   {
@@ -4932,6 +4943,10 @@ void do_connect(struct st_command *comma
       con_ssl= 1;
     else if (!strncmp(con_options, "COMPRESS", 8))
       con_compress= 1;
+    else if (!strncmp(con_options, "PIPE", 4))
+      con_pipe= 1;
+    else if (!strncmp(con_options, "SHM", 3))
+      con_shm= 1;
     else
       die("Illegal option to connect: %.*s", 
           (int) (end - con_options), con_options);
@@ -4979,6 +4994,26 @@ void do_connect(struct st_command *comma
   }
 #endif
 
+#ifdef __WIN__
+  if (con_pipe)
+  {
+    uint protocol= MYSQL_PROTOCOL_PIPE;
+    mysql_options(&con_slot->mysql, MYSQL_OPT_PROTOCOL, &protocol);
+  }
+#endif
+
+#ifdef HAVE_SMEM
+  if (con_shm)
+  {
+    uint protocol= MYSQL_PROTOCOL_MEMORY;
+    if (!ds_shm.length)
+      die("Missing shared memory base name");
+    mysql_options(&con_slot->mysql, MYSQL_OPT_PROTOCOL, &protocol);
+    mysql_options(&con_slot->mysql, MYSQL_SHARED_MEMORY_BASE_NAME, ds_shm.str);
+  }
+#endif
+
+
   /* Use default db name */
   if (ds_database.length == 0)
     dynstr_set(&ds_database, opt_db);
@@ -5011,6 +5046,9 @@ void do_connect(struct st_command *comma
   dynstr_free(&ds_port);
   dynstr_free(&ds_sock);
   dynstr_free(&ds_options);
+#ifdef HAVE_SMEM
+  dynstr_free(&ds_shm);
+#endif
   DBUG_VOID_RETURN;
 }
 

=== modified file 'include/violite.h'
--- a/include/violite.h	2008-04-23 12:33:25 +0000
+++ b/include/violite.h	2009-05-21 19:47:54 +0000
@@ -51,9 +51,6 @@ Vio* vio_new_win32shared_memory(NET *net
                                 HANDLE event_client_wrote,
                                 HANDLE event_client_read,
                                 HANDLE event_conn_closed);
-size_t vio_read_pipe(Vio *vio, uchar * buf, size_t size);
-size_t vio_write_pipe(Vio *vio, const uchar * buf, size_t size);
-int vio_close_pipe(Vio * vio);
 #else
 #define HANDLE void *
 #endif /* __WIN__ */
@@ -85,8 +82,8 @@ int	vio_errno(Vio*vio);
 my_socket vio_fd(Vio*vio);
 /* Remote peer's address and name in text form */
 my_bool vio_peer_addr(Vio *vio, char *buf, uint16 *port, size_t buflen);
-my_bool	vio_poll_read(Vio *vio,uint timeout);
-my_bool vio_peek_read(Vio *vio, uint *bytes);
+my_bool vio_poll_read(Vio *vio, uint timeout);
+my_bool vio_is_connected(Vio *vio);
 ssize_t vio_pending(Vio *vio);
 
 #ifdef HAVE_OPENSSL
@@ -131,12 +128,6 @@ void free_vio_ssl_acceptor_fd(struct st_
 #endif /* ! EMBEDDED_LIBRARY */
 #endif /* HAVE_OPENSSL */
 
-#ifdef HAVE_SMEM
-size_t vio_read_shared_memory(Vio *vio, uchar * buf, size_t size);
-size_t vio_write_shared_memory(Vio *vio, const uchar * buf, size_t size);
-int vio_close_shared_memory(Vio * vio);
-#endif
-
 void vio_end(void);
 
 #ifdef	__cplusplus
@@ -158,6 +149,8 @@ void vio_end(void);
 #define vio_close(vio)				((vio)->vioclose)(vio)
 #define vio_peer_addr(vio, buf, prt, buflen)	(vio)->peer_addr(vio, buf, prt, buflen)
 #define vio_timeout(vio, which, seconds)	(vio)->timeout(vio, which, seconds)
+#define vio_poll_read(vio, timeout)             (vio)->poll_read(vio, timeout)
+#define vio_is_connected(vio)                   (vio)->is_connected(vio)
 #endif /* !defined(DONT_MAP_VIO) */
 
 /* This enumerator is used in parser - should be always visible */
@@ -203,6 +196,8 @@ struct st_vio
   my_bool (*was_interrupted)(Vio*);
   int     (*vioclose)(Vio*);
   void	  (*timeout)(Vio*, unsigned int which, unsigned int timeout);
+  my_bool (*poll_read)(Vio *vio, uint timeout);
+  my_bool (*is_connected)(Vio*);
 #ifdef HAVE_OPENSSL
   void	  *ssl_arg;
 #endif

=== modified file 'mysql-test/t/named_pipe.test'
--- a/mysql-test/t/named_pipe.test	2007-09-24 10:42:44 +0000
+++ b/mysql-test/t/named_pipe.test	2009-05-21 19:47:54 +0000
@@ -9,6 +9,11 @@ if (`SELECT '$nmp' != 'ON'`){
   skip No named pipe support;
 }
 
+# Connect using named pipe for testing
+connect(pipe_con,localhost,root,,,,,PIPE);
+
 # Source select test case
 -- source include/common-tests.inc
 
+connection default;
+disconnect pipe_con;

=== modified file 'mysql-test/t/shm.test'
--- a/mysql-test/t/shm.test	2009-05-06 12:54:50 +0000
+++ b/mysql-test/t/shm.test	2009-05-21 19:47:54 +0000
@@ -7,10 +7,17 @@ let $shm= query_get_value("SHOW VARIABLE
 if (`SELECT '$shm' != 'ON'`){
   skip No shm support;
 }
+let $shm_name= query_get_value("SHOW GLOBAL VARIABLES LIKE 'shared_memory_base_name'", Value, 1);
+
+# Connect using SHM for testing
+connect(shm_con,localhost,root,,,,$shm_name,SHM);
 
 # Source select test case
 -- source include/common-tests.inc
 
+connection default;
+disconnect shm_con;
+
 #
 # Bug #24924: shared-memory-base-name that is too long causes buffer overflow
 #
@@ -20,7 +27,6 @@ if (`SELECT '$shm' != 'ON'`){
 # Bug #33899: Deadlock in mysql_real_query with shared memory connections
 #
 
-let $name= query_get_value("SHOW GLOBAL VARIABLES LIKE 'shared_memory_base_name'", Value, 1);
 let $stmt= `SELECT REPEAT('a', 2048)`;
 
 SET @max_allowed_packet= @@global.max_allowed_packet;
@@ -29,10 +35,8 @@ SET @net_buffer_length= @@global.net_buf
 SET GLOBAL max_allowed_packet= 1024;
 SET GLOBAL net_buffer_length= 1024;
 
---echo # The following test is disabled until Bug#41860 
---echo # "Without Windows named pipe" is fixed
-#--error 1
-#--exec echo SELECT '$stmt'| $MYSQL --protocol=memory --shared-memory-base-name=$name 2>&1
+--error 1
+--exec echo SELECT '$stmt'| $MYSQL --protocol=memory --shared-memory-base-name=$shm_name 2>&1
 
 SET GLOBAL max_allowed_packet= @max_allowed_packet;
 SET GLOBAL net_buffer_length= @net_buffer_length;

=== modified file 'sql/item_func.cc'
--- a/sql/item_func.cc	2009-05-18 05:02:11 +0000
+++ b/sql/item_func.cc	2009-05-21 19:47:54 +0000
@@ -3550,7 +3550,7 @@ static int interruptible_wait(THD *thd, 
     if (error == ETIMEDOUT || error == ETIME)
     {
       /* Return error if timed out or connection is broken. */
-      if (!timeout || (thd->vio_ok() && !thd->vio_is_connected()))
+      if (!timeout || !thd->is_connected())
         break;
     }
   } while (error && timeout);

=== modified file 'sql/set_var.cc'
--- a/sql/set_var.cc	2009-05-15 13:45:06 +0000
+++ b/sql/set_var.cc	2009-05-21 19:47:54 +0000
@@ -458,7 +458,7 @@ static sys_var_thd_enum         sys_myis
                                                 &myisam_stats_method_typelib,
                                                 NULL);
 
-#ifdef __NT__
+#ifdef _WIN32
 /* purecov: begin inspected */
 static sys_var_const            sys_named_pipe(&vars, "named_pipe",
                                                OPT_GLOBAL, SHOW_MY_BOOL,

=== modified file 'sql/sql_class.cc'
--- a/sql/sql_class.cc	2009-05-15 13:45:06 +0000
+++ b/sql/sql_class.cc	2009-05-21 19:47:54 +0000
@@ -1685,30 +1685,6 @@ void THD::rollback_item_tree_changes()
 }
 
 
-#ifndef EMBEDDED_LIBRARY
-
-/**
-  Check that the endpoint is still available.
-*/
-
-bool THD::vio_is_connected()
-{
-  uint bytes= 0;
-
-  /* End of input is signaled by poll if the socket is aborted. */
-  if (vio_poll_read(net.vio, 0))
-    return TRUE;
-
-  /* Socket is aborted if signaled but no data is available. */
-  if (vio_peek_read(net.vio, &bytes))
-    return TRUE;
-
-  return bytes ? TRUE : FALSE;
-}
-
-#endif
-
-
 /*****************************************************************************
 ** Functions to provide a interface to select results
 *****************************************************************************/

=== modified file 'sql/sql_class.h'
--- a/sql/sql_class.h	2009-05-15 13:45:06 +0000
+++ b/sql/sql_class.h	2009-05-21 19:47:54 +0000
@@ -2047,11 +2047,14 @@ public:
   }
   inline bool vio_ok() const { return net.vio != 0; }
   /** Return FALSE if connection to client is broken. */
-  bool vio_is_connected();
+  bool is_connected()
+  {
+    return vio_ok() ? vio_is_connected(net.vio) : FALSE;
+  }
 #else
   void clear_error();
   inline bool vio_ok() const { return TRUE; }
-  inline bool vio_is_connected() { return TRUE; }
+  inline bool is_connected() { return TRUE; }
 #endif
   /**
     Mark the current error as fatal. Warning: this does not

=== modified file 'vio/vio.c'
--- a/vio/vio.c	2008-01-24 20:18:48 +0000
+++ b/vio/vio.c	2009-05-21 19:47:54 +0000
@@ -22,6 +22,28 @@
 
 #include "vio_priv.h"
 
+#if defined(__WIN__) || defined(HAVE_SMEM)
+
+/**
+  Stub poll_read method that defaults to indicate that there
+  is data to read.
+
+  Used for named pipe and shared memory VIO types.
+
+  @param vio      Unused.
+  @param timeout  Unused.
+
+  @retval FALSE   There is data to read.
+*/
+
+static my_bool no_poll_read(Vio *vio __attribute__((unused)),
+                            uint timeout __attribute__((unused)))
+{
+  return FALSE;
+}
+
+#endif
+
 /*
  * Helper to fill most of the Vio* with defaults.
  */
@@ -59,6 +81,8 @@ static void vio_init(Vio* vio, enum enum
     vio->vioblocking	=vio_blocking;
     vio->is_blocking	=vio_is_blocking;
     vio->timeout	=vio_ignore_timeout;
+    vio->poll_read      =no_poll_read;
+    vio->is_connected   =vio_is_connected_pipe;
   }
   else					/* default is VIO_TYPE_TCPIP */
 #endif
@@ -78,6 +102,8 @@ static void vio_init(Vio* vio, enum enum
     vio->vioblocking	=vio_blocking;
     vio->is_blocking	=vio_is_blocking;
     vio->timeout	=vio_ignore_timeout;
+    vio->poll_read      =no_poll_read;
+    vio->is_connected   =vio_is_connected_shared_memory;
   }
   else
 #endif   
@@ -97,6 +123,8 @@ static void vio_init(Vio* vio, enum enum
     vio->vioblocking	=vio_ssl_blocking;
     vio->is_blocking	=vio_is_blocking;
     vio->timeout	=vio_timeout;
+    vio->poll_read      =vio_poll_read;
+    vio->is_connected   =vio_is_connected;
   }
   else					/* default is VIO_TYPE_TCPIP */
 #endif /* HAVE_OPENSSL */
@@ -114,6 +142,8 @@ static void vio_init(Vio* vio, enum enum
     vio->vioblocking	=vio_blocking;
     vio->is_blocking	=vio_is_blocking;
     vio->timeout	=vio_timeout;
+    vio->poll_read      =vio_poll_read;
+    vio->is_connected   =vio_is_connected;
   }
   DBUG_VOID_RETURN;
 }

=== modified file 'vio/vio_priv.h'
--- a/vio/vio_priv.h	2008-04-02 17:52:11 +0000
+++ b/vio/vio_priv.h	2009-05-21 19:47:54 +0000
@@ -25,8 +25,19 @@
 #ifndef __WIN__
 #include <sys/socket.h>
 #include <netdb.h>
+#else /* __WIN__ */
+size_t vio_read_pipe(Vio *vio, uchar * buf, size_t size);
+size_t vio_write_pipe(Vio *vio, const uchar * buf, size_t size);
+my_bool vio_is_connected_pipe(Vio *vio);
+int vio_close_pipe(Vio * vio);
 #endif
 
+#ifdef HAVE_SMEM
+size_t vio_read_shared_memory(Vio *vio, uchar * buf, size_t size);
+size_t vio_write_shared_memory(Vio *vio, const uchar * buf, size_t size);
+my_bool vio_is_connected_shared_memory(Vio *vio);
+int vio_close_shared_memory(Vio * vio);
+#endif
 
 void	vio_ignore_timeout(Vio *vio, uint which, uint timeout);
 void	vio_timeout(Vio *vio,uint which, uint timeout);

=== modified file 'vio/viosocket.c'
--- a/vio/viosocket.c	2009-03-26 23:30:56 +0000
+++ b/vio/viosocket.c	2009-05-21 19:47:54 +0000
@@ -356,16 +356,27 @@ my_bool vio_peer_addr(Vio *vio, char *bu
 }
 
 
-/* Return 0 if there is data to be read */
+/**
+  Indicate whether there is data to read on a given socket.
+
+  @note An exceptional condition event and/or errors are
+        interpreted as if there is data to read.
 
-my_bool vio_poll_read(Vio *vio,uint timeout)
+  @param sd       A connected socket.
+  @param timeout  Maximum time in seconds to poll.
+
+  @retval FALSE   There is data to read.
+  @retval TRUE    There is no data to read.
+*/
+
+static my_bool socket_poll_read(int sd, uint timeout)
 {
 #ifdef __WIN__
   int res;
-  my_socket fd= vio->sd;
+  my_socket fd= sd;
   fd_set readfds, errorfds;
   struct timeval tm;
-  DBUG_ENTER("vio_poll");
+  DBUG_ENTER("socket_poll_read");
   tm.tv_sec= timeout;
   tm.tv_usec= 0;
   FD_ZERO(&readfds);
@@ -382,8 +393,8 @@ my_bool vio_poll_read(Vio *vio,uint time
 #elif defined(HAVE_POLL)
   struct pollfd fds;
   int res;
-  DBUG_ENTER("vio_poll");
-  fds.fd=vio->sd;
+  DBUG_ENTER("socket_poll_read");
+  fds.fd=sd;
   fds.events=POLLIN;
   fds.revents=0;
   if ((res=poll(&fds,1,(int) timeout*1000)) <= 0)
@@ -397,7 +408,17 @@ my_bool vio_poll_read(Vio *vio,uint time
 }
 
 
-my_bool vio_peek_read(Vio *vio, uint *bytes)
+/**
+  Retrieve the amount of data that can be read from a socket.
+
+  @param vio          A VIO object.
+  @param bytes[out]   The amount of bytes available.
+
+  @retval FALSE   Success.
+  @retval TRUE    Failure.
+*/
+
+static my_bool socket_peek_read(Vio *vio, uint *bytes)
 {
 #ifdef __WIN__
   int len;
@@ -421,6 +442,78 @@ my_bool vio_peek_read(Vio *vio, uint *by
 #endif
 }
 
+
+/**
+  Indicate whether there is data to read on a given socket.
+
+  @remark Errors are interpreted as if there is data to read.
+
+  @param sd       A connected socket.
+  @param timeout  Maximum time in seconds to wait.
+
+  @retval FALSE   There is data (or EOF) to read. Also FALSE if error.
+  @retval TRUE    There is _NO_ data to read or timed out.
+*/
+
+my_bool vio_poll_read(Vio *vio, uint timeout)
+{
+  int sd= vio->sd;
+  DBUG_ENTER("vio_poll_read");
+#ifdef HAVE_OPENSSL
+  if (vio->type == VIO_TYPE_SSL)
+    sd= SSL_get_fd((SSL*) vio->ssl_arg);
+#endif
+  DBUG_RETURN(socket_poll_read(sd, timeout));
+}
+
+
+/**
+  Determine if the endpoint of a connection is still available.
+
+  @remark The socket is assumed to be disconnected if an EOF
+          condition is encountered.
+
+  @param vio      The VIO object.
+
+  @retval TRUE    EOF condition not found.
+  @retval FALSE   EOF condition is signaled.
+*/
+
+my_bool vio_is_connected(Vio *vio)
+{
+  uint bytes= 0;
+  DBUG_ENTER("vio_is_connected");
+
+  /* In the presence of errors the socket is assumed to be connected. */
+
+  /*
+    The first step of detecting a EOF condition is veryfing
+    whether there is data to read. Data in this case would
+    be the EOF.
+  */
+  if (vio_poll_read(vio, 0))
+    DBUG_RETURN(TRUE);
+
+  /*
+    The second step is read() or recv() from the socket returning
+    0 (EOF). Unfortunelly, it's not possible to call read directly
+    as we could inadvertently read meaningful connection data.
+    Simulate a read by retrieving the number of bytes available to
+    read -- 0 meaning EOF.
+  */
+  if (socket_peek_read(vio, &bytes))
+    DBUG_RETURN(TRUE);
+
+#ifdef HAVE_OPENSSL
+  /* There might be buffered data at the SSL layer. */
+  if (!bytes && vio->type == VIO_TYPE_SSL)
+    bytes= SSL_pending((SSL*) vio->ssl_arg);
+#endif
+
+  DBUG_RETURN(bytes ? TRUE : FALSE);
+}
+
+
 void vio_timeout(Vio *vio, uint which, uint timeout)
 {
 #if defined(SO_SNDTIMEO) && defined(SO_RCVTIMEO)
@@ -489,6 +582,16 @@ size_t vio_write_pipe(Vio * vio, const u
   DBUG_RETURN((size_t) length);
 }
 
+
+my_bool vio_is_connected_pipe(Vio *vio)
+{
+  if (PeekNamedPipe(vio->hPipe, NULL, 0, NULL, NULL, NULL))
+    return TRUE;
+  else
+    return (GetLastError() != ERROR_BROKEN_PIPE);
+}
+
+
 int vio_close_pipe(Vio * vio)
 {
   int r;
@@ -627,6 +730,12 @@ size_t vio_write_shared_memory(Vio * vio
 }
 
 
+my_bool vio_is_connected_shared_memory(Vio *vio)
+{
+  return (WaitForSingleObject(vio->event_conn_closed, 0) != WAIT_OBJECT_0);
+}
+
+
 /**
  Close shared memory and DBUG_PRINT any errors that happen on closing.
  @return Zero if all closing functions succeed, and nonzero otherwise.


Attachment: [text/bzr-bundle] bzr/davi.arnaut@sun.com-20090521194754-gfhfj35htarl57lp.bundle
Thread
bzr commit into mysql-6.0-bugteam branch (davi:3313) Bug#41860Davi Arnaut21 May
  • Re: bzr commit into mysql-6.0-bugteam branch (davi:3313) Bug#41860Konstantin Osipov22 May