@@ -462,6 +462,12 @@ public class S3AFileSystem extends FileSystem implements StreamCapabilities,
462
462
*/
463
463
private String scheme = FS_S3A ;
464
464
465
+ /**
466
+ * Flag to indicate that the higher performance copyFromLocalFile implementation
467
+ * should be used.
468
+ */
469
+ private boolean optimizedCopyFromLocal ;
470
+
465
471
/** Add any deprecated keys. */
466
472
@ SuppressWarnings ("deprecation" )
467
473
private static void addDeprecatedKeys () {
@@ -696,6 +702,9 @@ public void initialize(URI name, Configuration originalConf)
696
702
AWS_S3_VECTOR_ACTIVE_RANGE_READS , DEFAULT_AWS_S3_VECTOR_ACTIVE_RANGE_READS , 1 );
697
703
vectoredIOContext = populateVectoredIOContext (conf );
698
704
scheme = (this .uri != null && this .uri .getScheme () != null ) ? this .uri .getScheme () : FS_S3A ;
705
+ optimizedCopyFromLocal = conf .getBoolean (OPTIMIZED_COPY_FROM_LOCAL ,
706
+ OPTIMIZED_COPY_FROM_LOCAL_DEFAULT );
707
+ LOG .debug ("Using optimized copyFromLocal implementation: {}" , optimizedCopyFromLocal );
699
708
} catch (SdkException e ) {
700
709
// amazon client exception: stop all services then throw the translation
701
710
cleanupWithLogger (LOG , span );
@@ -4021,45 +4030,69 @@ private boolean s3Exists(final Path path, final Set<StatusProbeEnum> probes)
4021
4030
* the given dst name.
4022
4031
*
4023
4032
* This version doesn't need to create a temporary file to calculate the md5.
4024
- * Sadly this doesn't seem to be used by the shell cp :(
4033
+ * If {@link Constants#OPTIMIZED_COPY_FROM_LOCAL} is set to false,
4034
+ * the superclass implementation is used.
4025
4035
*
4026
- * delSrc indicates if the source should be removed
4027
4036
* @param delSrc whether to delete the src
4028
4037
* @param overwrite whether to overwrite an existing file
4029
4038
* @param src path
4030
4039
* @param dst path
4031
4040
* @throws IOException IO problem
4032
4041
* @throws FileAlreadyExistsException the destination file exists and
4033
4042
* overwrite==false
4034
- * @throws SdkException failure in the AWS SDK
4035
4043
*/
4036
4044
@ Override
4037
4045
@ AuditEntryPoint
4038
4046
public void copyFromLocalFile (boolean delSrc , boolean overwrite , Path src ,
4039
4047
Path dst ) throws IOException {
4040
4048
checkNotClosed ();
4041
- LOG .debug ("Copying local file from {} to {}" , src , dst );
4042
- trackDurationAndSpan (INVOCATION_COPY_FROM_LOCAL_FILE , dst ,
4043
- () -> new CopyFromLocalOperation (
4044
- createStoreContext (),
4045
- src ,
4046
- dst ,
4047
- delSrc ,
4048
- overwrite ,
4049
- createCopyFromLocalCallbacks ()).execute ());
4049
+ LOG .debug ("Copying local file from {} to {} (delSrc={} overwrite={}" ,
4050
+ src , dst , delSrc , overwrite );
4051
+ if (optimizedCopyFromLocal ) {
4052
+ trackDurationAndSpan (INVOCATION_COPY_FROM_LOCAL_FILE , dst , () ->
4053
+ new CopyFromLocalOperation (
4054
+ createStoreContext (),
4055
+ src ,
4056
+ dst ,
4057
+ delSrc ,
4058
+ overwrite ,
4059
+ createCopyFromLocalCallbacks (getActiveAuditSpan ()))
4060
+ .execute ());
4061
+ } else {
4062
+ // call the superclass, but still count statistics.
4063
+ // there is no overall span here, as each FS API call will
4064
+ // be in its own span.
4065
+ LOG .debug ("Using base copyFromLocalFile implementation" );
4066
+ trackDurationAndSpan (INVOCATION_COPY_FROM_LOCAL_FILE , dst , () -> {
4067
+ super .copyFromLocalFile (delSrc , overwrite , src , dst );
4068
+ return null ;
4069
+ });
4070
+ }
4050
4071
}
4051
4072
4073
+ /**
4074
+ * Create the CopyFromLocalCallbacks;
4075
+ * protected to assist in mocking.
4076
+ * @param span audit span.
4077
+ * @return the callbacks
4078
+ * @throws IOException failure to get the local fs.
4079
+ */
4052
4080
protected CopyFromLocalOperation .CopyFromLocalOperationCallbacks
4053
- createCopyFromLocalCallbacks () throws IOException {
4081
+ createCopyFromLocalCallbacks (final AuditSpanS3A span ) throws IOException {
4054
4082
LocalFileSystem local = getLocal (getConf ());
4055
- return new CopyFromLocalCallbacksImpl (local );
4083
+ return new CopyFromLocalCallbacksImpl (span , local );
4056
4084
}
4057
4085
4058
4086
protected final class CopyFromLocalCallbacksImpl implements
4059
4087
CopyFromLocalOperation .CopyFromLocalOperationCallbacks {
4088
+
4089
+ /** Span to use for all operations. */
4090
+ private final AuditSpanS3A span ;
4060
4091
private final LocalFileSystem local ;
4061
4092
4062
- private CopyFromLocalCallbacksImpl (LocalFileSystem local ) {
4093
+ private CopyFromLocalCallbacksImpl (final AuditSpanS3A span ,
4094
+ LocalFileSystem local ) {
4095
+ this .span = span ;
4063
4096
this .local = local ;
4064
4097
}
4065
4098
@@ -4081,20 +4114,18 @@ public boolean deleteLocal(Path path, boolean recursive) throws IOException {
4081
4114
4082
4115
@ Override
4083
4116
public void copyLocalFileFromTo (File file , Path from , Path to ) throws IOException {
4084
- trackDurationAndSpan (
4085
- OBJECT_PUT_REQUESTS ,
4086
- to ,
4087
- () -> {
4088
- final String key = pathToKey (to );
4089
- Progressable progress = null ;
4090
- PutObjectRequest .Builder putObjectRequestBuilder =
4091
- newPutObjectRequestBuilder (key , file .length (), false );
4092
- S3AFileSystem .this .invoker .retry ("putObject(" + "" + ")" , to .toString (), true ,
4093
- () -> executePut (putObjectRequestBuilder .build (), progress , putOptionsForPath (to ),
4094
- file ));
4095
-
4096
- return null ;
4097
- });
4117
+ // the duration of the put is measured, but the active span is the
4118
+ // constructor-supplied one -this ensures all audit log events are grouped correctly
4119
+ span .activate ();
4120
+ trackDuration (getDurationTrackerFactory (), OBJECT_PUT_REQUESTS .getSymbol (), () -> {
4121
+ final String key = pathToKey (to );
4122
+ PutObjectRequest .Builder putObjectRequestBuilder =
4123
+ newPutObjectRequestBuilder (key , file .length (), false );
4124
+ final String dest = to .toString ();
4125
+ S3AFileSystem .this .invoker .retry ("putObject(" + dest + ")" , dest , true , () ->
4126
+ executePut (putObjectRequestBuilder .build (), null , putOptionsForPath (to ), file ));
4127
+ return null ;
4128
+ });
4098
4129
}
4099
4130
4100
4131
@ Override
@@ -5399,6 +5430,10 @@ public boolean hasPathCapability(final Path path, final String capability)
5399
5430
case FS_S3A_CREATE_PERFORMANCE_ENABLED :
5400
5431
return performanceCreation ;
5401
5432
5433
+ // is the optimized copy from local enabled.
5434
+ case OPTIMIZED_COPY_FROM_LOCAL :
5435
+ return optimizedCopyFromLocal ;
5436
+
5402
5437
default :
5403
5438
return super .hasPathCapability (p , cap );
5404
5439
}
0 commit comments