|
21 | 21 |
|
22 | 22 | import ca.uhn.fhir.context.FhirContext; |
23 | 23 | import ca.uhn.fhir.context.RuntimeResourceDefinition; |
| 24 | +import ca.uhn.fhir.i18n.Msg; |
24 | 25 | import ca.uhn.fhir.interceptor.model.RequestPartitionId; |
| 26 | +import ca.uhn.fhir.jpa.api.config.JpaStorageSettings; |
25 | 27 | import ca.uhn.fhir.jpa.api.dao.DaoRegistry; |
26 | 28 | import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao; |
27 | 29 | import ca.uhn.fhir.jpa.api.pid.EmptyResourcePidList; |
|
39 | 41 | import ca.uhn.fhir.rest.api.SortSpec; |
40 | 42 | import ca.uhn.fhir.rest.api.server.SystemRequestDetails; |
41 | 43 | import ca.uhn.fhir.rest.api.server.storage.IResourcePersistentId; |
42 | | -import ca.uhn.fhir.rest.param.DateRangeParam; |
43 | | -import ca.uhn.fhir.util.DateRangeUtil; |
44 | | -import org.springframework.beans.factory.annotation.Autowired; |
| 44 | +import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; |
45 | 45 | import org.springframework.data.domain.Pageable; |
46 | 46 | import org.springframework.data.domain.Slice; |
47 | 47 |
|
| 48 | +import java.util.ArrayList; |
48 | 49 | import java.util.Date; |
49 | 50 | import java.util.List; |
50 | 51 | import java.util.stream.Collectors; |
51 | 52 | import javax.annotation.Nonnull; |
52 | 53 | import javax.annotation.Nullable; |
53 | 54 |
|
54 | | -import static org.apache.commons.collections4.CollectionUtils.isNotEmpty; |
55 | | - |
56 | 55 | public class Batch2DaoSvcImpl implements IBatch2DaoSvc { |
| 56 | + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(Batch2DaoSvcImpl.class); |
| 57 | + |
| 58 | + private final IResourceTableDao myResourceTableDao; |
57 | 59 |
|
58 | | - @Autowired |
59 | | - private IResourceTableDao myResourceTableDao; |
| 60 | + private final MatchUrlService myMatchUrlService; |
60 | 61 |
|
61 | | - @Autowired |
62 | | - private MatchUrlService myMatchUrlService; |
| 62 | + private final DaoRegistry myDaoRegistry; |
63 | 63 |
|
64 | | - @Autowired |
65 | | - private DaoRegistry myDaoRegistry; |
| 64 | + private final FhirContext myFhirContext; |
66 | 65 |
|
67 | | - @Autowired |
68 | | - private FhirContext myFhirContext; |
| 66 | + private final IHapiTransactionService myTransactionService; |
69 | 67 |
|
70 | | - @Autowired |
71 | | - private IHapiTransactionService myTransactionService; |
| 68 | + private final JpaStorageSettings myJpaStorageSettings; |
72 | 69 |
|
73 | 70 | @Override |
74 | 71 | public boolean isAllResourceTypeSupported() { |
75 | 72 | return true; |
76 | 73 | } |
77 | 74 |
|
| 75 | + public Batch2DaoSvcImpl( |
| 76 | + IResourceTableDao theResourceTableDao, |
| 77 | + MatchUrlService theMatchUrlService, |
| 78 | + DaoRegistry theDaoRegistry, |
| 79 | + FhirContext theFhirContext, |
| 80 | + IHapiTransactionService theTransactionService, |
| 81 | + JpaStorageSettings theJpaStorageSettings) { |
| 82 | + myResourceTableDao = theResourceTableDao; |
| 83 | + myMatchUrlService = theMatchUrlService; |
| 84 | + myDaoRegistry = theDaoRegistry; |
| 85 | + myFhirContext = theFhirContext; |
| 86 | + myTransactionService = theTransactionService; |
| 87 | + myJpaStorageSettings = theJpaStorageSettings; |
| 88 | + } |
| 89 | + |
78 | 90 | @Override |
79 | 91 | public IResourcePidList fetchResourceIdsPage( |
80 | | - Date theStart, |
81 | | - Date theEnd, |
82 | | - @Nonnull Integer thePageSize, |
83 | | - @Nullable RequestPartitionId theRequestPartitionId, |
84 | | - @Nullable String theUrl) { |
| 92 | + Date theStart, Date theEnd, @Nullable RequestPartitionId theRequestPartitionId, @Nullable String theUrl) { |
85 | 93 | return myTransactionService |
86 | 94 | .withSystemRequest() |
87 | 95 | .withRequestPartitionId(theRequestPartitionId) |
88 | 96 | .execute(() -> { |
89 | 97 | if (theUrl == null) { |
90 | | - return fetchResourceIdsPageNoUrl(theStart, theEnd, thePageSize, theRequestPartitionId); |
| 98 | + return fetchResourceIdsPageNoUrl(theStart, theEnd, theRequestPartitionId); |
91 | 99 | } else { |
92 | | - return fetchResourceIdsPageWithUrl( |
93 | | - theStart, theEnd, thePageSize, theUrl, theRequestPartitionId); |
| 100 | + return fetchResourceIdsPageWithUrl(theEnd, theUrl, theRequestPartitionId); |
94 | 101 | } |
95 | 102 | }); |
96 | 103 | } |
97 | 104 |
|
98 | | - private IResourcePidList fetchResourceIdsPageWithUrl( |
99 | | - Date theStart, Date theEnd, int thePageSize, String theUrl, RequestPartitionId theRequestPartitionId) { |
| 105 | + @Nonnull |
| 106 | + private HomogeneousResourcePidList fetchResourceIdsPageWithUrl( |
| 107 | + Date theEnd, @Nonnull String theUrl, @Nullable RequestPartitionId theRequestPartitionId) { |
| 108 | + if (!theUrl.contains("?")) { |
| 109 | + throw new InternalErrorException(Msg.code(2422) + "this should never happen: URL is missing a '?'"); |
| 110 | + } |
| 111 | + |
| 112 | + final Integer internalSynchronousSearchSize = myJpaStorageSettings.getInternalSynchronousSearchSize(); |
| 113 | + |
| 114 | + if (internalSynchronousSearchSize == null || internalSynchronousSearchSize <= 0) { |
| 115 | + throw new InternalErrorException(Msg.code(2423) |
| 116 | + + "this should never happen: internalSynchronousSearchSize is null or less than or equal to 0"); |
| 117 | + } |
| 118 | + |
| 119 | + List<IResourcePersistentId> currentIds = fetchResourceIdsPageWithUrl(0, theUrl, theRequestPartitionId); |
| 120 | + ourLog.debug("FIRST currentIds: {}", currentIds.size()); |
100 | 121 |
|
| 122 | + final List<IResourcePersistentId> allIds = new ArrayList<>(currentIds); |
| 123 | + |
| 124 | + while (internalSynchronousSearchSize < currentIds.size()) { |
| 125 | + // Ensure the offset is set to the last ID in the cumulative List, otherwise, we'll be stuck in an infinite |
| 126 | + // loop here: |
| 127 | + currentIds = fetchResourceIdsPageWithUrl(allIds.size(), theUrl, theRequestPartitionId); |
| 128 | + ourLog.debug("NEXT currentIds: {}", currentIds.size()); |
| 129 | + |
| 130 | + allIds.addAll(currentIds); |
| 131 | + } |
| 132 | + |
| 133 | + final String resourceType = theUrl.substring(0, theUrl.indexOf('?')); |
| 134 | + |
| 135 | + return new HomogeneousResourcePidList(resourceType, allIds, theEnd, theRequestPartitionId); |
| 136 | + } |
| 137 | + |
| 138 | + private List<IResourcePersistentId> fetchResourceIdsPageWithUrl( |
| 139 | + int theOffset, String theUrl, RequestPartitionId theRequestPartitionId) { |
101 | 140 | String resourceType = theUrl.substring(0, theUrl.indexOf('?')); |
102 | 141 | RuntimeResourceDefinition def = myFhirContext.getResourceDefinition(resourceType); |
103 | 142 |
|
104 | 143 | SearchParameterMap searchParamMap = myMatchUrlService.translateMatchUrl(theUrl, def); |
105 | | - searchParamMap.setSort(new SortSpec(Constants.PARAM_LASTUPDATED, SortOrderEnum.ASC)); |
106 | | - DateRangeParam chunkDateRange = |
107 | | - DateRangeUtil.narrowDateRange(searchParamMap.getLastUpdated(), theStart, theEnd); |
108 | | - searchParamMap.setLastUpdated(chunkDateRange); |
109 | | - searchParamMap.setCount(thePageSize); |
| 144 | + searchParamMap.setSort(new SortSpec(Constants.PARAM_ID, SortOrderEnum.ASC)); |
| 145 | + searchParamMap.setOffset(theOffset); |
| 146 | + searchParamMap.setLoadSynchronousUpTo(myJpaStorageSettings.getInternalSynchronousSearchSize() + 1); |
110 | 147 |
|
111 | 148 | IFhirResourceDao<?> dao = myDaoRegistry.getResourceDao(resourceType); |
112 | 149 | SystemRequestDetails request = new SystemRequestDetails(); |
113 | 150 | request.setRequestPartitionId(theRequestPartitionId); |
114 | | - List<IResourcePersistentId> ids = dao.searchForIds(searchParamMap, request); |
115 | | - |
116 | | - Date lastDate = null; |
117 | | - if (isNotEmpty(ids)) { |
118 | | - IResourcePersistentId lastResourcePersistentId = ids.get(ids.size() - 1); |
119 | | - lastDate = dao.readByPid(lastResourcePersistentId, true).getMeta().getLastUpdated(); |
120 | | - } |
121 | 151 |
|
122 | | - return new HomogeneousResourcePidList(resourceType, ids, lastDate, theRequestPartitionId); |
| 152 | + return dao.searchForIds(searchParamMap, request); |
123 | 153 | } |
124 | 154 |
|
125 | 155 | @Nonnull |
126 | 156 | private IResourcePidList fetchResourceIdsPageNoUrl( |
127 | | - Date theStart, Date theEnd, int thePagesize, RequestPartitionId theRequestPartitionId) { |
128 | | - Pageable page = Pageable.ofSize(thePagesize); |
| 157 | + Date theStart, Date theEnd, RequestPartitionId theRequestPartitionId) { |
| 158 | + final Pageable page = Pageable.unpaged(); |
129 | 159 | Slice<Object[]> slice; |
130 | 160 | if (theRequestPartitionId == null || theRequestPartitionId.isAllPartitions()) { |
131 | 161 | slice = myResourceTableDao.findIdsTypesAndUpdateTimesOfResourcesWithinUpdatedRangeOrderedFromOldest( |
|
0 commit comments