Merge pull request #2657 from hapifhir/issue-2655-configurable-expunge-size

Toggleable searchForIds size
This commit is contained in:
Tadgh 2021-05-13 13:29:17 -04:00 committed by GitHub
commit af1b0965a4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 71 additions and 3 deletions

View File

@ -0,0 +1,5 @@
---
type: change
issue: 2655
title: "Added a new configuration option to DaoConfig, `setInternalSynchronousSearchSize()`, this controls the loadSynchronousUpTo()
during internal operations such as delete with expunge, and certain CodeSystem searches."

View File

@ -126,3 +126,7 @@ With this interceptor in place, the following header can be added to individual
```http ```http
X-Retry-On-Version-Conflict: retry; max-retries=100 X-Retry-On-Version-Conflict: retry; max-retries=100
``` ```
# Controlling Delete with Expunge size
During the delete with expunge operation there is an internal synchronous search which locates all the resources to be deleted. The default maximum size of this search is 10000. This can be configured via the [Internal Synchronous Search Size](/hapi-fhir/apidocs/hapi-fhir-jpaserver-api/ca/uhn/fhir/jpa/api/config/DaoConfig.html#setInternalSynchronousSearchSize(int)) property.

View File

@ -89,6 +89,7 @@ public class DaoConfig {
/** /**
* Child Configurations * Child Configurations
*/ */
private static final Integer DEFAULT_INTERNAL_SYNCHRONOUS_SEARCH_SIZE = 10000;
private final ModelConfig myModelConfig = new ModelConfig(); private final ModelConfig myModelConfig = new ModelConfig();
/** /**
@ -155,6 +156,7 @@ public class DaoConfig {
private boolean myFilterParameterEnabled = false; private boolean myFilterParameterEnabled = false;
private StoreMetaSourceInformationEnum myStoreMetaSourceInformation = StoreMetaSourceInformationEnum.SOURCE_URI_AND_REQUEST_ID; private StoreMetaSourceInformationEnum myStoreMetaSourceInformation = StoreMetaSourceInformationEnum.SOURCE_URI_AND_REQUEST_ID;
private HistoryCountModeEnum myHistoryCountMode = DEFAULT_HISTORY_COUNT_MODE; private HistoryCountModeEnum myHistoryCountMode = DEFAULT_HISTORY_COUNT_MODE;
private int myInternalSynchronousSearchSize = DEFAULT_INTERNAL_SYNCHRONOUS_SEARCH_SIZE;
/** /**
* update setter javadoc if default changes * update setter javadoc if default changes
@ -2181,6 +2183,30 @@ public class DaoConfig {
// ignore // ignore
} }
/**
* <p>
* This determines the internal search size that is run synchronously during operations such as:
* 1. Delete with _expunge parameter.
* 2. Searching for Code System IDs by System and Code
* </p>
* @since 5.4.0
*/
public Integer getInternalSynchronousSearchSize() {
return myInternalSynchronousSearchSize;
}
/**
* <p>
* This determines the internal search size that is run synchronously during operations such as:
* 1. Delete with _expunge parameter.
* 2. Searching for Code System IDs by System and Code
* </p>
* @since 5.4.0
*/
public void setInternalSynchronousSearchSize(Integer theInternalSynchronousSearchSize) {
myInternalSynchronousSearchSize = theInternalSynchronousSearchSize;
}
public enum StoreMetaSourceInformationEnum { public enum StoreMetaSourceInformationEnum {
NONE(false, false), NONE(false, false),
SOURCE_URI(true, false), SOURCE_URI(true, false),

View File

@ -1446,7 +1446,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
@Override @Override
public Set<ResourcePersistentId> searchForIds(SearchParameterMap theParams, RequestDetails theRequest) { public Set<ResourcePersistentId> searchForIds(SearchParameterMap theParams, RequestDetails theRequest) {
return myTransactionService.execute(theRequest, tx -> { return myTransactionService.execute(theRequest, tx -> {
theParams.setLoadSynchronousUpTo(10000); theParams.setLoadSynchronousUpTo(myDaoConfig.getInternalSynchronousSearchSize());
ISearchBuilder builder = mySearchBuilderFactory.newSearchBuilder(this, getResourceName(), getResourceType()); ISearchBuilder builder = mySearchBuilderFactory.newSearchBuilder(this, getResourceName(), getResourceType());

View File

@ -69,8 +69,6 @@ public class DeleteExpungeService {
@Autowired @Autowired
private ResourceTableFKProvider myResourceTableFKProvider; private ResourceTableFKProvider myResourceTableFKProvider;
@Autowired @Autowired
private IResourceTableDao myResourceTableDao;
@Autowired
private IResourceLinkDao myResourceLinkDao; private IResourceLinkDao myResourceLinkDao;
@Autowired @Autowired
private IInterceptorBroadcaster myInterceptorBroadcaster; private IInterceptorBroadcaster myInterceptorBroadcaster;

View File

@ -4,6 +4,8 @@ import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.api.model.DeleteMethodOutcome; import ca.uhn.fhir.jpa.api.model.DeleteMethodOutcome;
import ca.uhn.fhir.jpa.dao.r4.BaseJpaR4Test; import ca.uhn.fhir.jpa.dao.r4.BaseJpaR4Test;
import ca.uhn.fhir.jpa.model.util.JpaConstants; import ca.uhn.fhir.jpa.model.util.JpaConstants;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.Organization; import org.hl7.fhir.r4.model.Organization;
@ -16,8 +18,12 @@ import org.springframework.beans.factory.annotation.Autowired;
import java.util.List; import java.util.List;
import static org.hamcrest.Matchers.hasSize;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail; import static org.junit.jupiter.api.Assertions.fail;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
class DeleteExpungeServiceTest extends BaseJpaR4Test { class DeleteExpungeServiceTest extends BaseJpaR4Test {
@ -29,6 +35,8 @@ class DeleteExpungeServiceTest extends BaseJpaR4Test {
myDaoConfig.setAllowMultipleDelete(true); myDaoConfig.setAllowMultipleDelete(true);
myDaoConfig.setExpungeEnabled(true); myDaoConfig.setExpungeEnabled(true);
myDaoConfig.setDeleteExpungeEnabled(true); myDaoConfig.setDeleteExpungeEnabled(true);
myDaoConfig.setInternalSynchronousSearchSize(new DaoConfig().getInternalSynchronousSearchSize());
} }
@AfterEach @AfterEach
@ -57,6 +65,32 @@ class DeleteExpungeServiceTest extends BaseJpaR4Test {
assertEquals(e.getMessage(), "DELETE with _expunge=true failed. Unable to delete " + organizationId.toVersionless() + " because " + patientId.toVersionless() + " refers to it via the path Patient.managingOrganization"); assertEquals(e.getMessage(), "DELETE with _expunge=true failed. Unable to delete " + organizationId.toVersionless() + " because " + patientId.toVersionless() + " refers to it via the path Patient.managingOrganization");
} }
} }
@Test
public void testDeleteExpungeRespectsSynchronousSize() {
//Given
myDaoConfig.setInternalSynchronousSearchSize(1);
Patient patient = new Patient();
myPatientDao.create(patient);
Patient otherPatient = new Patient();
myPatientDao.create(otherPatient);
//When
DeleteMethodOutcome deleteMethodOutcome = myPatientDao.deleteByUrl("Patient?" + JpaConstants.PARAM_DELETE_EXPUNGE + "=true", mySrd);
IBundleProvider remaining = myPatientDao.search(new SearchParameterMap().setLoadSynchronous(true));
//Then
assertThat(deleteMethodOutcome.getExpungedResourcesCount(), is(equalTo(1L)));
assertThat(remaining.size(), is(equalTo(1)));
//When
deleteMethodOutcome = myPatientDao.deleteByUrl("Patient?" + JpaConstants.PARAM_DELETE_EXPUNGE + "=true", mySrd);
remaining = myPatientDao.search(new SearchParameterMap().setLoadSynchronous(true));
//Then
assertThat(deleteMethodOutcome.getExpungedResourcesCount(), is(equalTo(1L)));
assertThat(remaining.size(), is(equalTo(0)));
}
@Test @Test
public void testDeleteExpungeNoThrowExceptionWhenLinkInSearchResults() { public void testDeleteExpungeNoThrowExceptionWhenLinkInSearchResults() {

View File

@ -162,6 +162,7 @@ public class FhirResourceDaoR4Test extends BaseJpaR4Test {
myDaoConfig.setEnforceReferentialIntegrityOnDelete(new DaoConfig().isEnforceReferentialIntegrityOnDelete()); myDaoConfig.setEnforceReferentialIntegrityOnDelete(new DaoConfig().isEnforceReferentialIntegrityOnDelete());
myDaoConfig.setEnforceReferenceTargetTypes(new DaoConfig().isEnforceReferenceTargetTypes()); myDaoConfig.setEnforceReferenceTargetTypes(new DaoConfig().isEnforceReferenceTargetTypes());
myDaoConfig.setIndexMissingFields(new DaoConfig().getIndexMissingFields()); myDaoConfig.setIndexMissingFields(new DaoConfig().getIndexMissingFields());
myDaoConfig.setInternalSynchronousSearchSize(new DaoConfig().getInternalSynchronousSearchSize());
myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_NOT_SUPPORTED); myModelConfig.setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_NOT_SUPPORTED);
myDaoConfig.setHistoryCountMode(DaoConfig.DEFAULT_HISTORY_COUNT_MODE); myDaoConfig.setHistoryCountMode(DaoConfig.DEFAULT_HISTORY_COUNT_MODE);
} }