JAMES-2583 Use PushBackInputStream for avoid unnecessary read whole InputStream contents when determining size of InputStreams
Project: http://git-wip-us.apache.org/repos/asf/james-project/repo Commit: http://git-wip-us.apache.org/repos/asf/james-project/commit/aa064ef6 Tree: http://git-wip-us.apache.org/repos/asf/james-project/tree/aa064ef6 Diff: http://git-wip-us.apache.org/repos/asf/james-project/diff/aa064ef6 Branch: refs/heads/master Commit: aa064ef64a224f01d4a7290d437da7d5938364c4 Parents: b48c491 Author: tran tien duc <[email protected]> Authored: Tue Nov 6 10:19:24 2018 +0700 Committer: Antoine Duprat <[email protected]> Committed: Wed Nov 7 14:12:19 2018 +0100 ---------------------------------------------------------------------- .../james/blob/joining/JoiningBlobStore.java | 22 +++++++--- .../blob/joining/JoiningBlobStoreTest.java | 44 ++++++++++++++++++++ 2 files changed, 61 insertions(+), 5 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/james-project/blob/aa064ef6/server/blob/blob-joining/src/main/java/org/apache/james/blob/joining/JoiningBlobStore.java ---------------------------------------------------------------------- diff --git a/server/blob/blob-joining/src/main/java/org/apache/james/blob/joining/JoiningBlobStore.java b/server/blob/blob-joining/src/main/java/org/apache/james/blob/joining/JoiningBlobStore.java index cd32a04..4548007 100644 --- a/server/blob/blob-joining/src/main/java/org/apache/james/blob/joining/JoiningBlobStore.java +++ b/server/blob/blob-joining/src/main/java/org/apache/james/blob/joining/JoiningBlobStore.java @@ -19,12 +19,13 @@ package org.apache.james.blob.joining; -import java.io.ByteArrayInputStream; +import java.io.IOException; import java.io.InputStream; +import java.io.PushbackInputStream; import java.util.Optional; import java.util.concurrent.CompletableFuture; +import java.util.function.Function; -import org.apache.commons.io.IOUtils; import org.apache.james.blob.api.BlobId; import org.apache.james.blob.api.BlobStore; import org.slf4j.Logger; @@ -36,6 +37,7 @@ import com.google.common.annotations.VisibleForTesting; public class JoiningBlobStore implements BlobStore { private static final Logger LOGGER = LoggerFactory.getLogger(JoiningBlobStore.class); + private static final int UN_AVAILABLE = -1; private final BlobStore primaryBlobStore; private final BlobStore secondaryBlobStore; @@ -78,12 +80,22 @@ public class JoiningBlobStore implements BlobStore { private InputStream readFallBackIfEmptyResult(BlobId blobId) { return Optional.ofNullable(primaryBlobStore.read(blobId)) - .map(Throwing.<InputStream, byte[]>function(IOUtils::toByteArray).sneakyThrow()) - .filter(this::hasContent) - .<InputStream>map(ByteArrayInputStream::new) + .map(PushbackInputStream::new) + .filter(Throwing.predicate(this::streamHasContent).sneakyThrow()) + .<InputStream>map(Function.identity()) .orElseGet(() -> secondaryBlobStore.read(blobId)); } + @VisibleForTesting + boolean streamHasContent(PushbackInputStream pushBackIS) throws IOException { + int byteRead = pushBackIS.read(); + if (byteRead != UN_AVAILABLE) { + pushBackIS.unread(byteRead); + return true; + } + return false; + } + private CompletableFuture<byte[]> readBytesFallBackIfFailsOrEmptyResult(BlobId blobId) { return primaryBlobStore.readBytes(blobId) .thenApply(Optional::ofNullable) http://git-wip-us.apache.org/repos/asf/james-project/blob/aa064ef6/server/blob/blob-joining/src/test/java/org/apache/james/blob/joining/JoiningBlobStoreTest.java ---------------------------------------------------------------------- diff --git a/server/blob/blob-joining/src/test/java/org/apache/james/blob/joining/JoiningBlobStoreTest.java b/server/blob/blob-joining/src/test/java/org/apache/james/blob/joining/JoiningBlobStoreTest.java index b324cbd..a26dff5 100644 --- a/server/blob/blob-joining/src/test/java/org/apache/james/blob/joining/JoiningBlobStoreTest.java +++ b/server/blob/blob-joining/src/test/java/org/apache/james/blob/joining/JoiningBlobStoreTest.java @@ -20,9 +20,11 @@ package org.apache.james.blob.joining; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; import java.io.ByteArrayInputStream; import java.io.InputStream; +import java.io.PushbackInputStream; import java.util.concurrent.CompletableFuture; import org.apache.james.blob.api.BlobId; @@ -220,4 +222,46 @@ class JoiningBlobStoreTest implements BlobStoreContract { assertThat(secondaryBlobStore.readBytes(blobId).get()) .isEmpty(); } + + @Test + void streamHasContentShouldReturnTrueWhenStreamHasContent() throws Exception { + PushbackInputStream pushBackIS = new PushbackInputStream(new ByteArrayInputStream(BLOB_CONTENT)); + + assertThat(joiningBlobStore.streamHasContent(pushBackIS)) + .isTrue(); + } + + @Test + void streamHasContentShouldReturnFalseWhenStreamHasNoContent() throws Exception { + PushbackInputStream pushBackIS = new PushbackInputStream(new ByteArrayInputStream(new byte[0])); + + assertThat(joiningBlobStore.streamHasContent(pushBackIS)) + .isFalse(); + } + + @Test + void streamHasContentShouldNotThrowWhenStreamHasNoContent() { + PushbackInputStream pushBackIS = new PushbackInputStream(new ByteArrayInputStream(new byte[0])); + + assertThatCode(() -> joiningBlobStore.streamHasContent(pushBackIS)) + .doesNotThrowAnyException(); + } + + @Test + void streamHasContentShouldNotDrainPushBackStreamContent() throws Exception { + PushbackInputStream pushBackIS = new PushbackInputStream(new ByteArrayInputStream(BLOB_CONTENT)); + joiningBlobStore.streamHasContent(pushBackIS); + + assertThat(pushBackIS) + .hasSameContentAs(new ByteArrayInputStream(BLOB_CONTENT)); + } + + @Test + void streamHasContentShouldKeepStreamEmptyWhenStreamIsEmpty() throws Exception { + PushbackInputStream pushBackIS = new PushbackInputStream(new ByteArrayInputStream(new byte[0])); + joiningBlobStore.streamHasContent(pushBackIS); + + assertThat(pushBackIS) + .hasSameContentAs(new ByteArrayInputStream(new byte[0])); + } } \ No newline at end of file --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
