More work on detecting deadlocks
This commit is contained in:
parent
fa050c4665
commit
f5f1f5bd67
|
@ -186,9 +186,9 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IBundleProvider registerSearch(final IDao theCallingDao, SearchParameterMap theParams, String theResourceType) {
|
public IBundleProvider registerSearch(final IDao theCallingDao, final SearchParameterMap theParams, String theResourceType) {
|
||||||
StopWatch w = new StopWatch();
|
StopWatch w = new StopWatch();
|
||||||
String searchUuid = UUID.randomUUID().toString();
|
final String searchUuid = UUID.randomUUID().toString();
|
||||||
|
|
||||||
Class<? extends IBaseResource> resourceTypeClass = myContext.getResourceDefinition(theResourceType).getImplementingClass();
|
Class<? extends IBaseResource> resourceTypeClass = myContext.getResourceDefinition(theResourceType).getImplementingClass();
|
||||||
final ISearchBuilder sb = theCallingDao.newSearchBuilder();
|
final ISearchBuilder sb = theCallingDao.newSearchBuilder();
|
||||||
|
@ -196,6 +196,13 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
||||||
|
|
||||||
if (theParams.isLoadSynchronous()) {
|
if (theParams.isLoadSynchronous()) {
|
||||||
|
|
||||||
|
// Execute the query and make sure we return distinct results
|
||||||
|
TransactionTemplate txTemplate = new TransactionTemplate(myManagedTxManager);
|
||||||
|
txTemplate.setPropagationBehavior(TransactionTemplate.PROPAGATION_REQUIRED);
|
||||||
|
return txTemplate.execute(new TransactionCallback<SimpleBundleProvider>() {
|
||||||
|
@Override
|
||||||
|
public SimpleBundleProvider doInTransaction(TransactionStatus theStatus) {
|
||||||
|
|
||||||
// Load the results synchronously
|
// Load the results synchronously
|
||||||
final List<Long> pids = new ArrayList<Long>();
|
final List<Long> pids = new ArrayList<Long>();
|
||||||
|
|
||||||
|
@ -220,12 +227,6 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
||||||
includedPids.addAll(sb.loadReverseIncludes(theCallingDao, myContext, myEntityManager, pids, theParams.getRevIncludes(), true, theParams.getLastUpdated()));
|
includedPids.addAll(sb.loadReverseIncludes(theCallingDao, myContext, myEntityManager, pids, theParams.getRevIncludes(), true, theParams.getLastUpdated()));
|
||||||
includedPids.addAll(sb.loadReverseIncludes(theCallingDao, myContext, myEntityManager, pids, theParams.getIncludes(), false, theParams.getLastUpdated()));
|
includedPids.addAll(sb.loadReverseIncludes(theCallingDao, myContext, myEntityManager, pids, theParams.getIncludes(), false, theParams.getLastUpdated()));
|
||||||
|
|
||||||
// Execute the query and make sure we return distinct results
|
|
||||||
TransactionTemplate txTemplate = new TransactionTemplate(myManagedTxManager);
|
|
||||||
txTemplate.setPropagationBehavior(TransactionTemplate.PROPAGATION_REQUIRED);
|
|
||||||
return txTemplate.execute(new TransactionCallback<SimpleBundleProvider>() {
|
|
||||||
@Override
|
|
||||||
public SimpleBundleProvider doInTransaction(TransactionStatus theStatus) {
|
|
||||||
List<IBaseResource> resources = new ArrayList<IBaseResource>();
|
List<IBaseResource> resources = new ArrayList<IBaseResource>();
|
||||||
sb.loadResourcesByPid(pids, resources, includedPids, false, myEntityManager, myContext, theCallingDao);
|
sb.loadResourcesByPid(pids, resources, includedPids, false, myEntityManager, myContext, theCallingDao);
|
||||||
return new SimpleBundleProvider(resources);
|
return new SimpleBundleProvider(resources);
|
||||||
|
|
|
@ -0,0 +1,289 @@
|
||||||
|
package ca.uhn.fhir.jpa.config;
|
||||||
|
|
||||||
|
import java.sql.*;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
|
public class ConnectionWrapper implements Connection {
|
||||||
|
|
||||||
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ConnectionWrapper.class);
|
||||||
|
|
||||||
|
private Connection myWrap;
|
||||||
|
|
||||||
|
public ConnectionWrapper(Connection theConnection) {
|
||||||
|
myWrap = theConnection;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void abort(Executor theExecutor) throws SQLException {
|
||||||
|
myWrap.abort(theExecutor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clearWarnings() throws SQLException {
|
||||||
|
myWrap.clearWarnings();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws SQLException {
|
||||||
|
ourLog.info("** Closing connection");
|
||||||
|
myWrap.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void commit() throws SQLException {
|
||||||
|
myWrap.commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Array createArrayOf(String theTypeName, Object[] theElements) throws SQLException {
|
||||||
|
return myWrap.createArrayOf(theTypeName, theElements);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Blob createBlob() throws SQLException {
|
||||||
|
return myWrap.createBlob();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Clob createClob() throws SQLException {
|
||||||
|
return myWrap.createClob();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public NClob createNClob() throws SQLException {
|
||||||
|
return myWrap.createNClob();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SQLXML createSQLXML() throws SQLException {
|
||||||
|
return myWrap.createSQLXML();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Statement createStatement() throws SQLException {
|
||||||
|
return myWrap.createStatement();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Statement createStatement(int theResultSetType, int theResultSetConcurrency) throws SQLException {
|
||||||
|
return myWrap.createStatement(theResultSetType, theResultSetConcurrency);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Statement createStatement(int theResultSetType, int theResultSetConcurrency, int theResultSetHoldability) throws SQLException {
|
||||||
|
return myWrap.createStatement(theResultSetType, theResultSetConcurrency, theResultSetHoldability);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Struct createStruct(String theTypeName, Object[] theAttributes) throws SQLException {
|
||||||
|
return myWrap.createStruct(theTypeName, theAttributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getAutoCommit() throws SQLException {
|
||||||
|
return myWrap.getAutoCommit();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCatalog() throws SQLException {
|
||||||
|
return myWrap.getCatalog();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Properties getClientInfo() throws SQLException {
|
||||||
|
return myWrap.getClientInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getClientInfo(String theName) throws SQLException {
|
||||||
|
return getClientInfo(theName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getHoldability() throws SQLException {
|
||||||
|
return myWrap.getHoldability();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DatabaseMetaData getMetaData() throws SQLException {
|
||||||
|
return myWrap.getMetaData();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getNetworkTimeout() throws SQLException {
|
||||||
|
return myWrap.getNetworkTimeout();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSchema() throws SQLException {
|
||||||
|
return myWrap.getSchema();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getTransactionIsolation() throws SQLException {
|
||||||
|
return myWrap.getTransactionIsolation();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Class<?>> getTypeMap() throws SQLException {
|
||||||
|
return myWrap.getTypeMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SQLWarning getWarnings() throws SQLException {
|
||||||
|
return myWrap.getWarnings();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isClosed() throws SQLException {
|
||||||
|
return myWrap.isClosed();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isReadOnly() throws SQLException {
|
||||||
|
return myWrap.isReadOnly();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValid(int theTimeout) throws SQLException {
|
||||||
|
return myWrap.isValid(theTimeout);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isWrapperFor(Class<?> theIface) throws SQLException {
|
||||||
|
return myWrap.isWrapperFor(theIface);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String nativeSQL(String theSql) throws SQLException {
|
||||||
|
return myWrap.nativeSQL(theSql);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CallableStatement prepareCall(String theSql) throws SQLException {
|
||||||
|
return myWrap.prepareCall(theSql);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CallableStatement prepareCall(String theSql, int theResultSetType, int theResultSetConcurrency) throws SQLException {
|
||||||
|
return myWrap.prepareCall(theSql, theResultSetType, theResultSetConcurrency);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CallableStatement prepareCall(String theSql, int theResultSetType, int theResultSetConcurrency, int theResultSetHoldability) throws SQLException {
|
||||||
|
return myWrap.prepareCall(theSql, theResultSetType, theResultSetConcurrency, theResultSetHoldability);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PreparedStatement prepareStatement(String theSql) throws SQLException {
|
||||||
|
return myWrap.prepareStatement(theSql);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PreparedStatement prepareStatement(String theSql, int theAutoGeneratedKeys) throws SQLException {
|
||||||
|
return myWrap.prepareStatement(theSql, theAutoGeneratedKeys);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PreparedStatement prepareStatement(String theSql, int theResultSetType, int theResultSetConcurrency) throws SQLException {
|
||||||
|
return myWrap.prepareStatement(theSql, theResultSetType, theResultSetConcurrency);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PreparedStatement prepareStatement(String theSql, int theResultSetType, int theResultSetConcurrency, int theResultSetHoldability) throws SQLException {
|
||||||
|
return myWrap.prepareStatement(theSql, theResultSetType, theResultSetConcurrency, theResultSetHoldability);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PreparedStatement prepareStatement(String theSql, int[] theColumnIndexes) throws SQLException {
|
||||||
|
return myWrap.prepareStatement(theSql, theColumnIndexes);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PreparedStatement prepareStatement(String theSql, String[] theColumnNames) throws SQLException {
|
||||||
|
return myWrap.prepareStatement(theSql, theColumnNames);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void releaseSavepoint(Savepoint theSavepoint) throws SQLException {
|
||||||
|
myWrap.releaseSavepoint(theSavepoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void rollback() throws SQLException {
|
||||||
|
myWrap.rollback();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void rollback(Savepoint theSavepoint) throws SQLException {
|
||||||
|
myWrap.rollback(theSavepoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setAutoCommit(boolean theAutoCommit) throws SQLException {
|
||||||
|
myWrap.setAutoCommit(theAutoCommit);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCatalog(String theCatalog) throws SQLException {
|
||||||
|
myWrap.setCatalog(theCatalog);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setClientInfo(Properties theProperties) throws SQLClientInfoException {
|
||||||
|
myWrap.setClientInfo(theProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setClientInfo(String theName, String theValue) throws SQLClientInfoException {
|
||||||
|
myWrap.setClientInfo(theName, theValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setHoldability(int theHoldability) throws SQLException {
|
||||||
|
myWrap.setHoldability(theHoldability);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setNetworkTimeout(Executor theExecutor, int theMilliseconds) throws SQLException {
|
||||||
|
myWrap.setNetworkTimeout(theExecutor, theMilliseconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setReadOnly(boolean theReadOnly) throws SQLException {
|
||||||
|
myWrap.setReadOnly(theReadOnly);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Savepoint setSavepoint() throws SQLException {
|
||||||
|
return myWrap.setSavepoint();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Savepoint setSavepoint(String theName) throws SQLException {
|
||||||
|
return myWrap.setSavepoint(theName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setSchema(String theSchema) throws SQLException {
|
||||||
|
myWrap.setSchema(theSchema);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setTransactionIsolation(int theLevel) throws SQLException {
|
||||||
|
myWrap.setTransactionIsolation(theLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setTypeMap(Map<String, Class<?>> theMap) throws SQLException {
|
||||||
|
myWrap.setTypeMap(theMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T unwrap(Class<T> theIface) throws SQLException {
|
||||||
|
return myWrap.unwrap(theIface);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,5 +1,7 @@
|
||||||
package ca.uhn.fhir.jpa.config;
|
package ca.uhn.fhir.jpa.config;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.SQLException;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
@ -8,9 +10,7 @@ import javax.sql.DataSource;
|
||||||
|
|
||||||
import org.apache.commons.dbcp2.BasicDataSource;
|
import org.apache.commons.dbcp2.BasicDataSource;
|
||||||
import org.hibernate.jpa.HibernatePersistenceProvider;
|
import org.hibernate.jpa.HibernatePersistenceProvider;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.*;
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.context.annotation.Lazy;
|
|
||||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||||
|
@ -18,21 +18,51 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||||
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
|
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
|
||||||
import ca.uhn.fhir.validation.ResultSeverityEnum;
|
import ca.uhn.fhir.validation.ResultSeverityEnum;
|
||||||
import net.ttddyy.dsproxy.listener.logging.SLF4JLogLevel;
|
|
||||||
import net.ttddyy.dsproxy.support.ProxyDataSourceBuilder;
|
import net.ttddyy.dsproxy.support.ProxyDataSourceBuilder;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableTransactionManagement()
|
@EnableTransactionManagement()
|
||||||
public class TestDstu3Config extends BaseJavaConfigDstu3 {
|
public class TestDstu3Config extends BaseJavaConfigDstu3 {
|
||||||
|
|
||||||
|
static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TestDstu3Config.class);
|
||||||
|
|
||||||
@Bean()
|
@Bean()
|
||||||
public DaoConfig daoConfig() {
|
public DaoConfig daoConfig() {
|
||||||
return new DaoConfig();
|
return new DaoConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean myLogConnection = false;
|
||||||
|
|
||||||
@Bean()
|
@Bean()
|
||||||
public DataSource dataSource() {
|
public DataSource dataSource() {
|
||||||
BasicDataSource retVal = new BasicDataSource();
|
BasicDataSource retVal = new BasicDataSource() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Connection getConnection() throws SQLException {
|
||||||
|
if (myLogConnection) {
|
||||||
|
logGetConnectionStackTrace();
|
||||||
|
return new ConnectionWrapper(super.getConnection());
|
||||||
|
} else {
|
||||||
|
return super.getConnection();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void logGetConnectionStackTrace() {
|
||||||
|
try {
|
||||||
|
throw new Exception();
|
||||||
|
} catch (Exception e) {
|
||||||
|
StringBuilder b = new StringBuilder();
|
||||||
|
b.append("New connection request:");
|
||||||
|
for (StackTraceElement next : e.getStackTrace()) {
|
||||||
|
if (next.getClassName().contains("fhir")) {
|
||||||
|
b.append("\n ").append(next.getClassName()).append(" ").append(next.getFileName()).append(":").append(next.getLineNumber());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ourLog.info(b.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
retVal.setDriver(new org.apache.derby.jdbc.EmbeddedDriver());
|
retVal.setDriver(new org.apache.derby.jdbc.EmbeddedDriver());
|
||||||
retVal.setUrl("jdbc:derby:memory:myUnitTestDB;create=true");
|
retVal.setUrl("jdbc:derby:memory:myUnitTestDB;create=true");
|
||||||
retVal.setUsername("");
|
retVal.setUsername("");
|
||||||
|
@ -56,13 +86,6 @@ public class TestDstu3Config extends BaseJavaConfigDstu3 {
|
||||||
return dataSource;
|
return dataSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean()
|
|
||||||
public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
|
|
||||||
JpaTransactionManager retVal = new JpaTransactionManager();
|
|
||||||
retVal.setEntityManagerFactory(entityManagerFactory);
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean()
|
@Bean()
|
||||||
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
|
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
|
||||||
LocalContainerEntityManagerFactoryBean retVal = new LocalContainerEntityManagerFactoryBean();
|
LocalContainerEntityManagerFactoryBean retVal = new LocalContainerEntityManagerFactoryBean();
|
||||||
|
@ -102,4 +125,11 @@ public class TestDstu3Config extends BaseJavaConfigDstu3 {
|
||||||
return requestValidator;
|
return requestValidator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean()
|
||||||
|
public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
|
||||||
|
JpaTransactionManager retVal = new JpaTransactionManager();
|
||||||
|
retVal.setEntityManagerFactory(entityManagerFactory);
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue