diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/validation/ValidationContext.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/validation/ValidationContext.java index 42846d7dd11..bdad87494d0 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/validation/ValidationContext.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/validation/ValidationContext.java @@ -96,12 +96,12 @@ public class ValidationContext extends BaseValidationContext implements IV IEncoder encoder = new IEncoder() { @Override public String encode() { - return theContext.newXmlParser().encodeResourceToString(theResource); + return theContext.newJsonParser().encodeResourceToString(theResource); } @Override public EncodingEnum getEncoding() { - return EncodingEnum.XML; + return EncodingEnum.JSON; } }; return new ValidationContext<>(theContext, theResource, encoder, options); diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/5_7_0/3236-change-validation-from-xml-to-java.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/5_7_0/3236-change-validation-from-xml-to-java.yaml new file mode 100644 index 00000000000..59d80b309ce --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/5_7_0/3236-change-validation-from-xml-to-java.yaml @@ -0,0 +1,3 @@ +--- +type: perf +title: "Improved validation performance by switching validation serialization from XML to JSON." diff --git a/hapi-fhir-jpaserver-base/src/test/resources/r4/code-in-unknown-system-with-required-binding.xml b/hapi-fhir-jpaserver-base/src/test/resources/r4/code-in-unknown-system-with-required-binding.xml index 07f6ff924b9..93a5b4e1525 100644 --- a/hapi-fhir-jpaserver-base/src/test/resources/r4/code-in-unknown-system-with-required-binding.xml +++ b/hapi-fhir-jpaserver-base/src/test/resources/r4/code-in-unknown-system-with-required-binding.xml @@ -22,7 +22,6 @@ - diff --git a/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/CachingValidationSupport.java b/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/CachingValidationSupport.java index a3089c9ba6e..c7ab4c296b7 100644 --- a/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/CachingValidationSupport.java +++ b/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/CachingValidationSupport.java @@ -141,7 +141,7 @@ public class CachingValidationSupport extends BaseValidationSupportWrapper imple @Override public boolean isCodeSystemSupported(ValidationSupportContext theValidationSupportContext, String theSystem) { String key = "isCodeSystemSupported " + theSystem; - Boolean retVal = loadFromCache(myCache, key, t -> super.isCodeSystemSupported(theValidationSupportContext, theSystem)); + Boolean retVal = loadFromCacheReentrantSafe(myCache, key, t -> super.isCodeSystemSupported(theValidationSupportContext, theSystem)); assert retVal != null; return retVal; } @@ -188,6 +188,27 @@ public class CachingValidationSupport extends BaseValidationSupportWrapper imple return result.orElse(null); } + /** + * The Caffeine cache uses ConcurrentHashMap which is not reentrant, so if we get unlucky and the hashtable + * needs to grow at the same time as we are in a reentrant cache lookup, the thread will deadlock. Use this + * method in place of loadFromCache in situations where a cache lookup calls another cache lookup within its lambda + */ + @Nullable + private T loadFromCacheReentrantSafe(Cache theCache, S theKey, Function theLoader) { + ourLog.trace("Reentrant fetch from cache: {}", theKey); + + Optional result = (Optional) theCache.getIfPresent(theKey); + if (result != null && result.isPresent()) { + return result.get(); + } + T value = theLoader.apply(theKey); + assert value != null; + + theCache.put(theKey, Optional.of(value)); + + return value; + } + private T loadFromCacheWithAsyncRefresh(Cache theCache, S theKey, Function theLoader) { T retVal = (T) theCache.getIfPresent(theKey); if (retVal == null) {