Add implementation and changelog, and test. (#3554)
* Add implementation and changelog, and test. * Add daoconfig settings * Updatae test * Rename deexternalize -> autoinflate
This commit is contained in:
parent
d20c6a7d25
commit
578d42c955
|
@ -0,0 +1,4 @@
|
|||
type: fix
|
||||
issue: 3553
|
||||
jira: SMILE-3964
|
||||
title: "Added a new setting to BinaryStorageInterceptor which allows you to disable binary de-externalization during resource reads."
|
|
@ -261,8 +261,11 @@ public class JpaConfig {
|
|||
|
||||
@Bean(name = "myBinaryStorageInterceptor")
|
||||
@Lazy
|
||||
public BinaryStorageInterceptor binaryStorageInterceptor() {
|
||||
return new BinaryStorageInterceptor();
|
||||
public BinaryStorageInterceptor binaryStorageInterceptor(DaoConfig theDaoConfig) {
|
||||
BinaryStorageInterceptor interceptor = new BinaryStorageInterceptor();
|
||||
interceptor.setAllowAutoInflateBinaries(theDaoConfig.isAllowAutoInflateBinaries());
|
||||
interceptor.setAutoInflateBinariesMaximumSize(theDaoConfig.getAutoInflateBinariesMaximumBytes());
|
||||
return interceptor;
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
|
|
@ -20,6 +20,8 @@ import org.slf4j.Logger;
|
|||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.blankOrNullString;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
|
@ -47,6 +49,7 @@ public class BinaryStorageInterceptorR4Test extends BaseResourceProviderR4Test {
|
|||
super.before();
|
||||
myStorageSvc.setMinimumBinarySize(10);
|
||||
myDaoConfig.setExpungeEnabled(true);
|
||||
|
||||
myInterceptorRegistry.registerInterceptor(myBinaryStorageInterceptor);
|
||||
}
|
||||
|
||||
|
@ -56,7 +59,8 @@ public class BinaryStorageInterceptorR4Test extends BaseResourceProviderR4Test {
|
|||
super.after();
|
||||
myStorageSvc.setMinimumBinarySize(0);
|
||||
myDaoConfig.setExpungeEnabled(new DaoConfig().isExpungeEnabled());
|
||||
myBinaryStorageInterceptor.setAutoDeExternalizeMaximumBytes(new BinaryStorageInterceptor().getAutoDeExternalizeMaximumBytes());
|
||||
myBinaryStorageInterceptor.setAutoInflateBinariesMaximumSize(new BinaryStorageInterceptor().getAutoInflateBinariesMaximumSize());
|
||||
myBinaryStorageInterceptor.setAllowAutoInflateBinaries(new BinaryStorageInterceptor().isAllowAutoInflateBinaries());
|
||||
|
||||
MemoryBinaryStorageSvcImpl binaryStorageSvc = (MemoryBinaryStorageSvcImpl) myBinaryStorageSvc;
|
||||
binaryStorageSvc.clear();
|
||||
|
@ -109,6 +113,29 @@ public class BinaryStorageInterceptorR4Test extends BaseResourceProviderR4Test {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateAndRetrieveBinary_ServerAssignedId_ExternalizedBinary_DoNotRehydrate() {
|
||||
myBinaryStorageInterceptor.setAllowAutoInflateBinaries(false);
|
||||
|
||||
// Create a resource with a big enough binary
|
||||
Binary binary = new Binary();
|
||||
binary.setContentType("application/octet-stream");
|
||||
binary.setData(SOME_BYTES);
|
||||
DaoMethodOutcome outcome = myBinaryDao.create(binary);
|
||||
|
||||
// Make sure it was externalized
|
||||
IIdType id = outcome.getId().toUnqualifiedVersionless();
|
||||
String encoded = myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome.getResource());
|
||||
ourLog.info("Encoded: {}", encoded);
|
||||
assertThat(encoded, containsString(HapiExtensions.EXT_EXTERNALIZED_BINARY_ID));
|
||||
assertThat(encoded, not(containsString("\"data\"")));
|
||||
|
||||
// Now read it back and make sure it was not de-externalized
|
||||
Binary output = myBinaryDao.read(id, mySrd);
|
||||
assertEquals("application/octet-stream", output.getContentType());
|
||||
assertArrayEquals(null, output.getData());
|
||||
assertThat(output.getDataElement().getExtensionByUrl(HapiExtensions.EXT_EXTERNALIZED_BINARY_ID), is(notNullValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateAndRetrieveBinary_ServerAssignedId_NonExternalizedBinary() {
|
||||
|
@ -294,7 +321,7 @@ public class BinaryStorageInterceptorR4Test extends BaseResourceProviderR4Test {
|
|||
|
||||
@Test
|
||||
public void testRetrieveBinaryAboveRetrievalThreshold() {
|
||||
myBinaryStorageInterceptor.setAutoDeExternalizeMaximumBytes(5);
|
||||
myBinaryStorageInterceptor.setAutoInflateBinariesMaximumSize(5);
|
||||
|
||||
// Create a resource with a big enough binary
|
||||
Binary binary = new Binary();
|
||||
|
|
|
@ -9,6 +9,7 @@ import ca.uhn.fhir.util.HapiExtensions;
|
|||
import ca.uhn.fhir.validation.FhirValidator;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.collect.Sets;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
|
@ -298,6 +299,15 @@ public class DaoConfig {
|
|||
*/
|
||||
private boolean myConcurrentBundleValidation;
|
||||
|
||||
/**
|
||||
* Since 6.0.0
|
||||
*/
|
||||
private boolean myAllowAutoInflateBinaries = true;
|
||||
/**
|
||||
* Since 6.0.0
|
||||
*/
|
||||
private long myAutoInflateBinariesMaximumBytes = 10 * FileUtils.ONE_MB;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
|
@ -2793,12 +2803,61 @@ public class DaoConfig {
|
|||
* This setting indicates if a cross-partition subscription can be made.
|
||||
*
|
||||
* @see ModelConfig#setCrossPartitionSubscription(boolean)
|
||||
* @since 7.5.0
|
||||
* @since 5.7.0
|
||||
*/
|
||||
public void setCrossPartitionSubscription(boolean theAllowCrossPartitionSubscription) {
|
||||
this.myModelConfig.setCrossPartitionSubscription(theAllowCrossPartitionSubscription);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* This setting indicates whether binaries are allowed to be automatically inflated from external storage during requests.
|
||||
* Default is true.
|
||||
*
|
||||
* @since 6.0.0
|
||||
* @return whether binaries are allowed to be automatically inflated from external storage during requests.
|
||||
*/
|
||||
public boolean isAllowAutoInflateBinaries() {
|
||||
return myAllowAutoInflateBinaries;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This setting indicates whether binaries are allowed to be automatically inflated from external storage during requests.
|
||||
* Default is true.
|
||||
*
|
||||
* @since 6.0.0
|
||||
* @param theAllowAutoDeExternalizingBinaries the value to set.
|
||||
*/
|
||||
public void setAllowAutoInflateBinaries(boolean theAllowAutoDeExternalizingBinaries) {
|
||||
myAllowAutoInflateBinaries = theAllowAutoDeExternalizingBinaries;
|
||||
}
|
||||
|
||||
/**
|
||||
* This setting controls how many bytes of binaries will be automatically inflated from external storage during requests.
|
||||
* which contain binary data.
|
||||
* Default is 10MB
|
||||
*
|
||||
* @since 6.0.0
|
||||
* @param theAutoInflateBinariesMaximumBytes the maximum number of bytes to de-externalize.
|
||||
*/
|
||||
public void setAutoInflateBinariesMaximumBytes(long theAutoInflateBinariesMaximumBytes) {
|
||||
myAutoInflateBinariesMaximumBytes = theAutoInflateBinariesMaximumBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* This setting controls how many bytes of binaries will be automatically inflated from external storage during requests.
|
||||
* which contain binary data.
|
||||
* Default is 10MB
|
||||
*
|
||||
* @since 6.0.0
|
||||
* @return the number of bytes to de-externalize during requests.
|
||||
*/
|
||||
public long getAutoInflateBinariesMaximumBytes() {
|
||||
return myAutoInflateBinariesMaximumBytes;
|
||||
}
|
||||
|
||||
public enum StoreMetaSourceInformationEnum {
|
||||
NONE(false, false),
|
||||
SOURCE_URI(true, false),
|
||||
|
|
|
@ -76,22 +76,23 @@ public class BinaryStorageInterceptor {
|
|||
private BinaryAccessProvider myBinaryAccessProvider;
|
||||
private Class<? extends IPrimitiveType<byte[]>> myBinaryType;
|
||||
private String myDeferredListKey;
|
||||
private long myAutoDeExternalizeMaximumBytes = 10 * FileUtils.ONE_MB;
|
||||
private long myAutoInflateBinariesMaximumBytes = 10 * FileUtils.ONE_MB;
|
||||
private boolean myAllowAutoInflateBinaries = true;
|
||||
|
||||
/**
|
||||
* Any externalized binaries will be rehydrated if their size is below this thhreshold when
|
||||
* reading the resource back. Default is 10MB.
|
||||
*/
|
||||
public long getAutoDeExternalizeMaximumBytes() {
|
||||
return myAutoDeExternalizeMaximumBytes;
|
||||
public long getAutoInflateBinariesMaximumSize() {
|
||||
return myAutoInflateBinariesMaximumBytes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Any externalized binaries will be rehydrated if their size is below this thhreshold when
|
||||
* reading the resource back. Default is 10MB.
|
||||
*/
|
||||
public void setAutoDeExternalizeMaximumBytes(long theAutoDeExternalizeMaximumBytes) {
|
||||
myAutoDeExternalizeMaximumBytes = theAutoDeExternalizeMaximumBytes;
|
||||
public void setAutoInflateBinariesMaximumSize(long theAutoInflateBinariesMaximumBytes) {
|
||||
myAutoInflateBinariesMaximumBytes = theAutoInflateBinariesMaximumBytes;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
@ -248,6 +249,10 @@ public class BinaryStorageInterceptor {
|
|||
|
||||
@Hook(Pointcut.STORAGE_PRESHOW_RESOURCES)
|
||||
public void preShow(IPreResourceShowDetails theDetails) throws IOException {
|
||||
if (!isAllowAutoInflateBinaries()) {
|
||||
return;
|
||||
}
|
||||
|
||||
long unmarshalledByteCount = 0;
|
||||
|
||||
for (IBaseResource nextResource : theDetails) {
|
||||
|
@ -265,7 +270,7 @@ public class BinaryStorageInterceptor {
|
|||
throw new InvalidRequestException(Msg.code(1330) + msg);
|
||||
}
|
||||
|
||||
if ((unmarshalledByteCount + blobDetails.getBytes()) < myAutoDeExternalizeMaximumBytes) {
|
||||
if ((unmarshalledByteCount + blobDetails.getBytes()) < myAutoInflateBinariesMaximumBytes) {
|
||||
|
||||
byte[] bytes = myBinaryStorageSvc.fetchBlob(resourceId, attachmentId.get());
|
||||
nextTarget.setData(bytes);
|
||||
|
@ -295,6 +300,14 @@ public class BinaryStorageInterceptor {
|
|||
return binaryTargets;
|
||||
}
|
||||
|
||||
public void setAllowAutoInflateBinaries(boolean theAllowAutoInflateBinaries) {
|
||||
myAllowAutoInflateBinaries = theAllowAutoInflateBinaries;
|
||||
}
|
||||
|
||||
public boolean isAllowAutoInflateBinaries() {
|
||||
return myAllowAutoInflateBinaries;
|
||||
}
|
||||
|
||||
private static class DeferredBinaryTarget {
|
||||
private final String myBlobId;
|
||||
private final IBinaryTarget myBinaryTarget;
|
||||
|
|
Loading…
Reference in New Issue