EMMA Coverage Report (generated Mon Oct 17 05:41:20 EDT 2011)
[all classes][org.jclouds.aws.s3.blobstore.strategy.internal]

COVERAGE SUMMARY FOR SOURCE FILE [SequentialMultipartUploadStrategy.java]

nameclass, %method, %block, %line, %
SequentialMultipartUploadStrategy.java100% (1/1)100% (3/3)85%  (158/186)87%  (33/38)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class SequentialMultipartUploadStrategy100% (1/1)100% (3/3)85%  (158/186)87%  (33/38)
prepareUploadPart (String, String, String, int, Payload, long, long, SortedMa... 100% (1/1)67%  (34/51)70%  (7/10)
execute (String, Blob): String 100% (1/1)91%  (106/117)91%  (21/23)
SequentialMultipartUploadStrategy (AWSS3BlobStore, PayloadSlicer): void 100% (1/1)100% (18/18)100% (5/5)

1/**
2 * Licensed to jclouds, Inc. (jclouds) under one or more
3 * contributor license agreements.  See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership.  jclouds licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License.  You may obtain a copy of the License at
9 *
10 *   http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied.  See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19package org.jclouds.aws.s3.blobstore.strategy.internal;
20 
21import static com.google.common.base.Preconditions.checkNotNull;
22 
23 
24import java.util.SortedMap;
25 
26import javax.annotation.Resource;
27import javax.inject.Named;
28 
29import org.jclouds.aws.s3.AWSS3Client;
30import org.jclouds.aws.s3.blobstore.AWSS3BlobStore;
31import org.jclouds.aws.s3.blobstore.strategy.MultipartUploadStrategy;
32import org.jclouds.blobstore.KeyNotFoundException;
33import org.jclouds.blobstore.domain.Blob;
34import org.jclouds.blobstore.reference.BlobStoreConstants;
35import org.jclouds.io.Payload;
36import org.jclouds.io.PayloadSlicer;
37import org.jclouds.logging.Logger;
38import org.jclouds.s3.domain.ObjectMetadataBuilder;
39import org.jclouds.util.Throwables2;
40 
41import com.google.common.collect.Maps;
42import com.google.inject.Inject;
43 
44/**
45 * Provides a sequential multipart upload strategy.
46 * 
47 * The file partitioning algorithm:
48 * 
49 * The default partition size we choose is 32mb. A multiple of this default partition size is used.
50 * The number of parts first grows to a chosen magnitude (for example 100 parts), then it grows the
51 * partition size instead of number of partitions. When we reached the maximum part size, then again
52 * it starts to grow the number of partitions.
53 * 
54 * @author Tibor Kiss
55 */
56public class SequentialMultipartUploadStrategy implements MultipartUploadStrategy {
57   @Resource
58   @Named(BlobStoreConstants.BLOBSTORE_LOGGER)
59   protected Logger logger = Logger.NULL;
60 
61   protected final AWSS3BlobStore ablobstore;
62   protected final PayloadSlicer slicer;
63 
64   @Inject
65   public SequentialMultipartUploadStrategy(AWSS3BlobStore ablobstore, PayloadSlicer slicer) {
66      this.ablobstore = checkNotNull(ablobstore, "ablobstore");
67      this.slicer = checkNotNull(slicer, "slicer");
68   }
69   
70   protected void prepareUploadPart(String container, String key, String uploadId, int part,
71         Payload payload, long offset, long size, SortedMap<Integer, String> etags) {
72      AWSS3Client client = (AWSS3Client) ablobstore.getContext()
73         .getProviderSpecificContext().getApi();
74      Payload chunkedPart = slicer.slice(payload, offset, size);
75      String eTag = null;
76      try {
77         eTag = client.uploadPart(container, key, part, uploadId, chunkedPart);
78         etags.put(new Integer(part), eTag);
79      } catch (KeyNotFoundException e) {
80         // note that because of eventual consistency, the upload id may not be present yet
81         // we may wish to add this condition to the retry handler
82 
83         // we may also choose to implement ListParts and wait for the uploadId to become
84         // available there.
85         eTag = client.uploadPart(container, key, part, uploadId, chunkedPart);
86         etags.put(new Integer(part), eTag);
87      }
88   }
89 
90   @Override
91   public String execute(String container, Blob blob) {
92      String key = blob.getMetadata().getName();
93      Payload payload = blob.getPayload();
94      MultipartUploadSlicingAlgorithm algorithm = new MultipartUploadSlicingAlgorithm();
95      algorithm
96               .calculateChunkSize(checkNotNull(
97                        payload.getContentMetadata().getContentLength(),
98                        "contentLength required on all uploads to amazon s3; please invoke payload.getContentMetadata().setContentLength(length) first"));
99      int parts = algorithm.getParts();
100      long chunkSize = algorithm.getChunkSize();
101      if (parts > 0) {
102         AWSS3Client client = (AWSS3Client) ablobstore.getContext()
103               .getProviderSpecificContext().getApi();
104         String uploadId = client.initiateMultipartUpload(container,
105               ObjectMetadataBuilder.create().key(key).build()); // TODO md5
106         try {
107            SortedMap<Integer, String> etags = Maps.newTreeMap();
108            int part;
109            while ((part = algorithm.getNextPart()) <= parts) {
110               prepareUploadPart(container, key, uploadId, part, payload, 
111                     algorithm.getNextChunkOffset(), chunkSize, etags);
112            }
113            long remaining = algorithm.getRemaining();
114            if (remaining > 0) {
115               prepareUploadPart(container, key, uploadId, part, payload, 
116                     algorithm.getNextChunkOffset(), remaining, etags);
117            }
118            return client.completeMultipartUpload(container, key, uploadId, etags);
119         } catch (Exception ex) {
120            RuntimeException rtex = Throwables2.getFirstThrowableOfType(ex, RuntimeException.class);
121            if (rtex == null) {
122               rtex = new RuntimeException(ex);
123            }
124            client.abortMultipartUpload(container, key, uploadId);
125            throw rtex;
126         }
127      } else {
128         return ablobstore.putBlob(container, blob);
129      }
130   }
131}

[all classes][org.jclouds.aws.s3.blobstore.strategy.internal]
EMMA 2.0.5312 (C) Vladimir Roubtsov