Fix an occassional failure in the stress test

This commit is contained in:
James Agnew 2019-03-06 09:26:54 -05:00
parent 9bc0f6784d
commit fd401165a9
2 changed files with 24 additions and 8 deletions

View File

@ -26,10 +26,12 @@ import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTable;
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedCompositeStringUnique; import ca.uhn.fhir.jpa.model.entity.ResourceIndexedCompositeStringUnique;
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException; import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.StaleStateException;
import org.hibernate.exception.ConstraintViolationException; import org.hibernate.exception.ConstraintViolationException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException; import org.springframework.dao.DataAccessException;
import org.springframework.dao.OptimisticLockingFailureException;
import org.springframework.orm.ObjectOptimisticLockingFailureException; import org.springframework.orm.ObjectOptimisticLockingFailureException;
import org.springframework.orm.jpa.vendor.HibernateJpaDialect; import org.springframework.orm.jpa.vendor.HibernateJpaDialect;
@ -68,10 +70,7 @@ public class HapiFhirHibernateJpaDialect extends HibernateJpaDialect {
if (isNotBlank(theMessageToPrepend)) { if (isNotBlank(theMessageToPrepend)) {
messageToPrepend = theMessageToPrepend + " - "; messageToPrepend = theMessageToPrepend + " - ";
} }
if (theException.toString().contains("Batch update")) {
theException.toString();
}
// <editor-fold desc="I HATE YOU">
if (theException instanceof ConstraintViolationException) { if (theException instanceof ConstraintViolationException) {
String constraintName = ((ConstraintViolationException) theException).getConstraintName(); String constraintName = ((ConstraintViolationException) theException).getConstraintName();
switch (defaultString(constraintName)) { switch (defaultString(constraintName)) {
@ -83,7 +82,25 @@ public class HapiFhirHibernateJpaDialect extends HibernateJpaDialect {
throw new ResourceVersionConflictException(messageToPrepend + myLocalizer.getMessage(HapiFhirHibernateJpaDialect.class, "forcedIdConstraintFailure")); throw new ResourceVersionConflictException(messageToPrepend + myLocalizer.getMessage(HapiFhirHibernateJpaDialect.class, "forcedIdConstraintFailure"));
} }
} }
// </editor-fold>
/*
* It would be nice if we could be more precise here, since technically any optimistic lock
* failure could result in a StaleStateException, but with the error message we're returning
* we're basically assuming it's an optimistic lock failure on HFJ_RESOURCE.
*
* That said, I think this is an OK trade-off. There is a high probability that if this happens
* it is a failure on HFJ_RESOURCE (there aren't many other tables in our schema that
* use @Version at all) and this error message is infinitely more comprehensible
* than the one we'd otherwise return.
*
* The actual StaleStateException is thrown in hibernate's Expectations
* class in a method called "checkBatched" currently. This can all be tested using the
* StressTestR4Test method testMultiThreadedUpdateSameResourceInTransaction()
*/
if (theException instanceof StaleStateException) {
String msg = messageToPrepend + myLocalizer.getMessage(HapiFhirHibernateJpaDialect.class, "resourceVersionConstraintFailure");
throw new ResourceVersionConflictException(msg);
}
return super.convertHibernateAccessException(theException); return super.convertHibernateAccessException(theException);
} }

View File

@ -3,7 +3,6 @@ package ca.uhn.fhir.jpa.config;
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.SingleQueryCountHolder; import net.ttddyy.dsproxy.listener.SingleQueryCountHolder;
import net.ttddyy.dsproxy.listener.logging.SLF4JLogLevel;
import net.ttddyy.dsproxy.support.ProxyDataSourceBuilder; import net.ttddyy.dsproxy.support.ProxyDataSourceBuilder;
import org.apache.commons.dbcp2.BasicDataSource; import org.apache.commons.dbcp2.BasicDataSource;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
@ -25,7 +24,7 @@ import static org.junit.Assert.fail;
@EnableTransactionManagement() @EnableTransactionManagement()
public class TestR4Config extends BaseJavaConfigR4 { public class TestR4Config extends BaseJavaConfigR4 {
static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TestR4Config.class); private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TestR4Config.class);
private static int ourMaxThreads; private static int ourMaxThreads;
static { static {
@ -96,7 +95,7 @@ public class TestR4Config extends BaseJavaConfigR4 {
DataSource dataSource = ProxyDataSourceBuilder DataSource dataSource = ProxyDataSourceBuilder
.create(retVal) .create(retVal)
.logQueryBySlf4j(SLF4JLogLevel.INFO, "SQL") // .logQueryBySlf4j(SLF4JLogLevel.INFO, "SQL")
// .logSlowQueryBySlf4j(10, TimeUnit.SECONDS) // .logSlowQueryBySlf4j(10, TimeUnit.SECONDS)
// .countQuery(new ThreadQueryCountHolder()) // .countQuery(new ThreadQueryCountHolder())
.beforeQuery(new BlockLargeNumbersOfParamsListener()) .beforeQuery(new BlockLargeNumbersOfParamsListener())