Skip to content

Commit

Permalink
Use StorageRpc.rewrite to implement Storage.copy
Browse files Browse the repository at this point in the history
- rename BlobRewriter to CopyWriter
- update Storage.copy and Blob.copyTo methods to use StorageRpc.openRewrite
- update Blob and Storage unit and intergration tests
- update StorageExample
  • Loading branch information
mziccard committed Oct 28, 2015
1 parent 15372f1 commit 43460b9
Show file tree
Hide file tree
Showing 9 changed files with 204 additions and 379 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import com.google.gcloud.storage.BlobId;
import com.google.gcloud.storage.BlobInfo;
import com.google.gcloud.storage.BlobReadChannel;
import com.google.gcloud.storage.CopyWriter;
import com.google.gcloud.storage.BlobWriteChannel;
import com.google.gcloud.storage.Bucket;
import com.google.gcloud.storage.BucketInfo;
Expand Down Expand Up @@ -366,21 +367,25 @@ public String params() {
private static class CopyAction extends StorageAction<CopyRequest> {
@Override
public void run(Storage storage, CopyRequest request) {
BlobInfo copiedBlobInfo = storage.copy(request);
System.out.println("Copied " + copiedBlobInfo);
CopyWriter copyWriter = storage.copy(request);
while (!copyWriter.isDone()) {
copyWriter.copyChunk();
}
System.out.println("Copied " + copyWriter.result());
}

@Override
CopyRequest parse(String... args) {
if (args.length != 4) {
if (args.length != 5) {
throw new IllegalArgumentException();
}
return CopyRequest.of(args[0], args[1], BlobInfo.builder(args[2], args[3]).build());
return CopyRequest.of(args[0], args[1],
BlobInfo.builder(args[2], args[3]).contentType(args[4]).build());
}

@Override
public String params() {
return "<from_bucket> <from_path> <to_bucket> <to_path>";
return "<from_bucket> <from_path> <to_bucket> <to_path> <to_content_type>";
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -213,19 +213,20 @@ public Blob update(BlobInfo blobInfo, BlobTargetOption... options) {
}

/**
* Copies this blob to the specified target. Possibly copying also some of the metadata
* (e.g. content-type).
* Sends a copy request for the current blob to the target blob. Possibly also some of the
* metadata are copied (e.g. content-type).
*
* @param targetBlob target blob's id
* @param options source blob options
* @return the copied blob
* @return a {@link CopyWriter} object that can be used to get information on the newly created
* blob or to complete the copy if more than one RPC request is needed
* @throws StorageException upon failure
*/
public Blob copyTo(BlobId targetBlob, BlobSourceOption... options) {
public CopyWriter copyTo(BlobId targetBlob, BlobSourceOption... options) {
BlobInfo updatedInfo = info.toBuilder().blobId(targetBlob).build();
CopyRequest copyRequest = CopyRequest.builder().source(info.bucket(), info.name())
.sourceOptions(convert(info, options)).target(updatedInfo).build();
return new Blob(storage, storage.copy(copyRequest));
return storage.copy(copyRequest);
}

/**
Expand All @@ -240,33 +241,35 @@ public boolean delete(BlobSourceOption... options) {
}

/**
* Copies this blob to the target bucket, preserving its name. Possibly copying also some of the
* metadata (e.g. content-type).
* Sends a copy request for the current blob to the target bucket, preserving its name. Possibly
* copying also some of the metadata (e.g. content-type).
*
* @param targetBucket target bucket's name
* @param options source blob options
* @return the copied blob
* @return a {@link CopyWriter} object that can be used to get information on the newly created
* blob or to complete the copy if more than one RPC request is needed
* @throws StorageException upon failure
*/
public Blob copyTo(String targetBucket, BlobSourceOption... options) {
public CopyWriter copyTo(String targetBucket, BlobSourceOption... options) {
return copyTo(targetBucket, info.name(), options);
}

/**
* Copies this blob to the target bucket with a new name. Possibly copying also some of the
* metadata (e.g. content-type).
* Sends a copy request for the current blob to the target blob. Possibly also some of the
* metadata are copied (e.g. content-type).
*
* @param targetBucket target bucket's name
* @param targetBlob target blob's name
* @param options source blob options
* @return the copied blob
* @return a {@link CopyWriter} object that can be used to get information on the newly created
* blob or to complete the copy if more than one RPC request is needed
* @throws StorageException upon failure
*/
public Blob copyTo(String targetBucket, String targetBlob, BlobSourceOption... options) {
public CopyWriter copyTo(String targetBucket, String targetBlob, BlobSourceOption... options) {
BlobInfo updatedInfo = info.toBuilder().blobId(BlobId.of(targetBucket, targetBlob)).build();
CopyRequest copyRequest = CopyRequest.builder().source(info.bucket(), info.name())
.sourceOptions(convert(info, options)).target(updatedInfo).build();
return new Blob(storage, storage.copy(copyRequest));
return storage.copy(copyRequest);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,20 @@
import java.util.concurrent.Callable;

/**
* Google Storage blob rewriter.
* Google Storage blob copy writer. This class holds the result of a copy request.
* If source and destination blobs do not share the same location or storage class more than one
* RPC request is needed to copy the blob. When this is the case {@link #copyChunk()} can be used
* to copy to destination other chunks of the source blob.
*
* @see <a href="https://cloud.google.com/storage/docs/json_api/v1/objects/rewrite">Rewrite</a>
*/
public final class BlobRewriter implements Restorable<BlobRewriter> {
public class CopyWriter implements Restorable<CopyWriter> {

private final StorageOptions serviceOptions;
private final StorageRpc storageRpc;
private RewriteResponse rewriteResponse;

BlobRewriter(StorageOptions serviceOptions, RewriteResponse rewriteResponse) {
CopyWriter(StorageOptions serviceOptions, RewriteResponse rewriteResponse) {
this.serviceOptions = serviceOptions;
this.rewriteResponse = rewriteResponse;
this.storageRpc = serviceOptions.rpc();
Expand Down Expand Up @@ -69,14 +74,14 @@ public Boolean isDone() {
}

/**
* Returns the number of bytes written.
* Returns the number of bytes copied.
*/
public Long totalBytesRewritten() {
public Long totalBytesCopied() {
return rewriteResponse.totalBytesRewritten;
}

/**
* Rewrite the next chunk of the blob. An RPC is issued only if rewrite has not finished yet
* Copies the next chunk of the blob. An RPC is issued only if copy has not finished yet
* ({@link #isDone} returns {@code false}).
*
* @throws StorageException upon failure
Expand All @@ -97,7 +102,7 @@ public RewriteResponse call() {
}

@Override
public RestorableState<BlobRewriter> capture() {
public RestorableState<CopyWriter> capture() {
return StateImpl.builder(
serviceOptions,
BlobId.fromPb(rewriteResponse.rewriteRequest.source),
Expand All @@ -108,11 +113,11 @@ public RestorableState<BlobRewriter> capture() {
.isDone(isDone())
.megabytesRewrittenPerCall(rewriteResponse.rewriteRequest.megabytesRewrittenPerCall)
.rewriteToken(rewriteResponse.rewriteToken)
.totalBytesRewritten(totalBytesRewritten())
.totalBytesRewritten(totalBytesCopied())
.build();
}

static class StateImpl implements RestorableState<BlobRewriter>, Serializable {
static class StateImpl implements RestorableState<CopyWriter>, Serializable {

private static final long serialVersionUID = 8279287678903181701L;

Expand All @@ -125,7 +130,7 @@ static class StateImpl implements RestorableState<BlobRewriter>, Serializable {
private final Long blobSize;
private final Boolean isDone;
private final String rewriteToken;
private final Long totalBytesRewritten;
private final Long totalBytesCopied;
private final Long megabytesRewrittenPerCall;

StateImpl(Builder builder) {
Expand All @@ -138,7 +143,7 @@ static class StateImpl implements RestorableState<BlobRewriter>, Serializable {
this.blobSize = builder.blobSize;
this.isDone = builder.isDone;
this.rewriteToken = builder.rewriteToken;
this.totalBytesRewritten = builder.totalBytesRewritten;
this.totalBytesCopied = builder.totalBytesCopied;
this.megabytesRewrittenPerCall = builder.megabytesRewrittenPerCall;
}

Expand All @@ -153,7 +158,7 @@ static class Builder {
private Long blobSize;
private Boolean isDone;
private String rewriteToken;
private Long totalBytesRewritten;
private Long totalBytesCopied;
private Long megabytesRewrittenPerCall;

private Builder(StorageOptions options, BlobId source,
Expand Down Expand Up @@ -187,7 +192,7 @@ Builder rewriteToken(String rewriteToken) {
}

Builder totalBytesRewritten(Long totalBytesRewritten) {
this.totalBytesRewritten = totalBytesRewritten;
this.totalBytesCopied = totalBytesRewritten;
return this;
}

Expand All @@ -196,7 +201,7 @@ Builder megabytesRewrittenPerCall(Long megabytesRewrittenPerCall) {
return this;
}

RestorableState<BlobRewriter> build() {
RestorableState<CopyWriter> build() {
return new StateImpl(this);
}
}
Expand All @@ -208,19 +213,19 @@ static Builder builder(StorageOptions options, BlobId source,
}

@Override
public BlobRewriter restore() {
public CopyWriter restore() {
RewriteRequest rewriteRequest = new RewriteRequest(
source.toPb(), sourceOptions, target.toPb(), targetOptions, megabytesRewrittenPerCall);
RewriteResponse rewriteResponse = new RewriteResponse(rewriteRequest,
result != null ? result.toPb() : null, blobSize, isDone, rewriteToken,
totalBytesRewritten);
return new BlobRewriter(serviceOptions, rewriteResponse);
totalBytesCopied);
return new CopyWriter(serviceOptions, rewriteResponse);
}

@Override
public int hashCode() {
return Objects.hash(serviceOptions, source, sourceOptions, target, targetOptions, result,
blobSize, isDone, megabytesRewrittenPerCall, rewriteToken, totalBytesRewritten);
blobSize, isDone, megabytesRewrittenPerCall, rewriteToken, totalBytesCopied);
}

@Override
Expand All @@ -242,7 +247,7 @@ public boolean equals(Object obj) {
&& Objects.equals(this.blobSize, other.blobSize)
&& Objects.equals(this.isDone, other.isDone)
&& Objects.equals(this.megabytesRewrittenPerCall, other.megabytesRewrittenPerCall)
&& Objects.equals(this.totalBytesRewritten, other.totalBytesRewritten);
&& Objects.equals(this.totalBytesCopied, other.totalBytesCopied);
}

@Override
Expand All @@ -251,7 +256,7 @@ public String toString() {
.add("source", source)
.add("target", target)
.add("isDone", isDone)
.add("totalBytesRewritten", totalBytesRewritten)
.add("totalBytesRewritten", totalBytesCopied)
.add("blobSize", blobSize)
.toString();
}
Expand Down
Loading

0 comments on commit 43460b9

Please sign in to comment.