Skip to content

Commit 509f184

Browse files
committed
Fix for Bug#28725534, MULTI HOST CONNECTION WOULD BLOCK IN CONNECTION POOLING.
1 parent ed64a73 commit 509f184

File tree

5 files changed

+80
-43
lines changed

5 files changed

+80
-43
lines changed

CHANGES

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
Version 8.0.27
55

6+
- Fix for Bug#28725534, MULTI HOST CONNECTION WOULD BLOCK IN CONNECTION POOLING.
7+
68
- Fix for Bug#95139 (29807572), CACHESERVERCONFIGURATION APPEARS TO THWART CHARSET DETECTION.
79

810
- Fix for Bug#104641 (33237255), DatabaseMetaData.getImportedKeys can return duplicated foreign keys.

src/main/user-impl/java/com/mysql/cj/jdbc/ha/FailoverConnectionProxy.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2010, 2020, Oracle and/or its affiliates.
2+
* Copyright (c) 2010, 2021, Oracle and/or its affiliates.
33
*
44
* This program is free software; you can redistribute it and/or modify it under
55
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -499,7 +499,7 @@ synchronized void doAbort(Executor executor) throws SQLException {
499499
* This is the continuation of MultiHostConnectionProxy#invoke(Object, Method, Object[]).
500500
*/
501501
@Override
502-
public synchronized Object invokeMore(Object proxy, Method method, Object[] args) throws Throwable {
502+
public Object invokeMore(Object proxy, Method method, Object[] args) throws Throwable {
503503
String methodName = method.getName();
504504

505505
if (METHOD_SET_READ_ONLY.equals(methodName)) {

src/main/user-impl/java/com/mysql/cj/jdbc/ha/LoadBalancedConnectionProxy.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2007, 2020, Oracle and/or its affiliates.
2+
* Copyright (c) 2007, 2021, Oracle and/or its affiliates.
33
*
44
* This program is free software; you can redistribute it and/or modify it under
55
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -536,7 +536,7 @@ synchronized void doAbort(Executor executor) {
536536
* This is the continuation of MultiHostConnectionProxy#invoke(Object, Method, Object[]).
537537
*/
538538
@Override
539-
public synchronized Object invokeMore(Object proxy, Method method, Object[] args) throws Throwable {
539+
Object invokeMore(Object proxy, Method method, Object[] args) throws Throwable {
540540
String methodName = method.getName();
541541

542542
if (this.isClosed && !allowedOnClosedConnection(method) && method.getExceptionTypes().length > 0) { // TODO remove method.getExceptionTypes().length ?

src/main/user-impl/java/com/mysql/cj/jdbc/ha/MultiHostConnectionProxy.java

Lines changed: 41 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2015, 2020, Oracle and/or its affiliates.
2+
* Copyright (c) 2015, 2021, Oracle and/or its affiliates.
33
*
44
* This program is free software; you can redistribute it and/or modify it under
55
* the terms of the GNU General Public License, version 2.0, as published by the
@@ -54,7 +54,6 @@
5454
public abstract class MultiHostConnectionProxy implements InvocationHandler {
5555
private static final String METHOD_GET_MULTI_HOST_SAFE_PROXY = "getMultiHostSafeProxy";
5656
private static final String METHOD_EQUALS = "equals";
57-
private static final String METHOD_HASH_CODE = "hashCode";
5857
private static final String METHOD_CLOSE = "close";
5958
private static final String METHOD_ABORT_INTERNAL = "abortInternal";
6059
private static final String METHOD_ABORT = "abort";
@@ -466,7 +465,7 @@ void syncSessionState(JdbcConnection source, JdbcConnection target, boolean read
466465
* if an error occurs
467466
*/
468467
@Override
469-
public synchronized Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
468+
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
470469
String methodName = method.getName();
471470

472471
if (METHOD_GET_MULTI_HOST_SAFE_PROXY.equals(methodName)) {
@@ -478,50 +477,53 @@ public synchronized Object invoke(Object proxy, Method method, Object[] args) th
478477
return args[0].equals(this);
479478
}
480479

481-
if (METHOD_HASH_CODE.equals(methodName)) {
482-
return this.hashCode();
480+
// Execute remaining ubiquitous methods right away.
481+
if (method.getDeclaringClass().equals(Object.class)) {
482+
return method.invoke(this, args);
483483
}
484484

485-
if (METHOD_CLOSE.equals(methodName)) {
486-
doClose();
487-
this.isClosed = true;
488-
this.closedReason = "Connection explicitly closed.";
489-
this.closedExplicitly = true;
490-
return null;
491-
}
485+
synchronized (this) {
486+
if (METHOD_CLOSE.equals(methodName)) {
487+
doClose();
488+
this.isClosed = true;
489+
this.closedReason = "Connection explicitly closed.";
490+
this.closedExplicitly = true;
491+
return null;
492+
}
492493

493-
if (METHOD_ABORT_INTERNAL.equals(methodName)) {
494-
doAbortInternal();
495-
this.currentConnection.abortInternal();
496-
this.isClosed = true;
497-
this.closedReason = "Connection explicitly closed.";
498-
return null;
499-
}
494+
if (METHOD_ABORT_INTERNAL.equals(methodName)) {
495+
doAbortInternal();
496+
this.currentConnection.abortInternal();
497+
this.isClosed = true;
498+
this.closedReason = "Connection explicitly closed.";
499+
return null;
500+
}
500501

501-
if (METHOD_ABORT.equals(methodName) && args.length == 1) {
502-
doAbort((Executor) args[0]);
503-
this.isClosed = true;
504-
this.closedReason = "Connection explicitly closed.";
505-
return null;
506-
}
502+
if (METHOD_ABORT.equals(methodName) && args.length == 1) {
503+
doAbort((Executor) args[0]);
504+
this.isClosed = true;
505+
this.closedReason = "Connection explicitly closed.";
506+
return null;
507+
}
507508

508-
if (METHOD_IS_CLOSED.equals(methodName)) {
509-
return this.isClosed;
510-
}
509+
if (METHOD_IS_CLOSED.equals(methodName)) {
510+
return this.isClosed;
511+
}
511512

512-
try {
513-
return invokeMore(proxy, method, args);
514-
} catch (InvocationTargetException e) {
515-
throw e.getCause() != null ? e.getCause() : e;
516-
} catch (Exception e) {
517-
// Check if the captured exception must be wrapped by an unchecked exception.
518-
Class<?>[] declaredException = method.getExceptionTypes();
519-
for (Class<?> declEx : declaredException) {
520-
if (declEx.isAssignableFrom(e.getClass())) {
521-
throw e;
513+
try {
514+
return invokeMore(proxy, method, args);
515+
} catch (InvocationTargetException e) {
516+
throw e.getCause() != null ? e.getCause() : e;
517+
} catch (Exception e) {
518+
// Check if the captured exception must be wrapped by an unchecked exception.
519+
Class<?>[] declaredException = method.getExceptionTypes();
520+
for (Class<?> declEx : declaredException) {
521+
if (declEx.isAssignableFrom(e.getClass())) {
522+
throw e;
523+
}
522524
}
525+
throw new IllegalStateException(e.getMessage(), e);
523526
}
524-
throw new IllegalStateException(e.getMessage(), e);
525527
}
526528
}
527529

src/test/java/testsuite/regression/ConnectionRegressionTest.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11502,4 +11502,37 @@ public void testBug95564() throws Exception {
1150211502
this.stmt.executeUpdate("DROP DATABASE IF EXISTS " + StringUtils.quoteIdentifier(databaseName, true));
1150311503
}
1150411504
}
11505+
11506+
/**
11507+
* Tests fix for Bug#28725534, MULTI HOST CONNECTION WOULD BLOCK IN CONNECTION POOLING.
11508+
*
11509+
* @throws Exception
11510+
*/
11511+
@Test
11512+
public void testBug28725534() throws Exception {
11513+
final Connection testConn = getFailoverConnection();
11514+
11515+
ExecutorService slowQueryExecutor = Executors.newSingleThreadExecutor();
11516+
slowQueryExecutor.execute(() -> {
11517+
try {
11518+
testConn.createStatement().executeQuery("SELECT SLEEP(3)");
11519+
} catch (SQLException e) {
11520+
fail("failed executing SLEEP()");
11521+
}
11522+
});
11523+
11524+
TimeUnit.SECONDS.sleep(1); // Give it some time to start the slow query.
11525+
11526+
long start = System.currentTimeMillis();
11527+
testConn.equals(testConn);
11528+
testConn.toString();
11529+
testConn.hashCode();
11530+
long end = System.currentTimeMillis();
11531+
11532+
slowQueryExecutor.shutdown();
11533+
slowQueryExecutor.awaitTermination(3, TimeUnit.SECONDS);
11534+
testConn.close();
11535+
11536+
assertTrue(end - start < 250, ".equals() took too long to exectute, the method is being locked by a synchronized block.");
11537+
}
1150511538
}

0 commit comments

Comments
 (0)