提交 601d7c52 编写于 作者: J jurgen

Txn close & disconnect in detached job to avoid UI freeze

Former-commit-id: 2a01f488
上级 533a5a44
......@@ -140,32 +140,6 @@ public class ApplicationWorkbenchAdvisor extends WorkbenchAdvisor
if (!closeActiveTransactions()) {
return false;
}
/*
final IWorkbenchWindow workbenchWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
DBRProgressMonitor nullMonitor = VoidProgressMonitor.INSTANCE;
for (IWorkbenchPage workbenchPage : workbenchWindow.getPages()) {
for (IEditorReference editorRef : workbenchPage.getEditorReferences()) {
try {
if (editorRef.getEditor(false) == null) {
continue;
}
IEditorInput editorInput = editorRef.getEditorInput();
if (editorInput instanceof IAutoSaveEditorInput && ((IAutoSaveEditorInput) editorInput).isAutoSaveEnabled()) {
IEditorPart editor = editorRef.getEditor(false);
if (editor != null) {
if (!RuntimeUtils.validateAndSave(nullMonitor, editor)) {
return false;
}
}
}
} catch (CoreException ex) {
log.error("Can't obtain editor storage", ex); //$NON-NLS-1$
}
}
}
*/
return true;
}
......
......@@ -81,6 +81,8 @@ public class DataSourceDescriptor
{
static final Log log = Log.getLog(DataSourceDescriptor.class);
public static final int END_TRANSACTION_WAIT_TIME = 3000;
public static class FilterMapping {
public final Class<?> type;
public DBSObjectFilter defaultFilter;
......@@ -864,62 +866,67 @@ public class DataSourceDescriptor
}
// First rollback active transaction
monitor.subTask("Rollback active transaction");
DBCTransactionManager txnManager = DBUtils.getTransactionManager(dataSource);
try {
if (txnManager != null && !txnManager.isAutoCommit()) {
// Check current transaction
// If there are some executions in last savepoint then ask user about commit/rollback
QMMCollector qmm = DBeaverCore.getInstance().getQueryManager().getMetaCollector();
if (qmm != null) {
QMMSessionInfo qmmSession = qmm.getSessionInfo(dataSource);
QMMTransactionInfo txn = qmmSession == null ? null : qmmSession.getTransaction();
QMMTransactionSavepointInfo sp = txn == null ? null : txn.getCurrentSavepoint();
if (sp != null && (sp.getPrevious() != null || sp.getLastExecute() != null)) {
boolean hasUserExec = false;
if (true) {
// Do not check whether we have user queries, just ask for confirmation
hasUserExec = true;
} else {
for (QMMTransactionSavepointInfo psp = sp; psp != null; psp = psp.getPrevious()) {
if (psp.hasUserExecutions()) {
hasUserExec = true;
break;
}
if (txnManager == null || txnManager.isAutoCommit()) {
return true;
}
// If there are some executions in last savepoint then ask user about commit/rollback
QMMCollector qmm = DBeaverCore.getInstance().getQueryManager().getMetaCollector();
if (qmm != null) {
QMMSessionInfo qmmSession = qmm.getSessionInfo(dataSource);
QMMTransactionInfo txn = qmmSession == null ? null : qmmSession.getTransaction();
QMMTransactionSavepointInfo sp = txn == null ? null : txn.getCurrentSavepoint();
if (sp != null && (sp.getPrevious() != null || sp.getLastExecute() != null)) {
boolean hasUserExec = false;
if (true) {
// Do not check whether we have user queries, just ask for confirmation
hasUserExec = true;
} else {
for (QMMTransactionSavepointInfo psp = sp; psp != null; psp = psp.getPrevious()) {
if (psp.hasUserExecutions()) {
hasUserExec = true;
break;
}
}
if (hasUserExec) {
// Ask for confirmation
TransactionCloseConfirmer closeConfirmer = new TransactionCloseConfirmer();
UIUtils.runInUI(null, closeConfirmer);
DBCSession session = dataSource.openSession(monitor, DBCExecutionPurpose.UTIL, "End active transaction");
try {
switch (closeConfirmer.result) {
case IDialogConstants.YES_ID:
txnManager.commit(session);
break;
case IDialogConstants.NO_ID:
txnManager.rollback(session, null);
break;
default:
return false;
}
} finally {
session.close();
}
if (hasUserExec) {
// Ask for confirmation
TransactionCloseConfirmer closeConfirmer = new TransactionCloseConfirmer(getName());
UIUtils.runInUI(null, closeConfirmer);
DBCSession session = dataSource.openSession(monitor, DBCExecutionPurpose.UTIL, "End active transaction");
try {
boolean commit;
switch (closeConfirmer.result) {
case IDialogConstants.YES_ID:
commit = true;
break;
case IDialogConstants.NO_ID:
commit = false;
break;
default:
return false;
}
monitor.subTask("End active transaction");
EndTransactionTask task = new EndTransactionTask(session, commit);
RuntimeUtils.runTask(task, END_TRANSACTION_WAIT_TIME);
} finally {
session.close();
}
return true;
}
}
}
return true;
}
catch (Throwable e) {
log.warn("Could not rollback active transaction before disconnect", e);
return true;
}
finally {
monitor.worked(1);
}
return true;
}
@Override
......@@ -1149,19 +1156,6 @@ public class DataSourceDescriptor
}
}
private class TransactionCloseConfirmer implements Runnable {
int result = IDialogConstants.NO_ID;
@Override
public void run()
{
result = ConfirmationDialog.showConfirmDialog(
null,
DBeaverPreferences.CONFIRM_TXN_DISCONNECT,
ConfirmationDialog.QUESTION_WITH_CANCEL,
getName());
}
}
public void copyFrom(DataSourceDescriptor descriptor) {
filterMap.clear();
for (FilterMapping mapping : descriptor.getObjectFilters()) {
......@@ -1180,4 +1174,50 @@ public class DataSourceDescriptor
public String toString() {
return name + " [" + driver + "]";
}
private static class EndTransactionTask implements DBRRunnableWithProgress {
private final DBCSession session;
private final boolean commit;
private EndTransactionTask(DBCSession session, boolean commit) {
this.session = session;
this.commit = commit;
}
@Override
public void run(DBRProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
DBCTransactionManager txnManager = DBUtils.getTransactionManager(session.getDataSource());
if (txnManager != null) {
try {
if (commit) {
txnManager.commit(session);
} else {
txnManager.rollback(session, null);
}
} catch (DBCException e) {
throw new InvocationTargetException(e);
}
}
}
}
private static class TransactionCloseConfirmer implements Runnable {
final String name;
int result = IDialogConstants.NO_ID;
private TransactionCloseConfirmer(String name) {
this.name = name;
}
@Override
public void run()
{
result = ConfirmationDialog.showConfirmDialog(
null,
DBeaverPreferences.CONFIRM_TXN_DISCONNECT,
ConfirmationDialog.QUESTION_WITH_CANCEL,
name);
}
}
}
......@@ -18,19 +18,15 @@
*/
package org.jkiss.dbeaver.registry;
import org.jkiss.dbeaver.core.Log;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.resource.StringConverter;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.core.DBeaverCore;
import org.jkiss.dbeaver.core.DBeaverUI;
import org.jkiss.dbeaver.core.Log;
import org.jkiss.dbeaver.model.*;
import org.jkiss.dbeaver.model.net.DBWHandlerConfiguration;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
......@@ -43,7 +39,6 @@ import org.jkiss.dbeaver.model.struct.rdb.DBSSchema;
import org.jkiss.dbeaver.registry.encode.EncryptionException;
import org.jkiss.dbeaver.registry.encode.PasswordEncrypter;
import org.jkiss.dbeaver.registry.encode.SimpleStringEncrypter;
import org.jkiss.dbeaver.runtime.AbstractJob;
import org.jkiss.dbeaver.runtime.RuntimeUtils;
import org.jkiss.dbeaver.runtime.VoidProgressMonitor;
import org.jkiss.dbeaver.utils.AbstractPreferenceStore;
......@@ -128,34 +123,7 @@ public class DataSourceRegistry implements DBPDataSourceRegistry
return;
}
final DisconnectTask disconnectTask = new DisconnectTask();
Job disconnectJob = new AbstractJob("Disconnect from data sources") {
@Override
protected IStatus run(DBRProgressMonitor monitor)
{
try {
disconnectTask.run(monitor);
} catch (InvocationTargetException e) {
return RuntimeUtils.makeExceptionStatus(e.getTargetException());
} catch (InterruptedException e) {
// do nothing
}
return Status.OK_STATUS;
}
};
disconnectJob.schedule();
// Wait for job to finish
long startTime = System.currentTimeMillis();
if (waitTime > 0) {
while (!disconnectTask.finished && System.currentTimeMillis() - startTime < waitTime) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
break;
}
}
}
if (!disconnectTask.finished) {
if (!RuntimeUtils.runTask(disconnectTask, waitTime)) {
log.warn("Some data source connections wasn't closed on shutdown in " + waitTime + "ms. Probably network timeout occurred.");
}
}
......@@ -810,7 +778,6 @@ public class DataSourceRegistry implements DBPDataSourceRegistry
private class DisconnectTask implements DBRRunnableWithProgress {
boolean disconnected;
volatile boolean finished;
@Override
public void run(DBRProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
List<DataSourceDescriptor> dsSnapshot;
......@@ -836,7 +803,6 @@ public class DataSourceRegistry implements DBPDataSourceRegistry
}
} finally {
monitor.done();
finished = true;
}
}
}
......
......@@ -24,6 +24,7 @@ import org.apache.commons.jexl2.JexlException;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.*;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.operation.IRunnableContext;
import org.eclipse.jface.operation.IRunnableWithProgress;
......@@ -44,6 +45,7 @@ import org.jkiss.dbeaver.model.runtime.DBRProcessDescriptor;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.dbeaver.model.runtime.DBRRunnableWithProgress;
import org.jkiss.dbeaver.model.runtime.DBRShellCommand;
import org.jkiss.dbeaver.registry.DataSourceDescriptor;
import org.jkiss.dbeaver.ui.UIUtils;
import org.jkiss.dbeaver.ui.dialogs.ConfirmationDialog;
import org.jkiss.dbeaver.ui.views.process.ShellProcessView;
......@@ -59,10 +61,7 @@ import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.*;
/**
* RuntimeUtils
......@@ -624,4 +623,59 @@ public class RuntimeUtils {
}
}
public static boolean runTask(final DBRRunnableWithProgress task, final long waitTime) {
final MonitoringTask monitoringTask = new MonitoringTask(task);
Job monitorJob = new AbstractJob("Disconnect from data sources") {
@Override
protected IStatus run(DBRProgressMonitor monitor)
{
try {
monitoringTask.run(monitor);
} catch (InvocationTargetException e) {
return RuntimeUtils.makeExceptionStatus(e.getTargetException());
} catch (InterruptedException e) {
// do nothing
}
return Status.OK_STATUS;
}
};
monitorJob.schedule();
// Wait for job to finish
long startTime = System.currentTimeMillis();
if (waitTime > 0) {
while (!monitoringTask.finished && System.currentTimeMillis() - startTime < waitTime) {
try {
Thread.sleep(50);
} catch (InterruptedException e) {
break;
}
}
}
return monitoringTask.finished;
}
private static class MonitoringTask implements DBRRunnableWithProgress {
private final DBRRunnableWithProgress task;
volatile boolean finished;
private MonitoringTask(DBRRunnableWithProgress task) {
this.task = task;
}
public boolean isFinished() {
return finished;
}
@Override
public void run(DBRProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
try {
task.run(monitor);
} finally {
monitor.done();
finished = true;
}
}
}
}
......@@ -28,13 +28,12 @@ import org.jkiss.dbeaver.registry.DataSourceDescriptor;
import org.jkiss.dbeaver.runtime.RuntimeUtils;
/**
* DisconnectJob
* Disconnect Job
*/
public class DisconnectJob extends EventProcessorJob
{
public DisconnectJob(
DataSourceDescriptor container)
public DisconnectJob(DataSourceDescriptor container)
{
super(NLS.bind(CoreMessages.runtime_jobs_disconnect_name, container.getName()), container);
setUser(true);
......
......@@ -533,7 +533,7 @@ public class SQLQueryJob extends DataSourceJob
// Retrieve source entity
if (result != null) {
DBCResultSetMetaData rsMeta = resultSet.getMeta();
String sourceName = null;
String sourceName = null;//resultSet.getResultSetName();
for (DBCAttributeMetaData attr : rsMeta.getAttributes()) {
String entityName = attr.getEntityName();
if (!CommonUtils.isEmpty(entityName)) {
......@@ -610,10 +610,8 @@ public class SQLQueryJob extends DataSourceJob
private boolean keepStatementOpen()
{
// Only in single query mode and if pref option set to true
DBSDataSourceContainer container = getDataSourceContainer();
return queries.size() == 1 &&
container != null &&
container.getPreferenceStore().getBoolean(DBeaverPreferences.KEEP_STATEMENT_OPEN);
getDataSourceContainer().getPreferenceStore().getBoolean(DBeaverPreferences.KEEP_STATEMENT_OPEN);
}
private void closeStatement()
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册