/blobstore/src/main/java/org/jclouds/blobstore/strategy/internal/MultipartUploadSlicingAlgorithm.java
Java | 158 lines | 116 code | 24 blank | 18 comment | 10 complexity | 838cb8c24487e1964acc93f8cbb6ccf0 MD5 | raw file
- /*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package org.jclouds.blobstore.strategy.internal;
- import static com.google.common.base.Preconditions.checkArgument;
- import javax.annotation.Resource;
- import javax.inject.Named;
- import org.jclouds.blobstore.reference.BlobStoreConstants;
- import org.jclouds.logging.Logger;
- import com.google.common.annotations.VisibleForTesting;
- import com.google.inject.Inject;
- public final class MultipartUploadSlicingAlgorithm {
- private final long minimumPartSize;
- private final long maximumPartSize;
- private final int maximumNumberOfParts;
- @Resource
- @Named(BlobStoreConstants.BLOBSTORE_LOGGER)
- protected Logger logger = Logger.NULL;
- @VisibleForTesting
- public static final long DEFAULT_PART_SIZE = 33554432; // 32MB
- @VisibleForTesting
- static final int DEFAULT_MAGNITUDE_BASE = 100;
- @Inject(optional = true)
- @Named("jclouds.mpu.parts.size")
- @VisibleForTesting
- long defaultPartSize = DEFAULT_PART_SIZE;
- @Inject(optional = true)
- @Named("jclouds.mpu.parts.magnitude")
- @VisibleForTesting
- int magnitudeBase = DEFAULT_MAGNITUDE_BASE;
- // calculated only once, but not from the constructor
- private volatile int parts; // required number of parts with chunkSize
- private volatile long chunkSize;
- private volatile long remaining; // number of bytes remained for the last part
- // sequentially updated values
- private volatile int part;
- private volatile long chunkOffset;
- private volatile long copied;
- public MultipartUploadSlicingAlgorithm(long minimumPartSize, long maximumPartSize, int maximumNumberOfParts) {
- checkArgument(minimumPartSize > 0);
- this.minimumPartSize = minimumPartSize;
- checkArgument(maximumPartSize > 0);
- this.maximumPartSize = maximumPartSize;
- checkArgument(maximumNumberOfParts > 0);
- this.maximumNumberOfParts = maximumNumberOfParts;
- }
- public long calculateChunkSize(long length) {
- long unitPartSize = defaultPartSize; // first try with default part size
- int parts = (int)(length / unitPartSize);
- long partSize = unitPartSize;
- int magnitude = parts / magnitudeBase;
- if (magnitude > 0) {
- partSize = magnitude * unitPartSize;
- if (partSize > maximumPartSize) {
- partSize = maximumPartSize;
- unitPartSize = maximumPartSize;
- }
- parts = (int)(length / partSize);
- if (parts * partSize < length) {
- partSize = (magnitude + 1) * unitPartSize;
- if (partSize > maximumPartSize) {
- partSize = maximumPartSize;
- unitPartSize = maximumPartSize;
- }
- parts = (int)(length / partSize);
- }
- }
- if (partSize < minimumPartSize) {
- partSize = minimumPartSize;
- unitPartSize = minimumPartSize;
- parts = (int)(length / unitPartSize);
- }
- if (partSize > maximumPartSize) {
- partSize = maximumPartSize;
- unitPartSize = maximumPartSize;
- parts = (int)(length / unitPartSize);
- }
- if (parts > maximumNumberOfParts) {
- partSize = length / maximumNumberOfParts;
- unitPartSize = partSize;
- parts = maximumNumberOfParts;
- }
- long remainder = length % unitPartSize;
- if (remainder == 0 && parts > 0) {
- parts -= 1;
- }
- this.chunkSize = partSize;
- this.parts = parts;
- this.remaining = length - partSize * parts;
- logger.debug(" %d bytes partitioned in %d parts of part size: %d, remaining: %d%s", length, parts, chunkSize,
- remaining, remaining > maximumPartSize ? " overflow!" : "");
- return this.chunkSize;
- }
- public long getCopied() {
- return copied;
- }
- public void setCopied(long copied) {
- this.copied = copied;
- }
- public int getParts() {
- return parts;
- }
- protected int getNextPart() {
- return ++part;
- }
- public void addCopied(long copied) {
- this.copied += copied;
- }
- protected long getNextChunkOffset() {
- long next = chunkOffset;
- chunkOffset += getChunkSize();
- return next;
- }
- @VisibleForTesting
- protected long getChunkSize() {
- return chunkSize;
- }
- public long getRemaining() {
- return remaining;
- }
- }