From 51806c1356f788caa80d2cbcfde46d973cda7865 Mon Sep 17 00:00:00 2001 From: serge-rider Date: Fri, 11 May 2018 23:36:56 +0300 Subject: [PATCH] #3415 Invalidate, connect, disconnect timeouts Former-commit-id: 2c823e619129ce3e67f054120d1e8e5d68b6b29d --- .../dbeaver/ui/dialogs/sql/BaseSQLDialog.java | 6 +- .../editors/content/ContentEditorInput.java | 11 +-- .../org/jkiss/dbeaver/ModelPreferences.java | 8 +++ .../model/impl/jdbc/JDBCDataSource.java | 70 ++++++++++--------- .../dbeaver/model/impl/jdbc/JDBCUtils.java | 53 ++++++++------ .../model/impl/net/HTTPTunnelImpl.java | 3 +- .../model/impl/net/SSLHandlerImpl.java | 3 +- .../model/impl/net/SocksProxyImpl.java | 3 +- .../dbeaver/model/net/DBWNetworkHandler.java | 3 +- .../dbeaver/runtime/jobs/InvalidateJob.java | 3 +- .../dbeaver/model/net/ssh/SSHTunnelImpl.java | 17 ++++- 11 files changed, 111 insertions(+), 69 deletions(-) diff --git a/plugins/org.jkiss.dbeaver.core/src/org/jkiss/dbeaver/ui/dialogs/sql/BaseSQLDialog.java b/plugins/org.jkiss.dbeaver.core/src/org/jkiss/dbeaver/ui/dialogs/sql/BaseSQLDialog.java index bd199c3b53..6487009904 100644 --- a/plugins/org.jkiss.dbeaver.core/src/org/jkiss/dbeaver/ui/dialogs/sql/BaseSQLDialog.java +++ b/plugins/org.jkiss.dbeaver.core/src/org/jkiss/dbeaver/ui/dialogs/sql/BaseSQLDialog.java @@ -160,7 +160,11 @@ public abstract class BaseSQLDialog extends BaseDialog { { try { this.sqlInput.setText(getSQLText()); - sqlViewer.init(subSite, sqlInput); + if (sqlViewer.getSite() != null) { + sqlViewer.setInput(sqlInput); + } else { + sqlViewer.init(subSite, sqlInput); + } sqlViewer.reloadSyntaxRules(); } catch (PartInitException e) { DBUserInterface.getInstance().showError(getShell().getText(), null, e); diff --git a/plugins/org.jkiss.dbeaver.core/src/org/jkiss/dbeaver/ui/editors/content/ContentEditorInput.java b/plugins/org.jkiss.dbeaver.core/src/org/jkiss/dbeaver/ui/editors/content/ContentEditorInput.java index c7109c9b60..69380a5fc4 100644 --- a/plugins/org.jkiss.dbeaver.core/src/org/jkiss/dbeaver/ui/editors/content/ContentEditorInput.java +++ b/plugins/org.jkiss.dbeaver.core/src/org/jkiss/dbeaver/ui/editors/content/ContentEditorInput.java @@ -22,10 +22,7 @@ import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.jface.resource.ImageDescriptor; -import org.eclipse.ui.IEditorPart; -import org.eclipse.ui.IPathEditorInput; -import org.eclipse.ui.IPersistableElement; -import org.eclipse.ui.PartInitException; +import org.eclipse.ui.*; import org.eclipse.ui.editors.text.IEncodingSupport; import org.jkiss.code.Nullable; import org.jkiss.dbeaver.DBException; @@ -390,7 +387,11 @@ public class ContentEditorInput implements IPathEditorInput, DBPContextProvider, this.fileCharset = fileCharset; for (IEditorPart part : editorParts) { try { - part.init(part.getEditorSite(), this); + if (part instanceof IReusableEditor) { + ((IReusableEditor) part).setInput(this); + } else { + part.init(part.getEditorSite(), this); + } } catch (PartInitException e) { log.error("Error refreshing content editor part " + part, e); } diff --git a/plugins/org.jkiss.dbeaver.model/src/org/jkiss/dbeaver/ModelPreferences.java b/plugins/org.jkiss.dbeaver.model/src/org/jkiss/dbeaver/ModelPreferences.java index a7ab92b3de..7cfa8d3c1d 100644 --- a/plugins/org.jkiss.dbeaver.model/src/org/jkiss/dbeaver/ModelPreferences.java +++ b/plugins/org.jkiss.dbeaver.model/src/org/jkiss/dbeaver/ModelPreferences.java @@ -46,6 +46,10 @@ public final class ModelPreferences public static final String EXECUTE_RECOVER_ENABLED = "execute.recover.enabled"; //$NON-NLS-1$ public static final String EXECUTE_RECOVER_RETRY_COUNT = "execute.recover.retryCount"; //$NON-NLS-1$ + public static final String CONNECTION_OPEN_TIMEOUT = "connection.open.timeout"; //$NON-NLS-1$ + public static final String CONNECTION_VALIDATION_TIMEOUT = "connection.validation.timeout"; //$NON-NLS-1$ + public static final String CONNECTION_CLOSE_TIMEOUT = "connection.close.timeout"; //$NON-NLS-1$ + public static final String SCRIPT_STATEMENT_DELIMITER = "script.sql.delimiter"; //$NON-NLS-1$ public static final String SCRIPT_IGNORE_NATIVE_DELIMITER = "script.sql.ignoreNativeDelimiter"; //$NON-NLS-1$ public static final String SCRIPT_STATEMENT_DELIMITER_BLANK = "script.sql.delimiter.blank"; //$NON-NLS-1$ @@ -124,6 +128,10 @@ public final class ModelPreferences PrefUtils.setDefaultPreferenceValue(store, EXECUTE_RECOVER_ENABLED, true); PrefUtils.setDefaultPreferenceValue(store, EXECUTE_RECOVER_RETRY_COUNT, 1); + PrefUtils.setDefaultPreferenceValue(store, CONNECTION_OPEN_TIMEOUT, 20000); + PrefUtils.setDefaultPreferenceValue(store, CONNECTION_VALIDATION_TIMEOUT, 5000); + PrefUtils.setDefaultPreferenceValue(store, CONNECTION_CLOSE_TIMEOUT, 5000); + // SQL execution PrefUtils.setDefaultPreferenceValue(store, SCRIPT_STATEMENT_DELIMITER, SQLConstants.DEFAULT_STATEMENT_DELIMITER); PrefUtils.setDefaultPreferenceValue(store, SCRIPT_IGNORE_NATIVE_DELIMITER, false); diff --git a/plugins/org.jkiss.dbeaver.model/src/org/jkiss/dbeaver/model/impl/jdbc/JDBCDataSource.java b/plugins/org.jkiss.dbeaver.model/src/org/jkiss/dbeaver/model/impl/jdbc/JDBCDataSource.java index 49a3a749e8..efb6beb084 100644 --- a/plugins/org.jkiss.dbeaver.model/src/org/jkiss/dbeaver/model/impl/jdbc/JDBCDataSource.java +++ b/plugins/org.jkiss.dbeaver.model/src/org/jkiss/dbeaver/model/impl/jdbc/JDBCDataSource.java @@ -37,7 +37,6 @@ import org.jkiss.dbeaver.model.impl.jdbc.exec.JDBCFactoryDefault; import org.jkiss.dbeaver.model.messages.ModelMessages; import org.jkiss.dbeaver.model.meta.Property; import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor; -import org.jkiss.dbeaver.model.runtime.DBRRunnableWithProgress; import org.jkiss.dbeaver.model.sql.SQLDataSource; import org.jkiss.dbeaver.model.sql.SQLDialect; import org.jkiss.dbeaver.model.sql.SQLState; @@ -48,7 +47,6 @@ import org.jkiss.dbeaver.utils.GeneralUtils; import org.jkiss.dbeaver.utils.RuntimeUtils; import org.jkiss.utils.CommonUtils; -import java.lang.reflect.InvocationTargetException; import java.net.SocketException; import java.sql.*; import java.util.ArrayList; @@ -74,8 +72,6 @@ public abstract class JDBCDataSource { private static final Log log = Log.getLog(JDBCDataSource.class); - public static final int DISCONNECT_TIMEOUT = 5000; - @NotNull private final DBPDataSourceContainer container; @NotNull @@ -143,22 +139,34 @@ public abstract class JDBCDataSource } } monitor.subTask("Connecting " + purpose); - Connection connection; - if (driverInstance == null) { - connection = DriverManager.getConnection(url, connectProps); - } else { - connection = driverInstance.connect(url, connectProps); + Connection[] connection = new Connection[1]; + Exception[] error = new Exception[1]; + int openTimeout = getContainer().getPreferenceStore().getInt(ModelPreferences.CONNECTION_OPEN_TIMEOUT); + + RuntimeUtils.runTask(monitor1 -> { + try { + if (driverInstance == null) { + connection[0] = DriverManager.getConnection(url, connectProps); + } else { + connection[0] = driverInstance.connect(url, connectProps); + } + } catch (Exception e) { + error[0] = e; + } + }, "Check connection is alive", openTimeout + 2000); + if (error[0] != null) { + throw error[0]; } - if (connection == null) { + if (connection[0] == null) { throw new DBCException("Null connection returned"); } // Set read-only flag if (container.isConnectionReadOnly() && !isConnectionReadOnlyBroken()) { - connection.setReadOnly(true); + connection[0].setReadOnly(true); } - return connection; + return connection[0]; } catch (SQLException ex) { throw new DBCConnectException(ex.getMessage(), ex, this); @@ -216,28 +224,26 @@ public abstract class JDBCDataSource { if (connection != null) { // Close datasource (in async task) - RuntimeUtils.runTask(new DBRRunnableWithProgress() { - @Override - public void run(DBRProgressMonitor monitor) throws InvocationTargetException, InterruptedException { - try { - // If we in transaction - rollback it. - // Any valuable transaction changes should be committed by UI - // so here we do it just in case to avoid error messages on close with open transaction - if (!connection.getAutoCommit()) { - connection.rollback(); - } - } catch (Throwable e) { - // Do not write warning because connection maybe broken before the moment of close - log.debug("Error closing transaction", e); - } - try { - connection.close(); - } - catch (Throwable ex) { - log.error("Error closing connection", ex); + RuntimeUtils.runTask(monitor -> { + try { + // If we in transaction - rollback it. + // Any valuable transaction changes should be committed by UI + // so here we do it just in case to avoid error messages on close with open transaction + if (!connection.getAutoCommit()) { + connection.rollback(); } + } catch (Throwable e) { + // Do not write warning because connection maybe broken before the moment of close + log.debug("Error closing transaction", e); + } + try { + connection.close(); + } + catch (Throwable ex) { + log.error("Error closing connection", ex); } - }, "Close JDBC connection (" + purpose + ")", DISCONNECT_TIMEOUT); + }, "Close JDBC connection (" + purpose + ")", + getContainer().getPreferenceStore().getInt(ModelPreferences.CONNECTION_CLOSE_TIMEOUT)); } } diff --git a/plugins/org.jkiss.dbeaver.model/src/org/jkiss/dbeaver/model/impl/jdbc/JDBCUtils.java b/plugins/org.jkiss.dbeaver.model/src/org/jkiss/dbeaver/model/impl/jdbc/JDBCUtils.java index b3af83ca9d..ba3f1775a1 100644 --- a/plugins/org.jkiss.dbeaver.model/src/org/jkiss/dbeaver/model/impl/jdbc/JDBCUtils.java +++ b/plugins/org.jkiss.dbeaver.model/src/org/jkiss/dbeaver/model/impl/jdbc/JDBCUtils.java @@ -20,6 +20,7 @@ import org.jkiss.code.NotNull; import org.jkiss.code.Nullable; import org.jkiss.dbeaver.DBException; import org.jkiss.dbeaver.Log; +import org.jkiss.dbeaver.ModelPreferences; import org.jkiss.dbeaver.model.DBPDataKind; import org.jkiss.dbeaver.model.DBPDataSource; import org.jkiss.dbeaver.model.DBPDataTypeProvider; @@ -36,6 +37,7 @@ import org.jkiss.dbeaver.model.sql.SQLDataSource; import org.jkiss.dbeaver.model.sql.SQLUtils; import org.jkiss.dbeaver.model.struct.DBSObjectFilter; import org.jkiss.dbeaver.model.struct.rdb.DBSForeignKeyModifyRule; +import org.jkiss.dbeaver.utils.RuntimeUtils; import org.jkiss.utils.CommonUtils; import java.lang.reflect.InvocationTargetException; @@ -50,7 +52,6 @@ import java.util.Map; */ public class JDBCUtils { private static final Log log = Log.getLog(JDBCUtils.class); - public static final int CONNECTION_VALIDATION_TIMEOUT = 5000; private static final Map badColumnNames = new HashMap<>(); @@ -479,30 +480,36 @@ public class JDBCUtils { log.debug(e); return false; } - String testSQL = null; - if (dataSource instanceof SQLDataSource) { - testSQL = ((SQLDataSource) dataSource).getSQLDialect().getTestSQL(); - } - try { - if (!CommonUtils.isEmpty(testSQL)) { - // Execute test SQL - try (Statement dbStat = connection.createStatement()) { - dbStat.execute(testSQL); - } - } else { - try { - return connection.isValid(CONNECTION_VALIDATION_TIMEOUT); - } catch (Throwable e) { - // isValid may be unsupported by driver - // Let's try to read table list - connection.getMetaData().getTables(null, null, "DBEAVER_FAKE_TABLE_NAME_FOR_PING", null); + final String testSQL = (dataSource instanceof SQLDataSource) ? + ((SQLDataSource) dataSource).getSQLDialect().getTestSQL() : null; + int invalidateTimeout = dataSource.getContainer().getPreferenceStore().getInt(ModelPreferences.CONNECTION_VALIDATION_TIMEOUT); + + // Invalidate in non-blocking task. + // Timeout is CONNECTION_VALIDATION_TIMEOUT + 2 seconds + final boolean[] isValid = new boolean[1]; + RuntimeUtils.runTask(monitor -> { + try { + if (!CommonUtils.isEmpty(testSQL)) { + // Execute test SQL + try (Statement dbStat = connection.createStatement()) { + dbStat.execute(testSQL); + isValid[0] = true; + } + } else { + try { + isValid[0] = connection.isValid(invalidateTimeout); + } catch (Throwable e) { + // isValid may be unsupported by driver + // Let's try to read table list + connection.getMetaData().getTables(null, null, "DBEAVER_FAKE_TABLE_NAME_FOR_PING", null); + isValid[0] = true; + } } + } catch (SQLException e) { + isValid[0] = false; } - return true; - } catch (Throwable e1) { - log.debug("Connection seems to be broken", e1); - return false; - } + }, "Check connection is alive", invalidateTimeout + 2000); + return isValid[0]; } public static void scrollResultSet(ResultSet dbResult, long offset, boolean forceFetch) throws SQLException diff --git a/plugins/org.jkiss.dbeaver.model/src/org/jkiss/dbeaver/model/impl/net/HTTPTunnelImpl.java b/plugins/org.jkiss.dbeaver.model/src/org/jkiss/dbeaver/model/impl/net/HTTPTunnelImpl.java index fb5ab7b603..5b43dbc796 100644 --- a/plugins/org.jkiss.dbeaver.model/src/org/jkiss/dbeaver/model/impl/net/HTTPTunnelImpl.java +++ b/plugins/org.jkiss.dbeaver.model/src/org/jkiss/dbeaver/model/impl/net/HTTPTunnelImpl.java @@ -17,6 +17,7 @@ package org.jkiss.dbeaver.model.impl.net; import org.jkiss.dbeaver.DBException; +import org.jkiss.dbeaver.model.DBPDataSource; import org.jkiss.dbeaver.model.app.DBPPlatform; import org.jkiss.dbeaver.model.connection.DBPConnectionConfiguration; import org.jkiss.dbeaver.model.net.DBWHandlerConfiguration; @@ -48,7 +49,7 @@ public class HTTPTunnelImpl implements DBWTunnel { } @Override - public void invalidateHandler(DBRProgressMonitor monitor) throws DBException, IOException { + public void invalidateHandler(DBRProgressMonitor monitor, DBPDataSource dataSource) throws DBException, IOException { } diff --git a/plugins/org.jkiss.dbeaver.model/src/org/jkiss/dbeaver/model/impl/net/SSLHandlerImpl.java b/plugins/org.jkiss.dbeaver.model/src/org/jkiss/dbeaver/model/impl/net/SSLHandlerImpl.java index 8ead6ce921..e1a2d8f0e0 100644 --- a/plugins/org.jkiss.dbeaver.model/src/org/jkiss/dbeaver/model/impl/net/SSLHandlerImpl.java +++ b/plugins/org.jkiss.dbeaver.model/src/org/jkiss/dbeaver/model/impl/net/SSLHandlerImpl.java @@ -17,6 +17,7 @@ package org.jkiss.dbeaver.model.impl.net; import org.jkiss.dbeaver.DBException; +import org.jkiss.dbeaver.model.DBPDataSource; import org.jkiss.dbeaver.model.net.DBWConfigProvider; import org.jkiss.dbeaver.model.net.DBWNetworkHandler; import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor; @@ -28,7 +29,7 @@ import java.io.IOException; */ public class SSLHandlerImpl implements DBWNetworkHandler, DBWConfigProvider { @Override - public void invalidateHandler(DBRProgressMonitor monitor) throws DBException, IOException { + public void invalidateHandler(DBRProgressMonitor monitor, DBPDataSource dataSource) throws DBException, IOException { } } diff --git a/plugins/org.jkiss.dbeaver.model/src/org/jkiss/dbeaver/model/impl/net/SocksProxyImpl.java b/plugins/org.jkiss.dbeaver.model/src/org/jkiss/dbeaver/model/impl/net/SocksProxyImpl.java index bbc3de36cd..98bc8f0864 100644 --- a/plugins/org.jkiss.dbeaver.model/src/org/jkiss/dbeaver/model/impl/net/SocksProxyImpl.java +++ b/plugins/org.jkiss.dbeaver.model/src/org/jkiss/dbeaver/model/impl/net/SocksProxyImpl.java @@ -17,6 +17,7 @@ package org.jkiss.dbeaver.model.impl.net; import org.jkiss.dbeaver.DBException; +import org.jkiss.dbeaver.model.DBPDataSource; import org.jkiss.dbeaver.model.net.DBWNetworkHandler; import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor; @@ -29,7 +30,7 @@ public class SocksProxyImpl implements DBWNetworkHandler { @Override - public void invalidateHandler(DBRProgressMonitor monitor) throws DBException, IOException { + public void invalidateHandler(DBRProgressMonitor monitor, DBPDataSource dataSource) throws DBException, IOException { } } diff --git a/plugins/org.jkiss.dbeaver.model/src/org/jkiss/dbeaver/model/net/DBWNetworkHandler.java b/plugins/org.jkiss.dbeaver.model/src/org/jkiss/dbeaver/model/net/DBWNetworkHandler.java index 6e869a7130..8ae9de6553 100644 --- a/plugins/org.jkiss.dbeaver.model/src/org/jkiss/dbeaver/model/net/DBWNetworkHandler.java +++ b/plugins/org.jkiss.dbeaver.model/src/org/jkiss/dbeaver/model/net/DBWNetworkHandler.java @@ -17,6 +17,7 @@ package org.jkiss.dbeaver.model.net; import org.jkiss.dbeaver.DBException; +import org.jkiss.dbeaver.model.DBPDataSource; import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor; import java.io.IOException; @@ -26,7 +27,7 @@ import java.io.IOException; */ public interface DBWNetworkHandler { - void invalidateHandler(DBRProgressMonitor monitor) + void invalidateHandler(DBRProgressMonitor monitor, DBPDataSource dataSource) throws DBException, IOException; } diff --git a/plugins/org.jkiss.dbeaver.model/src/org/jkiss/dbeaver/runtime/jobs/InvalidateJob.java b/plugins/org.jkiss.dbeaver.model/src/org/jkiss/dbeaver/runtime/jobs/InvalidateJob.java index 1a6f3cc8de..9a6888e85d 100644 --- a/plugins/org.jkiss.dbeaver.model/src/org/jkiss/dbeaver/runtime/jobs/InvalidateJob.java +++ b/plugins/org.jkiss.dbeaver.model/src/org/jkiss/dbeaver/runtime/jobs/InvalidateJob.java @@ -27,7 +27,6 @@ import org.jkiss.dbeaver.model.net.DBWNetworkHandler; import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor; import org.jkiss.dbeaver.runtime.DBeaverNotifications; import org.jkiss.dbeaver.runtime.ui.DBUserInterface; -import org.jkiss.dbeaver.utils.RuntimeUtils; import java.util.ArrayList; import java.util.List; @@ -96,7 +95,7 @@ public class InvalidateJob extends DataSourceJob for (DBWNetworkHandler nh : activeHandlers) { monitor.subTask("Invalidate network [" + container.getName() + "]"); try { - nh.invalidateHandler(monitor); + nh.invalidateHandler(monitor, dataSource); } catch (Exception e) { invalidateResults.add(new ContextInvalidateResult(DBCExecutionContext.InvalidateResult.ERROR, e)); networkOK = false; diff --git a/plugins/org.jkiss.dbeaver.net.ssh/src/org/jkiss/dbeaver/model/net/ssh/SSHTunnelImpl.java b/plugins/org.jkiss.dbeaver.net.ssh/src/org/jkiss/dbeaver/model/net/ssh/SSHTunnelImpl.java index 1f1d156d38..f2ca3adf61 100644 --- a/plugins/org.jkiss.dbeaver.net.ssh/src/org/jkiss/dbeaver/model/net/ssh/SSHTunnelImpl.java +++ b/plugins/org.jkiss.dbeaver.net.ssh/src/org/jkiss/dbeaver/model/net/ssh/SSHTunnelImpl.java @@ -17,6 +17,9 @@ package org.jkiss.dbeaver.model.net.ssh; import org.jkiss.dbeaver.DBException; +import org.jkiss.dbeaver.Log; +import org.jkiss.dbeaver.ModelPreferences; +import org.jkiss.dbeaver.model.DBPDataSource; import org.jkiss.dbeaver.model.app.DBPPlatform; import org.jkiss.dbeaver.model.connection.DBPConnectionConfiguration; import org.jkiss.dbeaver.model.net.DBWHandlerConfiguration; @@ -24,6 +27,7 @@ import org.jkiss.dbeaver.model.net.DBWTunnel; import org.jkiss.dbeaver.model.net.ssh.registry.SSHImplementationDescriptor; import org.jkiss.dbeaver.model.net.ssh.registry.SSHImplementationRegistry; import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor; +import org.jkiss.dbeaver.utils.RuntimeUtils; import org.jkiss.utils.CommonUtils; import java.io.IOException; @@ -34,6 +38,7 @@ import java.util.Map; */ public class SSHTunnelImpl implements DBWTunnel { + private static final Log log = Log.getLog(SSHTunnelImpl.class); private static final String DEF_IMPLEMENTATION = "jsch"; private SSHImplementation implementation; @@ -97,9 +102,17 @@ public class SSHTunnelImpl implements DBWTunnel { } @Override - public void invalidateHandler(DBRProgressMonitor monitor) throws DBException, IOException { + public void invalidateHandler(DBRProgressMonitor monitor, DBPDataSource dataSource) throws DBException, IOException { if (implementation != null) { - implementation.invalidateTunnel(monitor); + RuntimeUtils.runTask(monitor1 -> { + try { + implementation.invalidateTunnel(monitor1); + } catch (Exception e) { + log.error("Error invalidating SSH tunnel", e); + } + }, + "Check connection is alive", + dataSource.getContainer().getPreferenceStore().getInt(ModelPreferences.CONNECTION_VALIDATION_TIMEOUT)); } } -- GitLab