Skip to content

Commit 65cb6c5

Browse files
authored
Revert "feat: add blob.uploadfrom(inputstream)" (#190)
Reverts #162 Need to revert this for now. The issue is that the [Blob constructor is private](https://github.com/googleapis/java-storage/blob/1f53baa969331a94b5a73319df59711157ef2307/google-cloud-storage/src/main/java/com/google/cloud/storage/Blob.java#L545) and it requires creating the object as an [empty object before uploading with an InputStream](https://github.com/googleapis/java-storage/pull/162/files#diff-8c18a40b13cc5c5d90547c273470f5eeR2965-R2966). The implementation should be derived from the Storage class instead of Blob class to reduce the number of requests. cc: @dmitry-fa, could you recreate the PR? I haven't prioritized this, apologies for the delay.
1 parent b61a820 commit 65cb6c5

File tree

3 files changed

+3
-283
lines changed

3 files changed

+3
-283
lines changed

google-cloud-storage/src/main/java/com/google/cloud/storage/Blob.java

Lines changed: 1 addition & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,9 @@
3838
import com.google.common.io.BaseEncoding;
3939
import com.google.common.io.CountingOutputStream;
4040
import java.io.IOException;
41-
import java.io.InputStream;
4241
import java.io.ObjectInputStream;
4342
import java.io.OutputStream;
4443
import java.net.URL;
45-
import java.nio.ByteBuffer;
4644
import java.nio.file.Files;
4745
import java.nio.file.Path;
4846
import java.security.Key;
@@ -75,8 +73,7 @@ public Blob apply(Tuple<Storage, StorageObject> pb) {
7573
}
7674
};
7775

78-
private static final int DEFAULT_CHUNK_SIZE = 15 * 1024 * 1024;
79-
private static final int MIN_BUFFER_SIZE = 256 * 1024;
76+
private static final int DEFAULT_CHUNK_SIZE = 2 * 1024 * 1024;
8077

8178
/** Class for specifying blob source options when {@code Blob} methods are used. */
8279
public static class BlobSourceOption extends Option {
@@ -263,88 +260,6 @@ public void downloadTo(Path path) {
263260
downloadTo(path, new BlobSourceOption[0]);
264261
}
265262

266-
/**
267-
* Uploads the given file path to this blob using specified blob write options.
268-
*
269-
* @param path file to upload
270-
* @param options blob write options
271-
* @return updated blob
272-
* @throws IOException on I/O error
273-
* @throws StorageException on failure
274-
*/
275-
public Blob uploadFrom(Path path, BlobWriteOption... options) throws IOException {
276-
if (Files.isDirectory(path)) {
277-
throw new StorageException(0, path + " is a directory");
278-
}
279-
try (InputStream input = Files.newInputStream(path)) {
280-
return uploadFrom(input, options);
281-
}
282-
}
283-
284-
/**
285-
* Uploads the given content to this blob using specified blob write options.
286-
*
287-
* @param input content to upload
288-
* @param options blob write options
289-
* @return updated blob
290-
* @throws IOException on I/O error
291-
* @throws StorageException on failure
292-
*/
293-
public Blob uploadFrom(InputStream input, BlobWriteOption... options) throws IOException {
294-
try (WriteChannel writer = storage.writer(this, options)) {
295-
uploadFrom(input, writer);
296-
}
297-
BlobId blobId = getBlobId();
298-
try {
299-
return storage.get(BlobId.of(blobId.getBucket(), blobId.getName()));
300-
} catch (StorageException e) {
301-
throw new StorageException(
302-
e.getCode(), "Content has been uploaded successfully. Failed to retrieve blob.", e);
303-
}
304-
}
305-
306-
static void uploadFrom(InputStream input, WriteChannel writer) throws IOException {
307-
uploadFrom(input, writer, DEFAULT_CHUNK_SIZE);
308-
}
309-
310-
/**
311-
* Uploads the given content to the storage using specified write channel and the given buffer
312-
* size. Other uploadFrom() methods invoke this one with a buffer size of 15 MiB. Users can pass
313-
* alternative values. Larger buffer sizes might improve the upload performance but require more
314-
* memory. This can cause an OutOfMemoryError or add significant garbage collection overhead.
315-
* Smaller buffer sizes reduce memory consumption, that is noticeable when uploading many objects
316-
* in parallel. Buffer sizes less than 256 KiB are treated as 256 KiB.
317-
*
318-
* <p>This method does not close either the InputStream or the WriterChannel.
319-
*
320-
* <p>Example of uploading:
321-
*
322-
* <pre>{@code
323-
* BlobId blobId = BlobId.of(bucketName, blobName);
324-
* BlobInfo blobInfo = BlobInfo.newBuilder(blobId).setContentType("video/webm").build();
325-
* Path file = Paths.get("humongous.file");
326-
* try (InputStream input = Files.newInputStream(file); WriteChannel writer = storage.writer(blobInfo)) {
327-
* Blob.uploadFrom(input, writer, 150 * 1024 * 1024);
328-
* } catch (IOException e) {
329-
* // your handler
330-
* }
331-
* }</pre>
332-
*
333-
* @param input content to upload
334-
* @param writer channel
335-
* @param bufferSize size of the buffer to read from input and send over writer
336-
* @throws IOException on I/O error
337-
*/
338-
public static void uploadFrom(InputStream input, WriteChannel writer, int bufferSize)
339-
throws IOException {
340-
bufferSize = Math.max(bufferSize, MIN_BUFFER_SIZE);
341-
byte[] buffer = new byte[bufferSize];
342-
int length;
343-
while ((length = input.read(buffer)) >= 0) {
344-
writer.write(ByteBuffer.wrap(buffer, 0, length));
345-
}
346-
}
347-
348263
/** Builder for {@code Blob}. */
349264
public static class Builder extends BlobInfo.Builder {
350265

google-cloud-storage/src/test/java/com/google/cloud/storage/BlobTest.java

Lines changed: 2 additions & 142 deletions
Original file line numberDiff line numberDiff line change
@@ -32,13 +32,11 @@
3232
import static org.junit.Assert.assertNull;
3333
import static org.junit.Assert.assertSame;
3434
import static org.junit.Assert.assertTrue;
35-
import static org.junit.Assert.fail;
3635

3736
import com.google.api.core.ApiClock;
3837
import com.google.api.gax.retrying.RetrySettings;
3938
import com.google.api.services.storage.model.StorageObject;
4039
import com.google.cloud.ReadChannel;
41-
import com.google.cloud.WriteChannel;
4240
import com.google.cloud.storage.Acl.Project;
4341
import com.google.cloud.storage.Acl.Project.ProjectRole;
4442
import com.google.cloud.storage.Acl.Role;
@@ -50,17 +48,10 @@
5048
import com.google.common.collect.ImmutableList;
5149
import com.google.common.collect.ImmutableMap;
5250
import com.google.common.io.BaseEncoding;
53-
import java.io.ByteArrayInputStream;
5451
import java.io.File;
55-
import java.io.IOException;
56-
import java.io.InputStream;
5752
import java.io.OutputStream;
5853
import java.net.URL;
59-
import java.nio.ByteBuffer;
6054
import java.nio.file.Files;
61-
import java.nio.file.NoSuchFileException;
62-
import java.nio.file.Path;
63-
import java.nio.file.Paths;
6455
import java.security.Key;
6556
import java.util.List;
6657
import java.util.Map;
@@ -595,7 +586,7 @@ public void testBuilder() {
595586
}
596587

597588
@Test
598-
public void testDownloadTo() throws Exception {
589+
public void testDownload() throws Exception {
599590
final byte[] expected = {1, 2};
600591
StorageRpc mockStorageRpc = createNiceMock(StorageRpc.class);
601592
expect(storage.getOptions()).andReturn(mockOptions).times(1);
@@ -627,7 +618,7 @@ public Long answer() throws Throwable {
627618
}
628619

629620
@Test
630-
public void testDownloadToWithRetries() throws Exception {
621+
public void testDownloadWithRetries() throws Exception {
631622
final byte[] expected = {1, 2};
632623
StorageRpc mockStorageRpc = createNiceMock(StorageRpc.class);
633624
expect(storage.getOptions()).andReturn(mockOptions);
@@ -671,135 +662,4 @@ public Long answer() throws Throwable {
671662
byte actual[] = Files.readAllBytes(file.toPath());
672663
assertArrayEquals(expected, actual);
673664
}
674-
675-
@Test
676-
public void testUploadFromNonExistentFile() {
677-
initializeExpectedBlob(1);
678-
expect(storage.getOptions()).andReturn(mockOptions);
679-
replay(storage);
680-
blob = new Blob(storage, new BlobInfo.BuilderImpl(BLOB_INFO));
681-
String fileName = "non_existing_file.txt";
682-
try {
683-
blob.uploadFrom(Paths.get(fileName));
684-
fail();
685-
} catch (IOException e) {
686-
assertEquals(NoSuchFileException.class, e.getClass());
687-
assertEquals(fileName, e.getMessage());
688-
}
689-
}
690-
691-
@Test
692-
public void testUploadFromDirectory() throws IOException {
693-
initializeExpectedBlob(1);
694-
expect(storage.getOptions()).andReturn(mockOptions);
695-
replay(storage);
696-
blob = new Blob(storage, new BlobInfo.BuilderImpl(BLOB_INFO));
697-
Path dir = Files.createTempDirectory("unit_");
698-
try {
699-
blob.uploadFrom(dir);
700-
fail();
701-
} catch (StorageException e) {
702-
assertEquals(dir + " is a directory", e.getMessage());
703-
}
704-
}
705-
706-
private WriteChannel createWriteChannelMock(byte[] bytes) throws Exception {
707-
WriteChannel channel = createMock(WriteChannel.class);
708-
ByteBuffer expectedByteBuffer = ByteBuffer.wrap(bytes, 0, bytes.length);
709-
expect(channel.write(expectedByteBuffer)).andReturn(bytes.length);
710-
channel.close();
711-
replay(channel);
712-
return channel;
713-
}
714-
715-
private Blob createBlobForUpload(WriteChannel channel) {
716-
initializeExpectedBlob(1);
717-
BlobId blobId = BlobId.of(BLOB_INFO.getBucket(), BLOB_INFO.getName());
718-
expect(storage.getOptions()).andReturn(mockOptions);
719-
expect(storage.writer(eq(expectedBlob))).andReturn(channel);
720-
expect(storage.get(blobId)).andReturn(expectedBlob);
721-
replay(storage);
722-
return new Blob(storage, new BlobInfo.BuilderImpl(BLOB_INFO));
723-
}
724-
725-
@Test
726-
public void testUploadFromFile() throws Exception {
727-
byte[] dataToSend = {1, 2, 3};
728-
WriteChannel channel = createWriteChannelMock(dataToSend);
729-
blob = createBlobForUpload(channel);
730-
Path tempFile = Files.createTempFile("testUpload", ".tmp");
731-
Files.write(tempFile, dataToSend);
732-
blob = blob.uploadFrom(tempFile);
733-
assertSame(expectedBlob, blob);
734-
}
735-
736-
@Test
737-
public void testUploadFromStream() throws Exception {
738-
byte[] dataToSend = {1, 2, 3, 4, 5};
739-
WriteChannel channel = createWriteChannelMock(dataToSend);
740-
blob = createBlobForUpload(channel);
741-
InputStream input = new ByteArrayInputStream(dataToSend);
742-
blob = blob.uploadFrom(input);
743-
assertSame(expectedBlob, blob);
744-
}
745-
746-
@Test
747-
public void testUploadFromStreamRetrieveFailed() throws Exception {
748-
byte[] dataToSend = {1, 2, 3, 4, 5};
749-
StorageException storageException = new StorageException(123, "message");
750-
WriteChannel channel = createWriteChannelMock(dataToSend);
751-
initializeExpectedBlob(1);
752-
BlobId blobId = BlobId.of(BLOB_INFO.getBucket(), BLOB_INFO.getName());
753-
expect(storage.getOptions()).andReturn(mockOptions);
754-
expect(storage.writer(eq(expectedBlob))).andReturn(channel);
755-
expect(storage.get(blobId)).andThrow(storageException);
756-
replay(storage);
757-
Blob blob = new Blob(storage, new BlobInfo.BuilderImpl(BLOB_INFO));
758-
InputStream input = new ByteArrayInputStream(dataToSend);
759-
try {
760-
blob.uploadFrom(input);
761-
fail();
762-
} catch (StorageException e) {
763-
assertEquals(
764-
"Content has been uploaded successfully. Failed to retrieve blob.", e.getMessage());
765-
assertSame(e.getCause(), storageException);
766-
}
767-
}
768-
769-
@Test
770-
public void testUpload() throws Exception {
771-
replay(storage);
772-
byte[] dataToSend = {1, 2, 3, 4, 5};
773-
WriteChannel channel = createWriteChannelMock(dataToSend);
774-
InputStream input = new ByteArrayInputStream(dataToSend);
775-
Blob.uploadFrom(input, channel);
776-
}
777-
778-
@Test
779-
public void testUploadSmallBufferSize() throws Exception {
780-
replay(storage);
781-
byte[] dataToSend = new byte[100_000];
782-
WriteChannel channel = createWriteChannelMock(dataToSend);
783-
InputStream input = new ByteArrayInputStream(dataToSend);
784-
Blob.uploadFrom(input, channel, 100);
785-
}
786-
787-
@Test
788-
public void testUploadMultiplePortions() throws Exception {
789-
replay(storage);
790-
int totalSize = 400_000;
791-
int bufferSize = 300_000;
792-
byte[] dataToSend = new byte[totalSize];
793-
dataToSend[0] = 42;
794-
dataToSend[bufferSize] = 43;
795-
796-
WriteChannel channel = createMock(WriteChannel.class);
797-
expect(channel.write(ByteBuffer.wrap(dataToSend, 0, bufferSize))).andReturn(bufferSize);
798-
expect(channel.write(ByteBuffer.wrap(dataToSend, bufferSize, totalSize - bufferSize)))
799-
.andReturn(bufferSize - bufferSize);
800-
channel.close();
801-
replay(channel);
802-
InputStream input = new ByteArrayInputStream(dataToSend);
803-
Blob.uploadFrom(input, channel, bufferSize);
804-
}
805665
}

google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITStorageTest.java

Lines changed: 0 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@
4040
import com.google.cloud.Policy;
4141
import com.google.cloud.ReadChannel;
4242
import com.google.cloud.RestorableState;
43-
import com.google.cloud.RetryHelper;
4443
import com.google.cloud.TransportOptions;
4544
import com.google.cloud.WriteChannel;
4645
import com.google.cloud.http.HttpTransportOptions;
@@ -104,8 +103,6 @@
104103
import java.net.URL;
105104
import java.net.URLConnection;
106105
import java.nio.ByteBuffer;
107-
import java.nio.file.Files;
108-
import java.nio.file.Path;
109106
import java.security.Key;
110107
import java.util.ArrayList;
111108
import java.util.Arrays;
@@ -3211,56 +3208,4 @@ public void testBucketLogging() throws ExecutionException, InterruptedException
32113208
RemoteStorageHelper.forceDelete(storage, loggingBucket, 5, TimeUnit.SECONDS);
32123209
}
32133210
}
3214-
3215-
@Test
3216-
public void testUpload() throws Exception {
3217-
String blobName = "test-upload-static";
3218-
BlobId blobId = BlobId.of(BUCKET, blobName);
3219-
try (WriteChannel writer = storage.writer(BlobInfo.newBuilder(blobId).build())) {
3220-
Blob.uploadFrom(new ByteArrayInputStream(BLOB_STRING_CONTENT.getBytes(UTF_8)), writer, 1);
3221-
}
3222-
Blob blob = storage.get(blobId);
3223-
String readString = new String(blob.getContent(), UTF_8);
3224-
assertEquals(BLOB_STRING_CONTENT, readString);
3225-
}
3226-
3227-
@Test
3228-
public void testUploadFromDownloadTo() throws Exception {
3229-
String blobName = "test-uploadFrom-downloadTo-blob";
3230-
BlobInfo blobInfo = BlobInfo.newBuilder(BUCKET, blobName).build();
3231-
3232-
Path tempFileFrom = Files.createTempFile("ITStorageTest_", ".tmp");
3233-
Files.write(tempFileFrom, BLOB_BYTE_CONTENT);
3234-
Blob blob = storage.create(blobInfo);
3235-
blob = blob.uploadFrom(tempFileFrom);
3236-
3237-
Path tempFileTo = Files.createTempFile("ITStorageTest_", ".tmp");
3238-
blob.downloadTo(tempFileTo);
3239-
byte[] readBytes = Files.readAllBytes(tempFileTo);
3240-
assertArrayEquals(BLOB_BYTE_CONTENT, readBytes);
3241-
}
3242-
3243-
@Test
3244-
public void testUploadFromDownloadToWithEncryption() throws Exception {
3245-
String blobName = "test-uploadFrom-downloadTo-withEncryption-blob";
3246-
BlobInfo blobInfo = BlobInfo.newBuilder(BUCKET, blobName).build();
3247-
3248-
Path tempFileFrom = Files.createTempFile("ITStorageTest_", ".tmp");
3249-
Files.write(tempFileFrom, BLOB_BYTE_CONTENT);
3250-
Blob blob = storage.create(blobInfo);
3251-
blob = blob.uploadFrom(tempFileFrom, Storage.BlobWriteOption.encryptionKey(KEY));
3252-
3253-
Path tempFileTo = Files.createTempFile("ITStorageTest_", ".tmp");
3254-
try {
3255-
blob.downloadTo(tempFileTo);
3256-
} catch (RetryHelper.RetryHelperException e) {
3257-
// Expected to be StorageException
3258-
String expectedMessage =
3259-
"The target object is encrypted by a customer-supplied encryption key.";
3260-
assertTrue(e.getMessage().contains(expectedMessage));
3261-
}
3262-
blob.downloadTo(tempFileTo, Blob.BlobSourceOption.decryptionKey(KEY));
3263-
byte[] readBytes = Files.readAllBytes(tempFileTo);
3264-
assertArrayEquals(BLOB_BYTE_CONTENT, readBytes);
3265-
}
32663211
}

0 commit comments

Comments
 (0)