mirror of https://github.com/apache/druid.git
do not explode if mysql transient exception class does not exist (#12213)
Follow up to #12205 to allow druid-mysql-extensions to work with mysql connector/j 8.x again, which does not contain MySQLTransientException, and while would have had the same problem as mariadb if a transient exception was checked, the new check eagerly loads the class when starting up, causing immediate failure.
This commit is contained in:
parent
c4fa3ccfc4
commit
978b8f7dde
|
@ -19,7 +19,6 @@
|
||||||
|
|
||||||
package org.apache.druid.metadata.storage.mysql;
|
package org.apache.druid.metadata.storage.mysql;
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
|
||||||
import com.google.common.base.Joiner;
|
import com.google.common.base.Joiner;
|
||||||
import com.google.common.base.Supplier;
|
import com.google.common.base.Supplier;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
|
@ -62,10 +61,10 @@ public class MySQLConnector extends SQLMetadataConnector
|
||||||
{
|
{
|
||||||
super(config, dbTables);
|
super(config, dbTables);
|
||||||
log.info("Loading \"MySQL\" metadata connector driver %s", driverConfig.getDriverClassName());
|
log.info("Loading \"MySQL\" metadata connector driver %s", driverConfig.getDriverClassName());
|
||||||
tryLoadDriverClass(driverConfig.getDriverClassName());
|
tryLoadDriverClass(driverConfig.getDriverClassName(), true);
|
||||||
|
|
||||||
if (driverConfig.getDriverClassName().contains("mysql")) {
|
if (driverConfig.getDriverClassName().contains("mysql")) {
|
||||||
myTransientExceptionClass = tryLoadDriverClass(MYSQL_TRANSIENT_EXCEPTION_CLASS_NAME);
|
myTransientExceptionClass = tryLoadDriverClass(MYSQL_TRANSIENT_EXCEPTION_CLASS_NAME, false);
|
||||||
} else {
|
} else {
|
||||||
myTransientExceptionClass = null;
|
myTransientExceptionClass = null;
|
||||||
}
|
}
|
||||||
|
@ -205,7 +204,11 @@ public class MySQLConnector extends SQLMetadataConnector
|
||||||
@Override
|
@Override
|
||||||
protected boolean connectorIsTransientException(Throwable e)
|
protected boolean connectorIsTransientException(Throwable e)
|
||||||
{
|
{
|
||||||
return isTransientException(myTransientExceptionClass, e);
|
if (myTransientExceptionClass != null) {
|
||||||
|
return myTransientExceptionClass.isAssignableFrom(e.getClass())
|
||||||
|
|| e instanceof SQLException && ((SQLException) e).getErrorCode() == 1317 /* ER_QUERY_INTERRUPTED */;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -241,28 +244,23 @@ public class MySQLConnector extends SQLMetadataConnector
|
||||||
return dbi;
|
return dbi;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Class<?> tryLoadDriverClass(String className)
|
@Nullable
|
||||||
|
private Class<?> tryLoadDriverClass(String className, boolean failIfNotFound)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
return Class.forName(className, false, getClass().getClassLoader());
|
return Class.forName(className, false, getClass().getClassLoader());
|
||||||
}
|
}
|
||||||
catch (ClassNotFoundException e) {
|
catch (ClassNotFoundException e) {
|
||||||
throw new ISE(e, "Could not find %s on the classpath. The MySQL Connector library is not included in the Druid "
|
if (failIfNotFound) {
|
||||||
+ "distribution but is required to use MySQL. Please download a compatible library (for example "
|
throw new ISE(e, "Could not find %s on the classpath. The MySQL Connector library is not included in the Druid "
|
||||||
+ "'mysql-connector-java-5.1.48.jar') and place it under 'extensions/mysql-metadata-storage/'. See "
|
+ "distribution but is required to use MySQL. Please download a compatible library (for example "
|
||||||
+ "https://druid.apache.org/downloads for more details.",
|
+ "'mysql-connector-java-5.1.48.jar') and place it under 'extensions/mysql-metadata-storage/'. See "
|
||||||
className
|
+ "https://druid.apache.org/downloads for more details.",
|
||||||
);
|
className
|
||||||
|
);
|
||||||
|
}
|
||||||
|
log.warn("Could not find %s on the classpath.", className);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
|
||||||
static boolean isTransientException(@Nullable Class<?> driverClazz, Throwable e)
|
|
||||||
{
|
|
||||||
if (driverClazz != null) {
|
|
||||||
return driverClazz.isAssignableFrom(e.getClass())
|
|
||||||
|| e instanceof SQLException && ((SQLException) e).getErrorCode() == 1317 /* ER_QUERY_INTERRUPTED */;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,8 +19,11 @@
|
||||||
|
|
||||||
package org.apache.druid.metadata.storage.mysql;
|
package org.apache.druid.metadata.storage.mysql;
|
||||||
|
|
||||||
|
import com.google.common.base.Supplier;
|
||||||
import com.mysql.jdbc.exceptions.MySQLTransactionRollbackException;
|
import com.mysql.jdbc.exceptions.MySQLTransactionRollbackException;
|
||||||
import com.mysql.jdbc.exceptions.MySQLTransientException;
|
import com.mysql.jdbc.exceptions.MySQLTransientException;
|
||||||
|
import org.apache.druid.metadata.MetadataStorageConnectorConfig;
|
||||||
|
import org.apache.druid.metadata.MetadataStorageTablesConfig;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
@ -29,37 +32,63 @@ import java.sql.SQLTransientConnectionException;
|
||||||
|
|
||||||
public class MySQLConnectorTest
|
public class MySQLConnectorTest
|
||||||
{
|
{
|
||||||
@Test
|
private static final MySQLConnectorDriverConfig MYSQL_DRIVER_CONFIG = new MySQLConnectorDriverConfig();
|
||||||
public void testIsExceptionTransient()
|
private static final MySQLConnectorDriverConfig MARIADB_DRIVER_CONFIG = new MySQLConnectorDriverConfig()
|
||||||
{
|
{
|
||||||
final Class<?> clazz = MySQLTransientException.class;
|
@Override
|
||||||
Assert.assertTrue(MySQLConnector.isTransientException(clazz, new MySQLTransientException()));
|
public String getDriverClassName()
|
||||||
Assert.assertTrue(MySQLConnector.isTransientException(clazz, new MySQLTransactionRollbackException()));
|
{
|
||||||
|
return "org.mariadb.jdbc.Driver";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
private static final Supplier<MetadataStorageConnectorConfig> CONNECTOR_CONFIG_SUPPLIER =
|
||||||
|
MetadataStorageConnectorConfig::new;
|
||||||
|
private static final Supplier<MetadataStorageTablesConfig> TABLES_CONFIG_SUPPLIER =
|
||||||
|
() -> new MetadataStorageTablesConfig(null, null, null, null, null, null, null, null, null, null, null);
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsExceptionTransientMySql()
|
||||||
|
{
|
||||||
|
MySQLConnector connector = new MySQLConnector(
|
||||||
|
CONNECTOR_CONFIG_SUPPLIER,
|
||||||
|
TABLES_CONFIG_SUPPLIER,
|
||||||
|
new MySQLConnectorSslConfig(),
|
||||||
|
MYSQL_DRIVER_CONFIG
|
||||||
|
);
|
||||||
|
Assert.assertTrue(connector.connectorIsTransientException(new MySQLTransientException()));
|
||||||
|
Assert.assertTrue(connector.connectorIsTransientException(new MySQLTransactionRollbackException()));
|
||||||
Assert.assertTrue(
|
Assert.assertTrue(
|
||||||
MySQLConnector.isTransientException(clazz, new SQLException("some transient failure", "wtf", 1317))
|
connector.connectorIsTransientException(new SQLException("some transient failure", "wtf", 1317))
|
||||||
);
|
);
|
||||||
Assert.assertFalse(
|
Assert.assertFalse(
|
||||||
MySQLConnector.isTransientException(clazz, new SQLException("totally realistic test data", "wtf", 1337))
|
connector.connectorIsTransientException(new SQLException("totally realistic test data", "wtf", 1337))
|
||||||
);
|
);
|
||||||
// this method does not specially handle normal transient exceptions either, since it is not vendor specific
|
// this method does not specially handle normal transient exceptions either, since it is not vendor specific
|
||||||
Assert.assertFalse(
|
Assert.assertFalse(
|
||||||
MySQLConnector.isTransientException(clazz, new SQLTransientConnectionException("transient"))
|
connector.connectorIsTransientException(new SQLTransientConnectionException("transient"))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testIsExceptionTransientNoMySqlClazz()
|
public void testIsExceptionTransientNoMySqlClazz()
|
||||||
{
|
{
|
||||||
|
MySQLConnector connector = new MySQLConnector(
|
||||||
|
CONNECTOR_CONFIG_SUPPLIER,
|
||||||
|
TABLES_CONFIG_SUPPLIER,
|
||||||
|
new MySQLConnectorSslConfig(),
|
||||||
|
MARIADB_DRIVER_CONFIG
|
||||||
|
);
|
||||||
// no vendor specific for MariaDb, so should always be false
|
// no vendor specific for MariaDb, so should always be false
|
||||||
Assert.assertFalse(MySQLConnector.isTransientException(null, new MySQLTransientException()));
|
Assert.assertFalse(connector.connectorIsTransientException(new MySQLTransientException()));
|
||||||
Assert.assertFalse(
|
Assert.assertFalse(
|
||||||
MySQLConnector.isTransientException(null, new SQLException("some transient failure", "wtf", 1317))
|
connector.connectorIsTransientException(new SQLException("some transient failure", "wtf", 1317))
|
||||||
);
|
);
|
||||||
Assert.assertFalse(
|
Assert.assertFalse(
|
||||||
MySQLConnector.isTransientException(null, new SQLException("totally realistic test data", "wtf", 1337))
|
connector.connectorIsTransientException(new SQLException("totally realistic test data", "wtf", 1337))
|
||||||
);
|
);
|
||||||
Assert.assertFalse(
|
Assert.assertFalse(
|
||||||
MySQLConnector.isTransientException(null, new SQLTransientConnectionException("transient"))
|
connector.connectorIsTransientException(new SQLTransientConnectionException("transient"))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue