Fix deadlock

This commit is contained in:
James Agnew 2017-07-20 11:00:17 -04:00
parent a220405e97
commit 9d08e1e211
3 changed files with 40 additions and 50 deletions

View File

@ -3,6 +3,9 @@ package ca.uhn.fhir.jpa.dao.data;
import java.util.Collection;
import java.util.Date;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Slice;
/*
* #%L
* HAPI FHIR JPA Server
@ -36,7 +39,7 @@ public interface ISearchDao extends JpaRepository<Search, Long> {
public Search findByUuid(@Param("uuid") String theUuid);
@Query("SELECT s.myId FROM Search s WHERE s.mySearchLastReturned < :cutoff")
public Collection<Long> findWhereLastReturnedBefore(@Param("cutoff") Date theCutoff);
public Slice<Long> findWhereLastReturnedBefore(@Param("cutoff") Date theCutoff, Pageable thePage);
// @Query("SELECT s FROM Search s WHERE s.myCreated < :cutoff")
// public Collection<Search> findWhereCreatedBefore(@Param("cutoff") Date theCutoff);

View File

@ -1,44 +1,23 @@
package ca.uhn.fhir.jpa.search;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2017 University Health Network
* %%
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.util.Collection;
import java.util.Date;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Slice;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
import com.google.common.annotations.VisibleForTesting;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.dao.data.ISearchDao;
import ca.uhn.fhir.jpa.dao.data.ISearchIncludeDao;
import ca.uhn.fhir.jpa.dao.data.ISearchResultDao;
import ca.uhn.fhir.jpa.dao.data.*;
import ca.uhn.fhir.jpa.entity.Search;
/**
@ -47,7 +26,6 @@ import ca.uhn.fhir.jpa.entity.Search;
public class StaleSearchDeletingSvcImpl implements IStaleSearchDeletingSvc {
public static final long DEFAULT_CUTOFF_SLACK = 10 * DateUtils.MILLIS_PER_SECOND;
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(StaleSearchDeletingSvcImpl.class);
/*
* We give a bit of extra leeway just to avoid race conditions where a query result
@ -71,41 +49,47 @@ public class StaleSearchDeletingSvcImpl implements IStaleSearchDeletingSvc {
@Autowired
private PlatformTransactionManager myTransactionManager;
protected void deleteSearch(final Long theSearchPid) {
TransactionTemplate tt = new TransactionTemplate(myTransactionManager);
tt.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus theArg0) {
Search searchToDelete = mySearchDao.findOne(theSearchPid);
ourLog.info("Deleting search {}/{} - Created[{}] -- Last returned[{}]", searchToDelete.getId(), searchToDelete.getUuid(), searchToDelete.getCreated(), searchToDelete.getSearchLastReturned());
mySearchIncludeDao.deleteForSearch(searchToDelete.getId());
mySearchResultDao.deleteForSearch(searchToDelete.getId());
mySearchDao.delete(searchToDelete);
}
});
private void deleteSearch(final Long theSearchPid) {
Search searchToDelete = mySearchDao.findOne(theSearchPid);
ourLog.info("Deleting search {}/{} - Created[{}] -- Last returned[{}]", searchToDelete.getId(), searchToDelete.getUuid(), searchToDelete.getCreated(), searchToDelete.getSearchLastReturned());
mySearchIncludeDao.deleteForSearch(searchToDelete.getId());
mySearchResultDao.deleteForSearch(searchToDelete.getId());
mySearchDao.delete(searchToDelete);
}
@Override
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void pollForStaleSearchesAndDeleteThem() {
long cutoffMillis = myDaoConfig.getExpireSearchResultsAfterMillis();
if (myDaoConfig.getReuseCachedSearchResultsForMillis() != null) {
cutoffMillis = Math.max(cutoffMillis, myDaoConfig.getReuseCachedSearchResultsForMillis());
}
Date cutoff = new Date((System.currentTimeMillis() - cutoffMillis) - myCutoffSlack);
final Date cutoff = new Date((System.currentTimeMillis() - cutoffMillis) - myCutoffSlack);
ourLog.debug("Searching for searches which are before {}", cutoff);
Collection<Long> toDelete = mySearchDao.findWhereLastReturnedBefore(cutoff);
if (!toDelete.isEmpty()) {
for (final Long next : toDelete) {
deleteSearch(next);
TransactionTemplate tt = new TransactionTemplate(myTransactionManager);
int count = tt.execute(new TransactionCallback<Integer>() {
@Override
public Integer doInTransaction(TransactionStatus theStatus) {
Slice<Long> toDelete = mySearchDao.findWhereLastReturnedBefore(cutoff, new PageRequest(0, 1000));
for (final Long next : toDelete) {
deleteSearch(next);
}
return toDelete.getContent().size();
}
});
long total = tt.execute(new TransactionCallback<Long>() {
@Override
public Long doInTransaction(TransactionStatus theStatus) {
return mySearchDao.count();
}
});
ourLog.info("Deleted {} searches, {} remaining", count, total);
ourLog.info("Deleted {} searches, {} remaining", toDelete.size(), mySearchDao.count());
}
}
@Scheduled(fixedDelay = DEFAULT_CUTOFF_SLACK)

View File

@ -176,6 +176,9 @@
elements are a choice type (i.e. named "foo[x]"). Thanks to
GitHub user @CarthageKing for the pull request!
</action>
<action type="fix">
Fix potential deadlock in stale search deleting task in JPA server
</action>
</release>
<release version="2.5" date="2017-06-08">
<action type="fix">