Bug #62518 Connector/J - Named Pipe connection cannot be closed
Submitted: 23 Sep 2011 17:10 Modified: 17 Nov 2011 14:37
Reporter: Lucas Still Email Updates:
Status: Won't fix Impact on me:
None 
Category:Connector / J Severity:S2 (Serious)
Version:Community Server 5.5.15 OS:Microsoft Windows (7)
Assigned to: Bogdan Degtyariov CPU Architecture:Any
Tags: Connector/J, Named-Pipe

[23 Sep 2011 17:10] Lucas Still
Description:
Windows 7
MySQL Community Server 5.5.15
Connector/J 5.1.17
Java 1.7.0

A named pipe connection can be made and used, but throws a warning on "close" and does not properly close the connection to the MySQL server. The following "warning" is thrown by the Connector/J Log:

Fri Sep 23 12:57:54 EDT 2011 WARN: Caught while disconnecting...

EXCEPTION STACK TRACE:

** BEGIN NESTED EXCEPTION ** 

java.net.SocketException
MESSAGE: Socket is not connected

STACKTRACE:

java.net.SocketException: Socket is not connected
	at java.net.Socket.shutdownInput(Socket.java:1456)
	at com.mysql.jdbc.MysqlIO.quit(MysqlIO.java:1687)
	at com.mysql.jdbc.ConnectionImpl.realClose(ConnectionImpl.java:4368)
	at com.mysql.jdbc.ConnectionImpl.close(ConnectionImpl.java:1557)
	at myprogram.main.main(main.java:41)

** END NESTED EXCEPTION **

---
Additionally, the MySQL server will display that the connection remains.

I wanted to establish a connection to a MySQL server using java, make a query, and then close the connection. I attempted each of these and was successful in the first two, but was unsuccessful in properly closing the connection. I expect the connection to be closed properly; i.e. without a warning and have the MySQL server terminate the connection.

How to repeat:
Create and run the following java program:

------------

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;

public final class main {
    public static void main(String[] args) {
        Connection conn = null;
        try {
            conn =
               DriverManager.getConnection("jdbc:mysql:///database?socketFactory=com.mysql.jdbc.NamedPipeSocketFactory&namedPipePath=\\\\.\\Pipe\\mysql.sock", "root", "password");

            conn.close();

           
        } catch (SQLException ex) {
            // handle any errors
            System.out.println("SQLException: " + ex.getMessage());
            System.out.println("SQLState: " + ex.getSQLState());
            System.out.println("VendorError: " + ex.getErrorCode());
        }
    }
}

------------

A SQLException will not be "caught", but the aforementioned warning will be printed and the connection to the MySQL server will persist until the java program terminates (in this case the program terminates immediately, but any variety of methods can be added/used to keep the program running).
[23 Sep 2011 19:29] Lucas Still
Accidental severity selection corrected.
[9 Nov 2011 8:48] Bogdan Degtyariov
Verified using 5.1.18.
What is interesting - the database queries and results work as normal, it is just connection.close() failing.
[9 Nov 2011 14:55] Lucas Still
Indeed. It isn't a game breaker, but I'm not positive about the compounding ramifications of failed closings.
[10 Nov 2011 2:42] Bogdan Degtyariov
Lucas, you are absolutely right. This must be fixed.
[10 Nov 2011 2:48] Mark Matthews
I don't think this is a driver bug. When one calls Connection.close(), it ends up calling Socket.close() on the socket in question. In this case, it's com.mysql.jdbc.NamedPipeSocket.

This does the following:

public synchronized void close() throws IOException {
			this.namedPipeFile.close();
			this.isClosed = true;
		}

If that's not enough to get the other end of the connection to "die", then there's not really much of anything that can be done from the driver side of things. It's either a JVM bug, or it's a Windows bug.
[10 Nov 2011 2:53] Lucas Still
Is it that, or is the driver not properly keeping the socket "alive" so that it may be closed later? The only reason I ask this is because of the wording in the error message: "MESSAGE: Socket is not connected".

This would lead me to believe that the socket was already "killed" before .close() was even called.
[10 Nov 2011 14:21] Mark Matthews
This message is due to us trying to do Socket.shutdownInput(), which doesn't actually work on our socket wrapper around RandomAccessFile (which is why it's a warning).
[14 Nov 2011 6:14] Bogdan Degtyariov
Mark,

I tried debugging Connector/J and found one interesting thing, which might be helpful:

The method you named (com.mysql.jdbc.NamedPipeSocket.close()) is called after
the exception is thrown.

Here is the stack tracke for the exception:

java.net.SocketException: Socket is not connected
	at java.net.Socket.shutdownInput(Socket.java:1346)
	at com.mysql.jdbc.MysqlIO.quit(MysqlIO.java:1696)
	at com.mysql.jdbc.ConnectionImpl.realClose(ConnectionImpl.java:4371)
	at com.mysql.jdbc.ConnectionImpl.close(ConnectionImpl.java:1556)
	at bug62518.main(bug62518.java:24)

Here is the stack trace for the close() call, which actually closes the pipe:

Thread [main] (Suspended (breakpoint at line 64 in NamedPipeSocketFactory$NamedPipeSocket))	
	NamedPipeSocketFactory$NamedPipeSocket.close()(NamedPipeSocketFactory.java line: 64)
	MysqlIO.forceClose()(MysqlIO.java: 542)
	MysqlIO.quit()(MysqlIO.java: 1710) <-------------- pipe closure
	ConnectionImpl.realClose()(ConnectionImpl.java:4371)	
	ConnectionImpl.close()(ConnectionImpl.java:1556)	
	bug62518.main(String[])(bug62518.java:24)	

Maybe this.mysqlConnection.shutdownInput(); (MysqlIO.java:1696) should not be called at all for pipe connections and let forceClose(); (MysqlIO.java: 1710)
finish the job.
[14 Nov 2011 20:06] Mark Matthews
It's not an exception, it's a log message:

catch (IOException ioEx) {
                        this.connection.getLog().logWarn("Caught while disconnecting...", ioEx);
}

This doesn't prevent the close() of the underlying socket, and thus random access file in the named pipe's case from happening as far as I can see.
[15 Nov 2011 3:48] Bogdan Degtyariov
Thanks Mark, that makes sense. Have to try with C API client and see if a similar problem occurs.
[17 Nov 2011 6:27] Bogdan Degtyariov
MySQL C API client processed the pipe connect/disconnect quite well.
Indeed, mysql_close() function does not return any result or error.

Uploading the C test case below.
[17 Nov 2011 6:28] Bogdan Degtyariov
C test case

Attachment: bug62518.c (text/plain), 1.12 KiB.

[17 Nov 2011 11:08] Bogdan Degtyariov
Another test using C/NET showed no problems as well.

    private void button8_Click(object sender, EventArgs e)
    {
      using (MySqlConnection conn = new MySqlConnection(
       "server=.;protocol=pipe;database=test;User Id=*****;password=******"))
      {
        conn.Open();
        MessageBox.Show("Connection opened");

        // just to see that something is actually going on
        String SQL = "SHOW VARIABLES LIKE '%timeout'"; 
        using (MySqlCommand cmd = new MySqlCommand(SQL, conn))
        {
          cmd.CommandType = System.Data.CommandType.Text;
          MySqlDataReader dr = cmd.ExecuteReader();
          MessageBox.Show("Behold!!!!");

          String cnames = "";
          while (dr.Read())
          {
            cnames += dr[0] + " : " + dr[1] + "\r\n";
          }
          MessageBox.Show("Results: \r\n\r\n" + cnames);
        }
        conn.Close();
        MessageBox.Show("Closed!");
      }

    }
[17 Nov 2011 14:00] Mark Matthews
We can verify that close() is called on the underlying file descriptor, so we'll have to leave this chalked up to a JVM bug, unfortunately.
[17 Nov 2011 14:37] Tonci Grgin
Bogdan, thanks for your efforts. Setting to "Won't Fix" as per Mark's comment.
[31 May 2013 11:43] Vladislav Vaintroub
Why not you just overwrite shutdownSocket() in the custom socket class, so it does nothing?