diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java index 86fcab0ce66..4d9d0af6c3b 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java @@ -1772,8 +1772,12 @@ public abstract class BaseHapiFhirDao implements IDao, protected ResourceTable updateEntity(RequestDetails theRequest, final IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing, boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) { + Validate.notNull(theEntity); + Validate.isTrue(theDeletedTimestampOrNull != null || theResource != null, "Must have either a resource[{}] or a deleted timestamp[{}] for resource PID[{}]", theDeletedTimestampOrNull != null, theResource != null, theEntity.getId()); + ourLog.debug("Starting entity update"); + /* * This should be the very first thing.. */ @@ -1863,6 +1867,7 @@ public abstract class BaseHapiFhirDao implements IDao, theEntity.setNarrativeTextParsedIntoWords(null); theEntity.setContentTextParsedIntoWords(null); theEntity.setHashSha256(null); + theEntity.setIndexStatus(INDEX_STATUS_INDEXED); changed = populateResourceIntoEntity(theRequest, theResource, theEntity, true); } else { diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java index a3a9e71cf79..411ea977d39 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java @@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.dao; * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -927,10 +927,14 @@ public abstract class BaseHapiFhirResourceDao extends B @Override public void reindex(T theResource, ResourceTable theEntity) { - ourLog.debug("Indexing resource {} - PID {}", theResource.getIdElement().getValue(), theEntity.getId()); - CURRENTLY_REINDEXING.put(theResource, Boolean.TRUE); - updateEntity(null, theResource, theEntity, null, true, false, theEntity.getUpdatedDate(), true, false); - CURRENTLY_REINDEXING.put(theResource, null); + ourLog.debug("Indexing resource {} - PID {}", theEntity.getIdDt().getValue(), theEntity.getId()); + if (theResource != null) { + CURRENTLY_REINDEXING.put(theResource, Boolean.TRUE); + } + updateEntity(null, theResource, theEntity, theEntity.getDeleted(), true, false, theEntity.getUpdatedDate(), true, false); + if (theResource != null) { + CURRENTLY_REINDEXING.put(theResource, null); + } } @Override @@ -1062,6 +1066,11 @@ public abstract class BaseHapiFhirResourceDao extends B mySecondaryPrimaryKeyParamName = theSecondaryPrimaryKeyParamName; } + @PostConstruct + public void start() { + ourLog.debug("Starting resource DAO for type: {}", getResourceName()); + } + protected MT toMetaDt(Class theType, Collection tagDefinitions) { MT retVal; try { @@ -1333,9 +1342,4 @@ public abstract class BaseHapiFhirResourceDao extends B } } - @PostConstruct - public void start() { - ourLog.debug("Starting resource DAO for type: {}", getResourceName()); - } - } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/IResourceIndexedSearchParamStringDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/IResourceIndexedSearchParamStringDao.java index 6bd5724bc8a..7b1ae15b3e7 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/IResourceIndexedSearchParamStringDao.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/IResourceIndexedSearchParamStringDao.java @@ -23,7 +23,12 @@ package ca.uhn.fhir.jpa.dao.data; import org.springframework.data.jpa.repository.JpaRepository; import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamString; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; public interface IResourceIndexedSearchParamStringDao extends JpaRepository { - // nothing yet + + @Query("select count(*) from ResourceIndexedSearchParamString t WHERE t.myResourcePid = :resid") + int countForResourceId(@Param("resid") Long theResourcePid); + } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/IResourceIndexedSearchParamTokenDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/IResourceIndexedSearchParamTokenDao.java index 09679d390b0..9e30fd3b026 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/IResourceIndexedSearchParamTokenDao.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/IResourceIndexedSearchParamTokenDao.java @@ -20,10 +20,14 @@ package ca.uhn.fhir.jpa.dao.data; * #L% */ -import org.springframework.data.jpa.repository.JpaRepository; - import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamToken; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; public interface IResourceIndexedSearchParamTokenDao extends JpaRepository { - // nothing yet + + @Query("select count(*) from ResourceIndexedSearchParamToken t WHERE t.myResourcePid = :resid") + int countForResourceId(@Param("resid") Long theResourcePid); + } diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4Test.java index 5144f0fcfa7..20e3dfc0f09 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4Test.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4Test.java @@ -1,10 +1,7 @@ package ca.uhn.fhir.jpa.dao.r4; import ca.uhn.fhir.jpa.dao.*; -import ca.uhn.fhir.jpa.entity.ResourceEncodingEnum; -import ca.uhn.fhir.jpa.entity.ResourceHistoryTable; -import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamString; -import ca.uhn.fhir.jpa.entity.TagTypeEnum; +import ca.uhn.fhir.jpa.entity.*; import ca.uhn.fhir.model.api.Include; import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum; import ca.uhn.fhir.model.valueset.BundleEntrySearchModeEnum; @@ -152,6 +149,42 @@ public class FhirResourceDaoR4Test extends BaseJpaR4Test { return retVal; } + + @Test + public void testDeletedResourcesAreReindexed() { + myDaoConfig.setSchedulingDisabled(true); + + Patient pt1 = new Patient(); + pt1.setActive(true); + pt1.addName().setFamily("FAM"); + IIdType id1 = myPatientDao.create(pt1).getId().toUnqualifiedVersionless(); + + runInTransaction(()->{ + assertThat(myResourceIndexedSearchParamTokenDao.countForResourceId(id1.getIdPartAsLong()), greaterThan(0)); + }); + + runInTransaction(()->{ + Optional tableOpt = myResourceTableDao.findById(id1.getIdPartAsLong()); + assertTrue(tableOpt.isPresent()); + ResourceTable table = tableOpt.get(); + table.setIndexStatus(null); + table.setDeleted(new Date()); + }); + + mySystemDao.performReindexingPass(1000); + mySystemDao.performReindexingPass(1000); + + runInTransaction(()->{ + Optional tableOpt = myResourceTableDao.findById(id1.getIdPartAsLong()); + assertTrue(tableOpt.isPresent()); + assertEquals(BaseHapiFhirDao.INDEX_STATUS_INDEXED, tableOpt.get().getIndexStatus().longValue()); + assertThat(myResourceIndexedSearchParamTokenDao.countForResourceId(id1.getIdPartAsLong()), not(greaterThan(0))); + }); + + + } + + @Test public void testCantSearchForDeletedResourceByLanguageOrTag() { String methodName = "testCantSearchForDeletedResourceByLanguageOrTag"; diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4UniqueSearchParamTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4UniqueSearchParamTest.java index 89442af5487..ea57f398263 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4UniqueSearchParamTest.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4UniqueSearchParamTest.java @@ -1,9 +1,11 @@ package ca.uhn.fhir.jpa.dao.r4; +import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao; import ca.uhn.fhir.jpa.dao.DaoConfig; import ca.uhn.fhir.jpa.dao.SearchBuilder; import ca.uhn.fhir.jpa.dao.SearchParameterMap; import ca.uhn.fhir.jpa.entity.ResourceIndexedCompositeStringUnique; +import ca.uhn.fhir.jpa.entity.ResourceTable; import ca.uhn.fhir.jpa.search.JpaRuntimeSearchParam; import ca.uhn.fhir.jpa.util.JpaConstants; import ca.uhn.fhir.rest.api.server.IBundleProvider; @@ -27,6 +29,7 @@ import org.springframework.transaction.support.TransactionTemplate; import javax.annotation.Nonnull; import java.util.Collections; import java.util.List; +import java.util.Optional; import java.util.UUID; import static org.hamcrest.Matchers.*; diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 632407ba051..6f30cebad09 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -134,6 +134,10 @@ A crash was fixed when deleting a ConceptMap resource in the JPA server. This crash was a regression in HAPI FHIR 3.4.0. + + A crash in the JPA server when performing a manual reindex of a deleted resource + was fixed. +