33
33
import com .emc .object .s3 .bean .MultipartPartETag ;
34
34
import com .emc .object .s3 .request .*;
35
35
import com .emc .object .util .InputStreamSegment ;
36
+ import com .emc .object .util .ProgressInputStream ;
37
+ import com .emc .object .util .ProgressListener ;
36
38
import com .emc .rest .util .SizedInputStream ;
37
39
import org .apache .log4j .Logger ;
38
40
47
49
import java .util .concurrent .ExecutorService ;
48
50
import java .util .concurrent .Executors ;
49
51
import java .util .concurrent .Future ;
52
+ import java .util .concurrent .atomic .AtomicLong ;
50
53
51
54
/**
52
55
* Convenience class to facilitate multipart upload for large files. This class will split the file
@@ -74,8 +77,9 @@ public class LargeFileUploader implements Runnable {
74
77
private Long partSize = DEFAULT_PART_SIZE ;
75
78
private int threads = DEFAULT_THREADS ;
76
79
private ExecutorService executorService ;
80
+ private AtomicLong bytesTransferred = new AtomicLong ();
81
+ private ProgressListener progressListener ;
77
82
78
- private long bytesTransferred ;
79
83
private String eTag ;
80
84
81
85
/**
@@ -113,22 +117,14 @@ public void doMultipartUpload() {
113
117
String uploadId = s3Client .initiateMultipartUpload (initRequest ).getUploadId ();
114
118
115
119
List <Future <MultipartPartETag >> futures = new ArrayList <Future <MultipartPartETag >>();
116
- List <SizedInputStream > segmentStreams = new ArrayList <SizedInputStream >();
117
120
try {
118
121
// submit all upload tasks
119
122
int partNumber = 1 ;
120
123
long offset = 0 , length = partSize ;
121
124
while (offset < fullSize ) {
122
125
if (offset + length > fullSize ) length = fullSize - offset ;
123
126
124
- SizedInputStream segmentStream = file != null
125
- ? new InputStreamSegment (new FileInputStream (file ), offset , length )
126
- : new SizedInputStream (stream , length );
127
- segmentStreams .add (segmentStream );
128
-
129
- UploadPartRequest partRequest = new UploadPartRequest (bucket , key , uploadId , partNumber ++, segmentStream );
130
- partRequest .setContentLength (length );
131
- futures .add (executorService .submit (new UploadPartTask (partRequest )));
127
+ futures .add (executorService .submit (new UploadPartTask (uploadId , partNumber ++, offset , length )));
132
128
133
129
offset += length ;
134
130
}
@@ -155,10 +151,6 @@ public void doMultipartUpload() {
155
151
if (e instanceof RuntimeException ) throw (RuntimeException ) e ;
156
152
throw new RuntimeException ("error during upload" , e );
157
153
} finally {
158
- for (SizedInputStream segmentStream : segmentStreams ) {
159
- bytesTransferred += segmentStream .getRead ();
160
- }
161
-
162
154
// make sure all spawned threads are shut down
163
155
executorService .shutdown ();
164
156
@@ -184,22 +176,13 @@ public void doByteRangeUpload() {
184
176
s3Client .putObject (request );
185
177
186
178
List <Future <String >> futures = new ArrayList <Future <String >>();
187
- List <SizedInputStream > segmentStreams = new ArrayList <SizedInputStream >();
188
179
try {
189
180
// submit all upload tasks
190
- PutObjectRequest rangeRequest ;
191
181
long offset = 0 , length = partSize ;
192
182
while (offset < fullSize ) {
193
183
if (offset + length > fullSize ) length = fullSize - offset ;
194
- Range range = Range .fromOffsetLength (offset , length );
195
184
196
- SizedInputStream segmentStream = file != null
197
- ? new InputStreamSegment (new FileInputStream (file ), offset , length )
198
- : new SizedInputStream (stream , length );
199
- segmentStreams .add (segmentStream );
200
-
201
- rangeRequest = new PutObjectRequest (bucket , key , segmentStream ).withRange (range );
202
- futures .add (executorService .submit (new PutObjectTask (rangeRequest )));
185
+ futures .add (executorService .submit (new PutObjectTask (offset , length )));
203
186
204
187
offset += length ;
205
188
}
@@ -219,10 +202,6 @@ public void doByteRangeUpload() {
219
202
if (e instanceof RuntimeException ) throw (RuntimeException ) e ;
220
203
throw new RuntimeException ("error during upload" , e );
221
204
} finally {
222
- for (SizedInputStream segmentStream : segmentStreams ) {
223
- bytesTransferred += segmentStream .getRead ();
224
- }
225
-
226
205
// make sure all spawned threads are shut down
227
206
executorService .shutdown ();
228
207
@@ -300,7 +279,7 @@ public long getFullSize() {
300
279
}
301
280
302
281
public long getBytesTransferred () {
303
- return bytesTransferred ;
282
+ return bytesTransferred . get () ;
304
283
}
305
284
306
285
public String getETag () {
@@ -339,6 +318,14 @@ public void setCloseStream(boolean closeStream) {
339
318
this .closeStream = closeStream ;
340
319
}
341
320
321
+ public ProgressListener getProgressListener () {
322
+ return progressListener ;
323
+ }
324
+
325
+ public void setProgressListener (ProgressListener progressListener ) {
326
+ this .progressListener = progressListener ;
327
+ }
328
+
342
329
public long getPartSize () {
343
330
return partSize ;
344
331
}
@@ -368,6 +355,14 @@ public ExecutorService getExecutorService() {
368
355
return executorService ;
369
356
}
370
357
358
+ private void updateBytesTransferred (long count ) {
359
+ long totalTransferred = bytesTransferred .addAndGet (count );
360
+
361
+ if (progressListener != null ) {
362
+ progressListener .progress (totalTransferred , fullSize );
363
+ }
364
+ }
365
+
371
366
/**
372
367
* Allows for providing a custom thread executor (i.e. for custom thread factories). Note that if
373
368
* you set a custom executor service, the <code>threads</code> property will be ignored.
@@ -411,29 +406,71 @@ public LargeFileUploader withExecutorService(ExecutorService executorService) {
411
406
return this ;
412
407
}
413
408
414
- protected class UploadPartTask implements Callable <MultipartPartETag > {
415
- private UploadPartRequest request ;
409
+ public LargeFileUploader withProgressListener (ProgressListener progressListener ) {
410
+ setProgressListener (progressListener );
411
+ return this ;
412
+ }
413
+
414
+ private class UploadPartTask implements Callable <MultipartPartETag > {
415
+ private String uploadId ;
416
+ private int partNumber ;
417
+ private long offset ;
418
+ private long length ;
416
419
417
- public UploadPartTask (UploadPartRequest request ) {
418
- this .request = request ;
420
+ public UploadPartTask (String uploadId , int partNumber , long offset , long length ) {
421
+ this .uploadId = uploadId ;
422
+ this .partNumber = partNumber ;
423
+ this .offset = offset ;
424
+ this .length = length ;
419
425
}
420
426
421
427
@ Override
422
428
public MultipartPartETag call () throws Exception {
423
- return s3Client .uploadPart (request );
429
+ SizedInputStream segmentStream ;
430
+ if (file != null ) {
431
+ segmentStream = new InputStreamSegment (new ProgressInputStream (new FileInputStream (file ), progressListener ), offset , length );
432
+ } else {
433
+ segmentStream = new SizedInputStream (new ProgressInputStream (stream , progressListener ), length );
434
+ }
435
+
436
+ UploadPartRequest request = new UploadPartRequest (bucket , key , uploadId , partNumber ++, segmentStream );
437
+ request .setContentLength (length );
438
+
439
+ MultipartPartETag etag = s3Client .uploadPart (request );
440
+ updateBytesTransferred (length );
441
+ return etag ;
424
442
}
425
443
}
426
444
427
445
protected class PutObjectTask implements Callable <String > {
428
- private PutObjectRequest request ;
446
+ private long offset ;
447
+ private long length ;
429
448
430
- public PutObjectTask (PutObjectRequest request ) {
431
- this .request = request ;
449
+ public PutObjectTask (long offset , long length ) {
450
+ this .offset = offset ;
451
+ this .length = length ;
432
452
}
433
453
434
454
@ Override
435
455
public String call () throws Exception {
436
- return s3Client .putObject (request ).getETag ();
456
+ Range range = Range .fromOffsetLength (offset , length );
457
+
458
+ SizedInputStream segmentStream = file != null
459
+ ? new InputStreamSegment (new ProgressInputStream (new FileInputStream (file ), progressListener ),
460
+ offset , length ) : new SizedInputStream (new ProgressInputStream (stream , progressListener ),
461
+ length );
462
+
463
+ PutObjectRequest request = new PutObjectRequest (bucket , key , segmentStream ).withRange (range );
464
+
465
+ String etag = s3Client .putObject (request ).getETag ();
466
+ long length = 0 ;
467
+ if (request .getRange () != null ) {
468
+ length = request .getRange ().getLast () - request .getRange ().getFirst () + 1 ;
469
+ } else if (request .getContentLength () != null ) {
470
+ length = request .getContentLength ();
471
+ }
472
+ updateBytesTransferred (length );
473
+ return etag ;
437
474
}
438
475
}
439
476
}
0 commit comments