* Improving performance, using caching when testing for primitives (#6252) Caching primitive type names for faster lookup if a type is primitive. * Credit for #6253 --------- Co-authored-by: James Agnew <jamesagnew@gmail.com>
This commit is contained in:
parent
6f94e228b0
commit
9a73079c33
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
type: perf
|
||||
issue: 6253
|
||||
title: "A cache has been added to the validation services layer which results
|
||||
in improved validation performance. Thanks to Max Bureck for the
|
||||
contribution!"
|
|
@ -55,11 +55,15 @@ import org.slf4j.LoggerFactory;
|
|||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import static java.util.stream.Collectors.collectingAndThen;
|
||||
import static java.util.stream.Collectors.toSet;
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
|
@ -69,6 +73,7 @@ public class VersionSpecificWorkerContextWrapper extends I18nBase implements IWo
|
|||
private final VersionCanonicalizer myVersionCanonicalizer;
|
||||
private final LoadingCache<ResourceKey, IBaseResource> myFetchResourceCache;
|
||||
private volatile List<StructureDefinition> myAllStructures;
|
||||
private volatile Set<String> myAllPrimitiveTypes;
|
||||
private Parameters myExpansionProfile;
|
||||
|
||||
public VersionSpecificWorkerContextWrapper(
|
||||
|
@ -617,11 +622,23 @@ public class VersionSpecificWorkerContextWrapper extends I18nBase implements IWo
|
|||
|
||||
@Override
|
||||
public boolean isPrimitiveType(String theType) {
|
||||
List<StructureDefinition> allStructures = new ArrayList<>(allStructures());
|
||||
return allStructures.stream()
|
||||
.filter(structureDefinition ->
|
||||
structureDefinition.getKind() == StructureDefinition.StructureDefinitionKind.PRIMITIVETYPE)
|
||||
.anyMatch(structureDefinition -> theType.equals(structureDefinition.getName()));
|
||||
return allPrimitiveTypes().contains(theType);
|
||||
}
|
||||
|
||||
private Set<String> allPrimitiveTypes() {
|
||||
Set<String> retVal = myAllPrimitiveTypes;
|
||||
if (retVal == null) {
|
||||
// Collector may be changed to Collectors.toUnmodifiableSet() when switching to Android API level >= 33
|
||||
retVal = allStructures().stream()
|
||||
.filter(structureDefinition ->
|
||||
structureDefinition.getKind() == StructureDefinition.StructureDefinitionKind.PRIMITIVETYPE)
|
||||
.map(StructureDefinition::getName)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(collectingAndThen(toSet(), Collections::unmodifiableSet));
|
||||
myAllPrimitiveTypes = retVal;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -7,7 +7,10 @@ import ca.uhn.fhir.context.support.ValidationSupportContext;
|
|||
import ca.uhn.fhir.fhirpath.BaseValidationTestWithInlineMocks;
|
||||
import ca.uhn.fhir.i18n.HapiLocalizer;
|
||||
import ca.uhn.hapi.converters.canonical.VersionCanonicalizer;
|
||||
|
||||
import org.hl7.fhir.r5.model.Resource;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind;
|
||||
import org.hl7.fhir.r5.model.ValueSet;
|
||||
import org.hl7.fhir.utilities.validation.ValidationOptions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
@ -22,6 +25,8 @@ import static org.mockito.Mockito.verify;
|
|||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.Mockito.withSettings;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class VersionSpecificWorkerContextWrapperTest extends BaseValidationTestWithInlineMocks {
|
||||
|
||||
final byte[] EXPECTED_BINARY_CONTENT_1 = "dummyBinaryContent1".getBytes();
|
||||
|
@ -96,6 +101,66 @@ public class VersionSpecificWorkerContextWrapperTest extends BaseValidationTestW
|
|||
verify(validationSupport, times(1)).validateCode(any(), any(), eq("http://codesystems.com/system"), eq("code0"), any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isPrimitive_primitive() {
|
||||
// setup
|
||||
IValidationSupport validationSupport = mockValidationSupport();
|
||||
ValidationSupportContext mockContext = mockValidationSupportContext(validationSupport);
|
||||
VersionCanonicalizer versionCanonicalizer = new VersionCanonicalizer(FhirContext.forR5Cached());
|
||||
VersionSpecificWorkerContextWrapper wrapper = new VersionSpecificWorkerContextWrapper(mockContext, versionCanonicalizer);
|
||||
|
||||
List<StructureDefinition> structDefs = createStructureDefinitions();
|
||||
|
||||
when(mockContext.getRootValidationSupport().<StructureDefinition>fetchAllStructureDefinitions()).thenReturn(structDefs);
|
||||
assertThat(wrapper.isPrimitiveType("boolean")).isTrue();
|
||||
|
||||
// try again to check if lookup after cache is built is working
|
||||
assertThat(wrapper.isPrimitiveType("string")).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isPrimitive_not_primitive() {
|
||||
// setup
|
||||
IValidationSupport validationSupport = mockValidationSupport();
|
||||
ValidationSupportContext mockContext = mockValidationSupportContext(validationSupport);
|
||||
VersionCanonicalizer versionCanonicalizer = new VersionCanonicalizer(FhirContext.forR5Cached());
|
||||
VersionSpecificWorkerContextWrapper wrapper = new VersionSpecificWorkerContextWrapper(mockContext, versionCanonicalizer);
|
||||
|
||||
List<StructureDefinition> structDefs = createStructureDefinitions();
|
||||
|
||||
when(mockContext.getRootValidationSupport().<StructureDefinition>fetchAllStructureDefinitions()).thenReturn(structDefs);
|
||||
assertThat(wrapper.isPrimitiveType("Person")).isFalse();
|
||||
|
||||
// try again to check if lookup after cache is built is working
|
||||
assertThat(wrapper.isPrimitiveType("Organization")).isFalse();
|
||||
|
||||
// Assert that unknown types are not regarded as primitive
|
||||
assertThat(wrapper.isPrimitiveType("Unknown")).isFalse();
|
||||
}
|
||||
|
||||
private List<StructureDefinition> createStructureDefinitions() {
|
||||
StructureDefinition stringType = createPrimitive("string");
|
||||
StructureDefinition boolType = createPrimitive("boolean");
|
||||
StructureDefinition personType = createComplex("Person");
|
||||
StructureDefinition orgType = createComplex("Organization");
|
||||
|
||||
return List.of(personType, boolType, orgType, stringType);
|
||||
}
|
||||
|
||||
private StructureDefinition createComplex(String name){
|
||||
return createStructureDefinition(name).setKind(StructureDefinitionKind.COMPLEXTYPE);
|
||||
}
|
||||
|
||||
private StructureDefinition createPrimitive(String name){
|
||||
return createStructureDefinition(name).setKind(StructureDefinitionKind.PRIMITIVETYPE);
|
||||
}
|
||||
|
||||
private StructureDefinition createStructureDefinition(String name) {
|
||||
StructureDefinition sd = new StructureDefinition();
|
||||
sd.setUrl("http://hl7.org/fhir/StructureDefinition/"+name).setName(name);
|
||||
return sd;
|
||||
}
|
||||
|
||||
private IValidationSupport mockValidationSupportWithTwoBinaries() {
|
||||
IValidationSupport validationSupport;
|
||||
validationSupport = mockValidationSupport();
|
||||
|
|
Loading…
Reference in New Issue