| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| Expand Up | @@ -18,8 +18,10 @@ | |
|
|
||
| import com.google.cloud.storage.Crc32cValue.Crc32cLengthKnown; | ||
| import com.google.common.annotations.VisibleForTesting; | ||
| import com.google.common.base.MoreObjects; | ||
| import com.google.common.base.Preconditions; | ||
| import com.google.common.math.IntMath; | ||
| import com.google.common.primitives.Ints; | ||
| import com.google.protobuf.ByteString; | ||
| import java.math.RoundingMode; | ||
| import java.nio.ByteBuffer; | ||
| Expand Down Expand Up | @@ -97,66 +99,96 @@ ChunkSegment[] segmentBuffers( | |
| // turn this into a single branch, rather than multiple that would need to be checked each | ||
| // element of the iteration | ||
| if (allowUnalignedBlocks) { | ||
| return segmentWithUnaligned(bbs, offset, length); | ||
| return segmentWithUnaligned(bbs, offset, length, Long.MAX_VALUE); | ||
| } else { | ||
| return segmentWithoutUnaligned(bbs, offset, length); | ||
| return segmentWithoutUnaligned(bbs, offset, length, Long.MAX_VALUE); | ||
| } | ||
| } | ||
|
|
||
| private ChunkSegment[] segmentWithUnaligned(ByteBuffer[] bbs, int offset, int length) { | ||
| ChunkSegment[] segmentBuffers( | ||
| ByteBuffer[] bbs, | ||
| int offset, | ||
| int length, | ||
| boolean allowUnalignedBlocks, | ||
| long maxBytesToConsume) { | ||
| // turn this into a single branch, rather than multiple that would need to be checked each | ||
| // element of the iteration | ||
| if (allowUnalignedBlocks) { | ||
| return segmentWithUnaligned(bbs, offset, length, maxBytesToConsume); | ||
| } else { | ||
| long misaligned = maxBytesToConsume % blockSize; | ||
| long alignedMaxBytesToConsume = maxBytesToConsume - misaligned; | ||
| return segmentWithoutUnaligned(bbs, offset, length, alignedMaxBytesToConsume); | ||
| } | ||
| } | ||
|
|
||
| private ChunkSegment[] segmentWithUnaligned( | ||
| ByteBuffer[] bbs, int offset, int length, long maxBytesToConsume) { | ||
| Deque<ChunkSegment> data = new ArrayDeque<>(); | ||
|
|
||
| long consumed = 0; | ||
| for (int i = offset; i < length; i++) { | ||
| ByteBuffer buffer = bbs[i]; | ||
| int remaining; | ||
| while ((remaining = buffer.remaining()) > 0) { | ||
| consumeBytes(data, remaining, buffer); | ||
| while ((remaining = buffer.remaining()) > 0 && consumed < maxBytesToConsume) { | ||
| long remainingConsumable = maxBytesToConsume - consumed; | ||
| int toConsume = remaining; | ||
| if (remainingConsumable < remaining) { | ||
| toConsume = Math.toIntExact(remainingConsumable); | ||
| } | ||
| long consumeBytes = consumeBytes(data, toConsume, buffer); | ||
| consumed += consumeBytes; | ||
| } | ||
| } | ||
|
|
||
| return data.toArray(new ChunkSegment[0]); | ||
| } | ||
|
|
||
| private ChunkSegment[] segmentWithoutUnaligned(ByteBuffer[] bbs, int offset, int length) { | ||
| private ChunkSegment[] segmentWithoutUnaligned( | ||
| ByteBuffer[] bbs, int offset, int length, long maxBytesToConsume) { | ||
| Deque<ChunkSegment> data = new ArrayDeque<>(); | ||
|
|
||
| final long totalRemaining = Buffers.totalRemaining(bbs, offset, length); | ||
| long buffersTotalRemaining = Buffers.totalRemaining(bbs, offset, length); | ||
| final long totalRemaining = Math.min(maxBytesToConsume, buffersTotalRemaining); | ||
| long consumedSoFar = 0; | ||
|
|
||
| int currentBlockPending = blockSize; | ||
|
|
||
| outerloop: | ||
| for (int i = offset; i < length; i++) { | ||
| ByteBuffer buffer = bbs[i]; | ||
| int remaining; | ||
| while ((remaining = buffer.remaining()) > 0) { | ||
| long overallRemaining = totalRemaining - consumedSoFar; | ||
| if (overallRemaining < blockSize && currentBlockPending == blockSize) { | ||
| break; | ||
| break outerloop; | ||
| } | ||
|
|
||
| int numBytesConsumable; | ||
| if (remaining >= blockSize) { | ||
| if (remaining >= blockSize && currentBlockPending == blockSize) { | ||
| int blockCount = IntMath.divide(remaining, blockSize, RoundingMode.DOWN); | ||
| numBytesConsumable = blockCount * blockSize; | ||
| } else if (currentBlockPending < blockSize) { | ||
| numBytesConsumable = currentBlockPending; | ||
| currentBlockPending = blockSize; | ||
| } else { | ||
| numBytesConsumable = remaining; | ||
| currentBlockPending = currentBlockPending - remaining; | ||
| numBytesConsumable = Math.min(remaining, currentBlockPending); | ||
| } | ||
| if (numBytesConsumable <= 0) { | ||
| continue; | ||
| break outerloop; | ||
|
Comment thread
Copy link
Copy Markdown
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityK...now I'm starting to worry a bit about cyclomatic complexity
Sorry, something went wrong.
All reactions
Copy link
Copy Markdown
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityPrior to the appendable upload stuff we generally had a pretty firm bulkhead on the number of buffers that would be passed into these methods outside of tests. With the appendable addition we place less emphasis on early buffering in favor of passing things through wherever possible, so if multiple buffers are passed in here, logically the conditions would prevent consuming any bytes once a break from the while takes place, but by breaking the for as well we avoid the cycles performing work that isn't productive. And, refactoring everything to nested method calls to allow early returns instead of break to label didn't seem worth it to me.
Sorry, something went wrong.
All reactions
Copy link
Copy Markdown
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityWhat's the follow up here?
Sorry, something went wrong.
All reactions
Copy link
Copy Markdown
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low QualityNothing from my perspective. There isn't a functional difference here between the label break and a separate method with early returns.
Sorry, something went wrong.
All reactions
|
||
| } | ||
|
|
||
| consumedSoFar += consumeBytes(data, numBytesConsumable, buffer); | ||
| int consumed = consumeBytes(data, numBytesConsumable, buffer); | ||
| int currentBlockPendingLessConsumed = currentBlockPending - consumed; | ||
| currentBlockPending = currentBlockPendingLessConsumed % blockSize; | ||
| if (currentBlockPending == 0) { | ||
| currentBlockPending = blockSize; | ||
| } | ||
| consumedSoFar += consumed; | ||
| } | ||
| } | ||
|
|
||
| return data.toArray(new ChunkSegment[0]); | ||
| } | ||
|
|
||
| private long consumeBytes(Deque<ChunkSegment> data, int numBytesConsumable, ByteBuffer buffer) { | ||
| private int consumeBytes(Deque<ChunkSegment> data, int numBytesConsumable, ByteBuffer buffer) { | ||
| // either no chunk or most recent chunk is full, start a new one | ||
| ChunkSegment peekLast = data.peekLast(); | ||
| if (peekLast == null || peekLast.b.size() == maxSegmentSize) { | ||
| Expand All | @@ -167,7 +199,8 @@ private long consumeBytes(Deque<ChunkSegment> data, int numBytesConsumable, Byte | |
| } else { | ||
| ChunkSegment chunkSoFar = data.pollLast(); | ||
| //noinspection ConstantConditions -- covered by peekLast check above | ||
| int limit = Math.min(numBytesConsumable, maxSegmentSize - chunkSoFar.b.size()); | ||
| int limit = | ||
| Ints.min(buffer.remaining(), numBytesConsumable, maxSegmentSize - chunkSoFar.b.size()); | ||
| ChunkSegment datum = newSegment(buffer, limit); | ||
| ChunkSegment plus = chunkSoFar.concat(datum); | ||
| data.addLast(plus); | ||
| Expand Down Expand Up | @@ -218,5 +251,14 @@ public Crc32cLengthKnown getCrc32c() { | |
| public boolean isOnlyFullBlocks() { | ||
| return onlyFullBlocks; | ||
| } | ||
|
|
||
| @Override | ||
| public String toString() { | ||
| return MoreObjects.toStringHelper(this) | ||
| .add("crc32c", crc32c) | ||
| .add("onlyFullBlocks", onlyFullBlocks) | ||
| .add("b", b) | ||
| .toString(); | ||
| } | ||
| } | ||
| } | ||
| Back | FazBrowse Home | New Git URL |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Qualityooo, label break, those're rare!
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.