[CONJ-693] Connection leak when executing query with invalid parameters Created: 2019-03-13  Updated: 2021-05-17  Resolved: 2021-05-17

Status: Closed
Project: MariaDB Connector/J
Component/s: protocol
Affects Version/s: 2.4.0
Fix Version/s: N/A

Type: Bug Priority: Major
Reporter: Maciej Zieniuk Assignee: Diego Dupin
Resolution: Fixed Votes: 0
Labels: None


 Description   

Happens when running in sequential HA mode with Client Prepared Statement in a transaction.

Create prepared statement and bind parameter to non-serializable object:

try(PreparedStatement statement = connection.prepareStatement("SELECT * FROM test WHERE column = ?"))
{
    statement.setObject(1, new Object());
    statement.execute();
}

Executing such query and writing parameters into the OutputStream (i.e. when calling "ComQuery.sendSubCmd"), results in "java.io.NotSerializableException: java.lang.Object".

Stack trace:

java.io.NotSerializableException: java.lang.Object
	at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
	at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
	at org.mariadb.jdbc.internal.com.send.parameters.SerializableParameter.writeObjectToBytes(SerializableParameter.java:91)
	at org.mariadb.jdbc.internal.com.send.parameters.SerializableParameter.writeTo(SerializableParameter.java:80)
	at org.mariadb.jdbc.internal.com.send.ComQuery.sendSubCmd(ComQuery.java:85)
	at org.mariadb.jdbc.internal.protocol.AbstractQueryProtocol.executeQuery(AbstractQueryProtocol.java:285)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.mariadb.jdbc.internal.failover.AbstractMastersListener.invoke(AbstractMastersListener.java:398)
	at org.mariadb.jdbc.internal.failover.FailoverProxy.executeInvocation(FailoverProxy.java:278)
	at org.mariadb.jdbc.internal.failover.FailoverProxy.invoke(FailoverProxy.java:270)
	at com.sun.proxy.$Proxy8.executeQuery(Unknown Source)
	at org.mariadb.jdbc.ClientSidePreparedStatement.executeInternal(ClientSidePreparedStatement.java:221)
	at org.mariadb.jdbc.ClientSidePreparedStatement.execute(ClientSidePreparedStatement.java:157)
	at org.mariadb.jdbc.ClientSidePreparedStatement.executeUpdate(ClientSidePreparedStatement.java:192)

What is happening:

  1. "AbstractQueryProtocol.handleIoException" method will mark the protocol as not connected, via: "connected = false;"
  2. FailoverProxy.executeInvocation catches the exception and enters the block:

              if (hasToHandleFailover(queryException)) {
                return handleFailOver(queryException, method, args, protocol);
              }
    

  3. MastersFailoverLustener.primaryFail will reconnect with a new protocol, but because the protocol returns false on "currentProtocol.isConnected()", existing protocol is not closed.

      @Override
      public HandleErrorResult primaryFail(Method method, Object[] args, boolean killCmd) {
        boolean alreadyClosed = !currentProtocol.isConnected();
        boolean inTransaction = currentProtocol != null && currentProtocol.inTransaction();
     
        if (currentProtocol.isConnected()) {
          currentProtocol.close();
        }
     
        try {
          reconnectFailedConnection(new SearchFilter(true, false));
    

  4. During reconnection in "reconnectFailedConnection" method, "MastersFailoverListener.foundActiveMaster" method is called, which override current protocol's reference, without closing existing one, as "currentProtocol.isClosed()" returns true

          if (currentProtocol != null && !currentProtocol.isClosed()) {
            currentProtocol.close();
          }
          currentProtocol = protocol;
    

Results in hanging open connection to database every time you run into above scenario. Calling "close" on the Connection, does not close the old protocol.

I would expect that "AbstractQueryProtocol.handleIoException" method to not assume that IOExceptions is due to connection being broken and actually close the protocol and not just flag it as "closed".



 Comments   
Comment by Diego Dupin [ 2021-05-17 ]

fixed with https://jira.mariadb.org/browse/CONJ-849

Generated at Thu Feb 08 03:17:37 UTC 2024 using Jira 8.20.16#820016-sha1:9d11dbea5f4be3d4cc21f03a88dd11d8c8687422.