Modify expunge everything to use small batches of deletes
This commit is contained in:
parent
c811fe8a2f
commit
f6c7ff1dbb
|
@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.dao.expunge;
|
|||
* 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.
|
||||
|
@ -34,15 +34,19 @@ import org.springframework.transaction.support.TransactionTemplate;
|
|||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.PersistenceContext;
|
||||
import javax.persistence.PersistenceContextType;
|
||||
import javax.persistence.TypedQuery;
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
@Service
|
||||
public class ExpungeEverythingService {
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(ExpungeEverythingService.class);
|
||||
@Autowired
|
||||
private PlatformTransactionManager myPlatformTransactionManager;
|
||||
@PersistenceContext(type = PersistenceContextType.TRANSACTION)
|
||||
protected EntityManager myEntityManager;
|
||||
@Autowired
|
||||
private PlatformTransactionManager myPlatformTransactionManager;
|
||||
|
||||
void expungeEverything() {
|
||||
|
||||
|
@ -57,52 +61,43 @@ public class ExpungeEverythingService {
|
|||
counter.addAndGet(doExpungeEverythingQuery("UPDATE " + TermCodeSystem.class.getSimpleName() + " d SET d.myCurrentVersion = null"));
|
||||
return null;
|
||||
});
|
||||
counter.addAndGet(doExpungeEverythingQuery(txTemplate, SearchParamPresent.class));
|
||||
counter.addAndGet(doExpungeEverythingQuery(txTemplate, ForcedId.class));
|
||||
counter.addAndGet(doExpungeEverythingQuery(txTemplate, ResourceIndexedSearchParamDate.class));
|
||||
counter.addAndGet(doExpungeEverythingQuery(txTemplate, ResourceIndexedSearchParamNumber.class));
|
||||
counter.addAndGet(doExpungeEverythingQuery(txTemplate, ResourceIndexedSearchParamQuantity.class));
|
||||
counter.addAndGet(doExpungeEverythingQuery(txTemplate, ResourceIndexedSearchParamString.class));
|
||||
counter.addAndGet(doExpungeEverythingQuery(txTemplate, ResourceIndexedSearchParamToken.class));
|
||||
counter.addAndGet(doExpungeEverythingQuery(txTemplate, ResourceIndexedSearchParamUri.class));
|
||||
counter.addAndGet(doExpungeEverythingQuery(txTemplate, ResourceIndexedSearchParamCoords.class));
|
||||
counter.addAndGet(doExpungeEverythingQuery(txTemplate, ResourceIndexedCompositeStringUnique.class));
|
||||
counter.addAndGet(doExpungeEverythingQuery(txTemplate, ResourceLink.class));
|
||||
counter.addAndGet(doExpungeEverythingQuery(txTemplate, SearchResult.class));
|
||||
counter.addAndGet(doExpungeEverythingQuery(txTemplate, SearchInclude.class));
|
||||
counter.addAndGet(doExpungeEverythingQuery(txTemplate, TermConceptParentChildLink.class));
|
||||
counter.addAndGet(doExpungeEverythingQuery(txTemplate, TermConceptMapGroupElementTarget.class));
|
||||
counter.addAndGet(doExpungeEverythingQuery(txTemplate, TermConceptMapGroupElement.class));
|
||||
counter.addAndGet(doExpungeEverythingQuery(txTemplate, TermConceptMapGroup.class));
|
||||
counter.addAndGet(doExpungeEverythingQuery(txTemplate, TermConceptMap.class));
|
||||
counter.addAndGet(doExpungeEverythingQuery(txTemplate, TermConceptProperty.class));
|
||||
counter.addAndGet(doExpungeEverythingQuery(txTemplate, TermConceptDesignation.class));
|
||||
counter.addAndGet(doExpungeEverythingQuery(txTemplate, TermConcept.class));
|
||||
txTemplate.execute(t -> {
|
||||
counter.addAndGet(doExpungeEverythingQuery("DELETE from " + SearchParamPresent.class.getSimpleName() + " d"));
|
||||
counter.addAndGet(doExpungeEverythingQuery("DELETE from " + ForcedId.class.getSimpleName() + " d"));
|
||||
counter.addAndGet(doExpungeEverythingQuery("DELETE from " + ResourceIndexedSearchParamDate.class.getSimpleName() + " d"));
|
||||
counter.addAndGet(doExpungeEverythingQuery("DELETE from " + ResourceIndexedSearchParamNumber.class.getSimpleName() + " d"));
|
||||
counter.addAndGet(doExpungeEverythingQuery("DELETE from " + ResourceIndexedSearchParamQuantity.class.getSimpleName() + " d"));
|
||||
counter.addAndGet(doExpungeEverythingQuery("DELETE from " + ResourceIndexedSearchParamString.class.getSimpleName() + " d"));
|
||||
counter.addAndGet(doExpungeEverythingQuery("DELETE from " + ResourceIndexedSearchParamToken.class.getSimpleName() + " d"));
|
||||
counter.addAndGet(doExpungeEverythingQuery("DELETE from " + ResourceIndexedSearchParamUri.class.getSimpleName() + " d"));
|
||||
counter.addAndGet(doExpungeEverythingQuery("DELETE from " + ResourceIndexedSearchParamCoords.class.getSimpleName() + " d"));
|
||||
counter.addAndGet(doExpungeEverythingQuery("DELETE from " + ResourceIndexedCompositeStringUnique.class.getSimpleName() + " d"));
|
||||
counter.addAndGet(doExpungeEverythingQuery("DELETE from " + ResourceLink.class.getSimpleName() + " d"));
|
||||
counter.addAndGet(doExpungeEverythingQuery("DELETE from " + SearchResult.class.getSimpleName() + " d"));
|
||||
counter.addAndGet(doExpungeEverythingQuery("DELETE from " + SearchInclude.class.getSimpleName() + " d"));
|
||||
counter.addAndGet(doExpungeEverythingQuery("DELETE from " + TermConceptParentChildLink.class.getSimpleName() + " d"));
|
||||
return null;
|
||||
});
|
||||
txTemplate.execute(t -> {
|
||||
counter.addAndGet(doExpungeEverythingQuery("DELETE from " + TermConceptMapGroupElementTarget.class.getSimpleName() + " d"));
|
||||
counter.addAndGet(doExpungeEverythingQuery("DELETE from " + TermConceptMapGroupElement.class.getSimpleName() + " d"));
|
||||
counter.addAndGet(doExpungeEverythingQuery("DELETE from " + TermConceptMapGroup.class.getSimpleName() + " d"));
|
||||
counter.addAndGet(doExpungeEverythingQuery("DELETE from " + TermConceptMap.class.getSimpleName() + " d"));
|
||||
return null;
|
||||
});
|
||||
txTemplate.execute(t -> {
|
||||
counter.addAndGet(doExpungeEverythingQuery("DELETE from " + TermConceptProperty.class.getSimpleName() + " d"));
|
||||
counter.addAndGet(doExpungeEverythingQuery("DELETE from " + TermConceptDesignation.class.getSimpleName() + " d"));
|
||||
counter.addAndGet(doExpungeEverythingQuery("DELETE from " + TermConcept.class.getSimpleName() + " d"));
|
||||
for (TermCodeSystem next : myEntityManager.createQuery("SELECT c FROM " + TermCodeSystem.class.getName() + " c", TermCodeSystem.class).getResultList()) {
|
||||
next.setCurrentVersion(null);
|
||||
myEntityManager.merge(next);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
counter.addAndGet(doExpungeEverythingQuery(txTemplate, TermCodeSystemVersion.class));
|
||||
counter.addAndGet(doExpungeEverythingQuery(txTemplate, TermCodeSystem.class));
|
||||
counter.addAndGet(doExpungeEverythingQuery(txTemplate, SubscriptionTable.class));
|
||||
counter.addAndGet(doExpungeEverythingQuery(txTemplate, ResourceHistoryTag.class));
|
||||
counter.addAndGet(doExpungeEverythingQuery(txTemplate, ResourceTag.class));
|
||||
counter.addAndGet(doExpungeEverythingQuery(txTemplate, TagDefinition.class));
|
||||
counter.addAndGet(doExpungeEverythingQuery(txTemplate, ResourceHistoryTable.class));
|
||||
counter.addAndGet(doExpungeEverythingQuery(txTemplate, ResourceTable.class));
|
||||
txTemplate.execute(t -> {
|
||||
counter.addAndGet(doExpungeEverythingQuery("DELETE from " + TermCodeSystemVersion.class.getSimpleName() + " d"));
|
||||
counter.addAndGet(doExpungeEverythingQuery("DELETE from " + TermCodeSystem.class.getSimpleName() + " d"));
|
||||
return null;
|
||||
});
|
||||
txTemplate.execute(t -> {
|
||||
counter.addAndGet(doExpungeEverythingQuery("DELETE from " + SubscriptionTable.class.getSimpleName() + " d"));
|
||||
counter.addAndGet(doExpungeEverythingQuery("DELETE from " + ResourceHistoryTag.class.getSimpleName() + " d"));
|
||||
counter.addAndGet(doExpungeEverythingQuery("DELETE from " + ResourceTag.class.getSimpleName() + " d"));
|
||||
counter.addAndGet(doExpungeEverythingQuery("DELETE from " + TagDefinition.class.getSimpleName() + " d"));
|
||||
counter.addAndGet(doExpungeEverythingQuery("DELETE from " + ResourceHistoryTable.class.getSimpleName() + " d"));
|
||||
counter.addAndGet(doExpungeEverythingQuery("DELETE from " + ResourceTable.class.getSimpleName() + " d"));
|
||||
counter.addAndGet(doExpungeEverythingQuery("DELETE from " + org.hibernate.search.jpa.Search.class.getSimpleName() + " d"));
|
||||
return null;
|
||||
});
|
||||
|
@ -110,10 +105,42 @@ public class ExpungeEverythingService {
|
|||
ourLog.info("COMPLETED GLOBAL $expunge - Deleted {} rows", counter.get());
|
||||
}
|
||||
|
||||
private int doExpungeEverythingQuery(TransactionTemplate txTemplate, Class<?> theEntityType) {
|
||||
|
||||
int outcome = 0;
|
||||
while (true) {
|
||||
StopWatch sw = new StopWatch();
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
int count = txTemplate.execute(t -> {
|
||||
CriteriaBuilder cb = myEntityManager.getCriteriaBuilder();
|
||||
CriteriaQuery<?> cq = cb.createQuery(theEntityType);
|
||||
cq.from(theEntityType);
|
||||
TypedQuery<?> query = myEntityManager.createQuery(cq);
|
||||
query.setMaxResults(1000);
|
||||
List<?> results = query.getResultList();
|
||||
for (Object result : results) {
|
||||
myEntityManager.remove(result);
|
||||
}
|
||||
return results.size();
|
||||
});
|
||||
|
||||
outcome += count;
|
||||
if (count == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
ourLog.info("Have deleted {} entities of type {} in {}", outcome, theEntityType.getSimpleName(), sw.toString());
|
||||
}
|
||||
|
||||
return outcome;
|
||||
}
|
||||
|
||||
private int doExpungeEverythingQuery(String theQuery) {
|
||||
StopWatch sw = new StopWatch();
|
||||
int outcome = myEntityManager.createQuery(theQuery).executeUpdate();
|
||||
ourLog.debug("Query affected {} rows in {}: {}", outcome, sw.toString(), theQuery);
|
||||
return outcome;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,6 +6,13 @@
|
|||
<title>HAPI FHIR Changelog</title>
|
||||
</properties>
|
||||
<body>
|
||||
<release version="4.0.0" date="TBD" description="Igloo">
|
||||
<action type="add">
|
||||
The $expunge global everything operation has been refactored to do deletes
|
||||
in small batches. This change will likely reduce performance, but does allow
|
||||
for the operation to succeed without timing out in larger system.
|
||||
</action>
|
||||
</release>
|
||||
<release version="3.8.0" date="2019-05-30" description="Hippo">
|
||||
<action type="fix">
|
||||
A potential security vulnerability in the hapi-fhir-testpage-overlay project was corrected: A URL
|
||||
|
|
Loading…
Reference in New Issue