Merge pull request #1910 from jamesagnew/im_20200605_db_blob_mssql

Im 20200605 db blob mssql
This commit is contained in:
IanMMarshall 2020-06-09 13:48:53 -04:00 committed by GitHub
commit 926afd01f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 78 additions and 2 deletions

View File

@ -222,6 +222,11 @@ public class DaoConfig {
*/ */
private boolean myLastNEnabled = false; private boolean myLastNEnabled = false;
/**
* @since 5.1.0
*/
private boolean myPreloadBlobFromInputStream = false;
/** /**
* Constructor * Constructor
*/ */
@ -2083,4 +2088,42 @@ public class DaoConfig {
myMaximumDeleteConflictQueryCount = theMaximumDeleteConflictQueryCount; myMaximumDeleteConflictQueryCount = theMaximumDeleteConflictQueryCount;
} }
/**
* <p>
* This determines whether $binary-access-write operations should first load the InputStream into memory before persisting the
* contents to the database. This needs to be enabled for MS SQL Server as this DB requires that the blob size be known
* in advance.
* </p>
* <p>
* Note that this setting should be enabled with caution as it can lead to significant demands on memory.
* </p>
* <p>
* The default value for this setting is {@code false}.
* </p>
*
* @since 5.1.0
*/
public boolean isPreloadBlobFromInputStream() {
return myPreloadBlobFromInputStream;
}
/**
* <p>
* This determines whether $binary-access-write operations should first load the InputStream into memory before persisting the
* contents to the database. This needs to be enabled for MS SQL Server as this DB requires that the blob size be known
* in advance.
* </p>
* <p>
* Note that this setting should be enabled with caution as it can lead to significant demands on memory.
* </p>
* <p>
* The default value for this setting is {@code false}.
* </p>
*
* @since 5.1.0
*/
public void setPreloadBlobFromInputStream(Boolean thePreloadBlobFromInputStream) {
myPreloadBlobFromInputStream = thePreloadBlobFromInputStream;
}
} }

View File

@ -20,6 +20,7 @@ package ca.uhn.fhir.jpa.binstore;
* #L% * #L%
*/ */
import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.dao.data.IBinaryStorageEntityDao; import ca.uhn.fhir.jpa.dao.data.IBinaryStorageEntityDao;
import ca.uhn.fhir.jpa.model.entity.BinaryStorageEntity; import ca.uhn.fhir.jpa.model.entity.BinaryStorageEntity;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
@ -55,10 +56,12 @@ public class DatabaseBlobBinaryStorageSvcImpl extends BaseBinaryStorageSvcImpl {
private IBinaryStorageEntityDao myBinaryStorageEntityDao; private IBinaryStorageEntityDao myBinaryStorageEntityDao;
@Autowired @Autowired
private PlatformTransactionManager myPlatformTransactionManager; private PlatformTransactionManager myPlatformTransactionManager;
@Autowired
private DaoConfig myDaoConfig;
@Override @Override
@Transactional(Transactional.TxType.SUPPORTS) @Transactional(Transactional.TxType.SUPPORTS)
public StoredDetails storeBlob(IIdType theResourceId, String theBlobIdOrNull, String theContentType, InputStream theInputStream) { public StoredDetails storeBlob(IIdType theResourceId, String theBlobIdOrNull, String theContentType, InputStream theInputStream) throws IOException {
Date publishedDate = new Date(); Date publishedDate = new Date();
HashingInputStream hashingInputStream = createHashingInputStream(theInputStream); HashingInputStream hashingInputStream = createHashingInputStream(theInputStream);
@ -74,7 +77,13 @@ public class DatabaseBlobBinaryStorageSvcImpl extends BaseBinaryStorageSvcImpl {
Session session = (Session) myEntityManager.getDelegate(); Session session = (Session) myEntityManager.getDelegate();
LobHelper lobHelper = session.getLobHelper(); LobHelper lobHelper = session.getLobHelper();
Blob dataBlob = lobHelper.createBlob(countingInputStream, 0); Blob dataBlob;
if (myDaoConfig.isPreloadBlobFromInputStream()) {
byte[] loadedStream = IOUtils.toByteArray(countingInputStream);
dataBlob = lobHelper.createBlob(loadedStream);
} else {
dataBlob = lobHelper.createBlob(countingInputStream, 0);
}
entity.setBlob(dataBlob); entity.setBlob(dataBlob);
// Save the entity // Save the entity

View File

@ -1,9 +1,12 @@
package ca.uhn.fhir.jpa.binstore; package ca.uhn.fhir.jpa.binstore;
import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.dao.r4.BaseJpaR4Test; import ca.uhn.fhir.jpa.dao.r4.BaseJpaR4Test;
import ca.uhn.fhir.jpa.model.entity.BinaryStorageEntity; import ca.uhn.fhir.jpa.model.entity.BinaryStorageEntity;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import org.hl7.fhir.r4.model.IdType; import org.hl7.fhir.r4.model.IdType;
import org.junit.After;
import org.junit.Before;
import org.junit.Test; import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Qualifier;
@ -32,6 +35,21 @@ public class DatabaseBlobBinaryStorageSvcImplTest extends BaseJpaR4Test {
@Qualifier("databaseBlobBinaryStorageSvc") @Qualifier("databaseBlobBinaryStorageSvc")
private IBinaryStorageSvc mySvc; private IBinaryStorageSvc mySvc;
@Autowired
private DaoConfig myDaoConfig;
@Before
public void backupDaoConfig() {
defaultPreloadBlobFromInputStream = myDaoConfig.isPreloadBlobFromInputStream();
}
@After
public void restoreDaoConfig() {
myDaoConfig.setPreloadBlobFromInputStream(defaultPreloadBlobFromInputStream);
}
boolean defaultPreloadBlobFromInputStream;
@Test @Test
public void testStoreAndRetrieve() throws IOException { public void testStoreAndRetrieve() throws IOException {
@ -78,6 +96,12 @@ public class DatabaseBlobBinaryStorageSvcImplTest extends BaseJpaR4Test {
assertArrayEquals(SOME_BYTES, mySvc.fetchBlob(resourceId, outcome.getBlobId())); assertArrayEquals(SOME_BYTES, mySvc.fetchBlob(resourceId, outcome.getBlobId()));
} }
@Test
public void testStoreAndRetrieveWithPreload() throws IOException {
myDaoConfig.setPreloadBlobFromInputStream(true);
testStoreAndRetrieve();
}
@Test @Test
public void testStoreAndRetrieveWithManualId() throws IOException { public void testStoreAndRetrieveWithManualId() throws IOException {