提交 cfbe2378 编写于 作者: S Serge Rider

#6479 Abortedtransaction auto-recovery

上级 6e509b88
......@@ -88,7 +88,7 @@ public class PostgreConstants {
public static final String HANDLER_SSL = "postgre_ssl";
/**
* @see https://www.postgresql.org/docs/9.2/static/errcodes-appendix.html
* @see [https://www.postgresql.org/docs/9.2/static/errcodes-appendix.html]
*/
public static final String EC_PERMISSION_DENIED = "42501"; //$NON-NLS-1$
public static final String EC_QUERY_CANCELED = "57014"; //$NON-NLS-1$
......@@ -111,6 +111,8 @@ public class PostgreConstants {
public static final String TYPE_FLOAT8 = "float8";
public static final String ERROR_ADMIN_SHUTDOWN = "57P01";
public static final String ERROR_TRANSACTION_ABORTED = "25P02";
public static final String PSQL_EXCEPTION_CLASS_NAME = "org.postgresql.util.PSQLException";
public static final String COLLATION_DEFAULT = "default";
......
......@@ -550,11 +550,13 @@ public class PostgreDataSource extends JDBCDataSource implements DBSObjectSelect
}
@Override
public ErrorType discoverErrorType(Throwable error) {
public ErrorType discoverErrorType(@NotNull Throwable error) {
String sqlState = SQLState.getStateFromException(error);
if (sqlState != null) {
if (PostgreConstants.ERROR_ADMIN_SHUTDOWN.equals(sqlState)) {
return ErrorType.CONNECTION_LOST;
} else if (PostgreConstants.ERROR_TRANSACTION_ABORTED.equals(sqlState)) {
return ErrorType.TRANSACTION_ABORTED;
}
}
......
......@@ -32,7 +32,8 @@ public interface DBPErrorAssistant
CONNECTION_LOST,
DRIVER_CLASS_MISSING,
PERMISSION_DENIED,
FEATURE_UNSUPPORTED
FEATURE_UNSUPPORTED,
TRANSACTION_ABORTED
}
class ErrorPosition
......
......@@ -148,10 +148,15 @@ public class DBExecUtils {
break;
} catch (InvocationTargetException e) {
lastError = e.getTargetException();
if (!recoverEnabled || discoverErrorType(dataSource, lastError) != DBPErrorAssistant.ErrorType.CONNECTION_LOST) {
if (!recoverEnabled) {
// Can't recover
break;
}
DBPErrorAssistant.ErrorType errorType = discoverErrorType(dataSource, lastError);
if (errorType != DBPErrorAssistant.ErrorType.TRANSACTION_ABORTED && errorType != DBPErrorAssistant.ErrorType.CONNECTION_LOST) {
// Some other error
break;
}
log.debug("Invalidate datasource '" + dataSource.getContainer().getName() + "' connections...");
DBRProgressMonitor monitor;
if (param instanceof DBRProgressMonitor) {
......@@ -162,11 +167,17 @@ public class DBExecUtils {
monitor = new VoidProgressMonitor();
}
if (!monitor.isCanceled()) {
// Do not recover if connection was canceled
InvalidateJob.invalidateDataSource(monitor, dataSource, false,
() -> DBWorkbench.getPlatformUI().openConnectionEditor(dataSource.getContainer()));
if (i < tryCount - 1) {
log.error("Operation failed. Retry count remains = " + (tryCount - i - 1), lastError);
if (errorType == DBPErrorAssistant.ErrorType.TRANSACTION_ABORTED) {
// Transaction aborted
InvalidateJob.invalidateTransaction(monitor, dataSource);
} else {
// Do not recover if connection was canceled
InvalidateJob.invalidateDataSource(monitor, dataSource, false,
() -> DBWorkbench.getPlatformUI().openConnectionEditor(dataSource.getContainer()));
if (i < tryCount - 1) {
log.error("Operation failed. Retry count remains = " + (tryCount - i - 1), lastError);
}
}
}
} catch (InterruptedException e) {
......
......@@ -22,7 +22,8 @@ import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.DBPDataSource;
import org.jkiss.dbeaver.model.DBPDataSourceContainer;
import org.jkiss.dbeaver.model.DBPMessageType;
import org.jkiss.dbeaver.model.exec.DBCExecutionContext;
import org.jkiss.dbeaver.model.DBUtils;
import org.jkiss.dbeaver.model.exec.*;
import org.jkiss.dbeaver.model.net.DBWNetworkHandler;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.dbeaver.model.struct.DBSInstance;
......@@ -182,6 +183,32 @@ public class InvalidateJob extends DataSourceJob
return invalidateResults;
}
public static void invalidateTransaction(DBRProgressMonitor monitor, DBPDataSource dataSource) {
// Invalidate transactions
monitor.subTask("Invalidate transactions of [" + dataSource.getContainer().getName() + "]");
for (DBSInstance instance : dataSource.getAvailableInstances()) {
for (DBCExecutionContext context : instance.getAllContexts()) {
invalidateTransaction(monitor, context);
}
}
}
public static void invalidateTransaction(DBRProgressMonitor monitor, DBCExecutionContext context) {
DBCTransactionManager txnManager = DBUtils.getTransactionManager(context);
if (txnManager != null) {
try {
if (!txnManager.isAutoCommit()) {
try (DBCSession session = context.openSession(monitor, DBCExecutionPurpose.UTIL, "Rollback failed transaction")) {
txnManager.rollback(session, null);
}
}
} catch (DBCException e) {
log.error("Error invalidating aborted transaction", e);
}
}
}
@Override
protected void canceling()
{
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册