Store the MPU ETag for the transient blobstore

JCLOUDS-1582: fixes a bug in the transient blobstore where after
uploading a multipart upload, GET/HEAD returns the hash of the content,
rather than the MPU ETag.
This commit is contained in:
Timur Alperovich 2021-08-04 01:33:57 -07:00 committed by Andrew Gaul
parent 720e92c54a
commit a1df0bb1f5
2 changed files with 35 additions and 3 deletions

View File

@ -193,7 +193,14 @@ public class TransientStorageStrategy implements LocalStorageStrategy {
Closeables2.closeQuietly(input); Closeables2.closeQuietly(input);
} }
Blob newBlob = createUpdatedCopyOfBlobInContainer(containerName, blob, payload, actualHashCode); String eTag = null;
if (blob.getMetadata() != null) {
eTag = blob.getMetadata().getETag();
}
if (eTag == null) {
eTag = base16().lowerCase().encode(actualHashCode.asBytes());
}
Blob newBlob = createUpdatedCopyOfBlobInContainer(containerName, blob, payload, actualHashCode, eTag);
Map<String, Blob> map = containerToBlobs.get(containerName); Map<String, Blob> map = containerToBlobs.get(containerName);
String blobName = newBlob.getMetadata().getName(); String blobName = newBlob.getMetadata().getName();
map.put(blobName, newBlob); map.put(blobName, newBlob);
@ -240,11 +247,12 @@ public class TransientStorageStrategy implements LocalStorageStrategy {
return "/"; return "/";
} }
private Blob createUpdatedCopyOfBlobInContainer(String containerName, Blob in, byte[] input, HashCode contentMd5) { private Blob createUpdatedCopyOfBlobInContainer(String containerName, Blob in, byte[] input, HashCode contentMd5, String eTag) {
checkNotNull(containerName, "containerName"); checkNotNull(containerName, "containerName");
checkNotNull(in, "blob"); checkNotNull(in, "blob");
checkNotNull(input, "input"); checkNotNull(input, "input");
checkNotNull(contentMd5, "contentMd5"); checkNotNull(contentMd5, "contentMd5");
checkNotNull(eTag, "eTag");
Payload payload = createPayload(input); Payload payload = createPayload(input);
MutableContentMetadata oldMd = in.getPayload().getContentMetadata(); MutableContentMetadata oldMd = in.getPayload().getContentMetadata();
HttpUtils.copy(oldMd, payload.getContentMetadata()); HttpUtils.copy(oldMd, payload.getContentMetadata());
@ -255,7 +263,6 @@ public class TransientStorageStrategy implements LocalStorageStrategy {
blob.getMetadata().setContainer(containerName); blob.getMetadata().setContainer(containerName);
blob.getMetadata().setLastModified(new Date()); blob.getMetadata().setLastModified(new Date());
blob.getMetadata().setSize((long) input.length); blob.getMetadata().setSize((long) input.length);
String eTag = base16().lowerCase().encode(contentMd5.asBytes());
blob.getMetadata().setETag(eTag); blob.getMetadata().setETag(eTag);
// Set HTTP headers to match metadata // Set HTTP headers to match metadata
blob.getAllHeaders().replaceValues(HttpHeaders.LAST_MODIFIED, blob.getAllHeaders().replaceValues(HttpHeaders.LAST_MODIFIED,

View File

@ -16,10 +16,19 @@
*/ */
package org.jclouds.blobstore.integration; package org.jclouds.blobstore.integration;
import com.google.common.hash.Hasher;
import com.google.common.hash.Hashing;
import com.google.common.io.BaseEncoding;
import org.jclouds.blobstore.domain.Blob;
import org.jclouds.blobstore.domain.MultipartPart;
import org.jclouds.blobstore.integration.internal.BaseBlobIntegrationTest; import org.jclouds.blobstore.integration.internal.BaseBlobIntegrationTest;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import org.testng.SkipException; import org.testng.SkipException;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
@Test(groups = { "integration" }) @Test(groups = { "integration" })
public class TransientBlobIntegrationTest extends BaseBlobIntegrationTest { public class TransientBlobIntegrationTest extends BaseBlobIntegrationTest {
public TransientBlobIntegrationTest() { public TransientBlobIntegrationTest() {
@ -31,4 +40,20 @@ public class TransientBlobIntegrationTest extends BaseBlobIntegrationTest {
public void testSetBlobAccess() throws Exception { public void testSetBlobAccess() throws Exception {
throw new SkipException("transient does not support anonymous access"); throw new SkipException("transient does not support anonymous access");
} }
@Override
protected void checkMPUParts(Blob blob, List<MultipartPart> parts) {
assertThat(blob.getMetadata().getETag()).endsWith(String.format("-%d\"", parts.size()));
Hasher eTagHasher = Hashing.md5().newHasher();
for (MultipartPart part : parts) {
eTagHasher.putBytes(BaseEncoding.base16().lowerCase().decode(part.partETag()));
}
String expectedETag = new StringBuilder("\"")
.append(eTagHasher.hash())
.append("-")
.append(parts.size())
.append("\"")
.toString();
assertThat(blob.getMetadata().getETag()).isEqualTo(expectedETag);
}
} }