diff --git a/hapi-fhir-cli/hapi-fhir-cli-api/pom.xml b/hapi-fhir-cli/hapi-fhir-cli-api/pom.xml
index fc7c270042f..1ffeda550f2 100644
--- a/hapi-fhir-cli/hapi-fhir-cli-api/pom.xml
+++ b/hapi-fhir-cli/hapi-fhir-cli-api/pom.xml
@@ -188,7 +188,7 @@
org.thymeleaf
- thymeleaf-spring4
+ thymeleaf-spring5
diff --git a/hapi-fhir-jpaserver-base/pom.xml b/hapi-fhir-jpaserver-base/pom.xml
index 0ae95813b59..125398d7113 100644
--- a/hapi-fhir-jpaserver-base/pom.xml
+++ b/hapi-fhir-jpaserver-base/pom.xml
@@ -163,7 +163,7 @@
org.thymeleaf
- thymeleaf-spring4
+ thymeleaf-spring5
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/BaseConfig.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/BaseConfig.java
index 9667e2ba924..235eeca6adf 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/BaseConfig.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/BaseConfig.java
@@ -42,6 +42,7 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.core.env.Environment;
+import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.hibernate5.HibernateExceptionTranslator;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
@@ -162,7 +163,7 @@ public abstract class BaseConfig implements SchedulingConfigurer {
return new SubscriptionWebsocketInterceptor();
}
- @Bean(name = TASK_EXECUTOR_NAME)
+ @Bean()
public TaskScheduler taskScheduler() {
ConcurrentTaskScheduler retVal = new ConcurrentTaskScheduler();
retVal.setConcurrentExecutor(scheduledExecutorService());
@@ -170,6 +171,14 @@ public abstract class BaseConfig implements SchedulingConfigurer {
return retVal;
}
+ @Bean(name = TASK_EXECUTOR_NAME)
+ public AsyncTaskExecutor taskExecutor() {
+ ConcurrentTaskScheduler retVal = new ConcurrentTaskScheduler();
+ retVal.setConcurrentExecutor(scheduledExecutorService());
+ retVal.setScheduledExecutor(scheduledExecutorService());
+ return retVal;
+ }
+
@Bean
public IResourceReindexingSvc resourceReindexingSvc() {
return new ResourceReindexingSvcImpl();
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 da6135a5456..846eefe5d84 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
@@ -37,6 +37,7 @@ import javax.xml.stream.events.Characters;
import javax.xml.stream.events.XMLEvent;
import ca.uhn.fhir.jpa.dao.data.*;
+import com.google.common.collect.Lists;
import org.apache.commons.lang3.NotImplementedException;
import org.apache.commons.lang3.Validate;
import org.apache.http.NameValuePair;
@@ -255,6 +256,8 @@ public abstract class BaseHapiFhirDao implements IDao,
protected IResourceIndexedSearchParamStringDao myResourceIndexedSearchParamStringDao;
@Autowired()
protected IResourceIndexedSearchParamTokenDao myResourceIndexedSearchParamTokenDao;
+ @Autowired
+ protected IResourceLinkDao myResourceLinkDao;
@Autowired()
protected IResourceIndexedSearchParamDateDao myResourceIndexedSearchParamDateDao;
@Autowired()
@@ -328,6 +331,7 @@ public abstract class BaseHapiFhirDao implements IDao,
protected ExpungeOutcome doExpunge(String theResourceName, Long theResourceId, Long theVersion, ExpungeOptions theExpungeOptions) {
TransactionTemplate txTemplate = new TransactionTemplate(myPlatformTransactionManager);
+ txTemplate.setPropagationBehavior(TransactionTemplate.PROPAGATION_REQUIRES_NEW);
ourLog.info("Expunge: ResourceName[{}] Id[{}] Version[{}] Options[{}]", theResourceName, theResourceId, theVersion, theExpungeOptions);
if (!getConfig().isExpungeEnabled()) {
@@ -367,11 +371,14 @@ public abstract class BaseHapiFhirDao implements IDao,
});
/*
- * Delete any search result cache entries pointing to the given resource
+ * Delete any search result cache entries pointing to the given resource. We do
+ * this in batches to avoid sending giant batches of parameters to the DB
*/
- if (resourceIds.getContent().size() > 0) {
+ List> partitions = Lists.partition(resourceIds.getContent(), 800);
+ for (List nextPartition : partitions) {
+ ourLog.info("Expunging any search results pointing to {} resources", nextPartition.size());
txTemplate.execute(t -> {
- mySearchResultDao.deleteByResourceIds(resourceIds.getContent());
+ mySearchResultDao.deleteByResourceIds(nextPartition);
return null;
});
}
@@ -438,7 +445,7 @@ public abstract class BaseHapiFhirDao implements IDao,
ourLog.info("** BEGINNING GLOBAL $expunge **");
TransactionTemplate txTemplate = new TransactionTemplate(myPlatformTransactionManager);
- txTemplate.setPropagationBehavior(TransactionTemplate.PROPAGATION_REQUIRED);
+ txTemplate.setPropagationBehavior(TransactionTemplate.PROPAGATION_REQUIRES_NEW);
txTemplate.execute(t -> {
doExpungeEverythingQuery("UPDATE " + ResourceHistoryTable.class.getSimpleName() + " d SET d.myForcedId = null");
doExpungeEverythingQuery("UPDATE " + ResourceTable.class.getSimpleName() + " d SET d.myForcedId = null");
@@ -521,6 +528,8 @@ public abstract class BaseHapiFhirDao implements IDao,
myResourceIndexedSearchParamQuantityDao.deleteAll(resource.getParamsQuantity());
myResourceIndexedSearchParamStringDao.deleteAll(resource.getParamsString());
myResourceIndexedSearchParamTokenDao.deleteAll(resource.getParamsToken());
+ myResourceLinkDao.deleteAll(resource.getResourceLinks());
+ myResourceLinkDao.deleteAll(resource.getResourceLinksAsTarget());
myResourceTagDao.deleteAll(resource.getTags());
resource.getTags().clear();
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirSystemDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirSystemDao.java
index 830d5abbfc1..c37c458b0c2 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirSystemDao.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirSystemDao.java
@@ -65,7 +65,7 @@ public abstract class BaseHapiFhirSystemDao extends BaseHapiFhirDao {
- // nothing
+
+
+
}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceTable.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceTable.java
index e30a9b83438..891c31641b8 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceTable.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/ResourceTable.java
@@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.entity;
* 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.
@@ -185,27 +185,33 @@ public class ResourceTable extends BaseHasResource implements Serializable {
@IndexedEmbedded()
@OptimisticLock(excluded = true)
private Collection myResourceLinks;
-
+ @OneToMany(mappedBy = "myTargetResource", cascade = {}, fetch = FetchType.LAZY, orphanRemoval = false)
+ @IndexedEmbedded()
+ @OptimisticLock(excluded = true)
+ private Collection myResourceLinksAsTarget;
@Column(name = "RES_TYPE", length = RESTYPE_LEN)
@Field
@OptimisticLock(excluded = true)
private String myResourceType;
-
@OneToMany(mappedBy = "myResource", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
@OptimisticLock(excluded = true)
private Collection mySearchParamPresents;
-
@OneToMany(mappedBy = "myResource", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
@OptimisticLock(excluded = true)
private Set myTags;
-
@Transient
private transient boolean myUnchangedInCurrentOperation;
-
@Version
@Column(name = "RES_VER")
private long myVersion;
+ public Collection getResourceLinksAsTarget() {
+ if (myResourceLinksAsTarget == null) {
+ myResourceLinksAsTarget = new ArrayList<>();
+ }
+ return myResourceLinksAsTarget;
+ }
+
@Override
public ResourceTag addTag(TagDefinition theTag) {
for (ResourceTag next : getTags()) {
diff --git a/hapi-fhir-testpage-overlay/pom.xml b/hapi-fhir-testpage-overlay/pom.xml
index bdc30afcf4d..d377521707b 100644
--- a/hapi-fhir-testpage-overlay/pom.xml
+++ b/hapi-fhir-testpage-overlay/pom.xml
@@ -67,7 +67,7 @@
org.thymeleaf
- thymeleaf-spring4
+ thymeleaf-spring5
javax.servlet
diff --git a/pom.xml b/pom.xml
index cdbeb43ae80..38c44e721ab 100644
--- a/pom.xml
+++ b/pom.xml
@@ -518,9 +518,9 @@
3.0.2
5.3.6.Final
+ 5.10.3.Final
5.4.1.Final
- 5.10.3.Final
4.4.6
4.5.3
2.9.7
@@ -1246,7 +1246,7 @@
org.thymeleaf
- thymeleaf-spring4
+ thymeleaf-spring5
${thymeleaf-version}
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index e4199967673..f73f46251e1 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -6,6 +6,25 @@
HAPI FHIR Changelog
+
+
+ The version of a few dependencies have been bumped to the
+ latest versions (dependent HAPI modules listed in brackets):
+
+ thymeleaf-spring4 (Testpage Overlay) has been replaced with thymeleaf-spring5
+
+ ]]>
+
+
+ The JPA server $expunge operation could sometimes fail to expunge if
+ another resource linked to a resource that was being
+ expunged. This has been corrected. In addition, the $expunge operation
+ has been refactored to use smaller chunks of work
+ within a single DB transaction. This improves performance and reduces contention when
+ performing large expunge workloads.
+
+
The version of a few dependencies have been bumped to the