PageRenderTime 39ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/blobstore/src/main/java/org/jclouds/blobstore/strategy/internal/MultipartUploadSlicingAlgorithm.java

http://github.com/jclouds/jclouds
Java | 158 lines | 116 code | 24 blank | 18 comment | 10 complexity | 838cb8c24487e1964acc93f8cbb6ccf0 MD5 | raw file
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. package org.jclouds.blobstore.strategy.internal;
  18. import static com.google.common.base.Preconditions.checkArgument;
  19. import javax.annotation.Resource;
  20. import javax.inject.Named;
  21. import org.jclouds.blobstore.reference.BlobStoreConstants;
  22. import org.jclouds.logging.Logger;
  23. import com.google.common.annotations.VisibleForTesting;
  24. import com.google.inject.Inject;
  25. public final class MultipartUploadSlicingAlgorithm {
  26. private final long minimumPartSize;
  27. private final long maximumPartSize;
  28. private final int maximumNumberOfParts;
  29. @Resource
  30. @Named(BlobStoreConstants.BLOBSTORE_LOGGER)
  31. protected Logger logger = Logger.NULL;
  32. @VisibleForTesting
  33. public static final long DEFAULT_PART_SIZE = 33554432; // 32MB
  34. @VisibleForTesting
  35. static final int DEFAULT_MAGNITUDE_BASE = 100;
  36. @Inject(optional = true)
  37. @Named("jclouds.mpu.parts.size")
  38. @VisibleForTesting
  39. long defaultPartSize = DEFAULT_PART_SIZE;
  40. @Inject(optional = true)
  41. @Named("jclouds.mpu.parts.magnitude")
  42. @VisibleForTesting
  43. int magnitudeBase = DEFAULT_MAGNITUDE_BASE;
  44. // calculated only once, but not from the constructor
  45. private volatile int parts; // required number of parts with chunkSize
  46. private volatile long chunkSize;
  47. private volatile long remaining; // number of bytes remained for the last part
  48. // sequentially updated values
  49. private volatile int part;
  50. private volatile long chunkOffset;
  51. private volatile long copied;
  52. public MultipartUploadSlicingAlgorithm(long minimumPartSize, long maximumPartSize, int maximumNumberOfParts) {
  53. checkArgument(minimumPartSize > 0);
  54. this.minimumPartSize = minimumPartSize;
  55. checkArgument(maximumPartSize > 0);
  56. this.maximumPartSize = maximumPartSize;
  57. checkArgument(maximumNumberOfParts > 0);
  58. this.maximumNumberOfParts = maximumNumberOfParts;
  59. }
  60. public long calculateChunkSize(long length) {
  61. long unitPartSize = defaultPartSize; // first try with default part size
  62. int parts = (int)(length / unitPartSize);
  63. long partSize = unitPartSize;
  64. int magnitude = parts / magnitudeBase;
  65. if (magnitude > 0) {
  66. partSize = magnitude * unitPartSize;
  67. if (partSize > maximumPartSize) {
  68. partSize = maximumPartSize;
  69. unitPartSize = maximumPartSize;
  70. }
  71. parts = (int)(length / partSize);
  72. if (parts * partSize < length) {
  73. partSize = (magnitude + 1) * unitPartSize;
  74. if (partSize > maximumPartSize) {
  75. partSize = maximumPartSize;
  76. unitPartSize = maximumPartSize;
  77. }
  78. parts = (int)(length / partSize);
  79. }
  80. }
  81. if (partSize < minimumPartSize) {
  82. partSize = minimumPartSize;
  83. unitPartSize = minimumPartSize;
  84. parts = (int)(length / unitPartSize);
  85. }
  86. if (partSize > maximumPartSize) {
  87. partSize = maximumPartSize;
  88. unitPartSize = maximumPartSize;
  89. parts = (int)(length / unitPartSize);
  90. }
  91. if (parts > maximumNumberOfParts) {
  92. partSize = length / maximumNumberOfParts;
  93. unitPartSize = partSize;
  94. parts = maximumNumberOfParts;
  95. }
  96. long remainder = length % unitPartSize;
  97. if (remainder == 0 && parts > 0) {
  98. parts -= 1;
  99. }
  100. this.chunkSize = partSize;
  101. this.parts = parts;
  102. this.remaining = length - partSize * parts;
  103. logger.debug(" %d bytes partitioned in %d parts of part size: %d, remaining: %d%s", length, parts, chunkSize,
  104. remaining, remaining > maximumPartSize ? " overflow!" : "");
  105. return this.chunkSize;
  106. }
  107. public long getCopied() {
  108. return copied;
  109. }
  110. public void setCopied(long copied) {
  111. this.copied = copied;
  112. }
  113. public int getParts() {
  114. return parts;
  115. }
  116. protected int getNextPart() {
  117. return ++part;
  118. }
  119. public void addCopied(long copied) {
  120. this.copied += copied;
  121. }
  122. protected long getNextChunkOffset() {
  123. long next = chunkOffset;
  124. chunkOffset += getChunkSize();
  125. return next;
  126. }
  127. @VisibleForTesting
  128. protected long getChunkSize() {
  129. return chunkSize;
  130. }
  131. public long getRemaining() {
  132. return remaining;
  133. }
  134. }