Source:
<code>private CopyResult copyFile(String srcKey, String dstKey, long size) throws IOException, InterruptedIOException { LOG.debug("copyFile -> ", srcKey, dstKey); ProgressListener progressListener = progressEvent -> { switch (progressEvent.getEventType()) { case TRANSFER_PART_COMPLETED_EVENT: incrementWriteOperations(); break; default: break; } }; return once("copyFile(" + srcKey + ", " + dstKey + ")", srcKey, () -> { ObjectMetadata srcom = getObjectMetadata(srcKey); ObjectMetadata dstom = cloneObjectMetadata(srcom); setOptionalObjectMetadata(dstom); CopyObjectRequest copyObjectRequest = new CopyObjectRequest(bucket, srcKey, bucket, dstKey); setOptionalCopyObjectRequestParameters(copyObjectRequest); copyObjectRequest.setCannedAccessControlList(cannedACL); copyObjectRequest.setNewObjectMetadata(dstom); String id = srcom.getVersionId(); <START> if (id != null) { <END> copyObjectRequest.setSourceVersionId(id); } else if (isNotEmpty(srcom.getETag())) { copyObjectRequest.withMatchingETagConstraint(srcom.getETag()); } Copy copy = transfers.copy(copyObjectRequest); copy.addProgressListener(progressListener); try { CopyResult r = copy.waitForCopyResult(); incrementWriteOperations(); instrumentation.filesCopied(1, size); return r; } catch (InterruptedException e) { throw new InterruptedIOException("Interrupted copying " + srcKey + " to " + dstKey + ", cancelling"); } }); }</code><technical_language>I approaching this in work for HADOOP-16085 is ChangeDetectionPolicy ChangeTracker. I adding new ChangeTracker.maybeApplyConstraint(CopyObjectRequest) ChangeDetectionPolicy.applyRevisionConstraint(CopyObjectRequest, revisionId) methods support that. I call ChangeTracker.processMetadata(srcom) ChangeTracker.maybeApplyConstraint(copyObjectRequest). Resulting behavior depends ChangeDetectionPolicy, generally similar here. A couple of differences: * if change.detection.mode=none, code add constraint * if change.detection.version.required=true, code throw NoVersionAttributeException attribute defined change.detection.source is unavailable do that? Side note: branch currently handle exceptions copy (the 412 error condition) properly. This PR helped remind of that</technical_language>

Target:
private CopyResult copyFile(String srcKey, String dstKey, long size) throws IOException, InterruptedIOException { LOG.debug("copyFile -> ", srcKey, dstKey); ProgressListener progressListener = progressEvent -> { switch (progressEvent.getEventType()) { case TRANSFER_PART_COMPLETED_EVENT: incrementWriteOperations(); break; default: break; } }; try { return once("copyFile(" + srcKey + ", " + dstKey + ")", srcKey, () -> { ObjectMetadata srcom = getObjectMetadata(srcKey); ObjectMetadata dstom = cloneObjectMetadata(srcom); setOptionalObjectMetadata(dstom); CopyObjectRequest copyObjectRequest = new CopyObjectRequest(bucket, srcKey, bucket, dstKey); setOptionalCopyObjectRequestParameters(copyObjectRequest); copyObjectRequest.setCannedAccessControlList(cannedACL); copyObjectRequest.setNewObjectMetadata(dstom); String id = srcom.getVersionId(); if (id != null) { copyObjectRequest.setSourceVersionId(id); } else if (isNotEmpty(srcom.getETag())) { copyObjectRequest.withMatchingETagConstraint(srcom.getETag()); } Copy copy = transfers.copy(copyObjectRequest); copy.addProgressListener(progressListener); try { CopyResult r = copy.waitForCopyResult(); incrementWriteOperations(); instrumentation.filesCopied(1, size); return r; } catch (InterruptedException e) { throw (IOException) new InterruptedIOException( "Interrupted copying " + srcKey + " to " + dstKey + ", cancelling").initCause(e); } }); } catch (RemoteFileChangedException e) { instrumentation.incrementCounter(STREAM_READ_VERSION_MISMATCHES, 1); throw e; } }