4444import java .util .HashMap ;
4545import java .util .HashSet ;
4646import java .util .List ;
47+ import java .util .Locale ;
4748import java .util .Map ;
4849import java .util .Set ;
4950import java .util .concurrent .*;
@@ -79,20 +80,29 @@ public CompletableFuture<UploadFilesResult> uploadFilesAsync(UploadFilesRequest
7980 String localDirOrFilePath = request .getSourceFilePath ();
8081 Pair <List <String >, Long > localPathPair = FileUtils .processLocalPath (localDirOrFilePath );
8182 String volumePath = convertDirPath (request .getTargetVolumePath ());
82-
83- UploadContext uploadContext = new UploadContext (refreshVolumeAndClient (volumePath ));
84- VolumeSession initialSession = uploadContext .currentSession ();
85- initValidator (localPathPair , initialSession .applyVolumeResponse );
8683 int uploadConcurrency = Math .max (1 , request .getUploadConcurrency ());
8784 int maxRetries = Math .max (1 , request .getMaxRetries ());
8885 long retryIntervalMillis = Math .max (0L , request .getRetryIntervalMillis ());
8986 long partSizeBytes = Math .max (0L , request .getPartSizeBytes ());
90- ExecutorService uploadExecutor = Executors .newFixedThreadPool (uploadConcurrency );
91-
9287 long totalBytes = localPathPair .getValue ();
9388 long totalFilesCount = localPathPair .getKey ().size ();
94- UploadProgressTracker progressTracker = new UploadProgressTracker (totalBytes , totalFilesCount , request .getProgressListener ());
9589 long startTime = System .currentTimeMillis ();
90+ logger .info ("Starting volume upload: sourcePath:{}, volumeName:{}, volumePath:{}, totalFileCount:{}, totalFileSize:{} bytes ({}), uploadConcurrency:{}, maxRetries:{}, retryInterval:{}, partSize:{}, startTime:{}" ,
91+ localDirOrFilePath , volumeName , volumePath , totalFilesCount , totalBytes , formatBytes (totalBytes ),
92+ uploadConcurrency , maxRetries , formatDurationMillis (retryIntervalMillis ),
93+ formatPartSize (partSizeBytes ), Instant .ofEpochMilli (startTime ));
94+
95+ UploadContext uploadContext ;
96+ try {
97+ uploadContext = new UploadContext (refreshVolumeAndClient (volumePath ));
98+ VolumeSession initialSession = uploadContext .currentSession ();
99+ initValidator (localPathPair , initialSession .applyVolumeResponse );
100+ } catch (RuntimeException e ) {
101+ logUploadFailed (localDirOrFilePath , volumePath , startTime );
102+ throw e ;
103+ }
104+ ExecutorService uploadExecutor = Executors .newFixedThreadPool (uploadConcurrency );
105+ UploadProgressTracker progressTracker = new UploadProgressTracker (totalBytes , totalFilesCount , request .getProgressListener ());
96106
97107 return CompletableFuture .allOf (localPathPair .getKey ().stream ()
98108 .map (localFilePath -> CompletableFuture .runAsync (() -> {
@@ -114,13 +124,19 @@ public CompletableFuture<UploadFilesResult> uploadFilesAsync(UploadFilesRequest
114124 }, uploadExecutor )).toArray (CompletableFuture []::new ))
115125 .whenComplete ((v , t ) -> {
116126 uploadExecutor .shutdown ();
127+ if (t != null ) {
128+ logUploadFailed (localDirOrFilePath , volumePath , startTime );
129+ }
117130 })
118131 .thenApply (v -> {
119132 progressTracker .finishUpload ();
120- long totalElapsed = (System .currentTimeMillis () - startTime ) / 1000 ;
133+ long endTime = System .currentTimeMillis ();
134+ long totalElapsed = endTime - startTime ;
121135 VolumeSession session = uploadContext .currentSession ();
122- logger .info ("all files in {} has been async uploaded to volume, volumeName:{}, volumePath:{}, totalFileCount:{}, totalFileSize:{}, cost times:{} s" ,
123- localDirOrFilePath , session .applyVolumeResponse .getVolumeName (), volumePath , localPathPair .getKey ().size (), localPathPair .getValue (), totalElapsed );
136+ logger .info ("Volume upload completed: sourcePath:{}, volumeName:{}, volumePath:{}, totalFileCount:{}, totalFileSize:{} bytes ({}), endTime:{}, totalElapsed:{}" ,
137+ localDirOrFilePath , session .applyVolumeResponse .getVolumeName (), volumePath ,
138+ localPathPair .getKey ().size (), localPathPair .getValue (), formatBytes (localPathPair .getValue ()),
139+ Instant .ofEpochMilli (endTime ), formatDurationMillis (totalElapsed ));
124140 return UploadFilesResult .builder ()
125141 .volumeName (session .applyVolumeResponse .getVolumeName ())
126142 .path (volumePath )
@@ -141,6 +157,51 @@ public UploadFilesResult uploadFiles(UploadFilesRequest request) throws Executio
141157 public void shutdownGracefully () {
142158 }
143159
160+ private void logUploadFailed (String localDirOrFilePath , String volumePath , long startTime ) {
161+ long endTime = System .currentTimeMillis ();
162+ logger .warn ("Volume upload failed: sourcePath:{}, volumeName:{}, volumePath:{}, endTime:{}, totalElapsed:{}" ,
163+ localDirOrFilePath , volumeName , volumePath ,
164+ Instant .ofEpochMilli (endTime ), formatDurationMillis (endTime - startTime ));
165+ }
166+
167+ private static String formatPartSize (long partSizeBytes ) {
168+ if (partSizeBytes <= 0L ) {
169+ return "auto" ;
170+ }
171+ return partSizeBytes + " bytes (" + formatBytes (partSizeBytes ) + ")" ;
172+ }
173+
174+ private static String formatBytes (long bytes ) {
175+ if (bytes < 1024L ) {
176+ return bytes + " B" ;
177+ }
178+ double value = bytes ;
179+ String [] units = new String []{"B" , "KiB" , "MiB" , "GiB" , "TiB" , "PiB" };
180+ int unitIndex = 0 ;
181+ while (value >= 1024.0 && unitIndex < units .length - 1 ) {
182+ value /= 1024.0 ;
183+ unitIndex ++;
184+ }
185+ return String .format (Locale .ROOT , "%.2f %s" , value , units [unitIndex ]);
186+ }
187+
188+ private static String formatDurationMillis (long durationMillis ) {
189+ if (durationMillis < 0L ) {
190+ return "unknown" ;
191+ }
192+ long totalSeconds = (durationMillis + 999L ) / 1000L ;
193+ long hours = totalSeconds / 3600L ;
194+ long minutes = (totalSeconds % 3600L ) / 60L ;
195+ long seconds = totalSeconds % 60L ;
196+ if (hours > 0L ) {
197+ return String .format (Locale .ROOT , "%dh %02dm %02ds" , hours , minutes , seconds );
198+ }
199+ if (minutes > 0L ) {
200+ return String .format (Locale .ROOT , "%dm %02ds" , minutes , seconds );
201+ }
202+ return String .format (Locale .ROOT , "%ds" , seconds );
203+ }
204+
144205 private void initValidator (Pair <List <String >, Long > localPathPair , ApplyVolumeResponse applyVolumeResponse ) {
145206 Long maxContentLength = applyVolumeResponse .getCondition ().getMaxContentLength ();
146207 Long uploadFileContentLength = localPathPair .getValue ();
@@ -459,23 +520,6 @@ private long estimatedRemainingTimeMillis(long currentUploadedBytes, long speedB
459520 return (long ) Math .ceil (remainingBytes * 1000.0 / speedBps );
460521 }
461522
462- private String formatDurationMillis (long durationMillis ) {
463- if (durationMillis < 0L ) {
464- return "unknown" ;
465- }
466- long totalSeconds = (durationMillis + 999L ) / 1000L ;
467- long hours = totalSeconds / 3600L ;
468- long minutes = (totalSeconds % 3600L ) / 60L ;
469- long seconds = totalSeconds % 60L ;
470- if (hours > 0L ) {
471- return String .format ("%dh %02dm %02ds" , hours , minutes , seconds );
472- }
473- if (minutes > 0L ) {
474- return String .format ("%dm %02ds" , minutes , seconds );
475- }
476- return String .format ("%ds" , seconds );
477- }
478-
479523 private UploadProgress progressIfNeeded (String currentFile , long currentFileUploadedBytes , long currentFileTotalBytes ) {
480524 long now = System .currentTimeMillis ();
481525 double percent = percent ();
0 commit comments