Use uploadId for stub blob name

This makes MPU overwrites of an existing blob atomic.  Fixes #108.
pull/114/head
Andrew Gaul 2015-12-28 16:40:13 -08:00
rodzic 4247ae803f
commit 05bd2c1158
2 zmienionych plików z 37 dodań i 9 usunięć

Wyświetl plik

@ -1594,7 +1594,6 @@ final class S3ProxyHandler extends AbstractHandler {
.payload(payload);
addContentMetdataFromHttpRequest(builder, request);
builder.contentLength(payload.size());
Blob blob = builder.build();
BlobAccess access;
String cannedAcl = request.getHeader("x-amz-acl");
@ -1610,13 +1609,14 @@ final class S3ProxyHandler extends AbstractHandler {
}
PutOptions options = new PutOptions().setBlobAccess(access);
MultipartUpload mpu = blobStore.initiateMultipartUpload(containerName,
builder.build().getMetadata(), options);
// S3 requires blob metadata during the initiate call while Azure and
// Swift require it in the complete call. Store a stub blob which
// allows reproducing this metadata later.
blobStore.putBlob(containerName, blob, options);
MultipartUpload mpu = blobStore.initiateMultipartUpload(containerName,
blob.getMetadata(), options);
blobStore.putBlob(containerName, builder.name(mpu.id()).build(),
options);
try (Writer writer = response.getWriter()) {
XMLStreamWriter xml = xmlOutputFactory.createXMLStreamWriter(
@ -1640,8 +1640,8 @@ final class S3ProxyHandler extends AbstractHandler {
HttpServletResponse response, InputStream is, BlobStore blobStore,
String containerName, String blobName, String uploadId)
throws IOException, S3Exception {
Blob stubBlob = blobStore.getBlob(containerName, blobName);
BlobAccess access = blobStore.getBlobAccess(containerName, blobName);
Blob stubBlob = blobStore.getBlob(containerName, uploadId);
BlobAccess access = blobStore.getBlobAccess(containerName, uploadId);
MultipartUpload mpu = MultipartUpload.create(containerName,
blobName, uploadId, stubBlob.getMetadata(),
new PutOptions().setBlobAccess(access));
@ -1721,11 +1721,11 @@ final class S3ProxyHandler extends AbstractHandler {
HttpServletResponse response, BlobStore blobStore,
String containerName, String blobName, String uploadId)
throws IOException, S3Exception {
if (!blobStore.blobExists(containerName, blobName)) {
if (!blobStore.blobExists(containerName, uploadId)) {
throw new S3Exception(S3ErrorCode.NO_SUCH_UPLOAD);
}
blobStore.removeBlob(containerName, blobName);
blobStore.removeBlob(containerName, uploadId);
// TODO: how to reconstruct original mpu?
MultipartUpload mpu = MultipartUpload.create(containerName,

Wyświetl plik

@ -44,6 +44,7 @@ import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.S3ClientOptions;
import com.amazonaws.services.s3.model.AbortMultipartUploadRequest;
import com.amazonaws.services.s3.model.AccessControlList;
import com.amazonaws.services.s3.model.AmazonS3Exception;
import com.amazonaws.services.s3.model.CompleteMultipartUploadRequest;
@ -402,6 +403,33 @@ public final class S3AwsSdkTest {
assertThat(summary.getKey()).isEqualTo(blobName);
}
@Test
public void testAtomicMpuAbort() throws Exception {
String key = "testAtomicMpuAbort";
ObjectMetadata metadata = new ObjectMetadata();
metadata.setContentLength(BYTE_SOURCE.size());
client.putObject(containerName, key, BYTE_SOURCE.openStream(),
metadata);
InitiateMultipartUploadRequest initRequest =
new InitiateMultipartUploadRequest(containerName, key);
InitiateMultipartUploadResult initResponse =
client.initiateMultipartUpload(initRequest);
String uploadId = initResponse.getUploadId();
client.abortMultipartUpload(new AbortMultipartUploadRequest(
containerName, key, uploadId));
S3Object object = client.getObject(new GetObjectRequest(containerName,
key));
assertThat(object.getObjectMetadata().getContentLength()).isEqualTo(
BYTE_SOURCE.size());
try (InputStream actual = object.getObjectContent();
InputStream expected = BYTE_SOURCE.openStream()) {
assertThat(actual).hasContentEqualTo(expected);
}
}
private static final class NullX509TrustManager
implements X509TrustManager {
@Override