Skip to content

Commit ec271f5

Browse files
committed
Remove failIfAlreadyExists from BlobContainer.copyBlob
1 parent 7ec3301 commit ec271f5

File tree

6 files changed

+15
-31
lines changed

6 files changed

+15
-31
lines changed

modules/repository-s3/src/internalClusterTest/java/org/elasticsearch/repositories/s3/S3RepositoryThirdPartyTests.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ public void testCopy() {
240240
sourceBlobContainer.writeBlob(randomPurpose(), sourceBlobName, blobBytes, true);
241241

242242
final var targetBlobContainer = repository.blobStore().blobContainer(repository.basePath().add("target"));
243-
sourceBlobContainer.copyBlob(randomPurpose(), sourceBlobName, targetBlobContainer, targetBlobName, false);
243+
sourceBlobContainer.copyBlob(randomPurpose(), sourceBlobName, targetBlobContainer, targetBlobName);
244244

245245
return sourceBlobContainer.readBlob(randomPurpose(), sourceBlobName).readAllBytes();
246246
});

modules/repository-s3/src/main/java/org/elasticsearch/repositories/s3/S3BlobContainer.java

+7-10
Original file line numberDiff line numberDiff line change
@@ -324,31 +324,25 @@ public void writeBlobAtomic(OperationPurpose purpose, String blobName, BytesRefe
324324
* Server-side copy can be done for any size object, but if the object is larger than 5 GB then
325325
* it must be done through a series of part copy operations rather than a single blob copy.
326326
* See <a href="https://docs.aws.amazon.com/AmazonS3/latest/API/API_CopyObject.html">CopyObject</a>.
327+
* Note that this operation will overwrite the destination if it already exists.
327328
* @param purpose The purpose of the operation
328329
* @param sourceBlobName The name of the blob to copy from
329330
* @param destinationBlobContainer The blob container to copy the blob into
330331
* @param destinationBlobName The name of the blob to copy to
331-
* @param failIfAlreadyExists Whether to throw a FileAlreadyExistsException if the target blob already exists
332-
* On S3, if true, throws UnsupportedOperationException because we don't know how
333-
* to do this atomically.
334-
* @throws IOException
332+
* @throws IOException If the operation fails on the server side
335333
*/
336334
@Override
337335
public void copyBlob(
338336
OperationPurpose purpose,
339337
String sourceBlobName,
340338
BlobContainer destinationBlobContainer,
341-
String destinationBlobName,
342-
boolean failIfAlreadyExists
339+
String destinationBlobName
343340
) throws IOException {
344341
assert BlobContainer.assertPurposeConsistency(purpose, sourceBlobName);
345342
assert BlobContainer.assertPurposeConsistency(purpose, destinationBlobName);
346343
if (destinationBlobContainer instanceof S3BlobContainer == false) {
347344
throw new IllegalArgumentException("target blob container must be a S3BlobContainer");
348345
}
349-
if (failIfAlreadyExists) {
350-
throw new UnsupportedOperationException("S3 blob container does not support failIfAlreadyExists");
351-
}
352346

353347
final var s3TargetBlobContainer = (S3BlobContainer) destinationBlobContainer;
354348

@@ -365,7 +359,10 @@ public void copyBlob(
365359
try (AmazonS3Reference clientReference = blobStore.clientReference()) {
366360
SocketAccess.doPrivilegedVoid(() -> { clientReference.client().copyObject(copyRequest); });
367361
} catch (final AmazonClientException e) {
368-
throw new IOException("Unable to copy object [" + sourceBlobName + "]", e);
362+
throw new IOException(
363+
"Unable to copy object [" + sourceBlobName + "] to [" + destinationBlobContainer + "][" + destinationBlobName + "]",
364+
e
365+
);
369366
}
370367
}
371368

modules/repository-s3/src/test/java/org/elasticsearch/repositories/s3/S3BlobStoreContainerTests.java

+1-7
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,7 @@ public void testCopy() throws Exception {
386386
final ArgumentCaptor<CopyObjectRequest> captor = ArgumentCaptor.forClass(CopyObjectRequest.class);
387387
when(client.copyObject(captor.capture())).thenReturn(new CopyObjectResult());
388388

389-
sourceBlobContainer.copyBlob(randomPurpose(), sourceBlobName, targetBlobContainer, targetBlobName, false);
389+
sourceBlobContainer.copyBlob(randomPurpose(), sourceBlobName, targetBlobContainer, targetBlobName);
390390

391391
final CopyObjectRequest request = captor.getValue();
392392
assertEquals(sourceBucketName, request.getSourceBucketName());
@@ -396,12 +396,6 @@ public void testCopy() throws Exception {
396396
assertEquals(storageClass.toString(), request.getStorageClass());
397397
assertEquals(cannedAccessControlList, request.getCannedAccessControlList());
398398

399-
// failIfAlreadyExists is not currently supported on S3
400-
assertThrows(
401-
UnsupportedOperationException.class,
402-
() -> sourceBlobContainer.copyBlob(randomPurpose(), sourceBlobName, targetBlobContainer, targetBlobName, true)
403-
);
404-
405399
closeMockClient(blobStore);
406400
}
407401

server/src/main/java/org/elasticsearch/common/blobstore/BlobContainer.java

+3-5
Original file line numberDiff line numberDiff line change
@@ -182,22 +182,20 @@ default void writeBlobAtomic(OperationPurpose purpose, String blobName, BytesRef
182182
* If copy is unavailable then throws UnsupportedOperationException.
183183
* It may be unavailable either because the blob container has no copy implementation
184184
* or because the target blob container is not on the same store as the source.
185+
* If the destination blob already exists, this operation will overwrite it.
185186
*
186187
* @param purpose The purpose of the operation
187188
* @param sourceBlobName The name of the blob to copy from
188189
* @param destinationBlobContainer The blob container to copy the blob into
189190
* @param destinationBlobName The name of the blob to copy to
190-
* @param failIfAlreadyExists Whether to throw a FileAlreadyExistsException if the target blob already exists
191191
* @throws NoSuchFileException If the source blob does not exist
192-
* @throws FileAlreadyExistsException If failIfAlreadyExists is true and the target blob already exists
193-
* @throws IOException If the operation generates an IO error (e.g., due to local copy fallback)
192+
* @throws IOException If the operation generates an IO error
194193
*/
195194
default void copyBlob(
196195
OperationPurpose purpose,
197196
String sourceBlobName,
198197
BlobContainer destinationBlobContainer,
199-
String destinationBlobName,
200-
boolean failIfAlreadyExists
198+
String destinationBlobName
201199
) throws IOException {
202200
throw new UnsupportedOperationException("this blob container does not support copy");
203201
}

server/src/main/java/org/elasticsearch/common/blobstore/fs/FsBlobContainer.java

+2-3
Original file line numberDiff line numberDiff line change
@@ -354,8 +354,7 @@ public void copyBlob(
354354
OperationPurpose purpose,
355355
String sourceBlobName,
356356
BlobContainer destinationBlobContainer,
357-
String destinationBlobName,
358-
boolean failIfAlreadyExists
357+
String destinationBlobName
359358
) throws IOException {
360359
if (destinationBlobContainer instanceof FsBlobContainer == false) {
361360
throw new IllegalArgumentException("targetBlobContainer must be a FsBlobContainer");
@@ -366,7 +365,7 @@ public void copyBlob(
366365
final Path tempBlobPath = targetContainer.path.resolve(tempBlob);
367366
Files.copy(sourceBlobPath, tempBlobPath, StandardCopyOption.REPLACE_EXISTING);
368367
try {
369-
targetContainer.moveBlobAtomic(purpose, tempBlob, destinationBlobName, failIfAlreadyExists);
368+
targetContainer.moveBlobAtomic(purpose, tempBlob, destinationBlobName, false);
370369
} catch (IOException ex) {
371370
try {
372371
targetContainer.deleteBlobsIgnoringIfNotExists(purpose, Iterators.single(tempBlob));

server/src/test/java/org/elasticsearch/common/blobstore/fs/FsBlobContainerTests.java

+1-5
Original file line numberDiff line numberDiff line change
@@ -389,11 +389,7 @@ public void testCopy() throws IOException {
389389
final var targetBlobName = randomAlphaOfLengthBetween(1, 20).toLowerCase(Locale.ROOT);
390390
final var contents = new BytesArray(randomByteArrayOfLength(randomIntBetween(1, 512)));
391391
sourceContainer.writeBlob(randomPurpose(), sourceBlobName, contents, true);
392-
sourceContainer.copyBlob(randomPurpose(), sourceBlobName, targetContainer, targetBlobName, true);
393-
assertThrows(
394-
FileAlreadyExistsException.class,
395-
() -> sourceContainer.copyBlob(randomPurpose(), sourceBlobName, targetContainer, targetBlobName, true)
396-
);
392+
sourceContainer.copyBlob(randomPurpose(), sourceBlobName, targetContainer, targetBlobName);
397393

398394
var sourceContents = Streams.readFully(sourceContainer.readBlob(randomPurpose(), sourceBlobName));
399395
var targetContents = Streams.readFully(targetContainer.readBlob(randomPurpose(), targetBlobName));

0 commit comments

Comments
 (0)