From 2e55b07b6466d50eea88e025febc5988e39e7d87 Mon Sep 17 00:00:00 2001 From: kolzeq Date: Mon, 26 Jul 2021 17:17:42 +0200 Subject: [PATCH] [CONJ-884] ensure pool state when connection error occurs --- .../mariadb/jdbc/MariaDbPooledConnection.java | 8 +- .../org/mariadb/jdbc/MariaDbStatement.java | 81 ++++++++++--------- .../util/exceptions/ExceptionFactory.java | 5 +- .../mariadb/jdbc/internal/util/pool/Pool.java | 12 ++- 4 files changed, 60 insertions(+), 46 deletions(-) diff --git a/src/main/java/org/mariadb/jdbc/MariaDbPooledConnection.java b/src/main/java/org/mariadb/jdbc/MariaDbPooledConnection.java index b07486d38..577e95178 100644 --- a/src/main/java/org/mariadb/jdbc/MariaDbPooledConnection.java +++ b/src/main/java/org/mariadb/jdbc/MariaDbPooledConnection.java @@ -191,7 +191,7 @@ public void fireStatementClosed(Statement st) { * @param st statement * @param ex exception */ - public void fireStatementErrorOccured(Statement st, SQLException ex) { + public void fireStatementErrorOccurred(Statement st, SQLException ex) { if (st instanceof PreparedStatement) { StatementEvent event = new StatementEvent(this, (PreparedStatement) st, ex); for (StatementEventListener listener : statementEventListeners) { @@ -213,7 +213,7 @@ public void fireConnectionClosed() { * * @param ex exception */ - public void fireConnectionErrorOccured(SQLException ex) { + public void fireConnectionErrorOccurred(SQLException ex) { ConnectionEvent event = new ConnectionEvent(this, ex); for (ConnectionEventListener listener : connectionEventListeners) { listener.connectionErrorOccurred(event); @@ -242,4 +242,8 @@ public AtomicLong getLastUsed() { public void lastUsedToNow() { lastUsed.set(System.nanoTime()); } + + public void ensureValidation() { + lastUsed.set(0); + } } diff --git a/src/main/java/org/mariadb/jdbc/MariaDbStatement.java b/src/main/java/org/mariadb/jdbc/MariaDbStatement.java index 973c045d5..890eb820f 100755 --- a/src/main/java/org/mariadb/jdbc/MariaDbStatement.java +++ b/src/main/java/org/mariadb/jdbc/MariaDbStatement.java @@ -245,35 +245,37 @@ private void stopTimeoutTask() { * @return SQLException exception with new message in case of timer timeout. */ protected SQLException executeExceptionEpilogue(SQLException sqle) { - // if has a failover, closing the statement - if (sqle.getSQLState() != null && sqle.getSQLState().startsWith("08")) { - try { - close(); - } catch (SQLException sqlee) { - // eat exception + try { + if (sqle.getErrorCode() == 1148 && !options.allowLocalInfile) { + return exceptionFactory + .raiseStatementError(connection, this) + .create( + "Usage of LOCAL INFILE is disabled. To use it enable it via the connection property allowLocalInfile=true", + "42000", + 1148, + sqle); } - } - if (sqle.getErrorCode() == 1148 && !options.allowLocalInfile) { - return exceptionFactory - .raiseStatementError(connection, this) - .create( - "Usage of LOCAL INFILE is disabled. " - + "To use it enable it via the connection property allowLocalInfile=true", - "42000", - 1148, - sqle); - } + if (isTimedout) { + return exceptionFactory + .raiseStatementError(connection, this) + .create("Query timed out", "70100", 1317, sqle); + } - if (isTimedout) { - return exceptionFactory - .raiseStatementError(connection, this) - .create("Query timed out", "70100", 1317, sqle); - } + SQLException sqlException = exceptionFactory.raiseStatementError(connection, this).create(sqle); + logger.error("error executing query", sqlException); + return sqlException; + } finally { + // if has a failover, closing the statement + if (sqle.getSQLState() != null && sqle.getSQLState().startsWith("08")) { + try { + close(); + } catch (SQLException sqlee) { + // eat exception + } + } - SQLException sqlException = exceptionFactory.raiseStatementError(connection, this).create(sqle); - logger.error("error executing query", sqlException); - return sqlException; + } } protected void executeEpilogue() { @@ -290,22 +292,23 @@ protected void executeBatchEpilogue() { } private SQLException handleFailoverAndTimeout(SQLException sqle) { - - // if has a failover, closing the statement - if (sqle.getSQLState() != null && sqle.getSQLState().startsWith("08")) { - try { - close(); - } catch (SQLException sqlee) { - // eat exception + try { + if (isTimedout) { + return exceptionFactory + .raiseStatementError(connection, this) + .create("Query timed out", "70100", 1317, sqle); + } + return sqle; + } finally { + // if has a failover, closing the statement + if (sqle.getSQLState() != null && sqle.getSQLState().startsWith("08")) { + try { + close(); + } catch (SQLException sqlee) { + // eat exception + } } } - - if (isTimedout) { - return exceptionFactory - .raiseStatementError(connection, this) - .create("Query timed out", "70100", 1317, sqle); - } - return sqle; } protected BatchUpdateException executeBatchExceptionEpilogue(SQLException initialSqle, int size) { diff --git a/src/main/java/org/mariadb/jdbc/internal/util/exceptions/ExceptionFactory.java b/src/main/java/org/mariadb/jdbc/internal/util/exceptions/ExceptionFactory.java index dfd3d602f..2396a5d7b 100644 --- a/src/main/java/org/mariadb/jdbc/internal/util/exceptions/ExceptionFactory.java +++ b/src/main/java/org/mariadb/jdbc/internal/util/exceptions/ExceptionFactory.java @@ -81,7 +81,10 @@ private static SQLException createException( } if (connection != null && connection.pooledConnection != null) { - connection.pooledConnection.fireStatementErrorOccured(statement, returnEx); + connection.pooledConnection.fireStatementErrorOccurred(statement, returnEx); + if (returnEx instanceof SQLNonTransientConnectionException) { + connection.pooledConnection.fireConnectionErrorOccurred(returnEx); + } } return returnEx; } diff --git a/src/main/java/org/mariadb/jdbc/internal/util/pool/Pool.java b/src/main/java/org/mariadb/jdbc/internal/util/pool/Pool.java index 22526abb6..dc7948812 100644 --- a/src/main/java/org/mariadb/jdbc/internal/util/pool/Pool.java +++ b/src/main/java/org/mariadb/jdbc/internal/util/pool/Pool.java @@ -357,12 +357,16 @@ public void connectionClosed(ConnectionEvent event) { @Override public void connectionErrorOccurred(ConnectionEvent event) { - MariaDbPooledConnection item = ((MariaDbPooledConnection) event.getSource()); - if (idleConnections.remove(item)) { - totalConnection.decrementAndGet(); - } + totalConnection.decrementAndGet(); + // if occurs when idle, remove from list + idleConnections.remove(item); silentCloseConnection(item); + + // ensure that other connection will be validated before being use + // since one connection failed, better to assume the other might as well + idleConnections.stream().forEach(c -> c.lastUsedToNow()); + addConnectionRequest(); logger.debug( "connection {} removed from pool {} due to having throw a Connection exception (total:{}, active:{}, pending:{})",